Ram Gandikota / Mbed OS ABCD
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers m2mobject.cpp Source File

m2mobject.cpp

00001 /*
00002  * Copyright (c) 2015 ARM Limited. All rights reserved.
00003  * SPDX-License-Identifier: Apache-2.0
00004  * Licensed under the Apache License, Version 2.0 (the License); you may
00005  * not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  * http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
00012  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include "mbed-client/m2mobject.h"
00017 #include "mbed-client/m2mobservationhandler.h"
00018 #include "mbed-client/m2mconstants.h"
00019 #include "include/m2mtlvserializer.h"
00020 #include "include/m2mtlvdeserializer.h"
00021 #include "include/m2mreporthandler.h"
00022 #include "mbed-trace/mbed_trace.h"
00023 #include "mbed-client/m2mstringbuffer.h"
00024 
00025 #include <stdlib.h>
00026 
00027 #define BUFFER_SIZE 10
00028 #define TRACE_GROUP "mClt"
00029 
00030 M2MObject::M2MObject(const String &object_name, char *path, bool external_blockwise_store)
00031 : M2MBase(object_name,
00032           M2MBase::Dynamic,
00033           "",
00034           path,
00035           external_blockwise_store),
00036   _max_instance_count(MAX_UNINT_16_COUNT)
00037 {
00038     M2MBase::set_base_type(M2MBase::Object);
00039     if(M2MBase::name_id() != -1) {
00040         M2MBase::set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE);
00041     }
00042 }
00043 
00044 M2MObject::M2MObject(const M2MBase::lwm2m_parameters_s* static_res)
00045 : M2MBase(static_res),
00046   _max_instance_count(MAX_UNINT_16_COUNT)
00047 {
00048     if(static_res->name_id != -1) {
00049         M2MBase::set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE);
00050     }
00051 }
00052 
00053 M2MObject::~M2MObject()
00054 {
00055     if(!_instance_list.empty()) {
00056 
00057         M2MObjectInstanceList::const_iterator it;
00058         it = _instance_list.begin();
00059         M2MObjectInstance* obj = NULL;
00060         uint16_t index = 0;
00061         for (; it!=_instance_list.end(); it++, index++ ) {
00062             //Free allocated memory for object instances.
00063             obj = *it;
00064             delete obj;
00065         }
00066 
00067         _instance_list.clear();
00068     }
00069 }
00070 
00071 M2MObjectInstance* M2MObject::create_object_instance(uint16_t instance_id)
00072 {
00073     tr_debug("M2MObject::create_object_instance - id: %d", instance_id);
00074     M2MObjectInstance *instance = NULL;
00075     if(!object_instance(instance_id)) {
00076         char* path = create_path(*this, instance_id);
00077         // Note: the object instance's name contains actually object's name.
00078         instance = new M2MObjectInstance(*this, this->name(), "", path);
00079         if(instance) {
00080             instance->add_observation_level(observation_level());
00081             instance->set_instance_id(instance_id);
00082             if(M2MBase::name_id() != -1) {
00083                 instance->set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE);
00084             }
00085             _instance_list.push_back(instance);
00086         }
00087     }
00088     return instance;
00089 }
00090 
00091 // KS: is this needed for object instance?? TODO!
00092 M2MObjectInstance* M2MObject::create_object_instance(const lwm2m_parameters_s* s)
00093 {
00094     tr_debug("M2MObject::create_object_instance - id: %d", s->instance_id);
00095     M2MObjectInstance *instance = NULL;
00096     if(!object_instance(s->instance_id)) {
00097 
00098         instance = new M2MObjectInstance(*this, s);
00099         if(instance) {
00100             instance->add_observation_level(observation_level());
00101             //instance->set_instance_id(instance_id);
00102             //if(M2MBase::name_id() != -1) {
00103               //  instance->set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE);
00104             //}
00105             _instance_list.push_back(instance);
00106         }
00107     }
00108     return instance;
00109 }
00110 
00111 bool M2MObject::remove_object_instance(uint16_t inst_id)
00112 {
00113     tr_debug("M2MObject::remove_object_instance(inst_id %d)", inst_id);
00114     bool success = false;
00115     if(!_instance_list.empty()) {
00116         M2MObjectInstance* obj = NULL;
00117         M2MObjectInstanceList::const_iterator it;
00118         it = _instance_list.begin();
00119         int pos = 0;
00120         for ( ; it != _instance_list.end(); it++, pos++ ) {
00121             if((*it)->instance_id() == inst_id) {
00122                 // Instance found and deleted.
00123                 obj = *it;
00124 
00125                 _instance_list.erase(pos);
00126                 delete obj;
00127                 success = true;
00128                 break;
00129             }
00130         }
00131     }
00132     return success;
00133 }
00134 
00135 M2MObjectInstance* M2MObject::object_instance(uint16_t inst_id) const
00136 {
00137     tr_debug("M2MObject::object_instance(inst_id %d)", inst_id);
00138     M2MObjectInstance *obj = NULL;
00139     if(!_instance_list.empty()) {
00140         M2MObjectInstanceList::const_iterator it;
00141         it = _instance_list.begin();
00142         for ( ; it != _instance_list.end(); it++ ) {
00143             if((*it)->instance_id() == inst_id) {
00144                 // Instance found.
00145                 obj = *it;
00146                 break;
00147             }
00148         }
00149     }
00150     return obj;
00151 }
00152 
00153 const M2MObjectInstanceList& M2MObject::instances() const
00154 {
00155     return _instance_list;
00156 }
00157 
00158 uint16_t M2MObject::instance_count() const
00159 {
00160     return (uint16_t)_instance_list.size();
00161 }
00162 
00163 M2MBase::BaseType M2MObject::base_type() const
00164 {
00165     return M2MBase::base_type();
00166 }
00167 
00168 void M2MObject::add_observation_level(M2MBase::Observation observation_level)
00169 {
00170     M2MBase::add_observation_level(observation_level);
00171     if(!_instance_list.empty()) {
00172          M2MObjectInstanceList::const_iterator it;
00173          it = _instance_list.begin();
00174          for ( ; it != _instance_list.end(); it++ ) {
00175              (*it)->add_observation_level(observation_level);
00176          }
00177     }
00178 }
00179 
00180 void M2MObject::remove_observation_level(M2MBase::Observation observation_level)
00181 {
00182     M2MBase::remove_observation_level(observation_level);
00183     if(!_instance_list.empty()) {
00184         M2MObjectInstanceList::const_iterator it;
00185         it = _instance_list.begin();
00186         for ( ; it != _instance_list.end(); it++ ) {
00187             (*it)->remove_observation_level(observation_level);
00188         }
00189     }
00190 }
00191 
00192 sn_coap_hdr_s* M2MObject::handle_get_request(nsdl_s *nsdl,
00193                                              sn_coap_hdr_s *received_coap_header,
00194                                              M2MObservationHandler *observation_handler)
00195 {
00196     tr_debug("M2MObject::handle_get_request()");
00197     sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CONTENT;
00198     sn_coap_hdr_s * coap_response = sn_nsdl_build_response(nsdl,
00199                                                            received_coap_header,
00200                                                            msg_code);
00201     uint8_t * data = NULL;
00202     uint32_t  data_length = 0;
00203     if(received_coap_header) {
00204         // process the GET if we have registered a callback for it
00205         if ((operation() & SN_GRS_GET_ALLOWED) != 0) {
00206             if(coap_response) {
00207                 uint16_t coap_content_type = 0;
00208                 bool content_type_present = false;
00209                 if(received_coap_header->content_format != COAP_CT_NONE) {
00210                     content_type_present = true;
00211                     coap_content_type = received_coap_header->content_format;
00212                 }
00213                 if(!content_type_present &&
00214                    M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE) {
00215                     coap_content_type = COAP_CONTENT_OMA_TLV_TYPE;
00216                 }
00217 
00218                 tr_debug("M2MObject::handle_get_request() - Request Content-Type %d", coap_content_type);
00219                 if (coap_response->content_format == COAP_CT_NONE) {
00220                     coap_response->content_format = sn_coap_content_format_e(coap_content_type);
00221 
00222                     if (coap_response->content_format != COAP_CT_NONE) {
00223                         set_coap_content_type(coap_content_type);
00224                     }
00225                 }
00226                 // fill in the CoAP response payload
00227                 if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type) {
00228                     M2MTLVSerializer serializer;
00229                     data = serializer.serialize(_instance_list, data_length);
00230 
00231                 } else { // TOD0: Implement JSON Format.
00232                     msg_code = COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; // Content format not supported
00233                 }
00234 
00235                 coap_response->payload_len = data_length;
00236                 coap_response->payload_ptr = data;
00237 
00238                 coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response);
00239 
00240                 coap_response->options_list_ptr->max_age = max_age();
00241 
00242                 if(data){
00243                     if(received_coap_header->options_list_ptr) {
00244                         if(received_coap_header->options_list_ptr->observe != -1) {
00245                             if (is_observable()) {
00246                                 uint32_t number = 0;
00247                                 uint8_t observe_option = 0;
00248                                 observe_option = received_coap_header->options_list_ptr->observe;
00249 
00250                                 if(START_OBSERVATION == observe_option) {
00251                                     tr_debug("M2MObject::handle_get_request - Starts Observation");
00252                                     // If the observe length is 0 means register for observation.
00253                                     if(received_coap_header->options_list_ptr->observe != -1) {
00254                                         number = received_coap_header->options_list_ptr->observe;
00255                                     }
00256                                     if(received_coap_header->token_ptr) {
00257                                         tr_debug("M2MObject::handle_get_request - Sets Observation Token to resource");
00258                                         set_observation_token(received_coap_header->token_ptr,
00259                                                               received_coap_header->token_len);
00260                                     }
00261 
00262                                     // If the observe value is 0 means register for observation.
00263                                     if(number == 0) {
00264                                         tr_debug("M2MObject::handle_get_request - Put Resource under Observation");
00265                                         set_under_observation(true,observation_handler);
00266                                         add_observation_level(M2MBase::O_Attribute);
00267                                         tr_debug("M2MObject::handle_get_request - Observation Number %d", observation_number());
00268                                         coap_response->options_list_ptr->observe = observation_number();
00269                                     }
00270                                 } else if (STOP_OBSERVATION == observe_option) {
00271                                     tr_debug("M2MObject::handle_get_request - Stops Observation");
00272                                     // If the observe options_list_ptr->observe value is 1 means de-register from observation.
00273                                     set_under_observation(false,NULL);
00274                                     remove_observation_level(M2MBase::O_Attribute);
00275                                 }
00276                                 msg_code = COAP_MSG_CODE_RESPONSE_CONTENT;
00277                             }
00278                             else {
00279                                 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
00280                             }
00281                         }
00282                     }
00283                 } else {
00284                     msg_code = COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; // Content format not supported
00285                 }
00286             }
00287         }else {
00288             tr_error("M2MResource::handle_get_request - Return COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED");
00289             // Operation is not allowed.
00290             msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
00291         }
00292     } else {
00293         msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
00294     }
00295     if(coap_response) {
00296         coap_response->msg_code = msg_code;
00297     }
00298     return coap_response;
00299 }
00300 
00301 sn_coap_hdr_s* M2MObject::handle_put_request(nsdl_s *nsdl,
00302                                              sn_coap_hdr_s *received_coap_header,
00303                                              M2MObservationHandler */*observation_handler*/,
00304                                              bool &/*execute_value_updated*/)
00305 {
00306     tr_debug("M2MObject::handle_put_request()");
00307     sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04
00308     sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl,
00309                                                           received_coap_header,
00310                                                           msg_code);
00311     if(received_coap_header) {
00312         if(received_coap_header->options_list_ptr &&
00313            received_coap_header->options_list_ptr->uri_query_ptr) {
00314             char *query = (char*)alloc_string_copy(received_coap_header->options_list_ptr->uri_query_ptr,
00315                                                     received_coap_header->options_list_ptr->uri_query_len);
00316             if (query){
00317                 tr_debug("M2MObject::handle_put_request() - Query %s", query);
00318                 // if anything was updated, re-initialize the stored notification attributes
00319                 if (!handle_observation_attribute(query)){
00320                     tr_debug("M2MObject::handle_put_request() - Invalid query");
00321                     msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 4.00
00322                 }
00323                 free(query);
00324             }
00325         } else {
00326             tr_error("M2MObject::handle_put_request() - COAP_MSG_CODE_RESPONSE_BAD_REQUEST - Empty URI_QUERY");
00327             msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
00328         }
00329     } else {
00330         msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
00331     }
00332     if(coap_response) {
00333         coap_response->msg_code = msg_code;
00334     }
00335     return coap_response;
00336 }
00337 
00338 
00339 sn_coap_hdr_s* M2MObject::handle_post_request(nsdl_s *nsdl,
00340                                               sn_coap_hdr_s *received_coap_header,
00341                                               M2MObservationHandler *observation_handler,
00342                                               bool &execute_value_updated,
00343                                               sn_nsdl_addr_s *)
00344 {
00345     tr_debug("M2MObject::handle_post_request()");
00346     sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04
00347     // process the POST if we have registered a callback for it
00348     sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl,
00349                                       received_coap_header,
00350                                       msg_code);
00351 
00352     if(received_coap_header) {
00353         if ((operation() & SN_GRS_POST_ALLOWED) != 0) {
00354             if(received_coap_header->payload_ptr) {
00355                 tr_debug("M2MObject::handle_post_request() - Update Object with new values");
00356                 uint16_t coap_content_type = 0;
00357                 bool content_type_present = false;
00358                 if(received_coap_header->content_format != COAP_CT_NONE) {
00359                     content_type_present = true;
00360                     if(coap_response) {
00361                         coap_content_type = received_coap_header->content_format;
00362                     }
00363                 } // if(received_coap_header->content_format)
00364                 if(!content_type_present &&
00365                    M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE) {
00366                     coap_content_type = COAP_CONTENT_OMA_TLV_TYPE;
00367                 }
00368 
00369                 tr_debug("M2MObject::handle_post_request() - Request Content-Type %d", coap_content_type);
00370 
00371                 if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type) {
00372                     uint16_t instance_id = 0;
00373                     // Check next free instance id
00374                     for(instance_id = 0; instance_id <= _max_instance_count; instance_id++) {
00375                         if(NULL == object_instance(instance_id)) {
00376                             break;
00377                         }
00378                         if(instance_id == _max_instance_count) {
00379                             msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
00380                             break;
00381                         }
00382                     }
00383                     if(COAP_MSG_CODE_RESPONSE_CHANGED == msg_code) {
00384                         M2MTLVDeserializer deserializer;
00385                         bool is_obj_instance = false;
00386                         bool obj_instance_exists = false;
00387                         is_obj_instance = deserializer.is_object_instance(received_coap_header->payload_ptr);
00388                         if (is_obj_instance) {
00389                             instance_id = deserializer.instance_id(received_coap_header->payload_ptr);
00390                             tr_debug("M2MObject::handle_post_request() - instance id in TLV: %d", instance_id);
00391                             // Check if instance id already exists
00392                             if (object_instance(instance_id)){
00393                                 obj_instance_exists = true;
00394                             }
00395                         }
00396                         if (!obj_instance_exists) {
00397                             M2MObjectInstance *obj_instance = create_object_instance(instance_id);
00398                             if(obj_instance) {
00399                                 obj_instance->set_operation(M2MBase::GET_PUT_ALLOWED);
00400                             }
00401 
00402                             M2MTLVDeserializer::Error error = M2MTLVDeserializer::None;
00403                             if(is_obj_instance) {
00404                                 tr_debug("M2MObject::handle_post_request() - TLV data contains ObjectInstance");
00405                                 error = deserializer.deserialise_object_instances(received_coap_header->payload_ptr,
00406                                                                            received_coap_header->payload_len,
00407                                                                            *this,
00408                                                                            M2MTLVDeserializer::Post);
00409                             } else if(obj_instance &&
00410                                         (deserializer.is_resource(received_coap_header->payload_ptr) ||
00411                                          deserializer.is_multiple_resource(received_coap_header->payload_ptr))) {
00412                                 tr_debug("M2MObject::handle_post_request() - TLV data contains Resources");
00413                                 error = deserializer.deserialize_resources(received_coap_header->payload_ptr,
00414                                                                             received_coap_header->payload_len,
00415                                                                             *obj_instance,
00416                                                                             M2MTLVDeserializer::Post);
00417                             } else {
00418                                 error = M2MTLVDeserializer::NotValid;
00419                             }
00420                             switch(error) {
00421                                 case M2MTLVDeserializer::None:
00422                                     if(observation_handler) {
00423                                         execute_value_updated = true;
00424                                     }
00425                                     coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response);
00426 
00427                                     if (coap_response->options_list_ptr) {
00428 
00429                                         StringBuffer<MAX_OBJECT_PATH_NAME> obj_name;
00430 
00431                                         if (obj_name.ensure_space(M2MBase::resource_name_length() + (1 + 5 + 1))) {
00432                                             obj_name.append(M2MBase::name());
00433                                             obj_name.append('/');
00434                                             obj_name.append_int(instance_id);
00435 
00436                                             coap_response->options_list_ptr->location_path_len = obj_name.get_size();
00437                                             coap_response->options_list_ptr->location_path_ptr =
00438                                                     alloc_copy((uint8_t*)obj_name.c_str(), obj_name.get_size());
00439                                             // todo: else return error
00440                                         }
00441                                     }
00442                                     // todo: else return error
00443                                     msg_code = COAP_MSG_CODE_RESPONSE_CREATED;
00444                                     break;
00445                                 case M2MTLVDeserializer::NotAllowed:
00446                                     msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
00447                                     break;
00448                                 case M2MTLVDeserializer::NotValid:
00449                                     msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
00450                                     break;
00451                                 case M2MTLVDeserializer::NotFound:
00452                                     msg_code = COAP_MSG_CODE_RESPONSE_NOT_FOUND;
00453                                     break;
00454                             }
00455 
00456                         } else {
00457                             tr_debug("M2MObject::handle_post_request() - COAP_MSG_CODE_RESPONSE_BAD_REQUEST");
00458                             msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
00459                         }
00460                     }
00461                 } else {
00462                     msg_code =COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT;
00463                 } // if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type)
00464             } else {
00465                 tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_BAD_REQUEST - Missing Payload");
00466                 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; //
00467             }
00468         } else { // if ((object->operation() & SN_GRS_POST_ALLOWED) != 0)
00469             tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED");
00470             msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; // 4.05
00471         }
00472     } else { //if(received_coap_header)
00473         tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED");
00474         msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; // 4.05
00475     }
00476 
00477     if(coap_response) {
00478         coap_response->msg_code = msg_code;
00479     }
00480     return coap_response;
00481 }
00482 
00483 void M2MObject::notification_update(uint16_t obj_instance_id)
00484 {
00485     tr_debug("M2MObject::notification_update - id: %d", obj_instance_id);
00486     M2MReportHandler *report_handler = M2MBase::report_handler();
00487     if(report_handler && is_under_observation()) {
00488         report_handler->set_notification_trigger(obj_instance_id);
00489     }
00490 }
00491