Server-side changes to support observe functionality.
authorJoseph Morrow <joseph.l.morrow@intel.com>
Sun, 3 Aug 2014 23:23:37 +0000 (19:23 -0400)
committerGerrit Code Review <gerrit@fmygit6002.fm.intel.com>
Mon, 4 Aug 2014 19:33:16 +0000 (12:33 -0700)
Moved/Added occoaptoken.h. There were some weird cyclical dependency patterns in the compiler.

CoAP token storage for observe sends.

Sending sequence numbers with observations.

Change-Id: Ib101a093c6c37066e4b6d51218fc689f2c5423e5

16 files changed:
csdk/libcoap-4.1.1/debug.c
csdk/makefile
csdk/occoap/include/occoap.h
csdk/occoap/include/occoaphelper.h
csdk/occoap/include/occoaptoken.h [new file with mode: 0644]
csdk/occoap/src/occoap.c
csdk/occoap/src/occoaphelper.c
csdk/stack/include/internal/occlientcb.h
csdk/stack/include/internal/ocobserve.h [new file with mode: 0644]
csdk/stack/include/internal/ocstackinternal.h
csdk/stack/include/ocstack.h
csdk/stack/samples/SimpleClientServer/makefile
csdk/stack/samples/SimpleClientServer/occlient.cpp
csdk/stack/samples/SimpleClientServer/ocserver.cpp
csdk/stack/src/ocobserve.c [new file with mode: 0644]
csdk/stack/src/ocstack.c

index 2ea2ce4..fbe07d8 100644 (file)
@@ -265,7 +265,8 @@ coap_show_pdu(const coap_pdu_t *pdu) {
        opt_iter.type == COAP_OPTION_URI_HOST ||
        opt_iter.type == COAP_OPTION_LOCATION_PATH ||
        opt_iter.type == COAP_OPTION_LOCATION_QUERY ||
-         opt_iter.type == COAP_OPTION_URI_PATH ||
+    opt_iter.type == COAP_OPTION_URI_PATH ||
+    opt_iter.type == COAP_OPTION_OBSERVE ||
        opt_iter.type == COAP_OPTION_URI_QUERY) {
       encode = 0;
     } else {
index e715b71..34c232e 100644 (file)
@@ -58,6 +58,7 @@ OCTBSTACK_SOURCES     := $(OCTBSTACK_SRC)/ocstack.c
 OCTBSTACK_SOURCES      += $(OCTBSTACK_SRC)/occlientcb.c
 OCTBSTACK_SOURCES      += $(OCTBSTACK_SRC)/ocserverrequest.c
 OCTBSTACK_SOURCES      += $(OCTBSTACK_SRC)/ocresource.c
+OCTBSTACK_SOURCES      += $(OCTBSTACK_SRC)/ocobserve.c
 
 SOURCES                        := $(CJSON_SOURCES)
 SOURCES                        += $(OCCOAP_SOURCES)
index 0554cb5..8effdf4 100644 (file)
@@ -25,6 +25,7 @@
 // Includes
 //-----------------------------------------------------------------------------
 #include "ocstack.h"
+#include "occoaptoken.h"
 #include "ocstackinternal.h"
 #include "occoaphelper.h"
 #include <stdint.h>
@@ -91,5 +92,10 @@ int OCStopCoAP();
 int OCProcessCoAP();
 
 OCCoAPToken * OCGenerateCoAPToken();
+/* Vijay: TODO: Add description */
+
+int OCCoAPSendMessage (OCDevAddr *dstAddr, OCStackResult msgCode, 
+                       OCQualityOfService qos, OCCoAPToken * token,
+                       const char *payload, uint32_t seqNum);
 
 #endif /* OCCOAP_H_ */
index 2efae66..4b7b309 100644 (file)
 //-----------------------------------------------------------------------------
 #include "coap.h"
 #include "ocstack.h"
+#include "occoaptoken.h"
 #include "ocstackinternal.h"
 #include <unistd.h>
 #include <limits.h>
 #include <ctype.h>
 
-#define MAX_TOKEN_LENGTH (8)
-
-typedef struct {
-    uint8_t token[MAX_TOKEN_LENGTH];
-    size_t tokenLength;
-} OCCoAPToken;
-
 // Convert OCStack code to CoAP code
 uint8_t OCToCoAPResponseCode(OCStackResult result);
 
diff --git a/csdk/occoap/include/occoaptoken.h b/csdk/occoap/include/occoaptoken.h
new file mode 100644 (file)
index 0000000..503ca80
--- /dev/null
@@ -0,0 +1,33 @@
+
+//******************************************************************
+//
+// Copyright 2014 Intel Corporation All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+
+#ifndef OCCOAPTOKEN_H_
+#define OCCOAPTOKEN_H_
+
+#define MAX_TOKEN_LENGTH (8)
+
+typedef struct {
+    uint8_t token[MAX_TOKEN_LENGTH];
+    size_t tokenLength;
+} OCCoAPToken;
+
+#endif
index 3efc09a..6d0eff7 100644 (file)
@@ -148,11 +148,11 @@ static void HandleCoAPRequests(struct coap_context_t *ctx,
     }
 
     OC_LOG_V(INFO, TAG, "TID %d", tid);
-    OC_LOG(INFO, TAG, "Deleting PDU");
     // unlike stock libcoap (deletion in handle_request in net.c), we are deleting the response here
     // in the future, the response might be queued for SLOW resources
     if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID)
     {
+        OC_LOG(INFO, TAG, "Deleting PDU");
         coap_delete_pdu(pdu);
     }
 
