terence zhang / Mbed OS mbed-os-example-wakaama

Dependencies:   C12832 LM75B

Revision:
5:917e1705e5c2
Parent:
1:3549d3c3967c
Child:
10:df97539c6ddd
--- a/wakaama/liblwm2m.c	Fri Apr 28 18:20:36 2017 +0800
+++ b/wakaama/liblwm2m.c	Fri Apr 28 18:30:50 2017 +0800
@@ -15,6 +15,7 @@
  *    Fabien Fleutot - Please refer to git log
  *    Simon Bernard - Please refer to git log
  *    Toby Jaffey - Please refer to git log
+ *    Pascal Rieux - Please refer to git log
  *    
  *******************************************************************************/
 
@@ -64,138 +65,129 @@
 }
 #endif
 
-lwm2m_context_t * lwm2m_init(char * endpointName,
-                             uint16_t numObject,
-                             lwm2m_object_t * objectList[],
-                             lwm2m_buffer_send_callback_t bufferSendCallback,
-                             void * bufferSendUserData)
+lwm2m_context_t * lwm2m_init(void * userData)
 {
     lwm2m_context_t * contextP;
 
-    if (NULL == bufferSendCallback)
-        return NULL;
-
-#ifdef LWM2M_CLIENT_MODE
-    if (numObject != 0)
-    {
-        int i;
-
-        for (i = 0 ; i < numObject ; i++)
-        {
-            if (objectList[i]->objID <= LWM2M_ACL_OBJECT_ID)
-            {
-                // Use of a reserved object ID
-                return NULL;
-            }
-        }
-    }
-#endif
-
+    LOG("Entering");
     contextP = (lwm2m_context_t *)lwm2m_malloc(sizeof(lwm2m_context_t));
     if (NULL != contextP)
     {
         memset(contextP, 0, sizeof(lwm2m_context_t));
-        contextP->bufferSendCallback = bufferSendCallback;
-        contextP->bufferSendUserData = bufferSendUserData;
-        srand(time(NULL));
+        contextP->userData = userData;
+        srand((int)lwm2m_gettime());
         contextP->nextMID = rand();
-#ifdef LWM2M_CLIENT_MODE
-        
-        contextP->endpointName = (char *)lwm2m_malloc(strlen(endpointName));
-        if (contextP->endpointName == NULL)
-        {
-            lwm2m_free(contextP);
-            return NULL;
-        }
-        
-        strcpy(contextP->endpointName,endpointName);
-        printf("name: %s, %s, %d\n",endpointName,contextP->endpointName,strlen(endpointName));
-        
-        //contextP->endpointName = strdup(endpointName);
-
-        if (numObject != 0)
-        {
-            contextP->objectList = (lwm2m_object_t **)lwm2m_malloc(numObject * sizeof(lwm2m_object_t *));
-            if (NULL != contextP->objectList)
-            {
-                memcpy(contextP->objectList, objectList, numObject * sizeof(lwm2m_object_t *));
-                contextP->numObject = numObject;
-            }
-            else
-            {
-                lwm2m_free(contextP->endpointName);
-                lwm2m_free(contextP);
-                return NULL;
-            }
-        }
-#endif
     }
 
     return contextP;
 }
 
-void lwm2m_close(lwm2m_context_t * contextP)
+#ifdef LWM2M_CLIENT_MODE
+void lwm2m_deregister(lwm2m_context_t * context)
 {
-    int i;
+    lwm2m_server_t * server = context->serverList;
 
-#ifdef LWM2M_CLIENT_MODE
-    for (i = 0 ; i < contextP->numObject ; i++)
+    LOG("Entering");
+    while (NULL != server)
     {
-        if (NULL != contextP->objectList[i]->closeFunc)
-        {
-            contextP->objectList[i]->closeFunc(contextP->objectList[i]);
-        }
-        lwm2m_free(contextP->objectList[i]);
+        registration_deregister(context, server);
+        server = server->next;
     }
+}
 
