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.
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 Mon Aug 29 2022 19:53:40 by
