merge master code to build iotivity
[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, CARequestInfo_t *outReqInfo,
71                                    CATransportFlags_t flags)
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, &code, &(outReqInfo->info), flags);
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                                     CATransportFlags_t flags)
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, &code, &(outResInfo->info), flags);
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, CAErrorInfo_t *errorInfo,
109                                  CATransportFlags_t flags)
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, &code, &errorInfo->info, flags);
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, NULL, info, endpoint)))
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, optlist, info, endpoint);
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                        CATransportFlags_t flags)
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 CI_ADAPTER
227     if (CA_IPV4_TCP == flags)
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);
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 CI_ADAPTER
256     if (CA_IPV4_TCP == flags)
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, coap_list_t *options, const CAInfo_t *info,
289                               const CAEndpoint_t *endpoint)
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
297 #ifdef CI_ADAPTER
298     if (CA_IPV4_TCP == endpoint->flags)
299     {
300
301         transport = coap_get_tcp_header_type_from_size(info->payloadSize);
302     }
303     else
304 #endif
305     {
306         transport = coap_udp;
307     }
308
309     coap_pdu_t *pdu = coap_new_pdu(transport);
310
311     if (NULL == pdu)
312     {
313         OIC_LOG(ERROR, TAG, "malloc failed");
314         return NULL;
315     }
316
317     OIC_LOG_V(DEBUG, TAG, "transport type: %d, payload size: %d",
318               transport, info->payloadSize);
319
320 #ifdef CI_ADAPTER
321     if (CA_IPV4_TCP == endpoint->flags)
322     {
323         coap_add_code(pdu, transport, code);
324         coap_add_length(pdu, transport, info->payloadSize);
325     }
326     else
327 #endif
328     {
329         OIC_LOG_V(DEBUG, TAG, "msgID is %d", info->messageId);
330         uint16_t message_id;
331         if (0 == info->messageId)
332         {
333             /* initialize message id */
334             prng((uint8_t * ) &message_id, sizeof(message_id));
335
336             OIC_LOG_V(DEBUG, TAG, "gen msg id=%d", message_id);
337         }
338         else
339         {
340             /* use saved message id */
341             message_id = info->messageId;
342         }
343         pdu->hdr->coap_hdr_udp_t.id = message_id;
344         OIC_LOG_V(DEBUG, TAG, "messageId in pdu is %d, %d", message_id, pdu->hdr->coap_hdr_udp_t.id);
345
346         pdu->hdr->coap_hdr_udp_t.type = info->type;
347         coap_add_code(pdu, transport, code);
348     }
349
350     if (info->token && CA_EMPTY != code)
351     {
352         uint32_t tokenLength = info->tokenLength;
353         OIC_LOG_V(DEBUG, TAG, "token info token length: %d, token :", tokenLength);
354         OIC_LOG_BUFFER(DEBUG, TAG, (const uint8_t *)info->token, tokenLength);
355
356         int32_t ret = coap_add_token(pdu, tokenLength, (unsigned char *)info->token, transport);
357         if (0 == ret)
358         {
359             OIC_LOG(ERROR, TAG, "can't add token");
360         }
361     }
362
363     if (options)
364     {
365         for (coap_list_t *opt = options; opt; opt = opt->next)
366         {
367             OIC_LOG_V(DEBUG, TAG, "[%s] opt will be added.",
368                       COAP_OPTION_DATA(*(coap_option *) opt->data));
369
370             OIC_LOG_V(DEBUG, TAG, "[%d] pdu length", pdu->length);
371             coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option *) opt->data),
372                             COAP_OPTION_LENGTH(*(coap_option *) opt->data),
373                             COAP_OPTION_DATA(*(coap_option *) opt->data), transport);
374         }
375     }
376
377     bool enabledPayload = false;
378 #ifndef WITH_BWT
379     enabledPayload = true;
380 #endif
381
382     if (enabledPayload || CA_ADAPTER_GATT_BTLE == endpoint->adapter
383 #ifdef CI_ADAPTER
384             || CA_IPV4_TCP == endpoint->flags
385 #endif
386             )
387     {
388         if (NULL != info->payload && 0 < info->payloadSize)
389         {
390             OIC_LOG(DEBUG, TAG, "payload is added");
391             coap_add_data(pdu, info->payloadSize, (const unsigned char *) info->payload);
392         }
393     }
394
395     OIC_LOG(DEBUG, TAG, "OUT");
396     return pdu;
397 }
398
399 CAResult_t CAParseURI(const char *uriInfo, coap_list_t **optlist)
400 {
401     OIC_LOG(DEBUG, TAG, "IN");
402
403     if (NULL == uriInfo)
404     {
405         OIC_LOG(ERROR, TAG, "uriInfo is null");
406         return CA_STATUS_INVALID_PARAM;
407     }
408
409     OIC_LOG_V(DEBUG, TAG, "url : %s", uriInfo);
410
411     if (NULL == optlist)
412     {
413         OIC_LOG(ERROR, TAG, "optlist is null");
414         return CA_STATUS_INVALID_PARAM;
415     }
416
417     /* split arg into Uri-* options */
418     coap_uri_t uri;
419     coap_split_uri((unsigned char *) uriInfo, strlen(uriInfo), &uri);
420
421     if (uri.port != COAP_DEFAULT_PORT)
422     {
423         unsigned char portbuf[CA_PORT_BUFFER_SIZE] = { 0 };
424         int ret = coap_insert(optlist,
425                               CACreateNewOptionNode(COAP_OPTION_URI_PORT,
426                                                     coap_encode_var_bytes(portbuf, uri.port),
427                                                     (char *)portbuf),
428                               CAOrderOpts);
429         if (ret <= 0)
430         {
431             return CA_STATUS_INVALID_PARAM;
432         }
433     }
434
435     if (uri.path.s && uri.path.length)
436     {
437         CAResult_t ret = CAParseUriPartial(uri.path.s, uri.path.length,
438                                            COAP_OPTION_URI_PATH, optlist);
439         if (CA_STATUS_OK != ret)
440         {
441             OIC_LOG(ERROR, TAG, "CAParseUriPartial failed(uri path)");
442             return ret;
443         }
444     }
445
446     if (uri.query.s && uri.query.length)
447     {
448         CAResult_t ret = CAParseUriPartial(uri.query.s, uri.query.length, COAP_OPTION_URI_QUERY,
449                                            optlist);
450         if (CA_STATUS_OK != ret)
451         {
452             OIC_LOG(ERROR, TAG, "CAParseUriPartial failed(uri query)");
453             return ret;
454         }
455     }
456
457     OIC_LOG(DEBUG, TAG, "OUT");
458     return CA_STATUS_OK;
459 }
460
461 CAResult_t CAParseUriPartial(const unsigned char *str, size_t length, int target,
462                              coap_list_t **optlist)
463 {
464     if (!optlist)
465     {
466         OIC_LOG(ERROR, TAG, "optlist is null");
467         return CA_STATUS_INVALID_PARAM;
468     }
469
470     if ((target != COAP_OPTION_URI_PATH) && (target != COAP_OPTION_URI_QUERY))
471     {
472         // should never occur. Log just in case.
473         OIC_LOG(DEBUG, TAG, "Unexpected URI component.");
474         return CA_NOT_SUPPORTED;
475     }
476     else if (str && length)
477     {
478         unsigned char uriBuffer[CA_BUFSIZE] = { 0 };
479         unsigned char *pBuf = uriBuffer;
480         size_t buflen = sizeof(uriBuffer);
481         int res = (target == COAP_OPTION_URI_PATH) ? coap_split_path(str, length, pBuf, &buflen) :
482                                                      coap_split_query(str, length, pBuf, &buflen);
483
484         if (res > 0)
485         {
486             size_t prevIdx = 0;
487             while (res--)
488             {
489                 int ret = coap_insert(optlist,
490                                       CACreateNewOptionNode(target, COAP_OPT_LENGTH(pBuf),
491                                                             (char *)COAP_OPT_VALUE(pBuf)),
492                                       CAOrderOpts);
493                 if (ret <= 0)
494                 {
495                     return CA_STATUS_INVALID_PARAM;
496                 }
497
498                 size_t optSize = COAP_OPT_SIZE(pBuf);
499                 if ((prevIdx + optSize) < buflen)
500                 {
501                     pBuf += optSize;
502                     prevIdx += optSize;
503                 }
504             }
505         }
506         else
507         {
508             OIC_LOG_V(ERROR, TAG, "Problem parsing URI : %d for %d", res, target);
509             return CA_STATUS_FAILED;
510         }
511     }
512     else
513     {
514         OIC_LOG(ERROR, TAG, "str or length is not available");
515         return CA_STATUS_FAILED;
516     }
517
518     return CA_STATUS_OK;
519 }
520
521 CAResult_t CAParseHeadOption(uint32_t code, const CAInfo_t *info, coap_list_t **optlist)
522 {
523     (void)code;
524     OIC_LOG(DEBUG, TAG, "IN");
525     VERIFY_NON_NULL_RET(info, TAG, "info is NULL", CA_STATUS_INVALID_PARAM);
526
527     OIC_LOG_V(DEBUG, TAG, "parse Head Opt: %d", info->numOptions);
528
529     if (!optlist)
530     {
531         OIC_LOG(ERROR, TAG, "optlist is null");
532         return CA_STATUS_INVALID_PARAM;
533     }
534
535     for (uint32_t i = 0; i < info->numOptions; i++)
536     {
537         if(!(info->options + i))
538         {
539             OIC_LOG(ERROR, TAG, "options is not available");
540             return CA_STATUS_FAILED;
541         }
542
543         uint32_t id = (info->options + i)->optionID;
544         if (COAP_OPTION_URI_PATH == id || COAP_OPTION_URI_QUERY == id)
545         {
546             OIC_LOG_V(DEBUG, TAG, "not Header Opt: %d", id);
547         }
548         else
549         {
550             if ((info->options + i)->optionData && (info->options + i)->optionLength > 0)
551             {
552                 OIC_LOG_V(DEBUG, TAG, "Head opt ID: %d", id);
553                 OIC_LOG_V(DEBUG, TAG, "Head opt data: %s", (info->options + i)->optionData);
554                 OIC_LOG_V(DEBUG, TAG, "Head opt length: %d", (info->options + i)->optionLength);
555                 int ret = coap_insert(optlist,
556                                       CACreateNewOptionNode(id, (info->options + i)->optionLength,
557                                                             (info->options + i)->optionData),
558                                       CAOrderOpts);
559                 if (ret <= 0)
560                 {
561                     return CA_STATUS_INVALID_PARAM;
562                 }
563             }
564         }
565     }
566
567     OIC_LOG(DEBUG, TAG, "OUT");
568     return CA_STATUS_OK;
569 }
570
571 coap_list_t *CACreateNewOptionNode(uint16_t key, uint32_t length, const char *data)
572 {
573     OIC_LOG(DEBUG, TAG, "IN");
574
575     if (!data)
576     {
577         OIC_LOG(ERROR, TAG, "invalid pointer parameter");
578         return NULL;
579     }
580
581     coap_option *option = coap_malloc(sizeof(coap_option) + length + 1);
582     if (!option)
583     {
584         OIC_LOG(ERROR, TAG, "Out of memory");
585         return NULL;
586     }
587     memset(option, 0, sizeof(coap_option) + length + 1);
588
589     COAP_OPTION_KEY(*option) = key;
590     COAP_OPTION_LENGTH(*option) = length;
591     memcpy(COAP_OPTION_DATA(*option), data, length);
592
593     /* we can pass NULL here as delete function since option is released automatically  */
594     coap_list_t *node = coap_new_listnode(option, NULL);
595
596     if (!node)
597     {
598         OIC_LOG(ERROR, TAG, "node is NULL");
599         coap_free(option);
600         return NULL;
601     }
602
603     OIC_LOG(DEBUG, TAG, "OUT");
604     return node;
605 }
606
607 int CAOrderOpts(void *a, void *b)
608 {
609     OIC_LOG(DEBUG, TAG, "IN");
610     if (!a || !b)
611     {
612         return a < b ? -1 : 1;
613     }
614
615     if (COAP_OPTION_KEY(*(coap_option *) a) < COAP_OPTION_KEY(*(coap_option * ) b))
616     {
617         return -1;
618     }
619
620     OIC_LOG(DEBUG, TAG, "OUT");
621     return COAP_OPTION_KEY(*(coap_option *) a) == COAP_OPTION_KEY(*(coap_option * ) b);
622 }
623
624 uint32_t CAGetOptionCount(coap_opt_iterator_t opt_iter)
625 {
626     OIC_LOG(DEBUG, TAG, "IN");
627     uint32_t count = 0;
628     coap_opt_t *option;
629
630     while ((option = coap_option_next(&opt_iter)))
631     {
632         if (COAP_OPTION_URI_PATH != opt_iter.type && COAP_OPTION_URI_QUERY != opt_iter.type
633             && COAP_OPTION_BLOCK1 != opt_iter.type && COAP_OPTION_BLOCK2 != opt_iter.type
634             && COAP_OPTION_SIZE1 != opt_iter.type && COAP_OPTION_SIZE2 != opt_iter.type)
635         {
636             count++;
637         }
638     }
639
640     OIC_LOG(DEBUG, TAG, "OUT");
641     return count;
642 }
643
644 CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, uint32_t *outCode, CAInfo_t *outInfo,
645                             CATransportFlags_t flags)
646 {
647     OIC_LOG(DEBUG, TAG, "IN");
648
649     if (!pdu || !outCode || !outInfo)
650     {
651         OIC_LOG(ERROR, TAG, "NULL pointer param");
652         return CA_STATUS_INVALID_PARAM;
653     }
654
655     coap_transport_type transport;
656 #ifdef CI_ADAPTER
657     if (CA_IPV4_TCP == flags)
658     {
659         transport = coap_get_tcp_header_type_from_initbyte(((unsigned char *)pdu->hdr)[0] >> 4);
660     }
661     else
662 #endif
663     {
664         transport = coap_udp;
665     }
666
667     coap_opt_iterator_t opt_iter;
668     coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL, transport);
669
670     if (outCode)
671     {
672         (*outCode) = (uint32_t) CA_RESPONSE_CODE(coap_get_code(pdu, transport));
673     }
674
675     // init HeaderOption list
676     uint32_t count = CAGetOptionCount(opt_iter);
677     memset(outInfo, 0, sizeof(*outInfo));
678
679     outInfo->numOptions = count;
680
681 #ifdef CI_ADAPTER
682     if (CA_IPV4_TCP == flags)
683     {
684         // set type
685         outInfo->type = CA_MSG_NONCONFIRM;
686     }
687     else
688 #endif
689     {
690         // set type
691         outInfo->type = pdu->hdr->coap_hdr_udp_t.type;
692
693         // set message id
694         outInfo->messageId = pdu->hdr->coap_hdr_udp_t.id;
695     }
696
697
698     if (count > 0)
699     {
700         outInfo->options = (CAHeaderOption_t *) OICCalloc(count, sizeof(CAHeaderOption_t));
701         if (NULL == outInfo->options)
702         {
703             OIC_LOG(ERROR, TAG, "Out of memory");
704             return CA_MEMORY_ALLOC_FAILED;
705         }
706     }
707
708     coap_opt_t *option;
709     char optionResult[CA_MAX_URI_LENGTH] = {0};
710     uint32_t idx = 0;
711     uint32_t optionLength = 0;
712     bool isfirstsetflag = false;
713     bool isQueryBeingProcessed = false;
714
715     while ((option = coap_option_next(&opt_iter)))
716     {
717         char buf[COAP_MAX_PDU_SIZE] = {0};
718         if (CAGetOptionData((uint8_t *)(COAP_OPT_VALUE(option)),
719                             COAP_OPT_LENGTH(option), (uint8_t *)buf, sizeof(buf)))
720         {
721             OIC_LOG_V(DEBUG, TAG, "COAP URI element : %s", buf);
722             uint32_t bufLength = strlen(buf);
723             if (COAP_OPTION_URI_PATH == opt_iter.type || COAP_OPTION_URI_QUERY == opt_iter.type)
724             {
725                 if (false == isfirstsetflag)
726                 {
727                     isfirstsetflag = true;
728                     optionResult[optionLength] = '/';
729                     optionLength++;
730                     // Make sure there is enough room in the optionResult buffer
731                     if ((optionLength + bufLength) < sizeof(optionResult))
732                     {
733                         memcpy(&optionResult[optionLength], buf, bufLength);
734                         optionLength += bufLength;
735                     }
736                     else
737                     {
738                         goto exit;
739                     }
740                 }
741                 else
742                 {
743                     if (COAP_OPTION_URI_PATH == opt_iter.type)
744                     {
745                         // Make sure there is enough room in the optionResult buffer
746                         if (optionLength < sizeof(optionResult))
747                         {
748                             optionResult[optionLength] = '/';
749                             optionLength++;
750                         }
751                         else
752                         {
753                             goto exit;
754                         }
755                     }
756                     else if (COAP_OPTION_URI_QUERY == opt_iter.type)
757                     {
758                         if (false == isQueryBeingProcessed)
759                         {
760                             // Make sure there is enough room in the optionResult buffer
761                             if (optionLength < sizeof(optionResult))
762                             {
763                                 optionResult[optionLength] = '?';
764                                 optionLength++;
765                                 isQueryBeingProcessed = true;
766                             }
767                             else
768                             {
769                                 goto exit;
770                             }
771                         }
772                         else
773                         {
774                             // Make sure there is enough room in the optionResult buffer
775                             if (optionLength < sizeof(optionResult))
776                             {
777                                 optionResult[optionLength] = ';';
778                                 optionLength++;
779                             }
780                             else
781                             {
782                                 goto exit;
783                             }
784                         }
785                     }
786                     // Make sure there is enough room in the optionResult buffer
787                     if ((optionLength + bufLength) < sizeof(optionResult))
788                     {
789                         memcpy(&optionResult[optionLength], buf, bufLength);
790                         optionLength += bufLength;
791                     }
792                     else
793                     {
794                         goto exit;
795                     }
796                 }
797             }
798             else if (COAP_OPTION_BLOCK1 == opt_iter.type || COAP_OPTION_BLOCK2 == opt_iter.type
799                     || COAP_OPTION_SIZE1 == opt_iter.type || COAP_OPTION_SIZE2 == opt_iter.type)
800             {
801                 OIC_LOG_V(DEBUG, TAG, "option[%d] will be filtering", opt_iter.type);
802             }
803             else
804             {
805                 if (idx < count)
806                 {
807                     uint32_t length = bufLength;
808
809                     if (length <= CA_MAX_HEADER_OPTION_DATA_LENGTH)
810                     {
811                         outInfo->options[idx].optionID = opt_iter.type;
812                         outInfo->options[idx].optionLength = length;
813                         outInfo->options[idx].protocolID = CA_COAP_ID;
814                         memcpy(outInfo->options[idx].optionData, buf, length);
815                         idx++;
816                     }
817                 }
818             }
819         }
820     }
821
822     unsigned char* token;
823     unsigned int token_length;
824     coap_get_token(pdu->hdr, transport, &token, &token_length);
825
826     // set token data
827     if (token_length > 0)
828     {
829         OIC_LOG_V(DEBUG, TAG, "inside token length : %d", token_length);
830         outInfo->token = (char *) OICMalloc(token_length);
831         if (NULL == outInfo->token)
832         {
833             OIC_LOG(ERROR, TAG, "Out of memory");
834             OICFree(outInfo->options);
835             return CA_MEMORY_ALLOC_FAILED;
836         }
837         memcpy(outInfo->token, token, token_length);
838     }
839
840     outInfo->tokenLength = token_length;
841
842     // set payload data
843     size_t dataSize;
844     uint8_t *data;
845     if (coap_get_data(pdu, &dataSize, &data))
846     {
847         OIC_LOG(DEBUG, TAG, "inside pdu->data");
848         outInfo->payload = (uint8_t *) OICMalloc(dataSize);
849         if (NULL == outInfo->payload)
850         {
851             OIC_LOG(ERROR, TAG, "Out of memory");
852             OICFree(outInfo->options);
853             OICFree(outInfo->token);
854             return CA_MEMORY_ALLOC_FAILED;
855         }
856         memcpy(outInfo->payload, pdu->data, dataSize);
857         outInfo->payloadSize = dataSize;
858     }
859
860     if (optionResult[0] != '\0')
861     {
862         OIC_LOG_V(DEBUG, TAG, "URL length:%d", strlen(optionResult));
863         outInfo->resourceUri = OICStrdup(optionResult);
864         if (!outInfo->resourceUri)
865         {
866             OIC_LOG(ERROR, TAG, "Out of memory");
867             OICFree(outInfo->options);
868             OICFree(outInfo->token);
869             return CA_MEMORY_ALLOC_FAILED;
870         }
871     }
872
873     OIC_LOG(DEBUG, TAG, "OUT");
874     return CA_STATUS_OK;
875
876 exit:
877     OIC_LOG(ERROR, TAG, "buffer too small");
878     OICFree(outInfo->options);
879     return CA_STATUS_FAILED;
880 }
881
882 CAResult_t CAGetTokenFromPDU(const coap_hdr_t *pdu_hdr, CAInfo_t *outInfo,
883                              CATransportFlags_t flags)
884 {
885     OIC_LOG(DEBUG, TAG, "IN");
886     if (NULL == pdu_hdr)
887     {
888         OIC_LOG(ERROR, TAG, "pdu_hdr is null");
889         return CA_STATUS_INVALID_PARAM;
890     }
891
892     if (NULL == outInfo)
893     {
894         OIC_LOG(ERROR, TAG, "outInfo is null");
895         return CA_STATUS_INVALID_PARAM;
896     }
897
898     coap_transport_type transport;
899 #ifdef CI_ADAPTER
900     if (CA_IPV4_TCP == flags)
901     {
902         transport = coap_get_tcp_header_type_from_initbyte(((unsigned char *)pdu_hdr)[0] >> 4);
903     }
904     else
905 #endif
906     {
907         transport = coap_udp;
908     }
909
910     unsigned char* token;
911     unsigned int token_length;
912     coap_get_token(pdu_hdr, transport, &token, &token_length);
913
914     // set token data
915     if (token_length > 0)
916     {
917         OIC_LOG_V(DEBUG, TAG, "token len:%d", token_length);
918         outInfo->token = (char *) OICMalloc(token_length);
919         if (NULL == outInfo->token)
920         {
921             OIC_LOG(ERROR, TAG, "Out of memory");
922             return CA_MEMORY_ALLOC_FAILED;
923         }
924         memcpy(outInfo->token, token, token_length);
925     }
926
927     outInfo->tokenLength = token_length;
928
929     OIC_LOG(DEBUG, TAG, "OUT");
930
931     return CA_STATUS_OK;
932 }
933
934 CAResult_t CAGenerateTokenInternal(CAToken_t *token, uint8_t tokenLength)
935 {
936     OIC_LOG(DEBUG, TAG, "IN");
937
938     if (!token)
939     {
940         OIC_LOG(ERROR, TAG, "invalid token pointer");
941         return CA_STATUS_INVALID_PARAM;
942     }
943
944     if ((tokenLength > CA_MAX_TOKEN_LEN) || (0 == tokenLength))
945     {
946         OIC_LOG(ERROR, TAG, "invalid token length");
947         return CA_STATUS_INVALID_PARAM;
948     }
949
950     if (SEED == 0)
951     {
952 #ifdef ARDUINO
953         SEED = now();
954 #else
955         SEED = time(NULL);
956 #endif
957         if (SEED == (unsigned int)((time_t)-1))
958         {
959             OIC_LOG(ERROR, TAG, "seed is not made");
960             SEED = 0;
961             return CA_STATUS_FAILED;
962         }
963 #if HAVE_SRANDOM
964         srandom(SEED);
965 #else
966         srand(SEED);
967 #endif
968     }
969
970     // memory allocation
971     char *temp = (char *) OICCalloc(tokenLength, sizeof(char));
972     if (NULL == temp)
973     {
974         OIC_LOG(ERROR, TAG, "Out of memory");
975         return CA_MEMORY_ALLOC_FAILED;
976     }
977
978     // set random byte
979     for (uint8_t index = 0; index < tokenLength; index++)
980     {
981         // use valid characters
982 #ifdef ARDUINO
983         temp[index] = rand() & 0x00FF;
984 #else
985         temp[index] = random() & 0x00FF;
986 #endif
987     }
988
989     // save token
990     *token = temp;
991
992     OIC_LOG_V(DEBUG, TAG, "token len:%d, token:", tokenLength);
993     OIC_LOG_BUFFER(DEBUG, TAG, (const uint8_t *)(*token), tokenLength);
994
995     OIC_LOG(DEBUG, TAG, "OUT");
996     return CA_STATUS_OK;
997 }
998
999 void CADestroyTokenInternal(CAToken_t token)
1000 {
1001     OIC_LOG(DEBUG, TAG, "IN");
1002     OICFree(token);
1003     OIC_LOG(DEBUG, TAG, "OUT");
1004 }
1005
1006 void CADestroyInfo(CAInfo_t *info)
1007 {
1008     OIC_LOG(DEBUG, TAG, "IN");
1009
1010     if (NULL != info)
1011     {
1012         OIC_LOG(DEBUG, TAG, "free options");
1013         OICFree(info->options);
1014
1015         OIC_LOG(DEBUG, TAG, "free token");
1016         OICFree(info->token);
1017
1018         OIC_LOG(DEBUG, TAG, "free payload");
1019         OICFree(info->payload);
1020     }
1021
1022     OIC_LOG(DEBUG, TAG, "OUT");
1023 }
1024
1025 uint32_t CAGetOptionData(const uint8_t *data, uint32_t len, uint8_t *option, uint32_t buflen)
1026 {
1027     if (0 == buflen || 0 == len)
1028     {
1029         OIC_LOG(ERROR, TAG, "len 0");
1030         return 0;
1031     }
1032
1033     if (NULL == data || NULL == option)
1034     {
1035         OIC_LOG(ERROR, TAG, "data/option NULL");
1036         return 0;
1037     }
1038
1039     if (buflen <= len)
1040     {
1041         OIC_LOG(ERROR, TAG, "option buffer too small");
1042         return 0;
1043     }
1044
1045     memcpy(option, data, len);
1046     option[len] = '\0';
1047
1048     return len;
1049 }
1050
1051 CAMessageType_t CAGetMessageTypeFromPduBinaryData(const void *pdu, uint32_t size)
1052 {
1053     if (NULL == pdu)
1054     {
1055         OIC_LOG(ERROR, TAG, "pdu is null");
1056         return CA_MSG_NONCONFIRM;
1057     }
1058
1059     // pdu minimum size is 4 byte.
1060     if (size < CA_PDU_MIN_SIZE)
1061     {
1062         OIC_LOG(ERROR, TAG, "min size");
1063         return CA_MSG_NONCONFIRM;
1064     }
1065
1066     coap_hdr_t *hdr = (coap_hdr_t *) pdu;
1067
1068     return (CAMessageType_t) hdr->coap_hdr_udp_t.type;
1069 }
1070
1071 uint16_t CAGetMessageIdFromPduBinaryData(const void *pdu, uint32_t size)
1072 {
1073     if (NULL == pdu)
1074     {
1075         OIC_LOG(ERROR, TAG, "pdu is null");
1076         return 0;
1077     }
1078
1079     // pdu minimum size is 4 byte.
1080     if (size < CA_PDU_MIN_SIZE)
1081     {
1082         OIC_LOG(ERROR, TAG, "min size");
1083         return 0;
1084     }
1085
1086     coap_hdr_t *hdr = (coap_hdr_t *) pdu;
1087
1088     return hdr->coap_hdr_udp_t.id;
1089 }
1090
1091 CAResponseResult_t CAGetCodeFromPduBinaryData(const void *pdu, uint32_t size)
1092 {
1093     if (NULL == pdu)
1094     {
1095         OIC_LOG(ERROR, TAG, "pdu is null");
1096         return CA_NOT_FOUND;
1097     }
1098
1099     // pdu minimum size is 4 byte.
1100     if (size < CA_PDU_MIN_SIZE)
1101     {
1102         OIC_LOG(ERROR, TAG, "min size");
1103         return CA_NOT_FOUND;
1104     }
1105
1106     coap_hdr_t *hdr = (coap_hdr_t *) pdu;
1107
1108     return (CAResponseResult_t) CA_RESPONSE_CODE(hdr->coap_hdr_udp_t.code);
1109 }