terence zhang / wakaama-core
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers liblwm2m.c Source File

liblwm2m.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  *    Fabien Fleutot - Please refer to git log
00016  *    Simon Bernard - Please refer to git log
00017  *    Toby Jaffey - Please refer to git log
00018  *    Pascal Rieux - Please refer to git log
00019  *    
00020  *******************************************************************************/
00021 
00022 /*
00023  Copyright (c) 2013, 2014 Intel Corporation
00024 
00025  Redistribution and use in source and binary forms, with or without modification,
00026  are permitted provided that the following conditions are met:
00027 
00028      * Redistributions of source code must retain the above copyright notice,
00029        this list of conditions and the following disclaimer.
00030      * Redistributions in binary form must reproduce the above copyright notice,
00031        this list of conditions and the following disclaimer in the documentation
00032        and/or other materials provided with the distribution.
00033      * Neither the name of Intel Corporation nor the names of its contributors
00034        may be used to endorse or promote products derived from this software
00035        without specific prior written permission.
00036 
00037  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00038  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00039  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00040  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00041  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00042  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00043  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00044  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00045  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
00046  THE POSSIBILITY OF SUCH DAMAGE.
00047 
00048  David Navarro <david.navarro@intel.com>
00049 
00050 */
00051 
00052 #include "internals.h"
00053 
00054 #include <stdlib.h>
00055 #include <string.h>
00056 
00057 #include <stdio.h>
00058 
00059 
00060 lwm2m_context_t * lwm2m_init(void * userData)
00061 {
00062     lwm2m_context_t * contextP;
00063 
00064     LOG("Entering");
00065     contextP = (lwm2m_context_t *)lwm2m_malloc(sizeof(lwm2m_context_t));
00066     if (NULL != contextP)
00067     {
00068         memset(contextP, 0, sizeof(lwm2m_context_t));
00069         contextP->userData = userData;
00070         srand((int)lwm2m_gettime());
00071         contextP->nextMID = rand();
00072     }
00073 
00074     return contextP;
00075 }
00076 
00077 #ifdef LWM2M_CLIENT_MODE
00078 void lwm2m_deregister(lwm2m_context_t * context)
00079 {
00080     lwm2m_server_t * server = context->serverList;
00081 
00082     LOG("Entering");
00083     while (NULL != server)
00084     {
00085         registration_deregister(context, server);
00086         server = server->next;
00087     }
00088 }
00089 
00090 static void prv_deleteServer(lwm2m_server_t * serverP)
00091 {
00092     // TODO parse transaction and observation to remove the ones related to this server
00093     if (NULL != serverP->location)
00094     {
00095         lwm2m_free(serverP->location);
00096     }
00097     free_block1_buffer(serverP->block1Data);
00098     lwm2m_free(serverP);
00099 }
00100 
00101 static void prv_deleteServerList(lwm2m_context_t * context)
00102 {
00103     while (NULL != context->serverList)
00104     {
00105         lwm2m_server_t * server;
00106         server = context->serverList;
00107         context->serverList = server->next;
00108         prv_deleteServer(server);
00109     }
00110 }
00111 
00112 static void prv_deleteBootstrapServer(lwm2m_server_t * serverP)
00113 {
00114     // TODO should we free location as in prv_deleteServer ?
00115     // TODO should we parse transaction and observation to remove the ones related to this server ?
00116     free_block1_buffer(serverP->block1Data);
00117     lwm2m_free(serverP);
00118 }
00119 
00120 static void prv_deleteBootstrapServerList(lwm2m_context_t * context)
00121 {
00122     while (NULL != context->bootstrapServerList)
00123     {
00124         lwm2m_server_t * server;
00125         server = context->bootstrapServerList;
00126         context->bootstrapServerList = server->next;
00127         prv_deleteBootstrapServer(server);
00128     }
00129 }
00130 
00131 static void prv_deleteObservedList(lwm2m_context_t * contextP)
00132 {
00133     while (NULL != contextP->observedList)
00134     {
00135         lwm2m_observed_t * targetP;
00136         lwm2m_watcher_t * watcherP;
00137 
00138         targetP = contextP->observedList;
00139         contextP->observedList = contextP->observedList->next;
00140 
00141         for (watcherP = targetP->watcherList ; watcherP != NULL ; watcherP = watcherP->next)
00142         {
00143             if (watcherP->parameters != NULL) lwm2m_free(watcherP->parameters);
00144         }
00145         LWM2M_LIST_FREE(targetP->watcherList);
00146 
00147         lwm2m_free(targetP);
00148     }
00149 }
00150 #endif
00151 
00152 void prv_deleteTransactionList(lwm2m_context_t * context)
00153 {
00154     while (NULL != context->transactionList)
00155     {
00156         lwm2m_transaction_t * transaction;
00157 
00158         transaction = context->transactionList;
00159         context->transactionList = context->transactionList->next;
00160         transaction_free(transaction);
00161     }
00162 }
00163 
00164 void lwm2m_close(lwm2m_context_t * contextP)
00165 {
00166 #ifdef LWM2M_CLIENT_MODE
00167 
00168     LOG("Entering");
00169     lwm2m_deregister(contextP);
00170     prv_deleteServerList(contextP);
00171     prv_deleteBootstrapServerList(contextP);
00172     prv_deleteObservedList(contextP);
00173     lwm2m_free(contextP->endpointName);
00174     if (contextP->msisdn != NULL)
00175     {
00176         lwm2m_free(contextP->msisdn);
00177     }
00178     if (contextP->altPath != NULL)
00179     {
00180         lwm2m_free(contextP->altPath);
00181     }
00182 
00183 #endif
00184 
00185 #ifdef LWM2M_SERVER_MODE
00186     while (NULL != contextP->clientList)
00187     {
00188         lwm2m_client_t * clientP;
00189 
00190         clientP = contextP->clientList;
00191         contextP->clientList = contextP->clientList->next;
00192 
00193         registration_freeClient(clientP);
00194     }
00195 #endif
00196 
00197     prv_deleteTransactionList(contextP);
00198     lwm2m_free(contextP);
00199 }
00200 
00201 #ifdef LWM2M_CLIENT_MODE
00202 static int prv_refreshServerList(lwm2m_context_t * contextP)
00203 {
00204     lwm2m_server_t * targetP;
00205     lwm2m_server_t * nextP;
00206 
00207     // Remove all servers marked as dirty
00208     targetP = contextP->bootstrapServerList;
00209     contextP->bootstrapServerList = NULL;
00210     while (targetP != NULL)
00211     {
00212         nextP = targetP->next;
00213         targetP->next = NULL;
00214         if (!targetP->dirty)
00215         {
00216             targetP->status = STATE_DEREGISTERED;
00217             contextP->bootstrapServerList = (lwm2m_server_t *)LWM2M_LIST_ADD(contextP->bootstrapServerList, targetP);
00218         }
00219         else
00220         {
00221             prv_deleteServer(targetP);
00222         }
00223         targetP = nextP;
00224     }
00225     targetP = contextP->serverList;
00226     contextP->serverList = NULL;
00227     while (targetP != NULL)
00228     {
00229         nextP = targetP->next;
00230         targetP->next = NULL;
00231         if (!targetP->dirty)
00232         {
00233             // TODO: Should we revert the status to STATE_DEREGISTERED ?
00234             contextP->serverList = (lwm2m_server_t *)LWM2M_LIST_ADD(contextP->serverList, targetP);
00235         }
00236         else
00237         {
00238             prv_deleteServer(targetP);
00239         }
00240         targetP = nextP;
00241     }
00242 
00243     return object_getServers(contextP);
00244 }
00245 
00246 int lwm2m_configure(lwm2m_context_t * contextP,
00247                     const char * endpointName,
00248                     const char * msisdn,
00249                     const char * altPath,
00250                     uint16_t numObject,
00251                     lwm2m_object_t * objectList[])
00252 {
00253     int i;
00254     uint8_t found;
00255 
00256     LOG_ARG("endpointName: \"%s\", msisdn: \"%s\", altPath: \"%s\", numObject: %d", endpointName, msisdn, altPath, numObject);
00257     // This API can be called only once for now
00258     if (contextP->endpointName != NULL || contextP->objectList != NULL) return COAP_400_BAD_REQUEST;
00259 
00260     if (endpointName == NULL) return COAP_400_BAD_REQUEST;
00261     if (numObject < 3) return COAP_400_BAD_REQUEST;
00262     // Check that mandatory objects are present
00263     found = 0;
00264     for (i = 0 ; i < numObject ; i++)
00265     {
00266         if (objectList[i]->objID == LWM2M_SECURITY_OBJECT_ID) found |= 0x01;
00267         if (objectList[i]->objID == LWM2M_SERVER_OBJECT_ID) found |= 0x02;
00268         if (objectList[i]->objID == LWM2M_DEVICE_OBJECT_ID) found |= 0x04;
00269     }
00270     if (found != 0x07) return COAP_400_BAD_REQUEST;
00271     if (altPath != NULL)
00272     {
00273         if (0 == utils_isAltPathValid(altPath))
00274         {
00275             return COAP_400_BAD_REQUEST;
00276         }
00277         if (altPath[1] == 0)
00278         {
00279             altPath = NULL;
00280         }
00281     }
00282     contextP->endpointName = lwm2m_strdup(endpointName);
00283     if (contextP->endpointName == NULL)
00284     {
00285         return COAP_500_INTERNAL_SERVER_ERROR;
00286     }
00287 
00288     if (msisdn != NULL)
00289     {
00290         contextP->msisdn = lwm2m_strdup(msisdn);
00291         if (contextP->msisdn == NULL)
00292         {
00293             return COAP_500_INTERNAL_SERVER_ERROR;
00294         }
00295     }
00296 
00297     if (altPath != NULL)
00298     {
00299         contextP->altPath = lwm2m_strdup(altPath);
00300         if (contextP->altPath == NULL)
00301         {
00302             return COAP_500_INTERNAL_SERVER_ERROR;
00303         }
00304     }
00305 
00306     for (i = 0; i < numObject; i++)
00307     {
00308         objectList[i]->next = NULL;
00309         contextP->objectList = (lwm2m_object_t *)LWM2M_LIST_ADD(contextP->objectList, objectList[i]);
00310     }
00311 
00312     return COAP_NO_ERROR;
00313 }
00314 
00315 int lwm2m_add_object(lwm2m_context_t * contextP,
00316                      lwm2m_object_t * objectP)
00317 {
00318     lwm2m_object_t * targetP;
00319 
00320     LOG_ARG("ID: %d", objectP->objID);
00321     targetP = (lwm2m_object_t *)LWM2M_LIST_FIND(contextP->objectList, objectP->objID);
00322     if (targetP != NULL) return COAP_406_NOT_ACCEPTABLE;
00323     objectP->next = NULL;
00324 
00325     contextP->objectList = (lwm2m_object_t *)LWM2M_LIST_ADD(contextP->objectList, objectP);
00326 
00327     if (contextP->state == STATE_READY)
00328     {
00329         return lwm2m_update_registration(contextP, 0, true);
00330     }
00331 
00332     return COAP_NO_ERROR;
00333 }
00334 
00335 int lwm2m_remove_object(lwm2m_context_t * contextP,
00336                         uint16_t id)
00337 {
00338     lwm2m_object_t * targetP;
00339 
00340     LOG_ARG("ID: %d", id);
00341     contextP->objectList = (lwm2m_object_t *)LWM2M_LIST_RM(contextP->objectList, id, &targetP);
00342 
00343     if (targetP == NULL) return COAP_404_NOT_FOUND;
00344 
00345     if (contextP->state == STATE_READY)
00346     {
00347         return lwm2m_update_registration(contextP, 0, true);
00348     }
00349 
00350     return 0;
00351 }
00352 
00353 #endif
00354 
00355 
00356 int lwm2m_step(lwm2m_context_t * contextP,
00357                time_t * timeoutP)
00358 {
00359     time_t tv_sec;
00360     int result;
00361 
00362     LOG_ARG("timeoutP: %" PRId64, *timeoutP);
00363     tv_sec = lwm2m_gettime();
00364     if (tv_sec < 0) return COAP_500_INTERNAL_SERVER_ERROR;
00365 
00366 #ifdef LWM2M_CLIENT_MODE
00367     LOG_ARG("State: %s", STR_STATE(contextP->state));
00368     // state can also be modified in bootstrap_handleCommand().
00369 
00370 next_step:
00371     switch (contextP->state)
00372     {
00373     case STATE_INITIAL:
00374         if (0 != prv_refreshServerList(contextP)) return COAP_503_SERVICE_UNAVAILABLE;
00375         if (contextP->serverList != NULL)
00376         {
00377             contextP->state = STATE_REGISTER_REQUIRED;
00378         }
00379         else
00380         {
00381             // Bootstrapping
00382             contextP->state = STATE_BOOTSTRAP_REQUIRED;
00383         }
00384         goto next_step;
00385         break;
00386 
00387     case STATE_BOOTSTRAP_REQUIRED:
00388 #ifdef LWM2M_BOOTSTRAP
00389         if (contextP->bootstrapServerList != NULL)
00390         {
00391             bootstrap_start(contextP);
00392             contextP->state = STATE_BOOTSTRAPPING;
00393             bootstrap_step(contextP, tv_sec, timeoutP);
00394         }
00395         else
00396 #endif
00397         {
00398             return COAP_503_SERVICE_UNAVAILABLE;
00399         }
00400         break;
00401 
00402 #ifdef LWM2M_BOOTSTRAP
00403     case STATE_BOOTSTRAPPING:
00404         switch (bootstrap_getStatus(contextP))
00405         {
00406         case STATE_BS_FINISHED:
00407             contextP->state = STATE_INITIAL;
00408             goto next_step;
00409             break;
00410 
00411         case STATE_BS_FAILED:
00412             return COAP_503_SERVICE_UNAVAILABLE;
00413 
00414         default:
00415             // keep on waiting
00416             bootstrap_step(contextP, tv_sec, timeoutP);
00417             break;
00418         }
00419         break;
00420 #endif
00421     case STATE_REGISTER_REQUIRED:
00422         result = registration_start(contextP);
00423         if (COAP_NO_ERROR != result) return result;
00424         contextP->state = STATE_REGISTERING;
00425         break;
00426 
00427     case STATE_REGISTERING:
00428     {
00429         switch (registration_getStatus(contextP))
00430         {
00431         case STATE_REGISTERED:
00432             contextP->state = STATE_READY;
00433             break;
00434 
00435         case STATE_REG_FAILED:
00436             // TODO avoid infinite loop by checking the bootstrap info is different
00437             contextP->state = STATE_BOOTSTRAP_REQUIRED;
00438             goto next_step;
00439             break;
00440 
00441         case STATE_REG_PENDING:
00442         default:
00443             // keep on waiting
00444             break;
00445         }
00446     }
00447     break;
00448 
00449     case STATE_READY:
00450         if (registration_getStatus(contextP) == STATE_REG_FAILED)
00451         {
00452             // TODO avoid infinite loop by checking the bootstrap info is different
00453             contextP->state = STATE_BOOTSTRAP_REQUIRED;
00454             goto next_step;
00455             break;
00456         }
00457         break;
00458 
00459     default:
00460         // do nothing
00461         break;
00462     }
00463 
00464     observe_step(contextP, tv_sec, timeoutP);
00465 #endif
00466 
00467     registration_step(contextP, tv_sec, timeoutP);
00468     transaction_step(contextP, tv_sec, timeoutP);
00469 
00470     LOG_ARG("Final timeoutP: %" PRId64, *timeoutP);
00471 #ifdef LWM2M_CLIENT_MODE
00472     LOG_ARG("Final state: %s", STR_STATE(contextP->state));
00473 #endif
00474     return 0;
00475 }