Umar Naeem / C027_SupportTest_coapp

Dependencies:   C027_Support mbed-dev

Fork of C027_SupportTest_coap by Umar Naeem

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers coap_msg.cpp Source File

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