[IOT-3044]Adding token to empty signaling message
[iotivity.git] / resource / csdk / connectivity / src / caprotocolmessage.c
1 /******************************************************************
2  *
3  * Copyright 2014 Samsung Electronics 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 // Defining _BSD_SOURCE or _DEFAULT_SOURCE causes header files to expose
22 // definitions that may otherwise be skipped. Skipping can cause implicit
23 // declaration warnings and/or bugs and subtle problems in code execution.
24 // For glibc information on feature test macros,
25 // Refer http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
26 //
27 // For details on compatibility and glibc support,
28 // Refer http://www.gnu.org/software/libc/manual/html_node/BSD-Random.html
29 #define _DEFAULT_SOURCE
30
31 #include "iotivity_config.h"
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <stdbool.h>
36 #ifdef HAVE_TIME_H
37 #include <time.h>
38 #endif
39
40 #include "caprotocolmessage.h"
41 #include "experimental/logger.h"
42 #include "oic_malloc.h"
43 #include "oic_string.h"
44 #include "experimental/ocrandom.h"
45 #include "cacommonutil.h"
46 #include "cablockwisetransfer.h"
47
48 #define TAG "OIC_CA_PRTCL_MSG"
49
50 #define CA_PDU_MIN_SIZE (4)
51 #define CA_ENCODE_BUFFER_SIZE (4)
52
53 static const char COAP_URI_HEADER[] = "coap://[::]/";
54
55 static char g_chproxyUri[CA_MAX_URI_LENGTH];
56
57 CAResult_t CASetProxyUri(const char *uri)
58 {
59     VERIFY_NON_NULL(uri, TAG, "uri");
60     OICStrcpy(g_chproxyUri, sizeof (g_chproxyUri), uri);
61     return CA_STATUS_OK;
62 }
63
64 CAResult_t CAGetRequestInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
65                                    CARequestInfo_t *outReqInfo)
66 {
67     VERIFY_NON_NULL(pdu, TAG, "pdu");
68     VERIFY_NON_NULL(outReqInfo, TAG, "outReqInfo");
69
70     uint32_t code = CA_NOT_FOUND;
71     CAResult_t ret = CAGetInfoFromPDU(pdu, endpoint, &code, &(outReqInfo->info));
72     outReqInfo->method = code;
73
74     return ret;
75 }
76
77 CAResult_t CAGetResponseInfoFromPDU(const coap_pdu_t *pdu, CAResponseInfo_t *outResInfo,
78                                     const CAEndpoint_t *endpoint)
79 {
80     VERIFY_NON_NULL(pdu, TAG, "pdu");
81     VERIFY_NON_NULL(outResInfo, TAG, "outResInfo");
82
83     uint32_t code = CA_NOT_FOUND;
84     CAResult_t ret = CAGetInfoFromPDU(pdu, endpoint, &code, &(outResInfo->info));
85     outResInfo->result = code;
86
87     return ret;
88 }
89
90 CAResult_t CAGetErrorInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
91                                  CAErrorInfo_t *errorInfo)
92 {
93     VERIFY_NON_NULL(pdu, TAG, "pdu");
94
95     uint32_t code = 0;
96     CAResult_t ret = CAGetInfoFromPDU(pdu, endpoint, &code, &errorInfo->info);
97
98     return ret;
99 }
100
101 CAResult_t CAGetSignalingInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
102                                      CASignalingInfo_t *outSigInfo)
103 {
104     VERIFY_NON_NULL(pdu, TAG, "pdu");
105     VERIFY_NON_NULL(endpoint, TAG, "endpoint");
106     VERIFY_NON_NULL(outSigInfo, TAG, "outSigInfo");
107
108     uint32_t code = CA_NOT_FOUND;
109     CAResult_t ret = CAGetInfoFromPDU(pdu, endpoint, &code, &(outSigInfo->info));
110     outSigInfo->code = code;
111
112     return ret;
113 }
114
115 coap_pdu_t *CAGeneratePDU(uint32_t code, const CAInfo_t *info, const CAEndpoint_t *endpoint,
116                           coap_list_t **optlist, coap_transport_t *transport)
117 {
118     VERIFY_NON_NULL_RET(info, TAG, "info", NULL);
119     VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL);
120     VERIFY_NON_NULL_RET(optlist, TAG, "optlist", NULL);
121
122     OIC_LOG_V(DEBUG, TAG, "generate pdu for [%d]adapter, [%d]flags",
123               endpoint->adapter, endpoint->flags);
124
125     coap_pdu_t *pdu = NULL;
126
127     // RESET have to use only 4byte (empty message)
128     // and ACKNOWLEDGE can use empty message when code is empty.
129     if (CA_MSG_RESET == info->type || (CA_EMPTY == code && CA_MSG_ACKNOWLEDGE == info->type))
130     {
131         if (CA_EMPTY != code)
132         {
133             OIC_LOG(ERROR, TAG, "reset is not empty message");
134             return NULL;
135         }
136
137         if (info->payloadSize > 0 || info->payload || info->token || info->tokenLength > 0)
138         {
139             OIC_LOG(ERROR, TAG, "Empty message has unnecessary data after messageID");
140             return NULL;
141         }
142
143         OIC_LOG(DEBUG, TAG, "code is empty");
144         if (!(pdu = CAGeneratePDUImpl((code_t) code, info, endpoint, NULL, transport)))
145         {
146             OIC_LOG(ERROR, TAG, "pdu NULL");
147             return NULL;
148         }
149     }
150     else
151     {
152         if (info->resourceUri)
153         {
154             OIC_LOG_V(DEBUG, TAG, "uri : %s", info->resourceUri);
155
156             size_t length = strlen(info->resourceUri);
157             if (CA_MAX_URI_LENGTH < length)
158             {
159                 OIC_LOG(ERROR, TAG, "URI len err");
160                 return NULL;
161             }
162
163             size_t uriLength = length + sizeof(COAP_URI_HEADER);
164             char *coapUri = (char *) OICCalloc(1, uriLength);
165             if (NULL == coapUri)
166             {
167                 OIC_LOG(ERROR, TAG, "out of memory");
168                 return NULL;
169             }
170             OICStrcat(coapUri, uriLength, COAP_URI_HEADER);
171             OICStrcat(coapUri, uriLength, info->resourceUri);
172
173             // parsing options in URI
174             CAResult_t res = CAParseURI(coapUri, optlist);
175             if (CA_STATUS_OK != res)
176             {
177                 OICFree(coapUri);
178                 return NULL;
179             }
180
181             OICFree(coapUri);
182         }
183         // parsing options in HeadOption
184         CAResult_t ret = CAParseHeadOption(code, info, optlist);
185         if (CA_STATUS_OK != ret)
186         {
187             return NULL;
188         }
189
190         pdu = CAGeneratePDUImpl((code_t) code, info, endpoint, *optlist, transport);
191         if (NULL == pdu)
192         {
193             OIC_LOG(ERROR, TAG, "pdu NULL");
194             return NULL;
195         }
196     }
197
198     // pdu print method : coap_show_pdu(pdu);
199     return pdu;
200 }
201
202 coap_pdu_t *CAParsePDU(const char *data, size_t length, uint32_t *outCode,
203                        const CAEndpoint_t *endpoint)
204 {
205     VERIFY_NON_NULL_RET(data, TAG, "data", NULL);
206     VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL);
207
208     coap_transport_t transport = COAP_UDP;
209 #ifdef WITH_TCP
210     if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
211     {
212         transport = coap_get_tcp_header_type_from_initbyte(((unsigned char *)data)[0] >> 4);
213     }
214 #endif
215
216     coap_pdu_t *outpdu =
217         coap_pdu_init2(0, 0, ntohs((unsigned short)COAP_INVALID_TID), length, transport);
218     if (NULL == outpdu)
219     {
220         OIC_LOG(ERROR, TAG, "outpdu is null");
221         OIC_LOG_V(DEBUG, TAG, "data length: %" PRIuPTR, length);
222         return NULL;
223     }
224
225     OIC_LOG_V(DEBUG, TAG, "pdu parse-transport type : %d", transport);
226
227     int ret = coap_pdu_parse2((unsigned char *) data, length, outpdu, transport);
228     OIC_LOG_V(DEBUG, TAG, "pdu parse ret: %d", ret);
229     if (0 >= ret)
230     {
231         OIC_LOG(ERROR, TAG, "pdu parse failed");
232         goto exit;
233     }
234
235 #ifdef WITH_TCP
236     if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
237     {
238         OIC_LOG(INFO, TAG, "there is no version info in coap header");
239     }
240     else
241 #endif
242     {
243         if (outpdu->transport_hdr->udp.version != COAP_DEFAULT_VERSION)
244         {
245             OIC_LOG_V(ERROR, TAG, "coap version is not available : %d",
246                       outpdu->transport_hdr->udp.version);
247             goto exit;
248         }
249         if (outpdu->transport_hdr->udp.token_length > CA_MAX_TOKEN_LEN)
250         {
251             OIC_LOG_V(ERROR, TAG, "token length has been exceed : %d",
252                       outpdu->transport_hdr->udp.token_length);
253             goto exit;
254         }
255     }
256
257     if (outCode)
258     {
259         (*outCode) = (uint32_t) CA_RESPONSE_CODE(coap_get_code(outpdu, transport));
260     }
261
262     return outpdu;
263
264 exit:
265     OIC_LOG(DEBUG, TAG, "data :");
266     OIC_LOG_BUFFER(DEBUG, TAG,  (const uint8_t *)data, length);
267     coap_delete_pdu(outpdu);
268     return NULL;
269 }
270
271 coap_pdu_t *CAGeneratePDUImpl(code_t code, const CAInfo_t *info,
272                               const CAEndpoint_t *endpoint, coap_list_t *options,
273                               coap_transport_t *transport)
274 {
275     VERIFY_NON_NULL_RET(info, TAG, "info", NULL);
276     VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL);
277     VERIFY_NON_NULL_RET(transport, TAG, "transport", NULL);
278     VERIFY_TRUE_RET((info->payloadSize <= UINT_MAX), TAG,
279                     "info->payloadSize", NULL);
280
281     size_t length = COAP_MAX_PDU_SIZE;
282 #ifdef WITH_TCP
283     size_t msgLength = 0;
284     if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
285     {
286         if (options)
287         {
288             unsigned short prevOptNumber = 0;
289             for (coap_list_t *opt = options; opt; opt = opt->next)
290             {
291                 unsigned short curOptNumber = COAP_OPTION_KEY(*(coap_option *) opt->data);
292                 if (prevOptNumber > curOptNumber)
293                 {
294                     OIC_LOG(ERROR, TAG, "option list is wrong");
295                     return NULL;
296                 }
297
298                 size_t optValueLen = COAP_OPTION_LENGTH(*(coap_option *) opt->data);
299                 size_t optLength = coap_get_opt_header_length(curOptNumber - prevOptNumber, optValueLen);
300                 if (0 == optLength)
301                 {
302                     OIC_LOG(ERROR, TAG, "Reserved for the Payload marker for the option");
303                     return NULL;
304                 }
305                 msgLength += optLength;
306                 prevOptNumber = curOptNumber;
307                 OIC_LOG_V(DEBUG, TAG, "curOptNumber[%d], prevOptNumber[%d], optValueLen[%" PRIuPTR "], "
308                         "optLength[%" PRIuPTR "], msgLength[%" PRIuPTR "]",
309                           curOptNumber, prevOptNumber, optValueLen, optLength, msgLength);
310             }
311         }
312
313         if (info->payloadSize > 0)
314         {
315             msgLength = msgLength + info->payloadSize + PAYLOAD_MARKER;
316         }
317
318         *transport = coap_get_tcp_header_type_from_size((unsigned int)msgLength);
319         length = msgLength + coap_get_tcp_header_length_for_transport(*transport)
320                 + info->tokenLength;
321     }
322     else
323 #endif
324     {
325         *transport = COAP_UDP;
326     }
327
328     coap_pdu_t *pdu = coap_pdu_init2(0, 0,
329                                      ntohs((unsigned short)COAP_INVALID_TID),
330                                      length, *transport);
331
332     if (NULL == pdu)
333     {
334         OIC_LOG(ERROR, TAG, "malloc failed");
335         return NULL;
336     }
337
338     OIC_LOG_V(DEBUG, TAG, "transport type: %d, payload size: %" PRIuPTR,
339               *transport, info->payloadSize);
340
341 #ifdef WITH_TCP
342     if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
343     {
344         coap_add_length(pdu, *transport, (unsigned int)msgLength);
345     }
346     else
347 #endif
348     {
349         OIC_LOG_V(DEBUG, TAG, "msgID is %d", info->messageId);
350         uint16_t message_id = 0;
351         if (0 == info->messageId)
352         {
353             /* initialize message id */
354             prng((uint8_t * ) &message_id, sizeof(message_id));
355
356             OIC_LOG_V(DEBUG, TAG, "gen msg id=%d", message_id);
357         }
358         else
359         {
360             /* use saved message id */
361             message_id = info->messageId;
362         }
363         pdu->transport_hdr->udp.id = message_id;
364         OIC_LOG_V(DEBUG, TAG, "messageId in pdu is %d, %d", message_id, pdu->transport_hdr->udp.id);
365
366         pdu->transport_hdr->udp.type = info->type;
367     }
368
369     coap_add_code(pdu, *transport, code);
370
371     if (info->token && CA_EMPTY != code)
372     {
373         uint32_t tokenLength = info->tokenLength;
374         OIC_LOG_V(DEBUG, TAG, "token info token length: %d, token :", tokenLength);
375         OIC_LOG_BUFFER(DEBUG, TAG, (const uint8_t *)info->token, tokenLength);
376
377         if (info->payloadSize == 0 && (code == CA_CSM || code == CA_PING ||
378                                        code == CA_PONG || code == CA_RELEASE ||
379                                        code == CA_ABORT))
380         {
381             int32_t ret = coap_add_token_to_empty_message(pdu, tokenLength,
382                             (unsigned char *)info->token, *transport);
383             if (0 == ret)
384             {
385                 OIC_LOG(ERROR, TAG, "can't add token");
386             }
387         }
388         else
389         {
390             int32_t ret = coap_add_token2(pdu, tokenLength, (unsigned char *)info->token,
391                             *transport);
392             if (0 == ret)
393             {
394                 OIC_LOG(ERROR, TAG, "can't add token");
395             }
396         }
397     }
398
399 #ifdef WITH_BWT
400     if (CA_ADAPTER_GATT_BTLE != endpoint->adapter
401 #ifdef WITH_TCP
402             && !CAIsSupportedCoAPOverTCP(endpoint->adapter)
403 #endif
404             )
405     {
406         // option list will be added in blockwise-transfer
407         return pdu;
408     }
409 #endif
410
411     if (options)
412     {
413         for (coap_list_t *opt = options; opt; opt = opt->next)
414         {
415             OIC_LOG_V(DEBUG, TAG, "[%s] opt will be added.",
416                       COAP_OPTION_DATA(*(coap_option *) opt->data));
417
418             OIC_LOG_V(DEBUG, TAG, "[%d] pdu length", pdu->length);
419             if (0 == coap_add_option2(pdu, COAP_OPTION_KEY(*(coap_option *) opt->data),
420                                       COAP_OPTION_LENGTH(*(coap_option *) opt->data),
421                                       COAP_OPTION_DATA(*(coap_option *) opt->data), *transport))
422             {
423                 OIC_LOG(ERROR, TAG, "coap_add_option2 has failed");
424                 coap_delete_pdu(pdu);
425                 return NULL;
426             }
427         }
428     }
429
430     OIC_LOG_V(DEBUG, TAG, "[%d] pdu length after option", pdu->length);
431
432     if ((NULL != info->payload) && (0 < info->payloadSize))
433     {
434         OIC_LOG(DEBUG, TAG, "payload is added");
435         coap_add_data(pdu, (unsigned int)info->payloadSize,
436                       (const unsigned char*)info->payload);
437     }
438
439     return pdu;
440 }
441
442 CAResult_t CAParseURI(const char *uriInfo, coap_list_t **optlist)
443 {
444     VERIFY_NON_NULL(uriInfo, TAG, "uriInfo");
445     VERIFY_NON_NULL(optlist, TAG, "optlist");
446
447     /* split arg into Uri-* options */
448     coap_uri_t uri;
449     coap_split_uri((unsigned char *) uriInfo, strlen(uriInfo), &uri);
450
451     if (uri.port != COAP_DEFAULT_PORT)
452     {
453         unsigned char portbuf[CA_ENCODE_BUFFER_SIZE] = { 0 };
454         int ret = coap_insert(optlist,
455                               CACreateNewOptionNode(COAP_OPTION_URI_PORT,
456                                                     coap_encode_var_bytes(portbuf, uri.port),
457                                                     (char *)portbuf),
458                               CAOrderOpts);
459         if (ret <= 0)
460         {
461             return CA_STATUS_INVALID_PARAM;
462         }
463     }
464
465     if (uri.path.s && uri.path.length)
466     {
467         CAResult_t ret = CAParseUriPartial(uri.path.s, uri.path.length,
468                                            COAP_OPTION_URI_PATH, optlist);
469         if (CA_STATUS_OK != ret)
470         {
471             OIC_LOG(ERROR, TAG, "CAParseUriPartial failed(uri path)");
472             return ret;
473         }
474     }
475
476     if (uri.query.s && uri.query.length)
477     {
478         CAResult_t ret = CAParseUriPartial(uri.query.s, uri.query.length, COAP_OPTION_URI_QUERY,
479                                            optlist);
480         if (CA_STATUS_OK != ret)
481         {
482             OIC_LOG(ERROR, TAG, "CAParseUriPartial failed(uri query)");
483             return ret;
484         }
485     }
486
487     return CA_STATUS_OK;
488 }
489
490 CAResult_t CAParseUriPartial(const unsigned char *str, size_t length, uint16_t target,
491                              coap_list_t **optlist)
492 {
493     VERIFY_NON_NULL(optlist, TAG, "optlist");
494
495     if ((target != COAP_OPTION_URI_PATH) && (target != COAP_OPTION_URI_QUERY))
496     {
497         // should never occur. Log just in case.
498         OIC_LOG(DEBUG, TAG, "Unexpected URI component.");
499         return CA_NOT_SUPPORTED;
500     }
501     else if (str && length)
502     {
503         unsigned char uriBuffer[CA_MAX_URI_LENGTH] = { 0 };
504         unsigned char *pBuf = uriBuffer;
505         size_t unusedBufferSize = sizeof(uriBuffer);
506         int res = (target == COAP_OPTION_URI_PATH) ? coap_split_path(str, length, pBuf, &unusedBufferSize) :
507                                                      coap_split_query(str, length, pBuf, &unusedBufferSize);
508
509         if (res > 0)
510         {
511             assert(unusedBufferSize < sizeof(uriBuffer));
512             size_t usedBufferSize = sizeof(uriBuffer) - unusedBufferSize;
513             size_t prevIdx = 0;
514             while (res--)
515             {
516                 int ret = coap_insert(optlist,
517                                       CACreateNewOptionNode(target, COAP_OPT_LENGTH(pBuf),
518                                                             (char *)COAP_OPT_VALUE(pBuf)),
519                                       CAOrderOpts);
520                 if (ret <= 0)
521                 {
522                     return CA_STATUS_INVALID_PARAM;
523                 }
524
525                 size_t optSize = COAP_OPT_SIZE(pBuf);
526                 if (prevIdx + optSize > usedBufferSize)
527                 {
528                     assert(false);
529                     return CA_STATUS_INVALID_PARAM;
530                 }
531                 pBuf += optSize;
532                 prevIdx += optSize;
533             }
534         }
535         else
536         {
537             OIC_LOG_V(ERROR, TAG, "Problem parsing URI : %d for %d", res, target);
538             return CA_STATUS_FAILED;
539         }
540     }
541     else
542     {
543         OIC_LOG(ERROR, TAG, "str or length is not available");
544         return CA_STATUS_FAILED;
545     }
546
547     return CA_STATUS_OK;
548 }
549
550 CAResult_t CAParseHeadOption(uint32_t code, const CAInfo_t *info, coap_list_t **optlist)
551 {
552     (void)code;
553     VERIFY_NON_NULL_RET(info, TAG, "info", CA_STATUS_INVALID_PARAM);
554
555     OIC_LOG_V(DEBUG, TAG, "parse Head Opt: %d", info->numOptions);
556
557     if (!optlist)
558     {
559         OIC_LOG(ERROR, TAG, "optlist is null");
560         return CA_STATUS_INVALID_PARAM;
561     }
562
563     for (uint32_t i = 0; i < info->numOptions; i++)
564     {
565         if(!(info->options + i))
566         {
567             OIC_LOG(ERROR, TAG, "options is not available");
568             return CA_STATUS_FAILED;
569         }
570
571         uint16_t id = (info->options + i)->optionID;
572         switch (id)
573         {
574             case COAP_OPTION_URI_PATH:
575             case COAP_OPTION_URI_QUERY:
576                 OIC_LOG_V(DEBUG, TAG, "not Header Opt: %d", id);
577                 break;
578             case COAP_OPTION_ACCEPT:
579             case CA_OPTION_ACCEPT_VERSION:
580             case COAP_OPTION_CONTENT_FORMAT:
581             case CA_OPTION_CONTENT_VERSION:
582                 // this is handled below via CAParsePayloadFormatHeadOption
583                 break;
584             default:
585                 OIC_LOG_V(DEBUG, TAG, "Head opt ID[%d], length[%d]", id,
586                     (info->options + i)->optionLength);
587                 int ret = coap_insert(optlist,
588                                       CACreateNewOptionNode(id, (info->options + i)->optionLength,
589                                                             (info->options + i)->optionData),
590                                       CAOrderOpts);
591                 if (ret <= 0)
592                 {
593                     return CA_STATUS_INVALID_PARAM;
594                 }
595         }
596     }
597
598     // insert one extra header with the payload format if applicable.
599     if (CA_FORMAT_UNDEFINED != info->payloadFormat)
600     {
601         CAParsePayloadFormatHeadOption(COAP_OPTION_CONTENT_FORMAT, info->payloadFormat, CA_OPTION_CONTENT_VERSION, info->payloadVersion, optlist);
602     }
603
604     if (CA_FORMAT_UNDEFINED != info->acceptFormat)
605     {
606         CAParsePayloadFormatHeadOption(COAP_OPTION_ACCEPT, info->acceptFormat, CA_OPTION_ACCEPT_VERSION, info->acceptVersion, optlist);
607     }
608
609     return CA_STATUS_OK;
610 }
611
612 CAResult_t CAParsePayloadFormatHeadOption(uint16_t formatOption, CAPayloadFormat_t format,
613         uint16_t versionOption, uint16_t version, coap_list_t **optlist)
614 {
615     coap_list_t* encodeNode = NULL;
616     coap_list_t* versionNode = NULL;
617     uint8_t encodeBuf[CA_ENCODE_BUFFER_SIZE] = { 0 };
618     uint8_t versionBuf[CA_ENCODE_BUFFER_SIZE] = { 0 };
619
620     switch (format)
621     {
622         case CA_FORMAT_APPLICATION_CBOR:
623             encodeNode = CACreateNewOptionNode(formatOption,
624                     coap_encode_var_bytes(encodeBuf,
625                             (unsigned short) COAP_MEDIATYPE_APPLICATION_CBOR), (char *) encodeBuf);
626             break;
627         case CA_FORMAT_APPLICATION_VND_OCF_CBOR:
628             encodeNode = CACreateNewOptionNode(formatOption,
629                     coap_encode_var_bytes(encodeBuf,
630                             (unsigned short) COAP_MEDIATYPE_APPLICATION_VND_OCF_CBOR),
631                     (char *) encodeBuf);
632             break;
633         default:
634             OIC_LOG_V(ERROR, TAG, "Format option:[%d] not supported", format);
635     }
636     if (!encodeNode)
637     {
638         OIC_LOG(ERROR, TAG, "Format option not created");
639         return CA_STATUS_INVALID_PARAM;
640     }
641     int ret = coap_insert(optlist, encodeNode, CAOrderOpts);
642     if (0 >= ret)
643     {
644         coap_delete(encodeNode);
645         OIC_LOG(ERROR, TAG, "Format option not inserted in header");
646         return CA_STATUS_INVALID_PARAM;
647     }
648
649     if ((CA_OPTION_ACCEPT_VERSION == versionOption ||
650          CA_OPTION_CONTENT_VERSION == versionOption) &&
651         CA_FORMAT_APPLICATION_VND_OCF_CBOR == format)
652     {
653         versionNode = CACreateNewOptionNode(versionOption,
654                 coap_encode_var_bytes(versionBuf, version), (char *) versionBuf);
655
656         if (!versionNode)
657         {
658             OIC_LOG(ERROR, TAG, "Version option not created");
659             coap_delete(encodeNode);
660             return CA_STATUS_INVALID_PARAM;
661         }
662         ret = coap_insert(optlist, versionNode, CAOrderOpts);
663         if (0 >= ret)
664         {
665             coap_delete(versionNode);
666             coap_delete(encodeNode);
667             OIC_LOG(ERROR, TAG, "Content version option not inserted in header");
668             return CA_STATUS_INVALID_PARAM;
669         }
670     }
671     return CA_STATUS_OK;
672 }
673
674 coap_list_t *CACreateNewOptionNode(uint16_t key, uint32_t length, const char *data)
675 {
676     VERIFY_NON_NULL_RET(data, TAG, "data", NULL);
677
678     coap_option *option = coap_malloc(sizeof(coap_option) + length + 1);
679     if (!option)
680     {
681         OIC_LOG(ERROR, TAG, "Out of memory");
682         return NULL;
683     }
684     memset(option, 0, sizeof(coap_option) + length + 1);
685
686     COAP_OPTION_KEY(*option) = key;
687
688     coap_option_def_t* def = coap_opt_def(key);
689     if (NULL != def && coap_is_var_bytes(def))
690     {
691        if (length > def->max)
692         {
693             // make sure we shrink the value so it fits the coap option definition
694             // by truncating the value, disregard the leading bytes.
695             OIC_LOG_V(DEBUG, TAG, "Option [%d] data size [%d] shrunk to [%d]",
696                     def->key, length, def->max);
697             data = &(data[length-def->max]);
698             length = def->max;
699         }
700         // Shrink the encoding length to a minimum size for coap
701         // options that support variable length encoding.
702          COAP_OPTION_LENGTH(*option) = coap_encode_var_bytes(
703                 COAP_OPTION_DATA(*option),
704                 coap_decode_var_bytes((unsigned char *)data, length));
705     }
706     else
707     {
708         COAP_OPTION_LENGTH(*option) = length;
709         memcpy(COAP_OPTION_DATA(*option), data, length);
710     }
711
712     /* we can pass NULL here as delete function since option is released automatically  */
713     coap_list_t *node = coap_new_listnode(option, NULL);
714
715     if (!node)
716     {
717         OIC_LOG(ERROR, TAG, "node is NULL");
718         coap_free(option);
719         return NULL;
720     }
721
722     return node;
723 }
724
725 int CAOrderOpts(void *a, void *b)
726 {
727     if (!a || !b)
728     {
729         return a < b ? -1 : 1;
730     }
731
732     if (COAP_OPTION_KEY(*(coap_option *) a) < COAP_OPTION_KEY(*(coap_option * ) b))
733     {
734         return -1;
735     }
736
737     return COAP_OPTION_KEY(*(coap_option *) a) == COAP_OPTION_KEY(*(coap_option * ) b);
738 }
739
740 CAResult_t CAGetOptionCount(coap_opt_iterator_t opt_iter, uint8_t *optionCount)
741 {
742     CAResult_t result = CA_STATUS_OK;
743     coap_opt_t *option = NULL;
744     *optionCount = 0;
745
746     while ((option = coap_option_next(&opt_iter)))
747     {
748         if (COAP_OPTION_URI_PATH != opt_iter.type && COAP_OPTION_URI_QUERY != opt_iter.type
749             && COAP_OPTION_BLOCK1 != opt_iter.type && COAP_OPTION_BLOCK2 != opt_iter.type
750             && COAP_OPTION_SIZE1 != opt_iter.type && COAP_OPTION_SIZE2 != opt_iter.type
751             && COAP_OPTION_URI_HOST != opt_iter.type && COAP_OPTION_URI_PORT != opt_iter.type
752             && COAP_OPTION_ETAG != opt_iter.type && COAP_OPTION_MAXAGE != opt_iter.type
753             && COAP_OPTION_PROXY_SCHEME != opt_iter.type)
754         {
755             if (*optionCount < UINT8_MAX)
756             {
757                 (*optionCount)++;
758             }
759             else
760             {
761                 // Overflow. Return an error to the caller.
762                 assert(false);
763                 OIC_LOG_V(ERROR, TAG, "Overflow detected in %s", __func__);
764                 *optionCount = 0;
765                 result = CA_STATUS_FAILED;
766                 break;
767             }
768         }
769     }
770
771     return result;
772 }
773
774 CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
775                             uint32_t *outCode, CAInfo_t *outInfo)
776 {
777     OIC_LOG(INFO, TAG, "IN - CAGetInfoFromPDU");
778     VERIFY_NON_NULL(pdu, TAG, "pdu");
779     VERIFY_NON_NULL(endpoint, TAG, "endpoint");
780     VERIFY_NON_NULL(outCode, TAG, "outCode");
781     VERIFY_NON_NULL(outInfo, TAG, "outInfo");
782
783     coap_transport_t transport = COAP_UDP;
784 #ifdef WITH_TCP
785     if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
786     {
787         transport = coap_get_tcp_header_type_from_initbyte(((unsigned char *)pdu->transport_hdr)[0] >> 4);
788     }
789 #endif
790
791     coap_opt_iterator_t opt_iter;
792     coap_option_iterator_init2((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL, transport);
793
794     if (outCode)
795     {
796         (*outCode) = (uint32_t) CA_RESPONSE_CODE(coap_get_code(pdu, transport));
797     }
798
799     // init HeaderOption list
800     uint8_t count = 0;
801     CAResult_t countResult = CAGetOptionCount(opt_iter, &count);
802     if (CA_STATUS_OK != countResult)
803     {
804         OIC_LOG_V(ERROR, TAG, "CAGetOptionCount failed with error: %d!", countResult);
805         return countResult;
806     }
807
808     memset(outInfo, 0, sizeof(*outInfo));
809
810     outInfo->numOptions = count;
811
812 #ifdef WITH_TCP
813     if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
814     {
815         // set type
816         outInfo->type = CA_MSG_NONCONFIRM;
817         outInfo->payloadFormat = CA_FORMAT_UNDEFINED;
818     }
819     else
820 #else
821     (void) endpoint;
822 #endif
823     {
824         // set type
825         outInfo->type = pdu->transport_hdr->udp.type;
826
827         // set message id
828         outInfo->messageId = pdu->transport_hdr->udp.id;
829         outInfo->payloadFormat = CA_FORMAT_UNDEFINED;
830         outInfo->acceptFormat = CA_FORMAT_UNDEFINED;
831     }
832
833     if (count > 0)
834     {
835         outInfo->options = (CAHeaderOption_t *) OICCalloc(count, sizeof(CAHeaderOption_t));
836         if (NULL == outInfo->options)
837         {
838             OIC_LOG(ERROR, TAG, "Out of memory");
839             return CA_MEMORY_ALLOC_FAILED;
840         }
841     }
842
843     coap_opt_t *option = NULL;
844     char *optionResult = (char *)OICCalloc(1, CA_MAX_URI_LENGTH * sizeof(char));
845     if (NULL == optionResult)
846     {
847         goto exit;
848     }
849
850     uint32_t idx = 0;
851     uint32_t optionLength = 0;
852     bool isfirstsetflag = false;
853     bool isQueryBeingProcessed = false;
854     bool isProxyRequest = false;
855
856     while ((option = coap_option_next(&opt_iter)))
857     {
858         char *buf = (char *)OICCalloc(1, COAP_MAX_PDU_SIZE * sizeof(char));
859         if (NULL == buf)
860         {
861             goto exit;
862         }
863
864         uint32_t bufLength =
865             CAGetOptionData(opt_iter.type, (uint8_t *)(COAP_OPT_VALUE(option)),
866                     COAP_OPT_LENGTH(option), (uint8_t *)buf, COAP_MAX_PDU_SIZE);
867         if (bufLength)
868         {
869             OIC_LOG_V(DEBUG, TAG, "COAP URI element : %s", buf);
870             if (COAP_OPTION_URI_PATH == opt_iter.type || COAP_OPTION_URI_QUERY == opt_iter.type)
871             {
872                 if (false == isfirstsetflag)
873                 {
874                     isfirstsetflag = true;
875                     optionResult[optionLength] = '/';
876                     optionLength++;
877                     // Make sure there is enough room in the optionResult buffer
878                     if ((optionLength + bufLength) < CA_MAX_URI_LENGTH)
879                     {
880                         memcpy(&optionResult[optionLength], buf, bufLength);
881                         optionLength += bufLength;
882                     }
883                     else
884                     {
885                         OICFree(buf);
886                         goto exit;
887                     }
888                 }
889                 else
890                 {
891                     if (COAP_OPTION_URI_PATH == opt_iter.type)
892                     {
893                         // Make sure there is enough room in the optionResult buffer
894                         if (optionLength < CA_MAX_URI_LENGTH)
895                         {
896                             optionResult[optionLength] = '/';
897                             optionLength++;
898                         }
899                         else
900                         {
901                             OICFree(buf);
902                             goto exit;
903                         }
904                     }
905                     else if (COAP_OPTION_URI_QUERY == opt_iter.type)
906                     {
907                         if (false == isQueryBeingProcessed)
908                         {
909                             // Make sure there is enough room in the optionResult buffer
910                             if (optionLength < CA_MAX_URI_LENGTH)
911                             {
912                                 optionResult[optionLength] = '?';
913                                 optionLength++;
914                                 isQueryBeingProcessed = true;
915                             }
916                             else
917                             {
918                                 OICFree(buf);
919                                 goto exit;
920                             }
921                         }
922                         else
923                         {
924                             // Make sure there is enough room in the optionResult buffer
925                             if (optionLength < CA_MAX_URI_LENGTH)
926                             {
927                                 optionResult[optionLength] = ';';
928                                 optionLength++;
929                             }
930                             else
931                             {
932                                 OICFree(buf);
933                                 goto exit;
934                             }
935                         }
936                     }
937                     // Make sure there is enough room in the optionResult buffer
938                     if ((optionLength + bufLength) < CA_MAX_URI_LENGTH)
939                     {
940                         memcpy(&optionResult[optionLength], buf, bufLength);
941                         optionLength += bufLength;
942                     }
943                     else
944                     {
945                         OICFree(buf);
946                         goto exit;
947                     }
948                 }
949             }
950             else if (COAP_OPTION_BLOCK1 == opt_iter.type || COAP_OPTION_BLOCK2 == opt_iter.type
951                     || COAP_OPTION_SIZE1 == opt_iter.type || COAP_OPTION_SIZE2 == opt_iter.type)
952             {
953                 OIC_LOG_V(DEBUG, TAG, "option[%d] will be filtering", opt_iter.type);
954             }
955             else if (COAP_OPTION_URI_PORT == opt_iter.type ||
956                     COAP_OPTION_URI_HOST == opt_iter.type ||
957                     COAP_OPTION_ETAG == opt_iter.type ||
958                     COAP_OPTION_MAXAGE == opt_iter.type ||
959                     COAP_OPTION_PROXY_SCHEME== opt_iter.type)
960             {
961                 OIC_LOG_V(INFO, TAG, "option[%d] has an unsupported format [%d]",
962                           opt_iter.type, (uint8_t)buf[0]);
963             }
964             else
965             {
966                 if (COAP_OPTION_PROXY_URI == opt_iter.type)
967                 {
968                     isProxyRequest = true;
969                 }
970                 else if (CA_OPTION_ACCEPT_VERSION == opt_iter.type)
971                 {
972                     if (2 == COAP_OPT_LENGTH(option))
973                     {
974                         unsigned int decodedVersion = coap_decode_var_bytes(COAP_OPT_VALUE(option),
975                                 COAP_OPT_LENGTH(option));
976                         assert(decodedVersion <= UINT16_MAX);
977                         outInfo->acceptVersion = (uint16_t) decodedVersion;
978                     }
979                     else
980                     {
981                         OIC_LOG(DEBUG, TAG, "unsupported accept version");
982                         outInfo->acceptVersion = DEFAULT_VERSION_VALUE;
983                     }
984                 }
985                 else if (COAP_OPTION_ACCEPT == opt_iter.type)
986                 {
987                     if (1 == COAP_OPT_LENGTH(option))
988                     {
989                         outInfo->acceptFormat = CAConvertFormat((uint8_t) buf[0]);
990                     }
991                     else if (2 == COAP_OPT_LENGTH(option))
992                     {
993                         unsigned int decodedFormat = coap_decode_var_bytes(COAP_OPT_VALUE(option),
994                                 COAP_OPT_LENGTH(option));
995                         assert(decodedFormat <= UINT16_MAX);
996                         outInfo->acceptFormat = CAConvertFormat((uint16_t) decodedFormat);
997                     }
998                     else
999                     {
1000                         outInfo->acceptFormat = CA_FORMAT_UNSUPPORTED;
1001                         OIC_LOG(DEBUG, TAG, "option has an unsupported accept format");
1002                     }
1003                 }
1004                 else if (CA_OPTION_CONTENT_VERSION == opt_iter.type)
1005                 {
1006                     if (2 == COAP_OPT_LENGTH(option))
1007                     {
1008                         unsigned int decodedVersion = coap_decode_var_bytes(COAP_OPT_VALUE(option),
1009                                 COAP_OPT_LENGTH(option));
1010                         assert(decodedVersion <= UINT16_MAX);
1011                         outInfo->payloadVersion = (uint16_t) decodedVersion;
1012                     }
1013                     else
1014                     {
1015                         OIC_LOG(DEBUG, TAG, "unsupported payload version");
1016                         outInfo->payloadVersion = DEFAULT_VERSION_VALUE;
1017                     }
1018                 }
1019                 else if (COAP_OPTION_CONTENT_FORMAT == opt_iter.type)
1020                 {
1021                     if (1 == COAP_OPT_LENGTH(option))
1022                     {
1023                         outInfo->payloadFormat = CAConvertFormat((uint8_t) buf[0]);
1024                     }
1025                     else if (2 == COAP_OPT_LENGTH(option))
1026                     {
1027                         unsigned int decodedFormat = coap_decode_var_bytes(COAP_OPT_VALUE(option),
1028                                 COAP_OPT_LENGTH(option));
1029                         assert(decodedFormat <= UINT16_MAX);
1030                         outInfo->payloadFormat = CAConvertFormat((uint16_t) decodedFormat);
1031                     }
1032                     else
1033                     {
1034                         outInfo->payloadFormat = CA_FORMAT_UNSUPPORTED;
1035                         OIC_LOG(DEBUG, TAG, "option has an unsupported accept format");
1036                     }
1037                 }
1038
1039                 if (idx < count)
1040                 {
1041                     if (bufLength <= sizeof(outInfo->options[0].optionData))
1042                     {
1043                         outInfo->options[idx].optionID = opt_iter.type;
1044                         assert(bufLength <= UINT16_MAX);
1045                         outInfo->options[idx].optionLength = (uint16_t)bufLength;
1046                         outInfo->options[idx].protocolID = CA_COAP_ID;
1047                         memcpy(outInfo->options[idx].optionData, buf, bufLength);
1048                         idx++;
1049                     }
1050                 }
1051             }
1052         }
1053         OICFree(buf);
1054     } // while
1055
1056     unsigned char* token = NULL;
1057     unsigned int token_length = 0;
1058     coap_get_token2(pdu->transport_hdr, transport, &token, &token_length);
1059
1060     // set token data
1061     if (token_length > 0)
1062     {
1063         OIC_LOG_V(DEBUG, TAG, "inside token length : %d", token_length);
1064         outInfo->token = (char *) OICMalloc(token_length);
1065         if (NULL == outInfo->token)
1066         {
1067             OIC_LOG(ERROR, TAG, "Out of memory");
1068             OICFree(outInfo->options);
1069             OICFree(optionResult);
1070             return CA_MEMORY_ALLOC_FAILED;
1071         }
1072         memcpy(outInfo->token, token, token_length);
1073     }
1074
1075     assert(token_length <= UINT8_MAX);
1076     outInfo->tokenLength = (uint8_t)token_length;
1077
1078     // set payload data
1079     size_t dataSize;
1080     uint8_t *data;
1081     if (coap_get_data(pdu, &dataSize, &data))
1082     {
1083         OIC_LOG(DEBUG, TAG, "inside pdu->data");
1084         outInfo->payload = (uint8_t *) OICMalloc(dataSize);
1085         if (NULL == outInfo->payload)
1086         {
1087             OIC_LOG(ERROR, TAG, "Out of memory");
1088             OICFree(outInfo->options);
1089             OICFree(outInfo->token);
1090             OICFree(optionResult);
1091             return CA_MEMORY_ALLOC_FAILED;
1092         }
1093         memcpy(outInfo->payload, pdu->data, dataSize);
1094         outInfo->payloadSize = dataSize;
1095     }
1096
1097     if (optionResult[0] != '\0')
1098     {
1099         optionResult[optionLength] = '\0';
1100         OIC_LOG_V(DEBUG, TAG, "URL length:%" PRIuPTR, strlen(optionResult));
1101         outInfo->resourceUri = OICStrdup(optionResult);
1102         if (!outInfo->resourceUri)
1103         {
1104             OIC_LOG(ERROR, TAG, "Out of memory");
1105             OICFree(outInfo->options);
1106             OICFree(outInfo->token);
1107             OICFree(optionResult);
1108             return CA_MEMORY_ALLOC_FAILED;
1109         }
1110     }
1111     else if(isProxyRequest && g_chproxyUri[0] != '\0')
1112     {
1113        /*
1114         *   A request for Proxy will not have any URI element as per CoAP specs
1115         *   and only COAP_OPTION_PROXY_URI will be present. Use preset proxy URI
1116         *   for such requests.
1117         */
1118         outInfo->resourceUri = OICStrdup(g_chproxyUri);
1119         if (!outInfo->resourceUri)
1120         {
1121             OIC_LOG(ERROR, TAG, "Out of memory");
1122             OICFree(outInfo->options);
1123             OICFree(outInfo->token);
1124             OICFree(optionResult);
1125             return CA_MEMORY_ALLOC_FAILED;
1126         }
1127     }
1128     OICFree(optionResult);
1129     OIC_LOG(INFO, TAG, "OUT - CAGetInfoFromPDU");
1130     return CA_STATUS_OK;
1131
1132 exit:
1133     OIC_LOG(ERROR, TAG, "buffer too small");
1134     OICFree(outInfo->options);
1135     OICFree(optionResult);
1136     return CA_STATUS_FAILED;
1137 }
1138
1139 CAResult_t CAGetTokenFromPDU(const coap_hdr_transport_t *pdu_hdr,
1140                              CAInfo_t *outInfo,
1141                              const CAEndpoint_t *endpoint)
1142 {
1143     VERIFY_NON_NULL(pdu_hdr, TAG, "pdu_hdr");
1144     VERIFY_NON_NULL(outInfo, TAG, "outInfo");
1145     VERIFY_NON_NULL(endpoint, TAG, "endpoint");
1146
1147     coap_transport_t transport = COAP_UDP;
1148 #ifdef WITH_TCP
1149     if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
1150     {
1151         transport = coap_get_tcp_header_type_from_initbyte(((unsigned char *)pdu_hdr)[0] >> 4);
1152     }
1153 #endif
1154
1155     unsigned char* token = NULL;
1156     unsigned int token_length = 0;
1157     coap_get_token2(pdu_hdr, transport, &token, &token_length);
1158
1159     // set token data
1160     if (token_length > 0)
1161     {
1162         OIC_LOG_V(DEBUG, TAG, "token len:%d", token_length);
1163         outInfo->token = (char *) OICMalloc(token_length);
1164         if (NULL == outInfo->token)
1165         {
1166             OIC_LOG(ERROR, TAG, "Out of memory");
1167             return CA_MEMORY_ALLOC_FAILED;
1168         }
1169         memcpy(outInfo->token, token, token_length);
1170     }
1171
1172     assert(token_length <= UINT8_MAX);
1173     outInfo->tokenLength = (uint8_t)token_length;
1174
1175     return CA_STATUS_OK;
1176 }
1177
1178 CAResult_t CAGenerateTokenInternal(CAToken_t *token, uint8_t tokenLength)
1179 {
1180     VERIFY_NON_NULL(token, TAG, "token");
1181
1182     if ((tokenLength > CA_MAX_TOKEN_LEN) || (0 == tokenLength))
1183     {
1184         OIC_LOG(ERROR, TAG, "invalid token length");
1185         return CA_STATUS_INVALID_PARAM;
1186     }
1187
1188     // memory allocation, token is stored as a Pascal-style string
1189     char *temp = (char *) OICCalloc(tokenLength + 1, sizeof(char));
1190     if (NULL == temp)
1191     {
1192         OIC_LOG(ERROR, TAG, "Out of memory");
1193         return CA_MEMORY_ALLOC_FAILED;
1194     }
1195
1196     *temp++ = tokenLength;
1197     if (!OCGetRandomBytes((uint8_t *)temp, tokenLength))
1198     {
1199         OIC_LOG(ERROR, TAG, "Failed to generate random token");
1200         return CA_STATUS_FAILED;
1201     }
1202
1203     // save token
1204     *token = temp;
1205
1206     OIC_LOG_V(DEBUG, TAG, "token len:%d, token:", tokenLength);
1207     OIC_LOG_BUFFER(DEBUG, TAG, (const uint8_t *)(*token), tokenLength);
1208
1209     return CA_STATUS_OK;
1210 }
1211
1212 void CADestroyTokenInternal(CAToken_t token)
1213 {
1214     if (token)
1215     {
1216         char *temp = token - 1;
1217 #ifdef WITH_BWT
1218         CARemoveBlockMulticastDataFromListWithSeed(token, *temp);
1219 #endif
1220         OICFree(temp);
1221     }
1222 }
1223
1224 uint32_t CAGetOptionData(uint16_t key, const uint8_t *data, uint32_t len,
1225         uint8_t *option, uint32_t buflen)
1226 {
1227     if (0 == buflen)
1228     {
1229         OIC_LOG(ERROR, TAG, "buflen 0");
1230         return 0;
1231     }
1232
1233     if (buflen <= len)
1234     {
1235         OIC_LOG(ERROR, TAG, "option buffer too small");
1236         return 0;
1237     }
1238
1239     coap_option_def_t* def = coap_opt_def(key);
1240     if (NULL != def && coap_is_var_bytes(def) && 0 == len)
1241     {
1242         // A 0 length option is permitted in CoAP but the
1243         // rest or the stack is unaware of variable byte encoding
1244         // should remain that way so a 0 byte of length 1 is inserted.
1245         len = 1;
1246         option[0]=0;
1247     }
1248     else
1249     {
1250         memcpy(option, data, len);
1251         option[len] = '\0';
1252     }
1253
1254     return len;
1255 }
1256
1257 CAMessageType_t CAGetMessageTypeFromPduBinaryData(const void *pdu, uint32_t size)
1258 {
1259     VERIFY_NON_NULL_RET(pdu, TAG, "pdu", CA_MSG_NONCONFIRM);
1260
1261     // pdu minimum size is 4 byte.
1262     if (size < CA_PDU_MIN_SIZE)
1263     {
1264         OIC_LOG(ERROR, TAG, "min size");
1265         return CA_MSG_NONCONFIRM;
1266     }
1267
1268     coap_hdr_t *hdr = (coap_hdr_t *) pdu;
1269
1270     return (CAMessageType_t) hdr->type;
1271 }
1272
1273 uint16_t CAGetMessageIdFromPduBinaryData(const void *pdu, uint32_t size)
1274 {
1275     VERIFY_NON_NULL_RET(pdu, TAG, "pdu", 0);
1276
1277     // pdu minimum size is 4 byte.
1278     if (size < CA_PDU_MIN_SIZE)
1279     {
1280         OIC_LOG(ERROR, TAG, "min size");
1281         return 0;
1282     }
1283
1284     coap_hdr_t *hdr = (coap_hdr_t *) pdu;
1285
1286     return hdr->id;
1287 }
1288
1289 CAResponseResult_t CAGetCodeFromPduBinaryData(const void *pdu, uint32_t size)
1290 {
1291     VERIFY_NON_NULL_RET(pdu, TAG, "pdu", CA_NOT_FOUND);
1292
1293     // pdu minimum size is 4 byte.
1294     if (size < CA_PDU_MIN_SIZE)
1295     {
1296         OIC_LOG(ERROR, TAG, "min size");
1297         return CA_NOT_FOUND;
1298     }
1299
1300     coap_hdr_t *hdr = (coap_hdr_t *) pdu;
1301
1302     return (CAResponseResult_t) CA_RESPONSE_CODE(hdr->code);
1303 }
1304
1305 CAPayloadFormat_t CAConvertFormat(uint16_t format)
1306 {
1307     switch (format)
1308     {
1309         case COAP_MEDIATYPE_TEXT_PLAIN:
1310             return CA_FORMAT_TEXT_PLAIN;
1311         case COAP_MEDIATYPE_APPLICATION_LINK_FORMAT:
1312             return CA_FORMAT_APPLICATION_LINK_FORMAT;
1313         case COAP_MEDIATYPE_APPLICATION_XML:
1314             return CA_FORMAT_APPLICATION_XML;
1315         case COAP_MEDIATYPE_APPLICATION_OCTET_STREAM:
1316             return CA_FORMAT_APPLICATION_OCTET_STREAM;
1317         case COAP_MEDIATYPE_APPLICATION_RDF_XML:
1318             return CA_FORMAT_APPLICATION_RDF_XML;
1319         case COAP_MEDIATYPE_APPLICATION_EXI:
1320             return CA_FORMAT_APPLICATION_EXI;
1321         case COAP_MEDIATYPE_APPLICATION_JSON:
1322             return CA_FORMAT_APPLICATION_JSON;
1323         case COAP_MEDIATYPE_APPLICATION_CBOR:
1324             return CA_FORMAT_APPLICATION_CBOR;
1325         case COAP_MEDIATYPE_APPLICATION_VND_OCF_CBOR:
1326             return CA_FORMAT_APPLICATION_VND_OCF_CBOR;
1327         default:
1328             return CA_FORMAT_UNSUPPORTED;
1329     }
1330 }
1331
1332 #ifdef WITH_BWT
1333 bool CAIsSupportedBlockwiseTransfer(CATransportAdapter_t adapter)
1334 {
1335     if (CA_ADAPTER_IP & adapter || CA_ADAPTER_NFC & adapter
1336             || CA_DEFAULT_ADAPTER == adapter)
1337     {
1338         return true;
1339     }
1340     OIC_LOG_V(INFO, TAG, "adapter value of BWT is %d", adapter);
1341     return false;
1342 }
1343 #endif
1344
1345 #ifdef WITH_TCP
1346 bool CAIsSupportedCoAPOverTCP(CATransportAdapter_t adapter)
1347 {
1348     if (CA_ADAPTER_GATT_BTLE & adapter || CA_ADAPTER_RFCOMM_BTEDR & adapter
1349             || CA_ADAPTER_TCP & adapter || CA_DEFAULT_ADAPTER == adapter)
1350     {
1351         return true;
1352     }
1353     OIC_LOG_V(INFO, TAG, "adapter value of CoAP/TCP is %d", adapter);
1354     return false;
1355 }
1356 #endif