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 #include "mbed-client/m2mobject.h" 00017 #include "mbed-client/m2mobservationhandler.h" 00018 #include "mbed-client/m2mconstants.h" 00019 #include "include/m2mtlvserializer.h" 00020 #include "include/m2mtlvdeserializer.h" 00021 #include "include/nsdllinker.h" 00022 #include "include/m2mreporthandler.h" 00023 #include "mbed-trace/mbed_trace.h" 00024 00025 #define BUFFER_SIZE 10 00026 #define TRACE_GROUP "mClt" 00027 00028 M2MObject::M2MObject(const String &object_name) 00029 : M2MBase(object_name,M2MBase::Dynamic), 00030 _max_instance_count(MAX_UNINT_16_COUNT) 00031 { 00032 M2MBase::set_base_type(M2MBase::Object); 00033 if(M2MBase::name_id() != -1) { 00034 M2MBase::set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE); 00035 } 00036 } 00037 00038 M2MObject::~M2MObject() 00039 { 00040 if(!_instance_list.empty()) { 00041 remove_resource_from_coap(name()); 00042 M2MObjectInstanceList::const_iterator it; 00043 it = _instance_list.begin(); 00044 M2MObjectInstance* obj = NULL; 00045 uint16_t index = 0; 00046 for (; it!=_instance_list.end(); it++, index++ ) { 00047 //Free allocated memory for object instances. 00048 obj = *it; 00049 delete obj; 00050 } 00051 remove_object_from_coap(); 00052 _instance_list.clear(); 00053 } 00054 } 00055 00056 M2MObject& M2MObject::operator=(const M2MObject& other) 00057 { 00058 if (this != &other) { // protect against invalid self-assignment 00059 if(!other._instance_list.empty()){ 00060 M2MObjectInstance* ins = NULL; 00061 M2MObjectInstanceList::const_iterator it; 00062 it = other._instance_list.begin(); 00063 for (; it!=other._instance_list.end(); it++ ) { 00064 ins = *it; 00065 _instance_list.push_back(new M2MObjectInstance(*ins)); 00066 } 00067 } 00068 } 00069 return *this; 00070 } 00071 00072 M2MObject::M2MObject(const M2MObject& other) 00073 : M2MBase(other), 00074 _max_instance_count(MAX_UNINT_16_COUNT) 00075 { 00076 this->operator=(other); 00077 } 00078 00079 M2MObjectInstance* M2MObject::create_object_instance(uint16_t instance_id) 00080 { 00081 tr_debug("M2MObject::create_object_instance - id: %d", instance_id); 00082 M2MObjectInstance *instance = NULL; 00083 if(!object_instance(instance_id)) { 00084 instance = new M2MObjectInstance(this->name(),*this); 00085 if(instance) { 00086 instance->add_observation_level(observation_level()); 00087 instance->set_instance_id(instance_id); 00088 if(M2MBase::name_id() != -1) { 00089 instance->set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE); 00090 } 00091 _instance_list.push_back(instance); 00092 } 00093 } 00094 return instance; 00095 } 00096 00097 bool M2MObject::remove_object_instance(uint16_t inst_id) 00098 { 00099 tr_debug("M2MObject::remove_object_instance(inst_id %d)", inst_id); 00100 bool success = false; 00101 if(!_instance_list.empty()) { 00102 M2MObjectInstance* obj = NULL; 00103 M2MObjectInstanceList::const_iterator it; 00104 it = _instance_list.begin(); 00105 int pos = 0; 00106 for ( ; it != _instance_list.end(); it++, pos++ ) { 00107 if((*it)->instance_id() == inst_id) { 00108 // Instance found and deleted. 00109 obj = *it; 00110 String obj_name = name(); 00111 obj_name.push_back('/'); 00112 obj_name.append_int(obj->instance_id()); 00113 obj->remove_resource_from_coap(obj_name); 00114 _instance_list.erase(pos); 00115 delete obj; 00116 success = true; 00117 break; 00118 } 00119 } 00120 } 00121 return success; 00122 } 00123 00124 M2MObjectInstance* M2MObject::object_instance(uint16_t inst_id) const 00125 { 00126 tr_debug("M2MObject::object_instance(inst_id %d)", inst_id); 00127 M2MObjectInstance *obj = NULL; 00128 if(!_instance_list.empty()) { 00129 M2MObjectInstanceList::const_iterator it; 00130 it = _instance_list.begin(); 00131 for ( ; it != _instance_list.end(); it++ ) { 00132 if((*it)->instance_id() == inst_id) { 00133 // Instance found. 00134 obj = *it; 00135 break; 00136 } 00137 } 00138 } 00139 return obj; 00140 } 00141 00142 const M2MObjectInstanceList& M2MObject::instances() const 00143 { 00144 return _instance_list; 00145 } 00146 00147 uint16_t M2MObject::instance_count() const 00148 { 00149 return (uint16_t)_instance_list.size(); 00150 } 00151 00152 M2MBase::BaseType M2MObject::base_type() const 00153 { 00154 return M2MBase::base_type(); 00155 } 00156 00157 void M2MObject::add_observation_level(M2MBase::Observation observation_level) 00158 { 00159 M2MBase::add_observation_level(observation_level); 00160 if(!_instance_list.empty()) { 00161 M2MObjectInstanceList::const_iterator it; 00162 it = _instance_list.begin(); 00163 for ( ; it != _instance_list.end(); it++ ) { 00164 (*it)->add_observation_level(observation_level); 00165 } 00166 } 00167 } 00168 00169 void M2MObject::remove_observation_level(M2MBase::Observation observation_level) 00170 { 00171 M2MBase::remove_observation_level(observation_level); 00172 if(!_instance_list.empty()) { 00173 M2MObjectInstanceList::const_iterator it; 00174 it = _instance_list.begin(); 00175 for ( ; it != _instance_list.end(); it++ ) { 00176 (*it)->remove_observation_level(observation_level); 00177 } 00178 } 00179 } 00180 00181 sn_coap_hdr_s* M2MObject::handle_get_request(nsdl_s *nsdl, 00182 sn_coap_hdr_s *received_coap_header, 00183 M2MObservationHandler *observation_handler) 00184 { 00185 tr_debug("M2MObject::handle_get_request()"); 00186 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; 00187 sn_coap_hdr_s * coap_response = sn_nsdl_build_response(nsdl, 00188 received_coap_header, 00189 msg_code); 00190 uint8_t * data = NULL; 00191 uint32_t data_length = 0; 00192 if(received_coap_header) { 00193 // process the GET if we have registered a callback for it 00194 if ((operation() & SN_GRS_GET_ALLOWED) != 0) { 00195 if(coap_response) { 00196 uint16_t coap_content_type = 0; 00197 bool content_type_present = false; 00198 if(received_coap_header->content_type_ptr) { 00199 content_type_present = true; 00200 coap_response->content_type_ptr = alloc_copy(received_coap_header->content_type_ptr, 00201 received_coap_header->content_type_len); 00202 if(coap_response->content_type_ptr) { 00203 coap_response->content_type_len = received_coap_header->content_type_len; 00204 for(uint8_t i = 0; i < coap_response->content_type_len; i++) { 00205 coap_content_type = (coap_content_type << 8) + 00206 (coap_response->content_type_ptr[i] & 0xFF); 00207 } 00208 } 00209 } 00210 if(!content_type_present && 00211 M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE) { 00212 coap_content_type = COAP_CONTENT_OMA_TLV_TYPE; 00213 } 00214 00215 tr_debug("M2MObject::handle_get_request() - Request Content-Type %d", coap_content_type); 00216 if (!coap_response->content_type_ptr) { 00217 coap_response->content_type_ptr = 00218 m2m::String::convert_integer_to_array(coap_content_type, 00219 coap_response->content_type_len); 00220 if (coap_response->content_type_ptr) { 00221 set_coap_content_type(coap_content_type); 00222 } 00223 } 00224 // fill in the CoAP response payload 00225 if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type) { 00226 M2MTLVSerializer *serializer = new M2MTLVSerializer(); 00227 data = serializer->serialize(_instance_list, data_length); 00228 delete serializer; 00229 00230 } else { // TOD0: Implement JSON Format. 00231 msg_code = COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; // Content format not supported 00232 } 00233 00234 coap_response->payload_len = data_length; 00235 coap_response->payload_ptr = data; 00236 00237 coap_response->options_list_ptr = (sn_coap_options_list_s*)malloc(sizeof(sn_coap_options_list_s)); 00238 memset(coap_response->options_list_ptr, 0, sizeof(sn_coap_options_list_s)); 00239 00240 coap_response->options_list_ptr->max_age_ptr = 00241 m2m::String::convert_integer_to_array(max_age(), 00242 coap_response->options_list_ptr->max_age_len); 00243 00244 if(data){ 00245 if(received_coap_header->options_list_ptr) { 00246 if(received_coap_header->options_list_ptr->observe) { 00247 if (is_observable()) { 00248 uint32_t number = 0; 00249 uint8_t observe_option = 0; 00250 if(received_coap_header->options_list_ptr->observe_ptr) { 00251 observe_option = *received_coap_header->options_list_ptr->observe_ptr; 00252 } 00253 if(START_OBSERVATION == observe_option) { 00254 tr_debug("M2MObject::handle_get_request - Starts Observation"); 00255 // If the observe length is 0 means register for observation. 00256 if(received_coap_header->options_list_ptr->observe_len != 0) { 00257 for(int i=0;i < received_coap_header->options_list_ptr->observe_len; i++) { 00258 number = (*(received_coap_header->options_list_ptr->observe_ptr + i) & 0xff) << 00259 8*(received_coap_header->options_list_ptr->observe_len- 1 - i); 00260 } 00261 } 00262 if(received_coap_header->token_ptr) { 00263 tr_debug("M2MObject::handle_get_request - Sets Observation Token to resource"); 00264 set_observation_token(received_coap_header->token_ptr, 00265 received_coap_header->token_len); 00266 } 00267 00268 // If the observe value is 0 means register for observation. 00269 if(number == 0) { 00270 tr_debug("M2MObject::handle_get_request - Put Resource under Observation"); 00271 set_under_observation(true,observation_handler); 00272 add_observation_level(M2MBase::O_Attribute); 00273 tr_debug("M2MObject::handle_get_request - Observation Number %d", observation_number()); 00274 coap_response->options_list_ptr->observe_ptr = 00275 m2m::String::convert_integer_to_array(observation_number(), 00276 coap_response->options_list_ptr->observe_len); 00277 } 00278 } else if (STOP_OBSERVATION == observe_option) { 00279 tr_debug("M2MObject::handle_get_request - Stops Observation"); 00280 // If the observe options_list_ptr->observe_ptr value is 1 means de-register from observation. 00281 set_under_observation(false,NULL); 00282 remove_observation_level(M2MBase::O_Attribute); 00283 } 00284 msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; 00285 } 00286 else { 00287 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00288 } 00289 } 00290 } 00291 } else { 00292 msg_code = COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; // Content format not supported 00293 } 00294 } 00295 }else { 00296 tr_error("M2MResource::handle_get_request - Return COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00297 // Operation is not allowed. 00298 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00299 } 00300 } else { 00301 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00302 } 00303 if(coap_response) { 00304 coap_response->msg_code = msg_code; 00305 } 00306 return coap_response; 00307 } 00308 00309 sn_coap_hdr_s* M2MObject::handle_put_request(nsdl_s *nsdl, 00310 sn_coap_hdr_s *received_coap_header, 00311 M2MObservationHandler */*observation_handler*/, 00312 bool &/*execute_value_updated*/) 00313 { 00314 tr_debug("M2MObject::handle_put_request()"); 00315 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 00316 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, 00317 received_coap_header, 00318 msg_code); 00319 if(received_coap_header) { 00320 if(received_coap_header->options_list_ptr && 00321 received_coap_header->options_list_ptr->uri_query_ptr) { 00322 char *query = (char*)alloc_string_copy(received_coap_header->options_list_ptr->uri_query_ptr, 00323 received_coap_header->options_list_ptr->uri_query_len); 00324 if (query){ 00325 tr_debug("M2MObject::handle_put_request() - Query %s", query); 00326 // if anything was updated, re-initialize the stored notification attributes 00327 if (!handle_observation_attribute(query)){ 00328 tr_debug("M2MObject::handle_put_request() - Invalid query"); 00329 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 4.00 00330 } 00331 free(query); 00332 } 00333 } else { 00334 tr_error("M2MObject::handle_put_request() - COAP_MSG_CODE_RESPONSE_BAD_REQUEST - Empty URI_QUERY"); 00335 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 00336 } 00337 } else { 00338 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00339 } 00340 if(coap_response) { 00341 coap_response->msg_code = msg_code; 00342 } 00343 return coap_response; 00344 } 00345 00346 00347 sn_coap_hdr_s* M2MObject::handle_post_request(nsdl_s *nsdl, 00348 sn_coap_hdr_s *received_coap_header, 00349 M2MObservationHandler *observation_handler, 00350 bool &execute_value_updated) 00351 { 00352 tr_debug("M2MObject::handle_post_request()"); 00353 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 00354 // process the POST if we have registered a callback for it 00355 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, 00356 received_coap_header, 00357 msg_code); 00358 00359 if(received_coap_header) { 00360 if ((operation() & SN_GRS_POST_ALLOWED) != 0) { 00361 if(received_coap_header->payload_ptr) { 00362 tr_debug("M2MObject::handle_post_request() - Update Object with new values"); 00363 uint16_t coap_content_type = 0; 00364 bool content_type_present = false; 00365 if(received_coap_header->content_type_ptr) { 00366 content_type_present = true; 00367 if(coap_response) { 00368 coap_response->content_type_ptr = (uint8_t*)alloc_copy(received_coap_header->content_type_ptr, 00369 received_coap_header->content_type_len); 00370 if(coap_response->content_type_ptr) { 00371 coap_response->content_type_len = received_coap_header->content_type_len; 00372 for(uint8_t i = 0; i < coap_response->content_type_len; i++) { 00373 coap_content_type = (coap_content_type << 8) + 00374 (coap_response->content_type_ptr[i] & 0xFF); 00375 } 00376 } 00377 } 00378 } // if(received_coap_header->content_type_ptr) 00379 if(!content_type_present && 00380 M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE) { 00381 coap_content_type = COAP_CONTENT_OMA_TLV_TYPE; 00382 } 00383 00384 tr_debug("M2MObject::handle_post_request() - Request Content-Type %d", coap_content_type); 00385 00386 if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type) { 00387 uint16_t instance_id = 0; 00388 // Check next free instance id 00389 for(instance_id = 0; instance_id <= _max_instance_count; instance_id++) { 00390 if(NULL == object_instance(instance_id)) { 00391 break; 00392 } 00393 if(instance_id == _max_instance_count) { 00394 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00395 break; 00396 } 00397 } 00398 if(COAP_MSG_CODE_RESPONSE_CHANGED == msg_code) { 00399 M2MTLVDeserializer *deserializer = new M2MTLVDeserializer(); 00400 bool is_obj_instance = false; 00401 bool obj_instance_exists = false; 00402 if (deserializer) { 00403 is_obj_instance = deserializer->is_object_instance(received_coap_header->payload_ptr); 00404 if (is_obj_instance) { 00405 instance_id = deserializer->instance_id(received_coap_header->payload_ptr); 00406 tr_debug("M2MObject::handle_post_request() - instance id in TLV: %d", instance_id); 00407 // Check if instance id already exists 00408 if (object_instance(instance_id)){ 00409 obj_instance_exists = true; 00410 } 00411 } 00412 } 00413 if (!obj_instance_exists) { 00414 M2MObjectInstance *obj_instance = create_object_instance(instance_id); 00415 if(obj_instance) { 00416 obj_instance->set_operation(M2MBase::GET_PUT_ALLOWED); 00417 } 00418 00419 if(deserializer) { 00420 String obj_name = ""; 00421 M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; 00422 if(is_obj_instance) { 00423 tr_debug("M2MObject::handle_post_request() - TLV data contains ObjectInstance"); 00424 error = deserializer->deserialise_object_instances(received_coap_header->payload_ptr, 00425 received_coap_header->payload_len, 00426 *this, 00427 M2MTLVDeserializer::Post); 00428 } else if(deserializer->is_resource(received_coap_header->payload_ptr) || 00429 deserializer->is_multiple_resource(received_coap_header->payload_ptr)) { 00430 tr_debug("M2MObject::handle_post_request() - TLV data contains Resources"); 00431 error = deserializer->deserialize_resources(received_coap_header->payload_ptr, 00432 received_coap_header->payload_len, 00433 *obj_instance, 00434 M2MTLVDeserializer::Post); 00435 } else { 00436 error = M2MTLVDeserializer::NotValid; 00437 } 00438 switch(error) { 00439 case M2MTLVDeserializer::None: 00440 if(observation_handler) { 00441 execute_value_updated = true; 00442 } 00443 coap_response->options_list_ptr = (sn_coap_options_list_s*)malloc(sizeof(sn_coap_options_list_s)); 00444 if (coap_response->options_list_ptr) { 00445 memset(coap_response->options_list_ptr, 0, sizeof(sn_coap_options_list_s)); 00446 00447 obj_name = M2MBase::name(); 00448 obj_name.push_back('/'); 00449 obj_name.append_int(instance_id); 00450 00451 coap_response->options_list_ptr->location_path_len = obj_name.length(); 00452 if (coap_response->options_list_ptr->location_path_len != 0) { 00453 coap_response->options_list_ptr->location_path_ptr = 00454 (uint8_t*)malloc(coap_response->options_list_ptr->location_path_len); 00455 if (coap_response->options_list_ptr->location_path_ptr) { 00456 memcpy(coap_response->options_list_ptr->location_path_ptr, 00457 obj_name.c_str(), 00458 coap_response->options_list_ptr->location_path_len); 00459 } 00460 } 00461 } 00462 msg_code = COAP_MSG_CODE_RESPONSE_CREATED; 00463 break; 00464 case M2MTLVDeserializer::NotAllowed: 00465 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00466 break; 00467 case M2MTLVDeserializer::NotValid: 00468 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 00469 break; 00470 case M2MTLVDeserializer::NotFound: 00471 msg_code = COAP_MSG_CODE_RESPONSE_NOT_FOUND; 00472 break; 00473 } 00474 } 00475 } else { 00476 tr_debug("M2MObject::handle_post_request() - COAP_MSG_CODE_RESPONSE_BAD_REQUEST"); 00477 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 00478 } 00479 delete deserializer; 00480 } 00481 } else { 00482 msg_code =COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; 00483 } // if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type) 00484 } else { 00485 tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_BAD_REQUEST - Missing Payload"); 00486 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 00487 } 00488 } else { // if ((object->operation() & SN_GRS_POST_ALLOWED) != 0) 00489 tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00490 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; // 4.05 00491 } 00492 } else { //if(received_coap_header) 00493 tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00494 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; // 4.05 00495 } 00496 00497 if(coap_response) { 00498 coap_response->msg_code = msg_code; 00499 } 00500 return coap_response; 00501 } 00502 00503 void M2MObject::notification_update(uint16_t obj_instance_id) 00504 { 00505 tr_debug("M2MObject::notification_update - id: %d", obj_instance_id); 00506 M2MReportHandler *report_handler = M2MBase::report_handler(); 00507 if(report_handler && is_under_observation()) { 00508 report_handler->set_notification_trigger(obj_instance_id); 00509 } 00510 } 00511
Generated on Tue Jul 12 2022 13:05:11 by
1.7.2