Simulated product dispenser
Fork of mbed-cloud-workshop-connect-HTS221 by
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 19:12:13 by 1.7.2