This is an example of BLE GATT Client, which receives broadcast data from BLE_Server_BME280 ( a GATT server) , then transfers values up to mbed Device Connector (cloud).

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 // Note: this macro is needed on armcc to get the the PRI*32 macros
00018 // from inttypes.h in a C++ code.
00019 #ifndef __STDC_FORMAT_MACROS
00020 #define __STDC_FORMAT_MACROS
00021 #endif
00022 
00023 // Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX
00024 #ifndef __STDC_LIMIT_MACROS
00025 #define __STDC_LIMIT_MACROS
00026 #endif
00027 
00028 
00029 #include "include/nsdlaccesshelper.h"
00030 #include "include/m2mnsdlobserver.h"
00031 #include "include/m2mtlvdeserializer.h"
00032 #include "include/m2mtlvserializer.h"
00033 #include "include/m2mnsdlinterface.h"
00034 #include "mbed-client/m2mstring.h"
00035 #include "mbed-client/m2msecurity.h"
00036 #include "mbed-client/m2mserver.h"
00037 #include "mbed-client/m2mobject.h"
00038 #include "mbed-client/m2mobjectinstance.h"
00039 #include "mbed-client/m2mresource.h"
00040 #include "mbed-client/m2mconstants.h"
00041 #include "mbed-trace/mbed_trace.h"
00042 #include "mbed-client/m2mtimer.h"
00043 #include "source/libNsdl/src/include/sn_grs.h"
00044 
00045 #include <assert.h>
00046 #include <inttypes.h>
00047 #include <stdlib.h>
00048 
00049 #define BUFFER_SIZE 21
00050 #define TRACE_GROUP "mClt"
00051 
00052 M2MNsdlInterface::M2MNsdlInterface(M2MNsdlObserver &observer)
00053 : _observer(observer),
00054   _endpoint(NULL),
00055   _nsdl_handle(NULL),
00056   _security(NULL),
00057   _server(),
00058   _nsdl_exceution_timer(new M2MTimer(*this)),
00059   _registration_timer(new M2MTimer(*this)),
00060   _counter_for_nsdl(0),
00061   _bootstrap_id(0),
00062   _unregister_ongoing(false),
00063   _identity_accepted(false)
00064 {
00065     tr_debug("M2MNsdlInterface::M2MNsdlInterface()");
00066     __nsdl_interface_list.push_back(this);
00067     _sn_nsdl_address.addr_len = 0;
00068     _sn_nsdl_address.addr_ptr = NULL;
00069     _sn_nsdl_address.port = 0;
00070     _sn_nsdl_address.type = SN_NSDL_ADDRESS_TYPE_NONE;
00071 
00072     // This initializes libCoap and libNsdl
00073     // Parameters are function pointers to used memory allocation
00074     // and free functions in structure and used functions for sending
00075     // and receiving purposes.
00076     _nsdl_handle = sn_nsdl_init(&(__nsdl_c_send_to_server), &(__nsdl_c_received_from_server),
00077                  &(__nsdl_c_memory_alloc), &(__nsdl_c_memory_free));
00078 
00079     initialize();
00080 }
00081 
00082 M2MNsdlInterface::~M2MNsdlInterface()
00083 {
00084     tr_debug("M2MNsdlInterface::~M2MNsdlInterface() - IN");
00085     if(_endpoint) {
00086          memory_free(_endpoint->endpoint_name_ptr);
00087          memory_free(_endpoint->lifetime_ptr);
00088          memory_free(_endpoint->location_ptr);
00089          memory_free(_endpoint);
00090     }
00091     delete _nsdl_exceution_timer;
00092     delete _registration_timer;
00093     _object_list.clear();
00094     _security = NULL;
00095 
00096     sn_nsdl_destroy(_nsdl_handle);
00097     _nsdl_handle = NULL;
00098 
00099     M2MNsdlInterfaceList::const_iterator it;
00100     it = __nsdl_interface_list.begin();
00101     int index = 0;
00102     for (; it!=__nsdl_interface_list.end(); it++) {
00103         if ((*it) == this) {
00104             __nsdl_interface_list.erase(index);
00105             break;
00106         }
00107         index++;
00108     }
00109     tr_debug("M2MNsdlInterface::~M2MNsdlInterface() - OUT");
00110 }
00111 
00112 bool M2MNsdlInterface::initialize()
00113 {
00114     tr_debug("M2MNsdlInterface::initialize()");
00115     bool success = false;
00116 
00117     //Sets the packet retransmission attempts and time interval
00118     sn_nsdl_set_retransmission_parameters(_nsdl_handle,
00119                                           MBED_CLIENT_RECONNECTION_COUNT,
00120                                           MBED_CLIENT_RECONNECTION_INTERVAL);
00121 
00122     //Allocate the memory for endpoint
00123     _endpoint = (sn_nsdl_ep_parameters_s*)memory_alloc(sizeof(sn_nsdl_ep_parameters_s));
00124     if(_endpoint) {
00125         memset(_endpoint, 0, sizeof(sn_nsdl_ep_parameters_s));
00126         success = true;
00127     }
00128     return success;
00129 }
00130 
00131 void M2MNsdlInterface::create_endpoint(const String &name,
00132                                        const String &type,
00133                                        const int32_t life_time,
00134                                        const String &domain,
00135                                        const uint8_t mode,
00136                                        const String &/*context_address*/)
00137 {
00138     tr_debug("M2MNsdlInterface::create_endpoint( name %s type %s lifetime %" PRId32 ", domain %s, mode %d)",
00139               name.c_str(), type.c_str(), life_time, domain.c_str(), mode);
00140     _endpoint_name = name;
00141     if(_endpoint){
00142         memset(_endpoint, 0, sizeof(sn_nsdl_ep_parameters_s));
00143         if(!_endpoint_name.empty()) {
00144             memory_free(_endpoint->endpoint_name_ptr);
00145             _endpoint->endpoint_name_ptr = alloc_string_copy((uint8_t*)_endpoint_name.c_str(), _endpoint_name.length());
00146             _endpoint->endpoint_name_len = _endpoint_name.length();
00147         }
00148         if(!type.empty()) {
00149             _endpoint->type_ptr = (uint8_t*)type.c_str();
00150             _endpoint->type_len =  type.length();
00151         }
00152         if(!domain.empty()) {
00153             _endpoint->domain_name_ptr = (uint8_t*)domain.c_str();
00154             _endpoint->domain_name_len = domain.length();
00155         }
00156         _endpoint->binding_and_mode = (sn_nsdl_oma_binding_and_mode_t)mode;
00157 
00158         // If lifetime is less than zero then leave the field empty
00159         if( life_time > 0) {
00160             set_endpoint_lifetime_buffer(life_time);
00161         }
00162     }
00163 }
00164 
00165 void M2MNsdlInterface::set_endpoint_lifetime_buffer(int lifetime)
00166 {
00167     // max len of "-9223372036854775808" plus zero termination
00168     char buffer[20+1];
00169 
00170     uint32_t size = m2m::itoa_c(lifetime, buffer);
00171 
00172     if (_endpoint && size <= sizeof(buffer)) {
00173         _endpoint->lifetime_ptr = alloc_string_copy((uint8_t*)buffer, size);
00174         if(_endpoint->lifetime_ptr) {
00175             _endpoint->lifetime_len =  size;
00176         } else {
00177             _endpoint->lifetime_len = 0;
00178         }
00179     }
00180 }
00181 
00182 
00183 void M2MNsdlInterface::delete_endpoint()
00184 {
00185     tr_debug("M2MNsdlInterface::delete_endpoint()");
00186     if(_endpoint) {
00187         free(_endpoint->lifetime_ptr);
00188 
00189         memory_free(_endpoint);
00190         _endpoint = NULL;
00191     }
00192 }
00193 
00194 bool M2MNsdlInterface::create_nsdl_list_structure(const M2MObjectList &object_list)
00195 {
00196     tr_debug("M2MNsdlInterface::create_nsdl_list_structure()");
00197     bool success = false;
00198     if(!object_list.empty()) {
00199        tr_debug("M2MNsdlInterface::create_nsdl_list_structure - Object count is %d", object_list.size());
00200         M2MObjectList::const_iterator it;
00201         it = object_list.begin();
00202         for ( ; it != object_list.end(); it++ ) {
00203             // Create NSDL structure for all Objects inside
00204             success = create_nsdl_object_structure(*it);
00205             add_object_to_list(*it);
00206         }
00207     }
00208     return success;
00209 }
00210 
00211 bool M2MNsdlInterface::remove_nsdl_resource(M2MBase *base)
00212 {
00213     sn_nsdl_dynamic_resource_parameters_s* resource = base->get_nsdl_resource();
00214     return sn_nsdl_pop_resource(_nsdl_handle, resource);
00215 }
00216 
00217 bool M2MNsdlInterface::create_bootstrap_resource(sn_nsdl_addr_s *address, const String &bootstrap_endpoint_name)
00218 {
00219 #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE
00220     tr_debug("M2MNsdlInterface::create_bootstrap_resource()");
00221     _identity_accepted = false;
00222     bool success = false;
00223     sn_nsdl_bs_ep_info_t bootstrap_endpoint;
00224     tr_debug("M2MNsdlInterface::create_bootstrap_resource() - endpoint name: %s", bootstrap_endpoint_name.c_str());
00225     if (_endpoint->endpoint_name_ptr) {
00226         memory_free(_endpoint->endpoint_name_ptr);
00227     }
00228 
00229     _endpoint->endpoint_name_ptr = alloc_string_copy((uint8_t*)bootstrap_endpoint_name.c_str(), bootstrap_endpoint_name.length());
00230     _endpoint->endpoint_name_len = bootstrap_endpoint_name.length();
00231     if(_bootstrap_id == 0) {
00232         _bootstrap_id = sn_nsdl_oma_bootstrap(_nsdl_handle,
00233                                                address,
00234                                                _endpoint,
00235                                                &bootstrap_endpoint);
00236         tr_debug("M2MNsdlInterface::create_bootstrap_resource - _bootstrap_id %d", _bootstrap_id);
00237         success = _bootstrap_id != 0;
00238     }
00239     return success;
00240 #else
00241     (void)address;
00242     (void)bootstrap_endpoint_name;
00243     return false;
00244 #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE
00245 }
00246 
00247 bool M2MNsdlInterface::send_register_message(uint8_t* address,
00248                                              uint8_t address_length,
00249                                              const uint16_t port,
00250                                              sn_nsdl_addr_type_e address_type)
00251 {
00252     tr_debug("M2MNsdlInterface::send_register_message()");
00253     _nsdl_exceution_timer->stop_timer();
00254     _nsdl_exceution_timer->start_timer(ONE_SECOND_TIMER * 1000,
00255                                        M2MTimerObserver::NsdlExecution,
00256                                        false);
00257     bool success = false;
00258     if(set_NSP_address(_nsdl_handle, address, address_length, port, address_type) == 0) {
00259         success = sn_nsdl_register_endpoint(_nsdl_handle,_endpoint) != 0;
00260     }
00261     return success;
00262 }
00263 
00264 bool M2MNsdlInterface::send_update_registration(const uint32_t lifetime)
00265 {
00266     tr_debug("M2MNsdlInterface::send_update_registration( lifetime %" PRIu32 ")", lifetime);
00267     bool success = false;
00268     create_nsdl_list_structure(_object_list);
00269 
00270     //If Lifetime value is 0, then don't change the existing lifetime value
00271     if(lifetime != 0) {
00272         if(_endpoint && _endpoint->lifetime_ptr) {
00273             memory_free(_endpoint->lifetime_ptr);
00274             _endpoint->lifetime_ptr = NULL;
00275             _endpoint->lifetime_len = 0;
00276         }
00277         set_endpoint_lifetime_buffer(lifetime);
00278 
00279         _registration_timer->stop_timer();
00280         _registration_timer->start_timer(registration_time() * 1000,
00281                                          M2MTimerObserver::Registration,
00282                                          false);
00283         if(_nsdl_handle &&
00284            _endpoint && _endpoint->lifetime_ptr) {
00285             tr_debug("M2MNsdlInterface::send_update_registration - new lifetime value");
00286             success = sn_nsdl_update_registration(_nsdl_handle,
00287                                                   _endpoint->lifetime_ptr,
00288                                                   _endpoint->lifetime_len) != 0;
00289         }
00290     } else {
00291         if(_nsdl_handle) {
00292             tr_debug("M2MNsdlInterface::send_update_registration - regular update");
00293             success = sn_nsdl_update_registration(_nsdl_handle, NULL, 0) != 0;
00294         }
00295     }
00296     return success;
00297 }
00298 
00299 bool M2MNsdlInterface::send_unregister_message()
00300 {
00301     tr_debug("M2MNsdlInterface::send_unregister_message");
00302     if (_unregister_ongoing) {
00303         tr_debug("M2MNsdlInterface::send_unregister_message - unregistration already in progress");
00304         return true;
00305     }
00306 
00307     bool success = false;
00308     _unregister_ongoing = true;
00309     success = sn_nsdl_unregister_endpoint(_nsdl_handle) != 0;
00310     return success;
00311 }
00312 
00313 // XXX: move these to common place, no need to copy these wrappers to multiple places:
00314 void *M2MNsdlInterface::memory_alloc(uint16_t size)
00315 {
00316     if(size)
00317         return malloc(size);
00318     else
00319         return 0;
00320 }
00321 
00322 void M2MNsdlInterface::memory_free(void *ptr)
00323 {
00324     if(ptr)
00325         free(ptr);
00326 }
00327 
00328 uint8_t* M2MNsdlInterface::alloc_string_copy(const uint8_t* source, uint16_t size)
00329 {
00330     assert(source != NULL);
00331 
00332     uint8_t* result = (uint8_t*)memory_alloc(size + 1);
00333     if (result) {
00334         memcpy(result, source, size);
00335         result[size] = '\0';
00336     }
00337     return result;
00338 }
00339 
00340 uint8_t M2MNsdlInterface::send_to_server_callback(struct nsdl_s * /*nsdl_handle*/,
00341                                                   sn_nsdl_capab_e /*protocol*/,
00342                                                   uint8_t *data_ptr,
00343                                                   uint16_t data_len,
00344                                                   sn_nsdl_addr_s *address)
00345 {
00346     tr_debug("M2MNsdlInterface::send_to_server_callback()");
00347     _observer.coap_message_ready(data_ptr,data_len,address);
00348     return 1;
00349 }
00350 
00351 uint8_t M2MNsdlInterface::received_from_server_callback(struct nsdl_s *nsdl_handle,
00352                                                         sn_coap_hdr_s *coap_header,
00353                                                         sn_nsdl_addr_s *address)
00354 {
00355     _observer.coap_data_processed();
00356     uint8_t value = 0;
00357     if(nsdl_handle && coap_header) {
00358         tr_debug("M2MNsdlInterface::received_from_server_callback - incoming msg id:%" PRIu16, coap_header->msg_id);
00359         tr_debug("M2MNsdlInterface::received_from_server_callback - registration id:%" PRIu16, nsdl_handle->register_msg_id);
00360         tr_debug("M2MNsdlInterface::received_from_server_callback - unregistration id:%" PRIu16, nsdl_handle->unregister_msg_id);
00361         tr_debug("M2MNsdlInterface::received_from_server_callback - update registration id:%" PRIu16, nsdl_handle->update_register_msg_id);
00362         bool is_bootstrap_msg = address && (nsdl_handle->oma_bs_address_len == address->addr_len) &&
00363                                    (nsdl_handle->oma_bs_port == address->port) &&
00364                                    !memcmp(nsdl_handle->oma_bs_address_ptr, address->addr_ptr, nsdl_handle->oma_bs_address_len);
00365         if(coap_header->msg_id == nsdl_handle->register_msg_id) {
00366             if(coap_header->msg_code == COAP_MSG_CODE_RESPONSE_CREATED) {
00367                 tr_debug("M2MNsdlInterface::received_from_server_callback - registration callback");
00368                 _observer.client_registered(&_server);
00369                 // If lifetime is less than zero then leave the field empty
00370                 if(coap_header->options_list_ptr) {
00371                     memory_free(_endpoint->lifetime_ptr);
00372                     _endpoint->lifetime_ptr = NULL;
00373                     _endpoint->lifetime_len = 0;
00374 
00375                     uint32_t max_time = coap_header->options_list_ptr->max_age;
00376                     // If lifetime is less than zero then leave the field empty
00377                     if( max_time > 0) {
00378                         set_endpoint_lifetime_buffer(max_time);
00379                     }
00380                     if(coap_header->options_list_ptr->location_path_ptr) {
00381 
00382                         memory_free(_endpoint->location_ptr);
00383 
00384                         _endpoint->location_ptr = alloc_string_copy(coap_header->options_list_ptr->location_path_ptr, coap_header->options_list_ptr->location_path_len);
00385                         if (_endpoint->location_ptr != NULL) {
00386                             _endpoint->location_len = coap_header->options_list_ptr->location_path_len;
00387                         }
00388                         sn_nsdl_set_endpoint_location(_nsdl_handle,_endpoint->location_ptr,_endpoint->location_len);
00389                     }
00390                 }
00391                 if(_endpoint->lifetime_ptr) {
00392                     _registration_timer->stop_timer();
00393                     _registration_timer->start_timer(registration_time() * 1000,
00394                                                      M2MTimerObserver::Registration,
00395                                                      false);
00396                 }
00397             } else {
00398                 tr_error("M2MNsdlInterface::received_from_server_callback - registration error %d", coap_header->msg_code);
00399                 // Try to do clean register again
00400                 if(COAP_MSG_CODE_RESPONSE_BAD_REQUEST == coap_header->msg_code ||
00401                    COAP_MSG_CODE_RESPONSE_FORBIDDEN == coap_header->msg_code) {
00402                     _observer.registration_error(M2MInterface::InvalidParameters, false);
00403                 } else {
00404                     _observer.registration_error(M2MInterface::NetworkError, true);
00405                 }
00406 
00407             }
00408         } else if(coap_header->msg_id == nsdl_handle->unregister_msg_id) {
00409             _unregister_ongoing = false;
00410             tr_debug("M2MNsdlInterface::received_from_server_callback - unregistration callback");
00411             if(coap_header->msg_code == COAP_MSG_CODE_RESPONSE_DELETED) {
00412                 _registration_timer->stop_timer();
00413                 _observer.client_unregistered();
00414             } else {
00415                 tr_error("M2MNsdlInterface::received_from_server_callback - unregistration error %d", coap_header->msg_code);
00416                 M2MInterface::Error error = interface_error(coap_header);
00417                 _observer.registration_error(error);
00418             }
00419         } else if(coap_header->msg_id == nsdl_handle->update_register_msg_id) {
00420             if(coap_header->msg_code == COAP_MSG_CODE_RESPONSE_CHANGED) {
00421                 tr_debug("M2MNsdlInterface::received_from_server_callback - registration_updated successfully");
00422                 _observer.registration_updated(_server);
00423             } else {
00424                 tr_error("M2MNsdlInterface::received_from_server_callback - registration_updated failed %d", coap_header->msg_code);
00425                 _registration_timer->stop_timer();
00426                 sn_nsdl_register_endpoint(_nsdl_handle,_endpoint);
00427             }
00428         }
00429 #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE
00430         else if(coap_header->msg_id == nsdl_handle->bootstrap_msg_id) {
00431             tr_debug("M2MNsdlInterface::received_from_server_callback - bootstrap");
00432             _bootstrap_id = 0;
00433             M2MInterface::Error error = interface_error(coap_header);
00434             if(error != M2MInterface::ErrorNone) {
00435                 handle_bootstrap_error();
00436             } else {
00437                 _identity_accepted = true;
00438             }
00439         }
00440 #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE
00441         else {
00442 
00443             sn_coap_hdr_s *coap_response = NULL;
00444             bool execute_value_updated = false;
00445             M2MObjectInstance *obj_instance = NULL;
00446             String resource_name;
00447 
00448             if(COAP_MSG_CODE_REQUEST_PUT == coap_header->msg_code) {
00449                 if (is_bootstrap_msg) {
00450                     handle_bootstrap_put_message(coap_header, address);
00451                 }
00452                 else{
00453                     tr_debug("M2MNsdlInterface::received_from_server_callback - Method not allowed (PUT).");
00454                     coap_response = sn_nsdl_build_response(_nsdl_handle,
00455                                                            coap_header,
00456                                                            COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED);
00457                 }
00458             }
00459             else if(COAP_MSG_CODE_REQUEST_DELETE == coap_header->msg_code) {
00460                 if (is_bootstrap_msg) {
00461                     handle_bootstrap_delete(coap_header, address);
00462                 }
00463                 else{
00464                     tr_debug("M2MNsdlInterface::received_from_server_callback - Method not allowed (DELETE).");
00465                     coap_response = sn_nsdl_build_response(_nsdl_handle,
00466                                                            coap_header,
00467                                                            COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED);
00468                 }
00469             }
00470             else if(COAP_MSG_CODE_REQUEST_POST == coap_header->msg_code) {
00471                 if(is_bootstrap_msg) {
00472                     handle_bootstrap_finished(coap_header, address);
00473                 }
00474                 else if(coap_header->uri_path_ptr) {
00475 
00476                     resource_name = coap_to_string(coap_header->uri_path_ptr,
00477                                                           coap_header->uri_path_len);
00478 
00479                     String object_name;
00480                     int slash_found = resource_name.find_last_of('/');
00481                     //The POST operation here is only allowed for non-existing object instances
00482                     if(slash_found != -1) {
00483                         object_name = resource_name.substr(0,slash_found);
00484                         if( object_name.find_last_of('/') != -1){
00485                             coap_response = sn_nsdl_build_response(_nsdl_handle,
00486                                                                    coap_header,
00487                                                                    COAP_MSG_CODE_RESPONSE_NOT_FOUND);
00488                         } else {
00489                             int32_t instance_id = atoi(resource_name.substr(slash_found+1,
00490                                                      resource_name.size()-object_name.size()).c_str());
00491                             M2MBase* base = find_resource(object_name);
00492                             if(base && (instance_id >= 0) && (instance_id < UINT16_MAX)) {
00493                                 if(coap_header->payload_ptr) {
00494                                     M2MObject* object = static_cast<M2MObject*> (base);
00495                                     obj_instance = object->create_object_instance(instance_id);
00496                                     if(obj_instance) {
00497                                         obj_instance->set_operation(M2MBase::GET_PUT_POST_ALLOWED);
00498                                         coap_response = obj_instance->handle_post_request(_nsdl_handle,
00499                                                                                           coap_header,
00500                                                                                           this,
00501                                                                                           execute_value_updated);
00502                                     }
00503                                     if(coap_response && coap_response->msg_code != COAP_MSG_CODE_RESPONSE_CREATED) {
00504                                         //Invalid request so remove created ObjectInstance
00505                                         object->remove_object_instance(instance_id);
00506                                     } else  {
00507                                         tr_debug("M2MNsdlInterface::received_from_server_callback - Send Update registration for Create");
00508                                         send_update_registration();
00509                                     }
00510                                 } else {
00511                                     tr_debug("M2MNsdlInterface::received_from_server_callback - Missing Payload - Cannot create");
00512                                     coap_response = sn_nsdl_build_response(_nsdl_handle,
00513                                                                            coap_header,
00514                                                                            COAP_MSG_CODE_RESPONSE_BAD_REQUEST);
00515                                 }
00516                             } else { //if(base)
00517                                 tr_debug("M2MNsdlInterface::received_from_server_callback - Missing BASE - Cannot create");
00518                                 coap_response = sn_nsdl_build_response(_nsdl_handle,
00519                                                                        coap_header,
00520                                                                        COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED);
00521                             }
00522                         }
00523                     } else{ // if(slash_found != -1)
00524                         tr_debug("M2MNsdlInterface::received_from_server_callback - slash_found - Cannot create");
00525                         coap_response = sn_nsdl_build_response(_nsdl_handle,
00526                                                                coap_header,
00527                                                                COAP_MSG_CODE_RESPONSE_NOT_FOUND);
00528                     }
00529 
00530                 }
00531             }
00532             else if(COAP_MSG_CODE_EMPTY == coap_header->msg_code) {
00533                 if (COAP_MSG_TYPE_RESET == coap_header->msg_type) {
00534                     // Cancel ongoing observation
00535                     tr_error("M2MNsdlInterface::received_from_server_callback() - RESET message");
00536                     M2MBase *base = find_resource("", coap_header->token_ptr, coap_header->token_len);
00537                     if (base) {
00538                         M2MBase::BaseType type = base->base_type();
00539                         switch (type) {
00540                             case M2MBase::Object:
00541                                 base->remove_observation_level(M2MBase::O_Attribute);
00542                                 break;
00543                             case M2MBase::Resource:
00544                                 base->remove_observation_level(M2MBase::R_Attribute);
00545                                 break;
00546                             case M2MBase::ObjectInstance:
00547                                 base->remove_observation_level(M2MBase::OI_Attribute);
00548                                 break;
00549                             default:
00550                                 break;
00551                         }
00552                         base->set_under_observation(false, this);
00553                     }
00554                 } else {
00555                     tr_debug("M2MNsdlInterface::received_from_server_callback - Empty ACK, msg id: %d", coap_header->msg_id);
00556                     M2MBase *base = find_resource("", coap_header->token_ptr, coap_header->token_len);
00557                     if (base) {
00558                         // Supported only in Resource level
00559                         if (M2MBase::Resource == base->base_type()) {
00560                             M2MResource *resource = static_cast<M2MResource *> (base);
00561                             resource->notification_sent();
00562                         }
00563                     }
00564                 }
00565             }
00566 
00567             if(coap_response) {
00568                 tr_debug("M2MNsdlInterface::received_from_server_callback - send CoAP response");
00569                 (sn_nsdl_send_coap_message(_nsdl_handle, address, coap_response) == 0) ? value = 0 : value = 1;
00570                 sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response);
00571             }
00572 
00573             if (execute_value_updated) {
00574                 value_updated(obj_instance, resource_name);
00575             }
00576 
00577         }
00578     }
00579     return value;
00580 }
00581 
00582 uint8_t M2MNsdlInterface::resource_callback(struct nsdl_s */*nsdl_handle*/,
00583                                             sn_coap_hdr_s *received_coap_header,
00584                                             sn_nsdl_addr_s *address,
00585                                             sn_nsdl_capab_e /*nsdl_capab*/)
00586 {
00587     tr_debug("M2MNsdlInterface::resource_callback()");
00588     _observer.coap_data_processed();
00589     uint8_t result = 1;
00590     sn_coap_hdr_s *coap_response = NULL;
00591     sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 4.00
00592     String resource_name = coap_to_string(received_coap_header->uri_path_ptr,
00593                                           received_coap_header->uri_path_len);
00594     tr_debug("M2MNsdlInterface::resource_callback() - resource_name %s", resource_name.c_str());
00595     bool execute_value_updated = false;
00596     M2MBase* base = find_resource(resource_name);
00597     if(base) {
00598         if(COAP_MSG_CODE_REQUEST_GET == received_coap_header->msg_code) {
00599             coap_response = base->handle_get_request(_nsdl_handle, received_coap_header,this);
00600         } else if(COAP_MSG_CODE_REQUEST_PUT == received_coap_header->msg_code) {
00601             coap_response = base->handle_put_request(_nsdl_handle, received_coap_header, this, execute_value_updated);
00602         } else if(COAP_MSG_CODE_REQUEST_POST == received_coap_header->msg_code) {
00603             if(base->base_type() == M2MBase::ResourceInstance) {
00604                 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
00605             } else {
00606                 coap_response = base->handle_post_request(_nsdl_handle,
00607                                                           received_coap_header,
00608                                                           this,
00609                                                           execute_value_updated,
00610                                                           address);
00611             }
00612         } else if(COAP_MSG_CODE_REQUEST_DELETE == received_coap_header->msg_code) {
00613             // Delete the object instance
00614             tr_debug("M2MNsdlInterface::resource_callback() - DELETE the object instance");
00615             M2MBase::BaseType type = base->base_type();
00616             if(M2MBase::ObjectInstance == type) {
00617                 M2MBase* base_object = find_resource(base->name());
00618                 if(base_object) {
00619                     M2MObject *object = static_cast<M2MObject*> (base_object);
00620                     int slash_found = resource_name.find_last_of('/');
00621                     // Object instance validty checks done in upper level, no need for error handling
00622                     if(slash_found != -1) {
00623                         String object_name;
00624                         object_name = resource_name.substr(slash_found + 1, resource_name.length());
00625                         if (object->remove_object_instance(strtoul(
00626                                 object_name.c_str(),
00627                                 NULL,
00628                                 10))) {
00629                             msg_code = COAP_MSG_CODE_RESPONSE_DELETED;
00630                         }
00631                     }
00632                 }
00633             } else {
00634                 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 4.00
00635             }
00636         }
00637     } else  {
00638         tr_debug("M2MNsdlInterface::resource_callback() - Resource NOT FOUND");
00639         msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 4.00
00640     }
00641     if(!coap_response) {
00642             coap_response = sn_nsdl_build_response(_nsdl_handle,
00643                                                    received_coap_header,
00644                                                    msg_code);
00645     }
00646     if(coap_response &&
00647             coap_response->coap_status != COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING &&
00648             coap_response->msg_code != COAP_MSG_CODE_EMPTY) {
00649 
00650         tr_debug("M2MNsdlInterface::resource_callback() - send CoAP response");
00651         (sn_nsdl_send_coap_message(_nsdl_handle, address, coap_response) == 0) ? result = 0 : result = 1;
00652         if(coap_response->payload_ptr) {
00653             free(coap_response->payload_ptr);
00654             coap_response->payload_ptr = NULL;
00655         }
00656     }
00657     // If the external blockwise storing is enabled call value updated once all the blocks have been received
00658     if (execute_value_updated &&
00659             coap_response &&
00660             coap_response->coap_status != COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING) {
00661         value_updated(base,resource_name);
00662     }
00663 
00664     sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response);
00665     return result;
00666 }
00667 
00668 bool M2MNsdlInterface::process_received_data(uint8_t *data,
00669                                              uint16_t data_size,
00670                                              sn_nsdl_addr_s *address)
00671 {
00672     tr_debug("M2MNsdlInterface::process_received_data( data size %d)", data_size);
00673     return (0 == sn_nsdl_process_coap(_nsdl_handle,
00674                                       data,
00675                                       data_size,
00676                                       address)) ? true : false;
00677 }
00678 
00679 void M2MNsdlInterface::stop_timers()
00680 {
00681     tr_debug("M2MNsdlInterface::stop_timers()");
00682     if(_registration_timer) {
00683         _registration_timer->stop_timer();
00684     }
00685     if (_nsdl_exceution_timer) {
00686         _nsdl_exceution_timer->stop_timer();
00687     }
00688     _bootstrap_id = 0;
00689     _unregister_ongoing = false;
00690 }
00691 
00692 void M2MNsdlInterface::timer_expired(M2MTimerObserver::Type type)
00693 {
00694     if(M2MTimerObserver::NsdlExecution == type) {
00695         sn_nsdl_exec(_nsdl_handle, _counter_for_nsdl);
00696         _counter_for_nsdl++;
00697     } else if(M2MTimerObserver::Registration == type) {
00698         tr_debug("M2MNsdlInterface::timer_expired - M2MTimerObserver::Registration - Send update registration");
00699         send_update_registration();
00700     }
00701 }
00702 
00703 void M2MNsdlInterface::observation_to_be_sent(M2MBase *object,
00704                                               uint16_t obs_number,
00705                                               m2m::Vector<uint16_t> changed_instance_ids,
00706                                               bool send_object)
00707 {
00708     __mutex_claim();
00709     if(object) {
00710         tr_debug("M2MNsdlInterface::observation_to_be_sent()");
00711         M2MBase::BaseType type = object->base_type();
00712         if(type == M2MBase::Object) {
00713             send_object_observation(static_cast<M2MObject*> (object),
00714                                     obs_number,
00715                                     changed_instance_ids,
00716                                     send_object);
00717         } else if(type == M2MBase::ObjectInstance) {
00718             send_object_instance_observation(static_cast<M2MObjectInstance*> (object), obs_number);
00719         } else if(type == M2MBase::Resource) {
00720             send_resource_observation(static_cast<M2MResource*> (object), obs_number);
00721         }
00722     }
00723     __mutex_release();
00724 }
00725 
00726 void M2MNsdlInterface::send_delayed_response(M2MBase *base)
00727 {
00728     __mutex_claim();
00729     tr_debug("M2MNsdlInterface::send_delayed_response()");
00730     M2MResource *resource = NULL;
00731     if(base) {
00732         if(M2MBase::Resource == base->base_type()) {
00733             resource = static_cast<M2MResource *> (base);
00734         }
00735         if(resource) {
00736             sn_coap_hdr_s * coap_response = static_cast<sn_coap_hdr_s *>(malloc(sizeof(sn_coap_hdr_s)));
00737             if(coap_response) {
00738                 memset(coap_response,0,sizeof(sn_coap_hdr_s));
00739 
00740                 coap_response->msg_type = COAP_MSG_TYPE_CONFIRMABLE;
00741                 coap_response->msg_code = COAP_MSG_CODE_RESPONSE_CONTENT;
00742                 resource->get_delayed_token(coap_response->token_ptr,coap_response->token_len);
00743 
00744                 uint32_t length = 0;
00745                 resource->get_value(coap_response->payload_ptr, length);
00746                 coap_response->payload_len = length;
00747 
00748                 sn_nsdl_send_coap_message(_nsdl_handle, _nsdl_handle->nsp_address_ptr->omalw_address_ptr, coap_response);
00749 
00750                 if(coap_response->payload_ptr) {
00751                    free(coap_response->payload_ptr);
00752                    coap_response->payload_ptr = NULL;
00753                 }
00754                 if(coap_response->token_ptr) {
00755                     free(coap_response->token_ptr);
00756                     coap_response->token_ptr = NULL;
00757                 }
00758                 free(coap_response);
00759             }
00760         }
00761     }
00762     __mutex_release();
00763 }
00764 
00765 void M2MNsdlInterface::resource_to_be_deleted(M2MBase *base)
00766 {
00767     __mutex_claim();
00768     remove_nsdl_resource(base);
00769     __mutex_release();
00770 }
00771 
00772 void M2MNsdlInterface::value_updated(M2MBase *base,
00773                                      const String &object_name)
00774 {
00775     tr_debug("M2MNsdlInterface::value_updated()");
00776     if(base) {
00777         switch(base->base_type()) {
00778             case M2MBase::Object:
00779                 create_nsdl_object_structure(static_cast<M2MObject*> (base));
00780             break;
00781             case M2MBase::ObjectInstance:
00782                 create_nsdl_object_instance_structure(static_cast<M2MObjectInstance*> (base));
00783             break;
00784             case M2MBase::Resource: {
00785                     M2MResource* resource = static_cast<M2MResource*> (base);
00786                     create_nsdl_resource_structure(resource,
00787                                                resource->supports_multiple_instances());
00788             }
00789             break;
00790             case M2MBase::ResourceInstance: {
00791                 M2MResourceInstance* instance = static_cast<M2MResourceInstance*> (base);
00792                 create_nsdl_resource(instance);
00793             }
00794             break;
00795         }
00796     }
00797 
00798     if (base && base->is_value_updated_function_set()) {
00799         base->execute_value_updated(base->name());
00800     }
00801     else {
00802         _observer.value_updated(base);
00803     }
00804 }
00805 
00806 void M2MNsdlInterface::remove_object(M2MBase *object)
00807 {
00808     __mutex_claim();
00809     tr_debug("M2MNsdlInterface::remove_object()");
00810     M2MObject* rem_object = static_cast<M2MObject*> (object);
00811     if(rem_object && !_object_list.empty()) {
00812         M2MObjectList::const_iterator it;
00813         it = _object_list.begin();
00814         int index = 0;
00815         for ( ; it != _object_list.end(); it++, index++ ) {
00816             if((*it) == rem_object) {
00817                 _object_list.erase(index);
00818                 break;
00819             }
00820         }
00821     }
00822     if(_object_list.empty()) {
00823         _object_list.clear();
00824     }
00825     __mutex_release();
00826 }
00827 
00828 bool M2MNsdlInterface::create_nsdl_object_structure(M2MObject *object)
00829 {
00830     tr_debug("M2MNsdlInterface::create_nsdl_object_structure()");
00831     bool success = false;
00832     if(object) {
00833         M2MObjectInstanceList instance_list = object->instances();
00834         tr_debug("M2MNsdlInterface::create_nsdl_object_structure - Object Instance count %d", instance_list.size());
00835         if(!instance_list.empty()) {
00836            M2MObjectInstanceList::const_iterator it;
00837            it = instance_list.begin();
00838            for ( ; it != instance_list.end(); it++ ) {
00839                // Create NSDL structure for all object instances inside
00840                success = create_nsdl_object_instance_structure(*it);
00841            }
00842         }
00843     }
00844     if(object && object->operation() != M2MBase::NOT_ALLOWED) {
00845         success = create_nsdl_resource(object);
00846     }
00847     return success;
00848 }
00849 
00850 bool M2MNsdlInterface::create_nsdl_object_instance_structure(M2MObjectInstance *object_instance)
00851 {
00852     tr_debug("M2MNsdlInterface::create_nsdl_object_instance_structure()");
00853     bool success = false;
00854     if( object_instance) {
00855         M2MResourceList res_list = object_instance->resources();
00856         tr_debug("M2MNsdlInterface::create_nsdl_object_instance_structure - ResourceBase count %d", res_list.size());
00857         if(!res_list.empty()) {
00858             M2MResourceList::const_iterator it;
00859             it = res_list.begin();
00860             for ( ; it != res_list.end(); it++ ) {
00861                 // Create NSDL structure for all resources inside
00862                 success = create_nsdl_resource_structure(*it,
00863                                                          (*it)->supports_multiple_instances());
00864             }
00865         }
00866         if(object_instance->operation() != M2MBase::NOT_ALLOWED) {
00867             success = create_nsdl_resource(object_instance);
00868         }
00869     }
00870     return success;
00871 }
00872 
00873 bool M2MNsdlInterface::create_nsdl_resource_structure(M2MResource *res,
00874                                                       bool multiple_instances)
00875 {
00876     tr_debug("M2MNsdlInterface::create_nsdl_resource_structure()");
00877     bool success = false;
00878     if(res) {
00879         // if there are multiple instances supported
00880         if(multiple_instances) {
00881             M2MResourceInstanceList res_list = res->resource_instances();
00882             tr_debug("M2MNsdlInterface::create_nsdl_resource_structure - ResourceInstance count %d", res_list.size());
00883             if(!res_list.empty()) {
00884                 M2MResourceInstanceList::const_iterator it;
00885                 it = res_list.begin();
00886                 for ( ; it != res_list.end(); it++ ) {
00887                     success = create_nsdl_resource((*it));
00888                     if(!success) {
00889                         tr_error("M2MNsdlInterface::create_nsdl_resource_structure - instance creation failed");
00890                         return false;
00891                     }
00892                 }
00893                 // Register the main Resource as well along with ResourceInstances
00894                 success = create_nsdl_resource(res);
00895             }
00896         } else {
00897             success = create_nsdl_resource(res);
00898         }
00899     }
00900     return success;
00901 }
00902 
00903 bool M2MNsdlInterface::create_nsdl_resource(M2MBase *base)
00904 {
00905     __mutex_claim();
00906     tr_debug("M2MNsdlInterface::create_nsdl_resource");
00907     bool success = false;
00908     if(base) {
00909         int8_t result = 0;
00910         sn_nsdl_dynamic_resource_parameters_s* orig_resource = base->get_nsdl_resource();
00911         tr_debug("M2MNsdlInterface::create_nsdl_resource - path (%.*s)", orig_resource->static_resource_parameters->pathlen,
00912                  orig_resource->static_resource_parameters->path);
00913 
00914         // needed on deletion
00915         if (base->observation_handler() == NULL) {
00916             base->set_observation_handler(this);
00917         }
00918 
00919         result = sn_nsdl_put_resource(_nsdl_handle, orig_resource);
00920         tr_debug("M2MNsdlInterface::create_nsdl_resource - Creating in NSDL-C result %d", result);
00921 
00922         // Either the resource is created or it already
00923         // exists , then result is success.
00924         if (result == 0 ||
00925            result == -2){
00926             success = true;
00927         }
00928     }
00929     __mutex_release();
00930     return success;
00931 }
00932 
00933 // convenience method to get the URI from its buffer field...
00934 String M2MNsdlInterface::coap_to_string(uint8_t *coap_data,int coap_data_length)
00935 {
00936     String value = "";
00937     if (coap_data != NULL && coap_data_length > 0) {
00938         value.append_raw((char *)coap_data,coap_data_length);
00939     }
00940     return value;
00941 }
00942 
00943 uint64_t M2MNsdlInterface::registration_time()
00944 {
00945     uint64_t value = 0;
00946     if(_endpoint && _endpoint->lifetime_ptr) {
00947         value = atol((const char*)_endpoint->lifetime_ptr);
00948     }
00949 
00950     if(value >= OPTIMUM_LIFETIME) {
00951         value = value - REDUCE_LIFETIME;
00952     } else {
00953         value = REDUCTION_FACTOR * value;
00954     }
00955     tr_debug("M2MNsdlInterface::registration_time - value (in seconds) %ld", value);
00956     return value;
00957 }
00958 
00959 M2MBase* M2MNsdlInterface::find_resource(const String &object_name,
00960                                          uint8_t *token,
00961                                          uint8_t token_len)
00962 {
00963     tr_debug("M2MNsdlInterface::find_resource(object level) - name (%s)", object_name.c_str());
00964     tr_debug("M2MNsdlInterface::find_resource - token (%.*s)", token_len, token);
00965     M2MBase *object = NULL;
00966     if(!_object_list.empty()) {
00967         M2MObjectList::const_iterator it;
00968         it = _object_list.begin();
00969         for ( ; it != _object_list.end(); it++ ) {
00970             if (token_len == 0) {
00971                 tr_debug("M2MNsdlInterface::find_resource(object level) - path (%s)",
00972                          (char*)(*it)->uri_path());
00973                 if (strcmp((char*)(*it)->uri_path(), object_name.c_str()) == 0) {
00974                     object = (*it);
00975                     tr_debug("M2MNsdlInterface::find_resource(%s) found", object_name.c_str());
00976                     break;
00977                 }
00978             } else {
00979                 uint8_t *stored_token = 0;
00980                 uint32_t stored_token_length = 0;
00981                 (*it)->get_observation_token(stored_token, stored_token_length);
00982                 tr_debug("M2MNsdlInterface::find_resource(object level) - stored token (%.*s)", stored_token_length, stored_token);
00983                 if (stored_token) {
00984                     if (stored_token_length == token_len &&
00985                             memcmp(token, stored_token, token_len) == 0) {
00986                         object = (*it);
00987                         tr_debug("M2MNsdlInterface::find_resource - token found");
00988                         free(stored_token);
00989                         break;
00990                     } else {
00991                         free(stored_token);
00992                     }
00993                 }
00994             }
00995             object = find_resource((*it), object_name, token, token_len);
00996             if(object != NULL) {
00997                 break;
00998             }
00999         }
01000     }
01001     return object;
01002 }
01003 
01004 M2MBase* M2MNsdlInterface::find_resource(const M2MObject *object,
01005                                          const String &object_instance,
01006                                          uint8_t *token,
01007                                          uint8_t token_len)
01008 {
01009     tr_debug("M2MNsdlInterface::find_resource(object instance level) - name (%s)", object_instance.c_str());
01010     M2MBase *instance = NULL;
01011     if(object) {
01012         M2MObjectInstanceList list = object->instances();
01013         if(!list.empty()) {
01014             M2MObjectInstanceList::const_iterator it;
01015             it = list.begin();
01016             for ( ; it != list.end(); it++ ) {
01017                 if (!token) {
01018                     tr_debug("M2MNsdlInterface::find_resource(object instance level) - path (%s)",
01019                              (char*)(*it)->uri_path());
01020                     if(!strcmp((char*)(*it)->uri_path(), object_instance.c_str())){
01021                         instance = (*it);
01022                         break;
01023                     }
01024                 } else {
01025                     uint8_t *stored_token = 0;
01026                     uint32_t stored_token_length = 0;
01027                     tr_debug("M2MNsdlInterface::find_resource(object instance level) - in token (%.*s)", token_len, token);
01028                     (*it)->get_observation_token(stored_token, stored_token_length);
01029                     tr_debug("M2MNsdlInterface::find_resource(object instance level) - stored token (%.*s)", stored_token_length, stored_token);
01030                     if (stored_token) {
01031                         if (stored_token_length == token_len &&
01032                                 memcmp(token, stored_token, token_len) == 0) {
01033                             instance = (*it);
01034                             free(stored_token);
01035                             break;
01036                         } else {
01037                             free(stored_token);
01038                         }
01039                     }
01040                 }
01041                 instance = find_resource((*it),object_instance, token, token_len);
01042                 if(instance != NULL){
01043                     break;
01044                 }
01045             }
01046         }
01047     }
01048     return instance;
01049 }
01050 
01051 M2MBase* M2MNsdlInterface::find_resource(const M2MObjectInstance *object_instance,
01052                                          const String &resource_instance,
01053                                          uint8_t *token,
01054                                          uint8_t token_len)
01055 {
01056     tr_debug("M2MNsdlInterface::find_resource(resource level) - name (%s)", resource_instance.c_str());
01057     M2MBase *instance = NULL;
01058     if(object_instance) {
01059         M2MResourceList list = object_instance->resources();
01060         if(!list.empty()) {
01061             M2MResourceList::const_iterator it;
01062             it = list.begin();
01063             for ( ; it != list.end(); it++ ) {
01064                 if (!token) {
01065                     if(!strcmp((char*)(*it)->uri_path(), resource_instance.c_str())) {
01066                         instance = *it;
01067                         break;
01068                     }
01069                     else if((*it)->supports_multiple_instances()) {
01070                         instance = find_resource((*it), (*it)->uri_path(),
01071                                                  resource_instance, token, token_len);
01072                         if(instance != NULL){
01073                             break;
01074                         }
01075                     }
01076                 } else {
01077                     uint8_t *stored_token = 0;
01078                     uint32_t stored_token_length = 0;
01079                     tr_debug("M2MNsdlInterface::find_resource(resource level) - in token (%.*s)", token_len, token);
01080                     (*it)->get_observation_token(stored_token, stored_token_length);
01081                     tr_debug("M2MNsdlInterface::find_resource(resource level) - stored token (%.*s)", stored_token_length, stored_token);
01082                     if (stored_token) {
01083                         if (stored_token_length == token_len &&
01084                                 memcmp(token, stored_token, token_len) == 0) {
01085                             instance = *it;
01086                             free(stored_token);
01087                             break;
01088                         } else {
01089                             free(stored_token);
01090                         }
01091                     }
01092                 }
01093             }
01094         }
01095     }
01096     return instance;
01097 }
01098 
01099 M2MBase* M2MNsdlInterface::find_resource(const M2MResource *resource,
01100                                          const String &object_name,
01101                                          const String &resource_instance,
01102                                          uint8_t */*token*/,
01103                                          uint8_t /*token_len*/)
01104 {
01105     tr_debug("M2MNsdlInterface::find_resource(resource instance level)");
01106     M2MBase *res = NULL;
01107     if(resource) {
01108         if(resource->supports_multiple_instances()) {
01109             M2MResourceInstanceList list = resource->resource_instances();
01110             if(!list.empty()) {
01111                 M2MResourceInstanceList::const_iterator it;
01112                 it = list.begin();
01113                 for ( ; it != list.end(); it++ ) {
01114                     if(!strcmp((char*)(*it)->uri_path(), resource_instance.c_str())){
01115                         res = (*it);
01116                         break;
01117                     }
01118                 }
01119             }
01120         }
01121     }
01122     return res;
01123 }
01124 
01125 bool M2MNsdlInterface::object_present(M2MObject* object) const
01126 {
01127     bool success = false;
01128     if(object && !_object_list.empty()) {
01129         M2MObjectList::const_iterator it;
01130         it = _object_list.begin();
01131         for ( ; it != _object_list.end(); it++ ) {
01132             if((*it) == object) {
01133                 success = true;
01134                 break;
01135             }
01136         }
01137     }
01138     return success;
01139 }
01140 
01141 bool M2MNsdlInterface::add_object_to_list(M2MObject* object)
01142 {
01143     bool success = false;
01144     if(object && !object_present(object)) {
01145         _object_list.push_back(object);
01146         success = true;
01147     }
01148     return success;
01149 }
01150 
01151 M2MInterface::Error M2MNsdlInterface::interface_error(sn_coap_hdr_s *coap_header)
01152 {
01153     M2MInterface::Error error = M2MInterface::ErrorNone;
01154     if(coap_header) {
01155         switch(coap_header->msg_code) {
01156             case COAP_MSG_CODE_RESPONSE_BAD_REQUEST:
01157             case COAP_MSG_CODE_RESPONSE_BAD_OPTION:
01158             case COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_INCOMPLETE:
01159             case COAP_MSG_CODE_RESPONSE_PRECONDITION_FAILED:
01160             case COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE:
01161             case COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT:
01162                 error = M2MInterface::InvalidParameters;
01163                 break;
01164             case COAP_MSG_CODE_RESPONSE_UNAUTHORIZED:
01165             case COAP_MSG_CODE_RESPONSE_FORBIDDEN:
01166             case COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE:
01167             case COAP_MSG_CODE_RESPONSE_NOT_FOUND:
01168             case COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED:
01169                 error = M2MInterface::NotAllowed;
01170                 break;
01171             case COAP_MSG_CODE_RESPONSE_CREATED:
01172             case COAP_MSG_CODE_RESPONSE_DELETED:
01173             case COAP_MSG_CODE_RESPONSE_VALID:
01174             case COAP_MSG_CODE_RESPONSE_CHANGED:
01175             case COAP_MSG_CODE_RESPONSE_CONTENT:
01176                 error = M2MInterface::ErrorNone;
01177                 break;
01178             default:
01179                 error = M2MInterface::UnknownError;
01180                 break;
01181         }
01182         if(coap_header->coap_status == COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED) {
01183             error = M2MInterface::NetworkError;
01184         }
01185     }
01186     return error;
01187 }
01188 
01189 void M2MNsdlInterface::send_object_observation(M2MObject *object,
01190                                                uint16_t obs_number,
01191                                                m2m::Vector<uint16_t> changed_instance_ids,
01192                                                bool send_object)
01193 {
01194     tr_debug("M2MNsdlInterface::send_object_observation");
01195     if(object) {
01196         uint8_t *value = 0;
01197         uint32_t length = 0;
01198         uint8_t *token = 0;
01199         uint32_t token_length = 0;
01200 
01201         M2MTLVSerializer serializer;
01202         // Send whole object structure
01203         if (send_object) {
01204             value = serializer.serialize(object->instances(), length);
01205         }
01206         // Send only changed object instances
01207         else {
01208             M2MObjectInstanceList list;
01209             Vector<uint16_t>::const_iterator it;
01210             it = changed_instance_ids.begin();
01211             for (; it != changed_instance_ids.end(); it++){
01212                 M2MObjectInstance* obj_instance = object->object_instance(*it);
01213                 if (obj_instance){
01214                     list.push_back(obj_instance);
01215                 }
01216             }
01217             if (!list.empty()) {
01218                 value = serializer.serialize(list, length);
01219                 list.clear();
01220             }
01221         }
01222 
01223         object->get_observation_token(token,token_length);
01224 
01225         send_notification(token,
01226                           token_length,
01227                           value,
01228                           length,
01229                           obs_number,
01230                           object->max_age(),
01231                           object->coap_content_type());
01232         memory_free(value);
01233         memory_free(token);
01234     }
01235 }
01236 
01237 void M2MNsdlInterface::send_object_instance_observation(M2MObjectInstance *object_instance,
01238                                                         uint16_t obs_number)
01239 {
01240     tr_debug("M2MNsdlInterface::send_object_instance_observation");
01241     if(object_instance) {
01242         uint8_t *value = 0;
01243         uint32_t length = 0;
01244         uint8_t *token = 0;
01245         uint32_t token_length = 0;
01246 
01247         M2MTLVSerializer serializer;
01248         value = serializer.serialize(object_instance->resources(), length);
01249 
01250         object_instance->get_observation_token(token,token_length);
01251 
01252         send_notification(token,
01253                           token_length,
01254                           value,
01255                           length,
01256                           obs_number,
01257                           object_instance->max_age(),
01258                           object_instance->coap_content_type());
01259         memory_free(value);
01260         memory_free(token);
01261     }
01262 }
01263 
01264 void M2MNsdlInterface::send_resource_observation(M2MResource *resource,
01265                                                  uint16_t obs_number)
01266 {
01267     tr_debug("M2MNsdlInterface::send_resource_observation");
01268     if(resource) {
01269         uint8_t *value = 0;
01270         uint32_t length = 0;
01271         uint8_t *token = 0;
01272         uint32_t token_length = 0;
01273 
01274         resource->get_observation_token(token,token_length);
01275         uint8_t content_type = 0;
01276         if(M2MResourceInstance::OPAQUE == resource->resource_instance_type()) {
01277             content_type = COAP_CONTENT_OMA_OPAQUE_TYPE;
01278         }
01279         if (resource->resource_instance_count() > 0) {
01280             content_type = COAP_CONTENT_OMA_TLV_TYPE;
01281             M2MTLVSerializer serializer;
01282             value = serializer.serialize(resource, length);
01283         } else {
01284             resource->get_value(value,length);
01285         }
01286         send_notification(token,
01287                           token_length,
01288                           value,
01289                           length,
01290                           obs_number,
01291                           resource->max_age(),
01292                           content_type);
01293 
01294         memory_free(value);
01295         memory_free(token);
01296     }
01297 }
01298 
01299 void M2MNsdlInterface::send_notification(uint8_t *token,
01300                                          uint8_t  token_length,
01301                                          uint8_t *value,
01302                                          uint32_t value_length,
01303                                          uint16_t observation,
01304                                          uint32_t max_age,
01305                                          uint8_t  coap_content_type)
01306 
01307 {
01308     tr_debug("M2MNsdlInterface::send_notification");
01309     sn_coap_hdr_s *notification_message_ptr;
01310 
01311     /* Allocate and initialize memory for header struct */
01312     notification_message_ptr = static_cast<sn_coap_hdr_s *>(memory_alloc(sizeof(sn_coap_hdr_s)));
01313     if (notification_message_ptr) {
01314         memset(notification_message_ptr, 0, sizeof(sn_coap_hdr_s));
01315 
01316         notification_message_ptr->options_list_ptr = sn_nsdl_alloc_options_list(_nsdl_handle, notification_message_ptr);
01317         if (notification_message_ptr->options_list_ptr) {
01318             /* Fill header */
01319             notification_message_ptr->msg_type = COAP_MSG_TYPE_CONFIRMABLE;
01320             notification_message_ptr->msg_code = COAP_MSG_CODE_RESPONSE_CONTENT;
01321 
01322             /* Fill token */
01323             notification_message_ptr->token_len = token_length;
01324             notification_message_ptr->token_ptr = token;
01325 
01326             /* Fill payload */
01327             notification_message_ptr->payload_len = value_length;
01328             notification_message_ptr->payload_ptr = value;
01329 
01330             /* Fill observe */
01331             notification_message_ptr->options_list_ptr->observe = observation;
01332 
01333             notification_message_ptr->options_list_ptr->max_age = max_age;
01334 
01335             notification_message_ptr->content_format = sn_coap_content_format_e(coap_content_type);
01336 
01337             /* Send message */
01338             sn_nsdl_send_coap_message(_nsdl_handle,
01339                                       _nsdl_handle->nsp_address_ptr->omalw_address_ptr,
01340                                       notification_message_ptr);
01341 
01342             /* Free memory */
01343             notification_message_ptr->payload_ptr = NULL;
01344             notification_message_ptr->options_list_ptr->observe = -1;
01345             notification_message_ptr->token_ptr = NULL;
01346         }
01347         sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, notification_message_ptr);
01348     }
01349 }
01350 
01351 nsdl_s * M2MNsdlInterface::get_nsdl_handle()
01352 {
01353     return _nsdl_handle;
01354 }
01355 
01356 void M2MNsdlInterface::handle_bootstrap_put_message(sn_coap_hdr_s *coap_header,
01357                                                 sn_nsdl_addr_s *address) {
01358 #ifndef M2M_CLIENT_DISABLE_BOOTSTRAP_FEATURE
01359     tr_debug("M2MNsdlInterface::handle_bootstrap_message");
01360     uint8_t response_code = COAP_MSG_CODE_RESPONSE_CHANGED;
01361     sn_coap_hdr_s *coap_response = NULL;
01362     bool success = false;
01363     bool security_object = false;
01364     uint16_t content_type = 0;
01365 
01366     if (!_security) {
01367         _security = new M2MSecurity(M2MSecurity::M2MServer);
01368     }
01369 
01370     String resource_name = coap_to_string(coap_header->uri_path_ptr,
01371                                           coap_header->uri_path_len);
01372     tr_debug("M2MNsdlInterface::handle_bootstrap_message - uri %s", resource_name.c_str());
01373 
01374     // Check incoming object
01375     if (resource_name.compare(0,1,"0") == 0) {
01376         security_object = true;
01377         if(_security) {
01378             success = true;
01379             // Not mandatory resource that's why it must be created first
01380             _security->create_resource(M2MSecurity::ShortServerID, 1);
01381             // Change operation mode
01382             M2MResourceList list = _security->object_instance()->resources();
01383             if(!list.empty()) {
01384                 M2MResourceList::const_iterator it;
01385                 it = list.begin();
01386                 for ( ; it != list.end(); it++ ) {
01387                     (*it)->set_operation(M2MBase::PUT_ALLOWED);
01388                 }
01389             }
01390         }
01391     }
01392     else if (resource_name.compare(0,1,"1") == 0) {
01393         success = true;
01394     }
01395 
01396     if (success) {
01397         // Send delayed response if token is part of the message
01398         if (coap_header->token_ptr) {
01399             tr_debug("M2MNsdlInterface::handle_bootstrap_message - send delayed response");
01400             coap_response = sn_nsdl_build_response(_nsdl_handle,
01401                                                    coap_header,
01402                                                    COAP_MSG_CODE_EMPTY);
01403             if (coap_response) {
01404                 coap_response->msg_type = COAP_MSG_TYPE_ACKNOWLEDGEMENT;
01405                 sn_nsdl_send_coap_message(_nsdl_handle, address, coap_response);
01406                 sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response);
01407             }
01408         }
01409 
01410         if(coap_header->content_format != COAP_CT_NONE) {
01411             content_type = coap_header->content_format;
01412         }
01413 
01414         tr_debug("M2MNsdlInterface::handle_bootstrap_message - content_type %d", content_type);
01415         if (content_type != COAP_CONTENT_OMA_TLV_TYPE) {
01416             success = false;
01417         }
01418         if (success) {
01419             success = parse_bootstrap_message(coap_header, security_object);
01420             // Set operation back to default ones
01421             if (_security) {
01422                 M2MResourceList list = _security->object_instance()->resources();
01423                 if(!list.empty()) {
01424                     M2MResourceList::const_iterator it;
01425                     it = list.begin();
01426                     for ( ; it != list.end(); it++ ) {
01427                         (*it)->set_operation(M2MBase::NOT_ALLOWED);
01428                     }
01429                 }
01430             }
01431         }
01432     }
01433 
01434     if (!success) {
01435         response_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
01436         handle_bootstrap_error();
01437     }
01438     coap_response = sn_nsdl_build_response(_nsdl_handle,
01439                                            coap_header,
01440                                            response_code);
01441     if (coap_response) {
01442         sn_nsdl_send_coap_message(_nsdl_handle, address, coap_response);
01443         sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response);
01444     }
01445 #else
01446     (void) coap_header;
01447     (void) address;
01448 #endif
01449 }
01450 
01451 bool M2MNsdlInterface::parse_bootstrap_message(sn_coap_hdr_s *coap_header, bool is_security_object)
01452 {
01453 #ifndef M2M_CLIENT_DISABLE_BOOTSTRAP_FEATURE
01454     tr_debug("M2MNsdlInterface::parse_bootstrap_put_message");
01455     bool ret = false;
01456     bool is_obj_instance = false;
01457     uint16_t instance_id = 0;
01458     if (_security) {
01459         // Actually there are no member variables on the M2MTLVDeserializer so all the methods
01460         // could be converted to static ones.
01461         M2MTLVDeserializer deserializer;
01462 
01463         ret = is_obj_instance = deserializer.is_object_instance(coap_header->payload_ptr);
01464         if (!is_obj_instance) {
01465             ret = deserializer.is_resource(coap_header->payload_ptr);
01466         }
01467 
01468         if (ret) {
01469             M2MTLVDeserializer::Error error = M2MTLVDeserializer::None;
01470             if (is_obj_instance) {
01471                 if (is_security_object) {
01472                     error = deserializer.deserialise_object_instances(coap_header->payload_ptr,
01473                                                                coap_header->payload_len,
01474                                                                *_security,
01475                                                                M2MTLVDeserializer::Put);
01476                     }
01477                 else {
01478                     error = deserializer.deserialise_object_instances(coap_header->payload_ptr,
01479                                                                coap_header->payload_len,
01480                                                                _server,
01481                                                                M2MTLVDeserializer::Put);
01482                 }
01483             }
01484             else {
01485                 if (is_security_object) {
01486                     instance_id = deserializer.instance_id(coap_header->payload_ptr);
01487                     error = deserializer.deserialize_resources(coap_header->payload_ptr,
01488                                                                coap_header->payload_len,
01489                                                                *_security->object_instance(instance_id),
01490                                                                M2MTLVDeserializer::Put);
01491                 }
01492                 else {
01493                     instance_id = deserializer.instance_id(coap_header->payload_ptr);
01494                     error = deserializer.deserialize_resources(coap_header->payload_ptr,
01495                                                                coap_header->payload_len,
01496                                                                *(_server.object_instance(instance_id)),
01497                                                                M2MTLVDeserializer::Post);
01498                 }
01499             }
01500 
01501             if (error != M2MTLVDeserializer::None) {
01502                 tr_error("M2MNsdlInterface::parse_bootstrap_put_message - error %d", error);
01503                 ret = false;
01504             }
01505         }
01506     }
01507     return ret;
01508 #else
01509     (void) coap_header;
01510     (void) is_security_object;
01511     return false;
01512 #endif
01513 }
01514 
01515 void M2MNsdlInterface::handle_bootstrap_finished(sn_coap_hdr_s *coap_header,sn_nsdl_addr_s *address)
01516 {
01517 #ifndef M2M_CLIENT_DISABLE_BOOTSTRAP_FEATURE
01518     String object_name = coap_to_string(coap_header->uri_path_ptr,
01519                                           coap_header->uri_path_len);
01520     tr_debug("M2MNsdlInterface::handle_bootstrap_finished - path: %s", object_name.c_str());
01521     sn_coap_hdr_s *coap_response = NULL;
01522     uint8_t msg_code = COAP_MSG_CODE_RESPONSE_CHANGED;
01523 
01524     // Accept only '/bs' path and check that needed data is in security object
01525     if (object_name.size() != 2 ||
01526             object_name.compare(0,2,BOOTSTRAP_URI) != 0 ||
01527             !validate_security_object()) {
01528         msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
01529     } else {
01530         // Add short server id to server object
01531         _server.set_resource_value(M2MServer::ShortServerID,
01532                                     _security->resource_value_int(M2MSecurity::ShortServerID));
01533     }
01534 
01535     coap_response = sn_nsdl_build_response(_nsdl_handle,
01536                                            coap_header,
01537                                            msg_code);
01538     if(coap_response) {
01539         sn_nsdl_send_coap_message(_nsdl_handle, address, coap_response);
01540         sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response);
01541     }
01542     if (COAP_MSG_CODE_RESPONSE_CHANGED == msg_code) {
01543         // Switch back to original ep name
01544         if (_endpoint->endpoint_name_ptr) {
01545             memory_free(_endpoint->endpoint_name_ptr);
01546         }
01547         _endpoint->endpoint_name_ptr = alloc_string_copy((uint8_t*)_endpoint_name.c_str(), _endpoint_name.length());
01548         _endpoint->endpoint_name_len = _endpoint_name.length();
01549         // Inform observer that bootstrap is finished but it should wait until nsdl has sent data.
01550         // The final bootstrap_done callback is called in the observers data_sent callback.
01551         _observer.bootstrap_wait(_security);
01552     } else {
01553         handle_bootstrap_error();
01554     }
01555 #else
01556     (void) coap_header;
01557     (void) address;
01558 #endif
01559 }
01560 
01561 void M2MNsdlInterface::handle_bootstrap_delete(sn_coap_hdr_s *coap_header,sn_nsdl_addr_s *address)
01562 {
01563 #ifndef M2M_CLIENT_DISABLE_BOOTSTRAP_FEATURE
01564     sn_coap_hdr_s *coap_response = NULL;
01565     uint8_t msg_code = COAP_MSG_CODE_RESPONSE_DELETED;
01566     String object_name = coap_to_string(coap_header->uri_path_ptr,
01567                                           coap_header->uri_path_len);
01568     tr_debug("M2MNsdlInterface::handle_bootstrap_delete - obj %s", object_name.c_str());
01569     if(!_identity_accepted) {
01570         msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
01571     }
01572     // Only following paths are accepted, 0, 0/0
01573     else if (object_name.size() == 2 || object_name.size() > 3) {
01574         msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
01575     }
01576     else if ((object_name.size() == 1 && object_name.compare(0,1,"0") != 0) ||
01577             (object_name.size() == 3 && object_name.compare(0,3,"0/0") != 0)) {
01578         msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
01579     }
01580 
01581     coap_response = sn_nsdl_build_response(_nsdl_handle,
01582                                            coap_header,
01583                                            msg_code);
01584 
01585     if(coap_response) {
01586         sn_nsdl_send_coap_message(_nsdl_handle, address, coap_response);
01587         sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response);
01588         if(_security) {
01589             _security->clear_resources();
01590         }
01591     }
01592     if (!coap_response || COAP_MSG_CODE_RESPONSE_DELETED != msg_code) {
01593         handle_bootstrap_error();
01594     }
01595 #else
01596     (void) coap_header;
01597     (void) address;
01598 #endif
01599 }
01600 
01601 bool M2MNsdlInterface::validate_security_object()
01602 {
01603 #ifndef M2M_CLIENT_DISABLE_BOOTSTRAP_FEATURE
01604     tr_debug("M2MNsdlInterface::validate_security_object");
01605     if (_security) {
01606         String address = _security->resource_value_string(M2MSecurity::M2MServerUri);
01607         uint32_t sec_mode = _security->resource_value_int(M2MSecurity::SecurityMode);
01608         bool is_bs_server = _security->resource_value_int(M2MSecurity::BootstrapServer);
01609         uint32_t public_key_size = _security->get_resource(M2MSecurity::PublicKey)->value_length();
01610         uint32_t server_key_size = _security->get_resource(M2MSecurity::ServerPublicKey)->value_length();
01611         uint32_t pkey_size = _security->get_resource(M2MSecurity::Secretkey)->value_length();
01612         tr_debug("M2MNsdlInterface::validate_security_object - Server URI /0/0: %s", address.c_str());
01613         tr_debug("M2MNsdlInterface::validate_security_object - is bs server /0/1: %d", is_bs_server);
01614         tr_debug("M2MNsdlInterface::validate_security_object - Security Mode /0/2: %" PRIu32, sec_mode);
01615         tr_debug("M2MNsdlInterface::validate_security_object - Public key size /0/3: %" PRIu32, public_key_size);
01616         tr_debug("M2MNsdlInterface::validate_security_object - Server Public key size /0/4: %" PRIu32, server_key_size);
01617         tr_debug("M2MNsdlInterface::validate_security_object - Secret key size /0/5: %" PRIu32, pkey_size);
01618         // Only NoSec and Certificate modes are supported
01619         if (!address.empty() && !is_bs_server) {
01620             if (M2MSecurity::Certificate == sec_mode) {
01621                 if (!public_key_size || !server_key_size || !pkey_size) {
01622                     return false;
01623                 } else {
01624                     return true;
01625                 }
01626             } else if (M2MSecurity::NoSecurity == sec_mode){
01627                 return true;
01628             } else {
01629                 return false;
01630             }
01631         } else {
01632             return false;
01633         }
01634     }
01635     return false;
01636 #else
01637     return false;
01638 #endif
01639 }
01640 
01641 void M2MNsdlInterface::handle_bootstrap_error()
01642 {
01643     tr_debug("M2MNsdlInterface::handle_bootstrap_error()");
01644     _identity_accepted = false;
01645     if (_security) {
01646         delete _security;
01647         _security = NULL;
01648     }
01649     _observer.bootstrap_error();
01650 }
01651 
01652 const String& M2MNsdlInterface::endpoint_name() const
01653 {
01654     return _endpoint_name;
01655 }