07ef6fd3247e0877dccfcfa30da66b8535262ea8
[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 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25
26 #include "caprotocolmessage.h"
27 #include "logger.h"
28 #include "oic_malloc.h"
29
30 #define TAG "CA"
31
32 #define CA_BUFSIZE 128
33 #define CA_PDU_MIN_SIZE 4
34
35 static const char COAP_HEADER[] = "coap://[::]/";
36 static uint32_t SEED = 0;
37
38 void CAGetRequestInfoFromPdu(const coap_pdu_t *pdu, CARequestInfo_t *outReqInfo, char *outUri,
39                              uint32_t buflen)
40 {
41     OIC_LOG(DEBUG, TAG, "CAGetRequestInfoFromPdu IN");
42
43     if (NULL == pdu)
44     {
45         return;
46     }
47
48     uint32_t code = CA_NOT_FOUND;
49     CAGetInfoFromPDU(pdu, &code, &(outReqInfo->info), outUri, buflen);
50     outReqInfo->method = code;
51     OIC_LOG(DEBUG, TAG, "CAGetRequestInfoFromPdu OUT");
52 }
53
54 void CAGetResponseInfoFromPdu(const coap_pdu_t *pdu, CAResponseInfo_t *outResInfo, char *outUri,
55                               uint32_t buflen)
56 {
57     OIC_LOG(DEBUG, TAG, "CAGetResponseInfoFromPdu IN");
58     if (NULL == pdu)
59     {
60         return;
61     }
62
63     uint32_t code = CA_NOT_FOUND;
64     CAGetInfoFromPDU(pdu, &code, &(outResInfo->info), outUri, buflen);
65     outResInfo->result = code;
66     OIC_LOG(DEBUG, TAG, "CAGetResponseInfoFromPdu OUT");
67 }
68
69 coap_pdu_t *CAGeneratePdu(const char *uri, const uint32_t code, const CAInfo_t info)
70 {
71     OIC_LOG(DEBUG, TAG, "CAGeneratePdu IN");
72
73     if (NULL == uri)
74     {
75         return NULL;
76     }
77
78     uint32_t length = strlen(uri);
79     if (CA_MAX_URI_LENGTH < length)
80     {
81         OIC_LOG(ERROR, TAG, "check URI length..");
82         return NULL;
83     }
84
85     uint32_t uriLength = length + sizeof(COAP_HEADER);
86     char *coapUri = NULL;
87     coapUri = (char *) OICCalloc(1, uriLength * sizeof(char));
88     if (NULL == coapUri)
89     {
90         OIC_LOG(ERROR, TAG, "CAGeneratePdu, Memory allocation failed !");
91         return NULL;
92     }
93
94     coap_list_t *optlist = NULL;
95     if (NULL != coapUri)
96     {
97         strcat(coapUri, COAP_HEADER);
98         strcat(coapUri, uri);
99
100         // parsing options in URI
101         CAParseURI(coapUri, &optlist);
102         OICFree(coapUri);
103         coapUri = NULL;
104
105         // parsing options in HeadOption
106         CAParseHeadOption(code, info, &optlist);
107     }
108
109     coap_pdu_t *pdu;
110     if (!(pdu = CAGeneratePduImpl((code_t) code, optlist, info, info.payload)))
111     {
112         return NULL;
113     }
114
115     // free option list
116     coap_delete_list(optlist);
117
118     // pdu print method : coap_show_pdu(pdu);
119     OIC_LOG(DEBUG, TAG, "CAGeneratePdu OUT");
120     return pdu;
121 }
122
123 coap_pdu_t *CAParsePDU(const char *data, uint32_t length, uint32_t *outCode)
124 {
125     OIC_LOG(DEBUG, TAG, "CAParsePDU IN");
126     coap_pdu_t *outpdu = coap_new_pdu();
127
128     if (0 >= coap_pdu_parse((unsigned char *) data, length, outpdu))
129     {
130         OIC_LOG(ERROR, TAG, "coap_pdu_parse failed");
131         coap_delete_pdu(outpdu);
132         return NULL;
133     }
134
135     if (outCode)
136     {
137         (*outCode) = (uint32_t) outpdu->hdr->code;
138     }OIC_LOG(DEBUG, TAG, "CAParsePDU OUT");
139     return outpdu;
140 }
141
142 coap_pdu_t *CAGeneratePduImpl(const code_t code, coap_list_t *options, const CAInfo_t info,
143                               const char *payload)
144 {
145     OIC_LOG(DEBUG, TAG, "CAGeneratePduImpl IN");
146
147     coap_pdu_t *pdu = coap_new_pdu();
148     if (!pdu)
149     {
150         OIC_LOG(ERROR, TAG, "Out of memory");
151         return NULL;
152     }
153
154     OIC_LOG_V(DEBUG, TAG, "messageId is %d", info.messageId);
155     if (CA_MSG_ACKNOWLEDGE == info.type || CA_MSG_RESET == info.type)
156     {
157         pdu->hdr->id = htons(info.messageId);
158     }
159     else
160     {
161         uint16_t message_id;
162         if (info.messageId == 0)
163         {
164             /* initialize message id */
165             prng((uint8_t * ) &message_id, sizeof(uint16_t));
166
167             OIC_LOG_V(DEBUG, TAG, "generate the message id(%d)", message_id);
168         }
169         else
170         {
171             /* use saved message id */
172             message_id = info.messageId;
173         }
174         pdu->hdr->id = htons(message_id);
175     }
176     pdu->hdr->type = info.type;
177     pdu->hdr->code = COAP_RESPONSE_CODE(code);
178
179     if (info.token)
180     {
181         uint32_t tokenLength = strlen(info.token);
182         OIC_LOG_V(DEBUG, TAG, "token info : %s, %d", info.token, tokenLength);
183
184         int32_t ret = coap_add_token(pdu, tokenLength, (uint8_t *) info.token);
185         if (0 == ret)
186         {
187             OIC_LOG(DEBUG, TAG, "cannot add token to request");
188         }
189     }
190
191     if (options)
192     {
193         coap_list_t *opt;
194         for (opt = options; opt; opt = opt->next)
195         {
196             OIC_LOG_V(DEBUG, TAG, "[%s] opt will be added.",
197                     COAP_OPTION_DATA(*(coap_option *) opt->data));
198             coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option * ) opt->data),
199                             COAP_OPTION_LENGTH(*(coap_option * ) opt->data),
200                             COAP_OPTION_DATA(*(coap_option * ) opt->data));
201         }
202     }
203
204     if (NULL != payload)
205     {
206         uint32_t len = strlen(payload);
207         OIC_LOG_V(DEBUG, TAG, "coap_add_data, payload: %s", payload);
208         coap_add_data(pdu, len, (const uint8_t *) payload);
209     }
210
211     OIC_LOG(DEBUG, TAG, "CAGeneratePduImpl OUT");
212     return pdu;
213 }
214
215 void CAParseURI(const char *uriInfo, coap_list_t **optlist)
216 {
217     OIC_LOG(DEBUG, TAG, "CAParseURI IN");OIC_LOG_V(DEBUG, TAG, "url : %s", uriInfo);
218
219     /* split arg into Uri-* options */
220     coap_uri_t uri;
221     coap_split_uri((unsigned char *) uriInfo, strlen(uriInfo), &uri);
222
223     unsigned char portbuf[2];
224     if (uri.port != COAP_DEFAULT_PORT)
225     {
226         coap_insert(
227                 optlist,
228                 CACreateNewOptionNode(COAP_OPTION_URI_PORT,
229                                       coap_encode_var_bytes(portbuf, uri.port), portbuf),
230                 CAOrderOpts);
231     }
232
233     unsigned char uriBuffer[CA_BUFSIZE] =
234     { 0 };
235     unsigned char *pBuf = uriBuffer;
236     uint32_t buflen;
237     int32_t res;
238
239     if (uri.path.length)
240     {
241         buflen = CA_BUFSIZE;
242         res = coap_split_path(uri.path.s, uri.path.length, pBuf, &buflen);
243
244         if (res > 0)
245         {
246             uint32_t prevIdx = 0;
247             while (res--)
248             {
249                 coap_insert(
250                         optlist,
251                         CACreateNewOptionNode(COAP_OPTION_URI_PATH, COAP_OPT_LENGTH(pBuf),
252                                               COAP_OPT_VALUE(pBuf)),
253                         CAOrderOpts);
254
255                 uint32_t optSize = COAP_OPT_SIZE(pBuf);
256                 uint32_t nextIdx = prevIdx + optSize;
257                 if (nextIdx < buflen)
258                 {
259                     pBuf += optSize;
260                     prevIdx += nextIdx;
261                 }
262             }
263         }
264     }
265
266     if (uri.query.length)
267     {
268         buflen = CA_BUFSIZE;
269         pBuf = uriBuffer;
270         res = coap_split_query(uri.query.s, uri.query.length, pBuf, &buflen);
271
272         if (res > 0)
273         {
274             uint32_t prevIdx = 0;
275             while (res--)
276             {
277                 coap_insert(
278                         optlist,
279                         CACreateNewOptionNode(COAP_OPTION_URI_QUERY, COAP_OPT_LENGTH(pBuf),
280                                               COAP_OPT_VALUE(pBuf)),
281                         CAOrderOpts);
282
283                 uint32_t optSize = COAP_OPT_SIZE(pBuf);
284                 uint32_t nextIdx = prevIdx + optSize;
285                 if (nextIdx < buflen)
286                 {
287                     pBuf += optSize;
288                     prevIdx += nextIdx;
289                 }
290             }
291         }
292     }
293
294     OIC_LOG(DEBUG, TAG, "CAParseURI OUT");
295 }
296
297 void CAParseHeadOption(const uint32_t code, const CAInfo_t info, coap_list_t **optlist)
298 {
299     OIC_LOG(DEBUG, TAG, "CAParseHeadOption IN");
300
301     OIC_LOG_V(DEBUG, TAG, "start parse Head Option : %d", info.numOptions);
302
303     uint32_t i;
304     for (i = 0; i < info.numOptions; i++)
305     {
306         uint32_t id = info.options[i].optionID;
307         if (COAP_OPTION_URI_PATH == id || COAP_OPTION_URI_QUERY == id)
308         {
309             OIC_LOG_V(DEBUG, TAG, "it is not Header Option : %d", id);
310         }
311         else
312         {
313             OIC_LOG_V(DEBUG, TAG, "Head Option ID: %d", info.options[i].optionID);
314
315             OIC_LOG_V(DEBUG, TAG, "Head Option data: %s", info.options[i].optionData);
316
317             OIC_LOG_V(DEBUG, TAG, "Head Option length: %d", info.options[i].optionLength);
318
319             coap_insert(
320                     optlist,
321                     CACreateNewOptionNode(info.options[i].optionID, info.options[i].optionLength,
322                                           info.options[i].optionData),
323                     CAOrderOpts);
324         }
325     }
326
327     OIC_LOG(DEBUG, TAG, "CAParseHeadOption OUT");
328 }
329
330 coap_list_t *CACreateNewOptionNode(const uint16_t key, const uint32_t length, const uint8_t *data)
331 {
332     OIC_LOG(DEBUG, TAG, "CACreateNewOptionNode IN");
333     coap_option *option = coap_malloc(sizeof(coap_option) + length + 1);
334     if (!option)
335     {
336         OIC_LOG(DEBUG, TAG, "Out of memory");
337         return NULL;
338     }
339     memset(option, 0, sizeof(coap_option) + length + 1);
340
341     COAP_OPTION_KEY(*option) = key;
342     COAP_OPTION_LENGTH(*option) = length;
343     memcpy(COAP_OPTION_DATA(*option), data, length);
344
345     /* we can pass NULL here as delete function since option is released automatically  */
346     coap_list_t *node = coap_new_listnode(option, NULL);
347
348     if (!node)
349     {
350         OIC_LOG(DEBUG, TAG, "coap_new_listnode returns NULL");
351         coap_free(option);
352         return NULL;
353     }
354     //coap_free(option);
355     OIC_LOG(DEBUG, TAG, "CACreateNewOptionNode OUT");
356     return node;
357 }
358
359 int CAOrderOpts(void *a, void *b)
360 {
361     OIC_LOG(DEBUG, TAG, "CAOrderOpts IN");
362     if (!a || !b)
363     {
364         return a < b ? -1 : 1;
365     }
366
367     if (COAP_OPTION_KEY(*(coap_option *)a) < COAP_OPTION_KEY(*(coap_option * )b))
368     {
369         return -1;
370     }
371
372     OIC_LOG(DEBUG, TAG, "CAOrderOpts OUT");
373     return COAP_OPTION_KEY(*(coap_option *)a) == COAP_OPTION_KEY(*(coap_option * )b);
374 }
375
376 uint32_t CAGetOptionCount(coap_opt_iterator_t opt_iter)
377 {
378     OIC_LOG(DEBUG, TAG, "CAGetOptionCount IN");
379     uint32_t count = 0;
380     coap_opt_t *option;
381
382     while ((option = coap_option_next(&opt_iter)))
383     {
384         if (COAP_OPTION_URI_PATH != opt_iter.type && COAP_OPTION_URI_QUERY != opt_iter.type)
385         {
386             count++;
387         }
388     }
389
390     OIC_LOG(DEBUG, TAG, "CAGetOptionCount OUT");
391     return count;
392 }
393
394 void CAGetInfoFromPDU(const coap_pdu_t *pdu, uint32_t *outCode, CAInfo_t *outInfo, char *outUri,
395                       uint32_t buflen)
396 {
397     OIC_LOG(DEBUG, TAG, "CAGetInfoFromPDU IN");
398
399     coap_opt_iterator_t opt_iter;
400     coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL);
401
402     // set code
403     if (outCode)
404     {
405         (*outCode) = (uint32_t) CA_RESPONSE_CODE(pdu->hdr->code);
406     }
407
408     // init HeaderOption list
409     uint32_t count = CAGetOptionCount(opt_iter);
410
411     if (!outInfo)
412     {
413         OIC_LOG(ERROR, TAG, "outInfo is null");
414         return;
415     }
416     memset(outInfo, 0, sizeof(*outInfo));
417     outInfo->numOptions = count;
418     // set type
419     outInfo->type = pdu->hdr->type;
420
421     // set message id
422     outInfo->messageId = ntohs(pdu->hdr->id);
423
424     if (count > 0)
425     {
426         outInfo->options = (CAHeaderOption_t *) OICCalloc(count, sizeof(CAHeaderOption_t));
427         if (outInfo->options == NULL)
428         {
429             OIC_LOG(DEBUG, TAG, "CAGetInfoFromPDU, Memory allocation failed !");
430             return;
431         }
432     }
433
434     char buf[COAP_MAX_PDU_SIZE] =
435     { 0 };
436     coap_opt_t *option;
437     char optionResult[CA_MAX_URI_LENGTH] =
438     { 0 };
439     uint32_t idx = 0;
440     uint32_t optionLength = 0;
441     bool isfirstsetflag = false;
442     bool isQueryBeingProcessed = false;
443
444     while ((option = coap_option_next(&opt_iter)))
445     {
446         if (CAGetOptionData((uint8_t *) (COAP_OPT_VALUE(option)), COAP_OPT_LENGTH(option),
447                             (uint8_t *) buf, sizeof(buf)))
448         {
449             OIC_LOG_V(DEBUG, TAG, "COAP URI element : %s", buf);
450             uint32_t bufLength = strlen(buf);
451             if (COAP_OPTION_URI_PATH == opt_iter.type || COAP_OPTION_URI_QUERY == opt_iter.type)
452             {
453                 if (false == isfirstsetflag)
454                 {
455                     isfirstsetflag = true;
456                     optionResult[optionLength] = '/';
457                     optionLength++;
458                     memcpy(optionResult + optionLength, buf, bufLength);
459                     optionLength += bufLength;
460                 }
461                 else
462                 {
463                     if (COAP_OPTION_URI_PATH == opt_iter.type)
464                     {
465                         optionResult[optionLength] = '/';
466                         optionLength++;
467                     }
468                     else if (COAP_OPTION_URI_QUERY == opt_iter.type)
469                     {
470                         if(false == isQueryBeingProcessed)
471                         {
472                             optionResult[optionLength] = '?';
473                             optionLength++;
474                             isQueryBeingProcessed = true;
475                         }
476                         else
477                         {
478                             optionResult[optionLength] = '&';
479                             optionLength++;
480                         }
481                     }
482                     memcpy(optionResult + optionLength, buf, bufLength);
483                     optionLength += bufLength;
484                 }
485             }
486             else
487             {
488                 if (idx < count)
489                 {
490                     uint32_t length = bufLength;
491
492                     if (length <= CA_MAX_HEADER_OPTION_DATA_LENGTH)
493                     {
494                         outInfo->options[idx].optionID = opt_iter.type;
495                         outInfo->options[idx].optionLength = length;
496                         outInfo->options[idx].protocolID = CA_COAP_ID;
497                         memcpy(outInfo->options[idx].optionData, buf, length);
498                         idx++;
499                     }
500                 }
501             }
502         }
503     }
504
505     // set token data
506     if (pdu->hdr->token_length > 0)
507     {
508         OIC_LOG(DEBUG, TAG, "inside pdu->hdr->token_length");
509         outInfo->token = (char *) OICMalloc(pdu->hdr->token_length + 1);
510         if (outInfo->token == NULL)
511         {
512             OIC_LOG(DEBUG, TAG, "CAGetInfoFromPDU, Memory allocation failed !");
513             OICFree(outInfo->options);
514             return;
515         }
516         memcpy(outInfo->token, pdu->hdr->token, pdu->hdr->token_length);
517         outInfo->token[pdu->hdr->token_length] = '\0';
518     }
519
520     // set payload data
521     if (NULL != pdu->data)
522     {
523         uint32_t payloadLength = strlen((char*) pdu->data);
524         OIC_LOG(DEBUG, TAG, "inside pdu->data");
525         outInfo->payload = (char *) OICMalloc(payloadLength + 1);
526         if (outInfo->payload == NULL)
527         {
528             OIC_LOG(DEBUG, TAG, "CAGetInfoFromPDU, Memory allocation failed !");
529             OICFree(outInfo->options);
530             OICFree(outInfo->token);
531             return;
532         }
533         memcpy(outInfo->payload, pdu->data, payloadLength);
534         outInfo->payload[payloadLength] = '\0';
535     }
536
537     uint32_t length = strlen(optionResult);
538     OIC_LOG_V(DEBUG, TAG, "made URL length: %d, %d, %d...\n", length, buflen, strlen(outUri));
539     if (buflen >= length)
540     {
541         memcpy(outUri, optionResult, length);
542         outUri[length] = '\0';
543         OIC_LOG_V(DEBUG, TAG, "made URL : %s, %s\n", optionResult, outUri);
544     }OIC_LOG(DEBUG, TAG, "CAGetInfoFromPDU OUT");
545 }
546
547 CAResult_t CAGenerateTokenInternal(CAToken_t *token)
548 {
549     OIC_LOG(DEBUG, TAG, "CAGenerateTokenInternal IN");
550     if (token == NULL)
551     {
552         return CA_STATUS_FAILED;
553     }
554
555     // memory allocation
556     char *temp = (char *) OICCalloc(1, (CA_MAX_TOKEN_LEN + 1) * sizeof(char));
557     if (temp == NULL)
558     {
559         OIC_LOG(DEBUG, TAG, "CAGenerateTokenInternal, Memory allocation failed !");
560         return CA_MEMORY_ALLOC_FAILED;
561     }
562
563     if (SEED == 0)
564     {
565         SEED = time(NULL);
566         if (SEED == -1)
567         {
568             OIC_LOG(DEBUG, TAG, "Failed to Create Seed!");
569             SEED = 0;
570             OICFree(temp);
571             return CA_STATUS_FAILED;
572         }
573         srandom(SEED);
574     }
575
576     // set random byte
577     uint32_t index;
578     for (index = 0; index < CA_MAX_TOKEN_LEN; index++)
579     {
580         // use valid characters
581         temp[index] = (random() % 94 + 33) & 0xFF;
582     }
583
584     temp[index] = '\0';
585     // save token
586     *token = temp;
587
588     OIC_LOG_V(DEBUG, TAG, "generate the token(%s)!!", *token);
589
590     OIC_LOG(DEBUG, TAG, "CAGenerateTokenInternal OUT");
591     return CA_STATUS_OK;
592 }
593
594 void CADestroyTokenInternal(CAToken_t token)
595 {
596     OIC_LOG(DEBUG, TAG, "CADestroyTokenInternal IN");
597     if (token != NULL)
598     {
599         OIC_LOG_V(DEBUG, TAG, "destroy the token(%s)!!", token);
600
601         OICFree(token);
602         token = NULL;
603     }
604
605     OIC_LOG(DEBUG, TAG, "CADestroyTokenInternal OUT");
606 }
607
608 void CADestroyInfo(CAInfo_t *info)
609 {
610     OIC_LOG(DEBUG, TAG, "CADestroyInfo IN");
611
612     if (NULL != info)
613     {
614         if (NULL != info->options)
615         {
616             OIC_LOG(DEBUG, TAG, "free options in CAInfo");
617             OICFree(info->options);
618         }
619
620         if (NULL != info->token)
621         {
622             OIC_LOG(DEBUG, TAG, "free token in CAInfo");
623             OICFree(info->token);
624         }
625
626         if (NULL != info->payload)
627         {
628             OIC_LOG(DEBUG, TAG, "free payload in CAInfo");
629             OICFree(info->payload);
630         }
631     }
632
633     OIC_LOG(DEBUG, TAG, "OUT");
634 }
635
636 uint32_t CAGetOptionData(const uint8_t *data, uint32_t len, uint8_t *option, uint32_t buflen)
637 {
638     assert(data || 0 == len);
639
640     if (0 == buflen || 0 == len)
641     {
642         OIC_LOG(ERROR, TAG, "buflen or len is not available");
643         return 0;
644     }
645
646     if (NULL == data)
647     {
648         OIC_LOG(ERROR, TAG, "data not available");
649         return 0;
650     }
651
652     if (NULL == option)
653     {
654         OIC_LOG(ERROR, TAG, "option pointer is null");
655         return 0;
656     }
657
658     uint32_t cnt = 0;
659     while (len)
660     {
661         if (cnt == buflen - 1)
662         {
663             break;
664         }
665
666         *option++ = *data;
667         ++cnt;
668         ++data;
669         --len;
670     }
671
672     *option = '\0';
673     return cnt;
674 }
675
676 CAMessageType_t CAGetMessageTypeFromPduBinaryData(const void *pdu, uint32_t size)
677 {
678     // pdu minimum size is 4 byte.
679     if (size < CA_PDU_MIN_SIZE)
680     {
681         return CA_MSG_NONCONFIRM;
682     }
683
684     coap_hdr_t *hdr = (coap_hdr_t *) pdu;
685     if (NULL == hdr)
686     {
687         return CA_MSG_NONCONFIRM;
688     }
689
690     return (CAMessageType_t) hdr->type;
691 }
692
693 uint16_t CAGetMessageIdFromPduBinaryData(const void *pdu, uint32_t size)
694 {
695     // pdu minimum size is 4 byte.
696     if (size < CA_PDU_MIN_SIZE)
697     {
698         return 0;
699     }
700
701     coap_hdr_t *hdr = (coap_hdr_t *) pdu;
702     if (NULL == hdr)
703     {
704         return 0;
705     }
706
707     return ntohs(hdr->id);
708 }