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