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/observe.c
- Revision:
- 0:f9d13e09cf11
- Child:
- 3:a280069151ac
diff -r 000000000000 -r f9d13e09cf11 wakaama/observe.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/wakaama/observe.c Mon Apr 24 23:03:31 2017 +0000
@@ -0,0 +1,503 @@
+/*******************************************************************************
+ *
+ * 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
+ * Toby Jaffey - 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 <stdio.h>
+
+
+#ifdef LWM2M_CLIENT_MODE
+static lwm2m_observed_t * prv_findObserved(lwm2m_context_t * contextP,
+ lwm2m_uri_t * uriP)
+{
+ lwm2m_observed_t * targetP;
+
+ targetP = contextP->observedList;
+ while (targetP != NULL
+ && (targetP->uri.objectId != uriP->objectId
+ || targetP->uri.flag != uriP->flag
+ || (LWM2M_URI_IS_SET_INSTANCE(uriP) && targetP->uri.instanceId != uriP->instanceId)
+ || (LWM2M_URI_IS_SET_RESOURCE(uriP) && targetP->uri.resourceId != uriP->resourceId)))
+ {
+ targetP = targetP->next;
+ }
+
+ return targetP;
+}
+
+static obs_list_t * prv_getObservedList(lwm2m_context_t * contextP,
+ lwm2m_uri_t * uriP)
+{
+ obs_list_t * resultP;
+ lwm2m_observed_t * targetP;
+
+ resultP = NULL;
+
+ targetP = contextP->observedList;
+ while (targetP != NULL)
+ {
+ if (targetP->uri.objectId == uriP->objectId)
+ {
+ if (!LWM2M_URI_IS_SET_INSTANCE(uriP)
+ || (targetP->uri.flag & LWM2M_URI_FLAG_INSTANCE_ID) == 0
+ || uriP->instanceId == targetP->uri.instanceId)
+ {
+ if (!LWM2M_URI_IS_SET_RESOURCE(uriP)
+ || (targetP->uri.flag & LWM2M_URI_FLAG_RESOURCE_ID) == 0
+ || uriP->resourceId == targetP->uri.resourceId)
+ {
+ obs_list_t * newP;
+
+ newP = (obs_list_t *)lwm2m_malloc(sizeof(obs_list_t));
+ if (newP != NULL)
+ {
+ newP->item = targetP;
+ newP->next = resultP;
+ resultP = newP;
+ }
+ }
+ }
+ }
+ targetP = targetP->next;
+ }
+
+ return resultP;
+}
+
+static void prv_unlinkObserved(lwm2m_context_t * contextP,
+ lwm2m_observed_t * observedP)
+{
+ if (contextP->observedList == observedP)
+ {
+ contextP->observedList = contextP->observedList->next;
+ }
+ else
+ {
+ lwm2m_observed_t * parentP;
+
+ parentP = contextP->observedList;
+ while (parentP->next != NULL
+ && parentP->next != observedP)
+ {
+ parentP = parentP->next;
+ }
+ if (parentP->next != NULL)
+ {
+ parentP->next = parentP->next->next;
+ }
+ }
+}
+
+static lwm2m_server_t * prv_findServer(lwm2m_context_t * contextP,
+ void * fromSessionH)
+{
+ lwm2m_server_t * targetP;
+
+ targetP = contextP->serverList;
+ while (targetP != NULL
+ && targetP->sessionH != fromSessionH)
+ {
+ targetP = targetP->next;
+ }
+
+ return targetP;
+}
+
+static lwm2m_watcher_t * prv_findWatcher(lwm2m_observed_t * observedP,
+ lwm2m_server_t * serverP)
+{
+ lwm2m_watcher_t * targetP;
+
+ targetP = observedP->watcherList;
+ while (targetP != NULL
+ && targetP->server != serverP)
+ {
+ targetP = targetP->next;
+ }
+
+ return targetP;
+}
+
+coap_status_t handle_observe_request(lwm2m_context_t * contextP,
+ lwm2m_uri_t * uriP,
+ void * fromSessionH,
+ coap_packet_t * message,
+ coap_packet_t * response)
+{
+ lwm2m_observed_t * observedP;
+ lwm2m_watcher_t * watcherP;
+ lwm2m_server_t * serverP;
+
+ LOG("handle_observe_request()\r\n");
+
+ if (!LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(uriP)) return COAP_400_BAD_REQUEST;
+ if (message->token_len == 0) return COAP_400_BAD_REQUEST;
+
+ serverP = prv_findServer(contextP, fromSessionH);
+ if (serverP == NULL || serverP->status != STATE_REGISTERED) return COAP_401_UNAUTHORIZED;
+
+ observedP = prv_findObserved(contextP, uriP);
+ if (observedP == NULL)
+ {
+ observedP = (lwm2m_observed_t *)lwm2m_malloc(sizeof(lwm2m_observed_t));
+ if (observedP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
+ memset(observedP, 0, sizeof(lwm2m_observed_t));
+ memcpy(&(observedP->uri), uriP, sizeof(lwm2m_uri_t));
+ observedP->next = contextP->observedList;
+ contextP->observedList = observedP;
+ }
+
+ watcherP = prv_findWatcher(observedP, serverP);
+ if (watcherP == NULL)
+ {
+ watcherP = (lwm2m_watcher_t *)lwm2m_malloc(sizeof(lwm2m_watcher_t));
+ if (watcherP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
+ memset(watcherP, 0, sizeof(lwm2m_watcher_t));
+ watcherP->server = serverP;
+ watcherP->tokenLen = message->token_len;
+ memcpy(watcherP->token, message->token, message->token_len);
+ watcherP->next = observedP->watcherList;
+ observedP->watcherList = watcherP;
+ }
+
+ coap_set_header_observe(response, watcherP->counter++);
+
+ return COAP_205_CONTENT;
+}
+
+void cancel_observe(lwm2m_context_t * contextP,
+ uint16_t mid,
+ void * fromSessionH)
+{
+ lwm2m_observed_t * observedP;
+
+ LOG("cancel_observe()\r\n");
+
+ for (observedP = contextP->observedList;
+ observedP != NULL;
+ observedP = observedP->next)
+ {
+ lwm2m_watcher_t * targetP = NULL;
+
+ if (observedP->watcherList->lastMid == mid
+ && observedP->watcherList->server->sessionH == fromSessionH)
+ {
+ targetP = observedP->watcherList;
+ observedP->watcherList = observedP->watcherList->next;
+ }
+ else
+ {
+ lwm2m_watcher_t * parentP;
+
+ parentP = observedP->watcherList;
+ while (parentP->next != NULL
+ && (parentP->next->lastMid != mid
+ || parentP->next->server->sessionH != fromSessionH))
+ {
+ parentP = parentP->next;
+ }
+ if (parentP->next != NULL)
+ {
+ targetP = parentP->next;
+ parentP->next = parentP->next->next;
+ }
+ }
+ if (targetP != NULL)
+ {
+ lwm2m_free(targetP);
+ if (observedP->watcherList == NULL)
+ {
+ prv_unlinkObserved(contextP, observedP);
+ lwm2m_free(observedP);
+ }
+ return;
+ }
+ }
+}
+
+void lwm2m_resource_value_changed(lwm2m_context_t * contextP,
+ lwm2m_uri_t * uriP)
+{
+ int result;
+ obs_list_t * listP;
+ lwm2m_watcher_t * watcherP;
+
+ listP = prv_getObservedList(contextP, uriP);
+ while (listP != NULL)
+ {
+ obs_list_t * targetP;
+ char * buffer = NULL;
+ int length = 0;
+
+ result = object_read(contextP, &listP->item->uri, &buffer, &length);
+ if (result == COAP_205_CONTENT)
+ {
+ coap_packet_t message[1];
+
+ coap_init_message(message, COAP_TYPE_NON, COAP_204_CHANGED, 0);
+ coap_set_payload(message, buffer, length);
+
+ for (watcherP = listP->item->watcherList ; watcherP != NULL ; watcherP = watcherP->next)
+ {
+ watcherP->lastMid = contextP->nextMID++;
+ message->mid = watcherP->lastMid;
+ coap_set_header_token(message, watcherP->token, watcherP->tokenLen);
+ coap_set_header_observe(message, watcherP->counter++);
+ (void)message_send(contextP, message, watcherP->server->sessionH);
+ }
+ }
+
+ targetP = listP;
+ listP = listP->next;
+ lwm2m_free(targetP);
+ }
+
+}
+#endif
+
+#ifdef LWM2M_SERVER_MODE
+static lwm2m_observation_t * prv_findObservationByURI(lwm2m_client_t * clientP,
+ lwm2m_uri_t * uriP)
+{
+ lwm2m_observation_t * targetP;
+
+ targetP = clientP->observationList;
+ while (targetP != NULL)
+ {
+ if (targetP->uri.objectId == uriP->objectId
+ && targetP->uri.flag == uriP->flag
+ && targetP->uri.instanceId == uriP->instanceId
+ && targetP->uri.resourceId == uriP->resourceId)
+ {
+ return targetP;
+ }
+
+ targetP = targetP->next;
+ }
+
+ return targetP;
+}
+
+void observation_remove(lwm2m_client_t * clientP,
+ lwm2m_observation_t * observationP)
+{
+ if (clientP->observationList == observationP)
+ {
+ clientP->observationList = clientP->observationList->next;
+ }
+ else if (clientP->observationList != NULL)
+ {
+ lwm2m_observation_t * parentP;
+
+ parentP = clientP->observationList;
+
+ while (parentP->next != NULL
+ && parentP->next != observationP)
+ {
+ parentP = parentP->next;
+ }
+ if (parentP->next != NULL)
+ {
+ parentP->next = parentP->next->next;
+ }
+ }
+
+ lwm2m_free(observationP);
+}
+
+static void prv_obsRequestCallback(lwm2m_transaction_t * transacP,
+ void * message)
+{
+ lwm2m_observation_t * observationP = (lwm2m_observation_t *)transacP->userData;
+ coap_packet_t * packet = (coap_packet_t *)message;
+ uint8_t code;
+
+ if (message == NULL)
+ {
+ code = COAP_503_SERVICE_UNAVAILABLE;
+ }
+ else if (packet->code == COAP_205_CONTENT
+ && !IS_OPTION(packet, COAP_OPTION_OBSERVE))
+ {
+ code = COAP_405_METHOD_NOT_ALLOWED;
+ }
+ else
+ {
+ code = packet->code;
+ }
+
+ if (code != COAP_205_CONTENT)
+ {
+ observationP->callback(((lwm2m_client_t*)transacP->peerP)->internalID,
+ &observationP->uri,
+ code,
+ NULL, 0,
+ observationP->userData);
+ observation_remove(((lwm2m_client_t*)transacP->peerP), observationP);
+ }
+ else
+ {
+ observationP->clientP->observationList = (lwm2m_observation_t *)LWM2M_LIST_ADD(observationP->clientP->observationList, observationP);
+ observationP->callback(((lwm2m_client_t*)transacP->peerP)->internalID,
+ &observationP->uri,
+ 0,
+ packet->payload, packet->payload_len,
+ observationP->userData);
+ }
+}
+
+int lwm2m_observe(lwm2m_context_t * contextP,
+ uint16_t clientID,
+ lwm2m_uri_t * uriP,
+ lwm2m_result_callback_t callback,
+ void * userData)
+{
+ lwm2m_client_t * clientP;
+ lwm2m_transaction_t * transactionP;
+ lwm2m_observation_t * observationP;
+ uint8_t token[4];
+
+ if (!LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(uriP)) return COAP_400_BAD_REQUEST;
+
+ clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID);
+ if (clientP == NULL) return COAP_404_NOT_FOUND;
+
+ observationP = (lwm2m_observation_t *)lwm2m_malloc(sizeof(lwm2m_observation_t));
+ if (observationP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
+ memset(observationP, 0, sizeof(lwm2m_observation_t));
+
+ transactionP = transaction_new(COAP_GET, uriP, contextP->nextMID++, ENDPOINT_CLIENT, (void *)clientP);
+ if (transactionP == NULL)
+ {
+ lwm2m_free(observationP);
+ return COAP_500_INTERNAL_SERVER_ERROR;
+ }
+
+ observationP->id = lwm2m_list_newId((lwm2m_list_t *)clientP->observationList);
+ memcpy(&observationP->uri, uriP, sizeof(lwm2m_uri_t));
+ observationP->clientP = clientP;
+ observationP->callback = callback;
+ observationP->userData = userData;
+
+ token[0] = clientP->internalID >> 8;
+ token[1] = clientP->internalID & 0xFF;
+ token[2] = observationP->id >> 8;
+ token[3] = observationP->id & 0xFF;
+
+ coap_set_header_observe(transactionP->message, 0);
+ coap_set_header_token(transactionP->message, token, sizeof(token));
+
+ transactionP->callback = prv_obsRequestCallback;
+ transactionP->userData = (void *)observationP;
+
+ contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transactionP);
+
+ return transaction_send(contextP, transactionP);
+}
+
+int lwm2m_observe_cancel(lwm2m_context_t * contextP,
+ uint16_t clientID,
+ lwm2m_uri_t * uriP,
+ lwm2m_result_callback_t callback,
+ void * userData)
+{
+ lwm2m_client_t * clientP;
+ lwm2m_observation_t * observationP;
+
+ clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID);
+ if (clientP == NULL) return COAP_404_NOT_FOUND;
+
+ observationP = prv_findObservationByURI(clientP, uriP);
+ if (observationP == NULL) return COAP_404_NOT_FOUND;
+
+ observation_remove(clientP, observationP);
+
+ return 0;
+}
+
+void handle_observe_notify(lwm2m_context_t * contextP,
+ void * fromSessionH,
+ coap_packet_t * message)
+{
+ uint8_t * tokenP;
+ int token_len;
+ uint16_t clientID;
+ uint16_t obsID;
+ lwm2m_client_t * clientP;
+ lwm2m_observation_t * observationP;
+ uint32_t count;
+
+ token_len = coap_get_header_token(message, (const uint8_t **)&tokenP);
+ if (token_len != sizeof(uint32_t)) return;
+
+ if (1 != coap_get_header_observe(message, &count)) return;
+
+ clientID = (tokenP[0] << 8) | tokenP[1];
+ obsID = (tokenP[2] << 8) | tokenP[3];
+
+ clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID);
+ if (clientP == NULL) return;
+
+ observationP = (lwm2m_observation_t *)lwm2m_list_find((lwm2m_list_t *)clientP->observationList, obsID);
+ if (observationP == NULL)
+ {
+ coap_packet_t resetMsg;
+
+ coap_init_message(&resetMsg, COAP_TYPE_RST, 0, message->mid);
+
+ message_send(contextP, &resetMsg, fromSessionH);
+ }
+ else
+ {
+ observationP->callback(clientID,
+ &observationP->uri,
+ (int)count,
+ message->payload, message->payload_len,
+ observationP->userData);
+ }
+}
+#endif