16024c7f3dfa1fdf99e1dc633d8a9fc3557d8423
[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 #define _BSD_SOURCE
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stdbool.h>
37 #ifdef HAVE_TIME_H
38 #include <time.h>
39 #endif
40
41 #include "caprotocolmessage.h"
42 #include "logger.h"
43 #include "oic_malloc.h"
44 #include "oic_string.h"
45
46 // ARM GCC compiler doesnt define srandom function.
47 #if defined(ARDUINO) && !defined(ARDUINO_ARCH_SAM)
48 #define HAVE_SRANDOM 1
49 #endif
50
51 #define TAG "CA_PRTCL_MSG"
52
53 /**
54  * @def VERIFY_NON_NULL_RET
55  * @brief Macro to verify the validity of input argument
56  */
57 #define VERIFY_NON_NULL_RET(arg, log_tag, log_message,ret) \
58     if (NULL == arg ){ \
59         OIC_LOG_V(ERROR, log_tag, "Invalid input:%s", log_message); \
60         return ret; \
61     }
62
63 #define CA_BUFSIZE (128)
64 #define CA_PDU_MIN_SIZE (4)
65 #define CA_PORT_BUFFER_SIZE (4)
66
67 static const char COAP_URI_HEADER[] = "coap://[::]/";
68
69 static uint32_t SEED = 0;
70
71 CAResult_t CAGetRequestInfoFromPDU(const coap_pdu_t *pdu, 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, &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 {
91     OIC_LOG(DEBUG, TAG, "IN");
92
93     if (NULL == pdu || NULL == outResInfo)
94     {
95         OIC_LOG(ERROR, TAG, "parameter is null");
96         return CA_STATUS_INVALID_PARAM;
97     }
98
99     uint32_t code = CA_NOT_FOUND;
100     CAResult_t ret = CAGetInfoFromPDU(pdu, &code, &(outResInfo->info));
101     outResInfo->result = code;
102
103     OIC_LOG(DEBUG, TAG, "OUT");
104     return ret;
105 }
106
107 CAResult_t CAGetErrorInfoFromPDU(const coap_pdu_t *pdu, CAErrorInfo_t *errorInfo)
108 {
109     OIC_LOG(DEBUG, TAG, "IN");
110
111     if (!pdu)
112     {
113         OIC_LOG(ERROR, TAG, "parameter is null");
114         return CA_STATUS_INVALID_PARAM;
115     }
116
117     uint32_t code = 0;
118     CAResult_t ret = CAGetInfoFromPDU(pdu, &code, &errorInfo->info);
119     OIC_LOG(DEBUG, TAG, "OUT");
120     return ret;
121 }
122
123 coap_pdu_t *CAGeneratePDU(uint32_t code, const CAInfo_t *info)
124 {
125     OIC_LOG(DEBUG, TAG, "IN");
126
127     coap_pdu_t *pdu = NULL;
128
129     // RESET have to use only 4byte (empty message)
130     // and ACKNOWLEDGE can use empty message when code is empty.
131     if (CA_MSG_RESET == info->type || (CA_EMPTY == code && CA_MSG_ACKNOWLEDGE == info->type))
132     {
133         OIC_LOG(DEBUG, TAG, "code is empty");
134         if (!(pdu = CAGeneratePDUImpl((code_t) code, NULL, info, NULL, 0)))
135         {
136             OIC_LOG(ERROR, TAG, "pdu NULL");
137             return NULL;
138         }
139     }
140     else
141     {
142         coap_list_t *optlist = NULL;
143
144         if (CA_MSG_ACKNOWLEDGE != info->type)
145         {
146             const char *uri = info->resourceUri;
147             if (NULL == uri)
148             {
149                 OIC_LOG(ERROR, TAG, "uri NULL");
150                 return NULL;
151             }
152
153             uint32_t length = strlen(uri);
154             if (CA_MAX_URI_LENGTH < length)
155             {
156                 OIC_LOG(ERROR, TAG, "URI len err");
157                 return NULL;
158             }
159
160             uint32_t uriLength = length + sizeof(COAP_URI_HEADER);
161             char *coapUri = (char *) OICCalloc(1, uriLength);
162             if (NULL == coapUri)
163             {
164                 OIC_LOG(ERROR, TAG, "out of memory");
165                 return NULL;
166             }
167             OICStrcat(coapUri, uriLength, COAP_URI_HEADER);
168             OICStrcat(coapUri, uriLength, uri);
169
170             // parsing options in URI
171             CAResult_t res = CAParseURI(coapUri, &optlist);
172             if (CA_STATUS_OK != res)
173             {
174                 if (optlist)
175                 {
176                     coap_delete_list(optlist);
177                 }
178                 OICFree(coapUri);
179                 return NULL;
180             }
181
182             OICFree(coapUri);
183         }
184         // parsing options in HeadOption
185         CAResult_t ret = CAParseHeadOption(code, info, &optlist);
186         if (CA_STATUS_OK != ret)
187         {
188             coap_delete_list(optlist);
189             return NULL;
190         }
191         pdu = CAGeneratePDUImpl((code_t)code, optlist, info, info->payload, info->payloadSize);
192         if (NULL == pdu)
193         {
194             OIC_LOG(ERROR, TAG, "pdu NULL");
195             coap_delete_list(optlist);
196             return NULL;
197         }
198
199         // free option list
200         coap_delete_list(optlist);
201     }
202
203     // pdu print method : coap_show_pdu(pdu);
204     OIC_LOG(DEBUG, TAG, "OUT");
205     return pdu;
206 }
207
208 coap_pdu_t *CAParsePDU(const char *data, uint32_t length, uint32_t *outCode)
209 {
210     OIC_LOG(DEBUG, TAG, "IN");
211
212     if (NULL == data)
213     {
214         OIC_LOG(ERROR, TAG, "data is null");
215         return NULL;
216     }
217
218     coap_pdu_t *outpdu = coap_new_pdu();
219     if (NULL == outpdu)
220     {
221         OIC_LOG(ERROR, TAG, "outpdu is null");
222         return NULL;
223     }
224
225     if (0 >= coap_pdu_parse((unsigned char *) data, length, outpdu))
226     {
227         OIC_LOG(ERROR, TAG, "pdu parse failed");
228         coap_delete_pdu(outpdu);
229         return NULL;
230     }
231
232     if (outCode)
233     {
234         (*outCode) = (uint32_t) CA_RESPONSE_CODE(outpdu->hdr->code);
235     }
236
237     OIC_LOG(DEBUG, TAG, "OUT");
238     return outpdu;
239 }
240
241 coap_pdu_t *CAGeneratePDUImpl(code_t code, coap_list_t *options, const CAInfo_t *info,
242                               const uint8_t *payload, size_t payloadSize)
243 {
244     OIC_LOG(DEBUG, TAG, "IN");
245     VERIFY_NON_NULL_RET(info, TAG, "info is NULL", NULL);
246
247     coap_pdu_t *pdu = coap_new_pdu();
248
249     if (NULL == pdu)
250     {
251         OIC_LOG(ERROR, TAG, "malloc failed");
252         return NULL;
253     }
254
255     OIC_LOG_V(DEBUG, TAG, "msgID is %d", info->messageId);
256     uint16_t message_id;
257     if (0 == info->messageId)
258     {
259         /* initialize message id */
260         prng((uint8_t * ) &message_id, sizeof(message_id));
261
262         OIC_LOG_V(DEBUG, TAG, "gen msg id=%d", message_id);
263     }
264     else
265     {
266         /* use saved message id */
267         message_id = info->messageId;
268     }
269     pdu->hdr->id = message_id;
270     OIC_LOG_V(DEBUG, TAG, "messageId in pdu is %d, %d", message_id, pdu->hdr->id);
271
272     pdu->hdr->type = info->type;
273     pdu->hdr->code = COAP_RESPONSE_CODE(code);
274
275     if (info->token && CA_EMPTY != code)
276     {
277         uint32_t tokenLength = info->tokenLength;
278         OIC_LOG_V(DEBUG, TAG, "token info token length: %d, token :", tokenLength);
279         OIC_LOG_BUFFER(DEBUG, TAG, (const uint8_t *)info->token, tokenLength);
280
281         int32_t ret = coap_add_token(pdu, tokenLength, (unsigned char *)info->token);
282         if (0 == ret)
283         {
284             OIC_LOG(ERROR, TAG, "can't add token");
285         }
286     }
287
288     if (options)
289     {
290         for (coap_list_t *opt = options; opt; opt = opt->next)
291         {
292             OIC_LOG_V(DEBUG, TAG, "[%s] opt will be added.",
293                       COAP_OPTION_DATA(*(coap_option *) opt->data));
294             coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option *) opt->data),
295                             COAP_OPTION_LENGTH(*(coap_option *) opt->data),
296                             COAP_OPTION_DATA(*(coap_option *) opt->data));
297         }
298     }
299
300     if (NULL != payload)
301     {
302         coap_add_data(pdu, payloadSize, (const unsigned char *) payload);
303     }
304
305     OIC_LOG(DEBUG, TAG, "OUT");
306     return pdu;
307 }
308
309 CAResult_t CAParseURI(const char *uriInfo, coap_list_t **optlist)
310 {
311     OIC_LOG(DEBUG, TAG, "IN");
312
313     if (NULL == uriInfo)
314     {
315         OIC_LOG(ERROR, TAG, "uriInfo is null");
316         return CA_STATUS_INVALID_PARAM;
317     }
318
319     OIC_LOG_V(DEBUG, TAG, "url : %s", uriInfo);
320
321     if (NULL == optlist)
322     {
323         OIC_LOG(ERROR, TAG, "optlist is null");
324         return CA_STATUS_INVALID_PARAM;
325     }
326
327     /* split arg into Uri-* options */
328     coap_uri_t uri;
329     coap_split_uri((unsigned char *) uriInfo, strlen(uriInfo), &uri);
330
331     if (uri.port != COAP_DEFAULT_PORT)
332     {
333         unsigned char portbuf[CA_PORT_BUFFER_SIZE] = { 0 };
334         int ret = coap_insert(optlist,
335                               CACreateNewOptionNode(COAP_OPTION_URI_PORT,
336                                                     coap_encode_var_bytes(portbuf, uri.port),
337                                                     (char *)portbuf),
338                               CAOrderOpts);
339         if (ret <= 0)
340         {
341             return CA_STATUS_INVALID_PARAM;
342         }
343     }
344
345     if (uri.path.s && uri.path.length)
346     {
347         CAResult_t ret = CAParseUriPartial(uri.path.s, uri.path.length,
348                                            COAP_OPTION_URI_PATH, optlist);
349         if (CA_STATUS_OK != ret)
350         {
351             OIC_LOG(ERROR, TAG, "CAParseUriPartial failed(uri path)");
352             return ret;
353         }
354     }
355
356     if (uri.query.s && uri.query.length)
357     {
358         CAResult_t ret = CAParseUriPartial(uri.query.s, uri.query.length, COAP_OPTION_URI_QUERY,
359                                            optlist);
360         if (CA_STATUS_OK != ret)
361         {
362             OIC_LOG(ERROR, TAG, "CAParseUriPartial failed(uri query)");
363             return ret;
364         }
365     }
366
367     OIC_LOG(DEBUG, TAG, "OUT");
368     return CA_STATUS_OK;
369 }
370
371 CAResult_t CAParseUriPartial(const unsigned char *str, size_t length, int target,
372                              coap_list_t **optlist)
373 {
374     if (!optlist)
375     {
376         OIC_LOG(ERROR, TAG, "optlist is null");
377         return CA_STATUS_INVALID_PARAM;
378     }
379
380     if ((target != COAP_OPTION_URI_PATH) && (target != COAP_OPTION_URI_QUERY))
381     {
382         // should never occur. Log just in case.
383         OIC_LOG(DEBUG, TAG, "Unexpected URI component.");
384         return CA_NOT_SUPPORTED;
385     }
386     else if (str && length)
387     {
388         unsigned char uriBuffer[CA_BUFSIZE] = { 0 };
389         unsigned char *pBuf = uriBuffer;
390         size_t buflen = sizeof(uriBuffer);
391         int res = (target == COAP_OPTION_URI_PATH) ? coap_split_path(str, length, pBuf, &buflen) :
392                                                      coap_split_query(str, length, pBuf, &buflen);
393
394         if (res > 0)
395         {
396             size_t prevIdx = 0;
397             while (res--)
398             {
399                 int ret = coap_insert(optlist,
400                                       CACreateNewOptionNode(target, COAP_OPT_LENGTH(pBuf),
401                                                             (char *)COAP_OPT_VALUE(pBuf)),
402                                       CAOrderOpts);
403                 if (ret <= 0)
404                 {
405                     return CA_STATUS_INVALID_PARAM;
406                 }
407
408                 size_t optSize = COAP_OPT_SIZE(pBuf);
409                 if ((prevIdx + optSize) < buflen)
410                 {
411                     pBuf += optSize;
412                     prevIdx += optSize;
413                 }
414             }
415         }
416         else
417         {
418             OIC_LOG_V(ERROR, TAG, "Problem parsing URI : %d for %d", res, target);
419             return CA_STATUS_FAILED;
420         }
421     }
422     else
423     {
424         OIC_LOG(ERROR, TAG, "str or length is not available");
425         return CA_STATUS_FAILED;
426     }
427
428     return CA_STATUS_OK;
429 }
430
431 CAResult_t CAParseHeadOption(uint32_t code, const CAInfo_t *info, coap_list_t **optlist)
432 {
433     OIC_LOG(DEBUG, TAG, "IN");
434     VERIFY_NON_NULL_RET(info, TAG, "info is NULL", CA_STATUS_INVALID_PARAM);
435
436     OIC_LOG_V(DEBUG, TAG, "parse Head Opt: %d", info->numOptions);
437
438     if (!optlist)
439     {
440         OIC_LOG(ERROR, TAG, "optlist is null");
441         return CA_STATUS_INVALID_PARAM;
442     }
443
444     for (uint32_t i = 0; i < info->numOptions; i++)
445     {
446         if(!(info->options + i))
447         {
448             OIC_LOG(ERROR, TAG, "options is not available");
449             return CA_STATUS_FAILED;
450         }
451
452         uint32_t id = (info->options + i)->optionID;
453         if (COAP_OPTION_URI_PATH == id || COAP_OPTION_URI_QUERY == id)
454         {
455             OIC_LOG_V(DEBUG, TAG, "not Header Opt: %d", id);
456         }
457         else
458         {
459             if ((info->options + i)->optionData && (info->options + i)->optionLength > 0)
460             {
461                 OIC_LOG_V(DEBUG, TAG, "Head opt ID: %d", id);
462                 OIC_LOG_V(DEBUG, TAG, "Head opt data: %s", (info->options + i)->optionData);
463                 OIC_LOG_V(DEBUG, TAG, "Head opt length: %d", (info->options + i)->optionLength);
464                 int ret = coap_insert(optlist,
465                                       CACreateNewOptionNode(id, (info->options + i)->optionLength,
466                                                             (info->options + i)->optionData),
467                                       CAOrderOpts);
468                 if (ret <= 0)
469                 {
470                     return CA_STATUS_INVALID_PARAM;
471                 }
472             }
473         }
474     }
475
476     OIC_LOG(DEBUG, TAG, "OUT");
477     return CA_STATUS_OK;
478 }
479
480 coap_list_t *CACreateNewOptionNode(uint16_t key, uint32_t length, const char *data)
481 {
482     OIC_LOG(DEBUG, TAG, "IN");
483
484     if (!data)
485     {
486         OIC_LOG(ERROR, TAG, "invalid pointer parameter");
487         return NULL;
488     }
489
490     coap_option *option = coap_malloc(sizeof(coap_option) + length + 1);
491     if (!option)
492     {
493         OIC_LOG(ERROR, TAG, "Out of memory");
494         return NULL;
495     }
496     memset(option, 0, sizeof(coap_option) + length + 1);
497
498     COAP_OPTION_KEY(*option) = key;
499     COAP_OPTION_LENGTH(*option) = length;
500     memcpy(COAP_OPTION_DATA(*option), data, length);
501
502     /* we can pass NULL here as delete function since option is released automatically  */
503     coap_list_t *node = coap_new_listnode(option, NULL);
504
505     if (!node)
506     {
507         OIC_LOG(ERROR, TAG, "node is NULL");
508         coap_free(option);
509         return NULL;
510     }
511
512     OIC_LOG(DEBUG, TAG, "OUT");
513     return node;
514 }
515
516 int CAOrderOpts(void *a, void *b)
517 {
518     OIC_LOG(DEBUG, TAG, "IN");
519     if (!a || !b)
520     {
521         return a < b ? -1 : 1;
522     }
523
524     if (COAP_OPTION_KEY(*(coap_option *) a) < COAP_OPTION_KEY(*(coap_option * ) b))
525     {
526         return -1;
527     }
528
529     OIC_LOG(DEBUG, TAG, "OUT");
530     return COAP_OPTION_KEY(*(coap_option *) a) == COAP_OPTION_KEY(*(coap_option * ) b);
531 }
532
533 uint32_t CAGetOptionCount(coap_opt_iterator_t opt_iter)
534 {
535     OIC_LOG(DEBUG, TAG, "IN");
536     uint32_t count = 0;
537     coap_opt_t *option;
538
539     while ((option = coap_option_next(&opt_iter)))
540     {
541         if (COAP_OPTION_URI_PATH != opt_iter.type && COAP_OPTION_URI_QUERY != opt_iter.type
542             && COAP_OPTION_BLOCK1 != opt_iter.type && COAP_OPTION_BLOCK2 != opt_iter.type
543             && COAP_OPTION_SIZE1 != opt_iter.type && COAP_OPTION_SIZE2 != opt_iter.type)
544         {
545             count++;
546         }
547     }
548
549     OIC_LOG(DEBUG, TAG, "OUT");
550     return count;
551 }
552
553 CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, uint32_t *outCode, CAInfo_t *outInfo)
554 {
555     OIC_LOG(DEBUG, TAG, "IN");
556
557     if (!pdu || !outCode || !outInfo)
558     {
559         OIC_LOG(ERROR, TAG, "NULL pointer param");
560         return CA_STATUS_INVALID_PARAM;
561     }
562
563     coap_opt_iterator_t opt_iter;
564     coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL);
565
566     if (outCode)
567     {
568         (*outCode) = (uint32_t) CA_RESPONSE_CODE(pdu->hdr->code);
569     }
570
571     // init HeaderOption list
572     uint32_t count = CAGetOptionCount(opt_iter);
573     memset(outInfo, 0, sizeof(*outInfo));
574
575     outInfo->numOptions = count;
576
577     // set type
578     outInfo->type = pdu->hdr->type;
579
580     // set message id
581     outInfo->messageId = pdu->hdr->id;
582
583     if (count > 0)
584     {
585         outInfo->options = (CAHeaderOption_t *) OICCalloc(count, sizeof(CAHeaderOption_t));
586         if (NULL == outInfo->options)
587         {
588             OIC_LOG(ERROR, TAG, "Out of memory");
589             return CA_MEMORY_ALLOC_FAILED;
590         }
591     }
592
593     coap_opt_t *option;
594     char optionResult[CA_MAX_URI_LENGTH] = {0};
595     uint32_t idx = 0;
596     uint32_t optionLength = 0;
597     bool isfirstsetflag = false;
598     bool isQueryBeingProcessed = false;
599
600     while ((option = coap_option_next(&opt_iter)))
601     {
602         char buf[COAP_MAX_PDU_SIZE] = {0};
603         if (CAGetOptionData((uint8_t *)(COAP_OPT_VALUE(option)),
604                             COAP_OPT_LENGTH(option), (uint8_t *)buf, sizeof(buf)))
605         {
606             OIC_LOG_V(DEBUG, TAG, "COAP URI element : %s", buf);
607             uint32_t bufLength = strlen(buf);
608             if (COAP_OPTION_URI_PATH == opt_iter.type || COAP_OPTION_URI_QUERY == opt_iter.type)
609             {
610                 if (false == isfirstsetflag)
611                 {
612                     isfirstsetflag = true;
613                     optionResult[optionLength] = '/';
614                     optionLength++;
615                     // Make sure there is enough room in the optionResult buffer
616                     if ((optionLength + bufLength) < sizeof(optionResult))
617                     {
618                         memcpy(&optionResult[optionLength], buf, bufLength);
619                         optionLength += bufLength;
620                     }
621                     else
622                     {
623                         goto exit;
624                     }
625                 }
626                 else
627                 {
628                     if (COAP_OPTION_URI_PATH == opt_iter.type)
629                     {
630                         // Make sure there is enough room in the optionResult buffer
631                         if (optionLength < sizeof(optionResult))
632                         {
633                             optionResult[optionLength] = '/';
634                             optionLength++;
635                         }
636                         else
637                         {
638                             goto exit;
639                         }
640                     }
641                     else if (COAP_OPTION_URI_QUERY == opt_iter.type)
642                     {
643                         if (false == isQueryBeingProcessed)
644                         {
645                             // Make sure there is enough room in the optionResult buffer
646                             if (optionLength < sizeof(optionResult))
647                             {
648                                 optionResult[optionLength] = '?';
649                                 optionLength++;
650                                 isQueryBeingProcessed = true;
651                             }
652                             else
653                             {
654                                 goto exit;
655                             }
656                         }
657                         else
658                         {
659                             // Make sure there is enough room in the optionResult buffer
660                             if (optionLength < sizeof(optionResult))
661                             {
662                                 optionResult[optionLength] = ';';
663                                 optionLength++;
664                             }
665                             else
666                             {
667                                 goto exit;
668                             }
669                         }
670                     }
671                     // Make sure there is enough room in the optionResult buffer
672                     if ((optionLength + bufLength) < sizeof(optionResult))
673                     {
674                         memcpy(&optionResult[optionLength], buf, bufLength);
675                         optionLength += bufLength;
676                     }
677                     else
678                     {
679                         goto exit;
680                     }
681                 }
682             }
683             else if (COAP_OPTION_BLOCK1 == opt_iter.type || COAP_OPTION_BLOCK2 == opt_iter.type
684                     || COAP_OPTION_SIZE1 == opt_iter.type || COAP_OPTION_SIZE2 == opt_iter.type)
685             {
686                 OIC_LOG_V(DEBUG, TAG, "option[%d] will be filtering", opt_iter.type);
687             }
688             else
689             {
690                 if (idx < count)
691                 {
692                     uint32_t length = bufLength;
693
694                     if (length <= CA_MAX_HEADER_OPTION_DATA_LENGTH)
695                     {
696                         outInfo->options[idx].optionID = opt_iter.type;
697                         outInfo->options[idx].optionLength = length;
698                         outInfo->options[idx].protocolID = CA_COAP_ID;
699                         memcpy(outInfo->options[idx].optionData, buf, length);
700                         idx++;
701                     }
702                 }
703             }
704         }
705     }
706
707     // set token data
708     if (pdu->hdr->token_length > 0)
709     {
710         OIC_LOG_V(DEBUG, TAG, "inside token length : %d", pdu->hdr->token_length);
711         outInfo->token = (char *) OICMalloc(pdu->hdr->token_length);
712         if (NULL == outInfo->token)
713         {
714             OIC_LOG(ERROR, TAG, "Out of memory");
715             OICFree(outInfo->options);
716             return CA_MEMORY_ALLOC_FAILED;
717         }
718         memcpy(outInfo->token, pdu->hdr->token, pdu->hdr->token_length);
719     }
720
721     outInfo->tokenLength = pdu->hdr->token_length;
722
723     // set payload data
724     size_t dataSize;
725     uint8_t *data;
726     if (coap_get_data(pdu, &dataSize, &data))
727     {
728         OIC_LOG(DEBUG, TAG, "inside pdu->data");
729         outInfo->payload = (uint8_t *) OICMalloc(dataSize);
730         if (NULL == outInfo->payload)
731         {
732             OIC_LOG(ERROR, TAG, "Out of memory");
733             OICFree(outInfo->options);
734             OICFree(outInfo->token);
735             return CA_MEMORY_ALLOC_FAILED;
736         }
737         memcpy(outInfo->payload, pdu->data, dataSize);
738         outInfo->payloadSize = dataSize;
739     }
740
741     uint32_t length = strlen(optionResult);
742     OIC_LOG_V(DEBUG, TAG, "URL length:%d", length);
743
744     outInfo->resourceUri = OICMalloc(length + 1);
745     if (!outInfo->resourceUri)
746     {
747         OIC_LOG(ERROR, TAG, "Out of memory");
748         OICFree(outInfo->options);
749         OICFree(outInfo->token);
750         return CA_MEMORY_ALLOC_FAILED;
751     }
752     memcpy(outInfo->resourceUri, optionResult, length);
753     outInfo->resourceUri[length] = '\0';
754     OIC_LOG_V(DEBUG, TAG, "made URL : %s, %s", optionResult, outInfo->resourceUri);
755
756     OIC_LOG(DEBUG, TAG, "OUT");
757     return CA_STATUS_OK;
758
759 exit:
760     OIC_LOG(ERROR, TAG, "buffer too small");
761     OICFree(outInfo->options);
762     return CA_STATUS_FAILED;
763 }
764
765 CAResult_t CAGetTokenFromPDU(const coap_hdr_t *pdu_hdr, CAInfo_t *outInfo)
766 {
767     OIC_LOG(DEBUG, TAG, "IN");
768     if (NULL == pdu_hdr)
769     {
770         OIC_LOG(ERROR, TAG, "pdu_hdr is null");
771         return CA_STATUS_INVALID_PARAM;
772     }
773
774     if (NULL == outInfo)
775     {
776         OIC_LOG(ERROR, TAG, "outInfo is null");
777         return CA_STATUS_INVALID_PARAM;
778     }
779
780     // set token data
781     if (pdu_hdr->token_length > 0)
782     {
783         OIC_LOG_V(DEBUG, TAG, "token len:%d", pdu_hdr->token_length);
784         outInfo->token = (char *) OICMalloc(pdu_hdr->token_length);
785         if (NULL == outInfo->token)
786         {
787             OIC_LOG(ERROR, TAG, "out of memory");
788             return CA_MEMORY_ALLOC_FAILED;
789         }
790         memcpy(outInfo->token, pdu_hdr->token, pdu_hdr->token_length);
791     }
792
793     outInfo->tokenLength = pdu_hdr->token_length;
794
795     OIC_LOG(DEBUG, TAG, "OUT");
796
797     return CA_STATUS_OK;
798 }
799
800 CAResult_t CAGenerateTokenInternal(CAToken_t *token, uint8_t tokenLength)
801 {
802     OIC_LOG(DEBUG, TAG, "IN");
803
804     if (!token)
805     {
806         OIC_LOG(ERROR, TAG, "invalid token pointer");
807         return CA_STATUS_INVALID_PARAM;
808     }
809
810     if ((tokenLength > CA_MAX_TOKEN_LEN) || (0 == tokenLength))
811     {
812         OIC_LOG(ERROR, TAG, "invalid token length");
813         return CA_STATUS_INVALID_PARAM;
814     }
815
816     if (SEED == 0)
817     {
818 #ifdef ARDUINO
819         SEED = now();
820 #else
821         SEED = time(NULL);
822 #endif
823         if (SEED == -1)
824         {
825             OIC_LOG(ERROR, TAG, "seed is not made");
826             SEED = 0;
827             return CA_STATUS_FAILED;
828         }
829 #if HAVE_SRANDOM
830         srandom(SEED);
831 #else
832         srand(SEED);
833 #endif
834     }
835
836     // memory allocation
837     char *temp = (char *) OICCalloc(tokenLength, sizeof(char));
838     if (NULL == temp)
839     {
840         OIC_LOG(ERROR, TAG, "Out of memory");
841         return CA_MEMORY_ALLOC_FAILED;
842     }
843
844     // set random byte
845     for (uint8_t index = 0; index < tokenLength; index++)
846     {
847         // use valid characters
848 #ifdef ARDUINO
849         temp[index] = rand() & 0x00FF;
850 #else
851         temp[index] = random() & 0x00FF;
852 #endif
853     }
854
855     // save token
856     *token = temp;
857
858     OIC_LOG_V(DEBUG, TAG, "token len:%d, token:", tokenLength);
859     OIC_LOG_BUFFER(DEBUG, TAG, (const uint8_t *)(*token), tokenLength);
860
861     OIC_LOG(DEBUG, TAG, "OUT");
862     return CA_STATUS_OK;
863 }
864
865 void CADestroyTokenInternal(CAToken_t token)
866 {
867     OIC_LOG(DEBUG, TAG, "IN");
868     OICFree(token);
869     OIC_LOG(DEBUG, TAG, "OUT");
870 }
871
872 void CADestroyInfo(CAInfo_t *info)
873 {
874     OIC_LOG(DEBUG, TAG, "IN");
875
876     if (NULL != info)
877     {
878         OIC_LOG(DEBUG, TAG, "free options");
879         OICFree(info->options);
880
881         OIC_LOG(DEBUG, TAG, "free token");
882         OICFree(info->token);
883
884         OIC_LOG(DEBUG, TAG, "free payload");
885         OICFree(info->payload);
886     }
887
888     OIC_LOG(DEBUG, TAG, "OUT");
889 }
890
891 uint32_t CAGetOptionData(const uint8_t *data, uint32_t len, uint8_t *option, uint32_t buflen)
892 {
893     if (0 == buflen || 0 == len)
894     {
895         OIC_LOG(ERROR, TAG, "len 0");
896         return 0;
897     }
898
899     if (NULL == data || NULL == option)
900     {
901         OIC_LOG(ERROR, TAG, "data/option NULL");
902         return 0;
903     }
904
905     if (buflen <= len)
906     {
907         OIC_LOG(ERROR, TAG, "option buffer too small");
908         return 0;
909     }
910
911     memcpy(option, data, len);
912     option[len] = '\0';
913
914     return len;
915 }
916
917 CAMessageType_t CAGetMessageTypeFromPduBinaryData(const void *pdu, uint32_t size)
918 {
919     if (NULL == pdu)
920     {
921         OIC_LOG(ERROR, TAG, "pdu is null");
922         return CA_MSG_NONCONFIRM;
923     }
924
925     // pdu minimum size is 4 byte.
926     if (size < CA_PDU_MIN_SIZE)
927     {
928         OIC_LOG(ERROR, TAG, "min size");
929         return CA_MSG_NONCONFIRM;
930     }
931
932     coap_hdr_t *hdr = (coap_hdr_t *) pdu;
933
934     return (CAMessageType_t) hdr->type;
935 }
936
937 uint16_t CAGetMessageIdFromPduBinaryData(const void *pdu, uint32_t size)
938 {
939     if (NULL == pdu)
940     {
941         OIC_LOG(ERROR, TAG, "pdu is null");
942         return 0;
943     }
944
945     // pdu minimum size is 4 byte.
946     if (size < CA_PDU_MIN_SIZE)
947     {
948         OIC_LOG(ERROR, TAG, "min size");
949         return 0;
950     }
951
952     coap_hdr_t *hdr = (coap_hdr_t *) pdu;
953
954     return hdr->id;
955 }
956
957 CAResponseResult_t CAGetCodeFromPduBinaryData(const void *pdu, uint32_t size)
958 {
959     if (NULL == pdu)
960     {
961         OIC_LOG(ERROR, TAG, "pdu is null");
962         return CA_NOT_FOUND;
963     }
964
965     // pdu minimum size is 4 byte.
966     if (size < CA_PDU_MIN_SIZE)
967     {
968         OIC_LOG(ERROR, TAG, "min size");
969         return CA_NOT_FOUND;
970     }
971
972     coap_hdr_t *hdr = (coap_hdr_t *) pdu;
973
974     return (CAResponseResult_t) CA_RESPONSE_CODE(hdr->code);
975 }