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.
Dependencies: FXAS21002 FXOS8700Q
m2mnsdlinterface.cpp
00001 /* 00002 * Copyright (c) 2015-2019 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 // Needed for PRIu64 on FreeRTOS 00018 #include <stdio.h> 00019 // Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX 00020 #ifndef __STDC_LIMIT_MACROS 00021 #define __STDC_LIMIT_MACROS 00022 #endif 00023 00024 // Note: this macro is needed on armcc to get the the PRI*32 macros 00025 // from inttypes.h in a C++ code. 00026 #ifndef __STDC_FORMAT_MACROS 00027 #define __STDC_FORMAT_MACROS 00028 #endif 00029 00030 #include <assert.h> 00031 #include <inttypes.h> 00032 #include <stdlib.h> 00033 #include "include/nsdlaccesshelper.h" 00034 #include "include/m2mnsdlobserver.h" 00035 #include "include/m2mtlvdeserializer.h" 00036 #include "include/m2mtlvserializer.h" 00037 #include "include/m2mnsdlinterface.h" 00038 #include "include/m2mreporthandler.h" 00039 #include "mbed-client/m2mstring.h" 00040 #include "mbed-client/m2msecurity.h" 00041 #include "mbed-client/m2mserver.h" 00042 #include "mbed-client/m2mobject.h" 00043 #include "mbed-client/m2mendpoint.h" 00044 #include "mbed-client/m2mobjectinstance.h" 00045 #include "mbed-client/m2mresource.h" 00046 #include "mbed-client/m2mblockmessage.h" 00047 #include "mbed-client/m2mconstants.h" 00048 #include "mbed-client/uriqueryparser.h" 00049 #include "mbed-trace/mbed_trace.h" 00050 #include "sn_grs.h" 00051 #include "mbed-client/m2minterfacefactory.h" 00052 #include "mbed-client/m2mdevice.h" 00053 #include "randLIB.h" 00054 #include "common_functions.h" 00055 #include "sn_nsdl_lib.h" 00056 #include "sn_coap_protocol.h" 00057 #include "m2mnotificationhandler.h" 00058 #include "eventOS_event_timer.h" 00059 #include "eventOS_scheduler.h" 00060 #include "ns_hal_init.h" 00061 00062 #define MBED_CLIENT_NSDLINTERFACE_TASKLET_INIT_EVENT 0 // Tasklet init occurs always when generating a tasklet 00063 #define MBED_CLIENT_NSDLINTERFACE_EVENT 30 00064 #define MBED_CLIENT_NSDLINTERFACE_BS_EVENT 31 00065 #define MBED_CLIENT_NSDLINTERFACE_BS_PUT_EVENT 32 00066 #define MBED_CLIENT_NSDLINTERFACE_BS_FINISH_EVENT 33 00067 00068 #ifdef MBED_CONF_MBED_CLIENT_EVENT_LOOP_SIZE 00069 #define MBED_CLIENT_EVENT_LOOP_SIZE MBED_CONF_MBED_CLIENT_EVENT_LOOP_SIZE 00070 #else 00071 #define MBED_CLIENT_EVENT_LOOP_SIZE 1024 00072 #endif 00073 00074 #define BUFFER_SIZE 21 00075 #define TRACE_GROUP "mClt" 00076 #define MAX_QUERY_COUNT 10 00077 00078 const char *MCC_VERSION = "mccv=2.2.1"; 00079 00080 int8_t M2MNsdlInterface::_tasklet_id = -1; 00081 00082 extern "C" void nsdlinterface_tasklet_func(arm_event_s *event) 00083 { 00084 // skip the init event as there will be a timer event after 00085 if (event->event_type == MBED_CLIENT_NSDLINTERFACE_EVENT) { 00086 eventOS_scheduler_mutex_wait(); 00087 M2MNsdlInterface::nsdl_coap_data_s *coap_data = (M2MNsdlInterface::nsdl_coap_data_s*)event->data_ptr; 00088 M2MNsdlInterface *interface = (M2MNsdlInterface*)sn_nsdl_get_context(coap_data->nsdl_handle); 00089 if (interface) { 00090 interface->resource_callback_handle_event(coap_data->received_coap_header, &coap_data->address); 00091 if (coap_data->received_coap_header->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && 00092 coap_data->received_coap_header->payload_ptr) { 00093 coap_data->nsdl_handle->grs->sn_grs_free(coap_data->received_coap_header->payload_ptr); 00094 coap_data->received_coap_header->payload_ptr = 0; 00095 } 00096 } 00097 00098 M2MNsdlInterface::memory_free(coap_data->received_coap_header->payload_ptr); 00099 sn_coap_parser_release_allocated_coap_msg_mem(coap_data->nsdl_handle->grs->coap, coap_data->received_coap_header); 00100 M2MNsdlInterface::memory_free(coap_data->address.addr_ptr); 00101 M2MNsdlInterface::memory_free(coap_data); 00102 eventOS_scheduler_mutex_release(); 00103 00104 } else if (event->event_type == MBED_CLIENT_NSDLINTERFACE_BS_EVENT) { 00105 M2MNsdlInterface::nsdl_coap_data_s *coap_data = (M2MNsdlInterface::nsdl_coap_data_s*)event->data_ptr; 00106 M2MNsdlInterface *interface = (M2MNsdlInterface*)sn_nsdl_get_context(coap_data->nsdl_handle); 00107 00108 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(coap_data->nsdl_handle, 00109 coap_data->received_coap_header, 00110 coap_data->received_coap_header->msg_code); 00111 if (coap_response) { 00112 coap_response->msg_type = coap_data->received_coap_header->msg_type; 00113 00114 if (sn_nsdl_send_coap_message(coap_data->nsdl_handle, &coap_data->address, coap_response) == 0) { 00115 interface->store_bs_finished_response_id(coap_response->msg_id); 00116 } else { 00117 tr_error("Failed to send final response for BS finished"); 00118 } 00119 00120 sn_coap_parser_release_allocated_coap_msg_mem(coap_data->nsdl_handle->grs->coap, coap_response); 00121 00122 } else { 00123 tr_error("Failed to create final response message for BS finished"); 00124 } 00125 00126 // Release the memory 00127 M2MNsdlInterface::memory_free(coap_data->received_coap_header->payload_ptr); 00128 sn_coap_parser_release_allocated_coap_msg_mem(coap_data->nsdl_handle->grs->coap, coap_data->received_coap_header); 00129 M2MNsdlInterface::memory_free(coap_data->address.addr_ptr); 00130 M2MNsdlInterface::memory_free(coap_data); 00131 } else if (event->event_type == MBED_CLIENT_NSDLINTERFACE_BS_PUT_EVENT) { 00132 M2MNsdlInterface::nsdl_coap_data_s *coap_data = (M2MNsdlInterface::nsdl_coap_data_s*)event->data_ptr; 00133 M2MNsdlInterface *interface = (M2MNsdlInterface*)sn_nsdl_get_context(coap_data->nsdl_handle); 00134 interface->handle_bootstrap_put_message(coap_data->received_coap_header, &coap_data->address); 00135 00136 M2MNsdlInterface::memory_free(coap_data->received_coap_header->payload_ptr); 00137 sn_coap_parser_release_allocated_coap_msg_mem(coap_data->nsdl_handle->grs->coap, coap_data->received_coap_header); 00138 M2MNsdlInterface::memory_free(coap_data->address.addr_ptr); 00139 M2MNsdlInterface::memory_free(coap_data); 00140 } else if (event->event_type == MBED_CLIENT_NSDLINTERFACE_BS_FINISH_EVENT) { 00141 nsdl_s *nsdl_handle = (nsdl_s*)event->data_ptr; 00142 M2MNsdlInterface *interface = (M2MNsdlInterface*)sn_nsdl_get_context(nsdl_handle); 00143 interface->handle_bootstrap_finish_ack(event->event_data); 00144 } 00145 } 00146 00147 M2MNsdlInterface::M2MNsdlInterface(M2MNsdlObserver &observer, M2MConnectionHandler &connection_handler) 00148 : _observer(observer), 00149 _endpoint(NULL), 00150 _nsdl_handle(NULL), 00151 _security(NULL), 00152 _server(NULL), 00153 _nsdl_execution_timer(*this), 00154 _registration_timer(*this), 00155 _connection_handler(connection_handler), 00156 _counter_for_nsdl(0), 00157 _next_coap_ping_send_time(0), 00158 _server_address(NULL), 00159 _custom_uri_query_params(NULL), 00160 _notification_handler(new M2MNotificationHandler()), 00161 _bootstrap_id(0), 00162 _binding_mode(M2MInterface::NOT_SET), 00163 _identity_accepted(false), 00164 _nsdl_execution_timer_running(false), 00165 _notification_send_ongoing(false), 00166 _registered(false), 00167 _bootstrap_finish_ack_received(false), 00168 _download_retry_timer(*this), 00169 _download_retry_time(0) 00170 { 00171 tr_debug("M2MNsdlInterface::M2MNsdlInterface()"); 00172 00173 _event.data.data_ptr = NULL; 00174 _event.data.event_data = 0; 00175 _event.data.event_id = 0; 00176 _event.data.sender = 0; 00177 _event.data.event_type = 0; 00178 _event.data.priority = ARM_LIB_MED_PRIORITY_EVENT; 00179 00180 _server = new M2MServer(); 00181 00182 // This initializes libCoap and libNsdl 00183 // Parameters are function pointers to used memory allocation 00184 // and free functions in structure and used functions for sending 00185 // and receiving purposes. 00186 _nsdl_handle = sn_nsdl_init(&(__nsdl_c_send_to_server), &(__nsdl_c_received_from_server), 00187 &(__nsdl_c_memory_alloc), &(__nsdl_c_memory_free), &(__nsdl_c_auto_obs_token)); 00188 00189 sn_nsdl_set_context(_nsdl_handle, this); 00190 00191 ns_hal_init(NULL, MBED_CLIENT_EVENT_LOOP_SIZE, NULL, NULL); 00192 eventOS_scheduler_mutex_wait(); 00193 if (M2MNsdlInterface::_tasklet_id < 0) { 00194 M2MNsdlInterface::_tasklet_id = eventOS_event_handler_create(nsdlinterface_tasklet_func, MBED_CLIENT_NSDLINTERFACE_TASKLET_INIT_EVENT); 00195 assert(M2MNsdlInterface::_tasklet_id >= 0); 00196 } 00197 eventOS_scheduler_mutex_release(); 00198 00199 _event.data.receiver = M2MNsdlInterface::_tasklet_id; 00200 00201 // Randomize the initial auto obs token. Range is in 1 - 1023 00202 _auto_obs_token = randLIB_get_random_in_range(AUTO_OBS_TOKEN_MIN, AUTO_OBS_TOKEN_MAX); 00203 00204 initialize(); 00205 } 00206 00207 M2MNsdlInterface::~M2MNsdlInterface() 00208 { 00209 tr_debug("M2MNsdlInterface::~M2MNsdlInterface() - IN"); 00210 if (_endpoint) { 00211 memory_free(_endpoint->endpoint_name_ptr); 00212 memory_free(_endpoint->domain_name_ptr); 00213 memory_free(_endpoint->type_ptr); 00214 memory_free(_endpoint->lifetime_ptr); 00215 memory_free(_endpoint); 00216 } 00217 00218 delete _notification_handler; 00219 _base_list.clear(); 00220 _security = NULL; 00221 delete _server; 00222 sn_nsdl_destroy(_nsdl_handle); 00223 _nsdl_handle = NULL; 00224 memory_free(_server_address); 00225 free_request_context_list(NULL, false); 00226 free_response_list(); 00227 memory_free(_custom_uri_query_params); 00228 tr_debug("M2MNsdlInterface::~M2MNsdlInterface() - OUT"); 00229 } 00230 00231 bool M2MNsdlInterface::initialize() 00232 { 00233 tr_debug("M2MNsdlInterface::initialize()"); 00234 bool success = false; 00235 00236 // Sets the packet retransmission attempts and time interval 00237 sn_nsdl_set_retransmission_parameters(_nsdl_handle, 00238 MBED_CLIENT_RECONNECTION_COUNT, 00239 MBED_CLIENT_RECONNECTION_INTERVAL); 00240 00241 sn_nsdl_set_retransmission_buffer(_nsdl_handle, MBED_CLIENT_SN_COAP_RESENDING_QUEUE_SIZE_MSGS, 0); 00242 00243 sn_nsdl_handle_block2_response_internally(_nsdl_handle, false); 00244 00245 // Allocate the memory for endpoint 00246 _endpoint = (sn_nsdl_ep_parameters_s*)memory_alloc(sizeof(sn_nsdl_ep_parameters_s)); 00247 if (_endpoint) { 00248 memset(_endpoint, 0, sizeof(sn_nsdl_ep_parameters_s)); 00249 success = true; 00250 } 00251 00252 M2MResource* update_trigger = _server->get_resource(M2MServer::RegistrationUpdate); 00253 if (update_trigger) { 00254 update_trigger->set_execute_function(execute_callback(this, 00255 &M2MNsdlInterface::update_trigger_callback)); 00256 } 00257 00258 add_object_to_list(_server); 00259 create_nsdl_object_structure(_server); 00260 ns_list_init(&_request_context_list); 00261 ns_list_init(&_response_list); 00262 00263 return success; 00264 } 00265 00266 void M2MNsdlInterface::create_endpoint(const String &name, 00267 const String &type, 00268 const int32_t life_time, 00269 const String &domain, 00270 const uint8_t mode, 00271 const String &/*context_address*/) 00272 { 00273 tr_info("M2MNsdlInterface::create_endpoint( name %s type %s lifetime %" PRId32 ", domain %s, mode %d)", 00274 name.c_str(), type.c_str(), life_time, domain.c_str(), mode); 00275 _endpoint_name = name; 00276 _binding_mode = mode; 00277 00278 if (_endpoint){ 00279 memset(_endpoint, 0, sizeof(sn_nsdl_ep_parameters_s)); 00280 if (!_endpoint_name.empty()) { 00281 memory_free(_endpoint->endpoint_name_ptr); 00282 _endpoint->endpoint_name_ptr = alloc_string_copy((uint8_t*)_endpoint_name.c_str(), _endpoint_name.length()); 00283 _endpoint->endpoint_name_len = _endpoint_name.length(); 00284 } 00285 if (!type.empty()) { 00286 _endpoint->type_ptr = alloc_string_copy((uint8_t*)type.c_str(), type.length()); 00287 _endpoint->type_len = type.length(); 00288 } 00289 if (!domain.empty()) { 00290 _endpoint->domain_name_ptr = alloc_string_copy((uint8_t*)domain.c_str(), domain.length()); 00291 _endpoint->domain_name_len = domain.length(); 00292 } 00293 00294 // nsdl binding mode is only 3 least significant bits 00295 _endpoint->binding_and_mode = (sn_nsdl_oma_binding_and_mode_t)((uint8_t)mode & 0x07); 00296 00297 // If lifetime is less than zero then leave the field empty 00298 if (life_time > 0) { 00299 set_endpoint_lifetime_buffer(life_time); 00300 } 00301 } 00302 } 00303 00304 void M2MNsdlInterface::update_endpoint(const String &name) 00305 { 00306 _endpoint_name = name; 00307 if (_endpoint){ 00308 if (!_endpoint_name.empty()) { 00309 memory_free(_endpoint->endpoint_name_ptr); 00310 _endpoint->endpoint_name_ptr = alloc_string_copy((uint8_t*)_endpoint_name.c_str(), _endpoint_name.length()); 00311 _endpoint->endpoint_name_len = _endpoint_name.length(); 00312 } 00313 } 00314 } 00315 00316 void M2MNsdlInterface::update_domain(const String &domain) 00317 { 00318 if (_endpoint){ 00319 memory_free(_endpoint->domain_name_ptr); 00320 if (!domain.empty()) { 00321 _endpoint->domain_name_ptr = alloc_string_copy((uint8_t*)domain.c_str(), domain.length()); 00322 _endpoint->domain_name_len = domain.length(); 00323 } else { 00324 _endpoint->domain_name_ptr = NULL; 00325 _endpoint->domain_name_len = 0; 00326 } 00327 } 00328 } 00329 00330 void M2MNsdlInterface::set_endpoint_lifetime_buffer(int lifetime) 00331 { 00332 tr_info("M2MNsdlInterface::set_endpoint_lifetime_buffer - %d", lifetime); 00333 if (lifetime < MINIMUM_REGISTRATION_TIME) { 00334 return; 00335 } 00336 00337 _server->set_resource_value(M2MServer::Lifetime, lifetime); 00338 00339 if (_endpoint && _endpoint->lifetime_ptr) { 00340 memory_free(_endpoint->lifetime_ptr); 00341 _endpoint->lifetime_ptr = NULL; 00342 _endpoint->lifetime_len = 0; 00343 } 00344 00345 char buffer[20+1]; 00346 uint32_t size = m2m::itoa_c(lifetime, buffer); 00347 if (_endpoint && size <= sizeof(buffer)) { 00348 _endpoint->lifetime_len = 0; 00349 _endpoint->lifetime_ptr = alloc_string_copy((uint8_t*)buffer, size); 00350 if (_endpoint->lifetime_ptr) { 00351 _endpoint->lifetime_len = size; 00352 } 00353 } 00354 00355 set_retransmission_parameters(); 00356 } 00357 00358 00359 void M2MNsdlInterface::delete_endpoint() 00360 { 00361 tr_debug("M2MNsdlInterface::delete_endpoint()"); 00362 if (_endpoint) { 00363 free(_endpoint->lifetime_ptr); 00364 memory_free(_endpoint); 00365 _endpoint = NULL; 00366 } 00367 } 00368 00369 bool M2MNsdlInterface::create_nsdl_list_structure(const M2MBaseList &list) 00370 { 00371 tr_debug("M2MNsdlInterface::create_nsdl_list_structure()"); 00372 bool success = false; 00373 if (!list.empty()) { 00374 tr_debug("M2MNsdlInterface::create_nsdl_list_structure - Object count is %d", list.size()); 00375 M2MBaseList::const_iterator it; 00376 it = list.begin(); 00377 for ( ; it != list.end(); it++ ) { 00378 // Create NSDL structure for all Objects inside 00379 success = create_nsdl_structure(*it); 00380 if (!success) { 00381 tr_debug("M2MNsdlInterface::create_nsdl_list_structure - fail to create resource"); 00382 break; 00383 } 00384 00385 tr_debug("M2MNsdlInterface::create_nsdl_list_structure - create %d", success); 00386 add_object_to_list(*it); 00387 } 00388 } 00389 00390 return success; 00391 } 00392 00393 bool M2MNsdlInterface::remove_nsdl_resource(M2MBase *base) 00394 { 00395 sn_nsdl_dynamic_resource_parameters_s* resource = base->get_nsdl_resource(); 00396 return sn_nsdl_pop_resource(_nsdl_handle, resource); 00397 } 00398 00399 bool M2MNsdlInterface::create_bootstrap_resource(sn_nsdl_addr_s *address) 00400 { 00401 #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE 00402 tr_debug("M2MNsdlInterface::create_bootstrap_resource()"); 00403 _identity_accepted = false; 00404 _bootstrap_finish_ack_received = false; 00405 bool success = false; 00406 tr_debug("M2MNsdlInterface::create_bootstrap_resource() - endpoint name: %.*s", _endpoint->endpoint_name_len, 00407 _endpoint->endpoint_name_ptr); 00408 00409 if (_bootstrap_id == 0) { 00410 // Take copy of the address, uri_query_parameters() will modify the source buffer 00411 bool msg_sent = false; 00412 if (_server_address) { 00413 char *address_copy = M2MBase::alloc_string_copy(_server_address); 00414 if (address_copy) { 00415 char* query = parse_uri_query_parameters(_server_address); 00416 if (query != NULL) { 00417 size_t query_len = 1 + strlen(query) + 1 + strlen(MCC_VERSION) + 1; 00418 if (query_len <= MAX_URI_QUERY_LEN) { 00419 char query_params[MAX_URI_QUERY_LEN]; 00420 strcpy(query_params, "&"); 00421 strcat(query_params, query); 00422 strcat(query_params, "&"); 00423 strcat(query_params, MCC_VERSION); 00424 msg_sent = true; 00425 sn_nsdl_clear_coap_resending_queue(_nsdl_handle); 00426 _bootstrap_id = sn_nsdl_oma_bootstrap(_nsdl_handle, 00427 address, 00428 _endpoint, 00429 query_params); 00430 free(_server_address); 00431 _server_address = M2MBase::alloc_string_copy(address_copy); 00432 } else { 00433 tr_error("M2MNsdlInterface::create_bootstrap_resource() - max uri param length reached (%lu)", 00434 (unsigned long)query_len); 00435 } 00436 } 00437 free(address_copy); 00438 } 00439 } 00440 if (!msg_sent) { 00441 sn_nsdl_clear_coap_resending_queue(_nsdl_handle); 00442 _bootstrap_id = sn_nsdl_oma_bootstrap(_nsdl_handle, 00443 address, 00444 _endpoint, 00445 NULL); 00446 } 00447 success = _bootstrap_id != 0; 00448 tr_debug("M2MNsdlInterface::create_bootstrap_resource - _bootstrap_id %d", _bootstrap_id); 00449 } 00450 return success; 00451 #else 00452 (void)address; 00453 return false; 00454 #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE 00455 } 00456 00457 void M2MNsdlInterface::set_server_address(uint8_t* address, 00458 uint8_t address_length, 00459 const uint16_t port, 00460 sn_nsdl_addr_type_e address_type) 00461 { 00462 tr_debug("M2MNsdlInterface::set_server_address()"); 00463 set_NSP_address(_nsdl_handle, address, address_length, port, address_type); 00464 } 00465 00466 bool M2MNsdlInterface::send_register_message() 00467 { 00468 tr_info("M2MNsdlInterface::send_register_message()"); 00469 bool success = false; 00470 if (_server_address) { 00471 success = parse_and_send_uri_query_parameters(); 00472 } 00473 // If URI parsing fails or there is no parameters, try again without parameters 00474 if (!success) { 00475 // Clear the observation tokens 00476 send_next_notification(true); 00477 00478 success = sn_nsdl_register_endpoint(_nsdl_handle,_endpoint, NULL) != 0; 00479 } 00480 return success; 00481 } 00482 00483 void M2MNsdlInterface::send_request(DownloadType type, 00484 const char *uri, 00485 const sn_coap_msg_code_e msg_code, 00486 const size_t offset, 00487 const bool async, 00488 uint32_t token, 00489 const uint16_t payload_len, 00490 uint8_t *payload_ptr, 00491 request_data_cb data_cb, 00492 request_error_cb error_cb, 00493 void *context) 00494 { 00495 assert(uri != NULL); 00496 int32_t message_id = 0; 00497 request_context_s *data_request = NULL; 00498 00499 if (msg_code == COAP_MSG_CODE_REQUEST_GET && !_registered) { 00500 tr_error("M2MNsdlInterface::send_request - client not registered!"); 00501 error_cb(ERROR_NOT_REGISTERED, context); 00502 return; 00503 } 00504 00505 // Check the duplicate items 00506 request_context_s *data = (request_context_s *)ns_list_get_first(&_request_context_list); 00507 while (data) { 00508 if ((strcmp(uri, data->uri_path) == 0) && (offset == data->received_size)) { 00509 tr_debug("M2MNsdlInterface::send_request - item already exists"); 00510 // Remove queued message from the resend queue before resuming file download. 00511 // Otherwise there will be duplicate block transfer with a just different message id's. 00512 sn_nsdl_remove_msg_from_retransmission(_nsdl_handle, 00513 (uint8_t*)&data->msg_token, 00514 sizeof(data->msg_token)); 00515 data_request = data; 00516 break; 00517 } 00518 data = (request_context_s *)ns_list_get_next(&_request_context_list, data); 00519 } 00520 00521 if (data_request == NULL) { 00522 data_request = (struct request_context_s*)memory_alloc(sizeof(struct request_context_s)); 00523 if (data_request == NULL) { 00524 error_cb(FAILED_TO_ALLOCATE_MEMORY, context); 00525 return; 00526 } 00527 00528 data_request->resend = false; 00529 data_request->context = context; 00530 data_request->async_req = async; 00531 data_request->received_size = offset; 00532 data_request->download_type = type; 00533 data_request->uri_path = (char*)alloc_string_copy((uint8_t*)uri, strlen(uri)); 00534 if (data_request->uri_path == NULL) { 00535 memory_free(data_request); 00536 error_cb(FAILED_TO_ALLOCATE_MEMORY, context); 00537 return; 00538 } 00539 00540 data_request->on_request_data_cb = data_cb; 00541 data_request->on_request_error_cb = error_cb; 00542 00543 if (!token) { 00544 randLIB_get_n_bytes_random(&token, sizeof(token)); 00545 00546 if (!token) { 00547 token++; 00548 } 00549 } 00550 00551 data_request->msg_token = token; 00552 data_request->msg_code = msg_code; 00553 00554 ns_list_add_to_end(&_request_context_list, data_request); 00555 00556 } 00557 00558 message_id = sn_nsdl_send_request(_nsdl_handle, 00559 data_request->msg_code, 00560 data_request->uri_path, 00561 data_request->msg_token, 00562 data_request->received_size, 00563 payload_len, 00564 payload_ptr, 00565 data_request->download_type); 00566 00567 if (message_id == -4) { 00568 data_request->resend = true; 00569 } else if (message_id <= 0) { 00570 ns_list_remove(&_request_context_list, data_request); 00571 memory_free(data_request->uri_path); 00572 memory_free(data_request); 00573 error_cb(FAILED_TO_ALLOCATE_MEMORY, context); 00574 } 00575 } 00576 00577 bool M2MNsdlInterface::send_update_registration(const uint32_t lifetime) 00578 { 00579 tr_info("M2MNsdlInterface::send_update_registration( lifetime %" PRIu32 ")", lifetime); 00580 bool success = false; 00581 int32_t ret = 0; 00582 00583 _registration_timer.stop_timer(); 00584 bool lifetime_changed = true; 00585 00586 // If new resources have been created after registration those must be created and published to the server. 00587 create_nsdl_list_structure(_base_list); 00588 00589 // Check if resource(1/0/1) value has been updated and update it into _endpoint struct 00590 if (lifetime == 0) { 00591 lifetime_changed = lifetime_value_changed(); 00592 if (lifetime_changed) { 00593 set_endpoint_lifetime_buffer(_server->resource_value_int(M2MServer::Lifetime));; 00594 } 00595 } else { 00596 set_endpoint_lifetime_buffer(lifetime); 00597 } 00598 00599 if (_nsdl_handle) { 00600 if (!lifetime_changed) { 00601 tr_debug("M2MNsdlInterface::send_update_registration - regular update"); 00602 ret = sn_nsdl_update_registration(_nsdl_handle, NULL, 0); 00603 } else { 00604 if (_endpoint && _endpoint->lifetime_ptr) { 00605 tr_debug("M2MNsdlInterface::send_update_registration - new lifetime value"); 00606 ret = sn_nsdl_update_registration(_nsdl_handle, 00607 _endpoint->lifetime_ptr, 00608 _endpoint->lifetime_len); 00609 } 00610 } 00611 } 00612 00613 if (ret >= 0) { 00614 success = true; 00615 } 00616 00617 _registration_timer.start_timer(registration_time() * 1000, 00618 M2MTimerObserver::Registration, 00619 false); 00620 00621 return success; 00622 } 00623 00624 bool M2MNsdlInterface::send_unregister_message() 00625 { 00626 tr_info("M2MNsdlInterface::send_unregister_message"); 00627 if (is_unregister_ongoing()) { 00628 tr_debug("M2MNsdlInterface::send_unregister_message - unregistration already in progress"); 00629 return true; 00630 } 00631 00632 bool success = false; 00633 int32_t ret = 0; 00634 00635 ret = sn_nsdl_unregister_endpoint(_nsdl_handle); 00636 if (ret == -4) { 00637 tr_warn("Failed to send registration update. Clearing queue and retrying."); 00638 sn_nsdl_clear_coap_resending_queue(_nsdl_handle); 00639 ret = sn_nsdl_unregister_endpoint(_nsdl_handle); 00640 } 00641 if (ret >= 0) { 00642 success = true; 00643 } 00644 return success; 00645 } 00646 00647 // XXX: move these to common place, no need to copy these wrappers to multiple places: 00648 void *M2MNsdlInterface::memory_alloc(uint32_t size) 00649 { 00650 if(size) 00651 return malloc(size); 00652 else 00653 return 0; 00654 } 00655 00656 void M2MNsdlInterface::memory_free(void *ptr) 00657 { 00658 free(ptr); 00659 } 00660 00661 uint8_t* M2MNsdlInterface::alloc_string_copy(const uint8_t* source, uint16_t size) 00662 { 00663 assert(source != NULL); 00664 00665 uint8_t* result = (uint8_t*)memory_alloc(size + 1); 00666 if (result) { 00667 memcpy(result, source, size); 00668 result[size] = '\0'; 00669 } 00670 return result; 00671 } 00672 00673 uint8_t M2MNsdlInterface::send_to_server_callback(struct nsdl_s * /*nsdl_handle*/, 00674 sn_nsdl_capab_e /*protocol*/, 00675 uint8_t *data_ptr, 00676 uint16_t data_len, 00677 sn_nsdl_addr_s *address) 00678 { 00679 tr_debug("M2MNsdlInterface::send_to_server_callback(data size %d)", data_len); 00680 _observer.coap_message_ready(data_ptr,data_len,address); 00681 return 1; 00682 } 00683 00684 uint8_t M2MNsdlInterface::received_from_server_callback(struct nsdl_s *nsdl_handle, 00685 sn_coap_hdr_s *coap_header, 00686 sn_nsdl_addr_s *address) 00687 { 00688 tr_debug("M2MNsdlInterface::received_from_server_callback"); 00689 _observer.coap_data_processed(); 00690 uint8_t value = 0; 00691 request_context_s request_context; 00692 if(nsdl_handle && coap_header) { 00693 bool is_bootstrap_msg = nsdl_handle->is_bs_server; 00694 00695 if (coap_header->token_ptr && 00696 coap_header->token_len == sizeof(nsdl_handle->register_token) && 00697 memcmp(coap_header->token_ptr, &nsdl_handle->register_token, sizeof(nsdl_handle->register_token)) == 0) { 00698 00699 handle_register_response(coap_header); 00700 00701 } else if (coap_header->token_ptr && 00702 coap_header->token_len == sizeof(nsdl_handle->unregister_token) && 00703 memcmp(coap_header->token_ptr, 00704 &nsdl_handle->unregister_token, 00705 sizeof(nsdl_handle->unregister_token)) == 0) { 00706 00707 handle_unregister_response(coap_header); 00708 00709 } else if (coap_header->token_ptr && 00710 coap_header->token_len == sizeof(nsdl_handle->update_register_token) && 00711 memcmp(coap_header->token_ptr, 00712 &nsdl_handle->update_register_token, 00713 sizeof(nsdl_handle->update_register_token)) == 0) { 00714 00715 handle_register_update_response(coap_header); 00716 00717 } else if (coap_header->token_ptr && is_response_to_request(coap_header, request_context)) { 00718 00719 handle_request_response(coap_header, &request_context); 00720 00721 } 00722 #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE 00723 else if (coap_header->token_ptr && 00724 coap_header->token_len == sizeof(nsdl_handle->bootstrap_token) && 00725 memcmp(coap_header->token_ptr, &nsdl_handle->bootstrap_token, sizeof(nsdl_handle->bootstrap_token)) == 0) { 00726 00727 handle_bootstrap_response(coap_header); 00728 00729 } 00730 #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE 00731 else { 00732 00733 sn_coap_hdr_s *coap_response = NULL; 00734 bool execute_value_updated = false; 00735 M2MObjectInstance *obj_instance = NULL; 00736 00737 if (COAP_MSG_CODE_REQUEST_PUT == coap_header->msg_code) { 00738 if (is_bootstrap_msg) { 00739 send_empty_ack(coap_header, address); 00740 nsdl_coap_data_s *nsdl_coap_data = create_coap_event_data(coap_header, 00741 address, 00742 nsdl_handle, 00743 coap_header->msg_code); 00744 if (nsdl_coap_data) { 00745 _event.data.event_type = MBED_CLIENT_NSDLINTERFACE_BS_PUT_EVENT; 00746 _event.data.data_ptr = (void*)nsdl_coap_data; 00747 eventOS_event_send_user_allocated(&_event); 00748 return 2; // freeing will be performed in MBED_CLIENT_NSDLINTERFACE_BS_PUT_EVENT event 00749 } else { 00750 tr_error("M2MNsdlInterface::received_from_server_callback() - BS PUT failed to allocate nsdl_coap_data_s!"); 00751 coap_response = sn_nsdl_build_response(_nsdl_handle, 00752 coap_header, 00753 COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE); 00754 } 00755 00756 } else { 00757 tr_debug("M2MNsdlInterface::received_from_server_callback - Method not allowed (PUT)."); 00758 coap_response = sn_nsdl_build_response(_nsdl_handle, 00759 coap_header, 00760 COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED); 00761 } 00762 } 00763 else if (COAP_MSG_CODE_REQUEST_DELETE == coap_header->msg_code) { 00764 if (is_bootstrap_msg) { 00765 handle_bootstrap_delete(coap_header, address); 00766 } else { 00767 tr_debug("M2MNsdlInterface::received_from_server_callback - Method not allowed (DELETE)."); 00768 coap_response = sn_nsdl_build_response(_nsdl_handle, 00769 coap_header, 00770 COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED); 00771 } 00772 } else if (COAP_MSG_CODE_REQUEST_POST == coap_header->msg_code) { 00773 00774 execute_value_updated = handle_post_response(coap_header, 00775 address, 00776 coap_response, 00777 obj_instance, 00778 is_bootstrap_msg); 00779 00780 } else if (COAP_STATUS_BUILDER_BLOCK_SENDING_DONE == coap_header->coap_status && 00781 (coap_header->msg_code == COAP_MSG_CODE_RESPONSE_CONTENT || 00782 coap_header->msg_code == COAP_MSG_CODE_RESPONSE_CHANGED)) { 00783 00784 coap_response_s *resp = find_response(coap_header->msg_id); 00785 if (resp) { 00786 M2MBase *base = find_resource(resp->uri_path); 00787 if (base) { 00788 if (resp->type == M2MBase::BLOCK_SUBSCRIBE) { 00789 sn_coap_msg_code_e code; 00790 // This case coap response is not needed. 00791 // coap_header have the payload length and the observation number which is needed in following call. 00792 base->handle_observation(nsdl_handle, *coap_header, *coap_header, this, code); 00793 base->start_observation(*coap_header, this); 00794 } else { 00795 handle_message_delivered(base, resp->type); 00796 } 00797 00798 remove_item_from_response_list(NULL, coap_header->msg_id); 00799 } 00800 } 00801 00802 // Retransmission done 00803 } else if (COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED == coap_header->coap_status || 00804 COAP_STATUS_BUILDER_BLOCK_SENDING_FAILED == coap_header->coap_status) { 00805 00806 tr_info("M2MNsdlInterface::received_from_server_callback - message sending failed, id %d", coap_header->msg_id); 00807 _observer.registration_error(M2MInterface::NetworkError, true); 00808 00809 // Handle Server-side expections during registration flow 00810 // Client might receive error from server due to temporary connection/operability reasons, 00811 // server might not recover the flow in this case, so it is better for Client to restart registration. 00812 } else if (COAP_MSG_CODE_EMPTY == coap_header->msg_code) { 00813 00814 handle_empty_ack(coap_header, is_bootstrap_msg); 00815 00816 } else if (nsdl_handle->register_token && 00817 ((coap_header->msg_code == COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR) || 00818 (coap_header->msg_code == COAP_MSG_CODE_RESPONSE_BAD_GATEWAY) || 00819 (coap_header->msg_code == COAP_MSG_CODE_RESPONSE_SERVICE_UNAVAILABLE) || 00820 (coap_header->msg_code == COAP_MSG_CODE_RESPONSE_GATEWAY_TIMEOUT))) { 00821 00822 tr_error("M2MNsdlInterface::received_from_server_callback - registration error %d", coap_header->msg_code); 00823 tr_error("M2MNsdlInterface::received_from_server_callback - unexpected error received from server"); 00824 // Try to do clean register again 00825 _observer.registration_error(M2MInterface::NetworkError, true); 00826 00827 } else { 00828 // Add warn for any message that gets this far. We might be missing some handling in above. 00829 tr_warn("M2MNsdlInterface::received_from_server_callback - msg was ignored %d", coap_header->msg_code); 00830 } 00831 00832 // Send response to server 00833 if (coap_response) { 00834 tr_debug("M2MNsdlInterface::received_from_server_callback - send CoAP response"); 00835 (sn_nsdl_send_coap_message(_nsdl_handle, address, coap_response) == 0) ? value = 0 : value = 1; 00836 sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response); 00837 } 00838 00839 // Tell to application that value has been updated 00840 if (execute_value_updated) { 00841 value_updated(obj_instance); 00842 } 00843 } 00844 } 00845 return value; 00846 } 00847 #ifdef ENABLE_ASYNC_REST_RESPONSE 00848 M2MBase::Operation M2MNsdlInterface::operation_for_message_code(sn_coap_msg_code_e code) 00849 { 00850 M2MBase::Operation ret_val; 00851 switch (code) { 00852 case COAP_MSG_CODE_REQUEST_POST: { 00853 ret_val = M2MBase::POST_ALLOWED; 00854 break; 00855 } 00856 case COAP_MSG_CODE_REQUEST_GET: { 00857 ret_val = M2MBase::GET_ALLOWED; 00858 break; 00859 } 00860 case COAP_MSG_CODE_REQUEST_PUT: { 00861 ret_val = M2MBase::PUT_ALLOWED; 00862 break; 00863 } 00864 default: 00865 ret_val = M2MBase::NOT_ALLOWED; 00866 break; 00867 } 00868 return ret_val; 00869 } 00870 #endif // ENABLE_ASYNC_REST_RESPONSE 00871 00872 uint8_t M2MNsdlInterface::resource_callback(struct nsdl_s *nsdl_handle, 00873 sn_coap_hdr_s *received_coap_header, 00874 sn_nsdl_addr_s *address, 00875 sn_nsdl_capab_e /*nsdl_capab*/) 00876 { 00877 bool async_response = false; 00878 tr_debug("M2MNsdlInterface::resource_callback()"); 00879 00880 assert(received_coap_header); 00881 _observer.coap_data_processed(); 00882 00883 String resource_name = coap_to_string(received_coap_header->uri_path_ptr, 00884 received_coap_header->uri_path_len); 00885 00886 M2MBase *base = find_resource(resource_name); 00887 00888 #ifdef ENABLE_ASYNC_REST_RESPONSE 00889 if (base) { 00890 if (base->is_async_coap_request_callback_set()) { 00891 async_response = true; 00892 if (!handle_delayed_response_store(resource_name.c_str(), 00893 received_coap_header, 00894 address, 00895 M2MBase::DELAYED_RESPONSE)) { 00896 return 0; 00897 } 00898 } 00899 } 00900 #endif // ENABLE_ASYNC_REST_RESPONSE 00901 00902 // Use piggypacked response for any other types than POST 00903 if (received_coap_header->msg_code != COAP_MSG_CODE_REQUEST_POST) { 00904 // If there is a async callback set for this resource than skip this and 00905 // send empty ACK below, application will be responsible to send final response. 00906 if (!async_response) { 00907 uint8_t status = resource_callback_handle_event(received_coap_header, address); 00908 if (received_coap_header->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED) { 00909 memory_free(received_coap_header->payload_ptr); 00910 } 00911 sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, received_coap_header); 00912 return status; 00913 } 00914 } 00915 00916 // Only handle this in case of delayed response for POST and not for 00917 // implementation behind ENABLE_ASYNC_REST_RESPONSE 00918 if (base && !async_response) { 00919 M2MResource *res = NULL; 00920 if (M2MBase::Resource == base->base_type()) { 00921 res = static_cast<M2MResource *> (base); 00922 } 00923 00924 #ifndef DISABLE_DELAYED_RESPONSE 00925 if (res && res->delayed_response()) { 00926 if (!handle_delayed_response_store(resource_name.c_str(), 00927 received_coap_header, 00928 address, 00929 M2MBase::DELAYED_POST_RESPONSE)) { 00930 return 0; 00931 } 00932 } 00933 #endif // DISABLE_DELAYED_RESPONSE 00934 00935 } 00936 00937 send_empty_ack(received_coap_header, address); 00938 nsdl_coap_data_s *nsdl_coap_data = create_coap_event_data(received_coap_header, 00939 address, 00940 nsdl_handle, 00941 received_coap_header->msg_code); 00942 if (nsdl_coap_data) { 00943 _event.data.event_type = MBED_CLIENT_NSDLINTERFACE_EVENT; 00944 _event.data.data_ptr = (void*)nsdl_coap_data; 00945 eventOS_event_send_user_allocated(&_event); 00946 } else { 00947 tr_error("M2MNsdlInterface::resource_callback() - failed to allocate nsdl_coap_data_s!"); 00948 } 00949 return 0; 00950 } 00951 00952 uint8_t M2MNsdlInterface::resource_callback_handle_event(sn_coap_hdr_s *received_coap_header, 00953 sn_nsdl_addr_s *address) 00954 { 00955 tr_debug("M2MNsdlInterface::resource_callback_handle_event"); 00956 uint8_t result = 1; 00957 uint8_t *payload = NULL; 00958 bool free_payload = true; 00959 sn_coap_hdr_s *coap_response = NULL; 00960 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 4.00 00961 String resource_name = coap_to_string(received_coap_header->uri_path_ptr, 00962 received_coap_header->uri_path_len); 00963 00964 bool execute_value_updated = false; 00965 M2MBase* base = find_resource(resource_name); 00966 bool subscribed = false; 00967 if (base) { 00968 if (COAP_MSG_CODE_REQUEST_GET == received_coap_header->msg_code) { 00969 coap_response = base->handle_get_request(_nsdl_handle, received_coap_header,this); 00970 00971 if (coap_response && 00972 coap_response->options_list_ptr && 00973 coap_response->options_list_ptr->observe != STOP_OBSERVATION && 00974 coap_response->options_list_ptr->observe != -1 && 00975 coap_response->token_ptr) { 00976 if (M2MBase::is_blockwise_needed(_nsdl_handle, coap_response->payload_len)) { 00977 store_to_response_list(resource_name.c_str(), 00978 received_coap_header->msg_id, 00979 M2MBase::BLOCK_SUBSCRIBE); 00980 } 00981 subscribed = true; 00982 } 00983 } else if (COAP_MSG_CODE_REQUEST_PUT == received_coap_header->msg_code) { 00984 coap_response = base->handle_put_request(_nsdl_handle, received_coap_header, this, execute_value_updated); 00985 } else if (COAP_MSG_CODE_REQUEST_POST == received_coap_header->msg_code) { 00986 if (base->base_type() == M2MBase::ResourceInstance) { 00987 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 00988 } else { 00989 coap_response = base->handle_post_request(_nsdl_handle, 00990 received_coap_header, 00991 this, 00992 execute_value_updated, 00993 address); 00994 00995 #ifndef DISABLE_DELAYED_RESPONSE 00996 if (base->base_type() == M2MBase::Resource) { 00997 M2MResource *res = (M2MResource*) base; 00998 if (res->delayed_response()) { 00999 tr_debug("M2MNsdlInterface::resource_callback_handle_event - final response sent by application"); 01000 sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response); 01001 return 0; 01002 } 01003 } 01004 #endif // DISABLE_DELAYED_RESPONSE 01005 // Separate response used for POST 01006 if (coap_response) { 01007 coap_response->msg_type = COAP_MSG_TYPE_CONFIRMABLE; 01008 } 01009 } 01010 } else if (COAP_MSG_CODE_REQUEST_DELETE == received_coap_header->msg_code) { 01011 // Delete the object instance 01012 M2MBase::BaseType type = base->base_type(); 01013 if(M2MBase::ObjectInstance == type) { 01014 M2MBase* base_object = find_resource(base->uri_path()); 01015 if(base_object) { 01016 M2MObject &object = ((M2MObjectInstance*)base_object)->get_parent_object(); 01017 int slash_found = resource_name.find_last_of('/'); 01018 // Object instance validty checks done in upper level, no need for error handling 01019 if (slash_found != -1) { 01020 const String object_name = resource_name.substr(slash_found + 1, resource_name.length()); 01021 if (object.remove_object_instance(strtoul( 01022 object_name.c_str(), 01023 NULL, 01024 10))) { 01025 msg_code = COAP_MSG_CODE_RESPONSE_DELETED; 01026 } 01027 } 01028 } 01029 } else { 01030 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 4.00 01031 } 01032 } 01033 } else { 01034 tr_error("M2MNsdlInterface::resource_callback_handle_event() - Resource NOT FOUND"); 01035 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 4.00 01036 } 01037 01038 if (!coap_response) { 01039 coap_response = sn_nsdl_build_response(_nsdl_handle, received_coap_header, msg_code); 01040 } 01041 01042 // This copy will be passed to resource instance 01043 if (received_coap_header->payload_len > 0 && received_coap_header->payload_ptr) { 01044 payload = (uint8_t *) memory_alloc(received_coap_header->payload_len); 01045 if (payload) { 01046 assert(received_coap_header->payload_ptr); 01047 memcpy(payload, received_coap_header->payload_ptr, received_coap_header->payload_len); 01048 } else { 01049 if (coap_response) { 01050 coap_response->msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE; 01051 } 01052 } 01053 } 01054 01055 #ifdef ENABLE_ASYNC_REST_RESPONSE 01056 bool async_request_callback_called = false; 01057 #endif 01058 01059 if (coap_response && 01060 coap_response->coap_status != COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING && 01061 coap_response->msg_code != COAP_MSG_CODE_EMPTY) { 01062 bool send_response = true; 01063 01064 #ifdef ENABLE_ASYNC_REST_RESPONSE 01065 if (base) { 01066 if (base->is_async_coap_request_callback_set()) { 01067 // In case of error or callback not found go to default response flow 01068 if (coap_response->msg_code < COAP_MSG_CODE_RESPONSE_BAD_REQUEST) { 01069 M2MBase::Operation operation = operation_for_message_code(received_coap_header->msg_code); 01070 tr_debug("M2MNsdlInterface::resource_callback_handle_event - final response sent by application for " 01071 "operation 0x%x", operation); 01072 base->call_async_coap_request_callback(received_coap_header, 01073 operation, 01074 async_request_callback_called); 01075 01076 // Response sent by the application 01077 if (async_request_callback_called) { 01078 send_response = false; 01079 result = 0; 01080 } else { 01081 tr_error("M2MNsdlInterface::resource_callback_handle_event - async callback not called!"); 01082 } 01083 } else { 01084 remove_item_from_response_list(base->uri_path(), UNDEFINED_MSG_ID); 01085 } 01086 } 01087 } 01088 #endif //ENABLE_ASYNC_REST_RESPONSE 01089 01090 // Send CoAP response only for methods which are not handled by application 01091 if (send_response) { 01092 (sn_nsdl_send_coap_message(_nsdl_handle, address, coap_response) == 0) ? result = 0 : result = 1; 01093 } 01094 01095 free(coap_response->payload_ptr); 01096 coap_response->payload_ptr = NULL; 01097 01098 // See if there any pending notification to be sent after resource is subscribed. 01099 if (subscribed) { 01100 _notification_handler->send_notification(this); 01101 } 01102 } 01103 01104 // If the external blockwise storing is enabled call value updated only when all blocks have been received 01105 if (execute_value_updated && 01106 coap_response && 01107 coap_response->coap_status != COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING && 01108 coap_response->msg_code < COAP_MSG_CODE_RESPONSE_BAD_REQUEST) { 01109 if ((COAP_MSG_CODE_REQUEST_PUT == received_coap_header->msg_code) && 01110 (base->base_type() == M2MBase::Resource || 01111 base->base_type() == M2MBase::ResourceInstance)) { 01112 M2MResourceBase* res = (M2MResourceBase*)base; 01113 01114 #ifdef ENABLE_ASYNC_REST_RESPONSE 01115 if (!async_request_callback_called) { 01116 #endif 01117 // Clear the old resource value since the data is now passed to application 01118 if (res->block_message() && res->block_message()->is_block_message()) { 01119 res->clear_value(); 01120 } else { 01121 // Ownership of payload moved to resource, skip the freeing. 01122 free_payload = false; 01123 res->set_value_raw(payload, received_coap_header->payload_len); 01124 } 01125 #ifdef ENABLE_ASYNC_REST_RESPONSE 01126 } 01127 #endif 01128 } 01129 if (coap_response->msg_code != COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE) { 01130 value_updated(base); 01131 } 01132 } 01133 01134 if (free_payload) { 01135 free(payload); 01136 } 01137 01138 sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response); 01139 01140 return result; 01141 } 01142 01143 bool M2MNsdlInterface::process_received_data(uint8_t *data, 01144 uint16_t data_size, 01145 sn_nsdl_addr_s *address) 01146 { 01147 tr_debug("M2MNsdlInterface::process_received_data(data size %d)", data_size); 01148 return (0 == sn_nsdl_process_coap(_nsdl_handle, 01149 data, 01150 data_size, 01151 address)) ? true : false; 01152 } 01153 01154 void M2MNsdlInterface::stop_timers() 01155 { 01156 tr_debug("M2MNsdlInterface::stop_timers()"); 01157 _registration_timer.stop_timer(); 01158 _nsdl_execution_timer.stop_timer(); 01159 _nsdl_execution_timer_running = false; 01160 _bootstrap_id = 0; 01161 _nsdl_handle->update_register_token = 0; 01162 _nsdl_handle->unregister_token = 0; 01163 _download_retry_timer.stop_timer(); 01164 } 01165 01166 void M2MNsdlInterface::timer_expired(M2MTimerObserver::Type type) 01167 { 01168 if(M2MTimerObserver::NsdlExecution == type) { 01169 sn_nsdl_exec(_nsdl_handle, _counter_for_nsdl); 01170 _counter_for_nsdl++; 01171 send_coap_ping(); 01172 } else if((M2MTimerObserver::Registration) == type && 01173 (is_unregister_ongoing() == false) && 01174 (is_update_register_ongoing() == false)) { 01175 tr_debug("M2MNsdlInterface::timer_expired - Send update registration"); 01176 if (!send_update_registration()) { 01177 // Most likely case would be memory allocation failure 01178 _observer.registration_error(M2MInterface::MemoryFail, false); 01179 } 01180 } else if (M2MTimerObserver::RetryTimer == type) { 01181 send_pending_request(); 01182 } 01183 } 01184 01185 bool M2MNsdlInterface::observation_to_be_sent(M2MBase *object, 01186 uint16_t obs_number, 01187 const m2m::Vector<uint16_t> &changed_instance_ids, 01188 bool send_object) 01189 { 01190 claim_mutex(); 01191 01192 if (object && _nsdl_execution_timer_running && _registered) { 01193 tr_debug("M2MNsdlInterface::observation_to_be_sent() uri %s", object->uri_path()); 01194 01195 if (!_notification_send_ongoing) { 01196 _notification_send_ongoing = true; 01197 object->report_handler()->set_notification_in_queue(false); 01198 M2MBase::BaseType type = object->base_type(); 01199 01200 if (type == M2MBase::Object) { 01201 send_object_observation(static_cast<M2MObject*> (object), 01202 obs_number, 01203 changed_instance_ids, 01204 send_object); 01205 } else if (type == M2MBase::ObjectInstance) { 01206 send_object_instance_observation(static_cast<M2MObjectInstance*> (object), obs_number); 01207 } else if (type == M2MBase::Resource) { 01208 send_resource_observation(static_cast<M2MResource*> (object), obs_number); 01209 } 01210 01211 release_mutex(); 01212 return true; 01213 } else { 01214 tr_info("M2MNsdlInterface::observation_to_be_sent() - send already in progress"); 01215 } 01216 } else { 01217 tr_info("M2MNsdlInterface::observation_to_be_sent() - object NULL, in reconnection mode or not registered"); 01218 } 01219 01220 release_mutex(); 01221 01222 return false; 01223 } 01224 01225 #ifndef DISABLE_DELAYED_RESPONSE 01226 void M2MNsdlInterface::send_delayed_response(M2MBase *base) 01227 { 01228 claim_mutex(); 01229 tr_debug("M2MNsdlInterface::send_delayed_response()"); 01230 M2MResource *resource = NULL; 01231 if(base) { 01232 if(M2MBase::Resource == base->base_type()) { 01233 resource = static_cast<M2MResource *> (base); 01234 } 01235 if(resource) { 01236 coap_response_s* resp = find_delayed_response(resource->uri_path(), M2MBase::DELAYED_POST_RESPONSE); 01237 // If there is no response it means that this API is called 01238 // before actual POST request has received the device 01239 if (resp) { 01240 sn_coap_hdr_s coap_response; 01241 01242 memset(&coap_response,0,sizeof(sn_coap_hdr_s)); 01243 01244 coap_response.msg_type = COAP_MSG_TYPE_CONFIRMABLE; 01245 coap_response.msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; 01246 resource->get_delayed_token(coap_response.token_ptr,coap_response.token_len); 01247 01248 uint32_t length = 0; 01249 resource->get_value(coap_response.payload_ptr, length); 01250 coap_response.payload_len = length; 01251 01252 if (sn_nsdl_send_coap_message(_nsdl_handle, &_nsdl_handle->server_address, &coap_response) >= 0) { 01253 // Update msgid, this will be used to track server response 01254 resp->msg_id = coap_response.msg_id; 01255 base->send_message_delivery_status(*base, M2MBase::MESSAGE_STATUS_SENT, M2MBase::DELAYED_POST_RESPONSE); 01256 } else { 01257 // Failed to create a message 01258 base->send_message_delivery_status(*base, M2MBase::MESSAGE_STATUS_SEND_FAILED, M2MBase::DELAYED_POST_RESPONSE); 01259 // Remove stored response from the list 01260 remove_item_from_response_list(resource->uri_path(), UNDEFINED_MSG_ID); 01261 } 01262 01263 free(coap_response.payload_ptr); 01264 free(coap_response.token_ptr); 01265 } else { 01266 tr_error("M2MNsdlInterface::send_delayed_response() - request not in list!"); 01267 } 01268 } 01269 } 01270 release_mutex(); 01271 } 01272 #endif //DISABLE_DELAYED_RESPONSE 01273 01274 #ifdef ENABLE_ASYNC_REST_RESPONSE 01275 void M2MNsdlInterface::send_asynchronous_response(M2MBase *base, 01276 const uint8_t *payload, 01277 size_t payload_len, 01278 const uint8_t *token, 01279 const uint8_t token_len, 01280 coap_response_code_e code) 01281 { 01282 claim_mutex(); 01283 tr_debug("M2MNsdlInterface::send_asynchronous_response() %s", base->uri_path()); 01284 if (base) { 01285 coap_response_s* resp = find_delayed_response(base->uri_path(), M2MBase::DELAYED_RESPONSE); 01286 // If there is no response it means that this API is called 01287 // before actual GET/PUT/POST request has been received in the device. 01288 if (resp) { 01289 sn_coap_hdr_s *coap_response = (sn_coap_hdr_s *) memory_alloc(sizeof(sn_coap_hdr_s)); 01290 bool msg_sent = false; 01291 if (coap_response) { 01292 memset(coap_response, 0, sizeof(sn_coap_hdr_s)); 01293 01294 coap_response->msg_type = COAP_MSG_TYPE_CONFIRMABLE; 01295 coap_response->msg_code = (sn_coap_msg_code_e) code; 01296 coap_response->token_ptr = (uint8_t*)token; 01297 coap_response->token_len = token_len; 01298 coap_response->payload_ptr = (uint8_t*)payload; 01299 coap_response->payload_len = payload_len; 01300 01301 if (sn_nsdl_send_coap_message(_nsdl_handle, &_nsdl_handle->server_address, coap_response) >= 0) { 01302 // Update msgid, this will be used to track server response 01303 resp->msg_id = coap_response->msg_id; 01304 base->send_message_delivery_status(*base, M2MBase::MESSAGE_STATUS_SENT, M2MBase::DELAYED_RESPONSE); 01305 msg_sent = true; 01306 if (M2MBase::is_blockwise_needed(_nsdl_handle, payload_len)) { 01307 resp->blockwise_used = true; 01308 } 01309 } 01310 01311 coap_response->token_ptr = NULL; 01312 coap_response->payload_ptr = NULL; 01313 sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response); 01314 } 01315 01316 if (!msg_sent) { 01317 // Failed to create a message 01318 base->send_message_delivery_status(*base, M2MBase::MESSAGE_STATUS_SEND_FAILED, M2MBase::DELAYED_RESPONSE); 01319 // Remove stored response from the list 01320 remove_item_from_response_list(base->uri_path(), UNDEFINED_MSG_ID); 01321 } 01322 01323 } else { 01324 tr_error("M2MNsdlInterface::send_delayed_response() - request not in list!"); 01325 } 01326 01327 } 01328 release_mutex(); 01329 } 01330 #endif //ENABLE_ASYNC_REST_RESPONSE 01331 01332 void M2MNsdlInterface::resource_to_be_deleted(M2MBase *base) 01333 { 01334 tr_debug("M2MNsdlInterface::resource_to_be_deleted() %p", base); 01335 claim_mutex(); 01336 remove_nsdl_resource(base); 01337 #if !defined(DISABLE_DELAYED_RESPONSE) || defined(ENABLE_ASYNC_REST_RESPONSE) 01338 remove_items_from_response_list_for_uri(base->uri_path()); 01339 #endif 01340 // Since the M2MObject's are stored in _base_list, they need to be removed from there also. 01341 if (base && base->base_type() == M2MBase::Object) { 01342 remove_object(base); 01343 } 01344 01345 release_mutex(); 01346 } 01347 01348 void M2MNsdlInterface::value_updated(M2MBase *base) 01349 { 01350 tr_debug("M2MNsdlInterface::value_updated()"); 01351 String name; 01352 if(base) { 01353 switch(base->base_type()) { 01354 case M2MBase::Object: 01355 create_nsdl_object_structure(static_cast<M2MObject*> (base)); 01356 name = base->name(); 01357 break; 01358 case M2MBase::ObjectInstance: 01359 create_nsdl_object_instance_structure(static_cast<M2MObjectInstance*> (base)); 01360 name = static_cast<M2MObjectInstance*> (base)->get_parent_object().name(); 01361 break; 01362 case M2MBase::Resource: { 01363 M2MResource* resource = static_cast<M2MResource*> (base); 01364 create_nsdl_resource_structure(resource, resource->supports_multiple_instances()); 01365 name = base->name(); 01366 break; 01367 } 01368 case M2MBase::ResourceInstance: { 01369 M2MResourceInstance* instance = static_cast<M2MResourceInstance*> (base); 01370 create_nsdl_resource(instance); 01371 name = static_cast<M2MResourceInstance*> (base)->get_parent_resource().name(); 01372 break; 01373 } 01374 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 01375 case M2MBase::ObjectDirectory: 01376 tr_error("M2MNsdlInterface::value_updated() - unsupported ObjectDirectory base type!"); 01377 return; 01378 #endif 01379 } 01380 } 01381 01382 if (base && base->is_value_updated_function_set()) { 01383 base->execute_value_updated(name); 01384 } 01385 else { 01386 _observer.value_updated(base); 01387 } 01388 } 01389 01390 void M2MNsdlInterface::remove_object(M2MBase *object) 01391 { 01392 claim_mutex(); 01393 tr_debug("M2MNsdlInterface::remove_object() %p", object); 01394 M2MObject* rem_object = static_cast<M2MObject*> (object); 01395 if(rem_object && !_base_list.empty()) { 01396 M2MBaseList::const_iterator it; 01397 it = _base_list.begin(); 01398 int index = 0; 01399 for ( ; it != _base_list.end(); it++, index++ ) { 01400 if((*it)->base_type() == M2MBase::Object && (*it) == rem_object) { 01401 _base_list.erase(index); 01402 break; 01403 } 01404 } 01405 } 01406 release_mutex(); 01407 } 01408 01409 bool M2MNsdlInterface::create_nsdl_structure(M2MBase *base) 01410 { 01411 tr_debug("M2MNsdlInterface::create_nsdl_structure()"); 01412 bool success = false; 01413 if(base) { 01414 switch (base->base_type()) { 01415 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 01416 case M2MBase::ObjectDirectory: 01417 success = create_nsdl_endpoint_structure((M2MEndpoint*)base); 01418 break; 01419 #endif 01420 case M2MBase::Object: 01421 success = create_nsdl_object_structure((M2MObject*)base); 01422 break; 01423 default: 01424 break; 01425 } 01426 } 01427 return success; 01428 } 01429 01430 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 01431 bool M2MNsdlInterface::create_nsdl_endpoint_structure(M2MEndpoint *endpoint) 01432 { 01433 tr_debug("M2MNsdlInterface::create_nsdl_endpoint_structure()"); 01434 bool success = false; 01435 if(endpoint) { 01436 success = true; 01437 if (endpoint->get_changed()) { 01438 const M2MObjectList &object_list = endpoint->objects(); 01439 tr_debug("M2MNsdlInterface::create_nsdl_endpoint_structure - Object count %d", object_list.size()); 01440 if(!endpoint->is_deleted() && !object_list.empty()) { 01441 M2MObjectList::const_iterator it; 01442 it = object_list.begin(); 01443 for ( ; it != object_list.end(); it++ ) { 01444 // Create NSDL structure for all object instances inside 01445 success = create_nsdl_object_structure(*it); 01446 } 01447 } 01448 if (!create_nsdl_resource(endpoint)) { 01449 success = false; 01450 } 01451 endpoint->clear_changed(); 01452 } 01453 } 01454 return success; 01455 } 01456 #endif 01457 01458 bool M2MNsdlInterface::create_nsdl_object_structure(M2MObject *object) 01459 { 01460 bool success = false; 01461 if (object) { 01462 const M2MObjectInstanceList &instance_list = object->instances(); 01463 if (!instance_list.empty()) { 01464 M2MObjectInstanceList::const_iterator it; 01465 it = instance_list.begin(); 01466 for ( ; it != instance_list.end(); it++ ) { 01467 // Create NSDL structure for all object instances inside 01468 success = create_nsdl_object_instance_structure(*it); 01469 if (!success) { 01470 tr_error("M2MNsdlInterface::create_nsdl_object_structure - fail to create resource"); 01471 return false; 01472 } 01473 } 01474 } 01475 } 01476 01477 // If marked as NOT_ALLOWED then there is no need to 01478 // create nsdl resource at all since it will not be published to mds 01479 if (object && object->operation() != M2MBase::NOT_ALLOWED) { 01480 success = create_nsdl_resource(object); 01481 } else { 01482 success = true; 01483 } 01484 01485 return success; 01486 } 01487 01488 bool M2MNsdlInterface::create_nsdl_object_instance_structure(M2MObjectInstance *object_instance) 01489 { 01490 bool success = false; 01491 01492 if (object_instance) { 01493 const M2MResourceList &res_list = object_instance->resources(); 01494 if (!res_list.empty()) { 01495 M2MResourceList::const_iterator it; 01496 it = res_list.begin(); 01497 for ( ; it != res_list.end(); it++ ) { 01498 // Create NSDL structure for all resources inside 01499 success = create_nsdl_resource_structure(*it, (*it)->supports_multiple_instances()); 01500 if (!success) { 01501 tr_error("M2MNsdlInterface::create_nsdl_object_instance_structure - fail to create resource"); 01502 return false; 01503 } 01504 } 01505 } 01506 01507 // If marked as NOT_ALLOWED then there is no need to 01508 // create nsdl resource at all since it will not be published to mds 01509 if (object_instance->operation() != M2MBase::NOT_ALLOWED) { 01510 success = create_nsdl_resource(object_instance); 01511 } else { 01512 success = true; 01513 } 01514 } 01515 01516 return success; 01517 } 01518 01519 bool M2MNsdlInterface::create_nsdl_resource_structure(M2MResource *res, 01520 bool multiple_instances) 01521 { 01522 bool success = false; 01523 if (res) { 01524 // if there are multiple instances supported 01525 if (multiple_instances) { 01526 const M2MResourceInstanceList &res_list = res->resource_instances(); 01527 if (!res_list.empty()) { 01528 M2MResourceInstanceList::const_iterator it; 01529 it = res_list.begin(); 01530 for ( ; it != res_list.end(); it++ ) { 01531 success = create_nsdl_resource((*it)); 01532 if (!success) { 01533 tr_error("M2MNsdlInterface::create_nsdl_resource_structure - instance creation failed"); 01534 return false; 01535 } 01536 } 01537 // Register the main Resource as well along with ResourceInstances 01538 success = create_nsdl_resource(res); 01539 } 01540 } else { 01541 success = create_nsdl_resource(res); 01542 } 01543 } 01544 return success; 01545 } 01546 01547 bool M2MNsdlInterface::create_nsdl_resource(M2MBase *base) 01548 { 01549 claim_mutex(); 01550 bool success = false; 01551 01552 if (base) { 01553 int8_t result = 0; 01554 sn_nsdl_dynamic_resource_parameters_s* nsdl_resource = base->get_nsdl_resource(); 01555 01556 // needed on deletion 01557 if (base->observation_handler() == NULL) { 01558 base->set_observation_handler(this); 01559 } 01560 01561 result = sn_nsdl_put_resource(_nsdl_handle, nsdl_resource); 01562 01563 // Put under observation if auto-obs feature is set. 01564 if (nsdl_resource && 01565 nsdl_resource->auto_observable && 01566 result != SN_GRS_RESOURCE_ALREADY_EXISTS) { 01567 base->set_under_observation(true, base->observation_handler()); 01568 01569 // Increment auto-obs token to be unique in every object 01570 _auto_obs_token++; 01571 if (_auto_obs_token > AUTO_OBS_TOKEN_MAX) { 01572 _auto_obs_token = 1; 01573 } 01574 01575 // Store token in big-endian byte order 01576 uint8_t token[sizeof(uint16_t)]; 01577 common_write_16_bit(_auto_obs_token, token); 01578 base->set_observation_token(token, sizeof(uint16_t)); 01579 01580 switch (base->base_type()) { 01581 case M2MBase::Object: 01582 base->add_observation_level(M2MBase::O_Attribute); 01583 break; 01584 01585 case M2MBase::ObjectInstance: 01586 base->add_observation_level(M2MBase::OI_Attribute); 01587 break; 01588 01589 case M2MBase::Resource: 01590 case M2MBase::ResourceInstance: 01591 base->add_observation_level(M2MBase::R_Attribute); 01592 break; 01593 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 01594 case M2MBase::ObjectDirectory: 01595 break; 01596 #endif 01597 } 01598 } 01599 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 01600 else if (base->base_type() == M2MBase::ObjectDirectory) { 01601 M2MEndpoint *endpoint = (M2MEndpoint*) base; 01602 if (endpoint->is_deleted()) { 01603 sn_nsdl_dynamic_resource_parameters_s *nsdl_resource = endpoint->get_nsdl_resource(); 01604 nsdl_resource->registered = SN_NDSL_RESOURCE_DELETE; 01605 } 01606 } 01607 #endif 01608 01609 // Either the resource is created or it already 01610 // exists , then result is success. 01611 if (result == 0 || 01612 result == SN_GRS_RESOURCE_ALREADY_EXISTS){ 01613 success = true; 01614 } 01615 } 01616 01617 release_mutex(); 01618 return success; 01619 } 01620 01621 // convenience method to get the URI from its buffer field... 01622 String M2MNsdlInterface::coap_to_string(const uint8_t *coap_data, int coap_data_length) 01623 { 01624 String value; 01625 if (coap_data != NULL && coap_data_length > 0) { 01626 value.append_raw((char *)coap_data,coap_data_length); 01627 } 01628 return value; 01629 } 01630 01631 uint64_t M2MNsdlInterface::registration_time() const 01632 { 01633 uint64_t value = 0; 01634 if(_endpoint) { 01635 value = _server->resource_value_int(M2MServer::Lifetime); 01636 } 01637 if(value < MINIMUM_REGISTRATION_TIME) { 01638 tr_warn("M2MNsdlInterface::registration_time - stored value in resource (in seconds) %" PRIu64, value); 01639 value = MINIMUM_REGISTRATION_TIME; 01640 } 01641 01642 if(value >= OPTIMUM_LIFETIME) { 01643 value = value - REDUCE_LIFETIME; 01644 } else { 01645 value = REDUCTION_FACTOR * value; 01646 } 01647 tr_debug("M2MNsdlInterface::registration_time - value (in seconds) %" PRIu64, value); 01648 return value; 01649 } 01650 01651 M2MBase* M2MNsdlInterface::find_resource(const String &object_name) const 01652 { 01653 tr_debug("M2MNsdlInterface::find_resource(object level) - from %p name (%s) ", this, object_name.c_str()); 01654 M2MObject *current = NULL; 01655 M2MBase *found = NULL; 01656 if(!_base_list.empty()) { 01657 M2MBaseList::const_iterator it; 01658 it = _base_list.begin(); 01659 for ( ; it != _base_list.end(); it++ ) { 01660 if ((*it)->base_type() == M2MBase::Object) { 01661 current = (M2MObject*)*it; 01662 tr_debug("M2MNsdlInterface::find_resource(object level) - path (%s)", 01663 (char*)current->uri_path()); 01664 if (strcmp((char*)current->uri_path(), object_name.c_str()) == 0) { 01665 found = current; 01666 tr_debug("M2MNsdlInterface::find_resource(%s) found", object_name.c_str()); 01667 break; 01668 } 01669 01670 found = find_resource(current, object_name); 01671 if(found != NULL) { 01672 break; 01673 } 01674 } 01675 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 01676 else if ((*it)->base_type() == M2MBase::ObjectDirectory) { 01677 M2MEndpoint *ep = (M2MEndpoint*)*it; 01678 if(!strcmp((char*)(*it)->uri_path(), object_name.c_str())) { 01679 found = NULL; 01680 break; 01681 } else { 01682 found = find_resource(ep, object_name); 01683 } 01684 if(found != NULL) { 01685 break; 01686 } 01687 } 01688 #endif 01689 } 01690 } 01691 return found; 01692 } 01693 01694 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 01695 M2MBase* M2MNsdlInterface::find_resource(const M2MEndpoint *endpoint, 01696 const String &object_name) const 01697 { 01698 tr_debug("M2MNsdlInterface::find_resource(endpoint level) - name (%s)", object_name.c_str()); 01699 M2MBase *object = NULL; 01700 if(endpoint) { 01701 const M2MObjectList &list = endpoint->objects(); 01702 if(!list.empty()) { 01703 M2MObjectList::const_iterator it; 01704 it = list.begin(); 01705 for ( ; it != list.end(); it++ ) { 01706 if (!strcmp((char*)(*it)->uri_path(), object_name.c_str())) { 01707 tr_debug("M2MNsdlInterface::find_resource(endpoint level) - object %p object name (%s)", 01708 object, object_name.c_str()); 01709 object = (*it); 01710 break; 01711 } 01712 01713 object = find_resource((*it),object_name); 01714 if(object != NULL){ 01715 break; 01716 } 01717 } 01718 } 01719 } 01720 return object; 01721 } 01722 #endif 01723 01724 M2MBase* M2MNsdlInterface::find_resource(const M2MObject *object, 01725 const String &object_instance) const 01726 { 01727 M2MBase *instance = NULL; 01728 if(object) { 01729 const M2MObjectInstanceList &list = object->instances(); 01730 if(!list.empty()) { 01731 M2MObjectInstanceList::const_iterator it; 01732 it = list.begin(); 01733 for ( ; it != list.end(); it++ ) { 01734 if(!strcmp((char*)(*it)->uri_path(), object_instance.c_str())){ 01735 instance = (*it); 01736 tr_debug("M2MNsdlInterface::find_resource(object instance level) - found (%s)", 01737 (char*)(*it)->uri_path()); 01738 break; 01739 } 01740 01741 instance = find_resource((*it),object_instance); 01742 if(instance != NULL){ 01743 break; 01744 } 01745 } 01746 } 01747 } 01748 return instance; 01749 } 01750 01751 M2MBase* M2MNsdlInterface::find_resource(const M2MObjectInstance *object_instance, 01752 const String &resource_instance) const 01753 { 01754 M2MBase *instance = NULL; 01755 if(object_instance) { 01756 const M2MResourceList &list = object_instance->resources(); 01757 if(!list.empty()) { 01758 M2MResourceList::const_iterator it; 01759 it = list.begin(); 01760 for ( ; it != list.end(); it++ ) { 01761 if(!strcmp((char*)(*it)->uri_path(), resource_instance.c_str())) { 01762 instance = *it; 01763 break; 01764 } 01765 else if((*it)->supports_multiple_instances()) { 01766 instance = find_resource((*it), (*it)->uri_path(), 01767 resource_instance); 01768 if(instance != NULL){ 01769 break; 01770 } 01771 } 01772 } 01773 } 01774 } 01775 return instance; 01776 } 01777 01778 M2MBase* M2MNsdlInterface::find_resource(const M2MResource *resource, 01779 const String &object_name, 01780 const String &resource_instance) const 01781 { 01782 M2MBase *res = NULL; 01783 if(resource) { 01784 if(resource->supports_multiple_instances()) { 01785 const M2MResourceInstanceList &list = resource->resource_instances(); 01786 if(!list.empty()) { 01787 M2MResourceInstanceList::const_iterator it; 01788 it = list.begin(); 01789 for ( ; it != list.end(); it++ ) { 01790 if(!strcmp((char*)(*it)->uri_path(), resource_instance.c_str())){ 01791 res = (*it); 01792 break; 01793 } 01794 } 01795 } 01796 } 01797 } 01798 return res; 01799 } 01800 01801 bool M2MNsdlInterface::object_present(M2MBase* base) const 01802 { 01803 bool success = false; 01804 if(base && !_base_list.empty()) { 01805 M2MBaseList::const_iterator it; 01806 it = _base_list.begin(); 01807 for ( ; it != _base_list.end(); it++ ) { 01808 if((*it) == base) { 01809 success = true; 01810 break; 01811 } 01812 } 01813 } 01814 return success; 01815 } 01816 01817 int M2MNsdlInterface::object_index(M2MBase* base) const 01818 { 01819 int found_index = -1; 01820 int index; 01821 if(base && !_base_list.empty()) { 01822 M2MBaseList::const_iterator it; 01823 01824 for (it = _base_list.begin(), index = 0; it != _base_list.end(); it++, index++) { 01825 if((*it) == base) { 01826 found_index = index; 01827 break; 01828 } 01829 } 01830 } 01831 return found_index; 01832 } 01833 01834 01835 bool M2MNsdlInterface::add_object_to_list(M2MBase* object) 01836 { 01837 tr_debug("M2MNsdlInterface::add_object_to_list this=%p object=%p", this, object); 01838 bool success = false; 01839 if(object && !object_present(object)) { 01840 _base_list.push_back(object); 01841 success = true; 01842 } 01843 return success; 01844 } 01845 01846 bool M2MNsdlInterface::remove_object_from_list(M2MBase* object) 01847 { 01848 tr_debug("M2MNsdlInterface::remove_object_from_list this=%p object=%p", this, object); 01849 bool success = false; 01850 int index; 01851 if(object && (-1 != (index = object_index(object)))) { 01852 tr_debug(" object found at index %d", index); 01853 _base_list.erase(index); 01854 success = true; 01855 } 01856 return success; 01857 } 01858 01859 M2MInterface::Error M2MNsdlInterface::interface_error(const sn_coap_hdr_s &coap_header) 01860 { 01861 M2MInterface::Error error; 01862 switch(coap_header.msg_code) { 01863 case COAP_MSG_CODE_RESPONSE_BAD_REQUEST: 01864 case COAP_MSG_CODE_RESPONSE_BAD_OPTION: 01865 case COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_INCOMPLETE: 01866 case COAP_MSG_CODE_RESPONSE_PRECONDITION_FAILED: 01867 case COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE: 01868 case COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT: 01869 error = M2MInterface::InvalidParameters; 01870 break; 01871 case COAP_MSG_CODE_RESPONSE_UNAUTHORIZED: 01872 case COAP_MSG_CODE_RESPONSE_FORBIDDEN: 01873 case COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE: 01874 case COAP_MSG_CODE_RESPONSE_NOT_FOUND: 01875 case COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED: 01876 error = M2MInterface::NotAllowed; 01877 break; 01878 case COAP_MSG_CODE_RESPONSE_CREATED: 01879 case COAP_MSG_CODE_RESPONSE_DELETED: 01880 case COAP_MSG_CODE_RESPONSE_VALID: 01881 case COAP_MSG_CODE_RESPONSE_CHANGED: 01882 case COAP_MSG_CODE_RESPONSE_CONTENT: 01883 error = M2MInterface::ErrorNone; 01884 break; 01885 default: 01886 error = M2MInterface::UnknownError; 01887 break; 01888 } 01889 if(coap_header.coap_status == COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED || 01890 coap_header.coap_status == COAP_STATUS_BUILDER_BLOCK_SENDING_FAILED) { 01891 error = M2MInterface::NetworkError; 01892 } 01893 return error; 01894 } 01895 01896 const char *M2MNsdlInterface::coap_error(const sn_coap_hdr_s &coap_header) 01897 { 01898 if (coap_header.msg_code == COAP_MSG_CODE_RESPONSE_BAD_REQUEST) { 01899 return COAP_ERROR_REASON_1; 01900 } else if (coap_header.msg_code == COAP_MSG_CODE_RESPONSE_BAD_OPTION) { 01901 return COAP_ERROR_REASON_2; 01902 } else if (coap_header.msg_code == COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_INCOMPLETE) { 01903 return COAP_ERROR_REASON_3; 01904 }else if (coap_header.msg_code == COAP_MSG_CODE_RESPONSE_PRECONDITION_FAILED) { 01905 return COAP_ERROR_REASON_4; 01906 } else if (coap_header.msg_code == COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE) { 01907 return COAP_ERROR_REASON_5; 01908 } else if (coap_header.msg_code == COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT) { 01909 return COAP_ERROR_REASON_6; 01910 } else if (coap_header.msg_code == COAP_MSG_CODE_RESPONSE_UNAUTHORIZED) { 01911 return COAP_ERROR_REASON_7; 01912 } else if (coap_header.msg_code == COAP_MSG_CODE_RESPONSE_FORBIDDEN) { 01913 return COAP_ERROR_REASON_8; 01914 } else if (coap_header.msg_code == COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE) { 01915 return COAP_ERROR_REASON_9; 01916 } else if (coap_header.msg_code == COAP_MSG_CODE_RESPONSE_NOT_FOUND) { 01917 return COAP_ERROR_REASON_10; 01918 } else if (coap_header.msg_code == COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED) { 01919 return COAP_ERROR_REASON_11; 01920 } else if (coap_header.msg_code == COAP_MSG_CODE_RESPONSE_SERVICE_UNAVAILABLE) { 01921 return COAP_ERROR_REASON_13; 01922 } else if (coap_header.msg_code == COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR) { 01923 return COAP_ERROR_REASON_14; 01924 } else if (coap_header.msg_code == COAP_MSG_CODE_RESPONSE_BAD_GATEWAY) { 01925 return COAP_ERROR_REASON_15; 01926 } else if (coap_header.msg_code == COAP_MSG_CODE_RESPONSE_GATEWAY_TIMEOUT) { 01927 return COAP_ERROR_REASON_16; 01928 } else if (coap_header.msg_code == COAP_MSG_CODE_RESPONSE_PROXYING_NOT_SUPPORTED) { 01929 return COAP_ERROR_REASON_17; 01930 } else if (coap_header.coap_status == COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED || 01931 coap_header.coap_status == COAP_STATUS_BUILDER_BLOCK_SENDING_FAILED) { 01932 return COAP_ERROR_REASON_12; 01933 } 01934 return COAP_NO_ERROR; 01935 } 01936 01937 void M2MNsdlInterface::send_object_observation(M2MObject *object, 01938 uint16_t obs_number, 01939 const m2m::Vector<uint16_t> &changed_instance_ids, 01940 bool send_object) 01941 { 01942 tr_info("M2MNsdlInterface::send_object_observation"); 01943 if(object) { 01944 uint8_t *value = 0; 01945 uint32_t length = 0; 01946 uint8_t token[MAX_TOKEN_SIZE]; 01947 uint8_t token_length = 0; 01948 01949 // Send whole object structure 01950 if (send_object) { 01951 value = M2MTLVSerializer::serialize(object->instances(), length); 01952 } 01953 // Send only changed object instances 01954 else { 01955 M2MObjectInstanceList list; 01956 Vector<uint16_t>::const_iterator it; 01957 it = changed_instance_ids.begin(); 01958 for (; it != changed_instance_ids.end(); it++){ 01959 M2MObjectInstance* obj_instance = object->object_instance(*it); 01960 if (obj_instance){ 01961 list.push_back(obj_instance); 01962 } 01963 } 01964 if (!list.empty()) { 01965 value = M2MTLVSerializer::serialize(list, length); 01966 list.clear(); 01967 } 01968 } 01969 01970 object->get_observation_token((uint8_t*)&token,token_length); 01971 01972 object->report_handler()->set_blockwise_notify(M2MBase::is_blockwise_needed(_nsdl_handle, length)); 01973 01974 int32_t msgid = sn_nsdl_send_observation_notification(_nsdl_handle, token, token_length, value, length, 01975 sn_coap_observe_e(obs_number), COAP_MSG_TYPE_CONFIRMABLE, 01976 sn_coap_content_format_e(object->coap_content_type()), -1); 01977 execute_notification_delivery_status_cb(object, msgid); 01978 01979 memory_free(value); 01980 } 01981 } 01982 01983 void M2MNsdlInterface::send_object_instance_observation(M2MObjectInstance *object_instance, 01984 uint16_t obs_number) 01985 { 01986 tr_info("M2MNsdlInterface::send_object_instance_observation"); 01987 if(object_instance) { 01988 uint8_t *value = 0; 01989 uint32_t length = 0; 01990 uint8_t token[MAX_TOKEN_SIZE]; 01991 uint8_t token_length = 0; 01992 01993 value = M2MTLVSerializer::serialize(object_instance->resources(), length); 01994 01995 object_instance->get_observation_token((uint8_t*)&token,token_length); 01996 01997 object_instance->report_handler()->set_blockwise_notify(M2MBase::is_blockwise_needed(_nsdl_handle, length)); 01998 01999 int32_t msgid = sn_nsdl_send_observation_notification(_nsdl_handle, token, token_length, value, length, 02000 sn_coap_observe_e(obs_number), COAP_MSG_TYPE_CONFIRMABLE, 02001 sn_coap_content_format_e(object_instance->coap_content_type()), -1); 02002 02003 execute_notification_delivery_status_cb(object_instance, msgid); 02004 02005 02006 memory_free(value); 02007 } 02008 } 02009 02010 void M2MNsdlInterface::send_resource_observation(M2MResource *resource, 02011 uint16_t obs_number) 02012 { 02013 if(resource) { 02014 tr_info("M2MNsdlInterface::send_resource_observation - uri %s", resource->uri_path()); 02015 uint8_t *value = 0; 02016 uint32_t length = 0; 02017 uint8_t token[MAX_TOKEN_SIZE]; 02018 uint8_t token_length = 0; 02019 02020 resource->get_observation_token((uint8_t*)token,token_length); 02021 uint16_t content_type = resource->coap_content_type(); 02022 if (M2MResourceBase::OPAQUE == resource->resource_instance_type()) { 02023 content_type = COAP_CONTENT_OMA_OPAQUE_TYPE; 02024 } 02025 02026 if (resource->resource_instance_count() > 0 || content_type == COAP_CONTENT_OMA_TLV_TYPE) { 02027 value = M2MTLVSerializer::serialize(resource, length); 02028 } else { 02029 resource->get_value(value,length); 02030 } 02031 02032 resource->report_handler()->set_blockwise_notify(M2MBase::is_blockwise_needed(_nsdl_handle, length)); 02033 02034 int32_t msgid = sn_nsdl_send_observation_notification(_nsdl_handle, token, token_length, value, length, 02035 sn_coap_observe_e(obs_number), 02036 COAP_MSG_TYPE_CONFIRMABLE, 02037 sn_coap_content_format_e(content_type), -1); 02038 execute_notification_delivery_status_cb(resource, msgid); 02039 02040 memory_free(value); 02041 } 02042 } 02043 nsdl_s * M2MNsdlInterface::get_nsdl_handle() const 02044 { 02045 return _nsdl_handle; 02046 } 02047 02048 void M2MNsdlInterface::handle_bootstrap_put_message(sn_coap_hdr_s *coap_header, 02049 sn_nsdl_addr_s *address) { 02050 #ifndef M2M_CLIENT_DISABLE_BOOTSTRAP_FEATURE 02051 tr_info("M2MNsdlInterface::handle_bootstrap_put_message"); 02052 uint8_t response_code = COAP_MSG_CODE_RESPONSE_CHANGED; 02053 sn_coap_hdr_s *coap_response = NULL; 02054 bool success = false; 02055 uint16_t content_type = 0; 02056 char buffer[MAX_ALLOWED_ERROR_STRING_LENGTH]; 02057 buffer[0] = '\0'; 02058 M2MNsdlInterface::ObjectType object_type = M2MNsdlInterface::SECURITY; 02059 02060 if (!_security) { 02061 _security = M2MSecurity::get_instance(); 02062 } 02063 02064 String resource_name = coap_to_string(coap_header->uri_path_ptr, 02065 coap_header->uri_path_len); 02066 tr_debug("M2MNsdlInterface::handle_bootstrap_put_message - object path %s", resource_name.c_str()); 02067 02068 // Security object 02069 if (resource_name.compare(0,1,"0") == 0) { 02070 object_type = M2MNsdlInterface::SECURITY; 02071 success = true; 02072 } 02073 // Server object 02074 else if (resource_name.compare(0,1,"1") == 0) { 02075 object_type = M2MNsdlInterface::SERVER; 02076 success = true; 02077 } 02078 // Device object 02079 else if (resource_name.compare(0,1,"3") == 0) { 02080 M2MDevice* dev = M2MInterfaceFactory::create_device(); 02081 // Not mandatory resource, that's why it must be created first 02082 M2MResource *res = dev->create_resource(M2MDevice::CurrentTime, 0); 02083 if (res) { 02084 res->set_auto_observable(true); 02085 } 02086 object_type = M2MNsdlInterface::DEVICE; 02087 success = true; 02088 } 02089 02090 if (success) { 02091 if(coap_header->content_format != COAP_CT_NONE) { 02092 content_type = coap_header->content_format; 02093 } 02094 02095 if (content_type != COAP_CONTENT_OMA_TLV_TYPE && 02096 content_type != COAP_CONTENT_OMA_TLV_TYPE_OLD) { 02097 tr_error("M2MNsdlInterface::handle_bootstrap_put_message - content_type %d", content_type); 02098 success = false; 02099 } 02100 // Parse TLV message and check is the object valid 02101 if (success) { 02102 change_operation_mode(_security, M2MBase::PUT_ALLOWED); 02103 success = parse_bootstrap_message(coap_header, object_type); 02104 if (success && object_type == M2MNsdlInterface::SECURITY) { 02105 success = validate_security_object(); 02106 if (!success) { 02107 const char *desc = "Invalid security object"; 02108 if (strlen(ERROR_REASON_22) + strlen(desc) <= MAX_ALLOWED_ERROR_STRING_LENGTH) { 02109 snprintf(buffer, sizeof(buffer), ERROR_REASON_22, desc); 02110 } 02111 response_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 02112 } 02113 } 02114 // Set operation back to default ones 02115 if (_security) { 02116 change_operation_mode(_security, M2MBase::NOT_ALLOWED); 02117 } 02118 } 02119 } 02120 02121 if (!success) { 02122 response_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 02123 } 02124 02125 coap_response = sn_nsdl_build_response(_nsdl_handle, 02126 coap_header, 02127 response_code); 02128 02129 if (coap_response) { 02130 sn_nsdl_send_coap_message(_nsdl_handle, address, coap_response); 02131 sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response); 02132 } 02133 02134 if (!success) { 02135 // Do not overwrite ERROR_REASON_22 02136 if (strlen(buffer) == 0) { 02137 if (strlen(ERROR_REASON_20) + resource_name.size() <= MAX_ALLOWED_ERROR_STRING_LENGTH) { 02138 snprintf(buffer, sizeof(buffer), ERROR_REASON_20, resource_name.c_str()); 02139 } 02140 } 02141 handle_bootstrap_error(buffer, true); 02142 } 02143 #else 02144 (void) coap_header; 02145 (void) address; 02146 #endif 02147 } 02148 02149 bool M2MNsdlInterface::parse_bootstrap_message(sn_coap_hdr_s *coap_header, 02150 M2MNsdlInterface::ObjectType lwm2m_object_type) 02151 { 02152 #ifndef M2M_CLIENT_DISABLE_BOOTSTRAP_FEATURE 02153 tr_info("M2MNsdlInterface::parse_bootstrap_message"); 02154 bool ret = false; 02155 bool is_obj_instance = false; 02156 uint16_t instance_id = 0; 02157 if (_security) { 02158 ret = is_obj_instance = M2MTLVDeserializer::is_object_instance(coap_header->payload_ptr); 02159 if (!is_obj_instance) { 02160 ret = M2MTLVDeserializer::is_resource(coap_header->payload_ptr); 02161 } 02162 if (ret) { 02163 M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; 02164 if (is_obj_instance) { 02165 M2MObject* dev_object = static_cast<M2MObject*> (M2MInterfaceFactory::create_device()); 02166 02167 switch (lwm2m_object_type) { 02168 case M2MNsdlInterface::SECURITY: 02169 instance_id = M2MTLVDeserializer::instance_id(coap_header->payload_ptr); 02170 if (_security->object_instance(instance_id) == NULL) { 02171 tr_debug("M2MNsdlInterface::parse_bootstrap_message - create instance %d", instance_id); 02172 _security->create_object_instance(M2MSecurity::M2MServer); 02173 change_operation_mode(_security, M2MBase::PUT_ALLOWED); 02174 } 02175 02176 error = M2MTLVDeserializer::deserialise_object_instances(coap_header->payload_ptr, 02177 coap_header->payload_len, 02178 *_security, 02179 M2MTLVDeserializer::Put); 02180 break; 02181 case M2MNsdlInterface::SERVER: 02182 error = M2MTLVDeserializer::deserialise_object_instances(coap_header->payload_ptr, 02183 coap_header->payload_len, 02184 *_server, 02185 M2MTLVDeserializer::Put); 02186 break; 02187 case M2MNsdlInterface::DEVICE: 02188 error = M2MTLVDeserializer::deserialise_object_instances(coap_header->payload_ptr, 02189 coap_header->payload_len, 02190 *dev_object, 02191 M2MTLVDeserializer::Put); 02192 break; 02193 default: 02194 break; 02195 } 02196 } 02197 else { 02198 instance_id = M2MTLVDeserializer::instance_id(coap_header->payload_ptr); 02199 M2MObjectInstance* instance = NULL; 02200 switch (lwm2m_object_type) { 02201 case M2MNsdlInterface::SECURITY: 02202 instance = _security->object_instance(instance_id); 02203 if (instance) { 02204 error = M2MTLVDeserializer::deserialize_resources(coap_header->payload_ptr, 02205 coap_header->payload_len, 02206 *instance, 02207 M2MTLVDeserializer::Put); 02208 } else { 02209 error = M2MTLVDeserializer::NotValid; 02210 } 02211 02212 break; 02213 case M2MNsdlInterface::SERVER: 02214 instance = _server->object_instance(instance_id); 02215 if (instance) { 02216 error = M2MTLVDeserializer::deserialize_resources(coap_header->payload_ptr, 02217 coap_header->payload_len, 02218 *instance, 02219 M2MTLVDeserializer::Post); 02220 } else { 02221 error = M2MTLVDeserializer::NotValid; 02222 } 02223 02224 break; 02225 case M2MNsdlInterface::DEVICE: 02226 default: 02227 break; 02228 } 02229 } 02230 02231 if (error != M2MTLVDeserializer::None) { 02232 tr_error("M2MNsdlInterface::parse_bootstrap_message - error %d", error); 02233 ret = false; 02234 } 02235 } 02236 } else { 02237 tr_error("M2MNsdlInterface::parse_bootstrap_message -- no security object!"); 02238 } 02239 return ret; 02240 #else 02241 (void) coap_header; 02242 (void) is_security_object; 02243 return false; 02244 #endif 02245 } 02246 02247 void M2MNsdlInterface::handle_bootstrap_finished(sn_coap_hdr_s *coap_header,sn_nsdl_addr_s *address) 02248 { 02249 #ifndef M2M_CLIENT_DISABLE_BOOTSTRAP_FEATURE 02250 char buffer[MAX_ALLOWED_ERROR_STRING_LENGTH]; 02251 02252 String object_name = coap_to_string(coap_header->uri_path_ptr, 02253 coap_header->uri_path_len); 02254 02255 int32_t m2m_id = -1; 02256 // Security object can be null in case messages are coming in wrong order, for example 02257 // BS POST is received before BS PUT. 02258 if (_security) { 02259 m2m_id = _security->get_security_instance_id(M2MSecurity::M2MServer); 02260 } 02261 02262 tr_info("M2MNsdlInterface::handle_bootstrap_finished - path: %s, m2mid: %" PRId32, object_name.c_str(), m2m_id); 02263 02264 #ifndef MBED_CLIENT_DISABLE_EST_FEATURE 02265 // In EST mode we must receive iep in uri-query 02266 bool est_iep_ok = false; 02267 if (m2m_id >= 0 && 02268 _security->resource_value_int(M2MSecurity::SecurityMode, m2m_id) == M2MSecurity::EST) { 02269 if (coap_header->options_list_ptr && coap_header->options_list_ptr->uri_query_ptr) { 02270 String uri_query = coap_to_string(coap_header->options_list_ptr->uri_query_ptr, 02271 coap_header->options_list_ptr->uri_query_len); 02272 tr_info("M2MNsdlInterface::handle_bootstrap_finished - query: %s", uri_query.c_str()); 02273 const char *iep_ptr = NULL; 02274 const int iep_len = parse_query_parameter_value_from_query(uri_query.c_str(), QUERY_PARAM_IEP, &iep_ptr); 02275 if (iep_ptr && iep_len > 0) { 02276 est_iep_ok = true; 02277 _internal_endpoint_name.clear(); 02278 _internal_endpoint_name.append_raw(iep_ptr, iep_len); 02279 tr_info("M2MNsdlInterface::handle_bootstrap_finished - iep: %s", _internal_endpoint_name.c_str()); 02280 } 02281 } 02282 } 02283 #endif 02284 02285 sn_coap_hdr_s *coap_response = NULL; 02286 uint8_t msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; 02287 // Accept only '/bs' path and check that needed data is in security object 02288 if (object_name.size() != 2 || 02289 object_name.compare(0, 2, BOOTSTRAP_URI) != 0) { 02290 if (strlen(ERROR_REASON_22) + object_name.size() <= MAX_ALLOWED_ERROR_STRING_LENGTH) { 02291 snprintf(buffer, sizeof(buffer), ERROR_REASON_22, object_name.c_str()); 02292 } 02293 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 02294 } 02295 #ifndef MBED_CLIENT_DISABLE_EST_FEATURE 02296 else if (!est_iep_ok && 02297 m2m_id >= 0 && 02298 _security->resource_value_int(M2MSecurity::SecurityMode, m2m_id) == M2MSecurity::EST) { 02299 tr_error("M2MNsdlInterface::handle_bootstrap_finished - EST mode but missing iep parameter!"); 02300 snprintf(buffer, sizeof(buffer), ERROR_REASON_26); 02301 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 02302 } 02303 #endif 02304 else { 02305 // Add short server id to server object 02306 if (m2m_id == -1) { 02307 snprintf(buffer,sizeof(buffer), ERROR_REASON_4); 02308 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 02309 } 02310 else { 02311 _server->set_resource_value(M2MServer::ShortServerID, 02312 _security->resource_value_int(M2MSecurity::ShortServerID, m2m_id)); 02313 } 02314 } 02315 02316 // In ok case send response as a separate response 02317 if (msg_code == COAP_MSG_CODE_RESPONSE_CHANGED) { 02318 send_empty_ack(coap_header, address); 02319 // In error case use piggybacked response 02320 } else { 02321 coap_response = sn_nsdl_build_response(_nsdl_handle, coap_header, msg_code); 02322 if (coap_response) { 02323 sn_nsdl_send_coap_message(_nsdl_handle, address, coap_response); 02324 sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response); 02325 } 02326 02327 handle_bootstrap_error(buffer, true); 02328 } 02329 02330 // Send a event which is responsible of sending the final response 02331 if (COAP_MSG_CODE_RESPONSE_CHANGED == msg_code) { 02332 bool success = false; 02333 sn_coap_hdr_s *coap_message = sn_nsdl_build_response(_nsdl_handle, 02334 coap_header, 02335 (sn_coap_msg_code_e)msg_code); 02336 if (coap_message) { 02337 // Switch back to original ep name 02338 memory_free(_endpoint->endpoint_name_ptr); 02339 _endpoint->endpoint_name_ptr = alloc_string_copy((uint8_t*)_endpoint_name.c_str(), _endpoint_name.length()); 02340 if (_endpoint->endpoint_name_ptr) { 02341 _endpoint->endpoint_name_len = _endpoint_name.length(); 02342 nsdl_coap_data_s *nsdl_coap_data = create_coap_event_data(coap_message, 02343 address, 02344 _nsdl_handle, 02345 (sn_coap_msg_code_e)msg_code); 02346 if (nsdl_coap_data) { 02347 success = true; 02348 _event.data.event_type = MBED_CLIENT_NSDLINTERFACE_BS_EVENT; 02349 _event.data.data_ptr = (void*)nsdl_coap_data; 02350 eventOS_event_send_user_allocated(&_event); 02351 } 02352 } 02353 } 02354 02355 if (!success) { 02356 const char *desc = "memory allocation failed"; 02357 if (strlen(ERROR_REASON_22) + strlen(desc) <= MAX_ALLOWED_ERROR_STRING_LENGTH) { 02358 snprintf(buffer, sizeof(buffer), ERROR_REASON_22, desc); 02359 } 02360 02361 handle_bootstrap_error(buffer, true); 02362 } 02363 } 02364 #else 02365 (void) coap_header; 02366 (void) address; 02367 #endif 02368 } 02369 02370 void M2MNsdlInterface::handle_bootstrap_delete(sn_coap_hdr_s *coap_header,sn_nsdl_addr_s *address) 02371 { 02372 02373 #ifndef M2M_CLIENT_DISABLE_BOOTSTRAP_FEATURE 02374 char buffer[MAX_ALLOWED_ERROR_STRING_LENGTH]; 02375 memset(buffer,0,sizeof(buffer)); 02376 sn_coap_hdr_s *coap_response = NULL; 02377 uint8_t msg_code = COAP_MSG_CODE_RESPONSE_DELETED; 02378 String object_name = coap_to_string(coap_header->uri_path_ptr, 02379 coap_header->uri_path_len); 02380 tr_info("M2MNsdlInterface::handle_bootstrap_delete - obj %s", object_name.c_str()); 02381 if(!_identity_accepted) { 02382 tr_warn("M2MNsdlInterface::handle_bootstrap_delete - Message received out-of-order - IGNORE"); 02383 return; 02384 } 02385 // Only following paths are accepted, 0, 0/0 02386 else if (object_name.size() == 2 || object_name.size() > 3) { 02387 if (strlen(ERROR_REASON_21) + object_name.size() <= MAX_ALLOWED_ERROR_STRING_LENGTH) { 02388 snprintf(buffer, sizeof(buffer), ERROR_REASON_21,object_name.c_str()); 02389 } 02390 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 02391 } 02392 else if ((object_name.size() == 1 && object_name.compare(0,1,"0") != 0) || 02393 (object_name.size() == 3 && object_name.compare(0,3,"0/0") != 0)) { 02394 if (strlen(ERROR_REASON_21) + object_name.size() <= MAX_ALLOWED_ERROR_STRING_LENGTH) { 02395 snprintf(buffer, sizeof(buffer), ERROR_REASON_21, object_name.c_str()); 02396 } 02397 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 02398 } 02399 02400 coap_response = sn_nsdl_build_response(_nsdl_handle, 02401 coap_header, 02402 msg_code); 02403 02404 if(coap_response) { 02405 sn_nsdl_send_coap_message(_nsdl_handle, address, coap_response); 02406 sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response); 02407 if(_security) { 02408 _security->clear_resources(); 02409 } 02410 } 02411 if (!coap_response || COAP_MSG_CODE_RESPONSE_DELETED != msg_code) { 02412 handle_bootstrap_error(buffer, true); 02413 } 02414 #else 02415 (void) coap_header; 02416 (void) address; 02417 #endif 02418 } 02419 02420 bool M2MNsdlInterface::validate_security_object() 02421 { 02422 bool valid = false; 02423 #ifndef M2M_CLIENT_DISABLE_BOOTSTRAP_FEATURE 02424 const M2MObjectInstanceList &instances = _security->instances(); 02425 M2MObjectInstanceList::const_iterator it; 02426 it = instances.begin(); 02427 uint16_t instance_id = 0; 02428 for ( ; it != instances.end(); it++ ) { 02429 valid = true; 02430 instance_id = (*it)->instance_id(); 02431 tr_debug("M2MNsdlInterface::validate_security_object - instance %d", instance_id); 02432 String address = _security->resource_value_string(M2MSecurity::M2MServerUri, instance_id); 02433 uint32_t sec_mode = _security->resource_value_int(M2MSecurity::SecurityMode, instance_id); 02434 uint32_t is_bs_server = _security->resource_value_int(M2MSecurity::BootstrapServer, instance_id); 02435 02436 uint32_t chain_size = 0; 02437 uint32_t server_key_size = 0; 02438 uint32_t pkey_size = 0; 02439 02440 size_t buffer_size = MAX_CERTIFICATE_SIZE; 02441 uint8_t certificate[MAX_CERTIFICATE_SIZE]; 02442 uint8_t *certificate_ptr = (uint8_t *)&certificate; 02443 02444 // Read through callback if set 02445 M2MResource *res = _security->get_resource(M2MSecurity::OpenCertificateChain, instance_id); 02446 if (res) { 02447 M2MBase::lwm2m_parameters_s *param = res->get_lwm2m_parameters(); 02448 if (param->read_write_callback_set) { 02449 // Read the chain size 02450 if (_security->resource_value_buffer(M2MSecurity::OpenCertificateChain, certificate_ptr, instance_id, &buffer_size) == 0) { 02451 // Only set size if no error when reading 02452 chain_size = buffer_size; 02453 } 02454 _security->resource_value_buffer(M2MSecurity::CloseCertificateChain, certificate_ptr, instance_id, &buffer_size); 02455 } else { 02456 // Read directly from the resource 02457 if (_security->resource_value_buffer(M2MSecurity::PublicKey, certificate_ptr, instance_id, &buffer_size) == 0) { 02458 // Only set size if no error when reading 02459 chain_size = buffer_size; 02460 } 02461 } 02462 } 02463 02464 buffer_size = MAX_CERTIFICATE_SIZE; 02465 02466 if (_security->resource_value_buffer(M2MSecurity::ServerPublicKey, certificate_ptr, instance_id, &buffer_size) == 0) { 02467 // Only set size if no error when reading 02468 server_key_size = buffer_size; 02469 } 02470 02471 buffer_size = MAX_CERTIFICATE_SIZE; 02472 if (_security->resource_value_buffer(M2MSecurity::Secretkey, certificate_ptr, instance_id, &buffer_size) == 0) { 02473 // Only set size if no error when reading 02474 pkey_size = buffer_size; 02475 } 02476 02477 tr_info("M2MNsdlInterface::validate_security_object - Server URI /0/0: %s", address.c_str()); 02478 tr_info("M2MNsdlInterface::validate_security_object - is bs server /0/1: %" PRIu32, is_bs_server); 02479 tr_info("M2MNsdlInterface::validate_security_object - Security Mode /0/2: %" PRIu32, sec_mode); 02480 tr_info("M2MNsdlInterface::validate_security_object - Public chain size /0/3: %" PRIu32, chain_size); 02481 tr_info("M2MNsdlInterface::validate_security_object - Server Public key size /0/4: %" PRIu32, server_key_size); 02482 tr_info("M2MNsdlInterface::validate_security_object - Secret key size /0/5: %" PRIu32, pkey_size); 02483 if (address.empty()) { 02484 return false; 02485 } 02486 02487 switch (sec_mode) { 02488 case M2MSecurity::Certificate: 02489 // Server public key and client private and public keys should be populated 02490 if (!chain_size || !server_key_size || !pkey_size) { 02491 return false; 02492 } 02493 break; 02494 #ifndef MBED_CLIENT_DISABLE_EST_FEATURE 02495 case M2MSecurity::EST: 02496 // Only server public key should be populated for lwm2m, client keys will be generated 02497 if (!is_bs_server && (!server_key_size || chain_size || pkey_size)) { 02498 return false; 02499 } 02500 break; 02501 #endif 02502 case M2MSecurity::NoSecurity: 02503 // Nothing to check for no security 02504 break; 02505 default: 02506 // Security mode not supported 02507 return false; 02508 } 02509 } 02510 #endif 02511 return valid; 02512 } 02513 02514 02515 void M2MNsdlInterface::handle_bootstrap_error(const char *reason, bool wait) 02516 { 02517 tr_error("M2MNsdlInterface::handle_bootstrap_error(%s)",reason); 02518 _identity_accepted = false; 02519 02520 if (wait) { 02521 _observer.bootstrap_error_wait(reason); 02522 } else { 02523 _observer.bootstrap_error(reason); 02524 } 02525 } 02526 02527 const String& M2MNsdlInterface::endpoint_name() const 02528 { 02529 return _endpoint_name; 02530 } 02531 02532 const String M2MNsdlInterface::internal_endpoint_name() const 02533 { 02534 String iep; 02535 if (_internal_endpoint_name.length() > 0) { 02536 iep = _internal_endpoint_name; 02537 } 02538 else if (_nsdl_handle->ep_information_ptr->location_ptr) { 02539 // If internal_endpoint_name not set yet, parse it from location path 02540 String temp((const char*)_nsdl_handle->ep_information_ptr->location_ptr, 02541 _nsdl_handle->ep_information_ptr->location_len); 02542 // Get last part of the location path. 02543 // In mbed Cloud environment full path is /rd/accountid/internal_endpoint 02544 int location = temp.find_last_of('/') + 1; 02545 iep.append_raw((const char*)_nsdl_handle->ep_information_ptr->location_ptr + location, 02546 _nsdl_handle->ep_information_ptr->location_len - location); 02547 } 02548 return iep; 02549 } 02550 02551 void M2MNsdlInterface::change_operation_mode(M2MObject *object, M2MBase::Operation operation) 02552 { 02553 const M2MObjectInstanceList &instances = object->instances(); 02554 M2MObjectInstanceList::const_iterator inst = instances.begin(); 02555 for (; inst != instances.end(); inst++ ) { 02556 (*inst)->set_operation(operation); 02557 const M2MResourceList &list = (*inst)->resources(); 02558 if(!list.empty()) { 02559 M2MResourceList::const_iterator it; 02560 it = list.begin(); 02561 for ( ; it != list.end(); it++ ) { 02562 (*it)->set_operation(operation); 02563 } 02564 } 02565 } 02566 } 02567 02568 void M2MNsdlInterface::set_server_address(const char* server_address) 02569 { 02570 free(_server_address); 02571 _server_address = M2MBase::alloc_string_copy(server_address); 02572 } 02573 02574 M2MTimer &M2MNsdlInterface::get_nsdl_execution_timer() 02575 { 02576 return _nsdl_execution_timer; 02577 } 02578 02579 bool M2MNsdlInterface::is_unregister_ongoing() const 02580 { 02581 return _nsdl_handle->unregister_token == 0 ? false : true; 02582 } 02583 02584 bool M2MNsdlInterface::parse_and_send_uri_query_parameters() 02585 { 02586 bool msg_sent = false; 02587 char *address_copy = M2MBase::alloc_string_copy(_server_address); 02588 if (address_copy) { 02589 const char* query = parse_uri_query_parameters(_server_address); 02590 if (query != NULL) { 02591 size_t query_len = 1 + strlen(query) + 1 + strlen(MCC_VERSION) + 1; 02592 if (_custom_uri_query_params) { 02593 query_len += 1 + strlen(_custom_uri_query_params); 02594 } 02595 02596 if (query_len <= MAX_URI_QUERY_LEN) { 02597 char query_params[MAX_URI_QUERY_LEN]; 02598 strcpy(query_params, "&"); 02599 strcat(query_params, query); 02600 strcat(query_params, "&"); 02601 strcat(query_params, MCC_VERSION); 02602 if (_custom_uri_query_params) { 02603 strcat(query_params, "&"); 02604 strcat(query_params, _custom_uri_query_params); 02605 } 02606 02607 tr_debug("M2MNsdlInterface::parse_and_send_uri_query_parameters - uri params: %s", query_params); 02608 msg_sent = sn_nsdl_register_endpoint(_nsdl_handle,_endpoint,query_params) != 0; 02609 } else { 02610 tr_error("M2MNsdlInterface::parse_and_send_uri_query_parameters - max uri param length reached (%lu)", 02611 (unsigned long)query_len); 02612 } 02613 } 02614 free(address_copy); 02615 } 02616 return msg_sent; 02617 } 02618 02619 void M2MNsdlInterface::claim_mutex() 02620 { 02621 _connection_handler.claim_mutex(); 02622 } 02623 02624 void M2MNsdlInterface::release_mutex() 02625 { 02626 _connection_handler.release_mutex(); 02627 } 02628 02629 void M2MNsdlInterface::start_nsdl_execution_timer() 02630 { 02631 tr_debug("M2MNsdlInterface::start_nsdl_execution_timer"); 02632 _nsdl_execution_timer_running = true; 02633 _nsdl_execution_timer.stop_timer(); 02634 _nsdl_execution_timer.start_timer(ONE_SECOND_TIMER * 1000, 02635 M2MTimerObserver::NsdlExecution, 02636 false); 02637 } 02638 02639 M2MSecurity* M2MNsdlInterface::get_security_object() 02640 { 02641 return _security; 02642 } 02643 02644 void M2MNsdlInterface::update_trigger_callback(void */*argument*/) 02645 { 02646 if (!send_update_registration()) { 02647 // Most likely case would be memory allocation failure 02648 _observer.registration_error(M2MInterface::MemoryFail, false); 02649 } 02650 } 02651 02652 bool M2MNsdlInterface::lifetime_value_changed() const 02653 { 02654 uint64_t value = 0; 02655 if (_endpoint && _endpoint->lifetime_ptr) { 02656 value = atol((const char*)_endpoint->lifetime_ptr); 02657 } 02658 if (_server->resource_value_int(M2MServer::Lifetime) != value) { 02659 return true; 02660 } 02661 return false; 02662 } 02663 02664 void M2MNsdlInterface::execute_notification_delivery_status_cb(M2MBase* object, int32_t msgid) 02665 { 02666 if (msgid > 0) { 02667 object->send_notification_delivery_status(*object, NOTIFICATION_STATUS_SENT); 02668 object->send_message_delivery_status(*object, 02669 M2MBase::MESSAGE_STATUS_SENT, 02670 M2MBase::NOTIFICATION); 02671 store_to_response_list(object->uri_path(), msgid, M2MBase::NOTIFICATION); 02672 } else { 02673 object->send_notification_delivery_status(*object, NOTIFICATION_STATUS_BUILD_ERROR); 02674 object->send_message_delivery_status(*object, 02675 M2MBase::MESSAGE_STATUS_BUILD_ERROR, 02676 M2MBase::NOTIFICATION); 02677 _notification_send_ongoing = false; 02678 } 02679 } 02680 02681 uint8_t M2MNsdlInterface::find_auto_obs_token(const char *path, uint8_t *token) const 02682 { 02683 uint8_t token_len = 0; 02684 const String name(path); 02685 M2MBase *object = find_resource(name); 02686 if (object) { 02687 object->get_observation_token(token, token_len); 02688 } 02689 return token_len; 02690 } 02691 02692 bool M2MNsdlInterface::is_response_to_request(const sn_coap_hdr_s *coap_header, request_context_s &get_data) 02693 { 02694 // ns_list_foreach() replacement since it does not compile with IAR 7.x versions. 02695 request_context_s *data = (request_context_s *)ns_list_get_first(&_request_context_list); 02696 while (data) { 02697 if (memcmp(coap_header->token_ptr, &data->msg_token, sizeof(data->msg_token)) == 0) { 02698 get_data = *data; 02699 return true; 02700 } 02701 data = (request_context_s *)ns_list_get_next(&_request_context_list, data); 02702 } 02703 02704 return false; 02705 } 02706 02707 void M2MNsdlInterface::free_request_context_list(const sn_coap_hdr_s *coap_header, bool call_error_cb, request_error_t error_code) 02708 { 02709 // Clean up whole list 02710 if (coap_header == NULL) { 02711 // ns_list_foreach() replacement since it does not compile with IAR 7.x versions. 02712 while (!ns_list_is_empty(&_request_context_list)) { 02713 request_context_s* data = (request_context_s*)ns_list_get_first(&_request_context_list); 02714 if (call_error_cb) { 02715 data->on_request_error_cb(error_code, data->context); 02716 } 02717 ns_list_remove(&_request_context_list, data); 02718 memory_free(data->uri_path); 02719 memory_free(data); 02720 } 02721 02722 // Clean just one item from the list 02723 } else { 02724 // ns_list_foreach() replacement since it does not compile with IAR 7.x versions. 02725 request_context_s *data = (request_context_s *)ns_list_get_first(&_request_context_list); 02726 while (data) { 02727 if (memcmp(coap_header->token_ptr, &data->msg_token, sizeof(data->msg_token)) == 0) { 02728 if (call_error_cb) { 02729 data->on_request_error_cb(error_code, data->context); 02730 } 02731 ns_list_remove(&_request_context_list, data); 02732 memory_free(data->uri_path); 02733 memory_free(data); 02734 return; 02735 } 02736 data = (request_context_s *)ns_list_get_next(&_request_context_list, data); 02737 } 02738 } 02739 } 02740 02741 void M2MNsdlInterface::set_request_context_to_be_resend(uint8_t *token, uint8_t token_len) 02742 { 02743 // ns_list_foreach() replacement since it does not compile with IAR 7.x versions. 02744 request_context_s *data = (request_context_s *)ns_list_get_first(&_request_context_list); 02745 while (data) { 02746 if (token && token_len) { 02747 if (token_len == sizeof(data->msg_token) && 02748 memcmp((uint8_t*)&data->msg_token, token, token_len) == 0) { 02749 data->resend = true; 02750 } 02751 } else { 02752 data->resend = true; 02753 } 02754 data = (request_context_s *)ns_list_get_next(&_request_context_list, data); 02755 } 02756 } 02757 02758 char* M2MNsdlInterface::parse_uri_query_parameters(char* uri) 02759 { 02760 char* query = strchr((char*)uri, '?'); 02761 if (query != NULL) { 02762 query++; 02763 if (*query == '\0') { 02764 return NULL; 02765 } else { 02766 return query; 02767 } 02768 } else { 02769 return NULL; 02770 } 02771 } 02772 02773 bool M2MNsdlInterface::set_uri_query_parameters(const char *uri_query_params) 02774 { 02775 tr_debug("M2MNsdlInterface::set_uri_query_parameters"); 02776 size_t query_len = uri_query_params == NULL ? 0:strlen(uri_query_params); 02777 size_t current_len = _custom_uri_query_params == NULL ? 0:strlen(_custom_uri_query_params); 02778 size_t new_size = query_len + current_len; 02779 02780 if (query_len == 0 || 02781 query_len > MAX_ALLOWED_STRING_LENGTH || 02782 new_size > MAX_ALLOWED_STRING_LENGTH) { 02783 tr_error("M2MNsdlInterface::set_uri_query_parameters - invalid params!"); 02784 return false; 02785 } 02786 02787 // Append into existing string 02788 if (_custom_uri_query_params) { 02789 // Reserve space for "&" and null marks 02790 _custom_uri_query_params = (char*)realloc(_custom_uri_query_params, 1 + new_size + 1); 02791 if (_custom_uri_query_params == NULL) { 02792 return false; 02793 } 02794 02795 memcpy(_custom_uri_query_params + current_len, "&", 1); 02796 memcpy(_custom_uri_query_params + current_len + 1, uri_query_params, query_len); 02797 _custom_uri_query_params[1 + new_size] = '\0'; 02798 } else { 02799 _custom_uri_query_params = (char*)alloc_string_copy((uint8_t*)uri_query_params, query_len + 1); 02800 if (_custom_uri_query_params == NULL) { 02801 return false; 02802 } 02803 } 02804 02805 tr_info("M2MNsdlInterface::set_uri_query_parameters - query %s", _custom_uri_query_params); 02806 return true; 02807 } 02808 02809 void M2MNsdlInterface::clear_sent_blockwise_messages() 02810 { 02811 sn_nsdl_clear_coap_sent_blockwise_messages(_nsdl_handle); 02812 } 02813 02814 void M2MNsdlInterface::clear_received_blockwise_messages() 02815 { 02816 sn_nsdl_clear_coap_received_blockwise_messages(_nsdl_handle); 02817 } 02818 02819 void M2MNsdlInterface::send_coap_ping() 02820 { 02821 if (_binding_mode == M2MInterface::TCP && _registered && 02822 _counter_for_nsdl == _next_coap_ping_send_time && 02823 !coap_ping_in_process()) { 02824 02825 tr_info("M2MNsdlInterface::send_coap_ping()"); 02826 02827 // Build the CoAP here as the CoAP builder would add the message to re-sending queue. 02828 // Store the id to prevent multiple simultanous ping messages, may happen if ping interval is shorter than total retransmission time. 02829 int32_t message_id = sn_nsdl_send_coap_ping(_nsdl_handle); 02830 if (message_id > 0) { 02831 store_to_response_list(NULL, message_id, M2MBase::PING); 02832 } else { 02833 tr_error("M2MNsdlInterface::send_coap_ping() - failed to create ping message!"); 02834 } 02835 } 02836 } 02837 02838 void M2MNsdlInterface::calculate_new_coap_ping_send_time() 02839 { 02840 if (_binding_mode != M2MInterface::TCP) { 02841 return; 02842 } 02843 02844 _next_coap_ping_send_time = _counter_for_nsdl + MBED_CLIENT_TCP_KEEPALIVE_INTERVAL; 02845 } 02846 02847 void M2MNsdlInterface::send_next_notification(bool clear_token) 02848 { 02849 tr_debug("M2MNsdlInterface::send_next_notification"); 02850 claim_mutex(); 02851 if (!_base_list.empty()) { 02852 M2MBaseList::const_iterator base_iterator; 02853 base_iterator = _base_list.begin(); 02854 for ( ; base_iterator != _base_list.end(); base_iterator++ ) { 02855 if ((*base_iterator)->base_type() == M2MBase::Object) { 02856 if (send_next_notification_for_object(*(M2MObject*)*base_iterator, clear_token)) { 02857 release_mutex(); 02858 return; 02859 } 02860 } 02861 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 02862 else if ((*base_iterator)->base_type() == M2MBase::ObjectDirectory) { 02863 M2MEndpoint* endpoint = static_cast<M2MEndpoint*> (*base_iterator); 02864 const M2MObjectList& object_list = endpoint->objects(); 02865 if (!object_list.empty()) { 02866 M2MObjectList::const_iterator object_iterator; 02867 object_iterator = object_list.begin(); 02868 // Object level 02869 for ( ; object_iterator != object_list.end(); object_iterator++ ) { 02870 if (send_next_notification_for_object(**object_iterator, clear_token)) { 02871 release_mutex(); 02872 return; 02873 } 02874 } 02875 } 02876 } 02877 #endif 02878 } 02879 } 02880 02881 _notification_send_ongoing = false; 02882 release_mutex(); 02883 tr_debug("M2MNsdlInterface::send_next_notification - nothing to send"); 02884 } 02885 02886 bool M2MNsdlInterface::send_next_notification_for_object(M2MObject& object, bool clear_token) { 02887 const M2MObjectInstanceList &object_instance_list = object.instances(); 02888 M2MReportHandler* reporter = object.report_handler(); 02889 if (reporter) { 02890 if (clear_token && !object.get_nsdl_resource()->auto_observable) { 02891 reporter->set_observation_token(NULL, 0); 02892 } else if (reporter->is_under_observation() && 02893 (reporter->notification_in_queue() || reporter->notification_send_in_progress())) { 02894 reporter->schedule_report(true); 02895 return true; 02896 } 02897 } 02898 02899 // Object instance level 02900 if (!object_instance_list.empty()) { 02901 M2MObjectInstanceList::const_iterator object_instance_iterator; 02902 object_instance_iterator = object_instance_list.begin(); 02903 for ( ; object_instance_iterator != object_instance_list.end(); object_instance_iterator++ ) { 02904 reporter = (*object_instance_iterator)->report_handler(); 02905 if (reporter) { 02906 if (clear_token && !(*object_instance_iterator)->get_nsdl_resource()->auto_observable) { 02907 reporter->set_observation_token(NULL, 0); 02908 } else if (reporter->is_under_observation() && 02909 (reporter->notification_in_queue() || reporter->notification_send_in_progress())) { 02910 reporter->schedule_report(true); 02911 return true; 02912 } 02913 } 02914 02915 // Resource level 02916 const M2MResourceList &resource_list = (*object_instance_iterator)->resources(); 02917 if (!resource_list.empty()) { 02918 M2MResourceList::const_iterator resource_iterator; 02919 resource_iterator = resource_list.begin(); 02920 for ( ; resource_iterator != resource_list.end(); resource_iterator++) { 02921 reporter = (*resource_iterator)->report_handler(); 02922 if (reporter) { 02923 // Auto obs token can't be cleared 02924 if (clear_token && !(*resource_iterator)->get_nsdl_resource()->auto_observable) { 02925 reporter->set_observation_token(NULL, 0); 02926 } else if (reporter->is_under_observation() && 02927 (reporter->notification_in_queue() || reporter->notification_send_in_progress())) { 02928 reporter->schedule_report(true); 02929 return true; 02930 } 02931 } 02932 } 02933 } 02934 } 02935 } 02936 02937 return false; 02938 } 02939 02940 void M2MNsdlInterface::send_empty_ack(const sn_coap_hdr_s *header, sn_nsdl_addr_s *address) 02941 { 02942 tr_debug("M2MNsdlInterface::send_empty_ack()"); 02943 sn_coap_hdr_s *empty_coap_ack = (sn_coap_hdr_s *) memory_alloc(sizeof(sn_coap_hdr_s)); 02944 if (empty_coap_ack) { 02945 memset(empty_coap_ack, 0, sizeof(sn_coap_hdr_s)); 02946 empty_coap_ack->msg_code = COAP_MSG_CODE_EMPTY; 02947 empty_coap_ack->msg_type = COAP_MSG_TYPE_ACKNOWLEDGEMENT; 02948 empty_coap_ack->msg_id = header->msg_id; 02949 sn_nsdl_send_coap_message(_nsdl_handle, address, empty_coap_ack); 02950 memory_free(empty_coap_ack); 02951 } 02952 } 02953 02954 void M2MNsdlInterface::store_bs_finished_response_id(uint16_t msg_id) 02955 { 02956 tr_debug("M2MNsdlInterface::store_bs_finished_response_id - id %d", msg_id); 02957 _bootstrap_id = msg_id; 02958 } 02959 02960 struct M2MNsdlInterface::nsdl_coap_data_s* M2MNsdlInterface::create_coap_event_data( 02961 sn_coap_hdr_s *received_coap_header, 02962 sn_nsdl_addr_s *address, 02963 struct nsdl_s *nsdl_handle, 02964 uint8_t coap_msg_code) 02965 { 02966 nsdl_coap_data_s *nsdl_coap_data = (nsdl_coap_data_s*)memory_alloc(sizeof(nsdl_coap_data_s)); 02967 02968 if (nsdl_coap_data) { 02969 nsdl_coap_data->nsdl_handle = nsdl_handle; 02970 nsdl_coap_data->address.addr_len = address->addr_len; 02971 nsdl_coap_data->address.type = address->type; 02972 nsdl_coap_data->address.port = address->port; 02973 02974 // Needs to copy all the dynamic data since it resides on stack and this wil turn into an event based call. 02975 nsdl_coap_data->address.addr_ptr = (uint8_t*) memory_alloc(address->addr_len); 02976 02977 if (nsdl_coap_data->address.addr_ptr) { 02978 memcpy(nsdl_coap_data->address.addr_ptr, address->addr_ptr, address->addr_len); 02979 nsdl_coap_data->received_coap_header = received_coap_header; 02980 nsdl_coap_data->received_coap_header->msg_type = COAP_MSG_TYPE_CONFIRMABLE; 02981 nsdl_coap_data->received_coap_header->msg_code = (sn_coap_msg_code_e)coap_msg_code; 02982 02983 // Copy payload 02984 if ((received_coap_header->payload_len > 0) && 02985 (received_coap_header->coap_status != COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED)) { 02986 assert(received_coap_header->payload_ptr); 02987 02988 uint8_t *temp_ptr = (uint8_t*) memory_alloc(received_coap_header->payload_len); 02989 if (temp_ptr) { 02990 memcpy(temp_ptr, received_coap_header->payload_ptr, received_coap_header->payload_len); 02991 nsdl_coap_data->received_coap_header->payload_ptr = temp_ptr; 02992 nsdl_coap_data->received_coap_header->payload_len = received_coap_header->payload_len; 02993 } else { 02994 memory_free(nsdl_coap_data->received_coap_header->payload_ptr); 02995 sn_coap_parser_release_allocated_coap_msg_mem(nsdl_handle->grs->coap, nsdl_coap_data->received_coap_header); 02996 memory_free(nsdl_coap_data->address.addr_ptr); 02997 memory_free(nsdl_coap_data); 02998 return NULL; 02999 } 03000 } 03001 } else { 03002 memory_free(nsdl_coap_data); 03003 return NULL; 03004 } 03005 } else { 03006 return NULL; 03007 } 03008 03009 return nsdl_coap_data; 03010 } 03011 03012 void M2MNsdlInterface::set_registration_status(bool registered) 03013 { 03014 _registered = registered; 03015 03016 // Unblock CoAP ping sending by removing ping request from the list. 03017 if (!registered) { 03018 remove_ping_from_response_list(); 03019 } 03020 } 03021 03022 void M2MNsdlInterface::handle_register_response(const sn_coap_hdr_s *coap_header) 03023 { 03024 if (coap_header->msg_code == COAP_MSG_CODE_RESPONSE_CREATED) { 03025 tr_info("M2MNsdlInterface::handle_register_response - registered"); 03026 // If lifetime is less than zero then leave the field empty 03027 if (coap_header->options_list_ptr) { 03028 uint32_t max_time = coap_header->options_list_ptr->max_age; 03029 03030 // If a sufficiently-large Max-Age option is present, we interpret it as registration lifetime; 03031 // mbed server (mDS) reports lifetime this way as a non-standard extension. Other servers 03032 // would likely not include an explicit Max-Age option, in which case we'd see the default 60 seconds. 03033 if (max_time >= MINIMUM_REGISTRATION_TIME) { 03034 set_endpoint_lifetime_buffer(max_time); 03035 } 03036 if (coap_header->options_list_ptr->location_path_ptr) { 03037 sn_nsdl_set_endpoint_location(_nsdl_handle, 03038 coap_header->options_list_ptr->location_path_ptr, 03039 coap_header->options_list_ptr->location_path_len); 03040 } 03041 03042 } 03043 if (_endpoint->lifetime_ptr) { 03044 _registration_timer.stop_timer(); 03045 _registration_timer.start_timer(registration_time() * 1000, 03046 M2MTimerObserver::Registration, 03047 false); 03048 } 03049 03050 _observer.client_registered(_server); 03051 03052 _notification_send_ongoing = false; 03053 03054 // Check if there are any pending download requests 03055 send_pending_request(); 03056 03057 } else { 03058 tr_error("M2MNsdlInterface::handle_register_response - registration error %d", coap_header->msg_code); 03059 if (coap_header->coap_status == COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED || 03060 coap_header->coap_status == COAP_STATUS_BUILDER_BLOCK_SENDING_FAILED) { 03061 tr_error("M2MNsdlInterface::handle_register_response - message sending failed !!!!"); 03062 } 03063 03064 if (COAP_MSG_CODE_RESPONSE_BAD_REQUEST == coap_header->msg_code || 03065 COAP_MSG_CODE_RESPONSE_FORBIDDEN == coap_header->msg_code) { 03066 _observer.registration_error(M2MInterface::InvalidParameters, false); 03067 } else { 03068 // Try to do clean register again 03069 _observer.registration_error(M2MInterface::NetworkError, true, true); 03070 } 03071 } 03072 } 03073 03074 void M2MNsdlInterface::handle_unregister_response(const sn_coap_hdr_s *coap_header) 03075 { 03076 tr_info("M2MNsdlInterface::handle_unregister_response - unregistered"); 03077 03078 // Clear out the ongoing requests and call error callback with status ERROR_NOT_REGISTERED 03079 free_request_context_list(NULL, true, ERROR_NOT_REGISTERED); 03080 03081 if(coap_header->msg_code == COAP_MSG_CODE_RESPONSE_DELETED) { 03082 _registration_timer.stop_timer(); 03083 _observer.client_unregistered(); 03084 } else { 03085 tr_error("M2MNsdlInterface::handle_unregister_response - unregistration error %d", coap_header->msg_code); 03086 M2MInterface::Error error = M2MInterface::UnregistrationFailed; 03087 if (coap_header->msg_code == COAP_MSG_CODE_RESPONSE_NOT_FOUND) { 03088 _observer.registration_error(error, false); 03089 } else { 03090 _observer.registration_error(error, true); 03091 } 03092 } 03093 } 03094 03095 void M2MNsdlInterface::handle_register_update_response(const sn_coap_hdr_s *coap_header) 03096 { 03097 if (coap_header->msg_code == COAP_MSG_CODE_RESPONSE_CHANGED) { 03098 tr_info("M2MNsdlInterface::handle_register_update_response - registration_updated"); 03099 _observer.registration_updated(*_server); 03100 03101 _notification_send_ongoing = false; 03102 // Check if there are any pending notifications in queue 03103 _notification_handler->send_notification(this); 03104 03105 // Check if there are any pending download requests 03106 send_pending_request(); 03107 03108 } else { 03109 tr_error("M2MNsdlInterface::handle_register_update_response - registration_updated failed %d, %d", coap_header->msg_code, coap_header->coap_status); 03110 _nsdl_handle->update_register_token = 0; 03111 _registration_timer.stop_timer(); 03112 03113 if (coap_header->coap_status == COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED || 03114 coap_header->coap_status == COAP_STATUS_BUILDER_BLOCK_SENDING_FAILED) { 03115 // Inform interfaceimpl to do a reconnection and registration update 03116 // till we get CoAP level response for the request 03117 _observer.registration_error(M2MInterface::NetworkError, true); 03118 } else { 03119 // Do a full registration 03120 bool msg_sent = false; 03121 if (_server_address) { 03122 msg_sent = parse_and_send_uri_query_parameters(); 03123 } 03124 if (!msg_sent) { 03125 sn_nsdl_register_endpoint(_nsdl_handle, _endpoint, NULL); 03126 } 03127 } 03128 } 03129 } 03130 03131 void M2MNsdlInterface::handle_request_response(const sn_coap_hdr_s *coap_header, 03132 request_context_s *request_context) 03133 { 03134 tr_info("M2MNsdlInterface::handle_request_response"); 03135 size_t total_size = 0; 03136 03137 if (coap_header->options_list_ptr) { 03138 if (coap_header->options_list_ptr->use_size2) { 03139 total_size = coap_header->options_list_ptr->size2; 03140 } 03141 } else { 03142 total_size = coap_header->payload_len; 03143 } 03144 03145 if (coap_header->msg_code >= COAP_MSG_CODE_RESPONSE_CREATED && 03146 coap_header->msg_code <= COAP_MSG_CODE_RESPONSE_CONTENT) { 03147 03148 // Reset retry timer for next GET request 03149 _download_retry_time = 0; 03150 03151 // Take copy of uri_path in case of sync mode 03152 // Pointer is freed already by "free_request_context_list" and then used again in send_request() call 03153 char *temp = NULL; 03154 if (!request_context->async_req) { 03155 temp = (char*)alloc_string_copy((uint8_t*)request_context->uri_path, strlen(request_context->uri_path)); 03156 if (temp == NULL) { 03157 free_request_context_list(coap_header, true, FAILED_TO_ALLOCATE_MEMORY); 03158 return; 03159 } 03160 } 03161 03162 // TODO: clean this up, could we keep request_context in the list a bit longer 03163 // or pass the existing one to send_request rather than copying? 03164 size_t rcv_size = request_context->received_size + coap_header->payload_len; 03165 request_data_cb data_cb = request_context->on_request_data_cb; 03166 request_error_cb error_cb = request_context->on_request_error_cb; 03167 void *ctx = request_context->context; 03168 bool async = request_context->async_req; 03169 sn_coap_msg_code_e msg_code = request_context->msg_code; 03170 uint32_t token = request_context->msg_token; 03171 DownloadType download_type = request_context->download_type; 03172 03173 // Remove the request before calling the "on_request_data_cb" callback 03174 free_request_context_list(coap_header, false); 03175 03176 bool last_block = true; 03177 if (coap_header->options_list_ptr && 03178 coap_header->options_list_ptr->block2 != -1 && 03179 coap_header->options_list_ptr->block2 & 0x08) { 03180 // Not last block if block2 is set (blockwised transfer) and more bit is set 03181 last_block = false; 03182 } 03183 03184 data_cb(coap_header->payload_ptr, 03185 coap_header->payload_len, 03186 total_size, 03187 last_block, 03188 ctx); 03189 03190 // In sync mode, call next request automatically until all blocks have been received 03191 if (!async) { 03192 if (!last_block) { 03193 // Note that payload will be empty here as it should have already been sent 03194 // when the initial request was sent! 03195 send_request(download_type, temp, msg_code, rcv_size, async, token, 0, NULL, data_cb, error_cb, ctx); 03196 } else { 03197 tr_info("M2MNsdlInterface::handle_request_response - all blocks received"); 03198 } 03199 03200 memory_free(temp); 03201 } 03202 03203 } else { 03204 // Retransmission completed 03205 if (coap_header->coap_status == COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED || 03206 coap_header->coap_status == COAP_STATUS_BUILDER_BLOCK_SENDING_FAILED) { 03207 _observer.registration_error(M2MInterface::NetworkError, true); 03208 03209 // Start retry logic, only for file download operation 03210 } else if (coap_header->msg_code == COAP_MSG_CODE_RESPONSE_SERVICE_UNAVAILABLE && 03211 request_context->msg_code == COAP_MSG_CODE_REQUEST_GET) { 03212 bool retry = true; 03213 03214 if (!_download_retry_time) { 03215 // Range is from 1 sec to 10 sec 03216 _download_retry_time = randLIB_get_random_in_range(1, 10); 03217 } else { 03218 _download_retry_time *= RECONNECT_INCREMENT_FACTOR; 03219 if (_download_retry_time > MAX_RECONNECT_TIMEOUT) { 03220 tr_error("M2MNsdlInterface::handle_request_response - file download failed, retry completed"); 03221 retry = false; 03222 failed_to_send_request(request_context, coap_header); 03223 } 03224 } 03225 03226 if (retry) { 03227 tr_info("M2MNsdlInterface::handle_request_response - continue file download after %" PRIu64, _download_retry_time); 03228 set_request_context_to_be_resend(coap_header->token_ptr, coap_header->token_len); 03229 _download_retry_timer.start_timer(_download_retry_time * 1000, M2MTimerObserver::RetryTimer); 03230 } 03231 03232 // Message sending has failed, inform application 03233 } else { 03234 failed_to_send_request(request_context, coap_header); 03235 } 03236 } 03237 } 03238 03239 void M2MNsdlInterface::handle_bootstrap_response(const sn_coap_hdr_s *coap_header) 03240 { 03241 #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE 03242 tr_info("M2MNsdlInterface::handle_bootstrap_response"); 03243 _bootstrap_id = 0; 03244 M2MInterface::Error error_code = interface_error(*coap_header); 03245 if (error_code != M2MInterface::ErrorNone) { 03246 03247 #ifdef DISABLE_ERROR_DESCRIPTION 03248 // this ifdef is saving +800B on ARMCC as it gets rid of the COAP_ERROR_* -strings from binary 03249 const char *buffer = ""; 03250 #else 03251 char buffer[MAX_ALLOWED_ERROR_STRING_LENGTH]; 03252 const char* error = coap_error(*coap_header); 03253 snprintf(buffer, sizeof(buffer), "%s:%.*s", error, coap_header->payload_len, coap_header->payload_ptr); 03254 #endif 03255 handle_bootstrap_error(buffer, false); 03256 } else { 03257 _identity_accepted = true; 03258 } 03259 #else 03260 (void)coap_header; 03261 #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE 03262 } 03263 03264 bool M2MNsdlInterface::handle_post_response(sn_coap_hdr_s* coap_header, 03265 sn_nsdl_addr_s* address, 03266 sn_coap_hdr_s *&coap_response, 03267 M2MObjectInstance *&obj_instance, 03268 bool is_bootstrap_msg) 03269 { 03270 bool execute_value_updated = false; 03271 03272 if (is_bootstrap_msg) { 03273 handle_bootstrap_finished(coap_header, address); 03274 } else if (coap_header->uri_path_ptr) { 03275 03276 String resource_name = coap_to_string(coap_header->uri_path_ptr, 03277 coap_header->uri_path_len); 03278 03279 String object_name; 03280 int slash_found = resource_name.find_last_of('/'); 03281 //The POST operation here is only allowed for non-existing object instances 03282 if (slash_found != -1) { 03283 object_name = resource_name.substr(0,slash_found); 03284 if (object_name.find_last_of('/') != -1){ 03285 coap_response = sn_nsdl_build_response(_nsdl_handle, 03286 coap_header, 03287 COAP_MSG_CODE_RESPONSE_NOT_FOUND); 03288 } else { 03289 int32_t instance_id = atoi(resource_name.substr(slash_found+1, 03290 resource_name.size()-object_name.size()).c_str()); 03291 M2MBase* base = find_resource(object_name); 03292 if(base) { 03293 if((instance_id >= 0) && (instance_id < UINT16_MAX)) { 03294 if(coap_header->payload_ptr) { 03295 M2MObject* object = static_cast<M2MObject*> (base); 03296 obj_instance = object->create_object_instance(instance_id); 03297 if(obj_instance) { 03298 obj_instance->set_operation(M2MBase::GET_PUT_POST_ALLOWED); 03299 coap_response = obj_instance->handle_post_request(_nsdl_handle, 03300 coap_header, 03301 this, 03302 execute_value_updated); 03303 } 03304 if (coap_response && coap_response->msg_code != COAP_MSG_CODE_RESPONSE_CREATED) { 03305 //Invalid request so remove created ObjectInstance 03306 object->remove_object_instance(instance_id); 03307 } else { 03308 tr_debug("M2MNsdlInterface::handle_post_response - Send Update registration for Create"); 03309 if (!send_update_registration()) { 03310 // Most likely case would be memory allocation failure 03311 _observer.registration_error(M2MInterface::MemoryFail, false); 03312 } 03313 } 03314 } else { 03315 tr_error("M2MNsdlInterface::handle_post_response - Missing Payload - Cannot create"); 03316 coap_response = sn_nsdl_build_response(_nsdl_handle, 03317 coap_header, 03318 COAP_MSG_CODE_RESPONSE_BAD_REQUEST); 03319 } 03320 } else { // instance id out of range 03321 tr_error("M2MNsdlInterface::handle_post_response - instance id out of range - Cannot create"); 03322 coap_response = sn_nsdl_build_response(_nsdl_handle, 03323 coap_header, 03324 COAP_MSG_CODE_RESPONSE_BAD_REQUEST); 03325 } 03326 } else { // if(base) 03327 tr_error("M2MNsdlInterface::handle_post_response - Missing BASE - Cannot create"); 03328 coap_response = sn_nsdl_build_response(_nsdl_handle, 03329 coap_header, 03330 COAP_MSG_CODE_RESPONSE_NOT_FOUND); 03331 } 03332 } 03333 } else { // if(slash_found != -1) 03334 tr_error("M2MNsdlInterface::handle_post_response - slash_found - Cannot create"); 03335 coap_response = sn_nsdl_build_response(_nsdl_handle, 03336 coap_header, 03337 COAP_MSG_CODE_RESPONSE_NOT_FOUND); 03338 } 03339 03340 } 03341 return execute_value_updated; 03342 } 03343 03344 void M2MNsdlInterface::handle_empty_ack(const sn_coap_hdr_s *coap_header, bool is_bootstrap_msg) 03345 { 03346 // Handle reset message 03347 if (COAP_MSG_TYPE_RESET == coap_header->msg_type) { 03348 coap_response_s *resp = find_response(coap_header->msg_id); 03349 if (resp) { 03350 if (resp->type == M2MBase::PING) { 03351 remove_item_from_response_list(resp->uri_path, coap_header->msg_id); 03352 } else { 03353 M2MBase *base = find_resource(resp->uri_path); 03354 if (base) { 03355 if (resp->type == M2MBase::NOTIFICATION) { 03356 M2MBase::BaseType type = base->base_type(); 03357 switch (type) { 03358 case M2MBase::Object: 03359 base->remove_observation_level(M2MBase::O_Attribute); 03360 break; 03361 case M2MBase::Resource: 03362 base->remove_observation_level(M2MBase::R_Attribute); 03363 break; 03364 case M2MBase::ObjectInstance: 03365 base->remove_observation_level(M2MBase::OI_Attribute); 03366 break; 03367 default: 03368 break; 03369 } 03370 base->set_under_observation(false, this); 03371 _notification_send_ongoing = false; 03372 base->send_notification_delivery_status(*base, NOTIFICATION_STATUS_UNSUBSCRIBED); 03373 base->send_message_delivery_status(*base, M2MBase::MESSAGE_STATUS_UNSUBSCRIBED, M2MBase::NOTIFICATION); 03374 _notification_handler->send_notification(this); 03375 } else if (resp->type == M2MBase::DELAYED_POST_RESPONSE) { 03376 base->send_message_delivery_status(*base, M2MBase::MESSAGE_STATUS_REJECTED, M2MBase::DELAYED_POST_RESPONSE); 03377 } 03378 #ifdef ENABLE_ASYNC_REST_RESPONSE 03379 else if (resp->type == M2MBase::DELAYED_RESPONSE) { 03380 base->send_message_delivery_status(*base, M2MBase::MESSAGE_STATUS_REJECTED, M2MBase::DELAYED_RESPONSE); 03381 } 03382 #endif // ENABLE_ASYNC_REST_RESPONSE 03383 remove_item_from_response_list(resp->uri_path, coap_header->msg_id); 03384 } 03385 } 03386 } 03387 } else if (is_bootstrap_msg) { 03388 if (!_bootstrap_finish_ack_received) { 03389 // The _bootstrap_finish_ack_received flag is used to avoid sending the finish event 03390 // twice incase we get the same ack before the event loop has handled the event. 03391 _observer.bootstrap_wait(); 03392 if (coap_header->coap_status == COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED || 03393 coap_header->coap_status == COAP_STATUS_BUILDER_BLOCK_SENDING_FAILED) { 03394 handle_bootstrap_error(ERROR_REASON_28, false); 03395 } else { 03396 tr_debug("M2MNsdlInterface::handle_empty_ack - sending finish event - status %d", coap_header->coap_status); 03397 _event.data.event_type = MBED_CLIENT_NSDLINTERFACE_BS_FINISH_EVENT; 03398 _event.data.event_data = coap_header->msg_id; 03399 _event.data.data_ptr = _nsdl_handle; 03400 _bootstrap_finish_ack_received = true; 03401 eventOS_event_send_user_allocated(&_event); 03402 } 03403 } 03404 else { 03405 tr_debug("M2MNsdlInterface::handle_empty_ack - finish event already in progress"); 03406 } 03407 } else { 03408 coap_response_s *data = find_response(coap_header->msg_id); 03409 if (data) { 03410 M2MBase *base = find_resource(data->uri_path); 03411 if (base) { 03412 bool report = true; 03413 if (data->type == M2MBase::NOTIFICATION) { 03414 if (base->report_handler()->blockwise_notify()) { 03415 report = false; 03416 } 03417 } 03418 03419 if (report) { 03420 if (!data->blockwise_used) { 03421 handle_message_delivered(base, data->type); 03422 remove_item_from_response_list(NULL, coap_header->msg_id); 03423 } 03424 } 03425 } 03426 } 03427 } 03428 } 03429 03430 void M2MNsdlInterface::handle_bootstrap_finish_ack(uint16_t msg_id) 03431 { 03432 // EMPTY ACK for BS finished 03433 tr_debug("M2MNsdlInterface::handle_bootstrap_finish_ack - id: %d", msg_id); 03434 if (_bootstrap_id == msg_id) { 03435 _observer.bootstrap_finish(); 03436 _bootstrap_id = 0; 03437 } else { 03438 tr_error("M2MNsdlInterface::handle_empty_ack - empty ACK id does not match to BS finished response id!"); 03439 char buffer[MAX_ALLOWED_ERROR_STRING_LENGTH]; 03440 const char *desc = "message id does not match"; 03441 snprintf(buffer, sizeof(buffer), ERROR_REASON_22, desc); 03442 handle_bootstrap_error(buffer, false); 03443 } 03444 } 03445 03446 void M2MNsdlInterface::handle_message_delivered(M2MBase *base, const M2MBase::MessageType type) 03447 { 03448 if (M2MBase::NOTIFICATION == type) { 03449 base->report_handler()->set_notification_send_in_progress(false); 03450 _notification_send_ongoing = false; 03451 base->send_notification_delivery_status(*base, NOTIFICATION_STATUS_DELIVERED); 03452 03453 _notification_handler->send_notification(this); 03454 03455 // Supported only in Resource level 03456 // TODO! remove below code once old API is removed 03457 if (M2MBase::Resource == base->base_type()) { 03458 M2MResource *resource = static_cast<M2MResource *> (base); 03459 resource->notification_sent(); 03460 } 03461 } 03462 03463 base->send_message_delivery_status(*base, M2MBase::MESSAGE_STATUS_DELIVERED, type); 03464 } 03465 03466 void M2MNsdlInterface::set_retransmission_parameters() 03467 { 03468 // in UDP mode, reconnection attempts must be scaled down so that last attempt does not slip 03469 // past the client lifetime. 03470 uint64_t lifetime = registration_time(); 03471 uint32_t resend_count = MBED_CLIENT_RECONNECTION_COUNT; 03472 03473 uint32_t reconnection_total_time = total_retransmission_time(resend_count); 03474 tr_debug("M2MNsdlInterface::set_retransmission_parameters() - total resend time %" PRIu32, reconnection_total_time); 03475 03476 while (resend_count > 1 && reconnection_total_time > lifetime) { 03477 reconnection_total_time = total_retransmission_time(--resend_count); 03478 } 03479 03480 tr_info("M2MNsdlInterface::set_retransmission_parameters() - setting max resend count to %" PRIu32 " with total time: %" PRIu32, resend_count, reconnection_total_time); 03481 sn_nsdl_set_retransmission_parameters(_nsdl_handle, resend_count, MBED_CLIENT_RECONNECTION_INTERVAL); 03482 } 03483 03484 uint32_t M2MNsdlInterface::total_retransmission_time(uint32_t resend_count) 03485 { 03486 uint32_t reconnection_total_time = 1; 03487 03488 for (uint32_t i = 0; i <= resend_count; i++) { 03489 reconnection_total_time *= 2; 03490 } 03491 03492 reconnection_total_time--; 03493 reconnection_total_time *= MBED_CLIENT_RECONNECTION_INTERVAL; 03494 03495 // We need to take into account that CoAP specification mentions that each retransmission 03496 // has to have a random multiplying factor between 1 - 1.5 , max of which can be 1.5 03497 reconnection_total_time *= RESPONSE_RANDOM_FACTOR; 03498 03499 return reconnection_total_time; 03500 } 03501 03502 bool M2MNsdlInterface::is_update_register_ongoing() const 03503 { 03504 return _nsdl_handle->update_register_token == 0 ? false : true; 03505 } 03506 03507 uint8_t M2MNsdlInterface::get_resend_count() 03508 { 03509 return sn_nsdl_get_retransmission_count(_nsdl_handle); 03510 } 03511 03512 void M2MNsdlInterface::send_pending_request() 03513 { 03514 // ns_list_foreach() replacement since it does not compile with IAR 7.x versions. 03515 request_context_s *data = (request_context_s *)ns_list_get_first(&_request_context_list); 03516 while (data) { 03517 if (data->resend && data->msg_code == COAP_MSG_CODE_REQUEST_GET) { 03518 send_request(data->download_type, 03519 data->uri_path, 03520 data->msg_code, 03521 data->received_size, 03522 data->async_req, 03523 data->msg_token, 03524 0, 03525 NULL, 03526 data->on_request_data_cb, 03527 data->on_request_error_cb, 03528 data->context); 03529 } 03530 03531 data = (request_context_s *)ns_list_get_next(&_request_context_list, data); 03532 } 03533 } 03534 03535 void M2MNsdlInterface::free_response_list() 03536 { 03537 // ns_list_foreach() replacement since it does not compile with IAR 7.x versions. 03538 while (!ns_list_is_empty(&_response_list)) { 03539 coap_response_s* data = (coap_response_s*)ns_list_get_first(&_response_list); 03540 ns_list_remove(&_response_list, data); 03541 memory_free(data->uri_path); 03542 memory_free(data); 03543 } 03544 } 03545 03546 void M2MNsdlInterface::remove_item_from_response_list(const char* uri_path, const int32_t msg_id) 03547 { 03548 // ns_list_foreach() replacement since it does not compile with IAR 7.x versions. 03549 coap_response_s *data = (coap_response_s *)ns_list_get_first(&_response_list); 03550 while (data) { 03551 if (data->msg_id == msg_id) { 03552 bool remove = true; 03553 if (uri_path) { 03554 remove = false; 03555 if ((strcmp(uri_path, data->uri_path) == 0)) { 03556 remove = true; 03557 } 03558 } 03559 if (remove) { 03560 ns_list_remove(&_response_list, data); 03561 memory_free(data->uri_path); 03562 memory_free(data); 03563 return; 03564 } 03565 } 03566 data = (coap_response_s *)ns_list_get_next(&_response_list, data); 03567 } 03568 } 03569 03570 #if !defined(DISABLE_DELAYED_RESPONSE) || defined(ENABLE_ASYNC_REST_RESPONSE) 03571 void M2MNsdlInterface::remove_items_from_response_list_for_uri(const char* uri_path) 03572 { 03573 // ns_list_foreach() replacement since it does not compile with IAR 7.x versions. 03574 coap_response_s *data = (coap_response_s *)ns_list_get_first(&_response_list); 03575 while (data) { 03576 bool remove = false; 03577 if (uri_path) { 03578 if ((strcmp(uri_path, data->uri_path) == 0)) { 03579 remove = true; 03580 } 03581 } 03582 coap_response_s *next = (coap_response_s *)ns_list_get_next(&_response_list, data); 03583 if (remove) { 03584 ns_list_remove(&_response_list, data); 03585 memory_free(data->uri_path); 03586 memory_free(data); 03587 } 03588 data = next; 03589 } 03590 } 03591 #endif 03592 03593 void M2MNsdlInterface::store_to_response_list(const char *uri, int32_t msg_id, M2MBase::MessageType type) 03594 { 03595 coap_response_s *resp = (struct coap_response_s*)memory_alloc(sizeof(struct coap_response_s)); 03596 if (resp) { 03597 resp->uri_path = NULL; 03598 if (uri) { 03599 resp->uri_path = M2MBase::alloc_string_copy(uri); 03600 if (resp->uri_path == NULL) { 03601 tr_error("M2MNsdlInterface::store_to_response_list - failed to allocate uri_path!"); 03602 memory_free(resp); 03603 return; 03604 } 03605 } 03606 03607 resp->msg_id = msg_id; 03608 resp->type = type; 03609 resp->blockwise_used = false; 03610 ns_list_add_to_end(&_response_list, resp); 03611 } else { 03612 tr_error("M2MNsdlInterface::store_to_response_list - failed to allocate coap_response_s!"); 03613 } 03614 } 03615 03616 struct M2MNsdlInterface::coap_response_s* M2MNsdlInterface::find_response(int32_t msg_id) 03617 { 03618 coap_response_s *data = (coap_response_s *)ns_list_get_first(&_response_list); 03619 while (data) { 03620 if (data->msg_id == msg_id) { 03621 return data; 03622 } 03623 data = (coap_response_s *)ns_list_get_next(&_response_list, data); 03624 } 03625 03626 return NULL; 03627 } 03628 03629 #if !defined(DISABLE_DELAYED_RESPONSE) || defined(ENABLE_ASYNC_REST_RESPONSE) 03630 struct M2MNsdlInterface::coap_response_s* M2MNsdlInterface::find_delayed_response(const char* uri_path, 03631 const M2MBase::MessageType type, 03632 int32_t message_id) 03633 { 03634 coap_response_s *data = (coap_response_s *)ns_list_get_first(&_response_list); 03635 while (data) { 03636 if (data->uri_path && 03637 strcmp(data->uri_path, uri_path) == 0 && 03638 data->type == type && 03639 ((message_id == UNDEFINED_MSG_ID)) || (data->msg_id == message_id)) { 03640 return data; 03641 } 03642 data = (coap_response_s *)ns_list_get_next(&_response_list, data); 03643 } 03644 03645 return NULL; 03646 } 03647 #endif // DISABLE_DELAYED_RESPONSE 03648 03649 void M2MNsdlInterface::failed_to_send_request(request_context_s *request, const sn_coap_hdr_s *coap_header) 03650 { 03651 sn_nsdl_remove_msg_from_retransmission(_nsdl_handle, 03652 (uint8_t*)&request->msg_token, 03653 sizeof(request->msg_token)); 03654 free_request_context_list(coap_header, true, FAILED_TO_SEND_MSG); 03655 } 03656 03657 bool M2MNsdlInterface::coap_ping_in_process() const 03658 { 03659 const coap_response_s *data = (coap_response_s *)ns_list_get_first(&_response_list); 03660 while (data) { 03661 if (data->type == M2MBase::PING) { 03662 tr_info("M2MNsdlInterface::coap_ping_in_process() - already in process"); 03663 return true; 03664 } 03665 data = (coap_response_s *)ns_list_get_next(&_response_list, data); 03666 } 03667 03668 return false; 03669 } 03670 03671 void M2MNsdlInterface::remove_ping_from_response_list() 03672 { 03673 // ns_list_foreach() replacement since it does not compile with IAR 7.x versions. 03674 coap_response_s *data = (coap_response_s *)ns_list_get_first(&_response_list); 03675 while (data) { 03676 if (data->type == M2MBase::PING) { 03677 ns_list_remove(&_response_list, data); 03678 memory_free(data->uri_path); 03679 memory_free(data); 03680 return; 03681 } 03682 data = (coap_response_s *)ns_list_get_next(&_response_list, data); 03683 } 03684 } 03685 03686 #if !defined(DISABLE_DELAYED_RESPONSE) || defined(ENABLE_ASYNC_REST_RESPONSE) 03687 bool M2MNsdlInterface::handle_delayed_response_store(const char* uri_path, 03688 sn_coap_hdr_s* received_coap, 03689 sn_nsdl_addr_s *address, 03690 const M2MBase::MessageType message_type) 03691 { 03692 coap_response_s *resp = NULL; 03693 // When running client in Edge, it can store more than one request per resource 03694 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 03695 resp = find_delayed_response(uri_path, message_type, received_coap->msg_id); 03696 #else 03697 resp = find_delayed_response(uri_path, message_type); 03698 #endif 03699 bool success = true; 03700 // Only one request can be in process at a time 03701 if (resp) { 03702 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(_nsdl_handle, 03703 received_coap, 03704 COAP_MSG_CODE_RESPONSE_PRECONDITION_FAILED); 03705 if (coap_response) { 03706 sn_nsdl_send_coap_message(_nsdl_handle, address, coap_response); 03707 sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response); 03708 } 03709 03710 sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, received_coap); 03711 success = false; 03712 } else { 03713 // When running client in Edge, it can store more than one request per resource 03714 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 03715 store_to_response_list(uri_path, received_coap->msg_id, message_type); 03716 #else 03717 store_to_response_list(uri_path, UNDEFINED_MSG_ID, message_type); 03718 #endif 03719 } 03720 03721 return success; 03722 } 03723 #endif
Generated on Tue Jul 12 2022 20:21:00 by
