fe7c5f737135a7fd7cfc0aa27b11698249e8a183
[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 coap_context_t *gCoAPCtx = NULL;
59
60 //=============================================================================
61 // Helper Functions
62 //=============================================================================
63
64 //generate a coap token
65 void OCGenerateCoAPToken(OCCoAPToken * token)
66 {
67     if (token)
68     {
69         token->tokenLength = MAX_TOKEN_LENGTH;
70         OCFillRandomMem((uint8_t*)token->token, token->tokenLength);
71     }
72 }
73
74 //This function is called back by libcoap when ack or rst are received
75 static void HandleCoAPAckRst(struct coap_context_t * ctx, uint8_t msgType,
76         const coap_queue_t * sentQueue){
77
78     // silence warnings
79     (void) ctx;
80     coap_pdu_t * sentPdu = sentQueue->pdu;
81     OCStackResult result = OC_STACK_ERROR;
82     uint32_t observationOption = OC_OBSERVE_NO_OPTION;
83     // {{0}} to eliminate warning for known compiler bug 53119
84     // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119
85
86 #ifdef CA_INT
87     CAToken_t  sentToken = NULL;
88 #else // CA_INT
89     OCCoAPToken sentToken = {{0}};
90 #endif // CA_INT
91
92     result = ParseCoAPPdu(sentPdu, NULL, NULL, &observationOption, NULL, NULL, NULL,
93             NULL, NULL, NULL, NULL, NULL);
94     VERIFY_SUCCESS(result, OC_STACK_OK);
95
96     // fill OCCoAPToken structure
97     RetrieveOCCoAPToken(sentPdu, &sentToken);
98
99     if(msgType == COAP_MESSAGE_RST)
100     {
101         if(myStackMode != OC_CLIENT)
102         {
103             result = OCStackFeedBack(&sentToken, OC_OBSERVER_NOT_INTERESTED);
104             if(result == OC_STACK_OK)
105             {
106 #ifdef CA_INT
107                 OC_LOG_V(DEBUG, TAG,
108                         "Received RST, removing all queues associated with Token %d bytes",
109                         CA_MAX_TOKEN_LEN);
110                 OC_LOG_BUFFER(INFO, TAG, sentToken, CA_MAX_TOKEN_LEN);
111                 coap_cancel_all_messages(ctx, &sentQueue->remote, (unsigned char *)sentToken,
112                         CA_MAX_TOKEN_LEN);
113 #else
114                 OC_LOG_V(DEBUG, TAG,
115                         "Received RST, removing all queues associated with Token %d bytes",
116                         sentToken.tokenLength);
117                 OC_LOG_BUFFER(INFO, TAG, sentToken.token, sentToken.tokenLength);
118                 coap_cancel_all_messages(ctx, &sentQueue->remote, sentToken.token,
119                         sentToken.tokenLength);
120 #endif
121             }
122         }
123     }
124     else if(observationOption != OC_OBSERVE_NO_OPTION && msgType == COAP_MESSAGE_ACK)
125     {
126 #ifdef CA_INT
127 #else
128         OC_LOG_V(DEBUG, TAG, "Received ACK, for Token %d bytes",sentToken.tokenLength);
129         OC_LOG_BUFFER(INFO, TAG, sentToken.token, sentToken.tokenLength);
130 #endif
131         // now the observer is still interested
132         if(myStackMode != OC_CLIENT)
133         {
134             OCStackFeedBack(&sentToken, OC_OBSERVER_STILL_INTERESTED);
135         }
136     }
137 exit:
138     return;
139 }
140
141 //This function is called back by libcoap when a request is received
142 static void HandleCoAPRequests(struct coap_context_t *ctx,
143         const coap_queue_t * rcvdRequest)
144 {
145     // silence warnings
146     (void) ctx;
147     OCServerProtocolRequest protocolRequest = {(OCMethod)0};
148     coap_block_t rcvdBlock1;
149     coap_block_t rcvdBlock2;
150     memset(&rcvdBlock1, COAP_BLOCK_FILL_VALUE, sizeof(coap_block_t));
151     memset(&rcvdBlock2, COAP_BLOCK_FILL_VALUE, sizeof(coap_block_t));
152     uint16_t rcvdSize1 = 0;
153     coap_pdu_t * rcvdPdu = rcvdRequest->pdu;
154     coap_pdu_t * sendPdu = NULL;
155     coap_send_flags_t sendFlag;
156     OCStackResult result = OC_STACK_ERROR;
157     OCStackResult requestResult = OC_STACK_ERROR;
158
159     if(myStackMode == OC_CLIENT)
160     {
161         //TODO: should the client be responding to requests?
162         return;
163     }
164
165     protocolRequest.observationOption = OC_OBSERVE_NO_OPTION;
166     protocolRequest.qos = (rcvdPdu->hdr->type == COAP_MESSAGE_CON) ?
167             OC_HIGH_QOS : OC_LOW_QOS;
168     protocolRequest.coapID = rcvdPdu->hdr->id;
169     protocolRequest.delayedResNeeded = rcvdRequest->delayedResNeeded;
170     protocolRequest.secured = rcvdRequest->secure;
171
172     // fill OCCoAPToken structure
173     RetrieveOCCoAPToken(rcvdPdu, &protocolRequest.requestToken);
174 #ifdef CA_INT
175 #else
176     OC_LOG_V(INFO, TAG, " Token received %d bytes",
177             protocolRequest.requestToken.tokenLength);
178     OC_LOG_BUFFER(INFO, TAG, protocolRequest.requestToken.token,
179             protocolRequest.requestToken.tokenLength);
180 #endif
181
182     // fill OCDevAddr
183     memcpy(&protocolRequest.requesterAddr, (OCDevAddr *) &rcvdRequest->remote,
184             sizeof(OCDevAddr));
185
186     // Retrieve Uri and Query from received coap pdu
187     result =  ParseCoAPPdu(rcvdPdu, protocolRequest.resourceUrl,
188             protocolRequest.query,
189             &(protocolRequest.observationOption), NULL,
190             &(protocolRequest.numRcvdVendorSpecificHeaderOptions),
191             protocolRequest.rcvdVendorSpecificHeaderOptions,
192             &rcvdBlock1, &rcvdBlock2, &rcvdSize1, NULL,
193             protocolRequest.reqJSONPayload);
194     VERIFY_SUCCESS(result, OC_STACK_OK);
195
196     switch (rcvdPdu->hdr->code)
197     {
198         case COAP_REQUEST_GET:
199         {
200             protocolRequest.method = OC_REST_GET;
201             break;
202         }
203         case COAP_REQUEST_POST:
204         {
205             protocolRequest.method = OC_REST_POST;
206             break;
207         }
208         case COAP_REQUEST_DELETE:
209         {
210             protocolRequest.method = OC_REST_DELETE;
211             break;
212         }
213         case COAP_REQUEST_PUT:
214         {
215             protocolRequest.method = OC_REST_PUT;
216             break;
217         }
218         default:
219         {
220             OC_LOG_V(ERROR, TAG, "Received CoAP method %d not supported",
221                     rcvdPdu->hdr->code);
222             goto exit;
223         }
224     }
225
226     if(rcvdBlock1.szx != 7)
227     {
228         protocolRequest.reqPacketSize = 1 << (rcvdBlock1.szx + 4);
229         protocolRequest.reqMorePacket = rcvdBlock1.m;
230         protocolRequest.reqPacketNum  = rcvdBlock1.num;
231     }
232     else
233     {
234         // No block1 received
235         rcvdSize1= strlen((const char*)protocolRequest.reqJSONPayload)+1;
236         protocolRequest.reqTotalSize = rcvdSize1;
237     }
238
239     if(rcvdBlock2.szx != 7)
240     {
241         protocolRequest.resPacketSize = 1 << (rcvdBlock2.szx + 4);
242         protocolRequest.resPacketNum  = rcvdBlock2.num;
243     }
244
245     requestResult = HandleStackRequests(&protocolRequest);
246
247     if(requestResult == OC_STACK_VIRTUAL_DO_NOT_HANDLE ||
248             requestResult == OC_STACK_OK ||
249             requestResult == OC_STACK_RESOURCE_CREATED ||
250             requestResult == OC_STACK_RESOURCE_DELETED ||
251             requestResult == OC_STACK_INVALID_DEVICE_INFO)
252     {
253         goto exit;
254     }
255     else if(requestResult == OC_STACK_NO_MEMORY ||
256             requestResult == OC_STACK_ERROR ||
257             requestResult == OC_STACK_NOTIMPL ||
258             requestResult == OC_STACK_NO_RESOURCE ||
259             requestResult == OC_STACK_RESOURCE_ERROR)
260     {
261         // TODO: should we send an error also when we receive a non-secured request to a secure resource?
262         // TODO: should we consider some sort of error response
263         OC_LOG(DEBUG, TAG, PCF("We should send some sort of error message"));
264         // generate the pdu, if the request was CON, then the response is ACK, otherwire NON
265         sendPdu = GenerateCoAPPdu((rcvdPdu->hdr->type == COAP_MESSAGE_CON)? COAP_MESSAGE_ACK : COAP_MESSAGE_NON,
266                 OCToCoAPResponseCode(requestResult), rcvdPdu->hdr->id,
267                 &protocolRequest.requestToken, NULL, NULL);
268         VERIFY_NON_NULL(sendPdu);
269         coap_show_pdu(sendPdu);
270         sendFlag = (coap_send_flags_t)(rcvdRequest->secure ? SEND_SECURE_PORT : 0);
271         if(SendCoAPPdu(gCoAPCtx, (coap_address_t*) &(rcvdRequest->remote), sendPdu,
272                 sendFlag)
273                 != OC_STACK_OK){
274             OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu"));
275         }
276         goto exit;
277     }
278     else if(requestResult == OC_STACK_SLOW_RESOURCE)
279     {
280         if(rcvdPdu->hdr->type == COAP_MESSAGE_CON)
281         {
282             // generate the pdu, if the request was CON, then the response is ACK, otherwire NON
283             sendPdu = GenerateCoAPPdu(COAP_MESSAGE_ACK, 0, rcvdPdu->hdr->id,
284                     NULL, NULL, NULL);
285             VERIFY_NON_NULL(sendPdu);
286             coap_show_pdu(sendPdu);
287
288             sendFlag = (coap_send_flags_t)(rcvdRequest->secure ? SEND_SECURE_PORT : 0);
289             if(SendCoAPPdu(gCoAPCtx, (coap_address_t*) &(rcvdRequest->remote), sendPdu,
290                     sendFlag)
291                     != OC_STACK_OK){
292                 OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu"));
293             }
294         }
295         else
296         {
297             goto exit;
298         }
299     }
300 exit:
301     return;
302 }
303
304 uint32_t GetTime(float afterSeconds)
305 {
306     coap_tick_t now;
307     coap_ticks(&now);
308     return now + (uint32_t)(afterSeconds * COAP_TICKS_PER_SECOND);
309 }
310
311 //This function is called back by libcoap when a response is received
312 static void HandleCoAPResponses(struct coap_context_t *ctx,
313         const coap_queue_t * rcvdResponse) {
314     OCStackResult result = OC_STACK_OK;
315 #ifdef CA_INT
316     CAToken_t  rcvdToken = NULL;
317 #else // CA_INT
318     OCCoAPToken rcvdToken = {{0}};
319 #endif // CA_INT
320     OCResponse * response = NULL;
321     OCClientResponse * clientResponse = NULL;
322     unsigned char bufRes[MAX_RESPONSE_LENGTH] = {0};
323     coap_pdu_t * sendPdu = NULL;
324     coap_pdu_t * recvPdu = NULL;
325     uint8_t remoteIpAddr[4] = {0};
326     uint16_t remotePortNu = 0;
327     uint32_t sequenceNumber = OC_OBSERVE_NO_OPTION;
328     uint32_t maxAge = 0;
329     unsigned char fullUri[MAX_URI_LENGTH] = { 0 };
330     unsigned char rcvdUri[MAX_URI_LENGTH] = { 0 };
331     coap_block_t rcvdBlock1 = {COAP_BLOCK_FILL_VALUE};
332     coap_block_t rcvdBlock2 = {COAP_BLOCK_FILL_VALUE};
333     uint16_t rcvdSize2 = 0;
334
335     VERIFY_NON_NULL(ctx);
336     VERIFY_NON_NULL(rcvdResponse);
337     recvPdu = rcvdResponse->pdu;
338
339     clientResponse = (OCClientResponse *) OCCalloc(1, sizeof(OCClientResponse));
340
341     result = ParseCoAPPdu(recvPdu, rcvdUri, NULL, &sequenceNumber, &maxAge,
342             &(clientResponse->numRcvdVendorSpecificHeaderOptions),
343             clientResponse->rcvdVendorSpecificHeaderOptions,
344             &rcvdBlock1, &rcvdBlock2, NULL, &rcvdSize2, bufRes);
345     VERIFY_SUCCESS(result, OC_STACK_OK);
346
347     // get the address of the remote
348     OCDevAddrToIPv4Addr((OCDevAddr *) &(rcvdResponse->remote), remoteIpAddr,
349             remoteIpAddr + 1, remoteIpAddr + 2, remoteIpAddr + 3);
350     OCDevAddrToPort((OCDevAddr *) &(rcvdResponse->remote), &remotePortNu);
351     snprintf((char *)fullUri, MAX_URI_LENGTH, "coap://%d.%d.%d.%d:%d%s",
352             remoteIpAddr[0],remoteIpAddr[1],remoteIpAddr[2],remoteIpAddr[3],
353             remotePortNu,rcvdUri);
354
355     // fill OCCoAPToken structure
356     RetrieveOCCoAPToken(recvPdu, &rcvdToken);
357 #ifdef CA_INT
358 #else
359     OC_LOG_V(INFO, TAG,"Received a pdu with Token", rcvdToken.tokenLength);
360     OC_LOG_BUFFER(INFO, TAG, rcvdToken.token, rcvdToken.tokenLength);
361 #endif
362
363     // fill OCClientResponse structure
364     result = FormOCClientResponse(clientResponse, CoAPToOCResponseCode(recvPdu->hdr->code),
365             (OCDevAddr *) &(rcvdResponse->remote), sequenceNumber, NULL);
366     VERIFY_SUCCESS(result, OC_STACK_OK);
367
368
369     result = FormOCResponse(&response, NULL, maxAge, fullUri, rcvdUri,
370             &rcvdToken, clientResponse, bufRes);
371     VERIFY_SUCCESS(result, OC_STACK_OK);
372
373     result = HandleStackResponses(response);
374
375     if(result == OC_STACK_ERROR)
376     {
377         OC_LOG(INFO, TAG, PCF("Received a notification or response that is malformed or incorrect \
378                          ------------ sending RESET"));
379         sendPdu = GenerateCoAPPdu(COAP_MESSAGE_RST, 0,
380                 recvPdu->hdr->id, NULL, NULL, NULL);
381         VERIFY_NON_NULL(sendPdu);
382         result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote, sendPdu,
383                      (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0));
384         VERIFY_SUCCESS(result, OC_STACK_OK);
385     }
386     else if(result == OC_STACK_NO_MEMORY)
387     {
388         OC_LOG(ERROR, TAG, PCF("Received a notification or response. While processing, local " \
389                 "platform or memory pool ran out memory."));
390     }
391
392     if(recvPdu->hdr->type == COAP_MESSAGE_CON)
393     {
394         sendPdu = GenerateCoAPPdu(COAP_MESSAGE_ACK, 0,
395                 recvPdu->hdr->id, NULL, NULL, NULL);
396         VERIFY_NON_NULL(sendPdu);
397         result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote,
398                 sendPdu,
399                 (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0));
400         VERIFY_SUCCESS(result, OC_STACK_OK);
401     }
402
403     exit:
404         OCFree(response);
405         OCFree(clientResponse);
406 }
407
408 //=============================================================================
409 // Functions
410 //=============================================================================
411
412 /**
413  * Initialize the CoAP client or server with its IPv4 address and CoAP port
414  *
415  * @param ipAddr
416  *     IP Address of host device
417  * @param port
418  *     Port of host device
419  * @param mode
420  *     Host device is client, server, or client-server
421  *
422  * @return
423  *   0   - success
424  *   TBD - TBD error
425  */
426 OCStackResult OCInitCoAP(const char *address, uint16_t port, OCMode mode) {
427
428     OCStackResult ret = OC_STACK_ERROR;
429
430     TODO ("Below should go away and be replaced by OC_LOG");
431     coap_log_t log_level = (coap_log_t)(LOG_DEBUG + 1);
432     OCDevAddr mcastAddr;
433     uint8_t ipAddr[4] = { 0 };
434     uint16_t parsedPort = 0;
435
436     OC_LOG(INFO, TAG, PCF("Entering OCInitCoAP"));
437
438     coap_set_log_level(log_level);
439
440     if (address)
441     {
442         if (!ParseIPv4Address((unsigned char *) address, ipAddr, &parsedPort))
443         {
444             ret = OC_STACK_ERROR;
445             goto exit;
446         }
447
448         OC_LOG_V(INFO, TAG, "Parsed IP Address %d.%d.%d.%d",
449                                ipAddr[0],ipAddr[1],ipAddr[2],ipAddr[3]);
450     }
451
452     gCoAPCtx = coap_new_context(ipAddr, port);
453     VERIFY_NON_NULL(gCoAPCtx);
454
455     // To allow presence notification work we need to init socket gCoAPCtx->sockfd_wellknown
456     // for servers as well as clients
457     OCBuildIPv4Address(COAP_WK_IPAddr_0, COAP_WK_IPAddr_1, COAP_WK_IPAddr_2,
458             COAP_WK_IPAddr_3, COAP_DEFAULT_PORT, &mcastAddr);
459     VERIFY_SUCCESS(
460             coap_join_wellknown_group(gCoAPCtx,
461                     (coap_address_t* )&mcastAddr), 0);
462
463     coap_register_request_handler(gCoAPCtx, HandleCoAPRequests);
464     coap_register_response_handler(gCoAPCtx, HandleCoAPResponses);
465     coap_register_ack_rst_handler(gCoAPCtx, HandleCoAPAckRst);
466
467     ret = OC_STACK_OK;
468
469 exit:
470     if (ret != OC_STACK_OK)
471     {
472         OCStopCoAP();
473     }
474     return ret;
475 }
476
477 /**
478  * Discover OC resources
479  *
480  * @param method          - method to perform on the resource
481  * @param qos             - Quality of Service the request will be sent on
482  * @param token           - token which will added to the request
483  * @param Uri             - URI of the resource to interact with
484  * @param payload         - the request payload to be added to the request before sending
485  *                          by the stack when discovery or resource interaction is complete
486  * @param options         - The address of an array containing the vendor specific
487  *                          header options to be sent with the request
488  * @return
489  *   0   - success
490  *   TBD - TBD error
491  */
492 #ifdef CA_INT
493 OCStackResult OCDoCoAPResource(OCMethod method, OCQualityOfService qos, CAToken_t * token,
494                      const char *Uri, const char *payload, OCHeaderOption * options, uint8_t numOptions)
495 #else
496 OCStackResult OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * token,
497                      const char *Uri, const char *payload, OCHeaderOption * options, uint8_t numOptions)
498 #endif
499 {
500
501     OCStackResult ret = OC_STACK_ERROR;
502     coap_pdu_t *pdu = NULL;
503     coap_uri_t uri;
504     OCDevAddr dst;
505     uint8_t ipAddr[4] = { 0 };
506     uint16_t port = 0;
507     coap_list_t *optList = NULL;
508     uint8_t coapMsgType;
509     uint8_t coapMethod;
510     uint32_t observeOption;
511     coap_send_flags_t flag = (coap_send_flags_t)0;
512
513     OC_LOG(INFO, TAG, PCF("Entering OCDoCoAPResource"));
514
515     if (Uri) {
516         OC_LOG_V(INFO, TAG, "URI = %s", Uri);
517         VERIFY_SUCCESS(coap_split_uri((unsigned char * )Uri, strlen(Uri), &uri), OC_STACK_OK);
518
519         // Generate the destination address
520         if (uri.host.length && ParseIPv4Address(uri.host.s, ipAddr, &port)) {
521             OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], uri.port,
522                     &dst);
523         } else {
524             goto exit;
525         }
526
527         VERIFY_SUCCESS(FormOptionList(&optList, NULL, NULL, NULL,
528                 (uint16_t*)&uri.port, uri.path.length, uri.path.s, uri.query.length,
529                 uri.query.s, options, numOptions), OC_STACK_OK);
530
531         //TODO : Investigate the scenario where there will be no uri for OCDoCoAPResource
532         flag = (coap_send_flags_t) (uri.secure ? SEND_SECURE_PORT : 0);
533         OC_LOG_V(DEBUG, TAG, "uri.host.s %s", uri.host.s);
534         OC_LOG_V(DEBUG, TAG, "uri.path.s %s", uri.path.s);
535         OC_LOG_V(DEBUG, TAG, "uri.port %d", uri.port);
536         OC_LOG_V(DEBUG, TAG, "uri.query.s %s", uri.query.s);
537         OC_LOG_V(DEBUG, TAG, "secure uri %d", uri.secure);
538     }
539
540     coapMsgType = OCToCoAPQoS(qos, ipAddr);
541
542     // Decide method type
543     switch (method) {
544         case OC_REST_GET:
545             coapMethod = COAP_REQUEST_GET;
546             break;
547         case OC_REST_PUT:
548             coapMethod = COAP_REQUEST_PUT;
549             break;
550         case OC_REST_POST:
551             coapMethod = COAP_REQUEST_POST;
552             break;
553         case OC_REST_DELETE:
554             coapMethod = COAP_REQUEST_DELETE;
555             break;
556         case OC_REST_OBSERVE_ALL:
557         case OC_REST_OBSERVE:
558         case OC_REST_CANCEL_OBSERVE:
559             coapMethod = COAP_REQUEST_GET;
560             observeOption = (method == OC_REST_CANCEL_OBSERVE)?
561                     OC_OBSERVE_DEREGISTER:OC_OBSERVE_REGISTER;
562             coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_OBSERVE,
563                         sizeof(observeOption), (uint8_t *)&observeOption), OrderOptions);
564             break;
565         default:
566             coapMethod = OC_REST_NOMETHOD;
567             OC_LOG(FATAL, TAG, PCF("OCDoCoAPResource only supports GET, PUT, & OBSERVE methods"));
568             break;
569     }
570
571     VERIFY_NON_NULL(gCoAPCtx);
572     pdu = GenerateCoAPPdu(coapMsgType, coapMethod,
573             coap_new_message_id(gCoAPCtx), token,
574             (unsigned char*) payload, optList);
575     VERIFY_NON_NULL(pdu);
576
577     ret = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &dst, pdu, flag);
578
579 exit:
580     if (ret!= OC_STACK_OK)
581     {
582         OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu"));
583     }
584     return ret;
585 }
586
587 OCStackResult OCDoCoAPResponse(OCServerProtocolResponse *response)
588 {
589     OCStackResult result = OC_STACK_ERROR;
590     coap_pdu_t * sendPdu = NULL;
591     coap_list_t *optList = NULL;
592     uint8_t msgType = COAP_MESSAGE_NON;
593     uint8_t mediaType = COAP_MEDIATYPE_APPLICATION_JSON;
594     uint32_t maxAge = 0x2ffff;
595     coap_send_flags_t sendFlag = (coap_send_flags_t)0;
596
597     //uint32_t observeOption = OC_OBSERVE_NO_OPTION;
598     //OCStackResult responseResult;
599
600     OC_LOG(INFO, TAG, PCF("Entering OCDoCoAPResponse"));
601
602     if(response->notificationFlag && response->qos == OC_HIGH_QOS)
603     {
604         msgType = COAP_MESSAGE_CON;
605     }
606     else if(response->notificationFlag && response->qos != OC_HIGH_QOS)
607     {
608         msgType = COAP_MESSAGE_NON;
609     }
610     else if(!response->notificationFlag && !response->slowFlag && response->qos == OC_HIGH_QOS)
611     {
612         msgType = COAP_MESSAGE_ACK;
613     }
614     else if(!response->notificationFlag && response->slowFlag && response->qos == OC_HIGH_QOS)
615     {
616         msgType = COAP_MESSAGE_CON;
617     }
618     else if(!response->notificationFlag)
619     {
620         msgType = COAP_MESSAGE_NON;
621     }
622
623     if(response->coapID == 0)
624     {
625         response->coapID = coap_new_message_id(gCoAPCtx);
626     }
627
628     if (response->observationOption != OC_OBSERVE_NO_OPTION)
629     {
630         result = FormOptionList(&optList, &mediaType, &maxAge,
631                 &response->observationOption, NULL,
632                 strlen((char *)response->resourceUri), response->resourceUri,
633                 0, NULL,
634                 response->sendVendorSpecificHeaderOptions,
635                 response->numSendVendorSpecificHeaderOptions);
636     }
637     else
638     {
639         result = FormOptionList(&optList, &mediaType, &maxAge,
640                 NULL, NULL,
641                 strlen((char *)response->resourceUri), response->resourceUri,
642                 0, NULL,
643                 response->sendVendorSpecificHeaderOptions,
644                 response->numSendVendorSpecificHeaderOptions);
645     }
646     VERIFY_SUCCESS(result, OC_STACK_OK);
647
648     sendPdu = GenerateCoAPPdu(msgType, OCToCoAPResponseCode(response->result),
649             response->coapID, response->requestToken, (unsigned char *)response->payload,
650             optList);
651
652     VERIFY_NON_NULL(sendPdu);
653     coap_show_pdu(sendPdu);
654
655     sendFlag = (coap_send_flags_t)(response->delayedResNeeded ? SEND_DELAYED : 0);
656     sendFlag = (coap_send_flags_t)( sendFlag | (response->secured ? SEND_SECURE_PORT : 0));
657
658     if (SendCoAPPdu(gCoAPCtx, (coap_address_t *) (response->requesterAddr), sendPdu, sendFlag)
659             != OC_STACK_OK)
660     {
661         OC_LOG(ERROR, TAG, PCF("A problem occurred in sending a pdu"));
662         return OC_STACK_ERROR;
663     }
664     return OC_STACK_OK;
665 exit:
666     OC_LOG(ERROR, TAG, PCF("Error formatting server response"));
667     return OC_STACK_ERROR;
668 }
669
670 /**
671  * Stop the CoAP client or server processing
672  *
673  * @return 0 - success, else - TBD error
674  */
675 OCStackResult OCStopCoAP() {
676     OC_LOG(INFO, TAG, PCF("Entering OCStopCoAP"));
677     coap_free_context(gCoAPCtx);
678     gCoAPCtx = NULL;
679     return OC_STACK_OK;
680 }
681
682 /**
683  * Called in main loop of CoAP client or server.  Allows low-level CoAP processing of
684  * send, receive, timeout, discovery, callbacks, etc.
685  *
686  * @return 0 - success, else - TBD error
687  */
688 OCStackResult OCProcessCoAP() {
689     int read = 0;
690     read = coap_read(gCoAPCtx, gCoAPCtx->sockfd);
691     if(read > 0) {
692         OC_LOG(INFO, TAG, PCF("This is a Unicast<============"));
693     }
694     if (-1 != gCoAPCtx->sockfd_wellknown) {
695         read = coap_read(gCoAPCtx, gCoAPCtx->sockfd_wellknown);
696         if(read > 0)
697         {
698             OC_LOG(INFO, TAG, PCF("This is a Multicast<==========="));
699         }
700     }
701     if (-1 != gCoAPCtx->sockfd_dtls) {
702         read = coap_read(gCoAPCtx, gCoAPCtx->sockfd_dtls);
703         if(read > 0)
704         {
705             OC_LOG(INFO, TAG, PCF("This is a Secure packet<==========="));
706         }
707     }
708     coap_dispatch(gCoAPCtx);
709
710     HandleSendQueue(gCoAPCtx);
711
712     return OC_STACK_OK;
713 }
714
715
716 /**
717  * Retrieve the info about the end-point where resource is being hosted.
718  * Currently, this method only provides the IP port with which the socket
719  * is bound.
720  *
721  * @return 0 - success, else - TBD error
722  */
723 OCStackResult OCGetResourceEndPointInfo (OCResource *resPtr, void *info) {
724
725     OCStackResult result = OC_STACK_ERROR;
726     int sfd;
727     OC_LOG(INFO, TAG, PCF("Entering OCGetResourceEndPointInfo"));
728     VERIFY_NON_NULL(resPtr);
729     VERIFY_NON_NULL(info);
730
731     sfd = (resPtr->resourceProperties & OC_SECURE) ? gCoAPCtx->sockfd_dtls :
732             gCoAPCtx->sockfd;
733
734     if (OCGetSocketInfo(sfd, (uint16_t*)info) == ERR_SUCCESS)
735         result = OC_STACK_OK;
736 exit:
737     return result;
738 }
739
740