Use `URI` all caps in documentation
[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         int32_t ret = coap_add_token2(pdu, tokenLength, (unsigned char *)info->token, *transport);
378         if (0 == ret)
379         {
380             OIC_LOG(ERROR, TAG, "can't add token");
381         }
382     }
383
384 #ifdef WITH_BWT
385     if (CA_ADAPTER_GATT_BTLE != endpoint->adapter
386 #ifdef WITH_TCP
387             && !CAIsSupportedCoAPOverTCP(endpoint->adapter)
388 #endif
389             )
390     {
391         // option list will be added in blockwise-transfer
392         return pdu;
393     }
394 #endif
395
396     if (options)
397     {
398         for (coap_list_t *opt = options; opt; opt = opt->next)
399         {
400             OIC_LOG_V(DEBUG, TAG, "[%s] opt will be added.",
401                       COAP_OPTION_DATA(*(coap_option *) opt->data));
402
403             OIC_LOG_V(DEBUG, TAG, "[%d] pdu length", pdu->length);
404             if (0 == coap_add_option2(pdu, COAP_OPTION_KEY(*(coap_option *) opt->data),
405                                       COAP_OPTION_LENGTH(*(coap_option *) opt->data),
406                                       COAP_OPTION_DATA(*(coap_option *) opt->data), *transport))
407             {
408                 OIC_LOG(ERROR, TAG, "coap_add_option2 has failed");
409                 coap_delete_pdu(pdu);
410                 return NULL;
411             }
412         }
413     }
414
415     OIC_LOG_V(DEBUG, TAG, "[%d] pdu length after option", pdu->length);
416
417     if ((NULL != info->payload) && (0 < info->payloadSize))
418     {
419         OIC_LOG(DEBUG, TAG, "payload is added");
420         coap_add_data(pdu, (unsigned int)info->payloadSize,
421                       (const unsigned char*)info->payload);
422     }
423
424     return pdu;
425 }
426
427 CAResult_t CAParseURI(const char *uriInfo, coap_list_t **optlist)
428 {
429     VERIFY_NON_NULL(uriInfo, TAG, "uriInfo");
430     VERIFY_NON_NULL(optlist, TAG, "optlist");
431
432     /* split arg into Uri-* options */
433     coap_uri_t uri;
434     coap_split_uri((unsigned char *) uriInfo, strlen(uriInfo), &uri);
435
436     if (uri.port != COAP_DEFAULT_PORT)
437     {
438         unsigned char portbuf[CA_ENCODE_BUFFER_SIZE] = { 0 };
439         int ret = coap_insert(optlist,
440                               CACreateNewOptionNode(COAP_OPTION_URI_PORT,
441                                                     coap_encode_var_bytes(portbuf, uri.port),
442                                                     (char *)portbuf),
443                               CAOrderOpts);
444         if (ret <= 0)
445         {
446             return CA_STATUS_INVALID_PARAM;
447         }
448     }
449
450     if (uri.path.s && uri.path.length)
451     {
452         CAResult_t ret = CAParseUriPartial(uri.path.s, uri.path.length,
453                                            COAP_OPTION_URI_PATH, optlist);
454         if (CA_STATUS_OK != ret)
455         {
456             OIC_LOG(ERROR, TAG, "CAParseUriPartial failed(uri path)");
457             return ret;
458         }
459     }
460
461     if (uri.query.s && uri.query.length)
462     {
463         CAResult_t ret = CAParseUriPartial(uri.query.s, uri.query.length, COAP_OPTION_URI_QUERY,
464                                            optlist);
465         if (CA_STATUS_OK != ret)
466         {
467             OIC_LOG(ERROR, TAG, "CAParseUriPartial failed(uri query)");
468             return ret;
469         }
470     }
471
472     return CA_STATUS_OK;
473 }
474
475 CAResult_t CAParseUriPartial(const unsigned char *str, size_t length, uint16_t target,
476                              coap_list_t **optlist)
477 {
478     VERIFY_NON_NULL(optlist, TAG, "optlist");
479
480     if ((target != COAP_OPTION_URI_PATH) && (target != COAP_OPTION_URI_QUERY))
481     {
482         // should never occur. Log just in case.
483         OIC_LOG(DEBUG, TAG, "Unexpected URI component.");
484         return CA_NOT_SUPPORTED;
485     }
486     else if (str && length)
487     {
488         unsigned char uriBuffer[CA_MAX_URI_LENGTH] = { 0 };
489         unsigned char *pBuf = uriBuffer;
490         size_t unusedBufferSize = sizeof(uriBuffer);
491         int res = (target == COAP_OPTION_URI_PATH) ? coap_split_path(str, length, pBuf, &unusedBufferSize) :
492                                                      coap_split_query(str, length, pBuf, &unusedBufferSize);
493
494         if (res > 0)
495         {
496             assert(unusedBufferSize < sizeof(uriBuffer));
497             size_t usedBufferSize = sizeof(uriBuffer) - unusedBufferSize;
498             size_t prevIdx = 0;
499             while (res--)
500             {
501                 int ret = coap_insert(optlist,
502                                       CACreateNewOptionNode(target, COAP_OPT_LENGTH(pBuf),
503                                                             (char *)COAP_OPT_VALUE(pBuf)),
504                                       CAOrderOpts);
505                 if (ret <= 0)
506                 {
507                     return CA_STATUS_INVALID_PARAM;
508                 }
509
510                 size_t optSize = COAP_OPT_SIZE(pBuf);
511                 if (prevIdx + optSize > usedBufferSize)
512                 {
513                     assert(false);
514                     return CA_STATUS_INVALID_PARAM;
515                 }
516                 pBuf += optSize;
517                 prevIdx += optSize;
518             }
519         }
520         else
521         {
522             OIC_LOG_V(ERROR, TAG, "Problem parsing URI : %d for %d", res, target);
523             return CA_STATUS_FAILED;
524         }
525     }
526     else
527     {
528         OIC_LOG(ERROR, TAG, "str or length is not available");
529         return CA_STATUS_FAILED;
530     }
531
532     return CA_STATUS_OK;
533 }
534
535 CAResult_t CAParseHeadOption(uint32_t code, const CAInfo_t *info, coap_list_t **optlist)
536 {
537     (void)code;
538     VERIFY_NON_NULL_RET(info, TAG, "info", CA_STATUS_INVALID_PARAM);
539
540     OIC_LOG_V(DEBUG, TAG, "parse Head Opt: %d", info->numOptions);
541
542     if (!optlist)
543     {
544         OIC_LOG(ERROR, TAG, "optlist is null");
545         return CA_STATUS_INVALID_PARAM;
546     }
547
548     for (uint32_t i = 0; i < info->numOptions; i++)
549     {
550         if(!(info->options + i))
551         {
552             OIC_LOG(ERROR, TAG, "options is not available");
553             return CA_STATUS_FAILED;
554         }
555
556         uint16_t id = (info->options + i)->optionID;
557         switch (id)
558         {
559             case COAP_OPTION_URI_PATH:
560             case COAP_OPTION_URI_QUERY:
561                 OIC_LOG_V(DEBUG, TAG, "not Header Opt: %d", id);
562                 break;
563             case COAP_OPTION_ACCEPT:
564             case CA_OPTION_ACCEPT_VERSION:
565             case COAP_OPTION_CONTENT_FORMAT:
566             case CA_OPTION_CONTENT_VERSION:
567                 // this is handled below via CAParsePayloadFormatHeadOption
568                 break;
569             default:
570                 OIC_LOG_V(DEBUG, TAG, "Head opt ID[%d], length[%d]", id,
571                     (info->options + i)->optionLength);
572                 int ret = coap_insert(optlist,
573                                       CACreateNewOptionNode(id, (info->options + i)->optionLength,
574                                                             (info->options + i)->optionData),
575                                       CAOrderOpts);
576                 if (ret <= 0)
577                 {
578                     return CA_STATUS_INVALID_PARAM;
579                 }
580         }
581     }
582
583     // insert one extra header with the payload format if applicable.
584     if (CA_FORMAT_UNDEFINED != info->payloadFormat)
585     {
586         CAParsePayloadFormatHeadOption(COAP_OPTION_CONTENT_FORMAT, info->payloadFormat, CA_OPTION_CONTENT_VERSION, info->payloadVersion, optlist);
587     }
588
589     if (CA_FORMAT_UNDEFINED != info->acceptFormat)
590     {
591         CAParsePayloadFormatHeadOption(COAP_OPTION_ACCEPT, info->acceptFormat, CA_OPTION_ACCEPT_VERSION, info->acceptVersion, optlist);
592     }
593
594     return CA_STATUS_OK;
595 }
596
597 CAResult_t CAParsePayloadFormatHeadOption(uint16_t formatOption, CAPayloadFormat_t format,
598         uint16_t versionOption, uint16_t version, coap_list_t **optlist)
599 {
600     coap_list_t* encodeNode = NULL;
601     coap_list_t* versionNode = NULL;
602     uint8_t encodeBuf[CA_ENCODE_BUFFER_SIZE] = { 0 };
603     uint8_t versionBuf[CA_ENCODE_BUFFER_SIZE] = { 0 };
604
605     switch (format)
606     {
607         case CA_FORMAT_APPLICATION_CBOR:
608             encodeNode = CACreateNewOptionNode(formatOption,
609                     coap_encode_var_bytes(encodeBuf,
610                             (unsigned short) COAP_MEDIATYPE_APPLICATION_CBOR), (char *) encodeBuf);
611             break;
612         case CA_FORMAT_APPLICATION_VND_OCF_CBOR:
613             encodeNode = CACreateNewOptionNode(formatOption,
614                     coap_encode_var_bytes(encodeBuf,
615                             (unsigned short) COAP_MEDIATYPE_APPLICATION_VND_OCF_CBOR),
616                     (char *) encodeBuf);
617             break;
618         default:
619             OIC_LOG_V(ERROR, TAG, "Format option:[%d] not supported", format);
620     }
621     if (!encodeNode)
622     {
623         OIC_LOG(ERROR, TAG, "Format option not created");
624         return CA_STATUS_INVALID_PARAM;
625     }
626     int ret = coap_insert(optlist, encodeNode, CAOrderOpts);
627     if (0 >= ret)
628     {
629         coap_delete(encodeNode);
630         OIC_LOG(ERROR, TAG, "Format option not inserted in header");
631         return CA_STATUS_INVALID_PARAM;
632     }
633
634     if ((CA_OPTION_ACCEPT_VERSION == versionOption ||
635          CA_OPTION_CONTENT_VERSION == versionOption) &&
636         CA_FORMAT_APPLICATION_VND_OCF_CBOR == format)
637     {
638         versionNode = CACreateNewOptionNode(versionOption,
639                 coap_encode_var_bytes(versionBuf, version), (char *) versionBuf);
640
641         if (!versionNode)
642         {
643             OIC_LOG(ERROR, TAG, "Version option not created");
644             coap_delete(encodeNode);
645             return CA_STATUS_INVALID_PARAM;
646         }
647         ret = coap_insert(optlist, versionNode, CAOrderOpts);
648         if (0 >= ret)
649         {
650             coap_delete(versionNode);
651             coap_delete(encodeNode);
652             OIC_LOG(ERROR, TAG, "Content version option not inserted in header");
653             return CA_STATUS_INVALID_PARAM;
654         }
655     }
656     return CA_STATUS_OK;
657 }
658
659 coap_list_t *CACreateNewOptionNode(uint16_t key, uint32_t length, const char *data)
660 {
661     VERIFY_NON_NULL_RET(data, TAG, "data", NULL);
662
663     coap_option *option = coap_malloc(sizeof(coap_option) + length + 1);
664     if (!option)
665     {
666         OIC_LOG(ERROR, TAG, "Out of memory");
667         return NULL;
668     }
669     memset(option, 0, sizeof(coap_option) + length + 1);
670
671     COAP_OPTION_KEY(*option) = key;
672
673     coap_option_def_t* def = coap_opt_def(key);
674     if (NULL != def && coap_is_var_bytes(def))
675     {
676        if (length > def->max)
677         {
678             // make sure we shrink the value so it fits the coap option definition
679             // by truncating the value, disregard the leading bytes.
680             OIC_LOG_V(DEBUG, TAG, "Option [%d] data size [%d] shrunk to [%d]",
681                     def->key, length, def->max);
682             data = &(data[length-def->max]);
683             length = def->max;
684         }
685         // Shrink the encoding length to a minimum size for coap
686         // options that support variable length encoding.
687          COAP_OPTION_LENGTH(*option) = coap_encode_var_bytes(
688                 COAP_OPTION_DATA(*option),
689                 coap_decode_var_bytes((unsigned char *)data, length));
690     }
691     else
692     {
693         COAP_OPTION_LENGTH(*option) = length;
694         memcpy(COAP_OPTION_DATA(*option), data, length);
695     }
696
697     /* we can pass NULL here as delete function since option is released automatically  */
698     coap_list_t *node = coap_new_listnode(option, NULL);
699
700     if (!node)
701     {
702         OIC_LOG(ERROR, TAG, "node is NULL");
703         coap_free(option);
704         return NULL;
705     }
706
707     return node;
708 }
709
710 int CAOrderOpts(void *a, void *b)
711 {
712     if (!a || !b)
713     {
714         return a < b ? -1 : 1;
715     }
716
717     if (COAP_OPTION_KEY(*(coap_option *) a) < COAP_OPTION_KEY(*(coap_option * ) b))
718     {
719         return -1;
720     }
721
722     return COAP_OPTION_KEY(*(coap_option *) a) == COAP_OPTION_KEY(*(coap_option * ) b);
723 }
724
725 CAResult_t CAGetOptionCount(coap_opt_iterator_t opt_iter, uint8_t *optionCount)
726 {
727     CAResult_t result = CA_STATUS_OK;
728     coap_opt_t *option = NULL;
729     *optionCount = 0;
730
731     while ((option = coap_option_next(&opt_iter)))
732     {
733         if (COAP_OPTION_URI_PATH != opt_iter.type && COAP_OPTION_URI_QUERY != opt_iter.type
734             && COAP_OPTION_BLOCK1 != opt_iter.type && COAP_OPTION_BLOCK2 != opt_iter.type
735             && COAP_OPTION_SIZE1 != opt_iter.type && COAP_OPTION_SIZE2 != opt_iter.type
736             && COAP_OPTION_URI_HOST != opt_iter.type && COAP_OPTION_URI_PORT != opt_iter.type
737             && COAP_OPTION_ETAG != opt_iter.type && COAP_OPTION_MAXAGE != opt_iter.type
738             && COAP_OPTION_PROXY_SCHEME != opt_iter.type)
739         {
740             if (*optionCount < UINT8_MAX)
741             {
742                 (*optionCount)++;
743             }
744             else
745             {
746                 // Overflow. Return an error to the caller.
747                 assert(false);
748                 OIC_LOG_V(ERROR, TAG, "Overflow detected in %s", __func__);
749                 *optionCount = 0;
750                 result = CA_STATUS_FAILED;
751                 break;
752             }
753         }
754     }
755
756     return result;
757 }
758
759 CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
760                             uint32_t *outCode, CAInfo_t *outInfo)
761 {
762     OIC_LOG(INFO, TAG, "IN - CAGetInfoFromPDU");
763     VERIFY_NON_NULL(pdu, TAG, "pdu");
764     VERIFY_NON_NULL(endpoint, TAG, "endpoint");
765     VERIFY_NON_NULL(outCode, TAG, "outCode");
766     VERIFY_NON_NULL(outInfo, TAG, "outInfo");
767
768     coap_transport_t transport = COAP_UDP;
769 #ifdef WITH_TCP
770     if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
771     {
772         transport = coap_get_tcp_header_type_from_initbyte(((unsigned char *)pdu->transport_hdr)[0] >> 4);
773     }
774 #endif
775
776     coap_opt_iterator_t opt_iter;
777     coap_option_iterator_init2((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL, transport);
778
779     if (outCode)
780     {
781         (*outCode) = (uint32_t) CA_RESPONSE_CODE(coap_get_code(pdu, transport));
782     }
783
784     // init HeaderOption list
785     uint8_t count = 0;
786     CAResult_t countResult = CAGetOptionCount(opt_iter, &count);
787     if (CA_STATUS_OK != countResult)
788     {
789         OIC_LOG_V(ERROR, TAG, "CAGetOptionCount failed with error: %d!", countResult);
790         return countResult;
791     }
792
793     memset(outInfo, 0, sizeof(*outInfo));
794
795     outInfo->numOptions = count;
796
797 #ifdef WITH_TCP
798     if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
799     {
800         // set type
801         outInfo->type = CA_MSG_NONCONFIRM;
802         outInfo->payloadFormat = CA_FORMAT_UNDEFINED;
803     }
804     else
805 #else
806     (void) endpoint;
807 #endif
808     {
809         // set type
810         outInfo->type = pdu->transport_hdr->udp.type;
811
812         // set message id
813         outInfo->messageId = pdu->transport_hdr->udp.id;
814         outInfo->payloadFormat = CA_FORMAT_UNDEFINED;
815         outInfo->acceptFormat = CA_FORMAT_UNDEFINED;
816     }
817
818     if (count > 0)
819     {
820         outInfo->options = (CAHeaderOption_t *) OICCalloc(count, sizeof(CAHeaderOption_t));
821         if (NULL == outInfo->options)
822         {
823             OIC_LOG(ERROR, TAG, "Out of memory");
824             return CA_MEMORY_ALLOC_FAILED;
825         }
826     }
827
828     coap_opt_t *option = NULL;
829     char *optionResult = (char *)OICCalloc(1, CA_MAX_URI_LENGTH * sizeof(char));
830     if (NULL == optionResult)
831     {
832         goto exit;
833     }
834
835     uint32_t idx = 0;
836     uint32_t optionLength = 0;
837     bool isfirstsetflag = false;
838     bool isQueryBeingProcessed = false;
839     bool isProxyRequest = false;
840
841     while ((option = coap_option_next(&opt_iter)))
842     {
843         char *buf = (char *)OICCalloc(1, COAP_MAX_PDU_SIZE * sizeof(char));
844         if (NULL == buf)
845         {
846             goto exit;
847         }
848
849         uint32_t bufLength =
850             CAGetOptionData(opt_iter.type, (uint8_t *)(COAP_OPT_VALUE(option)),
851                     COAP_OPT_LENGTH(option), (uint8_t *)buf, COAP_MAX_PDU_SIZE);
852         if (bufLength)
853         {
854             OIC_LOG_V(DEBUG, TAG, "COAP URI element : %s", buf);
855             if (COAP_OPTION_URI_PATH == opt_iter.type || COAP_OPTION_URI_QUERY == opt_iter.type)
856             {
857                 if (false == isfirstsetflag)
858                 {
859                     isfirstsetflag = true;
860                     optionResult[optionLength] = '/';
861                     optionLength++;
862                     // Make sure there is enough room in the optionResult buffer
863                     if ((optionLength + bufLength) < CA_MAX_URI_LENGTH)
864                     {
865                         memcpy(&optionResult[optionLength], buf, bufLength);
866                         optionLength += bufLength;
867                     }
868                     else
869                     {
870                         OICFree(buf);
871                         goto exit;
872                     }
873                 }
874                 else
875                 {
876                     if (COAP_OPTION_URI_PATH == opt_iter.type)
877                     {
878                         // Make sure there is enough room in the optionResult buffer
879                         if (optionLength < CA_MAX_URI_LENGTH)
880                         {
881                             optionResult[optionLength] = '/';
882                             optionLength++;
883                         }
884                         else
885                         {
886                             OICFree(buf);
887                             goto exit;
888                         }
889                     }
890                     else if (COAP_OPTION_URI_QUERY == opt_iter.type)
891                     {
892                         if (false == isQueryBeingProcessed)
893                         {
894                             // Make sure there is enough room in the optionResult buffer
895                             if (optionLength < CA_MAX_URI_LENGTH)
896                             {
897                                 optionResult[optionLength] = '?';
898                                 optionLength++;
899                                 isQueryBeingProcessed = true;
900                             }
901                             else
902                             {
903                                 OICFree(buf);
904                                 goto exit;
905                             }
906                         }
907                         else
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                             }
915                             else
916                             {
917                                 OICFree(buf);
918                                 goto exit;
919                             }
920                         }
921                     }
922                     // Make sure there is enough room in the optionResult buffer
923                     if ((optionLength + bufLength) < CA_MAX_URI_LENGTH)
924                     {
925                         memcpy(&optionResult[optionLength], buf, bufLength);
926                         optionLength += bufLength;
927                     }
928                     else
929                     {
930                         OICFree(buf);
931                         goto exit;
932                     }
933                 }
934             }
935             else if (COAP_OPTION_BLOCK1 == opt_iter.type || COAP_OPTION_BLOCK2 == opt_iter.type
936                     || COAP_OPTION_SIZE1 == opt_iter.type || COAP_OPTION_SIZE2 == opt_iter.type)
937             {
938                 OIC_LOG_V(DEBUG, TAG, "option[%d] will be filtering", opt_iter.type);
939             }
940             else if (COAP_OPTION_URI_PORT == opt_iter.type ||
941                     COAP_OPTION_URI_HOST == opt_iter.type ||
942                     COAP_OPTION_ETAG == opt_iter.type ||
943                     COAP_OPTION_MAXAGE == opt_iter.type ||
944                     COAP_OPTION_PROXY_SCHEME== opt_iter.type)
945             {
946                 OIC_LOG_V(INFO, TAG, "option[%d] has an unsupported format [%d]",
947                           opt_iter.type, (uint8_t)buf[0]);
948             }
949             else
950             {
951                 if (COAP_OPTION_PROXY_URI == opt_iter.type)
952                 {
953                     isProxyRequest = true;
954                 }
955                 else if (CA_OPTION_ACCEPT_VERSION == opt_iter.type)
956                 {
957                     if (2 == COAP_OPT_LENGTH(option))
958                     {
959                         unsigned int decodedVersion = coap_decode_var_bytes(COAP_OPT_VALUE(option),
960                                 COAP_OPT_LENGTH(option));
961                         assert(decodedVersion <= UINT16_MAX);
962                         outInfo->acceptVersion = (uint16_t) decodedVersion;
963                     }
964                     else
965                     {
966                         OIC_LOG(DEBUG, TAG, "unsupported accept version");
967                         outInfo->acceptVersion = DEFAULT_VERSION_VALUE;
968                     }
969                 }
970                 else if (COAP_OPTION_ACCEPT == opt_iter.type)
971                 {
972                     if (1 == COAP_OPT_LENGTH(option))
973                     {
974                         outInfo->acceptFormat = CAConvertFormat((uint8_t) buf[0]);
975                     }
976                     else if (2 == COAP_OPT_LENGTH(option))
977                     {
978                         unsigned int decodedFormat = coap_decode_var_bytes(COAP_OPT_VALUE(option),
979                                 COAP_OPT_LENGTH(option));
980                         assert(decodedFormat <= UINT16_MAX);
981                         outInfo->acceptFormat = CAConvertFormat((uint16_t) decodedFormat);
982                     }
983                     else
984                     {
985                         outInfo->acceptFormat = CA_FORMAT_UNSUPPORTED;
986                         OIC_LOG(DEBUG, TAG, "option has an unsupported accept format");
987                     }
988                 }
989                 else if (CA_OPTION_CONTENT_VERSION == opt_iter.type)
990                 {
991                     if (2 == COAP_OPT_LENGTH(option))
992                     {
993                         unsigned int decodedVersion = coap_decode_var_bytes(COAP_OPT_VALUE(option),
994                                 COAP_OPT_LENGTH(option));
995                         assert(decodedVersion <= UINT16_MAX);
996                         outInfo->payloadVersion = (uint16_t) decodedVersion;
997                     }
998                     else
999                     {
1000                         OIC_LOG(DEBUG, TAG, "unsupported payload version");
1001                         outInfo->payloadVersion = DEFAULT_VERSION_VALUE;
1002                     }
1003                 }
1004                 else if (COAP_OPTION_CONTENT_FORMAT == opt_iter.type)
1005                 {
1006                     if (1 == COAP_OPT_LENGTH(option))
1007                     {
1008                         outInfo->payloadFormat = CAConvertFormat((uint8_t) buf[0]);
1009                     }
1010                     else if (2 == COAP_OPT_LENGTH(option))
1011                     {
1012                         unsigned int decodedFormat = coap_decode_var_bytes(COAP_OPT_VALUE(option),
1013                                 COAP_OPT_LENGTH(option));
1014                         assert(decodedFormat <= UINT16_MAX);
1015                         outInfo->payloadFormat = CAConvertFormat((uint16_t) decodedFormat);
1016                     }
1017                     else
1018                     {
1019                         outInfo->payloadFormat = CA_FORMAT_UNSUPPORTED;
1020                         OIC_LOG(DEBUG, TAG, "option has an unsupported accept format");
1021                     }
1022                 }
1023
1024                 if (idx < count)
1025                 {
1026                     if (bufLength <= sizeof(outInfo->options[0].optionData))
1027                     {
1028                         outInfo->options[idx].optionID = opt_iter.type;
1029                         assert(bufLength <= UINT16_MAX);
1030                         outInfo->options[idx].optionLength = (uint16_t)bufLength;
1031                         outInfo->options[idx].protocolID = CA_COAP_ID;
1032                         memcpy(outInfo->options[idx].optionData, buf, bufLength);
1033                         idx++;
1034                     }
1035                 }
1036             }
1037         }
1038         OICFree(buf);
1039     } // while
1040
1041     unsigned char* token = NULL;
1042     unsigned int token_length = 0;
1043     coap_get_token2(pdu->transport_hdr, transport, &token, &token_length);
1044
1045     // set token data
1046     if (token_length > 0)
1047     {
1048         OIC_LOG_V(DEBUG, TAG, "inside token length : %d", token_length);
1049         outInfo->token = (char *) OICMalloc(token_length);
1050         if (NULL == outInfo->token)
1051         {
1052             OIC_LOG(ERROR, TAG, "Out of memory");
1053             OICFree(outInfo->options);
1054             OICFree(optionResult);
1055             return CA_MEMORY_ALLOC_FAILED;
1056         }
1057         memcpy(outInfo->token, token, token_length);
1058     }
1059
1060     assert(token_length <= UINT8_MAX);
1061     outInfo->tokenLength = (uint8_t)token_length;
1062
1063     // set payload data
1064     size_t dataSize;
1065     uint8_t *data;
1066     if (coap_get_data(pdu, &dataSize, &data))
1067     {
1068         OIC_LOG(DEBUG, TAG, "inside pdu->data");
1069         outInfo->payload = (uint8_t *) OICMalloc(dataSize);
1070         if (NULL == outInfo->payload)
1071         {
1072             OIC_LOG(ERROR, TAG, "Out of memory");
1073             OICFree(outInfo->options);
1074             OICFree(outInfo->token);
1075             OICFree(optionResult);
1076             return CA_MEMORY_ALLOC_FAILED;
1077         }
1078         memcpy(outInfo->payload, pdu->data, dataSize);
1079         outInfo->payloadSize = dataSize;
1080     }
1081
1082     if (optionResult[0] != '\0')
1083     {
1084         optionResult[optionLength] = '\0';
1085         OIC_LOG_V(DEBUG, TAG, "URL length:%" PRIuPTR, strlen(optionResult));
1086         outInfo->resourceUri = OICStrdup(optionResult);
1087         if (!outInfo->resourceUri)
1088         {
1089             OIC_LOG(ERROR, TAG, "Out of memory");
1090             OICFree(outInfo->options);
1091             OICFree(outInfo->token);
1092             OICFree(optionResult);
1093             return CA_MEMORY_ALLOC_FAILED;
1094         }
1095     }
1096     else if(isProxyRequest && g_chproxyUri[0] != '\0')
1097     {
1098        /*
1099         *   A request for Proxy will not have any URI element as per CoAP specs
1100         *   and only COAP_OPTION_PROXY_URI will be present. Use preset proxy URI
1101         *   for such requests.
1102         */
1103         outInfo->resourceUri = OICStrdup(g_chproxyUri);
1104         if (!outInfo->resourceUri)
1105         {
1106             OIC_LOG(ERROR, TAG, "Out of memory");
1107             OICFree(outInfo->options);
1108             OICFree(outInfo->token);
1109             OICFree(optionResult);
1110             return CA_MEMORY_ALLOC_FAILED;
1111         }
1112     }
1113     OICFree(optionResult);
1114     OIC_LOG(INFO, TAG, "OUT - CAGetInfoFromPDU");
1115     return CA_STATUS_OK;
1116
1117 exit:
1118     OIC_LOG(ERROR, TAG, "buffer too small");
1119     OICFree(outInfo->options);
1120     OICFree(optionResult);
1121     return CA_STATUS_FAILED;
1122 }
1123
1124 CAResult_t CAGetTokenFromPDU(const coap_hdr_transport_t *pdu_hdr,
1125                              CAInfo_t *outInfo,
1126                              const CAEndpoint_t *endpoint)
1127 {
1128     VERIFY_NON_NULL(pdu_hdr, TAG, "pdu_hdr");
1129     VERIFY_NON_NULL(outInfo, TAG, "outInfo");
1130     VERIFY_NON_NULL(endpoint, TAG, "endpoint");
1131
1132     coap_transport_t transport = COAP_UDP;
1133 #ifdef WITH_TCP
1134     if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
1135     {
1136         transport = coap_get_tcp_header_type_from_initbyte(((unsigned char *)pdu_hdr)[0] >> 4);
1137     }
1138 #endif
1139
1140     unsigned char* token = NULL;
1141     unsigned int token_length = 0;
1142     coap_get_token2(pdu_hdr, transport, &token, &token_length);
1143
1144     // set token data
1145     if (token_length > 0)
1146     {
1147         OIC_LOG_V(DEBUG, TAG, "token len:%d", token_length);
1148         outInfo->token = (char *) OICMalloc(token_length);
1149         if (NULL == outInfo->token)
1150         {
1151             OIC_LOG(ERROR, TAG, "Out of memory");
1152             return CA_MEMORY_ALLOC_FAILED;
1153         }
1154         memcpy(outInfo->token, token, token_length);
1155     }
1156
1157     assert(token_length <= UINT8_MAX);
1158     outInfo->tokenLength = (uint8_t)token_length;
1159
1160     return CA_STATUS_OK;
1161 }
1162
1163 CAResult_t CAGenerateTokenInternal(CAToken_t *token, uint8_t tokenLength)
1164 {
1165     VERIFY_NON_NULL(token, TAG, "token");
1166
1167     if ((tokenLength > CA_MAX_TOKEN_LEN) || (0 == tokenLength))
1168     {
1169         OIC_LOG(ERROR, TAG, "invalid token length");
1170         return CA_STATUS_INVALID_PARAM;
1171     }
1172
1173     // memory allocation, token is stored as a Pascal-style string
1174     char *temp = (char *) OICCalloc(tokenLength + 1, sizeof(char));
1175     if (NULL == temp)
1176     {
1177         OIC_LOG(ERROR, TAG, "Out of memory");
1178         return CA_MEMORY_ALLOC_FAILED;
1179     }
1180
1181     *temp++ = tokenLength;
1182     if (!OCGetRandomBytes((uint8_t *)temp, tokenLength))
1183     {
1184         OIC_LOG(ERROR, TAG, "Failed to generate random token");
1185         return CA_STATUS_FAILED;
1186     }
1187
1188     // save token
1189     *token = temp;
1190
1191     OIC_LOG_V(DEBUG, TAG, "token len:%d, token:", tokenLength);
1192     OIC_LOG_BUFFER(DEBUG, TAG, (const uint8_t *)(*token), tokenLength);
1193
1194     return CA_STATUS_OK;
1195 }
1196
1197 void CADestroyTokenInternal(CAToken_t token)
1198 {
1199     if (token)
1200     {
1201         char *temp = token - 1;
1202 #ifdef WITH_BWT
1203         CARemoveBlockMulticastDataFromListWithSeed(token, *temp);
1204 #endif
1205         OICFree(temp);
1206     }
1207 }
1208
1209 uint32_t CAGetOptionData(uint16_t key, const uint8_t *data, uint32_t len,
1210         uint8_t *option, uint32_t buflen)
1211 {
1212     if (0 == buflen)
1213     {
1214         OIC_LOG(ERROR, TAG, "buflen 0");
1215         return 0;
1216     }
1217
1218     if (buflen <= len)
1219     {
1220         OIC_LOG(ERROR, TAG, "option buffer too small");
1221         return 0;
1222     }
1223
1224     coap_option_def_t* def = coap_opt_def(key);
1225     if (NULL != def && coap_is_var_bytes(def) && 0 == len)
1226     {
1227         // A 0 length option is permitted in CoAP but the
1228         // rest or the stack is unaware of variable byte encoding
1229         // should remain that way so a 0 byte of length 1 is inserted.
1230         len = 1;
1231         option[0]=0;
1232     }
1233     else
1234     {
1235         memcpy(option, data, len);
1236         option[len] = '\0';
1237     }
1238
1239     return len;
1240 }
1241
1242 CAMessageType_t CAGetMessageTypeFromPduBinaryData(const void *pdu, uint32_t size)
1243 {
1244     VERIFY_NON_NULL_RET(pdu, TAG, "pdu", CA_MSG_NONCONFIRM);
1245
1246     // pdu minimum size is 4 byte.
1247     if (size < CA_PDU_MIN_SIZE)
1248     {
1249         OIC_LOG(ERROR, TAG, "min size");
1250         return CA_MSG_NONCONFIRM;
1251     }
1252
1253     coap_hdr_t *hdr = (coap_hdr_t *) pdu;
1254
1255     return (CAMessageType_t) hdr->type;
1256 }
1257
1258 uint16_t CAGetMessageIdFromPduBinaryData(const void *pdu, uint32_t size)
1259 {
1260     VERIFY_NON_NULL_RET(pdu, TAG, "pdu", 0);
1261
1262     // pdu minimum size is 4 byte.
1263     if (size < CA_PDU_MIN_SIZE)
1264     {
1265         OIC_LOG(ERROR, TAG, "min size");
1266         return 0;
1267     }
1268
1269     coap_hdr_t *hdr = (coap_hdr_t *) pdu;
1270
1271     return hdr->id;
1272 }
1273
1274 CAResponseResult_t CAGetCodeFromPduBinaryData(const void *pdu, uint32_t size)
1275 {
1276     VERIFY_NON_NULL_RET(pdu, TAG, "pdu", CA_NOT_FOUND);
1277
1278     // pdu minimum size is 4 byte.
1279     if (size < CA_PDU_MIN_SIZE)
1280     {
1281         OIC_LOG(ERROR, TAG, "min size");
1282         return CA_NOT_FOUND;
1283     }
1284
1285     coap_hdr_t *hdr = (coap_hdr_t *) pdu;
1286
1287     return (CAResponseResult_t) CA_RESPONSE_CODE(hdr->code);
1288 }
1289
1290 CAPayloadFormat_t CAConvertFormat(uint16_t format)
1291 {
1292     switch (format)
1293     {
1294         case COAP_MEDIATYPE_TEXT_PLAIN:
1295             return CA_FORMAT_TEXT_PLAIN;
1296         case COAP_MEDIATYPE_APPLICATION_LINK_FORMAT:
1297             return CA_FORMAT_APPLICATION_LINK_FORMAT;
1298         case COAP_MEDIATYPE_APPLICATION_XML:
1299             return CA_FORMAT_APPLICATION_XML;
1300         case COAP_MEDIATYPE_APPLICATION_OCTET_STREAM:
1301             return CA_FORMAT_APPLICATION_OCTET_STREAM;
1302         case COAP_MEDIATYPE_APPLICATION_RDF_XML:
1303             return CA_FORMAT_APPLICATION_RDF_XML;
1304         case COAP_MEDIATYPE_APPLICATION_EXI:
1305             return CA_FORMAT_APPLICATION_EXI;
1306         case COAP_MEDIATYPE_APPLICATION_JSON:
1307             return CA_FORMAT_APPLICATION_JSON;
1308         case COAP_MEDIATYPE_APPLICATION_CBOR:
1309             return CA_FORMAT_APPLICATION_CBOR;
1310         case COAP_MEDIATYPE_APPLICATION_VND_OCF_CBOR:
1311             return CA_FORMAT_APPLICATION_VND_OCF_CBOR;
1312         default:
1313             return CA_FORMAT_UNSUPPORTED;
1314     }
1315 }
1316
1317 #ifdef WITH_BWT
1318 bool CAIsSupportedBlockwiseTransfer(CATransportAdapter_t adapter)
1319 {
1320     if (CA_ADAPTER_IP & adapter || CA_ADAPTER_NFC & adapter
1321             || CA_DEFAULT_ADAPTER == adapter)
1322     {
1323         return true;
1324     }
1325     OIC_LOG_V(INFO, TAG, "adapter value of BWT is %d", adapter);
1326     return false;
1327 }
1328 #endif
1329
1330 #ifdef WITH_TCP
1331 bool CAIsSupportedCoAPOverTCP(CATransportAdapter_t adapter)
1332 {
1333     if (CA_ADAPTER_GATT_BTLE & adapter || CA_ADAPTER_RFCOMM_BTEDR & adapter
1334             || CA_ADAPTER_TCP & adapter || CA_DEFAULT_ADAPTER == adapter)
1335     {
1336         return true;
1337     }
1338     OIC_LOG_V(INFO, TAG, "adapter value of CoAP/TCP is %d", adapter);
1339     return false;
1340 }
1341 #endif