Added support for multicast presence
[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 // Private Variables
49 //=============================================================================
50
51 static uint8_t coapWKIpAddr[] = { 224, 0, 1, 187 };
52 static coap_context_t *gCoAPCtx = NULL;
53
54 //=============================================================================
55 // Helper Functions
56 //=============================================================================
57
58 //generate a coap token
59 void OCGenerateCoAPToken(OCCoAPToken * token)
60 {
61     if (token)
62     {
63         token->tokenLength = MAX_TOKEN_LENGTH;
64         OCFillRandomMem((uint8_t*)token->token, token->tokenLength);
65     }
66 }
67
68 //This function is called back by libcoap when ack or rst are received
69 static void HandleCoAPAckRst(struct coap_context_t * ctx, uint8_t msgType,
70         const coap_queue_t * sentQueue){
71
72     // silence warnings
73     (void) ctx;
74
75     OCStackResult result = OC_STACK_OK;
76     OCCoAPToken sentToken;
77     uint8_t * observeOption = NULL;
78     coap_pdu_t * sentPdu = sentQueue->pdu;
79
80     // fill the buffers of Uri and Query
81     result = ParseCoAPPdu(sentPdu, NULL, NULL, &observeOption, NULL, NULL, NULL, NULL);
82     VERIFY_SUCCESS(result, OC_STACK_OK);
83
84     // fill OCCoAPToken structure
85     RetrieveOCCoAPToken(sentPdu, &sentToken);
86
87     if(msgType == COAP_MESSAGE_RST){
88         // now the observer should be deleted
89         if(myStackMode != OC_CLIENT)
90         {
91             result = OCObserverStatus(&sentToken, OC_OBSERVER_NOT_INTERESTED);
92             if(result == OC_STACK_OK){
93                 OC_LOG_V(DEBUG, TAG,
94                         "Received RST, removing all queues associated with Token %d bytes",
95                         sentToken.tokenLength);
96                 OC_LOG_BUFFER(INFO, TAG, sentToken.token, sentToken.tokenLength);
97                 coap_cancel_all_messages(ctx, &sentQueue->remote, sentToken.token,
98                         sentToken.tokenLength);
99             }
100         }
101     }else if(observeOption && msgType == COAP_MESSAGE_ACK){
102         OC_LOG_V(DEBUG, TAG, "Received ACK, for Token %d bytes",sentToken.tokenLength);
103         OC_LOG_BUFFER(INFO, TAG, sentToken.token, sentToken.tokenLength);
104         // now the observer is still interested
105         if(myStackMode != OC_CLIENT)
106         {
107             OCObserverStatus(&sentToken, OC_OBSERVER_STILL_INTERESTED);
108         }
109     }
110
111     exit:
112         OCFree(observeOption);
113 }
114
115 //This function is called back by libcoap when a request is received
116 static void HandleCoAPRequests(struct coap_context_t *ctx,
117         const coap_queue_t * rcvdRequest)
118 {
119     // silence warnings
120     (void) ctx;
121
122     if(myStackMode == OC_CLIENT)
123     {
124         //TODO: should the client be responding to requests?
125         return;
126     }
127
128     OCStackResult result = OC_STACK_ERROR;
129     OCStackResult responseResult = OC_STACK_ERROR;
130     OCRequest * request = NULL;
131     OCEntityHandlerRequest entityHandlerRequest;
132     OCCoAPToken rcvdToken;
133     OCObserveReq * rcvdObsReq = NULL;
134     coap_pdu_t * sendPdu = NULL;
135     coap_list_t *optList = NULL;
136     uint8_t mediaType = COAP_MEDIATYPE_APPLICATION_JSON;
137     uint32_t maxAge = 0x2ffff;
138     OCMethod ocMethod;
139
140     unsigned char rcvdUri[MAX_URI_LENGTH] = { 0 };
141     unsigned char rcvdQuery[MAX_QUERY_LENGTH] = { 0 };
142     unsigned char bufRes[MAX_RESPONSE_LENGTH] = { 0 };
143     unsigned char newResourceUri[MAX_RESPONSE_LENGTH] = { 0 };
144     uint8_t * rcvObserveOption = NULL;
145     unsigned char * bufReqPayload = NULL;
146     uint32_t observeOption = OC_RESOURCE_NO_OBSERVE;
147     coap_send_flags_t sendFlag;
148     memset(&entityHandlerRequest, 0, sizeof(OCEntityHandlerRequest));
149
150     coap_pdu_t * recvPdu = rcvdRequest->pdu;
151
152     // fill the buffers of Uri and Query
153     result = ParseCoAPPdu(recvPdu, rcvdUri, rcvdQuery, &rcvObserveOption, NULL, &bufReqPayload,
154             entityHandlerRequest.rcvdVendorSpecificHeaderOptions,
155             &(entityHandlerRequest.numRcvdVendorSpecificHeaderOptions));
156     VERIFY_SUCCESS(result, OC_STACK_OK);
157     if(rcvObserveOption){
158         observeOption = (uint32_t)(*rcvObserveOption);
159     }
160
161     // fill OCCoAPToken structure
162     RetrieveOCCoAPToken(recvPdu, &rcvdToken);
163
164     switch (recvPdu->hdr->code)
165     {
166         case COAP_REQUEST_GET:
167             {
168                 ocMethod = OC_REST_GET;
169                 break;
170             }
171         case COAP_REQUEST_POST:
172             {
173                 ocMethod = OC_REST_POST;
174                 break;
175             }
176         case COAP_REQUEST_DELETE:
177             {
178                 ocMethod = OC_REST_DELETE;
179                 break;
180             }
181         case COAP_REQUEST_PUT:
182             {
183                 ocMethod = OC_REST_PUT;
184                 break;
185             }
186         default:
187             {
188                 OC_LOG_V(ERROR, TAG, "Received CoAP method %d not supported",
189                          recvPdu->hdr->code);
190                 goto exit;
191             }
192     }
193
194     // fill OCEntityHandlerRequest structure
195     result = FormOCEntityHandlerRequest(&entityHandlerRequest, ocMethod,
196                                         bufRes, bufReqPayload, rcvdQuery, newResourceUri);
197     VERIFY_SUCCESS(result, OC_STACK_OK);
198
199    // fill OCObserveReq
200    result = FormOCObserveReq(&rcvdObsReq, observeOption,
201            (OCDevAddr *)&(rcvdRequest->remote), &rcvdToken);
202    VERIFY_SUCCESS(result, OC_STACK_OK);
203
204     // fill OCRequest structure
205     result = FormOCRequest(&request, (recvPdu->hdr->type == COAP_MESSAGE_CON) ?
206             OC_HIGH_QOS : OC_LOW_QOS, rcvdUri, rcvdObsReq, &entityHandlerRequest);
207     VERIFY_SUCCESS(result, OC_STACK_OK);
208
209     OC_LOG_V(INFO, TAG, " Receveid uri:     %s", request->resourceUrl);
210     OC_LOG_V(INFO, TAG, " Receveid query:   %s", entityHandlerRequest.query);
211     OC_LOG_V(INFO, TAG, " Receveid payload: %s",
212             request->entityHandlerRequest->reqJSONPayload);
213     OC_LOG_V(INFO, TAG, " Token received %d bytes",
214             rcvdToken.tokenLength);
215     OC_LOG_BUFFER(INFO, TAG, rcvdToken.token, rcvdToken.tokenLength);
216
217     // process the request
218     responseResult = HandleStackRequests(request);
219     #ifdef WITH_PRESENCE
220     if(responseResult == OC_STACK_PRESENCE_DO_NOT_HANDLE)
221     {
222         goto exit;
223     }
224     #endif
225
226     OC_LOG_V(INFO, TAG, "Response from ocstack: %s",
227             request->entityHandlerRequest->resJSONPayload);
228
229     if(rcvdObsReq)
230     {
231         switch(rcvdObsReq->result)
232         {
233         case OC_STACK_OK:
234             observeOption = rcvdObsReq->option;
235             result = FormOptionList(&optList, &mediaType, &maxAge,
236                     sizeof(observeOption), &observeOption,
237                     NULL, 0, NULL, 0, NULL,
238                     request->entityHandlerRequest->sendVendorSpecificHeaderOptions,
239                     request->entityHandlerRequest->numSendVendorSpecificHeaderOptions);
240             break;
241         case OC_STACK_OBSERVER_NOT_ADDED:
242         case OC_STACK_OBSERVER_NOT_REMOVED:
243         case OC_STACK_INVALID_OBSERVE_PARAM:
244         default:
245             result = FormOptionList(&optList, &mediaType, &maxAge, 0, NULL, NULL,
246                     0, NULL, 0, NULL,
247                     request->entityHandlerRequest->sendVendorSpecificHeaderOptions,
248                     request->entityHandlerRequest->numSendVendorSpecificHeaderOptions);
249             break;
250         }
251     }
252     else
253     {
254         if (responseResult == OC_STACK_RESOURCE_CREATED)
255         {
256             result = FormOptionList(&optList, &mediaType, &maxAge, 0, NULL, NULL,
257                     strlen((char *)newResourceUri), newResourceUri, 0, NULL,
258                     request->entityHandlerRequest->sendVendorSpecificHeaderOptions,
259                     request->entityHandlerRequest->numSendVendorSpecificHeaderOptions);
260         }
261         else
262         {
263             result = FormOptionList(&optList, &mediaType, &maxAge, 0, NULL, NULL,
264                     0, NULL, 0, NULL,
265                     request->entityHandlerRequest->sendVendorSpecificHeaderOptions,
266                     request->entityHandlerRequest->numSendVendorSpecificHeaderOptions);
267         }
268     }
269
270     VERIFY_SUCCESS(result, OC_STACK_OK);
271
272     // generate the pdu, if the request was CON, then the response is ACK, otherwire NON
273     sendPdu = GenerateCoAPPdu(
274             (rcvdRequest->pdu->hdr->type == COAP_MESSAGE_CON) ?
275                     COAP_MESSAGE_ACK : COAP_MESSAGE_NON,
276                     OCToCoAPResponseCode(responseResult), rcvdRequest->pdu->hdr->id,
277                     &rcvdToken,
278                     request->entityHandlerRequest->resJSONPayload, optList);
279     VERIFY_NON_NULL(sendPdu);
280     coap_show_pdu(sendPdu);
281
282     sendFlag = (coap_send_flags_t)(rcvdRequest->delayedResponse ? SEND_DELAYED : 0);
283     sendFlag = (coap_send_flags_t)( sendFlag | (rcvdRequest->secure ? SEND_SECURE_PORT : 0));
284
285     if(SendCoAPPdu(gCoAPCtx, (coap_address_t*) &(rcvdRequest->remote), sendPdu,
286          sendFlag)
287             != OC_STACK_OK){
288         OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu"));
289     }
290
291 exit:
292     OCFree(rcvObserveOption);
293     OCFree(rcvdObsReq);
294     OCFree(request);
295 }
296
297 uint32_t GetTime(float afterSeconds)
298 {
299     coap_tick_t now;
300     coap_ticks(&now);
301     return now + (uint32_t)(afterSeconds * COAP_TICKS_PER_SECOND);
302 }
303
304 //This function is called back by libcoap when a response is received
305 static void HandleCoAPResponses(struct coap_context_t *ctx,
306         const coap_queue_t * rcvdResponse) {
307     OCResponse * response = NULL;
308     OCCoAPToken rcvdToken;
309     OCClientResponse clientResponse;
310     ClientCB * cbNode = NULL;
311     unsigned char * bufRes = NULL;
312     uint8_t * rcvObserveOption = NULL;
313     uint8_t * rcvMaxAgeOption = NULL;
314     uint32_t sequenceNumber = OC_RESOURCE_NO_OBSERVE;
315     uint32_t maxAge = 0;
316     OCStackResult result = OC_STACK_ERROR;
317     coap_pdu_t *sendPdu = NULL;
318     coap_pdu_t * recvPdu = NULL;
319     uint8_t remoteIpAddr[4];
320     uint16_t remotePortNu;
321     unsigned char fullUri[MAX_URI_LENGTH] = { 0 };
322     unsigned char rcvdUri[MAX_URI_LENGTH] = { 0 };
323     uint8_t isObserveNotification = 0;
324     #ifdef WITH_PRESENCE
325     uint8_t isPresenceNotification = 0;
326     uint8_t isMulticastPresence = 0;
327     uint32_t lowerBound;
328     uint32_t higherBound;
329     char * tok = NULL;
330     #endif
331     memset(&clientResponse, 0, sizeof(OCClientResponse));
332
333     VERIFY_NON_NULL(ctx);
334     VERIFY_NON_NULL(rcvdResponse);
335     recvPdu = rcvdResponse->pdu;
336
337     result = ParseCoAPPdu(recvPdu, rcvdUri, NULL, &rcvObserveOption, &rcvMaxAgeOption, &bufRes,
338             clientResponse.rcvdVendorSpecificHeaderOptions,
339             &(clientResponse.numRcvdVendorSpecificHeaderOptions));
340     VERIFY_SUCCESS(result, OC_STACK_OK);
341
342     if(rcvObserveOption){
343         sequenceNumber = *((uint32_t *) rcvObserveOption);
344     }
345
346     if(rcvMaxAgeOption){
347         maxAge = *((uint32_t *) rcvMaxAgeOption);
348     }
349
350     OC_LOG_V(DEBUG, TAG, "The sequenceNumber/NONCE of this response %u", sequenceNumber);
351     OC_LOG_V(DEBUG, TAG, "The maxAge/TTL of this response %u", maxAge);
352     OC_LOG_V(DEBUG, TAG, "The response received is %s", bufRes);
353
354     if(sequenceNumber >= OC_OFFSET_SEQUENCE_NUMBER)
355     {
356         isObserveNotification = 1;
357         OC_LOG(INFO, TAG, PCF("Received an observe notification"));
358     }
359
360     #ifdef WITH_PRESENCE
361     if(!strcmp((char *)rcvdUri, (char *)OC_PRESENCE_URI)){
362         isPresenceNotification = 1;
363         OC_LOG(INFO, TAG, PCF("Received a presence notification"));
364         tok = strtok((char *)bufRes, ":");
365         sequenceNumber = (uint32_t )atoi(tok);
366         OC_LOG_V(DEBUG, TAG, "The received NONCE is %u", sequenceNumber);
367         tok = strtok(NULL, ":");
368         maxAge = (uint32_t )atoi(tok);
369         OC_LOG_V(DEBUG, TAG, "The received TTL is %u", maxAge);
370         bufRes[strlen((char *)bufRes)] = ':';
371     }
372     #endif
373
374     // fill OCCoAPToken structure
375     RetrieveOCCoAPToken(recvPdu, &rcvdToken);
376     OC_LOG_V(INFO, TAG,"Received a pdu with Token", rcvdToken.tokenLength);
377     OC_LOG_BUFFER(INFO, TAG, rcvdToken.token, rcvdToken.tokenLength);
378
379     // fill OCClientResponse structure
380     result = FormOCClientResponse(&clientResponse, CoAPToOCResponseCode(recvPdu->hdr->code),
381             (OCDevAddr *) &(rcvdResponse->remote), sequenceNumber, bufRes);
382     VERIFY_SUCCESS(result, OC_STACK_OK);
383
384     cbNode = GetClientCB(&rcvdToken, NULL, NULL);
385
386     #ifdef WITH_PRESENCE
387     // Check if the application subcribed for presence
388     if(!cbNode)
389     {
390         // get the address of the remote
391         OCDevAddrToIPv4Addr((OCDevAddr *) &(rcvdResponse->remote), remoteIpAddr,
392                 remoteIpAddr + 1, remoteIpAddr + 2, remoteIpAddr + 3);
393         OCDevAddrToPort((OCDevAddr *) &(rcvdResponse->remote), &remotePortNu);
394         sprintf((char *)fullUri, "coap://%d.%d.%d.%d:%d%s",
395                 remoteIpAddr[0],remoteIpAddr[1],remoteIpAddr[2],remoteIpAddr[3],
396                 remotePortNu,rcvdUri);
397         cbNode = GetClientCB(NULL, NULL, fullUri);
398     }
399
400     // Check if application subscribed for multicast presence
401     if(!cbNode)
402     {
403         sprintf((char *)fullUri, "%s%s", OC_MULTICAST_IP, rcvdUri);
404         cbNode = GetClientCB(NULL, NULL, fullUri);
405         isMulticastPresence = 1;
406     }
407     #endif
408
409     // fill OCResponse structure
410     result = FormOCResponse(&response, cbNode, maxAge, &clientResponse);
411     VERIFY_SUCCESS(result, OC_STACK_OK);
412
413     if(cbNode)
414     {
415         if(isObserveNotification)
416         {
417             OC_LOG(INFO, TAG, PCF("Received an observe notification"));
418             if(recvPdu->hdr->type == COAP_MESSAGE_CON)
419             {
420                 sendPdu = GenerateCoAPPdu(COAP_MESSAGE_ACK, 0,
421                         recvPdu->hdr->id, NULL, NULL, NULL);
422                 VERIFY_NON_NULL(sendPdu);
423                 result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote,
424                         sendPdu,
425                         (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0));
426             }
427             //TODO: check the standard for methods to detect wrap around condition
428             if(cbNode->method == OC_REST_OBSERVE &&
429                     (clientResponse.sequenceNumber <= cbNode->sequenceNumber ||
430                             (clientResponse.sequenceNumber > cbNode->sequenceNumber &&
431                                     clientResponse.sequenceNumber == MAX_SEQUENCE_NUMBER)))
432             {
433                 OC_LOG_V(DEBUG, TAG, "Observe notification came out of order. \
434                         Ignoring Incoming:%d  Against Current:%d.",
435                         clientResponse.sequenceNumber, cbNode->sequenceNumber);
436                 goto exit;
437             }
438             if(clientResponse.sequenceNumber > cbNode->sequenceNumber){
439                 cbNode->sequenceNumber = clientResponse.sequenceNumber;
440             }
441         }
442         else
443         {
444             #ifdef WITH_PRESENCE
445             if(isPresenceNotification)
446             {
447                 OC_LOG(INFO, TAG, PCF("Received a presence notification"));
448                 if(!cbNode->presence)
449                 {
450                     cbNode->presence = (OCPresence *) OCMalloc(sizeof(OCPresence));
451                     VERIFY_NON_NULL(cbNode->presence);
452                     cbNode->presence->timeOut = NULL;
453                     cbNode->presence->timeOut = (uint32_t *)
454                             OCMalloc(PresenceTimeOutSize * sizeof(uint32_t));
455                     if(!(cbNode->presence->timeOut)){
456                         OCFree(cbNode->presence);
457                         goto exit;
458                     }
459                 }
460                 if(maxAge == 0)
461                 {
462                     OC_LOG(INFO, TAG, "===============Stopping presence");
463                     response->clientResponse->result = OC_STACK_PRESENCE_STOPPED;
464                 }
465                 else
466                 {
467                     OC_LOG_V(INFO, TAG, "===============Update presence TTL, now time is %d", GetTime(0));
468                     cbNode->presence->TTL = maxAge;
469                     for(int index = 0; index < PresenceTimeOutSize; index++)
470                     {
471                         lowerBound = GetTime(((float)(PresenceTimeOut[index])
472                                 /(float)100)*(float)cbNode->presence->TTL);
473                         higherBound = GetTime(((float)(PresenceTimeOut[index + 1])
474                                 /(float)100)*(float)cbNode->presence->TTL);
475                         cbNode->presence->timeOut[index] = OCGetRandomRange(lowerBound, higherBound);
476                         OC_LOG_V(DEBUG, TAG, "----------------lowerBound timeout  %d", lowerBound);
477                         OC_LOG_V(DEBUG, TAG, "----------------higherBound timeout %d", higherBound);
478                         OC_LOG_V(DEBUG, TAG, "----------------timeOut entry  %d", cbNode->presence->timeOut[index]);
479                     }
480                     cbNode->presence->TTLlevel = 0;
481                     OC_LOG_V(DEBUG, TAG, "----------------this TTL level %d", cbNode->presence->TTLlevel);
482                     if(cbNode->sequenceNumber == clientResponse.sequenceNumber)
483                     {
484                         OC_LOG(INFO, TAG, "===============No presence change");
485                         goto exit;
486                     }
487                     OC_LOG(INFO, TAG, "===============Presence changed, calling up the stack");
488                     cbNode->sequenceNumber = clientResponse.sequenceNumber;;
489                 }
490             }
491             else if(isMulticastPresence)
492             {
493                 // Check if the same nonce for a given host
494                 OCMulticastNode* mcNode = NULL;
495                 unsigned char senderUri[MAX_URI_LENGTH] = { 0 };
496                 sprintf((char *)senderUri, "%d.%d.%d.%d:%d",
497                     remoteIpAddr[0],remoteIpAddr[1],remoteIpAddr[2],remoteIpAddr[3],
498                     remotePortNu);
499                 mcNode = GetMCPresenceNode(senderUri);
500
501                 if(mcNode != NULL)
502                 {
503                     if(mcNode->nonce == clientResponse.sequenceNumber)
504                     {
505                         OC_LOG(INFO, TAG, PCF("===============No presence change (Multicast)"));
506                         goto exit;
507                     }
508                     mcNode->nonce = clientResponse.sequenceNumber;
509                 }
510                 else
511                 {
512                     uint32_t uriLen = strlen((char*)senderUri);
513                     unsigned char* uri = (unsigned char *) OCMalloc(uriLen + 1);
514                     if(uri)
515                     {
516                         memcpy(uri, senderUri, (uriLen + 1));
517                     }
518                     else
519                     {
520                         OC_LOG(INFO, TAG,
521                             PCF("===============No Memory for URI to store in the presence node"));
522                         goto exit;
523                     }
524                     result = AddMCPresenceNode(&mcNode, (unsigned char*) uri,
525                                                 clientResponse.sequenceNumber);
526                     if(result == OC_STACK_NO_MEMORY)
527                     {
528                         OC_LOG(INFO, TAG,
529                             PCF("===============No Memory for Multicast Presence Node"));
530                         goto exit;
531                     }
532                 }
533             }
534             #endif
535         }
536         HandleStackResponses(response);
537     }
538     else if(!cbNode && isObserveNotification)
539     {
540         OC_LOG(INFO, TAG, PCF("Received an observe notification, but I do not have callback \
541                  ------------ sending RESET"));
542         sendPdu = GenerateCoAPPdu(COAP_MESSAGE_RST, 0,
543                 recvPdu->hdr->id, NULL, NULL, NULL);
544         VERIFY_NON_NULL(sendPdu);
545         result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote, sendPdu,
546                      (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0));
547         VERIFY_SUCCESS(result, OC_STACK_OK);
548     }
549     #ifdef WITH_PRESENCE
550     else if(!cbNode && isPresenceNotification)
551     {
552         OC_LOG(INFO, TAG, PCF("Received a presence notification, but I do not have callback \
553                      ------------ ignoring"));
554     }
555     #endif
556     else
557     {
558         OC_LOG(INFO, TAG, PCF("Received a response, but I do not have callback. \
559                  ------------ sending RESET"));
560         sendPdu = GenerateCoAPPdu(COAP_MESSAGE_RST, 0,
561                 recvPdu->hdr->id, NULL, NULL, NULL);
562         VERIFY_NON_NULL(sendPdu);
563         result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote, sendPdu,
564                     (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0));
565         VERIFY_SUCCESS(result, OC_STACK_OK);
566     }
567     exit:
568         OCFree(rcvObserveOption);
569         OCFree(rcvMaxAgeOption);
570         OCFree(response);
571 }
572
573 //=============================================================================
574 // Functions
575 //=============================================================================
576
577 /**
578  * Initialize the CoAP client or server with its IPv4 address and CoAP port
579  *
580  * @param ipAddr
581  *     IP Address of host device
582  * @param port
583  *     Port of host device
584  * @param mode
585  *     Host device is client, server, or client-server
586  *
587  * @return
588  *   0   - success
589  *   TBD - TBD error
590  */
591 OCStackResult OCInitCoAP(const char *address, uint16_t port, OCMode mode) {
592
593     OCStackResult ret = OC_STACK_ERROR;
594
595     TODO ("Below should go away and be replaced by OC_LOG");
596     coap_log_t log_level = (coap_log_t)(LOG_DEBUG + 1);
597     OCDevAddr devAddr;
598     OCDevAddr mcastAddr;
599     uint8_t ipAddr[4] = { 0 };
600     uint16_t parsedPort = 0;
601
602     OC_LOG(INFO, TAG, PCF("Entering OCInitCoAP"));
603
604     coap_set_log_level(log_level);
605
606     if (address)
607     {
608         if (!ParseIPv4Address((unsigned char *) address, ipAddr, &parsedPort))
609         {
610             ret = OC_STACK_ERROR;
611             goto exit;
612         }
613
614         OC_LOG_V(INFO, TAG, "Parsed IP Address %d.%d.%d.%d",
615                                ipAddr[0],ipAddr[1],ipAddr[2],ipAddr[3]);
616     }
617
618     OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], port,
619             &devAddr);
620
621     gCoAPCtx = coap_new_context((coap_address_t*) &devAddr);
622     VERIFY_NON_NULL(gCoAPCtx);
623
624     // To allow presence notification work we need to init socket gCoAPCtx->sockfd_wellknown
625     // for servers as well as clients
626     OCBuildIPv4Address(coapWKIpAddr[0], coapWKIpAddr[1], coapWKIpAddr[2],
627             coapWKIpAddr[3], COAP_DEFAULT_PORT, &mcastAddr);
628     VERIFY_SUCCESS(
629             coap_join_wellknown_group(gCoAPCtx,
630                     (coap_address_t* )&mcastAddr), 0);
631
632     coap_register_request_handler(gCoAPCtx, HandleCoAPRequests);
633     coap_register_response_handler(gCoAPCtx, HandleCoAPResponses);
634     coap_register_ack_rst_handler(gCoAPCtx, HandleCoAPAckRst);
635
636     ret = OC_STACK_OK;
637
638 exit:
639     if (ret != OC_STACK_OK)
640     {
641         OCStopCoAP();
642     }
643     return ret;
644 }
645
646 /**
647  * Discover OC resources
648  *
649  * @param method          - method to perform on the resource
650  * @param qos             - Quality of Service the request will be sent on
651  * @param token           - token which will added to the request
652  * @param Uri             - URI of the resource to interact with
653  * @param payload         - the request payload to be added to the request before sending
654  *                          by the stack when discovery or resource interaction is complete
655  * @param options         - The address of an array containing the vendor specific
656  *                          header options to be sent with the request
657  * @return
658  *   0   - success
659  *   TBD - TBD error
660  */
661 OCStackResult OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * token,
662                      const char *Uri, const char *payload, OCHeaderOption * options, uint8_t numOptions)
663 {
664
665     OCStackResult ret = OC_STACK_ERROR;
666     coap_pdu_t *pdu = NULL;
667     coap_uri_t uri;
668     OCDevAddr dst;
669     uint8_t ipAddr[4] = { 0 };
670     uint16_t port = 0;
671     coap_list_t *optList = NULL;
672     uint8_t coapMsgType;
673     uint8_t coapMethod;
674     uint32_t observeOption;
675     coap_send_flags_t flag = (coap_send_flags_t)0;
676
677     OC_LOG(INFO, TAG, PCF("Entering OCDoCoAPResource"));
678
679     if (Uri) {
680         OC_LOG_V(INFO, TAG, "URI = %s", Uri);
681         VERIFY_SUCCESS(coap_split_uri((unsigned char * )Uri, strlen(Uri), &uri), OC_STACK_OK);
682
683         // Generate the destination address
684         if (uri.host.length && ParseIPv4Address(uri.host.s, ipAddr, &port)) {
685             OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], uri.port,
686                     &dst);
687         } else {
688             goto exit;
689         }
690
691         VERIFY_SUCCESS(FormOptionList(&optList, NULL, NULL, 0, NULL,
692                 (uint16_t*)&uri.port, uri.path.length, uri.path.s, uri.query.length,
693                 uri.query.s, options, numOptions), OC_STACK_OK);
694
695         //TODO : Investigate the scenario where there will be no uri for OCDoCoAPResource
696         //flag = (coap_send_flags_t) (uri.secure ? SEND_SECURE_PORT : 0);
697         OC_LOG_V(DEBUG, TAG, "uri.host.s %s", uri.host.s);
698         OC_LOG_V(DEBUG, TAG, "uri.path.s %s", uri.path.s);
699         OC_LOG_V(DEBUG, TAG, "uri.port %d", uri.port);
700         OC_LOG_V(DEBUG, TAG, "uri.query.s %s", uri.query.s);
701     }
702
703     coapMsgType = OCToCoAPQoS(qos);
704
705     // Decide method type
706     switch (method) {
707         case OC_REST_GET:
708         #ifdef WITH_PRESENCE
709         case OC_REST_PRESENCE:
710         #endif
711             coapMethod = COAP_REQUEST_GET;
712             break;
713         case OC_REST_PUT:
714             coapMethod = COAP_REQUEST_PUT;
715             break;
716         case OC_REST_POST:
717             coapMethod = COAP_REQUEST_POST;
718             break;
719         case OC_REST_DELETE:
720             coapMethod = COAP_REQUEST_DELETE;
721             break;
722         case OC_REST_OBSERVE_ALL:
723         case OC_REST_OBSERVE:
724         case OC_REST_CANCEL_OBSERVE:
725             coapMethod = COAP_REQUEST_GET;
726             observeOption = (method == OC_REST_CANCEL_OBSERVE)?
727                     OC_RESOURCE_OBSERVE_DEREGISTER:OC_RESOURCE_OBSERVE_REGISTER;
728             coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_OBSERVE,
729                         sizeof(observeOption), (uint8_t *)&observeOption), OrderOptions);
730             break;
731         default:
732             coapMethod = OC_REST_NOMETHOD;
733             OC_LOG(FATAL, TAG, PCF("OCDoCoAPResource only supports GET, PUT, & OBSERVE methods"));
734             break;
735     }
736
737     VERIFY_NON_NULL(gCoAPCtx);
738     pdu = GenerateCoAPPdu(coapMsgType, coapMethod,
739             coap_new_message_id(gCoAPCtx), token,
740             (unsigned char*) payload, optList);
741     VERIFY_NON_NULL(pdu);
742
743     ret = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &dst, pdu, flag);
744
745 exit:
746     if (ret!= OC_STACK_OK)
747     {
748         OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu"));
749     }
750     return ret;
751 }
752
753 OCStackResult OCSendCoAPNotification (unsigned char * uri, OCDevAddr *dstAddr,
754                        OCQualityOfService qos, OCCoAPToken * token,
755                        unsigned char *payload, OCResource *resPtr, uint32_t maxAge)
756 {
757     OCStackResult result = OC_STACK_ERROR;
758     coap_list_t *optList = NULL;
759     uint8_t coapMsgType = COAP_MESSAGE_NON;
760     uint8_t mediaType = COAP_MEDIATYPE_APPLICATION_JSON;
761     coap_pdu_t *sendPdu;
762
763     OC_LOG(INFO, TAG, PCF("Entering OCSendCoAPNotification"));
764
765     coapMsgType = OCToCoAPQoS(qos);
766
767     #ifdef WITH_PRESENCE
768     if(!strcmp((const char *)uri, OC_PRESENCE_URI))
769     {
770         result = FormOptionList(&optList, &mediaType, NULL, 0, NULL,
771                 NULL, strlen((char *)uri), uri, 0, NULL, NULL, 0);
772     }
773     else
774     {
775     #endif
776         result = FormOptionList(&optList, &mediaType, &maxAge, sizeof(resPtr->sequenceNum),
777                 &resPtr->sequenceNum, NULL, strlen((char *)uri), uri, 0, NULL, NULL, 0);
778     #ifdef WITH_PRESENCE
779     }
780     #endif
781     VERIFY_SUCCESS(result, OC_STACK_OK);
782
783     if(resPtr->resourceProperties == 0)
784     {
785         result = OC_STACK_RESOURCE_DELETED;
786     }
787
788     sendPdu = GenerateCoAPPdu(
789             coapMsgType == COAP_MESSAGE_CON ? COAP_MESSAGE_CON : COAP_MESSAGE_NON,
790                     OCToCoAPResponseCode(result), coap_new_message_id(gCoAPCtx),
791                     token, payload, optList);
792     VERIFY_NON_NULL(sendPdu);
793     coap_show_pdu(sendPdu);
794
795     // TODO : resourceProperties will determine if the packet will be send using secure port
796     if(SendCoAPPdu(gCoAPCtx, (coap_address_t*) dstAddr, sendPdu , (coap_send_flags_t)0 )
797             != OC_STACK_OK)
798     {
799         OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu"));
800     }
801     return OC_STACK_OK;
802 exit:
803     return OC_STACK_ERROR;
804 }
805
806 /**
807  * Stop the CoAP client or server processing
808  *
809  * @return 0 - success, else - TBD error
810  */
811 OCStackResult OCStopCoAP() {
812     OC_LOG(INFO, TAG, PCF("Entering OCStopCoAP"));
813     coap_free_context(gCoAPCtx);
814     gCoAPCtx = NULL;
815     return OC_STACK_OK;
816 }
817
818 /**
819  * Called in main loop of CoAP client or server.  Allows low-level CoAP processing of
820  * send, receive, timeout, discovery, callbacks, etc.
821  *
822  * @return 0 - success, else - TBD error
823  */
824 OCStackResult OCProcessCoAP() {
825
826     OC_LOG(INFO, TAG, PCF("Entering OCProcessCoAP"));
827     int read = 0;
828     read = coap_read(gCoAPCtx, gCoAPCtx->sockfd);
829     if(read > 0)
830     {
831         OC_LOG(INFO, TAG, PCF("This is a Unicast<============"));
832     }
833     if (-1 != gCoAPCtx->sockfd_wellknown) {
834         read = coap_read(gCoAPCtx, gCoAPCtx->sockfd_wellknown);
835         if(read > 0)
836         {
837             OC_LOG(INFO, TAG, PCF("This is a Multicast<==========="));
838         }
839     }
840     coap_dispatch(gCoAPCtx);
841
842     HandleSendQueue(gCoAPCtx);
843
844     return OC_STACK_OK;
845 }
846