@@ -329,6 +329,8 @@ int OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * toke
     int res;
     uint8_t coapMsgType;
     uint8_t coapMethod;
+    // Vijay: TODO Observation registration is hardcoded here - change
+    unsigned char obs[] = "0";
 
     OC_LOG(INFO, TAG, PCF("Entering OCDoCoAPResource"));
 
@@ -407,6 +409,9 @@ int OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * toke
         case OC_REST_OBSERVE_ALL:
         case OC_REST_OBSERVE:
             coapMethod = COAP_REQUEST_GET;
+#if 0
+            // Joey's add for observation registration: not working.
+            // Vijay's change below
             buflen = BUF_SIZE;
             buf = _buf;
             res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
@@ -419,6 +424,10 @@ int OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * toke
 
                 buf += COAP_OPT_SIZE(buf);
             }
+#endif
+            coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_OBSERVE,
+                        strlen((const char *)obs), (obs)), OrderOptions);
+
             break;
         default:
             coapMethod = 0;
@@ -458,6 +467,49 @@ exit:
     return ret;
 }
 
+int OCCoAPSendMessage (OCDevAddr *dstAddr, OCStackResult msgCode, 
+                       OCQualityOfService qos, OCCoAPToken * token,
+                       const char *payload, uint32_t seqNum)
+{
+    coap_list_t *optList = NULL;
+    coap_pdu_t *pdu;
+    unsigned char tempBuf[BUF_SIZE_ENCODE_OPTION];
+    uint8_t coapMsgType = COAP_MESSAGE_NON;
+    coap_tid_t tid = COAP_INVALID_TID;
+
+    OC_LOG(INFO, TAG, PCF("Entering OCCoAPSendMessage"));
+
+    printf ("Payload: %s\n", payload);
+    OC_LOG_V(INFO, TAG, "OCStack payload: %s", payload);
+    coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_CONTENT_TYPE,
+                coap_encode_var_bytes(tempBuf, COAP_MEDIATYPE_APPLICATION_JSON),
+                tempBuf), OrderOptions);
+    coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_MAXAGE,
+                coap_encode_var_bytes(tempBuf, 0x2ffff), tempBuf), OrderOptions);
+    coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_OBSERVE,
+                coap_encode_var_bytes(tempBuf, seqNum), tempBuf), OrderOptions);
+
+    pdu = GenerateCoAPPdu (coapMsgType, OCToCoAPResponseCode(msgCode),
+                           coap_new_message_id(gCoAPCtx), token->tokenLength, token->token,
+                           (unsigned char*) payload, optList);
+    VERIFY_NON_NULL(pdu);
+    coap_show_pdu(pdu);
+
+    tid = coap_send(gCoAPCtx, (coap_address_t*)dstAddr, pdu);
+    OC_LOG_V(INFO, TAG, "TID %d", tid);
+    if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID)
+    {
+        OC_LOG(INFO, TAG, "Deleting PDU");
+        coap_delete_pdu(pdu);
+        pdu = NULL;
+    }
+    return OC_COAP_OK;
+
+exit:
+    coap_delete_list(optList);
+    return OC_COAP_ERR;
+}
+
 /**
  * Stop the CoAP client or server processing
  *
index 49d1ed2..3c920e2 100644 (file)
@@ -69,6 +69,7 @@ OCStackResult FormOCRequest(const coap_queue_t * rcvdRequest,
         unsigned char * queryBuf) {
 
     OCRequest * request = NULL;
+    OCObserveReq *obsReq = NULL;
     size_t bufLen;
     size_t optLen;
     coap_opt_filter_t filter;
@@ -129,6 +130,46 @@ OCStackResult FormOCRequest(const coap_queue_t * rcvdRequest,
     // delete last '&'
     queryBuf[bufLen ? (bufLen - 1) : (bufLen)] = '\0';
 
+    // fill in observe, if present
+    request->observe = NULL;
+    coap_option_filter_clear(filter);
+    coap_option_setb(filter, COAP_OPTION_OBSERVE);
+    coap_option_iterator_init(rcvdRequest->pdu, &opt_iter, filter);
+    while ((option = coap_option_next(&opt_iter))) {
+        printf ("\n\n ******************* OBS ********** %d, %s\n\n\n", COAP_OPT_LENGTH(option), COAP_OPT_VALUE(option));
+        request->observe = (OCObserveReq *)OCMalloc(sizeof(OCObserveReq));
+        if (request->observe)
+        {
+            obsReq = request->observe;
+            obsReq->option = NULL;
+            obsReq->option = (unsigned char *)OCMalloc(COAP_OPT_LENGTH(option)+1);
+            if (obsReq->option)
+            {
+                memcpy(obsReq->option, COAP_OPT_VALUE(option),COAP_OPT_LENGTH(option));
+                (obsReq->option)[COAP_OPT_LENGTH(option)] = '\0';
+            }
+            else
+            {
+                OCFree (request->observe);
+                return OC_STACK_NO_MEMORY;
+            }
+            /*
+            // Vijay: TODO: Remove this code block before final commit
+            // TODO: Should we copy sizeof OCDevAddr or introspect the addr for size
+            memcpy (&(obsReq->subAddr), (OCDevAddr *) &(rcvdRequest->remote),sizeof(OCDevAddr));
+            coapTok = obsReq->coapTok;
+            coapTok->tokenLength = rcvdRequest->pdu->hdr->token_length;
+            memcpy(coapTok->token, rcvdRequest->pdu->hdr->token, coapTok->tokenLength);
+            */
+            obsReq->subAddr = (OCDevAddr *)&(rcvdRequest->remote);
+            obsReq->coapToken = rcvdRequest->pdu->hdr->token;
+            obsReq->coapTokenLen = rcvdRequest->pdu->hdr->token_length;
+        } else {
+            return OC_STACK_NO_MEMORY;
+        }
+    }
+    OC_LOG_V(INFO, TAG, "Observe option %d", request->observe);
+
     *requestLoc = request;
     return OC_STACK_OK;
 }
