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