Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
transaction.c
00001 /******************************************************************************* 00002 * 00003 * Copyright (c) 2013, 2014 Intel Corporation and others. 00004 * All rights reserved. This program and the accompanying materials 00005 * are made available under the terms of the Eclipse Public License v1.0 00006 * and Eclipse Distribution License v1.0 which accompany this distribution. 00007 * 00008 * The Eclipse Public License is available at 00009 * http://www.eclipse.org/legal/epl-v10.html 00010 * The Eclipse Distribution License is available at 00011 * http://www.eclipse.org/org/documents/edl-v10.php. 00012 * 00013 * Contributors: 00014 * David Navarro, Intel Corporation - initial API and implementation 00015 * Simon Bernard - Please refer to git log 00016 * Toby Jaffey - Please refer to git log 00017 * Pascal Rieux - Please refer to git log 00018 * Bosch Software Innovations GmbH - Please refer to git log 00019 * 00020 *******************************************************************************/ 00021 00022 /* 00023 Copyright (c) 2013, 2014 Intel Corporation 00024 00025 Redistribution and use in source and binary forms, with or without modification, 00026 are permitted provided that the following conditions are met: 00027 00028 * Redistributions of source code must retain the above copyright notice, 00029 this list of conditions and the following disclaimer. 00030 * Redistributions in binary form must reproduce the above copyright notice, 00031 this list of conditions and the following disclaimer in the documentation 00032 and/or other materials provided with the distribution. 00033 * Neither the name of Intel Corporation nor the names of its contributors 00034 may be used to endorse or promote products derived from this software 00035 without specific prior written permission. 00036 00037 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00038 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00039 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 00040 IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 00041 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00042 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00043 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00044 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00045 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 00046 THE POSSIBILITY OF SUCH DAMAGE. 00047 00048 David Navarro <david.navarro@intel.com> 00049 00050 */ 00051 00052 /* 00053 Contains code snippets which are: 00054 00055 * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich 00056 * All rights reserved. 00057 * 00058 * Redistribution and use in source and binary forms, with or without 00059 * modification, are permitted provided that the following conditions 00060 * are met: 00061 * 1. Redistributions of source code must retain the above copyright 00062 * notice, this list of conditions and the following disclaimer. 00063 * 2. Redistributions in binary form must reproduce the above copyright 00064 * notice, this list of conditions and the following disclaimer in the 00065 * documentation and/or other materials provided with the distribution. 00066 * 3. Neither the name of the Institute nor the names of its contributors 00067 * may be used to endorse or promote products derived from this software 00068 * without specific prior written permission. 00069 * 00070 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 00071 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00072 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00073 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 00074 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00075 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00076 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00077 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00078 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00079 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00080 * SUCH DAMAGE. 00081 00082 */ 00083 00084 /************************************************************************ 00085 * Function for communications transactions. 00086 * 00087 * Basic specification: rfc7252 00088 * 00089 * Transaction implements processing of piggybacked and separate response communication 00090 * dialogs specified in section 2.2 of the above specification. 00091 * The caller registers a callback function, which is called, when either the result is 00092 * received or a timeout occurs. 00093 * 00094 * Supported dialogs: 00095 * Requests (GET - DELETE): 00096 * - CON with mid, without token => regular finished with corresponding ACK.MID 00097 * - CON with mid, with token => regular finished with corresponding ACK.MID and response containing 00098 * the token. Supports both versions, with piggybacked ACK and separate ACK/response. 00099 * Though the ACK.MID may be lost in the separate version, a matching response may 00100 * finish the transaction even without the ACK.MID. 00101 * - NON without token => no transaction, no result expected! 00102 * - NON with token => regular finished with response containing the token. 00103 * Responses (COAP_201_CREATED - ?): 00104 * - CON with mid => regular finished with corresponding ACK.MID 00105 */ 00106 00107 #include "internals.h" 00108 00109 00110 /* 00111 * Modulo mask (+1 and +0.5 for rounding) for a random number to get the tick number for the random 00112 * retransmission time between COAP_RESPONSE_TIMEOUT and COAP_RESPONSE_TIMEOUT*COAP_RESPONSE_RANDOM_FACTOR. 00113 */ 00114 #define COAP_RESPONSE_TIMEOUT_TICKS (CLOCK_SECOND * COAP_RESPONSE_TIMEOUT) 00115 #define COAP_RESPONSE_TIMEOUT_BACKOFF_MASK ((CLOCK_SECOND * COAP_RESPONSE_TIMEOUT * (COAP_RESPONSE_RANDOM_FACTOR - 1)) + 1.5) 00116 00117 static int prv_checkFinished(lwm2m_transaction_t * transacP, 00118 coap_packet_t * receivedMessage) 00119 { 00120 int len; 00121 const uint8_t* token; 00122 coap_packet_t * transactionMessage = transacP->message; 00123 00124 if (COAP_DELETE < transactionMessage->code) 00125 { 00126 // response 00127 return transacP->ack_received ? 1 : 0; 00128 } 00129 if (!IS_OPTION(transactionMessage, COAP_OPTION_TOKEN)) 00130 { 00131 // request without token 00132 return transacP->ack_received ? 1 : 0; 00133 } 00134 00135 len = coap_get_header_token(receivedMessage, &token); 00136 if (transactionMessage->token_len == len) 00137 { 00138 if (memcmp(transactionMessage->token, token, len)==0) return 1; 00139 } 00140 00141 return 0; 00142 } 00143 00144 lwm2m_transaction_t * transaction_new(void * sessionH, 00145 coap_method_t method, 00146 char * altPath, 00147 lwm2m_uri_t * uriP, 00148 uint16_t mID, 00149 uint8_t token_len, 00150 uint8_t* token) 00151 { 00152 lwm2m_transaction_t * transacP; 00153 int result; 00154 00155 LOG_ARG("method: %d, altPath: \"%s\", mID: %d, token_len: %d", 00156 method, altPath, mID, token_len); 00157 LOG_URI(uriP); 00158 00159 // no transactions without peer 00160 if (NULL == sessionH) return NULL; 00161 00162 transacP = (lwm2m_transaction_t *)lwm2m_malloc(sizeof(lwm2m_transaction_t)); 00163 00164 if (NULL == transacP) return NULL; 00165 memset(transacP, 0, sizeof(lwm2m_transaction_t)); 00166 00167 transacP->message = lwm2m_malloc(sizeof(coap_packet_t)); 00168 if (NULL == transacP->message) goto error; 00169 00170 coap_init_message(transacP->message, COAP_TYPE_CON, method, mID); 00171 00172 transacP->peerH = sessionH; 00173 00174 transacP->mID = mID; 00175 00176 if (altPath != NULL) 00177 { 00178 // TODO: Support multi-segment alternative path 00179 coap_set_header_uri_path_segment(transacP->message, altPath + 1); 00180 } 00181 if (NULL != uriP) 00182 { 00183 result = utils_intCopy(transacP->objStringID, LWM2M_STRING_ID_MAX_LEN, uriP->objectId); 00184 if (result < 0) goto error; 00185 00186 coap_set_header_uri_path_segment(transacP->message, transacP->objStringID); 00187 00188 if (LWM2M_URI_IS_SET_INSTANCE(uriP)) 00189 { 00190 result = utils_intCopy(transacP->instanceStringID, LWM2M_STRING_ID_MAX_LEN, uriP->instanceId); 00191 if (result < 0) goto error; 00192 coap_set_header_uri_path_segment(transacP->message, transacP->instanceStringID); 00193 } 00194 else 00195 { 00196 if (LWM2M_URI_IS_SET_RESOURCE(uriP)) 00197 { 00198 coap_set_header_uri_path_segment(transacP->message, NULL); 00199 } 00200 } 00201 if (LWM2M_URI_IS_SET_RESOURCE(uriP)) 00202 { 00203 result = utils_intCopy(transacP->resourceStringID, LWM2M_STRING_ID_MAX_LEN, uriP->resourceId); 00204 if (result < 0) goto error; 00205 coap_set_header_uri_path_segment(transacP->message, transacP->resourceStringID); 00206 } 00207 } 00208 if (0 < token_len) 00209 { 00210 if (NULL != token) 00211 { 00212 coap_set_header_token(transacP->message, token, token_len); 00213 } 00214 else { 00215 // generate a token 00216 uint8_t temp_token[COAP_TOKEN_LEN]; 00217 time_t tv_sec = lwm2m_gettime(); 00218 00219 // initialize first 6 bytes, leave the last 2 random 00220 temp_token[0] = mID; 00221 temp_token[1] = mID >> 8; 00222 temp_token[2] = tv_sec; 00223 temp_token[3] = tv_sec >> 8; 00224 temp_token[4] = tv_sec >> 16; 00225 temp_token[5] = tv_sec >> 24; 00226 // use just the provided amount of bytes 00227 coap_set_header_token(transacP->message, temp_token, token_len); 00228 } 00229 } 00230 00231 LOG("Exiting on success"); 00232 return transacP; 00233 00234 error: 00235 LOG("Exiting on failure"); 00236 lwm2m_free(transacP); 00237 return NULL; 00238 } 00239 00240 void transaction_free(lwm2m_transaction_t * transacP) 00241 { 00242 LOG("Entering"); 00243 if (transacP->message) lwm2m_free(transacP->message); 00244 if (transacP->buffer) lwm2m_free(transacP->buffer); 00245 lwm2m_free(transacP); 00246 } 00247 00248 void transaction_remove(lwm2m_context_t * contextP, 00249 lwm2m_transaction_t * transacP) 00250 { 00251 LOG("Entering"); 00252 contextP->transactionList = (lwm2m_transaction_t *) LWM2M_LIST_RM(contextP->transactionList, transacP->mID, NULL); 00253 transaction_free(transacP); 00254 } 00255 00256 bool transaction_handleResponse(lwm2m_context_t * contextP, 00257 void * fromSessionH, 00258 coap_packet_t * message, 00259 coap_packet_t * response) 00260 { 00261 bool found = false; 00262 bool reset = false; 00263 lwm2m_transaction_t * transacP; 00264 00265 LOG("Entering"); 00266 transacP = contextP->transactionList; 00267 00268 while (NULL != transacP) 00269 { 00270 if (lwm2m_session_is_equal(fromSessionH, transacP->peerH, contextP->userData) == true) 00271 { 00272 if (!transacP->ack_received) 00273 { 00274 if ((COAP_TYPE_ACK == message->type) || (COAP_TYPE_RST == message->type)) 00275 { 00276 if (transacP->mID == message->mid) 00277 { 00278 found = true; 00279 transacP->ack_received = true; 00280 reset = COAP_TYPE_RST == message->type; 00281 } 00282 } 00283 } 00284 00285 if (reset || prv_checkFinished(transacP, message)) 00286 { 00287 // HACK: If a message is sent from the monitor callback, 00288 // it will arrive before the registration ACK. 00289 // So we resend transaction that were denied for authentication reason. 00290 if (!reset) 00291 { 00292 if (COAP_TYPE_CON == message->type && NULL != response) 00293 { 00294 coap_init_message(response, COAP_TYPE_ACK, 0, message->mid); 00295 message_send(contextP, response, fromSessionH); 00296 } 00297 00298 if ((COAP_401_UNAUTHORIZED == message->code) && (COAP_MAX_RETRANSMIT > transacP->retrans_counter)) 00299 { 00300 transacP->ack_received = false; 00301 transacP->retrans_time += COAP_RESPONSE_TIMEOUT; 00302 return true; 00303 } 00304 } 00305 if (transacP->callback != NULL) 00306 { 00307 transacP->callback(transacP, message); 00308 } 00309 transaction_remove(contextP, transacP); 00310 return true; 00311 } 00312 // if we found our guy, exit 00313 if (found) 00314 { 00315 time_t tv_sec = lwm2m_gettime(); 00316 if (0 <= tv_sec) 00317 { 00318 transacP->retrans_time = tv_sec; 00319 } 00320 if (transacP->response_timeout) 00321 { 00322 transacP->retrans_time += transacP->response_timeout; 00323 } 00324 else 00325 { 00326 transacP->retrans_time += COAP_RESPONSE_TIMEOUT * transacP->retrans_counter; 00327 } 00328 return true; 00329 } 00330 } 00331 00332 transacP = transacP->next; 00333 } 00334 return false; 00335 } 00336 00337 int transaction_send(lwm2m_context_t * contextP, 00338 lwm2m_transaction_t * transacP) 00339 { 00340 bool maxRetriesReached = false; 00341 00342 LOG("Entering"); 00343 if (transacP->buffer == NULL) 00344 { 00345 transacP->buffer_len = coap_serialize_get_size(transacP->message); 00346 if (transacP->buffer_len == 0) return COAP_500_INTERNAL_SERVER_ERROR; 00347 00348 transacP->buffer = (uint8_t*)lwm2m_malloc(transacP->buffer_len); 00349 if (transacP->buffer == NULL) return COAP_500_INTERNAL_SERVER_ERROR; 00350 00351 transacP->buffer_len = coap_serialize_message(transacP->message, transacP->buffer); 00352 if (transacP->buffer_len == 0) 00353 { 00354 lwm2m_free(transacP->buffer); 00355 transacP->buffer = NULL; 00356 transaction_remove(contextP, transacP); 00357 return COAP_500_INTERNAL_SERVER_ERROR; 00358 } 00359 } 00360 00361 if (!transacP->ack_received) 00362 { 00363 long unsigned timeout; 00364 00365 if (0 == transacP->retrans_counter) 00366 { 00367 time_t tv_sec = lwm2m_gettime(); 00368 if (0 <= tv_sec) 00369 { 00370 transacP->retrans_time = tv_sec + COAP_RESPONSE_TIMEOUT; 00371 transacP->retrans_counter = 1; 00372 timeout = 0; 00373 } 00374 else 00375 { 00376 maxRetriesReached = true; 00377 } 00378 } 00379 else 00380 { 00381 timeout = COAP_RESPONSE_TIMEOUT << (transacP->retrans_counter - 1); 00382 } 00383 00384 if (COAP_MAX_RETRANSMIT + 1 >= transacP->retrans_counter) 00385 { 00386 (void)lwm2m_buffer_send(transacP->peerH, transacP->buffer, transacP->buffer_len, contextP->userData); 00387 00388 transacP->retrans_time += timeout; 00389 transacP->retrans_counter += 1; 00390 } 00391 else 00392 { 00393 maxRetriesReached = true; 00394 } 00395 } 00396 00397 if (transacP->ack_received || maxRetriesReached) 00398 { 00399 if (transacP->callback) 00400 { 00401 transacP->callback(transacP, NULL); 00402 } 00403 transaction_remove(contextP, transacP); 00404 return -1; 00405 } 00406 00407 return 0; 00408 } 00409 00410 void transaction_step(lwm2m_context_t * contextP, 00411 time_t currentTime, 00412 time_t * timeoutP) 00413 { 00414 lwm2m_transaction_t * transacP; 00415 00416 LOG("Entering"); 00417 transacP = contextP->transactionList; 00418 while (transacP != NULL) 00419 { 00420 // transaction_send() may remove transaction from the linked list 00421 lwm2m_transaction_t * nextP = transacP->next; 00422 int removed = 0; 00423 00424 if (transacP->retrans_time <= currentTime) 00425 { 00426 removed = transaction_send(contextP, transacP); 00427 } 00428 00429 if (0 == removed) 00430 { 00431 time_t interval; 00432 00433 if (transacP->retrans_time > currentTime) 00434 { 00435 interval = transacP->retrans_time - currentTime; 00436 } 00437 else 00438 { 00439 interval = 1; 00440 } 00441 00442 if (*timeoutP > interval) 00443 { 00444 *timeoutP = interval; 00445 } 00446 } 00447 else 00448 { 00449 *timeoutP = 1; 00450 } 00451 00452 transacP = nextP; 00453 } 00454 }
Generated on Sun Jul 17 2022 20:01:04 by
1.7.2