index f33762f..60b89a1 100644 (file)
@@ -23,6 +23,7 @@
 #define OC_CLIENT_CB
 
 #include <ocstack.h>
+#include <occoaptoken.h>
 #include <occoap.h>
 
 typedef struct ClientCB {
diff --git a/csdk/stack/include/internal/ocobserve.h b/csdk/stack/include/internal/ocobserve.h
new file mode 100644 (file)
index 0000000..8c635dc
--- /dev/null
@@ -0,0 +1,49 @@
+//******************************************************************
+//
+// Copyright 2014 Intel Corporation All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#ifndef OC_OBSERVE_H
+#define OC_OBSERVE_H
+
+/* In CoAP sequence number is a 24 bit field */
+#define MAX_SEQUENCE_NUMBER              0xFFFFFF
+#define OC_RESOURCE_OBSERVE_REGISTER     "0"
+#define OC_RESOURCE_OBSERVE_DEREGISTER   "1"
+
+/* Vijay: TODO add comments */
+typedef struct ObserveResourceServer {
+    // xxxxxxxxxxxxxxxx
+    unsigned char *resUri;
+    // xxxxxxxxxxxxxxxxx
+    unsigned char *query;
+    // xxxxxxxxxxxxxxxxx
+    OCCoAPToken *coapTok;
+    // xxxxxxxxxxxxxxxxx
+    OCResource *resource;
+    // xxxxxxxxxxxxxxxxx
+    OCDevAddr *addr;
+    // next node in this list
+    struct ObserveResourceServer *next;
+} ObserveResourceServer;
+
+OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request);
+
+OCStackResult SendObserverNotification (OCResourceHandle handle, OCResource *resPtr);
+
+#endif //OC_OBSERVE_H
index 89c89a9..defd13a 100644 (file)
@@ -29,6 +29,7 @@
 // Includes
 //-----------------------------------------------------------------------------
 #include "ocstack.h"
