Austin Blackstone / Mbed 2 deprecated mbed-client-classic-example-lwip

Dependencies:   mbed Socket lwip-eth lwip-sys lwip

Fork of mbed-client-classic-example-lwip by sandbox

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers m2mresourceinstance.cpp Source File

m2mresourceinstance.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 <stdlib.h>
00017 #include "mbed-client/m2mresource.h"
00018 #include "mbed-client/m2mconstants.h"
00019 #include "mbed-client/m2mobservationhandler.h"
00020 #include "mbed-client/m2mobjectinstance.h"
00021 #include "include/m2mreporthandler.h"
00022 #include "include/nsdllinker.h"
00023 #include "ns_trace.h"
00024 
00025 M2MResourceInstance& M2MResourceInstance::operator=(const M2MResourceInstance& other)
00026 {
00027     if (this != &other) { // protect against invalid self-assignment
00028 
00029         if(_value) {
00030             free(_value);
00031             _value = NULL;
00032             _value_length = 0;
00033         }
00034         _value_length = other._value_length;
00035         if(other._value) {
00036             _value = (uint8_t *)malloc(other._value_length+1);
00037             if(_value) {
00038                 memset(_value, 0, other._value_length+1);
00039                 memcpy((uint8_t *)_value, (uint8_t *)other._value, other._value_length);
00040             }
00041         }
00042     }
00043     return *this;
00044 }
00045 
00046 M2MResourceInstance::M2MResourceInstance(const M2MResourceInstance& other)
00047 : M2MBase(other),
00048   _object_instance_callback(other._object_instance_callback),
00049   _execute_callback(NULL),
00050   _value(NULL),
00051   _value_length(0),
00052   _resource_type(M2MResourceInstance::STRING),
00053   _resource_callback(NULL)
00054 {
00055     this->operator=(other);
00056 }
00057 
00058 M2MResourceInstance::M2MResourceInstance(const String &res_name,
00059                                          const String &resource_type,
00060                                          M2MResourceInstance::ResourceType type,
00061                                          M2MObjectInstanceCallback &object_instance_callback)
00062 : M2MBase(res_name,
00063           M2MBase::Dynamic),
00064  _object_instance_callback(object_instance_callback),
00065  _execute_callback(NULL),
00066  _value(NULL),
00067  _value_length(0),
00068  _resource_type(type),
00069  _resource_callback(NULL)
00070 {
00071     M2MBase::set_resource_type(resource_type);
00072     M2MBase::set_base_type(M2MBase::ResourceInstance);
00073 }
00074 
00075 M2MResourceInstance::M2MResourceInstance(const String &res_name,
00076                                          const String &resource_type,
00077                                          M2MResourceInstance::ResourceType type,
00078                                          const uint8_t *value,
00079                                          const uint8_t value_length,
00080                                          M2MObjectInstanceCallback &object_instance_callback)
00081 : M2MBase(res_name,
00082           M2MBase::Static),
00083  _object_instance_callback(object_instance_callback),
00084  _execute_callback(NULL),
00085  _value(NULL),
00086  _value_length(0),
00087  _resource_type(type),
00088  _resource_callback(NULL)
00089 {
00090     M2MBase::set_resource_type(resource_type);
00091     M2MBase::set_base_type(M2MBase::Resource);
00092     if( value != NULL && value_length > 0 ) {
00093         _value = (uint8_t *)malloc(value_length+1);
00094         if(_value) {
00095             memset(_value, 0, value_length+1);
00096             memcpy((uint8_t *)_value, (uint8_t *)value, value_length);
00097             _value_length = value_length;
00098         }
00099     }
00100 }
00101 
00102 M2MResourceInstance::~M2MResourceInstance()
00103 {
00104     if(_value) {
00105         free(_value);
00106         _value = NULL;
00107         _value_length = 0;
00108     }
00109     _resource_callback = NULL;
00110 }
00111 
00112 M2MBase::BaseType M2MResourceInstance::base_type() const
00113 {
00114     return M2MBase::base_type();
00115 }
00116 
00117 M2MResourceInstance::ResourceType M2MResourceInstance::resource_instance_type() const
00118 {
00119     return _resource_type;
00120 }
00121 
00122 bool M2MResourceInstance::handle_observation_attribute(char *&query)
00123 {
00124     tr_debug("M2MResourceInstance::handle_observation_attribute()");
00125     bool success = false;
00126     M2MReportHandler *handler = M2MBase::report_handler();
00127     if (handler) {
00128         success = handler->parse_notification_attribute(query,
00129                 M2MBase::base_type(), _resource_type);
00130         if (success) {
00131             if ((handler->attribute_flags() & M2MReportHandler::Cancel) == 0) {
00132                 handler->set_under_observation(true);
00133             } else {
00134                 handler->set_under_observation(false);
00135             }
00136         }
00137         else {
00138             handler->set_default_values();
00139         }
00140     }
00141     return success;
00142 }
00143 
00144 void M2MResourceInstance::set_execute_function(execute_callback  callback)
00145 {
00146     _execute_callback = callback;
00147 }
00148 
00149 void M2MResourceInstance::clear_value()
00150 {
00151     tr_debug("M2MResourceInstance::clear_value");
00152     if(_value) {
00153          free(_value);
00154          _value = NULL;
00155          _value_length = 0;
00156     }
00157     report();
00158 }
00159 
00160 bool M2MResourceInstance::set_value(const uint8_t *value,
00161                                     const uint32_t value_length)
00162 {
00163     tr_debug("M2MResourceInstance::set_value()");
00164     bool success = false;
00165     bool string_value_changed = false;
00166     if(_resource_type == M2MResourceInstance::STRING) {
00167         if(is_value_changed(value,value_length)) {
00168             string_value_changed = true;
00169         }
00170     }
00171     if( value != NULL && value_length > 0 ) {
00172         success = true;
00173         if(_value) {
00174              free(_value);
00175              _value = NULL;
00176              _value_length = 0;
00177         }
00178         _value = (uint8_t *)malloc(value_length+1);
00179         if(_value) {
00180             memset(_value, 0, value_length+1);
00181             memcpy((uint8_t *)_value, (uint8_t *)value, value_length);
00182             _value_length = value_length;
00183             if(string_value_changed) {
00184                 M2MReportHandler *report_handler = M2MBase::report_handler();
00185                 if(report_handler && is_observable()) {
00186                     report_handler->set_notification_trigger();
00187                 }
00188             } else {
00189                 report();
00190             }
00191         }
00192     }
00193 
00194     return success;
00195 }
00196 
00197 
00198 void M2MResourceInstance::report()
00199 {
00200     tr_debug("M2MResourceInstance::report()");
00201     M2MBase::Observation  observation_level = M2MBase::observation_level();
00202     if(M2MBase::O_Attribute == observation_level ||
00203        M2MBase::OI_Attribute == observation_level||
00204        M2MBase::OOI_Attribute == observation_level) {
00205         _object_instance_callback.notification_update(observation_level);
00206     }
00207 
00208     if(M2MBase::Dynamic == mode()) {
00209         if(!_resource_callback && _resource_type != M2MResourceInstance::STRING) {
00210             M2MReportHandler *report_handler = M2MBase::report_handler();
00211             if (report_handler && is_observable()) {
00212                 if(_value) {
00213                     report_handler->set_value(atof((const char*)_value));
00214                 } else {
00215                     report_handler->set_value(0);
00216                 }
00217             }
00218         }
00219         else {
00220             if (_resource_callback && base_type() == M2MBase::ResourceInstance) {
00221                 _resource_callback->notification_update();
00222             }
00223         }
00224     } else if(M2MBase::Static == mode()) {
00225         M2MObservationHandler *observation_handler = M2MBase::observation_handler();
00226         if(observation_handler) {
00227             observation_handler->value_updated(this);
00228         }
00229     } else {
00230         tr_debug("M2MResourceInstance::report() - mode = %d, is_observable = %d", mode(), is_observable());
00231     }
00232 }
00233 
00234 bool M2MResourceInstance::is_value_changed(const uint8_t* value, const uint32_t value_len)
00235 {
00236     tr_debug("M2MResourceInstance::is_value_changed()");
00237     bool changed = false;
00238     if(value_len != _value_length) {
00239         changed = true;
00240     } else if(value && !_value) {
00241         changed = true;
00242     } else if(_value && !value) {
00243         changed = true;
00244     } else {        
00245         if (_value) {
00246             String val((const char*)value);
00247             String tmp_val((const char*)_value);
00248             if(!(val == tmp_val)){
00249                 changed = true;
00250             }
00251         }
00252     }
00253     return changed;
00254 }
00255 
00256 void M2MResourceInstance::execute(void *arguments)
00257 {
00258     tr_debug("M2MResourceInstance::execute");
00259     if(_execute_callback) {
00260         _execute_callback(arguments);
00261     }
00262 }
00263 
00264 void M2MResourceInstance::get_value(uint8_t *&value, uint32_t &value_length)
00265 {
00266     value_length = 0;
00267     if(value) {
00268         free(value);
00269         value = NULL;
00270     }
00271     if(_value && _value_length > 0) {
00272         value = (uint8_t *)malloc(_value_length+1);
00273         if(value) {
00274             value_length = _value_length;
00275             memset(value, 0, _value_length+1);
00276             memcpy((uint8_t *)value, (uint8_t *)_value, value_length);
00277         }
00278     }
00279 }
00280 
00281 uint8_t* M2MResourceInstance::value() const
00282 {
00283     return _value;
00284 }
00285 
00286 uint32_t M2MResourceInstance::value_length() const
00287 {
00288     return _value_length;
00289 }
00290 
00291 sn_coap_hdr_s* M2MResourceInstance::handle_get_request(nsdl_s *nsdl,
00292                                                sn_coap_hdr_s *received_coap_header,
00293                                                M2MObservationHandler *observation_handler)
00294 {
00295     tr_debug("M2MResourceInstance::handle_get_request()");
00296     sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CONTENT;
00297     sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl,
00298                                                           received_coap_header,
00299                                                           msg_code);
00300     if(received_coap_header) {
00301         // process the GET if we have registered a callback for it
00302         if ((operation() & SN_GRS_GET_ALLOWED) != 0) {
00303             if(coap_response) {
00304                 coap_response->content_type_ptr = (uint8_t*)malloc(1);
00305                 if(coap_response->content_type_ptr) {
00306                     memset(coap_response->content_type_ptr, 0, 1);
00307                     coap_response->content_type_len = 1;
00308                 }
00309 
00310                 // fill in the CoAP response payload
00311                 coap_response->payload_ptr = NULL;
00312                 uint32_t payload_len = 0;
00313                 get_value(coap_response->payload_ptr,payload_len);
00314                 coap_response->payload_len = payload_len;
00315 
00316                 coap_response->options_list_ptr = (sn_coap_options_list_s*)malloc(sizeof(sn_coap_options_list_s));
00317                 memset(coap_response->options_list_ptr, 0, sizeof(sn_coap_options_list_s));
00318 
00319                 coap_response->options_list_ptr->max_age_ptr = (uint8_t*)malloc(1);
00320                 memset(coap_response->options_list_ptr->max_age_ptr,0,1);
00321                 coap_response->options_list_ptr->max_age_len = 1;
00322 
00323                 if(received_coap_header->token_ptr) {
00324                     tr_debug("M2MResourceInstance::handle_get_request - Sets Observation Token to resource");
00325                     set_observation_token(received_coap_header->token_ptr,
00326                                           received_coap_header->token_len);
00327                 }
00328 
00329                 if(received_coap_header->options_list_ptr) {
00330                     if(received_coap_header->options_list_ptr->observe) {
00331                         if (is_observable()) {
00332                             uint32_t number = 0;
00333                             uint8_t observe_option = 0;
00334                             if(received_coap_header->options_list_ptr->observe_ptr) {
00335                                 observe_option = *received_coap_header->options_list_ptr->observe_ptr;
00336                             }
00337                             if(START_OBSERVATION == observe_option) {
00338                                 tr_debug("M2MResourceInstance::handle_get_request - Starts Observation");
00339                                 // If the observe length is 0 means register for observation.
00340                                 if(received_coap_header->options_list_ptr->observe_len != 0) {
00341                                     for(int i=0;i < received_coap_header->options_list_ptr->observe_len; i++) {
00342                                         number = (*(received_coap_header->options_list_ptr->observe_ptr + i) & 0xff) <<
00343                                                  8*(received_coap_header->options_list_ptr->observe_len- 1 - i);
00344                                         }
00345                                 }
00346                                 // If the observe value is 0 means register for observation.
00347                                 if(number == 0) {
00348                                     tr_debug("M2MResourceInstance::handle_get_request - Put Resource under Observation");
00349                                     set_under_observation(true,observation_handler);
00350                                     M2MBase::add_observation_level(M2MBase::R_Attribute);
00351                                     uint8_t *obs_number = (uint8_t*)malloc(3);
00352                                     memset(obs_number,0,3);
00353                                     uint8_t observation_number_length = 1;
00354 
00355                                     uint16_t number = observation_number();
00356 
00357                                     tr_debug("M2MResourceInstance::handle_get_request - Observation Number %d", number);
00358                                     obs_number[0] = ((number>>8) & 0xFF);
00359                                     obs_number[1] = (number & 0xFF);
00360 
00361                                     if(number > 0xFF) {
00362                                         observation_number_length = 2;
00363                                     }
00364                                     coap_response->options_list_ptr->observe_ptr = obs_number;
00365                                     coap_response->options_list_ptr->observe_len = observation_number_length;
00366                                 }
00367                             } else if (STOP_OBSERVATION == observe_option) {
00368                                 tr_debug("M2MResourceInstance::handle_get_request - Stops Observation");
00369                                 set_under_observation(false,NULL);
00370                                 M2MBase::remove_observation_level(M2MBase::R_Attribute);
00371                             }
00372                         } else {
00373                             msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
00374                         }
00375                     }
00376                 }
00377             }
00378         }else {
00379             tr_error("M2MResourceInstance::handle_get_request - Return COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED");
00380             // Operation is not allowed.
00381             msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
00382         }
00383     } else {
00384         msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
00385     }
00386     if(coap_response) {
00387         coap_response->msg_code = msg_code;
00388     }
00389     return coap_response;
00390 }
00391 
00392 sn_coap_hdr_s* M2MResourceInstance::handle_put_request(nsdl_s *nsdl,
00393                                                sn_coap_hdr_s *received_coap_header,
00394                                                M2MObservationHandler *observation_handler)
00395 {
00396     tr_debug("M2MResourceInstance::handle_put_request()");
00397     sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04
00398     sn_coap_hdr_s * coap_response = sn_nsdl_build_response(nsdl,
00399                                                            received_coap_header,
00400                                                            msg_code);
00401     // process the PUT if we have registered a callback for it
00402     if(received_coap_header) {
00403         if ((operation() & SN_GRS_PUT_ALLOWED) != 0) {
00404             uint16_t coap_content_type = 0;
00405             if(received_coap_header->content_type_ptr) {
00406                 if(coap_response) {
00407                     coap_response->content_type_ptr = (uint8_t*)malloc(received_coap_header->content_type_len);
00408                     if(coap_response->content_type_ptr) {
00409                         memset(coap_response->content_type_ptr, 0, received_coap_header->content_type_len);
00410                         memcpy(coap_response->content_type_ptr,
00411                                received_coap_header->content_type_ptr,
00412                                received_coap_header->content_type_len);
00413                         coap_response->content_type_len = received_coap_header->content_type_len;
00414                         for(uint8_t i = 0; i < coap_response->content_type_len; i++) {
00415                             coap_content_type = (coap_content_type << 8) + (coap_response->content_type_ptr[i] & 0xFF);
00416                         }
00417                     }
00418                 }
00419             }
00420 
00421             tr_debug("M2MResourceInstance::handle_put_request() - Request Content-Type %d", coap_content_type);
00422 
00423             if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type) {
00424                 msg_code = COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT;
00425             } else {
00426                 set_value(received_coap_header->payload_ptr, received_coap_header->payload_len);
00427                 if(received_coap_header->payload_ptr) {
00428                    tr_debug("M2MResourceInstance::handle_put_request() - Update Resource with new values");
00429                     if(observation_handler) {
00430                         String value = "";
00431                         if (received_coap_header->uri_path_ptr != NULL &&
00432                             received_coap_header->uri_path_len > 0) {
00433                             char* buf = (char*)malloc(received_coap_header->uri_path_len+1);
00434                             if(buf) {
00435                                 memset(buf,0,received_coap_header->uri_path_len+1);
00436                                 memcpy(buf,received_coap_header->uri_path_ptr,received_coap_header->uri_path_len);
00437                                 value = String(buf);
00438                                 free(buf);
00439                             }
00440                         }
00441                         observation_handler->value_updated(this,value);
00442                     }
00443                 }
00444                 if(received_coap_header->options_list_ptr &&
00445                    received_coap_header->options_list_ptr->uri_query_ptr) {
00446                     char *query = (char*)malloc(received_coap_header->options_list_ptr->uri_query_len+1);
00447                     if (query){
00448                         memset(query, 0, received_coap_header->options_list_ptr->uri_query_len+1);
00449                         memcpy(query,
00450                             received_coap_header->options_list_ptr->uri_query_ptr,
00451                             received_coap_header->options_list_ptr->uri_query_len);
00452                         memset(query + received_coap_header->options_list_ptr->uri_query_len,'\0',1);//String terminator
00453                         tr_debug("M2MResourceInstance::handle_put_request() - Query %s", query);
00454                         // if anything was updated, re-initialize the stored notification attributes
00455                         if (!handle_observation_attribute(query)){
00456                             tr_debug("M2MResourceInstance::handle_put_request() - Invalid query");
00457                             msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 4.00
00458                         }
00459                         free(query);
00460                     }
00461                 }
00462             }
00463         } else {
00464             // Operation is not allowed.
00465             tr_error("M2MResourceInstance::handle_put_request() - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED");
00466             msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
00467         }
00468     } else {
00469         msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
00470     }
00471     if(coap_response) {
00472         coap_response->msg_code = msg_code;
00473     }
00474     return coap_response;
00475 }
00476 
00477 void M2MResourceInstance::set_resource_observer(M2MResourceCallback *resource)
00478 {
00479     _resource_callback = resource;
00480 }