Simple interface for Mbed Cloud Client

Dependents:  

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers m2mresourcebase.cpp Source File

m2mresourcebase.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 
00017 // Needed for PRIu64 on FreeRTOS
00018 #include <stdio.h>
00019 // Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX
00020 #ifndef __STDC_LIMIT_MACROS
00021 #define __STDC_LIMIT_MACROS
00022 #endif
00023 
00024 // Note: this macro is needed on armcc to get the the PRI*32 macros
00025 // from inttypes.h in a C++ code.
00026 #ifndef __STDC_FORMAT_MACROS
00027 #define __STDC_FORMAT_MACROS
00028 #endif
00029 
00030 #include <stdlib.h>
00031 #include "mbed-client/m2mresourcebase.h"
00032 #include "mbed-client/m2mconstants.h"
00033 #include "mbed-client/m2mobservationhandler.h"
00034 #include "mbed-client/m2mobject.h"
00035 #include "mbed-client/m2mobjectinstance.h"
00036 #include "include/m2mcallbackstorage.h"
00037 #include "include/m2mreporthandler.h"
00038 #include "include/nsdllinker.h"
00039 #include "include/m2mtlvserializer.h"
00040 #include "mbed-client/m2mblockmessage.h"
00041 #include "mbed-trace/mbed_trace.h"
00042 
00043 #define TRACE_GROUP "mClt"
00044 
00045 M2MResourceBase::M2MResourceBase(
00046                                          const String &res_name,
00047                                          M2MBase::Mode resource_mode,
00048                                          const String &resource_type,
00049                                          M2MBase::DataType type,
00050                                          char* path,
00051                                          bool external_blockwise_store,
00052                                          bool multiple_instance)
00053 : M2MBase(res_name,
00054           resource_mode,
00055 #ifndef DISABLE_RESOURCE_TYPE
00056           resource_type,
00057 #endif
00058           path,
00059           external_blockwise_store,
00060           multiple_instance,
00061           type)
00062 #ifndef DISABLE_BLOCK_MESSAGE
00063  ,_block_message_data(NULL),
00064 #endif
00065   _notification_status(M2MResourceBase::INIT)
00066 {
00067 }
00068 
00069 M2MResourceBase::M2MResourceBase(
00070                                          const String &res_name,
00071                                          M2MBase::Mode resource_mode,
00072                                          const String &resource_type,
00073                                          M2MBase::DataType type,
00074                                          const uint8_t *value,
00075                                          const uint8_t value_length,
00076                                          char* path,
00077                                          bool external_blockwise_store,
00078                                          bool multiple_instance)
00079 : M2MBase(res_name,
00080           resource_mode,
00081 #ifndef DISABLE_RESOURCE_TYPE
00082           resource_type,
00083 #endif
00084           path,
00085           external_blockwise_store,
00086           multiple_instance,
00087           type)
00088 #ifndef DISABLE_BLOCK_MESSAGE
00089  ,_block_message_data(NULL),
00090 #endif
00091  _notification_status(M2MResourceBase::INIT)
00092 {
00093     M2MBase::set_base_type(M2MBase::ResourceInstance);
00094     if( value != NULL && value_length > 0 ) {
00095         sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource();
00096         res->resource = alloc_string_copy(value, value_length);
00097         res->resourcelen = value_length;
00098     }
00099 }
00100 
00101 M2MResourceBase::M2MResourceBase(
00102                                          const lwm2m_parameters_s* s,
00103                                          M2MBase::DataType /*type*/)
00104 : M2MBase(s)
00105 #ifndef DISABLE_BLOCK_MESSAGE
00106   ,_block_message_data(NULL),
00107 #endif
00108   _notification_status(M2MResourceBase::INIT)
00109 {
00110     // we are not there yet for this check as this is called from M2MResource(): assert(base_type() == M2MBase::ResourceInstance);
00111 }
00112 
00113 M2MResourceBase::~M2MResourceBase()
00114 {
00115     execute_callback* callback = (execute_callback*)M2MCallbackStorage::remove_callback(*this,
00116                                     M2MCallbackAssociation::M2MResourceInstanceExecuteCallback);
00117     delete callback;
00118 
00119     M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback2);
00120 #ifndef DISABLE_BLOCK_MESSAGE
00121     incoming_block_message_callback *in_callback = (incoming_block_message_callback*)M2MCallbackStorage::remove_callback(*this,
00122                                                         M2MCallbackAssociation::M2MResourceInstanceIncomingBlockMessageCallback);
00123     delete in_callback;
00124 
00125     outgoing_block_message_callback *out_callback = (outgoing_block_message_callback*)M2MCallbackStorage::remove_callback(*this,
00126                                                         M2MCallbackAssociation::M2MResourceInstanceOutgoingBlockMessageCallback);
00127     delete out_callback;
00128 #endif
00129 
00130     notification_sent_callback *notif_callback = (notification_sent_callback*)M2MCallbackStorage::remove_callback(*this,
00131                                                         M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback);
00132     delete notif_callback;
00133 
00134     M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback2);
00135 
00136     notification_status_callback *notif_status_callback = (notification_status_callback*)M2MCallbackStorage::remove_callback(*this,
00137                                                         M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback);
00138     delete notif_status_callback;
00139 
00140     M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback2);
00141 
00142 #ifndef DISABLE_BLOCK_MESSAGE
00143     delete _block_message_data;
00144 #endif
00145 }
00146 
00147 M2MResourceBase::ResourceType M2MResourceBase::resource_instance_type() const
00148 {
00149     M2MBase::lwm2m_parameters_s* param = M2MBase::get_lwm2m_parameters();
00150     M2MBase::DataType type = param->data_type;
00151     return convert_data_type(type);
00152 }
00153 
00154 
00155 bool M2MResourceBase::set_execute_function(execute_callback callback)
00156 {
00157     execute_callback* old_callback = (execute_callback*)M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback);
00158     delete old_callback;
00159     // XXX: create a copy of the copy of callback object. Perhaps it would better to
00160     // give a reference as parameter and just store that, as it would save some memory.
00161     execute_callback* new_callback = new execute_callback(callback);
00162 
00163     return M2MCallbackStorage::add_callback(*this, new_callback, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback);
00164 }
00165 
00166 bool M2MResourceBase::set_execute_function(execute_callback_2 callback)
00167 {
00168     M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback2);
00169 
00170     return M2MCallbackStorage::add_callback(*this, (void*)callback, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback2);
00171 }
00172 
00173 void M2MResourceBase::clear_value()
00174 {
00175     tr_debug("M2MResourceBase::clear_value");
00176     sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource();
00177     free(res->resource);
00178     res->resource = NULL;
00179     res->resourcelen = 0;
00180 
00181     report();
00182 }
00183 
00184 bool M2MResourceBase::set_value(int64_t value)
00185 {
00186     bool success;
00187     // max len of "-9223372036854775808" plus zero termination
00188     char buffer[20+1];
00189     uint32_t size = m2m::itoa_c(value, buffer);
00190 
00191     success = set_value((const uint8_t*)buffer, size);
00192 
00193     return success;
00194 }
00195 
00196 bool M2MResourceBase::set_value(const uint8_t *value,
00197                                 const uint32_t value_length)
00198 {
00199     tr_debug("M2MResourceBase::set_value()");
00200     bool success = false;
00201     bool changed = has_value_changed(value,value_length);
00202     if( value != NULL && value_length > 0 ) {
00203         sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource();
00204         free(res->resource);
00205         res->resource = NULL;
00206         res->resourcelen = 0;
00207         res->resource = alloc_string_copy(value, value_length);
00208         if(res->resource) {
00209             success = true;
00210             res->resourcelen = value_length;
00211             if (changed) {
00212                 report_value_change();
00213             }
00214         }
00215     }
00216     return success;
00217 }
00218 
00219 bool M2MResourceBase::set_value_raw(uint8_t *value,
00220                                 const uint32_t value_length)
00221 
00222 {
00223     tr_debug("M2MResourceBase::set_value_raw()");
00224     bool success = false;
00225     bool changed = has_value_changed(value,value_length);
00226     if( value != NULL && value_length > 0 ) {
00227         success = true;
00228         sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource();
00229         free(res->resource);
00230         res->resource = value;
00231         res->resourcelen = value_length;
00232         if (changed) {
00233             report_value_change();
00234         }
00235     }
00236     return success;
00237 }
00238 
00239 void M2MResourceBase::report()
00240 {
00241     M2MBase::Observation observation_level = M2MBase::observation_level();
00242     tr_debug("M2MResourceBase::report() - level %d", observation_level);
00243 
00244     // We must combine the parent object/objectinstance/resource observation information
00245     // when determining if there is observation set or not.
00246     M2MObjectInstance& object_instance = get_parent_resource().get_parent_object_instance();
00247     int parent_observation_level = (int)object_instance.observation_level();
00248 
00249     parent_observation_level |= (int)object_instance.get_parent_object().observation_level();
00250     parent_observation_level |= (int)get_parent_resource().observation_level();
00251     parent_observation_level |= (int)observation_level;
00252 
00253     tr_debug("M2MResourceBase::report() - combined level %d", parent_observation_level);
00254 
00255     if((M2MBase::O_Attribute & parent_observation_level) == M2MBase::O_Attribute ||
00256        (M2MBase::OI_Attribute & parent_observation_level) == M2MBase::OI_Attribute) {
00257         tr_debug("M2MResourceBase::report() -- object/instance level");
00258         M2MObjectInstance& object_instance = get_parent_resource().get_parent_object_instance();
00259         object_instance.notification_update((M2MBase::Observation)parent_observation_level);
00260     }
00261 
00262     if(M2MBase::Dynamic == mode() &&
00263        (M2MBase::R_Attribute & parent_observation_level) == M2MBase::R_Attribute) {
00264         tr_debug("M2MResourceBase::report() - resource level");
00265 
00266         if (((resource_instance_type() != M2MResourceBase::STRING) &&
00267              (resource_instance_type() != M2MResourceBase::OPAQUE)) &&
00268              (observation_level != M2MBase::None)) {
00269             M2MReportHandler *report_handler = M2MBase::report_handler();
00270             if (report_handler && is_observable()) {
00271                 sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource();
00272                 if(res->resource) {
00273                     report_handler->set_value(atof((const char*)res->resource));
00274                 } else {
00275                     report_handler->set_value(0);
00276                 }
00277             }
00278         }
00279         else {
00280             if (base_type() == M2MBase::ResourceInstance) {
00281                 const M2MResource& parent_resource = get_parent_resource();
00282                 M2MReportHandler *report_handler = parent_resource.report_handler();
00283                 if(report_handler && parent_resource.is_observable()) {
00284                     report_handler->set_notification_trigger(parent_resource.get_parent_object_instance().instance_id());
00285                 }
00286             }
00287         }
00288     } else if(M2MBase::Static == mode()) {
00289         M2MObservationHandler *obs_handler = observation_handler();
00290         if(obs_handler) {
00291             obs_handler->value_updated(this);
00292         }
00293     } else {
00294         if (is_observable()) {
00295             tr_warn("M2MResourceBase::report() - resource %s is observable but not yet subscribed!", uri_path());
00296         }
00297         tr_debug("M2MResourceBase::report() - mode = %d, is_observable = %d", mode(), is_observable());
00298     }
00299 }
00300 
00301 bool M2MResourceBase::has_value_changed(const uint8_t* value, const uint32_t value_len)
00302 {
00303     bool changed = false;
00304     sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource();
00305 
00306     if(value_len != res->resourcelen) {
00307         changed = true;
00308     } else if(value && !res->resource) {
00309         changed = true;
00310     } else if(res->resource && !value) {
00311         changed = true;
00312     } else {
00313         if (res->resource) {
00314             if (memcmp(value, res->resource, res->resourcelen) != 0) {
00315                 changed = true;
00316             }
00317         }
00318     }
00319     return changed;
00320 }
00321 
00322 void M2MResourceBase::report_value_change()
00323 {
00324     if (resource_instance_type() == M2MResourceBase::STRING ||
00325         resource_instance_type() == M2MResourceBase::OPAQUE) {
00326         M2MReportHandler *report_handler = M2MBase::report_handler();
00327         if(report_handler && is_under_observation()) {
00328             report_handler->set_notification_trigger();
00329         }
00330     }
00331     report();
00332 }
00333 
00334 void M2MResourceBase::execute(void *arguments)
00335 {
00336     // XXX: this line is expected by seven testcases and until this code hits master branch
00337     // the testcases can not be modified and we need to print the false information too.
00338     tr_debug("M2MResourceBase::execute");
00339 
00340     execute_callback* callback = (execute_callback*)M2MCallbackStorage::get_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback);
00341 
00342     if (callback) {
00343         (*callback)(arguments);
00344     }
00345 
00346     execute_callback_2 callback2 = (execute_callback_2)M2MCallbackStorage::get_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback2);
00347     if (callback2) {
00348         (*callback2)(arguments);
00349     }
00350 }
00351 
00352 void M2MResourceBase::get_value(uint8_t *&value, uint32_t &value_length)
00353 {
00354     value_length = 0;
00355     if(value) {
00356         free(value);
00357         value = NULL;
00358     }
00359     sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource();
00360     if(res->resource && res->resourcelen > 0) {
00361         value = alloc_string_copy(res->resource, res->resourcelen);
00362         if(value) {
00363             value_length = res->resourcelen;
00364         }
00365     }
00366 }
00367 
00368 int64_t M2MResourceBase::get_value_int() const
00369 {
00370     int64_t value_int = 0;
00371 
00372     // XXX: this relies on having a zero terminated value?!
00373     const char *value_string = (char *)value();
00374     if (value_string) {
00375         value_int = atoll(value_string);
00376     }
00377     return value_int;
00378 }
00379 
00380 String M2MResourceBase::get_value_string() const
00381 {
00382     // XXX: do a better constructor to avoid pointless malloc
00383     String value;
00384     if (get_nsdl_resource()->resource) {
00385         value.append_raw((char*)get_nsdl_resource()->resource, get_nsdl_resource()->resourcelen);
00386     }
00387     return value;
00388 }
00389 
00390 uint8_t* M2MResourceBase::value() const
00391 {
00392     return get_nsdl_resource()->resource;
00393 }
00394 
00395 uint32_t M2MResourceBase::value_length() const
00396 {
00397     return get_nsdl_resource()->resourcelen;
00398 }
00399 
00400 sn_coap_hdr_s* M2MResourceBase::handle_get_request(nsdl_s *nsdl,
00401                                                sn_coap_hdr_s *received_coap_header,
00402                                                M2MObservationHandler *observation_handler)
00403 {
00404     tr_info("M2MResourceBase::handle_get_request()");
00405     sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CONTENT;
00406     sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl,
00407                                                           received_coap_header,
00408                                                           msg_code);
00409     if(received_coap_header) {
00410         // process the GET if we have registered a callback for it
00411         if ((operation() & SN_GRS_GET_ALLOWED) != 0) {
00412             if(coap_response) {
00413                 bool content_type_present = false;
00414                 if(received_coap_header->options_list_ptr &&
00415                         received_coap_header->options_list_ptr->accept != COAP_CT_NONE) {
00416                     content_type_present = true;
00417                     coap_response->content_format = received_coap_header->options_list_ptr->accept;
00418                 }
00419                 if(!content_type_present) {
00420                     if(resource_instance_type() == M2MResourceInstance::OPAQUE) {
00421                         coap_response->content_format = sn_coap_content_format_e(COAP_CONTENT_OMA_OPAQUE_TYPE);
00422                     } else {
00423                         coap_response->content_format = sn_coap_content_format_e(COAP_CONTENT_OMA_PLAIN_TEXT_TYPE);
00424                     }
00425                 }
00426                 // fill in the CoAP response payload
00427                 coap_response->payload_ptr = NULL;
00428                 uint32_t payload_len = 0;
00429 #ifndef DISABLE_BLOCK_MESSAGE
00430                 //If handler exists it means that resource value is stored in application side
00431                 if (block_message() && block_message()->is_block_message()) {
00432                     outgoing_block_message_callback* outgoing_block_message_cb = (outgoing_block_message_callback*)M2MCallbackStorage::get_callback(*this,
00433                                                                                     M2MCallbackAssociation::M2MResourceInstanceOutgoingBlockMessageCallback);
00434                     if (outgoing_block_message_cb) {
00435                         String name = "";
00436                         if (received_coap_header->uri_path_ptr != NULL &&
00437                                 received_coap_header->uri_path_len > 0) {
00438                             name.append_raw((char *)received_coap_header->uri_path_ptr,
00439                                              received_coap_header->uri_path_len);
00440                         }
00441                         (*outgoing_block_message_cb)(name, coap_response->payload_ptr, payload_len);
00442                     }
00443                 } else {
00444 #endif
00445                     if (coap_response->content_format == COAP_CONTENT_OMA_TLV_TYPE ||
00446                         coap_response->content_format == COAP_CONTENT_OMA_TLV_TYPE_OLD) {
00447                         set_coap_content_type(coap_response->content_format);
00448                         coap_response->payload_ptr = M2MTLVSerializer::serialize(&get_parent_resource(), payload_len);
00449                     } else {
00450                         get_value(coap_response->payload_ptr,payload_len);
00451                     }
00452 #ifndef DISABLE_BLOCK_MESSAGE
00453                 }
00454 #endif
00455                 tr_debug("M2MResourceBase::handle_get_request() - Request Content-type: %d", coap_response->content_format);
00456                 coap_response->payload_len = payload_len;
00457                 coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response);
00458                 if (coap_response->options_list_ptr) {
00459                     coap_response->options_list_ptr->max_age = max_age();
00460                 }
00461 
00462                 if(received_coap_header->options_list_ptr) {
00463                     if(received_coap_header->options_list_ptr->observe != -1) {
00464                         if (is_observable()) {
00465                             uint32_t number = 0;
00466                             uint8_t observe_option = 0;
00467                             observe_option = received_coap_header->options_list_ptr->observe;
00468 
00469                             if(START_OBSERVATION == observe_option) {
00470                                 // If the observe length is 0 means register for observation.
00471                                 if(received_coap_header->options_list_ptr->observe != -1) {
00472                                     number = received_coap_header->options_list_ptr->observe;
00473                                 }
00474 
00475                                 // If the observe value is 0 means register for observation.
00476                                 if(number == 0) {
00477                                     tr_info("M2MResourceBase::handle_get_request - put resource under observation");
00478                                     set_under_observation(true,observation_handler);
00479                                     send_notification_delivery_status(*this, NOTIFICATION_STATUS_SUBSCRIBED);
00480                                     M2MBase::add_observation_level(M2MBase::R_Attribute);
00481                                     if (coap_response->options_list_ptr) {
00482                                         coap_response->options_list_ptr->observe = observation_number();
00483                                     }
00484                                 }
00485 
00486                                 if(received_coap_header->token_ptr) {
00487                                     set_observation_token(received_coap_header->token_ptr,
00488                                                           received_coap_header->token_len);
00489                                 }
00490 
00491                             } else if (STOP_OBSERVATION == observe_option) {
00492                                 tr_info("M2MResourceBase::handle_get_request - stops observation");
00493                                 set_under_observation(false,NULL);
00494                                 M2MBase::remove_observation_level(M2MBase::R_Attribute);
00495                                 send_notification_delivery_status(*this, NOTIFICATION_STATUS_UNSUBSCRIBED);
00496                             }
00497                         } else {
00498                             msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
00499                         }
00500                     }
00501                 }
00502             }
00503         }else {
00504             tr_error("M2MResourceBase::handle_get_request - Return COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED");
00505             // Operation is not allowed.
00506             msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
00507         }
00508     } else {
00509         msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
00510     }
00511     if(coap_response) {
00512         coap_response->msg_code = msg_code;
00513     }
00514     return coap_response;
00515 }
00516 
00517 sn_coap_hdr_s* M2MResourceBase::handle_put_request(nsdl_s *nsdl,
00518                                                sn_coap_hdr_s *received_coap_header,
00519                                                M2MObservationHandler *observation_handler,
00520                                                bool &execute_value_updated)
00521 {
00522     tr_info("M2MResourceBase::handle_put_request()");
00523 
00524     sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04
00525     sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl,
00526                                                            received_coap_header,
00527                                                            msg_code);
00528     // process the PUT if we have registered a callback for it
00529     if(received_coap_header && coap_response) {
00530         uint16_t coap_content_type = 0;
00531         if(received_coap_header->content_format != COAP_CT_NONE) {
00532             coap_content_type = received_coap_header->content_format;
00533         }
00534         if(received_coap_header->options_list_ptr &&
00535            received_coap_header->options_list_ptr->uri_query_ptr) {
00536             char *query = (char*)alloc_string_copy(received_coap_header->options_list_ptr->uri_query_ptr,
00537                                                     received_coap_header->options_list_ptr->uri_query_len);
00538             if (query){
00539                 tr_info("M2MResourceBase::handle_put_request() - query %s", query);
00540 
00541                 // if anything was updated, re-initialize the stored notification attributes
00542                 if (!handle_observation_attribute(query)){
00543                     tr_error("M2MResourceBase::handle_put_request() - Invalid query");
00544                     msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
00545                 }
00546                 free(query);
00547             }
00548             else {
00549                 // memory allocation for query fails
00550                 tr_error("M2MResourceBase::handle_put_request() - Out of memory !!!");
00551                 msg_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR; // 4.00
00552             }
00553         } else if ((operation() & SN_GRS_PUT_ALLOWED) != 0) {
00554             tr_debug("M2MResourceBase::handle_put_request() - Request Content-type: %d", coap_content_type);
00555 
00556             if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type ||
00557                COAP_CONTENT_OMA_TLV_TYPE_OLD == coap_content_type) {
00558                 msg_code = COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT;
00559             } else {
00560 #ifndef DISABLE_BLOCK_MESSAGE
00561                 if (block_message()) {
00562                     block_message()->set_message_info(received_coap_header);
00563                     if (block_message()->is_block_message()) {
00564                         incoming_block_message_callback* incoming_block_message_cb = (incoming_block_message_callback*)M2MCallbackStorage::get_callback(*this,
00565                                                                                 M2MCallbackAssociation::M2MResourceInstanceIncomingBlockMessageCallback);
00566                         if (incoming_block_message_cb) {
00567                             (*incoming_block_message_cb)(_block_message_data);
00568                         }
00569                         if (block_message()->is_last_block()) {
00570                             block_message()->clear_values();
00571                             coap_response->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED;
00572                         } else {
00573                             coap_response->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING;
00574                         }
00575                         if (block_message()->error_code() != M2MBlockMessage::ErrorNone) {
00576                             block_message()->clear_values();
00577                         }
00578                     }
00579                 }
00580 #endif
00581                 // Firmware object uri path is limited to be max 255 bytes
00582                 if ((strcmp(uri_path(), FIRMAWARE_PACKAGE_URI_PATH) == 0) &&
00583                     received_coap_header->payload_len > 255) {
00584                     msg_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE;
00585                 } else if ((strcmp(uri_path(), SERVER_LIFETIME_PATH) == 0)) {
00586                     // Check that lifetime can't go below 60s
00587                     char *query = (char*)alloc_string_copy(received_coap_header->payload_ptr,
00588                                                            received_coap_header->payload_len);
00589 
00590                     if (query) {
00591                         int32_t lifetime = atol(query);
00592                         if (lifetime < MINIMUM_REGISTRATION_TIME) {
00593                             tr_error("M2MResourceBase::handle_put_request() - lifetime value % " PRId32 " not acceptable", lifetime);
00594                             msg_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE;
00595                         }
00596                         free(query);
00597                     }
00598                     else {
00599                         // memory allocation for query fails
00600                         tr_error("M2MResourceBase::handle_put_request() - Out of memory !!!");
00601                         msg_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR;
00602                     }
00603                 }
00604 
00605                 // Do not update resource value in error case.
00606                 if ((received_coap_header->payload_ptr) && (msg_code == COAP_MSG_CODE_RESPONSE_CHANGED)) {
00607                     execute_value_updated = true;
00608                 }
00609             }
00610         } else {
00611             // Operation is not allowed.
00612             tr_error("M2MResourceBase::handle_put_request() - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED");
00613             msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
00614         }
00615     } else {
00616         msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
00617     }
00618     if(coap_response) {
00619         coap_response->msg_code = msg_code;
00620     }
00621 
00622     return coap_response;
00623 }
00624 
00625 
00626 #ifndef DISABLE_BLOCK_MESSAGE
00627 
00628 M2MBlockMessage* M2MResourceBase::block_message() const
00629 {
00630     return _block_message_data;
00631 }
00632 
00633 bool M2MResourceBase::set_incoming_block_message_callback(incoming_block_message_callback callback)
00634 {
00635     incoming_block_message_callback* old_callback = (incoming_block_message_callback*)M2MCallbackStorage::remove_callback(*this,
00636                                                         M2MCallbackAssociation::M2MResourceInstanceIncomingBlockMessageCallback);
00637     delete old_callback;
00638 
00639     // copy the callback object. This will change on next version to be a direct pointer to a interface class,
00640     // this FPn<> is just too heavy for this usage.
00641     incoming_block_message_callback* new_callback = new incoming_block_message_callback(callback);
00642 
00643     delete _block_message_data;
00644     _block_message_data = NULL;
00645     _block_message_data = new M2MBlockMessage();
00646 
00647     return M2MCallbackStorage::add_callback(*this,
00648                                             new_callback,
00649                                             M2MCallbackAssociation::M2MResourceInstanceIncomingBlockMessageCallback);
00650 }
00651 
00652 bool M2MResourceBase::set_outgoing_block_message_callback(outgoing_block_message_callback callback)
00653 {
00654     outgoing_block_message_callback *old_callback = (outgoing_block_message_callback*)M2MCallbackStorage::remove_callback(*this,
00655                                                          M2MCallbackAssociation::M2MResourceInstanceOutgoingBlockMessageCallback);
00656     delete old_callback;
00657 
00658     outgoing_block_message_callback *new_callback = new outgoing_block_message_callback(callback);
00659     return M2MCallbackStorage::add_callback(*this,
00660                                             new_callback,
00661                                             M2MCallbackAssociation::M2MResourceInstanceOutgoingBlockMessageCallback);
00662 }
00663 #endif
00664 
00665 bool M2MResourceBase::set_notification_sent_callback(notification_sent_callback callback)
00666 {
00667     notification_sent_callback *old_callback = (notification_sent_callback*)M2MCallbackStorage::remove_callback(*this,
00668                                                          M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback);
00669     delete old_callback;
00670 
00671     notification_sent_callback *new_callback = new notification_sent_callback(callback);
00672     return M2MCallbackStorage::add_callback(*this,
00673                                             new_callback,
00674                                             M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback);
00675 }
00676 
00677 bool M2MResourceBase::set_notification_sent_callback(notification_sent_callback_2 callback)
00678 {
00679     M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback2);
00680 
00681     return M2MCallbackStorage::add_callback(*this,
00682                                             (void*)callback,
00683                                             M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback2);
00684 }
00685 
00686 bool M2MResourceBase::set_notification_status_callback(notification_status_callback callback)
00687 {
00688     notification_status_callback *old_callback = (notification_status_callback*)M2MCallbackStorage::remove_callback(*this,
00689                                                          M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback);
00690     delete old_callback;
00691 
00692     notification_status_callback *new_callback = new notification_status_callback(callback);
00693     return M2MCallbackStorage::add_callback(*this,
00694                                             new_callback,
00695                                             M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback);
00696 }
00697 
00698 bool M2MResourceBase::set_notification_status_callback(notification_status_callback_2 callback)
00699 {
00700     M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback2);
00701 
00702     return M2MCallbackStorage::add_callback(*this,
00703                                             (void*)callback,
00704                                             M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback2);
00705 }
00706 
00707 void M2MResourceBase::notification_sent()
00708 {
00709     // Now we will call both callbacks, if they are set. This is different from original behavior.
00710     notification_sent_callback* callback =
00711             (notification_sent_callback*)M2MCallbackStorage::get_callback(*this,
00712                                                                           M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback);
00713     if (callback) {
00714         (*callback)();
00715     }
00716 
00717     notification_sent_callback_2 callback2 =
00718             (notification_sent_callback_2)M2MCallbackStorage::get_callback(*this,
00719                                                                            M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback2);
00720     if (callback2) {
00721         (*callback2)();
00722     }
00723 }
00724 
00725 void M2MResourceBase::notification_status(const uint16_t msg_id, const NotificationStatus status)
00726 {
00727     if (_notification_status != status) {
00728         _notification_status = status;
00729         // Now we will call both callbacks, if they are set. This is different from original behavior.
00730         notification_status_callback* callback =
00731                 (notification_status_callback*)M2MCallbackStorage::get_callback(*this,
00732                                                                               M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback);
00733         if (callback) {
00734             (*callback)(msg_id, status);
00735         }
00736 
00737         notification_status_callback_2 callback2 =
00738                 (notification_status_callback_2)M2MCallbackStorage::get_callback(*this,
00739                                                                                M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback2);
00740         if (callback2) {
00741             (*callback2)(msg_id, status);
00742         }
00743     }
00744 }
00745 
00746 M2MResourceBase::ResourceType M2MResourceBase::convert_data_type(M2MBase::DataType type) const
00747 {
00748     M2MResourceBase::ResourceType res_type = M2MResourceBase::OBJLINK;
00749     switch(type) {
00750         case M2MBase::STRING:
00751             res_type = M2MResourceBase::STRING;
00752             break;
00753         case M2MBase::INTEGER:
00754             res_type = M2MResourceBase::INTEGER;
00755             break;
00756         case M2MBase::FLOAT:
00757             res_type = M2MResourceBase::FLOAT;
00758             break;
00759         case M2MBase::OPAQUE:
00760             res_type = M2MResourceBase::OPAQUE;
00761             break;
00762         case M2MBase::BOOLEAN:
00763             res_type = M2MResourceBase::BOOLEAN;
00764             break;
00765         case M2MBase::TIME:
00766             res_type = M2MResourceBase::TIME;
00767             break;
00768         case M2MBase::OBJLINK:
00769             res_type = M2MResourceBase::OBJLINK;
00770             break;
00771     }
00772     return res_type;
00773 }
00774 
00775 M2MResourceBase::NotificationStatus M2MResourceBase::notification_status() const
00776 {
00777     return _notification_status;
00778 }
00779 
00780 void M2MResourceBase::clear_notification_status()
00781 {
00782     _notification_status = M2MResourceBase::INIT;
00783 }