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