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