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