Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers m2mnsdlinterface.cpp Source File

m2mnsdlinterface.cpp

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