From c7e9359f02c90a2fa0e02b9d89138bacf112b8b8 Mon Sep 17 00:00:00 2001 From: Jon Shallow Date: Thu, 26 Apr 2018 10:32:22 +0100 Subject: [PATCH] Make coap_encode_var_bytes() by replacing with coap_encode_var_safe() Update code / examples / man pages with the updated function. include/coap/libcoap.h: Add in new define COAP_DEPRECATED to generate compiler warnings when used include/coap/encode.h New coap_encode_var_safe() function that includes the size of the output buffer as a parameter. Make coap_encode_var_bytes() a wrapper for coap_encode_var_safe() and mark it as COAP_DEPRECATED for backwards compatability src/encode.c: New coap_encode_var_safe() function that includes the size of the output buffer as a parameter. examples/coap-server.c: examples/contiki/server.c: Make the ticks resource consistent in case --- examples/client.c | 12 ++-- examples/coap-rd.c | 14 ++--- examples/coap-server.c | 22 ++++--- examples/contiki/coap-observer.c | 4 +- examples/contiki/server.c | 28 +++++---- examples/etsi_iot_01.c | 18 ++++-- include/coap/encode.h | 48 +++++++++++++--- include/coap/libcoap.h | 11 ++++ include/coap/pdu.h | 4 +- libcoap-2.map | 2 +- libcoap-2.sym | 2 +- man/Makefile.am | 2 +- man/coap_handler.txt.in | 14 +++-- man/coap_observe.txt.in | 9 ++- man/coap_pdu_setup.txt.in | 99 ++++++++++++++++---------------- man/coap_resource.txt.in | 6 +- src/block.c | 25 ++++---- src/coap_session.c | 3 +- src/encode.c | 8 ++- src/net.c | 4 +- tests/test_wellknown.c | 9 +-- 21 files changed, 215 insertions(+), 129 deletions(-) diff --git a/examples/client.c b/examples/client.c index 7d6f7abb..6ac00638 100644 --- a/examples/client.c +++ b/examples/client.c @@ -188,7 +188,7 @@ clear_obs(coap_context_t *ctx, coap_session_t *session) { if (!coap_add_option(pdu, COAP_OPTION_OBSERVE, - coap_encode_var_bytes(buf, COAP_OBSERVE_CANCEL), + coap_encode_var_safe(buf, sizeof(buf), COAP_OBSERVE_CANCEL), buf)) { coap_log(LOG_CRIT, "cannot add option Observe: %u\n", COAP_OBSERVE_CANCEL); goto error; @@ -369,7 +369,7 @@ message_handler(struct coap_context_t *ctx, (coap_opt_block_num(block_opt) + 1)); coap_add_option(pdu, blktype, - coap_encode_var_bytes(buf, + coap_encode_var_safe(buf, sizeof(buf), ((coap_opt_block_num(block_opt) + 1) << 4) | COAP_OPT_BLOCK_SZX(block_opt)), buf); @@ -446,7 +446,7 @@ message_handler(struct coap_context_t *ctx, coap_log(LOG_DEBUG, "send block %d\n", block.num); coap_add_option(pdu, COAP_OPTION_BLOCK1, - coap_encode_var_bytes(buf, + coap_encode_var_safe(buf, sizeof(buf), (block.num << 4) | (block.m << 3) | block.szx), buf); coap_add_block(pdu, @@ -612,7 +612,7 @@ cmdline_content_type(char *arg, uint16_t key) { } for (i = 0; i < valcnt; ++i) { - node = coap_new_optlist(key, coap_encode_var_bytes(buf, value[i]), buf); + node = coap_new_optlist(key, coap_encode_var_safe(buf, sizeof(buf), value[i]), buf); if (node) { coap_insert_optlist(&optlist, node); } @@ -680,7 +680,7 @@ cmdline_uri(char *arg, int create_uri_opts) { if (uri.port != get_default_port(&uri) && create_uri_opts) { coap_insert_optlist(&optlist, coap_new_optlist(COAP_OPTION_URI_PORT, - coap_encode_var_bytes(portbuf, uri.port), + coap_encode_var_safe(portbuf, sizeof(portbuf), uri.port), portbuf)); } @@ -753,7 +753,7 @@ set_blocksize(void) { block.m = (opt == COAP_OPTION_BLOCK1) && ((1u << (block.szx + 4)) < payload.length); - opt_length = coap_encode_var_bytes(buf, + opt_length = coap_encode_var_safe(buf, sizeof(buf), (block.num << 4 | block.m << 3 | block.szx)); coap_insert_optlist(&optlist, coap_new_optlist(opt, opt_length, buf)); diff --git a/examples/coap-rd.c b/examples/coap-rd.c index 92b414d4..2046e8b9 100644 --- a/examples/coap-rd.c +++ b/examples/coap-rd.c @@ -105,9 +105,9 @@ hnd_get_resource(coap_context_t *ctx UNUSED_PARAM, coap_add_option(response, COAP_OPTION_CONTENT_TYPE, - coap_encode_var_bytes(buf, - COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), - buf); + coap_encode_var_safe(buf, sizeof(buf), + COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), + buf); if (rd && rd->etag_len) coap_add_option(response, COAP_OPTION_ETAG, rd->etag_len, rd->etag); @@ -231,13 +231,13 @@ hnd_get_rd(coap_context_t *ctx UNUSED_PARAM, coap_add_option(response, COAP_OPTION_CONTENT_TYPE, - coap_encode_var_bytes(buf, - COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), - buf); + coap_encode_var_safe(buf, sizeof(buf), + COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), + buf); coap_add_option(response, COAP_OPTION_MAXAGE, - coap_encode_var_bytes(buf, 0x2ffff), buf); + coap_encode_var_safe(buf, sizeof(buf), 0x2ffff), buf); } static int diff --git a/examples/coap-server.c b/examples/coap-server.c index 5fa7b286..495a6de7 100644 --- a/examples/coap-server.c +++ b/examples/coap-server.c @@ -82,11 +82,13 @@ hnd_get_index(coap_context_t *ctx UNUSED_PARAM, coap_add_option(response, COAP_OPTION_CONTENT_TYPE, - coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf); + coap_encode_var_safe(buf, sizeof(buf), + COAP_MEDIATYPE_TEXT_PLAIN), + buf); coap_add_option(response, COAP_OPTION_MAXAGE, - coap_encode_var_bytes(buf, 0x2ffff), buf); + coap_encode_var_safe(buf, sizeof(buf), 0x2ffff), buf); coap_add_data(response, strlen(INDEX), (const uint8_t *)INDEX); } @@ -115,17 +117,20 @@ hnd_get_time(coap_context_t *ctx UNUSED_PARAM, if (coap_find_observer(resource, session, token)) { coap_add_option(response, COAP_OPTION_OBSERVE, - coap_encode_var_bytes(buf, resource->observe), buf); + coap_encode_var_safe(buf, sizeof(buf), resource->observe), + buf); } if (my_clock_base) coap_add_option(response, COAP_OPTION_CONTENT_FORMAT, - coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf); + coap_encode_var_safe(buf, sizeof(buf), + COAP_MEDIATYPE_TEXT_PLAIN), + buf); coap_add_option(response, COAP_OPTION_MAXAGE, - coap_encode_var_bytes(buf, 0x01), buf); + coap_encode_var_safe(buf, sizeof(buf), 0x01), buf); if (my_clock_base) { @@ -134,7 +139,7 @@ hnd_get_time(coap_context_t *ctx UNUSED_PARAM, now = my_clock_base + (t / COAP_TICKS_PER_SECOND); if (query != NULL - && memcmp(query->s, "ticks", min(5, query->length)) == 0) { + && coap_string_equal(query, coap_make_str_const("ticks"))) { /* output ticks */ len = snprintf((char *)buf, sizeof(buf), "%u", (unsigned int)now); coap_add_data(response, len, buf); @@ -195,7 +200,8 @@ hnd_put_time(coap_context_t *ctx UNUSED_PARAM, response->code = COAP_RESPONSE_CODE(400); coap_add_option(response, COAP_OPTION_CONTENT_FORMAT, - coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf); + coap_encode_var_safe(buf, sizeof(buf), + COAP_MEDIATYPE_TEXT_PLAIN), buf); coap_add_data(response, 22, (const uint8_t*)"Invalid set time value"); /* re-init as value is bad */ my_clock_base = clock_offset; @@ -313,7 +319,7 @@ init_resources(coap_context_t *ctx) { coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0); coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"Internal Clock\""), 0); - coap_add_attr(r, coap_make_str_const("rt"), coap_make_str_const("\"Ticks\""), 0); + coap_add_attr(r, coap_make_str_const("rt"), coap_make_str_const("\"ticks\""), 0); coap_add_attr(r, coap_make_str_const("if"), coap_make_str_const("\"clock\""), 0); coap_add_resource(ctx, r); diff --git a/examples/contiki/coap-observer.c b/examples/contiki/coap-observer.c index 12115dac..2d4457d9 100644 --- a/examples/contiki/coap-observer.c +++ b/examples/contiki/coap-observer.c @@ -140,7 +140,9 @@ PROCESS_THREAD(coap_server_process, ev, data) if (uri.port != COAP_DEFAULT_PORT) { unsigned char portbuf[2]; coap_add_option(request, COAP_OPTION_URI_PORT, - coap_encode_var_bytes(portbuf, uri.port), portbuf); + coap_encode_var_safe(portbuf, sizeof(portbuf), + uri.port), + portbuf); } if (uri.path.length) { diff --git a/examples/contiki/server.c b/examples/contiki/server.c index 9ed0b055..d2d7230c 100644 --- a/examples/contiki/server.c +++ b/examples/contiki/server.c @@ -112,15 +112,19 @@ hnd_get_time(coap_context_t *ctx, struct coap_resource_t *resource, if (coap_find_observer(resource, peer, token)) { coap_add_option(response, COAP_OPTION_OBSERVE, - coap_encode_var_bytes(buf, resource->observe), buf); + coap_encode_var_safe(buf, sizeof(buf), + resource->observe), + buf); } if (my_clock_base) coap_add_option(response, COAP_OPTION_CONTENT_FORMAT, - coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf); + coap_encode_var_safe(buf, sizeof(buf), + COAP_MEDIATYPE_TEXT_PLAIN), + buf); coap_add_option(response, COAP_OPTION_MAXAGE, - coap_encode_var_bytes(buf, 0x01), buf); + coap_encode_var_safe(buf, sizeof(buf), 0x01), buf); if (my_clock_base) { @@ -146,14 +150,14 @@ init_coap_resources(coap_context_t *ctx) { r = coap_resource_init(NULL, 0, 0); coap_register_handler(r, COAP_REQUEST_GET, hnd_get_index); - coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0); - coap_add_attr(r, (unsigned char *)"title", 5, (unsigned char *)"\"General Info\"", 14, 0); + coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0); + coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"General Info\""), 0); coap_add_resource(ctx, r); #endif /* store clock base to use in /time */ my_clock_base = clock_offset; - r = coap_resource_init((unsigned char *)"time", 4, 0); + r = coap_resource_init(coap_make_str_const("time"), 0); if (!r) goto error; @@ -164,18 +168,18 @@ init_coap_resources(coap_context_t *ctx) { coap_register_handler(r, COAP_REQUEST_PUT, hnd_put_time); coap_register_handler(r, COAP_REQUEST_DELETE, hnd_delete_time); #endif - coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0); - /* coap_add_attr(r, (unsigned char *)"title", 5, (unsigned char *)"\"Internal Clock\"", 16, 0); */ - coap_add_attr(r, (unsigned char *)"rt", 2, (unsigned char *)"\"Ticks\"", 7, 0); - coap_add_attr(r, (unsigned char *)"if", 2, (unsigned char *)"\"clock\"", 7, 0); + coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0); + /* coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"Internal Clock\""), 0); */ + coap_add_attr(r, coap_make_str_const("rt"), coap_make_str_const("\"ticks\""), 0); + coap_add_attr(r, coap_make_str_const("if"), coap_make_str_const("\"clock\""), 0); coap_add_resource(ctx, r); #if 0 #ifndef WITHOUT_ASYNC - r = coap_resource_init((unsigned char *)"async", 5, 0); + r = coap_resource_init(coap_make_str_const("async"), 0); coap_register_handler(r, COAP_REQUEST_GET, hnd_get_async); - coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0); + coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0); coap_add_resource(ctx, r); #endif /* WITHOUT_ASYNC */ #endif diff --git a/examples/etsi_iot_01.c b/examples/etsi_iot_01.c index 1f5d5284..c8a989e1 100644 --- a/examples/etsi_iot_01.c +++ b/examples/etsi_iot_01.c @@ -134,10 +134,12 @@ hnd_get_index(coap_context_t *ctx, struct coap_resource_t *resource, response->code = COAP_RESPONSE_CODE(205); coap_add_option(response, COAP_OPTION_CONTENT_TYPE, - coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf); + coap_encode_var_safe(buf, sizeof(buf), + COAP_MEDIATYPE_TEXT_PLAIN), + buf); coap_add_option(response, COAP_OPTION_MAXAGE, - coap_encode_var_bytes(buf, 0x2ffff), buf); + coap_encode_var_safe(buf, sizeof(buf), 0x2ffff), buf); coap_add_data(response, strlen(INDEX), (unsigned char *)INDEX); } @@ -162,7 +164,9 @@ hnd_get_resource(coap_context_t *ctx, struct coap_resource_t *resource, response->code = COAP_RESPONSE_CODE(205); coap_add_option(response, COAP_OPTION_CONTENT_TYPE, - coap_encode_var_bytes(buf, test_payload->media_type), buf); + coap_encode_var_safe(buf, sizeof(buf), + test_payload->media_type), + buf); /* add etag for the resource */ if (test_payload->flags & REQUIRE_ETAG) { @@ -381,7 +385,9 @@ hnd_get_query(coap_context_t *ctx, struct coap_resource_t *resource, response->code = COAP_RESPONSE_CODE(205); coap_add_option(response, COAP_OPTION_CONTENT_TYPE, - coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf); + coap_encode_var_safe(buf, sizeof(buf), + COAP_MEDIATYPE_TEXT_PLAIN), + buf); coap_option_filter_clear(f); coap_option_setb(f, COAP_OPTION_URI_QUERY); @@ -480,7 +486,9 @@ check_async(coap_context_t *ctx, coap_tick_t now) { coap_add_token(response, async->tokenlen, async->token); coap_add_option(response, COAP_OPTION_CONTENT_TYPE, - coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf); + coap_encode_var_safe(buf, sizeof(buf), + COAP_MEDIATYPE_TEXT_PLAIN), + buf); coap_add_data(response, 4, (unsigned char *)"done"); diff --git a/include/coap/encode.h b/include/coap/encode.h index 582ad31b..334c5c79 100644 --- a/include/coap/encode.h +++ b/include/coap/encode.h @@ -46,16 +46,50 @@ extern int coap_flsll(long long i); #define COAP_PSEUDOFP_ENCODE_8_4_UP(v,ls,s) (v < HIBIT ? v : (ls = coap_fls(v) - Nn, (s = (((v + ((1<> ls) & MMASK)), s == 0 ? HIBIT + ls + 1 : s + ls)) /** - * Decodes multiple-length byte sequences. buf points to an input byte sequence - * of length len. Returns the decoded value. + * Decodes multiple-length byte sequences. @p buf points to an input byte + * sequence of length @p length. Returns the decoded value. + * + * @param buf The input byte sequence to decode from + * @param length The length of the input byte sequence + * + * @return The decoded value */ -unsigned int coap_decode_var_bytes(const uint8_t *buf, unsigned int len); +unsigned int coap_decode_var_bytes(const uint8_t *buf, unsigned int length); /** - * Encodes multiple-length byte sequences. buf points to an output buffer of - * sufficient length to store the encoded bytes. val is the value to encode. - * Returns the number of bytes used to encode val or 0 on error. + * Encodes multiple-length byte sequences. @p buf points to an output buffer of + * sufficient length to store the encoded bytes. @p value is the value to + * encode. + * Returns the number of bytes used to encode @p value or 0 on error. + * + * @param buf The output buffer to decode into + * @param length The output buffer size to encode into (must be sufficient) + * @param value The value to encode into the buffer + * + * @return The number of bytes used to encode @p value or @c 0 on error. */ -unsigned int coap_encode_var_bytes(uint8_t *buf, unsigned int val); +unsigned int coap_encode_var_safe(uint8_t *buf, + size_t length, + unsigned int value); + +/** + * @deprecated. Provided for backward compatability. As @p value has a + * maximum value of 0xffffffff, and buf is usually defined as an array, it + * is unsafe to continue to use this variant if buf[] is less than buf[4]. + * + * For example + * char buf[1],oops; + * .. + * coap_encode_var_bytes(buf, 0xfff); + * would cause oops to get overwritten. This error can only be found by code + * inspection. + * coap_encode_var_safe(buf, sizeof(buf), 0xfff); + * would catch this error at run-time and should be used instead. + */ +COAP_STATIC_INLINE COAP_DEPRECATED int +coap_encode_var_bytes(uint8_t *buf, unsigned int value +) { + return coap_encode_var_safe(buf, sizeof(value), value); +} #endif /* _COAP_ENCODE_H_ */ diff --git a/include/coap/libcoap.h b/include/coap/libcoap.h index fd25ec51..12d56a16 100644 --- a/include/coap/libcoap.h +++ b/include/coap/libcoap.h @@ -39,6 +39,17 @@ typedef USHORT in_port_t; # endif # endif #endif +#ifndef COAP_DEPRECATED +# if defined(__cplusplus) +# define COAP_DEPRECATED __attribute__ ((deprecated)) +# else +# if defined(_MSC_VER) +# define COAP_DEPRECATED __declspec(deprecated) +# else +# define COAP_DEPRECATED __attribute__ ((deprecated)) +# endif +# endif +#endif void coap_startup(void); diff --git a/include/coap/pdu.h b/include/coap/pdu.h index 3613b638..97a74c13 100644 --- a/include/coap/pdu.h +++ b/include/coap/pdu.h @@ -234,13 +234,13 @@ typedef int coap_tid_t; #define COAP_PAYLOAD_START 0xFF /* payload marker */ /** - * DEPRECATED. Use coap_optlist_t instead. + * @deprecated. Use coap_optlist_t instead. * * Structures for more convenient handling of options. (To be used with ordered * coap_list_t.) The option's data will be added to the end of the coap_option * structure (see macro COAP_OPTION_DATA). */ -typedef struct { +COAP_DEPRECATED typedef struct { uint16_t key; /* the option key (no delta coding) */ unsigned int length; } coap_option; diff --git a/libcoap-2.map b/libcoap-2.map index 06453357..5ee5bf20 100644 --- a/libcoap-2.map +++ b/libcoap-2.map @@ -42,7 +42,7 @@ global: coap_dtls_get_log_level; coap_dtls_is_supported; coap_dtls_set_log_level; - coap_encode_var_bytes; + coap_encode_var_safe; coap_endpoint_get_session; coap_endpoint_new_dtls_session; coap_endpoint_set_default_mtu; diff --git a/libcoap-2.sym b/libcoap-2.sym index 750514ab..1d1c5584 100644 --- a/libcoap-2.sym +++ b/libcoap-2.sym @@ -40,7 +40,7 @@ coap_dispatch coap_dtls_get_log_level coap_dtls_is_supported coap_dtls_set_log_level -coap_encode_var_bytes +coap_encode_var_safe coap_endpoint_get_session coap_endpoint_new_dtls_session coap_endpoint_set_default_mtu diff --git a/man/Makefile.am b/man/Makefile.am index d45f770d..b1447221 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -53,7 +53,7 @@ install-man: install-man3 install-man5 install-man7 @echo ".so man3/coap_context.3" > coap_session_reference.3 @echo ".so man3/coap_context.3" > coap_session_release.3 @echo ".so man3/coap_context.3" > coap_session_set_mtu.3 - @echo ".so man3/coap_pdu_setup.3" > coap_encode_var_bytes.3 + @echo ".so man3/coap_pdu_setup.3" > coap_encode_var_safe.3 @echo ".so man3/coap_pdu_setup.3" > coap_split_path.3 @echo ".so man3/coap_pdu_setup.3" > coap_split_query.3 $(INSTALL_DATA) *.3 "$(DESTDIR)$(man3dir)" diff --git a/man/coap_handler.txt.in b/man/coap_handler.txt.in index 16bd00b7..13b1381d 100644 --- a/man/coap_handler.txt.in +++ b/man/coap_handler.txt.in @@ -126,6 +126,7 @@ EXAMPLES -- #include +void hnd_get_time(coap_context_t *ctx, coap_resource_t *resource, coap_session_t *session, coap_pdu_t *request, coap_string_t *token, coap_string_t *query, coap_pdu_t *response) { @@ -142,22 +143,25 @@ coap_string_t *query, coap_pdu_t *response) { if (coap_find_observer(resource, session, token)) { coap_add_option(response, COAP_OPTION_OBSERVE, - coap_encode_var_bytes(buf, resource->observe), buf); + coap_encode_var_safe(buf, sizeof(buf), resource->observe), + buf); } /* Response is in plain text format */ coap_add_option(response, - COAP_OPTION_CONTENT_FORMAT, - coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf); + COAP_OPTION_CONTENT_FORMAT, + coap_encode_var_safe(buf, sizeof (buf), + COAP_MEDIATYPE_TEXT_PLAIN), + buf); /* Report on how long this response is valid for */ coap_add_option(response, COAP_OPTION_MAXAGE, - coap_encode_var_bytes(buf, 0x01), buf); + coap_encode_var_safe(buf, sizeof(buf), 0x01), buf); now = time(NULL); - if (query != NULL && memcmp(query->s, "secs", min(4, query->length)) == 0) { + if (query != NULL && coap_string_equal(query, coap_make_str_const("secs"))) { /* Output secs since Jan 1 1970 */ len = snprintf((char *)buf, sizeof(buf), "%lu", now); coap_add_data(response, len, buf); diff --git a/man/coap_observe.txt.in b/man/coap_observe.txt.in index 1fb5863f..933671b4 100644 --- a/man/coap_observe.txt.in +++ b/man/coap_observe.txt.in @@ -132,18 +132,21 @@ coap_string_t *query, coap_pdu_t *response) { if (coap_find_observer(resource, session, token)) { coap_add_option(response, COAP_OPTION_OBSERVE, - coap_encode_var_bytes(buf, resource->observe), buf); + coap_encode_var_safe(buf, sizeof(buf), resource->observe), + buf); } /* Response is in plain text format */ coap_add_option(response, COAP_OPTION_CONTENT_FORMAT, - coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf); + coap_encode_var_safe(buf, sizeof(buf), + COAP_MEDIATYPE_TEXT_PLAIN), + buf); /* Report on how long this response is valid for */ coap_add_option(response, COAP_OPTION_MAXAGE, - coap_encode_var_bytes(buf, 0x01), buf); + coap_encode_var_safe(buf, sizeof(buf), 0x01), buf); now = time(NULL); diff --git a/man/coap_pdu_setup.txt.in b/man/coap_pdu_setup.txt.in index b1e76523..0df70f09 100644 --- a/man/coap_pdu_setup.txt.in +++ b/man/coap_pdu_setup.txt.in @@ -10,7 +10,7 @@ coap_pdu_setup(3) NAME ---- -coap_pdu_setup, coap_pdu_init, coap_add_token, coap_new_optlist, +coap_pdu_setup, coap_pdu_init, coap_add_token, coap_new_optlist, coap_insert_optlist, coap_delete_optlist, coap_add_optlist_pdu, coap_add_option, coap_add_data - work with CoAP PDUs @@ -21,7 +21,7 @@ SYNOPSIS *coap_pdu_t *coap_pdu_init(uint8_t _type_, uint8_t _code_, uint16_t _message_id_, size_t _max_size_);* -*int coap_add_token(coap_pdu_t *_pdu_, size_t _length_, +*int coap_add_token(coap_pdu_t *_pdu_, size_t _length_, const uint8_t *_data_);* *coap_optlist_t *coap_new_optlist(uint16_t _number_, size_t _length_, @@ -39,7 +39,8 @@ const uint8_t *_data_);* *int coap_add_data(coap_pdu_t *_pdu_, size_t _length_, const uint8_t *_data_);* -*unsigned int coap_encode_var_bytes(uint8_t *_buffer_, unsigned int _value_);* +*unsigned int coap_encode_var_safe(uint8_t *_buffer_, size_t _size_, +unsigned int _value_);* *int coap_split_path(const uint8_t *_path_, size_t _length_, uint8_t *_buffer_, size_t *_buflen_);* @@ -58,25 +59,25 @@ The CoAP PDU is of the form --header--|--optional token--|--optional options--|--optional payload-- The PDU must be built in the correct order, from left to right. In particular, -the options need to be added in the correct numerical option order as they are -stored in the PDU using relative numeric offsets from the previous option +the options need to be added in the correct numerical option order as they are +stored in the PDU using relative numeric offsets from the previous option number. -There are option list functions available where options can be added to a -chained list of options and then the chain list is sorted and then be added to +There are option list functions available where options can be added to a +chained list of options and then the chain list is sorted and then be added to the PDU. -Typically for clients, when creating a request, the PDU needs to be created +Typically for clients, when creating a request, the PDU needs to be created before filling it with the appropriate information. Typically with a server, the response PDU, with the optional token already added -in, will already be created before the response handler is called, and the -response PDU will need to be updated as appropriate starting with the optional -options. Note that updating the response pdu's code variable will cause the -response pdu to get transmitted. If code does not get updated, then the +in, will already be created before the response handler is called, and the +response PDU will need to be updated as appropriate starting with the optional +options. Note that updating the response pdu's code variable will cause the +response pdu to get transmitted. If code does not get updated, then the response pdu is freed off by the underlying library. -The *coap_pdu_init*() function returns a newly created _PDU_ of type +The *coap_pdu_init*() function returns a newly created _PDU_ of type _coap_pdu_t_*. _type_ is one of the following [horizontal] @@ -111,18 +112,18 @@ The _message_id_ must be unique per request (which is not the same as the token), and must not be reused within EXCHANGE_LIFETIME (usually 247 seconds). To automate this, the function coap_new_message_id(session) should be called. -The _max_size_ parameter defines the maximum size of a _PDU_ and is usually -determined by calling coap_session_max_pdu_size(session); +The _max_size_ parameter defines the maximum size of a _PDU_ and is usually +determined by calling coap_session_max_pdu_size(session); -The *coap_add_token*() function adds in the specified token's _data_ of length +The *coap_add_token*() function adds in the specified token's _data_ of length _length_ to the PDU _pdu_. The maximum length of the token is 8 bytes. -Adding the token must be done before any options or data are added. +Adding the token must be done before any options or data are added. This function must only be called once per _pdu_, and must not be called in the appropriate response handler. The *coap_new_optlist*() function returns a newly created _optlist_ entry of -type _coap_optlist_t_*. The _number_ specifies which CoAP option is to be -used, and is one of the COAP_OPTION_* definitions. The _length_ is the length +type _coap_optlist_t_*. The _number_ specifies which CoAP option is to be +used, and is one of the COAP_OPTION_* definitions. The _length_ is the length of the data of the option, and _data_ points to the content of the option. The following is the current list of options with their numeric value @@ -149,22 +150,22 @@ The following is the current list of options with their numeric value ---- See FURTHER INFORMATION as to how to get the latest list. -The *coap_insert_optlist*() function adds the _optlist_ entry onto the +The *coap_insert_optlist*() function adds the _optlist_ entry onto the _optlist_chain_ and then sorts the _optlist_chain_ before returning. The initial _optlist_chain_ entry needs to be set to NULL before this function is first called. The coap_delete_optlist() function has to be called to free off all the _optlist_chain_ entries. -The *coap_delete_optlist*() function deletes and frees off all the optlist +The *coap_delete_optlist*() function deletes and frees off all the optlist entries in the _optlist_chain_. -The *coap_add_optlist_pdu*() function sorts all of the entries in -_optlist_chain_ into ascending option numeric order and adds all the entries +The *coap_add_optlist_pdu*() function sorts all of the entries in +_optlist_chain_ into ascending option numeric order and adds all the entries to the _pdu_. This function does not free off the entries in _optlist_chain_. This function must be called after adding any token and before adding in the payload data. -The *coap_add_option*() function adds in the specified option of type _number_ +The *coap_add_option*() function adds in the specified option of type _number_ with _data_ of length _length_ to the PDU _pdu_. It is critical that options are added to the _pdu_ with _number_ either being the same or greater than the previous option _number_ that was added. @@ -173,27 +174,27 @@ The *coap_add_data*() function added in the specified payload _data_ of length _length_ to the PDU _pdu_. Adding the payload data must be done after any token or options are added. This function must only be called once per _pdu_. -The *coap_encode_var_bytes*() function encodes _value_ into _buffer_. -_buffer_ needs to be dimensioned to be at least the sizeof(int) to prevent -any _buffer_ overflows. +The *coap_encode_var_safe*() function encodes _value_ into _buffer_ which has +a size of _size_ in bytes. Normally, the _buffer_ size should be at least +the sizeof(int) bytes unless you definitely know less space is required. -The *coap_split_path*() function splits up _path_ of length _length_ and +The *coap_split_path*() function splits up _path_ of length _length_ and places the result in _buffer_ which has a size of _buflen_. _buflen_ needs to be preset with the size of _buffer_ before the function call, and then _buflen_ is updated whith the actual size of _buffer_ used. -The *coap_split_query*() function splits up _query_ of length _length_ and +The *coap_split_query*() function splits up _query_ of length _length_ and places the result in _buffer_ which has a size of _buflen_. _buflen_ needs to be preset with the size of _buffer_ before the function call, and then _buflen_ is updated whith the actual size of _buffer_ used. RETURN VALUES ------------- -The *coap_pdu_init*() function returns a newly created _PDU_ or NULL if there -is a malloc or parameter failure. +The *coap_pdu_init*() function returns a newly created _PDU_ or NULL if there +is a malloc or parameter failure. The *coap_new_optlist*() function returns a newly created _optlist_ or NULL -if there is a malloc failure. +if there is a malloc failure. The *coap_add_token*(), *coap_insert_optlist*(), *coap_delete_optlist*(), *coap_add_optlist_pdu*() and *coap_add_data*() @@ -202,7 +203,7 @@ functions return 0 on failure, 1 on success. The *coap_add_optlist*() function returns either the length of the option or 0 on failure. -The *coap_encode_var_bytes*() function returns either the length of bytes +The *coap_encode_var_safe*() function returns either the length of bytes encoded or 0 on failure. EXAMPLES @@ -216,8 +217,8 @@ EXAMPLES static int token = 0; int -build_send_pdu(coap_context_t *context, coap_session_t *session, -uint8_t msgtype, uint8_t request_code, const char *uri, const char *query, +build_send_pdu(coap_context_t *context, coap_session_t *session, +uint8_t msgtype, uint8_t request_code, const char *uri, const char *query, unsigned char *data, size_t length, int observe) { coap_pdu_t *pdu; @@ -249,7 +250,7 @@ unsigned char *data, size_t length, int observe) { buflen = sizeof(buf); res = coap_split_path((const uint8_t*)uri, strlen(uri), sbuf, &buflen); while (res--) { - if (!coap_insert_optlist(&optlist_chain, + if (!coap_insert_optlist(&optlist_chain, coap_new_optlist(COAP_OPTION_URI_PATH, coap_opt_length(sbuf), coap_opt_value(sbuf)))) goto error; @@ -262,7 +263,7 @@ unsigned char *data, size_t length, int observe) { buflen = sizeof(buf); res = coap_split_query((const uint8_t*)query, strlen(query), sbuf, &buflen); while (res--) { - if (!coap_insert_optlist(&optlist_chain, + if (!coap_insert_optlist(&optlist_chain, coap_new_optlist(COAP_OPTION_URI_QUERY, coap_opt_length(sbuf), coap_opt_value(sbuf)))) goto error; @@ -272,7 +273,7 @@ unsigned char *data, size_t length, int observe) { if (request_code == COAP_REQUEST_GET && observe) { /* Indicate that we want to observe this resource */ - if (!coap_insert_optlist(&optlist_chain, + if (!coap_insert_optlist(&optlist_chain, coap_new_optlist(COAP_OPTION_OBSERVE, COAP_OBSERVE_ESTABLISH, NULL))) goto error; @@ -309,9 +310,9 @@ error: -- #include -static void -hnd_get_time(coap_context_t *context, coap_resource_t *resource, -coap_session_t *session, coap_pdu_t *request, coap_string_t *token, +static void +hnd_get_time(coap_context_t *context, coap_resource_t *resource, +coap_session_t *session, coap_pdu_t *request, coap_string_t *token, coap_string_t *query, coap_pdu_t *response) { unsigned char buf[40]; @@ -337,22 +338,25 @@ coap_string_t *query, coap_pdu_t *response) { if (coap_find_observer(resource, session, token)) { coap_add_option(response, COAP_OPTION_OBSERVE, - coap_encode_var_bytes(buf, resource->observe), buf); + coap_encode_var_safe(buf, sizeof(buf), resource->observe), + buf); } /* Response is in plain text format */ coap_add_option(response, - COAP_OPTION_CONTENT_FORMAT, - coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf); + COAP_OPTION_CONTENT_FORMAT, + coap_encode_var_safe(buf, sizeof(buf), + COAP_MEDIATYPE_TEXT_PLAIN), + buf); /* Report on how long this response is valid for (1 second in this case)*/ coap_add_option(response, COAP_OPTION_MAXAGE, - coap_encode_var_bytes(buf, 0x01), buf); + coap_encode_var_safe(buf, sizeof(buf), 0x01), buf); now = time(NULL); - if (query != NULL && memcmp(query->s, "secs", min(4, query->length)) == 0) { + if (query != NULL && coap_string_equal(query, coap_make_str_const("secs"))) { /* Output secs since Jan 1 1970 */ len = snprintf((char *)buf, sizeof(buf), "%lu", now); coap_add_data(response, len, buf); @@ -370,7 +374,6 @@ coap_string_t *query, coap_pdu_t *response) { */ } - -- SEE ALSO @@ -379,7 +382,7 @@ SEE ALSO FURTHER INFORMATION ------------------- -See "RFC7252: The Constrained Application Protocol (CoAP)" for further +See "RFC7252: The Constrained Application Protocol (CoAP)" for further information. See https://www.iana.org/assignments/core-parameters/core-parameters.xhtml#option-numbers diff --git a/man/coap_resource.txt.in b/man/coap_resource.txt.in index 1b5beff1..b42b9f3a 100644 --- a/man/coap_resource.txt.in +++ b/man/coap_resource.txt.in @@ -141,11 +141,13 @@ coap_string_t *query, coap_pdu_t *response) { coap_add_option(response, COAP_OPTION_CONTENT_TYPE, - coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf); + coap_encode_var_safe(buf, sizeof(buf), + COAP_MEDIATYPE_TEXT_PLAIN), + buf); coap_add_option(response, COAP_OPTION_MAXAGE, - coap_encode_var_bytes(buf, 0x2ffff), buf); + coap_encode_var_safe(buf, sizeof(buf), 0x2ffff), buf); coap_add_data(response, strlen(INDEX), (const uint8_t *)INDEX); } diff --git a/src/block.c b/src/block.c index 56084200..83cbf700 100644 --- a/src/block.c +++ b/src/block.c @@ -3,7 +3,7 @@ * Copyright (C) 2010--2012,2015-2016 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ #include "coap_config.h" @@ -25,18 +25,18 @@ unsigned int coap_opt_block_num(const coap_opt_t *block_opt) { unsigned int num = 0; uint16_t len; - + len = coap_opt_length(block_opt); if (len == 0) { return 0; } - + if (len > 1) { - num = coap_decode_var_bytes(coap_opt_value(block_opt), + num = coap_decode_var_bytes(coap_opt_value(block_opt), coap_opt_length(block_opt) - 1); } - + return (num << 4) | ((*COAP_OPT_BLOCK_LAST(block_opt) & 0xF0) >> 4); } @@ -81,7 +81,7 @@ coap_write_block_opt(coap_block_t *block, uint16_t type, debug("illegal block requested\n"); return -2; } - + assert(pdu->max_size > 0); avail = pdu->max_size - pdu->used_size - 4; want = (size_t)1 << (block->szx + 4); @@ -118,15 +118,16 @@ coap_write_block_opt(coap_block_t *block, uint16_t type, } /* to re-encode the block option */ - coap_add_option(pdu, type, coap_encode_var_bytes(buf, ((block->num << 4) | - (block->m << 3) | - block->szx)), + coap_add_option(pdu, type, coap_encode_var_safe(buf, sizeof(buf), + ((block->num << 4) | + (block->m << 3) | + block->szx)), buf); return 1; } -int +int coap_add_block(coap_pdu_t *pdu, unsigned int len, const uint8_t *data, unsigned int block_num, unsigned char block_szx) { unsigned int start; @@ -134,8 +135,8 @@ coap_add_block(coap_pdu_t *pdu, unsigned int len, const uint8_t *data, if (len <= start) return 0; - - return coap_add_data(pdu, + + return coap_add_data(pdu, min(len - start, (1U << (block_szx + 4))), data + start); } diff --git a/src/coap_session.c b/src/coap_session.c index a1396b77..f6d8ee83 100644 --- a/src/coap_session.c +++ b/src/coap_session.c @@ -289,7 +289,8 @@ void coap_session_send_csm(coap_session_t *session) { pdu = coap_pdu_init(COAP_MESSAGE_CON, COAP_SIGNALING_CSM, 0, 16); if ( pdu == NULL || coap_add_option(pdu, COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE, - coap_encode_var_bytes(buf, COAP_DEFAULT_MAX_PDU_RX_SIZE), buf) == 0 + coap_encode_var_safe(buf, sizeof(buf), + COAP_DEFAULT_MAX_PDU_RX_SIZE), buf) == 0 || coap_pdu_encode_header(pdu, session->proto) == 0 ) { coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE); diff --git a/src/encode.c b/src/encode.c index 3d5d960c..fa5968b4 100644 --- a/src/encode.c +++ b/src/encode.c @@ -11,6 +11,8 @@ #endif #include "coap_config.h" +#include "coap.h" +#include "mem.h" #include "encode.h" /* Carsten suggested this when fls() is not available: */ @@ -40,12 +42,16 @@ coap_decode_var_bytes(const uint8_t *buf,unsigned int len) { } unsigned int -coap_encode_var_bytes(uint8_t *buf, unsigned int val) { +coap_encode_var_safe(uint8_t *buf, size_t length, unsigned int val) { unsigned int n, i; for (n = 0, i = val; i && n < sizeof(val); ++n) i >>= 8; + if (n > length) { + assert (n <= length); + return 0; + } i = n; while (i--) { buf[i] = val & 0xff; diff --git a/src/net.c b/src/net.c index d823b430..c7cbfa61 100644 --- a/src/net.c +++ b/src/net.c @@ -1603,10 +1603,10 @@ coap_wellknown_response(coap_context_t *context, coap_session_t *session, /* Add Content-Format. As we have checked for available storage, * nothing should go wrong here. */ - assert(coap_encode_var_bytes(buf, + assert(coap_encode_var_safe(buf, sizeof(buf), COAP_MEDIATYPE_APPLICATION_LINK_FORMAT) == 1); coap_add_option(resp, COAP_OPTION_CONTENT_FORMAT, - coap_encode_var_bytes(buf, + coap_encode_var_safe(buf, sizeof(buf), COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), buf); /* check if Block2 option is required even if not requested */ diff --git a/tests/test_wellknown.c b/tests/test_wellknown.c index 74a97ee0..056f3896 100644 --- a/tests/test_wellknown.c +++ b/tests/test_wellknown.c @@ -192,9 +192,10 @@ t_wellknown5(void) { unsigned char buf[3]; if (!coap_add_option(pdu, COAP_OPTION_BLOCK2, - coap_encode_var_bytes(buf, ((inblock.num << 4) | - (inblock.m << 3) | - inblock.szx)), buf)) { + coap_encode_var_safe(buf, sizeof(buf), + ((inblock.num << 4) | + (inblock.m << 3) | + inblock.szx)), buf)) { CU_FAIL("cannot add Block2 option"); return; } @@ -230,7 +231,7 @@ t_wellknown6(void) { CU_ASSERT_PTR_NOT_NULL(pdu); if (!pdu || !coap_add_option(pdu, COAP_OPTION_BLOCK2, - coap_encode_var_bytes(buf, + coap_encode_var_safe(buf, sizeof(buf), ((block.num << 4) | block.szx)), buf)) { CU_FAIL("cannot create request"); return;