Patch 1 (Yamin): This is where all work is merged from
authorYamin S Al-mousa <yamin.s.al-mousa@intel.com>
Wed, 3 Sep 2014 02:16:08 +0000 (19:16 -0700)
committerYamin S Al-mousa <yamin.s.al-mousa@intel.com>
Wed, 3 Sep 2014 02:16:08 +0000 (19:16 -0700)
Sashi, Joey and myself

Patch 2 (Sashi): Looks like some debugging printf work. Should
be removed. Sashi?

Patch 3 (Joey): Applying changes as per review by Chanchala in parent
changeset Change-Id: I2625063e4a6bdfa53e3954310a060ea3c0ee5d3c

Patch 4 (Joey & Yamin): Squash all of Active Discovery and rebase
on to master.

Patch 5 (Joey): Cleaned up warnings and refactored merge conflicts
that caused build server to fail.

Patch 6 (Yamin): More debugging and restructuring... more work needed specifically for the TTL logic

Patch 7 and 8 (Yamin): Fixed TTL logic and presence cancelation, more clean up to come...

Patch 9: Added the random TTL logic and cleaned up.

Change-Id: I4bbd72e066ed4b50f4d2be52367844918a29823a

21 files changed:
csdk/libcoap-4.1.1/net.c
csdk/occoap/include/occoap.h
csdk/occoap/include/occoaphelper.h
csdk/occoap/src/occoap.c
csdk/occoap/src/occoaphelper.c
csdk/ocrandom/include/ocrandom.h
csdk/ocrandom/src/ocrandom.c
csdk/stack/include/internal/occlientcb.h
csdk/stack/include/internal/ocobserve.h
csdk/stack/include/internal/ocresource.h
csdk/stack/include/internal/ocstackinternal.h
csdk/stack/include/ocstack.h
csdk/stack/samples/linux/SimpleClientServer/common.cpp
csdk/stack/samples/linux/SimpleClientServer/occlient.cpp
csdk/stack/samples/linux/SimpleClientServer/occlientcoll.cpp
csdk/stack/samples/linux/SimpleClientServer/ocserver.cpp
csdk/stack/src/occlientcb.c
csdk/stack/src/occollection.c
csdk/stack/src/ocobserve.c
csdk/stack/src/ocresource.c
csdk/stack/src/ocstack.c

