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