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