+#include "occoaptoken.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -114,14 +115,30 @@ typedef struct rsrc_t {
     // NOTE: Methods supported by this resource should be based on the interface targeted
     // i.e. look into the interface structure based on the query request Can be removed here; place holder for the note above
     /* method_t methods; */
+    // Sequence number for observable resources. Per the CoAP standard it is a 24 bit value.
+    uint32_t sequenceNum;
 } OCResource;
 
+/* Vijay: TODO add comments */
+typedef struct {
+    // xxxxxxxxxxxxxxxx
+    unsigned char *option;
+    // xxxxxxxxxxxxxxxx
+    OCDevAddr *subAddr;
+    // xxxxxxxxxxxxxxxx
+    uint8_t *coapToken;
+    // xxxxxxxxxxxxxxxx
+    size_t coapTokenLen;
+} OCObserveReq;
+
 // following structure will be created in occoap and passed up the stack on the server side
 typedef struct {
     // resourceUrl will be filled in occoap using the path options in received request PDU
     unsigned char * resourceUrl;
     // qos is indicating if the request is CON or NON
     OCQualityOfService qos;
+    // this structure points to the information for processing observe option 
+    OCObserveReq *observe;
     // this structure will be passed to entity handler
     OCEntityHandlerRequest * entityHandlerRequest;
 } OCRequest;
index dd57c8b..d3810e6 100644 (file)
@@ -111,12 +111,14 @@ typedef enum {
     OC_STACK_INVALID_CALLBACK,
     OC_STACK_INVALID_METHOD,
     OC_STACK_INVALID_PARAM,
+    OC_STACK_INVALID_OBSERVE_PARAM,
     OC_STACK_NO_MEMORY,
     OC_STACK_COMM_ERROR,
     OC_STACK_NOTIMPL,
     OC_STACK_NO_RESOURCE, /* resource not found*/
     OC_STACK_RESOURCE_ERROR, /*ex: not supported method or interface*/
     OC_STACK_SLOW_RESOURCE,
+    OC_STACK_NO_OBSERVERS, /* resource has no registered observers */
     OC_STACK_ERROR
 } OCStackResult;
 
index 59fcf76..a4d493c 100644 (file)
@@ -36,7 +36,7 @@ CC_FLAGS.debug      := -O0 -g3 -Wall -ffunction-sections -fdata-sections -fno-ex
 CC_FLAGS.release    := -Os -Wall -fdata-sections -Wl,--gc-sections -Wl,-s -fno-exceptions \
                         $(INC_DIRS) -L$(ROOT_DIR) -DTB_LOG
                                        
-LDLIBS         += -loctbstack
+LDLIBS         += -loctbstack -lpthread
 CPPFLAGS       += $(CC_FLAGS.$(BUILD)) $(LDLIBS)
 
 PROGRAMS       += ocserver
