Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: C027_Support mbed-dev
Fork of C027_SupportTest_coap by
coap_msg.cpp
00001 /* 00002 * Copyright (c) 2015 Keith Cullen. 00003 * All Rights Reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. The name of the author may not be used to endorse or promote products 00014 * derived from this software without specific prior written permission. 00015 * 00016 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR 00017 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00018 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 00019 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00020 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00021 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 00022 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 00023 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00024 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 00025 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 */ 00027 00028 /** 00029 * @file coap_msg.c 00030 * 00031 * @brief Source file for the FreeCoAP message parser/formatter library 00032 */ 00033 00034 #include <stdlib.h> 00035 #include <string.h> 00036 #include <stdint.h> 00037 #include <time.h> 00038 #include <errno.h> 00039 #include "coap_msg.h" 00040 #include "coap_client.h" 00041 00042 #define coap_msg_op_list_get_first(list) ((list)->first) /**< Get the first option from an option linked-list */ 00043 #define coap_msg_op_list_get_last(list) ((list)->last) /**< Get the last option in an option linked-list */ 00044 #define coap_msg_op_list_is_empty(list) ((list)->first == NULL) /**< Indicate whether or not an option linked-list is empty */ 00045 00046 static int coap_msg_rand_init = 0; /**< Indicates whether or not the random number generator has been initialised */ 00047 00048 void coap_msg_gen_rand_str(char *buf, size_t len) 00049 { 00050 size_t i = 0; 00051 00052 if (!coap_msg_rand_init) 00053 { 00054 srand(time(NULL)); 00055 coap_msg_rand_init = 1; 00056 } 00057 for (i = 0; i < len; i++) 00058 { 00059 buf[i] = rand() & 0x000000ff; 00060 } 00061 } 00062 00063 int coap_msg_op_num_is_recognized(unsigned num) 00064 { 00065 switch (num) 00066 { 00067 case COAP_MSG_IF_MATCH: 00068 case COAP_MSG_URI_HOST: 00069 case COAP_MSG_ETAG: 00070 case COAP_MSG_IF_NONE_MATCH: 00071 case COAP_MSG_URI_PORT: 00072 case COAP_MSG_LOCATION_PATH: 00073 case COAP_MSG_URI_PATH: 00074 case COAP_MSG_CONTENT_FORMAT: 00075 case COAP_MSG_MAX_AGE: 00076 case COAP_MSG_URI_QUERY: 00077 case COAP_MSG_ACCEPT: 00078 case COAP_MSG_LOCATION_QUERY: 00079 case COAP_MSG_PROXY_URI: 00080 case COAP_MSG_PROXY_SCHEME: 00081 case COAP_MSG_SIZE1: 00082 return 1; 00083 } 00084 return 0; 00085 } 00086 00087 /** 00088 * @brief Allocate an option structure 00089 * 00090 * @param[in] num Option number 00091 * @param[in] len Option length 00092 * @param[in] val Pointer to the option value 00093 * 00094 * @returns Pointer to the option structure 00095 * @retval NULL Out-of-memory 00096 */ 00097 static coap_msg_op_t *coap_msg_op_new(unsigned num, unsigned len, const char *val) 00098 { 00099 coap_msg_op_t *op = NULL; 00100 00101 op = (coap_msg_op_t *)malloc(sizeof(coap_msg_op_t)); 00102 if (op == NULL) 00103 { 00104 return NULL; 00105 } 00106 op->num = num; 00107 op->len = len; 00108 op->val = (char *)malloc(len); 00109 if (op->val == NULL) 00110 { 00111 free(op); 00112 return NULL; 00113 } 00114 memcpy(op->val, val, len); 00115 op->next = NULL; 00116 return op; 00117 } 00118 00119 /** 00120 * @brief Free an option structure that was allocated by coap_msg_op_new 00121 * 00122 * @param[in,out] op Pointer to the option structure 00123 */ 00124 static void coap_msg_op_delete(coap_msg_op_t *op) 00125 { 00126 free(op->val); 00127 free(op); 00128 } 00129 00130 /** 00131 * @brief Initialise an option linked-list structure 00132 * 00133 * @param[out] list Pointer to an option linked-list structure 00134 */ 00135 static void coap_msg_op_list_create(coap_msg_op_list_t *list) 00136 { 00137 memset(list, 0, sizeof(coap_msg_op_list_t)); 00138 } 00139 00140 /** 00141 * @brief Deinitialise an option linked-list structure 00142 * 00143 * @param[in,out] list Pointer to an option linked-list structure 00144 */ 00145 static void coap_msg_op_list_destroy(coap_msg_op_list_t *list) 00146 { 00147 coap_msg_op_t *prev = NULL; 00148 coap_msg_op_t *op = NULL; 00149 00150 op = list->first; 00151 while (op != NULL) 00152 { 00153 prev = op; 00154 op = op->next; 00155 coap_msg_op_delete(prev); 00156 } 00157 memset(list, 0, sizeof(coap_msg_op_list_t)); 00158 } 00159 00160 /** 00161 * @brief Allocate an option structure and add it to the end of an option linked-list structure 00162 * 00163 * @param[in,out] list Pointer to an option linked-list structure 00164 * @param[in] num Option number 00165 * @param[in] len Option length 00166 * @param[in] val Pointer to a buffer containing the option value 00167 * 00168 * @returns Operation status 00169 * @retval 0 Success 00170 * @retval <0 Error 00171 */ 00172 static int coap_msg_op_list_add_last(coap_msg_op_list_t *list, unsigned num, unsigned len, const char *val) 00173 { 00174 coap_msg_op_t *op = NULL; 00175 00176 op = coap_msg_op_new(num, len, val); 00177 if (op == NULL) 00178 { 00179 return -ENOMEM; 00180 } 00181 if (list->first == NULL) 00182 { 00183 list->first = op; 00184 list->last = op; 00185 } 00186 else 00187 { 00188 list->last->next = op; 00189 list->last = op; 00190 } 00191 return 0; 00192 } 00193 00194 /** 00195 * @brief Allocate an option structure and add it to an option linked-list structure 00196 * 00197 * The option is added to the list at a position determined by the option number. 00198 * 00199 * @param[in,out] list Pointer to an option linked-list structure 00200 * @param[in] num Option number 00201 * @param[in] len Option length 00202 * @param[in] val Pointer to a buffer containing the option value 00203 * 00204 * @returns Operation status 00205 * @retval 0 Success 00206 * @retval <0 Error 00207 */ 00208 static int coap_msg_op_list_add(coap_msg_op_list_t *list, unsigned num, unsigned len, const char *val) 00209 { 00210 coap_msg_op_t *prev = NULL; 00211 coap_msg_op_t *op = NULL; 00212 00213 op = coap_msg_op_new(num, len, val); 00214 if (op == NULL) 00215 { 00216 return -ENOMEM; 00217 } 00218 if (list->first == NULL) 00219 { 00220 /* empty list */ 00221 list->first = op; 00222 list->last = op; 00223 return 0; 00224 } 00225 if (op->num < list->first->num) 00226 { 00227 /* start of the list */ 00228 op->next = list->first; 00229 list->first = op; 00230 return 0; 00231 } 00232 prev = list->first; 00233 while (prev != list->last) 00234 { 00235 /* middle of the list */ 00236 if ((prev->num <= op->num) && (op->num < prev->next->num)) 00237 { 00238 op->next = prev->next; 00239 prev->next = op; 00240 return 0; 00241 } 00242 prev = prev->next; 00243 } 00244 /* end of the list */ 00245 list->last->next = op; 00246 list->last = op; 00247 return 0; 00248 } 00249 00250 void coap_msg_create(coap_msg_t *msg) 00251 { 00252 memset(msg, 0, sizeof(coap_msg_t)); 00253 msg->ver = COAP_MSG_VER; 00254 coap_msg_op_list_create(&msg->op_list); 00255 } 00256 00257 void coap_msg_destroy(coap_msg_t *msg) 00258 { 00259 coap_msg_op_list_destroy(&msg->op_list); 00260 if (msg->payload != NULL) 00261 { 00262 free(msg->payload); 00263 } 00264 memset(msg, 0, sizeof(coap_msg_t)); 00265 } 00266 00267 void coap_msg_reset(coap_msg_t *msg) 00268 { 00269 coap_msg_destroy(msg); 00270 coap_msg_create(msg); 00271 } 00272 00273 /** 00274 * @brief Check a message for correctness 00275 * 00276 * The following checks from RFC7252 are performed: 00277 * 00278 * An Empty message has the Code field set to 0.00. The Token Length 00279 * field MUST be set to 0 and bytes of data MUST NOT be present after 00280 * the Message ID field. If there are any bytes, they MUST be processed 00281 * as a message format error. 00282 * 00283 * The Reset message MUST echo the Message ID of the Confirmable message 00284 * and MUST be Empty. 00285 * 00286 * A Non-confirmable message always carries either a request or response 00287 * and MUST NOT be Empty. 00288 * 00289 * @param[in] msg Pointer to a message structure 00290 * @returns Operation status 00291 * @retval 0 Success 00292 * @retval <0 Error 00293 */ 00294 static int coap_msg_check(coap_msg_t *msg) 00295 { 00296 if ((msg->code_class == 0) && (msg->code_detail == 0)) 00297 { 00298 /* empty message */ 00299 if ((msg->type == COAP_MSG_NON) 00300 || (msg->token_len != 0) 00301 || (!coap_msg_op_list_is_empty(&msg->op_list)) 00302 || (msg->payload_len != 0)) 00303 { 00304 return -EBADMSG; 00305 } 00306 } 00307 else 00308 { 00309 /* non-empty message */ 00310 if (msg->type == COAP_MSG_RST) 00311 { 00312 return -EBADMSG; 00313 } 00314 } 00315 return 0; 00316 } 00317 00318 unsigned coap_msg_check_critical_ops(coap_msg_t *msg) 00319 { 00320 coap_msg_op_t *op = NULL; 00321 unsigned num = 0; 00322 00323 op = coap_msg_get_first_op(msg); 00324 while (op != NULL) 00325 { 00326 num = coap_msg_op_get_num(op); 00327 if ((coap_msg_op_num_is_critical(num)) 00328 && (!coap_msg_op_num_is_recognized(num))) 00329 { 00330 return num; /* fail */ 00331 } 00332 op = coap_msg_op_get_next(op); 00333 } 00334 return 0; /* pass */ 00335 } 00336 00337 unsigned coap_msg_check_unsafe_ops(coap_msg_t *msg) 00338 { 00339 coap_msg_op_t *op = NULL; 00340 unsigned num = 0; 00341 00342 op = coap_msg_get_first_op(msg); 00343 while (op != NULL) 00344 { 00345 num = coap_msg_op_get_num(op); 00346 if ((coap_msg_op_num_is_unsafe(num)) 00347 && (!coap_msg_op_num_is_recognized(num))) 00348 { 00349 return num; /* fail */ 00350 } 00351 op = coap_msg_op_get_next(op); 00352 } 00353 return 0; /* pass */ 00354 } 00355 00356 int coap_msg_parse_type_msg_id(char *buf, size_t len, unsigned *type, unsigned *msg_id) 00357 { 00358 if (len < 4) 00359 { 00360 return -EBADMSG; 00361 } 00362 *type = (buf[0] >> 4) & 0x03; 00363 *msg_id = ntohs(*((uint16_t *)(&buf[2]))); 00364 return 0; 00365 } 00366 00367 /** 00368 * @brief Parse the header in a message 00369 * 00370 * @param[out] msg Pointer to a message structure 00371 * @param[in] buf Pointer to a buffer containing the message 00372 * @param[in] len Length of the buffer 00373 * 00374 * @returns Number of bytes parsed or error code 00375 * @retval >0 Number of bytes parsed 00376 * @retval <0 Error 00377 */ 00378 static int coap_msg_parse_hdr(coap_msg_t *msg, char *buf, size_t len) 00379 { 00380 char *p = buf; 00381 00382 if (len < 4) 00383 { 00384 return -EBADMSG; 00385 } 00386 msg->ver = (p[0] >> 6) & 0x03; 00387 if (msg->ver != COAP_MSG_VER) 00388 { 00389 return -EINVAL; 00390 } 00391 msg->type = (coap_msg_type_t)((p[0] >> 4) & 0x03); 00392 msg->token_len = p[0] & 0x0f; 00393 if (msg->token_len > sizeof(msg->token)) 00394 { 00395 return -EBADMSG; 00396 } 00397 msg->code_detail = p[1] & 0x1f; 00398 msg->code_class = (p[1] >> 5) & 0x07; 00399 if ((msg->code_class != COAP_MSG_REQ) 00400 && (msg->code_class != COAP_MSG_SUCCESS) 00401 && (msg->code_class != COAP_MSG_CLIENT_ERR) 00402 && (msg->code_class != COAP_MSG_SERVER_ERR)) 00403 { 00404 return -EBADMSG; 00405 } 00406 msg->msg_id = ntohs(*((uint16_t *)(&p[2]))); 00407 p += 4; 00408 len -= 4; 00409 return p - buf; 00410 } 00411 00412 /** 00413 * @brief Parse the token in a message 00414 * 00415 * @param[out] msg Pointer to a message structure 00416 * @param[in] buf Pointer to a buffer containing the message 00417 * @param[in] len Length of the buffer 00418 * 00419 * @returns Number of bytes parsed or error code 00420 * @retval >0 Number of bytes parsed 00421 * @retval <0 Error 00422 */ 00423 static int coap_msg_parse_token(coap_msg_t *msg, char *buf, size_t len) 00424 { 00425 if (len < msg->token_len) 00426 { 00427 return -EBADMSG; 00428 } 00429 memcpy(msg->token, buf, msg->token_len); 00430 return msg->token_len; 00431 } 00432 00433 /** 00434 * @brief Parse an option in a message 00435 * 00436 * @param[in,out] msg Pointer to a message structure 00437 * @param[in] buf Pointer to a buffer containing the message 00438 * @param[in] len Length of the buffer 00439 * 00440 * @returns Number of bytes parsed or error code 00441 * @retval >0 Number of bytes parsed 00442 * @retval <0 Error 00443 */ 00444 static int coap_msg_parse_op(coap_msg_t *msg, char *buf, size_t len) 00445 { 00446 coap_msg_op_t *prev = NULL; 00447 unsigned op_delta = 0; 00448 unsigned op_len = 0; 00449 unsigned op_num = 0; 00450 char *p = buf; 00451 int ret = 0; 00452 00453 if (len < 1) 00454 { 00455 return -EBADMSG; 00456 } 00457 op_delta = (p[0] >> 4) & 0x0f; 00458 op_len = p[0] & 0x0f; 00459 if ((op_delta == 15) || (op_len == 15)) 00460 { 00461 return -EBADMSG; 00462 } 00463 p++; 00464 len--; 00465 if (op_delta == 13) 00466 { 00467 if (len < 1) 00468 { 00469 return -EBADMSG; 00470 } 00471 op_delta += p[0]; 00472 p++; 00473 len--; 00474 } 00475 else if (op_delta == 14) 00476 { 00477 if (len < 2) 00478 { 00479 return -EBADMSG; 00480 } 00481 op_delta = 269 + ntohs(*((uint16_t *)(&p[0]))); 00482 p += 2; 00483 len -= 2; 00484 } 00485 if (op_len == 13) 00486 { 00487 if (len < 1) 00488 { 00489 return -EBADMSG; 00490 } 00491 op_len += p[0]; 00492 p++; 00493 len--; 00494 } 00495 else if (op_len == 14) 00496 { 00497 if (len < 2) 00498 { 00499 return -EBADMSG; 00500 } 00501 op_len = 269 + ntohs(*((uint16_t *)(&p[0]))); 00502 p += 2; 00503 len -= 2; 00504 } 00505 if (len < op_len) 00506 { 00507 return -EBADMSG; 00508 } 00509 prev = coap_msg_op_list_get_last(&msg->op_list); 00510 if (prev == NULL) 00511 { 00512 op_num = op_delta; 00513 } 00514 else 00515 { 00516 op_num = coap_msg_op_get_num(prev) + op_delta; 00517 } 00518 ret = coap_msg_op_list_add_last(&msg->op_list, op_num, op_len, p); 00519 if (ret < 0) 00520 { 00521 return ret; 00522 } 00523 p += op_len; 00524 return p - buf; 00525 } 00526 00527 /** 00528 * @brief Parse the options in a message 00529 * 00530 * @param[in,out] msg Pointer to a message structure 00531 * @param[in] buf Pointer to a buffer containing the message 00532 * @param[in] len Length of the buffer 00533 * 00534 * @returns Number of bytes parsed or error code 00535 * @retval >0 Number of bytes parsed 00536 * @retval <0 Error 00537 */ 00538 static int coap_msg_parse_ops(coap_msg_t *msg, char *buf, size_t len) 00539 { 00540 int num = 0; 00541 char *p = buf; 00542 00543 while (1) 00544 { 00545 if (((p[0] & 0xff) == 0xff) || (len == 0)) 00546 { 00547 break; 00548 } 00549 num = coap_msg_parse_op(msg, p, len); 00550 if (num < 0) 00551 { 00552 return num; 00553 } 00554 p += num; 00555 len -= num; 00556 } 00557 return p - buf; 00558 } 00559 00560 /** 00561 * @brief Parse the payload in a message 00562 * 00563 * @param[out] msg Pointer to a message structure 00564 * @param[in] buf Pointer to a buffer containing the message 00565 * @param[in] len Length of the buffer 00566 * 00567 * @returns Number of bytes parsed or error code 00568 * @retval >0 Number of bytes parsed 00569 * @retval <0 Error 00570 */ 00571 static int coap_msg_parse_payload(coap_msg_t *msg, char *buf, size_t len) 00572 { 00573 char *p = buf; 00574 00575 if (len == 0) 00576 { 00577 return 0; 00578 } 00579 if ((p[0] & 0xff) != 0xff) 00580 { 00581 return -EBADMSG; 00582 } 00583 p++; 00584 len--; 00585 if (len == 0) 00586 { 00587 return -EBADMSG; 00588 } 00589 msg->payload = (char *)malloc(len); 00590 if (msg->payload == NULL) 00591 { 00592 return -ENOMEM; 00593 } 00594 memcpy(msg->payload, p, len); 00595 msg->payload_len = len; 00596 p += len; 00597 return p - buf; 00598 } 00599 00600 int coap_msg_parse(coap_msg_t *msg, char *buf, size_t len) 00601 { 00602 int num = 0; 00603 char *p = buf; 00604 00605 coap_msg_reset(msg); 00606 num = coap_msg_parse_hdr(msg, p, len); 00607 if (num < 0) 00608 { 00609 coap_msg_destroy(msg); 00610 return num; 00611 } 00612 p += num; 00613 len -= num; 00614 num = coap_msg_parse_token(msg, p, len); 00615 if (num < 0) 00616 { 00617 coap_msg_destroy(msg); 00618 return num; 00619 } 00620 p += num; 00621 len -= num; 00622 num = coap_msg_parse_ops(msg, p, len); 00623 if (num < 0) 00624 { 00625 coap_msg_destroy(msg); 00626 return num; 00627 } 00628 p += num; 00629 len -= num; 00630 num = coap_msg_parse_payload(msg, p, len); 00631 if (num < 0) 00632 { 00633 coap_msg_destroy(msg); 00634 return num; 00635 } 00636 return coap_msg_check(msg); 00637 } 00638 00639 int coap_msg_set_type(coap_msg_t *msg, unsigned type) 00640 { 00641 if ((type != COAP_MSG_CON) 00642 && (type != COAP_MSG_NON) 00643 && (type != COAP_MSG_ACK) 00644 && (type != COAP_MSG_RST)) 00645 { 00646 return -EINVAL; 00647 } 00648 msg->type = (coap_msg_type_t)type; 00649 return 0; 00650 } 00651 00652 int coap_msg_set_code(coap_msg_t *msg, unsigned code_class, unsigned code_detail) 00653 { 00654 if (code_class > COAP_MSG_MAX_CODE_CLASS) 00655 { 00656 return -EINVAL; 00657 } 00658 if (code_detail > COAP_MSG_MAX_CODE_DETAIL) 00659 { 00660 return -EINVAL; 00661 } 00662 msg->code_class = code_class; 00663 msg->code_detail = code_detail; 00664 return 0; 00665 } 00666 00667 int coap_msg_set_msg_id(coap_msg_t *msg, unsigned msg_id) 00668 { 00669 if (msg_id > COAP_MSG_MAX_MSG_ID) 00670 { 00671 return -EINVAL; 00672 } 00673 msg->msg_id = msg_id; 00674 return 0; 00675 } 00676 00677 int coap_msg_set_token(coap_msg_t *msg, char *buf, size_t len) 00678 { 00679 if (len > COAP_MSG_MAX_TOKEN_LEN) 00680 { 00681 return -EINVAL; 00682 } 00683 memcpy(msg->token, buf, len); 00684 msg->token_len = len; 00685 return 0; 00686 } 00687 00688 int coap_msg_add_op(coap_msg_t *msg, unsigned num, unsigned len, const char *val) 00689 { 00690 return coap_msg_op_list_add(&msg->op_list, num, len, val); 00691 } 00692 00693 int coap_msg_set_payload(coap_msg_t *msg, char *buf, size_t len) 00694 { 00695 msg->payload_len = 0; 00696 if (msg->payload != NULL) 00697 { 00698 free(msg->payload); 00699 msg->payload = NULL; 00700 } 00701 if (len > 0) 00702 { 00703 msg->payload = (char *)malloc(len); 00704 if (msg->payload == NULL) 00705 { 00706 return -ENOMEM; 00707 } 00708 memcpy(msg->payload, buf, len); 00709 msg->payload_len = len; 00710 } 00711 return 0; 00712 } 00713 00714 /** 00715 * @brief Format the header in a message 00716 * 00717 * @param[in] msg Pointer to a message structure 00718 * @param[out] buf Pointer to a buffer to contain the formatted message 00719 * @param[in] len Length of the buffer 00720 * 00721 * @returns Length of the formatted message or error code 00722 * @retval >0 Length of the formatted message 00723 * @retval <0 Error 00724 */ 00725 static int coap_msg_format_hdr(coap_msg_t *msg, char *buf, size_t len) 00726 { 00727 uint16_t msg_id = 0; 00728 00729 if (len < 4) 00730 { 00731 return -ENOSPC; 00732 } 00733 buf[0] = (char)((COAP_MSG_VER << 6) 00734 | ((msg->type & 0x03) << 4) 00735 | (msg->token_len & 0x0f)); 00736 buf[1] = (char)(((msg->code_class & 0x07) << 5) 00737 | (msg->code_detail & 0x1f)); 00738 msg_id = htons(msg->msg_id); 00739 memcpy(&buf[2], &msg_id, 2); 00740 return 4; 00741 } 00742 00743 /** 00744 * @brief Format the token in a message 00745 * 00746 * @param[in] msg Pointer to a message structure 00747 * @param[out] buf Pointer to a buffer to contain the formatted message 00748 * @param[in] len Length of the buffer 00749 * 00750 * @returns Length of the formatted message or error code 00751 * @retval >0 Length of the formatted message 00752 * @retval <0 Error 00753 */ 00754 static int coap_msg_format_token(coap_msg_t *msg, char *buf, size_t len) 00755 { 00756 if (len < msg->token_len) 00757 { 00758 return -ENOSPC; 00759 } 00760 memcpy(buf, msg->token, msg->token_len); 00761 return msg->token_len; 00762 } 00763 00764 /** 00765 * @brief Format an option in a message 00766 * 00767 * @param[in] op Pointer to an option structure 00768 * @param[in] prev_num option number of the previous option 00769 * @param[out] buf Pointer to a buffer to contain the formatted message 00770 * @param[in] len Length of the buffer 00771 * 00772 * @returns Length of the formatted message or error code 00773 * @retval >0 Length of the formatted message 00774 * @retval <0 Error 00775 */ 00776 static int coap_msg_format_op(coap_msg_op_t *op, unsigned prev_num, char *buf, size_t len) 00777 { 00778 unsigned op_delta = 0; 00779 unsigned num = 0; 00780 uint16_t val = 0; 00781 char *p = buf; 00782 00783 op_delta = op->num - prev_num; 00784 num++; 00785 00786 /* option delta */ 00787 if (op_delta >= 269) 00788 { 00789 num += 2; 00790 } 00791 else if (op_delta >= 13) 00792 { 00793 num += 1; 00794 } 00795 00796 /* option length */ 00797 if (op->len >= 269) 00798 { 00799 num += 2; 00800 } 00801 else if (op->num >= 13) 00802 { 00803 num += 1; 00804 } 00805 00806 /* option value */ 00807 num += op->len; 00808 if (num > len) 00809 { 00810 return -ENOSPC; 00811 } 00812 00813 /* option delta */ 00814 if (op_delta >= 269) 00815 { 00816 p[0] = 14 << 4; 00817 } 00818 else if (op_delta >= 13) 00819 { 00820 p[0] = 13 << 4; 00821 } 00822 else 00823 { 00824 p[0] = op_delta << 4; 00825 } 00826 00827 /* option length */ 00828 if (op->len >= 269) 00829 { 00830 p[0] |= 14; 00831 } 00832 else if (op->len >= 13) 00833 { 00834 p[0] |= 13; 00835 } 00836 else 00837 { 00838 p[0] |= op->len; 00839 } 00840 p++; 00841 len--; 00842 00843 /* option delta extended */ 00844 if (op_delta >= 269) 00845 { 00846 val = htons(op_delta - 269); 00847 memcpy(p, &val, 2); 00848 p += 2; 00849 len -= 2; 00850 } 00851 else if (op_delta >= 13) 00852 { 00853 p[0] = op_delta - 13; 00854 p++; 00855 len--; 00856 } 00857 00858 /* option length extended */ 00859 if (op->len >= 269) 00860 { 00861 val = htons(op->len - 269); 00862 memcpy(p, &val, 2); 00863 p += 2; 00864 len -= 2; 00865 } 00866 else if (op->len >= 13) 00867 { 00868 p[0] = op->len - 13; 00869 p++; 00870 len--; 00871 } 00872 00873 /* option value */ 00874 memcpy(p, op->val, op->len); 00875 p += op->len; 00876 00877 return p - buf; 00878 } 00879 00880 /** 00881 * @brief Format the options in a message 00882 * 00883 * @param[in] msg Pointer to a message structure 00884 * @param[out] buf Pointer to a buffer to contain the formatted message 00885 * @param[in] len Length of the buffer 00886 * 00887 * @returns Length of the formatted message or error code 00888 * @retval >0 Length of the formatted message 00889 * @retval <0 Error 00890 */ 00891 static int coap_msg_format_ops(coap_msg_t *msg, char *buf, size_t len) 00892 { 00893 coap_msg_op_t *op = NULL; 00894 unsigned prev_num = 0; 00895 int num = 0; 00896 char *p = buf; 00897 00898 op = coap_msg_op_list_get_first(&msg->op_list); 00899 while (op != NULL) 00900 { 00901 num = coap_msg_format_op(op, prev_num, p, len); 00902 if (num < 0) 00903 { 00904 return num; 00905 } 00906 p += num; 00907 len -= num; 00908 prev_num = coap_msg_op_get_num(op); 00909 op = coap_msg_op_get_next(op); 00910 } 00911 return p - buf; 00912 } 00913 00914 /** 00915 * @brief Format the payload in a message 00916 * 00917 * @param[in] msg Pointer to a message structure 00918 * @param[out] buf Pointer to a buffer to contain the formatted message 00919 * @param[in] len Length of the buffer 00920 * 00921 * @returns Length of the formatted message or error code 00922 * @retval >0 Length of the formatted message 00923 * @retval <0 Error 00924 */ 00925 static int coap_msg_format_payload(coap_msg_t *msg, char *buf, size_t len) 00926 { 00927 if (msg->payload_len == 0) 00928 { 00929 return 0; 00930 } 00931 if (msg->payload_len + 1 > len) 00932 { 00933 return -ENOSPC; 00934 } 00935 buf[0] = 0xff; 00936 memcpy(&buf[1], msg->payload, msg->payload_len); 00937 return msg->payload_len + 1; 00938 } 00939 00940 int coap_msg_format(coap_msg_t *msg, char *buf, size_t len) 00941 { 00942 int num = 0; 00943 char *p = buf; 00944 int ret = 0; 00945 00946 ret = coap_msg_check(msg); 00947 if (ret != 0) 00948 { 00949 return ret; 00950 } 00951 num = coap_msg_format_hdr(msg, p, len); 00952 if (num < 0) 00953 { 00954 return num; 00955 } 00956 p += num; 00957 len -= num; 00958 num = coap_msg_format_token(msg, p, len); 00959 if (num < 0) 00960 { 00961 return num; 00962 } 00963 p += num; 00964 len -= num; 00965 num = coap_msg_format_ops(msg, p, len); 00966 if (num < 0) 00967 { 00968 return num; 00969 } 00970 p += num; 00971 len -= num; 00972 num = coap_msg_format_payload(msg, p, len); 00973 if (num < 0) 00974 { 00975 return num; 00976 } 00977 p += num; 00978 return p - buf; 00979 } 00980 00981 int coap_msg_copy(coap_msg_t *dst, coap_msg_t *src) 00982 { 00983 coap_msg_op_t *op = NULL; 00984 int ret = 0; 00985 00986 dst->ver = src->ver; 00987 ret = coap_msg_set_type(dst, coap_msg_get_type(src)); 00988 if (ret < 0) 00989 { 00990 return ret; 00991 } 00992 ret = coap_msg_set_code(dst, coap_msg_get_code_class(src), coap_msg_get_code_detail(src)); 00993 if (ret < 0) 00994 { 00995 return ret; 00996 } 00997 ret = coap_msg_set_msg_id(dst, coap_msg_get_msg_id(src)); 00998 if (ret < 0) 00999 { 01000 return ret; 01001 } 01002 ret = coap_msg_set_token(dst, coap_msg_get_token(src), coap_msg_get_token_len(src)); 01003 if (ret < 0) 01004 { 01005 return ret; 01006 } 01007 op = coap_msg_get_first_op(src); 01008 while (op != NULL) 01009 { 01010 ret = coap_msg_add_op(dst, coap_msg_op_get_num(op), coap_msg_op_get_len(op), coap_msg_op_get_val(op)); 01011 if (ret < 0) 01012 { 01013 return ret; 01014 } 01015 op = coap_msg_op_get_next(op); 01016 } 01017 ret = coap_msg_set_payload(dst, coap_msg_get_payload(src), coap_msg_get_payload_len(src)); 01018 if (ret < 0) 01019 { 01020 return ret; 01021 } 01022 return 0; 01023 } 01024
Generated on Sun Jul 17 2022 00:59:13 by