-    if (NULL != contextP->bootstrapServer)
+static void prv_deleteServer(lwm2m_server_t * serverP)
+{
+    // TODO parse transaction and observation to remove the ones related to this server
+    if (NULL != serverP->location)
+    {
+        lwm2m_free(serverP->location);
+    }
+    free_block1_buffer(serverP->block1Data);
+    lwm2m_free(serverP);
+}
+
+static void prv_deleteServerList(lwm2m_context_t * context)
+{
+    while (NULL != context->serverList)
     {
-        if (NULL != contextP->bootstrapServer->uri) lwm2m_free (contextP->bootstrapServer->uri);
-        if (NULL != contextP->bootstrapServer->security.privateKey) lwm2m_free (contextP->bootstrapServer->security.privateKey);
-        if (NULL != contextP->bootstrapServer->security.publicKey) lwm2m_free (contextP->bootstrapServer->security.publicKey);
-        lwm2m_free(contextP->bootstrapServer);
+        lwm2m_server_t * server;
+        server = context->serverList;
+        context->serverList = server->next;
+        prv_deleteServer(server);
     }
-
-    while (NULL != contextP->serverList)
-    {
-        lwm2m_server_t * targetP;
+}
 
-        targetP = contextP->serverList;
-        contextP->serverList = contextP->serverList->next;
-
-        registration_deregister(contextP, targetP);
+static void prv_deleteBootstrapServer(lwm2m_server_t * serverP)
+{
+    // TODO should we free location as in prv_deleteServer ?
+    // TODO should we parse transaction and observation to remove the ones related to this server ?
+    free_block1_buffer(serverP->block1Data);
+    lwm2m_free(serverP);
+}
 
-        if (NULL != targetP->location) lwm2m_free(targetP->location);
-        if (NULL != targetP->security.privateKey) lwm2m_free (targetP->security.privateKey);
-        if (NULL != targetP->security.publicKey) lwm2m_free (targetP->security.publicKey);
-        if (NULL != targetP->sms) lwm2m_free (targetP->sms);
-        lwm2m_free(targetP);
+static void prv_deleteBootstrapServerList(lwm2m_context_t * context)
+{
+    while (NULL != context->bootstrapServerList)
+    {
+        lwm2m_server_t * server;
+        server = context->bootstrapServerList;
+        context->bootstrapServerList = server->next;
+        prv_deleteBootstrapServer(server);
     }
+}
 
+static void prv_deleteObservedList(lwm2m_context_t * contextP)
+{
     while (NULL != contextP->observedList)
     {
         lwm2m_observed_t * targetP;
+        lwm2m_watcher_t * watcherP;
 
         targetP = contextP->observedList;
         contextP->observedList = contextP->observedList->next;
 
-        while (NULL != targetP->watcherList)
+        for (watcherP = targetP->watcherList ; watcherP != NULL ; watcherP = watcherP->next)
         {
-            lwm2m_watcher_t * watcherP;
+            if (watcherP->parameters != NULL) lwm2m_free(watcherP->parameters);
+        }
+        LWM2M_LIST_FREE(targetP->watcherList);
 
-            watcherP = targetP->watcherList;
-            targetP->watcherList = targetP->watcherList->next;
-            lwm2m_free(watcherP);
-        }
         lwm2m_free(targetP);
     }
+}
+#endif
 
-   if (NULL != contextP->objectList)
+void prv_deleteTransactionList(lwm2m_context_t * context)
+{
+    while (NULL != context->transactionList)
     {
-        lwm2m_free(contextP->objectList);
+        lwm2m_transaction_t * transaction;
+
+        transaction = context->transactionList;
+        context->transactionList = context->transactionList->next;
+        transaction_free(transaction);
+    }
+}
+
+void lwm2m_close(lwm2m_context_t * contextP)
+{
+#ifdef LWM2M_CLIENT_MODE
+
+    LOG("Entering");
+    lwm2m_deregister(contextP);
+    prv_deleteServerList(contextP);
+    prv_deleteBootstrapServerList(contextP);
+    prv_deleteObservedList(contextP);
+    lwm2m_free(contextP->endpointName);
+    if (contextP->msisdn != NULL)
+    {
+        lwm2m_free(contextP->msisdn);
+    }
+    if (contextP->altPath != NULL)
+    {
+        lwm2m_free(contextP->altPath);
     }
 
-    lwm2m_free(contextP->endpointName);
 #endif
 
 #ifdef LWM2M_SERVER_MODE
@@ -206,152 +198,286 @@
         clientP = contextP->clientList;
         contextP->clientList = contextP->clientList->next;
 
-        prv_freeClient(clientP);
+        registration_freeClient(clientP);
     }
 #endif
 
-    while (NULL != contextP->transactionList)
-    {
-        lwm2m_transaction_t * transacP;
-
-        transacP = contextP->transactionList;
-        contextP->transactionList = contextP->transactionList->next;
-
-        transaction_free(transacP);
-    }
-
+    prv_deleteTransactionList(contextP);
     lwm2m_free(contextP);
 }
 
 #ifdef LWM2M_CLIENT_MODE
