1 /******************************************************************
\r
3 * Copyright 2014 Samsung Electronics All Rights Reserved.
\r
7 * Licensed under the Apache License, Version 2.0 (the "License");
\r
8 * you may not use this file except in compliance with the License.
\r
9 * You may obtain a copy of the License at
\r
11 * http://www.apache.org/licenses/LICENSE-2.0
\r
13 * Unless required by applicable law or agreed to in writing, software
\r
14 * distributed under the License is distributed on an "AS IS" BASIS,
\r
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 * See the License for the specific language governing permissions and
\r
17 * limitations under the License.
\r
19 ******************************************************************/
\r
26 #include "caprotocolmessage.h"
\r
28 #include "oic_malloc.h"
\r
32 #define CA_MAX_TOKEN_LEN (8)
\r
33 #define CA_FLAGS_BLOCK 0x01
\r
34 #define CA_BUFSIZE 128
\r
35 #define CA_COAP_MESSAGE_CON 0
\r
37 static int32_t SEED = 0;
\r
39 uint32_t CAGetRequestInfoFromPdu(const coap_pdu_t *pdu, CARequestInfo_t *outReqInfo,
\r
42 OIC_LOG(DEBUG, TAG, "CAGetRequestInfoFromPdu IN");
\r
47 uint32_t code = CA_NOT_FOUND;
\r
48 CAGetRequestPDUInfo(pdu, &code, &(outReqInfo->info), outUri);
\r
49 outReqInfo->method = code;
\r
50 OIC_LOG(DEBUG, TAG, "CAGetRequestInfoFromPdu OUT");
\r
54 uint32_t CAGetResponseInfoFromPdu(const coap_pdu_t *pdu, CAResponseInfo_t *outResInfo,
\r
57 OIC_LOG(DEBUG, TAG, "CAGetResponseInfoFromPdu IN");
\r
61 uint32_t code = CA_NOT_FOUND;
\r
62 CAGetRequestPDUInfo(pdu, &code, &(outResInfo->info), outUri);
\r
63 outResInfo->result = code;
\r
64 OIC_LOG(DEBUG, TAG, "CAGetResponseInfoFromPdu OUT");
\r
68 coap_pdu_t *CAGeneratePdu(const char *uri, const uint32_t code, const CAInfo_t info)
\r
70 OIC_LOG(DEBUG, TAG, "CAGeneratePdu IN");
\r
73 char *coapUri = NULL;
\r
74 uint32_t coapHeaderLength = 12;
\r
76 coap_list_t *optlist = NULL;
\r
81 length = strlen(uri);
\r
82 if (CA_MAX_URI_LENGTH < length)
\r
84 OIC_LOG(DEBUG, TAG, "check URI length..");
\r
88 uint32_t uriLength = length + coapHeaderLength + 1;
\r
89 coapUri = (char *) OICMalloc(uriLength);
\r
90 if (NULL == coapUri)
\r
92 OIC_LOG(DEBUG, TAG, "CAGeneratePdu, Memory allocation failed !");
\r
95 memset(coapUri, 0, uriLength);
\r
97 if (NULL != coapUri)
\r
99 strcat(coapUri, "coap://[::]/");
\r
100 strcat(coapUri, uri);
\r
102 // parsing options in URI
\r
103 CAParseURI(coapUri, &optlist);
\r
107 // parsing options in HeadOption
\r
108 CAParseHeadOption(code, info, &optlist);
\r
111 if (NULL != info.payload) // payload is include in request / response
\r
113 if (!(pdu = CACreatePDUforRequestWithPayload((code_t) code, optlist, info.payload, info)))
\r
116 else // payload is not include in request / response
\r
118 if (!(pdu = CACreatePDUforRequest((code_t) code, optlist, info)))
\r
122 // free option list
\r
123 coap_delete_list(optlist);
\r
125 // pdu print method : coap_show_pdu(pdu);
\r
126 OIC_LOG(DEBUG, TAG, "CAGeneratePdu OUT");
\r
130 coap_pdu_t *CAParsePDU(const char *data, uint32_t length, uint32_t *outCode)
\r
132 OIC_LOG(DEBUG, TAG, "CAParsePDU IN");
\r
133 coap_pdu_t *outpdu = coap_new_pdu();
\r
135 coap_pdu_parse((unsigned char *) data, length, outpdu);
\r
136 (*outCode) = (uint32_t) outpdu->hdr->code;
\r
137 OIC_LOG(DEBUG, TAG, "CAParsePDU OUT");
\r
141 coap_pdu_t *CACreatePDUforRequestWithPayload(const code_t code, coap_list_t *options,
\r
142 const char *payload, const CAInfo_t info)
\r
144 OIC_LOG(DEBUG, TAG, "CACreatePDUforRequestWithPayload IN");
\r
149 uint32_t CAFlags = 0;
\r
150 coap_block_t CABlock =
\r
151 { .num = 0, .m = 0, .szx = 6 };
\r
153 if (!(pdu = coap_new_pdu()))
\r
156 unsigned short message_id;
\r
158 if (info.messageId == 0)
\r
160 /* initialize message id */
\r
161 prng((unsigned char * )&message_id, sizeof(unsigned short));
\r
164 OIC_LOG_V(DEBUG, TAG, "generate the message id(%d)", message_id);
\r
168 /* use saved message id */
\r
169 message_id = info.messageId;
\r
172 pdu->hdr->type = info.type;
\r
173 pdu->hdr->id = htons(message_id);
\r
174 pdu->hdr->code = code;
\r
178 pdu->hdr->token_length = CA_MAX_TOKEN_LEN;
\r
179 if (!coap_add_token(pdu, CA_MAX_TOKEN_LEN, (unsigned char *) info.token))
\r
181 OIC_LOG(DEBUG, TAG, "cannot add token to request");
\r
184 for (opt = options; opt; opt = opt->next)
\r
186 OIC_LOG_V(DEBUG, TAG, "[%s] opt will be added.", COAP_OPTION_DATA(*(coap_option * )opt->data));
\r
187 coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option * )opt->data),
\r
188 COAP_OPTION_LENGTH(*(coap_option * )opt->data),
\r
189 COAP_OPTION_DATA(*(coap_option * )opt->data));
\r
192 if (NULL != payload)
\r
194 uint32_t len = strlen(payload);
\r
195 if ((CAFlags & CA_FLAGS_BLOCK) == 0)
\r
197 OIC_LOG_V(DEBUG, TAG, "coap_add_data, payload: %s", payload);
\r
198 coap_add_data(pdu, len, (const unsigned char *) payload);
\r
202 OIC_LOG_V(DEBUG, TAG, "coap_add_block, payload: %s", payload);
\r
203 coap_add_block(pdu, len, (const unsigned char *) payload, CABlock.num, CABlock.szx);
\r
206 OIC_LOG(DEBUG, TAG, "CACreatePDUforRequestWithPayload OUT");
\r
210 coap_pdu_t *CACreatePDUforRequest(const code_t code, coap_list_t *options,
\r
211 const CAInfo_t info)
\r
213 OIC_LOG(DEBUG, TAG, "CACreatePDUforRequest IN");
\r
218 if (!(pdu = coap_new_pdu()))
\r
220 OIC_LOG(DEBUG, TAG, "Out of memory");
\r
224 unsigned short message_id;
\r
226 if (info.messageId == 0)
\r
228 /* initialize message id */
\r
229 prng((unsigned char * )&message_id, sizeof(unsigned short));
\r
232 OIC_LOG_V(DEBUG, TAG, "generate the message id(%d)", message_id);
\r
236 /* use saved message id */
\r
237 message_id = info.messageId;
\r
240 pdu->hdr->type = info.type;
\r
241 pdu->hdr->id = htons(message_id);
\r
242 pdu->hdr->code = code;
\r
244 OIC_LOG_V(DEBUG, TAG, "token info : %s, %d", info.token, strlen(info.token));
\r
245 pdu->hdr->token_length = CA_MAX_TOKEN_LEN;
\r
247 if (!coap_add_token(pdu, CA_MAX_TOKEN_LEN, (unsigned char *) info.token))
\r
249 OIC_LOG(DEBUG, TAG, "cannot add token to request");
\r
252 for (opt = options; opt; opt = opt->next)
\r
254 coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option * )opt->data),
\r
255 COAP_OPTION_LENGTH(*(coap_option * )opt->data),
\r
256 COAP_OPTION_DATA(*(coap_option * )opt->data));
\r
258 OIC_LOG(DEBUG, TAG, "CACreatePDUforRequest OUT");
\r
262 void CAParseURI(const char *uriInfo, coap_list_t **optlist)
\r
264 OIC_LOG(DEBUG, TAG, "CAParseURI IN");
\r
266 unsigned char portbuf[2];
\r
267 unsigned char _buf[CA_BUFSIZE];
\r
268 unsigned char *buf = _buf;
\r
273 OIC_LOG_V(DEBUG, TAG, "url : %s", uriInfo);
\r
275 /* split arg into Uri-* options */
\r
276 coap_split_uri((unsigned char *) uriInfo, strlen(uriInfo), &uri);
\r
278 if (uri.port != COAP_DEFAULT_PORT)
\r
280 coap_insert(optlist,
\r
281 CACreateNewOptionNode(COAP_OPTION_URI_PORT,
\r
282 coap_encode_var_bytes(portbuf, uri.port), portbuf),
\r
286 if (uri.path.length)
\r
288 buflen = CA_BUFSIZE;
\r
289 res = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
\r
293 coap_insert(optlist,
\r
294 CACreateNewOptionNode(COAP_OPTION_URI_PATH, COAP_OPT_LENGTH(buf),
\r
295 COAP_OPT_VALUE(buf)), CAOrderOpts);
\r
296 buf += COAP_OPT_SIZE(buf);
\r
300 if (uri.query.length)
\r
302 buflen = CA_BUFSIZE;
\r
304 res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
\r
308 coap_insert(optlist,
\r
309 CACreateNewOptionNode(COAP_OPTION_URI_QUERY, COAP_OPT_LENGTH(buf),
\r
310 COAP_OPT_VALUE(buf)), CAOrderOpts);
\r
312 buf += COAP_OPT_SIZE(buf);
\r
315 OIC_LOG(DEBUG, TAG, "CAParseURI OUT");
\r
318 void CAParseHeadOption(const uint32_t code, const CAInfo_t info, coap_list_t **optlist)
\r
320 OIC_LOG(DEBUG, TAG, "CAParseHeadOption IN");
\r
321 OIC_LOG_V(DEBUG, TAG, "start parse Head Option : %d", info.numOptions);
\r
324 for (i = 0; i < info.numOptions; i++)
\r
326 uint32_t id = info.options[i].optionID;
\r
327 if (COAP_OPTION_URI_PATH == id || COAP_OPTION_URI_QUERY == id)
\r
329 OIC_LOG_V(DEBUG, TAG, "it is not Header Option : %d", id);
\r
333 OIC_LOG_V(DEBUG, TAG, "Head Option ID: %d", info.options[i].optionID);
\r
334 OIC_LOG_V(DEBUG, TAG, "Head Option data: %s", info.options[i].optionData);
\r
335 OIC_LOG_V(DEBUG, TAG, "Head Option length: %d", info.options[i].optionLength);
\r
337 coap_insert(optlist,
\r
338 CACreateNewOptionNode(info.options[i].optionID,
\r
339 info.options[i].optionLength,
\r
340 info.options[i].optionData), CAOrderOpts);
\r
343 OIC_LOG(DEBUG, TAG, "CAParseHeadOption OUT");
\r
346 coap_list_t *CACreateNewOptionNode(const uint16_t key, const uint32_t length,
\r
347 const uint8_t *data)
\r
349 OIC_LOG(DEBUG, TAG, "CACreateNewOptionNode IN");
\r
350 coap_option *option;
\r
353 option = coap_malloc(sizeof(coap_option) + length + 1);
\r
356 OIC_LOG(DEBUG, TAG, "Out of memory");
\r
359 memset(option, 0, sizeof(coap_option) + length + 1);
\r
361 COAP_OPTION_KEY(*option) = key;
\r
362 COAP_OPTION_LENGTH(*option) = length;
\r
363 memcpy(COAP_OPTION_DATA(*option), data, length);
\r
365 /* we can pass NULL here as delete function since option is released automatically */
\r
366 node = coap_new_listnode(option, NULL);
\r
370 OIC_LOG(DEBUG, TAG, "coap_new_listnode returns NULL");
\r
374 //coap_free(option);
\r
375 OIC_LOG(DEBUG, TAG, "CACreateNewOptionNode OUT");
\r
379 int CAOrderOpts(void *a, void *b)
\r
381 OIC_LOG(DEBUG, TAG, "CAOrderOpts IN");
\r
384 return a < b ? -1 : 1;
\r
387 if (COAP_OPTION_KEY(*(coap_option *)a) < COAP_OPTION_KEY(*(coap_option * )b))
\r
391 OIC_LOG(DEBUG, TAG, "CAOrderOpts OUT");
\r
392 return COAP_OPTION_KEY(*(coap_option *)a) == COAP_OPTION_KEY(*(coap_option * )b);
\r
395 uint32_t CAGetOptionCount(coap_opt_iterator_t opt_iter)
\r
397 OIC_LOG(DEBUG, TAG, "CAGetOptionCount IN");
\r
398 uint32_t count = 0;
\r
399 coap_opt_t *option;
\r
401 while ((option = coap_option_next(&opt_iter)))
\r
403 if (COAP_OPTION_URI_PATH == opt_iter.type || COAP_OPTION_URI_QUERY == opt_iter.type)
\r
412 OIC_LOG(DEBUG, TAG, "CAGetOptionCount OUT");
\r
416 void CAGetRequestPDUInfo(const coap_pdu_t *pdu, uint32_t *outCode, CAInfo_t *outInfo,
\r
419 OIC_LOG(DEBUG, TAG, "CAGetRequestPDUInfo IN");
\r
420 char buf[COAP_MAX_PDU_SIZE]; /* need some space for output creation */
\r
421 uint32_t encode = 0;
\r
422 coap_opt_iterator_t opt_iter;
\r
423 coap_opt_t *option;
\r
424 char optionResult[CA_MAX_URI_LENGTH] =
\r
426 uint32_t count = 0, idx = 0;
\r
427 uint32_t optionLength = 0;
\r
428 uint32_t isfirstsetflag = 0;
\r
430 coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL);
\r
432 memset(optionResult, 0, sizeof(optionResult));
\r
435 (*outCode) = (uint32_t) pdu->hdr->code;
\r
437 // init HeaderOption list
\r
438 count = CAGetOptionCount(opt_iter);
\r
440 memset(outInfo, 0, sizeof(CAInfo_t));
\r
441 outInfo->numOptions = count;
\r
443 outInfo->type = pdu->hdr->type;
\r
446 outInfo->messageId = ntohs(pdu->hdr->id);
\r
450 outInfo->options = (CAHeaderOption_t *) OICMalloc(sizeof(CAHeaderOption_t) * count);
\r
451 if (outInfo->options == NULL)
\r
453 OIC_LOG(DEBUG, TAG, "CAGetRequestPDUInfo, Memory allocation failed !");
\r
456 memset(outInfo->options, 0, sizeof(CAHeaderOption_t) * count);
\r
459 while ((option = coap_option_next(&opt_iter)))
\r
462 if (CAGetOptionData((uint8_t *)(COAP_OPT_VALUE(option)),
\r
463 COAP_OPT_LENGTH(option), (uint8_t *)buf, sizeof(buf),
\r
466 OIC_LOG_V(DEBUG, TAG, "COAP URI element : %s", buf);
\r
467 if (COAP_OPTION_URI_PATH == opt_iter.type || COAP_OPTION_URI_QUERY == opt_iter.type)
\r
469 if (0 == isfirstsetflag)
\r
471 isfirstsetflag = 1;
\r
472 memcpy(optionResult + optionLength, "/", 1);
\r
474 memcpy(optionResult + optionLength, buf, strlen((const char *) buf));
\r
475 optionLength += strlen((const char *) buf);
\r
479 if (COAP_OPTION_URI_PATH == opt_iter.type)
\r
481 memcpy(optionResult + optionLength, "/", 1);
\r
484 else if (COAP_OPTION_URI_QUERY == opt_iter.type)
\r
486 memcpy(optionResult + optionLength, "?", 1);
\r
489 memcpy(optionResult + optionLength, buf, strlen((const char *) buf));
\r
490 optionLength += strlen((const char *) buf);
\r
497 uint32_t length = (uint32_t) strlen((const char *) buf);
\r
499 if (length <= CA_MAX_HEADER_OPTION_DATA_LENGTH)
\r
501 outInfo->options[idx].optionID = opt_iter.type;
\r
502 outInfo->options[idx].optionLength = length;
\r
503 outInfo->options[idx].protocolID = CA_COAP_ID;
\r
504 memcpy(outInfo->options[idx].optionData, buf, length);
\r
513 if (pdu->hdr->token_length > 0)
\r
515 OIC_LOG(DEBUG, TAG, "inside pdu->hdr->token_length");
\r
516 outInfo->token = (char *) OICMalloc(CA_MAX_TOKEN_LEN + 1);
\r
517 if (outInfo->token == NULL)
\r
519 OIC_LOG(DEBUG, TAG, "CAGetRequestPDUInfo, Memory allocation failed !");
\r
520 OICFree(outInfo->options);
\r
523 memset(outInfo->token, 0, CA_MAX_TOKEN_LEN + 1);
\r
524 memcpy(outInfo->token, pdu->hdr->token, CA_MAX_TOKEN_LEN);
\r
527 // set payload data
\r
528 if (NULL != pdu->data)
\r
530 OIC_LOG(DEBUG, TAG, "inside pdu->data");
\r
531 outInfo->payload = (char *) OICMalloc(strlen((const char *) pdu->data) + 1);
\r
532 if (outInfo->payload == NULL)
\r
534 OIC_LOG(DEBUG, TAG, "CAGetRequestPDUInfo, Memory allocation failed !");
\r
535 OICFree(outInfo->options);
\r
536 OICFree(outInfo->token);
\r
539 memcpy(outInfo->payload, pdu->data, strlen((const char *) pdu->data) + 1);
\r
543 memcpy(outUri, optionResult, strlen(optionResult));
\r
544 OIC_LOG_V(DEBUG, TAG, "made URL : %s\n", optionResult);
\r
545 OIC_LOG(DEBUG, TAG, "CAGetRequestPDUInfo OUT");
\r
549 CAResult_t CAGenerateTokenInternal(CAToken_t *token)
\r
551 OIC_LOG(DEBUG, TAG, "CAGenerateTokenInternal IN");
\r
554 return CA_STATUS_FAILED;
\r
557 // memory allocation
\r
558 char *temp = (char *) OICMalloc(sizeof(char) * (CA_MAX_TOKEN_LEN + 1));
\r
561 OIC_LOG(DEBUG, TAG, "CAGenerateTokenInternal, Memory allocation failed !");
\r
562 return CA_MEMORY_ALLOC_FAILED;
\r
564 memset(temp, 0, sizeof(char) * (CA_MAX_TOKEN_LEN + 1));
\r
571 OIC_LOG(DEBUG, TAG, "Failed to Create Seed!");
\r
574 return CA_STATUS_FAILED;
\r
581 for (index = 0; index < CA_MAX_TOKEN_LEN; index++)
\r
583 // use valid characters
\r
584 temp[index] = (rand() % 94 + 33) & 0xFF;
\r
587 temp[index] = '\0';
\r
591 OIC_LOG_V(DEBUG, TAG, "generate the token(%s)!!", *token);
\r
592 OIC_LOG(DEBUG, TAG, "CAGenerateTokenInternal OUT");
\r
593 return CA_STATUS_OK;
\r
596 void CADestroyTokenInternal(CAToken_t token)
\r
598 OIC_LOG(DEBUG, TAG, "CADestroyTokenInternal IN");
\r
601 OIC_LOG_V(DEBUG, TAG, "destroy the token(%s)!!", token);
\r
605 OIC_LOG(DEBUG, TAG, "CADestroyTokenInternal OUT");
\r
608 void CADeinitialize(CAInfo_t *info)
\r
610 OIC_LOG(DEBUG, TAG, "CADeinitialize IN");
\r
614 if (NULL != info->options)
\r
616 OIC_LOG(DEBUG, TAG, "free options in CAInfo");
\r
617 OICFree(info->options);
\r
620 if (NULL != info->token)
\r
622 OIC_LOG(DEBUG, TAG, "free token in CAInfo");
\r
623 OICFree(info->token);
\r
626 if (NULL != info->payload)
\r
628 OIC_LOG(DEBUG, TAG, "free payload in CAInfo");
\r
629 OICFree(info->payload);
\r
632 OIC_LOG(DEBUG, TAG, "CADeinitialize OUT");
\r
635 uint32_t CAGetOptionData(const uint8_t *data, uint32_t len, uint8_t *result,
\r
636 uint32_t buflen, uint32_t encode_always)
\r
638 const unsigned char hex[] = "0123456789ABCDEF";
\r
640 assert(data || len == 0);
\r
642 if (buflen == 0 || len == 0)
\r
652 if (!encode_always)
\r
661 if (cnt + 4 < buflen)
\r
665 *result++ = hex[(*data & 0xf0) >> 4];
\r
666 *result++ = hex[*data & 0x0f];
\r
681 CAMessageType_t CAGetMessageTypeFromPduBinaryData(const void *pdu, uint32_t size)
\r
683 // pdu minimum size is 4 byte.
\r
685 return CA_MSG_NONCONFIRM;
\r
687 coap_hdr_t *hdr = (coap_hdr_t *) pdu;
\r
689 return (CAMessageType_t) hdr->type;
\r
692 uint16_t CAGetMessageIdFromPduBinaryData(const void *pdu, uint32_t size)
\r
694 // pdu minimum size is 4 byte.
\r
698 coap_hdr_t *hdr = (coap_hdr_t *) pdu;
\r
700 return ntohs(hdr->id);
\r