index 8938506..2763d44 100644 (file)
@@ -65,6 +65,7 @@ OCStackApplicationResult clientApplicationGETCb(void* ctx, OCClientResponse * cl
        if(ctx == (void*)CTX_VAL) {
                OC_LOG_V(INFO, TAG, "Callback Context for GET query recvd successfully");
                OC_LOG_V(INFO, TAG, "JSON = %s =============> Discovered", clientResponse->resJSONPayload);
+#if 0
        //* Make a GET query*/
                std::ostringstream getQuery;
                getQuery << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
@@ -79,6 +80,7 @@ OCStackApplicationResult clientApplicationGETCb(void* ctx, OCClientResponse * cl
                        OC_LOG_V(ERROR, TAG, "OCStack resource error");
                        //reOC_LOG_Vturn 0;
                }
+#endif
        }
        return OC_STACK_KEEP_TRANSACTION;
 }
@@ -108,7 +110,19 @@ OCStackApplicationResult clientApplicationCB(void* ctx,
             "Device =============> Discovered %s @ %d.%d.%d.%d:%d",
             clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1],
             remoteIpAddr[2], remoteIpAddr[3], remotePortNu);
-
+   
+       std::ostringstream obsReg;
+       obsReg << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
+       OCCallbackData cbData;
+       cbData.cb = clientApplicationGETCb;
+       cbData.context = (void*)CTX_VAL;
+       if (OCDoResource(&handle, OC_REST_OBSERVE, obsReg.str().c_str(), 0, 0, OC_NON_CONFIRMABLE, &cbData)
+                       != OC_STACK_OK) {
+               OC_LOG(ERROR, TAG, "OCStack resource error");
+               //return 0;
+       }
+       return OC_STACK_KEEP_TRANSACTION;
+#if 0
        //* Make a GET query*/
        std::ostringstream getQuery;
        getQuery << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
@@ -122,6 +136,7 @@ OCStackApplicationResult clientApplicationCB(void* ctx,
        }
 
        return OC_STACK_KEEP_TRANSACTION;
+#endif
 }
 //This function is called back when a resource is discovered.
 
@@ -169,7 +184,7 @@ int main() {
                        return 0;
                }
 
-               sleep(1);
+               sleep(3);
        }
        OC_LOG(INFO, TAG, "Exiting occlient main loop...");
 
index e2035e4..899bf9f 100644 (file)
 #include <stdlib.h>
 #include <unistd.h>
 #include <signal.h>
+#include <pthread.h>
 #include <ocstack.h>
 #include <logger.h>
 
-
 char *getResult(OCStackResult result);
 
 #define TAG PCF("ocserver")
 
 int gQuitFlag = 0;
+int gLEDUnderObservation = 0;
 void createLEDResource();
 typedef struct LEDRESOURCE{
        OCResourceHandle handle;
-       bool power;
+       bool state;
+    int power;
 } LEDResource;
 
 static LEDResource LED;