-void lwm2m_set_bootstrap_server(lwm2m_context_t * contextP,
-                               lwm2m_bootstrap_server_t * serverP)
+static int prv_refreshServerList(lwm2m_context_t * contextP)
 {
-    if (NULL != contextP->bootstrapServer)
+    lwm2m_server_t * targetP;
+    lwm2m_server_t * nextP;
+
+    // Remove all servers marked as dirty
+    targetP = contextP->bootstrapServerList;
+    contextP->bootstrapServerList = NULL;
+    while (targetP != NULL)
     {
-        if (NULL != contextP->bootstrapServer->uri) lwm2m_free (contextP->bootstrapServer->uri);
-        if (NULL != contextP->bootstrapServer->security.privateKey) lwm2m_free (contextP->bootstrapServer->security.privateKey);
-        if (NULL != contextP->bootstrapServer->security.publicKey) lwm2m_free (contextP->bootstrapServer->security.publicKey);
-        lwm2m_free(contextP->bootstrapServer);
+        nextP = targetP->next;
+        targetP->next = NULL;
+        if (!targetP->dirty)
+        {
+            targetP->status = STATE_DEREGISTERED;
+            contextP->bootstrapServerList = (lwm2m_server_t *)LWM2M_LIST_ADD(contextP->bootstrapServerList, targetP);
+        }
+        else
+        {
+            prv_deleteServer(targetP);
+        }
+        targetP = nextP;
     }
-    contextP->bootstrapServer = serverP;
+    targetP = contextP->serverList;
+    contextP->serverList = NULL;
+    while (targetP != NULL)
+    {
+        nextP = targetP->next;
+        targetP->next = NULL;
+        if (!targetP->dirty)
+        {
+            // TODO: Should we revert the status to STATE_DEREGISTERED ?
+            contextP->serverList = (lwm2m_server_t *)LWM2M_LIST_ADD(contextP->serverList, targetP);
+        }
+        else
+        {
+            prv_deleteServer(targetP);
+        }
+        targetP = nextP;
+    }
+
+    return object_getServers(contextP);
 }
 
-int lwm2m_add_server(lwm2m_context_t * contextP,
-                     uint16_t shortID,
-                     uint32_t lifetime,
-                     char * sms,
-                     lwm2m_binding_t binding,
-                     void * sessionH,
-                     lwm2m_security_t * securityP)
+int lwm2m_configure(lwm2m_context_t * contextP,
+                    const char * endpointName,
+                    const char * msisdn,
+                    const char * altPath,
+                    uint16_t numObject,
+                    lwm2m_object_t * objectList[])
 {
-    lwm2m_server_t * serverP;
-    int status = COAP_500_INTERNAL_SERVER_ERROR;
+    int i;
+    uint8_t found;
 
-    serverP = (lwm2m_server_t *)lwm2m_malloc(sizeof(lwm2m_server_t));
-    if (serverP != NULL)
+    LOG_ARG("endpointName: \"%s\", msisdn: \"%s\", altPath: \"%s\", numObject: %d", endpointName, msisdn, altPath, numObject);
+    // This API can be called only once for now
+    if (contextP->endpointName != NULL || contextP->objectList != NULL) return COAP_400_BAD_REQUEST;
+
+    if (endpointName == NULL) return COAP_400_BAD_REQUEST;
+    if (numObject < 3) return COAP_400_BAD_REQUEST;
+    // Check that mandatory objects are present
+    found = 0;
+    for (i = 0 ; i < numObject ; i++)
     {
-        memset(serverP, 0, sizeof(lwm2m_server_t));
-        memcpy(&(serverP->security), securityP, sizeof(lwm2m_security_t));
-        serverP->shortID = shortID;
-        serverP->lifetime = lifetime;
-        serverP->binding = binding;
-        if (sms != NULL)
+        if (objectList[i]->objID == LWM2M_SECURITY_OBJECT_ID) found |= 0x01;
+        if (objectList[i]->objID == LWM2M_SERVER_OBJECT_ID) found |= 0x02;
+        if (objectList[i]->objID == LWM2M_DEVICE_OBJECT_ID) found |= 0x04;
+    }
+    if (found != 0x07) return COAP_400_BAD_REQUEST;
+    if (altPath != NULL)
+    {
+        if (0 == utils_isAltPathValid(altPath))
+        {
+            return COAP_400_BAD_REQUEST;
+        }
+        if (altPath[1] == 0)
         {
-            // copy the SMS number
-            int len = strlen(sms);
-            serverP->sms = (char*) lwm2m_malloc(strlen(sms)+1);
-            memcpy(serverP->sms, sms, len+1);
+            altPath = NULL;
         }
-        serverP->sessionH = sessionH;
-        contextP->serverList = (lwm2m_server_t*)LWM2M_LIST_ADD(contextP->serverList, serverP);
+    }
+    contextP->endpointName = lwm2m_strdup(endpointName);
+    if (contextP->endpointName == NULL)
+    {
+        return COAP_500_INTERNAL_SERVER_ERROR;
+    }
 
-        status = COAP_NO_ERROR;
+    if (msisdn != NULL)
+    {
+        contextP->msisdn = lwm2m_strdup(msisdn);
+        if (contextP->msisdn == NULL)
+        {
+            return COAP_500_INTERNAL_SERVER_ERROR;
+        }
     }
 
-    return status;
+    if (altPath != NULL)
+    {
+        contextP->altPath = lwm2m_strdup(altPath);
+        if (contextP->altPath == NULL)
+        {
+            return COAP_500_INTERNAL_SERVER_ERROR;
+        }
+    }
+
+    for (i = 0; i < numObject; i++)
+    {
+        objectList[i]->next = NULL;
+        contextP->objectList = (lwm2m_object_t *)LWM2M_LIST_ADD(contextP->objectList, objectList[i]);
+    }
+
+    return COAP_NO_ERROR;
 }
