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