h
Dependencies: C027_Support mbed-dev
Fork of C027_SupportTest_coapp by
Coap/coap_msg.cpp@40:da5f84f19a24, 2017-08-25 (annotated)
- Committer:
- iftaziz
- Date:
- Fri Aug 25 10:40:13 2017 +0000
- Revision:
- 40:da5f84f19a24
- Parent:
- 39:4f3f7463e55f
iazi
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ranaumarnaeem | 34:d6ce8f961b8b | 1 | /* |
ranaumarnaeem | 34:d6ce8f961b8b | 2 | * Copyright (c) 2015 Keith Cullen. |
ranaumarnaeem | 34:d6ce8f961b8b | 3 | * All Rights Reserved. |
ranaumarnaeem | 34:d6ce8f961b8b | 4 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 5 | * Redistribution and use in source and binary forms, with or without |
ranaumarnaeem | 34:d6ce8f961b8b | 6 | * modification, are permitted provided that the following conditions |
ranaumarnaeem | 34:d6ce8f961b8b | 7 | * are met: |
ranaumarnaeem | 34:d6ce8f961b8b | 8 | * 1. Redistributions of source code must retain the above copyright |
ranaumarnaeem | 34:d6ce8f961b8b | 9 | * notice, this list of conditions and the following disclaimer. |
ranaumarnaeem | 34:d6ce8f961b8b | 10 | * 2. Redistributions in binary form must reproduce the above copyright |
ranaumarnaeem | 34:d6ce8f961b8b | 11 | * notice, this list of conditions and the following disclaimer in the |
ranaumarnaeem | 34:d6ce8f961b8b | 12 | * documentation and/or other materials provided with the distribution. |
ranaumarnaeem | 34:d6ce8f961b8b | 13 | * 3. The name of the author may not be used to endorse or promote products |
ranaumarnaeem | 34:d6ce8f961b8b | 14 | * derived from this software without specific prior written permission. |
ranaumarnaeem | 34:d6ce8f961b8b | 15 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR |
ranaumarnaeem | 34:d6ce8f961b8b | 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
ranaumarnaeem | 34:d6ce8f961b8b | 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
ranaumarnaeem | 34:d6ce8f961b8b | 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
ranaumarnaeem | 34:d6ce8f961b8b | 20 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
ranaumarnaeem | 34:d6ce8f961b8b | 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
ranaumarnaeem | 34:d6ce8f961b8b | 22 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
ranaumarnaeem | 34:d6ce8f961b8b | 23 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
ranaumarnaeem | 34:d6ce8f961b8b | 24 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
ranaumarnaeem | 34:d6ce8f961b8b | 25 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
ranaumarnaeem | 34:d6ce8f961b8b | 26 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 27 | |
ranaumarnaeem | 34:d6ce8f961b8b | 28 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 29 | * @file coap_msg.c |
ranaumarnaeem | 34:d6ce8f961b8b | 30 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 31 | * @brief Source file for the FreeCoAP message parser/formatter library |
ranaumarnaeem | 34:d6ce8f961b8b | 32 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 33 | |
ranaumarnaeem | 34:d6ce8f961b8b | 34 | #include <stdlib.h> |
ranaumarnaeem | 34:d6ce8f961b8b | 35 | #include <string.h> |
ranaumarnaeem | 34:d6ce8f961b8b | 36 | #include <stdint.h> |
ranaumarnaeem | 34:d6ce8f961b8b | 37 | #include <time.h> |
ranaumarnaeem | 34:d6ce8f961b8b | 38 | #include <errno.h> |
ranaumarnaeem | 34:d6ce8f961b8b | 39 | #include "coap_msg.h" |
ranaumarnaeem | 34:d6ce8f961b8b | 40 | #include "coap_client.h" |
ranaumarnaeem | 34:d6ce8f961b8b | 41 | |
ranaumarnaeem | 34:d6ce8f961b8b | 42 | #define coap_msg_op_list_get_first(list) ((list)->first) /**< Get the first option from an option linked-list */ |
ranaumarnaeem | 34:d6ce8f961b8b | 43 | #define coap_msg_op_list_get_last(list) ((list)->last) /**< Get the last option in an option linked-list */ |
ranaumarnaeem | 34:d6ce8f961b8b | 44 | #define coap_msg_op_list_is_empty(list) ((list)->first == NULL) /**< Indicate whether or not an option linked-list is empty */ |
ranaumarnaeem | 34:d6ce8f961b8b | 45 | |
ranaumarnaeem | 34:d6ce8f961b8b | 46 | static int coap_msg_rand_init = 0; /**< Indicates whether or not the random number generator has been initialised */ |
ranaumarnaeem | 34:d6ce8f961b8b | 47 | |
ranaumarnaeem | 34:d6ce8f961b8b | 48 | void coap_msg_gen_rand_str(char *buf, size_t len) |
ranaumarnaeem | 34:d6ce8f961b8b | 49 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 50 | size_t i = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 51 | |
ranaumarnaeem | 34:d6ce8f961b8b | 52 | if (!coap_msg_rand_init) |
ranaumarnaeem | 34:d6ce8f961b8b | 53 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 54 | srand(time(NULL)); |
ranaumarnaeem | 34:d6ce8f961b8b | 55 | coap_msg_rand_init = 1; |
ranaumarnaeem | 34:d6ce8f961b8b | 56 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 57 | for (i = 0; i < len; i++) |
ranaumarnaeem | 34:d6ce8f961b8b | 58 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 59 | buf[i] = rand() & 0x000000ff; |
ranaumarnaeem | 34:d6ce8f961b8b | 60 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 61 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 62 | |
ranaumarnaeem | 34:d6ce8f961b8b | 63 | int coap_msg_op_num_is_recognized(unsigned num) |
ranaumarnaeem | 34:d6ce8f961b8b | 64 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 65 | switch (num) |
ranaumarnaeem | 34:d6ce8f961b8b | 66 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 67 | case COAP_MSG_IF_MATCH: |
ranaumarnaeem | 34:d6ce8f961b8b | 68 | case COAP_MSG_URI_HOST: |
ranaumarnaeem | 34:d6ce8f961b8b | 69 | case COAP_MSG_ETAG: |
ranaumarnaeem | 34:d6ce8f961b8b | 70 | case COAP_MSG_IF_NONE_MATCH: |
ranaumarnaeem | 34:d6ce8f961b8b | 71 | case COAP_MSG_URI_PORT: |
ranaumarnaeem | 34:d6ce8f961b8b | 72 | case COAP_MSG_LOCATION_PATH: |
ranaumarnaeem | 34:d6ce8f961b8b | 73 | case COAP_MSG_URI_PATH: |
ranaumarnaeem | 34:d6ce8f961b8b | 74 | case COAP_MSG_CONTENT_FORMAT: |
ranaumarnaeem | 34:d6ce8f961b8b | 75 | case COAP_MSG_MAX_AGE: |
ranaumarnaeem | 34:d6ce8f961b8b | 76 | case COAP_MSG_URI_QUERY: |
ranaumarnaeem | 34:d6ce8f961b8b | 77 | case COAP_MSG_ACCEPT: |
ranaumarnaeem | 34:d6ce8f961b8b | 78 | case COAP_MSG_LOCATION_QUERY: |
ranaumarnaeem | 34:d6ce8f961b8b | 79 | case COAP_MSG_PROXY_URI: |
ranaumarnaeem | 34:d6ce8f961b8b | 80 | case COAP_MSG_PROXY_SCHEME: |
ranaumarnaeem | 34:d6ce8f961b8b | 81 | case COAP_MSG_SIZE1: |
ranaumarnaeem | 34:d6ce8f961b8b | 82 | return 1; |
ranaumarnaeem | 34:d6ce8f961b8b | 83 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 84 | return 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 85 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 86 | |
ranaumarnaeem | 34:d6ce8f961b8b | 87 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 88 | * @brief Allocate an option structure |
ranaumarnaeem | 34:d6ce8f961b8b | 89 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 90 | * @param[in] num Option number |
ranaumarnaeem | 34:d6ce8f961b8b | 91 | * @param[in] len Option length |
ranaumarnaeem | 34:d6ce8f961b8b | 92 | * @param[in] val Pointer to the option value |
ranaumarnaeem | 34:d6ce8f961b8b | 93 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 94 | * @returns Pointer to the option structure |
ranaumarnaeem | 34:d6ce8f961b8b | 95 | * @retval NULL Out-of-memory |
ranaumarnaeem | 34:d6ce8f961b8b | 96 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 97 | static coap_msg_op_t *coap_msg_op_new(unsigned num, unsigned len, const char *val) |
ranaumarnaeem | 34:d6ce8f961b8b | 98 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 99 | coap_msg_op_t *op = NULL; |
ranaumarnaeem | 34:d6ce8f961b8b | 100 | |
ranaumarnaeem | 34:d6ce8f961b8b | 101 | op = (coap_msg_op_t *)malloc(sizeof(coap_msg_op_t)); |
ranaumarnaeem | 34:d6ce8f961b8b | 102 | if (op == NULL) |
ranaumarnaeem | 34:d6ce8f961b8b | 103 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 104 | return NULL; |
ranaumarnaeem | 34:d6ce8f961b8b | 105 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 106 | op->num = num; |
ranaumarnaeem | 34:d6ce8f961b8b | 107 | op->len = len; |
ranaumarnaeem | 34:d6ce8f961b8b | 108 | op->val = (char *)malloc(len); |
ranaumarnaeem | 34:d6ce8f961b8b | 109 | if (op->val == NULL) |
ranaumarnaeem | 34:d6ce8f961b8b | 110 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 111 | free(op); |
ranaumarnaeem | 34:d6ce8f961b8b | 112 | return NULL; |
ranaumarnaeem | 34:d6ce8f961b8b | 113 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 114 | memcpy(op->val, val, len); |
ranaumarnaeem | 34:d6ce8f961b8b | 115 | op->next = NULL; |
ranaumarnaeem | 34:d6ce8f961b8b | 116 | return op; |
ranaumarnaeem | 34:d6ce8f961b8b | 117 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 118 | |
ranaumarnaeem | 34:d6ce8f961b8b | 119 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 120 | * @brief Free an option structure that was allocated by coap_msg_op_new |
ranaumarnaeem | 34:d6ce8f961b8b | 121 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 122 | * @param[in,out] op Pointer to the option structure |
ranaumarnaeem | 34:d6ce8f961b8b | 123 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 124 | static void coap_msg_op_delete(coap_msg_op_t *op) |
ranaumarnaeem | 34:d6ce8f961b8b | 125 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 126 | free(op->val); |
ranaumarnaeem | 34:d6ce8f961b8b | 127 | free(op); |
ranaumarnaeem | 34:d6ce8f961b8b | 128 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 129 | |
ranaumarnaeem | 34:d6ce8f961b8b | 130 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 131 | * @brief Initialise an option linked-list structure |
ranaumarnaeem | 34:d6ce8f961b8b | 132 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 133 | * @param[out] list Pointer to an option linked-list structure |
ranaumarnaeem | 34:d6ce8f961b8b | 134 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 135 | static void coap_msg_op_list_create(coap_msg_op_list_t *list) |
ranaumarnaeem | 34:d6ce8f961b8b | 136 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 137 | memset(list, 0, sizeof(coap_msg_op_list_t)); |
ranaumarnaeem | 34:d6ce8f961b8b | 138 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 139 | |
ranaumarnaeem | 34:d6ce8f961b8b | 140 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 141 | * @brief Deinitialise an option linked-list structure |
ranaumarnaeem | 34:d6ce8f961b8b | 142 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 143 | * @param[in,out] list Pointer to an option linked-list structure |
ranaumarnaeem | 34:d6ce8f961b8b | 144 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 145 | static void coap_msg_op_list_destroy(coap_msg_op_list_t *list) |
ranaumarnaeem | 34:d6ce8f961b8b | 146 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 147 | coap_msg_op_t *prev = NULL; |
ranaumarnaeem | 34:d6ce8f961b8b | 148 | coap_msg_op_t *op = NULL; |
ranaumarnaeem | 34:d6ce8f961b8b | 149 | |
ranaumarnaeem | 34:d6ce8f961b8b | 150 | op = list->first; |
ranaumarnaeem | 34:d6ce8f961b8b | 151 | while (op != NULL) |
ranaumarnaeem | 34:d6ce8f961b8b | 152 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 153 | prev = op; |
ranaumarnaeem | 34:d6ce8f961b8b | 154 | op = op->next; |
ranaumarnaeem | 34:d6ce8f961b8b | 155 | coap_msg_op_delete(prev); |
ranaumarnaeem | 34:d6ce8f961b8b | 156 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 157 | memset(list, 0, sizeof(coap_msg_op_list_t)); |
ranaumarnaeem | 34:d6ce8f961b8b | 158 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 159 | |
ranaumarnaeem | 34:d6ce8f961b8b | 160 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 161 | * @brief Allocate an option structure and add it to the end of an option linked-list structure |
ranaumarnaeem | 34:d6ce8f961b8b | 162 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 163 | * @param[in,out] list Pointer to an option linked-list structure |
ranaumarnaeem | 34:d6ce8f961b8b | 164 | * @param[in] num Option number |
ranaumarnaeem | 34:d6ce8f961b8b | 165 | * @param[in] len Option length |
ranaumarnaeem | 34:d6ce8f961b8b | 166 | * @param[in] val Pointer to a buffer containing the option value |
ranaumarnaeem | 34:d6ce8f961b8b | 167 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 168 | * @returns Operation status |
ranaumarnaeem | 34:d6ce8f961b8b | 169 | * @retval 0 Success |
ranaumarnaeem | 34:d6ce8f961b8b | 170 | * @retval <0 Error |
ranaumarnaeem | 34:d6ce8f961b8b | 171 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 172 | static int coap_msg_op_list_add_last(coap_msg_op_list_t *list, unsigned num, unsigned len, const char *val) |
ranaumarnaeem | 34:d6ce8f961b8b | 173 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 174 | coap_msg_op_t *op = NULL; |
ranaumarnaeem | 34:d6ce8f961b8b | 175 | |
ranaumarnaeem | 34:d6ce8f961b8b | 176 | op = coap_msg_op_new(num, len, val); |
ranaumarnaeem | 34:d6ce8f961b8b | 177 | if (op == NULL) |
ranaumarnaeem | 34:d6ce8f961b8b | 178 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 179 | return -ENOMEM; |
ranaumarnaeem | 34:d6ce8f961b8b | 180 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 181 | if (list->first == NULL) |
ranaumarnaeem | 34:d6ce8f961b8b | 182 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 183 | list->first = op; |
ranaumarnaeem | 34:d6ce8f961b8b | 184 | list->last = op; |
ranaumarnaeem | 34:d6ce8f961b8b | 185 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 186 | else |
ranaumarnaeem | 34:d6ce8f961b8b | 187 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 188 | list->last->next = op; |
ranaumarnaeem | 34:d6ce8f961b8b | 189 | list->last = op; |
ranaumarnaeem | 34:d6ce8f961b8b | 190 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 191 | return 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 192 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 193 | |
ranaumarnaeem | 34:d6ce8f961b8b | 194 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 195 | * @brief Allocate an option structure and add it to an option linked-list structure |
ranaumarnaeem | 34:d6ce8f961b8b | 196 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 197 | * The option is added to the list at a position determined by the option number. |
ranaumarnaeem | 34:d6ce8f961b8b | 198 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 199 | * @param[in,out] list Pointer to an option linked-list structure |
ranaumarnaeem | 34:d6ce8f961b8b | 200 | * @param[in] num Option number |
ranaumarnaeem | 34:d6ce8f961b8b | 201 | * @param[in] len Option length |
ranaumarnaeem | 34:d6ce8f961b8b | 202 | * @param[in] val Pointer to a buffer containing the option value |
ranaumarnaeem | 34:d6ce8f961b8b | 203 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 204 | * @returns Operation status |
ranaumarnaeem | 34:d6ce8f961b8b | 205 | * @retval 0 Success |
ranaumarnaeem | 34:d6ce8f961b8b | 206 | * @retval <0 Error |
ranaumarnaeem | 34:d6ce8f961b8b | 207 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 208 | static int coap_msg_op_list_add(coap_msg_op_list_t *list, unsigned num, unsigned len, const char *val) |
ranaumarnaeem | 34:d6ce8f961b8b | 209 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 210 | coap_msg_op_t *prev = NULL; |
ranaumarnaeem | 34:d6ce8f961b8b | 211 | coap_msg_op_t *op = NULL; |
ranaumarnaeem | 34:d6ce8f961b8b | 212 | |
ranaumarnaeem | 34:d6ce8f961b8b | 213 | op = coap_msg_op_new(num, len, val); |
ranaumarnaeem | 34:d6ce8f961b8b | 214 | if (op == NULL) |
ranaumarnaeem | 34:d6ce8f961b8b | 215 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 216 | return -ENOMEM; |
ranaumarnaeem | 34:d6ce8f961b8b | 217 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 218 | if (list->first == NULL) |
ranaumarnaeem | 34:d6ce8f961b8b | 219 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 220 | /* empty list */ |
ranaumarnaeem | 34:d6ce8f961b8b | 221 | list->first = op; |
ranaumarnaeem | 34:d6ce8f961b8b | 222 | list->last = op; |
ranaumarnaeem | 34:d6ce8f961b8b | 223 | return 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 224 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 225 | if (op->num < list->first->num) |
ranaumarnaeem | 34:d6ce8f961b8b | 226 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 227 | /* start of the list */ |
ranaumarnaeem | 34:d6ce8f961b8b | 228 | op->next = list->first; |
ranaumarnaeem | 34:d6ce8f961b8b | 229 | list->first = op; |
ranaumarnaeem | 34:d6ce8f961b8b | 230 | return 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 231 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 232 | prev = list->first; |
ranaumarnaeem | 34:d6ce8f961b8b | 233 | while (prev != list->last) |
ranaumarnaeem | 34:d6ce8f961b8b | 234 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 235 | /* middle of the list */ |
ranaumarnaeem | 34:d6ce8f961b8b | 236 | if ((prev->num <= op->num) && (op->num < prev->next->num)) |
ranaumarnaeem | 34:d6ce8f961b8b | 237 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 238 | op->next = prev->next; |
ranaumarnaeem | 34:d6ce8f961b8b | 239 | prev->next = op; |
ranaumarnaeem | 34:d6ce8f961b8b | 240 | return 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 241 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 242 | prev = prev->next; |
ranaumarnaeem | 34:d6ce8f961b8b | 243 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 244 | /* end of the list */ |
ranaumarnaeem | 34:d6ce8f961b8b | 245 | list->last->next = op; |
ranaumarnaeem | 34:d6ce8f961b8b | 246 | list->last = op; |
ranaumarnaeem | 34:d6ce8f961b8b | 247 | return 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 248 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 249 | |
ranaumarnaeem | 34:d6ce8f961b8b | 250 | void coap_msg_create(coap_msg_t *msg) |
ranaumarnaeem | 34:d6ce8f961b8b | 251 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 252 | memset(msg, 0, sizeof(coap_msg_t)); |
ranaumarnaeem | 34:d6ce8f961b8b | 253 | msg->ver = COAP_MSG_VER; |
ranaumarnaeem | 34:d6ce8f961b8b | 254 | coap_msg_op_list_create(&msg->op_list); |
ranaumarnaeem | 34:d6ce8f961b8b | 255 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 256 | |
ranaumarnaeem | 34:d6ce8f961b8b | 257 | void coap_msg_destroy(coap_msg_t *msg) |
ranaumarnaeem | 34:d6ce8f961b8b | 258 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 259 | coap_msg_op_list_destroy(&msg->op_list); |
ranaumarnaeem | 34:d6ce8f961b8b | 260 | if (msg->payload != NULL) |
ranaumarnaeem | 34:d6ce8f961b8b | 261 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 262 | free(msg->payload); |
ranaumarnaeem | 34:d6ce8f961b8b | 263 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 264 | memset(msg, 0, sizeof(coap_msg_t)); |
ranaumarnaeem | 34:d6ce8f961b8b | 265 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 266 | |
ranaumarnaeem | 34:d6ce8f961b8b | 267 | void coap_msg_reset(coap_msg_t *msg) |
ranaumarnaeem | 34:d6ce8f961b8b | 268 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 269 | coap_msg_destroy(msg); |
ranaumarnaeem | 34:d6ce8f961b8b | 270 | coap_msg_create(msg); |
ranaumarnaeem | 34:d6ce8f961b8b | 271 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 272 | |
ranaumarnaeem | 34:d6ce8f961b8b | 273 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 274 | * @brief Check a message for correctness |
ranaumarnaeem | 34:d6ce8f961b8b | 275 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 276 | * The following checks from RFC7252 are performed: |
ranaumarnaeem | 34:d6ce8f961b8b | 277 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 278 | * An Empty message has the Code field set to 0.00. The Token Length |
ranaumarnaeem | 34:d6ce8f961b8b | 279 | * field MUST be set to 0 and bytes of data MUST NOT be present after |
ranaumarnaeem | 34:d6ce8f961b8b | 280 | * the Message ID field. If there are any bytes, they MUST be processed |
ranaumarnaeem | 34:d6ce8f961b8b | 281 | * as a message format error. |
ranaumarnaeem | 34:d6ce8f961b8b | 282 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 283 | * The Reset message MUST echo the Message ID of the Confirmable message |
ranaumarnaeem | 34:d6ce8f961b8b | 284 | * and MUST be Empty. |
ranaumarnaeem | 34:d6ce8f961b8b | 285 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 286 | * A Non-confirmable message always carries either a request or response |
ranaumarnaeem | 34:d6ce8f961b8b | 287 | * and MUST NOT be Empty. |
ranaumarnaeem | 34:d6ce8f961b8b | 288 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 289 | * @param[in] msg Pointer to a message structure |
ranaumarnaeem | 34:d6ce8f961b8b | 290 | * @returns Operation status |
ranaumarnaeem | 34:d6ce8f961b8b | 291 | * @retval 0 Success |
ranaumarnaeem | 34:d6ce8f961b8b | 292 | * @retval <0 Error |
ranaumarnaeem | 34:d6ce8f961b8b | 293 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 294 | static int coap_msg_check(coap_msg_t *msg) |
ranaumarnaeem | 34:d6ce8f961b8b | 295 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 296 | if ((msg->code_class == 0) && (msg->code_detail == 0)) |
ranaumarnaeem | 34:d6ce8f961b8b | 297 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 298 | /* empty message */ |
ranaumarnaeem | 34:d6ce8f961b8b | 299 | if ((msg->type == COAP_MSG_NON) |
ranaumarnaeem | 34:d6ce8f961b8b | 300 | || (msg->token_len != 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 301 | || (!coap_msg_op_list_is_empty(&msg->op_list)) |
ranaumarnaeem | 34:d6ce8f961b8b | 302 | || (msg->payload_len != 0)) |
ranaumarnaeem | 34:d6ce8f961b8b | 303 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 304 | return -EBADMSG; |
ranaumarnaeem | 34:d6ce8f961b8b | 305 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 306 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 307 | else |
ranaumarnaeem | 34:d6ce8f961b8b | 308 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 309 | /* non-empty message */ |
ranaumarnaeem | 34:d6ce8f961b8b | 310 | if (msg->type == COAP_MSG_RST) |
ranaumarnaeem | 34:d6ce8f961b8b | 311 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 312 | return -EBADMSG; |
ranaumarnaeem | 34:d6ce8f961b8b | 313 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 314 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 315 | return 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 316 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 317 | |
ranaumarnaeem | 34:d6ce8f961b8b | 318 | unsigned coap_msg_check_critical_ops(coap_msg_t *msg) |
ranaumarnaeem | 34:d6ce8f961b8b | 319 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 320 | coap_msg_op_t *op = NULL; |
ranaumarnaeem | 34:d6ce8f961b8b | 321 | unsigned num = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 322 | |
ranaumarnaeem | 34:d6ce8f961b8b | 323 | op = coap_msg_get_first_op(msg); |
ranaumarnaeem | 34:d6ce8f961b8b | 324 | while (op != NULL) |
ranaumarnaeem | 34:d6ce8f961b8b | 325 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 326 | num = coap_msg_op_get_num(op); |
ranaumarnaeem | 34:d6ce8f961b8b | 327 | if ((coap_msg_op_num_is_critical(num)) |
ranaumarnaeem | 34:d6ce8f961b8b | 328 | && (!coap_msg_op_num_is_recognized(num))) |
ranaumarnaeem | 34:d6ce8f961b8b | 329 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 330 | return num; /* fail */ |
ranaumarnaeem | 34:d6ce8f961b8b | 331 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 332 | op = coap_msg_op_get_next(op); |
ranaumarnaeem | 34:d6ce8f961b8b | 333 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 334 | return 0; /* pass */ |
ranaumarnaeem | 34:d6ce8f961b8b | 335 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 336 | |
ranaumarnaeem | 34:d6ce8f961b8b | 337 | unsigned coap_msg_check_unsafe_ops(coap_msg_t *msg) |
ranaumarnaeem | 34:d6ce8f961b8b | 338 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 339 | coap_msg_op_t *op = NULL; |
ranaumarnaeem | 34:d6ce8f961b8b | 340 | unsigned num = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 341 | |
ranaumarnaeem | 34:d6ce8f961b8b | 342 | op = coap_msg_get_first_op(msg); |
ranaumarnaeem | 34:d6ce8f961b8b | 343 | while (op != NULL) |
ranaumarnaeem | 34:d6ce8f961b8b | 344 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 345 | num = coap_msg_op_get_num(op); |
ranaumarnaeem | 34:d6ce8f961b8b | 346 | if ((coap_msg_op_num_is_unsafe(num)) |
ranaumarnaeem | 34:d6ce8f961b8b | 347 | && (!coap_msg_op_num_is_recognized(num))) |
ranaumarnaeem | 34:d6ce8f961b8b | 348 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 349 | return num; /* fail */ |
ranaumarnaeem | 34:d6ce8f961b8b | 350 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 351 | op = coap_msg_op_get_next(op); |
ranaumarnaeem | 34:d6ce8f961b8b | 352 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 353 | return 0; /* pass */ |
ranaumarnaeem | 34:d6ce8f961b8b | 354 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 355 | |
ranaumarnaeem | 34:d6ce8f961b8b | 356 | int coap_msg_parse_type_msg_id(char *buf, size_t len, unsigned *type, unsigned *msg_id) |
ranaumarnaeem | 34:d6ce8f961b8b | 357 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 358 | if (len < 4) |
ranaumarnaeem | 34:d6ce8f961b8b | 359 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 360 | return -EBADMSG; |
ranaumarnaeem | 34:d6ce8f961b8b | 361 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 362 | *type = (buf[0] >> 4) & 0x03; |
ranaumarnaeem | 34:d6ce8f961b8b | 363 | *msg_id = ntohs(*((uint16_t *)(&buf[2]))); |
ranaumarnaeem | 34:d6ce8f961b8b | 364 | return 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 365 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 366 | |
ranaumarnaeem | 34:d6ce8f961b8b | 367 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 368 | * @brief Parse the header in a message |
ranaumarnaeem | 34:d6ce8f961b8b | 369 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 370 | * @param[out] msg Pointer to a message structure |
ranaumarnaeem | 34:d6ce8f961b8b | 371 | * @param[in] buf Pointer to a buffer containing the message |
ranaumarnaeem | 34:d6ce8f961b8b | 372 | * @param[in] len Length of the buffer |
ranaumarnaeem | 34:d6ce8f961b8b | 373 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 374 | * @returns Number of bytes parsed or error code |
ranaumarnaeem | 34:d6ce8f961b8b | 375 | * @retval >0 Number of bytes parsed |
ranaumarnaeem | 34:d6ce8f961b8b | 376 | * @retval <0 Error |
ranaumarnaeem | 34:d6ce8f961b8b | 377 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 378 | static int coap_msg_parse_hdr(coap_msg_t *msg, char *buf, size_t len) |
ranaumarnaeem | 34:d6ce8f961b8b | 379 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 380 | char *p = buf; |
ranaumarnaeem | 34:d6ce8f961b8b | 381 | |
ranaumarnaeem | 34:d6ce8f961b8b | 382 | if (len < 4) |
ranaumarnaeem | 34:d6ce8f961b8b | 383 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 384 | return -EBADMSG; |
ranaumarnaeem | 34:d6ce8f961b8b | 385 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 386 | msg->ver = (p[0] >> 6) & 0x03; |
ranaumarnaeem | 34:d6ce8f961b8b | 387 | if (msg->ver != COAP_MSG_VER) |
ranaumarnaeem | 34:d6ce8f961b8b | 388 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 389 | return -EINVAL; |
ranaumarnaeem | 34:d6ce8f961b8b | 390 | } |
ranaumarnaeem | 39:4f3f7463e55f | 391 | msg->type = (coap_msg_type_t)((p[0] >> 4) & 0x03); |
ranaumarnaeem | 34:d6ce8f961b8b | 392 | msg->token_len = p[0] & 0x0f; |
ranaumarnaeem | 34:d6ce8f961b8b | 393 | if (msg->token_len > sizeof(msg->token)) |
ranaumarnaeem | 34:d6ce8f961b8b | 394 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 395 | return -EBADMSG; |
ranaumarnaeem | 34:d6ce8f961b8b | 396 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 397 | msg->code_detail = p[1] & 0x1f; |
ranaumarnaeem | 34:d6ce8f961b8b | 398 | msg->code_class = (p[1] >> 5) & 0x07; |
ranaumarnaeem | 34:d6ce8f961b8b | 399 | if ((msg->code_class != COAP_MSG_REQ) |
ranaumarnaeem | 34:d6ce8f961b8b | 400 | && (msg->code_class != COAP_MSG_SUCCESS) |
ranaumarnaeem | 34:d6ce8f961b8b | 401 | && (msg->code_class != COAP_MSG_CLIENT_ERR) |
ranaumarnaeem | 34:d6ce8f961b8b | 402 | && (msg->code_class != COAP_MSG_SERVER_ERR)) |
ranaumarnaeem | 34:d6ce8f961b8b | 403 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 404 | return -EBADMSG; |
ranaumarnaeem | 34:d6ce8f961b8b | 405 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 406 | msg->msg_id = ntohs(*((uint16_t *)(&p[2]))); |
ranaumarnaeem | 34:d6ce8f961b8b | 407 | p += 4; |
ranaumarnaeem | 34:d6ce8f961b8b | 408 | len -= 4; |
ranaumarnaeem | 34:d6ce8f961b8b | 409 | return p - buf; |
ranaumarnaeem | 34:d6ce8f961b8b | 410 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 411 | |
ranaumarnaeem | 34:d6ce8f961b8b | 412 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 413 | * @brief Parse the token in a message |
ranaumarnaeem | 34:d6ce8f961b8b | 414 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 415 | * @param[out] msg Pointer to a message structure |
ranaumarnaeem | 34:d6ce8f961b8b | 416 | * @param[in] buf Pointer to a buffer containing the message |
ranaumarnaeem | 34:d6ce8f961b8b | 417 | * @param[in] len Length of the buffer |
ranaumarnaeem | 34:d6ce8f961b8b | 418 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 419 | * @returns Number of bytes parsed or error code |
ranaumarnaeem | 34:d6ce8f961b8b | 420 | * @retval >0 Number of bytes parsed |
ranaumarnaeem | 34:d6ce8f961b8b | 421 | * @retval <0 Error |
ranaumarnaeem | 34:d6ce8f961b8b | 422 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 423 | static int coap_msg_parse_token(coap_msg_t *msg, char *buf, size_t len) |
ranaumarnaeem | 34:d6ce8f961b8b | 424 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 425 | if (len < msg->token_len) |
ranaumarnaeem | 34:d6ce8f961b8b | 426 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 427 | return -EBADMSG; |
ranaumarnaeem | 34:d6ce8f961b8b | 428 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 429 | memcpy(msg->token, buf, msg->token_len); |
ranaumarnaeem | 34:d6ce8f961b8b | 430 | return msg->token_len; |
ranaumarnaeem | 34:d6ce8f961b8b | 431 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 432 | |
ranaumarnaeem | 34:d6ce8f961b8b | 433 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 434 | * @brief Parse an option in a message |
ranaumarnaeem | 34:d6ce8f961b8b | 435 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 436 | * @param[in,out] msg Pointer to a message structure |
ranaumarnaeem | 34:d6ce8f961b8b | 437 | * @param[in] buf Pointer to a buffer containing the message |
ranaumarnaeem | 34:d6ce8f961b8b | 438 | * @param[in] len Length of the buffer |
ranaumarnaeem | 34:d6ce8f961b8b | 439 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 440 | * @returns Number of bytes parsed or error code |
ranaumarnaeem | 34:d6ce8f961b8b | 441 | * @retval >0 Number of bytes parsed |
ranaumarnaeem | 34:d6ce8f961b8b | 442 | * @retval <0 Error |
ranaumarnaeem | 34:d6ce8f961b8b | 443 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 444 | static int coap_msg_parse_op(coap_msg_t *msg, char *buf, size_t len) |
ranaumarnaeem | 34:d6ce8f961b8b | 445 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 446 | coap_msg_op_t *prev = NULL; |
ranaumarnaeem | 34:d6ce8f961b8b | 447 | unsigned op_delta = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 448 | unsigned op_len = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 449 | unsigned op_num = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 450 | char *p = buf; |
ranaumarnaeem | 34:d6ce8f961b8b | 451 | int ret = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 452 | |
ranaumarnaeem | 34:d6ce8f961b8b | 453 | if (len < 1) |
ranaumarnaeem | 34:d6ce8f961b8b | 454 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 455 | return -EBADMSG; |
ranaumarnaeem | 34:d6ce8f961b8b | 456 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 457 | op_delta = (p[0] >> 4) & 0x0f; |
ranaumarnaeem | 34:d6ce8f961b8b | 458 | op_len = p[0] & 0x0f; |
ranaumarnaeem | 34:d6ce8f961b8b | 459 | if ((op_delta == 15) || (op_len == 15)) |
ranaumarnaeem | 34:d6ce8f961b8b | 460 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 461 | return -EBADMSG; |
ranaumarnaeem | 34:d6ce8f961b8b | 462 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 463 | p++; |
ranaumarnaeem | 34:d6ce8f961b8b | 464 | len--; |
ranaumarnaeem | 34:d6ce8f961b8b | 465 | if (op_delta == 13) |
ranaumarnaeem | 34:d6ce8f961b8b | 466 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 467 | if (len < 1) |
ranaumarnaeem | 34:d6ce8f961b8b | 468 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 469 | return -EBADMSG; |
ranaumarnaeem | 34:d6ce8f961b8b | 470 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 471 | op_delta += p[0]; |
ranaumarnaeem | 34:d6ce8f961b8b | 472 | p++; |
ranaumarnaeem | 34:d6ce8f961b8b | 473 | len--; |
ranaumarnaeem | 34:d6ce8f961b8b | 474 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 475 | else if (op_delta == 14) |
ranaumarnaeem | 34:d6ce8f961b8b | 476 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 477 | if (len < 2) |
ranaumarnaeem | 34:d6ce8f961b8b | 478 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 479 | return -EBADMSG; |
ranaumarnaeem | 34:d6ce8f961b8b | 480 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 481 | op_delta = 269 + ntohs(*((uint16_t *)(&p[0]))); |
ranaumarnaeem | 34:d6ce8f961b8b | 482 | p += 2; |
ranaumarnaeem | 34:d6ce8f961b8b | 483 | len -= 2; |
ranaumarnaeem | 34:d6ce8f961b8b | 484 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 485 | if (op_len == 13) |
ranaumarnaeem | 34:d6ce8f961b8b | 486 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 487 | if (len < 1) |
ranaumarnaeem | 34:d6ce8f961b8b | 488 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 489 | return -EBADMSG; |
ranaumarnaeem | 34:d6ce8f961b8b | 490 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 491 | op_len += p[0]; |
ranaumarnaeem | 34:d6ce8f961b8b | 492 | p++; |
ranaumarnaeem | 34:d6ce8f961b8b | 493 | len--; |
ranaumarnaeem | 34:d6ce8f961b8b | 494 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 495 | else if (op_len == 14) |
ranaumarnaeem | 34:d6ce8f961b8b | 496 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 497 | if (len < 2) |
ranaumarnaeem | 34:d6ce8f961b8b | 498 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 499 | return -EBADMSG; |
ranaumarnaeem | 34:d6ce8f961b8b | 500 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 501 | op_len = 269 + ntohs(*((uint16_t *)(&p[0]))); |
ranaumarnaeem | 34:d6ce8f961b8b | 502 | p += 2; |
ranaumarnaeem | 34:d6ce8f961b8b | 503 | len -= 2; |
ranaumarnaeem | 34:d6ce8f961b8b | 504 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 505 | if (len < op_len) |
ranaumarnaeem | 34:d6ce8f961b8b | 506 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 507 | return -EBADMSG; |
ranaumarnaeem | 34:d6ce8f961b8b | 508 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 509 | prev = coap_msg_op_list_get_last(&msg->op_list); |
ranaumarnaeem | 34:d6ce8f961b8b | 510 | if (prev == NULL) |
ranaumarnaeem | 34:d6ce8f961b8b | 511 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 512 | op_num = op_delta; |
ranaumarnaeem | 34:d6ce8f961b8b | 513 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 514 | else |
ranaumarnaeem | 34:d6ce8f961b8b | 515 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 516 | op_num = coap_msg_op_get_num(prev) + op_delta; |
ranaumarnaeem | 34:d6ce8f961b8b | 517 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 518 | ret = coap_msg_op_list_add_last(&msg->op_list, op_num, op_len, p); |
ranaumarnaeem | 34:d6ce8f961b8b | 519 | if (ret < 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 520 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 521 | return ret; |
ranaumarnaeem | 34:d6ce8f961b8b | 522 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 523 | p += op_len; |
ranaumarnaeem | 34:d6ce8f961b8b | 524 | return p - buf; |
ranaumarnaeem | 34:d6ce8f961b8b | 525 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 526 | |
ranaumarnaeem | 34:d6ce8f961b8b | 527 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 528 | * @brief Parse the options in a message |
ranaumarnaeem | 34:d6ce8f961b8b | 529 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 530 | * @param[in,out] msg Pointer to a message structure |
ranaumarnaeem | 34:d6ce8f961b8b | 531 | * @param[in] buf Pointer to a buffer containing the message |
ranaumarnaeem | 34:d6ce8f961b8b | 532 | * @param[in] len Length of the buffer |
ranaumarnaeem | 34:d6ce8f961b8b | 533 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 534 | * @returns Number of bytes parsed or error code |
ranaumarnaeem | 34:d6ce8f961b8b | 535 | * @retval >0 Number of bytes parsed |
ranaumarnaeem | 34:d6ce8f961b8b | 536 | * @retval <0 Error |
ranaumarnaeem | 34:d6ce8f961b8b | 537 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 538 | static int coap_msg_parse_ops(coap_msg_t *msg, char *buf, size_t len) |
ranaumarnaeem | 34:d6ce8f961b8b | 539 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 540 | int num = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 541 | char *p = buf; |
ranaumarnaeem | 34:d6ce8f961b8b | 542 | |
ranaumarnaeem | 34:d6ce8f961b8b | 543 | while (1) |
ranaumarnaeem | 34:d6ce8f961b8b | 544 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 545 | if (((p[0] & 0xff) == 0xff) || (len == 0)) |
ranaumarnaeem | 34:d6ce8f961b8b | 546 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 547 | break; |
ranaumarnaeem | 34:d6ce8f961b8b | 548 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 549 | num = coap_msg_parse_op(msg, p, len); |
ranaumarnaeem | 34:d6ce8f961b8b | 550 | if (num < 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 551 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 552 | return num; |
ranaumarnaeem | 34:d6ce8f961b8b | 553 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 554 | p += num; |
ranaumarnaeem | 34:d6ce8f961b8b | 555 | len -= num; |
ranaumarnaeem | 34:d6ce8f961b8b | 556 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 557 | return p - buf; |
ranaumarnaeem | 34:d6ce8f961b8b | 558 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 559 | |
ranaumarnaeem | 34:d6ce8f961b8b | 560 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 561 | * @brief Parse the payload in a message |
ranaumarnaeem | 34:d6ce8f961b8b | 562 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 563 | * @param[out] msg Pointer to a message structure |
ranaumarnaeem | 34:d6ce8f961b8b | 564 | * @param[in] buf Pointer to a buffer containing the message |
ranaumarnaeem | 34:d6ce8f961b8b | 565 | * @param[in] len Length of the buffer |
ranaumarnaeem | 34:d6ce8f961b8b | 566 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 567 | * @returns Number of bytes parsed or error code |
ranaumarnaeem | 34:d6ce8f961b8b | 568 | * @retval >0 Number of bytes parsed |
ranaumarnaeem | 34:d6ce8f961b8b | 569 | * @retval <0 Error |
ranaumarnaeem | 34:d6ce8f961b8b | 570 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 571 | static int coap_msg_parse_payload(coap_msg_t *msg, char *buf, size_t len) |
ranaumarnaeem | 34:d6ce8f961b8b | 572 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 573 | char *p = buf; |
ranaumarnaeem | 34:d6ce8f961b8b | 574 | |
ranaumarnaeem | 34:d6ce8f961b8b | 575 | if (len == 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 576 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 577 | return 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 578 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 579 | if ((p[0] & 0xff) != 0xff) |
ranaumarnaeem | 34:d6ce8f961b8b | 580 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 581 | return -EBADMSG; |
ranaumarnaeem | 34:d6ce8f961b8b | 582 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 583 | p++; |
ranaumarnaeem | 34:d6ce8f961b8b | 584 | len--; |
ranaumarnaeem | 34:d6ce8f961b8b | 585 | if (len == 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 586 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 587 | return -EBADMSG; |
ranaumarnaeem | 34:d6ce8f961b8b | 588 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 589 | msg->payload = (char *)malloc(len); |
ranaumarnaeem | 34:d6ce8f961b8b | 590 | if (msg->payload == NULL) |
ranaumarnaeem | 34:d6ce8f961b8b | 591 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 592 | return -ENOMEM; |
ranaumarnaeem | 34:d6ce8f961b8b | 593 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 594 | memcpy(msg->payload, p, len); |
ranaumarnaeem | 34:d6ce8f961b8b | 595 | msg->payload_len = len; |
ranaumarnaeem | 34:d6ce8f961b8b | 596 | p += len; |
ranaumarnaeem | 34:d6ce8f961b8b | 597 | return p - buf; |
ranaumarnaeem | 34:d6ce8f961b8b | 598 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 599 | |
ranaumarnaeem | 34:d6ce8f961b8b | 600 | int coap_msg_parse(coap_msg_t *msg, char *buf, size_t len) |
ranaumarnaeem | 34:d6ce8f961b8b | 601 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 602 | int num = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 603 | char *p = buf; |
ranaumarnaeem | 34:d6ce8f961b8b | 604 | |
ranaumarnaeem | 34:d6ce8f961b8b | 605 | coap_msg_reset(msg); |
ranaumarnaeem | 34:d6ce8f961b8b | 606 | num = coap_msg_parse_hdr(msg, p, len); |
ranaumarnaeem | 34:d6ce8f961b8b | 607 | if (num < 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 608 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 609 | coap_msg_destroy(msg); |
ranaumarnaeem | 34:d6ce8f961b8b | 610 | return num; |
ranaumarnaeem | 34:d6ce8f961b8b | 611 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 612 | p += num; |
ranaumarnaeem | 34:d6ce8f961b8b | 613 | len -= num; |
ranaumarnaeem | 34:d6ce8f961b8b | 614 | num = coap_msg_parse_token(msg, p, len); |
ranaumarnaeem | 34:d6ce8f961b8b | 615 | if (num < 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 616 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 617 | coap_msg_destroy(msg); |
ranaumarnaeem | 34:d6ce8f961b8b | 618 | return num; |
ranaumarnaeem | 34:d6ce8f961b8b | 619 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 620 | p += num; |
ranaumarnaeem | 34:d6ce8f961b8b | 621 | len -= num; |
ranaumarnaeem | 34:d6ce8f961b8b | 622 | num = coap_msg_parse_ops(msg, p, len); |
ranaumarnaeem | 34:d6ce8f961b8b | 623 | if (num < 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 624 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 625 | coap_msg_destroy(msg); |
ranaumarnaeem | 34:d6ce8f961b8b | 626 | return num; |
ranaumarnaeem | 34:d6ce8f961b8b | 627 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 628 | p += num; |
ranaumarnaeem | 34:d6ce8f961b8b | 629 | len -= num; |
ranaumarnaeem | 34:d6ce8f961b8b | 630 | num = coap_msg_parse_payload(msg, p, len); |
ranaumarnaeem | 34:d6ce8f961b8b | 631 | if (num < 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 632 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 633 | coap_msg_destroy(msg); |
ranaumarnaeem | 34:d6ce8f961b8b | 634 | return num; |
ranaumarnaeem | 34:d6ce8f961b8b | 635 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 636 | return coap_msg_check(msg); |
ranaumarnaeem | 34:d6ce8f961b8b | 637 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 638 | |
ranaumarnaeem | 34:d6ce8f961b8b | 639 | int coap_msg_set_type(coap_msg_t *msg, unsigned type) |
ranaumarnaeem | 34:d6ce8f961b8b | 640 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 641 | if ((type != COAP_MSG_CON) |
ranaumarnaeem | 34:d6ce8f961b8b | 642 | && (type != COAP_MSG_NON) |
ranaumarnaeem | 34:d6ce8f961b8b | 643 | && (type != COAP_MSG_ACK) |
ranaumarnaeem | 34:d6ce8f961b8b | 644 | && (type != COAP_MSG_RST)) |
ranaumarnaeem | 34:d6ce8f961b8b | 645 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 646 | return -EINVAL; |
ranaumarnaeem | 34:d6ce8f961b8b | 647 | } |
ranaumarnaeem | 39:4f3f7463e55f | 648 | msg->type = (coap_msg_type_t)type; |
ranaumarnaeem | 34:d6ce8f961b8b | 649 | return 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 650 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 651 | |
ranaumarnaeem | 34:d6ce8f961b8b | 652 | int coap_msg_set_code(coap_msg_t *msg, unsigned code_class, unsigned code_detail) |
ranaumarnaeem | 34:d6ce8f961b8b | 653 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 654 | if (code_class > COAP_MSG_MAX_CODE_CLASS) |
ranaumarnaeem | 34:d6ce8f961b8b | 655 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 656 | return -EINVAL; |
ranaumarnaeem | 34:d6ce8f961b8b | 657 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 658 | if (code_detail > COAP_MSG_MAX_CODE_DETAIL) |
ranaumarnaeem | 34:d6ce8f961b8b | 659 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 660 | return -EINVAL; |
ranaumarnaeem | 34:d6ce8f961b8b | 661 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 662 | msg->code_class = code_class; |
ranaumarnaeem | 34:d6ce8f961b8b | 663 | msg->code_detail = code_detail; |
ranaumarnaeem | 34:d6ce8f961b8b | 664 | return 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 665 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 666 | |
ranaumarnaeem | 34:d6ce8f961b8b | 667 | int coap_msg_set_msg_id(coap_msg_t *msg, unsigned msg_id) |
ranaumarnaeem | 34:d6ce8f961b8b | 668 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 669 | if (msg_id > COAP_MSG_MAX_MSG_ID) |
ranaumarnaeem | 34:d6ce8f961b8b | 670 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 671 | return -EINVAL; |
ranaumarnaeem | 34:d6ce8f961b8b | 672 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 673 | msg->msg_id = msg_id; |
ranaumarnaeem | 34:d6ce8f961b8b | 674 | return 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 675 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 676 | |
ranaumarnaeem | 34:d6ce8f961b8b | 677 | int coap_msg_set_token(coap_msg_t *msg, char *buf, size_t len) |
ranaumarnaeem | 34:d6ce8f961b8b | 678 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 679 | if (len > COAP_MSG_MAX_TOKEN_LEN) |
ranaumarnaeem | 34:d6ce8f961b8b | 680 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 681 | return -EINVAL; |
ranaumarnaeem | 34:d6ce8f961b8b | 682 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 683 | memcpy(msg->token, buf, len); |
ranaumarnaeem | 34:d6ce8f961b8b | 684 | msg->token_len = len; |
ranaumarnaeem | 34:d6ce8f961b8b | 685 | return 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 686 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 687 | |
ranaumarnaeem | 34:d6ce8f961b8b | 688 | int coap_msg_add_op(coap_msg_t *msg, unsigned num, unsigned len, const char *val) |
ranaumarnaeem | 34:d6ce8f961b8b | 689 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 690 | return coap_msg_op_list_add(&msg->op_list, num, len, val); |
ranaumarnaeem | 34:d6ce8f961b8b | 691 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 692 | |
ranaumarnaeem | 34:d6ce8f961b8b | 693 | int coap_msg_set_payload(coap_msg_t *msg, char *buf, size_t len) |
ranaumarnaeem | 34:d6ce8f961b8b | 694 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 695 | msg->payload_len = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 696 | if (msg->payload != NULL) |
ranaumarnaeem | 34:d6ce8f961b8b | 697 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 698 | free(msg->payload); |
ranaumarnaeem | 34:d6ce8f961b8b | 699 | msg->payload = NULL; |
ranaumarnaeem | 34:d6ce8f961b8b | 700 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 701 | if (len > 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 702 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 703 | msg->payload = (char *)malloc(len); |
ranaumarnaeem | 34:d6ce8f961b8b | 704 | if (msg->payload == NULL) |
ranaumarnaeem | 34:d6ce8f961b8b | 705 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 706 | return -ENOMEM; |
ranaumarnaeem | 34:d6ce8f961b8b | 707 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 708 | memcpy(msg->payload, buf, len); |
ranaumarnaeem | 34:d6ce8f961b8b | 709 | msg->payload_len = len; |
ranaumarnaeem | 34:d6ce8f961b8b | 710 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 711 | return 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 712 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 713 | |
ranaumarnaeem | 34:d6ce8f961b8b | 714 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 715 | * @brief Format the header in a message |
ranaumarnaeem | 34:d6ce8f961b8b | 716 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 717 | * @param[in] msg Pointer to a message structure |
ranaumarnaeem | 34:d6ce8f961b8b | 718 | * @param[out] buf Pointer to a buffer to contain the formatted message |
ranaumarnaeem | 34:d6ce8f961b8b | 719 | * @param[in] len Length of the buffer |
ranaumarnaeem | 34:d6ce8f961b8b | 720 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 721 | * @returns Length of the formatted message or error code |
ranaumarnaeem | 34:d6ce8f961b8b | 722 | * @retval >0 Length of the formatted message |
ranaumarnaeem | 34:d6ce8f961b8b | 723 | * @retval <0 Error |
ranaumarnaeem | 34:d6ce8f961b8b | 724 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 725 | static int coap_msg_format_hdr(coap_msg_t *msg, char *buf, size_t len) |
ranaumarnaeem | 34:d6ce8f961b8b | 726 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 727 | uint16_t msg_id = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 728 | |
ranaumarnaeem | 34:d6ce8f961b8b | 729 | if (len < 4) |
ranaumarnaeem | 34:d6ce8f961b8b | 730 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 731 | return -ENOSPC; |
ranaumarnaeem | 34:d6ce8f961b8b | 732 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 733 | buf[0] = (char)((COAP_MSG_VER << 6) |
ranaumarnaeem | 34:d6ce8f961b8b | 734 | | ((msg->type & 0x03) << 4) |
ranaumarnaeem | 34:d6ce8f961b8b | 735 | | (msg->token_len & 0x0f)); |
ranaumarnaeem | 34:d6ce8f961b8b | 736 | buf[1] = (char)(((msg->code_class & 0x07) << 5) |
ranaumarnaeem | 34:d6ce8f961b8b | 737 | | (msg->code_detail & 0x1f)); |
ranaumarnaeem | 34:d6ce8f961b8b | 738 | msg_id = htons(msg->msg_id); |
ranaumarnaeem | 34:d6ce8f961b8b | 739 | memcpy(&buf[2], &msg_id, 2); |
ranaumarnaeem | 34:d6ce8f961b8b | 740 | return 4; |
ranaumarnaeem | 34:d6ce8f961b8b | 741 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 742 | |
ranaumarnaeem | 34:d6ce8f961b8b | 743 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 744 | * @brief Format the token in a message |
ranaumarnaeem | 34:d6ce8f961b8b | 745 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 746 | * @param[in] msg Pointer to a message structure |
ranaumarnaeem | 34:d6ce8f961b8b | 747 | * @param[out] buf Pointer to a buffer to contain the formatted message |
ranaumarnaeem | 34:d6ce8f961b8b | 748 | * @param[in] len Length of the buffer |
ranaumarnaeem | 34:d6ce8f961b8b | 749 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 750 | * @returns Length of the formatted message or error code |
ranaumarnaeem | 34:d6ce8f961b8b | 751 | * @retval >0 Length of the formatted message |
ranaumarnaeem | 34:d6ce8f961b8b | 752 | * @retval <0 Error |
ranaumarnaeem | 34:d6ce8f961b8b | 753 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 754 | static int coap_msg_format_token(coap_msg_t *msg, char *buf, size_t len) |
ranaumarnaeem | 34:d6ce8f961b8b | 755 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 756 | if (len < msg->token_len) |
ranaumarnaeem | 34:d6ce8f961b8b | 757 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 758 | return -ENOSPC; |
ranaumarnaeem | 34:d6ce8f961b8b | 759 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 760 | memcpy(buf, msg->token, msg->token_len); |
ranaumarnaeem | 34:d6ce8f961b8b | 761 | return msg->token_len; |
ranaumarnaeem | 34:d6ce8f961b8b | 762 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 763 | |
ranaumarnaeem | 34:d6ce8f961b8b | 764 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 765 | * @brief Format an option in a message |
ranaumarnaeem | 34:d6ce8f961b8b | 766 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 767 | * @param[in] op Pointer to an option structure |
ranaumarnaeem | 34:d6ce8f961b8b | 768 | * @param[in] prev_num option number of the previous option |
ranaumarnaeem | 34:d6ce8f961b8b | 769 | * @param[out] buf Pointer to a buffer to contain the formatted message |
ranaumarnaeem | 34:d6ce8f961b8b | 770 | * @param[in] len Length of the buffer |
ranaumarnaeem | 34:d6ce8f961b8b | 771 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 772 | * @returns Length of the formatted message or error code |
ranaumarnaeem | 34:d6ce8f961b8b | 773 | * @retval >0 Length of the formatted message |
ranaumarnaeem | 34:d6ce8f961b8b | 774 | * @retval <0 Error |
ranaumarnaeem | 34:d6ce8f961b8b | 775 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 776 | static int coap_msg_format_op(coap_msg_op_t *op, unsigned prev_num, char *buf, size_t len) |
ranaumarnaeem | 34:d6ce8f961b8b | 777 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 778 | unsigned op_delta = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 779 | unsigned num = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 780 | uint16_t val = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 781 | char *p = buf; |
ranaumarnaeem | 34:d6ce8f961b8b | 782 | |
ranaumarnaeem | 34:d6ce8f961b8b | 783 | op_delta = op->num - prev_num; |
ranaumarnaeem | 34:d6ce8f961b8b | 784 | num++; |
ranaumarnaeem | 34:d6ce8f961b8b | 785 | |
ranaumarnaeem | 34:d6ce8f961b8b | 786 | /* option delta */ |
ranaumarnaeem | 34:d6ce8f961b8b | 787 | if (op_delta >= 269) |
ranaumarnaeem | 34:d6ce8f961b8b | 788 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 789 | num += 2; |
ranaumarnaeem | 34:d6ce8f961b8b | 790 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 791 | else if (op_delta >= 13) |
ranaumarnaeem | 34:d6ce8f961b8b | 792 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 793 | num += 1; |
ranaumarnaeem | 34:d6ce8f961b8b | 794 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 795 | |
ranaumarnaeem | 34:d6ce8f961b8b | 796 | /* option length */ |
ranaumarnaeem | 34:d6ce8f961b8b | 797 | if (op->len >= 269) |
ranaumarnaeem | 34:d6ce8f961b8b | 798 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 799 | num += 2; |
ranaumarnaeem | 34:d6ce8f961b8b | 800 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 801 | else if (op->num >= 13) |
ranaumarnaeem | 34:d6ce8f961b8b | 802 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 803 | num += 1; |
ranaumarnaeem | 34:d6ce8f961b8b | 804 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 805 | |
ranaumarnaeem | 34:d6ce8f961b8b | 806 | /* option value */ |
ranaumarnaeem | 34:d6ce8f961b8b | 807 | num += op->len; |
ranaumarnaeem | 34:d6ce8f961b8b | 808 | if (num > len) |
ranaumarnaeem | 34:d6ce8f961b8b | 809 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 810 | return -ENOSPC; |
ranaumarnaeem | 34:d6ce8f961b8b | 811 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 812 | |
ranaumarnaeem | 34:d6ce8f961b8b | 813 | /* option delta */ |
ranaumarnaeem | 34:d6ce8f961b8b | 814 | if (op_delta >= 269) |
ranaumarnaeem | 34:d6ce8f961b8b | 815 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 816 | p[0] = 14 << 4; |
ranaumarnaeem | 34:d6ce8f961b8b | 817 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 818 | else if (op_delta >= 13) |
ranaumarnaeem | 34:d6ce8f961b8b | 819 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 820 | p[0] = 13 << 4; |
ranaumarnaeem | 34:d6ce8f961b8b | 821 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 822 | else |
ranaumarnaeem | 34:d6ce8f961b8b | 823 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 824 | p[0] = op_delta << 4; |
ranaumarnaeem | 34:d6ce8f961b8b | 825 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 826 | |
ranaumarnaeem | 34:d6ce8f961b8b | 827 | /* option length */ |
ranaumarnaeem | 34:d6ce8f961b8b | 828 | if (op->len >= 269) |
ranaumarnaeem | 34:d6ce8f961b8b | 829 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 830 | p[0] |= 14; |
ranaumarnaeem | 34:d6ce8f961b8b | 831 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 832 | else if (op->len >= 13) |
ranaumarnaeem | 34:d6ce8f961b8b | 833 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 834 | p[0] |= 13; |
ranaumarnaeem | 34:d6ce8f961b8b | 835 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 836 | else |
ranaumarnaeem | 34:d6ce8f961b8b | 837 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 838 | p[0] |= op->len; |
ranaumarnaeem | 34:d6ce8f961b8b | 839 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 840 | p++; |
ranaumarnaeem | 34:d6ce8f961b8b | 841 | len--; |
ranaumarnaeem | 34:d6ce8f961b8b | 842 | |
ranaumarnaeem | 34:d6ce8f961b8b | 843 | /* option delta extended */ |
ranaumarnaeem | 34:d6ce8f961b8b | 844 | if (op_delta >= 269) |
ranaumarnaeem | 34:d6ce8f961b8b | 845 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 846 | val = htons(op_delta - 269); |
ranaumarnaeem | 34:d6ce8f961b8b | 847 | memcpy(p, &val, 2); |
ranaumarnaeem | 34:d6ce8f961b8b | 848 | p += 2; |
ranaumarnaeem | 34:d6ce8f961b8b | 849 | len -= 2; |
ranaumarnaeem | 34:d6ce8f961b8b | 850 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 851 | else if (op_delta >= 13) |
ranaumarnaeem | 34:d6ce8f961b8b | 852 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 853 | p[0] = op_delta - 13; |
ranaumarnaeem | 34:d6ce8f961b8b | 854 | p++; |
ranaumarnaeem | 34:d6ce8f961b8b | 855 | len--; |
ranaumarnaeem | 34:d6ce8f961b8b | 856 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 857 | |
ranaumarnaeem | 34:d6ce8f961b8b | 858 | /* option length extended */ |
ranaumarnaeem | 34:d6ce8f961b8b | 859 | if (op->len >= 269) |
ranaumarnaeem | 34:d6ce8f961b8b | 860 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 861 | val = htons(op->len - 269); |
ranaumarnaeem | 34:d6ce8f961b8b | 862 | memcpy(p, &val, 2); |
ranaumarnaeem | 34:d6ce8f961b8b | 863 | p += 2; |
ranaumarnaeem | 34:d6ce8f961b8b | 864 | len -= 2; |
ranaumarnaeem | 34:d6ce8f961b8b | 865 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 866 | else if (op->len >= 13) |
ranaumarnaeem | 34:d6ce8f961b8b | 867 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 868 | p[0] = op->len - 13; |
ranaumarnaeem | 34:d6ce8f961b8b | 869 | p++; |
ranaumarnaeem | 34:d6ce8f961b8b | 870 | len--; |
ranaumarnaeem | 34:d6ce8f961b8b | 871 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 872 | |
ranaumarnaeem | 34:d6ce8f961b8b | 873 | /* option value */ |
ranaumarnaeem | 34:d6ce8f961b8b | 874 | memcpy(p, op->val, op->len); |
ranaumarnaeem | 34:d6ce8f961b8b | 875 | p += op->len; |
ranaumarnaeem | 34:d6ce8f961b8b | 876 | |
ranaumarnaeem | 34:d6ce8f961b8b | 877 | return p - buf; |
ranaumarnaeem | 34:d6ce8f961b8b | 878 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 879 | |
ranaumarnaeem | 34:d6ce8f961b8b | 880 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 881 | * @brief Format the options in a message |
ranaumarnaeem | 34:d6ce8f961b8b | 882 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 883 | * @param[in] msg Pointer to a message structure |
ranaumarnaeem | 34:d6ce8f961b8b | 884 | * @param[out] buf Pointer to a buffer to contain the formatted message |
ranaumarnaeem | 34:d6ce8f961b8b | 885 | * @param[in] len Length of the buffer |
ranaumarnaeem | 34:d6ce8f961b8b | 886 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 887 | * @returns Length of the formatted message or error code |
ranaumarnaeem | 34:d6ce8f961b8b | 888 | * @retval >0 Length of the formatted message |
ranaumarnaeem | 34:d6ce8f961b8b | 889 | * @retval <0 Error |
ranaumarnaeem | 34:d6ce8f961b8b | 890 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 891 | static int coap_msg_format_ops(coap_msg_t *msg, char *buf, size_t len) |
ranaumarnaeem | 34:d6ce8f961b8b | 892 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 893 | coap_msg_op_t *op = NULL; |
ranaumarnaeem | 34:d6ce8f961b8b | 894 | unsigned prev_num = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 895 | int num = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 896 | char *p = buf; |
ranaumarnaeem | 34:d6ce8f961b8b | 897 | |
ranaumarnaeem | 34:d6ce8f961b8b | 898 | op = coap_msg_op_list_get_first(&msg->op_list); |
ranaumarnaeem | 34:d6ce8f961b8b | 899 | while (op != NULL) |
ranaumarnaeem | 34:d6ce8f961b8b | 900 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 901 | num = coap_msg_format_op(op, prev_num, p, len); |
ranaumarnaeem | 34:d6ce8f961b8b | 902 | if (num < 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 903 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 904 | return num; |
ranaumarnaeem | 34:d6ce8f961b8b | 905 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 906 | p += num; |
ranaumarnaeem | 34:d6ce8f961b8b | 907 | len -= num; |
ranaumarnaeem | 34:d6ce8f961b8b | 908 | prev_num = coap_msg_op_get_num(op); |
ranaumarnaeem | 34:d6ce8f961b8b | 909 | op = coap_msg_op_get_next(op); |
ranaumarnaeem | 34:d6ce8f961b8b | 910 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 911 | return p - buf; |
ranaumarnaeem | 34:d6ce8f961b8b | 912 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 913 | |
ranaumarnaeem | 34:d6ce8f961b8b | 914 | /** |
ranaumarnaeem | 34:d6ce8f961b8b | 915 | * @brief Format the payload in a message |
ranaumarnaeem | 34:d6ce8f961b8b | 916 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 917 | * @param[in] msg Pointer to a message structure |
ranaumarnaeem | 34:d6ce8f961b8b | 918 | * @param[out] buf Pointer to a buffer to contain the formatted message |
ranaumarnaeem | 34:d6ce8f961b8b | 919 | * @param[in] len Length of the buffer |
ranaumarnaeem | 34:d6ce8f961b8b | 920 | * |
ranaumarnaeem | 34:d6ce8f961b8b | 921 | * @returns Length of the formatted message or error code |
ranaumarnaeem | 34:d6ce8f961b8b | 922 | * @retval >0 Length of the formatted message |
ranaumarnaeem | 34:d6ce8f961b8b | 923 | * @retval <0 Error |
ranaumarnaeem | 34:d6ce8f961b8b | 924 | */ |
ranaumarnaeem | 34:d6ce8f961b8b | 925 | static int coap_msg_format_payload(coap_msg_t *msg, char *buf, size_t len) |
ranaumarnaeem | 34:d6ce8f961b8b | 926 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 927 | if (msg->payload_len == 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 928 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 929 | return 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 930 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 931 | if (msg->payload_len + 1 > len) |
ranaumarnaeem | 34:d6ce8f961b8b | 932 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 933 | return -ENOSPC; |
ranaumarnaeem | 34:d6ce8f961b8b | 934 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 935 | buf[0] = 0xff; |
ranaumarnaeem | 34:d6ce8f961b8b | 936 | memcpy(&buf[1], msg->payload, msg->payload_len); |
ranaumarnaeem | 34:d6ce8f961b8b | 937 | return msg->payload_len + 1; |
ranaumarnaeem | 34:d6ce8f961b8b | 938 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 939 | |
ranaumarnaeem | 34:d6ce8f961b8b | 940 | int coap_msg_format(coap_msg_t *msg, char *buf, size_t len) |
ranaumarnaeem | 34:d6ce8f961b8b | 941 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 942 | int num = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 943 | char *p = buf; |
ranaumarnaeem | 34:d6ce8f961b8b | 944 | int ret = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 945 | |
ranaumarnaeem | 34:d6ce8f961b8b | 946 | ret = coap_msg_check(msg); |
ranaumarnaeem | 34:d6ce8f961b8b | 947 | if (ret != 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 948 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 949 | return ret; |
ranaumarnaeem | 34:d6ce8f961b8b | 950 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 951 | num = coap_msg_format_hdr(msg, p, len); |
ranaumarnaeem | 34:d6ce8f961b8b | 952 | if (num < 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 953 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 954 | return num; |
ranaumarnaeem | 34:d6ce8f961b8b | 955 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 956 | p += num; |
ranaumarnaeem | 34:d6ce8f961b8b | 957 | len -= num; |
ranaumarnaeem | 34:d6ce8f961b8b | 958 | num = coap_msg_format_token(msg, p, len); |
ranaumarnaeem | 34:d6ce8f961b8b | 959 | if (num < 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 960 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 961 | return num; |
ranaumarnaeem | 34:d6ce8f961b8b | 962 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 963 | p += num; |
ranaumarnaeem | 34:d6ce8f961b8b | 964 | len -= num; |
ranaumarnaeem | 34:d6ce8f961b8b | 965 | num = coap_msg_format_ops(msg, p, len); |
ranaumarnaeem | 34:d6ce8f961b8b | 966 | if (num < 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 967 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 968 | return num; |
ranaumarnaeem | 34:d6ce8f961b8b | 969 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 970 | p += num; |
ranaumarnaeem | 34:d6ce8f961b8b | 971 | len -= num; |
ranaumarnaeem | 34:d6ce8f961b8b | 972 | num = coap_msg_format_payload(msg, p, len); |
ranaumarnaeem | 34:d6ce8f961b8b | 973 | if (num < 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 974 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 975 | return num; |
ranaumarnaeem | 34:d6ce8f961b8b | 976 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 977 | p += num; |
ranaumarnaeem | 34:d6ce8f961b8b | 978 | return p - buf; |
ranaumarnaeem | 34:d6ce8f961b8b | 979 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 980 | |
ranaumarnaeem | 34:d6ce8f961b8b | 981 | int coap_msg_copy(coap_msg_t *dst, coap_msg_t *src) |
ranaumarnaeem | 34:d6ce8f961b8b | 982 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 983 | coap_msg_op_t *op = NULL; |
ranaumarnaeem | 34:d6ce8f961b8b | 984 | int ret = 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 985 | |
ranaumarnaeem | 34:d6ce8f961b8b | 986 | dst->ver = src->ver; |
ranaumarnaeem | 34:d6ce8f961b8b | 987 | ret = coap_msg_set_type(dst, coap_msg_get_type(src)); |
ranaumarnaeem | 34:d6ce8f961b8b | 988 | if (ret < 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 989 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 990 | return ret; |
ranaumarnaeem | 34:d6ce8f961b8b | 991 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 992 | ret = coap_msg_set_code(dst, coap_msg_get_code_class(src), coap_msg_get_code_detail(src)); |
ranaumarnaeem | 34:d6ce8f961b8b | 993 | if (ret < 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 994 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 995 | return ret; |
ranaumarnaeem | 34:d6ce8f961b8b | 996 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 997 | ret = coap_msg_set_msg_id(dst, coap_msg_get_msg_id(src)); |
ranaumarnaeem | 34:d6ce8f961b8b | 998 | if (ret < 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 999 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 1000 | return ret; |
ranaumarnaeem | 34:d6ce8f961b8b | 1001 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 1002 | ret = coap_msg_set_token(dst, coap_msg_get_token(src), coap_msg_get_token_len(src)); |
ranaumarnaeem | 34:d6ce8f961b8b | 1003 | if (ret < 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 1004 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 1005 | return ret; |
ranaumarnaeem | 34:d6ce8f961b8b | 1006 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 1007 | op = coap_msg_get_first_op(src); |
ranaumarnaeem | 34:d6ce8f961b8b | 1008 | while (op != NULL) |
ranaumarnaeem | 34:d6ce8f961b8b | 1009 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 1010 | ret = coap_msg_add_op(dst, coap_msg_op_get_num(op), coap_msg_op_get_len(op), coap_msg_op_get_val(op)); |
ranaumarnaeem | 34:d6ce8f961b8b | 1011 | if (ret < 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 1012 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 1013 | return ret; |
ranaumarnaeem | 34:d6ce8f961b8b | 1014 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 1015 | op = coap_msg_op_get_next(op); |
ranaumarnaeem | 34:d6ce8f961b8b | 1016 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 1017 | ret = coap_msg_set_payload(dst, coap_msg_get_payload(src), coap_msg_get_payload_len(src)); |
ranaumarnaeem | 34:d6ce8f961b8b | 1018 | if (ret < 0) |
ranaumarnaeem | 34:d6ce8f961b8b | 1019 | { |
ranaumarnaeem | 34:d6ce8f961b8b | 1020 | return ret; |
ranaumarnaeem | 34:d6ce8f961b8b | 1021 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 1022 | return 0; |
ranaumarnaeem | 34:d6ce8f961b8b | 1023 | } |
ranaumarnaeem | 34:d6ce8f961b8b | 1024 |