terence zhang / wakaama
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers observe.c Source File

observe.c

00001 /*******************************************************************************
00002  *
00003  * Copyright (c) 2013, 2014 Intel Corporation and others.
00004  * All rights reserved. This program and the accompanying materials
00005  * are made available under the terms of the Eclipse Public License v1.0
00006  * and Eclipse Distribution License v1.0 which accompany this distribution.
00007  *
00008  * The Eclipse Public License is available at
00009  *    http://www.eclipse.org/legal/epl-v10.html
00010  * The Eclipse Distribution License is available at
00011  *    http://www.eclipse.org/org/documents/edl-v10.php.
00012  *
00013  * Contributors:
00014  *    David Navarro, Intel Corporation - initial API and implementation
00015  *    Toby Jaffey - Please refer to git log
00016  *    Bosch Software Innovations GmbH - Please refer to git log
00017  *    
00018  *******************************************************************************/
00019 
00020 /*
00021  Copyright (c) 2013, 2014 Intel Corporation
00022 
00023  Redistribution and use in source and binary forms, with or without modification,
00024  are permitted provided that the following conditions are met:
00025 
00026      * Redistributions of source code must retain the above copyright notice,
00027        this list of conditions and the following disclaimer.
00028      * Redistributions in binary form must reproduce the above copyright notice,
00029        this list of conditions and the following disclaimer in the documentation
00030        and/or other materials provided with the distribution.
00031      * Neither the name of Intel Corporation nor the names of its contributors
00032        may be used to endorse or promote products derived from this software
00033        without specific prior written permission.
00034 
00035  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00036  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00037  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00038  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00039  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00040  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00041  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00042  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00043  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
00044  THE POSSIBILITY OF SUCH DAMAGE.
00045 
00046  David Navarro <david.navarro@intel.com>
00047 
00048 */
00049 
00050 #include "internals.h"
00051 #include <stdio.h>
00052 
00053 
00054 #ifdef LWM2M_CLIENT_MODE
00055 static lwm2m_observed_t * prv_findObserved(lwm2m_context_t * contextP,
00056                                            lwm2m_uri_t * uriP)
00057 {
00058     lwm2m_observed_t * targetP;
00059 
00060     targetP = contextP->observedList;
00061     while (targetP != NULL
00062         && (targetP->uri.objectId != uriP->objectId
00063          || targetP->uri.flag != uriP->flag
00064          || (LWM2M_URI_IS_SET_INSTANCE(uriP) && targetP->uri.instanceId != uriP->instanceId)
00065          || (LWM2M_URI_IS_SET_RESOURCE(uriP) && targetP->uri.resourceId != uriP->resourceId)))
00066     {
00067         targetP = targetP->next;
00068     }
00069 
00070     return targetP;
00071 }
00072 
00073 static void prv_unlinkObserved(lwm2m_context_t * contextP,
00074                                lwm2m_observed_t * observedP)
00075 {
00076     if (contextP->observedList == observedP)
00077     {
00078         contextP->observedList = contextP->observedList->next;
00079     }
00080     else
00081     {
00082         lwm2m_observed_t * parentP;
00083 
00084         parentP = contextP->observedList;
00085         while (parentP->next != NULL
00086             && parentP->next != observedP)
00087         {
00088             parentP = parentP->next;
00089         }
00090         if (parentP->next != NULL)
00091         {
00092             parentP->next = parentP->next->next;
00093         }
00094     }
00095 }
00096 
00097 static lwm2m_watcher_t * prv_findWatcher(lwm2m_observed_t * observedP,
00098                                          lwm2m_server_t * serverP)
00099 {
00100     lwm2m_watcher_t * targetP;
00101 
00102     targetP = observedP->watcherList;
00103     while (targetP != NULL
00104         && targetP->server != serverP)
00105     {
00106         targetP = targetP->next;
00107     }
00108 
00109     return targetP;
00110 }
00111 
00112 static lwm2m_watcher_t * prv_getWatcher(lwm2m_context_t * contextP,
00113                                         lwm2m_uri_t * uriP,
00114                                         lwm2m_server_t * serverP)
00115 {
00116     lwm2m_observed_t * observedP;
00117     bool allocatedObserver;
00118     lwm2m_watcher_t * watcherP;
00119 
00120     allocatedObserver = false;
00121 
00122     observedP = prv_findObserved(contextP, uriP);
00123     if (observedP == NULL)
00124     {
00125         observedP = (lwm2m_observed_t *)lwm2m_malloc(sizeof(lwm2m_observed_t));
00126         if (observedP == NULL) return NULL;
00127         allocatedObserver = true;
00128         memset(observedP, 0, sizeof(lwm2m_observed_t));
00129         memcpy(&(observedP->uri), uriP, sizeof(lwm2m_uri_t));
00130         observedP->next = contextP->observedList;
00131         contextP->observedList = observedP;
00132     }
00133 
00134     watcherP = prv_findWatcher(observedP, serverP);
00135     if (watcherP == NULL)
00136     {
00137         watcherP = (lwm2m_watcher_t *)lwm2m_malloc(sizeof(lwm2m_watcher_t));
00138         if (watcherP == NULL)
00139         {
00140             if (allocatedObserver == true)
00141             {
00142                 lwm2m_free(observedP);
00143             }
00144             return NULL;
00145         }
00146         memset(watcherP, 0, sizeof(lwm2m_watcher_t));
00147         watcherP->active = false;
00148         watcherP->server = serverP;
00149         watcherP->next = observedP->watcherList;
00150         observedP->watcherList = watcherP;
00151     }
00152 
00153     return watcherP;
00154 }
00155 
00156 coap_status_t observe_handleRequest(lwm2m_context_t * contextP,
00157                                     lwm2m_uri_t * uriP,
00158                                     lwm2m_server_t * serverP,
00159                                     int size,
00160                                     lwm2m_data_t * dataP,
00161                                     coap_packet_t * message,
00162                                     coap_packet_t * response)
00163 {
00164     lwm2m_watcher_t * watcherP;
00165     uint32_t count;
00166 
00167     LOG_ARG("Code: %02X, server status: %s", message->code, STR_STATUS(serverP->status));
00168     LOG_URI(uriP);
00169 
00170     coap_get_header_observe(message, &count);
00171 
00172     switch (count)
00173     {
00174     case 0:
00175         if (!LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(uriP)) return COAP_400_BAD_REQUEST;
00176         if (message->token_len == 0) return COAP_400_BAD_REQUEST;
00177 
00178         watcherP = prv_getWatcher(contextP, uriP, serverP);
00179         if (watcherP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
00180 
00181         watcherP->tokenLen = message->token_len;
00182         memcpy(watcherP->token, message->token, message->token_len);
00183         watcherP->active = true;
00184         watcherP->lastTime = lwm2m_gettime();
00185 
00186         if (LWM2M_URI_IS_SET_RESOURCE(uriP))
00187         {
00188             switch (dataP->type)
00189             {
00190             case LWM2M_TYPE_INTEGER:
00191                 if (1 != lwm2m_data_decode_int(dataP, &(watcherP->lastValue.asInteger))) return COAP_500_INTERNAL_SERVER_ERROR;
00192                 break;
00193             case LWM2M_TYPE_FLOAT:
00194                 if (1 != lwm2m_data_decode_float(dataP, &(watcherP->lastValue.asFloat))) return COAP_500_INTERNAL_SERVER_ERROR;
00195                 break;
00196             default:
00197                 break;
00198             }
00199         }
00200 
00201         coap_set_header_observe(response, watcherP->counter++);
00202 
00203         return COAP_205_CONTENT;
00204 
00205     case 1:
00206         // cancellation
00207         observe_cancel(contextP, LWM2M_MAX_ID, serverP->sessionH);
00208         return COAP_205_CONTENT;
00209 
00210     default:
00211         return COAP_400_BAD_REQUEST;
00212     }
00213 }
00214 
00215 void observe_cancel(lwm2m_context_t * contextP,
00216                     uint16_t mid,
00217                     void * fromSessionH)
00218 {
00219     lwm2m_observed_t * observedP;
00220 
00221     LOG_ARG("mid: %d", mid);
00222 
00223     for (observedP = contextP->observedList;
00224          observedP != NULL;
00225          observedP = observedP->next)
00226     {
00227         lwm2m_watcher_t * targetP = NULL;
00228 
00229         if ((LWM2M_MAX_ID == mid || observedP->watcherList->lastMid == mid)
00230          && lwm2m_session_is_equal(observedP->watcherList->server->sessionH, fromSessionH, contextP->userData))
00231         {
00232             targetP = observedP->watcherList;
00233             observedP->watcherList = observedP->watcherList->next;
00234         }
00235         else
00236         {
00237             lwm2m_watcher_t * parentP;
00238 
00239             parentP = observedP->watcherList;
00240             while (parentP->next != NULL
00241                 && (parentP->next->lastMid != mid
00242                  || lwm2m_session_is_equal(parentP->next->server->sessionH, fromSessionH, contextP->userData)))
00243             {
00244                 parentP = parentP->next;
00245             }
00246             if (parentP->next != NULL)
00247             {
00248                 targetP = parentP->next;
00249                 parentP->next = parentP->next->next;
00250             }
00251         }
00252         if (targetP != NULL)
00253         {
00254             lwm2m_free(targetP);
00255             if (observedP->watcherList == NULL)
00256             {
00257                 prv_unlinkObserved(contextP, observedP);
00258                 lwm2m_free(observedP);
00259             }
00260             return;
00261         }
00262     }
00263 }
00264 
00265 coap_status_t observe_setParameters(lwm2m_context_t * contextP,
00266                                     lwm2m_uri_t * uriP,
00267                                     lwm2m_server_t * serverP,
00268                                     lwm2m_attributes_t * attrP)
00269 {
00270     uint8_t result;
00271     lwm2m_watcher_t * watcherP;
00272 
00273     LOG_URI(uriP);
00274     LOG_ARG("toSet: %08X, toClear: %08X, minPeriod: %d, maxPeriod: %d, greaterThan: %f, lessThan: %f, step: %f",
00275             attrP->toSet, attrP->toClear, attrP->minPeriod, attrP->maxPeriod, attrP->greaterThan, attrP->lessThan, attrP->step);
00276 
00277     if (!LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(uriP)) return COAP_400_BAD_REQUEST;
00278 
00279     result = object_checkReadable(contextP, uriP);
00280     if (COAP_205_CONTENT != result) return result;
00281 
00282     if (0 != (attrP->toSet & ATTR_FLAG_NUMERIC))
00283     {
00284         result = object_checkNumeric(contextP, uriP);
00285         if (COAP_205_CONTENT != result) return result;
00286     }
00287 
00288     watcherP = prv_getWatcher(contextP, uriP, serverP);
00289     if (watcherP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
00290 
00291     // Check rule “lt” value + 2*”stp” values < “gt” value
00292     if ((((attrP->toSet | (watcherP->parameters?watcherP->parameters->toSet:0)) & ~attrP->toClear) & ATTR_FLAG_NUMERIC) == ATTR_FLAG_NUMERIC)
00293     {
00294         float gt;
00295         float lt;
00296         float stp;
00297 
00298         if (0 != (attrP->toSet & LWM2M_ATTR_FLAG_GREATER_THAN))
00299         {
00300             gt = attrP->greaterThan;
00301         }
00302         else
00303         {
00304             gt = watcherP->parameters->greaterThan;
00305         }
00306         if (0 != (attrP->toSet & LWM2M_ATTR_FLAG_LESS_THAN))
00307         {
00308             lt = attrP->lessThan;
00309         }
00310         else
00311         {
00312             lt = watcherP->parameters->lessThan;
00313         }
00314         if (0 != (attrP->toSet & LWM2M_ATTR_FLAG_STEP))
00315         {
00316             stp = attrP->step;
00317         }
00318         else
00319         {
00320             stp = watcherP->parameters->step;
00321         }
00322 
00323         if (lt + (2 * stp) >= gt) return COAP_400_BAD_REQUEST;
00324     }
00325 
00326     if (watcherP->parameters == NULL)
00327     {
00328         if (attrP->toSet != 0)
00329         {
00330             watcherP->parameters = (lwm2m_attributes_t *)lwm2m_malloc(sizeof(lwm2m_attributes_t));
00331             if (watcherP->parameters == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
00332             memcpy(watcherP->parameters, attrP, sizeof(lwm2m_attributes_t));
00333         }
00334     }
00335     else
00336     {
00337         watcherP->parameters->toSet &= ~attrP->toClear;
00338         if (attrP->toSet & LWM2M_ATTR_FLAG_MIN_PERIOD)
00339         {
00340             watcherP->parameters->minPeriod = attrP->minPeriod;
00341         }
00342         if (attrP->toSet & LWM2M_ATTR_FLAG_MAX_PERIOD)
00343         {
00344             watcherP->parameters->maxPeriod = attrP->maxPeriod;
00345         }
00346         if (attrP->toSet & LWM2M_ATTR_FLAG_GREATER_THAN)
00347         {
00348             watcherP->parameters->greaterThan = attrP->greaterThan;
00349         }
00350         if (attrP->toSet & LWM2M_ATTR_FLAG_LESS_THAN)
00351         {
00352             watcherP->parameters->lessThan = attrP->lessThan;
00353         }
00354         if (attrP->toSet & LWM2M_ATTR_FLAG_STEP)
00355         {
00356             watcherP->parameters->step = attrP->step;
00357         }
00358     }
00359 
00360     LOG_ARG("Final toSet: %08X, minPeriod: %d, maxPeriod: %d, greaterThan: %f, lessThan: %f, step: %f",
00361             watcherP->parameters->toSet, watcherP->parameters->minPeriod, watcherP->parameters->maxPeriod, watcherP->parameters->greaterThan, watcherP->parameters->lessThan, watcherP->parameters->step);
00362 
00363     return COAP_204_CHANGED;
00364 }
00365 
00366 lwm2m_observed_t * observe_findByUri(lwm2m_context_t * contextP,
00367                                      lwm2m_uri_t * uriP)
00368 {
00369     lwm2m_observed_t * targetP;
00370 
00371     LOG_URI(uriP);
00372     targetP = contextP->observedList;
00373     while (targetP != NULL)
00374     {
00375         if (targetP->uri.objectId == uriP->objectId)
00376         {
00377             if ((!LWM2M_URI_IS_SET_INSTANCE(uriP) && !LWM2M_URI_IS_SET_INSTANCE(&(targetP->uri)))
00378              || (LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_INSTANCE(&(targetP->uri)) && (uriP->instanceId == targetP->uri.instanceId)))
00379              {
00380                  if ((!LWM2M_URI_IS_SET_RESOURCE(uriP) && !LWM2M_URI_IS_SET_RESOURCE(&(targetP->uri)))
00381                      || (LWM2M_URI_IS_SET_RESOURCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(&(targetP->uri)) && (uriP->resourceId == targetP->uri.resourceId)))
00382                  {
00383                      LOG_ARG("Found one with%s observers.", targetP->watcherList ? "" : " no");
00384                      LOG_URI(&(targetP->uri));
00385                      return targetP;
00386                  }
00387              }
00388         }
00389         targetP = targetP->next;
00390     }
00391 
00392     LOG("Found nothing");
00393     return NULL;
00394 }
00395 
00396 void lwm2m_resource_value_changed(lwm2m_context_t * contextP,
00397                                   lwm2m_uri_t * uriP)
00398 {
00399     lwm2m_observed_t * targetP;
00400 
00401     LOG_URI(uriP);
00402     targetP = contextP->observedList;
00403     while (targetP != NULL)
00404     {
00405         if (targetP->uri.objectId == uriP->objectId)
00406         {
00407             if (!LWM2M_URI_IS_SET_INSTANCE(uriP)
00408              || (targetP->uri.flag & LWM2M_URI_FLAG_INSTANCE_ID) == 0
00409              || uriP->instanceId == targetP->uri.instanceId)
00410             {
00411                 if (!LWM2M_URI_IS_SET_RESOURCE(uriP)
00412                  || (targetP->uri.flag & LWM2M_URI_FLAG_RESOURCE_ID) == 0
00413                  || uriP->resourceId == targetP->uri.resourceId)
00414                 {
00415                     lwm2m_watcher_t * watcherP;
00416 
00417                     LOG("Found an observation");
00418                     LOG_URI(&(targetP->uri));
00419 
00420                     for (watcherP = targetP->watcherList ; watcherP != NULL ; watcherP = watcherP->next)
00421                     {
00422                         if (watcherP->active == true)
00423                         {
00424                             LOG("Tagging a watcher");
00425                             watcherP->update = true;
00426                         }
00427                     }
00428                 }
00429             }
00430         }
00431         targetP = targetP->next;
00432     }
00433 }
00434 
00435 void observe_step(lwm2m_context_t * contextP,
00436                   time_t currentTime,
00437                   time_t * timeoutP)
00438 {
00439     lwm2m_observed_t * targetP;
00440 
00441     LOG("Entering");
00442     for (targetP = contextP->observedList ; targetP != NULL ; targetP = targetP->next)
00443     {
00444         lwm2m_watcher_t * watcherP;
00445         uint8_t * buffer = NULL;
00446         size_t length = 0;
00447         lwm2m_data_t * dataP = NULL;
00448         int size = 0;
00449         double floatValue = 0;
00450         int64_t integerValue = 0;
00451         bool storeValue = false;
00452         lwm2m_media_type_t format = LWM2M_CONTENT_TEXT;
00453         coap_packet_t message[1];
00454         time_t interval;
00455 
00456         LOG_URI(&(targetP->uri));
00457         if (LWM2M_URI_IS_SET_RESOURCE(&targetP->uri))
00458         {
00459             if (COAP_205_CONTENT != object_readData(contextP, &targetP->uri, &size, &dataP)) continue;
00460             switch (dataP->type)
00461             {
00462             case LWM2M_TYPE_INTEGER:
00463                 if (1 != lwm2m_data_decode_int(dataP, &integerValue)) continue;
00464                 storeValue = true;
00465                 break;
00466             case LWM2M_TYPE_FLOAT:
00467                 if (1 != lwm2m_data_decode_float(dataP, &floatValue)) continue;
00468                 storeValue = true;
00469                 break;
00470             default:
00471                 break;
00472             }
00473         }
00474         for (watcherP = targetP->watcherList ; watcherP != NULL ; watcherP = watcherP->next)
00475         {
00476             if (watcherP->active == true)
00477             {
00478                 bool notify = false;
00479 
00480                 if (watcherP->update == true)
00481                 {
00482                     // value changed, should we notify the server ?
00483 
00484                     if (watcherP->parameters == NULL || watcherP->parameters->toSet == 0)
00485                     {
00486                         // no conditions
00487                         notify = true;
00488                         LOG("Notify with no conditions");
00489                         LOG_URI(&(targetP->uri));
00490                     }
00491 
00492                     if (notify == false
00493                      && watcherP->parameters != NULL
00494                      && (watcherP->parameters->toSet & ATTR_FLAG_NUMERIC) != 0)
00495                     {
00496                         if ((watcherP->parameters->toSet & LWM2M_ATTR_FLAG_LESS_THAN) != 0)
00497                         {
00498                             LOG("Checking lower treshold");
00499                             // Did we cross the lower treshold ?
00500                             switch (dataP->type)
00501                             {
00502                             case LWM2M_TYPE_INTEGER:
00503                                 if ((integerValue <= watcherP->parameters->lessThan
00504                                   && watcherP->lastValue.asInteger > watcherP->parameters->lessThan)
00505                                  || (integerValue >= watcherP->parameters->lessThan
00506                                   && watcherP->lastValue.asInteger < watcherP->parameters->lessThan))
00507                                 {
00508                                     LOG("Notify on lower treshold crossing");
00509                                     notify = true;
00510                                 }
00511                                 break;
00512                             case LWM2M_TYPE_FLOAT:
00513                                 if ((floatValue <= watcherP->parameters->lessThan
00514                                   && watcherP->lastValue.asFloat > watcherP->parameters->lessThan)
00515                                  || (floatValue >= watcherP->parameters->lessThan
00516                                   && watcherP->lastValue.asFloat < watcherP->parameters->lessThan))
00517                                 {
00518                                     LOG("Notify on lower treshold crossing");
00519                                     notify = true;
00520                                 }
00521                                 break;
00522                             default:
00523                                 break;
00524                             }
00525                         }
00526                         if ((watcherP->parameters->toSet & LWM2M_ATTR_FLAG_GREATER_THAN) != 0)
00527                         {
00528                             LOG("Checking upper treshold");
00529                             // Did we cross the upper treshold ?
00530                             switch (dataP->type)
00531                             {
00532                             case LWM2M_TYPE_INTEGER:
00533                                 if ((integerValue <= watcherP->parameters->greaterThan
00534                                   && watcherP->lastValue.asInteger > watcherP->parameters->greaterThan)
00535                                  || (integerValue >= watcherP->parameters->greaterThan
00536                                   && watcherP->lastValue.asInteger < watcherP->parameters->greaterThan))
00537                                 {
00538                                     LOG("Notify on lower upper crossing");
00539                                     notify = true;
00540                                 }
00541                                 break;
00542                             case LWM2M_TYPE_FLOAT:
00543                                 if ((floatValue <= watcherP->parameters->greaterThan
00544                                   && watcherP->lastValue.asFloat > watcherP->parameters->greaterThan)
00545                                  || (floatValue >= watcherP->parameters->greaterThan
00546                                   && watcherP->lastValue.asFloat < watcherP->parameters->greaterThan))
00547                                 {
00548                                     LOG("Notify on lower upper crossing");
00549                                     notify = true;
00550                                 }
00551                                 break;
00552                             default:
00553                                 break;
00554                             }
00555                         }
00556                         if ((watcherP->parameters->toSet & LWM2M_ATTR_FLAG_STEP) != 0)
00557                         {
00558                             LOG("Checking step");
00559 
00560                             switch (dataP->type)
00561                             {
00562                             case LWM2M_TYPE_INTEGER:
00563                             {
00564                                 int64_t diff;
00565 
00566                                 diff = integerValue - watcherP->lastValue.asInteger;
00567                                 if ((diff < 0 && (0 - diff) >= watcherP->parameters->step)
00568                                  || (diff >= 0 && diff >= watcherP->parameters->step))
00569                                 {
00570                                     LOG("Notify on step condition");
00571                                     notify = true;
00572                                 }
00573                             }
00574                                 break;
00575                             case LWM2M_TYPE_FLOAT:
00576                             {
00577                                 double diff;
00578 
00579                                 diff = floatValue - watcherP->lastValue.asFloat;
00580                                 if ((diff < 0 && (0 - diff) >= watcherP->parameters->step)
00581                                  || (diff >= 0 && diff >= watcherP->parameters->step))
00582                                 {
00583                                     LOG("Notify on step condition");
00584                                     notify = true;
00585                                 }
00586                             }
00587                                 break;
00588                             default:
00589                                 break;
00590                             }
00591                         }
00592                     }
00593 
00594                     if (watcherP->parameters != NULL
00595                      && (watcherP->parameters->toSet & LWM2M_ATTR_FLAG_MIN_PERIOD) != 0)
00596                     {
00597                         LOG_ARG("Checking minimal period (%d s)", watcherP->parameters->minPeriod);
00598 
00599                         if (watcherP->lastTime + watcherP->parameters->minPeriod > currentTime)
00600                         {
00601                             // Minimum Period did not elapse yet
00602                             interval = watcherP->lastTime + watcherP->parameters->minPeriod - currentTime;
00603                             if (*timeoutP > interval) *timeoutP = interval;
00604                             notify = false;
00605                         }
00606                         else
00607                         {
00608                             LOG("Notify on minimal period");
00609                             notify = true;
00610                         }
00611                     }
00612                 }
00613 
00614                 // Is the Maximum Period reached ?
00615                 if (notify == false
00616                  && watcherP->parameters != NULL
00617                  && (watcherP->parameters->toSet & LWM2M_ATTR_FLAG_MAX_PERIOD) != 0)
00618                 {
00619                     LOG_ARG("Checking maximal period (%d s)", watcherP->parameters->minPeriod);
00620 
00621                     if (watcherP->lastTime + watcherP->parameters->maxPeriod <= currentTime)
00622                     {
00623                         LOG("Notify on maximal period");
00624                         notify = true;
00625                     }
00626                 }
00627 
00628                 if (notify == true)
00629                 {
00630                     if (buffer == NULL)
00631                     {
00632                         if (dataP != NULL)
00633                         {
00634                             int res;
00635 
00636                             res = lwm2m_data_serialize(&targetP->uri, size, dataP, &format, &buffer);
00637                             if (res < 0)
00638                             {
00639                                 break;
00640                             }
00641                             else
00642                             {
00643                                 length = (size_t)res;
00644                             }
00645 
00646                         }
00647                         else
00648                         {
00649                             if (COAP_205_CONTENT != object_read(contextP, &targetP->uri, &format, &buffer, &length))
00650                             {
00651                                 buffer = NULL;
00652                                 break;
00653                             }
00654                         }
00655                         coap_init_message(message, COAP_TYPE_NON, COAP_205_CONTENT, 0);
00656                         coap_set_header_content_type(message, format);
00657                         coap_set_payload(message, buffer, length);
00658                     }
00659                     watcherP->lastTime = currentTime;
00660                     watcherP->lastMid = contextP->nextMID++;
00661                     message->mid = watcherP->lastMid;
00662                     coap_set_header_token(message, watcherP->token, watcherP->tokenLen);
00663                     coap_set_header_observe(message, watcherP->counter++);
00664                     (void)message_send(contextP, message, watcherP->server->sessionH);
00665                     watcherP->update = false;
00666                 }
00667 
00668                 // Store this value
00669                 if (notify == true && storeValue == true)
00670                 {
00671                     switch (dataP->type)
00672                     {
00673                     case LWM2M_TYPE_INTEGER:
00674                         watcherP->lastValue.asInteger = integerValue;
00675                         break;
00676                     case LWM2M_TYPE_FLOAT:
00677                         watcherP->lastValue.asFloat = floatValue;
00678                         break;
00679                     default:
00680                         break;
00681                     }
00682                 }
00683 
00684                 if (watcherP->parameters != NULL && (watcherP->parameters->toSet & LWM2M_ATTR_FLAG_MAX_PERIOD) != 0)
00685                 {
00686                     // update timers
00687                     interval = watcherP->lastTime + watcherP->parameters->maxPeriod - currentTime;
00688                     if (*timeoutP > interval) *timeoutP = interval;
00689                 }
00690             }
00691         }
00692         if (dataP != NULL) lwm2m_data_free(size, dataP);
00693         if (buffer != NULL) lwm2m_free(buffer);
00694     }
00695 }
00696 
00697 #endif
00698 
00699 #ifdef LWM2M_SERVER_MODE
00700 
00701 typedef struct
00702 {
00703     lwm2m_observation_t * observationP;
00704     lwm2m_result_callback_t callbackP;
00705     void * userDataP;
00706 } cancellation_data_t;
00707 
00708 static lwm2m_observation_t * prv_findObservationByURI(lwm2m_client_t * clientP,
00709                                                       lwm2m_uri_t * uriP)
00710 {
00711     lwm2m_observation_t * targetP;
00712 
00713     targetP = clientP->observationList;
00714     while (targetP != NULL)
00715     {
00716         if (targetP->uri.objectId == uriP->objectId
00717          && targetP->uri.flag == uriP->flag
00718          && targetP->uri.instanceId == uriP->instanceId
00719          && targetP->uri.resourceId == uriP->resourceId)
00720         {
00721             return targetP;
00722         }
00723 
00724         targetP = targetP->next;
00725     }
00726 
00727     return targetP;
00728 }
00729 
00730 void observe_remove(lwm2m_observation_t * observationP)
00731 {
00732     LOG("Entering");
00733     observationP->clientP->observationList = (lwm2m_observation_t *) LWM2M_LIST_RM(observationP->clientP->observationList, observationP->id, NULL);
00734     lwm2m_free(observationP);
00735 }
00736 
00737 static void prv_obsRequestCallback(lwm2m_transaction_t * transacP,
00738                                    void * message)
00739 {
00740     lwm2m_observation_t * observationP = (lwm2m_observation_t *)transacP->userData;
00741     coap_packet_t * packet = (coap_packet_t *)message;
00742     uint8_t code;
00743 
00744     switch (observationP->status)
00745     {
00746     case STATE_DEREG_PENDING:
00747         // Observation was canceled by the user.
00748         observe_remove(observationP);
00749         return;
00750 
00751     case STATE_REG_PENDING:
00752         observationP->status = STATE_REGISTERED;
00753         break;
00754 
00755     default:
00756         break;
00757     }
00758 
00759     if (message == NULL)
00760     {
00761         code = COAP_503_SERVICE_UNAVAILABLE;
00762     }
00763     else if (packet->code == COAP_205_CONTENT
00764          && !IS_OPTION(packet, COAP_OPTION_OBSERVE))
00765     {
00766         code = COAP_405_METHOD_NOT_ALLOWED;
00767     }
00768     else
00769     {
00770         code = packet->code;
00771     }
00772 
00773     if (code != COAP_205_CONTENT)
00774     {
00775         observationP->callback(observationP->clientP->internalID,
00776                                &observationP->uri,
00777                                code,
00778                                LWM2M_CONTENT_TEXT, NULL, 0,
00779                                observationP->userData);
00780         observe_remove(observationP);
00781     }
00782     else
00783     {
00784         observationP->callback(observationP->clientP->internalID,
00785                                &observationP->uri,
00786                                0,
00787                                packet->content_type, packet->payload, packet->payload_len,
00788                                observationP->userData);
00789     }
00790 }
00791 
00792 
00793 static void prv_obsCancelRequestCallback(lwm2m_transaction_t * transacP,
00794                                          void * message)
00795 {
00796     cancellation_data_t * cancelP = (cancellation_data_t *)transacP->userData;
00797     coap_packet_t * packet = (coap_packet_t *)message;
00798     uint8_t code;
00799 
00800     if (message == NULL)
00801     {
00802         code = COAP_503_SERVICE_UNAVAILABLE;
00803     }
00804     else
00805     {
00806         code = packet->code;
00807     }
00808 
00809     if (code != COAP_205_CONTENT)
00810     {
00811         cancelP->callbackP(cancelP->observationP->clientP->internalID,
00812                            &cancelP->observationP->uri,
00813                            code,
00814                            LWM2M_CONTENT_TEXT, NULL, 0,
00815                            cancelP->userDataP);
00816     }
00817     else
00818     {
00819         cancelP->callbackP(cancelP->observationP->clientP->internalID,
00820                            &cancelP->observationP->uri,
00821                            0,
00822                            packet->content_type, packet->payload, packet->payload_len,
00823                            cancelP->userDataP);
00824     }
00825 
00826     observe_remove(cancelP->observationP);
00827 
00828     lwm2m_free(cancelP);
00829 }
00830 
00831 
00832 int lwm2m_observe(lwm2m_context_t * contextP,
00833                   uint16_t clientID,
00834                   lwm2m_uri_t * uriP,
00835                   lwm2m_result_callback_t callback,
00836                   void * userData)
00837 {
00838     lwm2m_client_t * clientP;
00839     lwm2m_transaction_t * transactionP;
00840     lwm2m_observation_t * observationP;
00841     uint8_t token[4];
00842 
00843     LOG_ARG("clientID: %d", clientID);
00844     LOG_URI(uriP);
00845 
00846     if (!LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(uriP)) return COAP_400_BAD_REQUEST;
00847 
00848     clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID);
00849     if (clientP == NULL) return COAP_404_NOT_FOUND;
00850 
00851     observationP = (lwm2m_observation_t *)lwm2m_malloc(sizeof(lwm2m_observation_t));
00852     if (observationP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
00853     memset(observationP, 0, sizeof(lwm2m_observation_t));
00854 
00855     observationP->id = lwm2m_list_newId((lwm2m_list_t *)clientP->observationList);
00856     memcpy(&observationP->uri, uriP, sizeof(lwm2m_uri_t));
00857     observationP->clientP = clientP;
00858     observationP->status = STATE_REG_PENDING;
00859     observationP->callback = callback;
00860     observationP->userData = userData;
00861 
00862     token[0] = clientP->internalID >> 8;
00863     token[1] = clientP->internalID & 0xFF;
00864     token[2] = observationP->id >> 8;
00865     token[3] = observationP->id & 0xFF;
00866 
00867     transactionP = transaction_new(clientP->sessionH, COAP_GET, clientP->altPath, uriP, contextP->nextMID++, 4, token);
00868     if (transactionP == NULL)
00869     {
00870         lwm2m_free(observationP);
00871         return COAP_500_INTERNAL_SERVER_ERROR;
00872     }
00873 
00874     observationP->clientP->observationList = (lwm2m_observation_t *)LWM2M_LIST_ADD(observationP->clientP->observationList, observationP);
00875 
00876     coap_set_header_observe(transactionP->message, 0);
00877     coap_set_header_token(transactionP->message, token, sizeof(token));
00878 
00879     transactionP->callback = prv_obsRequestCallback;
00880     transactionP->userData = (void *)observationP;
00881 
00882     contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transactionP);
00883 
00884     return transaction_send(contextP, transactionP);
00885 }
00886 
00887 int lwm2m_observe_cancel(lwm2m_context_t * contextP,
00888                          uint16_t clientID,
00889                          lwm2m_uri_t * uriP,
00890                          lwm2m_result_callback_t callback,
00891                          void * userData)
00892 {
00893     lwm2m_client_t * clientP;
00894     lwm2m_observation_t * observationP;
00895 
00896     LOG_ARG("clientID: %d", clientID);
00897     LOG_URI(uriP);
00898 
00899     clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID);
00900     if (clientP == NULL) return COAP_404_NOT_FOUND;
00901 
00902     observationP = prv_findObservationByURI(clientP, uriP);
00903     if (observationP == NULL) return COAP_404_NOT_FOUND;
00904 
00905     switch (observationP->status)
00906     {
00907     case STATE_REGISTERED:
00908     {
00909         lwm2m_transaction_t * transactionP;
00910         cancellation_data_t * cancelP;
00911 
00912         transactionP = transaction_new(clientP->sessionH, COAP_GET, clientP->altPath, uriP, contextP->nextMID++, 0, NULL);
00913         if (transactionP == NULL)
00914         {
00915             return COAP_500_INTERNAL_SERVER_ERROR;
00916         }
00917         cancelP = (cancellation_data_t *)lwm2m_malloc(sizeof(cancellation_data_t));
00918         if (cancelP == NULL)
00919         {
00920             lwm2m_free(transactionP);
00921             return COAP_500_INTERNAL_SERVER_ERROR;
00922         }
00923 
00924         coap_set_header_observe(transactionP->message, 1);
00925 
00926         cancelP->observationP = observationP;
00927         cancelP->callbackP = callback;
00928         cancelP->userDataP = userData;
00929 
00930         transactionP->callback = prv_obsCancelRequestCallback;
00931         transactionP->userData = (void *)cancelP;
00932 
00933         contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transactionP);
00934 
00935         return transaction_send(contextP, transactionP);
00936     }
00937 
00938     case STATE_REG_PENDING:
00939         observationP->status = STATE_DEREG_PENDING;
00940         break;
00941 
00942     default:
00943         // Should not happen
00944         break;
00945     }
00946 
00947     return COAP_NO_ERROR;
00948 }
00949 
00950 bool observe_handleNotify(lwm2m_context_t * contextP,
00951                            void * fromSessionH,
00952                            coap_packet_t * message,
00953                            coap_packet_t * response)
00954 {
00955     uint8_t * tokenP;
00956     int token_len;
00957     uint16_t clientID;
00958     uint16_t obsID;
00959     lwm2m_client_t * clientP;
00960     lwm2m_observation_t * observationP;
00961     uint32_t count;
00962 
00963     LOG("Entering");
00964     token_len = coap_get_header_token(message, (const uint8_t **)&tokenP);
00965     if (token_len != sizeof(uint32_t)) return false;
00966 
00967     if (1 != coap_get_header_observe(message, &count)) return false;
00968 
00969     clientID = (tokenP[0] << 8) | tokenP[1];
00970     obsID = (tokenP[2] << 8) | tokenP[3];
00971 
00972     clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID);
00973     if (clientP == NULL) return false;
00974 
00975     observationP = (lwm2m_observation_t *)lwm2m_list_find((lwm2m_list_t *)clientP->observationList, obsID);
00976     if (observationP == NULL)
00977     {
00978         coap_init_message(response, COAP_TYPE_RST, 0, message->mid);
00979         message_send(contextP, response, fromSessionH);
00980     }
00981     else
00982     {
00983         if (message->type == COAP_TYPE_CON ) {
00984             coap_init_message(response, COAP_TYPE_ACK, 0, message->mid);
00985             message_send(contextP, response, fromSessionH);
00986         }
00987         observationP->callback(clientID,
00988                                &observationP->uri,
00989                                (int)count,
00990                                message->content_type, message->payload, message->payload_len,
00991                                observationP->userData);
00992     }
00993     return true;
00994 }
00995 #endif