@@ -47,6 +49,7 @@ static unsigned char responsePayloadPut[] = "{\"oc\": {\"payload\": {\"state\" :
 
 OCStackResult OCEntityHandlerCb(OCEntityHandlerFlag flag, OCEntityHandlerRequest * entityHandlerRequest ) {
        const char* typeOfMessage;
+
        switch (flag) {
                case OC_INIT_FLAG:
                        typeOfMessage = "OC_INIT_FLAG";
@@ -61,7 +64,7 @@ OCStackResult OCEntityHandlerCb(OCEntityHandlerFlag flag, OCEntityHandlerRequest
                        typeOfMessage = "UNKNOWN";
        }
        OC_LOG_V(INFO, TAG, "Receiving message type: %s", typeOfMessage);
-       if(entityHandlerRequest){ //[CL]
+       if(entityHandlerRequest && flag == OC_REQUEST_FLAG){ //[CL]
        if(OC_REST_GET == entityHandlerRequest->method)
                        //entityHandlerRequest->resJSONPayload = reinterpret_cast<unsigned char*>(const_cast<unsigned char*> (responsePayloadGet.c_str()));
                        entityHandlerRequest->resJSONPayload = responsePayloadGet;
@@ -73,7 +76,9 @@ OCStackResult OCEntityHandlerCb(OCEntityHandlerFlag flag, OCEntityHandlerRequest
                        //responsePayloadGet = responsePayloadPut; // just a bad hack!
                        }
 
-       }
+       } else if (entityHandlerRequest && flag == OC_OBSERVE_FLAG) {
+        gLEDUnderObservation = 1;
+    }
 
        //OC_LOG_V(INFO, TAG, "/nReceiving message type:/n/t %s. /n/nWith request:/n/t %s", typeOfMessage, request);
 
@@ -87,12 +92,35 @@ void handleSigInt(int signum) {
        }
 }
 
+void * ChangeLEDRepresentation (void *param)
+{
+    (void)param;
+    OCStackResult result = OC_STACK_ERROR;
+
+    while (1)
+    {
+        sleep (15);
+        LED.power += 5;
+        if (gLEDUnderObservation)
+        {
+               OC_LOG_V(INFO, TAG, " =====> Notifying stack of new power level %d\n", LED.power);
+            result = OCNotifyObservers (LED.handle);
+            printf ("==========> Result from stack: %s\n", getResult(result));
+            if (OC_STACK_NO_OBSERVERS == result)
+            {
+                gLEDUnderObservation = 0;
+            }
+        }
+    }
+}
+
 int main() {
        OC_LOG(DEBUG, TAG, "OCServer is starting...");
        uint8_t addr[20] = {0};
        uint8_t* paddr = NULL;
        uint16_t port = USE_RANDOM_PORT;
        uint8_t ifname[] = "eth0";
+    pthread_t threadId;
 
        /*Get Ip address on defined interface and initialize coap on it with random port number
         * this port number will be used as a source port in all coap communications*/
@@ -113,6 +141,11 @@ int main() {
         */
        createLEDResource();
 
+    /*
+     * Create a thread for changing the representation of the LED
+     */
+    pthread_create (&threadId, NULL, ChangeLEDRepresentation, (void *)NULL);
+
        // Break from loop with Ctrl-C
        OC_LOG(INFO, TAG, "Entering ocserver main loop...");
        signal(SIGINT, handleSigInt);
@@ -121,7 +154,7 @@ int main() {
                        OC_LOG(ERROR, TAG, "OCStack process error");
                        return 0;
                }
-               sleep(1);
+               sleep(3);
        }
 
        OC_LOG(INFO, TAG, "Exiting ocserver main loop...");
@@ -133,7 +166,7 @@ int main() {
        return 0;
 }
 void createLEDResource() {
-       LED.power = false;
+       LED.state = false;
        OCStackResult res = OCCreateResource(&LED.handle,
                        "core.led",
                        "state:oc.bt.b;power:oc.bt.i",
@@ -191,6 +224,9 @@ char *getResult(OCStackResult result) {
     case OC_STACK_SLOW_RESOURCE:
         strcat(resString, "OC_STACK_SLOW_RESOURCE");
         break;
+    case OC_STACK_NO_OBSERVERS:
+        strcat(resString, "OC_STACK_NO_OBSERVERS");
+        break;
     case OC_STACK_ERROR:
         strcat(resString, "OC_STACK_ERROR");
         break;
diff --git a/csdk/stack/src/ocobserve.c b/csdk/stack/src/ocobserve.c
new file mode 100644 (file)
index 0000000..3c4ea5c
--- /dev/null
@@ -0,0 +1,164 @@
+//******************************************************************
+//
+// Copyright 2014 Intel Corporation All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include <string.h>
+#include "ocstack.h"
+#include "ocstackinternal.h"
+#include "ocobserve.h"
+#include "occoap.h"
+#include "utlist.h"
+#include "debug.h"
+
+// Module Name
+#define MOD_NAME PCF("ocobserve")
+
+#define TAG  PCF("OCStackObserve")
+
+#define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
+
+static struct ObserveResourceServer *serverObsList = NULL;
+
+OCStackResult AddObserver (const char   *resUri,
+                           const char   *query,
+                           uint8_t      *token,
+                           size_t       tokenLength,
+                           OCDevAddr    *addr,
+                           OCResource   *resHandle);
+
+OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request)
+{
+    OCStackResult result;
+    OCEntityHandlerRequest *ehReq = request->entityHandlerRequest;
+    OCObserveReq *obs = request->observe;
+
+    OC_LOG(INFO, TAG, "Entering ProcessObserveRequest");
+    printf ("Observer option: %s\n", obs->option);
+    if (strcmp ((char *)obs->option, OC_RESOURCE_OBSERVE_REGISTER) == 0) {
+        // Register new observation
+        printf ("Register new observation\n\n");
+        result = resource->entityHandler(OC_OBSERVE_FLAG, request->entityHandlerRequest);
+        if (OC_STACK_OK == result)
+        {
+            // Add subscriber to the server observation list
+            result = AddObserver ((const char*)(request->resourceUrl), (const char *)(ehReq->query), 
+                                   obs->coapToken, obs->coapTokenLen, obs->subAddr, resource);
+        } 
+        return result;
+    } else if (strcmp ((char *)request->observe, OC_RESOURCE_OBSERVE_DEREGISTER) == 0) {
+        // Deregister observation
+        return OC_STACK_NOTIMPL;
+    } else {
+        // Invalid option
+        return OC_STACK_INVALID_OBSERVE_PARAM;
+    }
+}
+
+OCStackResult SendObserverNotification (OCResourceHandle handle, OCResource *resPtr) 
+{
+    uint8_t numObs = 0;
+    OCStackResult result;
+    ObserveResourceServer *obsRes = serverObsList;
+    OCEntityHandlerRequest entityHandlerReq;
+    unsigned char bufRes[MAX_RESPONSE_LENGTH] = {0};
+    /* 
+     * TODO: In the current releast all observes are set as non-confirmable since the
+     * entity handler does not have a way to specify the message QoS - add a parameter. 
+     * Sending all observes NON does not confirm with the observe draft (ver14).
+     */
+    OCQualityOfService qos = OC_NON_CONFIRMABLE;
+
+    // Increment the sequence number
+    resPtr->sequenceNum += 1;
+    if (resPtr->sequenceNum == MAX_SEQUENCE_NUMBER)
+        resPtr->sequenceNum = 1;
+
+    // Find clients that are observing this resource
+    while (obsRes) {
+        if (obsRes->resource == handle) {
+            // Invoke the entity handler for the client to process the query according to
+            // the new representation
+            numObs++;
+            entityHandlerReq.resource = handle;
+            entityHandlerReq.query = obsRes->query;
+            entityHandlerReq.method = OC_REST_GET;
+            entityHandlerReq.reqJSONPayload = NULL;
+            entityHandlerReq.resJSONPayload = bufRes;
+            entityHandlerReq.resJSONPayloadLen = MAX_RESPONSE_LENGTH;
+            // Even if entity handler for a resource is not successful we continue calling
+            // entity handler for other resources 
+            result = resPtr->entityHandler (OC_REQUEST_FLAG, &entityHandlerReq);
+            if (OC_STACK_OK == result)
+            {
+                printf ("Calling OCCoAPSendMessage: Payload: %s\n", entityHandlerReq.resJSONPayload);
+                OCCoAPSendMessage (obsRes->addr, result, qos, obsRes->coapTok,
+                                   (const char *)entityHandlerReq.resJSONPayload,
+                                    resPtr->sequenceNum);
+            }
+        }
+        obsRes = obsRes->next;
+    }
+    if (numObs == 0)
+    {
+        OC_LOG(INFO, TAG, "Resource has no observers");
+        return OC_STACK_NO_OBSERVERS;
+    }
+    return OC_STACK_OK;
+}
+
+OCStackResult AddObserver (const char   *resUri,
+                           const char   *query,
+                           uint8_t      *token,
+                           size_t       tokenLength,
+                           OCDevAddr    *addr,
+                           OCResource   *resHandle)
+{
+    ObserveResourceServer *obsNode;
+    OCCoAPToken *tokPtr;
+
+    obsNode = (ObserveResourceServer *) OCMalloc(sizeof(ObserveResourceServer));
+    if (obsNode) {
+        obsNode->resUri = (unsigned char *)OCMalloc(sizeof(strlen(resUri)+1));
+        VERIFY_NON_NULL (obsNode->resUri);
+        memcpy (obsNode->resUri, resUri, sizeof(strlen(resUri)+1));
+        obsNode->query = (unsigned char *)OCMalloc(sizeof(strlen(query)+1));
+        VERIFY_NON_NULL (obsNode->query);
+        memcpy (obsNode->query, query, sizeof(strlen(query)+1));
+        obsNode->coapTok = (OCCoAPToken *)OCMalloc(sizeof(OCCoAPToken));
+        VERIFY_NON_NULL (obsNode->coapTok);
+        tokPtr = obsNode->coapTok;
+        memcpy (tokPtr->token, token, sizeof(OCCoAPToken));
+        tokPtr->tokenLength = tokenLength;
+        obsNode->addr = (OCDevAddr *)OCMalloc(sizeof(OCDevAddr));
+        VERIFY_NON_NULL (obsNode->addr);
+        memcpy (obsNode->addr, addr, sizeof(OCDevAddr));
+        obsNode->resource = resHandle;
+
+        LL_APPEND (serverObsList, obsNode);
+        return OC_STACK_OK;
+    }
+
+exit:
+    OCFree(obsNode->resUri);
+    OCFree(obsNode->query);
+    OCFree(obsNode->coapTok);
+    OCFree(obsNode->addr);
+    OCFree(obsNode);
+    return OC_STACK_NO_MEMORY;
+}
index f881bb2..075763b 100644 (file)
@@ -27,6 +27,7 @@
 #include "ocserverrequest.h"
 #include "ocresource.h"
 #include "occlientcb.h"
+#include "ocobserve.h"
 #include "ocrandom.h"
 #include "debug.h"
 #include "occoap.h"
@@ -89,6 +90,11 @@ OCStackResult HandleStackRequests(OCRequest * request) {
         if (resource)
         {
             result = resource->entityHandler(OC_REQUEST_FLAG, request->entityHandlerRequest);
+            if (request->observe != NULL)
+            {
+                printf ("\n *** An observe is included in message \n");
+                ProcessObserveRequest (resource, request);
+            }
         }
         else
         {
@@ -326,6 +332,10 @@ OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requ
     // Validate required URI
     VERIFY_NON_NULL(requiredUri, FATAL, OC_STACK_INVALID_URI);
 
+    if (method == OC_REST_OBSERVE)
+    {
+        printf ("\n\n ********* OBSERVE REGISTRATION ******* \n\n");
+    }
     // Make call to OCCoAP layer
     if (OCDoCoAPResource(method, qos, _token, requiredUri, request) == OC_COAP_OK) {
         OC_LOG(INFO, TAG, "Done with this function");
@@ -1048,7 +1058,6 @@ OCEntityHandler OCGetResourceHandler(OCResourceHandle handle) {
 /**
  * Notify observers that an observed value has changed.
  *
- *   **NOTE: This API has NOT been finalized!!!**
  *
  * @param handle - handle of resource
  *
@@ -1057,14 +1066,23 @@ OCEntityHandler OCGetResourceHandler(OCResourceHandle handle) {
  *     OC_STACK_ERROR - stack not initialized
  */
 OCStackResult OCNotifyObservers(OCResourceHandle handle) {
+    OCResource *resPtr = NULL;
+    OCStackResult result;
 
-    TODO ("This API has NOT been finalized");
-
-    OC_LOG(INFO, TAG, PCF("Entering OCNotifyObservers"));
+    OC_LOG(INFO, TAG, PCF("====>Entering OCNotifyObservers"));
 
-    (void) handle;
+    VERIFY_NON_NULL(handle, ERROR, OC_STACK_ERROR);
 
-    return OC_STACK_NOTIMPL;
+    // Verify that the resource exists
+    printf ("====> Finding resource\n");
+    resPtr = findResource ((OCResource *) handle);
+    if (NULL == resPtr)
+    {
+        return OC_STACK_NO_RESOURCE;
+    } else {
+        result = SendObserverNotification (handle, resPtr);
+        return result;
+    }
 }
 
 //-----------------------------------------------------------------------------