iotivity 0.9.0
[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 #include "caprotocolmessage.h"
26 #include "logger.h"
27 #include "oic_malloc.h"
28
29 #define TAG PCF("CA")
30
31 #define CA_MAX_TOKEN_LEN   8
32 #define CA_FLAGS_BLOCK 0x01
33 #define CA_URI_MAX_SIZE 256
34 #define CA_BUFSIZE 40
35
36 uint32_t CAGetRequestInfoFromPdu(const coap_pdu_t *pdu, CARequestInfo_t* outReqInfo)
37 {
38     OIC_LOG(DEBUG, TAG, "get request info from PDU");
39     if (NULL == pdu)
40         return 0;
41
42     uint32_t code = CA_NOT_FOUND;
43     CAGetRequestPDUInfo(pdu, &code, &(outReqInfo->info));
44     outReqInfo->method = code;
45     return 1;
46 }
47
48 uint32_t CAGetResponseInfoFromPdu(const coap_pdu_t *pdu, CAResponseInfo_t* outResInfo)
49 {
50     OIC_LOG(DEBUG, TAG, "get response info from PDU");
51     if (NULL == pdu)
52         return 0;
53
54     uint32_t code = CA_NOT_FOUND;
55     CAGetRequestPDUInfo(pdu, &code, &(outResInfo->info));
56     outResInfo->result = code;
57
58     return 1;
59 }
60
61 coap_pdu_t* CAGeneratePdu(const char* uri, const uint32_t code, const CAInfo_t info)
62 {
63     OIC_LOG(DEBUG, TAG, "generate PDU");
64
65     coap_pdu_t *pdu;
66     char* coapUri = NULL;
67     uint32_t coapHeaderLength = 12;
68     uint32_t length;
69     coap_list_t *optlist = NULL;
70
71     if (NULL == uri)
72         return NULL;
73
74     length = strlen(uri);
75     coapUri = (char*) OICMalloc(length + coapHeaderLength + 1);
76     memset(coapUri, 0, length + coapHeaderLength + 1);
77
78     if (NULL != coapUri)
79     {
80
81         memcpy(coapUri, "coap://[::]/", coapHeaderLength);
82         memcpy(coapUri + coapHeaderLength, uri, length);
83
84         // parsing options in URI
85         CAParseURI(coapUri, &optlist);
86
87         // parsing options in HeadOption
88         if (NULL != &info)
89         {
90             CAParseHeadOption(code, info, &optlist);
91         }
92
93         OICFree(coapUri);
94     }
95
96     if (NULL != info.payload)
97     {
98         if (!(pdu = CACreatePDUforRequestWithPayload((code_t) code, optlist, info.payload)))
99             return NULL;
100     }
101     else
102     {
103         if (!(pdu = CACreatePDUforRequest((code_t) code, optlist)))
104             return NULL;
105     }
106
107     // pdu print method : coap_show_pdu(pdu);
108
109     return pdu;
110 }
111
112 coap_pdu_t* CAParsePDU(const char* data, uint32_t* outCode)
113 {
114     coap_pdu_t* outpdu = coap_new_pdu();
115     coap_pdu_parse((unsigned char *) data, strlen(data), outpdu);
116     (*outCode) = (uint32_t) outpdu->hdr->code;
117
118     return outpdu;
119 }
120
121 coap_pdu_t* CACreatePDUforRequestWithPayload(const code_t code, coap_list_t *options,
122         const char* payload)
123 {
124     OIC_LOG(DEBUG, TAG, "CACreatePDUforRequestWithPayload");
125
126     coap_pdu_t *pdu;
127     coap_list_t *opt;
128     unsigned char _token_data[8];
129     str the_token =
130     { 0, _token_data };
131
132     if (!(pdu = coap_new_pdu()))
133         return NULL;
134
135     /* initialize message id */
136     unsigned short message_id;
137     prng((unsigned char *)&message_id, sizeof(unsigned short));
138
139     pdu->hdr->type = msgtype;
140     pdu->hdr->id = htons(++message_id);
141     pdu->hdr->code = code;
142
143     pdu->hdr->token_length = the_token.length;
144     if (!coap_add_token(pdu, the_token.length, the_token.s))
145     {
146         OIC_LOG(DEBUG, TAG,"cannot add token to request");
147     }
148
149     for (opt = options; opt; opt = opt->next)
150     {
151         coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option *)opt->data),
152                 COAP_OPTION_LENGTH(*(coap_option *)opt->data),
153                 COAP_OPTION_DATA(*(coap_option *)opt->data));
154     }
155
156     if (NULL != payload)
157     {
158         uint32_t len = strlen(payload);
159         if ((flags & CA_FLAGS_BLOCK) == 0)
160         {
161             OIC_LOG_V(DEBUG, TAG, "coap_add_data, payload: %s", payload);
162             coap_add_data(pdu, len, payload);
163         }
164         else
165         {
166             OIC_LOG_V(DEBUG, TAG, "coap_add_block, payload: %s", payload);
167             coap_add_block(pdu, len, payload, block.num, block.szx);
168         }
169     }
170     return pdu;
171 }
172
173 coap_pdu_t* CACreatePDUforRequest(const code_t code, coap_list_t *options)
174 {
175     OIC_LOG(DEBUG, TAG, "CACreatePDUforRequest");
176
177     coap_pdu_t *pdu;
178     coap_list_t *opt;
179     unsigned char _token_data[8];
180     str the_token =
181     { 0, _token_data };
182
183     if (!(pdu = coap_new_pdu()))
184         return NULL;
185
186     /* initialize message id */
187     unsigned short message_id;
188     prng((unsigned char *)&message_id, sizeof(unsigned short));
189
190     pdu->hdr->type = msgtype;
191     pdu->hdr->id = htons(++message_id);
192     pdu->hdr->code = code;
193
194     pdu->hdr->token_length = the_token.length;
195     if (!coap_add_token(pdu, the_token.length, the_token.s))
196     {
197         OIC_LOG(DEBUG, TAG, "cannot add token to request");
198     }
199
200     for (opt = options; opt; opt = opt->next)
201     {
202         coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option *)opt->data),
203                 COAP_OPTION_LENGTH(*(coap_option *)opt->data),
204                 COAP_OPTION_DATA(*(coap_option *)opt->data));
205     }
206
207     return pdu;
208 }
209
210 void CAParseURI(const char* uriInfo, coap_list_t **optlist)
211 {
212     OIC_LOG(DEBUG, TAG, "parse URI");
213
214     unsigned char portbuf[2];
215     unsigned char _buf[CA_BUFSIZE];
216     unsigned char *buf = _buf;
217     coap_uri_t uri;
218     size_t buflen;
219     uint32_t res;
220
221     OIC_LOG_V(DEBUG, TAG, "url : %s", uriInfo);
222
223     /* split arg into Uri-* options */
224     coap_split_uri((unsigned char *) uriInfo, strlen(uriInfo), &uri);
225
226     if (uri.port != COAP_DEFAULT_PORT)
227     {
228         coap_insert(optlist,
229                 CACreateNewOptionNode(COAP_OPTION_URI_PORT,
230                         coap_encode_var_bytes(portbuf, uri.port), portbuf), CAOrderOpts);
231     }
232
233     if (uri.path.length)
234     {
235         buflen = CA_BUFSIZE;
236         res = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
237
238         while (res--)
239         {
240             coap_insert(optlist,
241                     CACreateNewOptionNode(COAP_OPTION_URI_PATH, COAP_OPT_LENGTH(buf),
242                             COAP_OPT_VALUE(buf)), CAOrderOpts);
243             buf += COAP_OPT_SIZE(buf);
244         }
245     }
246
247     if (uri.query.length)
248     {
249         buflen = CA_BUFSIZE;
250         buf = _buf;
251         res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
252
253         while (res--)
254         {
255             coap_insert(optlist,
256                     CACreateNewOptionNode(COAP_OPTION_URI_QUERY, COAP_OPT_LENGTH(buf),
257                             COAP_OPT_VALUE(buf)), CAOrderOpts);
258
259             buf += COAP_OPT_SIZE(buf);
260         }
261     }
262
263 }
264
265 void CAParseHeadOption(const uint32_t code, const CAInfo_t info, coap_list_t **optlist)
266 {
267     OIC_LOG_V(DEBUG, TAG, "start parse Head Option : %d", info.numOptions);
268
269     uint32_t i;
270     for (i = 0; i < info.numOptions; i++)
271     {
272         coap_insert(optlist,
273                 CACreateNewOptionNode(info.options->optionID, info.options->optionLength,
274                         info.options->optionData), CAOrderOpts);
275     }
276 }
277
278 coap_list_t* CACreateNewOptionNode(const uint16_t key, const uint32_t length, const uint8_t *data)
279 {
280     coap_option *option;
281     coap_list_t *node;
282
283     option = coap_malloc(sizeof(coap_option) + length);
284     if (!option)
285         goto error;
286
287     COAP_OPTION_KEY(*option) = key;
288     COAP_OPTION_LENGTH(*option) = length;
289     memcpy(COAP_OPTION_DATA(*option), data, length);
290
291     /* we can pass NULL here as delete function since option is released automatically  */
292     node = coap_new_listnode(option, NULL);
293
294     if (node)
295         return node;
296
297     error: perror("new_option_node: malloc");
298     coap_free( option);
299     return NULL;
300 }
301
302 int32_t CAOrderOpts(void *a, void *b)
303 {
304     if (!a || !b)
305         return a < b ? -1 : 1;
306
307     if (COAP_OPTION_KEY(*(coap_option *)a) < COAP_OPTION_KEY(*(coap_option *)b))
308         return -1;
309
310     return COAP_OPTION_KEY(*(coap_option *)a) == COAP_OPTION_KEY(*(coap_option *)b);
311 }
312
313 void CAGetRequestPDUInfo(const coap_pdu_t *pdu, uint32_t* outCode, CAInfo_t* outInfo)
314 {
315     unsigned char buf[COAP_MAX_PDU_SIZE]; /* need some space for output creation */
316     uint32_t encode = 0;
317     coap_opt_iterator_t opt_iter;
318     coap_opt_t *option;
319     char optionResult[CA_URI_MAX_SIZE] =
320     { 0, };
321     uint32_t count = 0;
322     uint32_t isfirstsetflag = 0;
323
324     /* show options, if any */
325     coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL);
326
327     memset(optionResult, 0, sizeof(optionResult));
328     while ((option = coap_option_next(&opt_iter)))
329     {
330
331         if (print_readable(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option), buf, sizeof(buf),
332                 encode))
333         {
334             if (opt_iter.type == COAP_OPTION_URI_PATH || opt_iter.type == COAP_OPTION_URI_QUERY)
335             {
336                 if (0 == isfirstsetflag)
337                 {
338                     isfirstsetflag = 1;
339                     memcpy(optionResult + count, buf, strlen(buf));
340                     count += strlen(buf);
341
342                 }
343                 else
344                 {
345                     if (opt_iter.type == COAP_OPTION_URI_PATH)
346                     {
347                         memcpy(optionResult + count, "/", 1);
348                         count++;
349                     }
350                     else if (opt_iter.type == COAP_OPTION_URI_QUERY)
351                     {
352                         memcpy(optionResult + count, "?", 1);
353                         count++;
354                     }
355                     memcpy(optionResult + count, buf, strlen(buf));
356                     count += strlen(buf);
357                 }
358             }
359         }
360     }
361
362     OIC_LOG(DEBUG, TAG, "set CAInfo_t after parsing");
363
364     // set pdu info
365     (*outCode) = (uint32_t) pdu->hdr->code;
366     memset(outInfo, 0, sizeof(CAInfo_t));
367
368     outInfo->options = (CAHeaderOption_t*) OICMalloc(sizeof(CAHeaderOption_t));
369     memset(outInfo->options, 0, sizeof(CAHeaderOption_t));
370
371     outInfo->options->optionID = opt_iter.type;
372     outInfo->options->optionLength = count;
373     memcpy(outInfo->options->optionData, optionResult, CA_MAX_HEADER_OPTION_DATA_LENGTH);
374
375     if (pdu->hdr->token_length > 0)
376     {
377         outInfo->token = (char*) OICMalloc(pdu->hdr->token_length);
378         memcpy(outInfo->token, pdu->hdr->token, pdu->hdr->token_length);
379     }
380
381     if (NULL != pdu->data)
382     {
383         outInfo->payload = (char*) OICMalloc(strlen(pdu->data) + 1);
384         memcpy(outInfo->payload, pdu->data, strlen(pdu->data) + 1);
385     }
386 }
387
388 CAResult_t CAGenerateTokenInternal(CAToken_t* token)
389 {
390     OIC_LOG(DEBUG, TAG, "generate the token");
391
392     return CA_STATUS_OK;
393 }
394
395 void CADestroyTokenInternal(CAToken_t token)
396 {
397     OIC_LOG(DEBUG, TAG, "destroy the token!!");
398
399     if (token != NULL)
400     {
401         OICFree(token);
402     }
403 }