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.
registration.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 * domedambrosio - Please refer to git log 00016 * Fabien Fleutot - Please refer to git log 00017 * Simon Bernard - Please refer to git log 00018 * Toby Jaffey - Please refer to git log 00019 * Manuel Sangoi - Please refer to git log 00020 * Julien Vermillard - Please refer to git log 00021 * Bosch Software Innovations GmbH - Please refer to git log 00022 * Pascal Rieux - Please refer to git log 00023 * 00024 *******************************************************************************/ 00025 00026 /* 00027 Copyright (c) 2013, 2014 Intel Corporation 00028 00029 Redistribution and use in source and binary forms, with or without modification, 00030 are permitted provided that the following conditions are met: 00031 00032 * Redistributions of source code must retain the above copyright notice, 00033 this list of conditions and the following disclaimer. 00034 * Redistributions in binary form must reproduce the above copyright notice, 00035 this list of conditions and the following disclaimer in the documentation 00036 and/or other materials provided with the distribution. 00037 * Neither the name of Intel Corporation nor the names of its contributors 00038 may be used to endorse or promote products derived from this software 00039 without specific prior written permission. 00040 00041 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00042 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00043 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 00044 IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 00045 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00046 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00047 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00048 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00049 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 00050 THE POSSIBILITY OF SUCH DAMAGE. 00051 00052 David Navarro <david.navarro@intel.com> 00053 00054 */ 00055 00056 #include "internals.h" 00057 00058 #include <stdlib.h> 00059 #include <string.h> 00060 #include <stdio.h> 00061 00062 #define MAX_LOCATION_LENGTH 10 // strlen("/rd/65534") + 1 00063 00064 #ifdef LWM2M_CLIENT_MODE 00065 00066 static int prv_getRegistrationQuery(lwm2m_context_t * contextP, 00067 lwm2m_server_t * server, 00068 char * buffer, 00069 size_t length) 00070 { 00071 int index; 00072 int res; 00073 00074 index = utils_stringCopy(buffer, length, QUERY_STARTER QUERY_VERSION_FULL QUERY_DELIMITER QUERY_NAME); 00075 if (index < 0) return 0; 00076 res = utils_stringCopy(buffer + index, length - index, contextP->endpointName); 00077 if (res < 0) return 0; 00078 index += res; 00079 00080 if (NULL != contextP->msisdn) 00081 { 00082 res = utils_stringCopy(buffer + index, length - index, QUERY_DELIMITER QUERY_SMS); 00083 if (res < 0) return 0; 00084 index += res; 00085 res = utils_stringCopy(buffer + index, length - index, contextP->msisdn); 00086 if (res < 0) return 0; 00087 index += res; 00088 } 00089 00090 switch (server->binding) 00091 { 00092 case BINDING_U: 00093 res = utils_stringCopy(buffer + index, length - index, "&b=U"); 00094 break; 00095 case BINDING_UQ: 00096 res = utils_stringCopy(buffer + index, length - index, "&b=UQ"); 00097 break; 00098 case BINDING_S: 00099 res = utils_stringCopy(buffer + index, length - index, "&b=S"); 00100 break; 00101 case BINDING_SQ: 00102 res = utils_stringCopy(buffer + index, length - index, "&b=SQ"); 00103 break; 00104 case BINDING_US: 00105 res = utils_stringCopy(buffer + index, length - index, "&b=US"); 00106 break; 00107 case BINDING_UQS: 00108 res = utils_stringCopy(buffer + index, length - index, "&b=UQS"); 00109 break; 00110 default: 00111 res = -1; 00112 } 00113 if (res < 0) return 0; 00114 00115 return index + res; 00116 } 00117 00118 static void prv_handleRegistrationReply(lwm2m_transaction_t * transacP, 00119 void * message) 00120 { 00121 coap_packet_t * packet = (coap_packet_t *)message; 00122 lwm2m_server_t * targetP = (lwm2m_server_t *)(transacP->userData); 00123 00124 if (targetP->status == STATE_REG_PENDING) 00125 { 00126 time_t tv_sec = lwm2m_gettime(); 00127 if (tv_sec >= 0) 00128 { 00129 targetP->registration = tv_sec; 00130 } 00131 if (packet != NULL && packet->code == COAP_201_CREATED) 00132 { 00133 targetP->status = STATE_REGISTERED; 00134 if (NULL != targetP->location) 00135 { 00136 lwm2m_free(targetP->location); 00137 } 00138 targetP->location = coap_get_multi_option_as_string(packet->location_path); 00139 00140 LOG("Registration successful"); 00141 } 00142 else 00143 { 00144 targetP->status = STATE_REG_FAILED; 00145 LOG("Registration failed"); 00146 } 00147 } 00148 } 00149 00150 #define PRV_QUERY_BUFFER_LENGTH 200 00151 00152 // send the registration for a single server 00153 static uint8_t prv_register(lwm2m_context_t * contextP, 00154 lwm2m_server_t * server) 00155 { 00156 char query[200]; 00157 int query_length; 00158 uint8_t payload[512]; 00159 int payload_length; 00160 lwm2m_transaction_t * transaction; 00161 00162 payload_length = object_getRegisterPayload(contextP, payload, sizeof(payload)); 00163 if (payload_length == 0) return COAP_500_INTERNAL_SERVER_ERROR; 00164 00165 query_length = prv_getRegistrationQuery(contextP, server, query, sizeof(query)); 00166 00167 if (query_length == 0) return COAP_500_INTERNAL_SERVER_ERROR; 00168 00169 if (0 != server->lifetime) 00170 { 00171 int res; 00172 00173 res = utils_stringCopy(query + query_length, PRV_QUERY_BUFFER_LENGTH - query_length, QUERY_DELIMITER QUERY_LIFETIME); 00174 if (res < 0) return COAP_500_INTERNAL_SERVER_ERROR; 00175 query_length += res; 00176 res = utils_intCopy(query + query_length, PRV_QUERY_BUFFER_LENGTH - query_length, server->lifetime); 00177 if (res < 0) return COAP_500_INTERNAL_SERVER_ERROR; 00178 query_length += res; 00179 } 00180 00181 if (server->sessionH == NULL) 00182 { 00183 server->sessionH = lwm2m_connect_server(server->secObjInstID, contextP->userData); 00184 } 00185 00186 if (NULL == server->sessionH) return COAP_503_SERVICE_UNAVAILABLE; 00187 00188 transaction = transaction_new(server->sessionH, COAP_POST, NULL, NULL, contextP->nextMID++, 4, NULL); 00189 if (transaction == NULL) return COAP_500_INTERNAL_SERVER_ERROR; 00190 00191 coap_set_header_uri_path(transaction->message, "/"URI_REGISTRATION_SEGMENT); 00192 coap_set_header_uri_query(transaction->message, query); 00193 coap_set_header_content_type(transaction->message, LWM2M_CONTENT_LINK); 00194 coap_set_payload(transaction->message, payload, payload_length); 00195 00196 transaction->callback = prv_handleRegistrationReply; 00197 transaction->userData = (void *) server; 00198 00199 contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transaction); 00200 if (transaction_send(contextP, transaction) != 0) return COAP_500_INTERNAL_SERVER_ERROR; 00201 00202 server->status = STATE_REG_PENDING; 00203 00204 return COAP_NO_ERROR; 00205 } 00206 00207 static void prv_handleRegistrationUpdateReply(lwm2m_transaction_t * transacP, 00208 void * message) 00209 { 00210 coap_packet_t * packet = (coap_packet_t *)message; 00211 lwm2m_server_t * targetP = (lwm2m_server_t *)(transacP->userData); 00212 00213 if (targetP->status == STATE_REG_UPDATE_PENDING) 00214 { 00215 time_t tv_sec = lwm2m_gettime(); 00216 if (tv_sec >= 0) 00217 { 00218 targetP->registration = tv_sec; 00219 } 00220 if (packet != NULL && packet->code == COAP_204_CHANGED) 00221 { 00222 targetP->status = STATE_REGISTERED; 00223 LOG("Registration update successful"); 00224 } 00225 else 00226 { 00227 targetP->status = STATE_REG_FAILED; 00228 LOG("Registration update failed"); 00229 } 00230 } 00231 } 00232 00233 static int prv_updateRegistration(lwm2m_context_t * contextP, 00234 lwm2m_server_t * server, 00235 bool withObjects) 00236 { 00237 lwm2m_transaction_t * transaction; 00238 uint8_t payload[512]; 00239 int payload_length; 00240 00241 transaction = transaction_new(server->sessionH, COAP_POST, NULL, NULL, contextP->nextMID++, 4, NULL); 00242 if (transaction == NULL) return COAP_500_INTERNAL_SERVER_ERROR; 00243 00244 coap_set_header_uri_path(transaction->message, server->location); 00245 00246 if (withObjects == true) 00247 { 00248 payload_length = object_getRegisterPayload(contextP, payload, sizeof(payload)); 00249 if (payload_length == 0) 00250 { 00251 transaction_free(transaction); 00252 return COAP_500_INTERNAL_SERVER_ERROR; 00253 } 00254 coap_set_payload(transaction->message, payload, payload_length); 00255 } 00256 00257 transaction->callback = prv_handleRegistrationUpdateReply; 00258 transaction->userData = (void *) server; 00259 00260 contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transaction); 00261 00262 if (transaction_send(contextP, transaction) == 0) 00263 { 00264 server->status = STATE_REG_UPDATE_PENDING; 00265 } 00266 00267 return COAP_NO_ERROR; 00268 } 00269 00270 // update the registration of a given server 00271 int lwm2m_update_registration(lwm2m_context_t * contextP, 00272 uint16_t shortServerID, 00273 bool withObjects) 00274 { 00275 lwm2m_server_t * targetP; 00276 uint8_t result; 00277 00278 LOG_ARG("State: %s, shortServerID: %d", STR_STATE(contextP->state), shortServerID); 00279 00280 result = COAP_NO_ERROR; 00281 00282 targetP = contextP->serverList; 00283 if (targetP == NULL) 00284 { 00285 if (object_getServers(contextP) == -1) 00286 { 00287 LOG("No server found"); 00288 return COAP_404_NOT_FOUND; 00289 } 00290 } 00291 while (targetP != NULL && result == COAP_NO_ERROR) 00292 { 00293 if (shortServerID != 0) 00294 { 00295 if (targetP->shortID == shortServerID) 00296 { 00297 // found the server, trigger the update transaction 00298 if (targetP->status == STATE_REGISTERED 00299 || targetP->status == STATE_REG_UPDATE_PENDING) 00300 { 00301 if (withObjects == true) 00302 { 00303 targetP->status = STATE_REG_FULL_UPDATE_NEEDED; 00304 } 00305 else 00306 { 00307 targetP->status = STATE_REG_UPDATE_NEEDED; 00308 } 00309 return COAP_NO_ERROR; 00310 } 00311 else if ((targetP->status == STATE_REG_FULL_UPDATE_NEEDED) 00312 || (targetP->status == STATE_REG_UPDATE_NEEDED)) 00313 { 00314 // if REG (FULL) UPDATE is already set, returns COAP_NO_ERROR 00315 if (withObjects == true) 00316 { 00317 targetP->status = STATE_REG_FULL_UPDATE_NEEDED; 00318 } 00319 return COAP_NO_ERROR; 00320 } 00321 else 00322 { 00323 return COAP_400_BAD_REQUEST; 00324 } 00325 } 00326 } 00327 else 00328 { 00329 if (targetP->status == STATE_REGISTERED 00330 || targetP->status == STATE_REG_UPDATE_PENDING) 00331 { 00332 if (withObjects == true) 00333 { 00334 targetP->status = STATE_REG_FULL_UPDATE_NEEDED; 00335 } 00336 else 00337 { 00338 targetP->status = STATE_REG_UPDATE_NEEDED; 00339 } 00340 } 00341 } 00342 targetP = targetP->next; 00343 } 00344 00345 if (shortServerID != 0 00346 && targetP == NULL) 00347 { 00348 // no server found 00349 result = COAP_404_NOT_FOUND; 00350 } 00351 00352 return result; 00353 } 00354 00355 uint8_t registration_start(lwm2m_context_t * contextP) 00356 { 00357 lwm2m_server_t * targetP; 00358 uint8_t result; 00359 00360 LOG_ARG("State: %s", STR_STATE(contextP->state)); 00361 00362 result = COAP_NO_ERROR; 00363 00364 targetP = contextP->serverList; 00365 while (targetP != NULL && result == COAP_NO_ERROR) 00366 { 00367 if (targetP->status == STATE_DEREGISTERED 00368 || targetP->status == STATE_REG_FAILED) 00369 { 00370 result = prv_register(contextP, targetP); 00371 } 00372 targetP = targetP->next; 00373 } 00374 00375 return result; 00376 } 00377 00378 00379 /* 00380 * Returns STATE_REG_PENDING if at least one registration is still pending 00381 * Returns STATE_REGISTERED if no registration is pending and there is at least one server the client is registered to 00382 * Returns STATE_REG_FAILED if all registration failed. 00383 */ 00384 lwm2m_status_t registration_getStatus(lwm2m_context_t * contextP) 00385 { 00386 lwm2m_server_t * targetP; 00387 lwm2m_status_t reg_status; 00388 00389 LOG_ARG("State: %s", STR_STATE(contextP->state)); 00390 00391 targetP = contextP->serverList; 00392 reg_status = STATE_REG_FAILED; 00393 00394 while (targetP != NULL) 00395 { 00396 LOG_ARG("targetP->status: %s", STR_STATUS(targetP->status)); 00397 switch (targetP->status) 00398 { 00399 case STATE_REGISTERED: 00400 case STATE_REG_UPDATE_NEEDED: 00401 case STATE_REG_FULL_UPDATE_NEEDED: 00402 case STATE_REG_UPDATE_PENDING: 00403 if (reg_status == STATE_REG_FAILED) 00404 { 00405 reg_status = STATE_REGISTERED; 00406 } 00407 break; 00408 00409 case STATE_REG_PENDING: 00410 reg_status = STATE_REG_PENDING; 00411 break; 00412 00413 case STATE_REG_FAILED: 00414 case STATE_DEREG_PENDING: 00415 case STATE_DEREGISTERED: 00416 default: 00417 break; 00418 } 00419 LOG_ARG("reg_status: %s", STR_STATUS(reg_status)); 00420 00421 targetP = targetP->next; 00422 } 00423 00424 return reg_status; 00425 } 00426 00427 static void prv_handleDeregistrationReply(lwm2m_transaction_t * transacP, 00428 void * message) 00429 { 00430 lwm2m_server_t * targetP; 00431 00432 targetP = (lwm2m_server_t *)(transacP->userData); 00433 if (NULL != targetP) 00434 { 00435 if (targetP->status == STATE_DEREG_PENDING) 00436 { 00437 targetP->status = STATE_DEREGISTERED; 00438 } 00439 } 00440 } 00441 00442 void registration_deregister(lwm2m_context_t * contextP, 00443 lwm2m_server_t * serverP) 00444 { 00445 lwm2m_transaction_t * transaction; 00446 00447 LOG_ARG("State: %s, serverP->status: %s", STR_STATE(contextP->state), STR_STATUS(serverP->status)); 00448 00449 if (serverP->status == STATE_DEREGISTERED 00450 || serverP->status == STATE_REG_PENDING 00451 || serverP->status == STATE_DEREG_PENDING 00452 || serverP->status == STATE_REG_FAILED 00453 || serverP->location == NULL) 00454 { 00455 return; 00456 } 00457 00458 transaction = transaction_new(serverP->sessionH, COAP_DELETE, NULL, NULL, contextP->nextMID++, 4, NULL); 00459 if (transaction == NULL) return; 00460 00461 coap_set_header_uri_path(transaction->message, serverP->location); 00462 00463 transaction->callback = prv_handleDeregistrationReply; 00464 transaction->userData = (void *) contextP; 00465 00466 contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transaction); 00467 if (transaction_send(contextP, transaction) == 0) 00468 { 00469 serverP->status = STATE_DEREG_PENDING; 00470 } 00471 } 00472 #endif 00473 00474 #ifdef LWM2M_SERVER_MODE 00475 static void prv_freeClientObjectList(lwm2m_client_object_t * objects) 00476 { 00477 while (objects != NULL) 00478 { 00479 lwm2m_client_object_t * objP; 00480 00481 while (objects->instanceList != NULL) 00482 { 00483 lwm2m_list_t * target; 00484 00485 target = objects->instanceList; 00486 objects->instanceList = objects->instanceList->next; 00487 lwm2m_free(target); 00488 } 00489 00490 objP = objects; 00491 objects = objects->next; 00492 lwm2m_free(objP); 00493 } 00494 } 00495 00496 static int prv_getParameters(multi_option_t * query, 00497 char ** nameP, 00498 uint32_t * lifetimeP, 00499 char ** msisdnP, 00500 lwm2m_binding_t * bindingP, 00501 char ** versionP) 00502 { 00503 *nameP = NULL; 00504 *lifetimeP = 0; 00505 *msisdnP = NULL; 00506 *bindingP = BINDING_UNKNOWN; 00507 *versionP = NULL; 00508 00509 while (query != NULL) 00510 { 00511 if (lwm2m_strncmp((char *)query->data, QUERY_NAME, QUERY_NAME_LEN) == 0) 00512 { 00513 if (*nameP != NULL) goto error; 00514 if (query->len == QUERY_NAME_LEN) goto error; 00515 00516 *nameP = (char *)lwm2m_malloc(query->len - QUERY_NAME_LEN + 1); 00517 if (*nameP != NULL) 00518 { 00519 memcpy(*nameP, query->data + QUERY_NAME_LEN, query->len - QUERY_NAME_LEN); 00520 (*nameP)[query->len - QUERY_NAME_LEN] = 0; 00521 } 00522 } 00523 else if (lwm2m_strncmp((char *)query->data, QUERY_SMS, QUERY_SMS_LEN) == 0) 00524 { 00525 if (*msisdnP != NULL) goto error; 00526 if (query->len == QUERY_SMS_LEN) goto error; 00527 00528 *msisdnP = (char *)lwm2m_malloc(query->len - QUERY_SMS_LEN + 1); 00529 if (*msisdnP != NULL) 00530 { 00531 memcpy(*msisdnP, query->data + QUERY_SMS_LEN, query->len - QUERY_SMS_LEN); 00532 (*msisdnP)[query->len - QUERY_SMS_LEN] = 0; 00533 } 00534 } 00535 else if (lwm2m_strncmp((char *)query->data, QUERY_LIFETIME, QUERY_LIFETIME_LEN) == 0) 00536 { 00537 int i; 00538 00539 if (*lifetimeP != 0) goto error; 00540 if (query->len == QUERY_LIFETIME_LEN) goto error; 00541 00542 for (i = QUERY_LIFETIME_LEN ; i < query->len ; i++) 00543 { 00544 if (query->data[i] < '0' || query->data[i] > '9') goto error; 00545 *lifetimeP = (*lifetimeP * 10) + (query->data[i] - '0'); 00546 } 00547 } 00548 else if (lwm2m_strncmp((char *)query->data, QUERY_VERSION, QUERY_VERSION_LEN) == 0) 00549 { 00550 if (*versionP != NULL) goto error; 00551 if (query->len == QUERY_VERSION_LEN) goto error; 00552 00553 *versionP = (char *)lwm2m_malloc(query->len - QUERY_VERSION_LEN + 1); 00554 if (*versionP != NULL) 00555 { 00556 memcpy(*versionP, query->data + QUERY_VERSION_LEN, query->len - QUERY_VERSION_LEN); 00557 (*versionP)[query->len - QUERY_VERSION_LEN] = 0; 00558 } 00559 } 00560 else if (lwm2m_strncmp((char *)query->data, QUERY_BINDING, QUERY_BINDING_LEN) == 0) 00561 { 00562 if (*bindingP != BINDING_UNKNOWN) goto error; 00563 if (query->len == QUERY_BINDING_LEN) goto error; 00564 00565 *bindingP = utils_stringToBinding(query->data + QUERY_BINDING_LEN, query->len - QUERY_BINDING_LEN); 00566 } 00567 query = query->next; 00568 } 00569 00570 return 0; 00571 00572 error: 00573 if (*nameP != NULL) lwm2m_free(*nameP); 00574 if (*msisdnP != NULL) lwm2m_free(*msisdnP); 00575 if (*versionP != NULL) lwm2m_free(*versionP); 00576 00577 return -1; 00578 } 00579 00580 static uint16_t prv_splitLinkAttribute(uint8_t * data, 00581 uint16_t length, 00582 uint16_t * keyStart, 00583 uint16_t * keyLength, 00584 uint16_t * valueStart, 00585 uint16_t * valueLength) 00586 { 00587 uint16_t index; 00588 uint16_t end; 00589 00590 index = 0; 00591 while (index < length && data[index] == ' ') index++; 00592 if (index == length) return 0; 00593 00594 if (data[index] == REG_ATTR_SEPARATOR) 00595 { 00596 index++; 00597 } 00598 if (index == length) return 0; 00599 00600 *keyStart = index; 00601 00602 while (index < length && data[index] != REG_ATTR_EQUALS) index++; 00603 if (index == *keyStart || index == length) return 0; 00604 00605 *keyLength = index - *keyStart; 00606 00607 index++; 00608 while (index < length && data[index] == ' ') index++; 00609 if (index == length) return 0; 00610 00611 *valueStart = index; 00612 00613 while (index < length && data[index] != REG_ATTR_SEPARATOR) index++; 00614 end = index; 00615 00616 index--; 00617 while (index > *valueStart && data[index] == ' ') index--; 00618 if (index == *valueStart) return 0; 00619 00620 *valueLength = index - *valueStart + 1; 00621 00622 return end; 00623 } 00624 00625 static int prv_parseLinkAttributes(uint8_t * data, 00626 uint16_t length, 00627 bool * supportJSON, 00628 char ** altPath) 00629 { 00630 uint16_t index; 00631 uint16_t pathStart; 00632 uint16_t pathLength; 00633 bool isValid; 00634 00635 isValid = false; 00636 00637 // Expecting application/link-format (RFC6690) 00638 // leading space were removed before. Remove trailing spaces. 00639 while (length > 0 && data[length-1] == ' ') length--; 00640 00641 // strip open tag 00642 if (length >= 2 && data[0] == REG_URI_START) 00643 { 00644 data += 1; 00645 length -= 1; 00646 } 00647 else 00648 { 00649 return 0; 00650 } 00651 00652 pathStart = 0; 00653 index = length - 1; 00654 while (index > 0 && data[index] != REG_URI_END) index--; 00655 // link attributes are required 00656 if (index == 0 || index == length - 1) return 0; 00657 00658 // If there is a preceding /, remove it 00659 if (data[pathStart] == '/') 00660 { 00661 pathStart += 1; 00662 } 00663 pathLength = index - pathStart; 00664 00665 index++; 00666 if (index >= length || data[index] != REG_ATTR_SEPARATOR) return 0; 00667 index++; 00668 00669 while (index < length) 00670 { 00671 uint16_t result; 00672 uint16_t keyStart; 00673 uint16_t keyLength; 00674 uint16_t valueStart; 00675 uint16_t valueLength; 00676 00677 result = prv_splitLinkAttribute(data + index, length - index, &keyStart, &keyLength, &valueStart, &valueLength); 00678 if (result == 0) return 0; 00679 00680 if (keyLength == REG_ATTR_TYPE_KEY_LEN 00681 && 0 == lwm2m_strncmp(REG_ATTR_TYPE_KEY, data + index + keyStart, keyLength)) 00682 { 00683 if (isValid == true) return 0; // declared twice 00684 if (valueLength != REG_ATTR_TYPE_VALUE_LEN 00685 || 0 != lwm2m_strncmp(REG_ATTR_TYPE_VALUE, data + index + valueStart, valueLength)) 00686 { 00687 return 0; 00688 } 00689 isValid = true; 00690 } 00691 else if (keyLength == REG_ATTR_CONTENT_KEY_LEN 00692 && 0 == lwm2m_strncmp(REG_ATTR_CONTENT_KEY, data + index + keyStart, keyLength)) 00693 { 00694 if (*supportJSON == true) return 0; // declared twice 00695 if (valueLength == REG_ATTR_CONTENT_JSON_LEN 00696 && 0 == lwm2m_strncmp(REG_ATTR_CONTENT_JSON, data + index + valueStart, valueLength)) 00697 { 00698 *supportJSON = true; 00699 } 00700 else 00701 { 00702 return 0; 00703 } 00704 } 00705 // else ignore this one 00706 00707 index += result; 00708 } 00709 00710 if (isValid == false) return 0; 00711 00712 if (pathLength != 0) 00713 { 00714 *altPath = (char *)lwm2m_malloc(pathLength + 1); 00715 if (*altPath == NULL) return 0; 00716 memcpy(*altPath, data + pathStart, pathLength); 00717 (*altPath)[pathLength] = 0; 00718 } 00719 00720 return 1; 00721 } 00722 00723 static int prv_getId(uint8_t * data, 00724 uint16_t length, 00725 uint16_t * objId, 00726 uint16_t * instanceId) 00727 { 00728 int value; 00729 uint16_t limit; 00730 00731 // Expecting application/link-format (RFC6690) 00732 // leading space were removed before. Remove trailing spaces. 00733 while (length > 0 && data[length-1] == ' ') length--; 00734 00735 // strip open and close tags 00736 if (length >= 1 && data[0] == REG_URI_START && data[length-1] == REG_URI_END) 00737 { 00738 data += 1; 00739 length -= 2; 00740 } 00741 else 00742 { 00743 return 0; 00744 } 00745 00746 // If there is a preceding /, remove it 00747 if (length >= 1 && data[0] == '/') 00748 { 00749 data += 1; 00750 length -= 1; 00751 } 00752 00753 limit = 0; 00754 while (limit < length && data[limit] != '/') limit++; 00755 value = uri_getNumber(data, limit); 00756 if (value < 0 || value >= LWM2M_MAX_ID) return 0; 00757 *objId = value; 00758 00759 if (limit < length) 00760 { 00761 limit += 1; 00762 data += limit; 00763 length -= limit; 00764 00765 if (length > 0) 00766 { 00767 value = uri_getNumber(data, length); 00768 if (value >= 0 && value < LWM2M_MAX_ID) 00769 { 00770 *instanceId = value; 00771 return 2; 00772 } 00773 else 00774 { 00775 return 0; 00776 } 00777 } 00778 } 00779 00780 return 1; 00781 } 00782 00783 static lwm2m_client_object_t * prv_decodeRegisterPayload(uint8_t * payload, 00784 uint16_t payloadLength, 00785 bool * supportJSON, 00786 char ** altPath) 00787 { 00788 uint16_t index; 00789 lwm2m_client_object_t * objList; 00790 bool linkAttrFound; 00791 00792 *altPath = NULL; 00793 *supportJSON = false; 00794 objList = NULL; 00795 linkAttrFound = false; 00796 index = 0; 00797 00798 while (index <= payloadLength) 00799 { 00800 uint16_t start; 00801 uint16_t length; 00802 int result; 00803 uint16_t id; 00804 uint16_t instance; 00805 00806 while (index < payloadLength && payload[index] == ' ') index++; 00807 if (index == payloadLength) break; 00808 00809 start = index; 00810 while (index < payloadLength && payload[index] != REG_DELIMITER) index++; 00811 length = index - start; 00812 00813 result = prv_getId(payload + start, length, &id, &instance); 00814 if (result != 0) 00815 { 00816 lwm2m_client_object_t * objectP; 00817 00818 objectP = (lwm2m_client_object_t *)lwm2m_list_find((lwm2m_list_t *)objList, id); 00819 if (objectP == NULL) 00820 { 00821 objectP = (lwm2m_client_object_t *)lwm2m_malloc(sizeof(lwm2m_client_object_t)); 00822 memset(objectP, 0, sizeof(lwm2m_client_object_t)); 00823 if (objectP == NULL) goto error; 00824 objectP->id = id; 00825 objList = (lwm2m_client_object_t *)LWM2M_LIST_ADD(objList, objectP); 00826 } 00827 if (result == 2) 00828 { 00829 lwm2m_list_t * instanceP; 00830 00831 instanceP = lwm2m_list_find(objectP->instanceList, instance); 00832 if (instanceP == NULL) 00833 { 00834 instanceP = (lwm2m_list_t *)lwm2m_malloc(sizeof(lwm2m_list_t)); 00835 memset(instanceP, 0, sizeof(lwm2m_list_t)); 00836 instanceP->id = instance; 00837 objectP->instanceList = LWM2M_LIST_ADD(objectP->instanceList, instanceP); 00838 } 00839 } 00840 } 00841 else if (linkAttrFound == false) 00842 { 00843 result = prv_parseLinkAttributes(payload + start, length, supportJSON, altPath); 00844 if (result == 0) goto error; 00845 00846 linkAttrFound = true; 00847 } 00848 else goto error; 00849 00850 index++; 00851 } 00852 00853 return objList; 00854 00855 error: 00856 if (*altPath != NULL) 00857 { 00858 lwm2m_free(*altPath); 00859 *altPath = NULL; 00860 } 00861 prv_freeClientObjectList(objList); 00862 00863 return NULL; 00864 } 00865 00866 static lwm2m_client_t * prv_getClientByName(lwm2m_context_t * contextP, 00867 char * name) 00868 { 00869 lwm2m_client_t * targetP; 00870 00871 targetP = contextP->clientList; 00872 while (targetP != NULL && strcmp(name, targetP->name) != 0) 00873 { 00874 targetP = targetP->next; 00875 } 00876 00877 return targetP; 00878 } 00879 00880 void registration_freeClient(lwm2m_client_t * clientP) 00881 { 00882 LOG("Entering"); 00883 if (clientP->name != NULL) lwm2m_free(clientP->name); 00884 if (clientP->msisdn != NULL) lwm2m_free(clientP->msisdn); 00885 if (clientP->altPath != NULL) lwm2m_free(clientP->altPath); 00886 prv_freeClientObjectList(clientP->objectList); 00887 while(clientP->observationList != NULL) 00888 { 00889 lwm2m_observation_t * targetP; 00890 00891 targetP = clientP->observationList; 00892 clientP->observationList = clientP->observationList->next; 00893 lwm2m_free(targetP); 00894 } 00895 lwm2m_free(clientP); 00896 } 00897 00898 static int prv_getLocationString(uint16_t id, 00899 char location[MAX_LOCATION_LENGTH]) 00900 { 00901 int index; 00902 int result; 00903 00904 memset(location, 0, MAX_LOCATION_LENGTH); 00905 00906 result = utils_stringCopy(location, MAX_LOCATION_LENGTH, "/"URI_REGISTRATION_SEGMENT"/"); 00907 if (result < 0) return 0; 00908 index = result; 00909 00910 result = utils_intCopy(location + index, MAX_LOCATION_LENGTH - index, id); 00911 if (result < 0) return 0; 00912 00913 return index + result; 00914 } 00915 00916 coap_status_t registration_handleRequest(lwm2m_context_t * contextP, 00917 lwm2m_uri_t * uriP, 00918 void * fromSessionH, 00919 coap_packet_t * message, 00920 coap_packet_t * response) 00921 { 00922 coap_status_t result; 00923 time_t tv_sec; 00924 00925 LOG_URI(uriP); 00926 tv_sec = lwm2m_gettime(); 00927 if (tv_sec < 0) return COAP_500_INTERNAL_SERVER_ERROR; 00928 00929 switch(message->code) 00930 { 00931 case COAP_POST: 00932 { 00933 char * name = NULL; 00934 uint32_t lifetime; 00935 char * msisdn; 00936 char * altPath; 00937 char * version; 00938 lwm2m_binding_t binding; 00939 lwm2m_client_object_t * objects; 00940 bool supportJSON; 00941 lwm2m_client_t * clientP; 00942 char location[MAX_LOCATION_LENGTH]; 00943 00944 if (0 != prv_getParameters(message->uri_query, &name, &lifetime, &msisdn, &binding, &version)) 00945 { 00946 return COAP_400_BAD_REQUEST; 00947 } 00948 if (message->content_type != LWM2M_CONTENT_LINK 00949 && message->content_type != LWM2M_CONTENT_TEXT) 00950 { 00951 return COAP_400_BAD_REQUEST; 00952 } 00953 00954 objects = prv_decodeRegisterPayload(message->payload, message->payload_len, &supportJSON, &altPath); 00955 00956 switch (uriP->flag & LWM2M_URI_MASK_ID) 00957 { 00958 case 0: 00959 // Register operation 00960 // Version is mandatory 00961 if (version == NULL) 00962 { 00963 if (name != NULL) lwm2m_free(name); 00964 if (msisdn != NULL) lwm2m_free(msisdn); 00965 return COAP_400_BAD_REQUEST; 00966 } 00967 // Endpoint client name is mandatory 00968 if (name == NULL) 00969 { 00970 lwm2m_free(version); 00971 if (msisdn != NULL) lwm2m_free(msisdn); 00972 return COAP_400_BAD_REQUEST; 00973 } 00974 // Object list is mandatory 00975 if (objects == NULL) 00976 { 00977 lwm2m_free(version); 00978 lwm2m_free(name); 00979 if (msisdn != NULL) lwm2m_free(msisdn); 00980 return COAP_400_BAD_REQUEST; 00981 } 00982 // version must be 1.0 00983 if (strlen(version) != LWM2M_VERSION_LEN 00984 || lwm2m_strncmp(version, LWM2M_VERSION, LWM2M_VERSION_LEN)) 00985 { 00986 lwm2m_free(version); 00987 lwm2m_free(name); 00988 if (msisdn != NULL) lwm2m_free(msisdn); 00989 return COAP_412_PRECONDITION_FAILED; 00990 } 00991 00992 if (lifetime == 0) 00993 { 00994 lifetime = LWM2M_DEFAULT_LIFETIME; 00995 } 00996 00997 clientP = prv_getClientByName(contextP, name); 00998 if (clientP != NULL) 00999 { 01000 // we reset this registration 01001 lwm2m_free(clientP->name); 01002 if (clientP->msisdn != NULL) lwm2m_free(clientP->msisdn); 01003 if (clientP->altPath != NULL) lwm2m_free(clientP->altPath); 01004 prv_freeClientObjectList(clientP->objectList); 01005 clientP->objectList = NULL; 01006 } 01007 else 01008 { 01009 clientP = (lwm2m_client_t *)lwm2m_malloc(sizeof(lwm2m_client_t)); 01010 if (clientP == NULL) 01011 { 01012 lwm2m_free(name); 01013 lwm2m_free(altPath); 01014 if (msisdn != NULL) lwm2m_free(msisdn); 01015 prv_freeClientObjectList(objects); 01016 return COAP_500_INTERNAL_SERVER_ERROR; 01017 } 01018 memset(clientP, 0, sizeof(lwm2m_client_t)); 01019 clientP->internalID = lwm2m_list_newId((lwm2m_list_t *)contextP->clientList); 01020 contextP->clientList = (lwm2m_client_t *)LWM2M_LIST_ADD(contextP->clientList, clientP); 01021 } 01022 clientP->name = name; 01023 clientP->binding = binding; 01024 clientP->msisdn = msisdn; 01025 clientP->altPath = altPath; 01026 clientP->supportJSON = supportJSON; 01027 clientP->lifetime = lifetime; 01028 clientP->endOfLife = tv_sec + lifetime; 01029 clientP->objectList = objects; 01030 clientP->sessionH = fromSessionH; 01031 01032 if (prv_getLocationString(clientP->internalID, location) == 0) 01033 { 01034 registration_freeClient(clientP); 01035 return COAP_500_INTERNAL_SERVER_ERROR; 01036 } 01037 if (coap_set_header_location_path(response, location) == 0) 01038 { 01039 registration_freeClient(clientP); 01040 return COAP_500_INTERNAL_SERVER_ERROR; 01041 } 01042 01043 if (contextP->monitorCallback != NULL) 01044 { 01045 contextP->monitorCallback(clientP->internalID, NULL, COAP_201_CREATED, LWM2M_CONTENT_TEXT, NULL, 0, contextP->monitorUserData); 01046 } 01047 result = COAP_201_CREATED; 01048 break; 01049 01050 case LWM2M_URI_FLAG_OBJECT_ID: 01051 clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, uriP->objectId); 01052 if (clientP == NULL) return COAP_404_NOT_FOUND; 01053 01054 // Endpoint client name MUST NOT be present 01055 if (name != NULL) 01056 { 01057 lwm2m_free(name); 01058 if (msisdn != NULL) lwm2m_free(msisdn); 01059 return COAP_400_BAD_REQUEST; 01060 } 01061 01062 if (binding != BINDING_UNKNOWN) 01063 { 01064 clientP->binding = binding; 01065 } 01066 if (msisdn != NULL) 01067 { 01068 if (clientP->msisdn != NULL) lwm2m_free(clientP->msisdn); 01069 clientP->msisdn = msisdn; 01070 } 01071 if (lifetime != 0) 01072 { 01073 clientP->lifetime = lifetime; 01074 } 01075 // client IP address, port or MSISDN may have changed 01076 clientP->sessionH = fromSessionH; 01077 01078 if (objects != NULL) 01079 { 01080 lwm2m_observation_t * observationP; 01081 01082 // remove observations on object/instance no longer existing 01083 observationP = clientP->observationList; 01084 while (observationP != NULL) 01085 { 01086 lwm2m_client_object_t * objP; 01087 lwm2m_observation_t * nextP; 01088 01089 nextP = observationP->next; 01090 01091 objP = (lwm2m_client_object_t *)lwm2m_list_find((lwm2m_list_t *)objects, observationP->uri.objectId); 01092 if (objP == NULL) 01093 { 01094 observationP->callback(clientP->internalID, 01095 &observationP->uri, 01096 COAP_202_DELETED, 01097 LWM2M_CONTENT_TEXT, NULL, 0, 01098 observationP->userData); 01099 observe_remove(observationP); 01100 } 01101 else 01102 { 01103 if ((observationP->uri.flag & LWM2M_URI_FLAG_INSTANCE_ID) != 0) 01104 { 01105 if (lwm2m_list_find((lwm2m_list_t *)objP->instanceList, observationP->uri.instanceId) == NULL) 01106 { 01107 observationP->callback(clientP->internalID, 01108 &observationP->uri, 01109 COAP_202_DELETED, 01110 LWM2M_CONTENT_TEXT, NULL, 0, 01111 observationP->userData); 01112 observe_remove(observationP); 01113 } 01114 } 01115 } 01116 01117 observationP = nextP; 01118 } 01119 01120 prv_freeClientObjectList(clientP->objectList); 01121 clientP->objectList = objects; 01122 } 01123 01124 clientP->endOfLife = tv_sec + clientP->lifetime; 01125 01126 if (contextP->monitorCallback != NULL) 01127 { 01128 contextP->monitorCallback(clientP->internalID, NULL, COAP_204_CHANGED, LWM2M_CONTENT_TEXT, NULL, 0, contextP->monitorUserData); 01129 } 01130 result = COAP_204_CHANGED; 01131 break; 01132 01133 default: 01134 return COAP_400_BAD_REQUEST; 01135 } 01136 } 01137 break; 01138 01139 case COAP_DELETE: 01140 { 01141 lwm2m_client_t * clientP; 01142 01143 if ((uriP->flag & LWM2M_URI_MASK_ID) != LWM2M_URI_FLAG_OBJECT_ID) return COAP_400_BAD_REQUEST; 01144 01145 contextP->clientList = (lwm2m_client_t *)LWM2M_LIST_RM(contextP->clientList, uriP->objectId, &clientP); 01146 if (clientP == NULL) return COAP_400_BAD_REQUEST; 01147 if (contextP->monitorCallback != NULL) 01148 { 01149 contextP->monitorCallback(clientP->internalID, NULL, COAP_202_DELETED, LWM2M_CONTENT_TEXT, NULL, 0, contextP->monitorUserData); 01150 } 01151 registration_freeClient(clientP); 01152 result = COAP_202_DELETED; 01153 } 01154 break; 01155 01156 default: 01157 return COAP_400_BAD_REQUEST; 01158 } 01159 01160 return result; 01161 } 01162 01163 void lwm2m_set_monitoring_callback(lwm2m_context_t * contextP, 01164 lwm2m_result_callback_t callback, 01165 void * userData) 01166 { 01167 LOG("Entering"); 01168 contextP->monitorCallback = callback; 01169 contextP->monitorUserData = userData; 01170 } 01171 #endif 01172 01173 // for each server update the registration if needed 01174 // for each client check if the registration expired 01175 void registration_step(lwm2m_context_t * contextP, 01176 time_t currentTime, 01177 time_t * timeoutP) 01178 { 01179 #ifdef LWM2M_CLIENT_MODE 01180 lwm2m_server_t * targetP = contextP->serverList; 01181 01182 LOG_ARG("State: %s", STR_STATE(contextP->state)); 01183 01184 targetP = contextP->serverList; 01185 while (targetP != NULL) 01186 { 01187 switch (targetP->status) 01188 { 01189 case STATE_REGISTERED: 01190 { 01191 time_t nextUpdate; 01192 time_t interval; 01193 01194 nextUpdate = targetP->lifetime; 01195 if (COAP_MAX_TRANSMIT_WAIT < nextUpdate) 01196 { 01197 nextUpdate -= COAP_MAX_TRANSMIT_WAIT; 01198 } 01199 else 01200 { 01201 nextUpdate = nextUpdate >> 1; 01202 } 01203 01204 interval = targetP->registration + nextUpdate - currentTime; 01205 if (0 >= interval) 01206 { 01207 LOG("Updating registration"); 01208 prv_updateRegistration(contextP, targetP, false); 01209 } 01210 else if (interval < *timeoutP) 01211 { 01212 *timeoutP = interval; 01213 } 01214 } 01215 break; 01216 01217 case STATE_REG_UPDATE_NEEDED: 01218 prv_updateRegistration(contextP, targetP, false); 01219 break; 01220 01221 case STATE_REG_FULL_UPDATE_NEEDED: 01222 prv_updateRegistration(contextP, targetP, true); 01223 break; 01224 01225 case STATE_REG_FAILED: 01226 if (targetP->sessionH != NULL) 01227 { 01228 lwm2m_close_connection(targetP->sessionH, contextP->userData); 01229 targetP->sessionH = NULL; 01230 } 01231 break; 01232 01233 default: 01234 break; 01235 } 01236 targetP = targetP->next; 01237 } 01238 01239 #endif 01240 #ifdef LWM2M_SERVER_MODE 01241 lwm2m_client_t * clientP; 01242 01243 LOG("Entering"); 01244 // monitor clients lifetime 01245 clientP = contextP->clientList; 01246 while (clientP != NULL) 01247 { 01248 lwm2m_client_t * nextP = clientP->next; 01249 01250 if (clientP->endOfLife <= currentTime) 01251 { 01252 contextP->clientList = (lwm2m_client_t *)LWM2M_LIST_RM(contextP->clientList, clientP->internalID, NULL); 01253 if (contextP->monitorCallback != NULL) 01254 { 01255 contextP->monitorCallback(clientP->internalID, NULL, COAP_202_DELETED, LWM2M_CONTENT_TEXT, NULL, 0, contextP->monitorUserData); 01256 } 01257 registration_freeClient(clientP); 01258 } 01259 else 01260 { 01261 time_t interval; 01262 01263 interval = clientP->endOfLife - currentTime; 01264 01265 if (*timeoutP > interval) 01266 { 01267 *timeoutP = interval; 01268 } 01269 } 01270 clientP = nextP; 01271 } 01272 #endif 01273 01274 } 01275
Generated on Sun Jul 17 2022 20:01:04 by
1.7.2