Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
m2mbase.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 #include "mbed-client/m2mbase.h" 00018 #include "mbed-client/m2mobservationhandler.h" 00019 #include "mbed-client/m2mconstants.h" 00020 #include "mbed-client/m2mtimer.h" 00021 00022 #include "mbed-client/m2mendpoint.h" 00023 #include "mbed-client/m2mobject.h" 00024 #include "mbed-client/m2mobjectinstance.h" 00025 #include "mbed-client/m2mresource.h" 00026 00027 #include "include/m2mreporthandler.h" 00028 #include "include/nsdlaccesshelper.h" 00029 #include "include/m2mcallbackstorage.h" 00030 #include "mbed-trace/mbed_trace.h" 00031 00032 #include "sn_nsdl_lib.h" 00033 #include <assert.h> 00034 #include <ctype.h> 00035 #include <string.h> 00036 #include <stdlib.h> 00037 #include "common_functions.h" 00038 00039 #define TRACE_GROUP "mClt" 00040 00041 M2MBase::M2MBase(const String& resource_name, 00042 M2MBase::Mode mode, 00043 #ifndef DISABLE_RESOURCE_TYPE 00044 const String &resource_type, 00045 #endif 00046 char *path, 00047 bool external_blockwise_store, 00048 bool multiple_instance, 00049 M2MBase::DataType type) 00050 : 00051 _sn_resource(NULL), 00052 _report_handler(NULL) 00053 { 00054 // Checking the name length properly, i.e returning error is impossible from constructor without exceptions 00055 assert(resource_name.length() <= MAX_ALLOWED_STRING_LENGTH); 00056 00057 _sn_resource = (lwm2m_parameters_s*)memory_alloc(sizeof(lwm2m_parameters_s)); 00058 if(_sn_resource) { 00059 memset(_sn_resource, 0, sizeof(lwm2m_parameters_s)); 00060 _sn_resource->free_on_delete = true; 00061 _sn_resource->multiple_instance = multiple_instance; 00062 _sn_resource->data_type = type; 00063 _sn_resource->read_write_callback_set = false; 00064 _sn_resource->dynamic_resource_params = 00065 (sn_nsdl_dynamic_resource_parameters_s*)memory_alloc(sizeof(sn_nsdl_dynamic_resource_parameters_s)); 00066 if(_sn_resource->dynamic_resource_params) { 00067 memset(_sn_resource->dynamic_resource_params, 00068 0, sizeof(sn_nsdl_dynamic_resource_parameters_s)); 00069 _sn_resource->dynamic_resource_params->static_resource_parameters = 00070 (sn_nsdl_static_resource_parameters_s*)memory_alloc(sizeof(sn_nsdl_static_resource_parameters_s)); 00071 00072 // Set callback function in case of both dynamic and static resource 00073 _sn_resource->dynamic_resource_params->sn_grs_dyn_res_callback = __nsdl_c_callback; 00074 00075 if(_sn_resource->dynamic_resource_params->static_resource_parameters) { 00076 // Cast const away to able to compile using MEMORY_OPTIMIZED_API flag 00077 sn_nsdl_static_resource_parameters_s *params = 00078 const_cast<sn_nsdl_static_resource_parameters_s *>(_sn_resource->dynamic_resource_params->static_resource_parameters); 00079 memset(params, 0, sizeof(sn_nsdl_static_resource_parameters_s)); 00080 const size_t len = strlen(resource_type.c_str()); 00081 params->free_on_delete = true; 00082 if (len > 0) { 00083 #ifndef RESOURCE_ATTRIBUTES_LIST 00084 #ifndef DISABLE_RESOURCE_TYPE 00085 params->resource_type_ptr = (char*)alloc_string_copy((uint8_t*) resource_type.c_str(), len); 00086 #endif 00087 #else 00088 sn_nsdl_attribute_item_s item; 00089 item.attribute_name = ATTR_RESOURCE_TYPE; 00090 item.value = (char*)alloc_string_copy((uint8_t*) resource_type.c_str(), len); 00091 sn_nsdl_set_resource_attribute(_sn_resource->dynamic_resource_params->static_resource_parameters, &item); 00092 #endif 00093 } 00094 params->path = path; 00095 params->mode = (unsigned)mode; 00096 params->external_memory_block = external_blockwise_store; 00097 _sn_resource->dynamic_resource_params->static_resource_parameters = params; 00098 } 00099 } 00100 00101 if((!resource_name.empty())) { 00102 _sn_resource->identifier_int_type = false; 00103 _sn_resource->identifier.name = stringdup((char*)resource_name.c_str()); 00104 } else { 00105 tr_debug("M2MBase::M2Mbase resource name is EMPTY ==========="); 00106 _sn_resource->identifier_int_type = true; 00107 _sn_resource->identifier.instance_id = 0; 00108 } 00109 _sn_resource->dynamic_resource_params->publish_uri = true; 00110 _sn_resource->dynamic_resource_params->free_on_delete = true; 00111 _sn_resource->dynamic_resource_params->auto_observable = false; 00112 _sn_resource->dynamic_resource_params->publish_value = false; 00113 } 00114 } 00115 00116 M2MBase::M2MBase(const lwm2m_parameters_s *s): 00117 _sn_resource((lwm2m_parameters_s*) s), 00118 _report_handler(NULL) 00119 { 00120 tr_debug("M2MBase::M2MBase(const lwm2m_parameters_s *s)"); 00121 // Set callback function in case of both dynamic and static resource 00122 _sn_resource->dynamic_resource_params->sn_grs_dyn_res_callback = __nsdl_c_callback; 00123 } 00124 00125 M2MBase::~M2MBase() 00126 { 00127 tr_debug("M2MBase::~M2MBase() %p", this); 00128 delete _report_handler; 00129 00130 value_updated_callback* callback = (value_updated_callback*)M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback); 00131 delete callback; 00132 00133 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback2); 00134 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MBaseNotificationDeliveryStatusCallback); 00135 #ifdef ENABLE_ASYNC_REST_RESPONSE 00136 M2MCallbackStorage::remove_callback(*this,M2MCallbackAssociation::M2MBaseAsyncCoapRequestCallback); 00137 #endif 00138 } 00139 00140 char* M2MBase::create_path_base(const M2MBase &parent, const char *name) 00141 { 00142 char * result = NULL; 00143 // Expectation is that every element can be MAX_NAME_SZE, + 4 /'s + \0 00144 StringBuffer<(MAX_NAME_SIZE * 4 + (4 + 1))> path; 00145 path.append(parent.uri_path()); 00146 path.append('/'); 00147 path.append(name); 00148 result = stringdup(path.c_str()); 00149 00150 return result; 00151 } 00152 00153 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 00154 char* M2MBase::create_path(const M2MEndpoint &parent, const char *name) 00155 { 00156 return create_path_base(parent, name); 00157 } 00158 #endif 00159 00160 char* M2MBase::create_path(const M2MObject &parent, uint16_t object_instance) 00161 { 00162 StringBuffer<6> obj_inst_id; 00163 obj_inst_id.append_int(object_instance); 00164 00165 return create_path_base(parent, obj_inst_id.c_str()); 00166 } 00167 00168 char* M2MBase::create_path(const M2MObject &parent, const char *name) 00169 { 00170 return create_path_base(parent, name); 00171 } 00172 00173 char* M2MBase::create_path(const M2MResource &parent, uint16_t resource_instance) 00174 { 00175 StringBuffer<6> res_inst; 00176 res_inst.append_int(resource_instance); 00177 00178 return create_path_base(parent, res_inst.c_str()); 00179 } 00180 00181 char* M2MBase::create_path(const M2MResource &parent, const char *name) 00182 { 00183 return create_path_base(parent, name); 00184 } 00185 00186 char* M2MBase::create_path(const M2MObjectInstance &parent, const char *name) 00187 { 00188 return create_path_base(parent, name); 00189 } 00190 00191 void M2MBase::set_operation(M2MBase::Operation opr) 00192 { 00193 // If the mode is Static, there is only GET_ALLOWED supported. 00194 if(M2MBase::Static == mode()) { 00195 _sn_resource->dynamic_resource_params->access = M2MBase::GET_ALLOWED; 00196 } else { 00197 _sn_resource->dynamic_resource_params->access = opr; 00198 } 00199 } 00200 00201 #ifndef RESOURCE_ATTRIBUTES_LIST 00202 #ifndef MEMORY_OPTIMIZED_API 00203 #ifndef DISABLE_INTERFACE_DESCRIPTION 00204 void M2MBase::set_interface_description(const char *desc) 00205 { 00206 assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete); 00207 free(_sn_resource->dynamic_resource_params->static_resource_parameters->interface_description_ptr); 00208 _sn_resource->dynamic_resource_params->static_resource_parameters->interface_description_ptr = NULL; 00209 const size_t len = strlen(desc); 00210 if (len > 0 ) { 00211 _sn_resource->dynamic_resource_params->static_resource_parameters->interface_description_ptr = 00212 (char*)alloc_string_copy((uint8_t*) desc, len); 00213 } 00214 set_changed(); 00215 } 00216 00217 void M2MBase::set_interface_description(const String &desc) 00218 { 00219 assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete); 00220 set_interface_description(desc.c_str()); 00221 } 00222 #endif // DISABLE_INTERFACE_DESCRIPTION 00223 00224 #ifndef DISABLE_RESOURCE_TYPE 00225 void M2MBase::set_resource_type(const String &res_type) 00226 { 00227 assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete); 00228 set_resource_type(res_type.c_str()); 00229 } 00230 00231 void M2MBase::set_resource_type(const char *res_type) 00232 { 00233 assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete); 00234 free(_sn_resource->dynamic_resource_params->static_resource_parameters->resource_type_ptr); 00235 _sn_resource->dynamic_resource_params->static_resource_parameters->resource_type_ptr = NULL; 00236 const size_t len = strlen(res_type); 00237 if (len > 0) { 00238 _sn_resource->dynamic_resource_params->static_resource_parameters->resource_type_ptr = (char*) 00239 alloc_string_copy((uint8_t*) res_type, len); 00240 } 00241 set_changed(); 00242 } 00243 #endif // DISABLE_RESOURCE_TYPE 00244 #endif //MEMORY_OPTIMIZED_API 00245 #else // RESOURCE_ATTRIBUTES_LIST 00246 void M2MBase::set_interface_description(const char *desc) 00247 { 00248 assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete); 00249 const size_t len = strlen(desc); 00250 if (len > 0 ) { 00251 sn_nsdl_attribute_item_s item; 00252 item.attribute_name = ATTR_INTERFACE_DESCRIPTION; 00253 item.value = (char*)alloc_string_copy((uint8_t*) desc, len); 00254 sn_nsdl_set_resource_attribute(_sn_resource->dynamic_resource_params->static_resource_parameters, &item); 00255 set_changed(); 00256 } 00257 } 00258 00259 void M2MBase::set_interface_description(const String &desc) 00260 { 00261 assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete); 00262 set_interface_description(desc.c_str()); 00263 } 00264 00265 void M2MBase::set_resource_type(const String &res_type) 00266 { 00267 assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete); 00268 set_resource_type(res_type.c_str()); 00269 } 00270 00271 void M2MBase::set_resource_type(const char *res_type) 00272 { 00273 assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete); 00274 const size_t len = strlen(res_type); 00275 if (len > 0) { 00276 sn_nsdl_attribute_item_s item; 00277 item.attribute_name = ATTR_RESOURCE_TYPE; 00278 item.value = (char*)alloc_string_copy((uint8_t*) res_type, len); 00279 sn_nsdl_set_resource_attribute(_sn_resource->dynamic_resource_params->static_resource_parameters, &item); 00280 set_changed(); 00281 } 00282 } 00283 #endif // RESOURCE_ATTRIBUTES_LIST 00284 00285 void M2MBase::set_coap_content_type(const uint16_t con_type) 00286 { 00287 _sn_resource->dynamic_resource_params->coap_content_type = con_type; 00288 set_changed(); 00289 } 00290 00291 void M2MBase::set_observable(bool observable) 00292 { 00293 _sn_resource->dynamic_resource_params->observable = observable; 00294 set_changed(); 00295 } 00296 00297 void M2MBase::set_auto_observable(bool auto_observable) 00298 { 00299 _sn_resource->dynamic_resource_params->auto_observable = auto_observable; 00300 set_changed(); 00301 } 00302 00303 void M2MBase::add_observation_level(M2MBase::Observation obs_level) 00304 { 00305 if(_report_handler) { 00306 _report_handler->add_observation_level(obs_level); 00307 } 00308 } 00309 00310 void M2MBase::remove_observation_level(M2MBase::Observation obs_level) 00311 { 00312 if(_report_handler) { 00313 _report_handler->remove_observation_level(obs_level); 00314 } 00315 } 00316 00317 00318 void M2MBase::set_under_observation(bool observed, 00319 M2MObservationHandler *handler) 00320 { 00321 tr_debug("M2MBase::set_under_observation - observed: %d", observed); 00322 tr_debug("M2MBase::set_under_observation - base_type: %d", base_type()); 00323 if(_report_handler) { 00324 _report_handler->set_under_observation(observed); 00325 } 00326 00327 set_observation_handler(handler); 00328 00329 if (handler) { 00330 if (base_type() != M2MBase::ResourceInstance) { 00331 // Create report handler only if it does not exist and one wants observation 00332 // This saves 76 bytes of memory on most usual case. 00333 if (observed) { 00334 if(!_report_handler) { 00335 _report_handler = new M2MReportHandler(*this, _sn_resource->data_type); 00336 } 00337 } 00338 if (_report_handler) { 00339 _report_handler->set_under_observation(observed); 00340 } 00341 } 00342 } else { 00343 delete _report_handler; 00344 _report_handler = NULL; 00345 } 00346 } 00347 00348 void M2MBase::set_observation_token(const uint8_t *token, const uint8_t length) 00349 { 00350 if (_report_handler) { 00351 _report_handler->set_observation_token(token, length); 00352 // This relates to sn_nsdl_auto_obs_token_callback in sn_nsdl.c 00353 set_changed(); 00354 } 00355 } 00356 00357 void M2MBase::set_instance_id(const uint16_t inst_id) 00358 { 00359 _sn_resource->identifier_int_type = true; 00360 _sn_resource->identifier.instance_id = inst_id; 00361 } 00362 00363 void M2MBase::set_max_age(const uint32_t max_age) 00364 { 00365 _sn_resource->max_age = max_age; 00366 } 00367 00368 M2MBase::BaseType M2MBase::base_type() const 00369 { 00370 return (M2MBase::BaseType)_sn_resource->base_type; 00371 } 00372 00373 M2MBase::Operation M2MBase::operation() const 00374 { 00375 return (M2MBase::Operation)_sn_resource->dynamic_resource_params->access; 00376 } 00377 00378 const char* M2MBase::name() const 00379 { 00380 assert(_sn_resource->identifier_int_type == false); 00381 return _sn_resource->identifier.name; 00382 } 00383 00384 int32_t M2MBase::name_id() const 00385 { 00386 int32_t name_id = -1; 00387 assert(_sn_resource->identifier_int_type == false); 00388 if(is_integer(_sn_resource->identifier.name) && strlen(_sn_resource->identifier.name) <= MAX_ALLOWED_STRING_LENGTH) { 00389 name_id = strtoul(_sn_resource->identifier.name, NULL, 10); 00390 if(name_id > 65535){ 00391 name_id = -1; 00392 } 00393 } 00394 return name_id; 00395 } 00396 00397 uint16_t M2MBase::instance_id() const 00398 { 00399 assert(_sn_resource->identifier_int_type == true); 00400 return _sn_resource->identifier.instance_id; 00401 } 00402 00403 #ifndef RESOURCE_ATTRIBUTES_LIST 00404 #ifndef DISABLE_INTERFACE_DESCRIPTION 00405 #ifndef MEMORY_OPTIMIZED_API 00406 const char* M2MBase::interface_description() const 00407 { 00408 return (reinterpret_cast<char*>( 00409 _sn_resource->dynamic_resource_params->static_resource_parameters->interface_description_ptr)); 00410 } 00411 #endif 00412 #endif 00413 00414 #ifndef DISABLE_RESOURCE_TYPE 00415 #ifndef MEMORY_OPTIMIZED_API 00416 const char* M2MBase::resource_type() const 00417 { 00418 return (reinterpret_cast<char*>( 00419 _sn_resource->dynamic_resource_params->static_resource_parameters->resource_type_ptr)); 00420 } 00421 #endif 00422 #endif 00423 #else // RESOURCE_ATTRIBUTES_LIST 00424 #ifndef DISABLE_INTERFACE_DESCRIPTION 00425 const char* M2MBase::interface_description() const 00426 { 00427 return sn_nsdl_get_resource_attribute(_sn_resource->dynamic_resource_params->static_resource_parameters, ATTR_INTERFACE_DESCRIPTION); 00428 } 00429 #endif 00430 00431 #ifndef DISABLE_RESOURCE_TYPE 00432 const char* M2MBase::resource_type() const 00433 { 00434 return sn_nsdl_get_resource_attribute(_sn_resource->dynamic_resource_params->static_resource_parameters, ATTR_RESOURCE_TYPE); 00435 } 00436 #endif 00437 #endif // RESOURCE_ATTRIBUTES_LIST 00438 const char* M2MBase::uri_path() const 00439 { 00440 return (reinterpret_cast<char*>( 00441 _sn_resource->dynamic_resource_params->static_resource_parameters->path)); 00442 } 00443 00444 uint16_t M2MBase::coap_content_type() const 00445 { 00446 return _sn_resource->dynamic_resource_params->coap_content_type; 00447 } 00448 00449 bool M2MBase::is_observable() const 00450 { 00451 return _sn_resource->dynamic_resource_params->observable; 00452 } 00453 00454 bool M2MBase::is_auto_observable() const 00455 { 00456 return _sn_resource->dynamic_resource_params->auto_observable; 00457 } 00458 00459 M2MBase::Observation M2MBase::observation_level() const 00460 { 00461 M2MBase::Observation obs_level = M2MBase::None; 00462 if(_report_handler) { 00463 obs_level = _report_handler->observation_level(); 00464 } 00465 return obs_level; 00466 } 00467 00468 void M2MBase::get_observation_token(uint8_t *token, uint8_t &token_length) const 00469 { 00470 if(_report_handler) { 00471 _report_handler->get_observation_token(token, token_length); 00472 } 00473 } 00474 00475 M2MBase::Mode M2MBase::mode() const 00476 { 00477 return (M2MBase::Mode)_sn_resource->dynamic_resource_params->static_resource_parameters->mode; 00478 } 00479 00480 uint16_t M2MBase::observation_number() const 00481 { 00482 uint16_t obs_number = 0; 00483 if(_report_handler) { 00484 obs_number = _report_handler->observation_number(); 00485 } 00486 return obs_number; 00487 } 00488 00489 uint32_t M2MBase::max_age() const 00490 { 00491 return _sn_resource->max_age; 00492 } 00493 00494 bool M2MBase::handle_observation_attribute(const char *query) 00495 { 00496 tr_debug("M2MBase::handle_observation_attribute - under observation(%d)", is_under_observation()); 00497 bool success = false; 00498 // Create handler if not already exists. Client must able to parse write attributes even when 00499 // observation is not yet set 00500 if (!_report_handler) { 00501 _report_handler = new M2MReportHandler(*this, _sn_resource->data_type); 00502 } 00503 00504 success = _report_handler->parse_notification_attribute(query,base_type()); 00505 if (success) { 00506 if (is_under_observation()) { 00507 _report_handler->set_under_observation(true); 00508 } 00509 } else { 00510 _report_handler->set_default_values(); 00511 } 00512 return success; 00513 } 00514 00515 bool M2MBase::observation_to_be_sent(const m2m::Vector<uint16_t> &changed_instance_ids, 00516 uint16_t obs_number, 00517 bool send_object) 00518 { 00519 //TODO: Move this to M2MResourceInstance 00520 M2MObservationHandler *obs_handler = observation_handler(); 00521 if (obs_handler) { 00522 return obs_handler->observation_to_be_sent(this, 00523 obs_number, 00524 changed_instance_ids, 00525 send_object); 00526 } 00527 return false; 00528 } 00529 00530 void M2MBase::set_base_type(M2MBase::BaseType type) 00531 { 00532 assert(_sn_resource->free_on_delete); 00533 _sn_resource->base_type = type; 00534 } 00535 00536 sn_coap_hdr_s* M2MBase::handle_get_request(nsdl_s */*nsdl*/, 00537 sn_coap_hdr_s */*received_coap_header*/, 00538 M2MObservationHandler */*observation_handler*/) 00539 { 00540 //Handled in M2MResource, M2MObjectInstance and M2MObject classes 00541 return NULL; 00542 } 00543 00544 sn_coap_hdr_s* M2MBase::handle_put_request(nsdl_s */*nsdl*/, 00545 sn_coap_hdr_s */*received_coap_header*/, 00546 M2MObservationHandler */*observation_handler*/, 00547 bool &) 00548 { 00549 //Handled in M2MResource, M2MObjectInstance and M2MObject classes 00550 return NULL; 00551 } 00552 00553 sn_coap_hdr_s* M2MBase::handle_post_request(nsdl_s */*nsdl*/, 00554 sn_coap_hdr_s */*received_coap_header*/, 00555 M2MObservationHandler */*observation_handler*/, 00556 bool &, 00557 sn_nsdl_addr_s *) 00558 { 00559 //Handled in M2MResource, M2MObjectInstance and M2MObject classes 00560 return NULL; 00561 } 00562 00563 void *M2MBase::memory_alloc(uint32_t size) 00564 { 00565 if(size) 00566 return malloc(size); 00567 else 00568 return 0; 00569 } 00570 00571 void M2MBase::memory_free(void *ptr) 00572 { 00573 free(ptr); 00574 } 00575 00576 char* M2MBase::alloc_string_copy(const char* source) 00577 { 00578 assert(source != NULL); 00579 00580 // Note: the armcc's libc does not have strdup, so we need to implement it here 00581 const size_t len = strlen(source); 00582 00583 return (char*)alloc_string_copy((uint8_t*)source, len); 00584 } 00585 00586 uint8_t* M2MBase::alloc_string_copy(const uint8_t* source, uint32_t size) 00587 { 00588 assert(source != NULL); 00589 00590 uint8_t* result = (uint8_t*)memory_alloc(size + 1); 00591 if (result) { 00592 memcpy(result, source, size); 00593 result[size] = '\0'; 00594 } 00595 return result; 00596 } 00597 00598 uint8_t* M2MBase::alloc_copy(const uint8_t* source, uint32_t size) 00599 { 00600 assert(source != NULL); 00601 00602 uint8_t* result = (uint8_t*)memory_alloc(size); 00603 if (result) { 00604 memcpy(result, source, size); 00605 } 00606 return result; 00607 } 00608 00609 bool M2MBase::validate_string_length(const String &string, size_t min_length, size_t max_length) 00610 { 00611 bool valid = false; 00612 00613 const size_t len = string.length(); 00614 if ((len >= min_length) && (len <= max_length)) { 00615 valid = true; 00616 } 00617 00618 return valid; 00619 } 00620 00621 bool M2MBase::validate_string_length(const char* string, size_t min_length, size_t max_length) 00622 { 00623 bool valid = false; 00624 00625 if (string != NULL) { 00626 const size_t len = strlen(string); 00627 if ((len >= min_length) && (len <= max_length)) { 00628 valid = true; 00629 } 00630 } 00631 return valid; 00632 } 00633 00634 M2MReportHandler* M2MBase::create_report_handler() 00635 { 00636 if (!_report_handler) { 00637 _report_handler = new M2MReportHandler(*this, _sn_resource->data_type); 00638 } 00639 return _report_handler; 00640 } 00641 00642 M2MReportHandler* M2MBase::report_handler() const 00643 { 00644 return _report_handler; 00645 } 00646 00647 void M2MBase::set_register_uri(bool register_uri) 00648 { 00649 _sn_resource->dynamic_resource_params->publish_uri = register_uri; 00650 } 00651 00652 bool M2MBase::register_uri() 00653 { 00654 return _sn_resource->dynamic_resource_params->publish_uri; 00655 } 00656 00657 bool M2MBase::is_integer(const String &value) 00658 { 00659 const char *s = value.c_str(); 00660 if(value.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) { 00661 return false; 00662 } 00663 char * p; 00664 strtol(value.c_str(), &p, 10); 00665 return (*p == 0); 00666 } 00667 00668 bool M2MBase::is_integer(const char *value) 00669 { 00670 assert(value != NULL); 00671 00672 if((strlen(value) < 1) || ((!isdigit(value[0])) && (value[0] != '-') && (value[0] != '+'))) { 00673 return false; 00674 } 00675 char * p; 00676 strtol(value, &p, 10); 00677 return (*p == 0); 00678 } 00679 00680 bool M2MBase::is_under_observation() const 00681 { 00682 bool under_observation = false; 00683 if(_report_handler) { 00684 under_observation = _report_handler->is_under_observation(); 00685 } 00686 return under_observation; 00687 } 00688 00689 bool M2MBase::set_value_updated_function(value_updated_callback callback) 00690 { 00691 value_updated_callback* old_callback = (value_updated_callback*)M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback); 00692 delete old_callback; 00693 // XXX: create a copy of the copy of callback object. Perhaps it would better to 00694 // give a reference as parameter and just store that, as it would save some memory. 00695 value_updated_callback* new_callback = new value_updated_callback(callback); 00696 00697 return M2MCallbackStorage::add_callback(*this, new_callback, M2MCallbackAssociation::M2MBaseValueUpdatedCallback); 00698 } 00699 00700 bool M2MBase::set_value_updated_function(value_updated_callback2 callback) 00701 { 00702 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback2); 00703 00704 return M2MCallbackStorage::add_callback(*this, (void*)callback, M2MCallbackAssociation::M2MBaseValueUpdatedCallback2); 00705 } 00706 00707 bool M2MBase::is_value_updated_function_set() const 00708 { 00709 bool func_set = false; 00710 if ((M2MCallbackStorage::does_callback_exist(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback) == true) || 00711 (M2MCallbackStorage::does_callback_exist(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback2) == true)) { 00712 00713 func_set = true; 00714 } 00715 return func_set; 00716 } 00717 00718 void M2MBase::execute_value_updated(const String& name) 00719 { 00720 // Q: is there a point to call both callback types? Or should we call just one of them? 00721 00722 value_updated_callback* callback = (value_updated_callback*)M2MCallbackStorage::get_callback(*this, 00723 M2MCallbackAssociation::M2MBaseValueUpdatedCallback); 00724 if (callback) { 00725 (*callback)(name.c_str()); 00726 } 00727 00728 value_updated_callback2 callback2 = (value_updated_callback2)M2MCallbackStorage::get_callback(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback2); 00729 if (callback2) { 00730 (*callback2)(name.c_str()); 00731 } 00732 } 00733 00734 bool M2MBase::build_path(StringBuffer<MAX_PATH_SIZE> &buffer, const char *s1, uint16_t i1, const char *s2, uint16_t i2) 00735 { 00736 00737 if(!buffer.ensure_space(strlen(s1) + strlen(s2) + (MAX_INSTANCE_SIZE * 2) + 3 + 1)){ 00738 return false; 00739 } 00740 00741 buffer.append(s1); 00742 buffer.append('/'); 00743 buffer.append_int(i1); 00744 buffer.append('/'); 00745 buffer.append(s2); 00746 buffer.append('/'); 00747 buffer.append_int(i2); 00748 00749 return true; 00750 00751 } 00752 00753 bool M2MBase::build_path(StringBuffer<MAX_PATH_SIZE_2> &buffer, const char *s1, uint16_t i1, const char *s2) 00754 { 00755 if(!buffer.ensure_space(strlen(s1) + strlen(s2) + MAX_INSTANCE_SIZE + 2 + 1)){ 00756 return false; 00757 } 00758 00759 buffer.append(s1); 00760 buffer.append('/'); 00761 buffer.append_int(i1); 00762 buffer.append('/'); 00763 buffer.append(s2); 00764 00765 return true; 00766 } 00767 00768 bool M2MBase::build_path(StringBuffer<MAX_PATH_SIZE_3> &buffer, const char *s1, uint16_t i1, uint16_t i2) 00769 { 00770 if(!buffer.ensure_space(strlen(s1) + (MAX_INSTANCE_SIZE * 2) + 2 + 1)){ 00771 return false; 00772 } 00773 00774 buffer.append(s1); 00775 buffer.append('/'); 00776 buffer.append_int(i1); 00777 buffer.append('/'); 00778 buffer.append_int(i2); 00779 00780 return true; 00781 } 00782 00783 bool M2MBase::build_path(StringBuffer<MAX_PATH_SIZE_4> &buffer, const char *s1, uint16_t i1) 00784 { 00785 if(!buffer.ensure_space(strlen(s1) + MAX_INSTANCE_SIZE + 1 + 1)){ 00786 return false; 00787 } 00788 00789 buffer.append(s1); 00790 buffer.append('/'); 00791 buffer.append_int(i1); 00792 00793 return true; 00794 } 00795 00796 char* M2MBase::stringdup(const char* src) 00797 { 00798 assert(src != NULL); 00799 00800 const size_t len = strlen(src) + 1; 00801 00802 char *dest = (char*)malloc(len); 00803 00804 if (dest) { 00805 memcpy(dest, src, len); 00806 } 00807 return dest; 00808 } 00809 00810 void M2MBase::free_resources() 00811 { 00812 // remove the nsdl structures from the nsdlinterface's lists. 00813 M2MObservationHandler *obs_handler = observation_handler(); 00814 if (obs_handler) { 00815 tr_debug("M2MBase::free_resources()"); 00816 obs_handler->resource_to_be_deleted(this); 00817 } 00818 00819 if (_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete) { 00820 sn_nsdl_static_resource_parameters_s *params = 00821 const_cast<sn_nsdl_static_resource_parameters_s *>(_sn_resource->dynamic_resource_params->static_resource_parameters); 00822 00823 free(params->path); 00824 //free(params->resource); 00825 #ifndef RESOURCE_ATTRIBUTES_LIST 00826 #ifndef DISABLE_RESOURCE_TYPE 00827 free(params->resource_type_ptr); 00828 #endif 00829 #ifndef DISABLE_INTERFACE_DESCRIPTION 00830 free(params->interface_description_ptr); 00831 #endif 00832 #else 00833 sn_nsdl_free_resource_attributes_list(_sn_resource->dynamic_resource_params->static_resource_parameters); 00834 #endif 00835 free(params); 00836 } 00837 if (_sn_resource->dynamic_resource_params->free_on_delete) { 00838 free(_sn_resource->dynamic_resource_params->resource); 00839 free(_sn_resource->dynamic_resource_params); 00840 } 00841 00842 if(_sn_resource->free_on_delete && _sn_resource->identifier_int_type == false) { 00843 tr_debug("M2MBase::free_resources()"); 00844 free(_sn_resource->identifier.name); 00845 } 00846 if(_sn_resource->free_on_delete) { 00847 free(_sn_resource); 00848 } 00849 } 00850 00851 size_t M2MBase::resource_name_length() const 00852 { 00853 assert(_sn_resource->identifier_int_type == false); 00854 return strlen(_sn_resource->identifier.name); 00855 } 00856 00857 sn_nsdl_dynamic_resource_parameters_s* M2MBase::get_nsdl_resource() const 00858 { 00859 return _sn_resource->dynamic_resource_params; 00860 } 00861 00862 M2MBase::lwm2m_parameters_s* M2MBase::get_lwm2m_parameters() const 00863 { 00864 return _sn_resource; 00865 } 00866 00867 #ifdef ENABLE_ASYNC_REST_RESPONSE 00868 bool M2MBase::send_async_response_with_code(const uint8_t *payload, 00869 size_t payload_len, 00870 const uint8_t* token, 00871 const uint8_t token_len, 00872 coap_response_code_e code) 00873 { 00874 bool success = false; 00875 if(is_async_coap_request_callback_set()) { 00876 success = true; 00877 // At least on some unit tests the resource object is not fully constructed, which would 00878 // cause issues if the observation_handler is NULL. So do the check before dereferencing pointer. 00879 M2MObservationHandler* obs = observation_handler(); 00880 if (obs) { 00881 obs->send_asynchronous_response(this, payload, payload_len, token, token_len, code); 00882 } 00883 } 00884 return success; 00885 } 00886 00887 bool M2MBase::set_async_coap_request_cb(handle_async_coap_request_cb callback, void *client_args) 00888 { 00889 M2MCallbackStorage::remove_callback(*this, 00890 M2MCallbackAssociation::M2MBaseAsyncCoapRequestCallback); 00891 00892 return M2MCallbackStorage::add_callback(*this, 00893 (void*)callback, 00894 M2MCallbackAssociation::M2MBaseAsyncCoapRequestCallback, 00895 client_args); 00896 } 00897 00898 void M2MBase::call_async_coap_request_callback(sn_coap_hdr_s *coap_request, 00899 M2MBase::Operation operation, 00900 bool &handled) 00901 { 00902 M2MCallbackAssociation* item = M2MCallbackStorage::get_association_item(*this, 00903 M2MCallbackAssociation::M2MBaseAsyncCoapRequestCallback); 00904 if (item) { 00905 handle_async_coap_request_cb callback = (handle_async_coap_request_cb)item->_callback; 00906 assert(callback); 00907 assert(coap_request); 00908 handled = true; 00909 (*callback)(*this, 00910 operation, 00911 coap_request->token_ptr, 00912 coap_request->token_len, 00913 coap_request->payload_ptr, 00914 coap_request->payload_len, 00915 item->_client_args); 00916 } 00917 } 00918 00919 bool M2MBase::is_async_coap_request_callback_set() 00920 { 00921 M2MCallbackAssociation* item = M2MCallbackStorage::get_association_item(*this, M2MCallbackAssociation::M2MBaseAsyncCoapRequestCallback); 00922 return (item) ? true : false; 00923 00924 } 00925 #endif // ENABLE_ASYNC_REST_RESPONSE 00926 00927 uint16_t M2MBase::get_notification_msgid() const 00928 { 00929 return 0; 00930 } 00931 00932 void M2MBase::set_notification_msgid(uint16_t /*msgid*/) 00933 { 00934 00935 } 00936 00937 bool M2MBase::set_notification_delivery_status_cb(notification_delivery_status_cb callback, void *client_args) 00938 { 00939 M2MCallbackStorage::remove_callback(*this, 00940 M2MCallbackAssociation::M2MBaseNotificationDeliveryStatusCallback); 00941 00942 return M2MCallbackStorage::add_callback(*this, 00943 (void*)callback, 00944 M2MCallbackAssociation::M2MBaseNotificationDeliveryStatusCallback, 00945 client_args); 00946 } 00947 00948 bool M2MBase::set_message_delivery_status_cb(message_delivery_status_cb callback, void *client_args) 00949 { 00950 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MBaseMessageDeliveryStatusCallback); 00951 00952 return M2MCallbackStorage::add_callback(*this, 00953 (void*)callback, 00954 M2MCallbackAssociation::M2MBaseMessageDeliveryStatusCallback, 00955 client_args); 00956 } 00957 00958 void M2MBase::send_notification_delivery_status(const M2MBase& object, const NotificationDeliveryStatus status) 00959 { 00960 M2MCallbackAssociation* item = M2MCallbackStorage::get_association_item(object, 00961 M2MCallbackAssociation::M2MBaseNotificationDeliveryStatusCallback); 00962 if (item) { 00963 notification_delivery_status_cb callback = (notification_delivery_status_cb)item->_callback; 00964 if (callback) { 00965 (*callback)(object, status, item->_client_args); 00966 } 00967 } 00968 } 00969 00970 void M2MBase::send_message_delivery_status(const M2MBase& object, const MessageDeliveryStatus status, const MessageType type) 00971 { 00972 M2MCallbackAssociation* item = M2MCallbackStorage::get_association_item(object, 00973 M2MCallbackAssociation::M2MBaseMessageDeliveryStatusCallback); 00974 if (item) { 00975 message_delivery_status_cb callback = (message_delivery_status_cb)item->_callback; 00976 if (callback) { 00977 (*callback)(object, status, type, item->_client_args); 00978 } 00979 } 00980 } 00981 00982 void M2MBase::set_changed() 00983 { 00984 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 00985 M2MBase *parent = get_parent(); 00986 if (parent) { 00987 parent->set_changed(); 00988 } 00989 #endif 00990 } 00991 00992 M2MBase *M2MBase::get_parent() const 00993 { 00994 return NULL; 00995 } 00996 00997 bool M2MBase::is_blockwise_needed(const nsdl_s *nsdl, uint32_t payload_len) 00998 { 00999 01000 uint16_t block_size = sn_nsdl_get_block_size(nsdl); 01001 01002 if (payload_len > block_size && block_size > 0) { 01003 return true; 01004 } else { 01005 return false; 01006 } 01007 } 01008 01009 void M2MBase::handle_observation(nsdl_s *nsdl, 01010 const sn_coap_hdr_s &received_coap_header, 01011 sn_coap_hdr_s &coap_response, 01012 M2MObservationHandler *observation_handler, 01013 sn_coap_msg_code_e &response_code) 01014 { 01015 tr_debug("M2MBase::handle_observation()"); 01016 assert(nsdl); 01017 assert(received_coap_header.options_list_ptr); 01018 01019 response_code = COAP_MSG_CODE_RESPONSE_CONTENT; 01020 01021 if (is_auto_observable() || received_coap_header.token_ptr == NULL) { 01022 tr_error("M2MBase::handle_observation() - already auto-observable or missing token!"); 01023 response_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 01024 return; 01025 } 01026 01027 if (!is_observable()) { 01028 tr_error("M2MBase::handle_observation() - not observable!"); 01029 response_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 01030 return; 01031 } 01032 01033 // Add observe value to response 01034 if (coap_response.options_list_ptr) { 01035 coap_response.options_list_ptr->observe = observation_number(); 01036 } 01037 01038 // In case of blockwise, delivery status callback is handled in m2mnsdlinterface after all the block have been transfered 01039 if (M2MBase::is_blockwise_needed(nsdl, coap_response.payload_len)) { 01040 tr_debug("M2MBase::handle_observation() - block message"); 01041 return; 01042 } 01043 01044 uint32_t obs_number = received_coap_header.options_list_ptr->observe; 01045 01046 // If the observe number is 0 means register for observation. 01047 if (START_OBSERVATION == obs_number) { 01048 01049 start_observation(received_coap_header, observation_handler); 01050 01051 } else if (STOP_OBSERVATION == obs_number) { 01052 tr_info("M2MBase::handle_observation() - stops observation"); 01053 01054 set_under_observation(false, NULL); 01055 send_notification_delivery_status(*this, NOTIFICATION_STATUS_UNSUBSCRIBED); 01056 send_message_delivery_status(*this, M2MBase::MESSAGE_STATUS_UNSUBSCRIBED, M2MBase::NOTIFICATION); 01057 01058 switch (base_type()) { 01059 case M2MBase::Object: 01060 M2MBase::remove_observation_level(M2MBase::O_Attribute); 01061 break; 01062 01063 case M2MBase::ObjectInstance: 01064 M2MBase::remove_observation_level(M2MBase::OI_Attribute); 01065 break; 01066 01067 case M2MBase::Resource: 01068 case M2MBase::ResourceInstance: 01069 M2MBase::remove_observation_level(M2MBase::R_Attribute); 01070 break; 01071 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 01072 case M2MBase::ObjectDirectory: 01073 // Observation not supported! 01074 break; 01075 #endif 01076 } 01077 } 01078 } 01079 01080 void M2MBase::start_observation(const sn_coap_hdr_s &received_coap_header, M2MObservationHandler *observation_handler) 01081 { 01082 set_under_observation(true, observation_handler); 01083 01084 switch (base_type()) { 01085 case M2MBase::Object: 01086 M2MBase::add_observation_level(M2MBase::O_Attribute); 01087 break; 01088 01089 case M2MBase::ObjectInstance: 01090 M2MBase::add_observation_level(M2MBase::OI_Attribute); 01091 break; 01092 01093 case M2MBase::Resource: 01094 case M2MBase::ResourceInstance: 01095 M2MBase::add_observation_level(M2MBase::R_Attribute); 01096 break; 01097 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 01098 case M2MBase::ObjectDirectory: 01099 // Observation not supported! 01100 break; 01101 #endif 01102 } 01103 01104 send_notification_delivery_status(*this, NOTIFICATION_STATUS_SUBSCRIBED); 01105 send_message_delivery_status(*this, M2MBase::MESSAGE_STATUS_SUBSCRIBED, M2MBase::NOTIFICATION); 01106 01107 set_observation_token(received_coap_header.token_ptr, 01108 received_coap_header.token_len); 01109 01110 } 01111 01112 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 01113 01114 void M2MBase::set_deleted() 01115 { 01116 // no-op 01117 } 01118 01119 bool M2MBase::is_deleted() 01120 { 01121 return false; 01122 } 01123 01124 #endif // MBED_CLOUD_CLIENT_EDGE_EXTENSION
Generated on Mon Aug 29 2022 19:53:39 by
