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