-#endif
 
-int lwm2m_step(lwm2m_context_t * contextP, struct timeval * timeoutP)
+int lwm2m_add_object(lwm2m_context_t * contextP,
+                     lwm2m_object_t * objectP)
 {
-    int ret =0;
-    lwm2m_transaction_t * transacP;
-    struct timeval tv;
-    //struct timezone tz;
-#ifdef LWM2M_SERVER_MODE
-    lwm2m_client_t * clientP;
+    lwm2m_object_t * targetP;
+
+    LOG_ARG("ID: %d", objectP->objID);
+    targetP = (lwm2m_object_t *)LWM2M_LIST_FIND(contextP->objectList, objectP->objID);
+    if (targetP != NULL) return COAP_406_NOT_ACCEPTABLE;
+    objectP->next = NULL;
+
+    contextP->objectList = (lwm2m_object_t *)LWM2M_LIST_ADD(contextP->objectList, objectP);
+
+    if (contextP->state == STATE_READY)
+    {
+        return lwm2m_update_registration(contextP, 0, true);
+    }
+
+    return COAP_NO_ERROR;
+}
+
+int lwm2m_remove_object(lwm2m_context_t * contextP,
+                        uint16_t id)
+{
+    lwm2m_object_t * targetP;
+
+    LOG_ARG("ID: %d", id);
+    contextP->objectList = (lwm2m_object_t *)LWM2M_LIST_RM(contextP->objectList, id, &targetP);
+
+    if (targetP == NULL) return COAP_404_NOT_FOUND;
+
+    if (contextP->state == STATE_READY)
+    {
+        return lwm2m_update_registration(contextP, 0, true);
+    }
+
+    return 0;
+}
+
 #endif
 
 
