Implemented libcoap's tinyDTLS interface
[contrib/iotivity.git] / resource / csdk / occoap / src / occoaphelper.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 // Includes
23 //-----------------------------------------------------------------------------
24 #include "occoaphelper.h"
25 #include "ocstackconfig.h"
26 #include "logger.h"
27 #include "ocobserve.h"
28 #include "coap_time.h"
29 #include "ocmalloc.h"
30
31 //-----------------------------------------------------------------------------
32 // Macros
33 //-----------------------------------------------------------------------------
34 #define TAG    PCF("OCCoAPHelper")
35 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG_V(FATAL, TAG, "%s is NULL", #arg); goto exit;} }
36
37 //=============================================================================
38 // Helper Functions
39 //=============================================================================
40
41 OCStackResult isVendorSpecific(uint16_t optionID)
42 {
43     if(optionID >= COAP_VENDOR_OPT_START && optionID <= COAP_MAX_OPT)
44     {
45         return OC_STACK_OK;
46     }
47     return OC_STACK_INVALID_OPTION;
48 }
49
50 // Convert OCStack code to CoAP code
51 uint8_t OCToCoAPResponseCode(OCStackResult result)
52 {
53     uint8_t ret;
54     switch(result)
55     {
56         case OC_STACK_OK :
57             ret = COAP_RESPONSE_200;
58             break;
59
60         case OC_STACK_RESOURCE_CREATED:
61             ret = COAP_RESPONSE_201;
62             break;
63
64         case OC_STACK_RESOURCE_DELETED:
65             ret = COAP_RESPONSE_202;
66             break;
67
68         case OC_STACK_INVALID_QUERY :
69             ret = COAP_RESPONSE_400;
70             break;
71
72         case OC_STACK_RESOURCE_ERROR:
73             return COAP_RESPONSE_403;
74             break;
75
76         case OC_STACK_NO_RESOURCE :
77             ret = COAP_RESPONSE_404;
78             break;
79
80         case OC_STACK_INVALID_METHOD :
81             ret = COAP_RESPONSE_405;
82             break;
83
84         default:
85             ret = COAP_RESPONSE_500;
86     }
87     return ret;
88 }
89
90 uint8_t OCToCoAPQoS(OCQualityOfService qos)
91 {
92     switch (qos)
93     {
94         case OC_HIGH_QOS:
95             return COAP_MESSAGE_CON;
96             break;
97         case OC_MEDIUM_QOS:
98         case OC_LOW_QOS:
99         case OC_NA_QOS:
100         default:
101             return COAP_MESSAGE_NON;
102             break;
103     }
104 }
105 // Convert CoAP code to OCStack code
106 OCStackResult CoAPToOCResponseCode(uint8_t coapCode)
107 {
108     OCStackResult ret;
109     int decimal;
110     switch(coapCode)
111     {
112         case COAP_RESPONSE_200 :
113             ret = OC_STACK_OK;
114             break;
115
116         case COAP_RESPONSE_201 :
117             ret = OC_STACK_RESOURCE_CREATED;
118             break;
119
120         case COAP_RESPONSE_202 :
121             ret = OC_STACK_RESOURCE_DELETED;
122             break;
123
124         case COAP_RESPONSE_400 :
125             ret = OC_STACK_INVALID_QUERY;
126             break;
127
128         case COAP_RESPONSE_403 :
129             ret = OC_STACK_RESOURCE_ERROR;
130             break;
131
132         case COAP_RESPONSE_404 :
133             ret = OC_STACK_NO_RESOURCE;
134             break;
135
136         case COAP_RESPONSE_405 :
137             ret = OC_STACK_INVALID_METHOD;
138             break;
139
140         default:
141             decimal = ((coapCode >> 5) * 100) + (coapCode & 31);
142             if (decimal >= 200 && decimal <= 231)
143             {
144                 ret = OC_STACK_OK;
145             }
146             else
147             {
148                 ret = OC_STACK_ERROR;
149             }
150     }
151     return ret;
152 }
153
154 // Retrieve Uri and Query from received coap pdu
155 OCStackResult ParseCoAPPdu(coap_pdu_t * pdu, unsigned char * uriBuf,
156         unsigned char * queryBuf, uint8_t * * observeOptionLoc,
157         uint8_t * * maxAgeOptionLoc, unsigned char * * payloadLoc,
158         OCHeaderOption * rcvVendorSpecificHeaderOptions,
159         uint8_t * numRcvVendorSpecificHeaderOptions)
160 {
161     coap_opt_filter_t filter;
162     coap_opt_iterator_t opt_iter;
163     coap_opt_t *option = NULL;
164     size_t bufLen = 0;
165     size_t optLen = 0;
166     uint8_t * observeOption = NULL;
167     uint8_t * maxAgeOption = NULL;
168     uint8_t optionFound = 0;
169
170     if(uriBuf)
171     {
172         // parse the Uri
173         coap_option_filter_clear(filter);
174         coap_option_setb(filter, COAP_OPTION_URI_PATH);
175         coap_option_iterator_init(pdu, &opt_iter, filter);
176         while ((option = coap_option_next(&opt_iter)))
177         {
178             optLen = COAP_OPT_LENGTH(option);
179             if (bufLen + 1 + optLen < MAX_URI_LENGTH)
180             {
181                 //we still have room in the buffer
182                 uriBuf[bufLen++] = '/';
183                 memcpy(uriBuf + bufLen, COAP_OPT_VALUE(option), optLen);
184                 bufLen += optLen;
185             }
186             else
187             {
188                 // TODO: we should check that resources do not have long uri at the resource creation
189                 return OC_STACK_NO_MEMORY;
190             }
191         }
192         uriBuf[bufLen] = '\0';
193     }
194
195     if(queryBuf)
196     {
197         // parse the Query
198         bufLen = 0;
199         coap_option_filter_clear(filter);
200         coap_option_setb(filter, COAP_OPTION_URI_QUERY);
201         coap_option_iterator_init(pdu, &opt_iter, filter);
202         while ((option = coap_option_next(&opt_iter)))
203         {
204             optLen = COAP_OPT_LENGTH(option);
205             if (bufLen + 1 + optLen < MAX_QUERY_LENGTH)
206             {
207                 //we still have room in the buffer
208                 memcpy(queryBuf + bufLen, COAP_OPT_VALUE(option), optLen);
209                 bufLen += optLen;
210                 queryBuf[bufLen++] = '&';
211             }
212             else
213             {
214                 // TODO: should it be OC_STACK_NO_MEMORY
215                 return OC_STACK_NO_MEMORY;
216             }
217         }
218         // delete last '&'
219         queryBuf[bufLen ? (bufLen - 1) : (bufLen)] = '\0';
220     }
221
222     if(observeOptionLoc)
223     {
224         optionFound = 0;
225         // parse the observe option
226         coap_option_filter_clear(filter);
227         coap_option_setb(filter, COAP_OPTION_OBSERVE);
228         coap_option_iterator_init(pdu, &opt_iter, filter);
229         while ((option = coap_option_next(&opt_iter)))
230         {
231             observeOption = (uint8_t *) OCMalloc(COAP_OPT_LENGTH(option));
232             if(!observeOption)
233             {
234                 return OC_STACK_NO_MEMORY;
235             }
236             memcpy(observeOption, COAP_OPT_VALUE(option),COAP_OPT_LENGTH(option));
237             optionFound = 1;
238             break;
239         }
240         if(optionFound)
241         {
242             *observeOptionLoc = observeOption;
243         }
244         else
245         {
246             OCFree(observeOption);
247             *observeOptionLoc = NULL;
248         }
249     }
250
251
252     if(maxAgeOptionLoc)
253     {
254         optionFound = 0;
255         // parse the observe option
256         coap_option_filter_clear(filter);
257         coap_option_setb(filter, COAP_OPTION_MAXAGE);
258         coap_option_iterator_init(pdu, &opt_iter, filter);
259         while ((option = coap_option_next(&opt_iter)))
260         {
261             maxAgeOption = (uint8_t *) OCMalloc(COAP_OPT_LENGTH(option));
262             if(!maxAgeOption)
263             {
264                 return OC_STACK_NO_MEMORY;
265             }
266             memcpy(maxAgeOption, COAP_OPT_VALUE(option),COAP_OPT_LENGTH(option));
267             optionFound = 1;
268             break;
269         }
270         if(optionFound)
271         {
272             *maxAgeOptionLoc = maxAgeOption;
273         }
274         else
275         {
276             OCFree(maxAgeOption);
277             *maxAgeOptionLoc = NULL;
278         }
279     }
280
281     if(rcvVendorSpecificHeaderOptions)
282     {
283         coap_option_filter_clear(filter);
284         coap_option_setbVendor(filter);
285         coap_option_iterator_init(pdu, &opt_iter, filter);
286         uint8_t i = 0;
287         while((option = coap_option_next(&opt_iter)))
288         {
289             if(i >= MAX_HEADER_OPTIONS ||
290                     COAP_OPT_LENGTH(option) > MAX_HEADER_OPTION_DATA_LENGTH)
291             {
292                 return OC_STACK_NO_MEMORY;
293             }
294             rcvVendorSpecificHeaderOptions[i].protocolID = OC_COAP_ID;
295             rcvVendorSpecificHeaderOptions[i].optionID = opt_iter.type;
296             rcvVendorSpecificHeaderOptions[i].optionLength = COAP_OPT_LENGTH(option);
297             memcpy(rcvVendorSpecificHeaderOptions[i].optionData, COAP_OPT_VALUE(option),
298                     rcvVendorSpecificHeaderOptions[i].optionLength);
299             OC_LOG_V(INFO, TAG, " Parsing option %d with", rcvVendorSpecificHeaderOptions[i].optionID);
300             OC_LOG_BUFFER(INFO, TAG, rcvVendorSpecificHeaderOptions[i].optionData,
301                     rcvVendorSpecificHeaderOptions[i].optionLength);
302             i++;
303             *numRcvVendorSpecificHeaderOptions = i;
304         }
305     }
306
307     // get the payload
308     if(payloadLoc)
309     {
310         coap_get_data(pdu, &bufLen, payloadLoc);
311     }
312
313     return OC_STACK_OK;
314 }
315
316 // Form the OCRequest struct
317 OCStackResult FormOCRequest(OCRequest * * requestLoc, OCQualityOfService qos,
318         unsigned char * uriBuf, OCObserveReq * observeReq,
319         OCEntityHandlerRequest * entityHandlerRequest,
320         uint8_t secure)
321 {
322     OCRequest * request = NULL;
323
324     // allocate it
325     request = (OCRequest *) OCMalloc(sizeof(OCRequest));
326     if (!request)
327     {
328         return OC_STACK_NO_MEMORY;
329     }
330
331     // fill in qos
332     request->qos = qos;
333
334     // fill in uri
335     request->resourceUrl = uriBuf;
336
337     request->secure = secure;
338
339     // fill in observe
340     request->observe = observeReq;
341
342     // add entityHandlerRequest
343     request->entityHandlerRequest = entityHandlerRequest;
344
345     //TODO: this needs to be filled in the future
346     request->sequenceNum = 0;
347
348     *requestLoc = request;
349     return OC_STACK_OK;
350 }
351
352 // Form the OCObserveReq struct
353 OCStackResult FormOCObserveReq(OCObserveReq ** observeReqLoc, uint32_t observeOption,
354             OCDevAddr * remote, OCCoAPToken * rcvdToken)
355 {
356     OCObserveReq * observeReq;
357
358     if(observeOption == OC_RESOURCE_NO_OBSERVE)
359     {
360         return OC_STACK_OK;
361     }
362
363     observeReq = (OCObserveReq *)OCMalloc(sizeof(OCObserveReq));
364     if(!observeReq)
365     {
366         *observeReqLoc = NULL;
367         return OC_STACK_NO_MEMORY;
368     }
369
370     observeReq->option = observeOption;
371     observeReq->subAddr = remote;
372     observeReq->token = rcvdToken;
373     observeReq->result = OC_STACK_OK;
374
375     *observeReqLoc = observeReq;
376     return OC_STACK_OK;
377 }
378
379 // Form the OCEntityHandlerRequest struct
380 OCStackResult FormOCEntityHandlerRequest(OCEntityHandlerRequest * entityHandlerRequestLoc,
381         OCMethod method, unsigned char * resBuf, unsigned char * bufReqPayload,
382         unsigned char * queryBuf, unsigned char *newResUriBuf)
383 {
384     if (entityHandlerRequestLoc)
385     {
386         //set it to NULL for now, it will be modified in ocstack
387         entityHandlerRequestLoc->resource = NULL;
388
389         entityHandlerRequestLoc->method = method;
390
391         // fill in query
392         entityHandlerRequestLoc->query = queryBuf;
393
394         // fill payload
395         entityHandlerRequestLoc->reqJSONPayload = bufReqPayload;
396
397         entityHandlerRequestLoc->resJSONPayload = resBuf;
398         entityHandlerRequestLoc->resJSONPayloadLen = MAX_RESPONSE_LENGTH;
399
400         entityHandlerRequestLoc->obsInfo = NULL;
401         entityHandlerRequestLoc->newResourceUri = newResUriBuf;
402
403         entityHandlerRequestLoc->numRcvdVendorSpecificHeaderOptions = 0;
404         entityHandlerRequestLoc->numSendVendorSpecificHeaderOptions = 0;
405         return OC_STACK_OK;
406     }
407
408     return OC_STACK_INVALID_PARAM;
409 }
410
411 // Retrieve the token from the PDU
412 void RetrieveOCCoAPToken(const coap_pdu_t * pdu, OCCoAPToken * rcvdToken)
413 {
414     if (pdu && rcvdToken)
415     {
416         rcvdToken->tokenLength = pdu->hdr->token_length;
417         memcpy(rcvdToken->token, pdu->hdr->token,
418             rcvdToken->tokenLength);
419     }
420 }
421
422 OCStackResult FormOCResponse(OCResponse * * responseLoc, ClientCB * cbNode,
423         uint8_t TTL, OCClientResponse * clientResponse)
424 {
425     OCResponse * response = (OCResponse *) OCMalloc(sizeof(OCResponse));
426     if (!response)
427     {
428         return OC_STACK_NO_MEMORY;
429     }
430     response->cbNode = cbNode;
431     response->TTL = TTL;
432     response->clientResponse = clientResponse;
433
434     *responseLoc = response;
435     return OC_STACK_OK;
436 }
437
438 OCStackResult FormOCClientResponse(OCClientResponse * clientResponse,
439         OCStackResult result, OCDevAddr * remote, uint32_t seqNum,
440         const unsigned char * resJSONPayload)
441 {
442     clientResponse->sequenceNumber = seqNum;
443     clientResponse->result = result;
444     clientResponse->addr = remote;
445     clientResponse->resJSONPayload = resJSONPayload;
446
447     return OC_STACK_OK;
448 }
449
450 OCStackResult FormOptionList(coap_list_t * * optListLoc, uint8_t * addMediaType,
451         uint32_t * addMaxAge, uint8_t observeOptionLength, uint32_t * observeOptionPtr,
452         uint16_t * addPortNumber, uint8_t uriLength, unsigned char * uri,
453         uint8_t queryLength, unsigned char * query,
454         OCHeaderOption * vendorSpecificHeaderOptions,
455         uint8_t numVendorSpecificHeaderOptions)
456 {
457     coap_list_t * optNode = NULL;
458     int res;
459     size_t buflen;
460     unsigned char _buf[BUF_SIZE];
461     unsigned char *buf = _buf;
462
463     if(addMediaType)
464     {
465         optNode = CreateNewOptionNode(COAP_OPTION_CONTENT_TYPE,
466                 sizeof(*addMediaType), addMediaType);
467         VERIFY_NON_NULL(optNode);
468         coap_insert(optListLoc, optNode, OrderOptions);
469     }
470
471     if(addMaxAge)
472     {
473         optNode = CreateNewOptionNode(COAP_OPTION_MAXAGE,
474                 sizeof(*addMaxAge), (uint8_t *)addMaxAge);
475         VERIFY_NON_NULL(optNode);
476         coap_insert(optListLoc, optNode, OrderOptions);
477     }
478
479     if(observeOptionLength && observeOptionPtr)
480     {
481         optNode = CreateNewOptionNode(COAP_OPTION_OBSERVE,
482                 observeOptionLength, (uint8_t *)observeOptionPtr);
483
484         VERIFY_NON_NULL(optNode);
485         coap_insert(optListLoc, optNode, OrderOptions);
486     }
487     if(addPortNumber && *addPortNumber != COAP_DEFAULT_PORT)
488     {
489         optNode = CreateNewOptionNode(COAP_OPTION_URI_PORT,
490                 sizeof(*addPortNumber), (uint8_t *)addPortNumber);
491         VERIFY_NON_NULL(optNode);
492         coap_insert(optListLoc, optNode, OrderOptions);
493     }
494
495     if(uri && uriLength)
496     {
497         buf = _buf;
498         buflen = BUF_SIZE;
499         res = coap_split_path(uri, uriLength, buf, &buflen);
500         while (res--) {
501             optNode = CreateNewOptionNode(COAP_OPTION_URI_PATH,
502                     COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf));
503             VERIFY_NON_NULL(optNode);
504             coap_insert(optListLoc, optNode, OrderOptions);
505             buf += COAP_OPT_SIZE(buf);
506         }
507     }
508
509     if(query && queryLength)
510     {
511         buf = _buf;
512         buflen = BUF_SIZE;
513         res = coap_split_query(query, queryLength, buf, &buflen);
514         while (res--) {
515             optNode = CreateNewOptionNode(COAP_OPTION_URI_QUERY,
516                     COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf));
517             VERIFY_NON_NULL(optNode);
518             coap_insert(optListLoc, optNode, OrderOptions);
519             buf += COAP_OPT_SIZE(buf);
520         }
521     }
522
523     // make sure that options are valid
524     if(vendorSpecificHeaderOptions && numVendorSpecificHeaderOptions)
525     {
526         uint8_t i = 0;
527         for( i = 0; i < numVendorSpecificHeaderOptions; i++)
528         {
529             if(vendorSpecificHeaderOptions[i].protocolID == OC_COAP_ID)
530             {
531                 if(isVendorSpecific(vendorSpecificHeaderOptions[i].optionID)
532                         == OC_STACK_OK &&
533                         vendorSpecificHeaderOptions[i].optionLength <=
534                         MAX_HEADER_OPTION_DATA_LENGTH)
535                 {
536                     OC_LOG_V(INFO, TAG, " Adding option %d with",
537                             vendorSpecificHeaderOptions[i].optionID);
538                     OC_LOG_BUFFER(INFO, TAG, vendorSpecificHeaderOptions[i].optionData,
539                             vendorSpecificHeaderOptions[i].optionLength);
540                     optNode = CreateNewOptionNode(vendorSpecificHeaderOptions[i].optionID,
541                             vendorSpecificHeaderOptions[i].optionLength,
542                             vendorSpecificHeaderOptions[i].optionData);
543                     VERIFY_NON_NULL(optNode);
544                     coap_insert(optListLoc, optNode, OrderOptions);
545                 }
546                 else
547                 {
548                     coap_delete_list(*optListLoc);
549                     return OC_STACK_INVALID_OPTION;
550                 }
551             }
552         }
553     }
554
555     return OC_STACK_OK;
556     exit:
557         coap_delete_list(*optListLoc);
558         return OC_STACK_NO_MEMORY;
559 }
560
561 //Send a coap pdu
562 OCStackResult
563 SendCoAPPdu(coap_context_t * gCoAPCtx, coap_address_t* dst, coap_pdu_t * pdu,
564         coap_send_flags_t flag)
565 {
566     coap_tid_t tid = COAP_INVALID_TID;
567     OCStackResult res = OC_STACK_COMM_ERROR;
568     uint8_t cache = 0;
569
570     if (!(flag & SEND_DELAYED))
571     {
572         flag = (coap_send_flags_t)( flag |
573             ((pdu->hdr->type == COAP_MESSAGE_CON) ? SEND_NOW_CON : SEND_NOW));
574     }
575
576     tid = coap_send(gCoAPCtx, dst, pdu, flag, &cache);
577     OC_LOG_V(INFO, TAG, "TID %d", tid);
578     if(tid != COAP_INVALID_TID)
579     {
580         OC_LOG(INFO, TAG, PCF("Sending a pdu with Token:"));
581         OC_LOG_BUFFER(INFO,TAG, pdu->hdr->token, pdu->hdr->token_length);
582         res = OC_STACK_OK;
583     }
584
585     if (( (pdu->hdr->type != COAP_MESSAGE_CON) && (!(flag & SEND_DELAYED)) && (!cache))
586         || (tid == COAP_INVALID_TID))
587     {
588         OC_LOG(INFO, TAG, PCF("Deleting PDU"));
589         coap_delete_pdu(pdu);
590     }
591     else
592     {
593         OC_LOG(INFO, TAG, PCF("Keeping PDU, we will handle the retry/delay of this pdu"));
594     }
595
596     return res;
597 }
598
599 //generate a coap message
600 coap_pdu_t *
601 GenerateCoAPPdu(uint8_t msgType, uint8_t code, unsigned short id,
602         OCCoAPToken * token, unsigned char * payloadJSON,
603         coap_list_t *options)
604 {
605     coap_pdu_t *pdu;
606     coap_list_t *opt;
607
608     if(token)
609     {
610         pdu = coap_pdu_init(msgType, code, id, COAP_MAX_PDU_SIZE);
611         VERIFY_NON_NULL(pdu);
612         pdu->hdr->token_length = token->tokenLength;
613          if (!coap_add_token(pdu, token->tokenLength, token->token))
614          {
615             OC_LOG(FATAL, TAG, PCF("coap_add_token failed"));
616         }
617     }
618     else
619     {
620         pdu = coap_pdu_init(msgType, code, id, sizeof(coap_pdu_t));
621         VERIFY_NON_NULL(pdu);
622     }
623
624     for (opt = options; opt; opt = opt->next)
625     {
626         coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option *) opt->data),
627                 COAP_OPTION_LENGTH(*(coap_option *) opt->data),
628                 COAP_OPTION_DATA(*(coap_option *) opt->data));
629     }
630
631     if (payloadJSON)
632     {
633         coap_add_data(pdu, strlen((const char *) payloadJSON) + 1,
634                 (unsigned char*) payloadJSON);
635     }
636
637     // display the pdu for debugging purposes
638     coap_show_pdu(pdu);
639
640     // clean up
641     coap_delete_list(options);
642     return pdu;
643
644     exit:
645     coap_delete_list(options);
646     return NULL;
647 }
648
649 //a function to help in ordering coap options
650 int OrderOptions(void *a, void *b)
651 {
652     if (!a || !b)
653     {
654         return a < b ? -1 : 1;
655     }
656
657     if (COAP_OPTION_KEY(*(coap_option *)a)
658             < COAP_OPTION_KEY(*(coap_option *)b) )
659     {
660         return -1;
661     }
662
663     return COAP_OPTION_KEY(*(coap_option *)a)
664             == COAP_OPTION_KEY(*(coap_option *)b) ;
665 }
666
667 //a function to create a coap option
668 coap_list_t *
669 CreateNewOptionNode(unsigned short key, unsigned int length, unsigned char *data)
670 {
671     coap_option *option = NULL;
672     coap_list_t *node;
673
674     VERIFY_NON_NULL(data);
675     option = (coap_option *)coap_malloc(sizeof(coap_option) + length);
676     VERIFY_NON_NULL(option);
677
678     COAP_OPTION_KEY(*option) = key;
679     COAP_OPTION_LENGTH(*option) = length;
680     memcpy(COAP_OPTION_DATA(*option), data, length);
681
682     /* we can pass NULL here as delete function since option is released automatically  */
683     node = coap_new_listnode(option, NULL);
684
685     if (node)
686     {
687         return node;
688     }
689
690 exit:
691     OC_LOG(ERROR,TAG, PCF("new_option_node: malloc: was not created"));
692     coap_free(option);
693     return NULL;
694 }
695
696 OCStackResult ReTXCoAPQueue(coap_context_t * ctx, coap_queue_t * queue)
697 {
698     coap_tid_t tid = COAP_INVALID_TID;
699     OCStackResult result = OC_STACK_ERROR;
700     tid = coap_retransmit( ctx, queue);
701     if(tid == COAP_INVALID_TID)
702     {
703         OC_LOG_V(DEBUG, TAG, "Retransmission Failed TID %d",
704                 queue->id);
705         result = OC_STACK_COMM_ERROR;
706     }
707     else
708     {
709         OC_LOG_V(DEBUG, TAG, "Retransmission TID %d, this is attempt %d",
710                 queue->id, queue->retransmit_cnt);
711         result = OC_STACK_OK;
712     }
713     return result;
714 }
715
716 OCStackResult HandleFailedCommunication(coap_context_t * ctx, coap_queue_t * queue)
717 {
718     OCResponse * response = NULL;
719     ClientCB * cbNode = NULL;
720     ResourceObserver * observer = NULL;
721     OCClientResponse clientResponse;
722     OCCoAPToken token;
723     OCStackResult result = OC_STACK_OK;
724
725     RetrieveOCCoAPToken(queue->pdu, &token);
726
727     cbNode = GetClientCB(&token, NULL, NULL);
728     if(!cbNode)
729     {
730         goto observation;
731     }
732     result = FormOCClientResponse(&clientResponse, OC_STACK_COMM_ERROR,
733             (OCDevAddr *) &(queue->remote), 0, NULL);
734     if(result != OC_STACK_OK)
735     {
736         goto observation;
737     }
738     result = FormOCResponse(&response, cbNode, 0, &clientResponse);
739     if(result != OC_STACK_OK)
740     {
741         goto observation;
742     }
743     HandleStackResponses(response);
744
745 observation:
746     observer = GetObserverUsingToken (&token);
747     if(!observer)
748     {
749         goto exit;
750     }
751
752     result = OCObserverStatus(&token, OC_OBSERVER_FAILED_COMM);
753     if(result == OC_STACK_OK)
754     {
755         coap_cancel_all_messages(ctx, &queue->remote, token.token, token.tokenLength);
756     }
757
758     exit:
759
760         OCFree(response);
761     return result;
762 }
763
764 // a function to handle the send queue in the passed context
765 void HandleSendQueue(coap_context_t * ctx)
766 {
767     coap_tick_t now;
768     coap_queue_t *nextQueue = NULL;
769
770     coap_ticks(&now);
771     nextQueue = coap_peek_next( ctx );
772     while (nextQueue && nextQueue->t <= now - ctx->sendqueue_basetime)
773     {
774         nextQueue = coap_pop_next( ctx );
775         if((uint8_t)nextQueue->delayedResponse)
776         {
777             OC_LOG_V(DEBUG, TAG, "Sending Delayed response TID %d",
778                     nextQueue->id);
779             if(SendCoAPPdu(ctx, &nextQueue->remote, nextQueue->pdu,
780                  (coap_send_flags_t)(nextQueue->secure ? SEND_SECURE_PORT : 0))
781                     == OC_STACK_COMM_ERROR)
782             {
783                 OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu"));
784                 HandleFailedCommunication(ctx, nextQueue);
785             }
786             nextQueue->pdu = NULL;
787             coap_delete_node(nextQueue);
788         }
789         else
790         {
791             OC_LOG_V(DEBUG, TAG, "Retrying a CON pdu TID %d",nextQueue->id);
792             if(ReTXCoAPQueue(ctx, nextQueue) == OC_STACK_COMM_ERROR)
793             {
794                 OC_LOG(DEBUG, TAG, PCF("A problem occurred in retransmitting a pdu"));
795                 HandleFailedCommunication(ctx, nextQueue);
796                 coap_delete_node(nextQueue);
797             }
798         }
799         nextQueue = coap_peek_next( ctx );
800     }
801 }