Skip to content

Commit

Permalink
Merge pull request #476 from mrdeep1/rfc_8768
Browse files Browse the repository at this point in the history
RFC8768: Add in support for CoAP Option Hop Limit loop detection
  • Loading branch information
obgm committed Sep 8, 2020
2 parents 1739507 + 7033555 commit ffc1979
Show file tree
Hide file tree
Showing 11 changed files with 694 additions and 89 deletions.
3 changes: 3 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,11 @@ coap_dtls_session_update_mtu \
coap_dtls_shutdown \
coap_dtls_startup \
coap_epoll_ctl_mod \
coap_insert_option \
coap_io_do_events \
coap_mfree_endpoint \
coap_packet_extract_pbuf \
coap_pdu_check_resize \
coap_pdu_from_pbuf \
coap_session_mfree \
coap_session_new_dtls_session \
Expand All @@ -199,6 +201,7 @@ coap_tls_new_client_session \
coap_tls_new_server_session \
coap_tls_read \
coap_tls_write \
coap_update_option \
"

# This helper is called by libcoap-$(LIBCOAP_API_VERSION).{map,sym} to see if
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ The following RFCs are supported
* RFC8132: PATCH and FETCH Methods for the Constrained Application Protocol (CoAP)

* RFC8323: CoAP (Constrained Application Protocol) over TCP, TLS, and WebSockets
[No WebSockets support]

* RFC8768: Constrained Application Protocol (CoAP) Hop-Limit Option

There is (D)TLS support for the following libraries

