Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers m2mnsdlinterface.cpp Source File

m2mnsdlinterface.cpp

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