Updated libcoap to send messages using secure port
[contrib/iotivity.git] / 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     uint32_t lowerBound;
327     uint32_t higherBound;
328     char * tok = NULL;
329     #endif
330     memset(&clientResponse, 0, sizeof(OCClientResponse));
331
332     VERIFY_NON_NULL(ctx);
333     VERIFY_NON_NULL(rcvdResponse);
334     recvPdu = rcvdResponse->pdu;
335
336     result = ParseCoAPPdu(recvPdu, rcvdUri, NULL, &rcvObserveOption, &rcvMaxAgeOption, &bufRes,
337             clientResponse.rcvdVendorSpecificHeaderOptions,
338             &(clientResponse.numRcvdVendorSpecificHeaderOptions));
339     VERIFY_SUCCESS(result, OC_STACK_OK);
340
341     if(rcvObserveOption){
342         sequenceNumber = *((uint32_t *) rcvObserveOption);
343     }
344
345     if(rcvMaxAgeOption){
346         maxAge = *((uint32_t *) rcvMaxAgeOption);
347     }
348
349     OC_LOG_V(DEBUG, TAG, "The sequenceNumber/NONCE of this response %u", sequenceNumber);
350     OC_LOG_V(DEBUG, TAG, "The maxAge/TTL of this response %u", maxAge);
351     OC_LOG_V(DEBUG, TAG, "The response received is %s", bufRes);
352
353     if(sequenceNumber >= OC_OFFSET_SEQUENCE_NUMBER)
354     {
355         isObserveNotification = 1;
356         OC_LOG(INFO, TAG, PCF("Received an observe notification"));
357     }
358
359     #ifdef WITH_PRESENCE
360     if(!strcmp((char *)rcvdUri, (char *)OC_PRESENCE_URI)){
361         isPresenceNotification = 1;
362         OC_LOG(INFO, TAG, PCF("Received a presence notification"));
363         tok = strtok((char *)bufRes, ":");
364         sequenceNumber = (uint32_t )atoi(tok);
365         OC_LOG_V(DEBUG, TAG, "The received NONCE is %u", sequenceNumber);
366         tok = strtok(NULL, ":");
367         maxAge = (uint32_t )atoi(tok);
368         OC_LOG_V(DEBUG, TAG, "The received TTL is %u", maxAge);
369         bufRes[strlen((char *)bufRes)] = ':';
370     }
371     #endif
372
373     // fill OCCoAPToken structure
374     RetrieveOCCoAPToken(recvPdu, &rcvdToken);
375     OC_LOG_V(INFO, TAG,"Received a pdu with Token", rcvdToken.tokenLength);
376     OC_LOG_BUFFER(INFO, TAG, rcvdToken.token, rcvdToken.tokenLength);
377
378     // fill OCClientResponse structure
379     result = FormOCClientResponse(&clientResponse, CoAPToOCResponseCode(recvPdu->hdr->code),
380             (OCDevAddr *) &(rcvdResponse->remote), sequenceNumber, bufRes);
381     VERIFY_SUCCESS(result, OC_STACK_OK);
382
383     cbNode = GetClientCB(&rcvdToken, NULL, NULL);
384     if(!cbNode)
385     {
386         // we should check if we are monitoring the presence of this resource
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     // fill OCResponse structure
398     result = FormOCResponse(&response, cbNode, maxAge, &clientResponse);
399     VERIFY_SUCCESS(result, OC_STACK_OK);
400
401     if(cbNode)
402     {
403         if(isObserveNotification)
404         {
405             OC_LOG(INFO, TAG, PCF("Received an observe notification"));
406             if(recvPdu->hdr->type == COAP_MESSAGE_CON)
407             {
408                 sendPdu = GenerateCoAPPdu(COAP_MESSAGE_ACK, 0,
409                         recvPdu->hdr->id, NULL, NULL, NULL);
410                 VERIFY_NON_NULL(sendPdu);
411                 result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote,
412                         sendPdu,
413                         (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0));
414             }
415             //TODO: check the standard for methods to detect wrap around condition
416             if(cbNode->method == OC_REST_OBSERVE &&
417                     (clientResponse.sequenceNumber <= cbNode->sequenceNumber ||
418                             (clientResponse.sequenceNumber > cbNode->sequenceNumber &&
419                                     clientResponse.sequenceNumber == MAX_SEQUENCE_NUMBER)))
420             {
421                 OC_LOG_V(DEBUG, TAG, "Observe notification came out of order. \
422                         Ignoring Incoming:%d  Against Current:%d.",
423                         clientResponse.sequenceNumber, cbNode->sequenceNumber);
424                 goto exit;
425             }
426             if(clientResponse.sequenceNumber > cbNode->sequenceNumber){
427                 cbNode->sequenceNumber = clientResponse.sequenceNumber;
428             }
429         }
430         else
431         {
432             #ifdef WITH_PRESENCE
433             if(isPresenceNotification)
434             {
435                 OC_LOG(INFO, TAG, PCF("Received a presence notification"));
436                 if(!cbNode->presence)
437                 {
438                     cbNode->presence = (OCPresence *) OCMalloc(sizeof(OCPresence));
439                     VERIFY_NON_NULL(cbNode->presence);
440                     cbNode->presence->timeOut = NULL;
441                     cbNode->presence->timeOut = (uint32_t *)
442                             OCMalloc(PresenceTimeOutSize * sizeof(uint32_t));
443                     if(!(cbNode->presence->timeOut)){
444                         OCFree(cbNode->presence);
445                         goto exit;
446                     }
447                 }
448                 if(maxAge == 0)
449                 {
450                     OC_LOG(INFO, TAG, "===============Stopping presence");
451                     response->clientResponse->result = OC_STACK_PRESENCE_STOPPED;
452                 }
453                 else
454                 {
455                     OC_LOG_V(INFO, TAG, "===============Update presence TTL, now time is %d", GetTime(0));
456                     cbNode->presence->TTL = maxAge;
457                     for(int index = 0; index < PresenceTimeOutSize; index++)
458                     {
459                         lowerBound = GetTime(((float)(PresenceTimeOut[index])
460                                 /(float)100)*(float)cbNode->presence->TTL);
461                         higherBound = GetTime(((float)(PresenceTimeOut[index + 1])
462                                 /(float)100)*(float)cbNode->presence->TTL);
463                         cbNode->presence->timeOut[index] = OCGetRandomRange(lowerBound, higherBound);
464                         OC_LOG_V(DEBUG, TAG, "----------------lowerBound timeout  %d", lowerBound);
465                         OC_LOG_V(DEBUG, TAG, "----------------higherBound timeout %d", higherBound);
466                         OC_LOG_V(DEBUG, TAG, "----------------timeOut entry  %d", cbNode->presence->timeOut[index]);
467                     }
468                     cbNode->presence->TTLlevel = 0;
469                     OC_LOG_V(DEBUG, TAG, "----------------this TTL level %d", cbNode->presence->TTLlevel);
470                     if(cbNode->sequenceNumber == clientResponse.sequenceNumber)
471                     {
472                         OC_LOG(INFO, TAG, "===============No presence change");
473                         goto exit;
474                     }
475                     OC_LOG(INFO, TAG, "===============Presence changed, calling up the stack");
476                     cbNode->sequenceNumber = clientResponse.sequenceNumber;;
477                 }
478             }
479             #endif
480         }
481         HandleStackResponses(response);
482     }
483     else if(!cbNode && isObserveNotification)
484     {
485         OC_LOG(INFO, TAG, PCF("Received an observe notification, but I do not have callback \
486                  ------------ sending RESET"));
487         sendPdu = GenerateCoAPPdu(COAP_MESSAGE_RST, 0,
488                 recvPdu->hdr->id, NULL, NULL, NULL);
489         VERIFY_NON_NULL(sendPdu);
490         result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote, sendPdu,
491                      (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0));
492         VERIFY_SUCCESS(result, OC_STACK_OK);
493     }
494     #ifdef WITH_PRESENCE
495     else if(!cbNode && isPresenceNotification)
496     {
497         OC_LOG(INFO, TAG, PCF("Received a presence notification, but I do not have callback \
498                          ------------ ignoring"));
499     }
500     #endif
501     else
502     {
503         OC_LOG(INFO, TAG, PCF("Received a response, but I do not have callback. \
504                  ------------ sending RESET"));
505         sendPdu = GenerateCoAPPdu(COAP_MESSAGE_RST, 0,
506                 recvPdu->hdr->id, NULL, NULL, NULL);
507         VERIFY_NON_NULL(sendPdu);
508         result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote, sendPdu,
509                     (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0));
510         VERIFY_SUCCESS(result, OC_STACK_OK);
511     }
512     exit:
513         OCFree(rcvObserveOption);
514         OCFree(rcvMaxAgeOption);
515         OCFree(response);
516 }
517
518 //=============================================================================
519 // Functions
520 //=============================================================================
521
522 /**
523  * Initialize the CoAP client or server with its IPv4 address and CoAP port
524  *
525  * @param ipAddr
526  *     IP Address of host device
527  * @param port
528  *     Port of host device
529  * @param mode
530  *     Host device is client, server, or client-server
531  *
532  * @return
533  *   0   - success
534  *   TBD - TBD error
535  */
536 OCStackResult OCInitCoAP(const char *address, uint16_t port, OCMode mode) {
537
538     OCStackResult ret = OC_STACK_ERROR;
539
540     TODO ("Below should go away and be replaced by OC_LOG");
541     coap_log_t log_level = (coap_log_t)(LOG_DEBUG + 1);
542     OCDevAddr devAddr;
543     OCDevAddr mcastAddr;
544     uint8_t ipAddr[4] = { 0 };
545     uint16_t parsedPort = 0;
546
547     OC_LOG(INFO, TAG, PCF("Entering OCInitCoAP"));
548
549     coap_set_log_level(log_level);
550
551     if (address)
552     {
553         if (!ParseIPv4Address((unsigned char *) address, ipAddr, &parsedPort))
554         {
555             ret = OC_STACK_ERROR;
556             goto exit;
557         }
558
559         OC_LOG_V(INFO, TAG, "Parsed IP Address %d.%d.%d.%d",
560                                ipAddr[0],ipAddr[1],ipAddr[2],ipAddr[3]);
561     }
562
563     OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], port,
564             &devAddr);
565
566     gCoAPCtx = coap_new_context((coap_address_t*) &devAddr);
567     VERIFY_NON_NULL(gCoAPCtx);
568
569     // To allow presence notification work we need to init socket gCoAPCtx->sockfd_wellknown
570     // for servers as well as clients
571     OCBuildIPv4Address(coapWKIpAddr[0], coapWKIpAddr[1], coapWKIpAddr[2],
572             coapWKIpAddr[3], COAP_DEFAULT_PORT, &mcastAddr);
573     VERIFY_SUCCESS(
574             coap_join_wellknown_group(gCoAPCtx,
575                     (coap_address_t* )&mcastAddr), 0);
576
577     coap_register_request_handler(gCoAPCtx, HandleCoAPRequests);
578     coap_register_response_handler(gCoAPCtx, HandleCoAPResponses);
579     coap_register_ack_rst_handler(gCoAPCtx, HandleCoAPAckRst);
580
581     ret = OC_STACK_OK;
582
583 exit:
584     if (ret != OC_STACK_OK)
585     {
586         OCStopCoAP();
587     }
588     return ret;
589 }
590
591 /**
592  * Discover OC resources
593  *
594  * @param method          - method to perform on the resource
595  * @param qos             - Quality of Service the request will be sent on
596  * @param token           - token which will added to the request
597  * @param Uri             - URI of the resource to interact with
598  * @param payload         - the request payload to be added to the request before sending
599  *                          by the stack when discovery or resource interaction is complete
600  * @param options         - The address of an array containing the vendor specific
601  *                          header options to be sent with the request
602  * @return
603  *   0   - success
604  *   TBD - TBD error
605  */
606 OCStackResult OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * token,
607                      const char *Uri, const char *payload, OCHeaderOption * options, uint8_t numOptions)
608 {
609
610     OCStackResult ret = OC_STACK_ERROR;
611     coap_pdu_t *pdu = NULL;
612     coap_uri_t uri;
613     OCDevAddr dst;
614     uint8_t ipAddr[4] = { 0 };
615     uint16_t port = 0;
616     coap_list_t *optList = NULL;
617     uint8_t coapMsgType;
618     uint8_t coapMethod;
619     uint32_t observeOption;
620     coap_send_flags_t flag = (coap_send_flags_t)0;
621
622     OC_LOG(INFO, TAG, PCF("Entering OCDoCoAPResource"));
623
624     if (Uri) {
625         OC_LOG_V(INFO, TAG, "URI = %s", Uri);
626         VERIFY_SUCCESS(coap_split_uri((unsigned char * )Uri, strlen(Uri), &uri), OC_STACK_OK);
627
628         // Generate the destination address
629         if (uri.host.length && ParseIPv4Address(uri.host.s, ipAddr, &port)) {
630             OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], uri.port,
631                     &dst);
632         } else {
633             goto exit;
634         }
635
636         VERIFY_SUCCESS(FormOptionList(&optList, NULL, NULL, 0, NULL,
637                 (uint16_t*)&uri.port, uri.path.length, uri.path.s, uri.query.length,
638                 uri.query.s, options, numOptions), OC_STACK_OK);
639
640         //TODO : Investigate the scenario where there will be no uri for OCDoCoAPResource
641         //flag = (coap_send_flags_t) (uri.secure ? SEND_SECURE_PORT : 0);
642         OC_LOG_V(DEBUG, TAG, "uri.host.s %s", uri.host.s);
643         OC_LOG_V(DEBUG, TAG, "uri.path.s %s", uri.path.s);
644         OC_LOG_V(DEBUG, TAG, "uri.port %d", uri.port);
645         OC_LOG_V(DEBUG, TAG, "uri.query.s %s", uri.query.s);
646     }
647
648     coapMsgType = OCToCoAPQoS(qos);
649
650     // Decide method type
651     switch (method) {
652         case OC_REST_GET:
653         #ifdef WITH_PRESENCE
654         case OC_REST_PRESENCE:
655         #endif
656             coapMethod = COAP_REQUEST_GET;
657             break;
658         case OC_REST_PUT:
659             coapMethod = COAP_REQUEST_PUT;
660             break;
661         case OC_REST_POST:
662             coapMethod = COAP_REQUEST_POST;
663             break;
664         case OC_REST_DELETE:
665             coapMethod = COAP_REQUEST_DELETE;
666             break;
667         case OC_REST_OBSERVE_ALL:
668         case OC_REST_OBSERVE:
669         case OC_REST_CANCEL_OBSERVE:
670             coapMethod = COAP_REQUEST_GET;
671             observeOption = (method == OC_REST_CANCEL_OBSERVE)?
672                     OC_RESOURCE_OBSERVE_DEREGISTER:OC_RESOURCE_OBSERVE_REGISTER;
673             coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_OBSERVE,
674                         sizeof(observeOption), (uint8_t *)&observeOption), OrderOptions);
675             break;
676         default:
677             coapMethod = OC_REST_NOMETHOD;
678             OC_LOG(FATAL, TAG, PCF("OCDoCoAPResource only supports GET, PUT, & OBSERVE methods"));
679             break;
680     }
681
682     VERIFY_NON_NULL(gCoAPCtx);
683     pdu = GenerateCoAPPdu(coapMsgType, coapMethod,
684             coap_new_message_id(gCoAPCtx), token,
685             (unsigned char*) payload, optList);
686     VERIFY_NON_NULL(pdu);
687
688     ret = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &dst, pdu, flag);
689
690 exit:
691     if (ret!= OC_STACK_OK)
692     {
693         OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu"));
694     }
695     return ret;
696 }
697
698 OCStackResult OCSendCoAPNotification (unsigned char * uri, OCDevAddr *dstAddr,
699                        OCQualityOfService qos, OCCoAPToken * token,
700                        unsigned char *payload, OCResource *resPtr, uint32_t maxAge)
701 {
702     OCStackResult result = OC_STACK_ERROR;
703     coap_list_t *optList = NULL;
704     uint8_t coapMsgType = COAP_MESSAGE_NON;
705     uint8_t mediaType = COAP_MEDIATYPE_APPLICATION_JSON;
706     coap_pdu_t *sendPdu;
707
708     OC_LOG(INFO, TAG, PCF("Entering OCSendCoAPNotification"));
709
710     coapMsgType = OCToCoAPQoS(qos);
711
712     #ifdef WITH_PRESENCE
713     if(!strcmp((const char *)uri, OC_PRESENCE_URI))
714     {
715         result = FormOptionList(&optList, &mediaType, NULL, 0, NULL,
716                 NULL, strlen((char *)uri), uri, 0, NULL, NULL, 0);
717     }
718     else
719     {
720     #endif
721         result = FormOptionList(&optList, &mediaType, &maxAge, sizeof(resPtr->sequenceNum),
722                 &resPtr->sequenceNum, NULL, strlen((char *)uri), uri, 0, NULL, NULL, 0);
723     #ifdef WITH_PRESENCE
724     }
725     #endif
726     VERIFY_SUCCESS(result, OC_STACK_OK);
727
728     if(resPtr->resourceProperties == 0)
729     {
730         result = OC_STACK_RESOURCE_DELETED;
731     }
732
733     sendPdu = GenerateCoAPPdu(
734             coapMsgType == COAP_MESSAGE_CON ? COAP_MESSAGE_CON : COAP_MESSAGE_NON,
735                     OCToCoAPResponseCode(result), coap_new_message_id(gCoAPCtx),
736                     token, payload, optList);
737     VERIFY_NON_NULL(sendPdu);
738     coap_show_pdu(sendPdu);
739
740     // TODO : resourceProperties will determine if the packet will be send using secure port
741     if(SendCoAPPdu(gCoAPCtx, (coap_address_t*) dstAddr, sendPdu , (coap_send_flags_t)0 )
742             != OC_STACK_OK)
743     {
744         OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu"));
745     }
746     return OC_STACK_OK;
747 exit:
748     return OC_STACK_ERROR;
749 }
750
751 /**
752  * Stop the CoAP client or server processing
753  *
754  * @return 0 - success, else - TBD error
755  */
756 OCStackResult OCStopCoAP() {
757     OC_LOG(INFO, TAG, PCF("Entering OCStopCoAP"));
758     coap_free_context(gCoAPCtx);
759     gCoAPCtx = NULL;
760     return OC_STACK_OK;
761 }
762
763 /**
764  * Called in main loop of CoAP client or server.  Allows low-level CoAP processing of
765  * send, receive, timeout, discovery, callbacks, etc.
766  *
767  * @return 0 - success, else - TBD error
768  */
769 OCStackResult OCProcessCoAP() {
770
771     OC_LOG(INFO, TAG, PCF("Entering OCProcessCoAP"));
772     int read = 0;
773     read = coap_read(gCoAPCtx, gCoAPCtx->sockfd);
774     if(read > 0)
775     {
776         OC_LOG(INFO, TAG, PCF("This is a Unicast<============"));
777     }
778     if (-1 != gCoAPCtx->sockfd_wellknown) {
779         read = coap_read(gCoAPCtx, gCoAPCtx->sockfd_wellknown);
780         if(read > 0)
781         {
782             OC_LOG(INFO, TAG, PCF("This is a Multicast<==========="));
783         }
784     }
785     coap_dispatch(gCoAPCtx);
786
787     HandleSendQueue(gCoAPCtx);
788
789     return OC_STACK_OK;
790 }
791