Expand Down
65 changes: 47 additions & 18 deletions examples/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,15 +251,16 @@ clear_obs(coap_context_t *ctx, coap_session_t *session) {

for (option = optlist; option; option = option->next ) {
switch (option->number) {
case COAP_OPTION_URI_PORT :
case COAP_OPTION_URI_PATH :
case COAP_OPTION_URI_QUERY :
case COAP_OPTION_URI_PORT : /* 7 */
case COAP_OPTION_URI_PATH : /* 11 */
case COAP_OPTION_URI_QUERY : /* 15 */
case COAP_OPTION_HOP_LIMIT : /* 16 */
if (!coap_add_option(pdu, option->number, option->length,
option->data)) {
goto error;
}
break;
default:
default:
;
}
}
Expand Down Expand Up @@ -453,13 +454,14 @@ message_handler(struct coap_context_t *ctx,
/* create pdu with request for next block */
pdu = coap_new_request(ctx, session, method, NULL, NULL, 0); /* first, create bare PDU w/o any option */
if ( pdu ) {
/* add URI components from optlist */
/* add URI components from optlist in ascending order */
for (option = optlist; option; option = option->next ) {
switch (option->number) {
case COAP_OPTION_URI_HOST :
case COAP_OPTION_URI_PORT :
case COAP_OPTION_URI_PATH :
case COAP_OPTION_URI_QUERY :
case COAP_OPTION_URI_HOST : /* 3 */
case COAP_OPTION_URI_PORT : /* 7 */
case COAP_OPTION_URI_PATH : /* 11 */
case COAP_OPTION_URI_QUERY : /* 15 */
case COAP_OPTION_HOP_LIMIT : /* 16 */
coap_add_option(pdu, option->number, option->length,
option->data);
break;
Expand Down Expand Up @@ -550,11 +552,12 @@ message_handler(struct coap_context_t *ctx,
/* add URI components from optlist */
for (option = optlist; option; option = option->next ) {
switch (option->number) {
case COAP_OPTION_URI_HOST :
case COAP_OPTION_URI_PORT :
case COAP_OPTION_URI_PATH :
case COAP_OPTION_CONTENT_FORMAT :
case COAP_OPTION_URI_QUERY :
case COAP_OPTION_URI_HOST : /* 3 */
case COAP_OPTION_URI_PORT : /* 7 */
case COAP_OPTION_URI_PATH : /* 11 */
case COAP_OPTION_CONTENT_FORMAT : /* 12 */
case COAP_OPTION_URI_QUERY : /* 15 */
case COAP_OPTION_HOP_LIMIT : /* 16 */
coap_add_option(pdu, option->number, option->length,
option->data);
break;
Expand Down Expand Up @@ -641,8 +644,8 @@ usage( const char *program, const char *version) {
"%s\n\n"
"Usage: %s [-a addr] [-b [num,]size] [-e text] [-f file] [-l loss]\n"
"\t\t[-m method] [-o file] [-p port] [-r] [-s duration] [-t type]\n"
"\t\t[-v num] [-A type] [-B seconds] [-K interval] [-N] [-O num,text]\n"
"\t\t[-P addr[:port]] [-T token] [-U]\n"
"\t\t[-v num] [-A type] [-B seconds] [-H hoplimit] [-K interval] [-N]\n"
"\t\t[-O num,text] [-P addr[:port]] [-T token] [-U]\n"
"\t\t[[-h match_hint_file] [-k key] [-u user]]\n"
"\t\t[[-c certfile] [-j keyfile] [-C cafile] [-J pkcs11_pin]\n"
"\t\t[-R root_cafile] [-S match_pki_sni_file]] URI\n"
Expand Down Expand Up @@ -674,6 +677,9 @@ usage( const char *program, const char *version) {
"\t-A type\t\tAccepted media type\n"
"\t-B seconds\tBreak operation after waiting given seconds\n"
"\t \t\t(default is %d)\n"
"\t-H hoplimit\tSet the Hop Limit count to hoplimit for proxies. Must\n"
"\t \t\thave a value between 1 and 255 inclusive.\n"
"\t \t\tDefault is '16'\n"
"\t-K interval\tsend a ping after interval seconds of inactivity\n"
"\t-N \t\tSend NON-confirmable message\n"
"\t-O num,text\tAdd option num with contents text to request. If the\n"
Expand Down Expand Up @@ -722,7 +728,8 @@ usage( const char *program, const char *version) {
"\t \t\t'trusted' for the verification.\n"
"\t \t\tAlternatively, this can point to a directory containing\n"
"\t \t\ta set of CA PEM files\n"
"\n"
);
fprintf( stderr,
"Examples:\n"
"\tcoap-client -m get coap://[::1]/\n"
"\tcoap-client -m get coap://[::1]/.well-known/core\n"
Expand Down Expand Up @@ -788,6 +795,24 @@ cmdline_content_type(char *arg, uint16_t key) {
}
}

static int
cmdline_hop_limit(char *arg) {
coap_optlist_t *node;
uint32_t value;
uint8_t buf[4];

value = strtol(arg, NULL, 10);
if (value < 1 || value > 255) {
return 0;
}
node = coap_new_optlist(COAP_OPTION_HOP_LIMIT, coap_encode_var_safe(buf, sizeof(buf), value), buf);
if (node) {
coap_insert_optlist(&optlist, node);
}
return 1;
}


static uint16_t
get_default_port(const coap_uri_t *u) {
return coap_uri_scheme_is_secure(u) ? COAPS_DEFAULT_PORT : COAP_DEFAULT_PORT;
Expand Down Expand Up @@ -1533,7 +1558,7 @@ main(int argc, char **argv) {
struct sigaction sa;
#endif

while ((opt = getopt(argc, argv, "a:b:c:e:f:h:j:k:l:m:o:p:rs:t:u:v:A:B:C:J:K:NO:P:R:T:U")) != -1) {
while ((opt = getopt(argc, argv, "a:b:c:e:f:h:j:k:l:m:o:p:rs:t:u:v:A:B:C:J:K:H:NO:P:R:T:U")) != -1) {
switch (opt) {
case 'a':
strncpy(node_str, optarg, NI_MAXHOST - 1);
Expand Down Expand Up @@ -1643,6 +1668,10 @@ main(int argc, char **argv) {
exit(1);
}
break;
case 'H':
if (!cmdline_hop_limit(optarg))
fprintf(stderr, "Hop Limit has to be > 0 and < 256\n");
break;
default:
usage( argv[0], LIBCOAP_PACKAGE_VERSION );
exit( 1 );
Expand Down
123 changes: 89 additions & 34 deletions include/coap2/pdu.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ struct coap_session_t;
#define COAP_DEFAULT_MTU 1152
#endif /* COAP_DEFAULT_MTU */

#ifndef COAP_DEFAULT_HOP_LIMIT
#define COAP_DEFAULT_HOP_LIMIT 16
#endif /* COAP_DEFAULT_HOP_LIMIT */

/* TCP Message format constants, do not modify */
#define COAP_MESSAGE_SIZE_OFFSET_TCP8 13
#define COAP_MESSAGE_SIZE_OFFSET_TCP16 269 /* 13 + 256 */
Expand Down Expand Up @@ -87,41 +91,60 @@ typedef enum coap_request_t {
} coap_request_t;

/*
* CoAP option types (be sure to update coap_option_check_critical() when
* adding options
* CoAP option types (be sure to update coap_option_check_critical() and
* coap_add_option() when adding options
*/

#define COAP_OPTION_IF_MATCH 1 /* C, opaque, 0-8 B, (none) */
#define COAP_OPTION_URI_HOST 3 /* C, String, 1-255 B, destination address */
#define COAP_OPTION_ETAG 4 /* E, opaque, 1-8 B, (none) */
#define COAP_OPTION_IF_NONE_MATCH 5 /* empty, 0 B, (none) */
#define COAP_OPTION_URI_PORT 7 /* C, uint, 0-2 B, destination port */
#define COAP_OPTION_LOCATION_PATH 8 /* E, String, 0-255 B, - */
#define COAP_OPTION_URI_PATH 11 /* C, String, 0-255 B, (none) */
#define COAP_OPTION_CONTENT_FORMAT 12 /* E, uint, 0-2 B, (none) */
#define COAP_OPTION_CONTENT_TYPE COAP_OPTION_CONTENT_FORMAT
#define COAP_OPTION_MAXAGE 14 /* E, uint, 0--4 B, 60 Seconds */
#define COAP_OPTION_URI_QUERY 15 /* C, String, 1-255 B, (none) */
#define COAP_OPTION_ACCEPT 17 /* C, uint, 0-2 B, (none) */
#define COAP_OPTION_LOCATION_QUERY 20 /* E, String, 0-255 B, (none) */
#define COAP_OPTION_SIZE2 28 /* E, uint, 0-4 B, (none) */
#define COAP_OPTION_PROXY_URI 35 /* C, String, 1-1034 B, (none) */
#define COAP_OPTION_PROXY_SCHEME 39 /* C, String, 1-255 B, (none) */
#define COAP_OPTION_SIZE1 60 /* E, uint, 0-4 B, (none) */

/* option types from RFC 7641 */

#define COAP_OPTION_OBSERVE 6 /* E, empty/uint, 0 B/0-3 B, (none) */
#define COAP_OPTION_SUBSCRIPTION COAP_OPTION_OBSERVE

/* selected option types from RFC 7959 */

#define COAP_OPTION_BLOCK2 23 /* C, uint, 0--3 B, (none) */
#define COAP_OPTION_BLOCK1 27 /* C, uint, 0--3 B, (none) */

/* selected option types from RFC 7967 */
/*
* The C, U, and N flags indicate the properties
* Critical, Unsafe, and NoCacheKey, respectively.
* If U is set, then N has no meaning as per
* https://tools.ietf.org/html/rfc7252#section-5.10
* and is set to a -.
*
* Separately, R is for the options that can be repeated
*
* The least significant byte of the option is set as followed
* as per https://tools.ietf.org/html/rfc7252#section-5.4.6
*
* 0 1 2 3 4 5 6 7
* --+---+---+---+---+---+---+---+
* | NoCacheKey| U | C |
* --+---+---+---+---+---+---+---+
*
* https://tools.ietf.org/html/rfc8613#section-4 goes on to define E, I and U
* properties Encrypted and Integrity Protected, Integrity Protected Only and
* Unprotected respectively. Integretity Protected Only is not currently used.
*
* An Option is tagged with CUNREIU with any of the letters replaced with _ if
* not set, or - for N if U is set (see above) for aiding understanding of the
* Option.
*/

#define COAP_OPTION_NORESPONSE 258 /* N, uint, 0--1 B, 0 */
#define COAP_OPTION_IF_MATCH 1 /* C__RE__, opaque, 0-8 B, RFC7252 */
#define COAP_OPTION_URI_HOST 3 /* CU-___U, String, 1-255 B, RFC7252 */
#define COAP_OPTION_ETAG 4 /* ___RE__, opaque, 1-8 B, RFC7252 */
#define COAP_OPTION_IF_NONE_MATCH 5 /* C___E__, empty, 0 B, RFC7252 */
#define COAP_OPTION_OBSERVE 6 /* _U-_E_U, empty/uint,0/0-3 B, RFC7641 */
#define COAP_OPTION_URI_PORT 7 /* CU-___U, uint, 0-2 B, RFC7252 */
#define COAP_OPTION_LOCATION_PATH 8 /* ___RE__, String, 0-255 B, RFC7252 */
#define COAP_OPTION_OSCORE 9 /* C_____U, *, 0-255 B, RFC8613 */
#define COAP_OPTION_URI_PATH 11 /* CU-RE__, String, 0-255 B, RFC7252 */
#define COAP_OPTION_CONTENT_FORMAT 12 /* ____E__, uint, 0-2 B, RFC7252 */
#define COAP_OPTION_CONTENT_TYPE COAP_OPTION_CONTENT_FORMAT
/* COAP_OPTION_MAXAGE default 60 seconds if not set */
#define COAP_OPTION_MAXAGE 14 /* _U-_E_U, uint, 0-4 B, RFC7252 */
#define COAP_OPTION_URI_QUERY 15 /* CU-RE__, String, 1-255 B, RFC7252 */
#define COAP_OPTION_HOP_LIMIT 16 /* ______U, uint, 1 B, RFC8768 */
#define COAP_OPTION_ACCEPT 17 /* C___E__, uint, 0-2 B, RFC7252 */
#define COAP_OPTION_LOCATION_QUERY 20 /* ___RE__, String, 0-255 B, RFC7252 */
#define COAP_OPTION_BLOCK2 23 /* CU-_E_U, uint, 0-3 B, RFC7959 */
#define COAP_OPTION_BLOCK1 27 /* CU-_E_U, uint, 0-3 B, RFC7959 */
#define COAP_OPTION_SIZE2 28 /* __N_E_U, uint, 0-4 B, RFC7959 */
#define COAP_OPTION_PROXY_URI 35 /* CU-___U, String, 1-1034 B, RFC7252 */
#define COAP_OPTION_PROXY_SCHEME 39 /* CU-___U, String, 1-255 B, RFC7252 */
#define COAP_OPTION_SIZE1 60 /* __N_E_U, uint, 0-4 B, RFC7252 */
#define COAP_OPTION_NORESPONSE 258 /* _U-_E_U, uint, 0-1 B, RFC7967 */

#define COAP_MAX_OPT 65535 /**< the highest option number we know */

Expand Down Expand Up @@ -273,7 +296,7 @@ typedef struct coap_pdu_t {
uint8_t type; /**< message type */
uint8_t code; /**< request method (value 1--31) or response code (value 64-255) */
uint8_t max_hdr_size; /**< space reserved for protocol-specific header */
uint8_t hdr_size; /**< actaul size used for protocol-specific header */
uint8_t hdr_size; /**< actual size used for protocol-specific header */
uint8_t token_length; /**< length of Token */
uint16_t tid; /**< transaction id, if any, in regular host byte order */
uint16_t max_delta; /**< highest option number */
Expand Down Expand Up @@ -359,6 +382,19 @@ coap_pdu_init(uint8_t type, uint8_t code, uint16_t tid, size_t size);
*/
int coap_pdu_resize(coap_pdu_t *pdu, size_t new_size);

/**
* Dynamically grows the size of @p pdu to @p new_size if needed. The new size
* must not exceed the PDU's configure maximum size. On success, this
* function returns 1, otherwise 0.
*
* Internal use only.
*
* @param pdu The PDU to resize.
* @param new_size The new size in bytes.
* @return 1 if the operation succeeded, 0 otherwise.
*/
int coap_pdu_check_resize(coap_pdu_t *pdu, size_t new_size);

/**
* Clears any contents from @p pdu and resets @c used_size,
* and @c data pointers. @c max_size is set to @p size, any
Expand Down Expand Up @@ -489,6 +525,25 @@ uint8_t *coap_add_option_later(coap_pdu_t *pdu,
uint16_t type,
size_t len);


/**
* Inserts option of given type in the @p pdu with the appropriate data.
* The option will be inserted in the appropriate place in the options in the pdu.
*
* Internal use only.
*/
size_t coap_insert_option(coap_pdu_t *pdu, uint16_t type,
size_t len, const uint8_t *data);

/**
* Updates existing first option of given type in the @p pdu with the new data.
*
* Internal use only.
*/
int coap_update_option(coap_pdu_t *pdu,
uint16_t type,
size_t len,
const uint8_t *data);
/**
* Adds given data to the pdu that is passed as first parameter. Note that the
* PDU's data is destroyed by coap_add_option(). coap_add_data() must be called
Expand All @@ -500,7 +555,7 @@ int coap_add_data(coap_pdu_t *pdu,

/**
* Adds given data to the pdu that is passed as first parameter but does not
* copyt it. Note that the PDU's data is destroyed by coap_add_option().
* copy it. Note that the PDU's data is destroyed by coap_add_option().
* coap_add_data() must be have been called once for this PDU, otherwise the
* result is undefined.
* The actual data must be copied at the returned location.
Expand Down
9 changes: 7 additions & 2 deletions man/coap-client.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ SYNOPSIS
--------
*coap-client* [*-a* addr] [*-b* [num,]size] [*-e* text] [*-f* file] [*-l* loss]
[*-m* method] [*-o* file] [*-p* port] [*-r*] [*-s duration*]
[*-t* type] [*-v* num] [*-A* type] [*-B* seconds] [*-K* interval]
[*-N*] [*-O* num,text] [*-P* addr[:port]] [*-T* token] [*-U*]
[*-t* type] [*-v* num] [*-A* type] [*-B* seconds]
[*-H* hoplimit] [*-K* interval] [*-N*] [*-O* num,text]
[*-P* addr[:port]] [*-T* token] [*-U*]
[[*-h* match_hint_file] [*-k* key] [*-u* user]]
[[*-c* certfile] [*-j* keyfile] [*-C* cafile] [*-J* pkcs11_pin]
[*-R* root_cafile]] URI
Expand Down Expand Up @@ -109,6 +110,10 @@ OPTIONS - General
*-B* seconds::
Break operation after waiting given seconds (default is 90).

*-H* hoplimit::
Set the Hop Limit count to hoplimit for proxies. Must have a value between
1 and 255 inclusive. Default is '16'.

*-K* interval::
Send a ping after interval seconds of inactivity.
If not specified (or 0), keep-alive is disabled (default).
Expand Down
2 changes: 2 additions & 0 deletions man/coap.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ See

"RFC8323: CoAP (Constrained Application Protocol) over TCP, TLS, and WebSockets"

"RFC8768: Constrained Application Protocol (CoAP) Hop-Limit Option"

for further information.

BUGS
Expand Down

0 comments on commit ffc1979

Please sign in to comment.