-    ret = lwm2m_gettimeofday(&tv,NULL);
-    if (0!=ret)
-        return COAP_500_INTERNAL_SERVER_ERROR;
+int lwm2m_step(lwm2m_context_t * contextP,
+               time_t * timeoutP)
+{
+    time_t tv_sec;
+    int result;
 
-    transacP = contextP->transactionList;
-    while (transacP != NULL)
-    {
-        // transaction_send() may remove transaction from the linked list
-        lwm2m_transaction_t * nextP = transacP->next;
-        int removed = 0;
-
-        if (transacP->retrans_time <= tv.tv_sec)
-        {
-            removed = transaction_send(contextP, transacP);
-        }
-
-        if (0 == removed)
-        {
-            time_t interval;
+    LOG_ARG("timeoutP: %" PRId64, *timeoutP);
+    tv_sec = lwm2m_gettime();
+    if (tv_sec < 0) return COAP_500_INTERNAL_SERVER_ERROR;
 
-            if (transacP->retrans_time > tv.tv_sec)
-            {
-                interval = transacP->retrans_time - tv.tv_sec;
-            }
-            else
-            {
-                interval = 1;
-            }
-
-            if (timeoutP->tv_sec > interval)
-            {
-                timeoutP->tv_sec = interval;
-            }
-        }
+#ifdef LWM2M_CLIENT_MODE
+    LOG_ARG("State: %s", STR_STATE(contextP->state));
+    // state can also be modified in bootstrap_handleCommand().
 
-        transacP = nextP;
-    }
-
-#ifdef LWM2M_SERVER_MODE
-    // monitor clients lifetime
-    clientP = contextP->clientList;
-    while (clientP != NULL)
+next_step:
+    switch (contextP->state)
     {
-        lwm2m_client_t * nextP = clientP->next;
-
-        if (clientP->endOfLife <= tv.tv_sec)
+    case STATE_INITIAL:
+        if (0 != prv_refreshServerList(contextP)) return COAP_503_SERVICE_UNAVAILABLE;
+        if (contextP->serverList != NULL)
         {
-            contextP->clientList = (lwm2m_client_t *)LWM2M_LIST_RM(contextP->clientList, clientP->internalID, NULL);
-            if (contextP->monitorCallback != NULL)
-            {
-                contextP->monitorCallback(clientP->internalID, NULL, DELETED_2_02, NULL, 0, contextP->monitorUserData);
-            }
-            prv_freeClient(clientP);
+            contextP->state = STATE_REGISTER_REQUIRED;
         }
         else
         {
-            time_t interval;
+            // Bootstrapping
+            contextP->state = STATE_BOOTSTRAP_REQUIRED;
+        }
+        goto next_step;
+        break;
 
-            interval = clientP->endOfLife - tv.tv_sec;
+    case STATE_BOOTSTRAP_REQUIRED:
+#ifdef LWM2M_BOOTSTRAP
+        if (contextP->bootstrapServerList != NULL)
+        {
+            bootstrap_start(contextP);
+            contextP->state = STATE_BOOTSTRAPPING;
+            bootstrap_step(contextP, tv_sec, timeoutP);
+        }
+        else
+#endif
+        {
+            return COAP_503_SERVICE_UNAVAILABLE;
+        }
+        break;
+
+#ifdef LWM2M_BOOTSTRAP
+    case STATE_BOOTSTRAPPING:
+        switch (bootstrap_getStatus(contextP))
+        {
+        case STATE_BS_FINISHED:
+            contextP->state = STATE_INITIAL;
+            goto next_step;
+            break;
+
+        case STATE_BS_FAILED:
+            return COAP_503_SERVICE_UNAVAILABLE;
 
-            if (timeoutP->tv_sec > interval)
-            {
-                timeoutP->tv_sec = interval;
-            }
+        default:
+            // keep on waiting
+            bootstrap_step(contextP, tv_sec, timeoutP);
+            break;
         }
-        clientP = nextP;
+        break;
+#endif
+    case STATE_REGISTER_REQUIRED:
+        result = registration_start(contextP);
+        if (COAP_NO_ERROR != result) return result;
+        contextP->state = STATE_REGISTERING;
+        break;
+
+    case STATE_REGISTERING:
+    {
+        switch (registration_getStatus(contextP))
+        {
+        case STATE_REGISTERED:
+            contextP->state = STATE_READY;
+            break;
+
+        case STATE_REG_FAILED:
+            // TODO avoid infinite loop by checking the bootstrap info is different
+            contextP->state = STATE_BOOTSTRAP_REQUIRED;
+            goto next_step;
+            break;
+
+        case STATE_REG_PENDING:
+        default:
+            // keep on waiting
+            break;
+        }
     }
+    break;
+
+    case STATE_READY:
+        if (registration_getStatus(contextP) == STATE_REG_FAILED)
+        {
+            // TODO avoid infinite loop by checking the bootstrap info is different
+            contextP->state = STATE_BOOTSTRAP_REQUIRED;
+            goto next_step;
+            break;
+        }
+        break;
+
+    default:
+        // do nothing
+        break;
+    }
+
+    observe_step(contextP, tv_sec, timeoutP);
 #endif
 
+    registration_step(contextP, tv_sec, timeoutP);
+    transaction_step(contextP, tv_sec, timeoutP);
+
+    LOG_ARG("Final timeoutP: %" PRId64, *timeoutP);
+#ifdef LWM2M_CLIENT_MODE
+    LOG_ARG("Final state: %s", STR_STATE(contextP->state));
+#endif
     return 0;
 }