mbed client lightswitch demo

Dependencies:   mbed Socket lwip-eth lwip-sys lwip

Fork of mbed-client-classic-example-lwip by Austin Blackstone

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers m2mresource.cpp Source File

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 }