Implement slow response feature.
[platform/upstream/iotivity.git] / resource / csdk / occoap / src / occoap.c
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21
22 //=============================================================================
23 // Includes
24 //=============================================================================
25 #include "occoap.h"
26 #include "ocstackconfig.h"
27 #include "occlientcb.h"
28 #include "ocobserve.h"
29 #include "logger.h"
30 #include "ocmalloc.h"
31 #include <coap.h>
32
33 #ifndef WITH_ARDUINO
34 #include <unistd.h>
35 #endif
36 #include <limits.h>
37 #include <ctype.h>
38
39 //=============================================================================
40 // Macros
41 //=============================================================================
42 #define TAG    PCF("OCCoAP")
43 #define VERIFY_SUCCESS(op, successCode) { if (op != successCode) \
44             {OC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
45 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG_V(FATAL, TAG, "%s is NULL", #arg); goto exit;} }
46
47 //=============================================================================
48 // Defines
49 //=============================================================================
50 #define COAP_BLOCK_FILL_VALUE   (0xFF)
51
52 //=============================================================================
53 // Private Variables
54 //=============================================================================
55
56 static uint8_t coapWKIpAddr[] = { 224, 0, 1, 187 };
57 static coap_context_t *gCoAPCtx = NULL;
58
59 //=============================================================================
60 // Helper Functions
61 //=============================================================================
62
63 //generate a coap token
64 void OCGenerateCoAPToken(OCCoAPToken * token)
65 {
66     if (token)
67     {
68         token->tokenLength = MAX_TOKEN_LENGTH;
69         OCFillRandomMem((uint8_t*)token->token, token->tokenLength);
70     }
71 }
72
73 //This function is called back by libcoap when ack or rst are received
74 static void HandleCoAPAckRst(struct coap_context_t * ctx, uint8_t msgType,
75         const coap_queue_t * sentQueue){
76
77     // silence warnings
78     (void) ctx;
79     coap_pdu_t * sentPdu = sentQueue->pdu;
80     OCStackResult result = OC_STACK_ERROR;
81     uint32_t observationOption = OC_OBSERVE_NO_OPTION;
82     // {{0}} to eliminate warning for known compiler bug 53119
83     // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119
84     OCCoAPToken sentToken = {{0}};
85
86     result = ParseCoAPPdu(sentPdu, NULL, NULL, &observationOption, NULL, NULL, NULL,
87             NULL, NULL, NULL, NULL, NULL);
88     VERIFY_SUCCESS(result, OC_STACK_OK);
89
90     // fill OCCoAPToken structure
91     RetrieveOCCoAPToken(sentPdu, &sentToken);
92
93     if(msgType == COAP_MESSAGE_RST)
94     {
95         if(myStackMode != OC_CLIENT)
96         {
97             result = OCStackFeedBack(&sentToken, OC_OBSERVER_NOT_INTERESTED);
98             if(result == OC_STACK_OK)
99             {
100                 OC_LOG_V(DEBUG, TAG,
101                         "Received RST, removing all queues associated with Token %d bytes",
102                         sentToken.tokenLength);
103                 OC_LOG_BUFFER(INFO, TAG, sentToken.token, sentToken.tokenLength);
104                 coap_cancel_all_messages(ctx, &sentQueue->remote, sentToken.token,
105                         sentToken.tokenLength);
106             }
107         }
108     }
109     else if(observationOption != OC_OBSERVE_NO_OPTION && msgType == COAP_MESSAGE_ACK)
110     {
111         OC_LOG_V(DEBUG, TAG, "Received ACK, for Token %d bytes",sentToken.tokenLength);
112         OC_LOG_BUFFER(INFO, TAG, sentToken.token, sentToken.tokenLength);
113         // now the observer is still interested
114         if(myStackMode != OC_CLIENT)
115         {
116             OCStackFeedBack(&sentToken, OC_OBSERVER_STILL_INTERESTED);
117         }
118     }
119 exit:
120     return;
121 }
122
123 //This function is called back by libcoap when a request is received
124 static void HandleCoAPRequests(struct coap_context_t *ctx,
125         const coap_queue_t * rcvdRequest)
126 {
127     // silence warnings
128     (void) ctx;
129     OCServerProtocolRequest protocolRequest;
130     memset(&protocolRequest, 0, sizeof(OCServerProtocolRequest));
131     coap_block_t rcvdBlock1;
132     coap_block_t rcvdBlock2;
133     memset(&rcvdBlock1, COAP_BLOCK_FILL_VALUE, sizeof(coap_block_t));
134     memset(&rcvdBlock2, COAP_BLOCK_FILL_VALUE, sizeof(coap_block_t));
135     uint16_t rcvdSize1 = 0;
136     coap_pdu_t * rcvdPdu = rcvdRequest->pdu;
137     coap_pdu_t * sendPdu = NULL;
138     coap_send_flags_t sendFlag;
139     OCStackResult result = OC_STACK_ERROR;
140     OCStackResult requestResult = OC_STACK_ERROR;
141
142     if(myStackMode == OC_CLIENT)
143     {
144         //TODO: should the client be responding to requests?
145         return;
146     }
147
148     protocolRequest.observationOption = OC_OBSERVE_NO_OPTION;
149     protocolRequest.qos = (rcvdPdu->hdr->type == COAP_MESSAGE_CON) ?
150             OC_HIGH_QOS : OC_LOW_QOS;
151     protocolRequest.coapID = rcvdPdu->hdr->id;
152     protocolRequest.delayedResNeeded = rcvdRequest->delayedResNeeded;
153     protocolRequest.secured = rcvdRequest->secure;
154
155     // fill OCCoAPToken structure
156     RetrieveOCCoAPToken(rcvdPdu, &protocolRequest.requestToken);
157     OC_LOG_V(INFO, TAG, " Token received %d bytes",
158             protocolRequest.requestToken.tokenLength);
159     OC_LOG_BUFFER(INFO, TAG, protocolRequest.requestToken.token,
160             protocolRequest.requestToken.tokenLength);
161
162     // fill OCDevAddr
163     memcpy(&protocolRequest.requesterAddr, (OCDevAddr *) &rcvdRequest->remote,
164             sizeof(OCDevAddr));
165
166     // Retrieve Uri and Query from received coap pdu
167     result =  ParseCoAPPdu(rcvdPdu, protocolRequest.resourceUrl,
168             protocolRequest.query,
169             &(protocolRequest.observationOption), NULL,
170             &(protocolRequest.numRcvdVendorSpecificHeaderOptions),
171             protocolRequest.rcvdVendorSpecificHeaderOptions,
172             &rcvdBlock1, &rcvdBlock2, &rcvdSize1, NULL,
173             protocolRequest.reqJSONPayload);
174     VERIFY_SUCCESS(result, OC_STACK_OK);
175
176     switch (rcvdPdu->hdr->code)
177     {
178         case COAP_REQUEST_GET:
179         {
180             protocolRequest.method = OC_REST_GET;
181             break;
182         }
183         case COAP_REQUEST_POST:
184         {
185             protocolRequest.method = OC_REST_POST;
186             break;
187         }
188         case COAP_REQUEST_DELETE:
189         {
190             protocolRequest.method = OC_REST_DELETE;
191             break;
192         }
193         case COAP_REQUEST_PUT:
194         {
195             protocolRequest.method = OC_REST_PUT;
196             break;
197         }
198         default:
199         {
200             OC_LOG_V(ERROR, TAG, "Received CoAP method %d not supported",
201                     rcvdPdu->hdr->code);
202             goto exit;
203         }
204     }
205
206     if(rcvdBlock1.szx != 7)
207     {
208         protocolRequest.reqPacketSize = 1 << (rcvdBlock1.szx + 4);
209         protocolRequest.reqMorePacket = rcvdBlock1.m;
210         protocolRequest.reqPacketNum  = rcvdBlock1.num;
211     }
212     else
213     {
214         // No block1 received
215         rcvdSize1 = strlen((const char *)protocolRequest.reqJSONPayload)+1;
216         protocolRequest.reqTotalSize = rcvdSize1;
217     }
218
219     if(rcvdBlock2.szx != 7)
220     {
221         protocolRequest.resPacketSize = 1 << (rcvdBlock2.szx + 4);
222         protocolRequest.resPacketNum  = rcvdBlock2.num;
223     }
224
225     requestResult = HandleStackRequests(&protocolRequest);
226
227     if(requestResult == OC_STACK_VIRTUAL_DO_NOT_HANDLE ||
228             requestResult == OC_STACK_OK ||
229             requestResult == OC_STACK_RESOURCE_CREATED ||
230             requestResult == OC_STACK_RESOURCE_DELETED)
231     {
232         goto exit;
233     }
234     else if(requestResult == OC_STACK_NO_MEMORY ||
235             requestResult == OC_STACK_ERROR ||
236             requestResult == OC_STACK_NOTIMPL ||
237             requestResult == OC_STACK_NO_RESOURCE ||
238             requestResult == OC_STACK_RESOURCE_ERROR)
239     {
240         // TODO: should we send an error also when we receive a non-secured request to a secure resource?
241         // TODO: should we consider some sort of error response
242         OC_LOG(DEBUG, TAG, PCF("We should send some sort of error message"));
243         // generate the pdu, if the request was CON, then the response is ACK, otherwire NON
244         sendPdu = GenerateCoAPPdu((rcvdPdu->hdr->type == COAP_MESSAGE_CON)? COAP_MESSAGE_ACK : COAP_MESSAGE_NON,
245                 OCToCoAPResponseCode(requestResult), rcvdPdu->hdr->id,
246                 &protocolRequest.requestToken, NULL, NULL);
247         VERIFY_NON_NULL(sendPdu);
248         coap_show_pdu(sendPdu);
249         sendFlag = (coap_send_flags_t)(rcvdRequest->secure ? SEND_SECURE_PORT : 0);
250         if(SendCoAPPdu(gCoAPCtx, (coap_address_t*) &(rcvdRequest->remote), sendPdu,
251                 sendFlag)
252                 != OC_STACK_OK){
253             OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu"));
254         }
255         goto exit;
256     }
257     else if(requestResult == OC_STACK_SLOW_RESOURCE)
258     {
259         if(rcvdPdu->hdr->type == COAP_MESSAGE_CON)
260         {
261             // generate the pdu, if the request was CON, then the response is ACK, otherwire NON
262             sendPdu = GenerateCoAPPdu(COAP_MESSAGE_ACK, 0, rcvdPdu->hdr->id,
263                     NULL, NULL, NULL);
264             VERIFY_NON_NULL(sendPdu);
265             coap_show_pdu(sendPdu);
266
267             sendFlag = (coap_send_flags_t)(rcvdRequest->secure ? SEND_SECURE_PORT : 0);
268             if(SendCoAPPdu(gCoAPCtx, (coap_address_t*) &(rcvdRequest->remote), sendPdu,
269                     sendFlag)
270                     != OC_STACK_OK){
271                 OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu"));
272             }
273         }
274         else
275         {
276             goto exit;
277         }
278     }
279 exit:
280     return;
281 }
282
283 uint32_t GetTime(float afterSeconds)
284 {
285     coap_tick_t now;
286     coap_ticks(&now);
287     return now + (uint32_t)(afterSeconds * COAP_TICKS_PER_SECOND);
288 }
289
290 //This function is called back by libcoap when a response is received
291 static void HandleCoAPResponses(struct coap_context_t *ctx,
292         const coap_queue_t * rcvdResponse) {
293     OCResponse * response = NULL;
294     OCCoAPToken rcvdToken;
295     OCClientResponse clientResponse;
296     memset(&clientResponse, 0, sizeof(OCClientResponse));
297     ClientCB * cbNode = NULL;
298     unsigned char bufRes[MAX_RESPONSE_LENGTH] = {0};
299     uint32_t sequenceNumber = OC_OBSERVE_NO_OPTION;
300     uint32_t maxAge = 0;
301     OCStackResult result = OC_STACK_ERROR;
302     coap_pdu_t * sendPdu = NULL;
303     coap_pdu_t * recvPdu = NULL;
304     unsigned char rcvdUri[MAX_URI_LENGTH] = { 0 };
305     uint8_t isObserveNotification = 0;
306     #ifdef WITH_PRESENCE
307     char * resourceTypeName = NULL;
308     uint8_t remoteIpAddr[4];
309     uint16_t remotePortNu;
310     unsigned char fullUri[MAX_URI_LENGTH] = { 0 };
311     uint8_t isPresenceNotification = 0;
312     uint8_t isMulticastPresence = 0;
313     uint32_t lowerBound;
314     uint32_t higherBound;
315     char * tok = NULL;
316     #endif
317     coap_block_t rcvdBlock1 = {COAP_BLOCK_FILL_VALUE};
318     coap_block_t rcvdBlock2 = {COAP_BLOCK_FILL_VALUE};
319     uint16_t rcvdSize2 = 0;
320
321     VERIFY_NON_NULL(ctx);
322     VERIFY_NON_NULL(rcvdResponse);
323     recvPdu = rcvdResponse->pdu;
324
325     result = ParseCoAPPdu(recvPdu, rcvdUri, NULL, &sequenceNumber, &maxAge,
326             &clientResponse.numRcvdVendorSpecificHeaderOptions,
327             clientResponse.rcvdVendorSpecificHeaderOptions,
328             &rcvdBlock1, &rcvdBlock2, NULL, &rcvdSize2, bufRes);
329
330     VERIFY_SUCCESS(result, OC_STACK_OK);
331
332     OC_LOG_V(DEBUG, TAG, "The sequenceNumber/NONCE of this response %u", sequenceNumber);
333     OC_LOG_V(DEBUG, TAG, "The maxAge/TTL of this response %u", maxAge);
334     OC_LOG_V(DEBUG, TAG, "The response received is %s", bufRes);
335
336     if(sequenceNumber >= OC_OFFSET_SEQUENCE_NUMBER)
337     {
338         isObserveNotification = 1;
339         OC_LOG(INFO, TAG, PCF("Received an observe notification"));
340     }
341
342     #ifdef WITH_PRESENCE
343     if(!strcmp((char *)rcvdUri, (char *)OC_PRESENCE_URI)){
344         isPresenceNotification = 1;
345         OC_LOG(INFO, TAG, PCF("Received a presence notification"));
346         tok = strtok((char *)bufRes, "[:]");
347         tok = strtok(NULL, "[:]");
348         VERIFY_NON_NULL(tok);
349         sequenceNumber = (uint32_t )atol(tok);
350         OC_LOG_V(DEBUG, TAG, "The received NONCE is %u", sequenceNumber);
351         tok = strtok(NULL, "[:]");
352         VERIFY_NON_NULL(tok);
353         maxAge = (uint32_t )atol(tok);
354         OC_LOG_V(DEBUG, TAG, "The received TTL is %u", maxAge);
355         tok = strtok(NULL, "[:]");
356         bufRes[strlen((char *)bufRes)] = ':';
357         if(tok) {
358             resourceTypeName = (char *)OCMalloc(strlen(tok));
359             if(!resourceTypeName)
360             {
361                 goto exit;
362             }
363             strcpy(resourceTypeName, tok);
364             bufRes[strlen((char *)bufRes)] = ':';
365             OC_LOG_V(DEBUG, TAG, "----------------resourceTypeName %s",
366                     resourceTypeName);
367         }
368     }
369     #endif
370
371     // fill OCCoAPToken structure
372     RetrieveOCCoAPToken(recvPdu, &rcvdToken);
373     OC_LOG_V(INFO, TAG,"Received a pdu with Token", rcvdToken.tokenLength);
374     OC_LOG_BUFFER(INFO, TAG, rcvdToken.token, rcvdToken.tokenLength);
375
376     // fill OCClientResponse structure
377     result = FormOCClientResponse(&clientResponse, CoAPToOCResponseCode(recvPdu->hdr->code),
378             (OCDevAddr *) &(rcvdResponse->remote), sequenceNumber, bufRes);
379     VERIFY_SUCCESS(result, OC_STACK_OK);
380
381     cbNode = GetClientCB(&rcvdToken, NULL, NULL);
382
383     #ifdef WITH_PRESENCE
384     // Check if the application subcribed for presence
385     if(!cbNode)
386     {
387         // get the address of the remote
388         OCDevAddrToIPv4Addr((OCDevAddr *) &(rcvdResponse->remote), remoteIpAddr,
389                 remoteIpAddr + 1, remoteIpAddr + 2, remoteIpAddr + 3);
390         OCDevAddrToPort((OCDevAddr *) &(rcvdResponse->remote), &remotePortNu);
391         sprintf((char *)fullUri, "coap://%d.%d.%d.%d:%d%s",
392                 remoteIpAddr[0],remoteIpAddr[1],remoteIpAddr[2],remoteIpAddr[3],
393                 remotePortNu,rcvdUri);
394         cbNode = GetClientCB(NULL, NULL, fullUri);
395     }
396
397     // Check if application subscribed for multicast presence
398     if(!cbNode)
399     {
400         sprintf((char *)fullUri, "%s%s", OC_MULTICAST_IP, rcvdUri);
401         cbNode = GetClientCB(NULL, NULL, fullUri);
402         isMulticastPresence = 1;
403     }
404     #endif
405
406     // fill OCResponse structure
407     result = FormOCResponse(&response, cbNode, maxAge, &clientResponse);
408     VERIFY_SUCCESS(result, OC_STACK_OK);
409
410     if(cbNode)
411     {
412         if(!isObserveNotification)
413         {
414             #ifdef WITH_PRESENCE
415             if(!isPresenceNotification)
416             {
417             #endif
418                 OC_LOG(INFO, TAG, PCF("Received a regular response"));
419                 if(recvPdu->hdr->type == COAP_MESSAGE_CON)
420                 {
421                     sendPdu = GenerateCoAPPdu(COAP_MESSAGE_ACK, 0,
422                             recvPdu->hdr->id, NULL, NULL, NULL);
423                     VERIFY_NON_NULL(sendPdu);
424                     result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote,
425                             sendPdu,
426                             (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0));
427                 }
428             #ifdef WITH_PRESENCE
429             }
430             #endif
431         }
432         if(isObserveNotification)
433         {
434             OC_LOG(INFO, TAG, PCF("Received an observe notification"));
435             if(recvPdu->hdr->type == COAP_MESSAGE_CON)
436             {
437                 sendPdu = GenerateCoAPPdu(COAP_MESSAGE_ACK, 0,
438                         recvPdu->hdr->id, NULL, NULL, NULL);
439                 VERIFY_NON_NULL(sendPdu);
440                 result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote,
441                         sendPdu,
442                         (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0));
443             }
444             //TODO: check the standard for methods to detect wrap around condition
445             if(cbNode->method == OC_REST_OBSERVE &&
446                     (clientResponse.sequenceNumber <= cbNode->sequenceNumber ||
447                             (clientResponse.sequenceNumber > cbNode->sequenceNumber &&
448                                     clientResponse.sequenceNumber == (MAX_SEQUENCE_NUMBER))))
449             {
450                 OC_LOG_V(DEBUG, TAG, "Observe notification came out of order. \
451                         Ignoring Incoming:%d  Against Current:%d.",
452                         clientResponse.sequenceNumber, cbNode->sequenceNumber);
453                 goto exit;
454             }
455             if(clientResponse.sequenceNumber > cbNode->sequenceNumber){
456                 cbNode->sequenceNumber = clientResponse.sequenceNumber;
457             }
458         }
459         else
460         {
461             #ifdef WITH_PRESENCE
462             if(isPresenceNotification)
463             {
464                 OC_LOG(INFO, TAG, PCF("Received a presence notification"));
465                 if(!cbNode->presence)
466                 {
467                     cbNode->presence = (OCPresence *) OCMalloc(sizeof(OCPresence));
468                     VERIFY_NON_NULL(cbNode->presence);
469                     cbNode->presence->timeOut = NULL;
470                     cbNode->presence->timeOut = (uint32_t *)
471                             OCMalloc(PresenceTimeOutSize * sizeof(uint32_t));
472                     if(!(cbNode->presence->timeOut)){
473                         OCFree(cbNode->presence);
474                         goto exit;
475                     }
476                 }
477                 if(maxAge == 0)
478                 {
479                     OC_LOG(INFO, TAG, PCF("===============Stopping presence"));
480                     response->clientResponse->result = OC_STACK_PRESENCE_STOPPED;
481                     if(cbNode->presence)
482                     {
483                         OCFree(cbNode->presence->timeOut);
484                         OCFree(cbNode->presence);
485                         cbNode->presence = NULL;
486                     }
487                 }
488                 else
489                 {
490                     OC_LOG_V(INFO, TAG, "===============Update presence TTL, now time is %d", GetTime(0));
491                     cbNode->presence->TTL = maxAge;
492                     for(int index = 0; index < PresenceTimeOutSize; index++)
493                     {
494                         lowerBound = GetTime(((float)(PresenceTimeOut[index])
495                                 /(float)100)*(float)cbNode->presence->TTL);
496                         higherBound = GetTime(((float)(PresenceTimeOut[index + 1])
497                                 /(float)100)*(float)cbNode->presence->TTL);
498                         cbNode->presence->timeOut[index] = OCGetRandomRange(lowerBound, higherBound);
499                         OC_LOG_V(DEBUG, TAG, "----------------lowerBound timeout  %d", lowerBound);
500                         OC_LOG_V(DEBUG, TAG, "----------------higherBound timeout %d", higherBound);
501                         OC_LOG_V(DEBUG, TAG, "----------------timeOut entry  %d", cbNode->presence->timeOut[index]);
502                     }
503                     cbNode->presence->TTLlevel = 0;
504                     OC_LOG_V(DEBUG, TAG, "----------------this TTL level %d", cbNode->presence->TTLlevel);
505                     if(cbNode->sequenceNumber == clientResponse.sequenceNumber)
506                     {
507                         OC_LOG(INFO, TAG, PCF("===============No presence change"));
508                         goto exit;
509                     }
510                     OC_LOG(INFO, TAG, PCF("===============Presence changed, calling up the stack"));
511                     cbNode->sequenceNumber = clientResponse.sequenceNumber;;
512                 }
513
514                 if(resourceTypeName && response->cbNode->filterResourceType)
515                 {
516                     if(strcmp(resourceTypeName,
517                             (const char *)response->cbNode->filterResourceType)!=0)
518                     {
519                         //Ignore presence callback if resource type does not match filter.
520                         goto exit;
521                     }
522                 }
523             }
524             else if(isMulticastPresence)
525             {
526                 // Check if the same nonce for a given host
527                 OCMulticastNode* mcNode = NULL;
528                 unsigned char senderUri[MAX_URI_LENGTH] = { 0 };
529                 sprintf((char *)senderUri, "%d.%d.%d.%d:%d",
530                     remoteIpAddr[0],remoteIpAddr[1],remoteIpAddr[2],remoteIpAddr[3],
531                     remotePortNu);
532                 mcNode = GetMCPresenceNode(senderUri);
533
534                 if(mcNode != NULL)
535                 {
536                     if(mcNode->nonce == clientResponse.sequenceNumber)
537                     {
538                         OC_LOG(INFO, TAG, PCF("===============No presence change (Multicast)"));
539                         goto exit;
540                     }
541                     mcNode->nonce = clientResponse.sequenceNumber;
542                 }
543                 else
544                 {
545                     uint32_t uriLen = strlen((char*)senderUri);
546                     unsigned char* uri = (unsigned char *) OCMalloc(uriLen + 1);
547                     if(uri)
548                     {
549                         memcpy(uri, senderUri, (uriLen + 1));
550                     }
551                     else
552                     {
553                         OC_LOG(INFO, TAG,
554                             PCF("===============No Memory for URI to store in the presence node"));
555                         goto exit;
556                     }
557                     result = AddMCPresenceNode(&mcNode, (unsigned char*) uri,
558                                                 clientResponse.sequenceNumber);
559                     if(result == OC_STACK_NO_MEMORY)
560                     {
561                         OC_LOG(INFO, TAG,
562                             PCF("===============No Memory for Multicast Presence Node"));
563                         goto exit;
564                     }
565                 }
566
567                 if(resourceTypeName && response->cbNode->filterResourceType)
568                 {
569                     if(strcmp(resourceTypeName,
570                             (const char *)response->cbNode->filterResourceType)!=0)
571                     {
572                         //Ignore presence callback if resource type does not match filter.
573                         goto exit;
574                     }
575                 }
576
577             }
578             #endif
579         }
580         HandleStackResponses(response);
581     }
582     else if(!cbNode && isObserveNotification)
583     {
584         OC_LOG(INFO, TAG, PCF("Received an observe notification, but I do not have callback \
585                  ------------ sending RESET"));
586         sendPdu = GenerateCoAPPdu(COAP_MESSAGE_RST, 0,
587                 recvPdu->hdr->id, NULL, NULL, NULL);
588         VERIFY_NON_NULL(sendPdu);
589         result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote, sendPdu,
590                      (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0));
591         VERIFY_SUCCESS(result, OC_STACK_OK);
592     }
593     #ifdef WITH_PRESENCE
594     else if(!cbNode && isPresenceNotification)
595     {
596         OC_LOG(INFO, TAG, PCF("Received a presence notification, but I do not have callback \
597                      ------------ ignoring"));
598     }
599     #endif
600     else
601     {
602         OC_LOG(INFO, TAG, PCF("Received a response, but I do not have callback. \
603                  ------------ sending RESET"));
604         sendPdu = GenerateCoAPPdu(COAP_MESSAGE_RST, 0,
605                 recvPdu->hdr->id, NULL, NULL, NULL);
606         VERIFY_NON_NULL(sendPdu);
607         result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote, sendPdu,
608                     (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0));
609         VERIFY_SUCCESS(result, OC_STACK_OK);
610     }
611     exit:
612         OCFree(response);
613 }
614
615 //=============================================================================
616 // Functions
617 //=============================================================================
618
619 /**
620  * Initialize the CoAP client or server with its IPv4 address and CoAP port
621  *
622  * @param ipAddr
623  *     IP Address of host device
624  * @param port
625  *     Port of host device
626  * @param mode
627  *     Host device is client, server, or client-server
628  *
629  * @return
630  *   0   - success
631  *   TBD - TBD error
632  */
633 OCStackResult OCInitCoAP(const char *address, uint16_t port, OCMode mode) {
634
635     OCStackResult ret = OC_STACK_ERROR;
636
637     TODO ("Below should go away and be replaced by OC_LOG");
638     coap_log_t log_level = (coap_log_t)(LOG_DEBUG + 1);
639     OCDevAddr mcastAddr;
640     uint8_t ipAddr[4] = { 0 };
641     uint16_t parsedPort = 0;
642
643     OC_LOG(INFO, TAG, PCF("Entering OCInitCoAP"));
644
645     coap_set_log_level(log_level);
646
647     if (address)
648     {
649         if (!ParseIPv4Address((unsigned char *) address, ipAddr, &parsedPort))
650         {
651             ret = OC_STACK_ERROR;
652             goto exit;
653         }
654
655         OC_LOG_V(INFO, TAG, "Parsed IP Address %d.%d.%d.%d",
656                                ipAddr[0],ipAddr[1],ipAddr[2],ipAddr[3]);
657     }
658
659     gCoAPCtx = coap_new_context(ipAddr, port);
660     VERIFY_NON_NULL(gCoAPCtx);
661
662     // To allow presence notification work we need to init socket gCoAPCtx->sockfd_wellknown
663     // for servers as well as clients
664     OCBuildIPv4Address(coapWKIpAddr[0], coapWKIpAddr[1], coapWKIpAddr[2],
665             coapWKIpAddr[3], COAP_DEFAULT_PORT, &mcastAddr);
666     VERIFY_SUCCESS(
667             coap_join_wellknown_group(gCoAPCtx,
668                     (coap_address_t* )&mcastAddr), 0);
669
670     coap_register_request_handler(gCoAPCtx, HandleCoAPRequests);
671     coap_register_response_handler(gCoAPCtx, HandleCoAPResponses);
672     coap_register_ack_rst_handler(gCoAPCtx, HandleCoAPAckRst);
673
674     ret = OC_STACK_OK;
675
676 exit:
677     if (ret != OC_STACK_OK)
678     {
679         OCStopCoAP();
680     }
681     return ret;
682 }
683
684 /**
685  * Discover OC resources
686  *
687  * @param method          - method to perform on the resource
688  * @param qos             - Quality of Service the request will be sent on
689  * @param token           - token which will added to the request
690  * @param Uri             - URI of the resource to interact with
691  * @param payload         - the request payload to be added to the request before sending
692  *                          by the stack when discovery or resource interaction is complete
693  * @param options         - The address of an array containing the vendor specific
694  *                          header options to be sent with the request
695  * @return
696  *   0   - success
697  *   TBD - TBD error
698  */
699 OCStackResult OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * token,
700                      const char *Uri, const char *payload, OCHeaderOption * options, uint8_t numOptions)
701 {
702
703     OCStackResult ret = OC_STACK_ERROR;
704     coap_pdu_t *pdu = NULL;
705     coap_uri_t uri;
706     OCDevAddr dst;
707     uint8_t ipAddr[4] = { 0 };
708     uint16_t port = 0;
709     coap_list_t *optList = NULL;
710     uint8_t coapMsgType;
711     uint8_t coapMethod;
712     uint32_t observeOption;
713     coap_send_flags_t flag = (coap_send_flags_t)0;
714
715     OC_LOG(INFO, TAG, PCF("Entering OCDoCoAPResource"));
716
717     if (Uri) {
718         OC_LOG_V(INFO, TAG, "URI = %s", Uri);
719         VERIFY_SUCCESS(coap_split_uri((unsigned char * )Uri, strlen(Uri), &uri), OC_STACK_OK);
720
721         // Generate the destination address
722         if (uri.host.length && ParseIPv4Address(uri.host.s, ipAddr, &port)) {
723             OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], uri.port,
724                     &dst);
725         } else {
726             goto exit;
727         }
728
729         VERIFY_SUCCESS(FormOptionList(&optList, NULL, NULL, NULL,
730                 (uint16_t*)&uri.port, uri.path.length, uri.path.s, uri.query.length,
731                 uri.query.s, options, numOptions), OC_STACK_OK);
732
733         //TODO : Investigate the scenario where there will be no uri for OCDoCoAPResource
734         flag = (coap_send_flags_t) (uri.secure ? SEND_SECURE_PORT : 0);
735         OC_LOG_V(DEBUG, TAG, "uri.host.s %s", uri.host.s);
736         OC_LOG_V(DEBUG, TAG, "uri.path.s %s", uri.path.s);
737         OC_LOG_V(DEBUG, TAG, "uri.port %d", uri.port);
738         OC_LOG_V(DEBUG, TAG, "uri.query.s %s", uri.query.s);
739         OC_LOG_V(DEBUG, TAG, "secure uri %d", uri.secure);
740     }
741
742     coapMsgType = OCToCoAPQoS(qos);
743
744     // Decide method type
745     switch (method) {
746         case OC_REST_GET:
747         #ifdef WITH_PRESENCE
748         case OC_REST_PRESENCE:
749         #endif
750             coapMethod = COAP_REQUEST_GET;
751             break;
752         case OC_REST_PUT:
753             coapMethod = COAP_REQUEST_PUT;
754             break;
755         case OC_REST_POST:
756             coapMethod = COAP_REQUEST_POST;
757             break;
758         case OC_REST_DELETE:
759             coapMethod = COAP_REQUEST_DELETE;
760             break;
761         case OC_REST_OBSERVE_ALL:
762         case OC_REST_OBSERVE:
763         case OC_REST_CANCEL_OBSERVE:
764             coapMethod = COAP_REQUEST_GET;
765             observeOption = (method == OC_REST_CANCEL_OBSERVE)?
766                     OC_OBSERVE_DEREGISTER:OC_OBSERVE_REGISTER;
767             coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_OBSERVE,
768                         sizeof(observeOption), (uint8_t *)&observeOption), OrderOptions);
769             break;
770         default:
771             coapMethod = OC_REST_NOMETHOD;
772             OC_LOG(FATAL, TAG, PCF("OCDoCoAPResource only supports GET, PUT, & OBSERVE methods"));
773             break;
774     }
775
776     VERIFY_NON_NULL(gCoAPCtx);
777     pdu = GenerateCoAPPdu(coapMsgType, coapMethod,
778             coap_new_message_id(gCoAPCtx), token,
779             (unsigned char*) payload, optList);
780     VERIFY_NON_NULL(pdu);
781
782     ret = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &dst, pdu, flag);
783
784 exit:
785     if (ret!= OC_STACK_OK)
786     {
787         OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu"));
788     }
789     return ret;
790 }
791
792 OCStackResult OCDoCoAPResponse(OCServerProtocolResponse *response)
793 {
794     OCStackResult result = OC_STACK_ERROR;
795     coap_pdu_t * sendPdu = NULL;
796     coap_list_t *optList = NULL;
797     uint8_t msgType = COAP_MESSAGE_NON;
798     uint8_t mediaType = COAP_MEDIATYPE_APPLICATION_JSON;
799     uint32_t maxAge = 0x2ffff;
800     coap_send_flags_t sendFlag = (coap_send_flags_t)0;
801
802     //uint32_t observeOption = OC_OBSERVE_NO_OPTION;
803     //OCStackResult responseResult;
804
805     OC_LOG(INFO, TAG, PCF("Entering OCDoCoAPResponse"));
806
807     if(response->notificationFlag && response->qos == OC_HIGH_QOS)
808     {
809         msgType = COAP_MESSAGE_CON;
810     }
811     else if(response->notificationFlag && response->qos != OC_HIGH_QOS)
812     {
813         msgType = COAP_MESSAGE_NON;
814     }
815     else if(!response->notificationFlag && !response->slowFlag && response->qos == OC_HIGH_QOS)
816     {
817         msgType = COAP_MESSAGE_ACK;
818     }
819     else if(!response->notificationFlag && response->slowFlag && response->qos == OC_HIGH_QOS)
820     {
821         msgType = COAP_MESSAGE_CON;
822     }
823     else if(!response->notificationFlag)
824     {
825         msgType = COAP_MESSAGE_NON;
826     }
827
828     if(response->coapID == 0)
829     {
830         response->coapID = coap_new_message_id(gCoAPCtx);
831     }
832
833     if (response->observationOption != OC_OBSERVE_NO_OPTION)
834     {
835         result = FormOptionList(&optList, &mediaType, &maxAge,
836                 &response->observationOption, NULL,
837                 strlen((char *)response->resourceUri), response->resourceUri,
838                 0, NULL,
839                 response->sendVendorSpecificHeaderOptions,
840                 response->numSendVendorSpecificHeaderOptions);
841     }
842     else
843     {
844         result = FormOptionList(&optList, &mediaType, &maxAge,
845                 NULL, NULL,
846                 strlen((char *)response->resourceUri), response->resourceUri,
847                 0, NULL,
848                 response->sendVendorSpecificHeaderOptions,
849                 response->numSendVendorSpecificHeaderOptions);
850     }
851     VERIFY_SUCCESS(result, OC_STACK_OK);
852
853     sendPdu = GenerateCoAPPdu(msgType, OCToCoAPResponseCode(response->result),
854             response->coapID, response->requestToken, (unsigned char *)response->payload,
855             optList);
856
857     VERIFY_NON_NULL(sendPdu);
858     coap_show_pdu(sendPdu);
859
860     sendFlag = (coap_send_flags_t)(response->delayedResNeeded ? SEND_DELAYED : 0);
861     sendFlag = (coap_send_flags_t)( sendFlag | (response->secured ? SEND_SECURE_PORT : 0));
862
863     if (SendCoAPPdu(gCoAPCtx, (coap_address_t *) (response->requesterAddr), sendPdu, sendFlag)
864             != OC_STACK_OK)
865     {
866         OC_LOG(ERROR, TAG, PCF("A problem occurred in sending a pdu"));
867         return OC_STACK_ERROR;
868     }
869
870     return OC_STACK_OK;
871
872 exit:
873     OC_LOG(ERROR, TAG, PCF("Error formatting server response"));
874     return OC_STACK_ERROR;
875 }
876
877
878 /**
879  * Stop the CoAP client or server processing
880  *
881  * @return 0 - success, else - TBD error
882  */
883 OCStackResult OCStopCoAP() {
884     OC_LOG(INFO, TAG, PCF("Entering OCStopCoAP"));
885     coap_free_context(gCoAPCtx);
886     gCoAPCtx = NULL;
887     return OC_STACK_OK;
888 }
889
890 /**
891  * Called in main loop of CoAP client or server.  Allows low-level CoAP processing of
892  * send, receive, timeout, discovery, callbacks, etc.
893  *
894  * @return 0 - success, else - TBD error
895  */
896 OCStackResult OCProcessCoAP() {
897
898     OC_LOG(INFO, TAG, PCF("Entering OCProcessCoAP"));
899     int read = 0;
900     read = coap_read(gCoAPCtx, gCoAPCtx->sockfd);
901     if(read > 0) {
902         OC_LOG(INFO, TAG, PCF("This is a Unicast<============"));
903     }
904     if (-1 != gCoAPCtx->sockfd_wellknown) {
905         read = coap_read(gCoAPCtx, gCoAPCtx->sockfd_wellknown);
906         if(read > 0)
907         {
908             OC_LOG(INFO, TAG, PCF("This is a Multicast<==========="));
909         }
910     }
911     if (-1 != gCoAPCtx->sockfd_dtls) {
912         read = coap_read(gCoAPCtx, gCoAPCtx->sockfd_dtls);
913         if(read > 0)
914         {
915             OC_LOG(INFO, TAG, PCF("This is a Secure packet<==========="));
916         }
917     }
918     coap_dispatch(gCoAPCtx);
919
920     HandleSendQueue(gCoAPCtx);
921
922     return OC_STACK_OK;
923 }
924
925
926 /**
927  * Retrieve the info about the end-point where resource is being hosted.
928  * Currently, this method only provides the IP port with which the socket
929  * is bound.
930  *
931  * @return 0 - success, else - TBD error
932  */
933 OCStackResult OCGetResourceEndPointInfo (OCResource *resPtr, void *info) {
934
935     OCStackResult result = OC_STACK_ERROR;
936     int sfd;
937     OC_LOG(INFO, TAG, PCF("Entering OCGetResourceEndPointInfo"));
938     VERIFY_NON_NULL(resPtr);
939     VERIFY_NON_NULL(info);
940
941     sfd = (resPtr->resourceProperties & OC_SECURE) ? gCoAPCtx->sockfd_dtls :
942             gCoAPCtx->sockfd;
943
944     if (OCGetSocketInfo(sfd, (uint16_t*)info) == ERR_SUCCESS)
945         result = OC_STACK_OK;
946 exit:
947     return result;
948 }
949
950