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.
Dependencies: FXAS21002 FXOS8700Q
m2mresourcebase.cpp
00001 /* 00002 * Copyright (c) 2015 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 // Needed for PRIu64 on FreeRTOS 00018 #include <stdio.h> 00019 // Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX 00020 #ifndef __STDC_LIMIT_MACROS 00021 #define __STDC_LIMIT_MACROS 00022 #endif 00023 00024 // Note: this macro is needed on armcc to get the the PRI*32 macros 00025 // from inttypes.h in a C++ code. 00026 #ifndef __STDC_FORMAT_MACROS 00027 #define __STDC_FORMAT_MACROS 00028 #endif 00029 00030 #include <stdlib.h> 00031 #include "mbed-client/m2mresourcebase.h" 00032 #include "mbed-client/m2mconstants.h" 00033 #include "mbed-client/m2mobservationhandler.h" 00034 #include "mbed-client/m2mobject.h" 00035 #include "mbed-client/m2mobjectinstance.h" 00036 #include "include/m2mcallbackstorage.h" 00037 #include "include/m2mreporthandler.h" 00038 #include "include/nsdllinker.h" 00039 #include "include/m2mtlvserializer.h" 00040 #include "mbed-client/m2mblockmessage.h" 00041 #include "mbed-trace/mbed_trace.h" 00042 00043 #define TRACE_GROUP "mClt" 00044 00045 // -9223372036854775808 - +9223372036854775807 00046 // max length of int64_t string is 20 bytes + nil 00047 #define REGISTRY_INT64_STRING_MAX_LEN 21 00048 // (space needed for -3.402823 × 10^38) + (magic decimal 6 digits added as no precision is added to "%f") + trailing zero 00049 #define REGISTRY_FLOAT_STRING_MAX_LEN 48 00050 00051 00052 00053 M2MResourceBase::M2MResourceBase( 00054 const String &res_name, 00055 M2MBase::Mode resource_mode, 00056 const String &resource_type, 00057 M2MBase::DataType type, 00058 char* path, 00059 bool external_blockwise_store, 00060 bool multiple_instance) 00061 : M2MBase(res_name, 00062 resource_mode, 00063 #ifndef DISABLE_RESOURCE_TYPE 00064 resource_type, 00065 #endif 00066 path, 00067 external_blockwise_store, 00068 multiple_instance, 00069 type) 00070 #ifndef DISABLE_BLOCK_MESSAGE 00071 ,_block_message_data(NULL), 00072 #endif 00073 _notification_status(M2MResourceBase::INIT) 00074 { 00075 } 00076 00077 M2MResourceBase::M2MResourceBase( 00078 const String &res_name, 00079 M2MBase::Mode resource_mode, 00080 const String &resource_type, 00081 M2MBase::DataType type, 00082 const uint8_t *value, 00083 const uint8_t value_length, 00084 char* path, 00085 bool external_blockwise_store, 00086 bool multiple_instance) 00087 : M2MBase(res_name, 00088 resource_mode, 00089 #ifndef DISABLE_RESOURCE_TYPE 00090 resource_type, 00091 #endif 00092 path, 00093 external_blockwise_store, 00094 multiple_instance, 00095 type) 00096 #ifndef DISABLE_BLOCK_MESSAGE 00097 ,_block_message_data(NULL), 00098 #endif 00099 _notification_status(M2MResourceBase::INIT) 00100 { 00101 M2MBase::set_base_type(M2MBase::ResourceInstance); 00102 if( value != NULL && value_length > 0 ) { 00103 sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); 00104 res->resource = alloc_string_copy(value, value_length); 00105 res->resource_len = value_length; 00106 } 00107 } 00108 00109 M2MResourceBase::M2MResourceBase( 00110 const lwm2m_parameters_s* s, 00111 M2MBase::DataType /*type*/) 00112 : M2MBase(s) 00113 #ifndef DISABLE_BLOCK_MESSAGE 00114 ,_block_message_data(NULL), 00115 #endif 00116 _notification_status(M2MResourceBase::INIT) 00117 { 00118 // we are not there yet for this check as this is called from M2MResource(): assert(base_type() == M2MBase::ResourceInstance); 00119 } 00120 00121 M2MResourceBase::~M2MResourceBase() 00122 { 00123 execute_callback* callback = (execute_callback*)M2MCallbackStorage::remove_callback(*this, 00124 M2MCallbackAssociation::M2MResourceInstanceExecuteCallback); 00125 delete callback; 00126 00127 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback2); 00128 #ifndef DISABLE_BLOCK_MESSAGE 00129 incoming_block_message_callback *in_callback = (incoming_block_message_callback*)M2MCallbackStorage::remove_callback(*this, 00130 M2MCallbackAssociation::M2MResourceInstanceIncomingBlockMessageCallback); 00131 delete in_callback; 00132 00133 outgoing_block_message_callback *out_callback = (outgoing_block_message_callback*)M2MCallbackStorage::remove_callback(*this, 00134 M2MCallbackAssociation::M2MResourceInstanceOutgoingBlockMessageCallback); 00135 delete out_callback; 00136 #endif 00137 00138 notification_sent_callback *notif_callback = (notification_sent_callback*)M2MCallbackStorage::remove_callback(*this, 00139 M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback); 00140 delete notif_callback; 00141 00142 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback2); 00143 00144 notification_status_callback *notif_status_callback = (notification_status_callback*)M2MCallbackStorage::remove_callback(*this, 00145 M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback); 00146 delete notif_status_callback; 00147 00148 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback2); 00149 00150 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceBaseValueReadCallback); 00151 00152 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceBaseValueWriteCallback); 00153 00154 #ifndef DISABLE_BLOCK_MESSAGE 00155 delete _block_message_data; 00156 #endif 00157 } 00158 00159 M2MResourceBase::ResourceType M2MResourceBase::resource_instance_type() const 00160 { 00161 M2MBase::lwm2m_parameters_s* param = M2MBase::get_lwm2m_parameters(); 00162 M2MBase::DataType type = param->data_type; 00163 return convert_data_type(type); 00164 } 00165 00166 00167 bool M2MResourceBase::set_execute_function(execute_callback callback) 00168 { 00169 execute_callback* old_callback = (execute_callback*)M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback); 00170 delete old_callback; 00171 // XXX: create a copy of the copy of callback object. Perhaps it would better to 00172 // give a reference as parameter and just store that, as it would save some memory. 00173 execute_callback* new_callback = new execute_callback(callback); 00174 00175 return M2MCallbackStorage::add_callback(*this, new_callback, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback); 00176 } 00177 00178 bool M2MResourceBase::set_execute_function(execute_callback_2 callback) 00179 { 00180 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback2); 00181 00182 return M2MCallbackStorage::add_callback(*this, (void*)callback, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback2); 00183 } 00184 00185 bool M2MResourceBase::set_resource_read_callback(read_resource_value_callback callback, void *client_args) 00186 { 00187 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceBaseValueReadCallback); 00188 M2MBase::lwm2m_parameters_s* param = M2MBase::get_lwm2m_parameters(); 00189 param->read_write_callback_set = true; 00190 return M2MCallbackStorage::add_callback(*this, 00191 (void*)callback, 00192 M2MCallbackAssociation::M2MResourceBaseValueReadCallback, 00193 client_args); 00194 00195 } 00196 00197 bool M2MResourceBase::set_resource_write_callback(write_resource_value_callback callback, void *client_args) 00198 { 00199 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceBaseValueWriteCallback); 00200 M2MBase::lwm2m_parameters_s* param = M2MBase::get_lwm2m_parameters(); 00201 param->read_write_callback_set = true; 00202 00203 return M2MCallbackStorage::add_callback(*this, 00204 (void*)callback, 00205 M2MCallbackAssociation::M2MResourceBaseValueWriteCallback, 00206 client_args); 00207 } 00208 00209 void M2MResourceBase::clear_value() 00210 { 00211 tr_debug("M2MResourceBase::clear_value"); 00212 00213 sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); 00214 free(res->resource); 00215 res->resource = NULL; 00216 res->resource_len = 0; 00217 00218 report(); 00219 } 00220 00221 bool M2MResourceBase::set_value_float(float value) 00222 { 00223 bool success; 00224 char buffer[REGISTRY_FLOAT_STRING_MAX_LEN]; 00225 00226 // Convert value to string 00227 /* write the float value to a decimal number string and copy it into a buffer allocated for caller */ 00228 uint32_t size = snprintf(buffer, REGISTRY_FLOAT_STRING_MAX_LEN, "%f", value); 00229 00230 success = set_value((const uint8_t*)buffer, size); 00231 00232 return success; 00233 } 00234 00235 bool M2MResourceBase::set_value(int64_t value) 00236 { 00237 bool success; 00238 char buffer[REGISTRY_INT64_STRING_MAX_LEN]; 00239 uint32_t size = m2m::itoa_c(value, buffer); 00240 00241 success = set_value((const uint8_t*)buffer, size); 00242 00243 return success; 00244 } 00245 00246 bool M2MResourceBase::set_value(const uint8_t *value, 00247 const uint32_t value_length) 00248 { 00249 tr_debug("M2MResourceBase::set_value()"); 00250 bool success = false; 00251 if( value != NULL && value_length > 0 ) { 00252 M2MBase::lwm2m_parameters_s* param = M2MBase::get_lwm2m_parameters(); 00253 if (param->read_write_callback_set) { 00254 return write_resource_value(*this, value, value_length); 00255 } else { 00256 uint8_t *value_copy = alloc_string_copy(value, value_length); 00257 if (value_copy) { 00258 value_set_callback callback = (value_set_callback)M2MCallbackStorage::get_callback(*this, M2MCallbackAssociation::M2MResourceBaseValueSetCallback); 00259 if (callback) { 00260 (*callback)((const M2MResourceBase*)this, value_copy, value_length); 00261 } 00262 else { 00263 update_value(value_copy, value_length); 00264 } 00265 success = true; 00266 } 00267 } 00268 } 00269 return success; 00270 } 00271 00272 bool M2MResourceBase::set_value_raw(uint8_t *value, 00273 const uint32_t value_length) 00274 00275 { 00276 tr_debug("M2MResourceBase::set_value_raw()"); 00277 bool success = false; 00278 if( value != NULL && value_length > 0 ) { 00279 success = true; 00280 value_set_callback callback = (value_set_callback)M2MCallbackStorage::get_callback(*this, M2MCallbackAssociation::M2MResourceBaseValueSetCallback); 00281 if (callback) { 00282 (*callback)((const M2MResourceBase*)this, value, value_length); 00283 } 00284 else { 00285 update_value(value, value_length); 00286 } 00287 } 00288 return success; 00289 } 00290 00291 void M2MResourceBase::update_value(uint8_t *value, const uint32_t value_length) 00292 { 00293 bool changed = has_value_changed(value,value_length); 00294 sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); 00295 free(res->resource); 00296 res->resource = value; 00297 res->resource_len = value_length; 00298 if (changed) { 00299 report_value_change(); 00300 } 00301 } 00302 00303 void M2MResourceBase::report() 00304 { 00305 M2MBase::Observation observation_level = M2MBase::observation_level(); 00306 tr_debug("M2MResourceBase::report() - level %d", observation_level); 00307 00308 // We must combine the parent object/objectinstance/resource observation information 00309 // when determining if there is observation set or not. 00310 M2MObjectInstance& object_instance = get_parent_resource().get_parent_object_instance(); 00311 int parent_observation_level = (int)object_instance.observation_level(); 00312 00313 parent_observation_level |= (int)object_instance.get_parent_object().observation_level(); 00314 parent_observation_level |= (int)get_parent_resource().observation_level(); 00315 parent_observation_level |= (int)observation_level; 00316 00317 tr_debug("M2MResourceBase::report() - combined level %d", parent_observation_level); 00318 00319 if((M2MBase::O_Attribute & parent_observation_level) == M2MBase::O_Attribute || 00320 (M2MBase::OI_Attribute & parent_observation_level) == M2MBase::OI_Attribute) { 00321 tr_debug("M2MResourceBase::report() -- object/instance level"); 00322 object_instance.notification_update((M2MBase::Observation)parent_observation_level); 00323 } 00324 00325 if(M2MBase::Dynamic == mode() && 00326 (M2MBase::R_Attribute & parent_observation_level) == M2MBase::R_Attribute) { 00327 tr_debug("M2MResourceBase::report() - resource level"); 00328 00329 if (((resource_instance_type() != M2MResourceBase::STRING) && 00330 (resource_instance_type() != M2MResourceBase::OPAQUE)) && 00331 (observation_level != M2MBase::None)) { 00332 M2MReportHandler *report_handler = M2MBase::report_handler(); 00333 if (report_handler && (is_observable() || is_auto_observable())) { 00334 if (resource_instance_type() == M2MResourceBase::FLOAT) { 00335 const float float_value = get_value_float(); 00336 report_handler->set_value_float(float_value); 00337 } else { 00338 const int64_t int_value = get_value_int(); 00339 report_handler->set_value_int(int_value); 00340 } 00341 } 00342 } 00343 else { 00344 if (base_type() == M2MBase::ResourceInstance) { 00345 const M2MResource& parent_resource = get_parent_resource(); 00346 M2MReportHandler *report_handler = parent_resource.report_handler(); 00347 if(report_handler && (parent_resource.is_observable() || parent_resource.is_auto_observable())) { 00348 report_handler->set_notification_trigger(parent_resource.get_parent_object_instance().instance_id()); 00349 } 00350 } 00351 } 00352 } else if(M2MBase::Static == mode()) { 00353 M2MObservationHandler *obs_handler = observation_handler(); 00354 if(obs_handler) { 00355 obs_handler->value_updated(this); 00356 } 00357 } else { 00358 if (is_observable() || is_auto_observable()) { 00359 tr_debug("M2MResourceBase::report() - resource %s is observable but not yet subscribed!", uri_path()); 00360 } 00361 tr_debug("M2MResourceBase::report() - mode = %d, is_observable = %d", mode(), is_observable()); 00362 } 00363 } 00364 00365 bool M2MResourceBase::has_value_changed(const uint8_t* value, const uint32_t value_len) 00366 { 00367 bool changed = false; 00368 sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); 00369 00370 if(value_len != res->resource_len) { 00371 changed = true; 00372 } else if(value && !res->resource) { 00373 changed = true; 00374 } else if(res->resource && !value) { 00375 changed = true; 00376 } else { 00377 if (res->resource) { 00378 if (memcmp(value, res->resource, res->resource_len) != 0) { 00379 changed = true; 00380 } 00381 } 00382 } 00383 return changed; 00384 } 00385 00386 void M2MResourceBase::report_value_change() 00387 { 00388 if (resource_instance_type() == M2MResourceBase::STRING || 00389 resource_instance_type() == M2MResourceBase::OPAQUE) { 00390 M2MReportHandler *report_handler = M2MBase::report_handler(); 00391 if(report_handler && is_under_observation()) { 00392 report_handler->set_notification_trigger(); 00393 } 00394 } 00395 report(); 00396 } 00397 00398 void M2MResourceBase::execute(void *arguments) 00399 { 00400 // XXX: this line is expected by seven testcases and until this code hits master branch 00401 // the testcases can not be modified and we need to print the false information too. 00402 tr_debug("M2MResourceBase::execute"); 00403 00404 execute_callback* callback = (execute_callback*)M2MCallbackStorage::get_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback); 00405 00406 if (callback) { 00407 (*callback)(arguments); 00408 } 00409 00410 execute_callback_2 callback2 = (execute_callback_2)M2MCallbackStorage::get_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback2); 00411 if (callback2) { 00412 (*callback2)(arguments); 00413 } 00414 } 00415 00416 int M2MResourceBase::read_resource_value(const M2MResourceBase &resource, void *buffer, size_t *buffer_len) 00417 { 00418 tr_debug("M2MResourceBase::read_resource_value"); 00419 00420 M2MCallbackAssociation* item = M2MCallbackStorage::get_association_item(resource, 00421 M2MCallbackAssociation::M2MResourceBaseValueReadCallback); 00422 00423 if (item) { 00424 read_resource_value_callback callback = (read_resource_value_callback)item->_callback; 00425 assert(callback); 00426 return (*callback)(resource, buffer, buffer_len, item->_client_args); 00427 } else { 00428 if (value_length() > *buffer_len) { 00429 return -1; 00430 } else { 00431 memcpy(buffer, value(), value_length()); 00432 *buffer_len = value_length(); 00433 return 0; 00434 } 00435 } 00436 } 00437 00438 bool M2MResourceBase::write_resource_value(const M2MResourceBase &resource, const uint8_t *buffer, const size_t buffer_size) 00439 { 00440 tr_debug("M2MResourceBase::write_resource_value"); 00441 M2MCallbackAssociation* item = M2MCallbackStorage::get_association_item(resource, 00442 M2MCallbackAssociation::M2MResourceBaseValueWriteCallback); 00443 if (item) { 00444 write_resource_value_callback callback = (write_resource_value_callback)item->_callback; 00445 if (callback) { 00446 return (*callback)(resource, buffer, buffer_size, item->_client_args); 00447 } 00448 } 00449 00450 return false; 00451 } 00452 00453 void M2MResourceBase::get_value(uint8_t *&value, uint32_t &value_length) 00454 { 00455 value_length = 0; 00456 if(value) { 00457 free(value); 00458 value = NULL; 00459 } 00460 00461 sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); 00462 if(res->resource && res->resource_len > 0) { 00463 value = alloc_string_copy(res->resource, res->resource_len); 00464 if(value) { 00465 value_length = res->resource_len; 00466 } 00467 } 00468 } 00469 00470 int64_t M2MResourceBase::get_value_int() const 00471 { 00472 int64_t value_int = 0; 00473 00474 const char *value_string = (char *)value(); 00475 const uint32_t value_len = value_length(); 00476 00477 if ((value_string) && (value_len <= REGISTRY_INT64_STRING_MAX_LEN)) { 00478 00479 // -9223372036854775808 - +9223372036854775807 00480 // max length of int64_t string is 20 bytes + nil 00481 // The +1 here is there in case the string was already zero terminated. 00482 00483 00484 bool success = String::convert_ascii_to_int(value_string, value_len, value_int); 00485 if (!success) { 00486 // note: the convert_ascii_to_int() actually allows one to pass the conversion 00487 // onwards, but this get_value_int() does not. Lets just dump error to log, but 00488 // do not log the value as that might be part of a attack. Same reason (valid or not) 00489 // is behind the selection of log level 00490 tr_warn("M2MResourceBase::get_value_int(): conversion failed"); 00491 } 00492 } 00493 return value_int; 00494 } 00495 00496 String M2MResourceBase::get_value_string() const 00497 { 00498 // XXX: do a better constructor to avoid pointless malloc 00499 String value; 00500 if (get_nsdl_resource()->resource) { 00501 value.append_raw((char*)get_nsdl_resource()->resource, get_nsdl_resource()->resource_len); 00502 } 00503 return value; 00504 } 00505 00506 float M2MResourceBase::get_value_float() const 00507 { 00508 float value_float = 0; 00509 00510 const char *value_string = (char *)value(); 00511 const uint32_t value_len = value_length(); 00512 00513 if ((value_string) && (value_len <= REGISTRY_FLOAT_STRING_MAX_LEN)) { 00514 00515 // (space needed for -3.402823 × 10^38) + (magic decimal 6 digits added as no precision is added to "%f") + trailing zero 00516 // The +1 here is there in case the string was already zero terminated. 00517 char temp[REGISTRY_FLOAT_STRING_MAX_LEN + 1]; 00518 00519 memcpy(temp, value_string, value_len); 00520 temp[value_len] = 0; 00521 00522 value_float = atof(temp); 00523 } 00524 00525 return value_float; 00526 } 00527 00528 uint8_t* M2MResourceBase::value() const 00529 { 00530 return get_nsdl_resource()->resource; 00531 } 00532 00533 uint32_t M2MResourceBase::value_length() const 00534 { 00535 return get_nsdl_resource()->resource_len; 00536 } 00537 00538 void M2MResourceBase::set_value_set_callback(value_set_callback callback) 00539 { 00540 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceBaseValueSetCallback); 00541 M2MCallbackStorage::add_callback(*this, (void*)callback, M2MCallbackAssociation::M2MResourceBaseValueSetCallback); 00542 } 00543 00544 sn_coap_hdr_s* M2MResourceBase::handle_get_request(nsdl_s *nsdl, 00545 sn_coap_hdr_s *received_coap_header, 00546 M2MObservationHandler *observation_handler) 00547 { 00548 tr_info("M2MResourceBase::handle_get_request()"); 00549 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; 00550 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, 00551 received_coap_header, 00552 msg_code); 00553 if (received_coap_header) { 00554 // process the GET if we have registered a callback for it 00555 if ((operation() & M2MBase::GET_ALLOWED) != 0) { 00556 if (coap_response) { 00557 bool content_type_present = false; 00558 if (received_coap_header->options_list_ptr && 00559 received_coap_header->options_list_ptr->accept != COAP_CT_NONE) { 00560 content_type_present = true; 00561 coap_response->content_format = received_coap_header->options_list_ptr->accept; 00562 set_coap_content_type(coap_response->content_format); 00563 } 00564 if (!content_type_present) { 00565 if (resource_instance_type() == M2MResourceInstance::OPAQUE) { 00566 coap_response->content_format = sn_coap_content_format_e(COAP_CONTENT_OMA_OPAQUE_TYPE); 00567 } else { 00568 coap_response->content_format = sn_coap_content_format_e(COAP_CONTENT_OMA_PLAIN_TEXT_TYPE); 00569 } 00570 } 00571 // fill in the CoAP response payload 00572 coap_response->payload_ptr = NULL; 00573 uint32_t payload_len = 0; 00574 #ifndef DISABLE_BLOCK_MESSAGE 00575 //If handler exists it means that resource value is stored in application side 00576 if (block_message() && block_message()->is_block_message()) { 00577 outgoing_block_message_callback* outgoing_block_message_cb = (outgoing_block_message_callback*)M2MCallbackStorage::get_callback(*this, 00578 M2MCallbackAssociation::M2MResourceInstanceOutgoingBlockMessageCallback); 00579 if (outgoing_block_message_cb) { 00580 String name = ""; 00581 if (received_coap_header->uri_path_ptr != NULL && 00582 received_coap_header->uri_path_len > 0) { 00583 name.append_raw((char *)received_coap_header->uri_path_ptr, received_coap_header->uri_path_len); 00584 } 00585 (*outgoing_block_message_cb)(name, coap_response->payload_ptr, payload_len); 00586 } 00587 } else { 00588 #endif 00589 if (coap_response->content_format == COAP_CONTENT_OMA_TLV_TYPE || 00590 coap_response->content_format == COAP_CONTENT_OMA_TLV_TYPE_OLD) { 00591 coap_response->payload_ptr = M2MTLVSerializer::serialize(&get_parent_resource(), payload_len); 00592 } else { 00593 get_value(coap_response->payload_ptr,payload_len); 00594 } 00595 #ifndef DISABLE_BLOCK_MESSAGE 00596 } 00597 #endif 00598 tr_debug("M2MResourceBase::handle_get_request() - Request Content-type: %d", coap_response->content_format); 00599 coap_response->payload_len = payload_len; 00600 coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response); 00601 if (coap_response->options_list_ptr) { 00602 coap_response->options_list_ptr->max_age = max_age(); 00603 } 00604 00605 if (received_coap_header->options_list_ptr) { 00606 if(received_coap_header->options_list_ptr->observe != -1) { 00607 handle_observation(nsdl, *received_coap_header, *coap_response, observation_handler, msg_code); 00608 } 00609 } 00610 } 00611 } else { 00612 tr_error("M2MResourceBase::handle_get_request - Return COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00613 // Operation is not allowed. 00614 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00615 } 00616 } else { 00617 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00618 } 00619 00620 if (coap_response) { 00621 coap_response->msg_code = msg_code; 00622 } 00623 00624 return coap_response; 00625 } 00626 00627 sn_coap_hdr_s* M2MResourceBase::handle_put_request(nsdl_s *nsdl, 00628 sn_coap_hdr_s *received_coap_header, 00629 M2MObservationHandler *observation_handler, 00630 bool &execute_value_updated) 00631 { 00632 tr_info("M2MResourceBase::handle_put_request()"); 00633 00634 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 00635 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, 00636 received_coap_header, 00637 msg_code); 00638 // process the PUT if we have registered a callback for it 00639 if(received_coap_header && coap_response) { 00640 uint16_t coap_content_type = 0; 00641 if(received_coap_header->content_format != COAP_CT_NONE) { 00642 coap_content_type = received_coap_header->content_format; 00643 } 00644 if(received_coap_header->options_list_ptr && 00645 received_coap_header->options_list_ptr->uri_query_ptr) { 00646 char *query = (char*)alloc_string_copy(received_coap_header->options_list_ptr->uri_query_ptr, 00647 received_coap_header->options_list_ptr->uri_query_len); 00648 if (query){ 00649 tr_info("M2MResourceBase::handle_put_request() - query %s", query); 00650 00651 // if anything was updated, re-initialize the stored notification attributes 00652 if (!handle_observation_attribute(query)){ 00653 tr_error("M2MResourceBase::handle_put_request() - Invalid query"); 00654 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 00655 } 00656 free(query); 00657 } 00658 else { 00659 // memory allocation for query fails 00660 tr_error("M2MResourceBase::handle_put_request() - Out of memory !!!"); 00661 msg_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR; // 4.00 00662 } 00663 } else if ((operation() & M2MBase::PUT_ALLOWED) != 0) { 00664 tr_debug("M2MResourceBase::handle_put_request() - Request Content-type: %d", coap_content_type); 00665 00666 if(COAP_CONTENT_OMA_OPAQUE_TYPE != coap_content_type && 00667 COAP_CONTENT_OMA_PLAIN_TEXT_TYPE != coap_content_type) { 00668 msg_code = COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; 00669 } else { 00670 #ifndef DISABLE_BLOCK_MESSAGE 00671 if (block_message()) { 00672 block_message()->set_message_info(received_coap_header); 00673 if (block_message()->is_block_message()) { 00674 incoming_block_message_callback* incoming_block_message_cb = (incoming_block_message_callback*)M2MCallbackStorage::get_callback(*this, 00675 M2MCallbackAssociation::M2MResourceInstanceIncomingBlockMessageCallback); 00676 if (incoming_block_message_cb) { 00677 (*incoming_block_message_cb)(_block_message_data); 00678 } 00679 if (block_message()->is_last_block()) { 00680 block_message()->clear_values(); 00681 coap_response->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED; 00682 } else { 00683 coap_response->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING; 00684 } 00685 if (block_message()->error_code() != M2MBlockMessage::ErrorNone) { 00686 block_message()->clear_values(); 00687 } 00688 } 00689 } 00690 #endif 00691 // Firmware object uri path is limited to be max 255 bytes 00692 if ((strcmp(uri_path(), FIRMAWARE_PACKAGE_URI_PATH) == 0) && 00693 received_coap_header->payload_len > 255) { 00694 msg_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE; 00695 } else if ((strcmp(uri_path(), SERVER_LIFETIME_PATH) == 0)) { 00696 // Check that lifetime can't go below 60s 00697 if(received_coap_header->payload_ptr) { 00698 int64_t lifetime; 00699 bool success = String::convert_ascii_to_int((char*)received_coap_header->payload_ptr, received_coap_header->payload_len, lifetime); 00700 if ((success == false) || (lifetime < MINIMUM_REGISTRATION_TIME)) { 00701 tr_error("M2MResourceBase::handle_put_request() - lifetime value % " PRId32 " not acceptable", lifetime); 00702 msg_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE; 00703 } 00704 } else { 00705 tr_error("M2MResourceBase::handle_put_request() - empty lifetime payload not acceptable"); 00706 msg_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE; 00707 } 00708 } 00709 00710 // Do not update resource value in error case. 00711 if ((received_coap_header->payload_ptr) && (msg_code == COAP_MSG_CODE_RESPONSE_CHANGED)) { 00712 execute_value_updated = true; 00713 } 00714 } 00715 } else { 00716 // Operation is not allowed. 00717 tr_error("M2MResourceBase::handle_put_request() - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00718 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00719 } 00720 } else { 00721 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00722 } 00723 if(coap_response) { 00724 coap_response->msg_code = msg_code; 00725 } 00726 00727 return coap_response; 00728 } 00729 00730 00731 #ifndef DISABLE_BLOCK_MESSAGE 00732 00733 M2MBlockMessage* M2MResourceBase::block_message() const 00734 { 00735 return _block_message_data; 00736 } 00737 00738 bool M2MResourceBase::set_incoming_block_message_callback(incoming_block_message_callback callback) 00739 { 00740 incoming_block_message_callback* old_callback = (incoming_block_message_callback*)M2MCallbackStorage::remove_callback(*this, 00741 M2MCallbackAssociation::M2MResourceInstanceIncomingBlockMessageCallback); 00742 delete old_callback; 00743 00744 // copy the callback object. This will change on next version to be a direct pointer to a interface class, 00745 // this FPn<> is just too heavy for this usage. 00746 incoming_block_message_callback* new_callback = new incoming_block_message_callback(callback); 00747 00748 delete _block_message_data; 00749 _block_message_data = NULL; 00750 _block_message_data = new M2MBlockMessage(); 00751 00752 return M2MCallbackStorage::add_callback(*this, 00753 new_callback, 00754 M2MCallbackAssociation::M2MResourceInstanceIncomingBlockMessageCallback); 00755 } 00756 00757 bool M2MResourceBase::set_outgoing_block_message_callback(outgoing_block_message_callback callback) 00758 { 00759 outgoing_block_message_callback *old_callback = (outgoing_block_message_callback*)M2MCallbackStorage::remove_callback(*this, 00760 M2MCallbackAssociation::M2MResourceInstanceOutgoingBlockMessageCallback); 00761 delete old_callback; 00762 00763 outgoing_block_message_callback *new_callback = new outgoing_block_message_callback(callback); 00764 return M2MCallbackStorage::add_callback(*this, 00765 new_callback, 00766 M2MCallbackAssociation::M2MResourceInstanceOutgoingBlockMessageCallback); 00767 } 00768 #endif 00769 00770 bool M2MResourceBase::set_notification_sent_callback(notification_sent_callback callback) 00771 { 00772 notification_sent_callback *old_callback = (notification_sent_callback*)M2MCallbackStorage::remove_callback(*this, 00773 M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback); 00774 delete old_callback; 00775 00776 notification_sent_callback *new_callback = new notification_sent_callback(callback); 00777 return M2MCallbackStorage::add_callback(*this, 00778 new_callback, 00779 M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback); 00780 } 00781 00782 bool M2MResourceBase::set_notification_sent_callback(notification_sent_callback_2 callback) 00783 { 00784 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback2); 00785 00786 return M2MCallbackStorage::add_callback(*this, 00787 (void*)callback, 00788 M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback2); 00789 } 00790 00791 bool M2MResourceBase::set_notification_status_callback(notification_status_callback callback) 00792 { 00793 notification_status_callback *old_callback = (notification_status_callback*)M2MCallbackStorage::remove_callback(*this, 00794 M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback); 00795 delete old_callback; 00796 00797 notification_status_callback *new_callback = new notification_status_callback(callback); 00798 return M2MCallbackStorage::add_callback(*this, 00799 new_callback, 00800 M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback); 00801 } 00802 00803 bool M2MResourceBase::set_notification_status_callback(notification_status_callback_2 callback) 00804 { 00805 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback2); 00806 00807 return M2MCallbackStorage::add_callback(*this, 00808 (void*)callback, 00809 M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback2); 00810 } 00811 00812 void M2MResourceBase::notification_sent() 00813 { 00814 // Now we will call both callbacks, if they are set. This is different from original behavior. 00815 notification_sent_callback* callback = 00816 (notification_sent_callback*)M2MCallbackStorage::get_callback(*this, 00817 M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback); 00818 if (callback) { 00819 (*callback)(); 00820 } 00821 00822 notification_sent_callback_2 callback2 = 00823 (notification_sent_callback_2)M2MCallbackStorage::get_callback(*this, 00824 M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback2); 00825 if (callback2) { 00826 (*callback2)(); 00827 } 00828 } 00829 00830 void M2MResourceBase::notification_status(const uint16_t msg_id, const NotificationStatus status) 00831 { 00832 if (_notification_status != status) { 00833 _notification_status = status; 00834 // Now we will call both callbacks, if they are set. This is different from original behavior. 00835 notification_status_callback* callback = 00836 (notification_status_callback*)M2MCallbackStorage::get_callback(*this, 00837 M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback); 00838 if (callback) { 00839 (*callback)(msg_id, status); 00840 } 00841 00842 notification_status_callback_2 callback2 = 00843 (notification_status_callback_2)M2MCallbackStorage::get_callback(*this, 00844 M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback2); 00845 if (callback2) { 00846 (*callback2)(msg_id, status); 00847 } 00848 } 00849 } 00850 00851 M2MResourceBase::ResourceType M2MResourceBase::convert_data_type(M2MBase::DataType type) const 00852 { 00853 M2MResourceBase::ResourceType res_type = M2MResourceBase::OBJLINK; 00854 switch(type) { 00855 case M2MBase::STRING: 00856 res_type = M2MResourceBase::STRING; 00857 break; 00858 case M2MBase::INTEGER: 00859 res_type = M2MResourceBase::INTEGER; 00860 break; 00861 case M2MBase::FLOAT: 00862 res_type = M2MResourceBase::FLOAT; 00863 break; 00864 case M2MBase::OPAQUE: 00865 res_type = M2MResourceBase::OPAQUE; 00866 break; 00867 case M2MBase::BOOLEAN: 00868 res_type = M2MResourceBase::BOOLEAN; 00869 break; 00870 case M2MBase::TIME: 00871 res_type = M2MResourceBase::TIME; 00872 break; 00873 case M2MBase::OBJLINK: 00874 res_type = M2MResourceBase::OBJLINK; 00875 break; 00876 } 00877 return res_type; 00878 } 00879 00880 M2MResourceBase::NotificationStatus M2MResourceBase::notification_status() const 00881 { 00882 return _notification_status; 00883 } 00884 00885 void M2MResourceBase::clear_notification_status() 00886 { 00887 _notification_status = M2MResourceBase::INIT; 00888 } 00889 00890 void M2MResourceBase::publish_value_in_registration_msg(bool publish_value) 00891 { 00892 M2MBase::lwm2m_parameters_s* param = M2MBase::get_lwm2m_parameters(); 00893 assert(param->data_type == M2MBase::INTEGER || 00894 param->data_type == M2MBase::STRING || 00895 param->data_type == M2MBase::FLOAT || 00896 param->data_type == M2MBase::BOOLEAN || 00897 param->data_type == M2MBase::OPAQUE); 00898 00899 uint8_t pub_value = publish_value; 00900 00901 if (param->data_type == M2MBase::OPAQUE) { 00902 pub_value = 2; 00903 } else { 00904 pub_value = (uint8_t)publish_value; 00905 } 00906 param->dynamic_resource_params->publish_value = pub_value; 00907 }
Generated on Tue Jul 12 2022 20:21:00 by
