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.
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 Mon Aug 29 2022 19:53:40 by
