sandbox / mbed-client

Fork of mbed-client by Christopher Haster

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