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