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.
m2mobject.cpp
00001 /* 00002 * Copyright (c) 2015 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 // Note: this macro is needed on armcc to get the the PRI*32 macros 00018 // from inttypes.h in a C++ code. 00019 #ifndef __STDC_FORMAT_MACROS 00020 #define __STDC_FORMAT_MACROS 00021 #endif 00022 #include <inttypes.h> 00023 00024 #include "mbed-client/m2mobject.h" 00025 #include "mbed-client/m2mconstants.h" 00026 #include "include/m2mtlvserializer.h" 00027 #include "include/m2mtlvdeserializer.h" 00028 #include "include/m2mreporthandler.h" 00029 #include "mbed-trace/mbed_trace.h" 00030 #include "mbed-client/m2mstringbuffer.h" 00031 #include "include/m2mcallbackstorage.h" 00032 00033 #include <stdlib.h> 00034 00035 #define BUFFER_SIZE 10 00036 #define TRACE_GROUP "mClt" 00037 00038 M2MObject::M2MObject(const String &object_name, char *path, bool external_blockwise_store) 00039 : M2MBase(object_name, 00040 M2MBase::Dynamic, 00041 #ifndef DISABLE_RESOURCE_TYPE 00042 "", 00043 #endif 00044 path, 00045 external_blockwise_store, 00046 false), 00047 _observation_handler(NULL) 00048 { 00049 M2MBase::set_base_type(M2MBase::Object); 00050 M2MBase::set_operation(M2MBase::GET_ALLOWED); 00051 if(M2MBase::name_id() != -1) { 00052 M2MBase::set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); 00053 } 00054 } 00055 00056 M2MObject::M2MObject(const M2MBase::lwm2m_parameters_s* static_res) 00057 : M2MBase(static_res), 00058 _observation_handler(NULL) 00059 { 00060 M2MBase::set_operation(M2MBase::GET_ALLOWED); 00061 if(M2MBase::name_id() != -1) { 00062 M2MBase::set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); 00063 } 00064 } 00065 00066 M2MObject::~M2MObject() 00067 { 00068 if(!_instance_list.empty()) { 00069 00070 M2MObjectInstanceList::const_iterator it; 00071 it = _instance_list.begin(); 00072 M2MObjectInstance* obj = NULL; 00073 uint16_t index = 0; 00074 for (; it!=_instance_list.end(); it++, index++ ) { 00075 //Free allocated memory for object instances. 00076 obj = *it; 00077 delete obj; 00078 } 00079 00080 _instance_list.clear(); 00081 } 00082 00083 free_resources(); 00084 } 00085 00086 M2MObjectInstance* M2MObject::create_object_instance(uint16_t instance_id) 00087 { 00088 tr_debug("M2MObject::create_object_instance - id: %d", instance_id); 00089 M2MObjectInstance *instance = NULL; 00090 if(!object_instance(instance_id)) { 00091 char* path = create_path(*this, instance_id); 00092 if (path) { 00093 // Note: the object instance's name contains actually object's name. 00094 instance = new M2MObjectInstance(*this, "", path); 00095 if(instance) { 00096 instance->add_observation_level(observation_level()); 00097 instance->set_instance_id(instance_id); 00098 if(M2MBase::name_id() != -1) { 00099 instance->set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); 00100 } 00101 _instance_list.push_back(instance); 00102 } 00103 } 00104 } 00105 return instance; 00106 } 00107 00108 00109 M2MObjectInstance* M2MObject::create_object_instance(const lwm2m_parameters_s* s) 00110 { 00111 tr_debug("M2MObject::create_object_instance - id: %d", s->identifier.instance_id); 00112 M2MObjectInstance *instance = NULL; 00113 if(!object_instance(s->identifier.instance_id)) { 00114 00115 instance = new M2MObjectInstance(*this, s); 00116 if(instance) { 00117 instance->add_observation_level(observation_level()); 00118 //instance->set_instance_id(instance_id); 00119 //if(M2MBase::name_id() != -1) { 00120 // instance->set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); 00121 //} 00122 _instance_list.push_back(instance); 00123 } 00124 } 00125 return instance; 00126 } 00127 00128 bool M2MObject::remove_object_instance(uint16_t inst_id) 00129 { 00130 tr_debug("M2MObject::remove_object_instance(inst_id %d)", inst_id); 00131 bool success = false; 00132 if(!_instance_list.empty()) { 00133 M2MObjectInstance* obj = NULL; 00134 M2MObjectInstanceList::const_iterator it; 00135 it = _instance_list.begin(); 00136 int pos = 0; 00137 for ( ; it != _instance_list.end(); it++, pos++ ) { 00138 if((*it)->instance_id() == inst_id) { 00139 // Instance found and deleted. 00140 obj = *it; 00141 00142 _instance_list.erase(pos); 00143 delete obj; 00144 success = true; 00145 break; 00146 } 00147 } 00148 } 00149 return success; 00150 } 00151 00152 M2MObjectInstance* M2MObject::object_instance(uint16_t inst_id) const 00153 { 00154 tr_debug("M2MObject::object_instance(inst_id %d)", inst_id); 00155 M2MObjectInstance *obj = NULL; 00156 if(!_instance_list.empty()) { 00157 M2MObjectInstanceList::const_iterator it; 00158 it = _instance_list.begin(); 00159 for ( ; it != _instance_list.end(); it++ ) { 00160 if((*it)->instance_id() == inst_id) { 00161 // Instance found. 00162 obj = *it; 00163 break; 00164 } 00165 } 00166 } 00167 return obj; 00168 } 00169 00170 const M2MObjectInstanceList& M2MObject::instances() const 00171 { 00172 return _instance_list; 00173 } 00174 00175 uint16_t M2MObject::instance_count() const 00176 { 00177 return (uint16_t)_instance_list.size(); 00178 } 00179 00180 M2MObservationHandler* M2MObject::observation_handler() const 00181 { 00182 // XXX: need to check the flag too 00183 return _observation_handler; 00184 } 00185 00186 void M2MObject::set_observation_handler(M2MObservationHandler *handler) 00187 { 00188 tr_debug("M2MObject::set_observation_handler - handler: 0x%p", (void*)handler); 00189 _observation_handler = handler; 00190 } 00191 00192 void M2MObject::add_observation_level(M2MBase::Observation observation_level) 00193 { 00194 M2MBase::add_observation_level(observation_level); 00195 if(!_instance_list.empty()) { 00196 M2MObjectInstanceList::const_iterator it; 00197 it = _instance_list.begin(); 00198 for ( ; it != _instance_list.end(); it++ ) { 00199 (*it)->add_observation_level(observation_level); 00200 } 00201 } 00202 } 00203 00204 void M2MObject::remove_observation_level(M2MBase::Observation observation_level) 00205 { 00206 M2MBase::remove_observation_level(observation_level); 00207 if(!_instance_list.empty()) { 00208 M2MObjectInstanceList::const_iterator it; 00209 it = _instance_list.begin(); 00210 for ( ; it != _instance_list.end(); it++ ) { 00211 (*it)->remove_observation_level(observation_level); 00212 } 00213 } 00214 } 00215 00216 sn_coap_hdr_s* M2MObject::handle_get_request(nsdl_s *nsdl, 00217 sn_coap_hdr_s *received_coap_header, 00218 M2MObservationHandler *observation_handler) 00219 { 00220 tr_info("M2MObject::handle_get_request()"); 00221 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; 00222 sn_coap_hdr_s * coap_response = sn_nsdl_build_response(nsdl, 00223 received_coap_header, 00224 msg_code); 00225 uint8_t *data = NULL; 00226 uint32_t data_length = 0; 00227 if(received_coap_header) { 00228 // process the GET if we have registered a callback for it 00229 if ((operation() & SN_GRS_GET_ALLOWED) != 0) { 00230 if(coap_response) { 00231 bool content_type_present = false; 00232 bool is_content_type_supported = true; 00233 00234 if (received_coap_header->options_list_ptr && 00235 received_coap_header->options_list_ptr->accept != COAP_CT_NONE) { 00236 content_type_present = true; 00237 coap_response->content_format = received_coap_header->options_list_ptr->accept; 00238 00239 } 00240 00241 // Check if preferred content type is supported 00242 if (content_type_present) { 00243 if (coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE_OLD && 00244 coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE) { 00245 is_content_type_supported = false; 00246 } 00247 } 00248 00249 if (is_content_type_supported) { 00250 if(!content_type_present && 00251 (M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE || 00252 M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE_OLD)) { 00253 coap_response->content_format = sn_coap_content_format_e(M2MBase::coap_content_type()); 00254 } 00255 00256 // fill in the CoAP response payload 00257 if(COAP_CONTENT_OMA_TLV_TYPE == coap_response->content_format || 00258 COAP_CONTENT_OMA_TLV_TYPE_OLD == coap_response->content_format) { 00259 set_coap_content_type(coap_response->content_format); 00260 data = M2MTLVSerializer::serialize(_instance_list, data_length); 00261 } 00262 00263 coap_response->payload_len = data_length; 00264 coap_response->payload_ptr = data; 00265 if(data){ 00266 coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response); 00267 if(coap_response->options_list_ptr){ 00268 coap_response->options_list_ptr->max_age = max_age(); 00269 } 00270 if(received_coap_header->options_list_ptr) { 00271 if(received_coap_header->options_list_ptr->observe != -1) { 00272 if (is_observable()) { 00273 uint32_t number = 0; 00274 uint8_t observe_option = 0; 00275 observe_option = received_coap_header->options_list_ptr->observe; 00276 00277 if(START_OBSERVATION == observe_option) { 00278 // If the observe length is 0 means register for observation. 00279 if(received_coap_header->options_list_ptr->observe != -1) { 00280 number = received_coap_header->options_list_ptr->observe; 00281 } 00282 00283 // If the observe value is 0 means register for observation. 00284 if(number == 0) { 00285 tr_info("M2MObject::handle_get_request - put resource under observation"); 00286 set_under_observation(true,observation_handler); 00287 add_observation_level(M2MBase::O_Attribute); 00288 send_notification_delivery_status(*this, NOTIFICATION_STATUS_SUBSCRIBED); 00289 if(coap_response->options_list_ptr){ 00290 coap_response->options_list_ptr->observe = observation_number(); 00291 } 00292 } 00293 00294 if(received_coap_header->token_ptr) { 00295 set_observation_token(received_coap_header->token_ptr, 00296 received_coap_header->token_len); 00297 } 00298 } else if (STOP_OBSERVATION == observe_option) { 00299 tr_info("M2MObject::handle_get_request - stops observation"); 00300 // If the observe options_list_ptr->observe value is 1 means de-register from observation. 00301 set_under_observation(false,NULL); 00302 remove_observation_level(M2MBase::O_Attribute); 00303 send_notification_delivery_status(*this, NOTIFICATION_STATUS_UNSUBSCRIBED); 00304 } 00305 msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; 00306 } 00307 else { 00308 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00309 } 00310 } 00311 } 00312 } else { 00313 msg_code = COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; // Content format not supported 00314 } 00315 } else { 00316 tr_error("M2MObject::handle_get_request() - Content-Type %d not supported", coap_response->content_format); 00317 msg_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE; 00318 } 00319 } 00320 }else { 00321 tr_error("M2MResource::handle_get_request - Return COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00322 // Operation is not allowed. 00323 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00324 } 00325 } else { 00326 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00327 } 00328 if(coap_response) { 00329 coap_response->msg_code = msg_code; 00330 } 00331 return coap_response; 00332 } 00333 00334 sn_coap_hdr_s* M2MObject::handle_put_request(nsdl_s *nsdl, 00335 sn_coap_hdr_s *received_coap_header, 00336 M2MObservationHandler */*observation_handler*/, 00337 bool &/*execute_value_updated*/) 00338 { 00339 tr_info("M2MObject::handle_put_request()"); 00340 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 00341 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, 00342 received_coap_header, 00343 msg_code); 00344 if(received_coap_header) { 00345 if(received_coap_header->content_format != COAP_CT_NONE) { 00346 set_coap_content_type(received_coap_header->content_format); 00347 } 00348 if(received_coap_header->options_list_ptr && 00349 received_coap_header->options_list_ptr->uri_query_ptr) { 00350 char *query = (char*)alloc_string_copy(received_coap_header->options_list_ptr->uri_query_ptr, 00351 received_coap_header->options_list_ptr->uri_query_len); 00352 00353 if (query){ 00354 tr_info("M2MObject::handle_put_request() - query %s", query); 00355 // if anything was updated, re-initialize the stored notification attributes 00356 if (!handle_observation_attribute(query)){ 00357 tr_debug("M2MObject::handle_put_request() - Invalid query"); 00358 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 4.00 00359 } 00360 free(query); 00361 } 00362 } else { 00363 tr_error("M2MObject::handle_put_request() - COAP_MSG_CODE_RESPONSE_BAD_REQUEST - Empty URI_QUERY"); 00364 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 00365 } 00366 } else { 00367 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00368 } 00369 if(coap_response) { 00370 coap_response->msg_code = msg_code; 00371 } 00372 return coap_response; 00373 } 00374 00375 00376 sn_coap_hdr_s* M2MObject::handle_post_request(nsdl_s *nsdl, 00377 sn_coap_hdr_s *received_coap_header, 00378 M2MObservationHandler *observation_handler, 00379 bool &execute_value_updated, 00380 sn_nsdl_addr_s *) 00381 { 00382 tr_info("M2MObject::handle_post_request()"); 00383 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 00384 // process the POST if we have registered a callback for it 00385 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, 00386 received_coap_header, 00387 msg_code); 00388 00389 if(received_coap_header) { 00390 if ((operation() & SN_GRS_POST_ALLOWED) != 0) { 00391 if(received_coap_header->content_format != COAP_CT_NONE) { 00392 set_coap_content_type(received_coap_header->content_format); 00393 } 00394 if(received_coap_header->payload_ptr) { 00395 tr_debug("M2MObject::handle_post_request() - Update Object with new values"); 00396 uint16_t coap_content_type = 0; 00397 bool content_type_present = false; 00398 if(received_coap_header->content_format != COAP_CT_NONE) { 00399 content_type_present = true; 00400 if(coap_response) { 00401 coap_content_type = received_coap_header->content_format; 00402 } 00403 } // if(received_coap_header->content_format) 00404 if(!content_type_present && 00405 (M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE || 00406 M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE_OLD)) { 00407 coap_content_type = M2MBase::coap_content_type(); 00408 } 00409 00410 tr_debug("M2MObject::handle_post_request() - Request Content-type: %d", coap_content_type); 00411 00412 if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type || 00413 COAP_CONTENT_OMA_TLV_TYPE_OLD == coap_content_type) { 00414 set_coap_content_type(coap_content_type); 00415 uint32_t instance_id = 0; 00416 // Check next free instance id 00417 for(instance_id = 0; instance_id <= MAX_UNINT_16_COUNT; instance_id++) { 00418 if(NULL == object_instance(instance_id)) { 00419 break; 00420 } 00421 if(instance_id == MAX_UNINT_16_COUNT) { 00422 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00423 break; 00424 } 00425 } 00426 if(COAP_MSG_CODE_RESPONSE_CHANGED == msg_code) { 00427 bool is_obj_instance = false; 00428 bool obj_instance_exists = false; 00429 is_obj_instance = M2MTLVDeserializer::is_object_instance(received_coap_header->payload_ptr); 00430 if (is_obj_instance) { 00431 instance_id = M2MTLVDeserializer::instance_id(received_coap_header->payload_ptr); 00432 tr_debug("M2MObject::handle_post_request() - instance id in TLV: %" PRIu32, instance_id); 00433 // Check if instance id already exists 00434 if (object_instance(instance_id)){ 00435 obj_instance_exists = true; 00436 } 00437 } 00438 if (!obj_instance_exists && coap_response) { 00439 M2MObjectInstance *obj_instance = create_object_instance(instance_id); 00440 if(obj_instance) { 00441 obj_instance->set_operation(M2MBase::GET_PUT_ALLOWED); 00442 } 00443 00444 M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; 00445 if(is_obj_instance) { 00446 tr_debug("M2MObject::handle_post_request() - TLV data contains ObjectInstance"); 00447 error = M2MTLVDeserializer::deserialise_object_instances(received_coap_header->payload_ptr, 00448 received_coap_header->payload_len, 00449 *this, 00450 M2MTLVDeserializer::Post); 00451 } else if(obj_instance && 00452 (M2MTLVDeserializer::is_resource(received_coap_header->payload_ptr) || 00453 M2MTLVDeserializer::is_multiple_resource(received_coap_header->payload_ptr))) { 00454 tr_debug("M2MObject::handle_post_request() - TLV data contains Resources"); 00455 error = M2MTLVDeserializer::deserialize_resources(received_coap_header->payload_ptr, 00456 received_coap_header->payload_len, 00457 *obj_instance, 00458 M2MTLVDeserializer::Post); 00459 } else { 00460 error = M2MTLVDeserializer::NotValid; 00461 } 00462 switch(error) { 00463 case M2MTLVDeserializer::None: 00464 if(observation_handler) { 00465 execute_value_updated = true; 00466 } 00467 coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response); 00468 00469 if (coap_response->options_list_ptr) { 00470 00471 StringBuffer<MAX_OBJECT_PATH_NAME> obj_name; 00472 00473 if (obj_name.ensure_space(M2MBase::resource_name_length() + (1 + 5 + 1))) { 00474 obj_name.append(M2MBase::name()); 00475 obj_name.append('/'); 00476 obj_name.append_int(instance_id); 00477 00478 coap_response->options_list_ptr->location_path_len = obj_name.get_size(); 00479 coap_response->options_list_ptr->location_path_ptr = 00480 alloc_copy((uint8_t*)obj_name.c_str(), obj_name.get_size()); 00481 // todo: else return error 00482 } 00483 } 00484 // todo: else return error 00485 msg_code = COAP_MSG_CODE_RESPONSE_CREATED; 00486 break; 00487 case M2MTLVDeserializer::NotAllowed: 00488 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00489 break; 00490 case M2MTLVDeserializer::NotValid: 00491 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 00492 break; 00493 case M2MTLVDeserializer::NotFound: 00494 msg_code = COAP_MSG_CODE_RESPONSE_NOT_FOUND; 00495 break; 00496 case M2MTLVDeserializer::OutOfMemory: 00497 msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE; 00498 break; 00499 } 00500 00501 } else { 00502 tr_error("M2MObject::handle_post_request() - COAP_MSG_CODE_RESPONSE_BAD_REQUEST"); 00503 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 00504 } 00505 } 00506 } else { 00507 msg_code =COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; 00508 } // if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type) 00509 } else { 00510 tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_BAD_REQUEST - Missing Payload"); 00511 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 00512 } 00513 } else { // if ((object->operation() & SN_GRS_POST_ALLOWED) != 0) 00514 tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00515 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; // 4.05 00516 } 00517 } else { //if(received_coap_header) 00518 tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00519 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; // 4.05 00520 } 00521 00522 if(coap_response) { 00523 coap_response->msg_code = msg_code; 00524 } 00525 return coap_response; 00526 } 00527 00528 void M2MObject::notification_update(uint16_t obj_instance_id) 00529 { 00530 tr_debug("M2MObject::notification_update - id: %d", obj_instance_id); 00531 M2MReportHandler *report_handler = M2MBase::report_handler(); 00532 if(report_handler && is_under_observation()) { 00533 report_handler->set_notification_trigger(obj_instance_id); 00534 } 00535 } 00536
Generated on Tue Jul 12 2022 19:01:35 by
1.7.2