6877d5eda2769ff8c3ffc0ac0a47002b1482bc4c
[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 {
321     OCRequest * request = NULL;
322
323     // allocate it
324     request = (OCRequest *) OCMalloc(sizeof(OCRequest));
325     if (!request)
326     {
327         return OC_STACK_NO_MEMORY;
328     }
329
330     // fill in qos
331     request->qos = qos;
332
333     // fill in uri
334     request->resourceUrl = uriBuf;
335
336     // fill in observe
337     request->observe = observeReq;
338
339     // add entityHandlerRequest
340     request->entityHandlerRequest = entityHandlerRequest;
341
342     //TODO: this needs to be filled in the future
343     request->sequenceNum = 0;
344
345     *requestLoc = request;
346     return OC_STACK_OK;
347 }
348
349 // Form the OCObserveReq struct
350 OCStackResult FormOCObserveReq(OCObserveReq ** observeReqLoc, uint32_t observeOption,
351             OCDevAddr * remote, OCCoAPToken * rcvdToken)
352 {
353     OCObserveReq * observeReq;
354
355     if(observeOption == OC_RESOURCE_NO_OBSERVE)
356     {
357         return OC_STACK_OK;
358     }
359
360     observeReq = (OCObserveReq *)OCMalloc(sizeof(OCObserveReq));
361     if(!observeReq)
362     {
363         *observeReqLoc = NULL;
364         return OC_STACK_NO_MEMORY;
365     }
366
367     observeReq->option = observeOption;
368     observeReq->subAddr = remote;
369     observeReq->token = rcvdToken;
370     observeReq->result = OC_STACK_OK;
371
372     *observeReqLoc = observeReq;
373     return OC_STACK_OK;
374 }
375
376 // Form the OCEntityHandlerRequest struct
377 OCStackResult FormOCEntityHandlerRequest(OCEntityHandlerRequest * entityHandlerRequestLoc,
378         OCMethod method, unsigned char * resBuf, unsigned char * bufReqPayload,
379         unsigned char * queryBuf, unsigned char *newResUriBuf)
380 {
381     if (entityHandlerRequestLoc)
382     {
383         //set it to NULL for now, it will be modified in ocstack
384         entityHandlerRequestLoc->resource = NULL;
385
386         entityHandlerRequestLoc->method = method;
387
388         // fill in query
389         entityHandlerRequestLoc->query = queryBuf;
390
391         // fill payload
392         entityHandlerRequestLoc->reqJSONPayload = bufReqPayload;
393
394         entityHandlerRequestLoc->resJSONPayload = resBuf;
395         entityHandlerRequestLoc->resJSONPayloadLen = MAX_RESPONSE_LENGTH;
396
397         entityHandlerRequestLoc->obsInfo = NULL;
398         entityHandlerRequestLoc->newResourceUri = newResUriBuf;
399
400         entityHandlerRequestLoc->numRcvdVendorSpecificHeaderOptions = 0;
401         entityHandlerRequestLoc->numSendVendorSpecificHeaderOptions = 0;
402         return OC_STACK_OK;
403     }
404
405     return OC_STACK_INVALID_PARAM;
406 }
407
408 // Retrieve the token from the PDU
409 void RetrieveOCCoAPToken(const coap_pdu_t * pdu, OCCoAPToken * rcvdToken)
410 {
411     if (pdu && rcvdToken)
412     {
413         rcvdToken->tokenLength = pdu->hdr->token_length;
414         memcpy(rcvdToken->token, pdu->hdr->token,
415             rcvdToken->tokenLength);
416     }
417 }
418
419 OCStackResult FormOCResponse(OCResponse * * responseLoc, ClientCB * cbNode,
420         uint8_t TTL, OCClientResponse * clientResponse)
421 {
422     OCResponse * response = (OCResponse *) OCMalloc(sizeof(OCResponse));
423     if (!response)
424     {
425         return OC_STACK_NO_MEMORY;
426     }
427     response->cbNode = cbNode;
428     response->TTL = TTL;
429     response->clientResponse = clientResponse;
430
431     *responseLoc = response;
432     return OC_STACK_OK;
433 }
434
435 OCStackResult FormOCClientResponse(OCClientResponse * clientResponse,
436         OCStackResult result, OCDevAddr * remote, uint32_t seqNum,
437         const unsigned char * resJSONPayload)
438 {
439     clientResponse->sequenceNumber = seqNum;
440     clientResponse->result = result;
441     clientResponse->addr = remote;
442     clientResponse->resJSONPayload = resJSONPayload;
443
444     return OC_STACK_OK;
445 }
446
447 OCStackResult FormOptionList(coap_list_t * * optListLoc, uint8_t * addMediaType,
448         uint32_t * addMaxAge, uint8_t observeOptionLength, uint32_t * observeOptionPtr,
449         uint16_t * addPortNumber, uint8_t uriLength, unsigned char * uri,
450         uint8_t queryLength, unsigned char * query,
451         OCHeaderOption * vendorSpecificHeaderOptions,
452         uint8_t numVendorSpecificHeaderOptions)
453 {
454     coap_list_t * optNode = NULL;
455     int res;
456     size_t buflen;
457     unsigned char _buf[BUF_SIZE];
458     unsigned char *buf = _buf;
459
460     if(addMediaType)
461     {
462         optNode = CreateNewOptionNode(COAP_OPTION_CONTENT_TYPE,
463                 sizeof(*addMediaType), addMediaType);
464         VERIFY_NON_NULL(optNode);
465         coap_insert(optListLoc, optNode, OrderOptions);
466     }
467
468     if(addMaxAge)
469     {
470         optNode = CreateNewOptionNode(COAP_OPTION_MAXAGE,
471                 sizeof(*addMaxAge), (uint8_t *)addMaxAge);
472         VERIFY_NON_NULL(optNode);
473         coap_insert(optListLoc, optNode, OrderOptions);
474     }
475
476     if(observeOptionLength && observeOptionPtr)
477     {
478         optNode = CreateNewOptionNode(COAP_OPTION_OBSERVE,
479                 observeOptionLength, (uint8_t *)observeOptionPtr);
480
481         VERIFY_NON_NULL(optNode);
482         coap_insert(optListLoc, optNode, OrderOptions);
483     }
484     if(addPortNumber && *addPortNumber != COAP_DEFAULT_PORT)
485     {
486         optNode = CreateNewOptionNode(COAP_OPTION_URI_PORT,
487                 sizeof(*addPortNumber), (uint8_t *)addPortNumber);
488         VERIFY_NON_NULL(optNode);
489         coap_insert(optListLoc, optNode, OrderOptions);
490     }
491
492     if(uri && uriLength)
493     {
494         buf = _buf;
495         buflen = BUF_SIZE;
496         res = coap_split_path(uri, uriLength, buf, &buflen);
497         while (res--) {
498             optNode = CreateNewOptionNode(COAP_OPTION_URI_PATH,
499                     COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf));
500             VERIFY_NON_NULL(optNode);
501             coap_insert(optListLoc, optNode, OrderOptions);
502             buf += COAP_OPT_SIZE(buf);
503         }
504     }
505
506     if(query && queryLength)
507     {
508         buf = _buf;
509         buflen = BUF_SIZE;
510         res = coap_split_query(query, queryLength, buf, &buflen);
511         while (res--) {
512             optNode = CreateNewOptionNode(COAP_OPTION_URI_QUERY,
513                     COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf));
514             VERIFY_NON_NULL(optNode);
515             coap_insert(optListLoc, optNode, OrderOptions);
516             buf += COAP_OPT_SIZE(buf);
517         }
518     }
519
520     // make sure that options are valid
521     if(vendorSpecificHeaderOptions && numVendorSpecificHeaderOptions)
522     {
523         uint8_t i = 0;
524         for( i = 0; i < numVendorSpecificHeaderOptions; i++)
525         {
526             if(vendorSpecificHeaderOptions[i].protocolID == OC_COAP_ID)
527             {
528                 if(isVendorSpecific(vendorSpecificHeaderOptions[i].optionID)
529                         == OC_STACK_OK &&
530                         vendorSpecificHeaderOptions[i].optionLength <=
531                         MAX_HEADER_OPTION_DATA_LENGTH)
532                 {
533                     OC_LOG_V(INFO, TAG, " Adding option %d with",
534                             vendorSpecificHeaderOptions[i].optionID);
535                     OC_LOG_BUFFER(INFO, TAG, vendorSpecificHeaderOptions[i].optionData,
536                             vendorSpecificHeaderOptions[i].optionLength);
537                     optNode = CreateNewOptionNode(vendorSpecificHeaderOptions[i].optionID,
538                             vendorSpecificHeaderOptions[i].optionLength,
539                             vendorSpecificHeaderOptions[i].optionData);
540                     VERIFY_NON_NULL(optNode);
541                     coap_insert(optListLoc, optNode, OrderOptions);
542                 }
543                 else
544                 {
545                     coap_delete_list(*optListLoc);
546                     return OC_STACK_INVALID_OPTION;
547                 }
548             }
549         }
550     }
551
552     return OC_STACK_OK;
553     exit:
554         coap_delete_list(*optListLoc);
555         return OC_STACK_NO_MEMORY;
556 }
557
558 //Send a coap pdu
559 OCStackResult
560 SendCoAPPdu(coap_context_t * gCoAPCtx, coap_address_t* dst, coap_pdu_t * pdu,
561         coap_send_flags_t flag)
562 {
563     coap_tid_t tid = COAP_INVALID_TID;
564     OCStackResult res = OC_STACK_COMM_ERROR;
565
566     if (!(flag & SEND_DELAYED))
567     {
568         flag = (coap_send_flags_t)( flag |
569             (pdu->hdr->type == COAP_MESSAGE_CON) ? SEND_NOW_CON : SEND_NOW);
570     }
571
572     tid = coap_send(gCoAPCtx, dst, pdu, flag);
573     OC_LOG_V(INFO, TAG, "TID %d", tid);
574     if(tid != COAP_INVALID_TID)
575     {
576         OC_LOG(INFO, TAG, PCF("Sending a pdu with Token:"));
577         OC_LOG_BUFFER(INFO,TAG, pdu->hdr->token, pdu->hdr->token_length);
578         res = OC_STACK_OK;
579     }
580
581     if ((pdu->hdr->type != COAP_MESSAGE_CON && (!(flag & SEND_DELAYED))) || tid == COAP_INVALID_TID)
582     {
583         OC_LOG(INFO, TAG, PCF("Deleting PDU"));
584         coap_delete_pdu(pdu);
585     }
586     else
587     {
588         OC_LOG(INFO, TAG, PCF("Keeping PDU, we will handle the retry/delay of this pdu"));
589     }
590
591     return res;
592 }
593
594 //generate a coap message
595 coap_pdu_t *
596 GenerateCoAPPdu(uint8_t msgType, uint8_t code, unsigned short id,
597         OCCoAPToken * token, unsigned char * payloadJSON,
598         coap_list_t *options)
599 {
600     coap_pdu_t *pdu;
601     coap_list_t *opt;
602
603     if(token)
604     {
605         pdu = coap_pdu_init(msgType, code, id, COAP_MAX_PDU_SIZE);
606         VERIFY_NON_NULL(pdu);
607         pdu->hdr->token_length = token->tokenLength;
608          if (!coap_add_token(pdu, token->tokenLength, token->token))
609          {
610             OC_LOG(FATAL, TAG, PCF("coap_add_token failed"));
611         }
612     }
613     else
614     {
615         pdu = coap_pdu_init(msgType, code, id, sizeof(coap_pdu_t));
616         VERIFY_NON_NULL(pdu);
617     }
618
619     for (opt = options; opt; opt = opt->next)
620     {
621         coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option *) opt->data),
622                 COAP_OPTION_LENGTH(*(coap_option *) opt->data),
623                 COAP_OPTION_DATA(*(coap_option *) opt->data));
624     }
625
626     if (payloadJSON)
627     {
628         coap_add_data(pdu, strlen((const char *) payloadJSON) + 1,
629                 (unsigned char*) payloadJSON);
630     }
631
632     // display the pdu for debugging purposes
633     coap_show_pdu(pdu);
634
635     // clean up
636     coap_delete_list(options);
637     return pdu;
638
639     exit:
640     coap_delete_list(options);
641     return NULL;
642 }
643
644 //a function to help in ordering coap options
645 int OrderOptions(void *a, void *b)
646 {
647     if (!a || !b)
648     {
649         return a < b ? -1 : 1;
650     }
651
652     if (COAP_OPTION_KEY(*(coap_option *)a)
653             < COAP_OPTION_KEY(*(coap_option *)b) )
654     {
655         return -1;
656     }
657
658     return COAP_OPTION_KEY(*(coap_option *)a)
659             == COAP_OPTION_KEY(*(coap_option *)b) ;
660 }
661
662 //a function to create a coap option
663 coap_list_t *
664 CreateNewOptionNode(unsigned short key, unsigned int length, unsigned char *data)
665 {
666     coap_option *option = NULL;
667     coap_list_t *node;
668
669     VERIFY_NON_NULL(data);
670     option = (coap_option *)coap_malloc(sizeof(coap_option) + length);
671     VERIFY_NON_NULL(option);
672
673     COAP_OPTION_KEY(*option) = key;
674     COAP_OPTION_LENGTH(*option) = length;
675     memcpy(COAP_OPTION_DATA(*option), data, length);
676
677     /* we can pass NULL here as delete function since option is released automatically  */
678     node = coap_new_listnode(option, NULL);
679
680     if (node)
681     {
682         return node;
683     }
684
685 exit:
686     OC_LOG(ERROR,TAG, PCF("new_option_node: malloc: was not created"));
687     coap_free(option);
688     return NULL;
689 }
690
691 OCStackResult ReTXCoAPQueue(coap_context_t * ctx, coap_queue_t * queue)
692 {
693     coap_tid_t tid = COAP_INVALID_TID;
694     OCStackResult result = OC_STACK_ERROR;
695     tid = coap_retransmit( ctx, queue);
696     if(tid == COAP_INVALID_TID)
697     {
698         OC_LOG_V(DEBUG, TAG, "Retransmission Failed TID %d",
699                 queue->id);
700         result = OC_STACK_COMM_ERROR;
701     }
702     else
703     {
704         OC_LOG_V(DEBUG, TAG, "Retransmission TID %d, this is attempt %d",
705                 queue->id, queue->retransmit_cnt);
706         result = OC_STACK_OK;
707     }
708     return result;
709 }
710
711 OCStackResult HandleFailedCommunication(coap_context_t * ctx, coap_queue_t * queue)
712 {
713     OCResponse * response = NULL;
714     ClientCB * cbNode = NULL;
715     ResourceObserver * observer = NULL;
716     OCClientResponse clientResponse;
717     OCCoAPToken token;
718     OCStackResult result = OC_STACK_OK;
719
720     RetrieveOCCoAPToken(queue->pdu, &token);
721
722     cbNode = GetClientCB(&token, NULL, NULL);
723     if(!cbNode)
724     {
725         goto observation;
726     }
727     result = FormOCClientResponse(&clientResponse, OC_STACK_COMM_ERROR,
728             (OCDevAddr *) &(queue->remote), 0, NULL);
729     if(result != OC_STACK_OK)
730     {
731         goto observation;
732     }
733     result = FormOCResponse(&response, cbNode, 0, &clientResponse);
734     if(result != OC_STACK_OK)
735     {
736         goto observation;
737     }
738     HandleStackResponses(response);
739
740 observation:
741     observer = GetObserverUsingToken (&token);
742     if(!observer)
743     {
744         goto exit;
745     }
746
747     result = OCObserverStatus(&token, OC_OBSERVER_FAILED_COMM);
748     if(result == OC_STACK_OK)
749     {
750         coap_cancel_all_messages(ctx, &queue->remote, token.token, token.tokenLength);
751     }
752
753     exit:
754
755         OCFree(response);
756     return result;
757 }
758
759 // a function to handle the send queue in the passed context
760 void HandleSendQueue(coap_context_t * ctx)
761 {
762     coap_tick_t now;
763     coap_queue_t *nextQueue = NULL;
764
765     coap_ticks(&now);
766     nextQueue = coap_peek_next( ctx );
767     while (nextQueue && nextQueue->t <= now - ctx->sendqueue_basetime)
768     {
769         nextQueue = coap_pop_next( ctx );
770         if((uint8_t)nextQueue->delayedResponse)
771         {
772             OC_LOG_V(DEBUG, TAG, "Sending Delayed response TID %d",
773                     nextQueue->id);
774             if(SendCoAPPdu(ctx, &nextQueue->remote, nextQueue->pdu,
775                  (coap_send_flags_t)(nextQueue->secure ? SEND_SECURE_PORT : 0))
776                     == OC_STACK_COMM_ERROR)
777             {
778                 OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu"));
779                 HandleFailedCommunication(ctx, nextQueue);
780             }
781             nextQueue->pdu = NULL;
782             coap_delete_node(nextQueue);
783         }
784         else
785         {
786             OC_LOG_V(DEBUG, TAG, "Retrying a CON pdu TID %d",nextQueue->id);
787             if(ReTXCoAPQueue(ctx, nextQueue) == OC_STACK_COMM_ERROR)
788             {
789                 OC_LOG(DEBUG, TAG, PCF("A problem occurred in retransmitting a pdu"));
790                 HandleFailedCommunication(ctx, nextQueue);
791                 coap_delete_node(nextQueue);
792             }
793         }
794         nextQueue = coap_peek_next( ctx );
795     }
796 }