Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: wakaama/registration.c
- Revision:
- 0:f9d13e09cf11
- Child:
- 3:a280069151ac
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/wakaama/registration.c Mon Apr 24 23:03:31 2017 +0000
@@ -0,0 +1,851 @@
+/*******************************************************************************
+ *
+ * Copyright (c) 2013, 2014 Intel Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * The Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * David Navarro, Intel Corporation - initial API and implementation
+ * domedambrosio - Please refer to git log
+ * Fabien Fleutot - Please refer to git log
+ * Simon Bernard - Please refer to git log
+ * Toby Jaffey - Please refer to git log
+ * Manuel Sangoi - Please refer to git log
+ * Julien Vermillard - Please refer to git log
+ *
+ *******************************************************************************/
+
+/*
+ Copyright (c) 2013, 2014 Intel Corporation
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Intel Corporation nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ THE POSSIBILITY OF SUCH DAMAGE.
+
+ David Navarro <david.navarro@intel.com>
+
+*/
+
+#include "internals.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#define MAX_LOCATION_LENGTH 10 // strlen("/rd/65534") + 1
+#define QUERY_TEMPLATE "ep="
+#define QUERY_LENGTH 3 // strlen("ep=")
+#define QUERY_SMS "sms="
+#define QUERY_SMS_LEN 4
+#define QUERY_LIFETIME "lt="
+#define QUERY_LIFETIME_LEN 3
+#define QUERY_VERSION "lwm2m="
+#define QUERY_VERSION_LEN 6
+#define QUERY_BINDING "b="
+#define QUERY_BINDING_LEN 2
+#define QUERY_DELIMITER "&"
+
+#define QUERY_VERSION_FULL "lwm2m=1.0"
+#define QUERY_VERSION_FULL_LEN 9
+
+#ifdef LWM2M_CLIENT_MODE
+static void prv_handleRegistrationReply(lwm2m_transaction_t * transacP,
+ void * message)
+{
+ lwm2m_server_t * targetP;
+ coap_packet_t * packet = (coap_packet_t *)message;
+
+ targetP = (lwm2m_server_t *)(transacP->peerP);
+
+ switch(targetP->status)
+ {
+ case STATE_REG_PENDING:
+ {
+ if (packet == NULL)
+ {
+ targetP->status = STATE_UNKNOWN;
+ targetP->mid = 0;
+ }
+ else if (packet->mid == targetP->mid
+ && packet->type == COAP_TYPE_ACK
+ && packet->location_path != NULL)
+ {
+ if (packet->code == CREATED_2_01)
+ {
+ targetP->status = STATE_REGISTERED;
+ targetP->location = coap_get_multi_option_as_string(packet->location_path);
+ }
+ else if (packet->code == BAD_REQUEST_4_00)
+ {
+ targetP->status = STATE_UNKNOWN;
+ targetP->mid = 0;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+int lwm2m_register(lwm2m_context_t * contextP)
+{
+ char query[200];
+ char payload[512];
+ int payload_length;
+ lwm2m_server_t * targetP;
+ int remaining;
+
+ payload_length = prv_getRegisterPayload(contextP, payload, sizeof(payload));
+ if (payload_length == 0) return INTERNAL_SERVER_ERROR_5_00;
+
+ targetP = contextP->serverList;
+ while (targetP != NULL)
+ {
+ remaining = sizeof(query) - snprintf(query,sizeof(query), "?ep=%s",contextP->endpointName);
+ if (remaining <= 1) return INTERNAL_SERVER_ERROR_5_00;
+
+ if (NULL != targetP->sms) {
+ remaining -= QUERY_SMS_LEN + 1 + strlen(targetP->sms);
+ if (remaining <= 1) return INTERNAL_SERVER_ERROR_5_00;
+
+ strcat(query, QUERY_DELIMITER);
+ strcat(query, QUERY_SMS);
+ strcat(query, targetP->sms);
+ }
+
+ if (0 != targetP->lifetime) {
+ if (remaining <=17) return INTERNAL_SERVER_ERROR_5_00;
+ char lt[16];
+ remaining -=sprintf(lt,"<=%d",targetP->lifetime);
+ strcat(query,lt);
+ }
+
+ switch (targetP->binding) {
+ case BINDING_U:
+ strcat(query,"&b=U");
+ break;
+ case BINDING_UQ:
+ strcat(query,"&b=UQ");
+ break;
+ case BINDING_S:
+ strcat(query,"&b=S");
+ break;
+ case BINDING_SQ:
+ strcat(query,"&b=SQ");
+ break;
+ case BINDING_US:
+ strcat(query,"&b=US");
+ break;
+ case BINDING_UQS:
+ strcat(query,"&b=UQS");
+ break;
+ default:
+ return INTERNAL_SERVER_ERROR_5_00;
+ }
+
+ lwm2m_transaction_t * transaction;
+
+ transaction = transaction_new(COAP_POST, NULL, contextP->nextMID++, ENDPOINT_SERVER, (void *)targetP);
+ if (transaction == NULL) return INTERNAL_SERVER_ERROR_5_00;
+
+ coap_set_header_uri_path(transaction->message, "/"URI_REGISTRATION_SEGMENT);
+ coap_set_header_uri_query(transaction->message, query);
+ coap_set_payload(transaction->message, payload, payload_length);
+
+ transaction->callback = prv_handleRegistrationReply;
+ transaction->userData = (void *) contextP;
+
+ contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transaction);
+ if (transaction_send(contextP, transaction) == 0)
+ {
+ targetP->status = STATE_REG_PENDING;
+ targetP->mid = transaction->mID;
+ }
+
+ targetP = targetP->next;
+ }
+ return 0;
+}
+
+static void prv_handleRegistrationUpdateReply(lwm2m_transaction_t * transacP,
+ void * message)
+{
+ lwm2m_server_t * targetP;
+ coap_packet_t * packet = (coap_packet_t *)message;
+
+ targetP = (lwm2m_server_t *)(transacP->peerP);
+
+ switch(targetP->status)
+ {
+ case STATE_REG_UPDATE_PENDING:
+ {
+ if (packet == NULL)
+ {
+ targetP->status = STATE_UNKNOWN;
+ targetP->mid = 0;
+ }
+ else if (packet->mid == targetP->mid
+ && packet->type == COAP_TYPE_ACK)
+ {
+ if (packet->code == CHANGED_2_04)
+ {
+ targetP->status = STATE_REGISTERED;
+ }
+ else if (packet->code == BAD_REQUEST_4_00)
+ {
+ targetP->status = STATE_UNKNOWN;
+ targetP->mid = 0;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+int lwm2m_update_registration(lwm2m_context_t * contextP, uint16_t shortServerID)
+{
+ // look for the server
+ lwm2m_server_t * targetP;
+ targetP = contextP->serverList;
+ while (targetP != NULL)
+ {
+ if (targetP->shortID == shortServerID)
+ {
+ // found the server, trigger the update transaction
+ lwm2m_transaction_t * transaction;
+
+ transaction = transaction_new(COAP_PUT, NULL, contextP->nextMID++, ENDPOINT_SERVER, (void *)targetP);
+ if (transaction == NULL) return INTERNAL_SERVER_ERROR_5_00;
+
+ coap_set_header_uri_path(transaction->message, targetP->location);
+
+ transaction->callback = prv_handleRegistrationUpdateReply;
+ transaction->userData = (void *) contextP;
+
+ contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transaction);
+
+ if (transaction_send(contextP, transaction) == 0)
+ {
+ targetP->status = STATE_REG_UPDATE_PENDING;
+ targetP->mid = transaction->mID;
+ }
+ return 0;
+ } else {
+ // try next server
+ targetP = targetP->next;
+ }
+ }
+
+ // no server found
+ return NOT_FOUND_4_04;
+}
+
+static void prv_handleDeregistrationReply(lwm2m_transaction_t * transacP,
+ void * message)
+{
+ lwm2m_server_t * targetP;
+ coap_packet_t * packet = (coap_packet_t *)message;
+
+ targetP = (lwm2m_server_t *)(transacP->peerP);
+
+ switch(targetP->status)
+ {
+ case STATE_DEREG_PENDING:
+ {
+ if (packet == NULL)
+ {
+ targetP->status = STATE_UNKNOWN;
+ targetP->mid = 0;
+ }
+ else if (packet->mid == targetP->mid
+ && packet->type == COAP_TYPE_ACK)
+ {
+ if (packet->code == DELETED_2_02)
+ {
+ targetP->status = STATE_UNKNOWN;
+ }
+ else if (packet->code == BAD_REQUEST_4_00)
+ {
+ targetP->status = STATE_UNKNOWN;
+ targetP->mid = 0;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void registration_deregister(lwm2m_context_t * contextP,
+ lwm2m_server_t * serverP)
+{
+ coap_packet_t message[1];
+ uint8_t pktBuffer[COAP_MAX_PACKET_SIZE+1];
+ size_t pktBufferLen = 0;
+
+ if (serverP->status == STATE_UNKNOWN
+ || serverP->status == STATE_DEREG_PENDING)
+ {
+ return;
+ }
+
+ lwm2m_transaction_t * transaction;
+ transaction = transaction_new(COAP_DELETE, NULL, contextP->nextMID++, ENDPOINT_SERVER, (void *)serverP);
+ if (transaction == NULL) return;
+
+ coap_set_header_uri_path(transaction->message, serverP->location);
+
+ transaction->callback = prv_handleDeregistrationReply;
+ transaction->userData = (void *) contextP;
+
+ contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transaction);
+ if (transaction_send(contextP, transaction) == 0)
+ {
+ serverP->status = STATE_REG_PENDING;
+ serverP->mid = transaction->mID;
+ }
+}
+#endif
+
+#ifdef LWM2M_SERVER_MODE
+static int prv_getParameters(multi_option_t * query,
+ char ** nameP,
+ uint32_t * lifetimeP,
+ char ** msisdnP,
+ lwm2m_binding_t * bindingP)
+{
+ const char * start;
+ int length;
+
+ *nameP = NULL;
+ *lifetimeP = 0;
+ *msisdnP = NULL;
+ *bindingP = BINDING_UNKNOWN;
+
+ while (query != NULL)
+ {
+ if (strncmp(query->data, QUERY_TEMPLATE, QUERY_LENGTH) == 0)
+ {
+ if (*nameP != NULL) goto error;
+ if (query->len == QUERY_LENGTH) goto error;
+
+ *nameP = (char *)lwm2m_malloc(query->len - QUERY_LENGTH + 1);
+ if (*nameP != NULL)
+ {
+ memcpy(*nameP, query->data + QUERY_LENGTH, query->len - QUERY_LENGTH);
+ (*nameP)[query->len - QUERY_LENGTH] = 0;
+ }
+ }
+ else if (strncmp(query->data, QUERY_SMS, QUERY_SMS_LEN) == 0)
+ {
+ if (*msisdnP != NULL) goto error;
+ if (query->len == QUERY_SMS_LEN) goto error;
+
+ *msisdnP = (char *)lwm2m_malloc(query->len - QUERY_SMS_LEN + 1);
+ if (*msisdnP != NULL)
+ {
+ memcpy(*msisdnP, query->data + QUERY_SMS_LEN, query->len - QUERY_SMS_LEN);
+ (*msisdnP)[query->len - QUERY_SMS_LEN] = 0;
+ }
+ }
+ else if (strncmp(query->data, QUERY_LIFETIME, QUERY_LIFETIME_LEN) == 0)
+ {
+ int i;
+
+ if (*lifetimeP != 0) goto error;
+ if (query->len == QUERY_LIFETIME_LEN) goto error;
+
+ for (i = QUERY_LIFETIME_LEN ; i < query->len ; i++)
+ {
+ if (query->data[i] < '0' || query->data[i] > '9') goto error;
+ *lifetimeP = (*lifetimeP * 10) + (query->data[i] - '0');
+ }
+ }
+ else if (strncmp(query->data, QUERY_VERSION, QUERY_VERSION_LEN) == 0)
+ {
+ if ((query->len != QUERY_VERSION_FULL_LEN)
+ || (strncmp(query->data, QUERY_VERSION_FULL, QUERY_VERSION_FULL_LEN) != 0))
+ {
+ goto error;
+ }
+ }
+ else if (strncmp(query->data, QUERY_BINDING, QUERY_BINDING_LEN) == 0)
+ {
+ if (*bindingP != BINDING_UNKNOWN) goto error;
+ if (query->len == QUERY_BINDING_LEN) goto error;
+
+ if (strncmp(query->data + QUERY_BINDING_LEN, "U", query->len - QUERY_BINDING_LEN) == 0)
+ {
+ *bindingP = BINDING_U;
+ }
+ else if (strncmp(query->data + QUERY_BINDING_LEN, "UQ", query->len - QUERY_BINDING_LEN) == 0)
+ {
+ *bindingP = BINDING_UQ;
+ }
+ else if (strncmp(query->data + QUERY_BINDING_LEN, "S", query->len - QUERY_BINDING_LEN) == 0)
+ {
+ *bindingP = BINDING_S;
+ }
+ else if (strncmp(query->data + QUERY_BINDING_LEN, "SQ", query->len - QUERY_BINDING_LEN) == 0)
+ {
+ *bindingP = BINDING_SQ;
+ }
+ else if (strncmp(query->data + QUERY_BINDING_LEN, "US", query->len - QUERY_BINDING_LEN) == 0)
+ {
+ *bindingP = BINDING_UQ;
+ }
+ else if (strncmp(query->data + QUERY_BINDING_LEN, "UQS", query->len - QUERY_BINDING_LEN) == 0)
+ {
+ *bindingP = BINDING_UQ;
+ }
+ else
+ {
+ goto error;
+ }
+ }
+ query = query->next;
+ }
+
+ return 0;
+
+error:
+ if (*nameP != NULL) lwm2m_free(*nameP);
+ if (*msisdnP != NULL) lwm2m_free(*msisdnP);
+
+ return -1;
+}
+
+static int prv_getId(uint8_t * data,
+ uint16_t length,
+ uint16_t * objId,
+ uint16_t * instanceId)
+{
+ int value;
+ uint16_t limit;
+ uint16_t end;
+
+ // Expecting application/link-format (RFC6690)
+ // strip open and close tags
+ if (length >= 1 && data[0] == '<' && data[length-1] == '>')
+ {
+ data++;
+ length-=2;
+ }
+ else
+ {
+ return 0;
+ }
+
+ // If there is a preceding /, remove it
+ if (length >= 1 && data[0] == '/')
+ {
+ data++;
+ length-=1;
+ }
+
+ limit = 0;
+ while (limit < length && data[limit] != '/' && data[limit] != ' ') limit++;
+ value = prv_get_number(data, limit);
+ if (value < 0 || value >= LWM2M_MAX_ID) return 0;
+ *objId = value;
+
+ if (limit != length)
+ {
+ limit += 1;
+ end = limit;
+ while (end < length && data[end] != ' ') end++;
+ if (end != limit)
+ {
+ value = prv_get_number(data + limit, end - limit);
+ if (value >= 0 && value < LWM2M_MAX_ID)
+ {
+ *instanceId = value;
+ return 2;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static lwm2m_client_object_t * prv_decodeRegisterPayload(uint8_t * payload,
+ uint16_t payloadLength)
+{
+ lwm2m_client_object_t * objList;
+ uint16_t id;
+ uint16_t instance;
+ uint16_t start;
+ uint16_t end;
+ int result;
+
+ objList = NULL;
+ start = 0;
+ while (start < payloadLength)
+ {
+ while (start < payloadLength && payload[start] == ' ') start++;
+ if (start == payloadLength) return objList;
+ end = start;
+ while (end < payloadLength && payload[end] != ',') end++;
+ result = prv_getId(payload + start, end - start, &id, &instance);
+ if (result != 0)
+ {
+ lwm2m_client_object_t * objectP;
+
+ objectP = (lwm2m_client_object_t *)lwm2m_list_find((lwm2m_list_t *)objList, id);
+ if (objectP == NULL)
+ {
+ objectP = (lwm2m_client_object_t *)lwm2m_malloc(sizeof(lwm2m_client_object_t));
+ memset(objectP, 0, sizeof(lwm2m_client_object_t));
+ if (objectP == NULL) return objList;
+ objectP->id = id;
+ objList = (lwm2m_client_object_t *)LWM2M_LIST_ADD(objList, objectP);
+ }
+ if (result == 2)
+ {
+ lwm2m_list_t * instanceP;
+
+ instanceP = lwm2m_list_find(objectP->instanceList, instance);
+ if (instanceP == NULL)
+ {
+ instanceP = (lwm2m_list_t *)lwm2m_malloc(sizeof(lwm2m_list_t));
+ memset(instanceP, 0, sizeof(lwm2m_list_t));
+ instanceP->id = instance;
+ objectP->instanceList = LWM2M_LIST_ADD(objectP->instanceList, instanceP);
+ }
+ }
+ }
+ start = end + 1;
+ }
+
+ return objList;
+}
+
+static lwm2m_client_t * prv_getClientByName(lwm2m_context_t * contextP,
+ char * name)
+{
+ lwm2m_client_t * targetP;
+
+ targetP = contextP->clientList;
+ while (targetP != NULL && strcmp(name, targetP->name) != 0)
+ {
+ targetP = targetP->next;
+ }
+
+ return targetP;
+}
+
+static void prv_freeClientObjectList(lwm2m_client_object_t * objects)
+{
+ while (objects != NULL)
+ {
+ lwm2m_client_object_t * objP;
+
+ while (objects->instanceList != NULL)
+ {
+ lwm2m_list_t * target;
+
+ target = objects->instanceList;
+ objects->instanceList = objects->instanceList->next;
+ lwm2m_free(target);
+ }
+
+ objP = objects;
+ objects = objects->next;
+ lwm2m_free(objP);
+ }
+}
+
+void prv_freeClient(lwm2m_client_t * clientP)
+{
+ if (clientP->name != NULL) lwm2m_free(clientP->name);
+ if (clientP->msisdn != NULL) lwm2m_free(clientP->msisdn);
+ prv_freeClientObjectList(clientP->objectList);
+ while(clientP->observationList != NULL)
+ {
+ lwm2m_observation_t * targetP;
+
+ targetP = clientP->observationList;
+ clientP->observationList = clientP->observationList->next;
+ lwm2m_free(targetP);
+ }
+ lwm2m_free(clientP);
+}
+
+static int prv_getLocationString(uint16_t id,
+ char location[MAX_LOCATION_LENGTH])
+{
+ int result;
+
+ memset(location, 0, MAX_LOCATION_LENGTH);
+
+ result = snprintf(location, MAX_LOCATION_LENGTH, "/"URI_REGISTRATION_SEGMENT"/%hu", id);
+ if (result <= 0 || result > MAX_LOCATION_LENGTH)
+ {
+ return 0;
+ }
+
+ return result;
+}
+
+coap_status_t handle_registration_request(lwm2m_context_t * contextP,
+ lwm2m_uri_t * uriP,
+ void * fromSessionH,
+ coap_packet_t * message,
+ coap_packet_t * response)
+{
+ coap_status_t result;
+ struct timeval tv;
+
+ if (lwm2m_gettimeofday(&tv, NULL) != 0)
+ {
+ return COAP_500_INTERNAL_SERVER_ERROR;
+ }
+
+ switch(message->code)
+ {
+ case COAP_POST:
+ {
+ char * name = NULL;
+ uint32_t lifetime;
+ char * msisdn;
+ lwm2m_binding_t binding;
+ lwm2m_client_object_t * objects;
+ lwm2m_client_t * clientP;
+ char location[MAX_LOCATION_LENGTH];
+
+ if ((uriP->flag & LWM2M_URI_MASK_ID) != 0) return COAP_400_BAD_REQUEST;
+ if (0 != prv_getParameters(message->uri_query, &name, &lifetime, &msisdn, &binding))
+ {
+ return COAP_400_BAD_REQUEST;
+ }
+ objects = prv_decodeRegisterPayload(message->payload, message->payload_len);
+ if (objects == NULL)
+ {
+ lwm2m_free(name);
+ if (msisdn != NULL) lwm2m_free(msisdn);
+ return COAP_400_BAD_REQUEST;
+ }
+ // Endpoint client name is mandatory
+ if (name == NULL)
+ {
+ if (msisdn != NULL) lwm2m_free(msisdn);
+ return COAP_400_BAD_REQUEST;
+ }
+ if (lifetime == 0)
+ {
+ lifetime = LWM2M_DEFAULT_LIFETIME;
+ }
+
+ clientP = prv_getClientByName(contextP, name);
+ if (clientP != NULL)
+ {
+ // we reset this registration
+ lwm2m_free(clientP->name);
+ if (clientP->msisdn != NULL) lwm2m_free(clientP->msisdn);
+ prv_freeClientObjectList(clientP->objectList);
+ clientP->objectList = NULL;
+ }
+ else
+ {
+ clientP = (lwm2m_client_t *)lwm2m_malloc(sizeof(lwm2m_client_t));
+ if (clientP == NULL)
+ {
+ lwm2m_free(name);
+ if (msisdn != NULL) lwm2m_free(msisdn);
+ prv_freeClientObjectList(objects);
+ return COAP_500_INTERNAL_SERVER_ERROR;
+ }
+ memset(clientP, 0, sizeof(lwm2m_client_t));
+ clientP->internalID = lwm2m_list_newId((lwm2m_list_t *)contextP->clientList);
+ contextP->clientList = (lwm2m_client_t *)LWM2M_LIST_ADD(contextP->clientList, clientP);
+ }
+ clientP->name = name;
+ clientP->binding = binding;
+ clientP->msisdn = msisdn;
+ clientP->lifetime = lifetime;
+ clientP->endOfLife = tv.tv_sec + lifetime;
+ clientP->objectList = objects;
+ clientP->sessionH = fromSessionH;
+
+ if (prv_getLocationString(clientP->internalID, location) == 0)
+ {
+ prv_freeClient(clientP);
+ return COAP_500_INTERNAL_SERVER_ERROR;
+ }
+ if (coap_set_header_location_path(response, location) == 0)
+ {
+ prv_freeClient(clientP);
+ return COAP_500_INTERNAL_SERVER_ERROR;
+ }
+
+ if (contextP->monitorCallback != NULL)
+ {
+ contextP->monitorCallback(clientP->internalID, NULL, CREATED_2_01, NULL, 0, contextP->monitorUserData);
+ }
+ result = COAP_201_CREATED;
+ }
+ break;
+
+ case COAP_PUT:
+ {
+ char * name = NULL;
+ uint32_t lifetime;
+ char * msisdn;
+ lwm2m_binding_t binding;
+ lwm2m_client_object_t * objects;
+ lwm2m_client_t * clientP;
+
+ if ((uriP->flag & LWM2M_URI_MASK_ID) != LWM2M_URI_FLAG_OBJECT_ID) return COAP_400_BAD_REQUEST;
+
+ clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, uriP->objectId);
+ if (clientP == NULL) return COAP_404_NOT_FOUND;
+
+ if (0 != prv_getParameters(message->uri_query, &name, &lifetime, &msisdn, &binding))
+ {
+ return COAP_400_BAD_REQUEST;
+ }
+ objects = prv_decodeRegisterPayload(message->payload, message->payload_len);
+
+ // Endpoint client name MUST NOT be present
+ if (name != NULL)
+ {
+ lwm2m_free(name);
+ if (msisdn != NULL) lwm2m_free(msisdn);
+ return COAP_400_BAD_REQUEST;
+ }
+
+ if (binding != BINDING_UNKNOWN)
+ {
+ clientP->binding = binding;
+ }
+ if (msisdn != NULL)
+ {
+ if (clientP->msisdn != NULL) lwm2m_free(clientP->msisdn);
+ clientP->msisdn = msisdn;
+ }
+ if (lifetime != 0)
+ {
+ clientP->lifetime = lifetime;
+ }
+ // client IP address, port or MSISDN may have changed
+ clientP->sessionH = fromSessionH;
+
+ if (objects != NULL)
+ {
+ lwm2m_observation_t * observationP;
+
+ // remove observations on object/instance no longer existing
+ observationP = clientP->observationList;
+ while (observationP != NULL)
+ {
+ lwm2m_client_object_t * objP;
+ lwm2m_observation_t * nextP;
+
+ nextP = observationP->next;
+
+ objP = (lwm2m_client_object_t *)lwm2m_list_find((lwm2m_list_t *)objects, observationP->uri.objectId);
+ if (objP == NULL)
+ {
+ observationP->callback(clientP->internalID,
+ &observationP->uri,
+ COAP_202_DELETED,
+ NULL, 0,
+ observationP->userData);
+ observation_remove(clientP, observationP);
+ }
+ else
+ {
+ if ((observationP->uri.flag & LWM2M_URI_FLAG_INSTANCE_ID) != 0)
+ {
+ if (lwm2m_list_find((lwm2m_list_t *)objP->instanceList, observationP->uri.instanceId) == NULL)
+ {
+ observationP->callback(clientP->internalID,
+ &observationP->uri,
+ COAP_202_DELETED,
+ NULL, 0,
+ observationP->userData);
+ observation_remove(clientP, observationP);
+ }
+ }
+ }
+
+ observationP = nextP;
+ }
+
+ prv_freeClientObjectList(clientP->objectList);
+ clientP->objectList = objects;
+ }
+
+ clientP->endOfLife = tv.tv_sec + clientP->lifetime;
+
+ if (contextP->monitorCallback != NULL)
+ {
+ contextP->monitorCallback(clientP->internalID, NULL, COAP_204_CHANGED, NULL, 0, contextP->monitorUserData);
+ }
+ result = COAP_204_CHANGED;
+ }
+ break;
+
+ case COAP_DELETE:
+ {
+ lwm2m_client_t * clientP;
+
+ if ((uriP->flag & LWM2M_URI_MASK_ID) != LWM2M_URI_FLAG_OBJECT_ID) return COAP_400_BAD_REQUEST;
+
+ contextP->clientList = (lwm2m_client_t *)LWM2M_LIST_RM(contextP->clientList, uriP->objectId, &clientP);
+ if (clientP == NULL) return COAP_400_BAD_REQUEST;
+ if (contextP->monitorCallback != NULL)
+ {
+ contextP->monitorCallback(clientP->internalID, NULL, DELETED_2_02, NULL, 0, contextP->monitorUserData);
+ }
+ prv_freeClient(clientP);
+ result = COAP_202_DELETED;
+ }
+ break;
+
+ default:
+ return COAP_400_BAD_REQUEST;
+ }
+
+ return result;
+}
+
+void lwm2m_set_monitoring_callback(lwm2m_context_t * contextP,
+ lwm2m_result_callback_t callback,
+ void * userData)
+{
+ contextP->monitorCallback = callback;
+ contextP->monitorUserData = userData;
+}
+
+
+#endif