index 58524cf..0e99510 100644 (file)
@@ -313,6 +313,7 @@ coap_new_context(const coap_address_t *listen_addr) {
 #endif /* WITH_CONTIKI */
 
     if (!listen_addr) {
+        coap_free(c);
         coap_log(LOG_EMERG, "no listen address specified\n");
         return NULL;
     }
index 4cffab9..57a3863 100644 (file)
 #include <stdint.h>
 
 //-----------------------------------------------------------------------------
-// Typedefs
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
 // Function Prototypes
 //-----------------------------------------------------------------------------
 
+uint32_t GetTime(float afterSeconds);
+
 /**
  * Initialize the CoAP client or server with the its IPv4 address and CoAP port
  *
@@ -93,8 +91,8 @@ OCCoAPToken * OCGenerateCoAPToken();
  *
  * @return 0 - success, else - TBD error
  */
-OCStackResult OCSendCoAPNotification (OCDevAddr *dstAddr, OCStackResult result,
+OCStackResult OCSendCoAPNotification (unsigned char * uri, OCDevAddr *dstAddr, OCStackResult result,
         OCQualityOfService qos, OCCoAPToken * token,
-        unsigned char *payload, uint32_t seqNum);
+        unsigned char *payload, uint32_t seqNum, uint32_t maxAge);
 
 #endif /* OCCOAP_H_ */
index 6a90a62..e69f916 100644 (file)
@@ -35,6 +35,8 @@
 #include "occoaptoken.h"
 #include "ocstackinternal.h"
 
+#define BUF_SIZE (64)
+
 // Convert OCStack code to CoAP code
 uint8_t OCToCoAPResponseCode(OCStackResult result);
 
@@ -72,7 +74,8 @@ OCStackResult FormOCEntityHandlerRequest(OCEntityHandlerRequest * * entityHandle
 
 // Internal function to retrieve Uri and Query from received coap pdu
 OCStackResult ParseCoAPPdu(coap_pdu_t * pdu, unsigned char * uriBuf,
-        unsigned char * queryBuf, uint8_t * * obsOptionLoc, unsigned char * * payloadLoc);
+        unsigned char * queryBuf, uint8_t * * observeOptionLoc,
+        uint8_t * * maxAgeOptionLoc, unsigned char * * payloadLoc);
 
 // Internal function to retrieve a Token from received coap pdu
 OCStackResult RetrieveOCCoAPToken(const coap_pdu_t * pdu,
@@ -84,7 +87,7 @@ OCStackResult FormOCObserveReq(OCObserveReq ** observeReqLoc, uint8_t obsOption,
 
 // Internal function to create OCResponse struct at the client from a received coap pdu
 OCStackResult FormOCResponse(OCResponse * * responseLoc, ClientCB * cbNode,
-        OCClientResponse * clientResponse);
+        uint8_t TTL, OCClientResponse * clientResponse);
 
 // Internal function to create OCClientResponse struct at the client from a received coap pdu
 OCStackResult FormOCClientResponse(OCClientResponse * * clientResponseLoc,
@@ -95,8 +98,10 @@ OCStackResult FormOCClientResponse(OCClientResponse * * clientResponseLoc,
 void HandleSendQueue(coap_context_t * gCoAPCtx);
 
 // Internal function to form the standard response option list
-OCStackResult FormResponseOptList(coap_list_t * * optList, uint8_t * addMediaType,
-        uint32_t * addMaxAge, uint8_t observeOptionLength, uint8_t * observeOptionPtr);
+OCStackResult FormOptionList(coap_list_t * * optListLoc, uint8_t * addMediaType,
+        uint32_t * addMaxAge, uint8_t observeOptionLength, uint8_t * observeOptionPtr,
+        uint16_t * addPortNumber, uint8_t uriLength, unsigned char * uri,
+        uint8_t queryLength, unsigned char * query);
 
 // Internal function to retransmit a queue
 OCStackResult ReTXCoAPQueue(coap_context_t * ctx, coap_queue_t * queue);
index 38b34c8..c74932a 100644 (file)
@@ -43,8 +43,6 @@
             {OC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG_V(FATAL, TAG, "%s is NULL", #arg); goto exit;} }
 
-#define BUF_SIZE (64)
-
 //=============================================================================
 // Private Variables
 //=============================================================================
@@ -84,7 +82,7 @@ static void HandleCoAPAckRst(struct coap_context_t * ctx, uint8_t msgType,
     coap_pdu_t * sentPdu = sentQueue->pdu;
 
     // fill the buffers of Uri and Query
-    result = ParseCoAPPdu(sentPdu, NULL, NULL, &observeOption, NULL);
+    result = ParseCoAPPdu(sentPdu, NULL, NULL, &observeOption, NULL, NULL);
     VERIFY_SUCCESS(result, OC_STACK_OK);
 
     // fill OCCoAPToken structure
@@ -119,6 +117,12 @@ static void HandleCoAPRequests(struct coap_context_t *ctx,
     // silence warnings
     (void) ctx;
 
+    if(myStackMode == OC_CLIENT)
+    {
+        //TODO: should the client be responding to requests?
+        return;
+    }
+
     OCStackResult result = OC_STACK_ERROR;
     OCStackResult responseResult = OC_STACK_ERROR;
     OCRequest * request = NULL;
@@ -140,7 +144,7 @@ static void HandleCoAPRequests(struct coap_context_t *ctx,
     coap_pdu_t * recvPdu = rcvdRequest->pdu;
 
     // fill the buffers of Uri and Query
-    result = ParseCoAPPdu(recvPdu, rcvdUri, rcvdQuery, &rcvObserveOption, &bufReqPayload);
+    result = ParseCoAPPdu(recvPdu, rcvdUri, rcvdQuery, &rcvObserveOption, NULL, &bufReqPayload);
     VERIFY_SUCCESS(result, OC_STACK_OK);
     if(rcvObserveOption){
         observeOption = (uint8_t)(*rcvObserveOption);
@@ -176,6 +180,12 @@ static void HandleCoAPRequests(struct coap_context_t *ctx,
 
     // process the request
     responseResult = HandleStackRequests(request);
+    #ifdef WITH_PRESENCE
+    if(responseResult == OC_STACK_PRESENCE_DO_NOT_HANDLE)
+    {
+        goto exit;
+    }
+    #endif
 
     TODO("we should return the same registration option; however, this will confuse the receiver \
              whether it is a sequence number or registration option!------------");
@@ -187,19 +197,28 @@ static void HandleCoAPRequests(struct coap_context_t *ctx,
         {
         case OC_STACK_OK:
             observeOption = rcvdObsReq->option;
-            result = FormResponseOptList(&optList, &mediaType, &maxAge, 0, NULL);
+            /*
+            OCStackResult FormOptionList(coap_list_t * * optListLoc, uint8_t * addMediaType,
+                                        uint32_t * addMaxAge, uint8_t observeOptionLength, uint8_t * observeOptionPtr,
+                                        uint16_t * addPortNumber, uint8_t uriLength, unsigned char * uri,
+                                        uint8_t queryLength, unsigned char * query)
+            */
+            result = FormOptionList(&optList, &mediaType, &maxAge, 0, NULL, NULL,
+                                    0, NULL, 0, NULL);
             break;
         case OC_STACK_OBSERVER_NOT_ADDED:
         case OC_STACK_OBSERVER_NOT_REMOVED:
         case OC_STACK_INVALID_OBSERVE_PARAM:
         default:
-            result = FormResponseOptList(&optList, &mediaType, &maxAge, 0, NULL);
+            result = FormOptionList(&optList, &mediaType, &maxAge, 0, NULL, NULL,
+                    0, NULL, 0, NULL);
             break;
         }
     }
     else
     {
-        result = FormResponseOptList(&optList, &mediaType, &maxAge, 0, NULL);
+        result = FormOptionList(&optList, &mediaType, &maxAge, 0, NULL, NULL,
+                0, NULL, 0, NULL);
     }
 
     VERIFY_SUCCESS(result, OC_STACK_OK);
@@ -227,6 +246,13 @@ exit:
     OCFree(request);
 }
 
+uint32_t GetTime(float afterSeconds)
+{
+    coap_tick_t now;
+    coap_ticks(&now);
+    return now + (uint32_t)(afterSeconds * COAP_TICKS_PER_SECOND);
+}
+
 //This function is called back by libcoap when a response is received
 static void HandleCoAPResponses(struct coap_context_t *ctx,
         const coap_queue_t * rcvdResponse) {
@@ -236,25 +262,43 @@ static void HandleCoAPResponses(struct coap_context_t *ctx,
     ClientCB * cbNode = NULL;
     unsigned char * bufRes = NULL;
     uint8_t * rcvObserveOption;
+    uint8_t * rcvMaxAgeOption;
     uint32_t sequenceNumber = 0;
+    uint32_t maxAge = 0;
     OCStackResult result = OC_STACK_ERROR;
     coap_pdu_t *sendPdu = NULL;
     coap_pdu_t * recvPdu = NULL;
-    //coap_list_t *optList = NULL;
-    //uint8_t deregisterObserveOption = OC_RESOURCE_OBSERVE_DEREGISTER;
+    uint8_t remoteIpAddr[4];
+    uint16_t remotePortNu;
+    unsigned char fullUri[MAX_URI_LENGTH] = { 0 };
+    unsigned char rcvdUri[MAX_URI_LENGTH] = { 0 };
+    #ifdef WITH_PRESENCE
+    uint8_t isPresenceUpdate = 0;
+    #endif
 
     VERIFY_NON_NULL(ctx);
     VERIFY_NON_NULL(rcvdResponse);
     recvPdu = rcvdResponse->pdu;
 
-    result = ParseCoAPPdu(recvPdu, NULL, NULL, &rcvObserveOption, &bufRes);
+    result = ParseCoAPPdu(recvPdu, rcvdUri, NULL, &rcvObserveOption, &rcvMaxAgeOption, &bufRes);
     VERIFY_SUCCESS(result, OC_STACK_OK);
 
     if(rcvObserveOption){
         sequenceNumber = *((uint32_t *) rcvObserveOption);
     }
 
+    if(rcvMaxAgeOption){
+        maxAge = *((uint32_t *) rcvMaxAgeOption);
+    }
+
+    #ifdef WITH_PRESENCE
+    if(!strcmp((char *)rcvdUri, (char *)OC_PRESENCE_URI)){
+        isPresenceUpdate = 1;
+    }
+    #endif
+
     OC_LOG_V(DEBUG, TAG, "The sequence number of this response %d", sequenceNumber);
+    OC_LOG_V(DEBUG, TAG, "The max age of this response %d", maxAge);
     OC_LOG_V(DEBUG, TAG, "The response received is %s", bufRes);
 
     // fill OCCoAPToken structure
@@ -268,38 +312,134 @@ static void HandleCoAPResponses(struct coap_context_t *ctx,
             (OCDevAddr *) &(rcvdResponse->remote), sequenceNumber, bufRes);
     VERIFY_SUCCESS(result, OC_STACK_OK);
 
-    cbNode = GetClientCB(rcvdToken, NULL);
+    cbNode = GetClientCB(rcvdToken, NULL, NULL);
+    if(!cbNode)
+    {
+        // we should check if we are monitoring the presence of this resource
+        //get the address of the remote
+        OCDevAddrToIPv4Addr((OCDevAddr *) &(rcvdResponse->remote), remoteIpAddr,
+                remoteIpAddr + 1, remoteIpAddr + 2, remoteIpAddr + 3);
+        OCDevAddrToPort((OCDevAddr *) &(rcvdResponse->remote), &remotePortNu);
+        sprintf((char *)fullUri, "coap://%d.%d.%d.%d:%d%s",
+                remoteIpAddr[0],remoteIpAddr[1],remoteIpAddr[2],remoteIpAddr[3],
+                remotePortNu,rcvdUri);
+        cbNode = GetClientCB(NULL, NULL, fullUri);
+    }
 
     // fill OCResponse structure
-    result = FormOCResponse(&response, cbNode, clientResponse);
+    result = FormOCResponse(&response, cbNode, maxAge, clientResponse);
     VERIFY_SUCCESS(result, OC_STACK_OK);
 
     if(cbNode)
     {
-        if(clientResponse->sequenceNumber != 0 &&
+        // following if statement is handling responses of
+        // observation/presence notifications
+        #ifdef WITH_PRESENCE
+        if((clientResponse->sequenceNumber != 0 || isPresenceUpdate) &&
                 (cbNode->method == OC_REST_OBSERVE ||
-                        cbNode->method == OC_REST_OBSERVE_ALL)){
-            OC_LOG(INFO, TAG, PCF("Received an observe notification"));
-            if(recvPdu->hdr->type == COAP_MESSAGE_CON){
+                        cbNode->method == OC_REST_OBSERVE_ALL ||
+                        cbNode->method == OC_REST_PRESENCE))
+        #else
+        if((clientResponse->sequenceNumber != 0) &&
+                (cbNode->method == OC_REST_OBSERVE ||
+                        cbNode->method == OC_REST_OBSERVE_ALL))
+        #endif
+        {
+            OC_LOG(INFO, TAG, PCF("Received an observe/presence notification"));
+            // we should not ACK when it is presence notification
+            // since presence notification is snet with muticast
+            #ifdef WITH_PRESENCE
+            if(recvPdu->hdr->type == COAP_MESSAGE_CON &&
+                    !isPresenceUpdate && cbNode->method != OC_REST_PRESENCE)
+            #else
+            if(recvPdu->hdr->type == COAP_MESSAGE_CON)
+            #endif
+                {
                 sendPdu = GenerateCoAPPdu(COAP_MESSAGE_ACK, 0,
                         recvPdu->hdr->id, NULL, NULL, NULL);
                 VERIFY_NON_NULL(sendPdu);
                 result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote,
                         sendPdu, 0);
             }
+            // we only process newer sequence numbers for OC_REST_OBSERVE and OC_REST_PRESENCE
+            #ifdef WITH_PRESENCE
+            if((cbNode->method == OC_REST_OBSERVE &&
+                    clientResponse->sequenceNumber <= cbNode->sequenceNumber) ||
+                    (cbNode->method == OC_REST_PRESENCE &&
+                            clientResponse->sequenceNumber < cbNode->sequenceNumber))
+            #else
             if(cbNode->method == OC_REST_OBSERVE &&
-                    clientResponse->sequenceNumber <= cbNode->sequenceNumber){
+                    clientResponse->sequenceNumber <= cbNode->sequenceNumber)
+            #endif
+            {
                 OC_LOG_V(DEBUG, TAG, "Observe notification came out of order. \
                         Ignoring Incoming:%d  Against Current:%d.",
                         clientResponse->sequenceNumber, cbNode->sequenceNumber);
                 goto exit;
             }
+            // in the case the presence update has the same sequence number
+            // as previous ones, we signal it as OC_STACK_PRESENCE_NO_UPDATE
+            // no change happend on server's resources
+            #ifdef WITH_PRESENCE
+            if(isPresenceUpdate && cbNode->sequenceNumber == clientResponse->sequenceNumber)
+            {
+                response->clientResponse->result = OC_STACK_PRESENCE_NO_UPDATE;
+            }
+            #endif
+            // update the monitored sequence number.
             if(clientResponse->sequenceNumber > cbNode->sequenceNumber){
                 cbNode->sequenceNumber = clientResponse->sequenceNumber;
             }
+            #ifdef WITH_PRESENCE
+            if(isPresenceUpdate && cbNode->method == OC_REST_PRESENCE){
+                if(!cbNode->presence){
+                    cbNode->presence = (OCPresence *) OCMalloc(sizeof(OCPresence));
+                    VERIFY_NON_NULL(cbNode->presence);
+                    cbNode->presence->timeOut = NULL;
+                    cbNode->presence->timeOut = (uint32_t *)
+                            OCMalloc(PresenceTimeOutSize * sizeof(uint32_t));
+                    if(!(cbNode->presence->timeOut)){
+                        OCFree(cbNode->presence);
+                        goto exit;
+                    }
+                }
+                cbNode->presence->TTL = maxAge;
+                uint32_t lowerBound;
+                uint32_t higherBound;
+                if(maxAge)
+                {
+                    uint32_t now = GetTime(0);
+                    OC_LOG_V(DEBUG, TAG, "----------------current ticks  %d", now);
+                    for(int index = 0; index < PresenceTimeOutSize; index++)
+                    {
+                        lowerBound = GetTime(((float)(PresenceTimeOut[index])
+                                /(float)100)*(float)cbNode->presence->TTL);
+                        higherBound = GetTime(((float)(PresenceTimeOut[index + 1])
+                                /(float)100)*(float)cbNode->presence->TTL);
+                        cbNode->presence->timeOut[index] = OCGetRandomRange(lowerBound, higherBound);
+                        OC_LOG_V(DEBUG, TAG, "----------------lowerBound timeout  %d", lowerBound);
+                        OC_LOG_V(DEBUG, TAG, "----------------higherBound timeout %d", higherBound);
+                        OC_LOG_V(DEBUG, TAG, "----------------timeOut entry  %d", cbNode->presence->timeOut[index]);
+                    }
+                    cbNode->presence->TTLlevel = 0;
+                    OC_LOG_V(DEBUG, TAG, "----------------this TTL level %d", cbNode->presence->TTLlevel);
+                }
+                else
+                {
+                    OC_LOG(INFO, TAG, "===============Stopping presence");
+                    response->clientResponse->result = OC_STACK_PRESENCE_STOPPED;
+                }
+            }
+            #endif
         }
         HandleStackResponses(response);
-    }else if(!cbNode && clientResponse->sequenceNumber != 0){
+    }
+    #ifdef WITH_PRESENCE
+    else if(!cbNode && clientResponse->sequenceNumber != 0 && !isPresenceUpdate)
+    #else
+    else if(!cbNode && clientResponse->sequenceNumber != 0)
+    #endif
+    {
         OC_LOG(INFO, TAG, PCF("Received an observe notification, but I do not have callback \
                  ------------ sending RESET"));
         sendPdu = GenerateCoAPPdu(COAP_MESSAGE_RST, 0,
@@ -307,11 +447,21 @@ static void HandleCoAPResponses(struct coap_context_t *ctx,
         VERIFY_NON_NULL(sendPdu);
         result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote, sendPdu, 0);
         VERIFY_SUCCESS(result, OC_STACK_OK);
-    }else{
+    }
+    #ifdef WITH_PRESENCE
+    else if(!cbNode && clientResponse->sequenceNumber != 0 && isPresenceUpdate)
+    {
+        OC_LOG(INFO, TAG, PCF("Received a presence notification, but I do not have callback \
+                         ------------ ignoring"));
+    }
+    #endif
+    else
+    {
         // TODO: we should send a RST here and..
     }
     exit:
         OCFree(rcvObserveOption);
+        OCFree(rcvMaxAgeOption);
         OCFree(rcvdToken);
         OCFree(clientResponse);
         OCFree(response);
@@ -344,6 +494,7 @@ OCStackResult OCInitCoAP(const char *address, uint16_t port, OCMode mode) {
     OCDevAddr devAddr;
     OCDevAddr mcastAddr;
     uint8_t ipAddr[4] = { 0 };
+    uint16_t parsedPort = 0;
 
     OC_LOG(INFO, TAG, PCF("Entering OCInitCoAP"));
 
@@ -351,7 +502,7 @@ OCStackResult OCInitCoAP(const char *address, uint16_t port, OCMode mode) {
 
     if (address)
     {
-        if (!ParseIPv4Address((unsigned char *) address, ipAddr))
+        if (!ParseIPv4Address((unsigned char *) address, ipAddr, &parsedPort))
         {
             ret = OC_STACK_ERROR;
             goto exit;
@@ -367,13 +518,14 @@ OCStackResult OCInitCoAP(const char *address, uint16_t port, OCMode mode) {
 
     gCoAPCtx = coap_new_context((coap_address_t*) &devAddr);
     VERIFY_NON_NULL(gCoAPCtx);
-    if (mode != OC_CLIENT) {
-        OCBuildIPv4Address(coapWKIpAddr[0], coapWKIpAddr[1], coapWKIpAddr[2],
-                coapWKIpAddr[3], COAP_DEFAULT_PORT, &mcastAddr);
-        VERIFY_SUCCESS(
-                coap_join_wellknown_group(gCoAPCtx,
-                        (coap_address_t* )&mcastAddr), 0);
-    }
+
+    // To allow presence notification work we need to init socket gCoAPCtx->sockfd_wellknown
+    // for servers as well as clients
+    OCBuildIPv4Address(coapWKIpAddr[0], coapWKIpAddr[1], coapWKIpAddr[2],
+            coapWKIpAddr[3], COAP_DEFAULT_PORT, &mcastAddr);
+    VERIFY_SUCCESS(
+            coap_join_wellknown_group(gCoAPCtx,
+                    (coap_address_t* )&mcastAddr), 0);
 
     coap_register_request_handler(gCoAPCtx, HandleCoAPRequests);
     coap_register_response_handler(gCoAPCtx, HandleCoAPResponses);
@@ -411,11 +563,8 @@ OCStackResult OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPTo
     coap_uri_t uri;
     OCDevAddr dst;
     uint8_t ipAddr[4] = { 0 };
+    uint16_t port = 0;
     coap_list_t *optList = NULL;
-    size_t buflen;
-    unsigned char _buf[BUF_SIZE];
-    unsigned char *buf = _buf;
-    int res;
     uint8_t coapMsgType;
     uint8_t coapMethod;
     uint8_t observeOption;
@@ -424,50 +573,19 @@ OCStackResult OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPTo
 
     if (Uri) {
         OC_LOG_V(INFO, TAG, "URI = %s", Uri);
-        VERIFY_SUCCESS(coap_split_uri((unsigned char * )Uri, strlen(Uri), &uri), 0);
+        VERIFY_SUCCESS(coap_split_uri((unsigned char * )Uri, strlen(Uri), &uri), OC_STACK_OK);
 
         // Generate the destination address
-        if (uri.host.length && ParseIPv4Address(uri.host.s, ipAddr)) {
+        if (uri.host.length && ParseIPv4Address(uri.host.s, ipAddr, &port)) {
             OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], uri.port,
                     &dst);
         } else {
             goto exit;
         }
 
-        //create appropriate coap options
-        if (uri.port != COAP_DEFAULT_PORT) {
-            coap_insert(&optList, CreateNewOptionNode( COAP_OPTION_URI_PORT,
-                            sizeof(uri.port), (uint8_t *)&(uri.port)), OrderOptions);
-        }
-
-        if (uri.path.length) {
-            buflen = BUF_SIZE;
-            res = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
-
-            while (res--) {
-                coap_insert(&optList,
-                        CreateNewOptionNode(COAP_OPTION_URI_PATH,
-                                COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf)),
-                        OrderOptions);
-
-                buf += COAP_OPT_SIZE(buf);
-            }
-        }
-
-        if (uri.query.length) {
-            buflen = BUF_SIZE;
-            buf = _buf;
-            res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
-
-            while (res--) {
-                coap_insert(&optList,
-                        CreateNewOptionNode(COAP_OPTION_URI_QUERY,
-                                COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf)),
-                        OrderOptions);
-
-                buf += COAP_OPT_SIZE(buf);
-            }
-        }
+        VERIFY_SUCCESS(FormOptionList(&optList, NULL, NULL, 0, NULL,
+                &uri.port, uri.path.length, uri.path.s, uri.query.length,
+                uri.query.s), OC_STACK_OK);
 
         OC_LOG_V(DEBUG, TAG, "uri.host.s %s", uri.host.s);
         OC_LOG_V(DEBUG, TAG, "uri.path.s %s", uri.path.s);
@@ -484,6 +602,9 @@ OCStackResult OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPTo
     // Decide method type
     switch (method) {
         case OC_REST_GET:
+        #ifdef WITH_PRESENCE
+        case OC_REST_PRESENCE:
+        #endif
             coapMethod = COAP_REQUEST_GET;
             break;
         case OC_REST_PUT:
@@ -519,14 +640,13 @@ exit:
     return ret;
 }
 
-OCStackResult OCSendCoAPNotification (OCDevAddr *dstAddr, OCStackResult result,
+OCStackResult OCSendCoAPNotification (unsigned char * uri, OCDevAddr *dstAddr, OCStackResult result,
                        OCQualityOfService qos, OCCoAPToken * token,
-                       unsigned char *payload, uint32_t seqNum)
+                       unsigned char *payload, uint32_t seqNum, uint32_t maxAge)
 {
     coap_list_t *optList = NULL;
     uint8_t coapMsgType = COAP_MESSAGE_NON;
     uint8_t mediaType = COAP_MEDIATYPE_APPLICATION_JSON;
-    uint32_t maxAge = 0x2ffff;
     coap_pdu_t *sendPdu;
 
     OC_LOG(INFO, TAG, PCF("Entering OCSendCoAPNotification"));
@@ -537,8 +657,10 @@ OCStackResult OCSendCoAPNotification (OCDevAddr *dstAddr, OCStackResult result,
         coapMsgType = COAP_MESSAGE_CON;
     }
 
-    result = FormResponseOptList(&optList, &mediaType, &maxAge, 4, (uint8_t *)(&seqNum));
+    result = FormOptionList(&optList, &mediaType, &maxAge, 4, (uint8_t *)(&seqNum),
+            NULL, strlen((char *)uri), uri, 0, NULL);
     VERIFY_SUCCESS(result, OC_STACK_OK);
+
     sendPdu = GenerateCoAPPdu(
             coapMsgType == COAP_MESSAGE_CON ? COAP_MESSAGE_CON : COAP_MESSAGE_NON,
                     OCToCoAPResponseCode(result), coap_new_message_id(gCoAPCtx),
index 54552ab..521c953 100644 (file)
@@ -105,7 +105,8 @@ OCStackResult CoAPToOCResponseCode(uint8_t coapCode)
 
 // Retrieve Uri and Query from received coap pdu
 OCStackResult ParseCoAPPdu(coap_pdu_t * pdu, unsigned char * uriBuf,
-        unsigned char * queryBuf, uint8_t * * observeOptionLoc, unsigned char * * payloadLoc)
+        unsigned char * queryBuf, uint8_t * * observeOptionLoc,
+        uint8_t * * maxAgeOptionLoc, unsigned char * * payloadLoc)
 {
     coap_opt_filter_t filter;
     coap_opt_iterator_t opt_iter;
@@ -113,7 +114,8 @@ OCStackResult ParseCoAPPdu(coap_pdu_t * pdu, unsigned char * uriBuf,
     size_t bufLen = 0;
     size_t optLen = 0;
     uint8_t * observeOption = NULL;
-    uint8_t observeOptionFound = 0;
+    uint8_t * maxAgeOption = NULL;
+    uint8_t optionFound = 0;
 
     if(uriBuf)
     {
@@ -169,6 +171,7 @@ OCStackResult ParseCoAPPdu(coap_pdu_t * pdu, unsigned char * uriBuf,
 
     if(observeOptionLoc)
     {
+        optionFound = 0;
         // parse the observe option
         coap_option_filter_clear(filter);
         coap_option_setb(filter, COAP_OPTION_OBSERVE);
@@ -181,10 +184,10 @@ OCStackResult ParseCoAPPdu(coap_pdu_t * pdu, unsigned char * uriBuf,
                 return OC_STACK_NO_MEMORY;
             }
             memcpy(observeOption, COAP_OPT_VALUE(option),COAP_OPT_LENGTH(option));
-            observeOptionFound = 1;
+            optionFound = 1;
             break;
         }
-        if(observeOptionFound)
+        if(optionFound)
         {
             *observeOptionLoc = observeOption;
         }
@@ -195,6 +198,36 @@ OCStackResult ParseCoAPPdu(coap_pdu_t * pdu, unsigned char * uriBuf,
         }
     }
 
+
+    if(maxAgeOptionLoc)
+    {
+        optionFound = 0;
+        // parse the observe option
+        coap_option_filter_clear(filter);
+        coap_option_setb(filter, COAP_OPTION_MAXAGE);
+        coap_option_iterator_init(pdu, &opt_iter, filter);
+        while ((option = coap_option_next(&opt_iter)))
+        {
+            maxAgeOption = (uint8_t *) OCMalloc(COAP_OPT_LENGTH(option));
+            if(!maxAgeOption)
+            {
+                return OC_STACK_NO_MEMORY;
+            }
+            memcpy(maxAgeOption, COAP_OPT_VALUE(option),COAP_OPT_LENGTH(option));
+            optionFound = 1;
+            break;
+        }
+        if(optionFound)
+        {
+            *maxAgeOptionLoc = maxAgeOption;
+        }
+        else
+        {
+            OCFree(maxAgeOption);
+            *maxAgeOptionLoc = NULL;
+        }
+    }
+
     // get the payload
     if(payloadLoc)
     {
@@ -315,7 +348,7 @@ OCStackResult RetrieveOCCoAPToken(const coap_pdu_t * pdu,
 }
 
 OCStackResult FormOCResponse(OCResponse * * responseLoc, ClientCB * cbNode,
-        OCClientResponse * clientResponse)
+        uint8_t TTL, OCClientResponse * clientResponse)
 {
     OCResponse * response = (OCResponse *) OCMalloc(sizeof(OCResponse));
     if (!response)
@@ -323,6 +356,7 @@ OCStackResult FormOCResponse(OCResponse * * responseLoc, ClientCB * cbNode,
         return OC_STACK_NO_MEMORY;
     }
     response->cbNode = cbNode;
+    response->TTL = TTL;
     response->clientResponse = clientResponse;
 
     *responseLoc = response;
@@ -349,10 +383,16 @@ OCStackResult FormOCClientResponse(OCClientResponse * * clientResponseLoc,
     return OC_STACK_OK;
 }
 
-OCStackResult FormResponseOptList(coap_list_t * * optListLoc, uint8_t * addMediaType,
-        uint32_t * addMaxAge, uint8_t observeOptionLength, uint8_t * observeOptionPtr)
+OCStackResult FormOptionList(coap_list_t * * optListLoc, uint8_t * addMediaType,
+        uint32_t * addMaxAge, uint8_t observeOptionLength, uint8_t * observeOptionPtr,
+        uint16_t * addPortNumber, uint8_t uriLength, unsigned char * uri,
+        uint8_t queryLength, unsigned char * query)
 {
     coap_list_t * optNode = NULL;
+    int res;
+    size_t buflen;
+    unsigned char _buf[BUF_SIZE];
+    unsigned char *buf = _buf;
 
     if(addMediaType)
     {
@@ -361,6 +401,7 @@ OCStackResult FormResponseOptList(coap_list_t * * optListLoc, uint8_t * addMedia
         VERIFY_NON_NULL(optNode);
         coap_insert(optListLoc, optNode, OrderOptions);
     }
+
     if(addMaxAge)
     {
         optNode = CreateNewOptionNode(COAP_OPTION_MAXAGE,
@@ -368,13 +409,49 @@ OCStackResult FormResponseOptList(coap_list_t * * optListLoc, uint8_t * addMedia
         VERIFY_NON_NULL(optNode);
         coap_insert(optListLoc, optNode, OrderOptions);
     }
-    if(observeOptionPtr)
+
+    if(observeOptionLength && observeOptionPtr)
     {
         optNode = CreateNewOptionNode(COAP_OPTION_OBSERVE,
                 observeOptionLength, (uint8_t *)observeOptionPtr);
+
         VERIFY_NON_NULL(optNode);
         coap_insert(optListLoc, optNode, OrderOptions);
     }
+    if(addPortNumber && *addPortNumber != COAP_DEFAULT_PORT)
+    {
+        optNode = CreateNewOptionNode(COAP_OPTION_URI_PORT,
+                sizeof(*addPortNumber), (uint8_t *)addPortNumber);
+        coap_insert(optListLoc, optNode, OrderOptions);
+    }
+
+    if(uri && uriLength)
+    {
+        buf = _buf;
+        buflen = BUF_SIZE;
+        res = coap_split_path(uri, uriLength, buf, &buflen);
+        while (res--) {
+            optNode = CreateNewOptionNode(COAP_OPTION_URI_PATH,
+                    COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf));
+            VERIFY_NON_NULL(optNode);
+            coap_insert(optListLoc, optNode, OrderOptions);
+            buf += COAP_OPT_SIZE(buf);
+        }
+    }
+
+    if(query && queryLength)
+    {
+        buf = _buf;
+        buflen = BUF_SIZE;
+        res = coap_split_query(query, queryLength, buf, &buflen);
+        while (res--) {
+            optNode = CreateNewOptionNode(COAP_OPTION_URI_QUERY,
+                    COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf));
+            VERIFY_NON_NULL(optNode);
+            coap_insert(optListLoc, optNode, OrderOptions);
+            buf += COAP_OPT_SIZE(buf);
+        }
+    }
 
     return OC_STACK_OK;
     exit:
@@ -561,7 +638,7 @@ OCStackResult HandleFailedCommunication(coap_context_t * ctx, coap_queue_t * que
         goto exit;
     }
 
-    cbNode = GetClientCB(token, NULL);
+    cbNode = GetClientCB(token, NULL, NULL);
     if(!cbNode)
     {
         goto observation;
@@ -572,7 +649,7 @@ OCStackResult HandleFailedCommunication(coap_context_t * ctx, coap_queue_t * que
     {
         goto observation;
     }
-    result = FormOCResponse(&response, cbNode, clientResponse);
+    result = FormOCResponse(&response, cbNode, 0, clientResponse);
     if(result != OC_STACK_OK)
     {
         goto observation;
index bde30f5..d516520 100644 (file)
@@ -64,6 +64,15 @@ uint8_t OCGetRandomByte(void);
  */
 void OCFillRandomMem(uint8_t * location, uint16_t len);
 
+/*
+ * Generate a uniformly distributed number on the defined bounded range
+ * @param[in] firstBound
+ *              the first bound of the range
+ * @param[in] secondBound
+ *              the second bound of the range
+ */
+uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound);
+
 #ifdef __cplusplus
 }
 #endif
index f17876a..836887d 100644 (file)
@@ -115,3 +115,20 @@ uint8_t OCGetRandomByte(void) {
     return random(256) & 0x00FF;
 #endif
 }
+
+uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound){
+    uint32_t base;
+    uint32_t diff;
+    uint32_t result;
+    if(firstBound == secondBound){
+        return secondBound;
+    }else if(firstBound > secondBound){
+        base = secondBound;
+        diff = firstBound - secondBound;
+    }else if(firstBound < secondBound){
+        base = firstBound;
+        diff = secondBound - firstBound;
+    }
+    result = ((float)OCGetRandom()/((float)(0xFFFFFFFF))*(float)diff) + (float) base;
+    return result;
+}
index f6520c0..cf236a2 100644 (file)
 #include <ocstack.h>
 #include <occoaptoken.h>
 
+// TODO platform independence (for time_t)
+#include <time.h>
+
+typedef struct OCPresence {
+    // This is the TTL associated with presence
+    uint32_t TTL;
+    uint32_t * timeOut;
+    uint32_t TTLlevel;
+}OCPresence;
+
 typedef struct ClientCB {
     // callback method defined in application address space
     OCClientResponseHandler callBack;
@@ -38,10 +48,18 @@ typedef struct ClientCB {
     OCMethod method;
     // This is the sequence identifier the server applies to the invocation tied to 'handle'.
     uint32_t sequenceNumber;
+    // This is the request uri associated with the call back
+    unsigned char * requestUri;
+    // Struct to hold TTL info for presence
+    #ifdef WITH_PRESENCE
+    OCPresence * presence;
+    #endif
     // next node in this list
     struct ClientCB    *next;
 } ClientCB;
 
+extern struct ClientCB *cbList;
+
 //-- AddClientCB -----------------------------------------------------------
 /** @ingroup ocstack
  *
@@ -55,13 +73,17 @@ typedef struct ClientCB {
  *              identifier for OTA CoAP comms.
  * @param[in] handle
  *              Masked in the public API as an 'invocation handle' - Used for callback management.
+ * @param[in] requestUri
+ *              the resource uri of the request.
  *
  * @brief If the handle you're looking for does not exist, the stack will reply with a RST message.
  *
  * @retval OC_STACK_OK for Success, otherwise some error value
  */
 //------------------------------------------------------------------------
-OCStackResult AddClientCB(ClientCB** clientCB, OCCallbackData *cbData, OCCoAPToken * token, OCDoHandle handle, OCMethod method);
+OCStackResult AddClientCB(ClientCB** clientCB, OCCallbackData* cbData,
+        OCCoAPToken * token, OCDoHandle handle, OCMethod method,
+        unsigned char * requestUri);
 
 //-- DeleteClientCB -----------------------------------------------------------
 /** @ingroup ocstack
@@ -84,13 +106,15 @@ void DeleteClientCB(ClientCB *cbNode);
  *              token to search for.
  * @param[in] handle
  *              handle to search for.
+ * @param[in] requestUri
+ *              Uri to search for.
  *
  * @brief You can search by token OR by handle. Not both.
  *
  * @retval address of the node if found, otherwise NULL
  */
 //------------------------------------------------------------------------
-ClientCB* GetClientCB(OCCoAPToken * token, OCDoHandle * handle);
+ClientCB* GetClientCB(OCCoAPToken * token, OCDoHandle * handle, unsigned char * requestUri);
 
 //-- DeleteClientCBList --------------------------------------------------
 /** @ingroup ocstack
index 8c55bec..0b0f516 100644 (file)
@@ -62,7 +62,7 @@ OCStackResult OCObserverStatus(OCCoAPToken * token, uint8_t status);
 
 OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request);
 
-OCStackResult SendObserverNotification (OCResource *resPtr);
+OCStackResult SendObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge);
 
 void DeleteObserverList();
 
index f661a41..4b3c1b6 100644 (file)
@@ -74,7 +74,7 @@ OCEntityHandlerResult
 BuildObsJSONResponse(OCResource *resource, OCEntityHandlerRequest *ehRequest);
 
 OCStackResult
-BuildDiscoveryResponse(OCResource *resourcePtr, uint8_t filterOn,
+BuildVirtualResourceResponse(OCResource *resourcePtr, uint8_t filterOn,
                         char *filterValue, char * out, uint16_t *remaining);
 
 #endif //OC_RESOURCE_H
index 5d67dd4..8e8ef06 100644 (file)
@@ -44,6 +44,17 @@ extern "C" {
 //-----------------------------------------------------------------------------
 #define OC_COAP_SCHEME "coap://"
 
+
+//-----------------------------------------------------------------------------
+// Virtual Resource Presence Attributes
+//-----------------------------------------------------------------------------
+#ifdef WITH_PRESENCE
+typedef struct PRESENCERESOURCE{
+    OCResourceHandle handle;
+    uint32_t presenceTTL;
+} PresenceResource;
+#endif
+
 //-----------------------------------------------------------------------------
 // Forward declarations
 //-----------------------------------------------------------------------------
@@ -153,6 +164,8 @@ typedef struct {
 typedef struct {
     // handle is retrieved by comparing the token-handle pair in the PDU.
     ClientCB * cbNode;
+    // This is how long this response is valid for (in seconds).
+    uint32_t TTL;
     // this structure will be passed to client
     OCClientResponse * clientResponse;
 } OCResponse;
@@ -163,7 +176,13 @@ typedef struct {
 
 OCStackResult HandleStackRequests(OCRequest * request);
 void HandleStackResponses(OCResponse * response);
-int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr);
+int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr, uint16_t * port);
+
+#ifdef WITH_PRESENCE
+//TODO: should the following function be public?
+OCStackResult OCChangeResourceProperty(OCResourceProperty * inputProperty,
+        OCResourceProperty resourceProperties, uint8_t enable);
+#endif
 
 // TODO: ultimately OCMalloc and OCFree should be defined in a different module
 void OCFree(void *ptr);
index 49cf0d8..5570d95 100644 (file)
@@ -26,7 +26,7 @@
 #ifdef __cplusplus
 extern "C" {
 #endif // __cplusplus
-
+#define WITH_PRESENCE
 //-----------------------------------------------------------------------------
 // Defines
 //-----------------------------------------------------------------------------
@@ -37,6 +37,12 @@ extern "C" {
 #define OC_MULTICAST_PREFIX                  PCF("coap://224.0.1.187:5683")
 
 #define USE_RANDOM_PORT (0)
+#ifdef WITH_PRESENCE
+#define OC_DEFAULT_PRESENCE_TTL (60)
+#define OC_PRESENCE_URI                      PCF("/oc/presence")
+extern uint8_t PresenceTimeOutSize; // lenght of PresenceTimeOut - 1
+extern uint32_t PresenceTimeOut[];
+#endif
 //-----------------------------------------------------------------------------
 // Typedefs
 //-----------------------------------------------------------------------------
@@ -45,10 +51,13 @@ extern "C" {
  * OC Virtual resources supported by every OC device
  */
 typedef enum {
-    OC_WELL_KNOWN_URI= 0,    // "/oc/core"
-    OC_DEVICE_URI,           // "/oc/core/d"
-    OC_RESOURCE_TYPES_URI,   // "/oc/core/d/type"
-    OC_MAX_VIRTUAL_RESOURCES         // Max items in the list
+    OC_WELL_KNOWN_URI= 0,       // "/oc/core"
+    OC_DEVICE_URI,              // "/oc/core/d"
+    OC_RESOURCE_TYPES_URI,      // "/oc/core/d/type"
+    #ifdef WITH_PRESENCE
+    OC_PRESENCE,                // "/oc/presence"
+    #endif
+    OC_MAX_VIRTUAL_RESOURCES    // Max items in the list
 } OCVirtualResources;
 
 /**
@@ -62,7 +71,9 @@ typedef enum {
     OC_REST_DELETE      = (1 << 3),     // Delete
     OC_REST_OBSERVE     = (1 << 4),     // Register observe request for most up date notifications ONLY.
     OC_REST_OBSERVE_ALL = (1 << 5),     // Register observe request for all notifications, including stale notifications.
+    #ifdef WITH_PRESENCE
     OC_REST_PRESENCE    = (1 << 6)      // Subscribe for all presence notifications of a particular resource.
+    #endif
 } OCMethod;
 
 /**
@@ -74,6 +85,7 @@ typedef enum {
     OC_CLIENT_SERVER
 } OCMode;
 
+extern OCMode myStackMode;
 /**
  * Quality of Service
  */
@@ -115,6 +127,11 @@ typedef enum {
     OC_STACK_OBSERVER_NOT_FOUND,
     OC_STACK_OBSERVER_NOT_ADDED,
     OC_STACK_OBSERVER_NOT_REMOVED,
+    #ifdef WITH_PRESENCE
+    OC_STACK_PRESENCE_NO_UPDATE,
+    OC_STACK_PRESENCE_STOPPED,
+    OC_STACK_PRESENCE_DO_NOT_HANDLE,
+    #endif
     OC_STACK_ERROR
 } OCStackResult;
 
@@ -277,6 +294,33 @@ OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char  *req
  */
 OCStackResult OCCancel(OCDoHandle handle);
 
+#ifdef WITH_PRESENCE
+/**
+ * When operating in @ref OCServer or @ref OCClientServer mode, this API will start sending out
+ * presence notifications to clients via multicast. Once this API has been called with a success,
+ * clients may query for this server's presence and this server's stack will respond via multicast.
+ *
+ * @param ttl (Time To Live in seconds) - Used to set the time a server
+ * Note: If ttl is '0', then the default stack value will be used (60 Seconds).
+ *
+ * @return
+ *     OC_STACK_OK      - No errors; Success
+ *     OC_STACK_ERROR   - @ref OCStartPresence has already been called.
+ */
+OCStackResult OCStartPresence(const uint32_t ttl);
+
+/**
+ * When operating in @ref OCServer or @ref OCClientServer mode, this API will stop sending out
+ * presence notifications to clients via multicast. Once this API has been called with a success,
+ * this server's stack will not respond to clients querying for this server's presence.
+ *
+ * @return
+ *     OC_STACK_OK      - No errors; Success
+ *     OC_STACK_ERROR   - @ref OCStartPresence has never been called or @ref OCStopPresence has
+ *                        already been called.
+ */
+OCStackResult OCStopPresence();
+#endif
 /**
  * Create a resource.
  *
index f31d1bc..8c96d6e 100644 (file)
@@ -54,6 +54,14 @@ const char *getResult(OCStackResult result) {
         return "OC_STACK_SLOW_RESOURCE";
     case OC_STACK_NO_OBSERVERS:
         return "OC_STACK_NO_OBSERVERS";
+    #ifdef WITH_PRESENCE
+    case OC_STACK_PRESENCE_NO_UPDATE:
+        return "OC_STACK_PRESENCE_NO_UPDATE";
+    case OC_STACK_PRESENCE_DO_NOT_HANDLE:
+        return "OC_STACK_PRESENCE_DO_NOT_HANDLE";
+    case OC_STACK_PRESENCE_STOPPED:
+        return "OC_STACK_PRESENCE_STOPPED";
+    #endif
     case OC_STACK_ERROR:
         return "OC_STACK_ERROR";
     default:
index d91046c..aca0d50 100644 (file)
@@ -50,6 +50,9 @@ typedef enum {
     TEST_GET_UNAVAILABLE_RES_REQ_NON,
     TEST_GET_REQ_CON,
     TEST_OBS_REQ_CON,
+    #ifdef WITH_PRESENCE
+    TEST_OBS_PRESENCE,
+    #endif
     MAX_TESTS
 } CLIENT_TEST;
 
@@ -63,8 +66,16 @@ static std::string coapServerResource = "/a/led";
 
 // The handle for the observe registration
 OCDoHandle gObserveDoHandle;
-// After this crosses a threshold client deregisters for further observations
-int gNumNotifies = 1;
+#ifdef WITH_PRESENCE
+// The handle for observe registration
+OCDoHandle gPresenceHandle;
+#endif
+// After this crosses a threshold client deregisters for further notifications
+int gNumObserveNotifies = 1;
+
+#ifdef WITH_PRESENCE
+int gNumPresenceNotifies = 1;
+#endif
 
 int gQuitFlag = 0;
 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
@@ -75,6 +86,10 @@ void handleSigInt(int signum) {
 }
 
 // Forward Declaration
+#ifdef WITH_PRESENCE
+int InitPresence();
+#endif
+
 int InitGetRequestToUnavailableResource();
 int InitObserveRequest(OCQualityOfService qos);
 int InitPutRequest();
@@ -93,6 +108,9 @@ static void PrintUsage()
     OC_LOG(INFO, TAG, "-t 5 : Discover Resources and Initiate Nonconfirmable Get Request for a resource which is unavailable");
     OC_LOG(INFO, TAG, "-t 6 : Discover Resources and Initiate Confirmable Get Request");
     OC_LOG(INFO, TAG, "-t 7 : Discover Resources and Initiate Confirmable Observe Requests");
+    #ifdef WITH_PRESENCE
+    OC_LOG(INFO, TAG, "-t 8 : Discover Resources and Initiate Nonconfirmable presence");
+    #endif
 }
 
 OCStackResult InvokeOCDoResource(std::ostringstream &query,
@@ -117,8 +135,13 @@ OCStackResult InvokeOCDoResource(std::ostringstream &query,
     else if (method == OC_REST_OBSERVE)
     {
         gObserveDoHandle = handle;
-        printf ("Obs handle %016" PRIxPTR "\n", (uintptr_t)gObserveDoHandle);
     }
+    #ifdef WITH_PRESENCE
+    else if (method == OC_REST_PRESENCE)
+    {
+        gPresenceHandle = handle;
+    }
+    #endif
 
     return ret;
 }
@@ -162,10 +185,10 @@ OCStackApplicationResult obsReqCB(void* ctx, OCDoHandle handle, OCClientResponse
     {
         OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
         OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
-        OC_LOG_V(INFO, TAG, "Callback Context for OBSERVE notification recvd successfully %d", gNumNotifies);
+        OC_LOG_V(INFO, TAG, "Callback Context for OBSERVE notification recvd successfully %d", gNumObserveNotifies);
         OC_LOG_V(INFO, TAG, "JSON = %s =============> Obs Response", clientResponse->resJSONPayload);
-        gNumNotifies++;
-        if (gNumNotifies == 3)
+        gNumObserveNotifies++;
+        if (gNumObserveNotifies == 3)
         {
             printf ("************************** CANCEL OBSERVE\n");
             if (OCCancel (gObserveDoHandle) != OC_STACK_OK){
@@ -176,7 +199,32 @@ OCStackApplicationResult obsReqCB(void* ctx, OCDoHandle handle, OCClientResponse
     }
     return OC_STACK_KEEP_TRANSACTION;
 }
+#ifdef WITH_PRESENCE
+OCStackApplicationResult presenceCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse) {
+    if(ctx == (void*)CTX_VAL)
+    {
+        OC_LOG_V(INFO, TAG, "Callback Context for Presence recvd successfully");
+    }
 
+    if(clientResponse)
+    {
+        OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
+        OC_LOG_V(INFO, TAG, "NONCE NUMBER: %d", clientResponse->sequenceNumber);
+        OC_LOG_V(INFO, TAG, "Callback Context for Presence notification recvd successfully %d", gNumPresenceNotifies);
+        OC_LOG_V(INFO, TAG, "JSON = %s =============> Presence Response", clientResponse->resJSONPayload);
+        gNumPresenceNotifies++;
+        if (gNumPresenceNotifies == 15)
+        {
+            printf ("************************** CANCEL PRESENCE\n");
+            if (OCCancel (gPresenceHandle) != OC_STACK_OK){
+                OC_LOG(ERROR, TAG, "Presence cancel error");
+            }
+            return OC_STACK_DELETE_TRANSACTION;
+        }
+    }
+    return OC_STACK_KEEP_TRANSACTION;
+}
+#endif
 
 // This is a function called back when a device is discovered
 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
@@ -223,13 +271,29 @@ OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
         case TEST_OBS_REQ_CON:
             InitObserveRequest(OC_CONFIRMABLE);
             break;
+        #ifdef WITH_PRESENCE
+        case TEST_OBS_PRESENCE:
+            InitPresence();
+            break;
+        #endif
+        default:
+            PrintUsage();
+            break;
         }
     }
 
     return (UNICAST_DISCOVERY) ? OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION ;
 
 }
-
+#ifdef WITH_PRESENCE
+int InitPresence()
+{
+    OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
+    std::ostringstream query;
+    query << "coap://" << coapServerIP << ":" << coapServerPort << OC_PRESENCE_URI;
+    return (InvokeOCDoResource(query, OC_REST_PRESENCE, OC_NON_CONFIRMABLE, presenceCB));
+}
+#endif
 int InitGetRequestToUnavailableResource()
 {
     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
index ed079de..44713c3 100644 (file)
@@ -47,7 +47,7 @@ static std::string putPayload = "{\"state\":\"off\",\"power\":\"0\"}";
 // The handle for the observe registration
 OCDoHandle gObserveDoHandle;
 // After this crosses a threshold client deregisters for further observations
-int gNumNotifies = 1;
+int gNumObserveNotifies = 1;
 
 int gQuitFlag = 0;
 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
@@ -95,10 +95,10 @@ OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse
             OC_LOG_V(INFO, TAG, "Fnd' Rsrc': %s", clientResponse->resJSONPayload);
         }
         else {
-            OC_LOG_V(INFO, TAG, "Callback Context for OBSERVE notification recvd successfully %d", gNumNotifies);
+            OC_LOG_V(INFO, TAG, "Callback Context for OBSERVE notification recvd successfully %d", gNumObserveNotifies);
             OC_LOG_V(INFO, TAG, "Fnd' Rsrc': %s", clientResponse->resJSONPayload);
-            gNumNotifies++;
-            if (gNumNotifies == 3)
+            gNumObserveNotifies++;
+            if (gNumObserveNotifies == 3)
             {
                 if (OCCancel (gObserveDoHandle) != OC_STACK_OK){
                     OC_LOG(ERROR, TAG, "Observe cancel error");
index ec85ac9..873e5ad 100644 (file)
@@ -43,6 +43,10 @@ typedef struct LEDRESOURCE{
 
 static LEDResource LED;
 
+#ifdef WITH_PRESENCE
+static int stopPresenceCount = 10;
+#endif
+
 // TODO: hard coded for now, change after Sprint4
 const char responsePayloadGet[] = "{\"href\":\"/a/led\",\"rep\":{\"state\":\"on\",\"power\":10}}";
 const char responsePayloadPut[] = "{\"href\":\"/a/led\",\"rep\":{\"state\":\"off\",\"power\":0}}";
@@ -106,6 +110,14 @@ void *ChangeLEDRepresentation (void *param)
                 gLEDUnderObservation = 0;
             }
         }
+        #ifdef WITH_PRESENCE
+        OC_LOG_V(INFO, TAG, "================ presence count %d",stopPresenceCount);
+        if(!stopPresenceCount--)
+        {
+            OC_LOG(INFO, TAG, "================ stopping presence");
+            OCStopPresence();
+        }
+        #endif
     }
     return NULL;
 }
@@ -131,7 +143,12 @@ int main() {
         OC_LOG(ERROR, TAG, "OCStack init error");
         return 0;
     }
-
+    #ifdef WITH_PRESENCE
+    if (OCStartPresence(0) != OC_STACK_OK) {
+        OC_LOG_V(ERROR, TAG, "OCStack presence/discovery error");
+        return 0;
+    }
+    #endif
     /*
      * Declare and create the example resource: LED
      */
@@ -150,6 +167,7 @@ int main() {
             OC_LOG(ERROR, TAG, "OCStack process error");
             return 0;
         }
+
         sleep(3);
     }
 
index 12bd1ce..cc4b283 100644 (file)
 /// Module Name
 #define MOD_NAME PCF("occlientcb")
 
-static struct ClientCB *cbList = NULL;
+struct ClientCB *cbList = NULL;
 
-OCStackResult AddClientCB(ClientCB** clientCB, OCCallbackData* cbData, OCCoAPToken * token, OCDoHandle handle, OCMethod method) {
+OCStackResult AddClientCB(ClientCB** clientCB, OCCallbackData* cbData,
+        OCCoAPToken * token, OCDoHandle handle, OCMethod method,
+        unsigned char * requestUri) {
     ClientCB *cbNode;
     cbNode = (ClientCB*) OCMalloc(sizeof(ClientCB));
     if (cbNode) {
@@ -40,6 +42,10 @@ OCStackResult AddClientCB(ClientCB** clientCB, OCCallbackData* cbData, OCCoAPTok
         cbNode->handle = handle;
         cbNode->method = method;
         cbNode->sequenceNumber = 0;
+        #ifdef WITH_PRESENCE
+        cbNode->presence = NULL;
+        #endif
+        cbNode->requestUri = requestUri;
         LL_APPEND(cbList, cbNode);
         *clientCB = cbNode;
         return OC_STACK_OK;
@@ -53,12 +59,17 @@ void DeleteClientCB(ClientCB * cbNode) {
         LL_DELETE(cbList, cbNode);
         OCFree(cbNode->token);
         OCFree(cbNode->handle);
+        OCFree(cbNode->requestUri);
+        #ifdef WITH_PRESENCE
+        OCFree(cbNode->presence->timeOut);
+        OCFree(cbNode->presence);
+        #endif
         OCFree(cbNode);
         cbNode = NULL;
     }
 }
 
-ClientCB* GetClientCB(OCCoAPToken * token, OCDoHandle * handle) {
+ClientCB* GetClientCB(OCCoAPToken * token, OCDoHandle * handle, unsigned char * requestUri) {
     ClientCB* out = NULL;
     if(token) {
         LL_FOREACH(cbList, out) {
@@ -74,6 +85,13 @@ ClientCB* GetClientCB(OCCoAPToken * token, OCDoHandle * handle) {
             }
         }
     }
+    else if(requestUri) {
+        LL_FOREACH(cbList, out) {
+            if(out->requestUri && strcmp((char *)out->requestUri, (char *)requestUri) == 0) {
+                return out;
+            }
+        }
+    }
     OC_LOG(INFO, MOD_NAME, PCF("Callback Not found !!"));
     return NULL;
 }
index 2be77d1..1a9dc42 100644 (file)
@@ -215,7 +215,7 @@ BuildCollectionJSONResponse(OCResource *resource, OCEntityHandlerRequest *ehRequ
             OCResource* temp = resource->rsrcResources[i];
             if (temp)
             {
-                ret = BuildDiscoveryResponse(temp, filterOn, filterValue, (char*)buffer, &remaining);
+                ret = BuildVirtualResourceResponse(temp, filterOn, filterValue, (char*)buffer, &remaining);
                 if (ret != OC_STACK_OK)
                 {
                     break;
index 93687fa..6bea913 100644 (file)
@@ -36,6 +36,7 @@
 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
 
 static struct ResourceObserver * serverObsList = NULL;
+extern uint32_t SERVER_DISCOVERABLE;
 
 OCStackResult OCObserverStatus(OCCoAPToken * token, uint8_t status)
 {
@@ -109,7 +110,7 @@ OCStackResult OCObserverStatus(OCCoAPToken * token, uint8_t status)
 
 OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request)
 {
-    OCStackResult stackRet = OC_STACK_OK;
+    OCStackResult stackRet = OC_STACK_ERROR;
     OCEntityHandlerResult ehRet = OC_EH_ERROR;
     OCEntityHandlerRequest *ehReq = request->entityHandlerRequest;
     OCObserveReq *obs = request->observe;
@@ -164,44 +165,53 @@ OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request)
     return stackRet;
 }
 
-OCStackResult SendObserverNotification (OCResource *resPtr)
+OCStackResult SendObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge)
 {
     uint8_t numObs = 0;
     OCStackResult stackRet = OC_STACK_ERROR;
     OCEntityHandlerResult ehRet = OC_EH_ERROR;
     ResourceObserver *resourceObserver = serverObsList;
     OCEntityHandlerRequest * entityHandlerReq = NULL;
+    unsigned char* jsonPayload = NULL;
     unsigned char bufRes[MAX_RESPONSE_LENGTH] = {0};
     // TODO: we should allow the server application to define qos for each notification
     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 (resourceObserver)
     {
         if (resourceObserver->resource == resPtr)
         {
-            // Invoke the entity handler for the client to process
-            // the query according to the new representation
             numObs++;
-            FormOCEntityHandlerRequest(&entityHandlerReq, OC_REST_GET, bufRes,
-                    NULL, resourceObserver->query);
-            entityHandlerReq->resource = (OCResourceHandle)resPtr;
+            #ifdef WITH_PRESENCE
+            if(method != OC_REST_PRESENCE)
+            {
+            #endif
+                // Invoke the entity handler for the client to process
+                // the query according to the new representation
+                FormOCEntityHandlerRequest(&entityHandlerReq, OC_REST_GET, bufRes,
+                        NULL, resourceObserver->query);
+                entityHandlerReq->resource = (OCResourceHandle)resPtr;
 
-            // Even if entity handler for a resource is not successful
-            // we continue calling entity handler for other resources
-            ehRet = BuildObsJSONResponse((OCResource *) resPtr, entityHandlerReq);
+                // Even if entity handler for a resource is not successful
+                // we continue calling entity handler for other resources
+                //ehRet = resPtr->entityHandler (OC_REQUEST_FLAG, entityHandlerReq);
+                ehRet = BuildObsJSONResponse((OCResource *) resPtr, entityHandlerReq);
+                jsonPayload = (unsigned char *)entityHandlerReq->resJSONPayload;
+            #ifdef WITH_PRESENCE
+            }
+            else
+            {
+                //we know it is the default entity handler
+                OC_LOG(DEBUG, TAG, "This notification is for Presence");
+                ehRet = OC_EH_OK;
+            }
+            #endif
             if (OC_EH_OK == ehRet)
             {
                 stackRet = OC_STACK_OK;
                 OC_LOG_V(INFO, TAG, "OCStack payload: %s",
-                        entityHandlerReq->resJSONPayload);
+                        jsonPayload);
 
                 // send notifications based on the qos of the request
                 qos = resourceObserver->qos;
@@ -209,8 +219,14 @@ OCStackResult SendObserverNotification (OCResource *resPtr)
                 {
                     OC_LOG_V(INFO, TAG, "Current NON count for this observer is %d",
                             resourceObserver->NONCount);
-                    if(resourceObserver->forceCON ||
-                            resourceObserver->NONCount >= MAX_OBSERVER_NON_COUNT)
+                    #ifdef WITH_PRESENCE
+                    if((resourceObserver->forceCON \
+                            || resourceObserver->NONCount >= MAX_OBSERVER_NON_COUNT) \
+                            && method != OC_REST_PRESENCE)
+                    #else
+                    if(resourceObserver->forceCON \
+                            || resourceObserver->NONCount >= MAX_OBSERVER_NON_COUNT)
+                    #endif
                     {
                         resourceObserver->NONCount = 0;
                         // at some point we have to to send CON to check on the
@@ -224,11 +240,10 @@ OCStackResult SendObserverNotification (OCResource *resPtr)
                         resourceObserver->NONCount++;
                     }
                 }
-
-                OCSendCoAPNotification(resourceObserver->addr, stackRet, qos,
+                OCSendCoAPNotification(resourceObserver->resUri, resourceObserver->addr,
+                        stackRet, qos,
                         resourceObserver->token,
-                        (unsigned char *)entityHandlerReq->resJSONPayload,
-                        resPtr->sequenceNum);
+                        jsonPayload, resPtr->sequenceNum, maxAge);
             }
             else
             {
@@ -258,13 +273,16 @@ OCStackResult AddObserver (const char   *resUri,
     obsNode = (ResourceObserver *) OCMalloc(sizeof(ResourceObserver));
     if (obsNode)
     {
-        obsNode->resUri = (unsigned char *)OCMalloc(sizeof(strlen(resUri)+1));
+        obsNode->resUri = (unsigned char *)OCMalloc(strlen(resUri)+1);
         VERIFY_NON_NULL (obsNode->resUri);
+        memcpy (obsNode->resUri, resUri, strlen(resUri)+1);
         obsNode->qos = qos;
-        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));
+        if(query)
+        {
+            obsNode->query = (unsigned char *)OCMalloc(strlen(query)+1);
+            VERIFY_NON_NULL (obsNode->query);
+            memcpy (obsNode->query, query, strlen(query)+1);
+        }
         obsNode->token = (OCCoAPToken *)OCMalloc(sizeof(OCCoAPToken));
         VERIFY_NON_NULL (obsNode->token);
         tokPtr = obsNode->token;
index a498798..34c2dd4 100644 (file)
@@ -40,6 +40,9 @@ static const char * VIRTUAL_RSRCS[] = {
        "/oc/core",
        "/oc/core/d",
        "/oc/core/types/d",
+       #ifdef WITH_PRESENCE
+       "/oc/presence"
+       #endif
 };
 
 //-----------------------------------------------------------------------------
@@ -81,7 +84,15 @@ static OCStackResult ValidateUrlQuery (unsigned char *url, unsigned char *query,
                 return OC_STACK_INVALID_QUERY;
             }
         }
-    } else {
+    }
+    #ifdef WITH_PRESENCE
+    else if (strcmp((char *)url, GetVirtualResourceUri(OC_PRESENCE)) == 0) {
+        //Nothing needs to be done, except for pass a OC_PRESENCE query through as OC_STACK_OK.
+        OC_LOG(INFO, TAG, "OC_PRESENCE Request!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+        *filterOn = STACK_RES_DISCOVERY_NOFILTER;
+    }
+    #endif
+    else {
         // Other URIs not yet supported
         return OC_STACK_INVALID_URI;
     }
@@ -89,9 +100,8 @@ static OCStackResult ValidateUrlQuery (unsigned char *url, unsigned char *query,
     return OC_STACK_OK;
 }
 
-
-OCStackResult BuildDiscoveryResponse(OCResource *resourcePtr, uint8_t filterOn,
-                            char *filterValue, char * out, uint16_t *remaining)
+OCStackResult BuildVirtualResourceResponse(OCResource *resourcePtr, uint8_t filterOn,
+                                            char *filterValue, char * out, uint16_t *remaining)
 {
     OCResourceType *resourceTypePtr;
     OCResourceInterface *interfacePtr;
@@ -101,7 +111,7 @@ OCStackResult BuildDiscoveryResponse(OCResource *resourcePtr, uint8_t filterOn,
     OCStackResult ret = OC_STACK_OK;
     uint16_t jsonLen;
 
-    OC_LOG(INFO, TAG, PCF("Entering BuildDiscoveryResponse"));
+    OC_LOG(INFO, TAG, PCF("Entering BuildVirtualResourceResponse"));
     resObj = cJSON_CreateObject();
 
     if (resourcePtr)
@@ -175,11 +185,10 @@ OCStackResult BuildDiscoveryResponse(OCResource *resourcePtr, uint8_t filterOn,
     free (jsonStr);
 
 
-    OC_LOG(INFO, TAG, PCF("Exiting BuildDiscoveryResponse"));
+    OC_LOG(INFO, TAG, PCF("Exiting BuildVirtualResourceResponse"));
     return ret;
 }
 
-
 OCEntityHandlerResult
 BuildObsJSONResponse(OCResource *resource, OCEntityHandlerRequest *ehRequest)
 {
@@ -317,11 +326,11 @@ OCStackResult DetermineResourceHandling (OCRequest *request,
 static OCStackResult
 HandleVirtualResource (OCRequest *request, OCResource* resource)
 {
-    OCStackResult result;
+    OCStackResult result = OC_STACK_ERROR;
     char *filterValue = NULL;
-    uint8_t filterOn;
-    uint16_t remaining;
-    unsigned char *buffer;
+    uint8_t filterOn = 0;
+    uint16_t remaining = 0;
+    unsigned char *buffer = NULL;
 
     OC_LOG(INFO, TAG, PCF("Entering HandleVirtualResource"));
 
@@ -331,25 +340,41 @@ HandleVirtualResource (OCRequest *request, OCResource* resource)
 
     if (result == OC_STACK_OK)
     {
-        remaining = request->entityHandlerRequest->resJSONPayloadLen;
-        buffer = request->entityHandlerRequest->resJSONPayload;
-        while( resource)
+        if (strcmp ((char *)request->resourceUrl, GetVirtualResourceUri(OC_WELL_KNOWN_URI)) == 0)
         {
-            result = BuildDiscoveryResponse(resource, filterOn, filterValue,
-                                            (char*)buffer, &remaining);
-            if (result != OC_STACK_OK)
+            remaining = request->entityHandlerRequest->resJSONPayloadLen;
+            buffer = request->entityHandlerRequest->resJSONPayload;
+            while(resource)
             {
-                break;
+                if((resource->resourceProperties & OC_ACTIVE)
+                        && (resource->resourceProperties & OC_DISCOVERABLE))
+                {
+                    result = BuildVirtualResourceResponse(resource, filterOn, filterValue,
+                            (char*)buffer, &remaining);
+                    if (result != OC_STACK_OK)
+                    {
+                        break;
+                    }
+                    buffer += strlen((char*)buffer);
+                    if ( resource->next && remaining >= (sizeof(OC_JSON_SEPARATOR) + 1) )
+                    {
+                        *buffer = OC_JSON_SEPARATOR;
+                        buffer++;
+                        remaining--;
+                    }
+                }
+                resource = resource->next;
             }
-            buffer += strlen((char*)buffer);
-            if ( resource->next && remaining >= (sizeof(OC_JSON_SEPARATOR) + 1) )
-            {
-                *buffer = OC_JSON_SEPARATOR;
-                buffer++;
-                remaining--;
+        }
+        #ifdef WITH_PRESENCE
+        else
+        {
+            if(resource->resourceProperties & OC_ACTIVE){
+                OCNotifyObservers((OCResourceHandle) resource);
             }
-            resource = resource->next;
+            result = OC_STACK_PRESENCE_DO_NOT_HANDLE;
         }
+        #endif
     }
 
     if (result == OC_STACK_OK)
index f670ccf..06db083 100644 (file)
@@ -43,6 +43,12 @@ typedef enum {
 //-----------------------------------------------------------------------------
 static OCStackState stackState = OC_STACK_UNINITIALIZED;
 OCResource *headResource = NULL;
+#ifdef WITH_PRESENCE
+static PresenceResource presenceResource;
+uint8_t PresenceTimeOutSize = 4;
+uint32_t PresenceTimeOut[] = {50, 75, 85, 95, 100};
+#endif
+OCMode myStackMode;
 
 //-----------------------------------------------------------------------------
 // Macros
@@ -83,25 +89,34 @@ void HandleStackResponses(OCResponse * response)
     OCStackApplicationResult result = OC_STACK_DELETE_TRANSACTION;
     OC_LOG(INFO, TAG, PCF("Entering HandleStackResponses (OCStack Layer)"));
 
+    //ToDo: if ttl is zero, we should notify the client!!!!
     if (response->cbNode)
     {
         OC_LOG(INFO, TAG, PCF("Calling into application address space"));
         result = response->cbNode->callBack(response->cbNode->context,
                 response->cbNode->handle, response->clientResponse);
+        #ifdef WITH_PRESENCE
+        if (result == OC_STACK_DELETE_TRANSACTION ||
+                response->clientResponse->result == OC_STACK_COMM_ERROR ||
+                response->clientResponse->result == OC_STACK_PRESENCE_STOPPED)
+        #else
         if (result == OC_STACK_DELETE_TRANSACTION ||
                 response->clientResponse->result == OC_STACK_COMM_ERROR)
+        #endif
         {
             FindAndDeleteClientCB(response->cbNode);
         }
     }
 }
 
-int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr)
+int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr, uint16_t * port)
 {
     size_t index = 0;
     unsigned char *itr, *coap;
     uint8_t dotCount = 0;
 
+    ipAddr[index] = 0;
+    *port = 0;
     /* search for scheme */
     itr = ipAddrStr;
     if (!isdigit((unsigned char) *ipAddrStr))
@@ -125,6 +140,7 @@ int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr)
         {
             index++;
             dotCount++;
+            ipAddr[index] = 0;
         }
         else
         {
@@ -132,6 +148,23 @@ int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr)
         }
         ipAddrStr++;
     }
+    if(*ipAddrStr == ':')
+    {
+        ipAddrStr++;
+        while (*ipAddrStr){
+            if (isdigit((unsigned char) *ipAddrStr))
+            {
+                *port *= 10;
+                *port += *ipAddrStr - '0';
+            }
+            else
+            {
+                break;
+            }
+            ipAddrStr++;
+        }
+    }
+
 
     if (ipAddr[0] < 255 && ipAddr[1] < 255 && ipAddr[2] < 255 && ipAddr[3] < 255
             && dotCount == 3)
@@ -143,12 +176,29 @@ int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr)
         return 0;
     }
 }
+
+#ifdef PRESENCE_NOTIFICATION
+OCStackResult sendPresenceNotification()
+{
+    OCStackResult result = OC_STACK_ERROR;
+    if(SERVER_DISCOVERABLE == 1)
+    {
+        result = SendObserverNotification(presenceResource, OC_REST_PRESENCE);
+    }
+    else
+    {
+        result = OC_STACK_OK;
+    }
+    return result;
+}
+#endif
+
 //-----------------------------------------------------------------------------
 // Private internal function prototypes
 //-----------------------------------------------------------------------------
 
 static OCDoHandle GenerateInvocationHandle();
-static void initResources();
+static OCStackResult initResources();
 static void insertResource(OCResource *resource);
 static OCResource *findResource(OCResource *resource);
 static void insertResourceType(OCResource *resource,
@@ -164,6 +214,7 @@ static void deleteResourceInterface(OCResourceInterface *resourceInterface);
 static void deleteResourceElements(OCResource *resource);
 static int deleteResource(OCResource *resource);
 static void deleteAllResources();
+static void incrementSequenceNumber(OCResource * resPtr);
 
 
 //-----------------------------------------------------------------------------
@@ -186,6 +237,7 @@ static void deleteAllResources();
  */
 OCStackResult OCInit(const char *ipAddr, uint16_t port, OCMode mode)
 {
+    OCStackResult result = OC_STACK_ERROR;
     OC_LOG(INFO, TAG, PCF("Entering OCInit"));
 
     if (ipAddr)
@@ -209,19 +261,23 @@ OCStackResult OCInit(const char *ipAddr, uint16_t port, OCMode mode)
         return OC_STACK_ERROR;
         break;
     }
-
-    // Initialize resource
-    initResources();
-
+    myStackMode = mode;
     // Make call to OCCoAP layer
-    if (OCInitCoAP(ipAddr, (uint16_t) port, mode) == OC_STACK_OK)
+    result = OCInitCoAP(ipAddr, (uint16_t) port, myStackMode);
+    if (result == OC_STACK_OK)
     {
         stackState = OC_STACK_INITIALIZED;
-        return OC_STACK_OK;
     }
-
-    OC_LOG(ERROR, TAG, PCF("Stack initialization error"));
-    return OC_STACK_ERROR;
+    // Initialize resource
+    if(result == OC_STACK_OK && myStackMode != OC_CLIENT)
+    {
+        result = initResources();
+    }
+    if(result != OC_STACK_OK)
+    {
+        OC_LOG(ERROR, TAG, PCF("Stack initialization error"));
+    }
+    return result;
 }
 
 /**
@@ -291,6 +347,7 @@ OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requ
     OCStackResult result = OC_STACK_ERROR;
     OCCoAPToken * token = NULL;
     ClientCB *clientCB = NULL;
+    unsigned char * requestUri = NULL;
     (void) referenceUri;
 
     OC_LOG(INFO, TAG, PCF("Entering OCDoResource"));
@@ -310,6 +367,17 @@ OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requ
         case OC_REST_OBSERVE:
         case OC_REST_OBSERVE_ALL:
             break;
+        #ifdef WITH_PRESENCE
+        case OC_REST_PRESENCE:
+            requestUri = (unsigned char *) OCMalloc(strlen(requiredUri) + 1);
+            if(requestUri){
+                memcpy(requestUri, requiredUri, strlen(requiredUri) + 1);
+            }else{
+                result = OC_STACK_NO_MEMORY;
+                goto exit;
+            }
+            break;
+        #endif
         default:
             result = OC_STACK_INVALID_METHOD;
             goto exit;
@@ -331,14 +399,14 @@ OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requ
         OCFree(token);
         goto exit;
     }
-    if((result = AddClientCB(&clientCB, cbData, token, *handle, method)) != OC_STACK_OK)
+    if((result = AddClientCB(&clientCB, cbData, token, *handle, method, requestUri)) != OC_STACK_OK)
     {
         result = OC_STACK_NO_MEMORY;
         goto exit;
     }
 
     // Make call to OCCoAP layer
-    result = (OCStackResult)OCDoCoAPResource(method, qos, token, requiredUri, request);
+    result = OCDoCoAPResource(method, qos, token, requiredUri, request);
 
 exit:
     if (result != OC_STACK_OK)
@@ -378,13 +446,16 @@ OCStackResult OCCancel(OCDoHandle handle) {
 
     OC_LOG(INFO, TAG, PCF("Entering OCCancel"));
 
-    ClientCB *clientCB = GetClientCB(NULL, &handle);
+    ClientCB *clientCB = GetClientCB(NULL, &handle, NULL);
 
     if(clientCB) {
         switch (clientCB->method)
         {
             case OC_REST_OBSERVE:
             case OC_REST_OBSERVE_ALL:
+            #ifdef WITH_PRESENCE
+            case OC_REST_PRESENCE:
+            #endif
                 FindAndDeleteClientCB(clientCB);
                 break;
             default:
@@ -393,6 +464,83 @@ OCStackResult OCCancel(OCDoHandle handle) {
     }
     return OC_STACK_OK;
 }
+#ifdef WITH_PRESENCE
+OCStackResult OCProcessPresence()
+{
+    OCStackResult result = OC_STACK_ERROR;
+    uint8_t ipAddr[4] = { 0 };
+    uint16_t port = 0;
+
+    OC_LOG(INFO, TAG, PCF("Entering RequestPresence"));
+    ClientCB* cbNode = NULL;
+    OCDevAddr dst;
+    OCClientResponse * clientResponse = NULL;
+    OCResponse * response = NULL;
+
+    LL_FOREACH(cbList, cbNode) {
+        if(OC_REST_PRESENCE == cbNode->method)
+        {
+            if(cbNode->presence)
+            {
+                uint32_t now = GetTime(0);
+                OC_LOG_V(DEBUG, TAG, "----------------this TTL level %d", cbNode->presence->TTLlevel);
+                OC_LOG_V(DEBUG, TAG, "----------------current ticks %d", now);
+                if(cbNode->presence->TTLlevel != PresenceTimeOutSize){
+                    OC_LOG_V(DEBUG, TAG, "----------------timeout ticks %d",
+                            cbNode->presence->timeOut[cbNode->presence->TTLlevel]);
+                }
+                if(cbNode->presence->TTLlevel == PresenceTimeOutSize)
+                {
+                    OC_LOG(DEBUG, TAG, "----------------No more timeout ticks");
+                    if (ParseIPv4Address( cbNode->requestUri, ipAddr, &port))
+                    {
+                        OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], port,
+                                &dst);
+                        result = FormOCClientResponse(&clientResponse, OC_STACK_PRESENCE_STOPPED,
+                                (OCDevAddr *) &dst, 0, NULL);
+                        if(result != OC_STACK_OK)
+                        {
+                            goto exit;
+                        }
+                        result = FormOCResponse(&response, cbNode, 0, clientResponse);
+                        if(result != OC_STACK_OK)
+                        {
+                            goto exit;
+                        }
+                    }
+                    else
+                    {
+                        goto exit;
+                    }
+                    HandleStackResponses(response);
+                }
+                if(now >= cbNode->presence->timeOut[cbNode->presence->TTLlevel])
+                {
+                    OC_LOG(DEBUG, TAG, "time to test server presence ==========");
+                    OCCoAPToken * token = NULL;
+                    token = OCGenerateCoAPToken();
+                    if (!token)
+                    {
+                        result = OC_STACK_NO_MEMORY;
+                        OCFree(token);
+                        goto exit;
+                    }
+                    result = OCDoCoAPResource(OC_REST_GET, OC_NON_CONFIRMABLE,
+                            token, (const char *)cbNode->requestUri, NULL);
+                    cbNode->presence->TTLlevel++;
+                    OC_LOG_V(DEBUG, TAG, "----------------moving to TTL level %d", cbNode->presence->TTLlevel);
+                }
+            }
+        }
+    }
+exit:
+    if (result != OC_STACK_OK)
+    {
+        OC_LOG(ERROR, TAG, PCF("OCProcessPresence error"));
+    }
+    return result;
+}
+#endif
 
 /**
  * Called in main loop of OC client or server.  Allows low-level processing of
@@ -405,10 +553,72 @@ OCStackResult OCCancel(OCDoHandle handle) {
 OCStackResult OCProcess() {
 
     OC_LOG(INFO, TAG, PCF("Entering OCProcess"));
+    #ifdef WITH_PRESENCE
+    OCProcessPresence();
+    #endif
     OCProcessCoAP();
 
     return OC_STACK_OK;
 }
+
+#ifdef WITH_PRESENCE
+/**
+ * When operating in @ref OCServer or @ref OCClientServer mode, this API will start sending out
+ * presence notifications to clients via multicast. Once this API has been called with a success,
+ * clients may query for this server's presence and this server's stack will respond via multicast.
+ *
+ * @param ttl (Time To Live in seconds) - Used to set the time a server
+ * Note: If ttl is '0', then the default stack value will be used (60 Seconds).
+ *
+ * @return
+ *     OC_STACK_OK      - No errors; Success
+ *     OC_STACK_ERROR   - @ref OCStartPresence has already been called.
+ */
+OCStackResult OCStartPresence(const uint32_t ttl)
+{
+    if(((OCResource *)presenceResource.handle)->resourceProperties & OC_ACTIVE)
+    {
+        return OC_STACK_ERROR;
+    }
+    OCChangeResourceProperty(
+            &(((OCResource *)presenceResource.handle)->resourceProperties),
+            OC_ACTIVE, 1);
+    if(ttl > 0)
+    {
+        presenceResource.presenceTTL = ttl;
+    }
+    OCDevAddr multiCastAddr = {0};
+    OCCoAPToken * token = OCGenerateCoAPToken();
+    OCBuildIPv4Address(224, 0, 1, 187, 5683, &multiCastAddr);
+    //add the presence observer
+    AddObserver(OC_PRESENCE_URI, NULL, token, &multiCastAddr,
+            (OCResource *)presenceResource.handle, OC_NON_CONFIRMABLE);
+
+    return OCNotifyObservers(presenceResource.handle);
+}
+
+/**
+ * When operating in @ref OCServer or @ref OCClientServer mode, this API will stop sending out
+ * presence notifications to clients via multicast. Once this API has been called with a success,
+ * this server's stack will not respond to clients querying for this server's presence.
+ *
+ * @return
+ *     OC_STACK_OK      - No errors; Success
+ *     OC_STACK_ERROR   - @ref OCStartPresence has never been called or @ref OCStopPresence has
+ *                        already been called.
+ */
+OCStackResult OCStopPresence()
+{
+    OCStackResult result = OC_STACK_ERROR;
+    //make resource inactive
+    result = OCChangeResourceProperty(
+            &(((OCResource *) presenceResource.handle)->resourceProperties),
+            OC_ACTIVE, 0);
+    result = OCNotifyObservers(presenceResource.handle);
+    return result;
+}
+#endif
+
 /**
  * Create a resource
  *
@@ -437,6 +647,10 @@ OCStackResult OCCreateResource(OCResourceHandle *handle,
 
     OC_LOG(INFO, TAG, PCF("Entering OCCreateResource"));
 
+    if(myStackMode == OC_CLIENT)
+    {
+        return result;
+    }
     // Validate parameters
     // Is it presented during resource discovery?
     if (!handle || !resourceTypeName || !resourceInterfaceName || !uri) {
@@ -516,6 +730,10 @@ OCStackResult OCCreateResource(OCResourceHandle *handle,
     *handle = pointer;
     result = OC_STACK_OK;
 
+    #ifdef WITH_PRESENCE
+    incrementSequenceNumber((OCResource *)presenceResource.handle);
+    OCNotifyObservers(presenceResource.handle);
+    #endif
 exit:
     if (result != OC_STACK_OK)
     {
@@ -676,9 +894,7 @@ OCStackResult OCBindResourceTypeToResource(OCResourceHandle handle,
     strncpy(str, resourceTypeName, size);
     pointer->resourcetypename = str;
 
-   // Bind the resourcetype to the resource
     insertResourceType(resource, pointer);
-
     result = OC_STACK_OK;
 
     exit: if (result != OC_STACK_OK) {
@@ -925,7 +1141,6 @@ const char *OCGetResourceTypeName(OCResourceHandle handle, uint8_t index) {
  * @return
  *     OC_STACK_OK    - no errors
  *     OC_STACK_ERROR - stack process error
-
  */
 OCStackResult OCGetNumberOfResourceInterfaces(OCResourceHandle handle,
         uint8_t *numResourceInterfaces) {
@@ -1056,6 +1271,17 @@ OCEntityHandler OCGetResourceHandler(OCResourceHandle handle) {
     return resource->entityHandler;
 }
 
+void incrementSequenceNumber(OCResource * resPtr)
+{
+    // Increment the sequence number
+    resPtr->sequenceNum += 1;
+    if (resPtr->sequenceNum == MAX_SEQUENCE_NUMBER)
+    {
+        resPtr->sequenceNum = 1;
+    }
+    return;
+}
+
 /**
  * Notify observers that an observed value has changed.
  *
@@ -1069,6 +1295,8 @@ OCEntityHandler OCGetResourceHandler(OCResourceHandle handle) {
 OCStackResult OCNotifyObservers(OCResourceHandle handle) {
     OCResource *resPtr = NULL;
     OCStackResult result;
+    OCMethod method = OC_REST_NOMETHOD;
+    uint32_t maxAge = 0;
 
     OC_LOG(INFO, TAG, PCF("Entering OCNotifyObservers"));
 
@@ -1076,11 +1304,35 @@ OCStackResult OCNotifyObservers(OCResourceHandle handle) {
 
     // Verify that the resource exists
     resPtr = findResource ((OCResource *) handle);
-    if (NULL == resPtr)
+    if (NULL == resPtr || myStackMode == OC_CLIENT)
     {
         return OC_STACK_NO_RESOURCE;
     } else {
-        result = SendObserverNotification (resPtr);
+        #ifdef WITH_PRESENCE
+        if(strcmp(resPtr->uri, OC_PRESENCE_URI))
+        {
+        #endif
+            //only increment in the case of regular observing (not presence)
+            incrementSequenceNumber(resPtr);
+            method = OC_REST_OBSERVE;
+            maxAge = 0x2FFFF;
+        #ifdef WITH_PRESENCE
+        }
+        else
+        {
+            method = OC_REST_PRESENCE;
+            if((((OCResource *) presenceResource.handle)->resourceProperties) & OC_ACTIVE)
+            {
+                maxAge = presenceResource.presenceTTL;
+            }
+            else
+            {
+                maxAge = 0;
+            }
+
+        }
+        #endif
+        result = SendObserverNotification (method, resPtr, maxAge);
         return result;
     }
 }
@@ -1103,14 +1355,50 @@ static OCDoHandle GenerateInvocationHandle()
 
     return handle;
 }
+#ifdef WITH_PRESENCE
+OCStackResult OCChangeResourceProperty(OCResourceProperty * inputProperty,
+        OCResourceProperty resourceProperties, uint8_t enable)
+{
+    if (resourceProperties
+            > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW)) {
+        OC_LOG(ERROR, TAG, PCF("Invalid property"));
+        return OC_STACK_INVALID_PARAM;
+    }
+    if(!enable)
+    {
+        *inputProperty = *inputProperty & ~(resourceProperties);
+    }
+    else
+    {
+        *inputProperty = *inputProperty | resourceProperties;
+    }
+    return OC_STACK_OK;
+}
+#endif
 
 /**
  * Initialize resource data structures, variables, etc.
  */
-void initResources() {
-    TODO ("Do we need to create a resource for /oc/core???");
-    // Init resource vars
+OCStackResult initResources() {
+    OCStackResult result = OC_STACK_OK;
+    // Init application resource vars
     headResource = NULL;
+    // Init Virtual Resources
+    #ifdef WITH_PRESENCE
+    presenceResource.presenceTTL = OC_DEFAULT_PRESENCE_TTL;
+    //presenceResource.token = OCGenerateCoAPToken();
+    result = OCCreateResource(&presenceResource.handle,
+            "core.presence",
+            "core.r",
+            OC_PRESENCE_URI,
+            NULL,
+            OC_OBSERVABLE);
+    //make resource inactive
+    result = OCChangeResourceProperty(
+            &(((OCResource *) presenceResource.handle)->resourceProperties),
+            OC_ACTIVE, 0);
+    #endif
+    return result;
 }
 
 /**