From cd31e488b5a695567ec42d70ded312b710888e24 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Thu, 8 May 2014 21:11:03 +0200 Subject: [PATCH 01/69] Add st-node specific definitions to address.h --- address.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/address.h b/address.h index 403240e0c9..0c1c9bb70b 100644 --- a/address.h +++ b/address.h @@ -122,6 +122,21 @@ case AF_INET6: return 0; } #endif /* WITH_POSIX */ +#ifdef WITH_STNODE +#include "net.h" + +typedef struct coap_address_t { + uint8_t size; + uint16_t port; + ipaddr_t addr; +} coap_address_t; + +#define _coap_address_equals_impl(A, B) ((A)->addr.u32 == (B)->addr.u32 && A->port == B->port) + +/* Multicast IPv4 addresses start with 0b1110 */ +#define _coap_is_mcast_impl(Address) ((Address)->addr.u8[0] && 0xF0 == 0xE0) + +#endif /* WITH_STNODE */ /** * Resets the given coap_address_t object @p addr to its default From aea902182fa2d612d6d4cfe7106ce5d4998dbe65 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Thu, 8 May 2014 21:42:40 +0200 Subject: [PATCH 02/69] Move file net.h to subdirectory to avoid conflict with st-node File net.h is present in both libcoap and st-node repository. To avoid name conflict, file in libcoap is moved to subdirectory libcoap/ . All #include statements are changed accordingly. --- async.h | 2 +- coap.h | 2 +- debug.c | 2 +- net.h => libcoap/net.h | 0 net.c | 2 +- resource.c | 2 +- resource.h | 2 +- subscribe.h | 2 +- 8 files changed, 7 insertions(+), 7 deletions(-) rename net.h => libcoap/net.h (100%) diff --git a/async.h b/async.h index a5168f8859..8e2e11aae3 100644 --- a/async.h +++ b/async.h @@ -16,7 +16,7 @@ #define _COAP_ASYNC_H_ #include "config.h" -#include "net.h" +#include "libcoap/net.h" #ifndef WITHOUT_ASYNC diff --git a/coap.h b/coap.h index 3e2828c953..facfbf9d29 100644 --- a/coap.h +++ b/coap.h @@ -19,7 +19,7 @@ extern "C" { #include "coap_list.h" #include "pdu.h" #include "option.h" -#include "net.h" +#include "libcoap/net.h" #include "encode.h" #include "str.h" #include "uri.h" diff --git a/debug.c b/debug.c index adff3c21a5..4eaf440de5 100644 --- a/debug.c +++ b/debug.c @@ -26,7 +26,7 @@ #endif #include "debug.h" -#include "net.h" +#include "libcoap/net.h" #ifdef WITH_CONTIKI # ifndef DEBUG diff --git a/net.h b/libcoap/net.h similarity index 100% rename from net.h rename to libcoap/net.h diff --git a/net.c b/net.c index cd00e35b33..9375d428f5 100644 --- a/net.c +++ b/net.c @@ -43,7 +43,7 @@ #include "option.h" #include "encode.h" #include "block.h" -#include "net.h" +#include "libcoap/net.h" #if defined(WITH_POSIX) diff --git a/resource.c b/resource.c index 23484ab15e..85ba40e0aa 100644 --- a/resource.c +++ b/resource.c @@ -7,7 +7,7 @@ */ #include "config.h" -#include "net.h" +#include "libcoap/net.h" #include "debug.h" #include "resource.h" #include "subscribe.h" diff --git a/resource.h b/resource.h index 0392b6e719..2925968e4b 100644 --- a/resource.h +++ b/resource.h @@ -38,7 +38,7 @@ #include "async.h" #include "str.h" #include "pdu.h" -#include "net.h" +#include "libcoap/net.h" #include "subscribe.h" /** Definition of message handler function (@sa coap_resource_t). */ diff --git a/subscribe.h b/subscribe.h index 0d2b7f7cdc..9a576b34e9 100644 --- a/subscribe.h +++ b/subscribe.h @@ -71,7 +71,7 @@ void coap_subscription_init(coap_subscription_t *); #include "uri.h" #include "list.h" #include "pdu.h" -#include "net.h" +#include "libcoap/net.h" #if 0 typedef unsigned long coap_key_t; From 77ae198075392ee1c407d500bd9376397f398113 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Thu, 8 May 2014 22:16:32 +0200 Subject: [PATCH 03/69] Add st-node specific definitions to coap_time.h --- coap_time.h | 27 +++++++++++++++++++++++++++ net.c | 6 ++++++ 2 files changed, 33 insertions(+) diff --git a/coap_time.h b/coap_time.h index f039b875f8..7af5b621a9 100644 --- a/coap_time.h +++ b/coap_time.h @@ -104,6 +104,33 @@ typedef int coap_tick_diff_t; extern time_t clock_offset; #endif /* WITH_POSIX */ +#ifdef WITH_STNODE +/* MWAS: based on lwIP implementation above. Uses chTimeNow() function from ChibiOS. */ +#include "ch.h" + +#define COAP_TICKS_PER_SECOND CH_FREQUENCY + +typedef systime_t coap_tick_t; +typedef int coap_tick_diff_t; /* TODO: MWAS: maybe it's better to use int32 */ + +extern systime_t clock_offset; + +static inline void coap_ticks_impl(coap_tick_t *t) +{ + *t = chTimeNow(); +} + +static inline void coap_clock_init_impl(void) +{ + clock_offset = chTimeNow(); +} + +#define coap_clock_init coap_clock_init_impl + +#define coap_ticks coap_ticks_impl + +#endif /* WITH_STNODE */ + #ifndef coap_clock_init static inline void coap_clock_init_impl(void) { diff --git a/net.c b/net.c index 9375d428f5..7496e14921 100644 --- a/net.c +++ b/net.c @@ -45,6 +45,12 @@ #include "block.h" #include "libcoap/net.h" +#ifdef WITH_STNODE +#include "system.h" + +systime_t clock_offset; + +#endif /* WITH_STNODE */ #if defined(WITH_POSIX) time_t clock_offset; From f039099f629d2feb9ede4839a96e37d2b19c9240 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Fri, 9 May 2014 19:22:05 +0200 Subject: [PATCH 04/69] Add .gitignore file --- .gitignore | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..5e3248252b --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# libcoap submodule +*.*~ +*.o +*.lst +*.sym +*.eep +*.elf +*.hex +*.bin +*.lss +*.map +*.log +*.swp +*.pyc + + From ac7de45a4bb3caddc2f787b4fd7385f242cee5a1 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Fri, 9 May 2014 19:25:31 +0200 Subject: [PATCH 05/69] Add st-node specific definitions to net.c --- net.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/net.c b/net.c index 7496e14921..02b1d073e0 100644 --- a/net.c +++ b/net.c @@ -50,6 +50,15 @@ systime_t clock_offset; +static inline coap_queue_t * +coap_malloc_node() { + return (coap_queue_t *)sys_malloc(sizeof(coap_queue_t)); +} + +static inline void +coap_free_node(coap_queue_t *node) { + sys_free(node); +} #endif /* WITH_STNODE */ #if defined(WITH_POSIX) @@ -314,6 +323,9 @@ coap_new_context( if (initialized) return NULL; #endif /* WITH_CONTIKI */ +#ifdef WITH_STNODE + coap_context_t *c = sys_malloc( sizeof( coap_context_t ) ); +#endif /* WITH_STNODE */ if (!listen_addr) { coap_log(LOG_EMERG, "no listen address specified\n"); @@ -419,6 +431,16 @@ coap_new_context( return c; #endif +#ifdef WITH_STNODE + /* TODO: MWAS: here two things should happen: + * 1. network socket should be created + * 2. binding of local address to socket should happen + * st-node allows only for connected UDP sockets. + * To create a socket, destination address is necessary. + * That requires either declaring extern address or passing address + * as an argument. TBD + */ +#endif } void @@ -840,6 +862,12 @@ coap_read( coap_context_t *ctx ) { #endif #if defined(WITH_LWIP) || defined(WITH_CONTIKI) char *buf; +#endif +#ifdef WITH_STNODE +/* + * TODO: MWAS: This is a temporary solution - to be investigated + */ + char *buf; #endif coap_hdr_t *pdu; ssize_t bytes_read = -1; @@ -1154,7 +1182,7 @@ get_wkc_len(coap_context_t *context, coap_opt_t *query_filter) { unsigned char buf[1]; size_t len = 0; - if (print_wellknown(context, buf, &len, UINT_MAX, query_filter) + if (print_wellknown(context, buf, &len, UINT_MAX, query_filter) /* MWAS: UINT_MAX requires limits.h */ & COAP_PRINT_STATUS_ERROR) { warn("cannot determine length of /.well-known/core\n"); return 0; From e26135149210bd882d48675f6af5a97a9e063e56 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Fri, 9 May 2014 20:40:36 +0200 Subject: [PATCH 06/69] Add st-node specific changes to resource.c --- resource.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/resource.c b/resource.c index 85ba40e0aa..64808b4743 100644 --- a/resource.c +++ b/resource.c @@ -12,6 +12,17 @@ #include "resource.h" #include "subscribe.h" +#ifdef WITH_STNODE +#include "utlist.h" +#include "mem.h" +#include "system.h" + +#define COAP_MALLOC_TYPE(Type) \ + ((coap_##Type##_t *)sys_malloc(sizeof(coap_##Type##_t))) +#define COAP_FREE_TYPE(Type, Object) sys_free(Object) + +#endif /* WITH_STNODE */ + #ifdef WITH_LWIP #include "utlist.h" /* mem.h is only needed for the string free calls for @@ -463,7 +474,7 @@ coap_delete_resource(coap_context_t *context, coap_key_t key) { if (!resource) return 0; -#if defined(WITH_POSIX) || defined(WITH_LWIP) +#if defined(WITH_POSIX) || defined(WITH_LWIP) || defined(WITH_STNODE) #ifdef COAP_RESOURCES_NOHASH LL_DELETE(context->resources, resource); #else @@ -482,7 +493,10 @@ coap_delete_resource(coap_context_t *context, coap_key_t key) { #ifdef WITH_LWIP memp_free(MEMP_COAP_RESOURCE, resource); #endif -#else /* not (WITH_POSIX || WITH_LWIP) */ +#ifdef WITH_STNODE + sys_free(resource); +#endif +#else /* not (WITH_POSIX || WITH_LWIP || WITH_STNODE) */ /* delete registered attributes */ while ( (attr = list_pop(resource->link_attr)) ) memb_free(&attribute_storage, attr); From 2939a667633765aee045d6e7ea75f0e9e157e322 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Fri, 9 May 2014 21:06:57 +0200 Subject: [PATCH 07/69] Add libcoap.mk makefile --- libcoap.mk | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 libcoap.mk diff --git a/libcoap.mk b/libcoap.mk new file mode 100644 index 0000000000..11ff64f966 --- /dev/null +++ b/libcoap.mk @@ -0,0 +1,17 @@ +# List of all the board related files. +EXTSRC += ext/libcoap/pdu.c \ + ext/libcoap/net.c \ + ext/libcoap/debug.c \ + ext/libcoap/encode.c \ + ext/libcoap/uri.c \ + ext/libcoap/coap_list.c \ + ext/libcoap/resource.c \ + ext/libcoap/hashkey.c \ + ext/libcoap/str.c \ + ext/libcoap/option.c \ + ext/libcoap/async.c \ + ext/libcoap/subscribe.c \ + ext/libcoap/block.c + +# Required include directories +EXTINC += ext/libcoap \ No newline at end of file From 7848c20388b48d26e28df6f2a04097b403257a2f Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 11 May 2014 21:50:26 +0200 Subject: [PATCH 08/69] Modify coap context structure for st-node --- libcoap/net.h | 7 +++++++ net.c | 31 ++++++++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/libcoap/net.h b/libcoap/net.h index f9afd48116..6cd179b74a 100644 --- a/libcoap/net.h +++ b/libcoap/net.h @@ -125,6 +125,9 @@ typedef struct coap_context_t { uint8_t timer_configured; /**< Set to 1 when a retransmission is scheduled using lwIP timers for this context, otherwise 0. */ #endif /* WITH_LWIP */ +#ifdef WITH_STNODE + net_socket_t *ns; +#endif /** * The last message id that was used is stored in this field. The @@ -183,7 +186,11 @@ coap_queue_t *coap_peek_next( coap_context_t *context ); coap_queue_t *coap_pop_next( coap_context_t *context ); /** Creates a new coap_context_t object that will hold the CoAP stack status. */ +#ifndef WITH_STNODE coap_context_t *coap_new_context(const coap_address_t *listen_addr); +#else /* WITH_STNODE */ +coap_context_t *coap_new_context(const coap_address_t *dest_addr); +#endif /* WITH_STNODE */ /** * Returns a new message id and updates @p context->message_id diff --git a/net.c b/net.c index 02b1d073e0..96039e8a03 100644 --- a/net.c +++ b/net.c @@ -47,6 +47,7 @@ #ifdef WITH_STNODE #include "system.h" +#include "net.h" systime_t clock_offset; @@ -307,9 +308,21 @@ is_wkc(coap_key_t k) { } #endif +#ifndef WITH_STNODE coap_context_t * coap_new_context( const coap_address_t *listen_addr) { +#else /* WITH_STNODE */ + /* + * MWAS: st-node network interface doesn't support + * specifying address for listening socket. + * Also st-node supoorts only connected sockets - + * destination address is required + */ +coap_context_t * +coap_new_context( + const coap_address_t *dest_addr) { +#endif /* WITH_STNODE */ #ifdef WITH_POSIX coap_context_t *c = coap_malloc( sizeof( coap_context_t ) ); int reuse = 1; @@ -327,17 +340,25 @@ coap_new_context( coap_context_t *c = sys_malloc( sizeof( coap_context_t ) ); #endif /* WITH_STNODE */ +#ifndef WITH_STNODE if (!listen_addr) { coap_log(LOG_EMERG, "no listen address specified\n"); return NULL; } - +#else /* WITH_STNODE */ + if (!dest_addr) { + coap_log(LOG_EMERG, "no destination address specified\n"); + return NULL; + } +#endif /* WITH_STNODE */ coap_clock_init(); #ifdef WITH_LWIP prng_init(LWIP_RAND()); -#else /* WITH_LWIP */ +#elif WITH_STNODE + prng_init((unsigned long)dest_addr ^ clock_offset); +#else prng_init((unsigned long)listen_addr ^ clock_offset); -#endif /* WITH_LWIP */ +#endif #ifndef WITH_CONTIKI if ( !c ) { @@ -440,6 +461,10 @@ coap_new_context( * That requires either declaring extern address or passing address * as an argument. TBD */ + c->ns = net_connect(dest_addr, COAP_DEFAULT_PORT, NET_UDP); + if (!c->ns) { + return NULL; + } #endif } From 8fe3bb01b5bf84f6eb6af0495fae04d00aebbf7a Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Mon, 12 May 2014 20:52:18 +0200 Subject: [PATCH 09/69] Add st-node code to coap_free_context function --- net.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/net.c b/net.c index 96039e8a03..85b7a07b98 100644 --- a/net.c +++ b/net.c @@ -470,12 +470,12 @@ coap_new_context( void coap_free_context( coap_context_t *context ) { -#if defined(WITH_POSIX) || defined(WITH_LWIP) +#if defined(WITH_POSIX) || defined(WITH_LWIP) || defined(WITH_STNODE) coap_resource_t *res; #ifndef COAP_RESOURCES_NOHASH coap_resource_t *rtmp; #endif -#endif /* WITH_POSIX || WITH_LWIP */ +#endif /* WITH_POSIX || WITH_LWIP || WITH_STNODE */ if ( !context ) return; @@ -487,7 +487,7 @@ coap_free_context( coap_context_t *context ) { coap_retransmittimer_restart(context); #endif -#if defined(WITH_POSIX) || defined(WITH_LWIP) +#if defined(WITH_POSIX) || defined(WITH_LWIP) || defined(WITH_STNODE) #ifdef COAP_RESOURCES_NOHASH LL_FOREACH(context->resources, res) { #else @@ -495,7 +495,7 @@ coap_free_context( coap_context_t *context ) { #endif coap_delete_resource(context, res->key); } -#endif /* WITH_POSIX || WITH_LWIP */ +#endif /* WITH_POSIX || WITH_LWIP || WITH_STNODE */ #ifdef WITH_POSIX /* coap_delete_list(context->subscriptions); */ @@ -510,6 +510,10 @@ coap_free_context( coap_context_t *context ) { memset(&the_coap_context, 0, sizeof(coap_context_t)); initialized = 0; #endif /* WITH_CONTIKI */ +#ifdef WITH_STNODE + net_disconnect(context->ns); + sys_free( context ); +#endif /* WITH_STNODE */ } int @@ -572,8 +576,9 @@ coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, return; } #endif -#if defined(WITH_LWIP) || defined(WITH_CONTIKI) +#if defined(WITH_LWIP) || defined(WITH_CONTIKI) || defined(WITH_STNODE) /* FIXME: with lwip, we can do better */ + /* TODO: MWAS: check better options */ coap_hash((const unsigned char *)&peer->port, sizeof(peer->port), h); coap_hash((const unsigned char *)&peer->addr, sizeof(peer->addr), h); #endif /* WITH_LWIP || WITH_CONTIKI */ From 80513cbdcf71bb8340bff54bb1011321610d8e36 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 1 Jun 2014 19:30:59 +0200 Subject: [PATCH 10/69] Add preliminary config.h file for libcoap --- config.h | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 config.h diff --git a/config.h b/config.h new file mode 100644 index 0000000000..a554b3b0be --- /dev/null +++ b/config.h @@ -0,0 +1,138 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define if building universal (internal helper macro) */ +#undef AC_APPLE_UNIVERSAL_BUILD + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have the header file. */ +#define HAVE_ASSERT_H 1 + +/* Define to 1 if you have the `getaddrinfo' function. */ +#undef HAVE_GETADDRINFO + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `coap' library (-lcoap). */ +#undef HAVE_LIBCOAP + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#undef HAVE_MALLOC + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the `select' function. */ +#undef HAVE_SELECT + +/* Define to 1 if you have the `socket' function. */ +#undef HAVE_SOCKET + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strnlen' function. */ +#define HAVE_STRNLEN 1 + +/* Define to 1 if you have the `strrchr' function. */ +#undef HAVE_STRRCHR + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_UNISTD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libcoap" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libcoap 4.1.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libcoap" + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define maximum size of CoAP message */ +#define COAP_MAX_PDU_SIZE 140 + +/* Define maximum size of CoAP block */ +#define COAP_MAX_BLOCK_SZX 2 + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +# undef WORDS_BIGENDIAN +# endif +#endif + +/* Define to rpl_malloc if the replacement function should be used. */ +#undef malloc + +/* Define to `unsigned int' if does not define. */ +#undef size_t + +/* Define to `int' if does not define. */ +#undef ssize_t + From 7810f010268bf72cc0aec8aafbaf9e6e0621e46c Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 1 Jun 2014 19:50:27 +0200 Subject: [PATCH 11/69] Rename libcoap debug ENUMs (temporary fix) This commit contains temporary fix for name conflict between st-node logging.h and libcoap debug.h. To be reverted when better solution is agreed upon. --- coap-observer.c | 2 +- coap-server.c | 2 +- debug.c | 4 ++-- debug.h | 8 ++++---- examples/client.c | 4 ++-- net.c | 6 +++--- resource.c | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/coap-observer.c b/coap-observer.c index e4b2fe5caa..dafa83ff0d 100644 --- a/coap-observer.c +++ b/coap-observer.c @@ -86,7 +86,7 @@ init_coap() { coap_context = coap_new_context(&listen_addr); - coap_set_log_level(LOG_DEBUG); + coap_set_log_level(CP_LOG_DEBUG); if (!coap_context) coap_log(LOG_CRIT, "cannot create CoAP context\r\n"); diff --git a/coap-server.c b/coap-server.c index 5dcdfcdc67..7b5fd317f7 100644 --- a/coap-server.c +++ b/coap-server.c @@ -81,7 +81,7 @@ init_coap() { coap_context = coap_new_context(&listen_addr); - coap_set_log_level(LOG_DEBUG); + coap_set_log_level(CP_LOG_DEBUG); if (!coap_context) coap_log(LOG_CRIT, "cannot create CoAP context\r\n"); diff --git a/debug.c b/debug.c index 4eaf440de5..14e5d6891b 100644 --- a/debug.c +++ b/debug.c @@ -345,7 +345,7 @@ coap_log_impl(coap_log_t level, const char *format, ...) { if (print_timestamp(timebuf,sizeof(timebuf), now)) fprintf(log_fd, "%s ", timebuf); - if (level <= LOG_DEBUG) + if (level <= CP_LOG_DEBUG) fprintf(log_fd, "%s ", loglevels[level]); va_start(ap, format); @@ -367,7 +367,7 @@ coap_log_impl(coap_log_t level, const char *format, ...) { if (print_timestamp(timebuf,sizeof(timebuf), now)) PRINTF("%s ", timebuf); - if (level <= LOG_DEBUG) + if (level <= CP_LOG_DEBUG) PRINTF("%s ", loglevels[level]); va_start(ap, format); diff --git a/debug.h b/debug.h index d18558fb7f..b521236ad5 100644 --- a/debug.h +++ b/debug.h @@ -24,8 +24,8 @@ typedef short coap_log_t; #else /** Pre-defined log levels akin to what is used in \b syslog. */ -typedef enum { LOG_EMERG=0, LOG_ALERT, LOG_CRIT, LOG_WARNING, - LOG_NOTICE, LOG_INFO, LOG_DEBUG +typedef enum {LOG_EMERG=0, LOG_ALERT, LOG_CRIT, LOG_WARNING, + LOG_NOTICE, CP_LOG_INFO, CP_LOG_DEBUG } coap_log_t; #endif @@ -56,9 +56,9 @@ void coap_log_impl(coap_log_t level, const char *format, ...); #ifndef NDEBUG /* A set of convenience macros for common log levels. */ -#define info(...) coap_log(LOG_INFO, __VA_ARGS__) +#define info(...) coap_log(CP_LOG_INFO, __VA_ARGS__) #define warn(...) coap_log(LOG_WARNING, __VA_ARGS__) -#define debug(...) coap_log(LOG_DEBUG, __VA_ARGS__) +#define debug(...) coap_log(CP_LOG_DEBUG, __VA_ARGS__) #include "pdu.h" void coap_show_pdu(const coap_pdu_t *); diff --git a/examples/client.c b/examples/client.c index bd6f9b5ad8..5421e08c2d 100644 --- a/examples/client.c +++ b/examples/client.c @@ -323,7 +323,7 @@ message_handler(struct coap_context_t *ctx, coap_tid_t tid; #ifndef NDEBUG - if (LOG_DEBUG <= coap_get_log_level()) { + if (CP_LOG_DEBUG <= coap_get_log_level()) { debug("** process incoming %d.%02d response:\n", (received->hdr->code >> 5), received->hdr->code & 0x1F); coap_show_pdu(received); @@ -1116,7 +1116,7 @@ main(int argc, char **argv) { return -1; #ifndef NDEBUG - if (LOG_DEBUG <= coap_get_log_level()) { + if (CP_LOG_DEBUG <= coap_get_log_level()) { debug("sending CoAP request:\n"); coap_show_pdu(pdu); } diff --git a/net.c b/net.c index 85b7a07b98..380373098f 100644 --- a/net.c +++ b/net.c @@ -984,7 +984,7 @@ if (!coap_pdu_parse((unsigned char *)buf, bytes_read, node->pdu)) { coap_insert_node(&ctx->recvqueue, node); #ifndef NDEBUG - if (LOG_DEBUG <= coap_get_log_level()) { + if (CP_LOG_DEBUG <= coap_get_log_level()) { #ifndef INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN 40 #endif @@ -1478,7 +1478,7 @@ handle_request(coap_context_t *context, coap_queue_t *node) { if ((observe_action & COAP_OBSERVE_CANCEL) == 0) { coap_subscription_t *subscription; - coap_log(LOG_DEBUG, "create new subscription\n"); + coap_log(CP_LOG_DEBUG, "create new subscription\n"); subscription = coap_add_observer(resource, &node->remote, &token); if (subscription) { subscription->non = node->pdu->hdr->type == COAP_MESSAGE_NON; @@ -1493,7 +1493,7 @@ handle_request(coap_context_t *context, coap_queue_t *node) { if (observe && ((COAP_RESPONSE_CLASS(response->hdr->code) > 2) || ((observe_action & COAP_OBSERVE_CANCEL) != 0))) { - coap_log(LOG_DEBUG, "removed observer"); + coap_log(CP_LOG_DEBUG, "removed observer"); coap_delete_observer(resource, &node->remote, &token); } diff --git a/resource.c b/resource.c index 64808b4743..cba9449c82 100644 --- a/resource.c +++ b/resource.c @@ -836,7 +836,7 @@ coap_remove_failed_observers(coap_context_t *context, obs->fail_cnt = 0; #ifndef NDEBUG - if (LOG_DEBUG <= coap_get_log_level()) { + if (CP_LOG_DEBUG <= coap_get_log_level()) { #ifndef INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN 40 #endif From d36e0f3dd9087156f8ec0c35101f775cde752ba1 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 1 Jun 2014 20:01:09 +0200 Subject: [PATCH 12/69] Modify coap_new_context for st-node --- libcoap/net.h | 2 +- net.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libcoap/net.h b/libcoap/net.h index 6cd179b74a..57f17cdd45 100644 --- a/libcoap/net.h +++ b/libcoap/net.h @@ -189,7 +189,7 @@ coap_queue_t *coap_pop_next( coap_context_t *context ); #ifndef WITH_STNODE coap_context_t *coap_new_context(const coap_address_t *listen_addr); #else /* WITH_STNODE */ -coap_context_t *coap_new_context(const coap_address_t *dest_addr); +coap_context_t *coap_new_context(coap_address_t *dest_addr); #endif /* WITH_STNODE */ /** diff --git a/net.c b/net.c index 380373098f..ccdf666ca7 100644 --- a/net.c +++ b/net.c @@ -320,8 +320,7 @@ coap_new_context( * destination address is required */ coap_context_t * -coap_new_context( - const coap_address_t *dest_addr) { +coap_new_context(coap_address_t *dest_addr) { #endif /* WITH_STNODE */ #ifdef WITH_POSIX coap_context_t *c = coap_malloc( sizeof( coap_context_t ) ); @@ -461,10 +460,12 @@ coap_new_context( * That requires either declaring extern address or passing address * as an argument. TBD */ - c->ns = net_connect(dest_addr, COAP_DEFAULT_PORT, NET_UDP); + c->destination_address = dest_addr; + c->ns = net_connect(&dest_addr->addr, dest_addr->port, NET_UDP); if (!c->ns) { return NULL; } + return c; #endif } From 49692e56a3d69ed8e402e946cd4b0646940e0e3b Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 1 Jun 2014 20:28:15 +0200 Subject: [PATCH 13/69] Change coap_pdu_init for st-node --- pdu.c | 24 ++++++++++++++++++++++++ pdu.h | 7 +++++++ 2 files changed, 31 insertions(+) diff --git a/pdu.c b/pdu.c index 04ef9c6fcc..0b5f0afd1d 100644 --- a/pdu.c +++ b/pdu.c @@ -43,10 +43,15 @@ void coap_pdu_clear(coap_pdu_t *pdu, size_t size) { assert(pdu); +#ifdef WITH_STNODE + memset(pdu, 0, sizeof(coap_pdu_t)); /* MWAS: for st-node payload is in separate memory area */ + pdu->max_size = size; +#else memset(pdu, 0, sizeof(coap_pdu_t) + size); pdu->max_size = size; pdu->hdr = (coap_hdr_t *)((unsigned char *)pdu + sizeof(coap_pdu_t)); pdu->hdr->version = COAP_DEFAULT_VERSION; +#endif /* data is NULL unless explicitly set by coap_add_data() */ pdu->length = sizeof(coap_hdr_t); @@ -85,6 +90,9 @@ coap_pdu_init(unsigned char type, unsigned char code, #ifdef WITH_LWIP struct pbuf *p; #endif +#ifdef WITH_STNODE + struct mbuf *m; +#endif assert(size <= COAP_MAX_PDU_SIZE); /* Size must be large enough to fit the header. */ @@ -109,9 +117,20 @@ coap_pdu_init(unsigned char type, unsigned char code, } else { pdu = NULL; } +#endif +#ifdef WITH_STNODE + //TODO: MWAS: get rid of sys_malloc + pdu = sys_malloc(sizeof(coap_pdu_t)); + m = mbuf_new(); #endif if (pdu) { coap_pdu_clear(pdu, size); +#ifdef WITH_STNODE + pdu->hdr = (coap_hdr_t *)((unsigned char *)m->payload); + pdu->hdr->version = COAP_DEFAULT_VERSION; + pdu->hdr->token_length = 0; + pdu->mbuf = m; +#endif pdu->hdr->id = id; pdu->hdr->type = type; pdu->hdr->code = code; @@ -151,10 +170,15 @@ coap_delete_pdu(coap_pdu_t *pdu) { #ifdef WITH_CONTIKI memb_free(&pdu_storage, pdu); #endif +#ifdef WITH_STNODE + if (pdu != NULL) + mbuf_free(pdu->mbuf); +#endif } int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data) { + const size_t HEADERLENGTH = len + 4; /* must allow for pdu == NULL as callers may rely on this */ if (!pdu || len > 8 || pdu->max_size < HEADERLENGTH) diff --git a/pdu.h b/pdu.h index 691bde8921..fe4d638ae8 100644 --- a/pdu.h +++ b/pdu.h @@ -16,6 +16,10 @@ #ifdef WITH_LWIP #include #endif +#ifdef WITH_STNODE +#include +#include "mbuf.h" +#endif /* pre-defined constants that reflect defaults for CoAP */ @@ -214,6 +218,9 @@ typedef struct { #ifdef WITH_LWIP struct pbuf *pbuf; /**< lwIP PBUF. The allocated coap_pdu_t will always reside inside the pbuf's payload, but the pointer has to be kept because no exact offset can be given. This field must not be accessed from outside, because the pbuf's reference count is checked to be 1 when the pbuf is assigned to the pdu, and the pbuf stays exclusive to this pdu. */ #endif +#ifdef WITH_STNODE + struct mbuf *mbuf; +#endif } coap_pdu_t; From 5c5374accc437599b9f058734caa1bd693ff80ac Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 1 Jun 2014 20:36:20 +0200 Subject: [PATCH 14/69] Modify coap_add_token for st-node --- pdu.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pdu.c b/pdu.c index 0b5f0afd1d..74f24ea72a 100644 --- a/pdu.c +++ b/pdu.c @@ -186,7 +186,12 @@ coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data) { pdu->hdr->token_length = len; if (len) +#if defined(WITH_LWIP) || defined(WITH_CONTIKI) || defined(WITH_POSIX) memcpy(pdu->hdr->token, data, len); +#elif defined(WITH_STNODE) + mbuf_write(pdu->mbuf, data, len, pdu->length); +#endif + pdu->max_delta = 0; pdu->length = HEADERLENGTH; pdu->data = NULL; From 6c840a363aa4d655350dd4126d83b11819d6957f Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 1 Jun 2014 20:38:00 +0200 Subject: [PATCH 15/69] Modify coap_add_data for st-node --- pdu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pdu.c b/pdu.c index 74f24ea72a..4418f87c01 100644 --- a/pdu.c +++ b/pdu.c @@ -280,8 +280,11 @@ coap_add_data(coap_pdu_t *pdu, unsigned int len, const unsigned char *data) { pdu->data = (unsigned char *)pdu->hdr + pdu->length; *pdu->data = COAP_PAYLOAD_START; pdu->data++; - +#if defined(WITH_LWIP) || defined(WITH_CONTIKI) || defined(WITH_POSIX) memcpy(pdu->data, data, len); +#elif defined(WITH_STNODE) + mbuf_write(pdu->mbuf, data, len, pdu->length+1); +#endif pdu->length += len + 1; return 1; } From 187346cda670fb52a177f9c35600895f14ca3010 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 1 Jun 2014 20:46:50 +0200 Subject: [PATCH 16/69] Add functions to encode options to mbuf Original libcoap functions operate on array of chars. New functions use mbuf_write. --- option.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ option.h | 12 ++++++-- 2 files changed, 99 insertions(+), 2 deletions(-) diff --git a/option.c b/option.c index a03fc9e618..fb10c64b2c 100644 --- a/option.c +++ b/option.c @@ -405,3 +405,92 @@ coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta, return l + length; } + +#if defined(WITH_STNODE) + + +size_t +coap_opt_setheader_to_mbuf(coap_pdu_t *pdu, unsigned short type, size_t length) { + size_t skip = 0; + unsigned short delta = type - pdu->max_delta; + unsigned short maxlen = pdu->max_size - pdu->length; + unsigned char opt[5]; + + if (maxlen == 0) + return 0; + + if (delta < 13) { + opt[0] = delta << 4; + } else if (delta < 270) { + if (maxlen < 2) { + debug("insufficient space to encode option delta %d", delta); + return 0; + } + + opt[0] = 0xd0; + opt[++skip] = delta - 13; + } else { + if (maxlen < 3) { + debug("insufficient space to encode option delta %d", delta); + return 0; + } + + opt[0] = 0xe0; + opt[++skip] = ((delta - 269) >> 8) & 0xff; + opt[++skip] = (delta - 269) & 0xff; + } + + if (length < 13) { + opt[0] |= length & 0x0f; + } else if (length < 270) { + if (maxlen < skip + 1) { + debug("insufficient space to encode option length %d", length); + return 0; + } + + opt[0] |= 0x0d; + opt[++skip] = length - 13; + } else { + if (maxlen < skip + 2) { + debug("insufficient space to encode option delta %d", delta); + return 0; + } + + opt[0] |= 0x0e; + opt[++skip] = ((length - 269) >> 8) & 0xff; + opt[++skip] = (length - 269) & 0xff; + } + + mbuf_write(pdu->mbuf, &opt, skip+1, pdu->length); + return skip + 1; +} + + + +size_t +coap_opt_encode_to_mbuf(coap_pdu_t *pdu, unsigned short type, + const unsigned char *val, size_t length) { + size_t l = 1; + unsigned short maxlen = pdu->max_size - pdu->length; + + l = coap_opt_setheader_to_mbuf(pdu, type, length); + assert(l <= maxlen); + + if (!l) { + debug("coap_opt_encode: cannot set option header\n"); + return 0; + } + + maxlen -= l; + + if (maxlen < length) { + debug("coap_opt_encode: option too large for buffer\n"); + return 0; + } + + if (val) + mbuf_write(pdu->mbuf, val, length, pdu->length+l); + + return l + length; +} +#endif diff --git a/option.h b/option.h index 60fe225f82..3a148de824 100644 --- a/option.h +++ b/option.h @@ -248,9 +248,13 @@ coap_opt_t *coap_check_option(coap_pdu_t *pdu, * @param length The actual length value to encode. * @return The number of bytes used or @c 0 on error. */ + size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, unsigned short delta, size_t length); - +#if defined(WITH_STNODE) +size_t coap_opt_setheader_to_mbuf(coap_pdu_t *pdu, unsigned short type, + size_t length); +#endif /** * Encodes option with given @p delta into @p opt. This function returns * the number of bytes written to @p opt or @c 0 on error. This happens @@ -265,9 +269,13 @@ size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, * @return The number of bytes that have been written to @p opt or * @c 0 on error. The return value will always be less than @p n. */ + size_t coap_opt_encode(coap_opt_t *opt, size_t n, unsigned short delta, const unsigned char *val, size_t length); - +#if defined(WITH_STNODE) +size_t coap_opt_encode_to_mbuf(coap_pdu_t *pdu, unsigned short type, + const unsigned char *val, size_t length); +#endif /** * Decodes the delta value of the next option. This function returns * the number of bytes read or @c 0 on error. The caller of this From 082bcdff2e1a8c5faeeeb89eee2f5e2bb5229f52 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 1 Jun 2014 20:51:38 +0200 Subject: [PATCH 17/69] Modify coap_add_option to use new encode functions --- pdu.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pdu.c b/pdu.c index 4418f87c01..ab740dc280 100644 --- a/pdu.c +++ b/pdu.c @@ -203,7 +203,9 @@ coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data) { size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data) { size_t optsize; +#ifndef WITH_STNODE coap_opt_t *opt; +#endif assert(pdu); pdu->data = NULL; @@ -213,11 +215,17 @@ coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const un return 0; } +#ifndef WITH_STNODE opt = (unsigned char *)pdu->hdr + pdu->length; +#endif /* encode option and check length */ +#if defined(WITH_LWIP) || defined(WITH_CONTIKI) || defined(WITH_POSIX) optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, type - pdu->max_delta, data, len); +#elif defined(WITH_STNODE) + optsize = coap_opt_encode_to_mbuf(pdu, type, data, len); +#endif if (!optsize) { warn("coap_add_option: cannot add option\n"); @@ -235,7 +243,9 @@ coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const un unsigned char* coap_add_option_later(coap_pdu_t *pdu, unsigned short type, unsigned int len) { size_t optsize; +#ifndef WITH_STNODE coap_opt_t *opt; +#endif assert(pdu); pdu->data = NULL; @@ -245,11 +255,17 @@ coap_add_option_later(coap_pdu_t *pdu, unsigned short type, unsigned int len) { return NULL; } +#ifndef WITH_STNODE opt = (unsigned char *)pdu->hdr + pdu->length; +#endif /* encode option and check length */ +#if defined(WITH_LWIP) || defined(WITH_CONTIKI) || defined(WITH_POSIX) optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, type - pdu->max_delta, NULL, len); +#elif defined(WITH_STNODE) + optsize = coap_opt_encode_to_mbuf(pdu, type, NULL, len); +#endif if (!optsize) { warn("coap_add_option: cannot add option\n"); From d4c02dc18893c357fc380cd80242458c4fa35c25 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 1 Jun 2014 20:53:21 +0200 Subject: [PATCH 18/69] Add coap_pdu_from_mbuf function This function uses mbuf supplied by net_receive to create a coap_pdu_t structure. It is based on LWIP port, but with significant change - LWIP stores coap_pdu_t structure inside mbuf (which seems to be pointless). --- pdu.c | 22 ++++++++++++++++++++++ pdu.h | 4 +++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/pdu.c b/pdu.c index ab740dc280..6c0d587259 100644 --- a/pdu.c +++ b/pdu.c @@ -83,6 +83,28 @@ coap_pdu_from_pbuf(struct pbuf *pbuf) } #endif +#ifdef WITH_STNODE +#include "net.h" +#include "system.h" + +coap_pdu_t * +coap_pdu_from_mbuf(struct mbuf *mbuf) +{ + coap_pdu_t *result; + //TODO: MWAS: get rid of sys_malloc + result = sys_malloc(sizeof(coap_pdu_t)); + + memset(result, 0, sizeof(coap_pdu_t)); + + result->max_size = mbuf->tot_len; + result->length = mbuf->tot_len; + result->hdr = (coap_hdr_t *)((unsigned char *)mbuf->payload); + result->mbuf = mbuf; + + return result; +} +#endif + coap_pdu_t * coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t size) { diff --git a/pdu.h b/pdu.h index fe4d638ae8..9a311a0c8b 100644 --- a/pdu.h +++ b/pdu.h @@ -247,7 +247,9 @@ typedef struct { */ coap_pdu_t * coap_pdu_from_pbuf(struct pbuf *pbuf); #endif - +#ifdef WITH_STNODE +coap_pdu_t * coap_pdu_from_mbuf(struct mbuf *mbuf); +#endif /** * Creates a new CoAP PDU of given @p size (must be large enough to hold the * basic CoAP message header (coap_hdr_t). The function returns a pointer to From 535660ce77810f09739bb8b0ac8cf4c31afea5a1 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 1 Jun 2014 21:12:05 +0200 Subject: [PATCH 19/69] Modify coap_read for st-node Function coap_read is modified to work with mbuf instead of array of chars. There is a possible problem with net_receive function - it is a blocking function, and it might cause errors with retransmissions. --- libcoap/net.h | 2 ++ net.c | 28 ++++++++++++++++++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/libcoap/net.h b/libcoap/net.h index 57f17cdd45..d16e7031d6 100644 --- a/libcoap/net.h +++ b/libcoap/net.h @@ -127,6 +127,8 @@ typedef struct coap_context_t { #endif /* WITH_LWIP */ #ifdef WITH_STNODE net_socket_t *ns; + struct mbuf *pending_package; + struct coap_address_t * destination_address; #endif /** diff --git a/net.c b/net.c index ccdf666ca7..8be6a11c49 100644 --- a/net.c +++ b/net.c @@ -894,13 +894,9 @@ coap_read( coap_context_t *ctx ) { #if defined(WITH_LWIP) || defined(WITH_CONTIKI) char *buf; #endif -#ifdef WITH_STNODE -/* - * TODO: MWAS: This is a temporary solution - to be investigated - */ - char *buf; -#endif +#ifndef WITH_STNODE coap_hdr_t *pdu; +#endif ssize_t bytes_read = -1; coap_address_t src, dst; coap_queue_t *node; @@ -914,7 +910,9 @@ coap_read( coap_context_t *ctx ) { buf = ctx->pending_package->payload; #endif /* WITH_LWIP */ +#ifndef WITH_STNODE pdu = (coap_hdr_t *)buf; +#endif /* WITH_STNODE */ coap_address_init(&src); @@ -942,6 +940,15 @@ coap_read( coap_context_t *ctx ) { src.port = ctx->pending_port; bytes_read = ctx->pending_package->tot_len; #endif /* WITH_LWIP */ +#ifdef WITH_STNODE + //TODO: MWAS 1: what is the correct value of timeout for net_receive + //TODO: MWAS 2: src and dst - no way to properly set them with current network stack + ctx->pending_package = net_receive(ctx->ns, 1000); + memcpy(&src.addr, &ctx->destination_address->addr, sizeof(ipaddr_t)); + src.port = ctx->destination_address->port; + src.size = 4; + bytes_read = ctx->pending_package->tot_len; +#endif /* WITH_STNODE */ if ( bytes_read < 0 ) { warn("coap_read: recvfrom"); @@ -953,10 +960,12 @@ coap_read( coap_context_t *ctx ) { goto error_early; } +#ifndef WITH_STNODE if ( pdu->version != COAP_DEFAULT_VERSION ) { debug("coap_read: unknown protocol version\n" ); goto error_early; } +#endif /* WITH_STNODE */ node = coap_new_node(); if ( !node ) @@ -965,6 +974,9 @@ coap_read( coap_context_t *ctx ) { #ifdef WITH_LWIP node->pdu = coap_pdu_from_pbuf(ctx->pending_package); ctx->pending_package = NULL; +#elif WITH_STNODE + node->pdu = coap_pdu_from_mbuf(ctx->pending_package); + ctx->pending_package = NULL; #else node->pdu = coap_pdu_init(0, 0, 0, bytes_read); #endif @@ -975,7 +987,11 @@ coap_read( coap_context_t *ctx ) { memcpy(&node->local, &dst, sizeof(coap_address_t)); memcpy(&node->remote, &src, sizeof(coap_address_t)); +#ifndef WITH_STNODE if (!coap_pdu_parse((unsigned char *)buf, bytes_read, node->pdu)) { +#else + if (!coap_pdu_parse((unsigned char *)node->pdu->mbuf->payload, bytes_read, node->pdu)) { +#endif warn("discard malformed PDU"); goto error; } From a2b696de9971e19fb3f8e8f980c04b5914c282dc Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 1 Jun 2014 21:26:12 +0200 Subject: [PATCH 20/69] Add coap_send_impl for st-node --- net.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/net.c b/net.c index 8be6a11c49..100ad99a21 100644 --- a/net.c +++ b/net.c @@ -707,6 +707,29 @@ coap_send_impl(coap_context_t *context, return id; } #endif /* WITH_LWIP */ +#ifdef WITH_STNODE +/* + * MWAS: st-node implementation doesn't require destination address for sending, + * destination address is currently used only for transaction id. + */ +coap_tid_t +coap_send_impl(coap_context_t *context, + const coap_address_t *dst, + coap_pdu_t *pdu) { + coap_tid_t id = COAP_INVALID_TID; + + if ( !context || !dst || !pdu ) + return id; + + coap_transaction_id(dst, pdu, &id); + + if(!net_send(context->ns, pdu->mbuf)) { + coap_log(LOG_CRIT, "coap_send: sendto\n"); + } + + return id; +} +#endif /* WITH_STNODE */ coap_tid_t coap_send(coap_context_t *context, From fcc34ce39bedd6bbf0d31861f112e5d4ba04781a Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 1 Jun 2014 21:27:19 +0200 Subject: [PATCH 21/69] Add resource functions for st-node (remove warnings) --- resource.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resource.c b/resource.c index cba9449c82..23bafb4942 100644 --- a/resource.c +++ b/resource.c @@ -326,6 +326,9 @@ coap_resource_init(const unsigned char *uri, size_t len, int flags) { #endif #ifdef WITH_CONTIKI r = (coap_resource_t *)memb_alloc(&resource_storage); +#endif +#ifdef WITH_STNODE + r = (coap_resource_t *)sys_malloc(sizeof(coap_resource_t)); #endif if (r) { memset(r, 0, sizeof(coap_resource_t)); @@ -367,6 +370,9 @@ coap_add_attr(coap_resource_t *resource, #ifdef WITH_CONTIKI attr = (coap_attr_t *)memb_alloc(&attribute_storage); #endif +#ifdef WITH_STNODE + attr = (coap_attr_t *)sys_malloc(sizeof(coap_attr_t)); +#endif if (attr) { attr->name.length = nlen; From 96ec225ecd3999921955fba80adcddc5cf1b7ce8 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 1 Jun 2014 21:35:47 +0200 Subject: [PATCH 22/69] Fix bug for coap_add_option_later --- pdu.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pdu.c b/pdu.c index 6c0d587259..6d49d22f2d 100644 --- a/pdu.c +++ b/pdu.c @@ -265,9 +265,7 @@ coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const un unsigned char* coap_add_option_later(coap_pdu_t *pdu, unsigned short type, unsigned int len) { size_t optsize; -#ifndef WITH_STNODE coap_opt_t *opt; -#endif assert(pdu); pdu->data = NULL; @@ -277,9 +275,7 @@ coap_add_option_later(coap_pdu_t *pdu, unsigned short type, unsigned int len) { return NULL; } -#ifndef WITH_STNODE opt = (unsigned char *)pdu->hdr + pdu->length; -#endif /* encode option and check length */ #if defined(WITH_LWIP) || defined(WITH_CONTIKI) || defined(WITH_POSIX) From 801b89fda9d557074ca0c201dc85882c61a84d90 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Tue, 10 Jun 2014 20:23:46 +0200 Subject: [PATCH 23/69] Change debug system to use st-node output and settings This commit is an intermediate step towards replacement of libcoap log and debug system with st-node's. --- async.c | 5 +++++ block.c | 5 +++++ coap-observer.c | 2 +- coap-server.c | 2 +- debug.c | 19 +++++++++++++------ debug.h | 19 ++++++++++++++++--- examples/client.c | 4 ++-- net.c | 14 ++++++++++---- option.c | 5 +++++ pdu.c | 5 +++++ resource.c | 8 +++++++- uri.c | 5 +++++ 12 files changed, 75 insertions(+), 18 deletions(-) diff --git a/async.c b/async.c index 976bf63317..b198127b7a 100644 --- a/async.c +++ b/async.c @@ -21,6 +21,11 @@ #include "debug.h" #include "async.h" +#ifdef WITH_STNODE +#include "logging.h" +DEFINE_LOG(LOG_DEFAULT_SEVERITY); +#endif + coap_async_state_t * coap_register_async(coap_context_t *context, coap_address_t *peer, coap_pdu_t *request, unsigned char flags, void *data) { diff --git a/block.c b/block.c index aaea2b314d..8f64d90c93 100644 --- a/block.c +++ b/block.c @@ -15,6 +15,11 @@ #include "debug.h" #include "block.h" +#ifdef WITH_STNODE +#include "logging.h" +DEFINE_LOG(LOG_DEFAULT_SEVERITY); +#endif + #define min(a,b) ((a) < (b) ? (a) : (b)) #ifndef WITHOUT_BLOCK diff --git a/coap-observer.c b/coap-observer.c index dafa83ff0d..e4b2fe5caa 100644 --- a/coap-observer.c +++ b/coap-observer.c @@ -86,7 +86,7 @@ init_coap() { coap_context = coap_new_context(&listen_addr); - coap_set_log_level(CP_LOG_DEBUG); + coap_set_log_level(LOG_DEBUG); if (!coap_context) coap_log(LOG_CRIT, "cannot create CoAP context\r\n"); diff --git a/coap-server.c b/coap-server.c index 7b5fd317f7..5dcdfcdc67 100644 --- a/coap-server.c +++ b/coap-server.c @@ -81,7 +81,7 @@ init_coap() { coap_context = coap_new_context(&listen_addr); - coap_set_log_level(CP_LOG_DEBUG); + coap_set_log_level(LOG_DEBUG); if (!coap_context) coap_log(LOG_CRIT, "cannot create CoAP context\r\n"); diff --git a/debug.c b/debug.c index 14e5d6891b..26a140516b 100644 --- a/debug.c +++ b/debug.c @@ -54,11 +54,12 @@ void coap_set_log_level(coap_log_t level) { maxlog = level; } - +#ifndef WITH_STNODE /* this array has the same order as the type log_t */ static char *loglevels[] = { "EMRG", "ALRT", "CRIT", "ERR", "WARN", "NOTE", "INFO", "DEBG" }; +#endif #ifdef HAVE_TIME_H @@ -328,7 +329,7 @@ coap_show_pdu(const coap_pdu_t *pdu) { #endif /* NDEBUG */ -#ifndef WITH_CONTIKI +#if defined(WITH_POSIX) | defined(WITH_LWIP) void coap_log_impl(coap_log_t level, const char *format, ...) { char timebuf[32]; @@ -345,7 +346,7 @@ coap_log_impl(coap_log_t level, const char *format, ...) { if (print_timestamp(timebuf,sizeof(timebuf), now)) fprintf(log_fd, "%s ", timebuf); - if (level <= CP_LOG_DEBUG) + if (level <= LOG_DEBUG) fprintf(log_fd, "%s ", loglevels[level]); va_start(ap, format); @@ -353,7 +354,7 @@ coap_log_impl(coap_log_t level, const char *format, ...) { va_end(ap); fflush(log_fd); } -#else /* WITH_CONTIKI */ +#elif defined(WITH_CONTIKI) void coap_log_impl(coap_log_t level, const char *format, ...) { char timebuf[32]; @@ -367,11 +368,17 @@ coap_log_impl(coap_log_t level, const char *format, ...) { if (print_timestamp(timebuf,sizeof(timebuf), now)) PRINTF("%s ", timebuf); - if (level <= CP_LOG_DEBUG) + if (level <= LOG_DEBUG) PRINTF("%s ", loglevels[level]); va_start(ap, format); PRINTF(format, ap); va_end(ap); } -#endif /* WITH_CONTIKI */ +#elif defined(WITH_STNODE) +void +coap_log_impl(coap_log_t level, const char *format, ...) { + + _log_printf((ROM_PTR)level, (log_t *)format, __LINE__, ROM_PSTR(format)); +} +#endif diff --git a/debug.h b/debug.h index b521236ad5..b70af622fc 100644 --- a/debug.h +++ b/debug.h @@ -24,11 +24,21 @@ typedef short coap_log_t; #else /** Pre-defined log levels akin to what is used in \b syslog. */ +#ifndef WITH_STNODE typedef enum {LOG_EMERG=0, LOG_ALERT, LOG_CRIT, LOG_WARNING, - LOG_NOTICE, CP_LOG_INFO, CP_LOG_DEBUG + LOG_NOTICE, LOG_INFO, LOG_DEBUG } coap_log_t; +#else +#include "logging.h" +typedef log_level_t coap_log_t; +#define LOG_WARNING LOG_WARN +#define LOG_CRIT LOG_ERROR +#define LOG_ALERT LOG_FATAL +#define LOG_EMERG LOG_FATAL +#endif #endif +#ifndef WITH_STNODE /** Returns the current log level. */ coap_log_t coap_get_log_level(); @@ -40,6 +50,7 @@ const char *coap_package_name(); /** Returns a zero-terminated string with the library version. */ const char *coap_package_version(); +#endif /** * Writes the given text to @c COAP_ERR_FD (for @p level <= @c @@ -55,10 +66,12 @@ void coap_log_impl(coap_log_t level, const char *format, ...); #ifndef NDEBUG +#ifndef WITH_STNODE /* A set of convenience macros for common log levels. */ -#define info(...) coap_log(CP_LOG_INFO, __VA_ARGS__) +#define info(...) coap_log(LOG_INFO, __VA_ARGS__) #define warn(...) coap_log(LOG_WARNING, __VA_ARGS__) -#define debug(...) coap_log(CP_LOG_DEBUG, __VA_ARGS__) +#define debug(...) coap_log(LOG_DEBUG, __VA_ARGS__) +#endif #include "pdu.h" void coap_show_pdu(const coap_pdu_t *); diff --git a/examples/client.c b/examples/client.c index 5421e08c2d..bd6f9b5ad8 100644 --- a/examples/client.c +++ b/examples/client.c @@ -323,7 +323,7 @@ message_handler(struct coap_context_t *ctx, coap_tid_t tid; #ifndef NDEBUG - if (CP_LOG_DEBUG <= coap_get_log_level()) { + if (LOG_DEBUG <= coap_get_log_level()) { debug("** process incoming %d.%02d response:\n", (received->hdr->code >> 5), received->hdr->code & 0x1F); coap_show_pdu(received); @@ -1116,7 +1116,7 @@ main(int argc, char **argv) { return -1; #ifndef NDEBUG - if (CP_LOG_DEBUG <= coap_get_log_level()) { + if (LOG_DEBUG <= coap_get_log_level()) { debug("sending CoAP request:\n"); coap_show_pdu(pdu); } diff --git a/net.c b/net.c index 100ad99a21..1710120e96 100644 --- a/net.c +++ b/net.c @@ -48,6 +48,8 @@ #ifdef WITH_STNODE #include "system.h" #include "net.h" +#include "logging.h" +DEFINE_LOG(LOG_DEFAULT_SEVERITY); systime_t clock_offset; @@ -1024,7 +1026,9 @@ if (!coap_pdu_parse((unsigned char *)buf, bytes_read, node->pdu)) { coap_insert_node(&ctx->recvqueue, node); #ifndef NDEBUG - if (CP_LOG_DEBUG <= coap_get_log_level()) { +#ifndef WITH_STNODE + if (LOG_DEBUG <= coap_get_log_level()) { +#endif #ifndef INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN 40 #endif @@ -1034,7 +1038,9 @@ if (!coap_pdu_parse((unsigned char *)buf, bytes_read, node->pdu)) { debug("** received %d bytes from %s:\n", (int)bytes_read, addr); coap_show_pdu( node->pdu ); - } +#ifndef WITH_STNODE + } +#endif #endif return 0; @@ -1518,7 +1524,7 @@ handle_request(coap_context_t *context, coap_queue_t *node) { if ((observe_action & COAP_OBSERVE_CANCEL) == 0) { coap_subscription_t *subscription; - coap_log(CP_LOG_DEBUG, "create new subscription\n"); + coap_log(LOG_DEBUG, "create new subscription\n"); subscription = coap_add_observer(resource, &node->remote, &token); if (subscription) { subscription->non = node->pdu->hdr->type == COAP_MESSAGE_NON; @@ -1533,7 +1539,7 @@ handle_request(coap_context_t *context, coap_queue_t *node) { if (observe && ((COAP_RESPONSE_CLASS(response->hdr->code) > 2) || ((observe_action & COAP_OBSERVE_CANCEL) != 0))) { - coap_log(CP_LOG_DEBUG, "removed observer"); + coap_log(LOG_DEBUG, "removed observer"); coap_delete_observer(resource, &node->remote, &token); } diff --git a/option.c b/option.c index fb10c64b2c..086096ef02 100644 --- a/option.c +++ b/option.c @@ -20,6 +20,11 @@ #include "option.h" #include "debug.h" +#ifdef WITH_STNODE +#include "logging.h" +DEFINE_LOG(LOG_DEFAULT_SEVERITY); +#endif + coap_opt_t * options_start(coap_pdu_t *pdu) { diff --git a/pdu.c b/pdu.c index 6d49d22f2d..9d39f23934 100644 --- a/pdu.c +++ b/pdu.c @@ -8,6 +8,11 @@ #include "config.h" +#ifdef WITH_STNODE +#include "logging.h" +DEFINE_LOG(LOG_DEFAULT_SEVERITY); +#endif + #if defined(HAVE_ASSERT_H) && !defined(assert) # include #endif diff --git a/resource.c b/resource.c index 23bafb4942..336d6b9c99 100644 --- a/resource.c +++ b/resource.c @@ -16,6 +16,8 @@ #include "utlist.h" #include "mem.h" #include "system.h" +#include "logging.h" +DEFINE_LOG(LOG_DEFAULT_SEVERITY); #define COAP_MALLOC_TYPE(Type) \ ((coap_##Type##_t *)sys_malloc(sizeof(coap_##Type##_t))) @@ -842,7 +844,9 @@ coap_remove_failed_observers(coap_context_t *context, obs->fail_cnt = 0; #ifndef NDEBUG - if (CP_LOG_DEBUG <= coap_get_log_level()) { +#ifndef WITH_STNODE + if (LOG_DEBUG <= coap_get_log_level()) { +#endif #ifndef INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN 40 #endif @@ -850,7 +854,9 @@ coap_remove_failed_observers(coap_context_t *context, if (coap_print_addr(&obs->subscriber, addr, INET6_ADDRSTRLEN+8)) debug("** removed observer %s\n", addr); +#ifndef WITH_STNODE } +#endif #endif coap_cancel_all_messages(context, &obs->subscriber, obs->token, obs->token_length); diff --git a/uri.c b/uri.c index 5acb959071..d8811dafe6 100644 --- a/uri.c +++ b/uri.c @@ -22,6 +22,11 @@ #include "option.h" #include "uri.h" +#ifdef WITH_STNODE +#include "logging.h" +DEFINE_LOG(LOG_DEFAULT_SEVERITY); +#endif + /** * A length-safe version of strchr(). This function returns a pointer * to the first occurrence of @p c in @p s, or @c NULL if not found. From 4221ed8140b4bec63c782813fa2d664379632d70 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Tue, 10 Jun 2014 20:30:29 +0200 Subject: [PATCH 24/69] Change coap_read function to allow timeouts Change necessary because of non-standard network handling of st-node. --- libcoap/net.h | 5 ++++- net.c | 23 ++++++++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/libcoap/net.h b/libcoap/net.h index d16e7031d6..1fb62f0b81 100644 --- a/libcoap/net.h +++ b/libcoap/net.h @@ -345,8 +345,11 @@ coap_tid_t coap_retransmit( coap_context_t *context, coap_queue_t *node ); * and a new node with the parsed PDU is added to the receive queue in the specified context * object. */ +#ifndef WITH_STNODE int coap_read( coap_context_t *context ); - +#else +int coap_read( coap_context_t *context, coap_tick_t timeout ); +#endif /** * Calculates a unique transaction id from given arguments @p peer and * @p pdu. The id is returned in @p id. diff --git a/net.c b/net.c index 1710120e96..cbe7c214ce 100644 --- a/net.c +++ b/net.c @@ -910,9 +910,12 @@ check_opt_size(coap_opt_t *opt, unsigned char *maxpos) { } return 0; } - +#ifndef WITH_STNODE +coap_read( coap_context_t *ctx) { +#else int -coap_read( coap_context_t *ctx ) { +coap_read( coap_context_t *ctx, coap_tick_t timeout) { +#endif #ifdef WITH_POSIX static char buf[COAP_MAX_PDU_SIZE]; #endif @@ -966,13 +969,15 @@ coap_read( coap_context_t *ctx ) { bytes_read = ctx->pending_package->tot_len; #endif /* WITH_LWIP */ #ifdef WITH_STNODE - //TODO: MWAS 1: what is the correct value of timeout for net_receive - //TODO: MWAS 2: src and dst - no way to properly set them with current network stack - ctx->pending_package = net_receive(ctx->ns, 1000); - memcpy(&src.addr, &ctx->destination_address->addr, sizeof(ipaddr_t)); - src.port = ctx->destination_address->port; - src.size = 4; - bytes_read = ctx->pending_package->tot_len; + //TODO: MWAS: src and dst - no way to properly set them with current network stack + ctx->pending_package = net_receive(ctx->ns, timeout); + if(ctx->pending_package) + { + memcpy(&src.addr, &ctx->destination_address->addr, sizeof(ipaddr_t)); + src.port = ctx->destination_address->port; + src.size = 4; + bytes_read = ctx->pending_package->tot_len; + } #endif /* WITH_STNODE */ if ( bytes_read < 0 ) { From 6466775645e61334687f793371d3164a6747ec60 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Tue, 10 Jun 2014 20:32:12 +0200 Subject: [PATCH 25/69] Fix bug with improper mbuf length setting. Bug existed for messages with empty token. --- pdu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pdu.c b/pdu.c index 9d39f23934..dff6fd5b19 100644 --- a/pdu.c +++ b/pdu.c @@ -157,6 +157,8 @@ coap_pdu_init(unsigned char type, unsigned char code, pdu->hdr->version = COAP_DEFAULT_VERSION; pdu->hdr->token_length = 0; pdu->mbuf = m; + pdu->mbuf->len = sizeof(coap_hdr_t); + pdu->mbuf->tot_len = sizeof(coap_hdr_t); #endif pdu->hdr->id = id; pdu->hdr->type = type; From 9e2f1df6ba4920a7fd97409994f8b59844558db1 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Tue, 10 Jun 2014 20:33:33 +0200 Subject: [PATCH 26/69] Fix bug with not freeing coap_pdu_t structure on delete --- pdu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pdu.c b/pdu.c index dff6fd5b19..5798aa9fb3 100644 --- a/pdu.c +++ b/pdu.c @@ -201,7 +201,10 @@ coap_delete_pdu(coap_pdu_t *pdu) { #endif #ifdef WITH_STNODE if (pdu != NULL) + { mbuf_free(pdu->mbuf); + sys_free(pdu); + } #endif } From a72d7ddd4c19baa40279ec1fa15d7c3bf1481b92 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sat, 14 Jun 2014 23:11:07 +0200 Subject: [PATCH 27/69] Modify context, send and read to support new st-node network functions Modify coap_new_context, coap_read and coap_send to work with new st-node network functions: - net_create - net_send_to - net_recv_from --- libcoap/net.h | 5 ----- net.c | 40 +++++----------------------------------- 2 files changed, 5 insertions(+), 40 deletions(-) diff --git a/libcoap/net.h b/libcoap/net.h index 1fb62f0b81..781bb3dd81 100644 --- a/libcoap/net.h +++ b/libcoap/net.h @@ -128,7 +128,6 @@ typedef struct coap_context_t { #ifdef WITH_STNODE net_socket_t *ns; struct mbuf *pending_package; - struct coap_address_t * destination_address; #endif /** @@ -188,11 +187,7 @@ coap_queue_t *coap_peek_next( coap_context_t *context ); coap_queue_t *coap_pop_next( coap_context_t *context ); /** Creates a new coap_context_t object that will hold the CoAP stack status. */ -#ifndef WITH_STNODE coap_context_t *coap_new_context(const coap_address_t *listen_addr); -#else /* WITH_STNODE */ -coap_context_t *coap_new_context(coap_address_t *dest_addr); -#endif /* WITH_STNODE */ /** * Returns a new message id and updates @p context->message_id diff --git a/net.c b/net.c index cbe7c214ce..2ca0c577dc 100644 --- a/net.c +++ b/net.c @@ -310,20 +310,11 @@ is_wkc(coap_key_t k) { } #endif -#ifndef WITH_STNODE + coap_context_t * coap_new_context( const coap_address_t *listen_addr) { -#else /* WITH_STNODE */ - /* - * MWAS: st-node network interface doesn't support - * specifying address for listening socket. - * Also st-node supoorts only connected sockets - - * destination address is required - */ -coap_context_t * -coap_new_context(coap_address_t *dest_addr) { -#endif /* WITH_STNODE */ + #ifdef WITH_POSIX coap_context_t *c = coap_malloc( sizeof( coap_context_t ) ); int reuse = 1; @@ -341,22 +332,13 @@ coap_new_context(coap_address_t *dest_addr) { coap_context_t *c = sys_malloc( sizeof( coap_context_t ) ); #endif /* WITH_STNODE */ -#ifndef WITH_STNODE if (!listen_addr) { coap_log(LOG_EMERG, "no listen address specified\n"); return NULL; } -#else /* WITH_STNODE */ - if (!dest_addr) { - coap_log(LOG_EMERG, "no destination address specified\n"); - return NULL; - } -#endif /* WITH_STNODE */ coap_clock_init(); #ifdef WITH_LWIP prng_init(LWIP_RAND()); -#elif WITH_STNODE - prng_init((unsigned long)dest_addr ^ clock_offset); #else prng_init((unsigned long)listen_addr ^ clock_offset); #endif @@ -454,16 +436,7 @@ coap_new_context(coap_address_t *dest_addr) { return c; #endif #ifdef WITH_STNODE - /* TODO: MWAS: here two things should happen: - * 1. network socket should be created - * 2. binding of local address to socket should happen - * st-node allows only for connected UDP sockets. - * To create a socket, destination address is necessary. - * That requires either declaring extern address or passing address - * as an argument. TBD - */ - c->destination_address = dest_addr; - c->ns = net_connect(&dest_addr->addr, dest_addr->port, NET_UDP); + c->ns = net_create(NET_UDP); if (!c->ns) { return NULL; } @@ -725,7 +698,7 @@ coap_send_impl(coap_context_t *context, coap_transaction_id(dst, pdu, &id); - if(!net_send(context->ns, pdu->mbuf)) { + if(!net_send_to(context->ns, &dst->addr, dst->port, pdu->mbuf)) { coap_log(LOG_CRIT, "coap_send: sendto\n"); } @@ -969,12 +942,9 @@ coap_read( coap_context_t *ctx, coap_tick_t timeout) { bytes_read = ctx->pending_package->tot_len; #endif /* WITH_LWIP */ #ifdef WITH_STNODE - //TODO: MWAS: src and dst - no way to properly set them with current network stack - ctx->pending_package = net_receive(ctx->ns, timeout); + ctx->pending_package = net_receive_from(ctx->ns, &src.addr, &src.port, timeout); if(ctx->pending_package) { - memcpy(&src.addr, &ctx->destination_address->addr, sizeof(ipaddr_t)); - src.port = ctx->destination_address->port; src.size = 4; bytes_read = ctx->pending_package->tot_len; } From fdf67bbdcb4017fbbf689f40a88792b9cc87be85 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Mon, 16 Jun 2014 19:10:18 +0200 Subject: [PATCH 28/69] Add socket bind to coap_new_context Allows to create servers. --- net.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net.c b/net.c index 2ca0c577dc..df525fe5e4 100644 --- a/net.c +++ b/net.c @@ -440,6 +440,11 @@ coap_new_context( if (!c->ns) { return NULL; } + if(!net_bind(c->ns, listen_addr->port)) + { + debug("can't bind socket to port %d\n", listen_addr->port); + return NULL; + } return c; #endif } From e349cedbb6694196392b5400c7b5c9900e470862 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Thu, 19 Jun 2014 12:26:29 +0200 Subject: [PATCH 29/69] Fix bugs in debug system (use st-node logging) --- debug.c | 28 +++++++++++++++++++++++++++- debug.h | 1 + 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/debug.c b/debug.c index 26a140516b..c3831069b3 100644 --- a/debug.c +++ b/debug.c @@ -35,6 +35,10 @@ #include "net/uip-debug.h" #endif +#ifdef WITH_STNODE +DEFINE_LOG(LOG_DEFAULT_SEVERITY); +#endif /* WITH_STNODE */ + static coap_log_t maxlog = LOG_WARNING; /* default maximum log level */ const char *coap_package_name() { @@ -379,6 +383,28 @@ coap_log_impl(coap_log_t level, const char *format, ...) { void coap_log_impl(coap_log_t level, const char *format, ...) { - _log_printf((ROM_PTR)level, (log_t *)format, __LINE__, ROM_PSTR(format)); + switch(level) + { + case LOG_FATAL: + fatal(format); + break; + case LOG_ERROR: + error(format); + break; + case LOG_WARN: + warn(format); + break; + case LOG_INFO: + info(format); + break; + case LOG_DEBUG: + debug(format); + break; + case LOG_TRACE: + trace(format); + break; + case LOG_OFF: + break; + } } #endif diff --git a/debug.h b/debug.h index b70af622fc..6b3faa7c5a 100644 --- a/debug.h +++ b/debug.h @@ -35,6 +35,7 @@ typedef log_level_t coap_log_t; #define LOG_CRIT LOG_ERROR #define LOG_ALERT LOG_FATAL #define LOG_EMERG LOG_FATAL +#define LOG_NOTICE LOG_INFO #endif #endif From b398e964e625c56d6fd281225bd0a42d0c49e4f1 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Thu, 19 Jun 2014 12:53:10 +0200 Subject: [PATCH 30/69] Modify print_wellknown to work with mbuf --- net.c | 15 +++++++++- resource.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++--- resource.h | 5 ++++ 3 files changed, 100 insertions(+), 5 deletions(-) diff --git a/net.c b/net.c index df525fe5e4..0008e1e3f0 100644 --- a/net.c +++ b/net.c @@ -152,7 +152,11 @@ static void received_package(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip #endif /* WITH_LWIP */ +#ifdef WITH_STNODE +int print_wellknown(coap_context_t *, coap_pdu_t *, size_t *, size_t, coap_opt_t *); +#else int print_wellknown(coap_context_t *, unsigned char *, size_t *, size_t, coap_opt_t *); +#endif void coap_handle_failed_notify(coap_context_t *, const coap_address_t *, const str *); @@ -1235,15 +1239,20 @@ coap_new_error_response(coap_pdu_t *request, unsigned char code, */ static inline size_t get_wkc_len(coap_context_t *context, coap_opt_t *query_filter) { +#ifndef WITH_STNODE unsigned char buf[1]; +#endif size_t len = 0; +#ifndef WITH_STNODE if (print_wellknown(context, buf, &len, UINT_MAX, query_filter) /* MWAS: UINT_MAX requires limits.h */ & COAP_PRINT_STATUS_ERROR) { warn("cannot determine length of /.well-known/core\n"); return 0; } - +#else + print_wellknown(context, NULL, &len, UINT_MAX, query_filter); +#endif debug("get_wkc_len: print_wellknown() returned %zu\n", len); return len; @@ -1349,7 +1358,11 @@ wellknown_response(coap_context_t *context, coap_pdu_t *request) { resp->length++; len = need_block2 ? SZX_TO_BYTES(block.szx) : resp->max_size - resp->length; +#ifndef WITH_STNODE result = print_wellknown(context, resp->data, &len, offset, query_filter); +#else + result = print_wellknown(context, resp, &len, offset, query_filter); +#endif if ((result & COAP_PRINT_STATUS_ERROR) != 0) { debug("print_wellknown failed\n"); goto error; diff --git a/resource.c b/resource.c index 336d6b9c99..32be4a1e46 100644 --- a/resource.c +++ b/resource.c @@ -175,16 +175,25 @@ print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen, size_t offset, coap_opt_t *query_filter __attribute__ ((unused))) { #else /* not a GCC */ +#ifndef WITH_STNODE coap_print_status_t print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen, size_t offset, coap_opt_t *query_filter) { +#else +coap_print_status_t +print_wellknown(coap_context_t *context, coap_pdu_t *pdu, size_t *buflen, + size_t offset, coap_opt_t *query_filter) { +#endif /* WITH_STNODE */ #endif /* GCC */ coap_resource_t *r; +#ifndef WITH_STNODE unsigned char *p = buf; const unsigned char *bufend = buf + *buflen; - size_t left, written = 0; - coap_print_status_t result; + size_t left = 0; const size_t old_offset = offset; +#endif + size_t written = 0; + coap_print_status_t result; int subsequent_resource = 0; #ifndef COAP_RESOURCES_NOHASH coap_resource_t *tmp; @@ -292,27 +301,42 @@ print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen, if (!subsequent_resource) { /* this is the first resource */ subsequent_resource = 1; } else { +#ifndef WITH_STNODE PRINT_COND_WITH_OFFSET(p, bufend, offset, ',', written); +#else + if(pdu) { + mbuf_write(pdu->mbuf, ",", 1, pdu->length+1); + pdu->length += 1; + } + written++; +#endif } +#ifndef WITH_STNODE left = bufend - p; /* calculate available space */ result = coap_print_link(r, p, &left, &offset); - +#else + result = coap_print_link(r, pdu, &written, &offset); +#endif if (result & COAP_PRINT_STATUS_ERROR) { break; } /* coap_print_link() returns the number of characters that * where actually written to p. Now advance to its end. */ +#ifndef WITH_STNODE p += COAP_PRINT_OUTPUT_LENGTH(result); written += left; +#endif } *buflen = written; +#ifndef WITH_STNODE result = p - buf; if (result + old_offset - offset < *buflen) { result |= COAP_PRINT_STATUS_TRUNC; } +#endif return result; } @@ -556,6 +580,7 @@ coap_get_resource_from_key(coap_context_t *context, coap_key_t key) { #endif /* WITH_CONTIKI */ } +#ifndef WITH_STNODE coap_print_status_t coap_print_link(const coap_resource_t *resource, unsigned char *buf, size_t *len, size_t *offset) { @@ -573,6 +598,27 @@ coap_print_link(const coap_resource_t *resource, resource->uri.s, resource->uri.length, *len); PRINT_COND_WITH_OFFSET(p, bufend, *offset, '>', *len); +#else /* WITH_STNODE */ +coap_print_status_t +coap_print_link(const coap_resource_t *resource, + coap_pdu_t *pdu, size_t *len, size_t *offset) { + //unsigned char *p = buf; + //const unsigned char *bufend = buf + *len; + coap_attr_t *attr; + coap_print_status_t result = 0; + + if(pdu) + { + mbuf_write(pdu->mbuf, "length+1); + pdu->length += 2; + if(resource->uri.length) /* MWAS: this check is mandatory for "/" resource to work */ + mbuf_write(pdu->mbuf, resource->uri.s, resource->uri.length, pdu->length+1); + pdu->length += resource->uri.length; + mbuf_write(pdu->mbuf, ">", 1, pdu->length+1); + pdu->length += 1; + } + *len += (3 + resource->uri.length); +#endif #ifndef WITH_CONTIKI LL_FOREACH(resource->link_attr, attr) { @@ -581,6 +627,7 @@ coap_print_link(const coap_resource_t *resource, attr = list_item_next(attr)) { #endif /* WITH_CONTIKI */ +#ifndef WITH_STNODE PRINT_COND_WITH_OFFSET(p, bufend, *offset, ';', *len); COPY_COND_WITH_OFFSET(p, bufend, *offset, @@ -602,7 +649,37 @@ coap_print_link(const coap_resource_t *resource, if (result + old_offset - *offset < *len) { result |= COAP_PRINT_STATUS_TRUNC; } - +#else /* WITH_STNODE */ + if(pdu) + { + mbuf_write(pdu->mbuf, ";", 1, pdu->length+1); + pdu->length += 1; + mbuf_write(pdu->mbuf, attr->name.s, attr->name.length, pdu->length+1); + pdu->length += attr->name.length; + } + *len += (1 + attr->name.length); + + if (attr->value.s) + { + if(pdu) + { + mbuf_write(pdu->mbuf, "=", 1, pdu->length+1); + pdu->length += 1; + mbuf_write(pdu->mbuf, attr->value.s, attr->value.length, pdu->length+1); + pdu->length += attr->value.length; + } + *len += (1 + attr->value.length); + } +} +if (resource->observable) { + if(pdu) + { + mbuf_write(pdu->mbuf, ";obs", 4, pdu->length+1); + pdu->length += 4; + } + *len += 4; +} +#endif return result; } diff --git a/resource.h b/resource.h index 2925968e4b..ffe46e9772 100644 --- a/resource.h +++ b/resource.h @@ -212,8 +212,13 @@ typedef unsigned int coap_print_status_t; * COAP_PRINT_STATUS_TRUNC indicates that the output has been * truncated. */ +#ifndef WITH_STNODE coap_print_status_t coap_print_link(const coap_resource_t *resource, unsigned char *buf, size_t *len, size_t *offset); +#else /* WITH_STNODE */ +coap_print_status_t coap_print_link(const coap_resource_t *resource, + coap_pdu_t *pdu, size_t *len, size_t *offset); +#endif /** * Registers the specified @p handler as message handler for the request type From 2130f6d042cf1f01a14045519af8594e92e447c7 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Thu, 19 Jun 2014 12:53:56 +0200 Subject: [PATCH 31/69] Change debug functions in net.c --- net.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net.c b/net.c index 0008e1e3f0..c69a6e4819 100644 --- a/net.c +++ b/net.c @@ -1517,7 +1517,7 @@ handle_request(coap_context_t *context, coap_queue_t *node) { if ((observe_action & COAP_OBSERVE_CANCEL) == 0) { coap_subscription_t *subscription; - coap_log(LOG_DEBUG, "create new subscription\n"); + debug("create new subscription\n"); subscription = coap_add_observer(resource, &node->remote, &token); if (subscription) { subscription->non = node->pdu->hdr->type == COAP_MESSAGE_NON; @@ -1532,7 +1532,7 @@ handle_request(coap_context_t *context, coap_queue_t *node) { if (observe && ((COAP_RESPONSE_CLASS(response->hdr->code) > 2) || ((observe_action & COAP_OBSERVE_CANCEL) != 0))) { - coap_log(LOG_DEBUG, "removed observer"); + debug("removed observer"); coap_delete_observer(resource, &node->remote, &token); } @@ -1654,7 +1654,7 @@ coap_dispatch( coap_context_t *context ) { * not only the transaction but also the subscriptions we might * have. */ - coap_log(LOG_ALERT, "got RST for message %u\n", ntohs(rcvd->pdu->hdr->id)); + warn("got RST for message %u\n", ntohs(rcvd->pdu->hdr->id)); /* find transaction in sendqueue to stop retransmission */ coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent); From 6d890b38456c657264b22298b5d70ed88f38d1ef Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Tue, 5 Aug 2014 11:26:43 +0200 Subject: [PATCH 32/69] Moved back changes from ext/libcoap --- ChangeLog | 25 + address.h | 92 --- async.c | 4 +- async.h | 2 +- block.c | 2 - coap.h | 2 +- coap_list.c | 6 +- coap_net.c | 1256 ++++++++++++++++++++++++++++++++++++++++ coap_net.h | 445 ++++++++++++++ coap_time.h | 75 --- config.h | 3 + debug.c | 201 +------ debug.h | 65 --- encode.c | 4 - encode.h | 4 - examples/client.c | 16 +- examples/etsi_iot_01.c | 8 +- libcoap.mk | 2 +- option.c | 7 - option.h | 8 +- pdu.c | 142 +---- pdu.h | 77 +-- prng.h | 26 - resource.c | 453 ++------------- resource.h | 66 ++- str.c | 6 +- subscribe.c | 19 +- subscribe.h | 2 +- t_list.h | 5 - uri.c | 4 +- uthash.h | 4 +- 31 files changed, 1921 insertions(+), 1110 deletions(-) create mode 100644 coap_net.c create mode 100644 coap_net.h diff --git a/ChangeLog b/ChangeLog index e362057122..6650fe652e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2014-06-22 Maciej Wasilak + + Remove all occurences of WITH_POSIX, WITH_LWIP and WITH_CONTIKI + from following files: + + * address.h + * async.c + * block.c + * coap_net.c + * coap_net.h + * coap_time.h + * debug.c + * debug.h + * encode.c + * encode.h + * option.c + * option.h + * pdu.c + * pdu.h + * prng.h + * resource.c + * resource.h + * t_list.h + * uri.c + 2014-03-09 Olaf Bergmann * net.c (coap_cancel): Removed 7.31 again and implemented new diff --git a/address.h b/address.h index 0c1c9bb70b..feb6633115 100644 --- a/address.h +++ b/address.h @@ -36,93 +36,6 @@ #include #endif -#ifdef WITH_LWIP -#include - -typedef struct coap_address_t { - uint16_t port; - ip_addr_t addr; -} coap_address_t; - -/* FIXME oversimplification: just assuming it's an ipv4 address instead of - * looking up the appropraite lwip function */ - -#define _coap_address_equals_impl(A, B) ((A)->addr.addr == (B)->addr.addr && A->port == B->port) - -/* FIXME sure there is something in lwip */ - -#define _coap_is_mcast_impl(Address) 0 - -#endif /* WITH_LWIP */ -#ifdef WITH_CONTIKI -#include "uip.h" - -typedef struct coap_address_t { - unsigned char size; - uip_ipaddr_t addr; - unsigned short port; -} coap_address_t; - -#define _coap_address_equals_impl(A,B) \ - ((A)->size == (B)->size \ - && (A)->port == (B)->port \ - && uip_ipaddr_cmp(&((A)->addr),&((B)->addr))) - -#define _coap_is_mcast_impl(Address) uip_is_addr_mcast(&((Address)->addr)) -#endif /* WITH_CONTIKI */ -#ifdef WITH_POSIX - -/** multi-purpose address abstraction */ -typedef struct coap_address_t { - socklen_t size; /**< size of addr */ - union { - struct sockaddr sa; - struct sockaddr_storage st; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - } addr; -} coap_address_t; - -static inline int -_coap_address_equals_impl(const coap_address_t *a, - const coap_address_t *b) { - if (a->size != b->size || a->addr.sa.sa_family != b->addr.sa.sa_family) - return 0; - - /* need to compare only relevant parts of sockaddr_in6 */ - switch (a->addr.sa.sa_family) { - case AF_INET: - return - a->addr.sin.sin_port == b->addr.sin.sin_port && - memcmp(&a->addr.sin.sin_addr, &b->addr.sin.sin_addr, - sizeof(struct in_addr)) == 0; - case AF_INET6: - return a->addr.sin6.sin6_port == b->addr.sin6.sin6_port && - memcmp(&a->addr.sin6.sin6_addr, &b->addr.sin6.sin6_addr, - sizeof(struct in6_addr)) == 0; - default: /* fall through and signal error */ - ; - } - return 0; -} - -static inline int -_coap_is_mcast_impl(const coap_address_t *a) { - if (!a) - return 0; - - switch (a->addr.sa.sa_family) { - case AF_INET: - return IN_MULTICAST(a->addr.sin.sin_addr.s_addr); -case AF_INET6: - return IN6_IS_ADDR_MULTICAST(&a->addr.sin6.sin6_addr); - default: /* fall through and signal error */ - ; - } - return 0; -} -#endif /* WITH_POSIX */ -#ifdef WITH_STNODE #include "net.h" typedef struct coap_address_t { @@ -136,8 +49,6 @@ typedef struct coap_address_t { /* Multicast IPv4 addresses start with 0b1110 */ #define _coap_is_mcast_impl(Address) ((Address)->addr.u8[0] && 0xF0 == 0xE0) -#endif /* WITH_STNODE */ - /** * Resets the given coap_address_t object @p addr to its default * values. In particular, the member size must be initialized to the @@ -149,10 +60,7 @@ static inline void coap_address_init(coap_address_t *addr) { assert(addr); memset(addr, 0, sizeof(coap_address_t)); -#ifndef WITH_LWIP - /* lwip has constandt address sizes and doesn't need the .size part */ addr->size = sizeof(addr->addr); -#endif } /** diff --git a/async.c b/async.c index b198127b7a..61439f1b5a 100644 --- a/async.c +++ b/async.c @@ -21,10 +21,8 @@ #include "debug.h" #include "async.h" -#ifdef WITH_STNODE #include "logging.h" DEFINE_LOG(LOG_DEFAULT_SEVERITY); -#endif coap_async_state_t * coap_register_async(coap_context_t *context, coap_address_t *peer, @@ -46,7 +44,7 @@ coap_register_async(coap_context_t *context, coap_address_t *peer, s = (coap_async_state_t *)coap_malloc(sizeof(coap_async_state_t) + request->hdr->token_length); if (!s) { - coap_log(LOG_CRIT, "coap_register_async: insufficient memory\n"); + error("coap_register_async: insufficient memory\n"); return NULL; } diff --git a/async.h b/async.h index 8e2e11aae3..27e6988f0f 100644 --- a/async.h +++ b/async.h @@ -16,7 +16,7 @@ #define _COAP_ASYNC_H_ #include "config.h" -#include "libcoap/net.h" +#include "coap_net.h" #ifndef WITHOUT_ASYNC diff --git a/block.c b/block.c index 8f64d90c93..7ae08cb6aa 100644 --- a/block.c +++ b/block.c @@ -15,10 +15,8 @@ #include "debug.h" #include "block.h" -#ifdef WITH_STNODE #include "logging.h" DEFINE_LOG(LOG_DEFAULT_SEVERITY); -#endif #define min(a,b) ((a) < (b) ? (a) : (b)) diff --git a/coap.h b/coap.h index facfbf9d29..91c7ccfb0f 100644 --- a/coap.h +++ b/coap.h @@ -19,7 +19,7 @@ extern "C" { #include "coap_list.h" #include "pdu.h" #include "option.h" -#include "libcoap/net.h" +#include "coap_net.h" #include "encode.h" #include "str.h" #include "uri.h" diff --git a/coap_list.c b/coap_list.c index e93003c5eb..3f30982137 100644 --- a/coap_list.c +++ b/coap_list.c @@ -15,6 +15,8 @@ #include "mem.h" #include "coap_list.h" +DEFINE_LOG(LOG_DEFAULT_SEVERITY); + int coap_insert(coap_list_t **queue, coap_list_t *node, int (*order)(void *, void *node) ) { @@ -74,9 +76,7 @@ coap_list_t * coap_new_listnode(void *data, void (*delete_func)(void *) ) { coap_list_t *node = coap_malloc( sizeof(coap_list_t) ); if ( ! node ) { -#ifndef NDEBUG - coap_log(LOG_CRIT, "coap_new_listnode: malloc\n"); -#endif + error("coap_new_listnode: malloc\n"); return NULL; } diff --git a/coap_net.c b/coap_net.c new file mode 100644 index 0000000000..25bdb888cd --- /dev/null +++ b/coap_net.c @@ -0,0 +1,1256 @@ +/* net.c -- CoAP network interface + * + * Copyright (C) 2010--2014 Olaf Bergmann + * + * This file is part of the CoAP library libcoap. Please see + * README for terms of use. + */ + +#include "config.h" + +#include +#include +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#elif HAVE_SYS_UNISTD_H +#include +#endif +#include +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#include "debug.h" +#include "mem.h" +#include "str.h" +#include "async.h" +#include "resource.h" +#include "option.h" +#include "encode.h" +#include "block.h" +#include "coap_net.h" + +#include "system.h" +#include "net.h" +#include "logging.h" +DEFINE_LOG(LOG_DEFAULT_SEVERITY); + +systime_t clock_offset; + +static inline coap_queue_t * +coap_malloc_node(void) { + return (coap_queue_t *)sys_malloc(sizeof(coap_queue_t)); +} + +static inline void +coap_free_node(coap_queue_t *node) { + sys_free(node); +} + +int print_wellknown(coap_context_t *, coap_pdu_t *, size_t *, size_t, coap_opt_t *); +void coap_handle_failed_notify(coap_context_t *, const coap_address_t *, + const str *); + +unsigned int +coap_adjust_basetime(coap_context_t *ctx, coap_tick_t now) { + unsigned int result = 0; + coap_tick_diff_t delta = now - ctx->sendqueue_basetime; + + if (ctx->sendqueue) { + /* delta < 0 means that the new time stamp is before the old. */ + if (delta <= 0) { + ctx->sendqueue->t -= delta; + } else { + /* This case is more complex: The time must be advanced forward, + * thus possibly leading to timed out elements at the queue's + * start. For every element that has timed out, its relative + * time is set to zero and the result counter is increased. */ + + coap_queue_t *q = ctx->sendqueue; + coap_tick_t t = 0; + while (q && (t + q->t < (coap_tick_t)delta)) { + t += q->t; + q->t = 0; + result++; + q = q->next; + } + + /* finally adjust the first element that has not expired */ + if (q) { + q->t = (coap_tick_t)delta - t; + } + } + } + + /* adjust basetime */ + ctx->sendqueue_basetime += delta; + + return result; +} + +int +coap_insert_node(coap_queue_t **queue, coap_queue_t *node) { + coap_queue_t *p, *q; + if ( !queue || !node ) + return 0; + + /* set queue head if empty */ + if ( !*queue ) { + *queue = node; + return 1; + } + + /* replace queue head if PDU's time is less than head's time */ + q = *queue; + if (node->t < q->t) { + node->next = q; + *queue = node; + q->t -= node->t; /* make q->t relative to node->t */ + return 1; + } + + /* search for right place to insert */ + do { + node->t -= q->t; /* make node-> relative to q->t */ + p = q; + q = q->next; + } while (q && q->t <= node->t); + + /* insert new item */ + if (q) { + q->t -= node->t; /* make q->t relative to node->t */ + } + node->next = q; + p->next = node; + return 1; +} + +int +coap_delete_node(coap_queue_t *node) { + if ( !node ) + return 0; + + coap_delete_pdu(node->pdu); + coap_free_node(node); + + return 1; +} + +void +coap_delete_all(coap_queue_t *queue) { + if ( !queue ) + return; + + coap_delete_all( queue->next ); + coap_delete_node( queue ); +} + +coap_queue_t * +coap_new_node(void) { + coap_queue_t *node; + node = coap_malloc_node(); + + if ( ! node ) { + error("coap_new_node: malloc\n"); + return NULL; + } + + memset(node, 0, sizeof *node ); + return node; +} + +coap_queue_t * +coap_peek_next( coap_context_t *context ) { + if ( !context || !context->sendqueue ) + return NULL; + + return context->sendqueue; +} + +coap_queue_t * +coap_pop_next( coap_context_t *context ) { + coap_queue_t *next; + + if ( !context || !context->sendqueue ) + return NULL; + + next = context->sendqueue; + context->sendqueue = context->sendqueue->next; + if (context->sendqueue) { + context->sendqueue->t += next->t; + } + next->next = NULL; + return next; +} + +#ifdef COAP_DEFAULT_WKC_HASHKEY +/** Checks if @p Key is equal to the pre-defined hash key for.well-known/core. */ +#define is_wkc(Key) \ + (memcmp((Key), COAP_DEFAULT_WKC_HASHKEY, sizeof(coap_key_t)) == 0) +#else +/* Implements a singleton to store a hash key for the .wellknown/core + * resources. */ +int +is_wkc(coap_key_t k) { + static coap_key_t wkc; + static unsigned char _initialized = 0; + if (!_initialized) { + _initialized = coap_hash_path((unsigned char *)COAP_DEFAULT_URI_WELLKNOWN, + sizeof(COAP_DEFAULT_URI_WELLKNOWN) - 1, wkc); + } + return memcmp(k, wkc, sizeof(coap_key_t)) == 0; +} +#endif + + +coap_context_t * +coap_new_context( + const coap_address_t *listen_addr) { + + coap_context_t *c = sys_malloc( sizeof( coap_context_t ) ); + + if (!listen_addr) { + debug("no listen address specified\n"); + return NULL; + } + coap_clock_init(); + prng_init((unsigned long)listen_addr ^ clock_offset); + + if ( !c ) { + debug("coap_init: malloc:\n"); + return NULL; + } + + memset(c, 0, sizeof( coap_context_t ) ); + + /* initialize message id */ + prng((unsigned char *)&c->message_id, sizeof(unsigned short)); + + /* register the critical options that we know */ + coap_register_option(c, COAP_OPTION_IF_MATCH); + coap_register_option(c, COAP_OPTION_URI_HOST); + coap_register_option(c, COAP_OPTION_IF_NONE_MATCH); + coap_register_option(c, COAP_OPTION_URI_PORT); + coap_register_option(c, COAP_OPTION_URI_PATH); + coap_register_option(c, COAP_OPTION_URI_QUERY); + coap_register_option(c, COAP_OPTION_ACCEPT); + coap_register_option(c, COAP_OPTION_PROXY_URI); + coap_register_option(c, COAP_OPTION_PROXY_SCHEME); + coap_register_option(c, COAP_OPTION_BLOCK2); + coap_register_option(c, COAP_OPTION_BLOCK1); + + c->ns = net_create(NET_UDP); + if (!c->ns) { + return NULL; + } + if(!net_bind(c->ns, listen_addr->port)) + { + debug("can't bind socket to port %d\n", listen_addr->port); + return NULL; + } + return c; +} + +void +coap_free_context( coap_context_t *context ) { + coap_resource_t *res; +#ifndef COAP_RESOURCES_NOHASH + coap_resource_t *rtmp; +#endif + if ( !context ) + return; + + coap_delete_all(context->recvqueue); + coap_delete_all(context->sendqueue); + +#ifdef COAP_RESOURCES_NOHASH + LL_FOREACH(context->resources, res) { +#else + HASH_ITER(hh, context->resources, res, rtmp) { +#endif + coap_delete_resource(context, res->key); + } + + net_disconnect(context->ns); + sys_free( context ); +} + +int +coap_option_check_critical(coap_context_t *ctx, + coap_pdu_t *pdu, + coap_opt_filter_t unknown) { + + coap_opt_iterator_t opt_iter; + int ok = 1; + + coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL); + + while (coap_option_next(&opt_iter)) { + + /* The following condition makes use of the fact that + * coap_option_getb() returns -1 if type exceeds the bit-vector + * filter. As the vector is supposed to be large enough to hold + * the largest known option, we know that everything beyond is + * bad. + */ + if (opt_iter.type & 0x01 && + coap_option_getb(ctx->known_options, opt_iter.type) < 1) { + debug("unknown critical option %d\n", opt_iter.type); + + ok = 0; + + /* When opt_iter.type is beyond our known option range, + * coap_option_setb() will return -1 and we are safe to leave + * this loop. */ + if (coap_option_setb(unknown, opt_iter.type) == -1) + break; + } + } + + return ok; +} + +void +coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, + coap_tid_t *id) { + coap_key_t h; + + memset(h, 0, sizeof(coap_key_t)); + + /* Compare the complete address structure in case of IPv4. For IPv6, + * we need to look at the transport address only. */ + + /* TODO: MWAS: check better options */ + coap_hash((const unsigned char *)&peer->port, sizeof(peer->port), h); + coap_hash((const unsigned char *)&peer->addr, sizeof(peer->addr), h); + + coap_hash((const unsigned char *)&pdu->hdr->id, sizeof(unsigned short), h); + + *id = ((h[0] << 8) | h[1]) ^ ((h[2] << 8) | h[3]); +} + +coap_tid_t +coap_send_ack(coap_context_t *context, + const coap_address_t *dst, + coap_pdu_t *request) { + coap_pdu_t *response; + coap_tid_t result = COAP_INVALID_TID; + + if (request && request->hdr->type == COAP_MESSAGE_CON) { + response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->hdr->id, + sizeof(coap_pdu_t)); + if (response) { + result = coap_send(context, dst, response); + coap_delete_pdu(response); + } + } + return result; +} + +coap_tid_t +coap_send_impl(coap_context_t *context, + const coap_address_t *dst, + coap_pdu_t *pdu) { + coap_tid_t id = COAP_INVALID_TID; + + if ( !context || !dst || !pdu ) + return id; + + coap_transaction_id(dst, pdu, &id); + + if(!net_send_to(context->ns, (ipaddr_t *)&dst->addr, dst->port, pdu->mbuf)) { + warn("coap_send: sendto\n"); + } + + return id; +} + +coap_tid_t +coap_send(coap_context_t *context, + const coap_address_t *dst, + coap_pdu_t *pdu) { + return coap_send_impl(context, dst, pdu); +} + +coap_tid_t +coap_send_error(coap_context_t *context, + coap_pdu_t *request, + const coap_address_t *dst, + unsigned char code, + coap_opt_filter_t opts) { + coap_pdu_t *response; + coap_tid_t result = COAP_INVALID_TID; + + assert(request); + assert(dst); + + response = coap_new_error_response(request, code, opts); + if (response) { + result = coap_send(context, dst, response); + coap_delete_pdu(response); + } + + return result; +} + +coap_tid_t +coap_send_message_type(coap_context_t *context, + const coap_address_t *dst, + coap_pdu_t *request, + unsigned char type) { + coap_pdu_t *response; + coap_tid_t result = COAP_INVALID_TID; + + if (request) { + response = coap_pdu_init(type, 0, request->hdr->id, sizeof(coap_pdu_t)); + if (response) { + result = coap_send(context, dst, response); + coap_delete_pdu(response); + } + } + return result; +} + +coap_tid_t +coap_send_confirmed(coap_context_t *context, + const coap_address_t *dst, + coap_pdu_t *pdu) { + coap_queue_t *node; + coap_tick_t now; + int r; + + node = coap_new_node(); + if (!node) { + debug("coap_send_confirmed: insufficient memory\n"); + return COAP_INVALID_TID; + } + + node->id = coap_send_impl(context, dst, pdu); + if (COAP_INVALID_TID == node->id) { + debug("coap_send_confirmed: error sending pdu\n"); + coap_free_node(node); + return COAP_INVALID_TID; + } + + prng((unsigned char *)&r,sizeof(r)); + + /* add randomized RESPONSE_TIMEOUT to determine retransmission timeout */ + node->timeout = COAP_DEFAULT_RESPONSE_TIMEOUT * COAP_TICKS_PER_SECOND + + (COAP_DEFAULT_RESPONSE_TIMEOUT >> 1) * + ((COAP_TICKS_PER_SECOND * (r & 0xFF)) >> 8); + + memcpy(&node->remote, dst, sizeof(coap_address_t)); + node->pdu = pdu; + + /* Set timer for pdu retransmission. If this is the first element in + * the retransmission queue, the base time is set to the current + * time and the retransmission time is node->timeout. If there is + * already an entry in the sendqueue, we must check if this node is + * to be retransmitted earlier. Therefore, node->timeout is first + * normalized to the base time and then inserted into the queue with + * an adjusted relative time. + */ + coap_ticks(&now); + if (context->sendqueue == NULL) { + node->t = node->timeout; + context->sendqueue_basetime = now; + } else { + /* make node->t relative to context->sendqueue_basetime */ + node->t = (now - context->sendqueue_basetime) + node->timeout; + } + + coap_insert_node(&context->sendqueue, node); + + return node->id; +} + +coap_tid_t +coap_retransmit( coap_context_t *context, coap_queue_t *node ) { + if ( !context || !node ) + return COAP_INVALID_TID; + + /* re-initialize timeout when maximum number of retransmissions are not reached yet */ + if ( node->retransmit_cnt < COAP_DEFAULT_MAX_RETRANSMIT ) { + node->retransmit_cnt++; + node->t = node->timeout << node->retransmit_cnt; + coap_insert_node(&context->sendqueue, node); + + debug("** retransmission #%d of transaction %d\n", + node->retransmit_cnt, ntohs(node->pdu->hdr->id)); + + node->id = coap_send_impl(context, &node->remote, node->pdu); + return node->id; + } + + /* no more retransmissions, remove node from system */ + debug("** removed transaction %d\n", ntohs(node->id)); + +#ifndef WITHOUT_OBSERVE + /* Check if subscriptions exist that should be canceled after + COAP_MAX_NOTIFY_FAILURES */ + if (node->pdu->hdr->code >= 64) { + str token = { 0, NULL }; + + token.length = node->pdu->hdr->token_length; + token.s = node->pdu->hdr->token; + + coap_handle_failed_notify(context, &node->remote, &token); + } +#endif /* WITHOUT_OBSERVE */ + + /* And finally delete the node */ + coap_delete_node( node ); + return COAP_INVALID_TID; +} + +/** + * Checks if @p opt fits into the message that ends with @p maxpos. + * This function returns @c 1 on success, or @c 0 if the option @p opt + * would exceed @p maxpos. + */ +static inline int +check_opt_size(coap_opt_t *opt, unsigned char *maxpos) { + if (opt && opt < maxpos) { + if (((*opt & 0x0f) < 0x0f) || (opt + 1 < maxpos)) + return opt + COAP_OPT_SIZE(opt) < maxpos; + } + return 0; +} + +int +coap_read( coap_context_t *ctx, coap_tick_t timeout) { + + ssize_t bytes_read = -1; + coap_address_t src, dst; + coap_queue_t *node; + + coap_address_init(&src); + + ctx->pending_package = net_receive_from(ctx->ns, &src.addr, &src.port, timeout); + if(ctx->pending_package) + { + src.size = 4; + bytes_read = ctx->pending_package->tot_len; + } + + if ( bytes_read < 0 ) { + debug("coap_read: recvfrom"); + goto error_early; + } + + if ( (size_t)bytes_read < sizeof(coap_hdr_t) ) { + debug("coap_read: discarded invalid frame\n" ); + goto error_early; + } + + node = coap_new_node(); + if ( !node ) + goto error_early; + + node->pdu = coap_pdu_from_mbuf(ctx->pending_package); + ctx->pending_package = NULL; + if (!node->pdu) + goto error; + + coap_ticks( &node->t ); + memcpy(&node->local, &dst, sizeof(coap_address_t)); + memcpy(&node->remote, &src, sizeof(coap_address_t)); + + if (!coap_pdu_parse((unsigned char *)node->pdu->mbuf->payload, bytes_read, node->pdu)) { + warn("discard malformed PDU"); + goto error; + } + + /* and add new node to receive queue */ + coap_transaction_id(&node->remote, node->pdu, &node->id); + coap_insert_node(&ctx->recvqueue, node); + + + if (LOG_DEBUG <= LOG.severity) { +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN 40 +#endif + unsigned char addr[INET6_ADDRSTRLEN+8]; + + if (coap_print_addr(&src, addr, INET6_ADDRSTRLEN+8)) + debug("** received %d bytes from %s:\n", (int)bytes_read, addr); + + coap_show_pdu( node->pdu ); + } + + return 0; + + error: + /* FIXME: send back RST? */ + coap_delete_node(node); + return -1; + error_early: + /* even if there was an error, clean up */ + if(ctx->pending_package) + mbuf_free(ctx->pending_package); + ctx->pending_package = NULL; + return -1; +} + +int +coap_remove_from_queue(coap_queue_t **queue, coap_tid_t id, coap_queue_t **node) { + coap_queue_t *p, *q; + + if ( !queue || !*queue) + return 0; + + /* replace queue head if PDU's time is less than head's time */ + + if ( id == (*queue)->id ) { /* found transaction */ + *node = *queue; + *queue = (*queue)->next; + if (*queue) { /* adjust relative time of new queue head */ + (*queue)->t += (*node)->t; + } + (*node)->next = NULL; + /* coap_delete_node( q ); */ + debug("*** removed transaction %u\n", id); + return 1; + } + + /* search transaction to remove (only first occurence will be removed) */ + q = *queue; + do { + p = q; + q = q->next; + } while ( q && id != q->id ); + + if ( q ) { /* found transaction */ + p->next = q->next; + if (p->next) { /* must update relative time of p->next */ + p->next->t += q->t; + } + q->next = NULL; + *node = q; + /* coap_delete_node( q ); */ + debug("*** removed transaction %u\n", id); + return 1; + } + + return 0; + +} + +static inline int +token_match(const unsigned char *a, size_t alen, + const unsigned char *b, size_t blen) { + return alen == blen && (alen == 0 || memcmp(a, b, alen) == 0); +} + +void +coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst, + const unsigned char *token, size_t token_length) { + /* cancel all messages in sendqueue that are for dst + * and use the specified token */ + coap_queue_t *p, *q; + + while (context->sendqueue && + coap_address_equals(dst, &context->sendqueue->remote) && + token_match(token, token_length, + context->sendqueue->pdu->hdr->token, + context->sendqueue->pdu->hdr->token_length)) { + q = context->sendqueue; + context->sendqueue = q->next; + debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id)); + coap_delete_node(q); + } + + if (!context->sendqueue) + return; + + p = context->sendqueue; + q = p->next; + + /* when q is not NULL, it does not match (dst, token), so we can skip it */ + while (q) { + if (coap_address_equals(dst, &q->remote) && + token_match(token, token_length, + q->pdu->hdr->token, q->pdu->hdr->token_length)) { + p->next = q->next; + debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id)); + coap_delete_node(q); + q = p->next; + } else { + p = q; + q = q->next; + } + } +} + +coap_queue_t * +coap_find_transaction(coap_queue_t *queue, coap_tid_t id) { + while (queue && queue->id != id) + queue = queue->next; + + return queue; +} + +coap_pdu_t * +coap_new_error_response(coap_pdu_t *request, unsigned char code, + coap_opt_filter_t opts) { + coap_opt_iterator_t opt_iter; + coap_pdu_t *response; + size_t size = sizeof(coap_hdr_t) + request->hdr->token_length; + int type; + coap_opt_t *option; + unsigned short opt_type = 0; /* used for calculating delta-storage */ + +#if COAP_ERROR_PHRASE_LENGTH > 0 + char *phrase = coap_response_phrase(code); + + /* Need some more space for the error phrase and payload start marker */ + if (phrase) + size += strlen(phrase) + 1; +#endif + + assert(request); + + /* cannot send ACK if original request was not confirmable */ + type = request->hdr->type == COAP_MESSAGE_CON + ? COAP_MESSAGE_ACK + : COAP_MESSAGE_NON; + + /* Estimate how much space we need for options to copy from + * request. We always need the Token, for 4.02 the unknown critical + * options must be included as well. */ + coap_option_clrb(opts, COAP_OPTION_CONTENT_TYPE); /* we do not want this */ + + coap_option_iterator_init(request, &opt_iter, opts); + + /* Add size of each unknown critical option. As known critical + options as well as elective options are not copied, the delta + value might grow. + */ + while((option = coap_option_next(&opt_iter))) { + unsigned short delta = opt_iter.type - opt_type; + /* calculate space required to encode (opt_iter.type - opt_type) */ + if (delta < 13) { + size++; + } else if (delta < 269) { + size += 2; + } else { + size += 3; + } + + /* add coap_opt_length(option) and the number of additional bytes + * required to encode the option length */ + + size += coap_opt_length(option); + switch (*option & 0x0f) { + case 0x0e: + size++; + /* fall through */ + case 0x0d: + size++; + break; + default: + ; + } + + opt_type = opt_iter.type; + } + + /* Now create the response and fill with options and payload data. */ + response = coap_pdu_init(type, code, request->hdr->id, size); + if (response) { + /* copy token */ + if (!coap_add_token(response, request->hdr->token_length, + request->hdr->token)) { + debug("cannot add token to error response\n"); + coap_delete_pdu(response); + return NULL; + } + + /* copy all options */ + coap_option_iterator_init(request, &opt_iter, opts); + while((option = coap_option_next(&opt_iter))) + coap_add_option(response, opt_iter.type, + COAP_OPT_LENGTH(option), + COAP_OPT_VALUE(option)); + +#if COAP_ERROR_PHRASE_LENGTH > 0 + /* note that diagnostic messages do not need a Content-Format option. */ + if (phrase) + coap_add_data(response, strlen(phrase), (unsigned char *)phrase); +#endif + } + + return response; +} + +/** + * Quick hack to determine the size of the resource description for + * .well-known/core. + */ +static inline size_t +get_wkc_len(coap_context_t *context, coap_opt_t *query_filter) { + size_t len = 0; + + if (print_wellknown(context, NULL, &len, UINT_MAX, query_filter) + & COAP_PRINT_STATUS_ERROR) { + warn("cannot determine length of /.well-known/core\n"); + return 0; + } + debug("get_wkc_len: print_wellknown() returned %zu\n", len); + + return len; +} + +coap_pdu_t * +wellknown_response(coap_context_t *context, coap_pdu_t *request) { + coap_pdu_t *resp; + coap_opt_iterator_t opt_iter; + size_t len, wkc_len; + unsigned char buf[2]; + int result = 0; + int need_block2 = 0; /* set to 1 if Block2 option is required */ + coap_block_t block; + coap_opt_t *query_filter; + size_t offset = 0; + + resp = coap_pdu_init(request->hdr->type == COAP_MESSAGE_CON + ? COAP_MESSAGE_ACK + : COAP_MESSAGE_NON, + COAP_RESPONSE_CODE(205), + request->hdr->id, COAP_MAX_PDU_SIZE); + if (!resp) { + debug("wellknown_response: cannot create PDU\n"); + return NULL; + } + + if (!coap_add_token(resp, request->hdr->token_length, request->hdr->token)) { + debug("wellknown_response: cannot add token\n"); + goto error; + } + + query_filter = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter); + wkc_len = get_wkc_len(context, query_filter); + + /* check whether the request contains the Block2 option */ + if (coap_get_block(request, COAP_OPTION_BLOCK2, &block)) { + offset = block.num << (block.szx + 4); + if (block.szx > 6) { /* invalid, MUST lead to 4.00 Bad Request */ + resp->hdr->code = COAP_RESPONSE_CODE(400); + return resp; + } else if (block.szx > COAP_MAX_BLOCK_SZX) { + block.szx = COAP_MAX_BLOCK_SZX; + block.num = offset >> (block.szx + 4); + } + + need_block2 = 1; + } + + /* Check if there is sufficient space to add Content-Format option + * and data. We do this before adding the Content-Format option to + * avoid sending error responses with that option but no actual + * content. */ + if (resp->max_size <= (size_t)resp->length + 3) { + debug("wellknown_response: insufficient storage space\n"); + goto error; + } + + /* Add Content-Format. As we have checked for available storage, + * nothing should go wrong here. */ + assert(coap_encode_var_bytes(buf, + COAP_MEDIATYPE_APPLICATION_LINK_FORMAT) == 1); + coap_add_option(resp, COAP_OPTION_CONTENT_FORMAT, + coap_encode_var_bytes(buf, + COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), buf); + + /* check if Block2 option is required even if not requested */ + if (!need_block2 && (resp->max_size - (size_t)resp->length < wkc_len)) { + assert(resp->length <= resp->max_size); + const size_t payloadlen = resp->max_size - resp->length; + /* yes, need block-wise transfer */ + block.num = 0; + block.m = 0; /* the M bit is set by coap_write_block_opt() */ + block.szx = COAP_MAX_BLOCK_SZX; + while (payloadlen < SZX_TO_BYTES(block.szx)) { + if (block.szx == 0) { + debug("wellknown_response: message to small even for szx == 0\n"); + goto error; + } else { + block.szx--; + } + } + + need_block2 = 1; + } + + /* write Block2 option if necessary */ + if (need_block2) { + if (coap_write_block_opt(&block, COAP_OPTION_BLOCK2, resp, wkc_len) < 0) { + debug("wellknown_response: cannot add Block2 option\n"); + goto error; + } + } + + /* Manually set payload of response to let print_wellknown() write, + * into our buffer without copying data. */ + + resp->data = (unsigned char *)resp->hdr + resp->length; + *resp->data = COAP_PAYLOAD_START; + resp->data++; + resp->length++; + len = need_block2 ? SZX_TO_BYTES(block.szx) : resp->max_size - resp->length; + + result = print_wellknown(context, resp, &len, offset, query_filter); + if ((result & COAP_PRINT_STATUS_ERROR) != 0) { + debug("print_wellknown failed\n"); + goto error; + } + + resp->length += COAP_PRINT_OUTPUT_LENGTH(result); + return resp; + + error: + /* set error code 5.03 and remove all options and data from response */ + resp->hdr->code = COAP_RESPONSE_CODE(503); + resp->length = sizeof(coap_hdr_t) + resp->hdr->token_length; + return resp; +} + +/** + * This function cancels outstanding messages for the remote peer and + * token specified in @p sent. Any observation relationship for + * sent->remote and the token are removed. Calling this function is + * required when receiving an RST message (usually in response to a + * notification) or a 7.31 response. + * + * This function returns @c 0 when the token is unknown with this + * peer, or a value greater than zero otherwise. + */ +static int +coap_cancel(coap_context_t *context, const coap_queue_t *sent) { +#ifndef WITHOUT_OBSERVE + coap_resource_t *r; +#ifndef COAP_RESOURCES_NOHASH + coap_resource_t *tmp; +#endif + str token = { 0, NULL }; + int num_cancelled = 0; /* the number of observers cancelled */ + + /* remove observer for this resource, if any + * get token from sent and try to find a matching resource. Uh! + */ + + COAP_SET_STR(&token, sent->pdu->hdr->token_length, sent->pdu->hdr->token); + +#ifdef COAP_RESOURCES_NOHASH + LL_FOREACH(context->resources, r) { +#else + HASH_ITER(hh, context->resources, r, tmp) { +#endif + num_cancelled += coap_delete_observer(r, &sent->remote, &token); + coap_cancel_all_messages(context, &sent->remote, token.s, token.length); + } + return num_cancelled; +#else /* WITOUT_OBSERVE */ + return 0; +#endif /* WITOUT_OBSERVE */ +} + +#define WANT_WKC(Pdu,Key) \ + (((Pdu)->hdr->code == COAP_REQUEST_GET) && is_wkc(Key)) + +void +handle_request(coap_context_t *context, coap_queue_t *node) { + coap_method_handler_t h = NULL; + coap_pdu_t *response = NULL; + coap_opt_filter_t opt_filter; + coap_resource_t *resource; + coap_key_t key; + + coap_option_filter_clear(opt_filter); + + /* try to find the resource from the request URI */ + coap_hash_request_uri(node->pdu, key); + resource = coap_get_resource_from_key(context, key); + + if (!resource) { + /* The resource was not found. Check if the request URI happens to + * be the well-known URI. In that case, we generate a default + * response, otherwise, we return 4.04 */ + + switch(node->pdu->hdr->code) { + + case COAP_REQUEST_GET: + if (is_wkc(key)) { /* GET request for .well-known/core */ + debug("create default response for %s\n", COAP_DEFAULT_URI_WELLKNOWN); + response = wellknown_response(context, node->pdu); + + } else { /* GET request for any another resource, return 4.04 */ + + debug("GET for unknown resource 0x%02x%02x%02x%02x, return 4.04\n", + key[0], key[1], key[2], key[3]); + response = + coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(404), + opt_filter); + } + break; + + default: /* any other request type */ + + debug("unhandled request for unknown resource 0x%02x%02x%02x%02x\r\n", + key[0], key[1], key[2], key[3]); + if (!coap_is_mcast(&node->local)) + response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), + opt_filter); + } + + if (response && coap_send(context, &node->remote, response) == COAP_INVALID_TID) { + warn("cannot send response for transaction %u\n", node->id); + } + coap_delete_pdu(response); + + return; + } + + /* the resource was found, check if there is a registered handler */ + if ((size_t)node->pdu->hdr->code - 1 < + sizeof(resource->handler)/sizeof(coap_method_handler_t)) + h = resource->handler[node->pdu->hdr->code - 1]; + + if (h) { + debug("call custom handler for resource 0x%02x%02x%02x%02x\n", + key[0], key[1], key[2], key[3]); + response = coap_pdu_init(node->pdu->hdr->type == COAP_MESSAGE_CON + ? COAP_MESSAGE_ACK + : COAP_MESSAGE_NON, + 0, node->pdu->hdr->id, COAP_MAX_PDU_SIZE); + + /* Implementation detail: coap_add_token() immediately returns 0 + if response == NULL */ + if (coap_add_token(response, node->pdu->hdr->token_length, + node->pdu->hdr->token)) { + str token = { node->pdu->hdr->token_length, node->pdu->hdr->token }; + coap_opt_iterator_t opt_iter; + coap_opt_t *observe = NULL; + int observe_action = COAP_OBSERVE_CANCEL; + + /* check for Observe option */ + if (resource->observable) { + observe = coap_check_option(node->pdu, COAP_OPTION_OBSERVE, &opt_iter); + if (observe) { + observe_action = + coap_decode_var_bytes(coap_opt_value(observe), + coap_opt_length(observe)); + + if ((observe_action & COAP_OBSERVE_CANCEL) == 0) { + coap_subscription_t *subscription; + + debug("create new subscription\n"); + subscription = coap_add_observer(resource, &node->remote, &token); + if (subscription) { + subscription->non = node->pdu->hdr->type == COAP_MESSAGE_NON; + coap_touch_observer(context, &node->remote, &token); + } + } + } + } + + h(context, resource, &node->remote, + node->pdu, &token, response); + + if (observe && ((COAP_RESPONSE_CLASS(response->hdr->code) > 2) + || ((observe_action & COAP_OBSERVE_CANCEL) != 0))) { + debug("removed observer"); + coap_delete_observer(resource, &node->remote, &token); + } + + /* If original request contained a token, and the registered + * application handler made no changes to the response, then + * this is an empty ACK with a token, which is a malformed + * PDU */ + if ((response->hdr->type == COAP_MESSAGE_ACK) + && (response->hdr->code == 0)) { + /* Remove token from otherwise-empty acknowledgment PDU */ + response->hdr->token_length = 0; + response->length = sizeof(coap_hdr_t); + } + + if (response->hdr->type != COAP_MESSAGE_NON || + (response->hdr->code >= 64 + && !coap_is_mcast(&node->local))) { + if (coap_send(context, &node->remote, response) == COAP_INVALID_TID) { + debug("cannot send response for message %d\n", node->pdu->hdr->id); + } + } + + coap_delete_pdu(response); + } else { + warn("cannot generate response\r\n"); + } + } else { + if (WANT_WKC(node->pdu, key)) { + debug("create default response for %s\n", COAP_DEFAULT_URI_WELLKNOWN); + response = wellknown_response(context, node->pdu); + } else + response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), + opt_filter); + + if (!response || (coap_send(context, &node->remote, response) + == COAP_INVALID_TID)) { + debug("cannot send response for transaction %u\n", node->id); + } + coap_delete_pdu(response); + } +} + +static inline void +handle_response(coap_context_t *context, + coap_queue_t *sent, coap_queue_t *rcvd) { + + coap_send_ack(context, &rcvd->remote, rcvd->pdu); + + /* In a lossy context, the ACK of a separate response may have + * been lost, so we need to stop retransmitting requests with the + * same token. + */ + coap_cancel_all_messages(context, &rcvd->remote, + rcvd->pdu->hdr->token, + rcvd->pdu->hdr->token_length); + + /* Call application-specific reponse handler when available. */ + if (context->response_handler) { + context->response_handler(context, + &rcvd->remote, sent ? sent->pdu : NULL, + rcvd->pdu, rcvd->id); + } +} + +static inline int +#ifdef __GNUC__ +handle_locally(coap_context_t *context __attribute__ ((unused)), + coap_queue_t *node __attribute__ ((unused))) { +#else /* not a GCC */ +handle_locally(coap_context_t *context, coap_queue_t *node) { +#endif /* GCC */ + /* this function can be used to check if node->pdu is really for us */ + return 1; +} + +void +coap_dispatch( coap_context_t *context ) { + coap_queue_t *rcvd = NULL, *sent = NULL; + coap_pdu_t *response; + coap_opt_filter_t opt_filter; + + if (!context) + return; + + memset(opt_filter, 0, sizeof(coap_opt_filter_t)); + + while ( context->recvqueue ) { + rcvd = context->recvqueue; + + /* remove node from recvqueue */ + context->recvqueue = context->recvqueue->next; + rcvd->next = NULL; + + if ( rcvd->pdu->hdr->version != COAP_DEFAULT_VERSION ) { + debug("dropped packet with unknown version %u\n", rcvd->pdu->hdr->version); + goto cleanup; + } + + switch ( rcvd->pdu->hdr->type ) { + case COAP_MESSAGE_ACK: + /* find transaction in sendqueue to stop retransmission */ + coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent); + + if (rcvd->pdu->hdr->code == 0) + goto cleanup; + + /* FIXME: if sent code was >= 64 the message might have been a + * notification. Then, we must flag the observer to be alive + * by setting obs->fail_cnt = 0. */ + if (sent && COAP_RESPONSE_CLASS(sent->pdu->hdr->code) == 2) { + const str token = + { sent->pdu->hdr->token_length, sent->pdu->hdr->token }; + coap_touch_observer(context, &sent->remote, &token); + } + break; + + case COAP_MESSAGE_RST : + /* We have sent something the receiver disliked, so we remove + * not only the transaction but also the subscriptions we might + * have. */ + + warn("got RST for message %u\n", ntohs(rcvd->pdu->hdr->id)); + + /* find transaction in sendqueue to stop retransmission */ + coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent); + + if (sent) + coap_cancel(context, sent); + goto cleanup; + + case COAP_MESSAGE_NON : /* check for unknown critical options */ + if (coap_option_check_critical(context, rcvd->pdu, opt_filter) == 0) + goto cleanup; + break; + + case COAP_MESSAGE_CON : /* check for unknown critical options */ + if (coap_option_check_critical(context, rcvd->pdu, opt_filter) == 0) { + + /* FIXME: send response only if we have received a request. Otherwise, + * send RST. */ + response = + coap_new_error_response(rcvd->pdu, COAP_RESPONSE_CODE(402), opt_filter); + + if (!response) + warn("coap_dispatch: cannot create error reponse\n"); + else { + if (coap_send(context, &rcvd->remote, response) + == COAP_INVALID_TID) { + warn("coap_dispatch: error sending reponse\n"); + } + coap_delete_pdu(response); + } + + goto cleanup; + } + break; + } + + /* Pass message to upper layer if a specific handler was + * registered for a request that should be handled locally. */ + if (handle_locally(context, rcvd)) { + if (COAP_MESSAGE_IS_REQUEST(rcvd->pdu->hdr)) + handle_request(context, rcvd); + else if (COAP_MESSAGE_IS_RESPONSE(rcvd->pdu->hdr)) + handle_response(context, sent, rcvd); + else { + debug("dropped message with invalid code (%d.%02d)\n", + COAP_RESPONSE_CLASS(rcvd->pdu->hdr->code), + rcvd->pdu->hdr->code & 0x1f); + coap_send_message_type(context, &rcvd->remote, rcvd->pdu, + COAP_MESSAGE_RST); + } + } + + cleanup: + coap_delete_node(sent); + coap_delete_node(rcvd); + } +} + +int +coap_can_exit( coap_context_t *context ) { + return !context || (context->recvqueue == NULL && context->sendqueue == NULL); +} + diff --git a/coap_net.h b/coap_net.h new file mode 100644 index 0000000000..08ce0e4f82 --- /dev/null +++ b/coap_net.h @@ -0,0 +1,445 @@ +/* net.h -- CoAP network interface + * + * Copyright (C) 2010--2013 Olaf Bergmann + * + * This file is part of the CoAP library libcoap. Please see + * README for terms of use. + */ + +#ifndef _COAP_NET_H_ +#define _COAP_NET_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "config.h" + +#ifdef HAVE_ASSERT_H +#include +#else +#ifndef assert +#warning "assertions are disabled" +# define assert(x) +#endif +#endif + +#include +#include +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#include "option.h" +#include "address.h" +#include "prng.h" +#include "pdu.h" +#include "coap_time.h" + +struct coap_queue_t; + +typedef struct coap_queue_t { + struct coap_queue_t *next; + + coap_tick_t t; /**< when to send PDU for the next time */ + unsigned char retransmit_cnt; /**< retransmission counter, will be removed when zero */ + unsigned int timeout; /**< the randomized timeout value */ + + coap_address_t local; /**< local address */ + coap_address_t remote; /**< remote address */ + coap_tid_t id; /**< unique transaction id */ + + coap_pdu_t *pdu; /**< the CoAP PDU to send */ +} coap_queue_t; + +/** Adds node to given queue, ordered by node->t. */ +int coap_insert_node(coap_queue_t **queue, coap_queue_t *node); + +/** Destroys specified node. */ +int coap_delete_node(coap_queue_t *node); + +/** Removes all items from given queue and frees the allocated storage. */ +void coap_delete_all(coap_queue_t *queue); + +/** Creates a new node suitable for adding to the CoAP sendqueue. */ +coap_queue_t *coap_new_node(void); + +#define SZX_TO_BYTES(SZX) ((size_t)(1 << ((SZX) + 4))) + +struct coap_resource_t; +struct coap_context_t; +#ifndef WITHOUT_ASYNC +struct coap_async_state_t; +#endif + +/** Message handler that is used as call-back in coap_context_t */ +typedef void (*coap_response_handler_t)(struct coap_context_t *, + const coap_address_t *remote, + coap_pdu_t *sent, + coap_pdu_t *received, + const coap_tid_t id); + +#define COAP_MID_CACHE_SIZE 3 +typedef struct { + unsigned char flags[COAP_MID_CACHE_SIZE]; + coap_key_t item[COAP_MID_CACHE_SIZE]; +} coap_mid_cache_t; + +/** The CoAP stack's global state is stored in a coap_context_t object */ +typedef struct coap_context_t { + coap_opt_filter_t known_options; + struct coap_resource_t *resources; /**< hash table or list of known resources */ +#ifndef WITHOUT_ASYNC + /** list of asynchronous transactions */ + struct coap_async_state_t *async_state; +#endif /* WITHOUT_ASYNC */ + /** + * The time stamp in the first element of the sendqeue is relative + * to sendqueue_basetime. */ + coap_tick_t sendqueue_basetime; + coap_queue_t *sendqueue, *recvqueue; + net_socket_t *ns; + struct mbuf *pending_package; + + /** + * The last message id that was used is stored in this field. The + * initial value is set by coap_new_context() and is usually a + * random value. A new message id can be created with + * coap_new_message_id(). + */ + unsigned short message_id; + + /** + * The next value to be used for Observe. This field is global for + * all resources and will be updated when notifications are created. + */ + unsigned int observe; + + coap_response_handler_t response_handler; +} coap_context_t; + +/** + * Registers a new message handler that is called whenever a response + * was received that matches an ongoing transaction. + * + * @param context The context to register the handler for. + * @param handler The response handler to register. + */ +static inline void +coap_register_response_handler(coap_context_t *context, + coap_response_handler_t handler) { + context->response_handler = handler; +} + +/** + * Registers the option type @p type with the given context object @p + * ctx. + * + * @param ctx The context to use. + * @param type The option type to register. + */ +inline static void +coap_register_option(coap_context_t *ctx, unsigned char type) { + coap_option_setb(ctx->known_options, type); +} + + +/** + * Set sendqueue_basetime in the given context object @p ctx to @p + * now. This function returns the number of elements in the queue + * head that have timed out. + */ +unsigned int coap_adjust_basetime(coap_context_t *ctx, coap_tick_t now); + +/** Returns the next pdu to send without removing from sendqeue. */ +coap_queue_t *coap_peek_next( coap_context_t *context ); + +/** Returns the next pdu to send and removes it from the sendqeue. */ +coap_queue_t *coap_pop_next( coap_context_t *context ); + +/** Creates a new coap_context_t object that will hold the CoAP stack status. */ +coap_context_t *coap_new_context(const coap_address_t *listen_addr); + +/** + * Returns a new message id and updates @p context->message_id + * accordingly. The message id is returned in network byte order + * to make it easier to read in tracing tools. + * + * @param context the current coap_context_t object + * @return incremented message id in network byte order + */ +static inline unsigned short +coap_new_message_id(coap_context_t *context) { + ++(context->message_id); + return htons(context->message_id); +} + +/* CoAP stack context must be released with coap_free_context() */ +void coap_free_context( coap_context_t *context ); + + +/** + * Sends a confirmed CoAP message to given destination. The memory + * that is allocated by pdu will not be released by + * coap_send_confirmed(). The caller must release the memory. + * + * @param context The CoAP context to use. + * @param dst The address to send to. + * @param pdu The CoAP PDU to send. + * @return The message id of the sent message or @c COAP_INVALID_TID on error. + */ +coap_tid_t coap_send_confirmed(coap_context_t *context, + const coap_address_t *dst, + coap_pdu_t *pdu); + +/** + * Creates a new ACK PDU with specified error @p code. The options + * specified by the filter expression @p opts will be copied from the + * original request contained in @p request. Unless @c + * SHORT_ERROR_RESPONSE was defined at build time, the textual reason + * phrase for @p code will be added as payload, with Content-Type @c + * 0. This function returns a pointer to the new response message, or + * @c NULL on error. The storage allocated for the new message must be + * relased with coap_free(). + * + * @param request Specification of the received (confirmable) request. + * @param code The error code to set. + * @param opts An option filter that specifies which options to copy + * from the original request in @p node. + * + * @return A pointer to the new message or @c NULL on error. + */ +coap_pdu_t *coap_new_error_response(coap_pdu_t *request, + unsigned char code, + coap_opt_filter_t opts); +/** + * Sends a non-confirmed CoAP message to given destination. The memory + * that is allocated by pdu will not be released by coap_send(). + * The caller must release the memory. + * + * @param context The CoAP context to use. + * @param dst The address to send to. + * @param pdu The CoAP PDU to send. + * @return The message id of the sent message or @c COAP_INVALID_TID on error. + */ +coap_tid_t coap_send(coap_context_t *context, + const coap_address_t *dst, + coap_pdu_t *pdu); + +/** + * Sends an error response with code @p code for request @p request to + * @p dst. @p opts will be passed to coap_new_error_response() to + * copy marked options from the request. This function returns the + * transaction id if the message was sent, or @c COAP_INVALID_TID + * otherwise. + * + * @param context The context to use. + * @param request The original request to respond to. + * @param dst The remote peer that sent the request. + * @param code The reponse code. + * @param opts A filter that specifies the options to copy from the + * @p request. + * + * @return The transaction id if the message was sent, or @c + * COAP_INVALID_TID otherwise. + */ +coap_tid_t coap_send_error(coap_context_t *context, + coap_pdu_t *request, + const coap_address_t *dst, + unsigned char code, + coap_opt_filter_t opts); + +/** + * Helper funktion to create and send a message with @p type (usually + * ACK or RST). This function returns @c COAP_INVALID_TID when the + * message was not sent, a valid transaction id otherwise. + * + * @param context The CoAP context. + * @param dst Where to send the context. + * @param request The request that should be responded to. + * @param type Which type to set + * @return transaction id on success or @c COAP_INVALID_TID otherwise. + */ +coap_tid_t +coap_send_message_type(coap_context_t *context, + const coap_address_t *dst, + coap_pdu_t *request, + unsigned char type); +/** + * Sends an ACK message with code @c 0 for the specified @p request to + * @p dst. This function returns the corresponding transaction id if + * the message was sent or @c COAP_INVALID_TID on error. + * + * @param context The context to use. + * @param dst The destination address. + * @param request The request to be acknowledged. + * + * @return The transaction id if ACK was sent or @c COAP_INVALID_TID + * on error. + */ +coap_tid_t coap_send_ack(coap_context_t *context, + const coap_address_t *dst, + coap_pdu_t *request); + +/** + * Sends an RST message with code @c 0 for the specified @p request to + * @p dst. This function returns the corresponding transaction id if + * the message was sent or @c COAP_INVALID_TID on error. + * + * @param context The context to use. + * @param dst The destination address. + * @param request The request to be reset. + * + * @return The transaction id if RST was sent or @c COAP_INVALID_TID + * on error. + */ +static inline coap_tid_t +coap_send_rst(coap_context_t *context, + const coap_address_t *dst, + coap_pdu_t *request) { + return coap_send_message_type(context, dst, request, COAP_MESSAGE_RST); +} + +/** Handles retransmissions of confirmable messages */ +coap_tid_t coap_retransmit( coap_context_t *context, coap_queue_t *node ); + +/** + * Reads data from the network and tries to parse as CoAP PDU. On success, 0 is returned + * and a new node with the parsed PDU is added to the receive queue in the specified context + * object. + */ +int coap_read( coap_context_t *context, coap_tick_t timeout ); + +/** + * Calculates a unique transaction id from given arguments @p peer and + * @p pdu. The id is returned in @p id. + * + * @param peer The remote party who sent @p pdu. + * @param pdu The message that initiated the transaction. + * @param id Set to the new id. + */ +void coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, + coap_tid_t *id); + +/** + * This function removes the element with given @p id from the list + * given list. If @p id was found, @p node is updated to point to the + * removed element. Note that the storage allocated by @p node is + * @b not released. The caller must do this manually using + * coap_delete_node(). This function returns @c 1 if the element with + * id @p id was found, @c 0 otherwise. For a return value of @c 0, + * the contents of @p node is undefined. + * + * @param queue The queue to search for @p id. + * @param id The node id to look for. + * @param node If found, @p node is updated to point to the + * removed node. You must release the storage pointed to by + * @p node manually. + * + * @return @c 1 if @p id was found, @c 0 otherwise. + */ +int coap_remove_from_queue(coap_queue_t **queue, + coap_tid_t id, + coap_queue_t **node); + +/** + * Removes the transaction identified by @p id from given @p queue. + * This is a convenience function for coap_remove_from_queue() with + * automatic deletion of the removed node. + * + * @param queue The queue to search for @p id. + * @param id The transaction id. + * + * @return @c 1 if node was found, removed and destroyed, @c 0 otherwise. + */ +inline static int +coap_remove_transaction(coap_queue_t **queue, coap_tid_t id) { + coap_queue_t *node; + if (!coap_remove_from_queue(queue, id, &node)) + return 0; + + coap_delete_node(node); + return 1; +} + +/** + * Retrieves transaction from queue. + * @queue The transaction queue to be searched + * @id Unique key of the transaction to find. + * @return A pointer to the transaction object or NULL if not found + */ +coap_queue_t *coap_find_transaction(coap_queue_t *queue, coap_tid_t id); + +/** + * Cancels all outstanding messages for peer @p dst that have the + * specified token. + * + * @param context The context in use + * @param dst Destination address of the messages to remove. + * @param token Message token + * @param token_length Actual length of @p token + */ +void coap_cancel_all_messages(coap_context_t *context, + const coap_address_t *dst, + const unsigned char *token, + size_t token_length); + +/** Dispatches the PDUs from the receive queue in given context. */ +void coap_dispatch( coap_context_t *context ); + +/** Returns 1 if there are no messages to send or to dispatch in the context's queues. */ +int coap_can_exit( coap_context_t *context ); + +/** + * Returns the current value of an internal tick counter. The counter + * counts \c COAP_TICKS_PER_SECOND ticks every second. + */ +void coap_ticks(coap_tick_t *); + +/** + * Verifies that @p pdu contains no unknown critical options. Options + * must be registered at @p ctx, using the function + * coap_register_option(). A basic set of options is registered + * automatically by coap_new_context(). This function returns @c 1 if + * @p pdu is ok, @c 0 otherwise. The given filter object @p unknown + * will be updated with the unknown options. As only @c COAP_MAX_OPT + * options can be signalled this way, remaining options must be + * examined manually. + * + * @code + coap_opt_filter_t f = COAP_OPT_NONE; + coap_opt_iterator_t opt_iter; + + if (coap_option_check_critical(ctx, pdu, f) == 0) { + coap_option_iterator_init(pdu, &opt_iter, f); + + while (coap_option_next(&opt_iter)) { + if (opt_iter.type & 0x01) { + ... handle unknown critical option in opt_iter ... + } + } + } + * @endcode + * + * @param ctx The context where all known options are registered. + * @param pdu The PDU to check. + * @param unknown The output filter that will be updated to indicate the + * unknown critical options found in @p pdu. + * + * @return @c 1 if everything was ok, @c 0 otherwise. + */ +int coap_option_check_critical(coap_context_t *ctx, + coap_pdu_t *pdu, + coap_opt_filter_t unknown); + +#ifdef __cplusplus +} +#endif + +#endif /* _COAP_NET_H_ */ diff --git a/coap_time.h b/coap_time.h index 7af5b621a9..a704247b65 100644 --- a/coap_time.h +++ b/coap_time.h @@ -31,80 +31,6 @@ extern "C" { * @{ */ -#ifdef WITH_LWIP - -#include -#include - -/* lwIP provides ms in sys_now */ -#define COAP_TICKS_PER_SECOND 1000 - -typedef uint32_t coap_tick_t; - -static inline void coap_ticks_impl(coap_tick_t *t) -{ - *t = sys_now(); -} - -static inline void coap_clock_init_impl(void) -{ -} - -#define coap_clock_init coap_clock_init_impl - -#define coap_ticks coap_ticks_impl - -#endif -#ifdef WITH_CONTIKI -#include "clock.h" - -typedef clock_time_t coap_tick_t; - -/** - * This data type is used to represent the difference between two - * clock_tick_t values. This data type must have the same size in - * memory as coap_tick_t to allow wrapping. - */ -typedef int coap_tick_diff_t; - -#define COAP_TICKS_PER_SECOND CLOCK_SECOND - -/** Set at startup to initialize the internal clock (time in seconds). */ -extern clock_time_t clock_offset; - -static inline void -contiki_clock_init_impl(void) { - clock_init(); - clock_offset = clock_time(); -} - -#define coap_clock_init contiki_clock_init_impl - -static inline void -contiki_ticks_impl(coap_tick_t *t) { - *t = clock_time(); -} - -#define coap_ticks contiki_ticks_impl - -#endif /* WITH_CONTIKI */ -#ifdef WITH_POSIX -typedef unsigned int coap_tick_t; - -/** - * This data type is used to represent the difference between two - * clock_tick_t values. This data type must have the same size in - * memory as coap_tick_t to allow wrapping. - */ -typedef int coap_tick_diff_t; - -#define COAP_TICKS_PER_SECOND 1024 - -/** Set at startup to initialize the internal clock (time in seconds). */ -extern time_t clock_offset; -#endif /* WITH_POSIX */ - -#ifdef WITH_STNODE /* MWAS: based on lwIP implementation above. Uses chTimeNow() function from ChibiOS. */ #include "ch.h" @@ -129,7 +55,6 @@ static inline void coap_clock_init_impl(void) #define coap_ticks coap_ticks_impl -#endif /* WITH_STNODE */ #ifndef coap_clock_init static inline void diff --git a/config.h b/config.h index a554b3b0be..57e50d5fcc 100644 --- a/config.h +++ b/config.h @@ -43,6 +43,9 @@ /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET +/* Define to 1 if you have the `snprintf' function */ +#define HAVE_SNPRINTF 1 + /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 diff --git a/debug.c b/debug.c index c3831069b3..a2db7daa39 100644 --- a/debug.c +++ b/debug.c @@ -26,44 +26,8 @@ #endif #include "debug.h" -#include "libcoap/net.h" - -#ifdef WITH_CONTIKI -# ifndef DEBUG -# define DEBUG DEBUG_PRINT -# endif /* DEBUG */ -#include "net/uip-debug.h" -#endif - -#ifdef WITH_STNODE -DEFINE_LOG(LOG_DEFAULT_SEVERITY); -#endif /* WITH_STNODE */ - -static coap_log_t maxlog = LOG_WARNING; /* default maximum log level */ - -const char *coap_package_name() { - return PACKAGE_NAME; -} - -const char *coap_package_version() { - return PACKAGE_STRING; -} - -coap_log_t -coap_get_log_level() { - return maxlog; -} - -void -coap_set_log_level(coap_log_t level) { - maxlog = level; -} -#ifndef WITH_STNODE -/* this array has the same order as the type log_t */ -static char *loglevels[] = { - "EMRG", "ALRT", "CRIT", "ERR", "WARN", "NOTE", "INFO", "DEBG" -}; -#endif +#include "coap_net.h" +#include "net.h" #ifdef HAVE_TIME_H @@ -91,7 +55,6 @@ print_timestamp(char *s, size_t len, coap_tick_t t) { #endif /* HAVE_TIME_H */ -#ifndef NDEBUG #ifndef HAVE_STRNLEN /** @@ -145,10 +108,6 @@ print_readable( const unsigned char *data, unsigned int len, return cnt; } -#ifndef min -#define min(a,b) ((a) < (b) ? (a) : (b)) -#endif - size_t coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t len) { #ifdef HAVE_ARPA_INET_H @@ -194,52 +153,20 @@ coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t le return buf + len - p; #else /* HAVE_ARPA_INET_H */ -# if WITH_CONTIKI - unsigned char *p = buf; - uint8_t i; -# if WITH_UIP6 - const unsigned char hex[] = "0123456789ABCDEF"; - - if (len < 41) - return 0; - - *p++ = '['; - - for (i=0; i < 16; i += 2) { - if (i) { - *p++ = ':'; - } - *p++ = hex[(addr->addr.u8[i] & 0xf0) >> 4]; - *p++ = hex[(addr->addr.u8[i] & 0x0f)]; - *p++ = hex[(addr->addr.u8[i+1] & 0xf0) >> 4]; - *p++ = hex[(addr->addr.u8[i+1] & 0x0f)]; - } - *p++ = ']'; -# else /* WITH_UIP6 */ -# warning "IPv4 network addresses will not be included in debug output" - - if (len < 21) - return 0; -# endif /* WITH_UIP6 */ - if (buf + len - p < 6) - return 0; - #ifdef HAVE_SNPRINTF - p += snprintf((char *)p, buf + len - p + 1, ":%d", uip_htons(addr->port)); -#else /* HAVE_SNPRINTF */ - /* @todo manual conversion of port number */ -#endif /* HAVE_SNPRINTF */ - + unsigned char *p = buf; + p += snprintf((char *)p, buf + len - p + 1, "%d.%d.%d.%d:%d", + addr->addr.u8[0], addr->addr.u8[1], addr->addr.u8[2], addr->addr.u8[3], + addr->port); return p - buf; -# else /* WITH_CONTIKI */ +#else /* HAVE_SNPRINTF */ /* TODO: output addresses manually */ # warning "inet_ntop() not available, network addresses will not be included in debug output" -# endif /* WITH_CONTIKI */ +#endif /* HAVE_SNPRINTF */ return 0; #endif } -#ifndef WITH_CONTIKI void coap_show_pdu(const coap_pdu_t *pdu) { unsigned char buf[COAP_MAX_PDU_SIZE]; /* need some space for output creation */ @@ -295,116 +222,4 @@ coap_show_pdu(const coap_pdu_t *pdu) { fflush(COAP_DEBUG_FD); } -#else /* WITH_CONTIKI */ - -void -coap_show_pdu(const coap_pdu_t *pdu) { - unsigned char buf[80]; /* need some space for output creation */ - - PRINTF("v:%d t:%d oc:%d c:%d id:%u", - pdu->hdr->version, pdu->hdr->type, - pdu->hdr->optcnt, pdu->hdr->code, uip_ntohs(pdu->hdr->id)); - /* show options, if any */ - if (pdu->hdr->optcnt) { - coap_opt_iterator_t opt_iter; - coap_opt_t *option; - coap_option_iterator_init((coap_pdu_t *)pdu, &opt_iter, COAP_OPT_ALL); - - PRINTF(" o:"); - while ((option = coap_option_next(&opt_iter))) { - - if (print_readable(COAP_OPT_VALUE(option), - COAP_OPT_LENGTH(option), - buf, sizeof(buf), 0)) - PRINTF(" %d:%s", opt_iter.type, buf); - } - } - - if (pdu->data < (unsigned char *)pdu->hdr + pdu->length) { - print_readable(pdu->data, - (unsigned char *)pdu->hdr + pdu->length - pdu->data, - buf, sizeof(buf), 0 ); - PRINTF(" d:%s", buf); - } - PRINTF("\r\n"); -} -#endif /* WITH_CONTIKI */ - -#endif /* NDEBUG */ - -#if defined(WITH_POSIX) | defined(WITH_LWIP) -void -coap_log_impl(coap_log_t level, const char *format, ...) { - char timebuf[32]; - coap_tick_t now; - va_list ap; - FILE *log_fd; - - if (maxlog < level) - return; - - log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD; - - coap_ticks(&now); - if (print_timestamp(timebuf,sizeof(timebuf), now)) - fprintf(log_fd, "%s ", timebuf); - - if (level <= LOG_DEBUG) - fprintf(log_fd, "%s ", loglevels[level]); - - va_start(ap, format); - vfprintf(log_fd, format, ap); - va_end(ap); - fflush(log_fd); -} -#elif defined(WITH_CONTIKI) -void -coap_log_impl(coap_log_t level, const char *format, ...) { - char timebuf[32]; - coap_tick_t now; - va_list ap; - - if (maxlog < level) - return; - - coap_ticks(&now); - if (print_timestamp(timebuf,sizeof(timebuf), now)) - PRINTF("%s ", timebuf); - - if (level <= LOG_DEBUG) - PRINTF("%s ", loglevels[level]); - - va_start(ap, format); - PRINTF(format, ap); - va_end(ap); -} -#elif defined(WITH_STNODE) -void -coap_log_impl(coap_log_t level, const char *format, ...) { - - switch(level) - { - case LOG_FATAL: - fatal(format); - break; - case LOG_ERROR: - error(format); - break; - case LOG_WARN: - warn(format); - break; - case LOG_INFO: - info(format); - break; - case LOG_DEBUG: - debug(format); - break; - case LOG_TRACE: - trace(format); - break; - case LOG_OFF: - break; - } -} -#endif diff --git a/debug.h b/debug.h index 6b3faa7c5a..aa2dfa766f 100644 --- a/debug.h +++ b/debug.h @@ -19,76 +19,11 @@ #define COAP_ERR_FD stderr #endif -#ifdef HAVE_SYSLOG_H -#include -typedef short coap_log_t; -#else -/** Pre-defined log levels akin to what is used in \b syslog. */ -#ifndef WITH_STNODE -typedef enum {LOG_EMERG=0, LOG_ALERT, LOG_CRIT, LOG_WARNING, - LOG_NOTICE, LOG_INFO, LOG_DEBUG -} coap_log_t; -#else #include "logging.h" -typedef log_level_t coap_log_t; -#define LOG_WARNING LOG_WARN -#define LOG_CRIT LOG_ERROR -#define LOG_ALERT LOG_FATAL -#define LOG_EMERG LOG_FATAL -#define LOG_NOTICE LOG_INFO -#endif -#endif - -#ifndef WITH_STNODE -/** Returns the current log level. */ -coap_log_t coap_get_log_level(); - -/** Sets the log level to the specified value. */ -void coap_set_log_level(coap_log_t level); - -/** Returns a zero-terminated string with the name of this library. */ -const char *coap_package_name(); - -/** Returns a zero-terminated string with the library version. */ -const char *coap_package_version(); -#endif - -/** - * Writes the given text to @c COAP_ERR_FD (for @p level <= @c - * LOG_CRIT) or @c COAP_DEBUG_FD (for @p level >= @c LOG_WARNING). The - * text is output only when @p level is below or equal to the log - * level that set by coap_set_log_level(). - */ -void coap_log_impl(coap_log_t level, const char *format, ...); - -#ifndef coap_log -#define coap_log(...) coap_log_impl(__VA_ARGS__) -#endif - -#ifndef NDEBUG - -#ifndef WITH_STNODE -/* A set of convenience macros for common log levels. */ -#define info(...) coap_log(LOG_INFO, __VA_ARGS__) -#define warn(...) coap_log(LOG_WARNING, __VA_ARGS__) -#define debug(...) coap_log(LOG_DEBUG, __VA_ARGS__) -#endif - #include "pdu.h" void coap_show_pdu(const coap_pdu_t *); struct coap_address_t; size_t coap_print_addr(const struct coap_address_t *, unsigned char *, size_t); -#else - -#define debug(...) -#define info(...) -#define warn(...) - -#define coap_show_pdu(x) -#define coap_print_addr(...) - -#endif - #endif /* _COAP_DEBUG_H_ */ diff --git a/encode.c b/encode.c index b034b6bb10..99cbd30ca4 100644 --- a/encode.c +++ b/encode.c @@ -6,10 +6,6 @@ * README for terms of use. */ -#ifndef NDEBUG -# include -#endif - #include "config.h" #include "encode.h" diff --git a/encode.h b/encode.h index bdb7aa56ff..0214b26779 100644 --- a/encode.h +++ b/encode.h @@ -9,11 +9,7 @@ #ifndef _COAP_ENCODE_H_ #define _COAP_ENCODE_H_ -#if (BSD >= 199103) || defined(WITH_CONTIKI) -# include -#else # include -#endif #define Nn 8 /* duplicate definition of N if built on sky motes */ #define E 4 diff --git a/examples/client.c b/examples/client.c index bd6f9b5ad8..a43d2394c4 100644 --- a/examples/client.c +++ b/examples/client.c @@ -179,7 +179,7 @@ clear_obs(coap_context_t *ctx, const coap_address_t *remote) { } if (!coap_add_token(pdu, the_token.length, the_token.s)) { - coap_log(LOG_CRIT, "cannot add token"); + error("cannot add token"); goto error; } @@ -198,7 +198,7 @@ clear_obs(coap_context_t *ctx, const coap_address_t *remote) { if (!coap_add_option(pdu, COAP_OPTION_OBSERVE, coap_encode_var_bytes(buf, COAP_OBSERVE_CANCEL), buf)) { - coap_log(LOG_CRIT, "cannot add option Observe: %u", COAP_OBSERVE_CANCEL); + error("cannot add option Observe: %u", COAP_OBSERVE_CANCEL); goto error; } @@ -322,13 +322,12 @@ message_handler(struct coap_context_t *ctx, unsigned char *databuf; coap_tid_t tid; -#ifndef NDEBUG - if (LOG_DEBUG <= coap_get_log_level()) { + if (LOG_DEBUG <= LOG.severity) { debug("** process incoming %d.%02d response:\n", (received->hdr->code >> 5), received->hdr->code & 0x1F); coap_show_pdu(received); } -#endif + /* check if this is a response to our original request */ if (!check_token(received)) { @@ -962,7 +961,6 @@ main(int argc, char **argv) { char port_str[NI_MAXSERV] = "0"; int opt, res; char *group = NULL; - coap_log_t log_level = LOG_WARNING; coap_tid_t tid = COAP_INVALID_TID; while ((opt = getopt(argc, argv, "Nb:e:f:g:m:p:s:t:o:v:A:B:O:P:T:")) != -1) { @@ -1084,7 +1082,7 @@ main(int argc, char **argv) { } if (!ctx) { - coap_log(LOG_EMERG, "cannot create context\n"); + fatal("cannot create context\n"); return -1; } @@ -1115,12 +1113,10 @@ main(int argc, char **argv) { if (! (pdu = coap_new_request(ctx, method, optlist))) return -1; -#ifndef NDEBUG - if (LOG_DEBUG <= coap_get_log_level()) { + if (LOG_DEBUG <= LOG.severity) { debug("sending CoAP request:\n"); coap_show_pdu(pdu); } -#endif if (pdu->hdr->type == COAP_MESSAGE_CON) tid = coap_send_confirmed(ctx, &dst, pdu); diff --git a/examples/etsi_iot_01.c b/examples/etsi_iot_01.c index 0edc8a9368..4ff7a45527 100644 --- a/examples/etsi_iot_01.c +++ b/examples/etsi_iot_01.c @@ -259,7 +259,7 @@ hnd_post_test(coap_context_t *ctx, struct coap_resource_t *resource, test_payload = coap_new_payload(len); uri = (coap_dynamic_uri_t *)coap_malloc(sizeof(coap_dynamic_uri_t) + l); if (!(test_payload && uri)) { - coap_log(LOG_CRIT, "cannot allocate new resource under /test"); + error("cannot allocate new resource under /test"); response->hdr->code = COAP_RESPONSE_CODE(500); coap_free(test_payload); coap_free(uri); @@ -536,7 +536,7 @@ init_resources(coap_context_t *ctx) { test_payload = coap_new_payload(200); if (!test_payload) - coap_log(LOG_CRIT, "cannot allocate resource /test"); + error("cannot allocate resource /test"); else { test_payload->length = 13; memcpy(test_payload->data, "put data here", test_payload->length); @@ -562,7 +562,7 @@ init_resources(coap_context_t *ctx) { * TD_COAP_BLOCK_02 */ test_payload = make_large("etsi_iot_01_largedata.txt"); if (!test_payload) - coap_log(LOG_CRIT, "cannot allocate resource /large\n"); + error("cannot allocate resource /large\n"); else { r = coap_resource_init((unsigned char *)"large", 5, 0); coap_register_handler(r, COAP_REQUEST_GET, hnd_get_resource); @@ -579,7 +579,7 @@ init_resources(coap_context_t *ctx) { /* For TD_COAP_CORE_12 */ test_payload = coap_new_payload(20); if (!test_payload) - coap_log(LOG_CRIT, "cannot allocate resource /seg1/seg2/seg3\n"); + error("cannot allocate resource /seg1/seg2/seg3\n"); else { test_payload->length = 10; memcpy(test_payload->data, "segsegseg!", test_payload->length); diff --git a/libcoap.mk b/libcoap.mk index 11ff64f966..efd127becf 100644 --- a/libcoap.mk +++ b/libcoap.mk @@ -1,6 +1,6 @@ # List of all the board related files. EXTSRC += ext/libcoap/pdu.c \ - ext/libcoap/net.c \ + ext/libcoap/coap_net.c \ ext/libcoap/debug.c \ ext/libcoap/encode.c \ ext/libcoap/uri.c \ diff --git a/option.c b/option.c index 086096ef02..6051effb80 100644 --- a/option.c +++ b/option.c @@ -20,10 +20,8 @@ #include "option.h" #include "debug.h" -#ifdef WITH_STNODE #include "logging.h" DEFINE_LOG(LOG_DEFAULT_SEVERITY); -#endif coap_opt_t * options_start(coap_pdu_t *pdu) { @@ -410,10 +408,6 @@ coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta, return l + length; } - -#if defined(WITH_STNODE) - - size_t coap_opt_setheader_to_mbuf(coap_pdu_t *pdu, unsigned short type, size_t length) { size_t skip = 0; @@ -498,4 +492,3 @@ coap_opt_encode_to_mbuf(coap_pdu_t *pdu, unsigned short type, return l + length; } -#endif diff --git a/option.h b/option.h index 3a148de824..57cd9f3006 100644 --- a/option.h +++ b/option.h @@ -251,10 +251,10 @@ coap_opt_t *coap_check_option(coap_pdu_t *pdu, size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, unsigned short delta, size_t length); -#if defined(WITH_STNODE) + size_t coap_opt_setheader_to_mbuf(coap_pdu_t *pdu, unsigned short type, size_t length); -#endif + /** * Encodes option with given @p delta into @p opt. This function returns * the number of bytes written to @p opt or @c 0 on error. This happens @@ -272,10 +272,10 @@ size_t coap_opt_setheader_to_mbuf(coap_pdu_t *pdu, unsigned short type, size_t coap_opt_encode(coap_opt_t *opt, size_t n, unsigned short delta, const unsigned char *val, size_t length); -#if defined(WITH_STNODE) + size_t coap_opt_encode_to_mbuf(coap_pdu_t *pdu, unsigned short type, const unsigned char *val, size_t length); -#endif + /** * Decodes the delta value of the next option. This function returns * the number of bytes read or @c 0 on error. The caller of this diff --git a/pdu.c b/pdu.c index 5798aa9fb3..a8db503d54 100644 --- a/pdu.c +++ b/pdu.c @@ -8,10 +8,8 @@ #include "config.h" -#ifdef WITH_STNODE #include "logging.h" DEFINE_LOG(LOG_DEFAULT_SEVERITY); -#endif #if defined(HAVE_ASSERT_H) && !defined(assert) # include @@ -29,66 +27,20 @@ DEFINE_LOG(LOG_DEFAULT_SEVERITY); #include "option.h" #include "encode.h" -#ifdef WITH_CONTIKI -#include "memb.h" - -typedef unsigned char _pdu[sizeof(coap_pdu_t) + COAP_MAX_PDU_SIZE]; - -MEMB(pdu_storage, _pdu, COAP_PDU_MAXCNT); - -void -coap_pdu_resources_init() { - memb_init(&pdu_storage); -} -#else /* WITH_CONTIKI */ #include "mem.h" -#endif /* WITH_CONTIKI */ + void coap_pdu_clear(coap_pdu_t *pdu, size_t size) { assert(pdu); -#ifdef WITH_STNODE memset(pdu, 0, sizeof(coap_pdu_t)); /* MWAS: for st-node payload is in separate memory area */ pdu->max_size = size; -#else - memset(pdu, 0, sizeof(coap_pdu_t) + size); - pdu->max_size = size; - pdu->hdr = (coap_hdr_t *)((unsigned char *)pdu + sizeof(coap_pdu_t)); - pdu->hdr->version = COAP_DEFAULT_VERSION; -#endif /* data is NULL unless explicitly set by coap_add_data() */ pdu->length = sizeof(coap_hdr_t); } -#ifdef WITH_LWIP -coap_pdu_t * -coap_pdu_from_pbuf(struct pbuf *pbuf) -{ - LWIP_ASSERT("Can only deal with contiguous PBUFs", pbuf->tot_len == pbuf->len); - LWIP_ASSERT("coap_read needs to receive an exclusive copy of the incoming pbuf", pbuf->ref == 1); - - void *data = pbuf->payload; - coap_pdu_t *result; - - u8_t header_error = pbuf_header(pbuf, sizeof(coap_pdu_t)); - LWIP_ASSERT("CoAP PDU header does not fit in existing header space", header_error == 0); - - result = (coap_pdu_t *)pbuf->payload; - - memset(result, 0, sizeof(coap_pdu_t)); - - result->max_size = pbuf->tot_len - sizeof(coap_pdu_t); - result->length = pbuf->tot_len - sizeof(coap_pdu_t); - result->hdr = data; - result->pbuf = pbuf; - - return result; -} -#endif - -#ifdef WITH_STNODE #include "net.h" #include "system.h" @@ -108,104 +60,57 @@ coap_pdu_from_mbuf(struct mbuf *mbuf) return result; } -#endif coap_pdu_t * coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t size) { coap_pdu_t *pdu; -#ifdef WITH_LWIP - struct pbuf *p; -#endif -#ifdef WITH_STNODE + struct mbuf *m; -#endif + assert(size <= COAP_MAX_PDU_SIZE); /* Size must be large enough to fit the header. */ if (size < sizeof(coap_hdr_t) || size > COAP_MAX_PDU_SIZE) return NULL; - /* size must be large enough for hdr */ -#ifdef WITH_POSIX - pdu = coap_malloc(sizeof(coap_pdu_t) + size); -#endif -#ifdef WITH_CONTIKI - pdu = (coap_pdu_t *)memb_alloc(&pdu_storage); -#endif -#ifdef WITH_LWIP - p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM); - if (p != NULL) { - u8_t header_error = pbuf_header(p, sizeof(coap_pdu_t)); - /* we could catch that case and allocate larger memory in advance, but then - * again, we'd run into greater trouble with incoming packages anyway */ - LWIP_ASSERT("CoAP PDU header does not fit in transport header", header_error == 0); - pdu = p->payload; - } else { - pdu = NULL; - } -#endif -#ifdef WITH_STNODE //TODO: MWAS: get rid of sys_malloc pdu = sys_malloc(sizeof(coap_pdu_t)); m = mbuf_new(); -#endif + if (pdu) { coap_pdu_clear(pdu, size); -#ifdef WITH_STNODE pdu->hdr = (coap_hdr_t *)((unsigned char *)m->payload); pdu->hdr->version = COAP_DEFAULT_VERSION; pdu->hdr->token_length = 0; pdu->mbuf = m; pdu->mbuf->len = sizeof(coap_hdr_t); pdu->mbuf->tot_len = sizeof(coap_hdr_t); -#endif pdu->hdr->id = id; pdu->hdr->type = type; pdu->hdr->code = code; -#ifdef WITH_LWIP - pdu->pbuf = p; -#endif } return pdu; } coap_pdu_t * -coap_new_pdu() { +coap_new_pdu(void) { coap_pdu_t *pdu; - -#ifndef WITH_CONTIKI - pdu = coap_pdu_init(0, 0, ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE); -#else /* WITH_CONTIKI */ - pdu = coap_pdu_init(0, 0, uip_ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE); -#endif /* WITH_CONTIKI */ -#ifndef NDEBUG + pdu = coap_pdu_init(0, 0, ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE); if (!pdu) - coap_log(LOG_CRIT, "coap_new_pdu: cannot allocate memory for new PDU\n"); -#endif + error("coap_new_pdu: cannot allocate memory for new PDU\n"); + return pdu; } void coap_delete_pdu(coap_pdu_t *pdu) { -#ifdef WITH_POSIX - coap_free( pdu ); -#endif -#ifdef WITH_LWIP - if (pdu != NULL) /* accepting double free as the other implementation accept that too */ - pbuf_free(pdu->pbuf); -#endif -#ifdef WITH_CONTIKI - memb_free(&pdu_storage, pdu); -#endif -#ifdef WITH_STNODE - if (pdu != NULL) - { + + if (pdu != NULL) { mbuf_free(pdu->mbuf); sys_free(pdu); } -#endif } int @@ -218,11 +123,7 @@ coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data) { pdu->hdr->token_length = len; if (len) -#if defined(WITH_LWIP) || defined(WITH_CONTIKI) || defined(WITH_POSIX) - memcpy(pdu->hdr->token, data, len); -#elif defined(WITH_STNODE) mbuf_write(pdu->mbuf, data, len, pdu->length); -#endif pdu->max_delta = 0; pdu->length = HEADERLENGTH; @@ -235,10 +136,7 @@ coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data) { size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data) { size_t optsize; -#ifndef WITH_STNODE - coap_opt_t *opt; -#endif - + assert(pdu); pdu->data = NULL; @@ -247,17 +145,8 @@ coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const un return 0; } -#ifndef WITH_STNODE - opt = (unsigned char *)pdu->hdr + pdu->length; -#endif - /* encode option and check length */ -#if defined(WITH_LWIP) || defined(WITH_CONTIKI) || defined(WITH_POSIX) - optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, - type - pdu->max_delta, data, len); -#elif defined(WITH_STNODE) optsize = coap_opt_encode_to_mbuf(pdu, type, data, len); -#endif if (!optsize) { warn("coap_add_option: cannot add option\n"); @@ -288,12 +177,7 @@ coap_add_option_later(coap_pdu_t *pdu, unsigned short type, unsigned int len) { opt = (unsigned char *)pdu->hdr + pdu->length; /* encode option and check length */ -#if defined(WITH_LWIP) || defined(WITH_CONTIKI) || defined(WITH_POSIX) - optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, - type - pdu->max_delta, NULL, len); -#elif defined(WITH_STNODE) optsize = coap_opt_encode_to_mbuf(pdu, type, NULL, len); -#endif if (!optsize) { warn("coap_add_option: cannot add option\n"); @@ -324,11 +208,7 @@ coap_add_data(coap_pdu_t *pdu, unsigned int len, const unsigned char *data) { pdu->data = (unsigned char *)pdu->hdr + pdu->length; *pdu->data = COAP_PAYLOAD_START; pdu->data++; -#if defined(WITH_LWIP) || defined(WITH_CONTIKI) || defined(WITH_POSIX) - memcpy(pdu->data, data, len); -#elif defined(WITH_STNODE) mbuf_write(pdu->mbuf, data, len, pdu->length+1); -#endif pdu->length += len + 1; return 1; } diff --git a/pdu.h b/pdu.h index 9a311a0c8b..23577f7d16 100644 --- a/pdu.h +++ b/pdu.h @@ -3,7 +3,7 @@ * Copyright (C) 2010--2012 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ #ifndef _PDU_H_ @@ -12,21 +12,28 @@ #include "config.h" #include "coap_list.h" #include "uri.h" - -#ifdef WITH_LWIP -#include -#endif -#ifdef WITH_STNODE #include #include "mbuf.h" -#endif + /* pre-defined constants that reflect defaults for CoAP */ +#ifndef COAP_DEFAULT_RESPONSE_TIMEOUT #define COAP_DEFAULT_RESPONSE_TIMEOUT 2 /* response timeout in seconds */ +#endif + +#ifndef COAP_DEFAULT_MAX_RETRANSMIT #define COAP_DEFAULT_MAX_RETRANSMIT 4 /* max number of retransmissions */ +#endif + +#ifndef COAP_DEFAULT_PORT #define COAP_DEFAULT_PORT 5683 /* CoAP default UDP port */ +#endif + +#ifndef COAP_DEFAULT_MAX_AGE #define COAP_DEFAULT_MAX_AGE 60 /* default maximum object lifetime in seconds */ +#endif + #ifndef COAP_MAX_PDU_SIZE #define COAP_MAX_PDU_SIZE 1400 /* maximum size of a CoAP PDU */ #endif /* COAP_MAX_PDU_SIZE */ @@ -99,13 +106,13 @@ #define COAP_RESPONSE_CLASS(C) (((C) >> 5) & 0xFF) #ifndef SHORT_ERROR_RESPONSE -/** +/** * Returns a human-readable response phrase for the specified CoAP * response @p code. This function returns @c NULL if not found. - * + * * @param code The response code for which the literal phrase should * be retrieved. - * + * * @return A zero-terminated string describing the error, or @c NULL * if not found. */ @@ -214,61 +221,39 @@ typedef struct { unsigned short max_delta; /**< highest option number */ unsigned short length; /**< PDU length (including header, options, data) */ unsigned char *data; /**< payload */ - -#ifdef WITH_LWIP - struct pbuf *pbuf; /**< lwIP PBUF. The allocated coap_pdu_t will always reside inside the pbuf's payload, but the pointer has to be kept because no exact offset can be given. This field must not be accessed from outside, because the pbuf's reference count is checked to be 1 when the pbuf is assigned to the pdu, and the pbuf stays exclusive to this pdu. */ -#endif -#ifdef WITH_STNODE - struct mbuf *mbuf; -#endif - + struct mbuf *mbuf; /**< mbuf */ } coap_pdu_t; /** Options in coap_pdu_t are accessed with the macro COAP_OPTION. */ #define COAP_OPTION(node) ((coap_option *)(node)->options) -#ifdef WITH_LWIP /** - * Creates a CoAP PDU from an lwIP @p pbuf, whose reference is passed on to + * Creates a CoAP PDU from st-node mbuf, whose reference is passed on to * this function. * - * The pbuf is checked for being contiguous, for having enough head space for - * the PDU struct (which is located directly in front of the data, overwriting - * the old other headers), and for having only one reference. The reference is - * stored in the PDU and will be freed when the PDU is freed. - * - * (For now, these are errors; in future, a new pbuf might be allocated, the - * data copied and the passed pbuf freed). - * - * This behaves like coap_pdu_init(0, 0, 0, pbuf->tot_len), and afterwards - * copying the contents of the pbuf to the pdu. - * * @return A pointer to the new PDU object or @c NULL on error. */ -coap_pdu_t * coap_pdu_from_pbuf(struct pbuf *pbuf); -#endif -#ifdef WITH_STNODE coap_pdu_t * coap_pdu_from_mbuf(struct mbuf *mbuf); -#endif -/** - * Creates a new CoAP PDU of given @p size (must be large enough to hold the + +/** + * Creates a new CoAP PDU of given @p size (must be large enough to hold the * basic CoAP message header (coap_hdr_t). The function returns a pointer to * the node coap_pdu_t object on success, or @c NULL on error. The storage * allocated for the result must be released with coap_delete_pdu(). - * + * * @param type The type of the PDU (one of COAP_MESSAGE_CON, - * COAP_MESSAGE_NON, COAP_MESSAGE_ACK, COAP_MESSAGE_RST). + * COAP_MESSAGE_NON, COAP_MESSAGE_ACK, COAP_MESSAGE_RST). * @param code The message code. * @param id The message id to set or COAP_INVALID_TID if unknown. * @param size The number of bytes to allocate for the actual message. - * + * * @return A pointer to the new PDU object or @c NULL on error. */ coap_pdu_t * -coap_pdu_init(unsigned char type, unsigned char code, +coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t size); -/** +/** * Clears any contents from @p pdu and resets @c version field, @c * length and @c data pointers. @c max_size is set to @p size, any * other field is set to @c 0. Note that @p pdu must be a valid @@ -279,11 +264,11 @@ void coap_pdu_clear(coap_pdu_t *pdu, size_t size); /** * Creates a new CoAP PDU. The object is created on the heap and must be released * using coap_delete_pdu(); - * + * * @deprecated This function allocates the maximum storage for each - * PDU. Use coap_pdu_init() instead. + * PDU. Use coap_pdu_init() instead. */ -coap_pdu_t *coap_new_pdu(); +coap_pdu_t *coap_new_pdu(void); void coap_delete_pdu(coap_pdu_t *); @@ -323,7 +308,7 @@ int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data); * the token must be added before coap_add_option() is called. * This function returns the number of bytes written or @c 0 on error. */ -size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, +size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data); /** diff --git a/prng.h b/prng.h index ce4cb12878..2131addb96 100644 --- a/prng.h +++ b/prng.h @@ -21,7 +21,6 @@ * @{ */ -#ifndef WITH_CONTIKI #include /** @@ -35,31 +34,6 @@ coap_prng_impl(unsigned char *buf, size_t len) { *buf++ = rand() & 0xFF; return 1; } -#else /* WITH_CONTIKI */ -#include - -/** - * Fills \p buf with \p len random bytes. This is the default - * implementation for prng(). You might want to change prng() to use - * a better PRNG on your specific platform. - */ -static inline int -contiki_prng_impl(unsigned char *buf, size_t len) { - unsigned short v = random_rand(); - while (len > sizeof(v)) { - memcpy(buf, &v, sizeof(v)); - len -= sizeof(v); - buf += sizeof(v); - v = random_rand(); - } - - memcpy(buf, &v, len); - return 1; -} - -#define prng(Buf,Length) contiki_prng_impl((Buf), (Length)) -#define prng_init(Value) random_init((unsigned short)(Value)) -#endif /* WITH_CONTIKI */ #ifndef prng /** diff --git a/resource.c b/resource.c index 32be4a1e46..54a4fbc8ce 100644 --- a/resource.c +++ b/resource.c @@ -3,16 +3,15 @@ * Copyright (C) 2010--2014 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ #include "config.h" -#include "libcoap/net.h" +#include "coap_net.h" #include "debug.h" #include "resource.h" #include "subscribe.h" -#ifdef WITH_STNODE #include "utlist.h" #include "mem.h" #include "system.h" @@ -23,100 +22,12 @@ DEFINE_LOG(LOG_DEFAULT_SEVERITY); ((coap_##Type##_t *)sys_malloc(sizeof(coap_##Type##_t))) #define COAP_FREE_TYPE(Type, Object) sys_free(Object) -#endif /* WITH_STNODE */ - -#ifdef WITH_LWIP -#include "utlist.h" -/* mem.h is only needed for the string free calls for - * COAP_ATTR_FLAGS_RELEASE_NAME / COAP_ATTR_FLAGS_RELEASE_VALUE / - * COAP_RESOURCE_FLAGS_RELEASE_URI. not sure what those lines should actually - * do on lwip. */ -#include "mem.h" - -#include - -#define COAP_MALLOC_TYPE(Type) \ - ((coap_##Type##_t *)memp_malloc(MEMP_COAP_##Type)) -#define COAP_FREE_TYPE(Type, Object) memp_free(MEMP_COAP_##Type, Object) - -#endif -#ifdef WITH_POSIX -#include "utlist.h" -#include "mem.h" - -#define COAP_MALLOC_TYPE(Type) \ - ((coap_##Type##_t *)coap_malloc(sizeof(coap_##Type##_t))) -#define COAP_FREE_TYPE(Type, Object) coap_free(Object) - -#endif /* WITH_POSIX */ -#ifdef WITH_CONTIKI -#include "memb.h" - -MEMB(resource_storage, coap_resource_t, COAP_MAX_RESOURCES); -MEMB(attribute_storage, coap_attr_t, COAP_MAX_ATTRIBUTES); -MEMB(subscription_storage, coap_subscription_t, COAP_MAX_SUBSCRIBERS); - -void -coap_resources_init() { - memb_init(&resource_storage); - memb_init(&attribute_storage); - memb_init(&subscription_storage); -} - -static inline coap_subscription_t * -coap_malloc_subscription() { - return memb_alloc(&subscription_storage); -} - -static inline void -coap_free_subscription(coap_subscription_t *subscription) { - memb_free(&subscription_storage, subscription); -} -#endif /* WITH_CONTIKI */ - #define min(a,b) ((a) < (b) ? (a) : (b)) -/* Helper functions for conditional output of character sequences into - * a given buffer. The first Offset characters are skipped. - */ - -/** - * Adds Char to Buf if Offset is zero. Otherwise, Char is not written - * and Offset is decremented. - */ -#define PRINT_WITH_OFFSET(Buf,Offset,Char) \ - if ((Offset) == 0) { \ - (*(Buf)++) = (Char); \ - } else { \ - (Offset)--; \ - } \ - -/** - * Adds Char to Buf if Offset is zero and Buf is less than Bufend. - */ -#define PRINT_COND_WITH_OFFSET(Buf,Bufend,Offset,Char,Result) { \ - if ((Buf) < (Bufend)) { \ - PRINT_WITH_OFFSET(Buf,Offset,Char); \ - } \ - (Result)++; \ - } - -/** - * Copies at most Length characters of Str to Buf. The first Offset - * characters are skipped. Output may be truncated to Bufend - Buf - * characters. - */ -#define COPY_COND_WITH_OFFSET(Buf,Bufend,Offset,Str,Length,Result) { \ - size_t i; \ - for (i = 0; i < (Length); i++) { \ - PRINT_COND_WITH_OFFSET((Buf), (Bufend), (Offset), (Str)[i], (Result)); \ - } \ - } - int match(const str *text, const str *pattern, int match_prefix, int match_substring) { assert(text); assert(pattern); - + if (text->length < pattern->length) return 0; @@ -136,7 +47,7 @@ match(const str *text, const str *pattern, int match_prefix, int match_substring token_length = remaining_length; remaining_length = 0; } - + if ((match_prefix || pattern->length == token_length) && memcmp(token, pattern->s, pattern->length) == 0) return 1; @@ -148,22 +59,22 @@ match(const str *text, const str *pattern, int match_prefix, int match_substring memcmp(text->s, pattern->s, pattern->length) == 0; } -/** +/** * Prints the names of all known resources to @p buf. This function * sets @p buflen to the number of bytes actually written and returns * @c 1 on succes. On error, the value in @p buflen is undefined and * the return value will be @c 0. - * + * * @param context The context with the resource map. * @param buf The buffer to write the result. * @param buflen Must be initialized to the maximum length of @p buf and will be * set to the length of the well-known response on return. * @param offset The offset in bytes where the output shall start and is * shifted accordingly with the characters that have been - * processed. This parameter is used to support the block - * option. + * processed. This parameter is used to support the block + * option. * @param query_filter A filter query according to Link Format - * + * * @return COAP_PRINT_STATUS_ERROR on error. Otherwise, the lower 28 bits are * set to the number of bytes that have actually been written to * @p buf. COAP_PRINT_STATUS_TRUNC is set when the output has been @@ -175,23 +86,11 @@ print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen, size_t offset, coap_opt_t *query_filter __attribute__ ((unused))) { #else /* not a GCC */ -#ifndef WITH_STNODE -coap_print_status_t -print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen, - size_t offset, coap_opt_t *query_filter) { -#else coap_print_status_t print_wellknown(coap_context_t *context, coap_pdu_t *pdu, size_t *buflen, size_t offset, coap_opt_t *query_filter) { -#endif /* WITH_STNODE */ #endif /* GCC */ coap_resource_t *r; -#ifndef WITH_STNODE - unsigned char *p = buf; - const unsigned char *bufend = buf + *buflen; - size_t left = 0; - const size_t old_offset = offset; -#endif size_t written = 0; coap_print_status_t result; int subsequent_resource = 0; @@ -211,10 +110,6 @@ print_wellknown(coap_context_t *context, coap_pdu_t *pdu, size_t *buflen, {0, NULL}}; #endif /* WITHOUT_QUERY_FILTER */ -#ifdef WITH_CONTIKI - int i; -#endif /* WITH_CONTIKI */ - #ifndef WITHOUT_QUERY_FILTER /* split query filter, if any */ if (query_filter) { @@ -222,15 +117,15 @@ print_wellknown(coap_context_t *context, coap_pdu_t *pdu, size_t *buflen, while (resource_param.length < COAP_OPT_LENGTH(query_filter) && resource_param.s[resource_param.length] != '=') resource_param.length++; - + if (resource_param.length < COAP_OPT_LENGTH(query_filter)) { const str *rt_attributes; - if (resource_param.length == 4 && + if (resource_param.length == 4 && memcmp(resource_param.s, "href", 4) == 0) flags |= MATCH_URI; for (rt_attributes = _rt_attributes; rt_attributes->s; rt_attributes++) { - if (resource_param.length == rt_attributes->length && + if (resource_param.length == rt_attributes->length && memcmp(resource_param.s, rt_attributes->s, rt_attributes->length) == 0) { flags |= MATCH_SUBSTRING; break; @@ -238,11 +133,11 @@ print_wellknown(coap_context_t *context, coap_pdu_t *pdu, size_t *buflen, } /* rest is query-pattern */ - query_pattern.s = + query_pattern.s = COAP_OPT_VALUE(query_filter) + resource_param.length + 1; assert((resource_param.length + 1) <= COAP_OPT_LENGTH(query_filter)); - query_pattern.length = + query_pattern.length = COAP_OPT_LENGTH(query_filter) - (resource_param.length + 1); if ((query_pattern.s[0] == '/') && ((flags & MATCH_URI) == MATCH_URI)) { @@ -250,32 +145,24 @@ print_wellknown(coap_context_t *context, coap_pdu_t *pdu, size_t *buflen, query_pattern.length--; } - if (query_pattern.length && + if (query_pattern.length && query_pattern.s[query_pattern.length-1] == '*') { query_pattern.length--; flags |= MATCH_PREFIX; - } + } } } #endif /* WITHOUT_QUERY_FILTER */ -#ifndef WITH_CONTIKI - #ifdef COAP_RESOURCES_NOHASH LL_FOREACH(context->resources, r) { #else HASH_ITER(hh, context->resources, r, tmp) { #endif -#else /* WITH_CONTIKI */ - r = (coap_resource_t *)resource_storage.mem; - for (i = 0; i < resource_storage.num; ++i, ++r) { - if (!resource_storage.count[i]) - continue; -#endif /* WITH_CONTIKI */ #ifndef WITHOUT_QUERY_FILTER if (resource_param.length) { /* there is a query filter */ - + if (flags & MATCH_URI) { /* match resource URI */ if (!match(&r->uri, &query_pattern, (flags & MATCH_PREFIX) != 0, (flags & MATCH_SUBSTRING) != 0)) continue; @@ -290,7 +177,7 @@ print_wellknown(coap_context_t *context, coap_pdu_t *pdu, size_t *buflen, } else { unquoted_val = attr->value; } - if (!(match(&unquoted_val, &query_pattern, + if (!(match(&unquoted_val, &query_pattern, (flags & MATCH_PREFIX) != 0, (flags & MATCH_SUBSTRING) != 0))) continue; @@ -301,42 +188,16 @@ print_wellknown(coap_context_t *context, coap_pdu_t *pdu, size_t *buflen, if (!subsequent_resource) { /* this is the first resource */ subsequent_resource = 1; } else { -#ifndef WITH_STNODE - PRINT_COND_WITH_OFFSET(p, bufend, offset, ',', written); -#else - if(pdu) { - mbuf_write(pdu->mbuf, ",", 1, pdu->length+1); - pdu->length += 1; - } - written++; -#endif + PRINT_COND_WITH_OFFSET(pdu, *buflen, offset, ",", written); } -#ifndef WITH_STNODE - left = bufend - p; /* calculate available space */ - result = coap_print_link(r, p, &left, &offset); -#else - result = coap_print_link(r, pdu, &written, &offset); -#endif + result = coap_print_link(r, pdu, buflen, &written, &offset); if (result & COAP_PRINT_STATUS_ERROR) { break; } - - /* coap_print_link() returns the number of characters that - * where actually written to p. Now advance to its end. */ -#ifndef WITH_STNODE - p += COAP_PRINT_OUTPUT_LENGTH(result); - written += left; -#endif } *buflen = written; -#ifndef WITH_STNODE - result = p - buf; - if (result + old_offset - offset < *buflen) { - result |= COAP_PRINT_STATUS_TRUNC; - } -#endif return result; } @@ -344,41 +205,28 @@ coap_resource_t * coap_resource_init(const unsigned char *uri, size_t len, int flags) { coap_resource_t *r; -#ifdef WITH_POSIX - r = (coap_resource_t *)coap_malloc(sizeof(coap_resource_t)); -#endif -#ifdef WITH_LWIP - r = (coap_resource_t *)memp_malloc(MEMP_COAP_RESOURCE); -#endif -#ifdef WITH_CONTIKI - r = (coap_resource_t *)memb_alloc(&resource_storage); -#endif -#ifdef WITH_STNODE r = (coap_resource_t *)sys_malloc(sizeof(coap_resource_t)); -#endif + if (r) { memset(r, 0, sizeof(coap_resource_t)); -#ifdef WITH_CONTIKI - LIST_STRUCT_INIT(r, link_attr); -#endif /* WITH_CONTIKI */ LIST_STRUCT_INIT(r, subscribers); r->uri.s = (unsigned char *)uri; r->uri.length = len; - + coap_hash_path(r->uri.s, r->uri.length, r->key); r->flags = flags; } else { debug("coap_resource_init: no memory left\n"); } - + return r; } coap_attr_t * -coap_add_attr(coap_resource_t *resource, +coap_add_attr(coap_resource_t *resource, const unsigned char *name, size_t nlen, const unsigned char *val, size_t vlen, int flags) { @@ -387,18 +235,7 @@ coap_add_attr(coap_resource_t *resource, if (!resource || !name) return NULL; -#ifdef WITH_POSIX - attr = (coap_attr_t *)coap_malloc(sizeof(coap_attr_t)); -#endif -#ifdef WITH_LWIP - attr = (coap_attr_t *)memp_malloc(MEMP_COAP_RESOURCEATTR); -#endif -#ifdef WITH_CONTIKI - attr = (coap_attr_t *)memb_alloc(&attribute_storage); -#endif -#ifdef WITH_STNODE attr = (coap_attr_t *)sys_malloc(sizeof(coap_attr_t)); -#endif if (attr) { attr->name.length = nlen; @@ -410,35 +247,27 @@ coap_add_attr(coap_resource_t *resource, attr->flags = flags; /* add attribute to resource list */ -#ifndef WITH_CONTIKI + LL_PREPEND(resource->link_attr, attr); -#else /* WITH_CONTIKI */ - list_add(resource->link_attr, attr); -#endif /* WITH_CONTIKI */ } else { debug("coap_add_attr: no memory left\n"); } - + return attr; } coap_attr_t * -coap_find_attr(coap_resource_t *resource, +coap_find_attr(coap_resource_t *resource, const unsigned char *name, size_t nlen) { coap_attr_t *attr; if (!resource || !name) return NULL; -#ifndef WITH_CONTIKI LL_FOREACH(resource->link_attr, attr) { -#else /* WITH_CONTIKI */ - for (attr = list_head(resource->link_attr); attr; - attr = list_item_next(attr)) { -#endif /* WITH_CONTIKI */ - if (attr->name.length == nlen && + if (attr->name.length == nlen && memcmp(attr->name.s, name, nlen) == 0) - return attr; + return attr; } return NULL; @@ -452,15 +281,7 @@ coap_delete_attr(coap_attr_t *attr) { coap_free(attr->name.s); if (attr->flags & COAP_ATTR_FLAGS_RELEASE_VALUE) coap_free(attr->value.s); -#ifdef POSIX - coap_free(attr); -#endif -#ifdef WITH_LWIP - memp_free(MEMP_COAP_RESOURCEATTR, attr); -#endif -#ifdef WITH_CONTIKI - /* FIXME it looks like this was never implemented */ -#endif + sys_free(attr); } void @@ -481,32 +302,26 @@ coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key) { void coap_add_resource(coap_context_t *context, coap_resource_t *resource) { -#ifndef WITH_CONTIKI #ifdef COAP_RESOURCES_NOHASH LL_PREPEND(context->resources, resource); #else HASH_ADD(hh, context->resources, key, sizeof(coap_key_t), resource); #endif -#endif /* WITH_CONTIKI */ } int coap_delete_resource(coap_context_t *context, coap_key_t key) { coap_resource_t *resource; coap_attr_t *attr, *tmp; -#ifdef WITH_CONTIKI - coap_subscription_t *obs; -#endif if (!context) return 0; resource = coap_get_resource_from_key(context, key); - if (!resource) + if (!resource) return 0; - -#if defined(WITH_POSIX) || defined(WITH_LWIP) || defined(WITH_STNODE) + #ifdef COAP_RESOURCES_NOHASH LL_DELETE(context->resources, resource); #else @@ -519,35 +334,13 @@ coap_delete_resource(coap_context_t *context, coap_key_t key) { if (resource->flags & COAP_RESOURCE_FLAGS_RELEASE_URI) coap_free(resource->uri.s); -#ifdef WITH_POSIX - coap_free(resource); -#endif -#ifdef WITH_LWIP - memp_free(MEMP_COAP_RESOURCE, resource); -#endif -#ifdef WITH_STNODE sys_free(resource); -#endif -#else /* not (WITH_POSIX || WITH_LWIP || WITH_STNODE) */ - /* delete registered attributes */ - while ( (attr = list_pop(resource->link_attr)) ) - memb_free(&attribute_storage, attr); - - /* delete subscribers */ - while ( (obs = list_pop(resource->subscribers)) ) { - /* FIXME: notify observer that its subscription has been removed */ - memb_free(&subscription_storage, obs); - } - - memb_free(&resource_storage, resource); -#endif /* WITH_CONTIKI */ return 1; } coap_resource_t * coap_get_resource_from_key(coap_context_t *context, coap_key_t key) { -#ifndef WITH_CONTIKI coap_resource_t *resource; #ifdef COAP_RESOURCES_NOHASH resource = NULL; @@ -563,123 +356,39 @@ coap_get_resource_from_key(coap_context_t *context, coap_key_t key) { return resource; #endif -#else /* WITH_CONTIKI */ - int i; - coap_resource_t *ptr2; - - /* the search function is basically taken from memb.c */ - ptr2 = (coap_resource_t *)resource_storage.mem; - for (i = 0; i < resource_storage.num; ++i) { - if (resource_storage.count[i] && - (memcmp(ptr2->key, key, sizeof(coap_key_t)) == 0)) - return (coap_resource_t *)ptr2; - ++ptr2; - } - return NULL; -#endif /* WITH_CONTIKI */ } -#ifndef WITH_STNODE -coap_print_status_t -coap_print_link(const coap_resource_t *resource, - unsigned char *buf, size_t *len, size_t *offset) { - unsigned char *p = buf; - const unsigned char *bufend = buf + *len; - coap_attr_t *attr; - coap_print_status_t result = 0; - const size_t old_offset = *offset; - - *len = 0; - PRINT_COND_WITH_OFFSET(p, bufend, *offset, '<', *len); - PRINT_COND_WITH_OFFSET(p, bufend, *offset, '/', *len); - - COPY_COND_WITH_OFFSET(p, bufend, *offset, - resource->uri.s, resource->uri.length, *len); - - PRINT_COND_WITH_OFFSET(p, bufend, *offset, '>', *len); -#else /* WITH_STNODE */ coap_print_status_t coap_print_link(const coap_resource_t *resource, - coap_pdu_t *pdu, size_t *len, size_t *offset) { - //unsigned char *p = buf; - //const unsigned char *bufend = buf + *len; + coap_pdu_t *pdu, size_t *left, size_t *len, size_t *offset) { coap_attr_t *attr; coap_print_status_t result = 0; - if(pdu) - { - mbuf_write(pdu->mbuf, "length+1); - pdu->length += 2; - if(resource->uri.length) /* MWAS: this check is mandatory for "/" resource to work */ - mbuf_write(pdu->mbuf, resource->uri.s, resource->uri.length, pdu->length+1); - pdu->length += resource->uri.length; - mbuf_write(pdu->mbuf, ">", 1, pdu->length+1); - pdu->length += 1; - } - *len += (3 + resource->uri.length); -#endif + PRINT_COND_WITH_OFFSET(pdu, *left, *offset, "<", *len); + PRINT_COND_WITH_OFFSET(pdu, *left, *offset, "/", *len); + if(resource->uri.length) + COPY_COND_WITH_OFFSET(pdu, *left, *offset, + resource->uri.s, resource->uri.length, *len); -#ifndef WITH_CONTIKI - LL_FOREACH(resource->link_attr, attr) { -#else /* WITH_CONTIKI */ - for (attr = list_head(resource->link_attr); attr; - attr = list_item_next(attr)) { -#endif /* WITH_CONTIKI */ + PRINT_COND_WITH_OFFSET(pdu, *left, *offset, ">", *len); -#ifndef WITH_STNODE - PRINT_COND_WITH_OFFSET(p, bufend, *offset, ';', *len); + LL_FOREACH(resource->link_attr, attr) { - COPY_COND_WITH_OFFSET(p, bufend, *offset, - attr->name.s, attr->name.length, *len); + PRINT_COND_WITH_OFFSET(pdu, *left, *offset, ";", *len); + COPY_COND_WITH_OFFSET(pdu, *left, *offset, + attr->name.s, attr->name.length, *len); if (attr->value.s) { - PRINT_COND_WITH_OFFSET(p, bufend, *offset, '=', *len); + PRINT_COND_WITH_OFFSET(pdu, *left, *offset, "=", *len); - COPY_COND_WITH_OFFSET(p, bufend, *offset, + COPY_COND_WITH_OFFSET(pdu, *left, *offset, attr->value.s, attr->value.length, *len); } - } if (resource->observable) { - COPY_COND_WITH_OFFSET(p, bufend, *offset, ";obs", 4, *len); - } - - result = p - buf; - if (result + old_offset - *offset < *len) { - result |= COAP_PRINT_STATUS_TRUNC; - } -#else /* WITH_STNODE */ - if(pdu) - { - mbuf_write(pdu->mbuf, ";", 1, pdu->length+1); - pdu->length += 1; - mbuf_write(pdu->mbuf, attr->name.s, attr->name.length, pdu->length+1); - pdu->length += attr->name.length; - } - *len += (1 + attr->name.length); - - if (attr->value.s) - { - if(pdu) - { - mbuf_write(pdu->mbuf, "=", 1, pdu->length+1); - pdu->length += 1; - mbuf_write(pdu->mbuf, attr->value.s, attr->value.length, pdu->length+1); - pdu->length += attr->value.length; - } - *len += (1 + attr->value.length); + COPY_COND_WITH_OFFSET(pdu, *left, *offset, ";obs", 4, *len); } -} -if (resource->observable) { - if(pdu) - { - mbuf_write(pdu->mbuf, ";obs", 4, pdu->length+1); - pdu->length += 4; - } - *len += 4; -} -#endif return result; } @@ -694,20 +403,20 @@ coap_find_observer(coap_resource_t *resource, const coap_address_t *peer, for (s = list_head(resource->subscribers); s; s = list_item_next(s)) { if (coap_address_equals(&s->subscriber, peer) - && (!token || (token->length == s->token_length + && (!token || (token->length == s->token_length && memcmp(token->s, s->token, token->length) == 0))) return s; } - + return NULL; } coap_subscription_t * -coap_add_observer(coap_resource_t *resource, +coap_add_observer(coap_resource_t *resource, const coap_address_t *observer, const str *token) { coap_subscription_t *s; - + assert(observer); /* Check if there is already a subscription for this peer. */ @@ -726,7 +435,7 @@ coap_add_observer(coap_resource_t *resource, coap_subscription_init(s); memcpy(&s->subscriber, observer, sizeof(coap_address_t)); - + if (token && token->length) { s->token_length = token->length; memcpy(s->token, token->s, min(s->token_length, 8)); @@ -744,7 +453,6 @@ coap_touch_observer(coap_context_t *context, const coap_address_t *observer, coap_resource_t *r; coap_subscription_t *s; -#ifndef WITH_CONTIKI #ifdef COAP_RESOURCES_NOHASH LL_FOREACH(context->resources, r) { #else @@ -756,17 +464,6 @@ coap_touch_observer(coap_context_t *context, const coap_address_t *observer, s->fail_cnt = 0; } } -#else /* WITH_CONTIKI */ - r = (coap_resource_t *)resource_storage.mem; - for (i = 0; i < resource_storage.num; ++i, ++r) { - if (resource_storage.count[i]) { - s = coap_find_observer(r, observer, token); - if (s) { - s->fail_cnt = 0; - } - } - } -#endif /* WITH_CONTIKI */ } int @@ -799,7 +496,7 @@ coap_notify_observers(coap_context_t *context, coap_resource_t *r) { h = r->handler[COAP_REQUEST_GET - 1]; assert(h); /* we do not allow subscriptions if no * GET handler is defined */ - + for (obs = list_head(r->subscribers); obs; obs = list_item_next(obs)) { if (r->dirty == 0 && obs->dirty == 0) /* running this resource due to partiallydirty, but this observation's notification was already enqueued */ @@ -836,7 +533,7 @@ coap_notify_observers(coap_context_t *context, coap_resource_t *r) { /* fill with observer-specific data */ h(context, r, &obs->subscriber, NULL, &token, response); - /* TODO: do not send response and remove observer when + /* TODO: do not send response and remove observer when * COAP_RESPONSE_CLASS(response->hdr->code) > 2 */ if (response->hdr->type == COAP_MESSAGE_CON) { @@ -867,7 +564,6 @@ coap_notify_observers(coap_context_t *context, coap_resource_t *r) { void coap_check_notify(coap_context_t *context) { coap_resource_t *r; -#ifndef WITH_CONTIKI #ifdef COAP_RESOURCES_NOHASH LL_FOREACH(context->resources, r) { @@ -877,16 +573,6 @@ coap_check_notify(coap_context_t *context) { #endif coap_notify_observers(context, r); } -#else /* WITH_CONTIKI */ - int i; - - r = (coap_resource_t *)resource_storage.mem; - for (i = 0; i < resource_storage.num; ++i, ++r) { - if (resource_storage.count[i]) { - coap_notify_observers(context, r); - } - } -#endif /* WITH_CONTIKI */ } /** @@ -906,12 +592,12 @@ coap_remove_failed_observers(coap_context_t *context, const str *token) { coap_subscription_t *obs; - for (obs = list_head(resource->subscribers); obs; + for (obs = list_head(resource->subscribers); obs; obs = list_item_next(obs)) { if (coap_address_equals(peer, &obs->subscriber) && token->length == obs->token_length && memcmp(token->s, obs->token, token->length) == 0) { - + /* count failed notifies and remove when * COAP_MAX_FAILED_NOTIFY is reached */ if (obs->fail_cnt < COAP_OBS_MAX_FAIL) @@ -919,11 +605,8 @@ coap_remove_failed_observers(coap_context_t *context, else { list_remove(resource->subscribers, obs); obs->fail_cnt = 0; - -#ifndef NDEBUG -#ifndef WITH_STNODE - if (LOG_DEBUG <= coap_get_log_level()) { -#endif + + if (LOG_DEBUG <= LOG.severity) { #ifndef INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN 40 #endif @@ -931,11 +614,9 @@ coap_remove_failed_observers(coap_context_t *context, if (coap_print_addr(&obs->subscriber, addr, INET6_ADDRSTRLEN+8)) debug("** removed observer %s\n", addr); -#ifndef WITH_STNODE } -#endif -#endif - coap_cancel_all_messages(context, &obs->subscriber, + + coap_cancel_all_messages(context, &obs->subscriber, obs->token, obs->token_length); COAP_FREE_TYPE(subscription, obs); @@ -946,13 +627,11 @@ coap_remove_failed_observers(coap_context_t *context, } void -coap_handle_failed_notify(coap_context_t *context, - const coap_address_t *peer, +coap_handle_failed_notify(coap_context_t *context, + const coap_address_t *peer, const str *token) { coap_resource_t *r; -#ifndef WITH_CONTIKI - #ifdef COAP_RESOURCES_NOHASH LL_FOREACH(context->resources, r) { #else @@ -961,15 +640,5 @@ coap_handle_failed_notify(coap_context_t *context, #endif coap_remove_failed_observers(context, r, peer, token); } -#else /* WITH_CONTIKI */ - int i; - - r = (coap_resource_t *)resource_storage.mem; - for (i = 0; i < resource_storage.num; ++i, ++r) { - if (resource_storage.count[i]) { - coap_remove_failed_observers(context, r, peer, token); - } - } -#endif /* WITH_CONTIKI */ } #endif /* WITHOUT_NOTIFY */ diff --git a/resource.h b/resource.h index ffe46e9772..0130b234bb 100644 --- a/resource.h +++ b/resource.h @@ -26,19 +26,16 @@ #define COAP_RESOURCE_CHECK_TIME 2 #endif /* COAP_RESOURCE_CHECK_TIME */ -#ifndef WITH_CONTIKI # ifdef COAP_RESOURCES_NOHASH # include "utlist.h" # else # include "uthash.h" # endif -#else /* WITH_CONTIKI */ -#endif /* WITH_CONTIKI */ #include "hashkey.h" #include "async.h" #include "str.h" #include "pdu.h" -#include "libcoap/net.h" +#include "coap_net.h" #include "subscribe.h" /** Definition of message handler function (@sa coap_resource_t). */ @@ -74,19 +71,13 @@ typedef struct coap_resource_t { coap_key_t key; /**< the actual key bytes for this resource */ -#ifndef WITH_CONTIKI #ifdef COAP_RESOURCES_NOHASH struct coap_resource_t *next; #else UT_hash_handle hh; #endif -#endif /* WITH_CONTIKI */ -#ifndef WITH_CONTIKI coap_attr_t *link_attr; /**< attributes to be included with the link format */ -#else /* WITH_CONTIKI */ - LIST_STRUCT(link_attr); /**< attributes to be included with the link format */ -#endif /* WITH_CONTIKI */ LIST_STRUCT(subscribers); /**< list of observers for this resource */ @@ -98,6 +89,48 @@ typedef struct coap_resource_t { } coap_resource_t; +/* Helper functions for conditional output of character sequences into + * a given buffer. The first Offset characters are skipped. + */ + +/** + * Writes Char to Pdu if Offset is zero. Otherwise, Char is not written + * and Offset is decremented. + */ +#define PRINT_WITH_OFFSET(Pdu,Left,Offset,Char) \ + if ((Offset) == 0) { \ + if((Left)>0) { \ + mbuf_write(Pdu->mbuf, Char, 1, Pdu->length++); \ + (Left)--; \ + } \ + } else { \ + (Offset)--; \ + } + +/** + * Writes Char to Buf if Offset is zero and Pdu is not empty + * Increases counter regardless of Pdu (used to obtain length + * prior to actual writing) + */ +#define PRINT_COND_WITH_OFFSET(Pdu,Left,Offset,Char,Result) { \ + if (Pdu) { \ + PRINT_WITH_OFFSET(Pdu,Left,Offset,Char); \ + } \ + (Result)++; \ + } + +/** + * Copies at most Length characters of Str to Pdu. The first Offset + * characters are skipped. Output may be truncated to Left + * characters. + */ +#define COPY_COND_WITH_OFFSET(Pdu,Left,Offset,Str,Length,Result) { \ + size_t i; \ + for (i = 0; i < (Length); i++) { \ + PRINT_COND_WITH_OFFSET((Pdu), (Left), (Offset), Str+i, (Result)); \ + } \ + } + /** * Creates a new resource object and initializes the link field to the * string of length @p len. This function returns the @@ -198,13 +231,9 @@ typedef unsigned int coap_print_status_t; * error. * * @param resource The resource to describe. - * @param buf The output buffer to write the description to. + * @param pdu CoAP PDU containing buffer to write to * @param len Must be initialized to the length of @p buf and * will be set to the length of the printed link description. - * @param offset The offset within the resource description where to - * start writing into @p buf. This is useful for dealing - * with the Block2 option. @p offset is updated during - * output as it is consumed. * * @return If COAP_PRINT_STATUS_ERROR is set, an error occured. Otherwise, * the lower 28 bits will indicate the number of characters that @@ -212,13 +241,8 @@ typedef unsigned int coap_print_status_t; * COAP_PRINT_STATUS_TRUNC indicates that the output has been * truncated. */ -#ifndef WITH_STNODE -coap_print_status_t coap_print_link(const coap_resource_t *resource, - unsigned char *buf, size_t *len, size_t *offset); -#else /* WITH_STNODE */ coap_print_status_t coap_print_link(const coap_resource_t *resource, - coap_pdu_t *pdu, size_t *len, size_t *offset); -#endif + coap_pdu_t *pdu, size_t *left, size_t *len, size_t *offset); /** * Registers the specified @p handler as message handler for the request type diff --git a/str.c b/str.c index 0956789c15..e035fb994d 100644 --- a/str.c +++ b/str.c @@ -14,12 +14,12 @@ #include "mem.h" #include "str.h" +DEFINE_LOG(LOG_DEFAULT_SEVERITY); + str *coap_new_string(size_t size) { str *s = coap_malloc(sizeof(str) + size + 1); if ( !s ) { -#ifndef NDEBUG - coap_log(LOG_CRIT, "coap_new_string: malloc\n"); -#endif + error("coap_new_string: malloc\n"); return NULL; } diff --git a/subscribe.c b/subscribe.c index d6834198d6..3e660a8c70 100644 --- a/subscribe.c +++ b/subscribe.c @@ -100,9 +100,7 @@ notify(coap_context_t *context, coap_resource_t *res, &sub->subscriber.addr.sa, sub->subscriber.size, pdu) == COAP_INVALID_TID) { -#ifndef NDEBUG debug("coap_check_resource_list: error sending notification\n"); -#endif coap_delete_pdu(pdu); } #endif @@ -164,14 +162,15 @@ coap_get_resource_from_key(coap_context_t *ctx, coap_key_t key) { coap_resource_t * coap_get_resource(coap_context_t *ctx, coap_uri_t *uri) { -#ifndef NDEBUG - int i; - printf("search resource %ux", coap_uri_hash(uri)); - for (i=0; i < uri->path.length; ++i) { - printf(" %02x", uri->path.s[i]); + + if (LOG_DEBUG <= LOG.severity) { + int i; + printf("search resource %ux", coap_uri_hash(uri)); + for (i=0; i < uri->path.length; ++i) { + printf(" %02x", uri->path.s[i]); + } + printf("\n"); } - printf("\n"); -#endif return uri ? coap_get_resource_from_key(ctx, coap_uri_hash(uri)) : NULL; } #endif @@ -236,9 +235,7 @@ coap_delete_resource(coap_context_t *context, coap_key_t key) { for (prev = NULL, node = context->resources; node; prev = node, node = node->next) { if (coap_uri_hash(COAP_RESOURCE(node)->uri) == key) { -#ifndef NDEBUG debug("removed key %lu (%s)\n",key,COAP_RESOURCE(node)->uri->path.s); -#endif if (!prev) context->resources = node->next; else diff --git a/subscribe.h b/subscribe.h index 9a576b34e9..543aa374d6 100644 --- a/subscribe.h +++ b/subscribe.h @@ -71,7 +71,7 @@ void coap_subscription_init(coap_subscription_t *); #include "uri.h" #include "list.h" #include "pdu.h" -#include "libcoap/net.h" +#include "coap_net.h" #if 0 typedef unsigned long coap_key_t; diff --git a/t_list.h b/t_list.h index ebbd70f02a..de2cd98e44 100644 --- a/t_list.h +++ b/t_list.h @@ -31,7 +31,6 @@ #ifndef _DTLS_LIST_H_ #define _DTLS_LIST_H_ -#ifndef WITH_CONTIKI #include "uthash.h" #include "utlist.h" @@ -138,9 +137,5 @@ list_item_next(void *item) return item == NULL? NULL: ((struct list *)item)->next; } -#else /* WITH_CONTIKI */ -#include "list.h" -#endif /* WITH_CONTIKI */ - #endif /* _DTLS_LIST_H_ */ diff --git a/uri.c b/uri.c index d8811dafe6..e1476458d5 100644 --- a/uri.c +++ b/uri.c @@ -21,11 +21,9 @@ #include "pdu.h" #include "option.h" #include "uri.h" - -#ifdef WITH_STNODE #include "logging.h" + DEFINE_LOG(LOG_DEFAULT_SEVERITY); -#endif /** * A length-safe version of strchr(). This function returns a pointer diff --git a/uthash.h b/uthash.h index 6f0e064d0e..0205b3be77 100644 --- a/uthash.h +++ b/uthash.h @@ -65,7 +65,7 @@ typedef unsigned int uint32_t; #define UTHASH_VERSION 1.9.3 #ifndef uthash_fatal -#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ +#define uthash_fatal(msg) return//exit(-1) /* fatal error (out of memory,etc) */ #endif #define uthash_malloc(sz) malloc(sz) /* malloc fcn */ #define uthash_free(ptr,sz) free(ptr) /* free fcn */ @@ -247,7 +247,7 @@ do { * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. */ #ifdef HASH_DEBUG -#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); return; } while (0)//exit(-1); } while (0) #define HASH_FSCK(hh,head) \ do { \ unsigned _bkt_i; \ From 38d3dfe2c05d62d76ab6615038d0d71a4e0572e4 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Tue, 5 Aug 2014 13:17:12 +0200 Subject: [PATCH 33/69] Backported mem.h and mem.c from master. Added basic memory mgmt for st-node --- async.c | 20 +++++------ impl/mem.h | 68 +++++++++++++++++++++++++++++++++++ impl/orignal/mem.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++ impl/st-node/mem.c | 58 ++++++++++++++++++++++++++++++ libcoap.mk | 32 +++++++++-------- mem.h | 18 ---------- 6 files changed, 242 insertions(+), 42 deletions(-) create mode 100644 impl/mem.h create mode 100644 impl/orignal/mem.c create mode 100644 impl/st-node/mem.c delete mode 100644 mem.h diff --git a/async.c b/async.c index 61439f1b5a..50b3ac1d74 100644 --- a/async.c +++ b/async.c @@ -3,10 +3,10 @@ * Copyright (C) 2010,2011 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ -/** +/** * @file async.c * @brief state management for asynchronous messages */ @@ -14,14 +14,14 @@ #ifndef WITHOUT_ASYNC #include "config.h" - #include "utlist.h" #include "mem.h" -#include "debug.h" #include "async.h" +#include "debug.h" #include "logging.h" + DEFINE_LOG(LOG_DEFAULT_SEVERITY); coap_async_state_t * @@ -41,7 +41,7 @@ coap_register_async(coap_context_t *context, coap_address_t *peer, } /* store information for handling the asynchronous task */ - s = (coap_async_state_t *)coap_malloc(sizeof(coap_async_state_t) + + s = (coap_async_state_t *)coap_malloc(sizeof(coap_async_state_t) + request->hdr->token_length); if (!s) { error("coap_register_async: insufficient memory\n"); @@ -63,7 +63,7 @@ coap_register_async(coap_context_t *context, coap_address_t *peer, s->tokenlen = request->hdr->token_length; memcpy(s->token, request->hdr->token, request->hdr->token_length); } - + memcpy(&s->id, &id, sizeof(coap_tid_t)); coap_touch_async(s); @@ -76,12 +76,12 @@ coap_register_async(coap_context_t *context, coap_address_t *peer, coap_async_state_t * coap_find_async(coap_context_t *context, coap_tid_t id) { coap_async_state_t *tmp; - LL_SEARCH_SCALAR(context->async_state,tmp,id,id); + LL_SEARCH_SCALAR(context->async_state,tmp,id,id); return tmp; } int -coap_remove_async(coap_context_t *context, coap_tid_t id, +coap_remove_async(coap_context_t *context, coap_tid_t id, coap_async_state_t **s) { coap_async_state_t *tmp = coap_find_async(context, id); @@ -92,11 +92,11 @@ coap_remove_async(coap_context_t *context, coap_tid_t id, return tmp != NULL; } -void +void coap_free_async(coap_async_state_t *s) { if (s && (s->flags & COAP_ASYNC_RELEASE_DATA) != 0) coap_free(s->appdata); - coap_free(s); + coap_free(s); } #else diff --git a/impl/mem.h b/impl/mem.h new file mode 100644 index 0000000000..ded9eaf8ab --- /dev/null +++ b/impl/mem.h @@ -0,0 +1,68 @@ +/* mem.h -- CoAP memory handling + * + * Copyright (C) 2010,2011,2014 Olaf Bergmann + * + * This file is part of the CoAP library libcoap. Please see + * README for terms of use. + */ + +#ifndef _COAP_MEM_H_ +#define _COAP_MEM_H_ + +#include + +/** + * Initializes libcoap's memory management. This function must be + * called once before coap_malloc() can be used on constrained + * devices. + */ +void coap_memory_init(void); + +/** + * Type specifiers for coap_malloc_type(). Memory objects can be typed + * to facilitate arrays of type objects to be used instead of dynamic + * memory management on constrained devices. + */ +typedef enum { + COAP_STRING, COAP_ATTRIBUTE_NAME, COAP_ATTRIBUTE_VALUE, COAP_ATTRIBUTE, COAP_RESOURCE, COAP_SUBSCRIPTION +} coap_memory_tag_t; + +/** + * Allocates a chunk of @p size bytes and returns a pointer to the + * newly allocated memory. The @p type is used to select the + * appropriate storage container on constrained devices. The storage + * allocated by coap_malloc_type() must be released with + * coap_free_type(). + * + * @param type The type of object to be stored. + * @param size The number of bytes requested. + * @return A pointer to the allocated storage or @c NULL on error. + */ +void *coap_malloc_type(coap_memory_tag_t type, size_t size); + +/** + * Releases the memory that was allocated by coap_malloc_type(). + * The type tag @p type must be the same that was used for + * allocating the object pointed to by @p. + * + * @param type The type of the object to release. + * @param p A pointer to memory that was allocated by + * coap_malloc_type(). + */ +void coap_free_type(coap_memory_tag_t type, void *p); + +/** + * Wrapper function to coap_malloc_type() for backwards compatibility. + */ +static inline void *coap_malloc(size_t size) { + return coap_malloc_type(COAP_STRING, size); +} + +/** + * Wrapper function to coap_free_type() for backwards compatibility. + */ +static inline void coap_free(void *object) { + coap_free_type(COAP_STRING, object); +} + +#endif /* _COAP_MEM_H_ */ diff --git a/impl/orignal/mem.c b/impl/orignal/mem.c new file mode 100644 index 0000000000..44508ca474 --- /dev/null +++ b/impl/orignal/mem.c @@ -0,0 +1,88 @@ +/* mem.c -- CoAP memory handling + * + * Copyright (C) 2014 Olaf Bergmann + * + * This file is part of the CoAP library libcoap. Please see + * README for terms of use. + */ + + +#include "config.h" +#include "mem.h" +#include "debug.h" + +#ifdef HAVE_ASSERT_H +#include +#else /* HAVE_ASSERT_H */ +#define assert(...) +#endif /* HAVE_ASSERT_H */ + +#ifdef HAVE_MALLOC +#include + +void +coap_memory_init() { +} + +#ifdef __GNUC__ +#define UNUSED_PARAM __attribute__((unused)) +#else +#define UNUSED_PARAM +#endif /* __GNUC__ */ + +void * +coap_malloc_type(coap_memory_tag_t type UNUSED_PARAM, size_t size) { + return malloc(size); +} + +void +coap_free_type(coap_memory_tag_t type UNUSED_PARAM, void *p) { + free(p); +} + +#else /* HAVE_MALLOC */ + +#ifdef WITH_CONTIKI +#define COAP_MAX_STRING_SIZE 12 +#define COAP_MAX_STRINGS 8 + +struct coap_string_t { + char data[COAP_MAX_STRING_SIZE]; +}; + +MEMB(string_storage, struct coap_string_t, COAP_MAX_STRINGS); + +static struct memb * +get_container(coap_memory_tag_t type) { + switch(type) { + default: + return &string_storage; + } +} + +void +coap_memory_init() { + memb_init(&string_storage); +} + +void * +coap_malloc_type(coap_memory_tag_t type, size_t size) { + struct memb *container = get_container(type); + + assert(container); + + if (size > container->size) { + debug("coap_malloc_type: Requested memory exceeds maximum object size\n"); + return NULL; + } + + return memb_alloc(container); +} + +void +coap_free_type(coap_memory_tag_t type, void *object) { + memb_free(get_container(type), object); +} +#endif /* WITH_CONTIKI */ + +#endif /* HAVE_MALLOC */ diff --git a/impl/st-node/mem.c b/impl/st-node/mem.c new file mode 100644 index 0000000000..faca0c34cb --- /dev/null +++ b/impl/st-node/mem.c @@ -0,0 +1,58 @@ +/* mem.c -- CoAP memory handling + * + * Copyright (C) 2014 Olaf Bergmann + * + * This file is part of the CoAP library libcoap. Please see + * README for terms of use. + */ + +#include "ch.h" + +#include "config.h" +#include "mem.h" +#include "debug.h" + +#include "resource.h" + +#ifndef MAX_RESOURCES +#define MAX_RESOURCES 50 +#endif + +#ifndef LIBCOAP_DEFAULT_HEAP_SIZE +#define LIBCOAP_DEFAULT_HEAP_SIZE 4096 +#endif + +static MemoryPool resource_pool; +static stkalign_t resource_buffer[MAX_RESOURCES*MEM_ALIGN_NEXT(sizeof(coap_resource_t))/sizeof(stkalign_t)]; + +static MemoryHeap default_heap; +static stkalign_t default_heap_buffer[STACK_ALIGN(LIBCOAP_DEFAULT_HEAP_SIZE)/sizeof(stkalign_t)]; + +void +coap_memory_init(void) { + chPoolInit(&resource_pool, sizeof(coap_resource_t), NULL); + for (int i = 0; i < MAX_RESOURCES; i++) { + chPoolFree(&resource_pool, (uint8_t *)resource_buffer + i*MEM_ALIGN_NEXT(sizeof(coap_resource_t))); + } + chHeapInit(&default_heap, default_heap_buffer, sizeof(default_heap_buffer)); +} + +void * +coap_malloc_type(coap_memory_tag_t type, size_t size) { + switch (type) { + case COAP_RESOURCE: + return chPoolAlloc(&resource_pool); + default: + return chHeapAlloc(&default_heap, size); + } +} + +void +coap_free_type(coap_memory_tag_t type, void *object) { + switch (type) { + case COAP_RESOURCE: + return chPoolFree(&resource_pool, object); + default: + return chHeapFree(object); + } +} diff --git a/libcoap.mk b/libcoap.mk index efd127becf..b17f9d1678 100644 --- a/libcoap.mk +++ b/libcoap.mk @@ -1,17 +1,21 @@ +get-cwd = $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))) +ROOT := $(call get-cwd) + # List of all the board related files. -EXTSRC += ext/libcoap/pdu.c \ - ext/libcoap/coap_net.c \ - ext/libcoap/debug.c \ - ext/libcoap/encode.c \ - ext/libcoap/uri.c \ - ext/libcoap/coap_list.c \ - ext/libcoap/resource.c \ - ext/libcoap/hashkey.c \ - ext/libcoap/str.c \ - ext/libcoap/option.c \ - ext/libcoap/async.c \ - ext/libcoap/subscribe.c \ - ext/libcoap/block.c +EXTSRC += $(ROOT)/pdu.c \ + $(ROOT)/coap_net.c \ + $(ROOT)/debug.c \ + $(ROOT)/encode.c \ + $(ROOT)/uri.c \ + $(ROOT)/coap_list.c \ + $(ROOT)/resource.c \ + $(ROOT)/hashkey.c \ + $(ROOT)/str.c \ + $(ROOT)/option.c \ + $(ROOT)/async.c \ + $(ROOT)/subscribe.c \ + $(ROOT)/block.c \ + $(ROOT)/impl/st-node/mem.c # Required include directories -EXTINC += ext/libcoap \ No newline at end of file +EXTINC += $(ROOT) $(ROOT)/impl \ No newline at end of file diff --git a/mem.h b/mem.h deleted file mode 100644 index a84405ee82..0000000000 --- a/mem.h +++ /dev/null @@ -1,18 +0,0 @@ -/* mem.h -- CoAP memory handling - * Currently, this is just a dummy for malloc/free - * - * Copyright (C) 2010,2011 Olaf Bergmann - * - * This file is part of the CoAP library libcoap. Please see - * README for terms of use. - */ - -#ifndef _COAP_MEM_H_ -#define _COAP_MEM_H_ - -#include - -#define coap_malloc(size) malloc(size) -#define coap_free(size) free(size) - -#endif /* _COAP_MEM_H_ */ From c3c4204cae4a4f5a7ad90822ef767367874d0d84 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Tue, 5 Aug 2014 13:20:03 +0200 Subject: [PATCH 34/69] Refactored memory mgmt in resource.c --- resource.c | 26 ++++++++++++-------------- resource.h | 4 ++-- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/resource.c b/resource.c index 54a4fbc8ce..ec77253486 100644 --- a/resource.c +++ b/resource.c @@ -14,13 +14,10 @@ #include "utlist.h" #include "mem.h" -#include "system.h" + #include "logging.h" -DEFINE_LOG(LOG_DEFAULT_SEVERITY); -#define COAP_MALLOC_TYPE(Type) \ - ((coap_##Type##_t *)sys_malloc(sizeof(coap_##Type##_t))) -#define COAP_FREE_TYPE(Type, Object) sys_free(Object) +DEFINE_LOG(LOG_DEFAULT_SEVERITY); #define min(a,b) ((a) < (b) ? (a) : (b)) @@ -205,7 +202,7 @@ coap_resource_t * coap_resource_init(const unsigned char *uri, size_t len, int flags) { coap_resource_t *r; - r = (coap_resource_t *)sys_malloc(sizeof(coap_resource_t)); + r = (coap_resource_t *)coap_malloc_type(COAP_RESOURCE, sizeof(coap_resource_t)); if (r) { memset(r, 0, sizeof(coap_resource_t)); @@ -235,7 +232,7 @@ coap_add_attr(coap_resource_t *resource, if (!resource || !name) return NULL; - attr = (coap_attr_t *)sys_malloc(sizeof(coap_attr_t)); + attr = (coap_attr_t *)coap_malloc_type(COAP_ATTRIBUTE, sizeof(coap_attr_t)); if (attr) { attr->name.length = nlen; @@ -281,7 +278,9 @@ coap_delete_attr(coap_attr_t *attr) { coap_free(attr->name.s); if (attr->flags & COAP_ATTR_FLAGS_RELEASE_VALUE) coap_free(attr->value.s); - sys_free(attr); + + coap_free_type(COAP_ATTRIBUTE, attr); +} } void @@ -334,7 +333,7 @@ coap_delete_resource(coap_context_t *context, coap_key_t key) { if (resource->flags & COAP_RESOURCE_FLAGS_RELEASE_URI) coap_free(resource->uri.s); - sys_free(resource); + coap_free_type(COAP_RESOURCE, resource); return 1; } @@ -428,7 +427,7 @@ coap_add_observer(coap_resource_t *resource, /* s points to a different subscription, so we have to create * another one. */ - s = COAP_MALLOC_TYPE(subscription); + s = coap_malloc_type(COAP_SUBSCRIPTION, sizeof(coap_subscription_t)); if (!s) return NULL; @@ -475,8 +474,7 @@ coap_delete_observer(coap_resource_t *resource, const coap_address_t *observer, if (s) { list_remove(resource->subscribers, s); - - COAP_FREE_TYPE(subscription,s); + coap_free_type(COAP_SUBSCRIPTION, s); } return s != NULL; @@ -619,7 +617,7 @@ coap_remove_failed_observers(coap_context_t *context, coap_cancel_all_messages(context, &obs->subscriber, obs->token, obs->token_length); - COAP_FREE_TYPE(subscription, obs); + coap_free_type(COAP_SUBSCRIPTION, obs); } } break; /* break loop if observer was found */ @@ -638,7 +636,7 @@ coap_handle_failed_notify(coap_context_t *context, coap_resource_t *tmp; HASH_ITER(hh, context->resources, r, tmp) { #endif - coap_remove_failed_observers(context, r, peer, token); + coap_remove_failed_observers(context, r, peer, token); } } #endif /* WITHOUT_NOTIFY */ diff --git a/resource.h b/resource.h index 0130b234bb..b5a1629161 100644 --- a/resource.h +++ b/resource.h @@ -3,10 +3,10 @@ * Copyright (C) 2010,2011,2014 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ -/** +/** * @file resource.h * @brief generic resource handling */ From 012b1711e100690ea0443216780f2e5358668741 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Tue, 5 Aug 2014 13:21:08 +0200 Subject: [PATCH 35/69] Added functions for setting/getting custom data in a resource --- resource.c | 13 +++++ resource.h | 145 ++++++++++++++++++++++++++++++++--------------------- 2 files changed, 101 insertions(+), 57 deletions(-) diff --git a/resource.c b/resource.c index ec77253486..1b91107257 100644 --- a/resource.c +++ b/resource.c @@ -215,6 +215,9 @@ coap_resource_init(const unsigned char *uri, size_t len, int flags) { coap_hash_path(r->uri.s, r->uri.length, r->key); r->flags = flags; + r->dynamic = 1; + r->pdata = NULL; + } else { debug("coap_resource_init: no memory left\n"); } @@ -281,8 +284,18 @@ coap_delete_attr(coap_attr_t *attr) { coap_free_type(COAP_ATTRIBUTE, attr); } + +void +coap_set_user_data(coap_resource_t *resource, void *p) { + resource->pdata = p; +} + +void * +coap_get_user_data(coap_resource_t *resource) { + return resource->pdata; } + void coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key) { coap_opt_iterator_t opt_iter; diff --git a/resource.h b/resource.h index b5a1629161..8718ea99d3 100644 --- a/resource.h +++ b/resource.h @@ -56,12 +56,13 @@ typedef struct coap_attr_t { #define COAP_RESOURCE_FLAGS_RELEASE_URI 0x1 typedef struct coap_resource_t { - unsigned int dirty:1; /**< set to 1 if resource has changed */ - unsigned int partiallydirty:1; /**< set to 1 if some subscribers have not yet been notified of the last change */ - unsigned int observable:1; /**< can be observed */ - unsigned int cacheable:1; /**< can be cached */ + unsigned int dirty:1; /**< set to 1 if resource has changed */ + unsigned int partiallydirty:1; /**< set to 1 if some subscribers have not yet been notified of the last change */ + unsigned int observable:1; /**< can be observed */ + unsigned int cacheable:1; /**< can be cached */ + unsigned int dynamic:1; /**< should be freed */ - /** + /** * Used to store handlers for the four coap methods @c GET, @c POST, * @c PUT, and @c DELETE. coap_dispatch() will pass incoming * requests to the handler that corresponds to its request method or @@ -87,6 +88,10 @@ typedef struct coap_resource_t { str uri; int flags; + /** + * A pointer to user data. + */ + void *pdata; } coap_resource_t; /* Helper functions for conditional output of character sequences into @@ -131,15 +136,24 @@ typedef struct coap_resource_t { } \ } -/** +/** + * A helper macro which can be used to create static resources. + */ +#define COAP_RESOURCE(_uri, _get, _post, _put, _delete) { \ + .uri = _uri, \ + .handler = {_get, _post, _put, _delete}, \ +} + + +/** * Creates a new resource object and initializes the link field to the * string of length @p len. This function returns the * new coap_resource_t object. - * + * * @param uri The URI path of the new resource. * @param len The length of @p uri. * @param flags Flags for memory management (in particular release of memory) - * + * * @return A pointer to the new object or @c NULL on error. */ coap_resource_t *coap_resource_init(const unsigned char *uri, size_t len, int flags); @@ -148,29 +162,29 @@ coap_resource_t *coap_resource_init(const unsigned char *uri, size_t len, int fl * Registers the given @p resource for @p context. The resource must * have been created by coap_resource_init(), the storage allocated * for the resource will be released by coap_delete_resource(). - * + * * @param context The context to use. * @param resource The resource to store. */ void coap_add_resource(coap_context_t *context, coap_resource_t *resource); -/** +/** * Deletes a resource identified by @p key. The storage allocated for * that resource is freed. - * + * * @param context The context where the resources are stored. * @param key The unique key for the resource to delete. - * + * * @return @c 1 if the resource was found (and destroyed), @c 0 otherwise. */ int coap_delete_resource(coap_context_t *context, coap_key_t key); -/** +/** * Registers a new attribute with the given @p resource. As the - * attributes str fields will point to @p name and @p val the + * attributes str fields will point to @p name and @p val the * caller must ensure that these pointers are valid during the * attribute's lifetime. - * + * * @param resource The resource to register the attribute with. * @param name The attribute's name. * @param nlen Length of @p name. @@ -195,17 +209,34 @@ coap_attr_t *coap_add_attr(coap_resource_t *resource, * @return The first attribute with specified @p name or @c NULL if * none was found. */ -coap_attr_t *coap_find_attr(coap_resource_t *resource, - const unsigned char *name, size_t nlen); +coap_attr_t *coap_find_attr(coap_resource_t *resource, + const unsigned char *name, size_t nlen); -/** +/** * Deletes an attribute - * + * * @param attr Pointer to a previously created attribute - * + * */ void coap_delete_attr(coap_attr_t *attr); +/** + * Associates user data with the given @p resource. + * + * @param resource The resource to which the data should be associated. + * @param p a pointer to user data + */ +void coap_set_user_data(coap_resource_t *resource, void *p); + +/** + * Returns pointer to user data associated with a given @p + * resource. + * + * @param resource The resource to get the user data. + * @return A pointer to user data or @c NULL if no data was associated. + */ +void *coap_get_user_data(coap_resource_t *resource); + /** * Status word to encode the result of conditional print or copy * operations such as coap_print_link(). The lower 28 bits of @@ -223,67 +254,67 @@ typedef unsigned int coap_print_status_t; #define COAP_PRINT_STATUS_ERROR 0x80000000u #define COAP_PRINT_STATUS_TRUNC 0x40000000u -/** +/** * Writes a description of this resource in link-format to given text * buffer. @p len must be initialized to the maximum length of @p buf * and will be set to the number of characters actually written if * successful. This function returns @c 1 on success or @c 0 on * error. - * + * * @param resource The resource to describe. * @param pdu CoAP PDU containing buffer to write to - * @param len Must be initialized to the length of @p buf and + * @param len Must be initialized to the length of @p buf and * will be set to the length of the printed link description. - * + * * @return If COAP_PRINT_STATUS_ERROR is set, an error occured. Otherwise, * the lower 28 bits will indicate the number of characters that * have actually been output into @p buffer. The flag * COAP_PRINT_STATUS_TRUNC indicates that the output has been - * truncated. + * truncated. */ coap_print_status_t coap_print_link(const coap_resource_t *resource, - coap_pdu_t *pdu, size_t *left, size_t *len, size_t *offset); + coap_pdu_t *pdu, size_t *left, size_t *len, size_t *offset); -/** +/** * Registers the specified @p handler as message handler for the request type - * @p method - * + * @p method + * * @param resource The resource for which the handler shall be registered. - * @param method The CoAP request method to handle. + * @param method The CoAP request method to handle. * @param handler The handler to register with @p resource. */ static inline void -coap_register_handler(coap_resource_t *resource, - unsigned char method, coap_method_handler_t handler) { +coap_register_handler(coap_resource_t *resource, + unsigned char method, coap_method_handler_t handler) { assert(resource); assert(method > 0 && (size_t)(method-1) < sizeof(resource->handler)/sizeof(coap_method_handler_t)); resource->handler[method-1] = handler; } -/** +/** * Returns the resource identified by the unique string @p key. If no * resource was found, this function returns @c NULL. - * + * * @param context The context to look for this resource. * @param key The unique key of the resource. - * + * * @return A pointer to the resource or @c NULL if not found. */ -coap_resource_t *coap_get_resource_from_key(coap_context_t *context, - coap_key_t key); +coap_resource_t *coap_get_resource_from_key(coap_context_t *context, + coap_key_t key); -/** +/** * Calculates the hash key for the resource requested by the * Uri-Options of @p request. This function calls coap_hash() for - * every path segment. - * + * every path segment. + * * @param request The requesting pdu. * @param key The resulting hash is stored in @p key */ void coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key); -/** - * @addtogroup observe +/** + * @addtogroup observe */ /** @@ -297,12 +328,12 @@ void coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key); * @param token The token that identifies this subscription. * @param token_length The actual length of @p token. Must be @c 0 when * @p token is @c NULL. - * @return A pointer to the added/updated subscription information or + * @return A pointer to the added/updated subscription information or * @c NULL on error. */ -coap_subscription_t *coap_add_observer(coap_resource_t *resource, - const coap_address_t *observer, - const str *token); +coap_subscription_t *coap_add_observer(coap_resource_t *resource, + const coap_address_t *observer, + const str *token); /** * Returns a subscription object for given @p peer. @@ -313,21 +344,21 @@ coap_subscription_t *coap_add_observer(coap_resource_t *resource, * token. * @return A valid subscription if exists or @c NULL otherwise. */ -coap_subscription_t *coap_find_observer(coap_resource_t *resource, - const coap_address_t *peer, - const str *token); +coap_subscription_t *coap_find_observer(coap_resource_t *resource, + const coap_address_t *peer, + const str *token); /** * Marks an observer as alive. * * @param context The CoAP context to use * @param observer The transport address of the observer - * @param token The corresponding token that has been used for + * @param token The corresponding token that has been used for * the subscription */ -void coap_touch_observer(coap_context_t *context, - const coap_address_t *observer, - const str *token); +void coap_touch_observer(coap_context_t *context, + const coap_address_t *observer, + const str *token); /** * Removes any subscription for @p observer from @p resource and releases @@ -340,11 +371,11 @@ void coap_touch_observer(coap_context_t *context, * token. * @return @c 1 if the observer has been deleted, @c 0 otherwise. */ -int coap_delete_observer(coap_resource_t *resource, - const coap_address_t *observer, - const str *token); +int coap_delete_observer(coap_resource_t *resource, + const coap_address_t *observer, + const str *token); -/** +/** * Checks for all known resources, if they are dirty and notifies * subscribed observers. */ From ba6934a224ada5a318f136cb8d6be7e754eed43f Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Tue, 5 Aug 2014 16:42:13 +0200 Subject: [PATCH 36/69] Updated makefile --- libcoap.mk | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libcoap.mk b/libcoap.mk index b17f9d1678..0d074dfc79 100644 --- a/libcoap.mk +++ b/libcoap.mk @@ -2,7 +2,7 @@ get-cwd = $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))) ROOT := $(call get-cwd) # List of all the board related files. -EXTSRC += $(ROOT)/pdu.c \ +LIBSRC += $(ROOT)/pdu.c \ $(ROOT)/coap_net.c \ $(ROOT)/debug.c \ $(ROOT)/encode.c \ @@ -18,4 +18,5 @@ EXTSRC += $(ROOT)/pdu.c \ $(ROOT)/impl/st-node/mem.c # Required include directories -EXTINC += $(ROOT) $(ROOT)/impl \ No newline at end of file +LIBINC += $(ROOT) \ + $(ROOT)/impl \ No newline at end of file From 8d82e0ca0f149b6104dbc116e645b176c2834bed Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Tue, 5 Aug 2014 16:42:29 +0200 Subject: [PATCH 37/69] Removed libcoap/net.h --- libcoap/net.h | 474 -------------------------------------------------- 1 file changed, 474 deletions(-) delete mode 100644 libcoap/net.h diff --git a/libcoap/net.h b/libcoap/net.h deleted file mode 100644 index 781bb3dd81..0000000000 --- a/libcoap/net.h +++ /dev/null @@ -1,474 +0,0 @@ -/* net.h -- CoAP network interface - * - * Copyright (C) 2010--2013 Olaf Bergmann - * - * This file is part of the CoAP library libcoap. Please see - * README for terms of use. - */ - -#ifndef _COAP_NET_H_ -#define _COAP_NET_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "config.h" - -#ifdef HAVE_ASSERT_H -#include -#else -#ifndef assert -#warning "assertions are disabled" -# define assert(x) -#endif -#endif - -#include -#include -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_TIME_H -#include -#endif -#ifdef HAVE_SYS_TIME_H -#include -#endif - -#ifdef WITH_LWIP -#include -#endif - -#include "option.h" -#include "address.h" -#include "prng.h" -#include "pdu.h" -#include "coap_time.h" - -struct coap_queue_t; - -typedef struct coap_queue_t { - struct coap_queue_t *next; - - coap_tick_t t; /**< when to send PDU for the next time */ - unsigned char retransmit_cnt; /**< retransmission counter, will be removed when zero */ - unsigned int timeout; /**< the randomized timeout value */ - - coap_address_t local; /**< local address */ - coap_address_t remote; /**< remote address */ - coap_tid_t id; /**< unique transaction id */ - - coap_pdu_t *pdu; /**< the CoAP PDU to send */ -} coap_queue_t; - -/** Adds node to given queue, ordered by node->t. */ -int coap_insert_node(coap_queue_t **queue, coap_queue_t *node); - -/** Destroys specified node. */ -int coap_delete_node(coap_queue_t *node); - -/** Removes all items from given queue and frees the allocated storage. */ -void coap_delete_all(coap_queue_t *queue); - -/** Creates a new node suitable for adding to the CoAP sendqueue. */ -coap_queue_t *coap_new_node(); - -struct coap_resource_t; -struct coap_context_t; -#ifndef WITHOUT_ASYNC -struct coap_async_state_t; -#endif - -/** Message handler that is used as call-back in coap_context_t */ -typedef void (*coap_response_handler_t)(struct coap_context_t *, - const coap_address_t *remote, - coap_pdu_t *sent, - coap_pdu_t *received, - const coap_tid_t id); - -#define COAP_MID_CACHE_SIZE 3 -typedef struct { - unsigned char flags[COAP_MID_CACHE_SIZE]; - coap_key_t item[COAP_MID_CACHE_SIZE]; -} coap_mid_cache_t; - -/** The CoAP stack's global state is stored in a coap_context_t object */ -typedef struct coap_context_t { - coap_opt_filter_t known_options; -#ifndef WITH_CONTIKI - struct coap_resource_t *resources; /**< hash table or list of known resources */ -#endif /* WITH_CONTIKI */ -#ifndef WITHOUT_ASYNC - /** list of asynchronous transactions */ - struct coap_async_state_t *async_state; -#endif /* WITHOUT_ASYNC */ - /** - * The time stamp in the first element of the sendqeue is relative - * to sendqueue_basetime. */ - coap_tick_t sendqueue_basetime; - coap_queue_t *sendqueue, *recvqueue; -#if WITH_POSIX - int sockfd; /**< send/receive socket */ -#endif /* WITH_POSIX */ -#ifdef WITH_CONTIKI - struct uip_udp_conn *conn; /**< uIP connection object */ - - struct etimer retransmit_timer; /**< fires when the next packet must be sent */ - struct etimer notify_timer; /**< used to check resources periodically */ -#endif /* WITH_CONTIKI */ -#ifdef WITH_LWIP - struct udp_pcb *pcb; /**< the underlying lwIP UDP PCB */ - struct pbuf *pending_package; /**< pbuf containing the last received package if not handled yet. This is only used to pass the package from the udp_recv callback into the coap_read function, which frees the pbuf and clears this field. */ - ip_addr_t pending_address; /**< the address associated with pending_package */ - u16_t pending_port; /**< the port associated with pending_package */ - - uint8_t timer_configured; /**< Set to 1 when a retransmission is scheduled using lwIP timers for this context, otherwise 0. */ -#endif /* WITH_LWIP */ -#ifdef WITH_STNODE - net_socket_t *ns; - struct mbuf *pending_package; -#endif - - /** - * The last message id that was used is stored in this field. The - * initial value is set by coap_new_context() and is usually a - * random value. A new message id can be created with - * coap_new_message_id(). - */ - unsigned short message_id; - - /** - * The next value to be used for Observe. This field is global for - * all resources and will be updated when notifications are created. - */ - unsigned int observe; - - coap_response_handler_t response_handler; -} coap_context_t; - -/** - * Registers a new message handler that is called whenever a response - * was received that matches an ongoing transaction. - * - * @param context The context to register the handler for. - * @param handler The response handler to register. - */ -static inline void -coap_register_response_handler(coap_context_t *context, - coap_response_handler_t handler) { - context->response_handler = handler; -} - -/** - * Registers the option type @p type with the given context object @p - * ctx. - * - * @param ctx The context to use. - * @param type The option type to register. - */ -inline static void -coap_register_option(coap_context_t *ctx, unsigned char type) { - coap_option_setb(ctx->known_options, type); -} - - -/** - * Set sendqueue_basetime in the given context object @p ctx to @p - * now. This function returns the number of elements in the queue - * head that have timed out. - */ -unsigned int coap_adjust_basetime(coap_context_t *ctx, coap_tick_t now); - -/** Returns the next pdu to send without removing from sendqeue. */ -coap_queue_t *coap_peek_next( coap_context_t *context ); - -/** Returns the next pdu to send and removes it from the sendqeue. */ -coap_queue_t *coap_pop_next( coap_context_t *context ); - -/** Creates a new coap_context_t object that will hold the CoAP stack status. */ -coap_context_t *coap_new_context(const coap_address_t *listen_addr); - -/** - * Returns a new message id and updates @p context->message_id - * accordingly. The message id is returned in network byte order - * to make it easier to read in tracing tools. - * - * @param context the current coap_context_t object - * @return incremented message id in network byte order - */ -static inline unsigned short -coap_new_message_id(coap_context_t *context) { -#ifndef WITH_CONTIKI - return htons(++(context->message_id)); -#else /* WITH_CONTIKI */ - return uip_htons(++context->message_id); -#endif -} - -/* CoAP stack context must be released with coap_free_context() */ -void coap_free_context( coap_context_t *context ); - - -/** - * Sends a confirmed CoAP message to given destination. The memory - * that is allocated by pdu will not be released by - * coap_send_confirmed(). The caller must release the memory. - * - * @param context The CoAP context to use. - * @param dst The address to send to. - * @param pdu The CoAP PDU to send. - * @return The message id of the sent message or @c COAP_INVALID_TID on error. - */ -coap_tid_t coap_send_confirmed(coap_context_t *context, - const coap_address_t *dst, - coap_pdu_t *pdu); - -/** - * Creates a new ACK PDU with specified error @p code. The options - * specified by the filter expression @p opts will be copied from the - * original request contained in @p request. Unless @c - * SHORT_ERROR_RESPONSE was defined at build time, the textual reason - * phrase for @p code will be added as payload, with Content-Type @c - * 0. This function returns a pointer to the new response message, or - * @c NULL on error. The storage allocated for the new message must be - * relased with coap_free(). - * - * @param request Specification of the received (confirmable) request. - * @param code The error code to set. - * @param opts An option filter that specifies which options to copy - * from the original request in @p node. - * - * @return A pointer to the new message or @c NULL on error. - */ -coap_pdu_t *coap_new_error_response(coap_pdu_t *request, - unsigned char code, - coap_opt_filter_t opts); -/** - * Sends a non-confirmed CoAP message to given destination. The memory - * that is allocated by pdu will not be released by coap_send(). - * The caller must release the memory. - * - * @param context The CoAP context to use. - * @param dst The address to send to. - * @param pdu The CoAP PDU to send. - * @return The message id of the sent message or @c COAP_INVALID_TID on error. - */ -coap_tid_t coap_send(coap_context_t *context, - const coap_address_t *dst, - coap_pdu_t *pdu); - -/** - * Sends an error response with code @p code for request @p request to - * @p dst. @p opts will be passed to coap_new_error_response() to - * copy marked options from the request. This function returns the - * transaction id if the message was sent, or @c COAP_INVALID_TID - * otherwise. - * - * @param context The context to use. - * @param request The original request to respond to. - * @param dst The remote peer that sent the request. - * @param code The reponse code. - * @param opts A filter that specifies the options to copy from the - * @p request. - * - * @return The transaction id if the message was sent, or @c - * COAP_INVALID_TID otherwise. - */ -coap_tid_t coap_send_error(coap_context_t *context, - coap_pdu_t *request, - const coap_address_t *dst, - unsigned char code, - coap_opt_filter_t opts); - -/** - * Helper funktion to create and send a message with @p type (usually - * ACK or RST). This function returns @c COAP_INVALID_TID when the - * message was not sent, a valid transaction id otherwise. - * - * @param context The CoAP context. - * @param dst Where to send the context. - * @param request The request that should be responded to. - * @param type Which type to set - * @return transaction id on success or @c COAP_INVALID_TID otherwise. - */ -coap_tid_t -coap_send_message_type(coap_context_t *context, - const coap_address_t *dst, - coap_pdu_t *request, - unsigned char type); -/** - * Sends an ACK message with code @c 0 for the specified @p request to - * @p dst. This function returns the corresponding transaction id if - * the message was sent or @c COAP_INVALID_TID on error. - * - * @param context The context to use. - * @param dst The destination address. - * @param request The request to be acknowledged. - * - * @return The transaction id if ACK was sent or @c COAP_INVALID_TID - * on error. - */ -coap_tid_t coap_send_ack(coap_context_t *context, - const coap_address_t *dst, - coap_pdu_t *request); - -/** - * Sends an RST message with code @c 0 for the specified @p request to - * @p dst. This function returns the corresponding transaction id if - * the message was sent or @c COAP_INVALID_TID on error. - * - * @param context The context to use. - * @param dst The destination address. - * @param request The request to be reset. - * - * @return The transaction id if RST was sent or @c COAP_INVALID_TID - * on error. - */ -static inline coap_tid_t -coap_send_rst(coap_context_t *context, - const coap_address_t *dst, - coap_pdu_t *request) { - return coap_send_message_type(context, dst, request, COAP_MESSAGE_RST); -} - -/** Handles retransmissions of confirmable messages */ -coap_tid_t coap_retransmit( coap_context_t *context, coap_queue_t *node ); - -/** - * Reads data from the network and tries to parse as CoAP PDU. On success, 0 is returned - * and a new node with the parsed PDU is added to the receive queue in the specified context - * object. - */ -#ifndef WITH_STNODE -int coap_read( coap_context_t *context ); -#else -int coap_read( coap_context_t *context, coap_tick_t timeout ); -#endif -/** - * Calculates a unique transaction id from given arguments @p peer and - * @p pdu. The id is returned in @p id. - * - * @param peer The remote party who sent @p pdu. - * @param pdu The message that initiated the transaction. - * @param id Set to the new id. - */ -void coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, - coap_tid_t *id); - -/** - * This function removes the element with given @p id from the list - * given list. If @p id was found, @p node is updated to point to the - * removed element. Note that the storage allocated by @p node is - * @b not released. The caller must do this manually using - * coap_delete_node(). This function returns @c 1 if the element with - * id @p id was found, @c 0 otherwise. For a return value of @c 0, - * the contents of @p node is undefined. - * - * @param queue The queue to search for @p id. - * @param id The node id to look for. - * @param node If found, @p node is updated to point to the - * removed node. You must release the storage pointed to by - * @p node manually. - * - * @return @c 1 if @p id was found, @c 0 otherwise. - */ -int coap_remove_from_queue(coap_queue_t **queue, - coap_tid_t id, - coap_queue_t **node); - -/** - * Removes the transaction identified by @p id from given @p queue. - * This is a convenience function for coap_remove_from_queue() with - * automatic deletion of the removed node. - * - * @param queue The queue to search for @p id. - * @param id The transaction id. - * - * @return @c 1 if node was found, removed and destroyed, @c 0 otherwise. - */ -inline static int -coap_remove_transaction(coap_queue_t **queue, coap_tid_t id) { - coap_queue_t *node; - if (!coap_remove_from_queue(queue, id, &node)) - return 0; - - coap_delete_node(node); - return 1; -} - -/** - * Retrieves transaction from queue. - * @queue The transaction queue to be searched - * @id Unique key of the transaction to find. - * @return A pointer to the transaction object or NULL if not found - */ -coap_queue_t *coap_find_transaction(coap_queue_t *queue, coap_tid_t id); - -/** - * Cancels all outstanding messages for peer @p dst that have the - * specified token. - * - * @param context The context in use - * @param dst Destination address of the messages to remove. - * @param token Message token - * @param token_length Actual length of @p token - */ -void coap_cancel_all_messages(coap_context_t *context, - const coap_address_t *dst, - const unsigned char *token, - size_t token_length); - -/** Dispatches the PDUs from the receive queue in given context. */ -void coap_dispatch( coap_context_t *context ); - -/** Returns 1 if there are no messages to send or to dispatch in the context's queues. */ -int coap_can_exit( coap_context_t *context ); - -/** - * Returns the current value of an internal tick counter. The counter - * counts \c COAP_TICKS_PER_SECOND ticks every second. - */ -void coap_ticks(coap_tick_t *); - -/** - * Verifies that @p pdu contains no unknown critical options. Options - * must be registered at @p ctx, using the function - * coap_register_option(). A basic set of options is registered - * automatically by coap_new_context(). This function returns @c 1 if - * @p pdu is ok, @c 0 otherwise. The given filter object @p unknown - * will be updated with the unknown options. As only @c COAP_MAX_OPT - * options can be signalled this way, remaining options must be - * examined manually. - * - * @code - coap_opt_filter_t f = COAP_OPT_NONE; - coap_opt_iterator_t opt_iter; - - if (coap_option_check_critical(ctx, pdu, f) == 0) { - coap_option_iterator_init(pdu, &opt_iter, f); - - while (coap_option_next(&opt_iter)) { - if (opt_iter.type & 0x01) { - ... handle unknown critical option in opt_iter ... - } - } - } - * @endcode - * - * @param ctx The context where all known options are registered. - * @param pdu The PDU to check. - * @param unknown The output filter that will be updated to indicate the - * unknown critical options found in @p pdu. - * - * @return @c 1 if everything was ok, @c 0 otherwise. - */ -int coap_option_check_critical(coap_context_t *ctx, - coap_pdu_t *pdu, - coap_opt_filter_t unknown); - -#ifdef __cplusplus -} -#endif - -#endif /* _COAP_NET_H_ */ From c14e7ceb671e0924d3e6d8a864e860453ad7ce12 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Wed, 13 Aug 2014 22:18:40 +0200 Subject: [PATCH 38/69] Copy files for static resource allocation from st-node rest --- impl/st-node/static-resource.c | 125 +++++++++++++++++++++++++++++++++ impl/st-node/static-resource.h | 45 ++++++++++++ libcoap.mk | 3 +- resource.h | 5 +- 4 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 impl/st-node/static-resource.c create mode 100644 impl/st-node/static-resource.h diff --git a/impl/st-node/static-resource.c b/impl/st-node/static-resource.c new file mode 100644 index 0000000000..68ce233348 --- /dev/null +++ b/impl/st-node/static-resource.c @@ -0,0 +1,125 @@ +#include +#include +#include "ch.h" +#include "hal.h" +#include "logging.h" +#include "utils.h" +#include "list.h" +#include "resource.h" +#include "static-resource.h" + +DEFINE_LOG(LOG_DEFAULT_SEVERITY); + +#ifndef RESOURCE_HEAP_SIZE +#define RESOURCE_HEAP_SIZE 4096 +#endif + +static MemoryHeap resource_heap; +static stkalign_t resource_heap_buffer[STACK_ALIGN(RESOURCE_HEAP_SIZE)/sizeof(stkalign_t)]; + +static uint16_t refcnt = 0; + +/** + * @brief Allocate memory on resource heap + * @param[in] size of memory block to be allocated in bytes + * + */ +inline void* resource_malloc(size_t size) +{ + void* p = NULL; + p = chHeapAlloc(&resource_heap, size); + if (p) { + trace("A[p=%p, size=%d, refcnt=%d]", p, size, refcnt++); + memset(p, 0, size); + } else { + warn("Failed to allocate [%d] bytes", size); + } + return p; +} + +/** + * @brief Release previously allocated memory + * + * @param[in] pointer to a memory block which should be released + */ +inline void resource_free(void *p) +{ + trace("F[p=%p, refcnt=%d]", p, --refcnt); + chHeapFree(p); +} + +/** + * @brief Delete resource. + */ +void delete_resource(coap_resource_t *r) +{ + resource_free(r); +} + +/** + * @brief Create resource. + */ +coap_resource_t* rest_create_resource(const char *uri, void *pdata, coap_method_handler_t (*handlers)[4]) +{ + uint8_t *p = (uint8_t *)resource_malloc(sizeof(coap_resource_t) + strlen(uri) + 1); + if (!p) { + return NULL; + } + + coap_resource_t *r = (coap_resource_t *)p; + memcpy(r->handler, handlers, sizeof(r->handler)); + r->pdata = pdata; + r->dynamic = 1; + r->uri = (char *)(p + sizeof(coap_resource_t)); + strcpy(r->uri, uri); + + return r; +} + +/** + * @brief Add resource to resource database. + * + */ +void rest_add_resource(resource_list_t *lst, coap_resource_t *resource) +{ + slist_append(&lst->resources, &resource->list); + info("Added resource [%s]", resource->uri); +} + +/** + * @brief Remove resource by URI. + */ +void rest_remove_resource(resource_list_t *lst, const char *pattern) +{ + slist_it_t it; + slist_for_each(&lst->resources, it) { + coap_resource_t *resource = slist_entry(it.q, coap_resource_t, list); + if (pattern && !strstr(resource->uri, pattern)) + continue; + slist_delete(&lst->resources, it.p, it.q); + if (resource->dynamic) { + resource_free(resource); + } + info("Removed resource [%s]", resource->uri); + } +} + +/** + * Init resources database. + * + */ +void rest_init(resource_list_t *lst) +{ + chHeapInit(&resource_heap, resource_heap_buffer, sizeof(resource_heap_buffer)); + lst->resources.size = 0; + lst->resources.head.next = &(lst->resources.head); + lst->resources.tail = &(lst->resources.head); +} + +/** + * Deinit resources database. + */ +void rest_deinit(resource_list_t *lst) +{ + rest_remove_resource(lst, NULL); +} diff --git a/impl/st-node/static-resource.h b/impl/st-node/static-resource.h new file mode 100644 index 0000000000..d2520c2ae8 --- /dev/null +++ b/impl/st-node/static-resource.h @@ -0,0 +1,45 @@ +/* + * static-resource.h + * + * Based on st-node src/rest/resource.h + * + * Created on: Sep 25, 2013 + * Author: wojtek + */ + +#ifndef RESOURCE_H_ +#define RESOURCE_H_ + +#include "resource.h" + +//struct rest_resource; +//struct teo_msg; +//struct teo_ctx; + +typedef struct resource_list { + slist_t resources; +} resource_list_t; + +//typedef struct rest_resource { +// unsigned int dynamic : 1; +// char *uri; +// void *pdata; +// rest_handler_t handler[4]; +// slist_element_t list; +//} rest_resource_t; + +#define RESOURCE(_uri, _get, _post, _put, _delete) { .uri = _uri, .handler = {_get, _post, _put, _delete} } + +void* resource_malloc(size_t size); +void resource_free(void *p); + +coap_resource_t* rest_create_resource(const char *uri, void *pdata, coap_method_handler_t (*handlers)[4]); + +void rest_add_resource(resource_list_t *lst, coap_resource_t *resource); +void rest_remove_resource(resource_list_t *lst, const char *pattern); + +void rest_init(resource_list_t *lst); +void rest_deinit(resource_list_t *lst); + + +#endif /* RESOURCE_H_ */ diff --git a/libcoap.mk b/libcoap.mk index 0d074dfc79..40d9990be3 100644 --- a/libcoap.mk +++ b/libcoap.mk @@ -15,7 +15,8 @@ LIBSRC += $(ROOT)/pdu.c \ $(ROOT)/async.c \ $(ROOT)/subscribe.c \ $(ROOT)/block.c \ - $(ROOT)/impl/st-node/mem.c + $(ROOT)/impl/st-node/mem.c \ + $(ROOT)/impl/st-node/static-resource.c # Required include directories LIBINC += $(ROOT) \ diff --git a/resource.h b/resource.h index 8718ea99d3..fc9a0fd1ef 100644 --- a/resource.h +++ b/resource.h @@ -85,13 +85,16 @@ typedef struct coap_resource_t { /** * Request URI for this resource. This field will point into the * static memory. */ - str uri; + //str uri; + char *uri; int flags; /** * A pointer to user data. */ void *pdata; + + slist_element_t list; } coap_resource_t; /* Helper functions for conditional output of character sequences into From cd438549d6e6713b94b67b8ca15778dab5296f08 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 17 Aug 2014 22:15:01 +0200 Subject: [PATCH 39/69] Modify static resources --- impl/mem.h | 2 +- impl/st-node/static-resource.c | 21 +++++++-------------- impl/st-node/static-resource.h | 2 +- resource.h | 4 ++-- 4 files changed, 11 insertions(+), 18 deletions(-) diff --git a/impl/mem.h b/impl/mem.h index ded9eaf8ab..7b8b7af8f7 100644 --- a/impl/mem.h +++ b/impl/mem.h @@ -24,7 +24,7 @@ void coap_memory_init(void); * memory management on constrained devices. */ typedef enum { - COAP_STRING, COAP_ATTRIBUTE_NAME, COAP_ATTRIBUTE_VALUE, COAP_ATTRIBUTE, COAP_RESOURCE, COAP_SUBSCRIPTION + COAP_STRING, COAP_ATTRIBUTE_NAME, COAP_ATTRIBUTE_VALUE, COAP_ATTRIBUTE, COAP_RESOURCE, COAP_SUBSCRIPTION, COAP_OPTION } coap_memory_tag_t; /** diff --git a/impl/st-node/static-resource.c b/impl/st-node/static-resource.c index 68ce233348..d86c0878b2 100644 --- a/impl/st-node/static-resource.c +++ b/impl/st-node/static-resource.c @@ -7,6 +7,7 @@ #include "list.h" #include "resource.h" #include "static-resource.h" +#include "mem.h" DEFINE_LOG(LOG_DEFAULT_SEVERITY); @@ -26,15 +27,7 @@ static uint16_t refcnt = 0; */ inline void* resource_malloc(size_t size) { - void* p = NULL; - p = chHeapAlloc(&resource_heap, size); - if (p) { - trace("A[p=%p, size=%d, refcnt=%d]", p, size, refcnt++); - memset(p, 0, size); - } else { - warn("Failed to allocate [%d] bytes", size); - } - return p; + return coap_malloc_type(COAP_RESOURCE, size); } /** @@ -44,8 +37,7 @@ inline void* resource_malloc(size_t size) */ inline void resource_free(void *p) { - trace("F[p=%p, refcnt=%d]", p, --refcnt); - chHeapFree(p); + coap_free_type(COAP_RESOURCE, p); } /** @@ -70,8 +62,9 @@ coap_resource_t* rest_create_resource(const char *uri, void *pdata, coap_method_ memcpy(r->handler, handlers, sizeof(r->handler)); r->pdata = pdata; r->dynamic = 1; - r->uri = (char *)(p + sizeof(coap_resource_t)); - strcpy(r->uri, uri); + r->uri.s = (unsigned char *)((char *)(p + sizeof(coap_resource_t))); + strcpy((char *)r->uri.s, uri); + r->uri.length = strlen(uri); return r; } @@ -94,7 +87,7 @@ void rest_remove_resource(resource_list_t *lst, const char *pattern) slist_it_t it; slist_for_each(&lst->resources, it) { coap_resource_t *resource = slist_entry(it.q, coap_resource_t, list); - if (pattern && !strstr(resource->uri, pattern)) + if (pattern && !strstr((char *)resource->uri.s, pattern)) continue; slist_delete(&lst->resources, it.p, it.q); if (resource->dynamic) { diff --git a/impl/st-node/static-resource.h b/impl/st-node/static-resource.h index d2520c2ae8..8359499512 100644 --- a/impl/st-node/static-resource.h +++ b/impl/st-node/static-resource.h @@ -28,7 +28,7 @@ typedef struct resource_list { // slist_element_t list; //} rest_resource_t; -#define RESOURCE(_uri, _get, _post, _put, _delete) { .uri = _uri, .handler = {_get, _post, _put, _delete} } +#define RESOURCE(_uri, _get, _post, _put, _delete) { .uri.s = (unsigned char*)_uri, .handler = {_get, _post, _put, _delete} } void* resource_malloc(size_t size); void resource_free(void *p); diff --git a/resource.h b/resource.h index fc9a0fd1ef..3278fc2aa5 100644 --- a/resource.h +++ b/resource.h @@ -85,8 +85,8 @@ typedef struct coap_resource_t { /** * Request URI for this resource. This field will point into the * static memory. */ - //str uri; - char *uri; + str uri; + //char *uri; int flags; /** From 7c04728bfd301e504f946c46988166c359c17351 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Mon, 18 Aug 2014 23:00:53 +0200 Subject: [PATCH 40/69] Move static resource handlers from libcoap to teo --- impl/st-node/static-resource.c | 118 --------------------------------- impl/st-node/static-resource.h | 45 ------------- libcoap.mk | 1 - 3 files changed, 164 deletions(-) delete mode 100644 impl/st-node/static-resource.c delete mode 100644 impl/st-node/static-resource.h diff --git a/impl/st-node/static-resource.c b/impl/st-node/static-resource.c deleted file mode 100644 index d86c0878b2..0000000000 --- a/impl/st-node/static-resource.c +++ /dev/null @@ -1,118 +0,0 @@ -#include -#include -#include "ch.h" -#include "hal.h" -#include "logging.h" -#include "utils.h" -#include "list.h" -#include "resource.h" -#include "static-resource.h" -#include "mem.h" - -DEFINE_LOG(LOG_DEFAULT_SEVERITY); - -#ifndef RESOURCE_HEAP_SIZE -#define RESOURCE_HEAP_SIZE 4096 -#endif - -static MemoryHeap resource_heap; -static stkalign_t resource_heap_buffer[STACK_ALIGN(RESOURCE_HEAP_SIZE)/sizeof(stkalign_t)]; - -static uint16_t refcnt = 0; - -/** - * @brief Allocate memory on resource heap - * @param[in] size of memory block to be allocated in bytes - * - */ -inline void* resource_malloc(size_t size) -{ - return coap_malloc_type(COAP_RESOURCE, size); -} - -/** - * @brief Release previously allocated memory - * - * @param[in] pointer to a memory block which should be released - */ -inline void resource_free(void *p) -{ - coap_free_type(COAP_RESOURCE, p); -} - -/** - * @brief Delete resource. - */ -void delete_resource(coap_resource_t *r) -{ - resource_free(r); -} - -/** - * @brief Create resource. - */ -coap_resource_t* rest_create_resource(const char *uri, void *pdata, coap_method_handler_t (*handlers)[4]) -{ - uint8_t *p = (uint8_t *)resource_malloc(sizeof(coap_resource_t) + strlen(uri) + 1); - if (!p) { - return NULL; - } - - coap_resource_t *r = (coap_resource_t *)p; - memcpy(r->handler, handlers, sizeof(r->handler)); - r->pdata = pdata; - r->dynamic = 1; - r->uri.s = (unsigned char *)((char *)(p + sizeof(coap_resource_t))); - strcpy((char *)r->uri.s, uri); - r->uri.length = strlen(uri); - - return r; -} - -/** - * @brief Add resource to resource database. - * - */ -void rest_add_resource(resource_list_t *lst, coap_resource_t *resource) -{ - slist_append(&lst->resources, &resource->list); - info("Added resource [%s]", resource->uri); -} - -/** - * @brief Remove resource by URI. - */ -void rest_remove_resource(resource_list_t *lst, const char *pattern) -{ - slist_it_t it; - slist_for_each(&lst->resources, it) { - coap_resource_t *resource = slist_entry(it.q, coap_resource_t, list); - if (pattern && !strstr((char *)resource->uri.s, pattern)) - continue; - slist_delete(&lst->resources, it.p, it.q); - if (resource->dynamic) { - resource_free(resource); - } - info("Removed resource [%s]", resource->uri); - } -} - -/** - * Init resources database. - * - */ -void rest_init(resource_list_t *lst) -{ - chHeapInit(&resource_heap, resource_heap_buffer, sizeof(resource_heap_buffer)); - lst->resources.size = 0; - lst->resources.head.next = &(lst->resources.head); - lst->resources.tail = &(lst->resources.head); -} - -/** - * Deinit resources database. - */ -void rest_deinit(resource_list_t *lst) -{ - rest_remove_resource(lst, NULL); -} diff --git a/impl/st-node/static-resource.h b/impl/st-node/static-resource.h deleted file mode 100644 index 8359499512..0000000000 --- a/impl/st-node/static-resource.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * static-resource.h - * - * Based on st-node src/rest/resource.h - * - * Created on: Sep 25, 2013 - * Author: wojtek - */ - -#ifndef RESOURCE_H_ -#define RESOURCE_H_ - -#include "resource.h" - -//struct rest_resource; -//struct teo_msg; -//struct teo_ctx; - -typedef struct resource_list { - slist_t resources; -} resource_list_t; - -//typedef struct rest_resource { -// unsigned int dynamic : 1; -// char *uri; -// void *pdata; -// rest_handler_t handler[4]; -// slist_element_t list; -//} rest_resource_t; - -#define RESOURCE(_uri, _get, _post, _put, _delete) { .uri.s = (unsigned char*)_uri, .handler = {_get, _post, _put, _delete} } - -void* resource_malloc(size_t size); -void resource_free(void *p); - -coap_resource_t* rest_create_resource(const char *uri, void *pdata, coap_method_handler_t (*handlers)[4]); - -void rest_add_resource(resource_list_t *lst, coap_resource_t *resource); -void rest_remove_resource(resource_list_t *lst, const char *pattern); - -void rest_init(resource_list_t *lst); -void rest_deinit(resource_list_t *lst); - - -#endif /* RESOURCE_H_ */ diff --git a/libcoap.mk b/libcoap.mk index 40d9990be3..7e55010e64 100644 --- a/libcoap.mk +++ b/libcoap.mk @@ -16,7 +16,6 @@ LIBSRC += $(ROOT)/pdu.c \ $(ROOT)/subscribe.c \ $(ROOT)/block.c \ $(ROOT)/impl/st-node/mem.c \ - $(ROOT)/impl/st-node/static-resource.c # Required include directories LIBINC += $(ROOT) \ From d1a1fd166099bb5e822e288064e102f565cff302 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 24 Aug 2014 22:44:18 +0200 Subject: [PATCH 41/69] Change resource finder to teo_get_resource_from_uri Wellknown resource support is temporarily commented out. --- coap_net.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/coap_net.c b/coap_net.c index 25bdb888cd..ef8f189e0a 100644 --- a/coap_net.c +++ b/coap_net.c @@ -46,6 +46,8 @@ DEFINE_LOG(LOG_DEFAULT_SEVERITY); systime_t clock_offset; +coap_resource_t * teo_get_resource_from_uri(coap_pdu_t *request); + static inline coap_queue_t * coap_malloc_node(void) { return (coap_queue_t *)sys_malloc(sizeof(coap_queue_t)); @@ -973,13 +975,13 @@ handle_request(coap_context_t *context, coap_queue_t *node) { coap_pdu_t *response = NULL; coap_opt_filter_t opt_filter; coap_resource_t *resource; - coap_key_t key; + //coap_key_t key; coap_option_filter_clear(opt_filter); /* try to find the resource from the request URI */ - coap_hash_request_uri(node->pdu, key); - resource = coap_get_resource_from_key(context, key); + //coap_hash_request_uri(node->pdu, key); + resource = teo_get_resource_from_uri(node->pdu);//coap_get_resource_from_key(context, key); if (!resource) { /* The resource was not found. Check if the request URI happens to @@ -989,14 +991,14 @@ handle_request(coap_context_t *context, coap_queue_t *node) { switch(node->pdu->hdr->code) { case COAP_REQUEST_GET: - if (is_wkc(key)) { /* GET request for .well-known/core */ + if (0) {//is_wkc(key)) { /* GET request for .well-known/core */ debug("create default response for %s\n", COAP_DEFAULT_URI_WELLKNOWN); response = wellknown_response(context, node->pdu); } else { /* GET request for any another resource, return 4.04 */ - debug("GET for unknown resource 0x%02x%02x%02x%02x, return 4.04\n", - key[0], key[1], key[2], key[3]); + //debug("GET for unknown resource 0x%02x%02x%02x%02x, return 4.04\n", + // key[0], key[1], key[2], key[3]); response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(404), opt_filter); @@ -1005,8 +1007,8 @@ handle_request(coap_context_t *context, coap_queue_t *node) { default: /* any other request type */ - debug("unhandled request for unknown resource 0x%02x%02x%02x%02x\r\n", - key[0], key[1], key[2], key[3]); + //debug("unhandled request for unknown resource 0x%02x%02x%02x%02x\r\n", + //key[0], key[1], key[2], key[3]); if (!coap_is_mcast(&node->local)) response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), opt_filter); @@ -1026,8 +1028,8 @@ handle_request(coap_context_t *context, coap_queue_t *node) { h = resource->handler[node->pdu->hdr->code - 1]; if (h) { - debug("call custom handler for resource 0x%02x%02x%02x%02x\n", - key[0], key[1], key[2], key[3]); + //debug("call custom handler for resource 0x%02x%02x%02x%02x\n", + //key[0], key[1], key[2], key[3]); response = coap_pdu_init(node->pdu->hdr->type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON, @@ -1096,7 +1098,7 @@ handle_request(coap_context_t *context, coap_queue_t *node) { warn("cannot generate response\r\n"); } } else { - if (WANT_WKC(node->pdu, key)) { + if (0){//(WANT_WKC(node->pdu, key)) { debug("create default response for %s\n", COAP_DEFAULT_URI_WELLKNOWN); response = wellknown_response(context, node->pdu); } else From 672b0ce11f8d14b907eece7f390c6b7f9f13d471 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 24 Aug 2014 22:46:43 +0200 Subject: [PATCH 42/69] Change message sizes to more appropriate for GSM links --- config.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.h b/config.h index 57e50d5fcc..795dd05bb9 100644 --- a/config.h +++ b/config.h @@ -113,10 +113,10 @@ #undef STDC_HEADERS /* Define maximum size of CoAP message */ -#define COAP_MAX_PDU_SIZE 140 +#define COAP_MAX_PDU_SIZE 1280 /* Define maximum size of CoAP block */ -#define COAP_MAX_BLOCK_SZX 2 +#define COAP_MAX_BLOCK_SZX 6 /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ From ba9e6ed8c91a8046ad3f8944f0f4fcf5d4cd6f3f Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sat, 6 Sep 2014 16:40:12 +0200 Subject: [PATCH 43/69] Modify pool size to account for uri and (optional) pdata --- impl/mem.h | 10 ++++++++++ impl/st-node/mem.c | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/impl/mem.h b/impl/mem.h index 7b8b7af8f7..6070e4249c 100644 --- a/impl/mem.h +++ b/impl/mem.h @@ -9,6 +9,16 @@ #ifndef _COAP_MEM_H_ #define _COAP_MEM_H_ +/* + * This is a maximum URI length for CoAP resource served by st-node. Using longer URIs may result in buffer overflow. + * */ +#define TEO_URI_LENGTH 50 +/* + * This is a maximum user data length for CoAP resource. User data is usually held in address pointed by resource->pdata. + * This value should be modified to acommodate longest possible pdata. Otherwise bad things happen. + * */ +#define TEO_USER_DATA_LENGTH 8 + #include /** diff --git a/impl/st-node/mem.c b/impl/st-node/mem.c index faca0c34cb..d4efa96fbf 100644 --- a/impl/st-node/mem.c +++ b/impl/st-node/mem.c @@ -23,7 +23,7 @@ #endif static MemoryPool resource_pool; -static stkalign_t resource_buffer[MAX_RESOURCES*MEM_ALIGN_NEXT(sizeof(coap_resource_t))/sizeof(stkalign_t)]; +static stkalign_t resource_buffer[MAX_RESOURCES*MEM_ALIGN_NEXT((sizeof(coap_resource_t)+TEO_URI_LENGTH+TEO_USER_DATA_LENGTH))/sizeof(stkalign_t)]; static MemoryHeap default_heap; static stkalign_t default_heap_buffer[STACK_ALIGN(LIBCOAP_DEFAULT_HEAP_SIZE)/sizeof(stkalign_t)]; From b0d3b89d9682a18c956755c85d69516b47150815 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 7 Sep 2014 21:16:13 +0200 Subject: [PATCH 44/69] Fix bug related to Teo resource size (no space for URI and pdata) --- impl/st-node/mem.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/impl/st-node/mem.c b/impl/st-node/mem.c index d4efa96fbf..7abf70107c 100644 --- a/impl/st-node/mem.c +++ b/impl/st-node/mem.c @@ -15,24 +15,26 @@ #include "resource.h" #ifndef MAX_RESOURCES -#define MAX_RESOURCES 50 +#define MAX_RESOURCES 60 #endif #ifndef LIBCOAP_DEFAULT_HEAP_SIZE #define LIBCOAP_DEFAULT_HEAP_SIZE 4096 #endif +#define TEO_RESOURCE_SIZE sizeof(coap_resource_t)+TEO_URI_LENGTH+TEO_USER_DATA_LENGTH + static MemoryPool resource_pool; -static stkalign_t resource_buffer[MAX_RESOURCES*MEM_ALIGN_NEXT((sizeof(coap_resource_t)+TEO_URI_LENGTH+TEO_USER_DATA_LENGTH))/sizeof(stkalign_t)]; +static stkalign_t resource_buffer[MAX_RESOURCES*MEM_ALIGN_NEXT(TEO_RESOURCE_SIZE)/sizeof(stkalign_t)]; static MemoryHeap default_heap; static stkalign_t default_heap_buffer[STACK_ALIGN(LIBCOAP_DEFAULT_HEAP_SIZE)/sizeof(stkalign_t)]; void coap_memory_init(void) { - chPoolInit(&resource_pool, sizeof(coap_resource_t), NULL); + chPoolInit(&resource_pool, MEM_ALIGN_NEXT(TEO_RESOURCE_SIZE), NULL); for (int i = 0; i < MAX_RESOURCES; i++) { - chPoolFree(&resource_pool, (uint8_t *)resource_buffer + i*MEM_ALIGN_NEXT(sizeof(coap_resource_t))); + chPoolFree(&resource_pool, (uint8_t *)resource_buffer + i*MEM_ALIGN_NEXT(TEO_RESOURCE_SIZE)); } chHeapInit(&default_heap, default_heap_buffer, sizeof(default_heap_buffer)); } From 53c6d423a26655fab6860ad879171296c2342bde Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sat, 13 Sep 2014 00:00:13 +0200 Subject: [PATCH 45/69] Remove static keywords from functions to enable teo version of dispatch --- coap_net.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/coap_net.c b/coap_net.c index ef8f189e0a..ada4e41485 100644 --- a/coap_net.c +++ b/coap_net.c @@ -936,7 +936,7 @@ wellknown_response(coap_context_t *context, coap_pdu_t *request) { * This function returns @c 0 when the token is unknown with this * peer, or a value greater than zero otherwise. */ -static int +int coap_cancel(coap_context_t *context, const coap_queue_t *sent) { #ifndef WITHOUT_OBSERVE coap_resource_t *r; @@ -975,13 +975,13 @@ handle_request(coap_context_t *context, coap_queue_t *node) { coap_pdu_t *response = NULL; coap_opt_filter_t opt_filter; coap_resource_t *resource; - //coap_key_t key; + coap_key_t key; coap_option_filter_clear(opt_filter); /* try to find the resource from the request URI */ - //coap_hash_request_uri(node->pdu, key); - resource = teo_get_resource_from_uri(node->pdu);//coap_get_resource_from_key(context, key); + coap_hash_request_uri(node->pdu, key); + resource = coap_get_resource_from_key(context, key); if (!resource) { /* The resource was not found. Check if the request URI happens to @@ -1113,7 +1113,7 @@ handle_request(coap_context_t *context, coap_queue_t *node) { } } -static inline void +void handle_response(coap_context_t *context, coap_queue_t *sent, coap_queue_t *rcvd) { @@ -1135,7 +1135,7 @@ handle_response(coap_context_t *context, } } -static inline int +int #ifdef __GNUC__ handle_locally(coap_context_t *context __attribute__ ((unused)), coap_queue_t *node __attribute__ ((unused))) { From a362584fce230b3bb961a9e15a544f5a09b2f351 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sat, 13 Sep 2014 22:07:24 +0200 Subject: [PATCH 46/69] Add function declarations and msgpack content type --- coap_net.h | 14 ++++++++++++++ pdu.h | 1 + 2 files changed, 15 insertions(+) diff --git a/coap_net.h b/coap_net.h index 08ce0e4f82..eb82936dac 100644 --- a/coap_net.h +++ b/coap_net.h @@ -438,6 +438,20 @@ int coap_option_check_critical(coap_context_t *ctx, coap_pdu_t *pdu, coap_opt_filter_t unknown); + +void +handle_response(coap_context_t *context, + coap_queue_t *sent, coap_queue_t *rcvd); +int +coap_cancel(coap_context_t *context, const coap_queue_t *sent); +int +#ifdef __GNUC__ +handle_locally(coap_context_t *context __attribute__ ((unused)), + coap_queue_t *node __attribute__ ((unused))); +#else /* not a GCC */ +handle_locally(coap_context_t *context, coap_queue_t *node); +#endif /* GCC */ + #ifdef __cplusplus } #endif diff --git a/pdu.h b/pdu.h index 23577f7d16..fca438be9f 100644 --- a/pdu.h +++ b/pdu.h @@ -156,6 +156,7 @@ char *coap_response_phrase(unsigned char code); #define COAP_MEDIATYPE_APPLICATION_RDF_XML 43 /* application/rdf+xml */ #define COAP_MEDIATYPE_APPLICATION_EXI 47 /* application/exi */ #define COAP_MEDIATYPE_APPLICATION_JSON 50 /* application/json */ +#define COAP_MEDIATYPE_APPLICATION_MSGPACK 59 /* application/x-msgpack */ /* Note that identifiers for registered media types are in the range 0-65535. We * use an unallocated type here and hope for the best. */ From dd65cad9d0f17aed9b18d5df775f90455068b844 Mon Sep 17 00:00:00 2001 From: Maciej Wasilak Date: Sun, 1 Mar 2015 18:49:48 +0100 Subject: [PATCH 47/69] Add payload offset field to PDU --- pdu.c | 3 +++ pdu.h | 1 + 2 files changed, 4 insertions(+) diff --git a/pdu.c b/pdu.c index a8db503d54..f1b85bee50 100644 --- a/pdu.c +++ b/pdu.c @@ -304,6 +304,8 @@ coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu) { assert(data); assert(pdu); + pdu->payload_offset = (unsigned short)length; + if (pdu->max_size < length) { debug("insufficient space to store parsed PDU\n"); return 0; @@ -360,6 +362,7 @@ coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu) { if (length) { assert(*opt == COAP_PAYLOAD_START); opt++; length--; + pdu->payload_offset -= (unsigned short)length; if (!length) { debug("coap_pdu_parse: message ending in payload start marker\n"); diff --git a/pdu.h b/pdu.h index fca438be9f..4fdf8786ed 100644 --- a/pdu.h +++ b/pdu.h @@ -222,6 +222,7 @@ typedef struct { unsigned short max_delta; /**< highest option number */ unsigned short length; /**< PDU length (including header, options, data) */ unsigned char *data; /**< payload */ + unsigned short payload_offset; /**< payload offset */ struct mbuf *mbuf; /**< mbuf */ } coap_pdu_t; From 134f50b1bd3a5b70654fb92afcd2f8684591d899 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Thu, 26 Mar 2015 11:53:06 +0100 Subject: [PATCH 48/69] Changed project structure to reflect changes in develop branch --- .gitignore | 56 +++++++++++++++++++++++++ README | 28 +------------ README.md | 30 +++++++++++++ address.h => include/coap/address.h | 6 --- async.h => include/coap/async.h | 2 +- bits.h => include/coap/bits.h | 0 block.h => include/coap/block.h | 0 coap.h => include/coap/coap.h | 4 +- coap_time.h => include/coap/coap_time.h | 0 config.h => include/coap/config.h | 0 debug.h => include/coap/debug.h | 0 encode.h => include/coap/encode.h | 0 hashkey.h => include/coap/hashkey.h | 0 coap_list.h => include/coap/list.h | 0 lwippools.h => include/coap/lwippools.h | 0 {impl => include/coap}/mem.h | 0 coap_net.h => include/coap/net.h | 0 option.h => include/coap/option.h | 0 pdu.h => include/coap/pdu.h | 3 +- prng.h => include/coap/prng.h | 0 resource.h => include/coap/resource.h | 12 ++++-- str.h => include/coap/str.h | 0 subscribe.h => include/coap/subscribe.h | 0 t_list.h => include/coap/t_list.h | 0 uri.h => include/coap/uri.h | 0 uthash.h => include/coap/uthash.h | 0 utlist.h => include/coap/utlist.h | 0 libcoap.mk | 32 +++++++------- async.c => src/async.c | 0 block.c => src/block.c | 0 coap-observer.c => src/coap-observer.c | 0 coap-server.c => src/coap-server.c | 0 coap_list.c => src/coap_list.c | 2 +- coap_net.c => src/coap_net.c | 2 +- debug.c => src/debug.c | 2 +- encode.c => src/encode.c | 0 hashkey.c => src/hashkey.c | 0 net.c => src/net.c | 0 option.c => src/option.c | 0 pdu.c => src/pdu.c | 6 +-- resource.c => src/resource.c | 19 ++++++++- str.c => src/str.c | 0 subscribe.c => src/subscribe.c | 0 uri.c => src/uri.c | 0 44 files changed, 139 insertions(+), 65 deletions(-) create mode 100644 README.md rename address.h => include/coap/address.h (95%) rename async.h => include/coap/async.h (99%) rename bits.h => include/coap/bits.h (100%) rename block.h => include/coap/block.h (100%) rename coap.h => include/coap/coap.h (92%) rename coap_time.h => include/coap/coap_time.h (100%) rename config.h => include/coap/config.h (100%) rename debug.h => include/coap/debug.h (100%) rename encode.h => include/coap/encode.h (100%) rename hashkey.h => include/coap/hashkey.h (100%) rename coap_list.h => include/coap/list.h (100%) rename lwippools.h => include/coap/lwippools.h (100%) rename {impl => include/coap}/mem.h (100%) rename coap_net.h => include/coap/net.h (100%) rename option.h => include/coap/option.h (100%) rename pdu.h => include/coap/pdu.h (99%) rename prng.h => include/coap/prng.h (100%) rename resource.h => include/coap/resource.h (98%) rename str.h => include/coap/str.h (100%) rename subscribe.h => include/coap/subscribe.h (100%) rename t_list.h => include/coap/t_list.h (100%) rename uri.h => include/coap/uri.h (100%) rename uthash.h => include/coap/uthash.h (100%) rename utlist.h => include/coap/utlist.h (100%) rename async.c => src/async.c (100%) rename block.c => src/block.c (100%) rename coap-observer.c => src/coap-observer.c (100%) rename coap-server.c => src/coap-server.c (100%) rename coap_list.c => src/coap_list.c (97%) rename coap_net.c => src/coap_net.c (99%) rename debug.c => src/debug.c (99%) rename encode.c => src/encode.c (100%) rename hashkey.c => src/hashkey.c (100%) rename net.c => src/net.c (100%) rename option.c => src/option.c (100%) rename pdu.c => src/pdu.c (99%) rename resource.c => src/resource.c (98%) rename str.c => src/str.c (100%) rename subscribe.c => src/subscribe.c (100%) rename uri.c => src/uri.c (100%) diff --git a/.gitignore b/.gitignore index 5e3248252b..0405271a20 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,59 @@ *.pyc +# .gitignore for libcoap + +# ignoring autogenerated files and directories by autoreconf +INSTALL +Makefile +Makefile.in +aclocal.m4 +ar-lib +autom4te.cache/ +coap_config.h* +compile +config.* +configure +debian/ +depcomp +install-sh +libcoap-*.tar.bz2 +libtool +ltmain.sh +m4/ +# warn about specific macros in the m4 directory if they missing +!m4/ax_* +missing +stamp-h1 + +# ignoring more files generated by the configure script or the make actions +.libs/ +libcoap*.la +libcoap*.pc +src/.deps/ +src/.dirstamp +src/.libs/ +src/*.o +src/*.lo + +# the doc/ folder +doc/Doxyfile +doc/Makefile.in +doc/doxyfile.stamp +doc/doxygen_sqlite3.db +doc/html/ + +# the examples/ folder +examples/.deps/ +examples/client.o +examples/coap-client +examples/coap-server +examples/coap_list.o +examples/rd +examples/rd.o +examples/server.o + +# the tests/ folder +tests/.deps +tests/testdriver +tests/*.o diff --git a/README b/README index 5faa3dc49c..42061c01a1 100644 --- a/README +++ b/README @@ -1,27 +1 @@ -libcoap: A C implementation of IETF Core Application protocol - -Copyright (C) 2010--2013 by Olaf Bergmann - -ABOUT LIBCOAP - -libcoap is a C implementation of a lightweight application-protocol -for devices that are constrained their resources such as computing -power, RF range, memory, bandwith, or network packet sizes. This -protocol, CoAP, is developed in the IETF working group "Constrained -RESTful Environments (core)", see . - -PACKAGE CONTENTS - -This directory contains a protocol parser and basic networking -functions for platform with support for malloc() and BSD-style -sockets. The examples directory contains a client and a server to -demonstrate the use of this library. - -LICENSE INFORMATION - -This library is published as open-source software without any warranty -of any kind. Use is permitted under the terms of the GNU General -Public License (GPL), Version 2 or higher, OR the revised BSD -license. Please refer to LICENSE.GPL oder LICENSE.BSD for further -details. - +README.md \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000000..2c5bcbcf41 --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +libcoap: A C implementation of IETF Constrained Application Protocol (RFC 7252) + +Copyright (C) 2010--2015 by Olaf Bergmann + +ABOUT LIBCOAP +============= + +libcoap is a C implementation of a lightweight application-protocol +for devices that are constrained their resources such as computing +power, RF range, memory, bandwith, or network packet sizes. This +protocol, CoAP, is standardized by the IETF as RFC 7252. For further +information related to CoAP, see . + +PACKAGE CONTENTS +================ + +This directory contains a protocol parser and basic networking +functions for platform with support for malloc() and BSD-style +sockets. The examples directory contains a client and a server to +demonstrate the use of this library. + +LICENSE INFORMATION +=================== + +This library is published as open-source software without any warranty +of any kind. Use is permitted under the terms of the GNU General +Public License (GPL), Version 2 or higher, OR the revised BSD +license. Please refer to LICENSE.GPL oder LICENSE.BSD for further +details. + diff --git a/address.h b/include/coap/address.h similarity index 95% rename from address.h rename to include/coap/address.h index feb6633115..86828b003f 100644 --- a/address.h +++ b/include/coap/address.h @@ -19,10 +19,6 @@ #ifdef HAVE_ASSERT_H #include #else -#ifndef assert -#warning "assertions are disabled" -# define assert(x) -#endif #endif #include @@ -36,8 +32,6 @@ #include #endif -#include "net.h" - typedef struct coap_address_t { uint8_t size; uint16_t port; diff --git a/async.h b/include/coap/async.h similarity index 99% rename from async.h rename to include/coap/async.h index 27e6988f0f..a5168f8859 100644 --- a/async.h +++ b/include/coap/async.h @@ -16,7 +16,7 @@ #define _COAP_ASYNC_H_ #include "config.h" -#include "coap_net.h" +#include "net.h" #ifndef WITHOUT_ASYNC diff --git a/bits.h b/include/coap/bits.h similarity index 100% rename from bits.h rename to include/coap/bits.h diff --git a/block.h b/include/coap/block.h similarity index 100% rename from block.h rename to include/coap/block.h diff --git a/coap.h b/include/coap/coap.h similarity index 92% rename from coap.h rename to include/coap/coap.h index 91c7ccfb0f..444f02db69 100644 --- a/coap.h +++ b/include/coap/coap.h @@ -16,10 +16,10 @@ extern "C" { #include "config.h" #include "debug.h" #include "mem.h" -#include "coap_list.h" +#include "list.h" #include "pdu.h" #include "option.h" -#include "coap_net.h" +#include "net.h" #include "encode.h" #include "str.h" #include "uri.h" diff --git a/coap_time.h b/include/coap/coap_time.h similarity index 100% rename from coap_time.h rename to include/coap/coap_time.h diff --git a/config.h b/include/coap/config.h similarity index 100% rename from config.h rename to include/coap/config.h diff --git a/debug.h b/include/coap/debug.h similarity index 100% rename from debug.h rename to include/coap/debug.h diff --git a/encode.h b/include/coap/encode.h similarity index 100% rename from encode.h rename to include/coap/encode.h diff --git a/hashkey.h b/include/coap/hashkey.h similarity index 100% rename from hashkey.h rename to include/coap/hashkey.h diff --git a/coap_list.h b/include/coap/list.h similarity index 100% rename from coap_list.h rename to include/coap/list.h diff --git a/lwippools.h b/include/coap/lwippools.h similarity index 100% rename from lwippools.h rename to include/coap/lwippools.h diff --git a/impl/mem.h b/include/coap/mem.h similarity index 100% rename from impl/mem.h rename to include/coap/mem.h diff --git a/coap_net.h b/include/coap/net.h similarity index 100% rename from coap_net.h rename to include/coap/net.h diff --git a/option.h b/include/coap/option.h similarity index 100% rename from option.h rename to include/coap/option.h diff --git a/pdu.h b/include/coap/pdu.h similarity index 99% rename from pdu.h rename to include/coap/pdu.h index 4fdf8786ed..b8f4fa8fec 100644 --- a/pdu.h +++ b/include/coap/pdu.h @@ -10,9 +10,10 @@ #define _PDU_H_ #include "config.h" -#include "coap_list.h" #include "uri.h" #include + +#include "list.h" #include "mbuf.h" diff --git a/prng.h b/include/coap/prng.h similarity index 100% rename from prng.h rename to include/coap/prng.h diff --git a/resource.h b/include/coap/resource.h similarity index 98% rename from resource.h rename to include/coap/resource.h index 3278fc2aa5..9260183a6e 100644 --- a/resource.h +++ b/include/coap/resource.h @@ -15,7 +15,8 @@ #define _COAP_RESOURCE_H_ #include "config.h" -#include "t_list.h" +#include "list.h" +//#include "t_list.h" #if defined(HAVE_ASSERT_H) && !defined(assert) # include @@ -35,7 +36,7 @@ #include "async.h" #include "str.h" #include "pdu.h" -#include "coap_net.h" +#include "net.h" #include "subscribe.h" /** Definition of message handler function (@sa coap_resource_t). */ @@ -93,8 +94,6 @@ typedef struct coap_resource_t { * A pointer to user data. */ void *pdata; - - slist_element_t list; } coap_resource_t; /* Helper functions for conditional output of character sequences into @@ -384,6 +383,11 @@ int coap_delete_observer(coap_resource_t *resource, */ void coap_check_notify(coap_context_t *context); +/** + * Invoke a visitor function for all registered resources. + */ +void coap_resource_visit(coap_context_t *context, int (*f)(coap_context_t *context, coap_resource_t *r)); + /** @} */ #endif /* _COAP_RESOURCE_H_ */ diff --git a/str.h b/include/coap/str.h similarity index 100% rename from str.h rename to include/coap/str.h diff --git a/subscribe.h b/include/coap/subscribe.h similarity index 100% rename from subscribe.h rename to include/coap/subscribe.h diff --git a/t_list.h b/include/coap/t_list.h similarity index 100% rename from t_list.h rename to include/coap/t_list.h diff --git a/uri.h b/include/coap/uri.h similarity index 100% rename from uri.h rename to include/coap/uri.h diff --git a/uthash.h b/include/coap/uthash.h similarity index 100% rename from uthash.h rename to include/coap/uthash.h diff --git a/utlist.h b/include/coap/utlist.h similarity index 100% rename from utlist.h rename to include/coap/utlist.h diff --git a/libcoap.mk b/libcoap.mk index 7e55010e64..61d480e580 100644 --- a/libcoap.mk +++ b/libcoap.mk @@ -2,21 +2,21 @@ get-cwd = $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))) ROOT := $(call get-cwd) # List of all the board related files. -LIBSRC += $(ROOT)/pdu.c \ - $(ROOT)/coap_net.c \ - $(ROOT)/debug.c \ - $(ROOT)/encode.c \ - $(ROOT)/uri.c \ - $(ROOT)/coap_list.c \ - $(ROOT)/resource.c \ - $(ROOT)/hashkey.c \ - $(ROOT)/str.c \ - $(ROOT)/option.c \ - $(ROOT)/async.c \ - $(ROOT)/subscribe.c \ - $(ROOT)/block.c \ - $(ROOT)/impl/st-node/mem.c \ - +LIBSRC += $(ROOT)/src/pdu.c \ + $(ROOT)/src/coap_net.c \ + $(ROOT)/src/debug.c \ + $(ROOT)/src/encode.c \ + $(ROOT)/src/uri.c \ + $(ROOT)/src/coap_list.c \ + $(ROOT)/src/resource.c \ + $(ROOT)/src/hashkey.c \ + $(ROOT)/src/str.c \ + $(ROOT)/src/option.c \ + $(ROOT)/src/async.c \ + $(ROOT)/src/subscribe.c \ + $(ROOT)/src/block.c \ + $(ROOT)/src/impl/st-node/mem.c \ + # Required include directories -LIBINC += $(ROOT) \ +LIBINC += $(ROOT)/include \ $(ROOT)/impl \ No newline at end of file diff --git a/async.c b/src/async.c similarity index 100% rename from async.c rename to src/async.c diff --git a/block.c b/src/block.c similarity index 100% rename from block.c rename to src/block.c diff --git a/coap-observer.c b/src/coap-observer.c similarity index 100% rename from coap-observer.c rename to src/coap-observer.c diff --git a/coap-server.c b/src/coap-server.c similarity index 100% rename from coap-server.c rename to src/coap-server.c diff --git a/coap_list.c b/src/coap_list.c similarity index 97% rename from coap_list.c rename to src/coap_list.c index 3f30982137..79a4e876a3 100644 --- a/coap_list.c +++ b/src/coap_list.c @@ -11,9 +11,9 @@ #include #include +#include "../include/coap/list.h" #include "debug.h" #include "mem.h" -#include "coap_list.h" DEFINE_LOG(LOG_DEFAULT_SEVERITY); diff --git a/coap_net.c b/src/coap_net.c similarity index 99% rename from coap_net.c rename to src/coap_net.c index ada4e41485..3d6ae19094 100644 --- a/coap_net.c +++ b/src/coap_net.c @@ -37,7 +37,7 @@ #include "option.h" #include "encode.h" #include "block.h" -#include "coap_net.h" +#include "../include/coap/net.h" #include "system.h" #include "net.h" diff --git a/debug.c b/src/debug.c similarity index 99% rename from debug.c rename to src/debug.c index a2db7daa39..36f7899ccb 100644 --- a/debug.c +++ b/src/debug.c @@ -26,7 +26,7 @@ #endif #include "debug.h" -#include "coap_net.h" +#include "../include/coap/net.h" #include "net.h" #ifdef HAVE_TIME_H diff --git a/encode.c b/src/encode.c similarity index 100% rename from encode.c rename to src/encode.c diff --git a/hashkey.c b/src/hashkey.c similarity index 100% rename from hashkey.c rename to src/hashkey.c diff --git a/net.c b/src/net.c similarity index 100% rename from net.c rename to src/net.c diff --git a/option.c b/src/option.c similarity index 100% rename from option.c rename to src/option.c diff --git a/pdu.c b/src/pdu.c similarity index 99% rename from pdu.c rename to src/pdu.c index f1b85bee50..569cd43e1b 100644 --- a/pdu.c +++ b/src/pdu.c @@ -28,7 +28,8 @@ DEFINE_LOG(LOG_DEFAULT_SEVERITY); #include "encode.h" #include "mem.h" - +#include "net.h" +#include "system.h" void coap_pdu_clear(coap_pdu_t *pdu, size_t size) { @@ -41,9 +42,6 @@ coap_pdu_clear(coap_pdu_t *pdu, size_t size) { pdu->length = sizeof(coap_hdr_t); } -#include "net.h" -#include "system.h" - coap_pdu_t * coap_pdu_from_mbuf(struct mbuf *mbuf) { diff --git a/resource.c b/src/resource.c similarity index 98% rename from resource.c rename to src/resource.c index 1b91107257..44edc27251 100644 --- a/resource.c +++ b/src/resource.c @@ -7,9 +7,10 @@ */ #include "config.h" -#include "coap_net.h" #include "debug.h" #include "resource.h" + +#include "../include/coap/net.h" #include "subscribe.h" #include "utlist.h" @@ -586,6 +587,22 @@ coap_check_notify(coap_context_t *context) { } } +void +coap_resource_visit(coap_context_t *context, int (*f)(coap_context_t *context, coap_resource_t *r)) +{ + coap_resource_t *r; +#ifdef COAP_RESOURCES_NOHASH + LL_FOREACH(context->resources, r) { +#else + coap_resource_t *tmp; + HASH_ITER(hh, context->resources, r, tmp) { +#endif + if (f(context, r)) { + return; + } + } +} + /** * Checks the failure counter for (peer, token) and removes peer from * the list of observers for the given resource when COAP_OBS_MAX_FAIL diff --git a/str.c b/src/str.c similarity index 100% rename from str.c rename to src/str.c diff --git a/subscribe.c b/src/subscribe.c similarity index 100% rename from subscribe.c rename to src/subscribe.c diff --git a/uri.c b/src/uri.c similarity index 100% rename from uri.c rename to src/uri.c From 742ae02854a0de789d12a30fc093fc00eae8b450 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Thu, 26 Mar 2015 12:28:00 +0100 Subject: [PATCH 49/69] Merged examples folder --- examples/Makefile.am | 26 ++ examples/Makefile.in.old | 63 ++++ examples/client.c | 552 +++++++++++++++++------------ examples/coap_list.c | 51 +++ examples/coap_list.h | 31 ++ examples/contiki/Makefile.common | 36 ++ examples/contiki/Makefile.contiki | 56 +++ examples/contiki/coap-observer.c | 185 ++++++++++ examples/contiki/radvd.conf.sample | 14 + examples/contiki/server.c | 228 ++++++++++++ examples/etsi_iot_01.c | 8 +- examples/lwip/config.h | 20 +- examples/lwip/server-coap.c | 1 - examples/lwip/server.c | 3 +- examples/rd.c | 75 ++-- examples/server.c | 73 ++-- 16 files changed, 1135 insertions(+), 287 deletions(-) create mode 100644 examples/Makefile.am create mode 100644 examples/Makefile.in.old create mode 100644 examples/coap_list.c create mode 100644 examples/coap_list.h create mode 100644 examples/contiki/Makefile.common create mode 100644 examples/contiki/Makefile.contiki create mode 100644 examples/contiki/coap-observer.c create mode 100644 examples/contiki/radvd.conf.sample create mode 100644 examples/contiki/server.c mode change 120000 => 100644 examples/lwip/config.h diff --git a/examples/Makefile.am b/examples/Makefile.am new file mode 100644 index 0000000000..2e266eba37 --- /dev/null +++ b/examples/Makefile.am @@ -0,0 +1,26 @@ +# doc/Makefile.am +# +# Copyright (C) 2015 Carsten Schoenert +# +# This file is part of the CoAP C library libcoap. Please see README and +# COPYING for terms of use. + +# just do nothing if 'BUILD_EXAMPLES' isn't defined +if BUILD_EXAMPLES + +# picking up the default warning CFLAGS into AM_CFLAGS +AM_CFLAGS = -isystem@top_builddir@/include/coap/ $(WARNING_CFLAGS) -std=c99 + +# etsi_iot_01 and tiny are missing +bin_PROGRAMS = coap-client coap-server rd + +coap_client_SOURCES = client.c coap_list.c +coap_client_LDADD = @top_builddir@/.libs/libcoap-$(LIBCOAP_API_VERSION).la + +coap_server_SOURCES = server.c +coap_server_LDADD = @top_builddir@/.libs/libcoap-$(LIBCOAP_API_VERSION).la + +rd_SOURCES = rd.c +rd_LDADD = @top_builddir@/.libs/libcoap-$(LIBCOAP_API_VERSION).la + +endif # BUILD_EXAMPLES diff --git a/examples/Makefile.in.old b/examples/Makefile.in.old new file mode 100644 index 0000000000..b04ff08947 --- /dev/null +++ b/examples/Makefile.in.old @@ -0,0 +1,63 @@ +# Makefile for libcoap +# +# Copyright (C) 2010,2011,2015 Olaf Bergmann +# +# This file is part of the CoAP library libcoap. Please see +# README for terms of use. + +# the library's version +VERSION:=@PACKAGE_VERSION@ + +# tools +@SET_MAKE@ +SHELL = /bin/sh +MKDIR = mkdir + +abs_builddir = @abs_builddir@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +# files and flags +PROGRAMS:=coap-server coap-client rd #etsi_iot_01 tiny +client_SOURCES:= client.o coap_list.o +client_OBJECTS:= $(patsubst %.c, %.o, $(client_SOURCES)) +SOURCES:= tiny.c $(client_SOURCES) server.c rd.c etsi_iot_01.c +OBJECTS:= $(patsubst %.c, %.o, $(SOURCES)) +#CFLAGS:=-g -Wall -ansi -pedantic -I.. +CFLAGS:=-g -Wall @CFLAGS@ +CPPFLAGS:=-I$(top_srcdir) @CPPFLAGS@ +DISTDIR?=$(top_builddir)/@PACKAGE_TARNAME@-@PACKAGE_VERSION@ +FILES:=Makefile.in $(SOURCES) +LDFLAGS:=-L$(top_builddir) +LDLIBS:=-lcoap @LIBS@ +libcoap =$(top_builddir)/libcoap.a + +.PHONY: clean distclean + +.SUFFIXES: +.SUFFIXES: .c .o + +all: $(PROGRAMS) + +check: + echo DISTDIR: $(DISTDIR) + echo top_builddir: $(top_builddir) + +tiny: tiny.o $(libcoap) + $(CC) -o $@ $< $(LDFLAGS) + +coap-client: $(client_OBJECTS) $(libcoap) + $(CC) -o $@ $(client_OBJECTS) $(LDFLAGS) $(LDLIBS) + +coap-server: server.o $(libcoap) + $(CC) -o $@ $< $(LDFLAGS) $(LDLIBS) + +clean: + @rm -f $(PROGRAMS) $(OBJECTS) + +distclean: clean + @rm -rf $(DISTDIR) + @rm -f *~ + +dist: $(FILES) + test -d $(DISTDIR)/examples || mkdir $(DISTDIR)/examples + cp $(FILES) $(DISTDIR)/examples diff --git a/examples/client.c b/examples/client.c index a43d2394c4..17b136501e 100644 --- a/examples/client.c +++ b/examples/client.c @@ -1,12 +1,12 @@ /* coap-client -- simple CoAP client * - * Copyright (C) 2010--2013 Olaf Bergmann + * Copyright (C) 2010--2015 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ -#include "config.h" +#include "coap_config.h" #include #include @@ -22,6 +22,7 @@ #include #include "coap.h" +#include "coap_list.h" int flags = 0; @@ -60,18 +61,24 @@ coap_tick_t obs_wait = 0; /* timeout for current subscription */ #define min(a,b) ((a) < (b) ? (a) : (b)) +#ifdef __GNUC__ +#define UNUSED_PARAM __attribute__ ((unused)) +#else /* not a GCC */ +#define UNUSED_PARAM +#endif /* GCC */ + static inline void set_timeout(coap_tick_t *timer, const unsigned int seconds) { coap_ticks(timer); *timer += seconds * COAP_TICKS_PER_SECOND; } -int +static int append_to_output(const unsigned char *data, size_t len) { size_t written; if (!file) { - if (!output_file.s || (output_file.length && output_file.s[0] == '-')) + if (!output_file.s || (output_file.length && output_file.s[0] == '-')) file = stdout; else { if (!(file = fopen((char *)output_file.s, "w"))) { @@ -91,12 +98,12 @@ append_to_output(const unsigned char *data, size_t len) { return 0; } -void -close_output() { +static void +close_output(void) { if (file) { /* add a newline before closing in case were writing to stdout */ - if (!output_file.s || (output_file.length && output_file.s[0] == '-')) + if (!output_file.s || (output_file.length && output_file.s[0] == '-')) fwrite("\n", 1, 1, file); fflush(file); @@ -104,31 +111,24 @@ close_output() { } } -coap_pdu_t * -new_ack( coap_context_t *ctx, coap_queue_t *node ) { - coap_pdu_t *pdu = coap_new_pdu(); - - if (pdu) { - pdu->hdr->type = COAP_MESSAGE_ACK; - pdu->hdr->code = 0; - pdu->hdr->id = node->pdu->hdr->id; - } - - return pdu; -} +static int +order_opts(void *a, void *b) { + coap_option *o1, *o2; -coap_pdu_t * -new_response( coap_context_t *ctx, coap_queue_t *node, unsigned int code ) { - coap_pdu_t *pdu = new_ack(ctx, node); + if (!a || !b) + return a < b ? -1 : 1; - if (pdu) - pdu->hdr->code = code; + o1 = (coap_option *)(((coap_list_t *)a)->data); + o2 = (coap_option *)(((coap_list_t *)b)->data); - return pdu; + return (COAP_OPTION_KEY(*o1) < COAP_OPTION_KEY(*o2)) + ? -1 + : (COAP_OPTION_KEY(*o1) != COAP_OPTION_KEY(*o2)); } -coap_pdu_t * -coap_new_request(coap_context_t *ctx, method_t m, coap_list_t *options ) { +static coap_pdu_t * +coap_new_request(coap_context_t *ctx, method_t m, coap_list_t **options, + unsigned char *data, size_t length) { coap_pdu_t *pdu; coap_list_t *opt; @@ -146,24 +146,32 @@ coap_new_request(coap_context_t *ctx, method_t m, coap_list_t *options ) { coap_show_pdu(pdu); - for (opt = options; opt; opt = opt->next) { - coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option *)opt->data), - COAP_OPTION_LENGTH(*(coap_option *)opt->data), - COAP_OPTION_DATA(*(coap_option *)opt->data)); + if (options) { + /* sort options for delta encoding */ + LL_SORT((*options), order_opts); + + LL_FOREACH((*options), opt) { + coap_option *o = (coap_option *)(opt->data); + coap_add_option(pdu, COAP_OPTION_KEY(*o), + COAP_OPTION_LENGTH(*o), + COAP_OPTION_DATA(*o)); + } } - if (payload.length) { + if (length) { if ((flags & FLAGS_BLOCK) == 0) - coap_add_data(pdu, payload.length, payload.s); + coap_add_data(pdu, length, data); else - coap_add_block(pdu, payload.length, payload.s, block.num, block.szx); + coap_add_block(pdu, length, data, block.num, block.szx); } return pdu; } -coap_tid_t -clear_obs(coap_context_t *ctx, const coap_address_t *remote) { +static coap_tid_t +clear_obs(coap_context_t *ctx, + const coap_endpoint_t *local_interface, + const coap_address_t *remote) { coap_pdu_t *pdu; coap_list_t *option; coap_tid_t tid = COAP_INVALID_TID; @@ -179,16 +187,16 @@ clear_obs(coap_context_t *ctx, const coap_address_t *remote) { } if (!coap_add_token(pdu, the_token.length, the_token.s)) { - error("cannot add token"); + coap_log(LOG_CRIT, "cannot add token"); goto error; } for (option = optlist; option; option = option->next ) { - if (COAP_OPTION_KEY(*(coap_option *)option->data) - == COAP_OPTION_URI_HOST) { - if (!coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option *)option->data), - COAP_OPTION_LENGTH(*(coap_option *)option->data), - COAP_OPTION_DATA(*(coap_option *)option->data))) { + coap_option *o = (coap_option *)(option->data); + if (COAP_OPTION_KEY(*o) == COAP_OPTION_URI_HOST) { + if (!coap_add_option(pdu, COAP_OPTION_KEY(*o), + COAP_OPTION_LENGTH(*o), + COAP_OPTION_DATA(*o))) { goto error; } break; @@ -198,22 +206,23 @@ clear_obs(coap_context_t *ctx, const coap_address_t *remote) { if (!coap_add_option(pdu, COAP_OPTION_OBSERVE, coap_encode_var_bytes(buf, COAP_OBSERVE_CANCEL), buf)) { - error("cannot add option Observe: %u", COAP_OBSERVE_CANCEL); + coap_log(LOG_CRIT, "cannot add option Observe: %u", COAP_OBSERVE_CANCEL); goto error; } for (option = optlist; option; option = option->next ) { - switch (COAP_OPTION_KEY(*(coap_option *)option->data)) { + coap_option *o = (coap_option *)(option->data); + switch (COAP_OPTION_KEY(*o)) { case COAP_OPTION_URI_PORT : case COAP_OPTION_URI_PATH : case COAP_OPTION_URI_QUERY : - if (!coap_add_option (pdu, COAP_OPTION_KEY(*(coap_option *)option->data), - COAP_OPTION_LENGTH(*(coap_option *)option->data), - COAP_OPTION_DATA(*(coap_option *)option->data))) { + if (!coap_add_option (pdu, COAP_OPTION_KEY(*o), + COAP_OPTION_LENGTH(*o), + COAP_OPTION_DATA(*o))) { goto error; } break; - default: + default: ; } } @@ -221,10 +230,10 @@ clear_obs(coap_context_t *ctx, const coap_address_t *remote) { coap_show_pdu(pdu); if (pdu->hdr->type == COAP_MESSAGE_CON) - tid = coap_send_confirmed(ctx, remote, pdu); - else - tid = coap_send(ctx, remote, pdu); - + tid = coap_send_confirmed(ctx, local_interface, remote, pdu); + else + tid = coap_send(ctx, local_interface, remote, pdu); + if (tid == COAP_INVALID_TID) { debug("clear_obs: error sending new request"); coap_delete_pdu(pdu); @@ -238,9 +247,9 @@ clear_obs(coap_context_t *ctx, const coap_address_t *remote) { return tid; } -int +static int resolve_address(const str *server, struct sockaddr *dst) { - + struct addrinfo *res, *ainfo; struct addrinfo hints; static char addrstr[256]; @@ -280,38 +289,25 @@ resolve_address(const str *server, struct sockaddr *dst) { return len; } -static inline coap_opt_t * -get_block(coap_pdu_t *pdu, coap_opt_iterator_t *opt_iter) { - coap_opt_filter_t f; - - assert(pdu); - - memset(f, 0, sizeof(coap_opt_filter_t)); - coap_option_setb(f, COAP_OPTION_BLOCK1); - coap_option_setb(f, COAP_OPTION_BLOCK2); - - coap_option_iterator_init(pdu, opt_iter, f); - return coap_option_next(opt_iter); -} - #define HANDLE_BLOCK1(Pdu) \ ((method == COAP_REQUEST_PUT || method == COAP_REQUEST_POST) && \ ((flags & FLAGS_BLOCK) == 0) && \ ((Pdu)->hdr->code == COAP_RESPONSE_CODE(201) || \ (Pdu)->hdr->code == COAP_RESPONSE_CODE(204))) -inline int +static inline int check_token(coap_pdu_t *received) { return received->hdr->token_length == the_token.length && memcmp(received->hdr->token, the_token.s, the_token.length) == 0; } -void -message_handler(struct coap_context_t *ctx, - const coap_address_t *remote, +static void +message_handler(struct coap_context_t *ctx, + const coap_endpoint_t *local_interface, + const coap_address_t *remote, coap_pdu_t *sent, coap_pdu_t *received, - const coap_tid_t id) { + const coap_tid_t id UNUSED_PARAM) { coap_pdu_t *pdu = NULL; coap_opt_t *block_opt; @@ -322,19 +318,20 @@ message_handler(struct coap_context_t *ctx, unsigned char *databuf; coap_tid_t tid; - if (LOG_DEBUG <= LOG.severity) { +#ifndef NDEBUG + if (LOG_DEBUG <= coap_get_log_level()) { debug("** process incoming %d.%02d response:\n", (received->hdr->code >> 5), received->hdr->code & 0x1F); coap_show_pdu(received); } - +#endif /* check if this is a response to our original request */ if (!check_token(received)) { /* drop if this was just some message, or send RST in case of notification */ - if (!sent && (received->hdr->type == COAP_MESSAGE_CON || + if (!sent && (received->hdr->type == COAP_MESSAGE_CON || received->hdr->type == COAP_MESSAGE_NON)) - coap_send_rst(ctx, remote, received); + coap_send_rst(ctx, local_interface, remote, received); return; } @@ -344,46 +341,43 @@ message_handler(struct coap_context_t *ctx, } /* output the received data, if any */ - if (received->hdr->code == COAP_RESPONSE_CODE(205)) { + if (COAP_RESPONSE_CLASS(received->hdr->code) == 2) { /* set obs timer if we have successfully subscribed a resource */ if (sent && coap_check_option(received, COAP_OPTION_SUBSCRIPTION, &opt_iter)) { debug("observation relationship established, set timeout to %d\n", obs_seconds); set_timeout(&obs_wait, obs_seconds); } - + /* Got some data, check if block option is set. Behavior is undefined if * both, Block1 and Block2 are present. */ - block_opt = get_block(received, &opt_iter); - if (!block_opt) { - /* There is no block option set, just read the data and we are done. */ - if (coap_get_data(received, &len, &databuf)) - append_to_output(databuf, len); - } else { + block_opt = coap_check_option(received, COAP_OPTION_BLOCK2, &opt_iter); + if (block_opt) { /* handle Block2 */ unsigned short blktype = opt_iter.type; /* TODO: check if we are looking at the correct block number */ if (coap_get_data(received, &len, &databuf)) append_to_output(databuf, len); - if (COAP_OPT_BLOCK_MORE(block_opt)) { + if(COAP_OPT_BLOCK_MORE(block_opt)) { /* more bit is set */ debug("found the M bit, block size is %u, block nr. %u\n", COAP_OPT_BLOCK_SZX(block_opt), coap_opt_block_num(block_opt)); /* create pdu with request for next block */ - pdu = coap_new_request(ctx, method, NULL); /* first, create bare PDU w/o any option */ + pdu = coap_new_request(ctx, method, NULL, NULL, 0); /* first, create bare PDU w/o any option */ if ( pdu ) { /* add URI components from optlist */ for (option = optlist; option; option = option->next ) { - switch (COAP_OPTION_KEY(*(coap_option *)option->data)) { + coap_option *o = (coap_option *)(option->data); + switch (COAP_OPTION_KEY(*o)) { case COAP_OPTION_URI_HOST : case COAP_OPTION_URI_PORT : case COAP_OPTION_URI_PATH : case COAP_OPTION_URI_QUERY : - coap_add_option ( pdu, COAP_OPTION_KEY(*(coap_option *)option->data), - COAP_OPTION_LENGTH(*(coap_option *)option->data), - COAP_OPTION_DATA(*(coap_option *)option->data) ); + coap_add_option (pdu, COAP_OPTION_KEY(*o), + COAP_OPTION_LENGTH(*o), + COAP_OPTION_DATA(*o)); break; default: ; /* skip other options */ @@ -393,33 +387,103 @@ message_handler(struct coap_context_t *ctx, /* finally add updated block option from response, clear M bit */ /* blocknr = (blocknr & 0xfffffff7) + 0x10; */ debug("query block %d\n", (coap_opt_block_num(block_opt) + 1)); - coap_add_option(pdu, blktype, coap_encode_var_bytes(buf, - ((coap_opt_block_num(block_opt) + 1) << 4) | + coap_add_option(pdu, blktype, coap_encode_var_bytes(buf, + ((coap_opt_block_num(block_opt) + 1) << 4) | COAP_OPT_BLOCK_SZX(block_opt)), buf); - if (received->hdr->type == COAP_MESSAGE_CON) - tid = coap_send_confirmed(ctx, remote, pdu); - else - tid = coap_send(ctx, remote, pdu); + if (pdu->hdr->type == COAP_MESSAGE_CON) + tid = coap_send_confirmed(ctx, local_interface, remote, pdu); + else + tid = coap_send(ctx, local_interface, remote, pdu); + + if (tid == COAP_INVALID_TID) { + debug("message_handler: error sending new request"); + coap_delete_pdu(pdu); + } else { + set_timeout(&max_wait, wait_seconds); + if (pdu->hdr->type != COAP_MESSAGE_CON) + coap_delete_pdu(pdu); + } + + return; + } + } + } else { /* no Block2 option */ + block_opt = coap_check_option(received, COAP_OPTION_BLOCK1, &opt_iter); + + if (block_opt) { /* handle Block1 */ + block.szx = COAP_OPT_BLOCK_SZX(block_opt); + block.num = coap_opt_block_num(block_opt); + + debug("found Block1, block size is %u, block nr. %u\n", + block.szx, block.num); + + if (payload.length <= (block.num+1) * (1 << (block.szx + 4))) { + debug("upload ready\n"); + ready = 1; + return; + } + + /* create pdu with request for next block */ + pdu = coap_new_request(ctx, method, NULL, NULL, 0); /* first, create bare PDU w/o any option */ + if (pdu) { + + /* add URI components from optlist */ + for (option = optlist; option; option = option->next ) { + coap_option *o = (coap_option *)(option->data); + switch (COAP_OPTION_KEY(*o)) { + 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 : + coap_add_option (pdu, COAP_OPTION_KEY(*o), + COAP_OPTION_LENGTH(*o), + COAP_OPTION_DATA(*o)); + break; + default: + ; /* skip other options */ + } + } + + /* finally add updated block option from response, clear M bit */ + /* blocknr = (blocknr & 0xfffffff7) + 0x10; */ + block.num++; + block.m = ((block.num+1) * (1 << (block.szx + 4)) < payload.length); + + debug("send block %d\n", block.num); + coap_add_option(pdu, COAP_OPTION_BLOCK1, coap_encode_var_bytes(buf, + (block.num << 4) | (block.m << 3) | block.szx), buf); + + coap_add_block(pdu, payload.length, payload.s, block.num, block.szx); + coap_show_pdu(pdu); + if (pdu->hdr->type == COAP_MESSAGE_CON) + tid = coap_send_confirmed(ctx, local_interface, remote, pdu); + else + tid = coap_send(ctx, local_interface, remote, pdu); if (tid == COAP_INVALID_TID) { debug("message_handler: error sending new request"); coap_delete_pdu(pdu); } else { set_timeout(&max_wait, wait_seconds); - if (received->hdr->type != COAP_MESSAGE_CON) + if (pdu->hdr->type != COAP_MESSAGE_CON) coap_delete_pdu(pdu); } return; } + } else { + /* There is no block option set, just read the data and we are done. */ + if (coap_get_data(received, &len, &databuf)) + append_to_output(databuf, len); } } } else { /* no 2.05 */ /* check if an error was signaled and output payload if so */ if (COAP_RESPONSE_CLASS(received->hdr->code) >= 4) { - fprintf(stderr, "%d.%02d", + fprintf(stderr, "%d.%02d", (received->hdr->code >> 5), received->hdr->code & 0x1F); if (coap_get_data(received, &len, &databuf)) { fprintf(stderr, " "); @@ -428,11 +492,11 @@ message_handler(struct coap_context_t *ctx, } fprintf(stderr, "\n"); } - + } /* finally send new request, if needed */ - if (pdu && coap_send(ctx, remote, pdu) == COAP_INVALID_TID) { + if (pdu && coap_send(ctx, local_interface, remote, pdu) == COAP_INVALID_TID) { debug("message_handler: error sending response"); } coap_delete_pdu(pdu); @@ -441,7 +505,7 @@ message_handler(struct coap_context_t *ctx, ready = coap_check_option(received, COAP_OPTION_SUBSCRIPTION, &opt_iter) == NULL; } -void +static void usage( const char *program, const char *version) { const char *p; @@ -450,11 +514,12 @@ usage( const char *program, const char *version) { program = ++p; fprintf( stderr, "%s v%s -- a small CoAP implementation\n" - "(c) 2010-2013 Olaf Bergmann \n\n" + "(c) 2010-2015 Olaf Bergmann \n\n" "usage: %s [-A type...] [-t type] [-b [num,]size] [-B seconds] [-e text]\n" "\t\t[-g group] [-m method] [-N] [-o file] [-P addr[:port]] [-p port]\n" - "\t\t[-s duration] [-O num,text] [-T string] [-v num] URI\n\n" + "\t\t[-s duration] [-O num,text] [-T string] [-v num] [-a addr] URI\n\n" "\tURI can be an absolute or relative coap URI,\n" + "\t-a addr\tthe local interface address to use\n" "\t-A type...\taccepted media types as comma-separated list of\n" "\t\t\tsymbolic or numeric values\n" "\t-t type\t\tcontent type for given resource for PUT/POST\n" @@ -487,7 +552,7 @@ usage( const char *program, const char *version) { ,program, version, program, wait_seconds); } -int +static int join( coap_context_t *ctx, char *group_name ){ struct ipv6_mreq mreq; struct addrinfo *reslocal = NULL, *resmulti = NULL, hints, *ainfo; @@ -500,7 +565,7 @@ join( coap_context_t *ctx, char *group_name ){ result = getaddrinfo("::", NULL, &hints, &reslocal); if ( result < 0 ) { - fprintf(stderr, "join: cannot resolve link-local interface: %s\n", + fprintf(stderr, "join: cannot resolve link-local interface: %s\n", gai_strerror(result)); goto finish; } @@ -522,7 +587,7 @@ join( coap_context_t *ctx, char *group_name ){ result = getaddrinfo(group_name, NULL, &hints, &resmulti); if ( result < 0 ) { - fprintf(stderr, "join: cannot resolve multicast address: %s\n", + fprintf(stderr, "join: cannot resolve multicast address: %s\n", gai_strerror(result)); goto finish; } @@ -547,49 +612,31 @@ join( coap_context_t *ctx, char *group_name ){ return result; } -int -order_opts(void *a, void *b) { - if (!a || !b) - return a < b ? -1 : 1; - - if (COAP_OPTION_KEY(*(coap_option *)a) < COAP_OPTION_KEY(*(coap_option *)b)) - return -1; - - return COAP_OPTION_KEY(*(coap_option *)a) == COAP_OPTION_KEY(*(coap_option *)b); -} - - -coap_list_t * +static coap_list_t * new_option_node(unsigned short key, unsigned int length, unsigned char *data) { - coap_option *option; coap_list_t *node; - option = coap_malloc(sizeof(coap_option) + length); - if ( !option ) - goto error; - - COAP_OPTION_KEY(*option) = key; - COAP_OPTION_LENGTH(*option) = length; - memcpy(COAP_OPTION_DATA(*option), data, length); - - /* we can pass NULL here as delete function since option is released automatically */ - node = coap_new_listnode(option, NULL); + node = coap_malloc(sizeof(coap_list_t) + sizeof(coap_option) + length); - if ( node ) - return node; + if (node) { + coap_option *option; + option = (coap_option *)(node->data); + COAP_OPTION_KEY(*option) = key; + COAP_OPTION_LENGTH(*option) = length; + memcpy(COAP_OPTION_DATA(*option), data, length); + } else { + coap_log(LOG_DEBUG, "new_option_node: malloc\n"); + } - error: - perror("new_option_node: malloc"); - coap_free( option ); - return NULL; + return node; } -typedef struct { +typedef struct { unsigned char code; char *media_type; } content_type_t; -void +static void cmdline_content_type(char *arg, unsigned short key) { static content_type_t content_types[] = { { 0, "plain" }, @@ -622,10 +669,10 @@ cmdline_content_type(char *arg, unsigned short key) { value[valcnt++] = atoi(q); } else { for (i=0; content_types[i].media_type && - strncmp(q,content_types[i].media_type, p ? p-q : strlen(q)) != 0 ; + strncmp(q,content_types[i].media_type, p ? (size_t)(p-q) : strlen(q)) != 0 ; ++i) ; - + if (content_types[i].media_type) { value[valcnt] = content_types[i].code; valcnt++; @@ -636,18 +683,19 @@ cmdline_content_type(char *arg, unsigned short key) { if (!p || key == COAP_OPTION_CONTENT_TYPE) break; - + q = p+1; } for (i = 0; i < valcnt; ++i) { node = new_option_node(key, coap_encode_var_bytes(buf, value[i]), buf); - if (node) - coap_insert( &optlist, node, order_opts ); + if (node) { + LL_PREPEND(optlist, node); + } } } -void +static void cmdline_uri(char *arg) { unsigned char portbuf[2]; #define BUFSIZE 40 @@ -659,27 +707,24 @@ cmdline_uri(char *arg) { if (proxy.length) { /* create Proxy-Uri from argument */ size_t len = strlen(arg); while (len > 270) { - coap_insert(&optlist, - new_option_node(COAP_OPTION_PROXY_URI, - 270, (unsigned char *)arg), - order_opts); + coap_insert(&optlist, new_option_node(COAP_OPTION_PROXY_URI, + 270, (unsigned char *)arg)); + len -= 270; arg += 270; } - coap_insert(&optlist, - new_option_node(COAP_OPTION_PROXY_URI, - len, (unsigned char *)arg), - order_opts); + coap_insert(&optlist, new_option_node(COAP_OPTION_PROXY_URI, + len, (unsigned char *)arg)); + } else { /* split arg into Uri-* options */ coap_split_uri((unsigned char *)arg, strlen(arg), &uri ); if (uri.port != COAP_DEFAULT_PORT) { - coap_insert( &optlist, - new_option_node(COAP_OPTION_URI_PORT, - coap_encode_var_bytes(portbuf, uri.port), - portbuf), - order_opts); + coap_insert(&optlist, + new_option_node(COAP_OPTION_URI_PORT, + coap_encode_var_bytes(portbuf, uri.port), + portbuf)); } if (uri.path.length) { @@ -689,10 +734,9 @@ cmdline_uri(char *arg) { while (res--) { coap_insert(&optlist, new_option_node(COAP_OPTION_URI_PATH, COAP_OPT_LENGTH(buf), - COAP_OPT_VALUE(buf)), - order_opts); + COAP_OPT_VALUE(buf))); - buf += COAP_OPT_SIZE(buf); + buf += COAP_OPT_SIZE(buf); } } @@ -704,16 +748,15 @@ cmdline_uri(char *arg) { while (res--) { coap_insert(&optlist, new_option_node(COAP_OPTION_URI_QUERY, COAP_OPT_LENGTH(buf), - COAP_OPT_VALUE(buf)), - order_opts); + COAP_OPT_VALUE(buf))); - buf += COAP_OPT_SIZE(buf); + buf += COAP_OPT_SIZE(buf); } } } } -int +static int cmdline_blocksize(char *arg) { unsigned short size; @@ -721,13 +764,13 @@ cmdline_blocksize(char *arg) { size = 0; while(*arg && *arg != ',') size = size * 10 + (*arg++ - '0'); - + if (*arg == ',') { arg++; block.num = size; goto again; } - + if (size) block.szx = (coap_fls(size >> 4) - 1) & 0x07; @@ -735,30 +778,34 @@ cmdline_blocksize(char *arg) { return 1; } -/* Called after processing the options from the commandline to set +/* Called after processing the options from the commandline to set * Block1 or Block2 depending on method. */ -void -set_blocksize() { +static void +set_blocksize(void) { static unsigned char buf[4]; /* hack: temporarily take encoded bytes */ unsigned short opt; + unsigned int opt_length; if (method != COAP_REQUEST_DELETE) { opt = method == COAP_REQUEST_GET ? COAP_OPTION_BLOCK2 : COAP_OPTION_BLOCK1; - coap_insert(&optlist, new_option_node(opt, - coap_encode_var_bytes(buf, (block.num << 4 | block.szx)), buf), - order_opts); + block.m = (opt == COAP_OPTION_BLOCK1) && + ((1u << (block.szx + 4)) < payload.length); + + opt_length = coap_encode_var_bytes(buf, + (block.num << 4 | block.m << 3 | block.szx)); + + coap_insert(&optlist, new_option_node(opt, opt_length, buf)); } } -void -cmdline_subscribe(char *arg) { +static void +cmdline_subscribe(char *arg UNUSED_PARAM) { obs_seconds = atoi(optarg); - coap_insert(&optlist, new_option_node(COAP_OPTION_SUBSCRIPTION, 0, NULL), - order_opts); + coap_insert(&optlist, new_option_node(COAP_OPTION_SUBSCRIPTION, 0, NULL)); } -int +static int cmdline_proxy(char *arg) { char *proxy_port_str = strrchr((const char *)arg, ':'); /* explicit port ? */ if (proxy_port_str) { @@ -791,13 +838,13 @@ cmdline_proxy(char *arg) { return 1; } -inline void +static inline void cmdline_token(char *arg) { strncpy((char *)the_token.s, arg, min(sizeof(_token_data), strlen(arg))); the_token.length = strlen(arg); } -void +static void cmdline_option(char *arg) { unsigned int num = 0; @@ -808,15 +855,74 @@ cmdline_option(char *arg) { if (*arg == ',') ++arg; - coap_insert( &optlist, new_option_node(num, - strlen(arg), - (unsigned char *)arg), order_opts); + coap_insert(&optlist, + new_option_node(num, strlen(arg), (unsigned char *)arg)); +} + +/** + * Calculates decimal value from hexadecimal ASCII character given in + * @p c. The caller must ensure that @p c actually represents a valid + * heaxdecimal character, e.g. with isxdigit(3). + * + * @hideinitializer + */ +#define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F)) + +/** + * Decodes percent-encoded characters while copying the string @p seg + * of size @p length to @p buf. The caller of this function must + * ensure that the percent-encodings are correct (i.e. the character + * '%' is always followed by two hex digits. and that @p buf provides + * sufficient space to hold the result. This function is supposed to + * be called by make_decoded_option() only. + * + * @param seg The segment to decode and copy. + * @param length Length of @p seg. + * @param buf The result buffer. + */ +static void +decode_segment(const unsigned char *seg, size_t length, unsigned char *buf) { + + while (length--) { + + if (*seg == '%') { + *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]); + + seg += 2; length -= 2; + } else { + *buf = *seg; + } + + ++buf; ++seg; + } } -extern int check_segment(const unsigned char *s, size_t length); -extern void decode_segment(const unsigned char *seg, size_t length, unsigned char *buf); +/** + * Runs through the given path (or query) segment and checks if + * percent-encodings are correct. This function returns @c -1 on error + * or the length of @p s when decoded. + */ +static int +check_segment(const unsigned char *s, size_t length) { -int + size_t n = 0; + + while (length) { + if (*s == '%') { + if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2]))) + return -1; + + s += 2; + length -= 2; + } + + ++s; ++n; --length; + } + + return n; +} + +static int cmdline_input(char *text, str *buf) { int len; len = check_segment((unsigned char *)text, strlen(text)); @@ -833,7 +939,7 @@ cmdline_input(char *text, str *buf) { return 1; } -int +static int cmdline_input_from_file(char *filename, str *buf) { FILE *inputfile = NULL; ssize_t len; @@ -872,7 +978,7 @@ cmdline_input_from_file(char *filename, str *buf) { len = fread(buf->s, 1, buf->length, inputfile); - if (len < buf->length) { + if (len < 0 || ((size_t)len < buf->length)) { if (ferror(inputfile) != 0) { perror("cmdline_input_from_file: fread"); coap_free(buf->s); @@ -890,7 +996,7 @@ cmdline_input_from_file(char *filename, str *buf) { return result; } -method_t +static method_t cmdline_method(char *arg) { static char *methods[] = { 0, "get", "post", "put", "delete", 0}; @@ -902,9 +1008,9 @@ cmdline_method(char *arg) { return i; /* note that we do not prevent illegal methods */ } -coap_context_t * +static coap_context_t * get_context(const char *node, const char *port) { - coap_context_t *ctx = NULL; + coap_context_t *ctx = NULL; int s; struct addrinfo hints; struct addrinfo *result, *rp; @@ -913,12 +1019,12 @@ get_context(const char *node, const char *port) { hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_DGRAM; /* Coap uses UDP */ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV | AI_ALL; - + s = getaddrinfo(node, port, &hints, &result); if ( s != 0 ) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); return NULL; - } + } /* iterate through results until success */ for (rp = result; rp != NULL; rp = rp->ai_next) { @@ -936,7 +1042,7 @@ get_context(const char *node, const char *port) { } } } - + fprintf(stderr, "no context available for interface '%s'\n", node); finish: @@ -959,21 +1065,27 @@ main(int argc, char **argv) { static str server; unsigned short port = COAP_DEFAULT_PORT; char port_str[NI_MAXSERV] = "0"; + char node_str[NI_MAXHOST] = ""; int opt, res; char *group = NULL; + coap_log_t log_level = LOG_WARNING; coap_tid_t tid = COAP_INVALID_TID; - while ((opt = getopt(argc, argv, "Nb:e:f:g:m:p:s:t:o:v:A:B:O:P:T:")) != -1) { + while ((opt = getopt(argc, argv, "Na:b:e:f:g:m:p:s:t:o:v:A:B:O:P:T:")) != -1) { switch (opt) { + case 'a' : + strncpy(node_str, optarg, NI_MAXHOST-1); + node_str[NI_MAXHOST - 1] = '\0'; + break; case 'b' : cmdline_blocksize(optarg); break; case 'B' : wait_seconds = atoi(optarg); break; - case 'e' : + case 'e' : if (!cmdline_input(optarg,&payload)) - payload.length = 0; + payload.length = 0; break; case 'f' : if (!cmdline_input_from_file(optarg,&payload)) @@ -998,7 +1110,7 @@ main(int argc, char **argv) { case 'o' : output_file.length = strlen(optarg); output_file.s = (unsigned char *)coap_malloc(output_file.length + 1); - + if (!output_file.s) { fprintf(stderr, "cannot set output file: insufficient memory\n"); exit(-1); @@ -1063,26 +1175,26 @@ main(int argc, char **argv) { dst.addr.sin.sin_port = htons(port); /* add Uri-Host if server address differs from uri.host */ - + switch (dst.addr.sa.sa_family) { - case AF_INET: + case AF_INET: addrptr = &dst.addr.sin.sin_addr; /* create context for IPv4 */ - ctx = get_context("0.0.0.0", port_str); + ctx = get_context(node_str[0] == 0 ? "0.0.0.0" : node_str, port_str); break; case AF_INET6: addrptr = &dst.addr.sin6.sin6_addr; /* create context for IPv6 */ - ctx = get_context("::", port_str); + ctx = get_context(node_str[0] == 0 ? "::" : node_str, port_str); break; default: ; } if (!ctx) { - fatal("cannot create context\n"); + coap_log(LOG_EMERG, "cannot create context\n"); return -1; } @@ -1097,31 +1209,32 @@ main(int argc, char **argv) { if (!proxy.length && addrptr && (inet_ntop(dst.addr.sa.sa_family, addrptr, addr, sizeof(addr)) != 0) - && (strlen(addr) != uri.host.length + && (strlen(addr) != uri.host.length || memcmp(addr, uri.host.s, uri.host.length) != 0)) { /* add Uri-Host */ coap_insert(&optlist, new_option_node(COAP_OPTION_URI_HOST, - uri.host.length, uri.host.s), - order_opts); + uri.host.length, uri.host.s)); } /* set block option if requested at commandline */ if (flags & FLAGS_BLOCK) set_blocksize(); - if (! (pdu = coap_new_request(ctx, method, optlist))) + if (! (pdu = coap_new_request(ctx, method, &optlist, payload.s, payload.length))) return -1; - if (LOG_DEBUG <= LOG.severity) { +#ifndef NDEBUG + if (LOG_DEBUG <= coap_get_log_level()) { debug("sending CoAP request:\n"); coap_show_pdu(pdu); } +#endif if (pdu->hdr->type == COAP_MESSAGE_CON) - tid = coap_send_confirmed(ctx, &dst, pdu); - else - tid = coap_send(ctx, &dst, pdu); + tid = coap_send_confirmed(ctx, ctx->endpoint, &dst, pdu); + else + tid = coap_send(ctx, ctx->endpoint, &dst, pdu); if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID) coap_delete_pdu(pdu); @@ -1141,7 +1254,7 @@ main(int argc, char **argv) { nextpdu = coap_peek_next( ctx ); } - if (nextpdu && nextpdu->t < min(obs_wait ? obs_wait : max_wait, max_wait) - now) { + if (nextpdu && nextpdu->t < min(obs_wait ? obs_wait : max_wait, max_wait) - now) { /* set timeout if there is a pdu to send */ tv.tv_usec = ((nextpdu->t) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND; tv.tv_sec = (nextpdu->t) / COAP_TICKS_PER_SECOND; @@ -1149,7 +1262,7 @@ main(int argc, char **argv) { /* check if obs_wait fires before max_wait */ if (obs_wait && obs_wait < max_wait) { tv.tv_usec = ((obs_wait - now) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND; - tv.tv_sec = (obs_wait - now) / COAP_TICKS_PER_SECOND; + tv.tv_sec = (obs_wait - now) / COAP_TICKS_PER_SECOND; } else { tv.tv_usec = ((max_wait - now) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND; tv.tv_sec = (max_wait - now) / COAP_TICKS_PER_SECOND; @@ -1163,27 +1276,28 @@ main(int argc, char **argv) { } else if ( result > 0 ) { /* read from socket */ if ( FD_ISSET( ctx->sockfd, &readfds ) ) { coap_read( ctx ); /* read received data */ - coap_dispatch( ctx ); /* and dispatch PDUs from receivequeue */ + /* coap_dispatch( ctx ); /\* and dispatch PDUs from receivequeue *\/ */ } } else { /* timeout */ coap_ticks(&now); if (max_wait <= now) { info("timeout\n"); break; - } + } if (obs_wait && obs_wait <= now) { debug("clear observation relationship\n"); - clear_obs(ctx, &dst); /* FIXME: handle error case COAP_TID_INVALID */ + clear_obs(ctx, ctx->endpoint, &dst); /* FIXME: handle error case COAP_TID_INVALID */ /* make sure that the obs timer does not fire again */ - obs_wait = 0; + obs_wait = 0; obs_seconds = 0; - } + } } } close_output(); + coap_delete_list(optlist); coap_free_context( ctx ); return 0; diff --git a/examples/coap_list.c b/examples/coap_list.c new file mode 100644 index 0000000000..6967281250 --- /dev/null +++ b/examples/coap_list.c @@ -0,0 +1,51 @@ +/* coap_list.c -- CoAP list structures + * + * Copyright (C) 2010,2011,2015 Olaf Bergmann + * + * This file is part of the CoAP library libcoap. Please see + * README for terms of use. + */ + +/* #include "coap_config.h" */ + +#include +#include + +#include "debug.h" +#include "mem.h" +#include "coap_list.h" + + +int +coap_insert(coap_list_t **head, coap_list_t *node) { + if (!node) { + coap_log(LOG_WARNING, "cannot create option Proxy-Uri\n"); + } else { + /* must append at the list end to avoid re-ordering of + * options during sort */ + LL_APPEND((*head), node); + } + + return node != NULL; +} + +int +coap_delete(coap_list_t *node) { + if (node) { + coap_free(node); + } + return 1; +} + +void +coap_delete_list(coap_list_t *queue) { + coap_list_t *elt, *tmp; + + if (!queue) + return; + + LL_FOREACH_SAFE(queue, elt, tmp) { + coap_delete(elt); + } +} + diff --git a/examples/coap_list.h b/examples/coap_list.h new file mode 100644 index 0000000000..293c2309a7 --- /dev/null +++ b/examples/coap_list.h @@ -0,0 +1,31 @@ +/* coap_list.h -- CoAP list structures + * + * Copyright (C) 2010,2011,2015 Olaf Bergmann + * + * This file is part of the CoAP library libcoap. Please see + * README for terms of use. + */ + +#ifndef _COAP_LIST_H_ +#define _COAP_LIST_H_ + +#include "utlist.h" + +typedef struct coap_list_t { + struct coap_list_t *next; + char data[]; +} coap_list_t; + +/** + * Adds node to given queue, ordered by specified order function. Returns 1 + * when insert was successful, 0 otherwise. + */ +int coap_insert(coap_list_t **queue, coap_list_t *node); + +/* destroys specified node */ +int coap_delete(coap_list_t *node); + +/* removes all items from given queue and frees the allocated storage */ +void coap_delete_list(coap_list_t *queue); + +#endif /* _COAP_LIST_H_ */ diff --git a/examples/contiki/Makefile.common b/examples/contiki/Makefile.common new file mode 100644 index 0000000000..e8d3fa24e1 --- /dev/null +++ b/examples/contiki/Makefile.common @@ -0,0 +1,36 @@ +top_srcdir ?= ../.. + +# coap library + +CFLAGS += -std=gnu99 + +CFLAGS += -I$(top_srcdir)/include/coap -DCOAP_RESOURCES_NOHASH + +vpath %.c $(top_srcdir)/src + +COAPOBJS = net.o debug.o option.o resource.o hashkey.o pdu.o encode.o subscribe.o coap_io.o block.o uri.o mem.o + +CFLAGS += -I$(CONTIKI)/core/ -I$(CONTIKI)/core/sys/ -I$(CONTIKI)/core/net/ip/ -I$(CONTIKI)/core/lib/ $(PLATFORM_CFLAGS) +CPPFLAGS += $(PLATFORM_CPPFLAGS) + +# making an executable out of all of it + +OBJS = server.o ${CONTIKIOBJS} ${COAPOBJS} + +server: ${OBJS} + +symbols.h: $(CONTIKI)/tools/empty-symbols.h + cp -p $< $@ + +symbols.c: $(CONTIKI)/tools/empty-symbols.c + cp -p $< $@ + +symbols.o: symbols.c symbols.h + +clean: + rm -f core server ${OBJS} symbols.c symbols.h + +distclean: clean + rm -rf *~ *.o contiki + +.PHONY: clean distclean contiki diff --git a/examples/contiki/Makefile.contiki b/examples/contiki/Makefile.contiki new file mode 100644 index 0000000000..7d7cac0c0b --- /dev/null +++ b/examples/contiki/Makefile.contiki @@ -0,0 +1,56 @@ +NODE_ADDR?=0x1000 + +######################################################################## +# platform-specific options + +ifeq ($(TARGET), econotag) +UIP_CONF_IPV6_RPL=0 +CFLAGS += -DUIP_CONF_TCP=0 +endif + +ifeq ($(TARGET), mbxxx) +CFLAGS += -DUIP_CONF_TCP=0 +endif + +ifeq ($(TARGET), minimal-net) +UIP_CONF_IPV6_RPL=0 +CFLAGS += -DUIP_CONF_IPV6_RPL=0 -DRPL_BORDER_ROUTER=0 +endif + +# usually, you should not need changing anything beyond this line +######################################################################## + +all: server + +CONTIKI=../../../.. +#CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\" + +CFLAGS += -DNODE_ADDR=$(NODE_ADDR) -DCOAP_MAX_BLOCK_SZX=1 + +ifeq ($(UIP_CONF_IPV6_RPL),0) +CFLAGS += -DUIP_CONF_IPV6_RPL=0 -DRPL_BORDER_ROUTER=0 -DUIP_CONF_ROUTER=0 +endif + +WITH_UIP6=1 +UIP_CONF_IPV6=1 + +# ifeq ($(TARGET), minimal-net) +# CFLAGS += -DHAVE_ASSERT_H -DWITH_UIP6=1 +# ifneq ($(ROLE),client) +# UIP_LLADDR="{0x00,0x06,0x98,0x00,0x02,0x32}" +# CFLAGS+= -DUIP_CONF_LLADDR=$(UIP_LLADDR) +# else +# UIP_LLADDR="{0x00,0x06,0x98,0x00,0x02,0x30}" +# CFLAGS+= -DUDP_CONNECTION_ADDR="fe80::206:98ff:fe00:232" \ +# -DUIP_CONF_LLADDR=$(UIP_LLADDR) +# endif +# endif + +CFLAGS += -ffunction-sections +LDFLAGS += -Wl,--gc-sections,--undefined=_reset_vector__,--undefined=InterruptVectors,--undefined=_copy_data_init__,--undefined=_clear_bss_init__,--undefined=_end_of_init__ + +CFLAGS += #-DSHORT_ERROR_RESPONSE -DNDEBUG + +APPS += libcoap + +include $(CONTIKI)/Makefile.include diff --git a/examples/contiki/coap-observer.c b/examples/contiki/coap-observer.c new file mode 100644 index 0000000000..6e30d32908 --- /dev/null +++ b/examples/contiki/coap-observer.c @@ -0,0 +1,185 @@ +/* coap-server.c -- Example CoAP server using Contiki and libcoap + * + * Copyright (C) 2011 Olaf Bergmann + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +#include "coap_config.h" +#include "net/uip-debug.h" + +#include + +#include "debug.h" +#include "coap.h" + +static coap_context_t *coap_context; + +/* Where the resource to subscribe is hosted */ +static coap_address_t dst; + +/* The resource to observe */ +static char resource[] = "/s/light"; + +/* when did the last notify arrive? (0 == never) */ +static coap_tick_t last_seen = 0; + +PROCESS(coap_server_process, "CoAP server process"); +AUTOSTART_PROCESSES(&coap_server_process); +/*---------------------------------------------------------------------------*/ +void +init_coap() { + coap_address_t listen_addr; + + coap_address_init(&listen_addr); + listen_addr.port = UIP_HTONS(COAP_DEFAULT_PORT); + +#ifdef WITH_CONTIKI + /* initialize uIP address for SLAAC */ + uip_ip6addr(&listen_addr.addr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0); + uip_ds6_set_addr_iid(&listen_addr.addr, &uip_lladdr); + uip_ds6_addr_add(&listen_addr.addr, 0, ADDR_AUTOCONF); + + uip_debug_lladdr_print(&uip_lladdr); + printf("\r\n"); + uip_debug_ipaddr_print(&listen_addr.addr); + printf("\r\n"); +#endif /* WITH_CONTIKI */ + +#ifdef WITH_CONTIKI + printf("tentative address: [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n", + listen_addr.addr.u8[0], listen_addr.addr.u8[1], + listen_addr.addr.u8[2], listen_addr.addr.u8[3], + listen_addr.addr.u8[4], listen_addr.addr.u8[5], + listen_addr.addr.u8[6], listen_addr.addr.u8[7], + listen_addr.addr.u8[8], listen_addr.addr.u8[9], + listen_addr.addr.u8[10], listen_addr.addr.u8[11], + listen_addr.addr.u8[12], listen_addr.addr.u8[13], + listen_addr.addr.u8[14], listen_addr.addr.u8[15] , + uip_ntohs(listen_addr.port)); +#endif + + coap_context = coap_new_context(&listen_addr); + + coap_set_log_level(LOG_DEBUG); + + if (!coap_context) + coap_log(LOG_CRIT, "cannot create CoAP context\r\n"); +} + +void +message_handler(struct coap_context_t *ctx, + const coap_address_t *remote, + coap_pdu_t *sent, + coap_pdu_t *received, + const coap_tid_t id) { + /* send ACK if received message is confirmable (i.e. a separate response) */ + coap_send_ack(ctx, remote, received); + + debug("** process incoming %d.%02d response:\n", + (received->hdr->code >> 5), received->hdr->code & 0x1F); + coap_show_pdu(received); + + coap_ticks(&last_seen); +} + +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(coap_server_process, ev, data) +{ + coap_pdu_t *request; + coap_uri_t uri; + PROCESS_BEGIN(); + + init_coap(); + + if (!coap_context) { + coap_log(LOG_EMERG, "cannot create context\n"); + PROCESS_EXIT(); + } + + coap_register_response_handler(coap_context, message_handler); + + /* setup subscription request */ + + coap_address_init(&dst); + dst.port = uip_htons(COAP_DEFAULT_PORT); + uip_ip6addr(&dst.addr, 0xaaaa, 0, 0, 0, 0x206, 0x98ff, 0xfe00, 0x232); + /* uip_ip6addr(&dst.addr, 0xfe80, 0, 0, 0, 0x206, 0x98ff, 0xfe00, 0x232); */ + + request = coap_pdu_init(COAP_MESSAGE_CON, COAP_REQUEST_GET, + coap_new_message_id(coap_context), + COAP_MAX_PDU_SIZE); + + coap_split_uri((unsigned char *)resource, strlen(resource), &uri); + + 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); + } + + if (uri.path.length) { +#define BUFSIZE 20 + unsigned char _buf[BUFSIZE]; + unsigned char *buf = _buf; + size_t buflen; + int res; + + buflen = BUFSIZE; +#undef BUFSIZE + res = coap_split_path(uri.path.s, uri.path.length, buf, &buflen); + + while (res--) { + coap_add_option(request, COAP_OPTION_URI_PATH, + COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf)); + + buf += COAP_OPT_SIZE(buf); + } + } + + coap_add_option(request, COAP_OPTION_SUBSCRIPTION, 0, NULL); + { + unsigned char buf[2]; + prng(buf, 2); + coap_add_option(request, COAP_OPTION_TOKEN, 2, buf); + } + + if (COAP_INVALID_TID == coap_send_confirmed(coap_context, &dst, request)) + coap_delete_pdu(request); + + while(1) { + PROCESS_YIELD(); + if(ev == tcpip_event) { + coap_read(coap_context); /* read received data */ + coap_dispatch(coap_context); /* and dispatch PDUs from receivequeue */ + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/contiki/radvd.conf.sample b/examples/contiki/radvd.conf.sample new file mode 100644 index 0000000000..26c218ba47 --- /dev/null +++ b/examples/contiki/radvd.conf.sample @@ -0,0 +1,14 @@ +interface tap0 +{ + AdvSendAdvert on; + MinRtrAdvInterval 3; + MaxRtrAdvInterval 20; + + prefix aaaa::/64 + { + AdvOnLink on; + AdvAutonomous on; + AdvRouterAddr on; + + }; +}; diff --git a/examples/contiki/server.c b/examples/contiki/server.c new file mode 100644 index 0000000000..9779951f92 --- /dev/null +++ b/examples/contiki/server.c @@ -0,0 +1,228 @@ +/* coap-server.c -- Example CoAP server using Contiki and libcoap + * + * Copyright (C) 2011 Olaf Bergmann + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +#include "coap_config.h" +#include "net/ip/uip-debug.h" + +#include + +#include "debug.h" +#include "coap.h" + +static coap_context_t *coap_context; + +static clock_time_t clock_offset; +/* changeable clock base (see handle_put_time()) */ +static clock_time_t my_clock_base = 0; +static coap_resource_t *time_resource = NULL; /* just for testing */ + +PROCESS(coap_server_process, "CoAP server process"); +AUTOSTART_PROCESSES(&coap_server_process); +/*---------------------------------------------------------------------------*/ +void +init_coap_server(coap_context_t **ctx) { + coap_address_t listen_addr; + uip_ipaddr_t gw_addr; + + assert(ctx); + + coap_set_log_level(LOG_DEBUG); + + coap_address_init(&listen_addr); + listen_addr.port = UIP_HTONS(COAP_DEFAULT_PORT); + + uip_ip6addr(&listen_addr.addr, 0xaaaa, 0, 0, 0, 0, 0, 0, NODE_ADDR); +#ifndef CONTIKI_TARGET_MINIMAL_NET + uip_ds6_prefix_add(&listen_addr.addr, 64, 0); +#endif /* not CONTIKI_TARGET_MINIMAL_NET */ + + uip_ds6_addr_add(&listen_addr.addr, 0, ADDR_MANUAL); + + /* set default route to gateway aaaa::1 */ + uip_ip6addr(&gw_addr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0x0001); + uip_ds6_defrt_add(&gw_addr, 0); + + uip_debug_lladdr_print(&uip_lladdr); + printf("\r\n"); + uip_debug_ipaddr_print(&listen_addr.addr); + printf("\r\n"); + + *ctx = coap_new_context(&listen_addr); + + if (!*ctx) { + coap_log(LOG_CRIT, "cannot create CoAP context\r\n"); + } +} + +/*---------------------------------------------------------------------------*/ +#ifndef min +# define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +void +hnd_get_time(coap_context_t *ctx, struct coap_resource_t *resource, + const coap_endpoint_t *local_interface, + coap_address_t *peer, coap_pdu_t *request, str *token, + coap_pdu_t *response) { + coap_opt_iterator_t opt_iter; + coap_opt_t *option; + unsigned char buf[40]; + size_t len; + coap_tick_t now; + coap_tick_t t; + + /* FIXME: return time, e.g. in human-readable by default and ticks + * when query ?ticks is given. */ + + /* if my_clock_base was deleted, we pretend to have no such resource */ + response->hdr->code = + my_clock_base ? COAP_RESPONSE_CODE(205) : COAP_RESPONSE_CODE(404); + + if (coap_find_observer(resource, peer, token)) { + /* FIXME: need to check for resource->dirty? */ + coap_add_option(response, COAP_OPTION_OBSERVE, + coap_encode_var_bytes(buf, ctx->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_add_option(response, COAP_OPTION_MAXAGE, + coap_encode_var_bytes(buf, 0x01), buf); + + if (my_clock_base) { + + /* calculate current time */ + coap_ticks(&t); + now = my_clock_base + (t / COAP_TICKS_PER_SECOND); + + if (request != NULL + && (option = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter)) + && memcmp(COAP_OPT_VALUE(option), "ticks", + min(5, COAP_OPT_LENGTH(option))) == 0) { + /* output ticks */ + len = snprintf((char *)buf, + min(sizeof(buf), response->max_size - response->length), + "%u", (unsigned int)now); + coap_add_data(response, len, buf); + + } + } +} + +void +init_coap_resources(coap_context_t *ctx) { + coap_resource_t *r; +#if 0 + 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_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); + if (!r) + goto error; + + r->observable = 1; + time_resource = r; + coap_register_handler(r, COAP_REQUEST_GET, hnd_get_time); +#if 0 + 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_resource(ctx, r); +#if 0 +#ifndef WITHOUT_ASYNC + r = coap_resource_init((unsigned char *)"async", 5, 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_resource(ctx, r); +#endif /* WITHOUT_ASYNC */ +#endif + + return; + error: + coap_log(LOG_CRIT, "cannot create resource\n"); +} + +/* struct etimer notify_timer; */ +struct etimer dirty_timer; + +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(coap_server_process, ev, data) +{ + PROCESS_BEGIN(); + + clock_offset = clock_time(); + init_coap_server(&coap_context); + + if (!coap_context) { + coap_log(LOG_EMERG, "cannot create context\n"); + PROCESS_EXIT(); + } + + init_coap_resources(coap_context); + + if (!coap_context) { + coap_log(LOG_EMERG, "cannot create context\n"); + PROCESS_EXIT(); + } + + /* etimer_set(¬ify_timer, 5 * CLOCK_SECOND); */ + etimer_set(&dirty_timer, 30 * CLOCK_SECOND); + + while(1) { + PROCESS_YIELD(); + if(ev == tcpip_event) { + coap_read(coap_context); /* read received data */ + /* coap_dispatch(coap_context); /\* and dispatch PDUs from receivequeue *\/ */ + } else if (ev == PROCESS_EVENT_TIMER && etimer_expired(&dirty_timer)) { + time_resource->dirty = 1; + etimer_reset(&dirty_timer); + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/etsi_iot_01.c b/examples/etsi_iot_01.c index 4ff7a45527..0edc8a9368 100644 --- a/examples/etsi_iot_01.c +++ b/examples/etsi_iot_01.c @@ -259,7 +259,7 @@ hnd_post_test(coap_context_t *ctx, struct coap_resource_t *resource, test_payload = coap_new_payload(len); uri = (coap_dynamic_uri_t *)coap_malloc(sizeof(coap_dynamic_uri_t) + l); if (!(test_payload && uri)) { - error("cannot allocate new resource under /test"); + coap_log(LOG_CRIT, "cannot allocate new resource under /test"); response->hdr->code = COAP_RESPONSE_CODE(500); coap_free(test_payload); coap_free(uri); @@ -536,7 +536,7 @@ init_resources(coap_context_t *ctx) { test_payload = coap_new_payload(200); if (!test_payload) - error("cannot allocate resource /test"); + coap_log(LOG_CRIT, "cannot allocate resource /test"); else { test_payload->length = 13; memcpy(test_payload->data, "put data here", test_payload->length); @@ -562,7 +562,7 @@ init_resources(coap_context_t *ctx) { * TD_COAP_BLOCK_02 */ test_payload = make_large("etsi_iot_01_largedata.txt"); if (!test_payload) - error("cannot allocate resource /large\n"); + coap_log(LOG_CRIT, "cannot allocate resource /large\n"); else { r = coap_resource_init((unsigned char *)"large", 5, 0); coap_register_handler(r, COAP_REQUEST_GET, hnd_get_resource); @@ -579,7 +579,7 @@ init_resources(coap_context_t *ctx) { /* For TD_COAP_CORE_12 */ test_payload = coap_new_payload(20); if (!test_payload) - error("cannot allocate resource /seg1/seg2/seg3\n"); + coap_log(LOG_CRIT, "cannot allocate resource /seg1/seg2/seg3\n"); else { test_payload->length = 10; memcpy(test_payload->data, "segsegseg!", test_payload->length); diff --git a/examples/lwip/config.h b/examples/lwip/config.h deleted file mode 120000 index 9ab365588b..0000000000 --- a/examples/lwip/config.h +++ /dev/null @@ -1 +0,0 @@ -../../config.h.lwip \ No newline at end of file diff --git a/examples/lwip/config.h b/examples/lwip/config.h new file mode 100644 index 0000000000..88f6f90e8e --- /dev/null +++ b/examples/lwip/config.h @@ -0,0 +1,19 @@ +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#include +#include +#include /* provide ntohs, htons */ + +#define WITH_LWIP 1 + +#define assert(x) LWIP_ASSERT("CoAP assert failed", x) + +/* it's just provided by libc. i hope we don't get too many of those, as + * actually we'd need autotools again to find out what environment we're + * building in */ +#define HAVE_STRNLEN 1 + +#define COAP_RESOURCES_NOHASH + +#endif /* _CONFIG_H_ */ diff --git a/examples/lwip/server-coap.c b/examples/lwip/server-coap.c index fcdb074eef..356034d6b7 100644 --- a/examples/lwip/server-coap.c +++ b/examples/lwip/server-coap.c @@ -19,6 +19,5 @@ void server_coap_init(void) void server_coap_poll(void) { - coap_dispatch(main_coap_context); coap_check_notify(main_coap_context); } diff --git a/examples/lwip/server.c b/examples/lwip/server.c index df8f34ba4e..ac7978f26f 100644 --- a/examples/lwip/server.c +++ b/examples/lwip/server.c @@ -43,7 +43,7 @@ #include "timer.h" #include -#include +#include "server-coap.h" static ip_addr_t ipaddr, netmask, gw; @@ -63,6 +63,7 @@ main(int argc, char **argv) printf("TCP/IP initialized.\n"); netif_add(&netif, &ipaddr, &netmask, &gw, NULL, mintapif_init, ethernet_input); + netif.flags |= NETIF_FLAG_ETHARP; netif_set_default(&netif); netif_set_up(&netif); #if LWIP_IPV6 diff --git a/examples/rd.c b/examples/rd.c index 271a78c2d9..3beae6b02d 100644 --- a/examples/rd.c +++ b/examples/rd.c @@ -1,7 +1,7 @@ /* coap -- simple implementation of the Constrained Application Protocol (CoAP) - * as defined in draft-ietf-core-coap + * as defined in RFC 7252 * - * Copyright (C) 2010--2013 Olaf Bergmann + * Copyright (C) 2010--2015 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see * README for terms of use. @@ -31,7 +31,7 @@ #include #include -#include "config.h" +#include "coap_config.h" #include "utlist.h" #include "resource.h" #include "coap.h" @@ -57,8 +57,14 @@ typedef struct rd_t { rd_t *resources = NULL; -inline rd_t * -rd_new() { +#ifdef __GNUC__ +#define UNUSED_PARAM __attribute__ ((unused)) +#else /* not a GCC */ +#define UNUSED_PARAM +#endif /* GCC */ + +static inline rd_t * +rd_new(void) { rd_t *rd; rd = (rd_t *)coap_malloc(sizeof(rd_t)); if (rd) @@ -67,7 +73,7 @@ rd_new() { return rd; } -inline void +static inline void rd_delete(rd_t *rd) { if (rd) { coap_free(rd->data.s); @@ -79,14 +85,15 @@ rd_delete(rd_t *rd) { static int quit = 0; /* SIGINT handler: set quit to 1 for graceful termination */ -void -handle_sigint(int signum) { +static void +handle_sigint(int signum UNUSED_PARAM) { quit = 1; } -void -hnd_get_resource(coap_context_t *ctx, struct coap_resource_t *resource, - coap_address_t *peer, coap_pdu_t *request, str *token, +static void +hnd_get_resource(coap_context_t *ctx UNUSED_PARAM, struct coap_resource_t *resource, + const coap_endpoint_t *local_interface UNUSED_PARAM, + coap_address_t *peer UNUSED_PARAM, coap_pdu_t *request UNUSED_PARAM, str *token UNUSED_PARAM, coap_pdu_t *response) { rd_t *rd = NULL; unsigned char buf[3]; @@ -105,9 +112,10 @@ hnd_get_resource(coap_context_t *ctx, struct coap_resource_t *resource, coap_add_data(response, rd->data.length, rd->data.s); } -void -hnd_put_resource(coap_context_t *ctx, struct coap_resource_t *resource, - coap_address_t *peer, coap_pdu_t *request, str *token, +static void +hnd_put_resource(coap_context_t *ctx UNUSED_PARAM, struct coap_resource_t *resource UNUSED_PARAM, + const coap_endpoint_t *local_interface UNUSED_PARAM, + coap_address_t *peer UNUSED_PARAM, coap_pdu_t *request UNUSED_PARAM, str *token UNUSED_PARAM, coap_pdu_t *response) { #if 1 response->hdr->code = COAP_RESPONSE_CODE(501); @@ -179,9 +187,10 @@ hnd_put_resource(coap_context_t *ctx, struct coap_resource_t *resource, #endif } -void +static void hnd_delete_resource(coap_context_t *ctx, struct coap_resource_t *resource, - coap_address_t *peer, coap_pdu_t *request, str *token, + const coap_endpoint_t *local_interface UNUSED_PARAM, + coap_address_t *peer UNUSED_PARAM, coap_pdu_t *request UNUSED_PARAM, str *token UNUSED_PARAM, coap_pdu_t *response) { rd_t *rd = NULL; @@ -197,9 +206,10 @@ hnd_delete_resource(coap_context_t *ctx, struct coap_resource_t *resource, response->hdr->code = COAP_RESPONSE_CODE(202); } -void -hnd_get_rd(coap_context_t *ctx, struct coap_resource_t *resource, - coap_address_t *peer, coap_pdu_t *request, str *token, +static void +hnd_get_rd(coap_context_t *ctx UNUSED_PARAM, struct coap_resource_t *resource UNUSED_PARAM, + const coap_endpoint_t *local_interface UNUSED_PARAM, + coap_address_t *peer UNUSED_PARAM, coap_pdu_t *request UNUSED_PARAM, str *token UNUSED_PARAM, coap_pdu_t *response) { unsigned char buf[3]; @@ -212,7 +222,7 @@ hnd_get_rd(coap_context_t *ctx, struct coap_resource_t *resource, coap_encode_var_bytes(buf, 0x2ffff), buf); } -int +static int parse_param(unsigned char *search, size_t search_len, unsigned char *data, size_t data_len, str *result) { @@ -256,7 +266,7 @@ parse_param(unsigned char *search, size_t search_len, return 0; } -void +static void add_source_address(struct coap_resource_t *resource, coap_address_t *peer) { #define BUFSIZE 64 char *buf; @@ -312,8 +322,8 @@ add_source_address(struct coap_resource_t *resource, coap_address_t *peer) { } -rd_t * -make_rd(coap_address_t *peer, coap_pdu_t *pdu) { +static rd_t * +make_rd(coap_address_t *peer UNUSED_PARAM, coap_pdu_t *pdu) { rd_t *rd; unsigned char *data; coap_opt_iterator_t opt_iter; @@ -345,9 +355,10 @@ make_rd(coap_address_t *peer, coap_pdu_t *pdu) { return rd; } -void -hnd_post_rd(coap_context_t *ctx, struct coap_resource_t *resource, - coap_address_t *peer, coap_pdu_t *request, str *token, +static void +hnd_post_rd(coap_context_t *ctx, struct coap_resource_t *resource UNUSED_PARAM, + const coap_endpoint_t *local_interface UNUSED_PARAM, + coap_address_t *peer, coap_pdu_t *request, str *token UNUSED_PARAM, coap_pdu_t *response) { coap_resource_t *r; coap_opt_iterator_t opt_iter; @@ -409,7 +420,7 @@ hnd_post_rd(coap_context_t *ctx, struct coap_resource_t *resource, loc_size += snprintf((char *)(loc + loc_size), LOCSIZE - loc_size - 1, - "-%x", now); + "-%x", (unsigned int)(now & (unsigned int)-1)); } } } @@ -480,7 +491,7 @@ hnd_post_rd(coap_context_t *ctx, struct coap_resource_t *resource, } } -void +static void init_resources(coap_context_t *ctx) { coap_resource_t *r; @@ -496,7 +507,7 @@ init_resources(coap_context_t *ctx) { } -void +static void usage( const char *program, const char *version) { const char *p; @@ -513,7 +524,7 @@ usage( const char *program, const char *version) { program, version, program ); } -coap_context_t * +static coap_context_t * get_context(const char *node, const char *port) { coap_context_t *ctx = NULL; int s; @@ -555,7 +566,7 @@ get_context(const char *node, const char *port) { return ctx; } -int +static int join(coap_context_t *ctx, char *group_name) { struct ipv6_mreq mreq; struct addrinfo *reslocal = NULL, *resmulti = NULL, hints, *ainfo; @@ -692,7 +703,7 @@ main(int argc, char **argv) { } else if ( result > 0 ) { /* read from socket */ if ( FD_ISSET( ctx->sockfd, &readfds ) ) { coap_read( ctx ); /* read received data */ - coap_dispatch( ctx ); /* and dispatch PDUs from receivequeue */ + /* coap_dispatch( ctx ); /\* and dispatch PDUs from receivequeue *\/ */ } } else { /* timeout */ /* coap_check_resource_list( ctx ); */ diff --git a/examples/server.c b/examples/server.c index fd42ef6d86..53938955d8 100644 --- a/examples/server.c +++ b/examples/server.c @@ -1,7 +1,7 @@ /* coap -- simple implementation of the Constrained Application Protocol (CoAP) - * as defined in draft-ietf-core-coap + * as defined in RFC 7252 * - * Copyright (C) 2010--2013 Olaf Bergmann + * Copyright (C) 2010--2015 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see * README for terms of use. @@ -23,7 +23,7 @@ #include #include -#include "config.h" +#include "coap_config.h" #include "resource.h" #include "coap.h" @@ -37,6 +37,7 @@ static int quit = 0; /* changeable clock base (see handle_put_time()) */ +static time_t clock_offset; static time_t my_clock_base = 0; struct coap_resource_t *time_resource = NULL; @@ -47,18 +48,25 @@ struct coap_resource_t *time_resource = NULL; static coap_async_state_t *async = NULL; #endif /* WITHOUT_ASYNC */ +#ifdef __GNUC__ +#define UNUSED_PARAM __attribute__ ((unused)) +#else /* not a GCC */ +#define UNUSED_PARAM +#endif /* GCC */ + /* SIGINT handler: set quit to 1 for graceful termination */ -void -handle_sigint(int signum) { +static void +handle_sigint(int signum UNUSED_PARAM) { quit = 1; } #define INDEX "This is a test server made with libcoap (see http://libcoap.sf.net)\n" \ "Copyright (C) 2010--2013 Olaf Bergmann \n\n" -void -hnd_get_index(coap_context_t *ctx, struct coap_resource_t *resource, - coap_address_t *peer, coap_pdu_t *request, str *token, +static void +hnd_get_index(coap_context_t *ctx UNUSED_PARAM, struct coap_resource_t *resource UNUSED_PARAM, + const coap_endpoint_t *local_interface UNUSED_PARAM, + coap_address_t *peer UNUSED_PARAM, coap_pdu_t *request UNUSED_PARAM, str *token UNUSED_PARAM, coap_pdu_t *response) { unsigned char buf[3]; @@ -73,8 +81,9 @@ hnd_get_index(coap_context_t *ctx, struct coap_resource_t *resource, coap_add_data(response, strlen(INDEX), (unsigned char *)INDEX); } -void -hnd_get_time(coap_context_t *ctx, struct coap_resource_t *resource, +static void +hnd_get_time(coap_context_t *ctx, struct coap_resource_t *resource, + const coap_endpoint_t *local_interface UNUSED_PARAM, coap_address_t *peer, coap_pdu_t *request, str *token, coap_pdu_t *response) { coap_opt_iterator_t opt_iter; @@ -131,9 +140,10 @@ hnd_get_time(coap_context_t *ctx, struct coap_resource_t *resource, } } -void -hnd_put_time(coap_context_t *ctx, struct coap_resource_t *resource, - coap_address_t *peer, coap_pdu_t *request, str *token, +static void +hnd_put_time(coap_context_t *ctx UNUSED_PARAM, struct coap_resource_t *resource UNUSED_PARAM, + const coap_endpoint_t *local_interface UNUSED_PARAM, + coap_address_t *peer UNUSED_PARAM, coap_pdu_t *request, str *token UNUSED_PARAM, coap_pdu_t *response) { coap_tick_t t; size_t size; @@ -163,10 +173,11 @@ hnd_put_time(coap_context_t *ctx, struct coap_resource_t *resource, } } -void -hnd_delete_time(coap_context_t *ctx, struct coap_resource_t *resource, - coap_address_t *peer, coap_pdu_t *request, str *token, - coap_pdu_t *response) { +static void +hnd_delete_time(coap_context_t *ctx UNUSED_PARAM, struct coap_resource_t *resource UNUSED_PARAM, + const coap_endpoint_t *local_interface UNUSED_PARAM, + coap_address_t *peer UNUSED_PARAM, coap_pdu_t *request UNUSED_PARAM, str *token UNUSED_PARAM, + coap_pdu_t *response UNUSED_PARAM) { my_clock_base = 0; /* mark clock as "deleted" */ /* type = request->hdr->type == COAP_MESSAGE_CON */ @@ -174,9 +185,10 @@ hnd_delete_time(coap_context_t *ctx, struct coap_resource_t *resource, } #ifndef WITHOUT_ASYNC -void -hnd_get_async(coap_context_t *ctx, struct coap_resource_t *resource, - coap_address_t *peer, coap_pdu_t *request, str *token, +static void +hnd_get_async(coap_context_t *ctx, struct coap_resource_t *resource UNUSED_PARAM, + const coap_endpoint_t *local_interface UNUSED_PARAM, + coap_address_t *peer, coap_pdu_t *request, str *token UNUSED_PARAM, coap_pdu_t *response) { coap_opt_iterator_t opt_iter; coap_opt_t *option; @@ -206,8 +218,9 @@ hnd_get_async(coap_context_t *ctx, struct coap_resource_t *resource, (void *)(COAP_TICKS_PER_SECOND * delay)); } -void -check_async(coap_context_t *ctx, coap_tick_t now) { +static void +check_async(coap_context_t *ctx, const coap_endpoint_t *local_if, + coap_tick_t now) { coap_pdu_t *response; coap_async_state_t *tmp; @@ -234,7 +247,7 @@ check_async(coap_context_t *ctx, coap_tick_t now) { coap_add_data(response, 4, (unsigned char *)"done"); - if (coap_send(ctx, &async->peer, response) == COAP_INVALID_TID) { + if (coap_send(ctx, local_if, &async->peer, response) == COAP_INVALID_TID) { debug("check_async: cannot send response for message %d\n", response->hdr->id); } @@ -245,7 +258,7 @@ check_async(coap_context_t *ctx, coap_tick_t now) { } #endif /* WITHOUT_ASYNC */ -void +static void init_resources(coap_context_t *ctx) { coap_resource_t *r; @@ -282,7 +295,7 @@ init_resources(coap_context_t *ctx) { #endif /* WITHOUT_ASYNC */ } -void +static void usage( const char *program, const char *version) { const char *p; @@ -291,7 +304,7 @@ usage( const char *program, const char *version) { program = ++p; fprintf( stderr, "%s v%s -- a small CoAP implementation\n" - "(c) 2010,2011 Olaf Bergmann \n\n" + "(c) 2010,2011,2015 Olaf Bergmann \n\n" "usage: %s [-A address] [-p port]\n\n" "\t-A address\tinterface address to bind to\n" "\t-p port\t\tlisten on specified port\n" @@ -299,7 +312,7 @@ usage( const char *program, const char *version) { program, version, program ); } -coap_context_t * +static coap_context_t * get_context(const char *node, const char *port) { coap_context_t *ctx = NULL; int s; @@ -354,6 +367,8 @@ main(int argc, char **argv) { int opt; coap_log_t log_level = LOG_WARNING; + clock_offset = time(NULL); + while ((opt = getopt(argc, argv, "A:p:v:")) != -1) { switch (opt) { case 'A' : @@ -413,7 +428,7 @@ main(int argc, char **argv) { } else if ( result > 0 ) { /* read from socket */ if ( FD_ISSET( ctx->sockfd, &readfds ) ) { coap_read( ctx ); /* read received data */ - coap_dispatch( ctx ); /* and dispatch PDUs from receivequeue */ + /* coap_dispatch( ctx ); /\* and dispatch PDUs from receivequeue *\/ */ } } else { /* timeout */ if (time_resource) { @@ -423,7 +438,7 @@ main(int argc, char **argv) { #ifndef WITHOUT_ASYNC /* check if we have to send asynchronous responses */ - check_async(ctx, now); + check_async(ctx, ctx->endpoint, now); #endif /* WITHOUT_ASYNC */ #ifndef WITHOUT_OBSERVE From 3136b323e4967ce48a48fde65b99eb22261cd03a Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Thu, 26 Mar 2015 14:20:19 +0100 Subject: [PATCH 50/69] Added eclipse project files to ignore --- .gitignore | 3 +++ libcoap.mk | 1 - src/net.c | 20 ++++++++++---------- src/option.c | 3 --- src/pdu.c | 12 +++++++++--- src/resource.c | 4 ---- src/str.c | 6 +++--- src/subscribe.c | 22 ++++++++++++++++++++++ src/uri.c | 3 --- 9 files changed, 47 insertions(+), 27 deletions(-) create mode 100644 src/subscribe.c diff --git a/.gitignore b/.gitignore index 0405271a20..86314d5ec5 100644 --- a/.gitignore +++ b/.gitignore @@ -70,3 +70,6 @@ examples/server.o tests/.deps tests/testdriver tests/*.o + +.project +.cproject diff --git a/libcoap.mk b/libcoap.mk index 61d480e580..19ae9ac6ab 100644 --- a/libcoap.mk +++ b/libcoap.mk @@ -7,7 +7,6 @@ LIBSRC += $(ROOT)/src/pdu.c \ $(ROOT)/src/debug.c \ $(ROOT)/src/encode.c \ $(ROOT)/src/uri.c \ - $(ROOT)/src/coap_list.c \ $(ROOT)/src/resource.c \ $(ROOT)/src/hashkey.c \ $(ROOT)/src/str.c \ diff --git a/src/net.c b/src/net.c index 5c1ff14698..13bfbae63f 100644 --- a/src/net.c +++ b/src/net.c @@ -145,7 +145,7 @@ coap_free_node(coap_queue_t *node) { } #endif /* WITH_LWIP */ -#ifdef WITH_STNODE2 +#ifdef ST_NODE #include "system.h" systime_t clock_offset; @@ -158,7 +158,7 @@ static inline void coap_free_node(coap_queue_t *node) { sys_free(node); } -#endif /* WITH_STNODE2 */ +#endif /* ST_NODE */ #ifdef WITH_CONTIKI # ifndef DEBUG # define DEBUG DEBUG_PRINT @@ -355,8 +355,8 @@ coap_new_context( if (initialized) return NULL; #endif /* WITH_CONTIKI */ -#ifdef WITH_STNODE - coap_context_t *c = sys_malloc( sizeof( coap_context_t ) ); +#ifdef ST_NODE + coap_context_t *c = sys_malloc(sizeof(coap_context_t)); #endif /* WITH_STNODE */ if (!listen_addr) { @@ -382,7 +382,6 @@ coap_new_context( #ifdef WITH_CONTIKI coap_resources_init(); coap_memory_init(); - coap_pdu_resources_init(); c = &the_coap_context; initialized = 1; @@ -437,7 +436,7 @@ coap_new_context( return c; #endif -#ifdef WITH_STNODE +#ifdef ST_NODE c->ns = net_create(NET_UDP); if (!c->ns) { return NULL; @@ -480,7 +479,7 @@ coap_free_context(coap_context_t *context) { #endif /* WITH_CONTIKI */ #ifdef WITH_STNODE net_disconnect(context->ns); - sys_free( context ); + sys_free(context); #endif /* WITH_STNODE */ } @@ -546,7 +545,7 @@ coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, return; } #endif -#if defined(WITH_LWIP) || defined(WITH_CONTIKI) || defined(WITH_STNODE) +#if defined(WITH_LWIP) || defined(WITH_CONTIKI) || defined(ST_NODE) /* FIXME: with lwip, we can do better */ /* TODO: MWAS: check better options */ coap_hash((const unsigned char *)&peer->port, sizeof(peer->port), h); @@ -633,13 +632,14 @@ coap_send_impl(coap_context_t *context, return id; } #endif /* WITH_LWIP */ -#ifdef WITH_STNODE +#ifdef ST_NODE /* * MWAS: st-node implementation doesn't require destination address for sending, * destination address is currently used only for transaction id. */ coap_tid_t coap_send_impl(coap_context_t *context, + const coap_endpoint_t *local_interface, const coap_address_t *dst, coap_pdu_t *pdu) { coap_tid_t id = COAP_INVALID_TID; @@ -1300,7 +1300,7 @@ coap_wellknown_response(coap_context_t *context, coap_pdu_t *request) { resp->length++; len = need_block2 ? SZX_TO_BYTES(block.szx) : resp->max_size - resp->length; -#ifndef WITH_STNODE +#ifndef ST_NODE result = coap_print_wellknown(context, resp->data, &len, offset, query_filter); #else result = coap_print_wellknown(context, resp, &len, offset, query_filter); diff --git a/src/option.c b/src/option.c index aff41ffca1..51ff809f25 100644 --- a/src/option.c +++ b/src/option.c @@ -20,9 +20,6 @@ #include "option.h" #include "debug.h" -#include "logging.h" -DEFINE_LOG(LOG_DEFAULT_SEVERITY); - coap_opt_t * options_start(coap_pdu_t *pdu) { diff --git a/src/pdu.c b/src/pdu.c index 9b1d61a90d..dad28c7b48 100644 --- a/src/pdu.c +++ b/src/pdu.c @@ -168,8 +168,13 @@ coap_new_pdu(void) { void coap_delete_pdu(coap_pdu_t *pdu) { -#ifdef WITH_POSIX - coap_free( pdu ); +#if defined(WITH_POSIX) || defined(WITH_CONTIKI) + if (pdu != NULL) { + if (pdu->hdr != NULL) { + coap_free_type(COAP_PDU_BUF, pdu->hdr); + } + coap_free_type(COAP_PDU, pdu); + } #endif #ifdef WITH_LWIP if (pdu != NULL) /* accepting double free as the other implementation accept that too */ @@ -194,12 +199,13 @@ coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data) { return 0; pdu->hdr->token_length = len; - if (len) + if (len) { #ifdef ST_NODE mbuf_write(pdu->mbuf, data, len, pdu->length); #else memcpy(pdu->hdr->token, data, len); #endif + } pdu->max_delta = 0; pdu->length = HEADERLENGTH; pdu->data = NULL; diff --git a/src/resource.c b/src/resource.c index 38b717191c..558542f62a 100644 --- a/src/resource.c +++ b/src/resource.c @@ -29,8 +29,6 @@ #endif #ifdef WITH_POSIX -#include "utlist.h" -#include "mem.h" #define COAP_MALLOC_TYPE(Type) \ ((coap_##Type##_t *)coap_malloc(sizeof(coap_##Type##_t))) @@ -393,7 +391,6 @@ coap_get_user_data(coap_resource_t *resource) { return resource->pdata; } - void coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key) { coap_opt_iterator_t opt_iter; @@ -442,7 +439,6 @@ coap_free_resource(coap_resource_t *resource) { int coap_delete_resource(coap_context_t *context, coap_key_t key) { coap_resource_t *resource; - coap_attr_t *attr, *tmp; if (!context) return 0; diff --git a/src/str.c b/src/str.c index c3f97ba705..f5800c257b 100644 --- a/src/str.c +++ b/src/str.c @@ -14,12 +14,12 @@ #include "mem.h" #include "str.h" -DEFINE_LOG(LOG_DEFAULT_SEVERITY); - str *coap_new_string(size_t size) { str *s = coap_malloc(sizeof(str) + size + 1); if ( !s ) { - error("coap_new_string: malloc\n"); +#ifndef NDEBUG + coap_log(LOG_CRIT, "coap_new_string: malloc\n"); +#endif return NULL; } diff --git a/src/subscribe.c b/src/subscribe.c new file mode 100644 index 0000000000..8195f8171a --- /dev/null +++ b/src/subscribe.c @@ -0,0 +1,22 @@ +/* subscribe.c -- subscription handling for CoAP + * see draft-ietf-coap-observe-16 + * + * Copyright (C) 2010--2013,2015 Olaf Bergmann + * + * This file is part of the CoAP library libcoap. Please see + * README for terms of use. + */ + +#include "coap_config.h" + +#if defined(HAVE_ASSERT_H) && !defined(assert) +# include +#endif + +#include "subscribe.h" + +void +coap_subscription_init(coap_subscription_t *s) { + assert(s); + memset(s, 0, sizeof(coap_subscription_t)); +} diff --git a/src/uri.c b/src/uri.c index dd5349c9e0..ec6c57ee9a 100644 --- a/src/uri.c +++ b/src/uri.c @@ -21,9 +21,6 @@ #include "pdu.h" #include "option.h" #include "uri.h" -#include "logging.h" - -DEFINE_LOG(LOG_DEFAULT_SEVERITY); /** * A length-safe version of strchr(). This function returns a pointer From c1f250ec36b357b09729dcd2d5659ffc66ff3cd8 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Thu, 26 Mar 2015 18:24:27 +0100 Subject: [PATCH 51/69] Fixes after libcoap/develop merge --- impl/orignal/mem.c | 88 --- impl/st-node/mem.c | 60 -- include/coap/address.h | 17 + include/coap/coap_io.h | 20 + include/coap/coap_list.h | 31 + include/coap/coap_time.h | 1 + include/coap/config.h | 141 ----- include/coap/mem.h | 16 +- include/coap/net.h | 5 +- include/coap/pdu.h | 10 +- include/coap/resource.h | 54 +- include/coap/subscribe.h | 72 +++ libcoap.mk | 21 - src/coap_list.c | 51 ++ src/coap_net.c | 1258 -------------------------------------- src/net.c | 143 ++--- src/option.c | 11 +- src/pdu.c | 27 +- src/resource.c | 50 +- 19 files changed, 330 insertions(+), 1746 deletions(-) delete mode 100644 impl/orignal/mem.c delete mode 100644 impl/st-node/mem.c create mode 100644 include/coap/coap_list.h delete mode 100644 include/coap/config.h create mode 100644 include/coap/subscribe.h delete mode 100644 libcoap.mk create mode 100644 src/coap_list.c delete mode 100644 src/coap_net.c diff --git a/impl/orignal/mem.c b/impl/orignal/mem.c deleted file mode 100644 index 44508ca474..0000000000 --- a/impl/orignal/mem.c +++ /dev/null @@ -1,88 +0,0 @@ -/* mem.c -- CoAP memory handling - * - * Copyright (C) 2014 Olaf Bergmann - * - * This file is part of the CoAP library libcoap. Please see - * README for terms of use. - */ - - -#include "config.h" -#include "mem.h" -#include "debug.h" - -#ifdef HAVE_ASSERT_H -#include -#else /* HAVE_ASSERT_H */ -#define assert(...) -#endif /* HAVE_ASSERT_H */ - -#ifdef HAVE_MALLOC -#include - -void -coap_memory_init() { -} - -#ifdef __GNUC__ -#define UNUSED_PARAM __attribute__((unused)) -#else -#define UNUSED_PARAM -#endif /* __GNUC__ */ - -void * -coap_malloc_type(coap_memory_tag_t type UNUSED_PARAM, size_t size) { - return malloc(size); -} - -void -coap_free_type(coap_memory_tag_t type UNUSED_PARAM, void *p) { - free(p); -} - -#else /* HAVE_MALLOC */ - -#ifdef WITH_CONTIKI -#define COAP_MAX_STRING_SIZE 12 -#define COAP_MAX_STRINGS 8 - -struct coap_string_t { - char data[COAP_MAX_STRING_SIZE]; -}; - -MEMB(string_storage, struct coap_string_t, COAP_MAX_STRINGS); - -static struct memb * -get_container(coap_memory_tag_t type) { - switch(type) { - default: - return &string_storage; - } -} - -void -coap_memory_init() { - memb_init(&string_storage); -} - -void * -coap_malloc_type(coap_memory_tag_t type, size_t size) { - struct memb *container = get_container(type); - - assert(container); - - if (size > container->size) { - debug("coap_malloc_type: Requested memory exceeds maximum object size\n"); - return NULL; - } - - return memb_alloc(container); -} - -void -coap_free_type(coap_memory_tag_t type, void *object) { - memb_free(get_container(type), object); -} -#endif /* WITH_CONTIKI */ - -#endif /* HAVE_MALLOC */ diff --git a/impl/st-node/mem.c b/impl/st-node/mem.c deleted file mode 100644 index 7abf70107c..0000000000 --- a/impl/st-node/mem.c +++ /dev/null @@ -1,60 +0,0 @@ -/* mem.c -- CoAP memory handling - * - * Copyright (C) 2014 Olaf Bergmann - * - * This file is part of the CoAP library libcoap. Please see - * README for terms of use. - */ - -#include "ch.h" - -#include "config.h" -#include "mem.h" -#include "debug.h" - -#include "resource.h" - -#ifndef MAX_RESOURCES -#define MAX_RESOURCES 60 -#endif - -#ifndef LIBCOAP_DEFAULT_HEAP_SIZE -#define LIBCOAP_DEFAULT_HEAP_SIZE 4096 -#endif - -#define TEO_RESOURCE_SIZE sizeof(coap_resource_t)+TEO_URI_LENGTH+TEO_USER_DATA_LENGTH - -static MemoryPool resource_pool; -static stkalign_t resource_buffer[MAX_RESOURCES*MEM_ALIGN_NEXT(TEO_RESOURCE_SIZE)/sizeof(stkalign_t)]; - -static MemoryHeap default_heap; -static stkalign_t default_heap_buffer[STACK_ALIGN(LIBCOAP_DEFAULT_HEAP_SIZE)/sizeof(stkalign_t)]; - -void -coap_memory_init(void) { - chPoolInit(&resource_pool, MEM_ALIGN_NEXT(TEO_RESOURCE_SIZE), NULL); - for (int i = 0; i < MAX_RESOURCES; i++) { - chPoolFree(&resource_pool, (uint8_t *)resource_buffer + i*MEM_ALIGN_NEXT(TEO_RESOURCE_SIZE)); - } - chHeapInit(&default_heap, default_heap_buffer, sizeof(default_heap_buffer)); -} - -void * -coap_malloc_type(coap_memory_tag_t type, size_t size) { - switch (type) { - case COAP_RESOURCE: - return chPoolAlloc(&resource_pool); - default: - return chHeapAlloc(&default_heap, size); - } -} - -void -coap_free_type(coap_memory_tag_t type, void *object) { - switch (type) { - case COAP_RESOURCE: - return chPoolFree(&resource_pool, object); - default: - return chHeapFree(object); - } -} diff --git a/include/coap/address.h b/include/coap/address.h index 1c21cdcdc6..8d40231c0d 100644 --- a/include/coap/address.h +++ b/include/coap/address.h @@ -57,6 +57,23 @@ typedef struct coap_address_t { #define _coap_is_mcast_impl(Address) 0 #endif /* WITH_LWIP */ +#ifdef ST_NODE +#include "net_addr.h" + +typedef struct coap_address_t { + uint8_t size; + uint16_t port; + ipaddr_t addr; +} coap_address_t; + +#define _coap_address_equals_impl(A, B) ((A)->addr.u32 == (B)->addr.u32 && A->port == B->port) + +/* Multicast IPv4 addresses start with 0b1110 */ +#define _coap_is_mcast_impl(Address) ((Address)->addr.u8[0] && 0xF0 == 0xE0) + +#define _coap_address_isany_impl(A) 0 + +#endif /* ST_NODE */ #ifdef WITH_CONTIKI #include "uip.h" diff --git a/include/coap/coap_io.h b/include/coap/coap_io.h index 3479bd6c9d..81a141cabf 100644 --- a/include/coap/coap_io.h +++ b/include/coap/coap_io.h @@ -30,6 +30,11 @@ # include #endif +#ifdef ST_NODE +#include +#include "net_common.h" +#endif + /** * Abstract handle that is used to identify a local network interface. */ @@ -59,6 +64,9 @@ typedef struct coap_endpoint_t { struct udp_pcb *pcb; struct coap_context_t *context; /**< @FIXME this was added in a hurry, not sure it confirms to the overall model --chrysn */ #endif /* WITH_LWIP */ +#ifdef ST_NODE + net_socket_t *ns; +#endif coap_address_t addr; /**< local interface address */ int ifindex; int flags; @@ -106,6 +114,9 @@ ssize_t coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet); # define coap_mcast_interface(Local) 0 #endif +/** Allocates store for a packet */ +coap_packet_t *coap_malloc_packet(void); + /** Releases the storage allocated for @p packet */ void coap_free_packet(coap_packet_t *packet); @@ -160,4 +171,13 @@ struct coap_packet_t { }; #endif +#ifdef ST_NODE +struct coap_packet_t { + struct mbuf *mbuf; + const coap_endpoint_t *interface; + coap_address_t src; /**< the packet's source address */ + coap_address_t dst; /**< the packet's destination address */ +}; +#endif + #endif /* _COAP_IO_H_ */ diff --git a/include/coap/coap_list.h b/include/coap/coap_list.h new file mode 100644 index 0000000000..293c2309a7 --- /dev/null +++ b/include/coap/coap_list.h @@ -0,0 +1,31 @@ +/* coap_list.h -- CoAP list structures + * + * Copyright (C) 2010,2011,2015 Olaf Bergmann + * + * This file is part of the CoAP library libcoap. Please see + * README for terms of use. + */ + +#ifndef _COAP_LIST_H_ +#define _COAP_LIST_H_ + +#include "utlist.h" + +typedef struct coap_list_t { + struct coap_list_t *next; + char data[]; +} coap_list_t; + +/** + * Adds node to given queue, ordered by specified order function. Returns 1 + * when insert was successful, 0 otherwise. + */ +int coap_insert(coap_list_t **queue, coap_list_t *node); + +/* destroys specified node */ +int coap_delete(coap_list_t *node); + +/* removes all items from given queue and frees the allocated storage */ +void coap_delete_list(coap_list_t *queue); + +#endif /* _COAP_LIST_H_ */ diff --git a/include/coap/coap_time.h b/include/coap/coap_time.h index 655002e810..872dbccfec 100644 --- a/include/coap/coap_time.h +++ b/include/coap/coap_time.h @@ -37,6 +37,7 @@ extern "C" { #define COAP_TICKS_PER_SECOND CH_FREQUENCY typedef systime_t coap_tick_t; +typedef systime_t coap_time_t; typedef int coap_tick_diff_t; /* TODO: MWAS: maybe it's better to use int32 */ extern systime_t clock_offset; diff --git a/include/coap/config.h b/include/coap/config.h deleted file mode 100644 index 795dd05bb9..0000000000 --- a/include/coap/config.h +++ /dev/null @@ -1,141 +0,0 @@ -/* config.h.in. Generated from configure.in by autoheader. */ - -/* Define if building universal (internal helper macro) */ -#undef AC_APPLE_UNIVERSAL_BUILD - -/* Define to 1 if you have the header file. */ -#undef HAVE_ARPA_INET_H - -/* Define to 1 if you have the header file. */ -#define HAVE_ASSERT_H 1 - -/* Define to 1 if you have the `getaddrinfo' function. */ -#undef HAVE_GETADDRINFO - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the `coap' library (-lcoap). */ -#undef HAVE_LIBCOAP - -/* Define to 1 if you have the header file. */ -#define HAVE_LIMITS_H 1 - -/* Define to 1 if your system has a GNU libc compatible `malloc' function, and - to 0 otherwise. */ -#undef HAVE_MALLOC - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have the `memset' function. */ -#undef HAVE_MEMSET - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETDB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IN_H - -/* Define to 1 if you have the `select' function. */ -#undef HAVE_SELECT - -/* Define to 1 if you have the `socket' function. */ -#undef HAVE_SOCKET - -/* Define to 1 if you have the `snprintf' function */ -#define HAVE_SNPRINTF 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the `strcasecmp' function. */ -#undef HAVE_STRCASECMP - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the `strnlen' function. */ -#define HAVE_STRNLEN 1 - -/* Define to 1 if you have the `strrchr' function. */ -#undef HAVE_STRRCHR - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYSLOG_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SOCKET_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TIME_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_UNISTD_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_TIME_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "libcoap" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libcoap 4.1.1" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "libcoap" - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Define maximum size of CoAP message */ -#define COAP_MAX_PDU_SIZE 1280 - -/* Define maximum size of CoAP block */ -#define COAP_MAX_BLOCK_SZX 6 - -/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most - significant byte first (like Motorola and SPARC, unlike Intel). */ -#if defined AC_APPLE_UNIVERSAL_BUILD -# if defined __BIG_ENDIAN__ -# define WORDS_BIGENDIAN 1 -# endif -#else -# ifndef WORDS_BIGENDIAN -# undef WORDS_BIGENDIAN -# endif -#endif - -/* Define to rpl_malloc if the replacement function should be used. */ -#undef malloc - -/* Define to `unsigned int' if does not define. */ -#undef size_t - -/* Define to `int' if does not define. */ -#undef ssize_t - diff --git a/include/coap/mem.h b/include/coap/mem.h index 32b7f2275d..557b2b54ec 100644 --- a/include/coap/mem.h +++ b/include/coap/mem.h @@ -27,8 +27,20 @@ void coap_memory_init(void); * to facilitate arrays of type objects to be used instead of dynamic * memory management on constrained devices. */ -typedef enum { - COAP_STRING, COAP_ATTRIBUTE_NAME, COAP_ATTRIBUTE_VALUE, COAP_PACKET, COAP_NODE, COAP_CONTEXT, COAP_ENDPOINT, COAP_PDU, COAP_PDU_BUF, COAP_RESOURCE, COAP_RESOURCEATTR +typedef enum { + COAP_STRING, + COAP_ATTRIBUTE_NAME, + COAP_ATTRIBUTE_VALUE, + COAP_PACKET, + COAP_NODE, + COAP_CONTEXT, + COAP_ENDPOINT, + COAP_PDU, + COAP_PDU_BUF, + COAP_RESOURCE, + COAP_SUBSCRIPTION, + COAP_RESOURCEATTR, + COAP_OPTION, } coap_memory_tag_t; #ifndef WITH_LWIP diff --git a/include/coap/net.h b/include/coap/net.h index 7fd1608667..66a9801d5a 100644 --- a/include/coap/net.h +++ b/include/coap/net.h @@ -120,9 +120,6 @@ typedef struct coap_context_t { #ifdef WITH_LWIP uint8_t timer_configured; /**< Set to 1 when a retransmission is scheduled using lwIP timers for this context, otherwise 0. */ #endif /* WITH_LWIP */ -#ifdef ST_NODE2 - net_socket_t *ns; -#endif /** * The last message id that was used is stored in this field. The @@ -189,7 +186,7 @@ coap_queue_t *coap_peek_next( coap_context_t *context ); coap_queue_t *coap_pop_next( coap_context_t *context ); /** Creates a new coap_context_t object that will hold the CoAP stack status. */ -coap_context_t *coap_new_context(const coap_address_t *listen_addr); +coap_context_t *coap_new_context(void); /** * Returns a new message id and updates @p context->message_id diff --git a/include/coap/pdu.h b/include/coap/pdu.h index 68028b24ea..36237dc87f 100644 --- a/include/coap/pdu.h +++ b/include/coap/pdu.h @@ -103,6 +103,8 @@ */ #define COAP_RESPONSE_CODE(N) (((N)/100 << 5) | (N)%100) +#define COAP_RESPONSE_CODE2(N) (((N) >> 5)*100 + ((N) & 0x1f)) + /* Determines the class of response code C */ #define COAP_RESPONSE_CLASS(C) (((C) >> 5) & 0xFF) @@ -228,7 +230,7 @@ typedef struct { #ifdef WITH_LWIP struct pbuf *pbuf; /**< lwIP PBUF. The package data will always reside inside the pbuf's payload, but this pointer has to be kept because no exact offset can be given. This field must not be accessed from outside, because the pbuf's reference count is checked to be 1 when the pbuf is assigned to the pdu, and the pbuf stays exclusive to this pdu. */ #endif -#ifdef ST_NODE2 +#ifdef ST_NODE unsigned short payload_offset; /**< payload offset */ struct mbuf *mbuf; /**< mbuf */ #endif @@ -237,6 +239,10 @@ typedef struct { /** Options in coap_pdu_t are accessed with the macro COAP_OPTION. */ #define COAP_OPTION(node) ((coap_option *)(node)->options) +#define COAP_PDU_CODE(pdu) ((pdu)->hdr->code) +#define COAP_PDU_TYPE(pdu) ((pdu)->hdr->type) +#define COAP_PDU_ID(pdu) ((pdu)->hdr->id) + #ifdef WITH_LWIP /** * Creates a CoAP PDU from an lwIP @p pbuf, whose reference is passed on to @@ -256,7 +262,7 @@ typedef struct { coap_pdu_t * coap_pdu_from_pbuf(struct pbuf *pbuf); #endif -#ifdef ST_NODE2 +#ifdef ST_NODE /** * Creates a CoAP PDU from st-node mbuf, whose reference is passed on to * this function. diff --git a/include/coap/resource.h b/include/coap/resource.h index 5158c96d2b..e19731157b 100644 --- a/include/coap/resource.h +++ b/include/coap/resource.h @@ -81,7 +81,6 @@ typedef struct coap_resource_t { coap_attr_t *link_attr; /**< attributes to be included with the link format */ coap_subscription_t *subscribers; /**< list of observers for this resource */ - /** * Request URI for this resource. This field will point into the * static memory. */ @@ -94,58 +93,7 @@ typedef struct coap_resource_t { void *pdata; } coap_resource_t; -/* Helper functions for conditional output of character sequences into - * a given buffer. The first Offset characters are skipped. - */ - -/** - * Writes Char to Pdu if Offset is zero. Otherwise, Char is not written - * and Offset is decremented. - */ -#define PRINT_WITH_OFFSET(Pdu,Left,Offset,Char) \ - if ((Offset) == 0) { \ - if((Left)>0) { \ - mbuf_write(Pdu->mbuf, Char, 1, Pdu->length++); \ - (Left)--; \ - } \ - } else { \ - (Offset)--; \ - } - -/** - * Writes Char to Buf if Offset is zero and Pdu is not empty - * Increases counter regardless of Pdu (used to obtain length - * prior to actual writing) - */ -#define PRINT_COND_WITH_OFFSET(Pdu,Left,Offset,Char,Result) { \ - if (Pdu) { \ - PRINT_WITH_OFFSET(Pdu,Left,Offset,Char); \ - } \ - (Result)++; \ - } - -/** - * Copies at most Length characters of Str to Pdu. The first Offset - * characters are skipped. Output may be truncated to Left - * characters. - */ -#define COPY_COND_WITH_OFFSET(Pdu,Left,Offset,Str,Length,Result) { \ - size_t i; \ - for (i = 0; i < (Length); i++) { \ - PRINT_COND_WITH_OFFSET((Pdu), (Left), (Offset), Str+i, (Result)); \ - } \ - } - -/** - * A helper macro which can be used to create static resources. - */ -#define COAP_RESOURCE(_uri, _get, _post, _put, _delete) { \ - .uri = _uri, \ - .handler = {_get, _post, _put, _delete}, \ -} - - -/** +/** * Creates a new resource object and initializes the link field to the * string of length @p len. This function returns the * new coap_resource_t object. diff --git a/include/coap/subscribe.h b/include/coap/subscribe.h new file mode 100644 index 0000000000..1da67e95b0 --- /dev/null +++ b/include/coap/subscribe.h @@ -0,0 +1,72 @@ +/* subscribe.h -- subscription handling for CoAP + * see draft-ietf-core-observe-16 + * + * Copyright (C) 2010--2012,2014,2015 Olaf Bergmann + * + * This file is part of the CoAP library libcoap. Please see + * README for terms of use. + */ + + +#ifndef _COAP_SUBSCRIBE_H_ +#define _COAP_SUBSCRIBE_H_ + +#include "coap_config.h" +#include "address.h" +#include "coap_io.h" + +/** + * @defgroup observe Resource observation + * @{ + */ + +/** + * The value COAP_OBSERVE_ESTABLISH in a GET request indicates + * a new observe relationship for (sender address, token) is requested. + */ +#define COAP_OBSERVE_ESTABLISH 0 + +/** + * The value COAP_OBSERVE_CANCEL in a GET request indicates that the + * observe relationship for (sender address, token) must be cancelled. + */ +#define COAP_OBSERVE_CANCEL 1 + +#ifndef COAP_OBS_MAX_NON +/** + * Number of notifications that may be sent non-confirmable before a + * confirmable message is sent to detect if observers are alive. The + * maximum allowed value here is @c 15. + */ +#define COAP_OBS_MAX_NON 5 +#endif /* COAP_OBS_MAX_NON */ + +#ifndef COAP_OBS_MAX_FAIL +/** + * Number of confirmable notifications that may fail (i.e. time out + * without being ACKed) before an observer is removed. The maximum + * value for COAP_OBS_MAX_FAIL is @c 3. + */ +#define COAP_OBS_MAX_FAIL 3 +#endif /* COAP_OBS_MAX_FAIL */ + +/** Subscriber information */ +typedef struct coap_subscription_t { + struct coap_subscription_t *next; /**< next element in linked list */ + coap_endpoint_t local_if; /**< local communication interface */ + coap_address_t subscriber; /**< address and port of subscriber */ + + unsigned int non:1; /**< send non-confirmable notifies if @c 1 */ + unsigned int non_cnt:4; /**< up to 15 non-confirmable notifies allowed */ + unsigned int fail_cnt:2; /**< up to 3 confirmable notifies can fail */ + unsigned int dirty:1; /**< set if the notification temporarily could not be sent (in that case, the resource's partiallydirty flag is set too) */ + + size_t token_length; /**< actual length of token */ + unsigned char token[8]; /**< token used for subscription */ +} coap_subscription_t; + +void coap_subscription_init(coap_subscription_t *); + +/** @} */ + +#endif /* _COAP_SUBSCRIBE_H_ */ diff --git a/libcoap.mk b/libcoap.mk deleted file mode 100644 index 19ae9ac6ab..0000000000 --- a/libcoap.mk +++ /dev/null @@ -1,21 +0,0 @@ -get-cwd = $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))) -ROOT := $(call get-cwd) - -# List of all the board related files. -LIBSRC += $(ROOT)/src/pdu.c \ - $(ROOT)/src/coap_net.c \ - $(ROOT)/src/debug.c \ - $(ROOT)/src/encode.c \ - $(ROOT)/src/uri.c \ - $(ROOT)/src/resource.c \ - $(ROOT)/src/hashkey.c \ - $(ROOT)/src/str.c \ - $(ROOT)/src/option.c \ - $(ROOT)/src/async.c \ - $(ROOT)/src/subscribe.c \ - $(ROOT)/src/block.c \ - $(ROOT)/src/impl/st-node/mem.c \ - -# Required include directories -LIBINC += $(ROOT)/include \ - $(ROOT)/impl \ No newline at end of file diff --git a/src/coap_list.c b/src/coap_list.c new file mode 100644 index 0000000000..6967281250 --- /dev/null +++ b/src/coap_list.c @@ -0,0 +1,51 @@ +/* coap_list.c -- CoAP list structures + * + * Copyright (C) 2010,2011,2015 Olaf Bergmann + * + * This file is part of the CoAP library libcoap. Please see + * README for terms of use. + */ + +/* #include "coap_config.h" */ + +#include +#include + +#include "debug.h" +#include "mem.h" +#include "coap_list.h" + + +int +coap_insert(coap_list_t **head, coap_list_t *node) { + if (!node) { + coap_log(LOG_WARNING, "cannot create option Proxy-Uri\n"); + } else { + /* must append at the list end to avoid re-ordering of + * options during sort */ + LL_APPEND((*head), node); + } + + return node != NULL; +} + +int +coap_delete(coap_list_t *node) { + if (node) { + coap_free(node); + } + return 1; +} + +void +coap_delete_list(coap_list_t *queue) { + coap_list_t *elt, *tmp; + + if (!queue) + return; + + LL_FOREACH_SAFE(queue, elt, tmp) { + coap_delete(elt); + } +} + diff --git a/src/coap_net.c b/src/coap_net.c deleted file mode 100644 index 3d6ae19094..0000000000 --- a/src/coap_net.c +++ /dev/null @@ -1,1258 +0,0 @@ -/* net.c -- CoAP network interface - * - * Copyright (C) 2010--2014 Olaf Bergmann - * - * This file is part of the CoAP library libcoap. Please see - * README for terms of use. - */ - -#include "config.h" - -#include -#include -#ifdef HAVE_LIMITS_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#elif HAVE_SYS_UNISTD_H -#include -#endif -#include -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif - -#include "debug.h" -#include "mem.h" -#include "str.h" -#include "async.h" -#include "resource.h" -#include "option.h" -#include "encode.h" -#include "block.h" -#include "../include/coap/net.h" - -#include "system.h" -#include "net.h" -#include "logging.h" -DEFINE_LOG(LOG_DEFAULT_SEVERITY); - -systime_t clock_offset; - -coap_resource_t * teo_get_resource_from_uri(coap_pdu_t *request); - -static inline coap_queue_t * -coap_malloc_node(void) { - return (coap_queue_t *)sys_malloc(sizeof(coap_queue_t)); -} - -static inline void -coap_free_node(coap_queue_t *node) { - sys_free(node); -} - -int print_wellknown(coap_context_t *, coap_pdu_t *, size_t *, size_t, coap_opt_t *); -void coap_handle_failed_notify(coap_context_t *, const coap_address_t *, - const str *); - -unsigned int -coap_adjust_basetime(coap_context_t *ctx, coap_tick_t now) { - unsigned int result = 0; - coap_tick_diff_t delta = now - ctx->sendqueue_basetime; - - if (ctx->sendqueue) { - /* delta < 0 means that the new time stamp is before the old. */ - if (delta <= 0) { - ctx->sendqueue->t -= delta; - } else { - /* This case is more complex: The time must be advanced forward, - * thus possibly leading to timed out elements at the queue's - * start. For every element that has timed out, its relative - * time is set to zero and the result counter is increased. */ - - coap_queue_t *q = ctx->sendqueue; - coap_tick_t t = 0; - while (q && (t + q->t < (coap_tick_t)delta)) { - t += q->t; - q->t = 0; - result++; - q = q->next; - } - - /* finally adjust the first element that has not expired */ - if (q) { - q->t = (coap_tick_t)delta - t; - } - } - } - - /* adjust basetime */ - ctx->sendqueue_basetime += delta; - - return result; -} - -int -coap_insert_node(coap_queue_t **queue, coap_queue_t *node) { - coap_queue_t *p, *q; - if ( !queue || !node ) - return 0; - - /* set queue head if empty */ - if ( !*queue ) { - *queue = node; - return 1; - } - - /* replace queue head if PDU's time is less than head's time */ - q = *queue; - if (node->t < q->t) { - node->next = q; - *queue = node; - q->t -= node->t; /* make q->t relative to node->t */ - return 1; - } - - /* search for right place to insert */ - do { - node->t -= q->t; /* make node-> relative to q->t */ - p = q; - q = q->next; - } while (q && q->t <= node->t); - - /* insert new item */ - if (q) { - q->t -= node->t; /* make q->t relative to node->t */ - } - node->next = q; - p->next = node; - return 1; -} - -int -coap_delete_node(coap_queue_t *node) { - if ( !node ) - return 0; - - coap_delete_pdu(node->pdu); - coap_free_node(node); - - return 1; -} - -void -coap_delete_all(coap_queue_t *queue) { - if ( !queue ) - return; - - coap_delete_all( queue->next ); - coap_delete_node( queue ); -} - -coap_queue_t * -coap_new_node(void) { - coap_queue_t *node; - node = coap_malloc_node(); - - if ( ! node ) { - error("coap_new_node: malloc\n"); - return NULL; - } - - memset(node, 0, sizeof *node ); - return node; -} - -coap_queue_t * -coap_peek_next( coap_context_t *context ) { - if ( !context || !context->sendqueue ) - return NULL; - - return context->sendqueue; -} - -coap_queue_t * -coap_pop_next( coap_context_t *context ) { - coap_queue_t *next; - - if ( !context || !context->sendqueue ) - return NULL; - - next = context->sendqueue; - context->sendqueue = context->sendqueue->next; - if (context->sendqueue) { - context->sendqueue->t += next->t; - } - next->next = NULL; - return next; -} - -#ifdef COAP_DEFAULT_WKC_HASHKEY -/** Checks if @p Key is equal to the pre-defined hash key for.well-known/core. */ -#define is_wkc(Key) \ - (memcmp((Key), COAP_DEFAULT_WKC_HASHKEY, sizeof(coap_key_t)) == 0) -#else -/* Implements a singleton to store a hash key for the .wellknown/core - * resources. */ -int -is_wkc(coap_key_t k) { - static coap_key_t wkc; - static unsigned char _initialized = 0; - if (!_initialized) { - _initialized = coap_hash_path((unsigned char *)COAP_DEFAULT_URI_WELLKNOWN, - sizeof(COAP_DEFAULT_URI_WELLKNOWN) - 1, wkc); - } - return memcmp(k, wkc, sizeof(coap_key_t)) == 0; -} -#endif - - -coap_context_t * -coap_new_context( - const coap_address_t *listen_addr) { - - coap_context_t *c = sys_malloc( sizeof( coap_context_t ) ); - - if (!listen_addr) { - debug("no listen address specified\n"); - return NULL; - } - coap_clock_init(); - prng_init((unsigned long)listen_addr ^ clock_offset); - - if ( !c ) { - debug("coap_init: malloc:\n"); - return NULL; - } - - memset(c, 0, sizeof( coap_context_t ) ); - - /* initialize message id */ - prng((unsigned char *)&c->message_id, sizeof(unsigned short)); - - /* register the critical options that we know */ - coap_register_option(c, COAP_OPTION_IF_MATCH); - coap_register_option(c, COAP_OPTION_URI_HOST); - coap_register_option(c, COAP_OPTION_IF_NONE_MATCH); - coap_register_option(c, COAP_OPTION_URI_PORT); - coap_register_option(c, COAP_OPTION_URI_PATH); - coap_register_option(c, COAP_OPTION_URI_QUERY); - coap_register_option(c, COAP_OPTION_ACCEPT); - coap_register_option(c, COAP_OPTION_PROXY_URI); - coap_register_option(c, COAP_OPTION_PROXY_SCHEME); - coap_register_option(c, COAP_OPTION_BLOCK2); - coap_register_option(c, COAP_OPTION_BLOCK1); - - c->ns = net_create(NET_UDP); - if (!c->ns) { - return NULL; - } - if(!net_bind(c->ns, listen_addr->port)) - { - debug("can't bind socket to port %d\n", listen_addr->port); - return NULL; - } - return c; -} - -void -coap_free_context( coap_context_t *context ) { - coap_resource_t *res; -#ifndef COAP_RESOURCES_NOHASH - coap_resource_t *rtmp; -#endif - if ( !context ) - return; - - coap_delete_all(context->recvqueue); - coap_delete_all(context->sendqueue); - -#ifdef COAP_RESOURCES_NOHASH - LL_FOREACH(context->resources, res) { -#else - HASH_ITER(hh, context->resources, res, rtmp) { -#endif - coap_delete_resource(context, res->key); - } - - net_disconnect(context->ns); - sys_free( context ); -} - -int -coap_option_check_critical(coap_context_t *ctx, - coap_pdu_t *pdu, - coap_opt_filter_t unknown) { - - coap_opt_iterator_t opt_iter; - int ok = 1; - - coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL); - - while (coap_option_next(&opt_iter)) { - - /* The following condition makes use of the fact that - * coap_option_getb() returns -1 if type exceeds the bit-vector - * filter. As the vector is supposed to be large enough to hold - * the largest known option, we know that everything beyond is - * bad. - */ - if (opt_iter.type & 0x01 && - coap_option_getb(ctx->known_options, opt_iter.type) < 1) { - debug("unknown critical option %d\n", opt_iter.type); - - ok = 0; - - /* When opt_iter.type is beyond our known option range, - * coap_option_setb() will return -1 and we are safe to leave - * this loop. */ - if (coap_option_setb(unknown, opt_iter.type) == -1) - break; - } - } - - return ok; -} - -void -coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, - coap_tid_t *id) { - coap_key_t h; - - memset(h, 0, sizeof(coap_key_t)); - - /* Compare the complete address structure in case of IPv4. For IPv6, - * we need to look at the transport address only. */ - - /* TODO: MWAS: check better options */ - coap_hash((const unsigned char *)&peer->port, sizeof(peer->port), h); - coap_hash((const unsigned char *)&peer->addr, sizeof(peer->addr), h); - - coap_hash((const unsigned char *)&pdu->hdr->id, sizeof(unsigned short), h); - - *id = ((h[0] << 8) | h[1]) ^ ((h[2] << 8) | h[3]); -} - -coap_tid_t -coap_send_ack(coap_context_t *context, - const coap_address_t *dst, - coap_pdu_t *request) { - coap_pdu_t *response; - coap_tid_t result = COAP_INVALID_TID; - - if (request && request->hdr->type == COAP_MESSAGE_CON) { - response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->hdr->id, - sizeof(coap_pdu_t)); - if (response) { - result = coap_send(context, dst, response); - coap_delete_pdu(response); - } - } - return result; -} - -coap_tid_t -coap_send_impl(coap_context_t *context, - const coap_address_t *dst, - coap_pdu_t *pdu) { - coap_tid_t id = COAP_INVALID_TID; - - if ( !context || !dst || !pdu ) - return id; - - coap_transaction_id(dst, pdu, &id); - - if(!net_send_to(context->ns, (ipaddr_t *)&dst->addr, dst->port, pdu->mbuf)) { - warn("coap_send: sendto\n"); - } - - return id; -} - -coap_tid_t -coap_send(coap_context_t *context, - const coap_address_t *dst, - coap_pdu_t *pdu) { - return coap_send_impl(context, dst, pdu); -} - -coap_tid_t -coap_send_error(coap_context_t *context, - coap_pdu_t *request, - const coap_address_t *dst, - unsigned char code, - coap_opt_filter_t opts) { - coap_pdu_t *response; - coap_tid_t result = COAP_INVALID_TID; - - assert(request); - assert(dst); - - response = coap_new_error_response(request, code, opts); - if (response) { - result = coap_send(context, dst, response); - coap_delete_pdu(response); - } - - return result; -} - -coap_tid_t -coap_send_message_type(coap_context_t *context, - const coap_address_t *dst, - coap_pdu_t *request, - unsigned char type) { - coap_pdu_t *response; - coap_tid_t result = COAP_INVALID_TID; - - if (request) { - response = coap_pdu_init(type, 0, request->hdr->id, sizeof(coap_pdu_t)); - if (response) { - result = coap_send(context, dst, response); - coap_delete_pdu(response); - } - } - return result; -} - -coap_tid_t -coap_send_confirmed(coap_context_t *context, - const coap_address_t *dst, - coap_pdu_t *pdu) { - coap_queue_t *node; - coap_tick_t now; - int r; - - node = coap_new_node(); - if (!node) { - debug("coap_send_confirmed: insufficient memory\n"); - return COAP_INVALID_TID; - } - - node->id = coap_send_impl(context, dst, pdu); - if (COAP_INVALID_TID == node->id) { - debug("coap_send_confirmed: error sending pdu\n"); - coap_free_node(node); - return COAP_INVALID_TID; - } - - prng((unsigned char *)&r,sizeof(r)); - - /* add randomized RESPONSE_TIMEOUT to determine retransmission timeout */ - node->timeout = COAP_DEFAULT_RESPONSE_TIMEOUT * COAP_TICKS_PER_SECOND + - (COAP_DEFAULT_RESPONSE_TIMEOUT >> 1) * - ((COAP_TICKS_PER_SECOND * (r & 0xFF)) >> 8); - - memcpy(&node->remote, dst, sizeof(coap_address_t)); - node->pdu = pdu; - - /* Set timer for pdu retransmission. If this is the first element in - * the retransmission queue, the base time is set to the current - * time and the retransmission time is node->timeout. If there is - * already an entry in the sendqueue, we must check if this node is - * to be retransmitted earlier. Therefore, node->timeout is first - * normalized to the base time and then inserted into the queue with - * an adjusted relative time. - */ - coap_ticks(&now); - if (context->sendqueue == NULL) { - node->t = node->timeout; - context->sendqueue_basetime = now; - } else { - /* make node->t relative to context->sendqueue_basetime */ - node->t = (now - context->sendqueue_basetime) + node->timeout; - } - - coap_insert_node(&context->sendqueue, node); - - return node->id; -} - -coap_tid_t -coap_retransmit( coap_context_t *context, coap_queue_t *node ) { - if ( !context || !node ) - return COAP_INVALID_TID; - - /* re-initialize timeout when maximum number of retransmissions are not reached yet */ - if ( node->retransmit_cnt < COAP_DEFAULT_MAX_RETRANSMIT ) { - node->retransmit_cnt++; - node->t = node->timeout << node->retransmit_cnt; - coap_insert_node(&context->sendqueue, node); - - debug("** retransmission #%d of transaction %d\n", - node->retransmit_cnt, ntohs(node->pdu->hdr->id)); - - node->id = coap_send_impl(context, &node->remote, node->pdu); - return node->id; - } - - /* no more retransmissions, remove node from system */ - debug("** removed transaction %d\n", ntohs(node->id)); - -#ifndef WITHOUT_OBSERVE - /* Check if subscriptions exist that should be canceled after - COAP_MAX_NOTIFY_FAILURES */ - if (node->pdu->hdr->code >= 64) { - str token = { 0, NULL }; - - token.length = node->pdu->hdr->token_length; - token.s = node->pdu->hdr->token; - - coap_handle_failed_notify(context, &node->remote, &token); - } -#endif /* WITHOUT_OBSERVE */ - - /* And finally delete the node */ - coap_delete_node( node ); - return COAP_INVALID_TID; -} - -/** - * Checks if @p opt fits into the message that ends with @p maxpos. - * This function returns @c 1 on success, or @c 0 if the option @p opt - * would exceed @p maxpos. - */ -static inline int -check_opt_size(coap_opt_t *opt, unsigned char *maxpos) { - if (opt && opt < maxpos) { - if (((*opt & 0x0f) < 0x0f) || (opt + 1 < maxpos)) - return opt + COAP_OPT_SIZE(opt) < maxpos; - } - return 0; -} - -int -coap_read( coap_context_t *ctx, coap_tick_t timeout) { - - ssize_t bytes_read = -1; - coap_address_t src, dst; - coap_queue_t *node; - - coap_address_init(&src); - - ctx->pending_package = net_receive_from(ctx->ns, &src.addr, &src.port, timeout); - if(ctx->pending_package) - { - src.size = 4; - bytes_read = ctx->pending_package->tot_len; - } - - if ( bytes_read < 0 ) { - debug("coap_read: recvfrom"); - goto error_early; - } - - if ( (size_t)bytes_read < sizeof(coap_hdr_t) ) { - debug("coap_read: discarded invalid frame\n" ); - goto error_early; - } - - node = coap_new_node(); - if ( !node ) - goto error_early; - - node->pdu = coap_pdu_from_mbuf(ctx->pending_package); - ctx->pending_package = NULL; - if (!node->pdu) - goto error; - - coap_ticks( &node->t ); - memcpy(&node->local, &dst, sizeof(coap_address_t)); - memcpy(&node->remote, &src, sizeof(coap_address_t)); - - if (!coap_pdu_parse((unsigned char *)node->pdu->mbuf->payload, bytes_read, node->pdu)) { - warn("discard malformed PDU"); - goto error; - } - - /* and add new node to receive queue */ - coap_transaction_id(&node->remote, node->pdu, &node->id); - coap_insert_node(&ctx->recvqueue, node); - - - if (LOG_DEBUG <= LOG.severity) { -#ifndef INET6_ADDRSTRLEN -#define INET6_ADDRSTRLEN 40 -#endif - unsigned char addr[INET6_ADDRSTRLEN+8]; - - if (coap_print_addr(&src, addr, INET6_ADDRSTRLEN+8)) - debug("** received %d bytes from %s:\n", (int)bytes_read, addr); - - coap_show_pdu( node->pdu ); - } - - return 0; - - error: - /* FIXME: send back RST? */ - coap_delete_node(node); - return -1; - error_early: - /* even if there was an error, clean up */ - if(ctx->pending_package) - mbuf_free(ctx->pending_package); - ctx->pending_package = NULL; - return -1; -} - -int -coap_remove_from_queue(coap_queue_t **queue, coap_tid_t id, coap_queue_t **node) { - coap_queue_t *p, *q; - - if ( !queue || !*queue) - return 0; - - /* replace queue head if PDU's time is less than head's time */ - - if ( id == (*queue)->id ) { /* found transaction */ - *node = *queue; - *queue = (*queue)->next; - if (*queue) { /* adjust relative time of new queue head */ - (*queue)->t += (*node)->t; - } - (*node)->next = NULL; - /* coap_delete_node( q ); */ - debug("*** removed transaction %u\n", id); - return 1; - } - - /* search transaction to remove (only first occurence will be removed) */ - q = *queue; - do { - p = q; - q = q->next; - } while ( q && id != q->id ); - - if ( q ) { /* found transaction */ - p->next = q->next; - if (p->next) { /* must update relative time of p->next */ - p->next->t += q->t; - } - q->next = NULL; - *node = q; - /* coap_delete_node( q ); */ - debug("*** removed transaction %u\n", id); - return 1; - } - - return 0; - -} - -static inline int -token_match(const unsigned char *a, size_t alen, - const unsigned char *b, size_t blen) { - return alen == blen && (alen == 0 || memcmp(a, b, alen) == 0); -} - -void -coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst, - const unsigned char *token, size_t token_length) { - /* cancel all messages in sendqueue that are for dst - * and use the specified token */ - coap_queue_t *p, *q; - - while (context->sendqueue && - coap_address_equals(dst, &context->sendqueue->remote) && - token_match(token, token_length, - context->sendqueue->pdu->hdr->token, - context->sendqueue->pdu->hdr->token_length)) { - q = context->sendqueue; - context->sendqueue = q->next; - debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id)); - coap_delete_node(q); - } - - if (!context->sendqueue) - return; - - p = context->sendqueue; - q = p->next; - - /* when q is not NULL, it does not match (dst, token), so we can skip it */ - while (q) { - if (coap_address_equals(dst, &q->remote) && - token_match(token, token_length, - q->pdu->hdr->token, q->pdu->hdr->token_length)) { - p->next = q->next; - debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id)); - coap_delete_node(q); - q = p->next; - } else { - p = q; - q = q->next; - } - } -} - -coap_queue_t * -coap_find_transaction(coap_queue_t *queue, coap_tid_t id) { - while (queue && queue->id != id) - queue = queue->next; - - return queue; -} - -coap_pdu_t * -coap_new_error_response(coap_pdu_t *request, unsigned char code, - coap_opt_filter_t opts) { - coap_opt_iterator_t opt_iter; - coap_pdu_t *response; - size_t size = sizeof(coap_hdr_t) + request->hdr->token_length; - int type; - coap_opt_t *option; - unsigned short opt_type = 0; /* used for calculating delta-storage */ - -#if COAP_ERROR_PHRASE_LENGTH > 0 - char *phrase = coap_response_phrase(code); - - /* Need some more space for the error phrase and payload start marker */ - if (phrase) - size += strlen(phrase) + 1; -#endif - - assert(request); - - /* cannot send ACK if original request was not confirmable */ - type = request->hdr->type == COAP_MESSAGE_CON - ? COAP_MESSAGE_ACK - : COAP_MESSAGE_NON; - - /* Estimate how much space we need for options to copy from - * request. We always need the Token, for 4.02 the unknown critical - * options must be included as well. */ - coap_option_clrb(opts, COAP_OPTION_CONTENT_TYPE); /* we do not want this */ - - coap_option_iterator_init(request, &opt_iter, opts); - - /* Add size of each unknown critical option. As known critical - options as well as elective options are not copied, the delta - value might grow. - */ - while((option = coap_option_next(&opt_iter))) { - unsigned short delta = opt_iter.type - opt_type; - /* calculate space required to encode (opt_iter.type - opt_type) */ - if (delta < 13) { - size++; - } else if (delta < 269) { - size += 2; - } else { - size += 3; - } - - /* add coap_opt_length(option) and the number of additional bytes - * required to encode the option length */ - - size += coap_opt_length(option); - switch (*option & 0x0f) { - case 0x0e: - size++; - /* fall through */ - case 0x0d: - size++; - break; - default: - ; - } - - opt_type = opt_iter.type; - } - - /* Now create the response and fill with options and payload data. */ - response = coap_pdu_init(type, code, request->hdr->id, size); - if (response) { - /* copy token */ - if (!coap_add_token(response, request->hdr->token_length, - request->hdr->token)) { - debug("cannot add token to error response\n"); - coap_delete_pdu(response); - return NULL; - } - - /* copy all options */ - coap_option_iterator_init(request, &opt_iter, opts); - while((option = coap_option_next(&opt_iter))) - coap_add_option(response, opt_iter.type, - COAP_OPT_LENGTH(option), - COAP_OPT_VALUE(option)); - -#if COAP_ERROR_PHRASE_LENGTH > 0 - /* note that diagnostic messages do not need a Content-Format option. */ - if (phrase) - coap_add_data(response, strlen(phrase), (unsigned char *)phrase); -#endif - } - - return response; -} - -/** - * Quick hack to determine the size of the resource description for - * .well-known/core. - */ -static inline size_t -get_wkc_len(coap_context_t *context, coap_opt_t *query_filter) { - size_t len = 0; - - if (print_wellknown(context, NULL, &len, UINT_MAX, query_filter) - & COAP_PRINT_STATUS_ERROR) { - warn("cannot determine length of /.well-known/core\n"); - return 0; - } - debug("get_wkc_len: print_wellknown() returned %zu\n", len); - - return len; -} - -coap_pdu_t * -wellknown_response(coap_context_t *context, coap_pdu_t *request) { - coap_pdu_t *resp; - coap_opt_iterator_t opt_iter; - size_t len, wkc_len; - unsigned char buf[2]; - int result = 0; - int need_block2 = 0; /* set to 1 if Block2 option is required */ - coap_block_t block; - coap_opt_t *query_filter; - size_t offset = 0; - - resp = coap_pdu_init(request->hdr->type == COAP_MESSAGE_CON - ? COAP_MESSAGE_ACK - : COAP_MESSAGE_NON, - COAP_RESPONSE_CODE(205), - request->hdr->id, COAP_MAX_PDU_SIZE); - if (!resp) { - debug("wellknown_response: cannot create PDU\n"); - return NULL; - } - - if (!coap_add_token(resp, request->hdr->token_length, request->hdr->token)) { - debug("wellknown_response: cannot add token\n"); - goto error; - } - - query_filter = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter); - wkc_len = get_wkc_len(context, query_filter); - - /* check whether the request contains the Block2 option */ - if (coap_get_block(request, COAP_OPTION_BLOCK2, &block)) { - offset = block.num << (block.szx + 4); - if (block.szx > 6) { /* invalid, MUST lead to 4.00 Bad Request */ - resp->hdr->code = COAP_RESPONSE_CODE(400); - return resp; - } else if (block.szx > COAP_MAX_BLOCK_SZX) { - block.szx = COAP_MAX_BLOCK_SZX; - block.num = offset >> (block.szx + 4); - } - - need_block2 = 1; - } - - /* Check if there is sufficient space to add Content-Format option - * and data. We do this before adding the Content-Format option to - * avoid sending error responses with that option but no actual - * content. */ - if (resp->max_size <= (size_t)resp->length + 3) { - debug("wellknown_response: insufficient storage space\n"); - goto error; - } - - /* Add Content-Format. As we have checked for available storage, - * nothing should go wrong here. */ - assert(coap_encode_var_bytes(buf, - COAP_MEDIATYPE_APPLICATION_LINK_FORMAT) == 1); - coap_add_option(resp, COAP_OPTION_CONTENT_FORMAT, - coap_encode_var_bytes(buf, - COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), buf); - - /* check if Block2 option is required even if not requested */ - if (!need_block2 && (resp->max_size - (size_t)resp->length < wkc_len)) { - assert(resp->length <= resp->max_size); - const size_t payloadlen = resp->max_size - resp->length; - /* yes, need block-wise transfer */ - block.num = 0; - block.m = 0; /* the M bit is set by coap_write_block_opt() */ - block.szx = COAP_MAX_BLOCK_SZX; - while (payloadlen < SZX_TO_BYTES(block.szx)) { - if (block.szx == 0) { - debug("wellknown_response: message to small even for szx == 0\n"); - goto error; - } else { - block.szx--; - } - } - - need_block2 = 1; - } - - /* write Block2 option if necessary */ - if (need_block2) { - if (coap_write_block_opt(&block, COAP_OPTION_BLOCK2, resp, wkc_len) < 0) { - debug("wellknown_response: cannot add Block2 option\n"); - goto error; - } - } - - /* Manually set payload of response to let print_wellknown() write, - * into our buffer without copying data. */ - - resp->data = (unsigned char *)resp->hdr + resp->length; - *resp->data = COAP_PAYLOAD_START; - resp->data++; - resp->length++; - len = need_block2 ? SZX_TO_BYTES(block.szx) : resp->max_size - resp->length; - - result = print_wellknown(context, resp, &len, offset, query_filter); - if ((result & COAP_PRINT_STATUS_ERROR) != 0) { - debug("print_wellknown failed\n"); - goto error; - } - - resp->length += COAP_PRINT_OUTPUT_LENGTH(result); - return resp; - - error: - /* set error code 5.03 and remove all options and data from response */ - resp->hdr->code = COAP_RESPONSE_CODE(503); - resp->length = sizeof(coap_hdr_t) + resp->hdr->token_length; - return resp; -} - -/** - * This function cancels outstanding messages for the remote peer and - * token specified in @p sent. Any observation relationship for - * sent->remote and the token are removed. Calling this function is - * required when receiving an RST message (usually in response to a - * notification) or a 7.31 response. - * - * This function returns @c 0 when the token is unknown with this - * peer, or a value greater than zero otherwise. - */ -int -coap_cancel(coap_context_t *context, const coap_queue_t *sent) { -#ifndef WITHOUT_OBSERVE - coap_resource_t *r; -#ifndef COAP_RESOURCES_NOHASH - coap_resource_t *tmp; -#endif - str token = { 0, NULL }; - int num_cancelled = 0; /* the number of observers cancelled */ - - /* remove observer for this resource, if any - * get token from sent and try to find a matching resource. Uh! - */ - - COAP_SET_STR(&token, sent->pdu->hdr->token_length, sent->pdu->hdr->token); - -#ifdef COAP_RESOURCES_NOHASH - LL_FOREACH(context->resources, r) { -#else - HASH_ITER(hh, context->resources, r, tmp) { -#endif - num_cancelled += coap_delete_observer(r, &sent->remote, &token); - coap_cancel_all_messages(context, &sent->remote, token.s, token.length); - } - return num_cancelled; -#else /* WITOUT_OBSERVE */ - return 0; -#endif /* WITOUT_OBSERVE */ -} - -#define WANT_WKC(Pdu,Key) \ - (((Pdu)->hdr->code == COAP_REQUEST_GET) && is_wkc(Key)) - -void -handle_request(coap_context_t *context, coap_queue_t *node) { - coap_method_handler_t h = NULL; - coap_pdu_t *response = NULL; - coap_opt_filter_t opt_filter; - coap_resource_t *resource; - coap_key_t key; - - coap_option_filter_clear(opt_filter); - - /* try to find the resource from the request URI */ - coap_hash_request_uri(node->pdu, key); - resource = coap_get_resource_from_key(context, key); - - if (!resource) { - /* The resource was not found. Check if the request URI happens to - * be the well-known URI. In that case, we generate a default - * response, otherwise, we return 4.04 */ - - switch(node->pdu->hdr->code) { - - case COAP_REQUEST_GET: - if (0) {//is_wkc(key)) { /* GET request for .well-known/core */ - debug("create default response for %s\n", COAP_DEFAULT_URI_WELLKNOWN); - response = wellknown_response(context, node->pdu); - - } else { /* GET request for any another resource, return 4.04 */ - - //debug("GET for unknown resource 0x%02x%02x%02x%02x, return 4.04\n", - // key[0], key[1], key[2], key[3]); - response = - coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(404), - opt_filter); - } - break; - - default: /* any other request type */ - - //debug("unhandled request for unknown resource 0x%02x%02x%02x%02x\r\n", - //key[0], key[1], key[2], key[3]); - if (!coap_is_mcast(&node->local)) - response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), - opt_filter); - } - - if (response && coap_send(context, &node->remote, response) == COAP_INVALID_TID) { - warn("cannot send response for transaction %u\n", node->id); - } - coap_delete_pdu(response); - - return; - } - - /* the resource was found, check if there is a registered handler */ - if ((size_t)node->pdu->hdr->code - 1 < - sizeof(resource->handler)/sizeof(coap_method_handler_t)) - h = resource->handler[node->pdu->hdr->code - 1]; - - if (h) { - //debug("call custom handler for resource 0x%02x%02x%02x%02x\n", - //key[0], key[1], key[2], key[3]); - response = coap_pdu_init(node->pdu->hdr->type == COAP_MESSAGE_CON - ? COAP_MESSAGE_ACK - : COAP_MESSAGE_NON, - 0, node->pdu->hdr->id, COAP_MAX_PDU_SIZE); - - /* Implementation detail: coap_add_token() immediately returns 0 - if response == NULL */ - if (coap_add_token(response, node->pdu->hdr->token_length, - node->pdu->hdr->token)) { - str token = { node->pdu->hdr->token_length, node->pdu->hdr->token }; - coap_opt_iterator_t opt_iter; - coap_opt_t *observe = NULL; - int observe_action = COAP_OBSERVE_CANCEL; - - /* check for Observe option */ - if (resource->observable) { - observe = coap_check_option(node->pdu, COAP_OPTION_OBSERVE, &opt_iter); - if (observe) { - observe_action = - coap_decode_var_bytes(coap_opt_value(observe), - coap_opt_length(observe)); - - if ((observe_action & COAP_OBSERVE_CANCEL) == 0) { - coap_subscription_t *subscription; - - debug("create new subscription\n"); - subscription = coap_add_observer(resource, &node->remote, &token); - if (subscription) { - subscription->non = node->pdu->hdr->type == COAP_MESSAGE_NON; - coap_touch_observer(context, &node->remote, &token); - } - } - } - } - - h(context, resource, &node->remote, - node->pdu, &token, response); - - if (observe && ((COAP_RESPONSE_CLASS(response->hdr->code) > 2) - || ((observe_action & COAP_OBSERVE_CANCEL) != 0))) { - debug("removed observer"); - coap_delete_observer(resource, &node->remote, &token); - } - - /* If original request contained a token, and the registered - * application handler made no changes to the response, then - * this is an empty ACK with a token, which is a malformed - * PDU */ - if ((response->hdr->type == COAP_MESSAGE_ACK) - && (response->hdr->code == 0)) { - /* Remove token from otherwise-empty acknowledgment PDU */ - response->hdr->token_length = 0; - response->length = sizeof(coap_hdr_t); - } - - if (response->hdr->type != COAP_MESSAGE_NON || - (response->hdr->code >= 64 - && !coap_is_mcast(&node->local))) { - if (coap_send(context, &node->remote, response) == COAP_INVALID_TID) { - debug("cannot send response for message %d\n", node->pdu->hdr->id); - } - } - - coap_delete_pdu(response); - } else { - warn("cannot generate response\r\n"); - } - } else { - if (0){//(WANT_WKC(node->pdu, key)) { - debug("create default response for %s\n", COAP_DEFAULT_URI_WELLKNOWN); - response = wellknown_response(context, node->pdu); - } else - response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), - opt_filter); - - if (!response || (coap_send(context, &node->remote, response) - == COAP_INVALID_TID)) { - debug("cannot send response for transaction %u\n", node->id); - } - coap_delete_pdu(response); - } -} - -void -handle_response(coap_context_t *context, - coap_queue_t *sent, coap_queue_t *rcvd) { - - coap_send_ack(context, &rcvd->remote, rcvd->pdu); - - /* In a lossy context, the ACK of a separate response may have - * been lost, so we need to stop retransmitting requests with the - * same token. - */ - coap_cancel_all_messages(context, &rcvd->remote, - rcvd->pdu->hdr->token, - rcvd->pdu->hdr->token_length); - - /* Call application-specific reponse handler when available. */ - if (context->response_handler) { - context->response_handler(context, - &rcvd->remote, sent ? sent->pdu : NULL, - rcvd->pdu, rcvd->id); - } -} - -int -#ifdef __GNUC__ -handle_locally(coap_context_t *context __attribute__ ((unused)), - coap_queue_t *node __attribute__ ((unused))) { -#else /* not a GCC */ -handle_locally(coap_context_t *context, coap_queue_t *node) { -#endif /* GCC */ - /* this function can be used to check if node->pdu is really for us */ - return 1; -} - -void -coap_dispatch( coap_context_t *context ) { - coap_queue_t *rcvd = NULL, *sent = NULL; - coap_pdu_t *response; - coap_opt_filter_t opt_filter; - - if (!context) - return; - - memset(opt_filter, 0, sizeof(coap_opt_filter_t)); - - while ( context->recvqueue ) { - rcvd = context->recvqueue; - - /* remove node from recvqueue */ - context->recvqueue = context->recvqueue->next; - rcvd->next = NULL; - - if ( rcvd->pdu->hdr->version != COAP_DEFAULT_VERSION ) { - debug("dropped packet with unknown version %u\n", rcvd->pdu->hdr->version); - goto cleanup; - } - - switch ( rcvd->pdu->hdr->type ) { - case COAP_MESSAGE_ACK: - /* find transaction in sendqueue to stop retransmission */ - coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent); - - if (rcvd->pdu->hdr->code == 0) - goto cleanup; - - /* FIXME: if sent code was >= 64 the message might have been a - * notification. Then, we must flag the observer to be alive - * by setting obs->fail_cnt = 0. */ - if (sent && COAP_RESPONSE_CLASS(sent->pdu->hdr->code) == 2) { - const str token = - { sent->pdu->hdr->token_length, sent->pdu->hdr->token }; - coap_touch_observer(context, &sent->remote, &token); - } - break; - - case COAP_MESSAGE_RST : - /* We have sent something the receiver disliked, so we remove - * not only the transaction but also the subscriptions we might - * have. */ - - warn("got RST for message %u\n", ntohs(rcvd->pdu->hdr->id)); - - /* find transaction in sendqueue to stop retransmission */ - coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent); - - if (sent) - coap_cancel(context, sent); - goto cleanup; - - case COAP_MESSAGE_NON : /* check for unknown critical options */ - if (coap_option_check_critical(context, rcvd->pdu, opt_filter) == 0) - goto cleanup; - break; - - case COAP_MESSAGE_CON : /* check for unknown critical options */ - if (coap_option_check_critical(context, rcvd->pdu, opt_filter) == 0) { - - /* FIXME: send response only if we have received a request. Otherwise, - * send RST. */ - response = - coap_new_error_response(rcvd->pdu, COAP_RESPONSE_CODE(402), opt_filter); - - if (!response) - warn("coap_dispatch: cannot create error reponse\n"); - else { - if (coap_send(context, &rcvd->remote, response) - == COAP_INVALID_TID) { - warn("coap_dispatch: error sending reponse\n"); - } - coap_delete_pdu(response); - } - - goto cleanup; - } - break; - } - - /* Pass message to upper layer if a specific handler was - * registered for a request that should be handled locally. */ - if (handle_locally(context, rcvd)) { - if (COAP_MESSAGE_IS_REQUEST(rcvd->pdu->hdr)) - handle_request(context, rcvd); - else if (COAP_MESSAGE_IS_RESPONSE(rcvd->pdu->hdr)) - handle_response(context, sent, rcvd); - else { - debug("dropped message with invalid code (%d.%02d)\n", - COAP_RESPONSE_CLASS(rcvd->pdu->hdr->code), - rcvd->pdu->hdr->code & 0x1f); - coap_send_message_type(context, &rcvd->remote, rcvd->pdu, - COAP_MESSAGE_RST); - } - } - - cleanup: - coap_delete_node(sent); - coap_delete_node(rcvd); - } -} - -int -coap_can_exit( coap_context_t *context ) { - return !context || (context->recvqueue == NULL && context->sendqueue == NULL); -} - diff --git a/src/net.c b/src/net.c index 13bfbae63f..e3e92a3805 100644 --- a/src/net.c +++ b/src/net.c @@ -36,6 +36,12 @@ #include #endif +#ifdef ST_NODE +#include "net_common.h" +#include "coap_io.h" +struct mbuf *coap_packet_extract_mbuf(coap_packet_t *packet); +#endif + #include "debug.h" #include "mem.h" #include "str.h" @@ -146,17 +152,16 @@ coap_free_node(coap_queue_t *node) { #endif /* WITH_LWIP */ #ifdef ST_NODE -#include "system.h" systime_t clock_offset; static inline coap_queue_t * -coap_malloc_node() { - return (coap_queue_t *)sys_malloc(sizeof(coap_queue_t)); +coap_malloc_node(void) { + return (coap_queue_t *)coap_malloc_type(COAP_NODE, sizeof(coap_queue_t)); } static inline void coap_free_node(coap_queue_t *node) { - sys_free(node); + coap_free_type(COAP_NODE, node); } #endif /* ST_NODE */ #ifdef WITH_CONTIKI @@ -326,8 +331,10 @@ coap_pop_next( coap_context_t *context ) { #ifdef COAP_DEFAULT_WKC_HASHKEY /** Checks if @p Key is equal to the pre-defined hash key for.well-known/core. */ -#define is_wkc(Key) \ - (memcmp((Key), COAP_DEFAULT_WKC_HASHKEY, sizeof(coap_key_t)) == 0) +int +is_wkc(coap_key_t k) { + return (memcmp(k, COAP_DEFAULT_WKC_HASHKEY, sizeof(coap_key_t)) == 0); +} #else /* Implements a singleton to store a hash key for the .wellknown/core * resources. */ @@ -344,8 +351,15 @@ is_wkc(coap_key_t k) { #endif coap_context_t * -coap_new_context( - const coap_address_t *listen_addr) { +coap_new_context(void) { + + /* + if (!listen_addr) { + coap_log(LOG_EMERG, "no listen address specified\n"); + return NULL; + } + */ + #ifndef WITH_CONTIKI coap_context_t *c = coap_malloc_type(COAP_CONTEXT, sizeof( coap_context_t ) ); #endif /* not WITH_CONTIKI */ @@ -355,21 +369,13 @@ coap_new_context( if (initialized) return NULL; #endif /* WITH_CONTIKI */ -#ifdef ST_NODE - coap_context_t *c = sys_malloc(sizeof(coap_context_t)); -#endif /* WITH_STNODE */ - - if (!listen_addr) { - coap_log(LOG_EMERG, "no listen address specified\n"); - return NULL; - } - coap_clock_init(); #ifdef WITH_LWIP prng_init(LWIP_RAND()); -#else - prng_init((unsigned long)listen_addr ^ clock_offset); -#endif +#endif /* WITH_LWIP */ +#if defined(WITH_POSIX) || defined(ST_NODE) + prng_init(clock_offset); +#endif /* WITH_POSIX */ #ifndef WITH_CONTIKI if (!c) { @@ -405,19 +411,19 @@ coap_new_context( coap_register_option(c, COAP_OPTION_BLOCK2); coap_register_option(c, COAP_OPTION_BLOCK1); - c->endpoint = coap_new_endpoint(listen_addr, COAP_ENDPOINT_NOSEC); + //c->endpoint = coap_new_endpoint(listen_addr, COAP_ENDPOINT_NOSEC); +// if (c->endpoint == NULL) { +// goto onerror; +// } + #ifdef WITH_LWIP c->endpoint->context = c; #endif - if (c->endpoint == NULL) { - goto onerror; - } - #ifdef WITH_POSIX c->sockfd = c->endpoint->handle.fd; #endif /* WITH_POSIX */ -#if defined(WITH_POSIX) || defined(WITH_CONTIKI) +#if defined(WITH_POSIX) || defined(WITH_CONTIKI) || defined(ST_NODE) c->network_send = coap_network_send; c->network_read = coap_network_read; #endif /* WITH_POSIX or WITH_CONTIKI */ @@ -435,22 +441,11 @@ coap_new_context( #endif /* WITH_CONTIKI */ return c; -#endif -#ifdef ST_NODE - c->ns = net_create(NET_UDP); - if (!c->ns) { - return NULL; - } - if(!net_bind(c->ns, listen_addr->port)) - { - debug("can't bind socket to port %d\n", listen_addr->port); - return NULL; - } - return c; -#endif onerror: - coap_free(c); + if (c) { + coap_free(c); + } return NULL; } @@ -469,7 +464,7 @@ coap_free_context(coap_context_t *context) { coap_delete_all_resources(context); - coap_free_endpoint(context->endpoint); + //coap_free_endpoint(context->endpoint); #ifndef WITH_CONTIKI coap_free_type(COAP_CONTEXT, context); #endif/* not WITH_CONTIKI */ @@ -477,10 +472,6 @@ coap_free_context(coap_context_t *context) { memset(&the_coap_context, 0, sizeof(coap_context_t)); initialized = 0; #endif /* WITH_CONTIKI */ -#ifdef WITH_STNODE - net_disconnect(context->ns); - sys_free(context); -#endif /* WITH_STNODE */ } int @@ -547,7 +538,6 @@ coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, #endif #if defined(WITH_LWIP) || defined(WITH_CONTIKI) || defined(ST_NODE) /* FIXME: with lwip, we can do better */ - /* TODO: MWAS: check better options */ coap_hash((const unsigned char *)&peer->port, sizeof(peer->port), h); coap_hash((const unsigned char *)&peer->addr, sizeof(peer->addr), h); #endif /* WITH_LWIP || WITH_CONTIKI */ @@ -632,30 +622,6 @@ coap_send_impl(coap_context_t *context, return id; } #endif /* WITH_LWIP */ -#ifdef ST_NODE -/* - * MWAS: st-node implementation doesn't require destination address for sending, - * destination address is currently used only for transaction id. - */ -coap_tid_t -coap_send_impl(coap_context_t *context, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - coap_pdu_t *pdu) { - coap_tid_t id = COAP_INVALID_TID; - - if ( !context || !dst || !pdu ) - return id; - - coap_transaction_id(dst, pdu, &id); - - if(!net_send_to(context->ns, &dst->addr, dst->port, pdu->mbuf)) { - coap_log(LOG_CRIT, "coap_send: sendto\n"); - } - - return id; -} -#endif /* WITH_STNODE */ coap_tid_t coap_send(coap_context_t *context, @@ -864,42 +830,25 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) { void coap_dispatch(coap_context_t *context, coap_queue_t *rcvd); -/** - * Checks if @p opt fits into the message that ends with @p maxpos. - * This function returns @c 1 on success, or @c 0 if the option @p opt - * would exceed @p maxpos. - */ -static inline int -check_opt_size(coap_opt_t *opt, unsigned char *maxpos) { - if (opt && opt < maxpos) { - if (((*opt & 0x0f) < 0x0f) || (opt + 1 < maxpos)) - return opt + COAP_OPT_SIZE(opt) < maxpos; - } - return 0; -} int coap_read( coap_context_t *ctx ) { ssize_t bytes_read = -1; coap_packet_t *packet; - coap_address_t src; int result = -1; /* the value to be returned */ - coap_address_init(&src); - -#if defined(WITH_POSIX) || defined(WITH_CONTIKI) +#if defined(WITH_POSIX) || defined(WITH_CONTIKI) || defined(ST_NODE) bytes_read = ctx->network_read(ctx->endpoint, &packet); #endif /* WITH_POSIX or WITH_CONTIKI */ if ( bytes_read < 0 ) { warn("coap_read: recvfrom"); } else { -#if defined(WITH_POSIX) || defined(WITH_CONTIKI) +#if defined(WITH_POSIX) || defined(WITH_CONTIKI) || defined(ST_NODE) result = coap_handle_message(ctx, packet); + coap_free_packet(packet); #endif /* WITH_POSIX or WITH_CONTIKI */ } - coap_free_packet(packet); - return result; } @@ -937,8 +886,10 @@ coap_handle_message(coap_context_t *ctx, /* from this point, the result code indicates that */ result = RESULT_ERR; -#ifdef WITH_LWIP +#if defined(WITH_LWIP) node->pdu = coap_pdu_from_pbuf(coap_packet_extract_pbuf(packet)); +#elif defined(ST_NODE) + node->pdu = coap_pdu_from_mbuf(coap_packet_extract_mbuf(packet)); #else node->pdu = coap_pdu_init(0, 0, 0, msg_len); #endif @@ -953,6 +904,8 @@ coap_handle_message(coap_context_t *ctx, coap_ticks(&node->t); + node->local_if = *packet->interface; + coap_packet_populate_endpoint(packet, &node->local_if); coap_packet_copy_source(packet, &node->remote); @@ -1330,7 +1283,7 @@ coap_wellknown_response(coap_context_t *context, coap_pdu_t *request) { * This function returns @c 0 when the token is unknown with this * peer, or a value greater than zero otherwise. */ -static int +/*static*/ int coap_cancel(coap_context_t *context, const coap_queue_t *sent) { #ifndef WITHOUT_OBSERVE str token = { 0, NULL }; @@ -1505,7 +1458,7 @@ handle_request(coap_context_t *context, coap_queue_t *node) { } } -static inline void +/*static inline */ void handle_response(coap_context_t *context, coap_queue_t *sent, coap_queue_t *rcvd) { @@ -1527,7 +1480,7 @@ handle_response(coap_context_t *context, } } -static inline int +/*static*/ inline int #ifdef __GNUC__ handle_locally(coap_context_t *context __attribute__ ((unused)), coap_queue_t *node __attribute__ ((unused))) { @@ -1538,7 +1491,7 @@ handle_locally(coap_context_t *context, coap_queue_t *node) { return 1; } -void +__attribute__((weak)) void coap_dispatch(coap_context_t *context, coap_queue_t *rcvd) { coap_queue_t *sent = NULL; coap_pdu_t *response; diff --git a/src/option.c b/src/option.c index 51ff809f25..35e8cb44f0 100644 --- a/src/option.c +++ b/src/option.c @@ -9,13 +9,17 @@ #include "coap_config.h" +#include +#include +#include #if defined(HAVE_ASSERT_H) && !defined(assert) # include #endif -#include -#include +#if defined(ST_NODE) +#include "mbuf.h" +#endif #include "option.h" #include "debug.h" @@ -485,8 +489,9 @@ coap_opt_encode_to_mbuf(coap_pdu_t *pdu, unsigned short type, return 0; } - if (val) + if (val) { mbuf_write(pdu->mbuf, val, length, pdu->length+l); + } return l + length; } diff --git a/src/pdu.c b/src/pdu.c index dad28c7b48..c78a7d861b 100644 --- a/src/pdu.c +++ b/src/pdu.c @@ -25,6 +25,11 @@ #include "encode.h" #include "mem.h" +#ifdef ST_NODE +#include "net_common.h" +#include "mbuf.h" +#endif + void coap_pdu_clear(coap_pdu_t *pdu, size_t size) { assert(pdu); @@ -33,13 +38,15 @@ coap_pdu_clear(coap_pdu_t *pdu, size_t size) { /* the pdu itself is not wiped as opposed to the other implementations, * because we have to rely on the pbuf to be set there. */ pdu->hdr = pdu->pbuf->payload; -#elif defined(ST_NODE) - memset(pdu, 0, sizeof(coap_pdu_t)); /* MWAS: for st-node payload is in separate memory area */ #else pdu->max_delta = 0; pdu->data = NULL; #endif +#if defined(ST_NODE) + pdu->hdr = pdu->mbuf->payload; +#else memset(pdu->hdr, 0, size); +#endif pdu->max_size = size; pdu->hdr->version = COAP_DEFAULT_VERSION; @@ -76,9 +83,7 @@ coap_pdu_from_pbuf(struct pbuf *pbuf) coap_pdu_t * coap_pdu_from_mbuf(struct mbuf *mbuf) { - coap_pdu_t *result; - //TODO: MWAS: get rid of sys_malloc - result = sys_malloc(sizeof(coap_pdu_t)); + coap_pdu_t *result = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t)); memset(result, 0, sizeof(coap_pdu_t)); @@ -127,8 +132,8 @@ coap_pdu_init(unsigned char type, unsigned char code, } #endif #ifdef ST_NODE - //TODO: MWAS: get rid of sys_malloc - pdu = sys_malloc(sizeof(coap_pdu_t)); + pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t)); + memset(pdu, 0, sizeof(coap_pdu_t)); /* MWAS: for st-node payload is in separate memory area */ m = mbuf_new(); #endif if (pdu) { @@ -136,7 +141,6 @@ coap_pdu_init(unsigned char type, unsigned char code, pdu->pbuf = p; #endif #ifdef ST_NODE - pdu->hdr = (coap_hdr_t *)((unsigned char *)m->payload); pdu->mbuf = m; pdu->mbuf->len = sizeof(coap_hdr_t); pdu->mbuf->tot_len = sizeof(coap_hdr_t); @@ -186,7 +190,7 @@ coap_delete_pdu(coap_pdu_t *pdu) { #ifdef ST_NODE if (pdu != NULL) { mbuf_free(pdu->mbuf); - sys_free(pdu); + coap_free_type(COAP_PDU, pdu); } #endif } @@ -217,7 +221,9 @@ coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data) { size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data) { size_t optsize; +#ifndef ST_NODE coap_opt_t *opt; +#endif assert(pdu); pdu->data = NULL; @@ -227,12 +233,11 @@ coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const un return 0; } - opt = (unsigned char *)pdu->hdr + pdu->length; - /* encode option and check length */ #ifdef ST_NODE optsize = coap_opt_encode_to_mbuf(pdu, type, data, len); #else + opt = (unsigned char *)pdu->hdr + pdu->length; optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, type - pdu->max_delta, data, len); #endif diff --git a/src/resource.c b/src/resource.c index 558542f62a..2688627183 100644 --- a/src/resource.c +++ b/src/resource.c @@ -289,8 +289,7 @@ coap_resource_init(const unsigned char *uri, size_t len, int flags) { #ifdef WITH_LWIP r = (coap_resource_t *)memp_malloc(MEMP_COAP_RESOURCE); -#endif -#ifndef WITH_LWIP +#else r = (coap_resource_t *)coap_malloc_type(COAP_RESOURCE, sizeof(coap_resource_t)); #endif if (r) { @@ -420,13 +419,17 @@ coap_free_resource(coap_resource_t *resource) { assert(resource); /* delete registered attributes */ - LL_FOREACH_SAFE(resource->link_attr, attr, tmp) coap_delete_attr(attr); + LL_FOREACH_SAFE(resource->link_attr, attr, tmp) { + coap_delete_attr(attr); + } if (resource->flags & COAP_RESOURCE_FLAGS_RELEASE_URI) coap_free(resource->uri.s); /* free all elements from resource->subscribers */ - LL_FOREACH_SAFE(resource->subscribers, obs, otmp) COAP_FREE_TYPE(subscription, obs); + LL_FOREACH_SAFE(resource->subscribers, obs, otmp) { + coap_free_type(COAP_SUBSCRIPTION, obs); + } #ifdef WITH_LWIP memp_free(MEMP_COAP_RESOURCE, resource); @@ -530,6 +533,38 @@ coap_print_link(const coap_resource_t *resource, return result; } +//void coap_print_link_to_mbuf(const coap_resource_t *resource, coap_pdu_t *pdu, size_t *left, size_t *len, size_t *offset) +//{ +// coap_attr_t *attr; +// +// PRINT_COND_WITH_OFFSET(pdu, *left, *offset, "<", *len); +// +// char* asterisk = strrchr((char*) resource->uri.s, '*'); +// if (resource->uri.length) { +// if (!asterisk) { +// COPY_COND_WITH_OFFSET(pdu, *left, *offset, resource->uri.s, resource->uri.length, *len); +// } else { +// COPY_COND_WITH_OFFSET(pdu, *left, *offset, resource->uri.s, resource->uri.length - 1, *len); +// } +// } +// +// PRINT_COND_WITH_OFFSET(pdu, *left, *offset, ">", *len); +// +// for (attr = resource->link_attr; attr; attr = attr->next) { +// PRINT_COND_WITH_OFFSET(pdu, *left, *offset, ";", *len); +// COPY_COND_WITH_OFFSET(pdu, *left, *offset, attr->name.s, attr->name.length, *len); +// +// if (attr->value.s) { +// PRINT_COND_WITH_OFFSET(pdu, *left, *offset, "=", *len); +// +// COPY_COND_WITH_OFFSET(pdu, *left, *offset, attr->value.s, attr->value.length, *len); +// } +// } +// if (resource->observable) { +// COPY_COND_WITH_OFFSET(pdu, *left, *offset, ";obs", 4, *len); +// } +//} + #ifndef WITHOUT_OBSERVE coap_subscription_t * coap_find_observer(coap_resource_t *resource, const coap_address_t *peer, @@ -567,7 +602,7 @@ coap_add_observer(coap_resource_t *resource, /* s points to a different subscription, so we have to create * another one. */ - s = COAP_MALLOC_TYPE(subscription); + s = coap_malloc_type(COAP_SUBSCRIPTION, sizeof(coap_subscription_t)); if (!s) return NULL; @@ -609,8 +644,7 @@ coap_delete_observer(coap_resource_t *resource, const coap_address_t *observer, if (resource->subscribers && s) { LL_DELETE(resource->subscribers, s); - - COAP_FREE_TYPE(subscription,s); + coap_free_type(COAP_SUBSCRIPTION, s); } return s != NULL; @@ -747,7 +781,7 @@ coap_remove_failed_observers(coap_context_t *context, coap_cancel_all_messages(context, &obs->subscriber, obs->token, obs->token_length); - COAP_FREE_TYPE(subscription, obs); + coap_free_type(COAP_SUBSCRIPTION, obs); } } break; /* break loop if observer was found */ From dc662bdc736025670526fb01e60852df53a99dd1 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Fri, 3 Apr 2015 16:14:44 +0200 Subject: [PATCH 52/69] Unified net API --- include/coap/address.h | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/include/coap/address.h b/include/coap/address.h index 8d40231c0d..2b2ba44b7a 100644 --- a/include/coap/address.h +++ b/include/coap/address.h @@ -3,10 +3,10 @@ * Copyright (C) 2010,2011,2015 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ -/** +/** * @file address.h * @brief representation of network addresses */ @@ -58,15 +58,14 @@ typedef struct coap_address_t { #endif /* WITH_LWIP */ #ifdef ST_NODE -#include "net_addr.h" +#include "net_common.h" typedef struct coap_address_t { - uint8_t size; uint16_t port; ipaddr_t addr; } coap_address_t; -#define _coap_address_equals_impl(A, B) ((A)->addr.u32 == (B)->addr.u32 && A->port == B->port) +#define _coap_address_equals_impl(A, B) ((memcmp(&(A)->addr, &(B)->addr, sizeof(ipaddr_t)) == 0) && A->port == B->port) /* Multicast IPv4 addresses start with 0b1110 */ #define _coap_is_mcast_impl(Address) ((Address)->addr.u8[0] && 0xF0 == 0xE0) @@ -144,11 +143,11 @@ case AF_INET6: } #endif /* WITH_POSIX */ -/** +/** * Resets the given coap_address_t object @p addr to its default * values. In particular, the member size must be initialized to the * available size for storing addresses. - * + * * @param addr The coap_address_t object to initialize. */ static inline void @@ -174,6 +173,15 @@ coap_address_equals(const coap_address_t *a, const coap_address_t *b) { } #endif +/** + * Copy given address from @p src to @p dest. + */ +static inline void +coap_address_copy(coap_address_t *dest, const coap_address_t *src) { + (void)dest; + (void)src; +} + /** * Checks if given address object @p a denotes the wildcard * address. This function returns @c 1 if this is the case, @c 0 @@ -189,9 +197,9 @@ coap_address_isany(const coap_address_t *a) { * Checks if given address @p a denotes a multicast address. This * function returns @c 1 if @p a is multicast, @c 0 otherwise. */ -static inline int +static inline int coap_is_mcast(const coap_address_t *a) { return a && _coap_is_mcast_impl(a); } - + #endif /* _COAP_ADDRESS_H_ */ From c9907d62ab75a17ba602474a812ce9b3d8cc19d7 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Fri, 3 Apr 2015 16:16:04 +0200 Subject: [PATCH 53/69] Changes to coap context creation/destruction --- include/coap/coap_io.h | 6 +-- include/coap/resource.h | 8 ++++ src/net.c | 4 +- src/resource.c | 103 ++++++++++++++++++++++++---------------- 4 files changed, 75 insertions(+), 46 deletions(-) diff --git a/include/coap/coap_io.h b/include/coap/coap_io.h index 81a141cabf..c3e988c00a 100644 --- a/include/coap/coap_io.h +++ b/include/coap/coap_io.h @@ -3,7 +3,7 @@ * Copyright (C) 2012--2013 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ #ifndef _COAP_IO_H_ @@ -87,7 +87,7 @@ void coap_free_endpoint(coap_endpoint_t *ep); * @param dst The address of the receiver. * @param data The data to send. * @param datalen The actual length of @p data. - * @return The number of bytes written on success, or a value less than zero + * @return The number of bytes written on success, or a value less than zero * on error. */ ssize_t coap_network_send(struct coap_context_t *context, @@ -105,7 +105,7 @@ ssize_t coap_network_send(struct coap_context_t *context, * packet structure is stored. The caller must call * coap_free_packet to release the storage used by this * packet. - * @return The number of bytes received on success, or a value less than zero + * @return The number of bytes received on success, or a value less than zero * on error. */ ssize_t coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet); diff --git a/include/coap/resource.h b/include/coap/resource.h index e19731157b..8ebcc5916a 100644 --- a/include/coap/resource.h +++ b/include/coap/resource.h @@ -134,6 +134,14 @@ int coap_delete_resource(coap_context_t *context, coap_key_t key); */ void coap_delete_all_resources(coap_context_t *context); +/** + * Deletes all resources from given @p context which uri matches given @p pattern. + * + * @param context The CoAP context with the resources to be deleted. + * @param pattern URI pattern to match + */ +void coap_delete_resource_by_pattern(coap_context_t *context, const char *pattern); + /** * Registers a new attribute with the given @p resource. As the * attributes str fields will point to @p name and @p val the diff --git a/src/net.c b/src/net.c index e3e92a3805..d131a25174 100644 --- a/src/net.c +++ b/src/net.c @@ -462,9 +462,9 @@ coap_free_context(coap_context_t *context) { coap_retransmittimer_restart(context); #endif - coap_delete_all_resources(context); - + //coap_delete_all_resources(context); //coap_free_endpoint(context->endpoint); + #ifndef WITH_CONTIKI coap_free_type(COAP_CONTEXT, context); #endif/* not WITH_CONTIKI */ diff --git a/src/resource.c b/src/resource.c index 2688627183..5c23f69fc3 100644 --- a/src/resource.c +++ b/src/resource.c @@ -3,7 +3,7 @@ * Copyright (C) 2010--2014 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" @@ -99,11 +99,11 @@ coap_free_subscription(coap_subscription_t *subscription) { PRINT_COND_WITH_OFFSET((Buf), (Bufend), (Offset), (Str)[i], (Result)); \ } \ } - + static int match(const str *text, const str *pattern, int match_prefix, int match_substring) { assert(text); assert(pattern); - + if (text->length < pattern->length) return 0; @@ -123,7 +123,7 @@ match(const str *text, const str *pattern, int match_prefix, int match_substring token_length = remaining_length; remaining_length = 0; } - + if ((match_prefix || pattern->length == token_length) && memcmp(token, pattern->s, pattern->length) == 0) return 1; @@ -135,22 +135,22 @@ match(const str *text, const str *pattern, int match_prefix, int match_substring memcmp(text->s, pattern->s, pattern->length) == 0; } -/** +/** * Prints the names of all known resources to @p buf. This function * sets @p buflen to the number of bytes actually written and returns * @c 1 on succes. On error, the value in @p buflen is undefined and * the return value will be @c 0. - * + * * @param context The context with the resource map. * @param buf The buffer to write the result. * @param buflen Must be initialized to the maximum length of @p buf and will be * set to the length of the well-known response on return. * @param offset The offset in bytes where the output shall start and is * shifted accordingly with the characters that have been - * processed. This parameter is used to support the block - * option. + * processed. This parameter is used to support the block + * option. * @param query_filter A filter query according to Link Format - * + * * @return COAP_PRINT_STATUS_ERROR on error. Otherwise, the lower 28 bits are * set to the number of bytes that have actually been written to * @p buf. COAP_PRINT_STATUS_TRUNC is set when the output has been @@ -192,15 +192,15 @@ coap_print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen while (resource_param.length < COAP_OPT_LENGTH(query_filter) && resource_param.s[resource_param.length] != '=') resource_param.length++; - + if (resource_param.length < COAP_OPT_LENGTH(query_filter)) { const str *rt_attributes; - if (resource_param.length == 4 && + if (resource_param.length == 4 && memcmp(resource_param.s, "href", 4) == 0) flags |= MATCH_URI; for (rt_attributes = _rt_attributes; rt_attributes->s; rt_attributes++) { - if (resource_param.length == rt_attributes->length && + if (resource_param.length == rt_attributes->length && memcmp(resource_param.s, rt_attributes->s, rt_attributes->length) == 0) { flags |= MATCH_SUBSTRING; break; @@ -208,11 +208,11 @@ coap_print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen } /* rest is query-pattern */ - query_pattern.s = + query_pattern.s = COAP_OPT_VALUE(query_filter) + resource_param.length + 1; assert((resource_param.length + 1) <= COAP_OPT_LENGTH(query_filter)); - query_pattern.length = + query_pattern.length = COAP_OPT_LENGTH(query_filter) - (resource_param.length + 1); if ((query_pattern.s[0] == '/') && ((flags & MATCH_URI) == MATCH_URI)) { @@ -220,11 +220,11 @@ coap_print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen query_pattern.length--; } - if (query_pattern.length && + if (query_pattern.length && query_pattern.s[query_pattern.length-1] == '*') { query_pattern.length--; flags |= MATCH_PREFIX; - } + } } } #endif /* WITHOUT_QUERY_FILTER */ @@ -233,7 +233,7 @@ coap_print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen #ifndef WITHOUT_QUERY_FILTER if (resource_param.length) { /* there is a query filter */ - + if (flags & MATCH_URI) { /* match resource URI */ if (!match(&r->uri, &query_pattern, (flags & MATCH_PREFIX) != 0, (flags & MATCH_SUBSTRING) != 0)) continue; @@ -248,7 +248,7 @@ coap_print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen } else { unquoted_val = attr->value; } - if (!(match(&unquoted_val, &query_pattern, + if (!(match(&unquoted_val, &query_pattern, (flags & MATCH_PREFIX) != 0, (flags & MATCH_SUBSTRING) != 0))) continue; @@ -297,7 +297,7 @@ coap_resource_init(const unsigned char *uri, size_t len, int flags) { r->uri.s = (unsigned char *)uri; r->uri.length = len; - + coap_hash_path(r->uri.s, r->uri.length, r->key); r->flags = flags; @@ -307,12 +307,12 @@ coap_resource_init(const unsigned char *uri, size_t len, int flags) { } else { debug("coap_resource_init: no memory left\n"); } - + return r; } coap_attr_t * -coap_add_attr(coap_resource_t *resource, +coap_add_attr(coap_resource_t *resource, const unsigned char *name, size_t nlen, const unsigned char *val, size_t vlen, int flags) { @@ -342,12 +342,12 @@ coap_add_attr(coap_resource_t *resource, } else { debug("coap_add_attr: no memory left\n"); } - + return attr; } coap_attr_t * -coap_find_attr(coap_resource_t *resource, +coap_find_attr(coap_resource_t *resource, const unsigned char *name, size_t nlen) { coap_attr_t *attr; @@ -435,10 +435,12 @@ coap_free_resource(coap_resource_t *resource) { memp_free(MEMP_COAP_RESOURCE, resource); #endif #ifndef WITH_LWIP - coap_free_type(COAP_RESOURCE, resource); + if (resource->dynamic) { + coap_free_type(COAP_RESOURCE, resource); + } #endif /* WITH_CONTIKI */ } - + int coap_delete_resource(coap_context_t *context, coap_key_t key) { coap_resource_t *resource; @@ -448,7 +450,7 @@ coap_delete_resource(coap_context_t *context, coap_key_t key) { resource = coap_get_resource_from_key(context, key); - if (!resource) + if (!resource) return 0; /* remove resource from list */ @@ -479,6 +481,25 @@ coap_delete_all_resources(coap_context_t *context) { context->resources = NULL; } +void +coap_delete_resource_by_pattern(coap_context_t *context, const char *pattern) { + coap_resource_t *res; + coap_resource_t *rtmp; + +#ifdef COAP_RESOURCES_NOHASH + LL_FOREACH_SAFE(context->resources, res, rtmp) { +#else + HASH_ITER(hh, context->resources, res, rtmp) { +#endif + if (strstr((char *)res->uri.s, pattern)) { + /* remove resource from list */ + RESOURCES_DELETE(context->resources, res); + /* and free its allocated memory */ + coap_free_resource(res); + } + } +} + coap_resource_t * coap_get_resource_from_key(coap_context_t *context, coap_key_t key) { coap_resource_t *result; @@ -489,21 +510,21 @@ coap_get_resource_from_key(coap_context_t *context, coap_key_t key) { } coap_print_status_t -coap_print_link(const coap_resource_t *resource, +coap_print_link(const coap_resource_t *resource, unsigned char *buf, size_t *len, size_t *offset) { unsigned char *p = buf; const unsigned char *bufend = buf + *len; coap_attr_t *attr; coap_print_status_t result = 0; const size_t old_offset = *offset; - + *len = 0; PRINT_COND_WITH_OFFSET(p, bufend, *offset, '<', *len); PRINT_COND_WITH_OFFSET(p, bufend, *offset, '/', *len); - COPY_COND_WITH_OFFSET(p, bufend, *offset, + COPY_COND_WITH_OFFSET(p, bufend, *offset, resource->uri.s, resource->uri.length, *len); - + PRINT_COND_WITH_OFFSET(p, bufend, *offset, '>', *len); LL_FOREACH(resource->link_attr, attr) { @@ -576,21 +597,21 @@ coap_find_observer(coap_resource_t *resource, const coap_address_t *peer, LL_FOREACH(resource->subscribers, s) { if (coap_address_equals(&s->subscriber, peer) - && (!token || (token->length == s->token_length + && (!token || (token->length == s->token_length && memcmp(token->s, s->token, token->length) == 0))) return s; } - + return NULL; } coap_subscription_t * -coap_add_observer(coap_resource_t *resource, +coap_add_observer(coap_resource_t *resource, const coap_endpoint_t *local_interface, const coap_address_t *observer, const str *token) { coap_subscription_t *s; - + assert(observer); /* Check if there is already a subscription for this peer. */ @@ -610,7 +631,7 @@ coap_add_observer(coap_resource_t *resource, coap_subscription_init(s); s->local_if = *local_interface; memcpy(&s->subscriber, observer, sizeof(coap_address_t)); - + if (token && token->length) { s->token_length = token->length; memcpy(s->token, token->s, min(s->token_length, 8)); @@ -701,7 +722,7 @@ coap_notify_observers(coap_context_t *context, coap_resource_t *r) { /* fill with observer-specific data */ h(context, r, &obs->local_if, &obs->subscriber, NULL, &token, response); - /* TODO: do not send response and remove observer when + /* TODO: do not send response and remove observer when * COAP_RESPONSE_CLASS(response->hdr->code) > 2 */ if (response->hdr->type == COAP_MESSAGE_CON) { @@ -758,7 +779,7 @@ coap_remove_failed_observers(coap_context_t *context, if (coap_address_equals(peer, &obs->subscriber) && token->length == obs->token_length && memcmp(token->s, obs->token, token->length) == 0) { - + /* count failed notifies and remove when * COAP_MAX_FAILED_NOTIFY is reached */ if (obs->fail_cnt < COAP_OBS_MAX_FAIL) @@ -766,7 +787,7 @@ coap_remove_failed_observers(coap_context_t *context, else { LL_DELETE(resource->subscribers, obs); obs->fail_cnt = 0; - + #ifndef NDEBUG if (LOG_DEBUG <= coap_get_log_level()) { #ifndef INET6_ADDRSTRLEN @@ -778,7 +799,7 @@ coap_remove_failed_observers(coap_context_t *context, debug("** removed observer %s\n", addr); } #endif - coap_cancel_all_messages(context, &obs->subscriber, + coap_cancel_all_messages(context, &obs->subscriber, obs->token, obs->token_length); coap_free_type(COAP_SUBSCRIPTION, obs); @@ -789,8 +810,8 @@ coap_remove_failed_observers(coap_context_t *context, } void -coap_handle_failed_notify(coap_context_t *context, - const coap_address_t *peer, +coap_handle_failed_notify(coap_context_t *context, + const coap_address_t *peer, const str *token) { RESOURCES_ITER(context->resources, r) { From d1fbc5e9010aa382dda61e316632f8f6fd38fdf7 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Thu, 9 Apr 2015 15:15:32 +0200 Subject: [PATCH 54/69] Modifed debug functions to include file and line --- include/coap/debug.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/coap/debug.h b/include/coap/debug.h index 07ad8d84bc..163f58f0b8 100644 --- a/include/coap/debug.h +++ b/include/coap/debug.h @@ -3,7 +3,7 @@ * Copyright (C) 2010,2011,2014 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ #ifndef _COAP_DEBUG_H_ @@ -24,7 +24,7 @@ typedef short coap_log_t; #else /** Pre-defined log levels akin to what is used in \b syslog. */ -typedef enum { LOG_EMERG=0, LOG_ALERT, LOG_CRIT, LOG_WARNING, +typedef enum { LOG_EMERG=0, LOG_ALERT, LOG_CRIT, LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG } coap_log_t; #endif @@ -41,16 +41,16 @@ const char *coap_package_name(void); /** Returns a zero-terminated string with the library version. */ const char *coap_package_version(void); -/** +/** * Writes the given text to @c COAP_ERR_FD (for @p level <= @c * LOG_CRIT) or @c COAP_DEBUG_FD (for @p level >= @c LOG_WARNING). The * text is output only when @p level is below or equal to the log * level that set by coap_set_log_level(). */ -void coap_log_impl(coap_log_t level, const char *format, ...); +void coap_log_impl(const char *file, int line, coap_log_t level, const char *format, ...); #ifndef coap_log -#define coap_log(...) coap_log_impl(__VA_ARGS__) +#define coap_log(...) coap_log_impl(__FILE__, __LINE__, __VA_ARGS__) #endif #ifndef NDEBUG From 648b5775ed3d5e37e29d91064c376e78de7f785f Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Thu, 9 Apr 2015 15:17:38 +0200 Subject: [PATCH 55/69] Make a few functions public --- src/net.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/net.c b/src/net.c index d131a25174..1bf7bd3d6a 100644 --- a/src/net.c +++ b/src/net.c @@ -442,7 +442,7 @@ coap_new_context(void) { return c; - onerror: +// onerror: if (c) { coap_free(c); } @@ -623,8 +623,13 @@ coap_send_impl(coap_context_t *context, } #endif /* WITH_LWIP */ -coap_tid_t -coap_send(coap_context_t *context, +coap_tid_t coap_send_impl(coap_context_t *context, + const coap_endpoint_t *local_interface, + const coap_address_t *dst, + coap_pdu_t *pdu); + +coap_tid_t +coap_send(coap_context_t *context, const coap_endpoint_t *local_interface, const coap_address_t *dst, coap_pdu_t *pdu) { @@ -1480,7 +1485,7 @@ handle_response(coap_context_t *context, } } -/*static*/ inline int +/*static inline */ int #ifdef __GNUC__ handle_locally(coap_context_t *context __attribute__ ((unused)), coap_queue_t *node __attribute__ ((unused))) { From e875572ca6b3574f2de545c471544a3bd78d38b9 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Thu, 9 Apr 2015 15:18:36 +0200 Subject: [PATCH 56/69] Added eclipse .settings folder to git ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 86314d5ec5..d55cda6c81 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,4 @@ tests/*.o .project .cproject +.settings From fe727894c1197d6027508ece98371b414bfd9946 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Wed, 15 Apr 2015 17:43:50 +0200 Subject: [PATCH 57/69] Don't change URI in coap_split_query() --- src/uri.c | 70 +++++++++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/uri.c b/src/uri.c index ec6c57ee9a..119dae0800 100644 --- a/src/uri.c +++ b/src/uri.c @@ -3,7 +3,7 @@ * Copyright (C) 2010--2012,2015 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" @@ -22,22 +22,22 @@ #include "option.h" #include "uri.h" -/** +/** * A length-safe version of strchr(). This function returns a pointer * to the first occurrence of @p c in @p s, or @c NULL if not found. - * + * * @param s The string to search for @p c. * @param len The length of @p s. * @param c The character to search. - * - * @return A pointer to the first occurence of @p c, or @c NULL + * + * @return A pointer to the first occurence of @p c, or @c NULL * if not found. */ static inline unsigned char * strnchr(unsigned char *s, size_t len, unsigned char c) { while (len && *s++ != c) --len; - + return len ? s : NULL; } @@ -63,7 +63,7 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) { while (len && *q && tolower(*p) == *q) { ++p; ++q; --len; } - + /* If q does not point to the string end marker '\0', the schema * identifier is wrong. */ if (*q) { @@ -90,7 +90,7 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) { q = p; if (len && *p == '[') { /* IPv6 address reference */ ++p; - + while (len && *q != ']') { ++q; --len; } @@ -98,13 +98,13 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) { if (!len || *q != ']' || p == q) { res = -3; goto error; - } + } COAP_SET_STR(&uri->host, q - p, p); ++q; --len; } else { /* IPv4 address or FQDN */ while (len && *q != ':' && *q != '/' && *q != '?') { - *q = tolower(*q); + //*q = tolower(*q); ++q; --len; } @@ -121,7 +121,7 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) { if (len && *q == ':') { p = ++q; --len; - + while (len && isdigit(*q)) { ++q; --len; @@ -129,7 +129,7 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) { if (p < q) { /* explicit port number given */ int uri_port = 0; - + while (p < q) uri_port = uri_port * 10 + (*p++ - '0'); @@ -140,14 +140,14 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) { } uri->port = uri_port; - } + } } - + path: /* at this point, p must point to an absolute path */ if (!len) goto end; - + if (*q == '/') { p = ++q; --len; @@ -156,7 +156,7 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) { ++q; --len; } - + if (p < q) { COAP_SET_STR(&uri->path, q - p, p); p = q; @@ -173,28 +173,28 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) { end: return len ? -1 : 0; - + error: return res; } -/** +/** * Calculates decimal value from hexadecimal ASCII character given in * @p c. The caller must ensure that @p c actually represents a valid - * heaxdecimal character, e.g. with isxdigit(3). + * heaxdecimal character, e.g. with isxdigit(3). * * @hideinitializer */ #define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F)) -/** +/** * Decodes percent-encoded characters while copying the string @p seg * of size @p length to @p buf. The caller of this function must * ensure that the percent-encodings are correct (i.e. the character * '%' is always followed by two hex digits. and that @p buf provides * sufficient space to hold the result. This function is supposed to * be called by make_decoded_option() only. - * + * * @param seg The segment to decode and copy. * @param length Length of @p seg. * @param buf The result buffer. @@ -206,12 +206,12 @@ decode_segment(const unsigned char *seg, size_t length, unsigned char *buf) { if (*seg == '%') { *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]); - + seg += 2; length -= 2; } else { *buf = *seg; } - + ++buf; ++seg; } } @@ -230,18 +230,18 @@ check_segment(const unsigned char *s, size_t length) { if (*s == '%') { if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2]))) return -1; - + s += 2; length -= 2; } ++s; ++n; --length; } - + return n; } - -/** + +/** * Writes a coap option from given string @p s to @p buf. @p s should * point to a (percent-encoded) path or query segment of a coap_uri_t * object. The created option will have type @c 0, and the length @@ -249,19 +249,19 @@ check_segment(const unsigned char *s, size_t length) { * On success, this function returns the option's size, or a value * less than zero on error. This function must be called from * coap_split_path_impl() only. - * + * * @param s The string to decode. * @param length The size of the percent-encoded string @p s. * @param buf The buffer to store the new coap option. * @param buflen The maximum size of @p buf. - * + * * @return The option's size, or @c -1 on error. * * @bug This function does not split segments that are bigger than 270 * bytes. */ static int -make_decoded_option(const unsigned char *s, size_t length, +make_decoded_option(const unsigned char *s, size_t length, unsigned char *buf, size_t buflen) { int res; size_t written; @@ -311,15 +311,15 @@ dots(unsigned char *s, size_t len) { return *s == '.' && (len == 1 || (*(s+1) == '.' && len == 2)); } -/** +/** * Splits the given string into segments. You should call one of the * macros coap_split_path() or coap_split_query() instead. - * + * * @param s The URI string to be tokenized. * @param length The length of @p s. * @param h A handler that is called with every token. * @param data Opaque data that is passed to @p h when called. - * + * * @return The number of characters that have been parsed from @p s. */ static size_t @@ -371,7 +371,7 @@ write_option(unsigned char *s, size_t len, void *data) { } int -coap_split_path(const unsigned char *s, size_t length, +coap_split_path(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen) { struct cnt_str tmp = { { *buflen, buf }, 0 }; @@ -383,7 +383,7 @@ coap_split_path(const unsigned char *s, size_t length, } int -coap_split_query(const unsigned char *s, size_t length, +coap_split_query(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen) { struct cnt_str tmp = { { *buflen, buf }, 0 }; const unsigned char *p; From 655f0a8c7f724fca3ca4bbd1146c5ba2a7fbe081 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Wed, 15 Apr 2015 17:44:14 +0200 Subject: [PATCH 58/69] Free pdu mbuf only if not NULL --- include/coap/pdu.h | 35 +++++++++++++++++++++-------------- src/pdu.c | 26 ++++++++++++++------------ 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/include/coap/pdu.h b/include/coap/pdu.h index 36237dc87f..7bf0252b5f 100644 --- a/include/coap/pdu.h +++ b/include/coap/pdu.h @@ -3,7 +3,7 @@ * Copyright (C) 2010--2014 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ #ifndef _PDU_H_ @@ -109,13 +109,13 @@ #define COAP_RESPONSE_CLASS(C) (((C) >> 5) & 0xFF) #ifndef SHORT_ERROR_RESPONSE -/** +/** * Returns a human-readable response phrase for the specified CoAP * response @p code. This function returns @c NULL if not found. - * + * * @param code The response code for which the literal phrase should * be retrieved. - * + * * @return A zero-terminated string describing the error, or @c NULL * if not found. */ @@ -272,25 +272,25 @@ coap_pdu_t * coap_pdu_from_pbuf(struct pbuf *pbuf); coap_pdu_t * coap_pdu_from_mbuf(struct mbuf *mbuf); #endif -/** - * Creates a new CoAP PDU of given @p size (must be large enough to hold the +/** + * Creates a new CoAP PDU of given @p size (must be large enough to hold the * basic CoAP message header (coap_hdr_t). The function returns a pointer to * the node coap_pdu_t object on success, or @c NULL on error. The storage * allocated for the result must be released with coap_delete_pdu(). - * + * * @param type The type of the PDU (one of COAP_MESSAGE_CON, - * COAP_MESSAGE_NON, COAP_MESSAGE_ACK, COAP_MESSAGE_RST). + * COAP_MESSAGE_NON, COAP_MESSAGE_ACK, COAP_MESSAGE_RST). * @param code The message code. * @param id The message id to set or COAP_INVALID_TID if unknown. * @param size The number of bytes to allocate for the actual message. - * + * * @return A pointer to the new PDU object or @c NULL on error. */ coap_pdu_t * -coap_pdu_init(unsigned char type, unsigned char code, +coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t size); -/** +/** * Clears any contents from @p pdu and resets @c version field, @c * length and @c data pointers. @c max_size is set to @p size, any * other field is set to @c 0. Note that @p pdu must be a valid @@ -301,9 +301,9 @@ void coap_pdu_clear(coap_pdu_t *pdu, size_t size); /** * Creates a new CoAP PDU. The object is created on the heap and must be released * using coap_delete_pdu(); - * + * * @deprecated This function allocates the maximum storage for each - * PDU. Use coap_pdu_init() instead. + * PDU. Use coap_pdu_init() instead. */ coap_pdu_t *coap_new_pdu(void); @@ -345,7 +345,7 @@ int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data); * the token must be added before coap_add_option() is called. * This function returns the number of bytes written or @c 0 on error. */ -size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, +size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data); /** @@ -372,4 +372,11 @@ int coap_add_data(coap_pdu_t *pdu, unsigned int len, const unsigned char *data); */ int coap_get_data(coap_pdu_t *pdu, size_t *len, unsigned char **data); +/** + * Return 1 if pdu contains payload, 0 otherwise. + */ +static inline int coap_has_data(coap_pdu_t *pdu) +{ + return (pdu->data != NULL); +} #endif /* _PDU_H_ */ diff --git a/src/pdu.c b/src/pdu.c index c78a7d861b..22f384ed98 100644 --- a/src/pdu.c +++ b/src/pdu.c @@ -3,7 +3,7 @@ * Copyright (C) 2010--2014 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" @@ -97,7 +97,7 @@ coap_pdu_from_mbuf(struct mbuf *mbuf) #endif coap_pdu_t * -coap_pdu_init(unsigned char type, unsigned char code, +coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t size) { coap_pdu_t *pdu; #ifdef WITH_LWIP @@ -149,14 +149,14 @@ coap_pdu_init(unsigned char type, unsigned char code, pdu->hdr->id = id; pdu->hdr->type = type; pdu->hdr->code = code; - } + } return pdu; } coap_pdu_t * coap_new_pdu(void) { coap_pdu_t *pdu; - + #ifndef WITH_CONTIKI pdu = coap_pdu_init(0, 0, ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE); #else /* WITH_CONTIKI */ @@ -189,7 +189,9 @@ coap_delete_pdu(coap_pdu_t *pdu) { #endif #ifdef ST_NODE if (pdu != NULL) { - mbuf_free(pdu->mbuf); + if (pdu->mbuf != NULL) { + mbuf_free(pdu->mbuf); + } coap_free_type(COAP_PDU, pdu); } #endif @@ -224,7 +226,7 @@ coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const un #ifndef ST_NODE coap_opt_t *opt; #endif - + assert(pdu); pdu->data = NULL; @@ -238,7 +240,7 @@ coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const un optsize = coap_opt_encode_to_mbuf(pdu, type, data, len); #else opt = (unsigned char *)pdu->hdr + pdu->length; - optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, + optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, type - pdu->max_delta, data, len); #endif @@ -339,7 +341,7 @@ typedef struct { char *phrase; } error_desc_t; -/* if you change anything here, make sure, that the longest string does not +/* if you change anything here, make sure, that the longest string does not * exceed COAP_ERROR_PHRASE_LENGTH. */ error_desc_t coap_error[] = { { COAP_RESPONSE_CODE(65), "2.01 Created" }, @@ -377,7 +379,7 @@ coap_response_phrase(unsigned char code) { #endif /** - * Advances *optp to next option if still in PDU. This function + * Advances *optp to next option if still in PDU. This function * returns the number of bytes opt has been advanced or @c 0 * on error. */ @@ -386,7 +388,7 @@ next_option_safe(coap_opt_t **optp, size_t *length) { coap_option_t option; size_t optsize; - assert(optp); assert(*optp); + assert(optp); assert(*optp); assert(length); optsize = coap_opt_parse(*optp, *length, &option); @@ -453,7 +455,7 @@ coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu) { /* append data (including the Token) to pdu structure */ memcpy(pdu->hdr + 1, data + sizeof(coap_hdr_t), length - sizeof(coap_hdr_t)); pdu->length = length; - + /* Finally calculate beginning of data block and thereby check integrity * of the PDU structure. */ #endif @@ -482,7 +484,7 @@ coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu) { goto discard; } - debug("set data to %p (pdu ends at %p)\n", (unsigned char *)opt, + debug("set data to %p (pdu ends at %p)\n", (unsigned char *)opt, (unsigned char *)pdu->hdr + pdu->length); pdu->data = (unsigned char *)opt; } From 08f331cfc85c7a88e4759ddc6dec2c2d6688d750 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Wed, 15 Apr 2015 17:44:44 +0200 Subject: [PATCH 59/69] Added coap_has_data() --- include/coap/net.h | 141 ++++++++++++++++---------------- src/net.c | 194 ++++++++++++++++++++++----------------------- 2 files changed, 168 insertions(+), 167 deletions(-) diff --git a/include/coap/net.h b/include/coap/net.h index 66a9801d5a..080d89f4d6 100644 --- a/include/coap/net.h +++ b/include/coap/net.h @@ -3,7 +3,7 @@ * Copyright (C) 2010--2015 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ #ifndef _COAP_NET_H_ @@ -79,7 +79,7 @@ struct coap_async_state_t; #endif /** Message handler that is used as call-back in coap_context_t */ -typedef void (*coap_response_handler_t)(struct coap_context_t *, +typedef void (*coap_response_handler_t)(struct coap_context_t *, const coap_endpoint_t *local_interface, const coap_address_t *remote, coap_pdu_t *sent, @@ -90,7 +90,7 @@ typedef void (*coap_response_handler_t)(struct coap_context_t *, typedef struct { unsigned char flags[COAP_MID_CACHE_SIZE]; coap_key_t item[COAP_MID_CACHE_SIZE]; -} coap_mid_cache_t; +} coap_mid_cache_t; /** The CoAP stack's global state is stored in a coap_context_t object */ typedef struct coap_context_t { @@ -107,13 +107,14 @@ typedef struct coap_context_t { * to sendqueue_basetime. */ coap_tick_t sendqueue_basetime; coap_queue_t *sendqueue; - coap_endpoint_t *endpoint; /**< the endpoint used for listening */ + //coap_endpoint_t *endpoint; /**< the endpoint used for listening */ + void *pdata; #ifdef WITH_POSIX int sockfd; /**< send/receive socket */ #endif /* WITH_POSIX */ #ifdef WITH_CONTIKI struct uip_udp_conn *conn; /**< uIP connection object */ - + struct etimer retransmit_timer; /**< fires when the next packet must be sent */ struct etimer notify_timer; /**< used to check resources periodically */ #endif /* WITH_CONTIKI */ @@ -126,7 +127,7 @@ typedef struct coap_context_t { * initial value is set by coap_new_context() and is usually a * random value. A new message id can be created with * coap_new_message_id(). - */ + */ unsigned short message_id; /** @@ -148,25 +149,25 @@ typedef struct coap_context_t { /** * Registers a new message handler that is called whenever a response - * was received that matches an ongoing transaction. - * + * was received that matches an ongoing transaction. + * * @param context The context to register the handler for. * @param handler The response handler to register. */ -static inline void -coap_register_response_handler(coap_context_t *context, +static inline void +coap_register_response_handler(coap_context_t *context, coap_response_handler_t handler) { context->response_handler = handler; } -/** +/** * Registers the option type @p type with the given context object @p * ctx. - * + * * @param ctx The context to use. * @param type The option type to register. */ -inline static void +inline static void coap_register_option(coap_context_t *ctx, unsigned char type) { coap_option_setb(ctx->known_options, type); } @@ -188,15 +189,15 @@ coap_queue_t *coap_pop_next( coap_context_t *context ); /** Creates a new coap_context_t object that will hold the CoAP stack status. */ coap_context_t *coap_new_context(void); -/** +/** * Returns a new message id and updates @p context->message_id * accordingly. The message id is returned in network byte order - * to make it easier to read in tracing tools. + * to make it easier to read in tracing tools. * * @param context the current coap_context_t object * @return incremented message id in network byte order */ -static inline unsigned short +static inline unsigned short coap_new_message_id(coap_context_t *context) { ++(context->message_id); #ifndef WITH_CONTIKI @@ -208,9 +209,9 @@ coap_new_message_id(coap_context_t *context) { /* CoAP stack context must be released with coap_free_context(). This * function clears all entries from the receive queue and send queue - * and deletes the resources that have been registered with + * and deletes the resources that have been registered with * @p context, and frees the attached endpoints. - * + * */ void coap_free_context(coap_context_t *context); @@ -227,12 +228,12 @@ void coap_free_context(coap_context_t *context); * @param pdu The CoAP PDU to send. * @return The message id of the sent message or @c COAP_INVALID_TID on error. */ -coap_tid_t coap_send_confirmed(coap_context_t *context, +coap_tid_t coap_send_confirmed(coap_context_t *context, const coap_endpoint_t *local_interface, const coap_address_t *dst, coap_pdu_t *pdu); -/** +/** * Creates a new ACK PDU with specified error @p code. The options * specified by the filter expression @p opts will be copied from the * original request contained in @p request. Unless @c @@ -241,16 +242,16 @@ coap_tid_t coap_send_confirmed(coap_context_t *context, * 0. This function returns a pointer to the new response message, or * @c NULL on error. The storage allocated for the new message must be * relased with coap_free(). - * + * * @param request Specification of the received (confirmable) request. * @param code The error code to set. * @param opts An option filter that specifies which options to copy * from the original request in @p node. - * + * * @return A pointer to the new message or @c NULL on error. */ -coap_pdu_t *coap_new_error_response(coap_pdu_t *request, - unsigned char code, +coap_pdu_t *coap_new_error_response(coap_pdu_t *request, + unsigned char code, coap_opt_filter_t opts); /** * Sends a non-confirmed CoAP message to given destination. The memory @@ -264,38 +265,38 @@ coap_pdu_t *coap_new_error_response(coap_pdu_t *request, * @param pdu The CoAP PDU to send. * @return The message id of the sent message or @c COAP_INVALID_TID on error. */ -coap_tid_t coap_send(coap_context_t *context, +coap_tid_t coap_send(coap_context_t *context, const coap_endpoint_t *local_interface, - const coap_address_t *dst, + const coap_address_t *dst, coap_pdu_t *pdu); -/** +/** * Sends an error response with code @p code for request @p request to * @p dst. @p opts will be passed to coap_new_error_response() to * copy marked options from the request. This function returns the * transaction id if the message was sent, or @c COAP_INVALID_TID * otherwise. - * + * * @param context The context to use. * @param request The original request to respond to. * @param local_interface The local network interface where the outbound * packet is sent. * @param dst The remote peer that sent the request. * @param code The reponse code. - * @param opts A filter that specifies the options to copy from the + * @param opts A filter that specifies the options to copy from the * @p request. - * + * * @return The transaction id if the message was sent, or @c * COAP_INVALID_TID otherwise. */ -coap_tid_t coap_send_error(coap_context_t *context, +coap_tid_t coap_send_error(coap_context_t *context, coap_pdu_t *request, const coap_endpoint_t *local_interface, const coap_address_t *dst, unsigned char code, coap_opt_filter_t opts); -/** +/** * Helper funktion to create and send a message with @p type (usually * ACK or RST). This function returns @c COAP_INVALID_TID when the * message was not sent, a valid transaction id otherwise. @@ -309,48 +310,48 @@ coap_tid_t coap_send_error(coap_context_t *context, * @return transaction id on success or @c COAP_INVALID_TID otherwise. */ coap_tid_t -coap_send_message_type(coap_context_t *context, +coap_send_message_type(coap_context_t *context, const coap_endpoint_t *local_interface, - const coap_address_t *dst, + const coap_address_t *dst, coap_pdu_t *request, unsigned char type); -/** +/** * Sends an ACK message with code @c 0 for the specified @p request to * @p dst. This function returns the corresponding transaction id if * the message was sent or @c COAP_INVALID_TID on error. - * + * * @param context The context to use. * @param local_interface The local network interface where the outbound * packet is sent. * @param dst The destination address. * @param request The request to be acknowledged. - * + * * @return The transaction id if ACK was sent or @c COAP_INVALID_TID * on error. */ -coap_tid_t coap_send_ack(coap_context_t *context, +coap_tid_t coap_send_ack(coap_context_t *context, const coap_endpoint_t *local_interface, - const coap_address_t *dst, + const coap_address_t *dst, coap_pdu_t *request); -/** +/** * Sends an RST message with code @c 0 for the specified @p request to * @p dst. This function returns the corresponding transaction id if * the message was sent or @c COAP_INVALID_TID on error. - * + * * @param context The context to use. * @param local_interface The local network interface where the outbound * packet is sent. * @param dst The destination address. * @param request The request to be reset. - * + * * @return The transaction id if RST was sent or @c COAP_INVALID_TID * on error. */ static inline coap_tid_t -coap_send_rst(coap_context_t *context, +coap_send_rst(coap_context_t *context, const coap_endpoint_t *local_interface, - const coap_address_t *dst, + const coap_address_t *dst, coap_pdu_t *request) { return coap_send_message_type(context, local_interface, dst, request, COAP_MESSAGE_RST); @@ -364,7 +365,7 @@ coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node); * and a new node with the parsed PDU is added to the receive queue in the specified context * object. */ -int coap_read(coap_context_t *context); +int coap_read(coap_context_t *context, coap_endpoint_t *endpoint); /** * Parses and interprets a CoAP message with context @p ctx. This function @@ -373,58 +374,58 @@ int coap_read(coap_context_t *context); * * @param ctx The current CoAP context. * @param packet The received packet. - * @return @c 0 if message was handled successfully, or less than + * @return @c 0 if message was handled successfully, or less than * zero on error. */ int coap_handle_message(coap_context_t *ctx, coap_packet_t *packet); -/** +/** * Calculates a unique transaction id from given arguments @p peer and * @p pdu. The id is returned in @p id. - * + * * @param peer The remote party who sent @p pdu. * @param pdu The message that initiated the transaction. * @param id Set to the new id. */ -void coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, +void coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, coap_tid_t *id); -/** +/** * This function removes the element with given @p id from the list * given list. If @p id was found, @p node is updated to point to the - * removed element. Note that the storage allocated by @p node is + * removed element. Note that the storage allocated by @p node is * @b not released. The caller must do this manually using * coap_delete_node(). This function returns @c 1 if the element with * id @p id was found, @c 0 otherwise. For a return value of @c 0, * the contents of @p node is undefined. - * + * * @param queue The queue to search for @p id. * @param id The node id to look for. - * @param node If found, @p node is updated to point to the + * @param node If found, @p node is updated to point to the * removed node. You must release the storage pointed to by * @p node manually. - * + * * @return @c 1 if @p id was found, @c 0 otherwise. */ -int coap_remove_from_queue(coap_queue_t **queue, - coap_tid_t id, +int coap_remove_from_queue(coap_queue_t **queue, + coap_tid_t id, coap_queue_t **node); -/** +/** * Removes the transaction identified by @p id from given @p queue. * This is a convenience function for coap_remove_from_queue() with * automatic deletion of the removed node. - * + * * @param queue The queue to search for @p id. * @param id The transaction id. - * + * * @return @c 1 if node was found, removed and destroyed, @c 0 otherwise. */ inline static int coap_remove_transaction(coap_queue_t **queue, coap_tid_t id) { coap_queue_t *node; - if (!coap_remove_from_queue(queue, id, &node)) + if (!coap_remove_from_queue(queue, id, &node)) return 0; coap_delete_node(node); @@ -440,15 +441,15 @@ coap_remove_transaction(coap_queue_t **queue, coap_tid_t id) { coap_queue_t *coap_find_transaction(coap_queue_t *queue, coap_tid_t id); /** - * Cancels all outstanding messages for peer @p dst that have the + * Cancels all outstanding messages for peer @p dst that have the * specified token. * * @param context The context in use * @param dst Destination address of the messages to remove. * @param token Message token - * @param token_length Actual length of @p token + * @param token_length Actual length of @p token */ -void coap_cancel_all_messages(coap_context_t *context, +void coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst, const unsigned char *token, size_t token_length); @@ -461,11 +462,11 @@ int coap_can_exit(coap_context_t *context); /** * Returns the current value of an internal tick counter. The counter - * counts \c COAP_TICKS_PER_SECOND ticks every second. + * counts \c COAP_TICKS_PER_SECOND ticks every second. */ void coap_ticks(coap_tick_t *); -/** +/** * Verifies that @p pdu contains no unknown critical options. Options * must be registered at @p ctx, using the function * coap_register_option(). A basic set of options is registered @@ -473,12 +474,12 @@ void coap_ticks(coap_tick_t *); * @p pdu is ok, @c 0 otherwise. The given filter object @p unknown * will be updated with the unknown options. As only @c COAP_MAX_OPT * options can be signalled this way, remaining options must be - * examined manually. + * examined manually. * * @code coap_opt_filter_t f = COAP_OPT_NONE; coap_opt_iterator_t opt_iter; - + if (coap_option_check_critical(ctx, pdu, f) == 0) { coap_option_iterator_init(pdu, &opt_iter, f); @@ -488,16 +489,16 @@ void coap_ticks(coap_tick_t *); } } } - * @endcode + * @endcode * * @param ctx The context where all known options are registered. * @param pdu The PDU to check. * @param unknown The output filter that will be updated to indicate the * unknown critical options found in @p pdu. - * + * * @return @c 1 if everything was ok, @c 0 otherwise. */ -int coap_option_check_critical(coap_context_t *ctx, +int coap_option_check_critical(coap_context_t *ctx, coap_pdu_t *pdu, coap_opt_filter_t unknown); diff --git a/src/net.c b/src/net.c index 1bf7bd3d6a..971f420eaf 100644 --- a/src/net.c +++ b/src/net.c @@ -3,7 +3,7 @@ * Copyright (C) 2010--2015 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" @@ -343,7 +343,7 @@ is_wkc(coap_key_t k) { static coap_key_t wkc; static unsigned char _initialized = 0; if (!_initialized) { - _initialized = coap_hash_path((unsigned char *)COAP_DEFAULT_URI_WELLKNOWN, + _initialized = coap_hash_path((unsigned char *)COAP_DEFAULT_URI_WELLKNOWN, sizeof(COAP_DEFAULT_URI_WELLKNOWN) - 1, wkc); } return memcmp(k, wkc, sizeof(coap_key_t)) == 0; @@ -359,7 +359,7 @@ coap_new_context(void) { return NULL; } */ - + #ifndef WITH_CONTIKI coap_context_t *c = coap_malloc_type(COAP_CONTEXT, sizeof( coap_context_t ) ); #endif /* not WITH_CONTIKI */ @@ -475,13 +475,13 @@ coap_free_context(coap_context_t *context) { } int -coap_option_check_critical(coap_context_t *ctx, +coap_option_check_critical(coap_context_t *ctx, coap_pdu_t *pdu, coap_opt_filter_t unknown) { coap_opt_iterator_t opt_iter; int ok = 1; - + coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL); while (coap_option_next(&opt_iter)) { @@ -492,10 +492,10 @@ coap_option_check_critical(coap_context_t *ctx, * the largest known option, we know that everything beyond is * bad. */ - if (opt_iter.type & 0x01 && + if (opt_iter.type & 0x01 && coap_option_getb(ctx->known_options, opt_iter.type) < 1) { debug("unknown critical option %d\n", opt_iter.type); - + ok = 0; /* When opt_iter.type is beyond our known option range, @@ -510,7 +510,7 @@ coap_option_check_critical(coap_context_t *ctx, } void -coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, +coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, coap_tid_t *id) { coap_key_t h; @@ -539,7 +539,7 @@ coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, #if defined(WITH_LWIP) || defined(WITH_CONTIKI) || defined(ST_NODE) /* FIXME: with lwip, we can do better */ coap_hash((const unsigned char *)&peer->port, sizeof(peer->port), h); - coap_hash((const unsigned char *)&peer->addr, sizeof(peer->addr), h); + coap_hash((const unsigned char *)&peer->addr, sizeof(peer->addr), h); #endif /* WITH_LWIP || WITH_CONTIKI */ coap_hash((const unsigned char *)&pdu->hdr->id, sizeof(unsigned short), h); @@ -548,7 +548,7 @@ coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, } coap_tid_t -coap_send_ack(coap_context_t *context, +coap_send_ack(coap_context_t *context, const coap_endpoint_t *local_interface, const coap_address_t *dst, coap_pdu_t *request) { @@ -556,8 +556,8 @@ coap_send_ack(coap_context_t *context, coap_tid_t result = COAP_INVALID_TID; if (request && request->hdr->type == COAP_MESSAGE_CON) { - response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->hdr->id, - sizeof(coap_pdu_t)); + response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->hdr->id, + sizeof(coap_pdu_t)); if (response) { result = coap_send(context, local_interface, dst, response); coap_delete_pdu(response); @@ -569,7 +569,7 @@ coap_send_ack(coap_context_t *context, #if defined(WITH_POSIX) || defined(WITH_CONTIKI) /* releases space allocated by PDU if free_pdu is set */ static coap_tid_t -coap_send_impl(coap_context_t *context, +coap_send_impl(coap_context_t *context, const coap_endpoint_t *local_interface, const coap_address_t *dst, coap_pdu_t *pdu) { @@ -579,7 +579,7 @@ coap_send_impl(coap_context_t *context, if ( !context || !dst || !pdu ) return id; - bytes_written = context->network_send(context, local_interface, dst, + bytes_written = context->network_send(context, local_interface, dst, (unsigned char *)pdu->hdr, pdu->length); if (bytes_written >= 0) { @@ -631,13 +631,13 @@ coap_tid_t coap_send_impl(coap_context_t *context, coap_tid_t coap_send(coap_context_t *context, const coap_endpoint_t *local_interface, - const coap_address_t *dst, + const coap_address_t *dst, coap_pdu_t *pdu) { return coap_send_impl(context, local_interface, dst, pdu); } coap_tid_t -coap_send_error(coap_context_t *context, +coap_send_error(coap_context_t *context, coap_pdu_t *request, const coap_endpoint_t *local_interface, const coap_address_t *dst, @@ -654,21 +654,21 @@ coap_send_error(coap_context_t *context, result = coap_send(context, local_interface, dst, response); coap_delete_pdu(response); } - + return result; } coap_tid_t -coap_send_message_type(coap_context_t *context, +coap_send_message_type(coap_context_t *context, const coap_endpoint_t *local_interface, - const coap_address_t *dst, + const coap_address_t *dst, coap_pdu_t *request, unsigned char type) { coap_pdu_t *response; coap_tid_t result = COAP_INVALID_TID; if (request) { - response = coap_pdu_init(type, 0, request->hdr->id, sizeof(coap_pdu_t)); + response = coap_pdu_init(type, 0, request->hdr->id, sizeof(coap_pdu_t)); if (response) { result = coap_send(context, local_interface, dst, response); coap_delete_pdu(response); @@ -715,7 +715,7 @@ calc_timeout(unsigned char r) { } coap_tid_t -coap_send_confirmed(coap_context_t *context, +coap_send_confirmed(coap_context_t *context, const coap_endpoint_t *local_interface, const coap_address_t *dst, coap_pdu_t *pdu) { @@ -735,7 +735,7 @@ coap_send_confirmed(coap_context_t *context, coap_free_node(node); return COAP_INVALID_TID; } - + prng((unsigned char *)&r,sizeof(r)); /* add timeout in range [ACK_TIMEOUT...ACK_TIMEOUT * ACK_RANDOM_FACTOR] */ @@ -804,7 +804,7 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) { debug("** retransmission #%d of transaction %d\n", node->retransmit_cnt, ntohs(node->pdu->hdr->id)); - node->id = coap_send_impl(context, &node->local_if, + node->id = coap_send_impl(context, &node->local_if, &node->remote, node->pdu); return node->id; } @@ -836,17 +836,17 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) { void coap_dispatch(coap_context_t *context, coap_queue_t *rcvd); int -coap_read( coap_context_t *ctx ) { +coap_read(coap_context_t *ctx, coap_endpoint_t *endpoint) { ssize_t bytes_read = -1; coap_packet_t *packet; int result = -1; /* the value to be returned */ #if defined(WITH_POSIX) || defined(WITH_CONTIKI) || defined(ST_NODE) - bytes_read = ctx->network_read(ctx->endpoint, &packet); + bytes_read = ctx->network_read(endpoint, &packet); #endif /* WITH_POSIX or WITH_CONTIKI */ if ( bytes_read < 0 ) { - warn("coap_read: recvfrom"); + //warn("coap_read: recvfrom"); } else { #if defined(WITH_POSIX) || defined(WITH_CONTIKI) || defined(ST_NODE) result = coap_handle_message(ctx, packet); @@ -890,7 +890,7 @@ coap_handle_message(coap_context_t *ctx, /* from this point, the result code indicates that */ result = RESULT_ERR; - + #if defined(WITH_LWIP) node->pdu = coap_pdu_from_pbuf(coap_packet_extract_pbuf(packet)); #elif defined(ST_NODE) @@ -928,7 +928,7 @@ coap_handle_message(coap_context_t *ctx, coap_print_addr(&packet->dst, localaddr, INET6_ADDRSTRLEN+8) ) debug("** received %d bytes from %s on interface %s:\n", (int)msg_len, addr, localaddr); - + */ coap_show_pdu(node->pdu); } @@ -991,7 +991,7 @@ coap_remove_from_queue(coap_queue_t **queue, coap_tid_t id, coap_queue_t **node) } static inline int -token_match(const unsigned char *a, size_t alen, +token_match(const unsigned char *a, size_t alen, const unsigned char *b, size_t blen) { return alen == blen && (alen == 0 || memcmp(a, b, alen) == 0); } @@ -999,16 +999,16 @@ token_match(const unsigned char *a, size_t alen, void coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst, const unsigned char *token, size_t token_length) { - /* cancel all messages in sendqueue that are for dst + /* cancel all messages in sendqueue that are for dst * and use the specified token */ coap_queue_t *p, *q; - - while (context->sendqueue && + + while (context->sendqueue && coap_address_equals(dst, &context->sendqueue->remote) && - token_match(token, token_length, - context->sendqueue->pdu->hdr->token, + token_match(token, token_length, + context->sendqueue->pdu->hdr->token, context->sendqueue->pdu->hdr->token_length)) { - q = context->sendqueue; + q = context->sendqueue; context->sendqueue = q->next; debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id)); coap_delete_node(q); @@ -1019,7 +1019,7 @@ coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst, p = context->sendqueue; q = p->next; - + /* when q is not NULL, it does not match (dst, token), so we can skip it */ while (q) { if (coap_address_equals(dst, &q->remote) && @@ -1045,12 +1045,12 @@ coap_find_transaction(coap_queue_t *queue, coap_tid_t id) { } coap_pdu_t * -coap_new_error_response(coap_pdu_t *request, unsigned char code, +coap_new_error_response(coap_pdu_t *request, unsigned char code, coap_opt_filter_t opts) { coap_opt_iterator_t opt_iter; coap_pdu_t *response; size_t size = sizeof(coap_hdr_t) + request->hdr->token_length; - int type; + int type; coap_opt_t *option; unsigned short opt_type = 0; /* used for calculating delta-storage */ @@ -1065,7 +1065,7 @@ coap_new_error_response(coap_pdu_t *request, unsigned char code, assert(request); /* cannot send ACK if original request was not confirmable */ - type = request->hdr->type == COAP_MESSAGE_CON + type = request->hdr->type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON; @@ -1093,7 +1093,7 @@ coap_new_error_response(coap_pdu_t *request, unsigned char code, /* add coap_opt_length(option) and the number of additional bytes * required to encode the option length */ - + size += coap_opt_length(option); switch (*option & 0x0f) { case 0x0e: @@ -1113,7 +1113,7 @@ coap_new_error_response(coap_pdu_t *request, unsigned char code, response = coap_pdu_init(type, code, request->hdr->id, size); if (response) { /* copy token */ - if (!coap_add_token(response, request->hdr->token_length, + if (!coap_add_token(response, request->hdr->token_length, request->hdr->token)) { debug("cannot add token to error response\n"); coap_delete_pdu(response); @@ -1123,7 +1123,7 @@ coap_new_error_response(coap_pdu_t *request, unsigned char code, /* copy all options */ coap_option_iterator_init(request, &opt_iter, opts); while((option = coap_option_next(&opt_iter))) - coap_add_option(response, opt_iter.type, + coap_add_option(response, opt_iter.type, COAP_OPT_LENGTH(option), COAP_OPT_VALUE(option)); @@ -1171,8 +1171,8 @@ coap_wellknown_response(coap_context_t *context, coap_pdu_t *request) { coap_opt_t *query_filter; size_t offset = 0; - resp = coap_pdu_init(request->hdr->type == COAP_MESSAGE_CON - ? COAP_MESSAGE_ACK + resp = coap_pdu_init(request->hdr->type == COAP_MESSAGE_CON + ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON, COAP_RESPONSE_CODE(205), request->hdr->id, COAP_MAX_PDU_SIZE); @@ -1180,7 +1180,7 @@ coap_wellknown_response(coap_context_t *context, coap_pdu_t *request) { debug("coap_wellknown_response: cannot create PDU\n"); return NULL; } - + if (!coap_add_token(resp, request->hdr->token_length, request->hdr->token)) { debug("coap_wellknown_response: cannot add token\n"); goto error; @@ -1204,7 +1204,7 @@ coap_wellknown_response(coap_context_t *context, coap_pdu_t *request) { need_block2 = 1; } - /* Check if there is sufficient space to add Content-Format option + /* Check if there is sufficient space to add Content-Format option * and data. We do this before adding the Content-Format option to * avoid sending error responses with that option but no actual * content. */ @@ -1215,10 +1215,10 @@ coap_wellknown_response(coap_context_t *context, coap_pdu_t *request) { /* 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_bytes(buf, COAP_MEDIATYPE_APPLICATION_LINK_FORMAT) == 1); coap_add_option(resp, COAP_OPTION_CONTENT_FORMAT, - coap_encode_var_bytes(buf, + coap_encode_var_bytes(buf, COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), buf); /* check if Block2 option is required even if not requested */ @@ -1266,8 +1266,8 @@ coap_wellknown_response(coap_context_t *context, coap_pdu_t *request) { if ((result & COAP_PRINT_STATUS_ERROR) != 0) { debug("coap_print_wellknown failed\n"); goto error; - } - + } + resp->length += COAP_PRINT_OUTPUT_LENGTH(result); return resp; @@ -1294,7 +1294,7 @@ coap_cancel(coap_context_t *context, const coap_queue_t *sent) { str token = { 0, NULL }; int num_cancelled = 0; /* the number of observers cancelled */ - /* remove observer for this resource, if any + /* remove observer for this resource, if any * get token from sent and try to find a matching resource. Uh! */ @@ -1306,16 +1306,16 @@ coap_cancel(coap_context_t *context, const coap_queue_t *sent) { } return num_cancelled; -#else /* WITOUT_OBSERVE */ +#else /* WITOUT_OBSERVE */ return 0; -#endif /* WITOUT_OBSERVE */ +#endif /* WITOUT_OBSERVE */ } #define WANT_WKC(Pdu,Key) \ (((Pdu)->hdr->code == COAP_REQUEST_GET) && is_wkc(Key)) static void -handle_request(coap_context_t *context, coap_queue_t *node) { +handle_request(coap_context_t *context, coap_queue_t *node) { coap_method_handler_t h = NULL; coap_pdu_t *response = NULL; coap_opt_filter_t opt_filter; @@ -1323,11 +1323,11 @@ handle_request(coap_context_t *context, coap_queue_t *node) { coap_key_t key; coap_option_filter_clear(opt_filter); - + /* try to find the resource from the request URI */ coap_hash_request_uri(node->pdu, key); resource = coap_get_resource_from_key(context, key); - + if (!resource) { /* The resource was not found. Check if the request URI happens to * be the well-known URI. In that case, we generate a default @@ -1335,17 +1335,17 @@ handle_request(coap_context_t *context, coap_queue_t *node) { switch(node->pdu->hdr->code) { - case COAP_REQUEST_GET: + case COAP_REQUEST_GET: if (is_wkc(key)) { /* GET request for .well-known/core */ info("create default response for %s\n", COAP_DEFAULT_URI_WELLKNOWN); response = coap_wellknown_response(context, node->pdu); } else { /* GET request for any another resource, return 4.04 */ - debug("GET for unknown resource 0x%02x%02x%02x%02x, return 4.04\n", + debug("GET for unknown resource 0x%02x%02x%02x%02x, return 4.04\n", key[0], key[1], key[2], key[3]); - response = - coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(404), + response = + coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(404), opt_filter); } break; @@ -1355,11 +1355,11 @@ handle_request(coap_context_t *context, coap_queue_t *node) { debug("unhandled request for unknown resource 0x%02x%02x%02x%02x\r\n", key[0], key[1], key[2], key[3]); if (!coap_mcast_interface(&node->local_if)) - response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), + response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), opt_filter); } - - if (response && coap_send(context, &node->local_if, + + if (response && coap_send(context, &node->local_if, &node->remote, response) == COAP_INVALID_TID) { warn("cannot send response for transaction %u\n", node->id); } @@ -1367,20 +1367,20 @@ handle_request(coap_context_t *context, coap_queue_t *node) { return; } - + /* the resource was found, check if there is a registered handler */ if ((size_t)node->pdu->hdr->code - 1 < sizeof(resource->handler)/sizeof(coap_method_handler_t)) h = resource->handler[node->pdu->hdr->code - 1]; - + if (h) { - debug("call custom handler for resource 0x%02x%02x%02x%02x\n", + debug("call custom handler for resource 0x%02x%02x%02x%02x\n", key[0], key[1], key[2], key[3]); - response = coap_pdu_init(node->pdu->hdr->type == COAP_MESSAGE_CON + response = coap_pdu_init(node->pdu->hdr->type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON, 0, node->pdu->hdr->id, COAP_MAX_PDU_SIZE); - + /* Implementation detail: coap_add_token() immediately returns 0 if response == NULL */ if (coap_add_token(response, node->pdu->hdr->token_length, @@ -1397,12 +1397,12 @@ handle_request(coap_context_t *context, coap_queue_t *node) { observe_action = coap_decode_var_bytes(coap_opt_value(observe), coap_opt_length(observe)); - + if ((observe_action & COAP_OBSERVE_CANCEL) == 0) { coap_subscription_t *subscription; coap_log(LOG_DEBUG, "create new subscription\n"); - subscription = coap_add_observer(resource, &node->local_if, + subscription = coap_add_observer(resource, &node->local_if, &node->remote, &token); if (subscription) { subscription->non = node->pdu->hdr->type == COAP_MESSAGE_NON; @@ -1433,10 +1433,10 @@ handle_request(coap_context_t *context, coap_queue_t *node) { } if (response->hdr->type != COAP_MESSAGE_NON || - (response->hdr->code >= 64 + (response->hdr->code >= 64 && !coap_mcast_interface(&node->local_if))) { - if (coap_send(context, &node->local_if, + if (coap_send(context, &node->local_if, &node->remote, response) == COAP_INVALID_TID) { debug("cannot send response for message %d\n", node->pdu->hdr->id); } @@ -1452,42 +1452,42 @@ handle_request(coap_context_t *context, coap_queue_t *node) { response = coap_wellknown_response(context, node->pdu); debug("have wellknown response %p\n", (void *)response); } else - response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), + response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), opt_filter); - + if (!response || (coap_send(context, &node->local_if, &node->remote, response) == COAP_INVALID_TID)) { debug("cannot send response for transaction %u\n", node->id); } coap_delete_pdu(response); - } + } } /*static inline */ void -handle_response(coap_context_t *context, +handle_response(coap_context_t *context, coap_queue_t *sent, coap_queue_t *rcvd) { coap_send_ack(context, &rcvd->local_if, &rcvd->remote, rcvd->pdu); - + /* In a lossy context, the ACK of a separate response may have * been lost, so we need to stop retransmitting requests with the * same token. */ coap_cancel_all_messages(context, &rcvd->remote, - rcvd->pdu->hdr->token, + rcvd->pdu->hdr->token, rcvd->pdu->hdr->token_length); /* Call application-specific reponse handler when available. */ if (context->response_handler) { context->response_handler(context, &rcvd->local_if, - &rcvd->remote, sent ? sent->pdu : NULL, + &rcvd->remote, sent ? sent->pdu : NULL, rcvd->pdu, rcvd->id); } } /*static inline */ int #ifdef __GNUC__ -handle_locally(coap_context_t *context __attribute__ ((unused)), +handle_locally(coap_context_t *context __attribute__ ((unused)), coap_queue_t *node __attribute__ ((unused))) { #else /* not a GCC */ handle_locally(coap_context_t *context, coap_queue_t *node) { @@ -1513,7 +1513,7 @@ coap_dispatch(coap_context_t *context, coap_queue_t *rcvd) { /* debug("dropped packet with unknown version %u\n", rcvd->pdu->hdr->version); */ /* goto cleanup; */ /* } */ - + switch (rcvd->pdu->hdr->type) { case COAP_MESSAGE_ACK: /* find transaction in sendqueue to stop retransmission */ @@ -1522,11 +1522,11 @@ coap_dispatch(coap_context_t *context, coap_queue_t *rcvd) { if (rcvd->pdu->hdr->code == 0) goto cleanup; - /* FIXME: if sent code was >= 64 the message might have been a + /* FIXME: if sent code was >= 64 the message might have been a * notification. Then, we must flag the observer to be alive * by setting obs->fail_cnt = 0. */ if (sent && COAP_RESPONSE_CLASS(sent->pdu->hdr->code) == 2) { - const str token = + const str token = { sent->pdu->hdr->token_length, sent->pdu->hdr->token }; coap_touch_observer(context, &sent->remote, &token); } @@ -1558,26 +1558,26 @@ coap_dispatch(coap_context_t *context, coap_queue_t *rcvd) { case COAP_MESSAGE_CON : /* check for unknown critical options */ if (coap_option_check_critical(context, rcvd->pdu, opt_filter) == 0) { - /* FIXME: send response only if we have received a request. Otherwise, + /* FIXME: send response only if we have received a request. Otherwise, * send RST. */ - response = + response = coap_new_error_response(rcvd->pdu, COAP_RESPONSE_CODE(402), opt_filter); if (!response) warn("coap_dispatch: cannot create error reponse\n"); else { - if (coap_send(context, &rcvd->local_if, &rcvd->remote, response) + if (coap_send(context, &rcvd->local_if, &rcvd->remote, response) == COAP_INVALID_TID) { warn("coap_dispatch: error sending reponse\n"); } coap_delete_pdu(response); - } - + } + goto cleanup; } default: break; } - + /* Pass message to upper layer if a specific handler was * registered for a request that should be handled locally. */ if (handle_locally(context, rcvd)) { @@ -1586,14 +1586,14 @@ coap_dispatch(coap_context_t *context, coap_queue_t *rcvd) { else if (COAP_MESSAGE_IS_RESPONSE(rcvd->pdu->hdr)) handle_response(context, sent, rcvd); else { - debug("dropped message with invalid code (%d.%02d)\n", + debug("dropped message with invalid code (%d.%02d)\n", COAP_RESPONSE_CLASS(rcvd->pdu->hdr->code), rcvd->pdu->hdr->code & 0x1f); - coap_send_message_type(context, &rcvd->local_if, &rcvd->remote, + coap_send_message_type(context, &rcvd->local_if, &rcvd->remote, rcvd->pdu, COAP_MESSAGE_RST); } } - + cleanup: coap_delete_node(sent); coap_delete_node(rcvd); @@ -1623,9 +1623,9 @@ PROCESS_THREAD(coap_retransmit_process, ev, data) PROCESS_YIELD(); if (ev == PROCESS_EVENT_TIMER) { if (etimer_expired(&the_coap_context.retransmit_timer)) { - + nextpdu = coap_peek_next(&the_coap_context); - + coap_ticks(&now); while (nextpdu && nextpdu->t <= now) { coap_retransmit(&the_coap_context, coap_pop_next(&the_coap_context)); @@ -1633,9 +1633,9 @@ PROCESS_THREAD(coap_retransmit_process, ev, data) } /* need to set timer to some value even if no nextpdu is available */ - etimer_set(&the_coap_context.retransmit_timer, + etimer_set(&the_coap_context.retransmit_timer, nextpdu ? nextpdu->t - now : 0xFFFF); - } + } #ifndef WITHOUT_OBSERVE if (etimer_expired(&the_coap_context.notify_timer)) { coap_check_notify(&the_coap_context); @@ -1644,7 +1644,7 @@ PROCESS_THREAD(coap_retransmit_process, ev, data) #endif /* WITHOUT_OBSERVE */ } } - + PROCESS_END(); } /*---------------------------------------------------------------------------*/ From c0c3a4b5bf75ae9e98e85a4ff5ddb559b400793e Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Wed, 3 Jun 2015 16:00:36 +0200 Subject: [PATCH 60/69] spike --- include/coap/coap_io.h | 8 +++++++ include/coap/debug.h | 7 +++--- include/coap/mem.h | 3 ++- include/coap/net.h | 7 ++++-- include/coap/option.h | 4 ++++ include/coap/pdu.h | 45 +++++++++++++++++++++++++++------------ include/coap/str.h | 12 +++++++++++ include/coap/uri.h | 40 +++++++++++++++++------------------ src/debug.c | 36 +++++++++++++++---------------- src/net.c | 26 +++++++++++------------ src/option.c | 48 +++++++++++++++++++++--------------------- src/pdu.c | 14 ++++++------ src/resource.c | 3 +++ 13 files changed, 151 insertions(+), 102 deletions(-) diff --git a/include/coap/coap_io.h b/include/coap/coap_io.h index 0fe719b5af..df2a6edcff 100644 --- a/include/coap/coap_io.h +++ b/include/coap/coap_io.h @@ -113,6 +113,14 @@ ssize_t coap_network_send(struct coap_context_t *context, */ ssize_t coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet); +/** + * Function interface for checking data availability. + * + * @param ep The endpoint that should be checked. + * @return The number of bytes present in @p ep receive queue. + */ +ssize_t coap_network_peek(coap_endpoint_t *ep); + #ifndef coap_mcast_interface # define coap_mcast_interface(Local) 0 #endif diff --git a/include/coap/debug.h b/include/coap/debug.h index b4a6ac7030..aed9d20aec 100644 --- a/include/coap/debug.h +++ b/include/coap/debug.h @@ -3,7 +3,7 @@ * Copyright (C) 2010,2011,2014 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ #ifndef _COAP_DEBUG_H_ @@ -52,10 +52,10 @@ const char *coap_package_version(void); * COAP_DEBUG_FD (for @p level >= @c LOG_WARNING). The text is output only when * @p level is below or equal to the log level that set by coap_set_log_level(). */ -void coap_log_impl(coap_log_t level, const char *format, ...); +void coap_log_impl(const char *file, int line, coap_log_t level, const char *format, ...); #ifndef coap_log -#define coap_log(...) coap_log_impl(__VA_ARGS__) +#define coap_log(...) coap_log_impl(__FILE__, __LINE__, __VA_ARGS__) #endif #ifndef NDEBUG @@ -64,6 +64,7 @@ void coap_log_impl(coap_log_t level, const char *format, ...); #define info(...) coap_log(LOG_INFO, __VA_ARGS__) #define warn(...) coap_log(LOG_WARNING, __VA_ARGS__) #define debug(...) coap_log(LOG_DEBUG, __VA_ARGS__) +#define critical(...) coap_log(LOG_CRIT, __VA_ARGS__) #include "pdu.h" void coap_show_pdu(const coap_pdu_t *); diff --git a/include/coap/mem.h b/include/coap/mem.h index 4e51c6c7b5..2de7dcdc1e 100644 --- a/include/coap/mem.h +++ b/include/coap/mem.h @@ -38,8 +38,9 @@ typedef enum { COAP_PDU, COAP_PDU_BUF, COAP_RESOURCE, - COAP_RESOURCEATTR + COAP_RESOURCEATTR, COAP_OPTION, + COAP_SUBSCRIPTION, } coap_memory_tag_t; #ifndef WITH_LWIP diff --git a/include/coap/net.h b/include/coap/net.h index b3bc1a6f15..18483198df 100644 --- a/include/coap/net.h +++ b/include/coap/net.h @@ -145,6 +145,8 @@ typedef struct coap_context_t { ssize_t (*network_read)(coap_endpoint_t *ep, coap_packet_t **packet); + ssize_t (*network_peek)(coap_endpoint_t *ep); + } coap_context_t; /** @@ -205,10 +207,11 @@ coap_context_t *coap_new_context(void); */ static inline unsigned short coap_new_message_id(coap_context_t *context) { + context->message_id += 1; #ifndef WITH_CONTIKI - return htons(++(context->message_id)); + return htons(context->message_id); #else /* WITH_CONTIKI */ - return uip_htons(++context->message_id); + return uip_htons(context->message_id); #endif } diff --git a/include/coap/option.h b/include/coap/option.h index 6e1567b5cf..ec49f94add 100644 --- a/include/coap/option.h +++ b/include/coap/option.h @@ -320,6 +320,10 @@ unsigned char *coap_opt_value(coap_opt_t *opt); /** @deprecated { Use coap_opt_value() instead. } */ #define COAP_OPT_VALUE(opt) coap_opt_value((coap_opt_t *)opt) +#if defined(ST_NODE) +size_t coap_opt_encode_to_mbuf(coap_pdu_t *pdu, unsigned short type, const unsigned char *val, size_t length); +#endif + /** @} */ #endif /* _OPTION_H_ */ diff --git a/include/coap/pdu.h b/include/coap/pdu.h index 46ce8be751..78c93cea25 100644 --- a/include/coap/pdu.h +++ b/include/coap/pdu.h @@ -25,11 +25,11 @@ /* pre-defined constants that reflect defaults for CoAP */ #ifndef COAP_DEFAULT_RESPONSE_TIMEOUT -#define COAP_DEFAULT_RESPONSE_TIMEOUT 2 /* response timeout in seconds */ +#define COAP_DEFAULT_RESPONSE_TIMEOUT 3 /* response timeout in seconds */ #endif #ifndef COAP_DEFAULT_MAX_RETRANSMIT -#define COAP_DEFAULT_MAX_RETRANSMIT 4 /* max number of retransmissions */ +#define COAP_DEFAULT_MAX_RETRANSMIT 3 /* max number of retransmissions */ #endif #ifndef COAP_DEFAULT_PORT @@ -138,17 +138,32 @@ char *coap_response_phrase(unsigned char code); #if 0 /* this does not exist any more */ #define COAP_RESPONSE_100 40 /* 100 Continue */ #endif -#define COAP_RESPONSE_200 COAP_RESPONSE_CODE(200) /* 2.00 OK */ -#define COAP_RESPONSE_201 COAP_RESPONSE_CODE(201) /* 2.01 Created */ -#define COAP_RESPONSE_304 COAP_RESPONSE_CODE(203) /* 2.03 Valid */ -#define COAP_RESPONSE_400 COAP_RESPONSE_CODE(400) /* 4.00 Bad Request */ -#define COAP_RESPONSE_404 COAP_RESPONSE_CODE(404) /* 4.04 Not Found */ -#define COAP_RESPONSE_405 COAP_RESPONSE_CODE(405) /* 4.05 Method Not Allowed */ -#define COAP_RESPONSE_415 COAP_RESPONSE_CODE(415) /* 4.15 Unsupported Media Type */ -#define COAP_RESPONSE_500 COAP_RESPONSE_CODE(500) /* 5.00 Internal Server Error */ -#define COAP_RESPONSE_501 COAP_RESPONSE_CODE(501) /* 5.01 Not Implemented */ -#define COAP_RESPONSE_503 COAP_RESPONSE_CODE(503) /* 5.03 Service Unavailable */ -#define COAP_RESPONSE_504 COAP_RESPONSE_CODE(504) /* 5.04 Gateway Timeout */ +#define COAP_RESPONSE_200 COAP_RESPONSE_CODE(200) /* 2.00 OK */ +#define COAP_RESPONSE_OK COAP_RESPONSE_200 +#define COAP_RESPONSE_201 COAP_RESPONSE_CODE(201) /* 2.01 Created */ +#define COAP_RESPONSE_CREATED COAP_RESPONSE_201 +#define COAP_RESPONSE_203 COAP_RESPONSE_CODE(203) /* 2.03 Valid */ +#define COAP_RESPONSE_VALID COAP_RESPONSE_203 +#define COAP_RESPONSE_204 COAP_RESPONSE_CODE(204) /* 2.04 Valid */ +#define COAP_RESPONSE_CHANGED COAP_RESPONSE_204 +#define COAP_RESPONSE_205 COAP_RESPONSE_CODE(205) /* 2.05 Content */ +#define COAP_RESPONSE_CONTENT COAP_RESPONSE_205 +#define COAP_RESPONSE_400 COAP_RESPONSE_CODE(400) /* 4.00 Bad Request */ +#define COAP_RESPONSE_BAD_REQUEST COAP_RESPONSE_400 +#define COAP_RESPONSE_404 COAP_RESPONSE_CODE(404) /* 4.04 Not Found */ +#define COAP_RESPONSE_NOT_FOUND COAP_RESPONSE_404 +#define COAP_RESPONSE_405 COAP_RESPONSE_CODE(405) /* 4.05 Method Not Allowed */ +#define COAP_RESPONSE_METHOD_NOT_ALLOWED COAP_RESPONSE_405 +#define COAP_RESPONSE_415 COAP_RESPONSE_CODE(415) /* 4.15 Unsupported Media Type */ +#define COAP_RESPONSE_UNSP_MEDIA_TYPE COAP_RESPONSE_415 +#define COAP_RESPONSE_500 COAP_RESPONSE_CODE(500) /* 5.00 Internal Server Error */ +#define COAP_RESPONSE_INT_SRV_ERR COAP_RESPONSE_500 +#define COAP_RESPONSE_501 COAP_RESPONSE_CODE(501) /* 5.01 Not Implemented */ +#define COAP_RESPONSE_NOT_IMPL COAP_RESPONSE_501 +#define COAP_RESPONSE_503 COAP_RESPONSE_CODE(503) /* 5.03 Service Unavailable */ +#define COAP_RESPONSE_SERVICE_UNAVAIL COAP_RESPONSE_503 +#define COAP_RESPONSE_504 COAP_RESPONSE_CODE(504) /* 5.04 Gateway Timeout */ +#define COAP_RESPONSE_GATEWAY_TIMEOUT COAP_RESPONSE_504 #if 0 /* these response codes do not have a valid code any more */ # define COAP_RESPONSE_X_240 240 /* Token Option required by server */ # define COAP_RESPONSE_X_241 241 /* Uri-Authority Option required by server */ @@ -405,4 +420,8 @@ static inline int coap_has_data(coap_pdu_t *pdu) { return (pdu->data != NULL); } + +#ifdef ST_NODE +coap_pdu_t *coap_pdu_from_mbuf(struct mbuf *mbuf); +#endif #endif /* _PDU_H_ */ diff --git a/include/coap/str.h b/include/coap/str.h index 92784ef1f0..05eea62e27 100644 --- a/include/coap/str.h +++ b/include/coap/str.h @@ -11,6 +11,10 @@ #include +#ifndef MIN +#define MIN(x , y) (((x) < (y)) ? (x) : (y)) +#endif + typedef struct { size_t length; /* length of string */ unsigned char *s; /* string data */ @@ -29,4 +33,12 @@ str *coap_new_string(size_t size); */ void coap_delete_string(str *); +/** + * Compare CoAP string with a null terminated string. + */ +static inline int coap_strcmp(const str *s1, const char *s2) +{ + return memcmp(s1->s, s2, MIN(s1->length, strlen(s2) - 1)); +} + #endif /* _COAP_STR_H_ */ diff --git a/include/coap/uri.h b/include/coap/uri.h index 438478a673..4824c730a9 100644 --- a/include/coap/uri.h +++ b/include/coap/uri.h @@ -3,7 +3,7 @@ * Copyright (C) 2010,2011 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ #ifndef _COAP_URI_H_ @@ -18,7 +18,7 @@ typedef struct { str host; /**< host part of the URI */ unsigned short port; /**< The port in host byte order */ - str path; /**< Beginning of the first path segment. + str path; /**< Beginning of the first path segment. Use coap_split_path() to create Uri-Path options */ str query; /**< The query part if present */ } coap_uri_t; @@ -40,14 +40,14 @@ coap_uri_t *coap_new_uri(const unsigned char *uri, unsigned int length); * be released with coap_free(). */ coap_uri_t *coap_clone_uri(const coap_uri_t *uri); -/** - * Calculates a hash over the given path and stores the result in +/** + * Calculates a hash over the given path and stores the result in * @p key. This function returns @c 0 on error or @c 1 on success. - * + * * @param path The URI path to generate hash for. * @param len The length of @p path. * @param key The output buffer. - * + * * @return @c 1 if @p key was set, @c 0 otherwise. */ int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key); @@ -60,14 +60,14 @@ int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key); * @{ */ -/** +/** * Parses a given string into URI components. The identified syntactic * components are stored in the result parameter @p uri. Optional URI * components that are not specified will be set to { 0, 0 }, except * for the port which is set to @c COAP_DEFAULT_PORT. This function * returns @p 0 if parsing succeeded, a value less than zero * otherwise. - * + * * @param str_var The string to split up. * @param len The actual length of @p str_var * @param uri The coap_uri_t object to store the result. @@ -79,38 +79,38 @@ int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key); int coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri); -/** +/** * Splits the given URI path into segments. Each segment is preceded * by an option pseudo-header with delta-value 0 and the actual length * of the respective segment after percent-decoding. - * - * @param s The path string to split. + * + * @param s The path string to split. * @param length The actual length of @p s. - * @param buf Result buffer for parsed segments. + * @param buf Result buffer for parsed segments. * @param buflen Maximum length of @p buf. Will be set to the actual number * of bytes written into buf on success. - * + * * @return The number of segments created or @c -1 on error. */ -int coap_split_path(const unsigned char *s, size_t length, +int coap_split_path(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen); -/** +/** * Splits the given URI query into segments. Each segment is preceded * by an option pseudo-header with delta-value 0 and the actual length * of the respective query term. - * - * @param s The query string to split. + * + * @param s The query string to split. * @param length The actual length of @p s. - * @param buf Result buffer for parsed segments. + * @param buf Result buffer for parsed segments. * @param buflen Maximum length of @p buf. Will be set to the actual number * of bytes written into buf on success. - * + * * @return The number of segments created or @c -1 on error. * * @bug This function does not reserve additional space for delta > 12. */ -int coap_split_query(const unsigned char *s, size_t length, +int coap_split_query(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen); /** @} */ diff --git a/src/debug.c b/src/debug.c index 811437d60a..a5f94c8076 100644 --- a/src/debug.c +++ b/src/debug.c @@ -3,7 +3,7 @@ * Copyright (C) 2010--2012,2014--2015 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" @@ -49,7 +49,7 @@ const char *coap_package_version(void) { return PACKAGE_STRING; } -coap_log_t +coap_log_t coap_get_log_level(void) { return maxlog; } @@ -61,7 +61,7 @@ coap_set_log_level(coap_log_t level) { /* this array has the same order as the type log_t */ static char *loglevels[] = { - "EMRG", "ALRT", "CRIT", "ERR", "WARN", "NOTE", "INFO", "DEBG" + "EMRG", "ALRT", "CRIT", "ERR", "WARN", "NOTE", "INFO", "DEBG" }; #ifdef HAVE_TIME_H @@ -79,7 +79,7 @@ print_timestamp(char *s, size_t len, coap_tick_t t) { static inline size_t print_timestamp(char *s, size_t len, coap_tick_t t) { #ifdef HAVE_SNPRINTF - return snprintf(s, len, "%u.%03u", + return snprintf(s, len, "%u.%03u", (unsigned int)coap_ticks_to_rt(t), (unsigned int)(t % COAP_TICKS_PER_SECOND)); #else /* HAVE_SNPRINTF */ @@ -93,12 +93,12 @@ print_timestamp(char *s, size_t len, coap_tick_t t) { #ifndef NDEBUG #ifndef HAVE_STRNLEN -/** - * A length-safe strlen() fake. - * +/** + * A length-safe strlen() fake. + * * @param s The string to count characters != 0. * @param maxlen The maximum length of @p s. - * + * * @return The length of @p s. */ static inline size_t @@ -156,7 +156,7 @@ coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t le unsigned char *p = buf; switch (addr->addr.sa.sa_family) { - case AF_INET: + case AF_INET: addrptr = &addr->addr.sin.sin_addr; port = ntohs(addr->addr.sin.sin_port); break; @@ -185,7 +185,7 @@ coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t le if (addr->addr.sa.sa_family == AF_INET6) { if (p < buf + len) { *p++ = ']'; - } else + } else return 0; } @@ -283,20 +283,20 @@ coap_show_pdu(const coap_pdu_t *pdu) { } else { encode = 1; } - - if (print_readable(COAP_OPT_VALUE(option), - COAP_OPT_LENGTH(option), + + if (print_readable(COAP_OPT_VALUE(option), + COAP_OPT_LENGTH(option), buf, sizeof(buf), encode )) fprintf(COAP_DEBUG_FD, " %d:'%s'", opt_iter.type, buf); } if (have_options) fprintf(COAP_DEBUG_FD, " ]"); - + if (pdu->data) { assert(pdu->data < (unsigned char *)pdu->hdr + pdu->length); - print_readable(pdu->data, - (unsigned char *)pdu->hdr + pdu->length - pdu->data, + print_readable(pdu->data, + (unsigned char *)pdu->hdr + pdu->length - pdu->data, buf, sizeof(buf), 0 ); fprintf(COAP_DEBUG_FD, " d:%s", buf); } @@ -307,7 +307,7 @@ coap_show_pdu(const coap_pdu_t *pdu) { #endif /* NDEBUG */ -void +void coap_log_impl(coap_log_t level, const char *format, ...) { char timebuf[32]; coap_tick_t now; @@ -316,7 +316,7 @@ coap_log_impl(coap_log_t level, const char *format, ...) { if (maxlog < level) return; - + log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD; coap_ticks(&now); diff --git a/src/net.c b/src/net.c index 971f420eaf..b5f24dba6b 100644 --- a/src/net.c +++ b/src/net.c @@ -353,13 +353,6 @@ is_wkc(coap_key_t k) { coap_context_t * coap_new_context(void) { - /* - if (!listen_addr) { - coap_log(LOG_EMERG, "no listen address specified\n"); - return NULL; - } - */ - #ifndef WITH_CONTIKI coap_context_t *c = coap_malloc_type(COAP_CONTEXT, sizeof( coap_context_t ) ); #endif /* not WITH_CONTIKI */ @@ -426,6 +419,7 @@ coap_new_context(void) { #if defined(WITH_POSIX) || defined(WITH_CONTIKI) || defined(ST_NODE) c->network_send = coap_network_send; c->network_read = coap_network_read; + c->network_peek = coap_network_peek; #endif /* WITH_POSIX or WITH_CONTIKI */ #ifdef WITH_CONTIKI @@ -763,6 +757,7 @@ coap_send_confirmed(coap_context_t *context, } coap_insert_node(&context->sendqueue, node); + debug(" *** transaction %d started\n", node->id); #ifdef WITH_LWIP if (node == context->sendqueue) /* don't bother with timer stuff if there are earlier retransmits */ @@ -802,17 +797,20 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) { #endif debug("** retransmission #%d of transaction %d\n", - node->retransmit_cnt, ntohs(node->pdu->hdr->id)); + node->retransmit_cnt, node->id); node->id = coap_send_impl(context, &node->local_if, &node->remote, node->pdu); + + debug("** done (%d)\n", node->id); + return node->id; } /* no more retransmissions, remove node from system */ #ifndef WITH_CONTIKI - debug("** removed transaction %d\n", ntohs(node->id)); + debug("** removed transaction %d\n", node->id); #endif #ifndef WITHOUT_OBSERVE @@ -930,7 +928,7 @@ coap_handle_message(coap_context_t *ctx, (int)msg_len, addr, localaddr); */ - coap_show_pdu(node->pdu); + //coap_show_pdu(node->pdu); } #endif @@ -1010,7 +1008,7 @@ coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst, context->sendqueue->pdu->hdr->token_length)) { q = context->sendqueue; context->sendqueue = q->next; - debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id)); + debug("**** removed transaction %d\n", q->id); coap_delete_node(q); } @@ -1026,7 +1024,7 @@ coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst, token_match(token, token_length, q->pdu->hdr->token, q->pdu->hdr->token_length)) { p->next = q->next; - debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id)); + debug("**** removed transaction %d\n", q->id); coap_delete_node(q); q = p->next; } else { @@ -1314,7 +1312,7 @@ coap_cancel(coap_context_t *context, const coap_queue_t *sent) { #define WANT_WKC(Pdu,Key) \ (((Pdu)->hdr->code == COAP_REQUEST_GET) && is_wkc(Key)) -static void +__attribute__((weak)) void handle_request(coap_context_t *context, coap_queue_t *node) { coap_method_handler_t h = NULL; coap_pdu_t *response = NULL; @@ -1496,7 +1494,7 @@ handle_locally(coap_context_t *context, coap_queue_t *node) { return 1; } -__attribute__((weak)) void +void coap_dispatch(coap_context_t *context, coap_queue_t *rcvd) { coap_queue_t *sent = NULL; coap_pdu_t *response; diff --git a/src/option.c b/src/option.c index 35e8cb44f0..6cc68dd70b 100644 --- a/src/option.c +++ b/src/option.c @@ -4,7 +4,7 @@ * Copyright (C) 2010-2013 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ @@ -27,14 +27,14 @@ coap_opt_t * options_start(coap_pdu_t *pdu) { - if (pdu && pdu->hdr && - (pdu->hdr->token + pdu->hdr->token_length + if (pdu && pdu->hdr && + (pdu->hdr->token + pdu->hdr->token_length < (unsigned char *)pdu->hdr + pdu->length)) { coap_opt_t *opt = pdu->hdr->token + pdu->hdr->token_length; return (*opt == COAP_PAYLOAD_START) ? NULL : opt; - - } else + + } else return NULL; } @@ -80,7 +80,7 @@ coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result) { ADVANCE_OPT(opt,length,1); result->delta += *opt & 0xff; break; - + default: ; } @@ -100,7 +100,7 @@ coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result) { ADVANCE_OPT(opt,length,1); result->length += *opt & 0xff; break; - + default: ; } @@ -122,10 +122,10 @@ coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result) { coap_opt_iterator_t * coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter) { - assert(pdu); + assert(pdu); assert(pdu->hdr); assert(oi); - + memset(oi, 0, sizeof(coap_opt_iterator_t)); oi->next_option = (unsigned char *)pdu->hdr + sizeof(coap_hdr_t) @@ -150,7 +150,7 @@ static inline int opt_finished(coap_opt_iterator_t *oi) { assert(oi); - if (oi->bad || oi->length == 0 || + if (oi->bad || oi->length == 0 || !oi->next_option || *oi->next_option == COAP_PAYLOAD_START) { oi->bad = 1; } @@ -175,16 +175,16 @@ coap_option_next(coap_opt_iterator_t *oi) { * opt_finished() filters out any bad conditions, we can assume that * oi->option is valid. */ current_opt = oi->next_option; - + /* Advance internal pointer to next option, skipping any option that * is not included in oi->filter. */ optsize = coap_opt_parse(oi->next_option, oi->length, &option); if (optsize) { assert(optsize <= oi->length); - + oi->next_option += optsize; oi->length -= optsize; - + oi->type += option.delta; } else { /* current option is malformed */ oi->bad = 1; @@ -194,7 +194,7 @@ coap_option_next(coap_opt_iterator_t *oi) { /* Exit the while loop when: * - no filtering is done at all * - the filter matches for the current option - * - the filter is too small for the current option number + * - the filter is too small for the current option number */ if (!oi->filtered || (b = coap_option_getb(oi->filter, oi->type)) > 0) @@ -209,10 +209,10 @@ coap_option_next(coap_opt_iterator_t *oi) { } coap_opt_t * -coap_check_option(coap_pdu_t *pdu, unsigned char type, +coap_check_option(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi) { coap_opt_filter_t f; - + coap_option_filter_clear(f); coap_option_setb(f, type); @@ -234,7 +234,7 @@ coap_opt_delta(const coap_opt_t *opt) { /* This case usually should not happen, hence we do not have a * proper way to indicate an error. */ return 0; - case 14: + case 14: /* Handle two-byte value: First, the MSB + 269 is stored as delta value. * After that, the option pointer is advanced to the LSB which is handled * just like case delta == 13. */ @@ -329,7 +329,7 @@ coap_opt_size(const coap_opt_t *opt) { } size_t -coap_opt_setheader(coap_opt_t *opt, size_t maxlen, +coap_opt_setheader(coap_opt_t *opt, size_t maxlen, unsigned short delta, size_t length) { size_t skip = 0; @@ -356,9 +356,9 @@ coap_opt_setheader(coap_opt_t *opt, size_t maxlen, opt[0] = 0xe0; opt[++skip] = ((delta - 269) >> 8) & 0xff; - opt[++skip] = (delta - 269) & 0xff; + opt[++skip] = (delta - 269) & 0xff; } - + if (length < 13) { opt[0] |= length & 0x0f; } else if (length < 270) { @@ -366,7 +366,7 @@ coap_opt_setheader(coap_opt_t *opt, size_t maxlen, debug("insufficient space to encode option length %zu", length); return 0; } - + opt[0] |= 0x0d; opt[++skip] = length - 13; } else { @@ -377,7 +377,7 @@ coap_opt_setheader(coap_opt_t *opt, size_t maxlen, opt[0] |= 0x0e; opt[++skip] = ((length - 269) >> 8) & 0xff; - opt[++skip] = (length - 269) & 0xff; + opt[++skip] = (length - 269) & 0xff; } return skip + 1; @@ -390,12 +390,12 @@ coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta, l = coap_opt_setheader(opt, maxlen, delta, length); assert(l <= maxlen); - + if (!l) { debug("coap_opt_encode: cannot set option header\n"); return 0; } - + maxlen -= l; opt += l; diff --git a/src/pdu.c b/src/pdu.c index 22f384ed98..fefe030510 100644 --- a/src/pdu.c +++ b/src/pdu.c @@ -49,6 +49,7 @@ coap_pdu_clear(coap_pdu_t *pdu, size_t size) { #endif pdu->max_size = size; pdu->hdr->version = COAP_DEFAULT_VERSION; + pdu->hdr->token_length = 0; /* data is NULL unless explicitly set by coap_add_data() */ pdu->length = sizeof(coap_hdr_t); @@ -103,10 +104,6 @@ coap_pdu_init(unsigned char type, unsigned char code, #ifdef WITH_LWIP struct pbuf *p; #endif -#ifdef ST_NODE - struct mbuf *m; -#endif - assert(size <= COAP_MAX_PDU_SIZE); /* Size must be large enough to fit the header. */ if (size < sizeof(coap_hdr_t) || size > COAP_MAX_PDU_SIZE) @@ -133,15 +130,18 @@ coap_pdu_init(unsigned char type, unsigned char code, #endif #ifdef ST_NODE pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t)); - memset(pdu, 0, sizeof(coap_pdu_t)); /* MWAS: for st-node payload is in separate memory area */ - m = mbuf_new(); #endif if (pdu) { #ifdef WITH_LWIP pdu->pbuf = p; #endif #ifdef ST_NODE - pdu->mbuf = m; + memset(pdu, 0, sizeof(coap_pdu_t)); /* MWAS: for st-node payload is in separate memory area */ + pdu->mbuf = mbuf_new(); + if (!pdu->mbuf) { + coap_free(pdu); + return NULL; + } pdu->mbuf->len = sizeof(coap_hdr_t); pdu->mbuf->tot_len = sizeof(coap_hdr_t); #endif diff --git a/src/resource.c b/src/resource.c index 5c23f69fc3..4ce73a4cd9 100644 --- a/src/resource.c +++ b/src/resource.c @@ -409,6 +409,9 @@ coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key) { void coap_add_resource(coap_context_t *context, coap_resource_t *resource) { RESOURCES_ADD(context->resources, resource); + if (!resource->dynamic) { + coap_hash_path(resource->uri.s, resource->uri.length, resource->key); + } } static void From 607829abfd0d35442414ac81807d020f4e4c94a5 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Fri, 3 Jul 2015 16:09:52 +0200 Subject: [PATCH 61/69] Platform refactoring --- coap_config.h.lwip | 2 - include/coap/bits.h | 1 - include/coap/coap_io.h | 96 +-- include/coap/coap_time.h | 132 ----- include/coap/debug.h | 2 +- include/coap/encode.h | 2 +- include/coap/mem.h | 46 +- include/coap/pdu.h | 41 +- include/coap/prng.h | 29 +- platform/coap_contiki.c | 182 ++++++ platform/coap_contiki.h | 62 ++ platform/coap_contiki_io.c | 196 ++++++ platform/coap_contiki_io.h | 40 ++ platform/coap_lwip.c | 185 ++++++ platform/coap_lwip.h | 64 ++ src/coap_io_lwip.c => platform/coap_lwip_io.c | 34 +- platform/coap_lwip_io.h | 73 +++ platform/coap_posix.c | 8 + platform/coap_posix.h | 57 ++ platform/coap_posix_io.c | 401 +++++++++++++ platform/coap_posix_io.h | 38 ++ {include/coap => platform}/lwippools.h | 0 src/coap_io.c | 557 ------------------ src/mem.c | 80 +-- src/net.c | 320 +--------- src/option.c | 5 +- src/pdu.c | 140 +---- src/resource.c | 73 +-- 28 files changed, 1394 insertions(+), 1472 deletions(-) create mode 100644 platform/coap_contiki.c create mode 100644 platform/coap_contiki.h create mode 100644 platform/coap_contiki_io.c create mode 100644 platform/coap_contiki_io.h create mode 100644 platform/coap_lwip.c create mode 100644 platform/coap_lwip.h rename src/coap_io_lwip.c => platform/coap_lwip_io.c (78%) create mode 100644 platform/coap_lwip_io.h create mode 100644 platform/coap_posix.c create mode 100644 platform/coap_posix.h create mode 100644 platform/coap_posix_io.c create mode 100644 platform/coap_posix_io.h rename {include/coap => platform}/lwippools.h (100%) delete mode 100644 src/coap_io.c diff --git a/coap_config.h.lwip b/coap_config.h.lwip index 5f397a0ea6..c42acb01de 100644 --- a/coap_config.h.lwip +++ b/coap_config.h.lwip @@ -17,9 +17,7 @@ * actually we'd need autotools again to find out what environment we're * building in */ #define HAVE_STRNLEN 1 - #define HAVE_LIMITS_H - #define COAP_RESOURCES_NOHASH #endif /* _CONFIG_H_ */ diff --git a/include/coap/bits.h b/include/coap/bits.h index 9eb8f24bdc..a7586a18e2 100644 --- a/include/coap/bits.h +++ b/include/coap/bits.h @@ -15,7 +15,6 @@ #ifndef _BITS_H_ #define _BITS_H_ -#include #include /** diff --git a/include/coap/coap_io.h b/include/coap/coap_io.h index df2a6edcff..6d7daa5283 100644 --- a/include/coap/coap_io.h +++ b/include/coap/coap_io.h @@ -26,55 +26,21 @@ #include "address.h" -#ifdef WITH_LWIP -# include -#endif - -#ifdef ST_NODE -#include -#include "net_common.h" -#endif - -/** - * Abstract handle that is used to identify a local network interface. - */ -typedef int coap_if_handle_t; - /** Invalid interface handle */ #define COAP_IF_INVALID -1 -struct coap_packet_t; -typedef struct coap_packet_t coap_packet_t; +#define COAP_ENDPOINT_NOSEC 0x00 +#define COAP_ENDPOINT_DTLS 0x01 struct coap_context_t; +struct coap_packet_t; /** - * Abstraction of virtual endpoint that can be attached to coap_context_t. The - * tuple (handle, addr) must uniquely identify this endpoint. + * Abstract handle that is used to identify a local network interface. */ -typedef struct coap_endpoint_t { -#if defined(WITH_POSIX) || defined(WITH_CONTIKI) - union { - int fd; /**< on POSIX systems */ - void *conn; /**< opaque connection (e.g. uip_conn in Contiki) */ - } handle; /**< opaque handle to identify this endpoint */ -#endif /* WITH_POSIX or WITH_CONTIKI */ - -#ifdef WITH_LWIP - struct udp_pcb *pcb; - /**< @FIXME this was added in a hurry, not sure it confirms to the overall model --chrysn */ - struct coap_context_t *context; -#endif /* WITH_LWIP */ -#ifdef ST_NODE - net_socket_t *ns; -#endif - coap_address_t addr; /**< local interface address */ - int ifindex; - int flags; -} coap_endpoint_t; +typedef int coap_if_handle_t; -#define COAP_ENDPOINT_NOSEC 0x00 -#define COAP_ENDPOINT_DTLS 0x01 +typedef struct coap_packet_t coap_packet_t; coap_endpoint_t *coap_new_endpoint(const coap_address_t *addr, int flags); @@ -155,54 +121,4 @@ void coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length); -#ifdef WITH_LWIP -/** - * Get the pbuf of a packet. The caller takes over responsibility for freeing - * the pbuf. - */ -struct pbuf *coap_packet_extract_pbuf(coap_packet_t *packet); -#endif - -#ifdef WITH_CONTIKI -/* - * This is only included in coap_io.h instead of .c in order to be available for - * sizeof in mem.c. - */ -struct coap_packet_t { - coap_if_handle_t hnd; /**< the interface handle */ - coap_address_t src; /**< the packet's source address */ - coap_address_t dst; /**< the packet's destination address */ - const coap_endpoint_t *interface; - int ifindex; - void *session; /**< opaque session data */ - size_t length; /**< length of payload */ - unsigned char payload[]; /**< payload */ -}; -#endif - -#ifdef WITH_LWIP -/* - * This is only included in coap_io.h instead of .c in order to be available for - * sizeof in lwippools.h. - * Simple carry-over of the incoming pbuf that is later turned into a node. - * - * Source address data is currently side-banded via ip_current_dest_addr & co - * as the packets have limited lifetime anyway. - */ -struct coap_packet_t { - struct pbuf *pbuf; - const coap_endpoint_t *local_interface; - uint16_t srcport; -}; -#endif - -#ifdef ST_NODE -struct coap_packet_t { - struct mbuf *mbuf; - const coap_endpoint_t *interface; - coap_address_t src; /**< the packet's source address */ - coap_address_t dst; /**< the packet's destination address */ -}; -#endif - #endif /* _COAP_IO_H_ */ diff --git a/include/coap/coap_time.h b/include/coap/coap_time.h index 42595bc78c..f4e0a430c5 100644 --- a/include/coap/coap_time.h +++ b/include/coap/coap_time.h @@ -29,138 +29,6 @@ extern "C" { * @{ */ -#ifdef ST_NODE -/* MWAS: based on lwIP implementation above. Uses chTimeNow() function from ChibiOS. */ -#include "ch.h" - -#define COAP_TICKS_PER_SECOND CH_FREQUENCY - -typedef systime_t coap_tick_t; -typedef systime_t coap_time_t; -typedef int coap_tick_diff_t; /* TODO: MWAS: maybe it's better to use int32 */ - -extern systime_t clock_offset; - -static inline void coap_ticks_impl(coap_tick_t *t) -{ - *t = chTimeNow(); -} - -static inline void coap_clock_init_impl(void) -{ - clock_offset = chTimeNow(); -} - -#define coap_clock_init coap_clock_init_impl -#define coap_ticks coap_ticks_impl - -static inline coap_time_t coap_ticks_to_rt(coap_tick_t t) { - return t / COAP_TICKS_PER_SECOND; -} -#endif /* ST_NODE */ -#ifdef WITH_LWIP - -#include -#include - -/* lwIP provides ms in sys_now */ -#define COAP_TICKS_PER_SECOND 1000 - -typedef uint32_t coap_tick_t; -typedef uint32_t coap_time_t; -typedef int32_t coap_tick_diff_t; - -static inline void coap_ticks_impl(coap_tick_t *t) { - *t = sys_now(); -} - -static inline void coap_clock_init_impl(void) { -} - -#define coap_clock_init coap_clock_init_impl -#define coap_ticks coap_ticks_impl - -static inline coap_time_t coap_ticks_to_rt(coap_tick_t t) { - return t / COAP_TICKS_PER_SECOND; -} -#endif - -#ifdef WITH_CONTIKI -#include "clock.h" - -typedef clock_time_t coap_tick_t; -typedef clock_time_t coap_time_t; - -/** - * This data type is used to represent the difference between two clock_tick_t - * values. This data type must have the same size in memory as coap_tick_t to - * allow wrapping. - */ -typedef int coap_tick_diff_t; - -#define COAP_TICKS_PER_SECOND CLOCK_SECOND - -static inline void coap_clock_init(void) { - clock_init(); -} - -static inline void coap_ticks(coap_tick_t *t) { - *t = clock_time(); -} - -static inline coap_time_t coap_ticks_to_rt(coap_tick_t t) { - return t / COAP_TICKS_PER_SECOND; -} -#endif /* WITH_CONTIKI */ - -#ifdef WITH_POSIX -/** - * This data type represents internal timer ticks with COAP_TICKS_PER_SECOND - * resolution. - */ -typedef unsigned long coap_tick_t; - -/** - * CoAP time in seconds since epoch. - */ -typedef time_t coap_time_t; - -/** - * This data type is used to represent the difference between two clock_tick_t - * values. This data type must have the same size in memory as coap_tick_t to - * allow wrapping. - */ -typedef long coap_tick_diff_t; - -/** Use ms resolution on POSIX systems */ -#define COAP_TICKS_PER_SECOND 1000 - -/** - * Initializes the internal clock. - */ -static inline void coap_clock_init(void) { -} - -/** - * Sets @p t to the internal time with COAP_TICKS_PER_SECOND resolution. - */ -void coap_ticks(coap_tick_t *t); - -/** - * Helper function that converts coap ticks to wallclock time. On POSIX, this - * function returns the number of seconds since the epoch. On other systems, it - * may be the calculated number of seconds since last reboot or so. - * - * @param t Internal system ticks. - * - * @return The number of seconds that has passed since a specific reference - * point (seconds since epoch on POSIX). - */ -static inline coap_time_t coap_ticks_to_rt(coap_tick_t t) { - return t / COAP_TICKS_PER_SECOND; -} -#endif /* WITH_POSIX */ - /** * Returns @c 1 if and only if @p a is less than @p b where less is defined on a * signed data type. diff --git a/include/coap/debug.h b/include/coap/debug.h index aed9d20aec..5248d03a5c 100644 --- a/include/coap/debug.h +++ b/include/coap/debug.h @@ -1,4 +1,4 @@ -/* debug.h -- debug utilities + /* debug.h -- debug utilities * * Copyright (C) 2010,2011,2014 Olaf Bergmann * diff --git a/include/coap/encode.h b/include/coap/encode.h index 5e80948550..ac9e02ac6d 100644 --- a/include/coap/encode.h +++ b/include/coap/encode.h @@ -9,7 +9,7 @@ #ifndef _COAP_ENCODE_H_ #define _COAP_ENCODE_H_ -# include +#include #define Nn 8 /* duplicate definition of N if built on sky motes */ #define E 4 diff --git a/include/coap/mem.h b/include/coap/mem.h index 2de7dcdc1e..b5f78a3b6e 100644 --- a/include/coap/mem.h +++ b/include/coap/mem.h @@ -13,15 +13,6 @@ #include #endif -#ifndef WITH_LWIP -/** - * Initializes libcoap's memory management. - * This function must be called once before coap_malloc() can be used on - * constrained devices. - */ -void coap_memory_init(void); -#endif /* WITH_LWIP */ - /** * Type specifiers for coap_malloc_type(). Memory objects can be typed to * facilitate arrays of type objects to be used instead of dynamic memory @@ -43,7 +34,12 @@ typedef enum { COAP_SUBSCRIPTION, } coap_memory_tag_t; -#ifndef WITH_LWIP +/** + * Initializes libcoap's memory management. + * This function must be called once before coap_malloc() can be used on + * constrained devices. + */ +void coap_memory_init(void); /** * Allocates a chunk of @p size bytes and returns a pointer to the newly @@ -81,34 +77,4 @@ static inline void coap_free(void *object) { coap_free_type(COAP_STRING, object); } -#endif /* not WITH_LWIP */ - -#ifdef WITH_LWIP - -#include - -/* no initialization needed with lwip (or, more precisely: lwip must be - * completely initialized anyway by the time coap gets active) */ -static inline void coap_memory_init(void) {} - -/* It would be nice to check that size equals the size given at the memp - * declaration, but i currently don't see a standard way to check that without - * sourcing the custom memp pools and becoming dependent of its syntax - */ -#define coap_malloc_type(type, size) memp_malloc(MEMP_ ## type) -#define coap_free_type(type, p) memp_free(MEMP_ ## type, p) - -/* Those are just here to make uri.c happy where string allocation has not been - * made conditional. - */ -static inline void *coap_malloc(size_t size) { - LWIP_ASSERT("coap_malloc must not be used in lwIP", 0); -} - -static inline void coap_free(void *pointer) { - LWIP_ASSERT("coap_free must not be used in lwIP", 0); -} - -#endif /* WITH_LWIP */ - #endif /* _COAP_MEM_H_ */ diff --git a/include/coap/pdu.h b/include/coap/pdu.h index 78c93cea25..df0cf2e0e8 100644 --- a/include/coap/pdu.h +++ b/include/coap/pdu.h @@ -18,10 +18,6 @@ #include "uri.h" #include -#ifdef WITH_LWIP -#include -#endif - /* pre-defined constants that reflect defaults for CoAP */ #ifndef COAP_DEFAULT_RESPONSE_TIMEOUT @@ -254,19 +250,8 @@ typedef struct { unsigned short length; /**< PDU length (including header, options, data) */ unsigned char *data; /**< payload */ -#ifdef WITH_LWIP - struct pbuf *pbuf; /**< lwIP PBUF. The package data will always reside - * inside the pbuf's payload, but this pointer - * has to be kept because no exact offset can be - * given. This field must not be accessed from - * outside, because the pbuf's reference count - * is checked to be 1 when the pbuf is assigned - * to the pdu, and the pbuf stays exclusive to - * this pdu. */ -#endif -#ifdef ST_NODE - unsigned short payload_offset; /**< payload offset */ - struct mbuf *mbuf; /**< mbuf */ +#ifdef CUSTOM_PDU_FIELDS + CUSTOM_PDU_FIELDS #endif } coap_pdu_t; @@ -279,25 +264,6 @@ typedef struct { #define COAP_PDU_TYPE(pdu) ((pdu)->hdr->type) #define COAP_PDU_ID(pdu) ((pdu)->hdr->id) -#ifdef WITH_LWIP -/** - * Creates a CoAP PDU from an lwIP @p pbuf, whose reference is passed on to this - * function. - * - * The pbuf is checked for being contiguous, and for having only one reference. - * The reference is stored in the PDU and will be freed when the PDU is freed. - * - * (For now, these are fatal errors; in future, a new pbuf might be allocated, - * the data copied and the passed pbuf freed). - * - * This behaves like coap_pdu_init(0, 0, 0, pbuf->tot_len), and afterwards - * copying the contents of the pbuf to the pdu. - * - * @return A pointer to the new PDU object or @c NULL on error. - */ -coap_pdu_t * coap_pdu_from_pbuf(struct pbuf *pbuf); -#endif - /** * Creates a new CoAP PDU of given @p size (must be large enough to hold the * basic CoAP message header (coap_hdr_t). The function returns a pointer to the @@ -421,7 +387,4 @@ static inline int coap_has_data(coap_pdu_t *pdu) return (pdu->data != NULL); } -#ifdef ST_NODE -coap_pdu_t *coap_pdu_from_mbuf(struct mbuf *mbuf); -#endif #endif /* _PDU_H_ */ diff --git a/include/coap/prng.h b/include/coap/prng.h index f963e79dfd..d56df0237b 100644 --- a/include/coap/prng.h +++ b/include/coap/prng.h @@ -21,9 +21,9 @@ * @{ */ -#ifndef WITH_CONTIKI #include +#ifndef prng /** * Fills \p buf with \p len random bytes. This is the default implementation for * prng(). You might want to change prng() to use a better PRNG on your specific @@ -35,33 +35,6 @@ coap_prng_impl(unsigned char *buf, size_t len) { *buf++ = rand() & 0xFF; return 1; } -#else /* WITH_CONTIKI */ -#include - -/** - * Fills \p buf with \p len random bytes. This is the default implementation for - * prng(). You might want to change prng() to use a better PRNG on your specific - * platform. - */ -static inline int -contiki_prng_impl(unsigned char *buf, size_t len) { - unsigned short v = random_rand(); - while (len > sizeof(v)) { - memcpy(buf, &v, sizeof(v)); - len -= sizeof(v); - buf += sizeof(v); - v = random_rand(); - } - - memcpy(buf, &v, len); - return 1; -} - -#define prng(Buf,Length) contiki_prng_impl((Buf), (Length)) -#define prng_init(Value) random_init((unsigned short)(Value)) -#endif /* WITH_CONTIKI */ - -#ifndef prng /** * Fills \p Buf with \p Length bytes of random data. * diff --git a/platform/coap_contiki.c b/platform/coap_contiki.c new file mode 100644 index 0000000000..ff94e8f666 --- /dev/null +++ b/platform/coap_contiki.c @@ -0,0 +1,182 @@ +/* + * coap_contiki.c + + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ +# ifndef DEBUG +# define DEBUG DEBUG_PRINT +# endif /* DEBUG */ + +#include "coap_config.h" +#include "net.h" +#include "pdu.h" +#include "coap_io.h" +#include "resource.h" + +#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) +#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN]) + +#define COAP_MAX_STRING_SIZE 12 +#define COAP_MAX_STRINGS 8 +#define COAP_MAX_PACKET_SIZE (sizeof(coap_packet_t) + COAP_MAX_PDU_SIZE) +#define COAP_MAX_PACKETS 2 + +static unsigned char initialized = 0; +static coap_context_t the_coap_context; + +PROCESS(coap_retransmit_process, "message retransmit process"); + +struct coap_string_t +{ + char data[COAP_MAX_STRING_SIZE]; +}; + +typedef union +{ + coap_pdu_t packet; /* try to convince the compiler to word-align this structure */ + char buf[COAP_MAX_PACKET_SIZE]; +} coap_packetbuf_t; + +MEMB(packet_storage, coap_packetbuf_t, COAP_MAX_PACKETS); +MEMB(node_storage, coap_queue_t, COAP_PDU_MAXCNT); +MEMB(pdu_storage, coap_pdu_t, COAP_PDU_MAXCNT); +MEMB(pdu_buf_storage, coap_packetbuf_t, COAP_PDU_MAXCNT); +MEMB(resource_storage, coap_resource_t, COAP_MAX_RESOURCES); +MEMB(attribute_storage, coap_attr_t, COAP_MAX_ATTRIBUTES); +MEMB(subscription_storage, coap_subscription_t, COAP_MAX_SUBSCRIBERS); +MEMB(string_storage, struct coap_string_t, COAP_MAX_STRINGS); + +static struct memb * +get_container(coap_memory_tag_t type) +{ + switch (type) { + case COAP_PACKET: + return &packet_storage; + case COAP_NODE: + return &node_storage; + case COAP_PDU: + return &pdu_storage; + case COAP_PDU_BUF: + return &pdu_buf_storage; + case COAP_RESOURCE: + return &resource_storage; + case COAP_RESOURCEATTR: + return &attribute_storage; + case COAP_SUBSCRIPTION: + return &subscription_storage; + default: + return &string_storage; + } +} + +void +coap_memory_init(void) +{ + memb_init(&string_storage); + memb_init(&packet_storage); + memb_init(&node_storage); + memb_init(&pdu_storage); + memb_init(&pdu_buf_storage); + memb_init(&resource_storage); + memb_init(&attribute_storage); +} + +void * +coap_malloc_type(coap_memory_tag_t type, size_t size) +{ + if (type != COAP_CONTEXT) { + struct memb *container = get_container(type); + + assert(container); + + if (size > container->size) { + debug("coap_malloc_type: Requested memory exceeds maximum object size\n"); + return NULL; + } + + return memb_alloc(container); + } else if (!initialized) { + return &the_coap_context; + } else { + return NULL; + } +} + +void +coap_free_type(coap_memory_tag_t type, void *object) +{ + if (type != COAP_CONTEXT) + memb_free(get_container(type), object); +} + +void +coap_platform_init(void) +{ + coap_resources_init(); + coap_memory_init(); + + process_start(&coap_retransmit_process, (char *) c); + + PROCESS_CONTEXT_BEGIN(&coap_retransmit_process); +#ifndef WITHOUT_OBSERVE + etimer_set(&c->notify_timer, + COAP_RESOURCE_CHECK_TIME * COAP_TICKS_PER_SECOND); +#endif /* WITHOUT_OBSERVE */ + /* the retransmit timer must be initialized to some large value */ + etimer_set(&the_coap_context.retransmit_timer, 0xFFFF); + PROCESS_CONTEXT_END(&coap_retransmit_process); + + c = &the_coap_context; + initialized = 1; +} + +void +coap_platform_deinit(void) +{ + memset(&the_coap_context, 0, sizeof(coap_context_t)); + initialized = 0; +} + +/*---------------------------------------------------------------------------*/ +/* CoAP message retransmission */ +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD( coap_retransmit_process, ev, data) +{ + coap_tick_t now; + coap_queue_t *nextpdu; + + PROCESS_BEGIN(); + + debug("Started retransmit process\r\n"); + + while (1) { + PROCESS_YIELD(); + if (ev == PROCESS_EVENT_TIMER) { + if (etimer_expired(&the_coap_context.retransmit_timer)) { + + nextpdu = coap_peek_next(&the_coap_context); + + coap_ticks(&now); + while (nextpdu && nextpdu->t <= now) { + coap_retransmit(&the_coap_context, coap_pop_next(&the_coap_context)); + nextpdu = coap_peek_next(&the_coap_context); + } + + /* need to set timer to some value even if no nextpdu is available */ + etimer_set(&the_coap_context.retransmit_timer, + nextpdu ? nextpdu->t - now : 0xFFFF); + } +#ifndef WITHOUT_OBSERVE + if (etimer_expired(&the_coap_context.notify_timer)) { + coap_check_notify(&the_coap_context); + etimer_reset(&the_coap_context.notify_timer); + } +#endif /* WITHOUT_OBSERVE */ + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/platform/coap_contiki.h b/platform/coap_contiki.h new file mode 100644 index 0000000000..d71ecb4942 --- /dev/null +++ b/platform/coap_contiki.h @@ -0,0 +1,62 @@ +/* + * coap_contiki.h + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ + +#ifndef INCLUDE_COAP_COAP_CONTIKI_H_ +#define INCLUDE_COAP_COAP_CONTIKI_H_ + +#include +#include "clock.h" +#include "mem.h" +#include "net/ip/uip-debug.h" + +typedef clock_time_t coap_tick_t; +typedef clock_time_t coap_time_t; + +/** + * This data type is used to represent the difference between two clock_tick_t + * values. This data type must have the same size in memory as coap_tick_t to + * allow wrapping. + */ +typedef int coap_tick_diff_t; + +#define COAP_TICKS_PER_SECOND CLOCK_SECOND + +static inline void coap_clock_init(void) { + clock_init(); +} + +static inline void coap_ticks(coap_tick_t *t) { + *t = clock_time(); +} + +static inline coap_time_t coap_ticks_to_rt(coap_tick_t t) { + return t / COAP_TICKS_PER_SECOND; +} + +/** + * Fills \p buf with \p len random bytes. This is the default implementation for + * prng(). You might want to change prng() to use a better PRNG on your specific + * platform. + */ +static inline int +coap_prng_impl(unsigned char *buf, size_t len) { + unsigned short v = random_rand(); + while (len > sizeof(v)) { + memcpy(buf, &v, sizeof(v)); + len -= sizeof(v); + buf += sizeof(v); + v = random_rand(); + } + + memcpy(buf, &v, len); + return 1; +} + +#define prng(Buf,Length) coap_prng_impl((Buf), (Length)) +#define prng_init(Value) random_init((unsigned short)(Value)) + +#endif /* INCLUDE_COAP_COAP_CONTIKI_H_ */ diff --git a/platform/coap_contiki_io.c b/platform/coap_contiki_io.c new file mode 100644 index 0000000000..29e5529e9d --- /dev/null +++ b/platform/coap_contiki_io.c @@ -0,0 +1,196 @@ +/* + * coap_contiki_io.c + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ + + +#include "coap_config.h" +#include "debug.h" +#include "mem.h" +#include "coap_io.h" + +#ifdef HAVE_STDIO_H +#include +#endif + +#include "uip.h" + /* FIXME: untested, make this work */ +#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) +#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN]) + +static int ep_initialized = 0; + +static inline struct coap_endpoint_t * +coap_malloc_contiki_endpoint() { + static struct coap_endpoint_t ep; + + if (ep_initialized) { + return NULL; + } else { + ep_initialized = 1; + return &ep; + } +} + +static inline void +coap_free_contiki_endpoint(struct coap_endpoint_t *ep) { + ep_initialized = 0; +} + +coap_endpoint_t * +coap_new_endpoint(const coap_address_t *addr, int flags) { + struct coap_endpoint_t *ep = coap_malloc_contiki_endpoint(); + + if (ep) { + memset(ep, 0, sizeof(struct coap_endpoint_t)); + ep->handle.conn = udp_new(NULL, 0, NULL); + + if (!ep->handle.conn) { + coap_free_endpoint(ep); + return NULL; + } + + coap_address_init(&ep->addr); + uip_ipaddr_copy(&ep->addr.addr, &addr->addr); + ep->addr.port = addr->port; + udp_bind((struct uip_udp_conn *)ep->handle.conn, addr->port); + } + return ep; +} + +void +coap_free_endpoint(coap_endpoint_t *ep) { + if (ep) { + if (ep->handle.conn) { + uip_udp_remove((struct uip_udp_conn *)ep->handle.conn); + } + coap_free_contiki_endpoint(ep); + } +} + +static inline coap_packet_t * +coap_malloc_packet(void) { + return (coap_packet_t *)coap_malloc_type(COAP_PACKET, 0); +} + +void +coap_free_packet(coap_packet_t *packet) { + coap_free_type(COAP_PACKET, packet); +} + +static inline size_t +coap_get_max_packetlength(const coap_packet_t *packet UNUSED_PARAM) { + return COAP_MAX_PDU_SIZE; +} + +void +coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target) +{ + target->handle = packet->interface->handle; + memcpy(&target->addr, &packet->dst, sizeof(target->addr)); + target->ifindex = packet->ifindex; + target->flags = 0; /* FIXME */ +} + +void +coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target) +{ + memcpy(target, &packet->src, sizeof(coap_address_t)); +} + +void +coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length) +{ + *address = packet->payload; + *length = packet->length; +} + +ssize_t +coap_network_send(struct coap_context_t *context, + const coap_endpoint_t *local_interface, + const coap_address_t *dst, + unsigned char *data, + size_t datalen) { + + struct coap_endpoint_t *ep = + (struct coap_endpoint_t *)local_interface; + + uip_udp_packet_sendto((struct uip_udp_conn *)ep->handle.conn, data, datalen, + &dst->addr, dst->port); + return datalen; +} + +/** + * Checks if a message with destination address @p dst matches the + * local interface with address @p local. This function returns @c 1 + * if @p dst is a valid match, and @c 0 otherwise. + */ +static inline int +is_local_if(const coap_address_t *local, const coap_address_t *dst) { + return coap_address_isany(local) || coap_address_equals(dst, local); +} + +ssize_t +coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) { + ssize_t len = -1; + + assert(ep); + assert(packet); + + *packet = coap_malloc_packet(); + + if (!*packet) { + warn("coap_network_read: insufficient memory, drop packet\n"); + return -1; + } + + coap_address_init(&(*packet)->dst); /* the local interface address */ + coap_address_init(&(*packet)->src); /* the remote peer */ + + if(uip_newdata()) { + uip_ipaddr_copy(&(*packet)->src.addr, &UIP_IP_BUF->srcipaddr); + (*packet)->src.port = UIP_UDP_BUF->srcport; + uip_ipaddr_copy(&(*packet)->dst.addr, &UIP_IP_BUF->destipaddr); + (*packet)->dst.port = UIP_UDP_BUF->destport; + + if (!is_local_if(&ep->addr, &(*packet)->dst)) { + coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n"); + goto error; + } + + len = uip_datalen(); + + if (len > coap_get_max_packetlength(*packet)) { + /* FIXME: we might want to send back a response */ + warn("discarded oversized packet\n"); + return -1; + } + + ((char *)uip_appdata)[len] = 0; +#ifndef NDEBUG + if (LOG_DEBUG <= coap_get_log_level()) { +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN 40 +#endif + unsigned char addr_str[INET6_ADDRSTRLEN+8]; + + if (coap_print_addr(&(*packet)->src, addr_str, INET6_ADDRSTRLEN+8)) { + debug("received %zd bytes from %s\n", len, addr_str); + } + } +#endif /* NDEBUG */ + + (*packet)->length = len; + memcpy(&(*packet)->payload, uip_appdata, len); + } + + (*packet)->interface = ep; + + return len; + error: + coap_free_packet(*packet); + *packet = NULL; + return -1; +} diff --git a/platform/coap_contiki_io.h b/platform/coap_contiki_io.h new file mode 100644 index 0000000000..8aaf121db5 --- /dev/null +++ b/platform/coap_contiki_io.h @@ -0,0 +1,40 @@ +/* + * coap_contiki_io.h + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ + +#ifndef _COAP_CONTIKI_IO_H_ +#define _COAP_CONTIKI_IO_H_ + +/* + * This is only included in coap_io.h instead of .c in order to be available for + * sizeof in mem.c. + */ +struct coap_packet_t { + coap_if_handle_t hnd; /**< the interface handle */ + coap_address_t src; /**< the packet's source address */ + coap_address_t dst; /**< the packet's destination address */ + const coap_endpoint_t *interface; + int ifindex; + void *session; /**< opaque session data */ + size_t length; /**< length of payload */ + unsigned char payload[]; /**< payload */ +}; + +/** + * Abstraction of virtual endpoint that can be attached to coap_context_t. The + * tuple (handle, addr) must uniquely identify this endpoint. + */ +typedef struct coap_endpoint_t { + union { + int fd; /**< on POSIX systems */ + void *conn; /**< opaque connection (e.g. uip_conn in Contiki) */ + } handle; /**< opaque handle to identify this endpoint */ + coap_address_t addr; /**< local interface address */ + int ifindex; + int flags; +} coap_endpoint_t; + +#endif /* _COAP_CONTIKI_IO_H_ */ diff --git a/platform/coap_lwip.c b/platform/coap_lwip.c new file mode 100644 index 0000000000..222d0dde7e --- /dev/null +++ b/platform/coap_lwip.c @@ -0,0 +1,185 @@ +/* + * coap_lwip.c + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ + +void coap_platform_init(void) +{ + prng_init(LWIP_RAND()); +} + +void coap_platform_deinit(void) +{ + +} + +/* FIXME: retransmits that are not required any more due to incoming packages + * do *not* get cleared at the moment, the wakeup when the transmission is due + * is silently accepted. this is mainly due to the fact that the required + * checks are similar in two places in the code (when receiving ACK and RST) + * and that they cause more than one patch chunk, as it must be first checked + * whether the sendqueue item to be dropped is the next one pending, and later + * the restart function has to be called. nothing insurmountable, but it can + * also be implemented when things have stabilized, and the performance + * penality is minimal + * + * also, this completely ignores COAP_RESOURCE_CHECK_TIME. + * */ + +static void coap_retransmittimer_execute(void *arg) +{ + coap_context_t *ctx = (coap_context_t*)arg; + coap_tick_t now; + coap_tick_t elapsed; + coap_queue_t *nextinqueue; + + ctx->timer_configured = 0; + + coap_ticks(&now); + + elapsed = now - ctx->sendqueue_basetime; /* that's positive for sure, and unless we haven't been called for a complete wrapping cycle, did not wrap */ + + nextinqueue = coap_peek_next(ctx); + while (nextinqueue != NULL) + { + if (nextinqueue->t > elapsed) { + nextinqueue->t -= elapsed; + break; + } else { + elapsed -= nextinqueue->t; + coap_retransmit(ctx, coap_pop_next(ctx)); + nextinqueue = coap_peek_next(ctx); + } + } + + ctx->sendqueue_basetime = now; + + coap_retransmittimer_restart(ctx); +} + +static void coap_retransmittimer_restart(coap_context_t *ctx) +{ + coap_tick_t now, elapsed, delay; + + if (ctx->timer_configured) + { + printf("clearing\n"); + sys_untimeout(coap_retransmittimer_execute, (void*)ctx); + ctx->timer_configured = 0; + } + if (ctx->sendqueue != NULL) + { + coap_ticks(&now); + elapsed = now - ctx->sendqueue_basetime; + if (ctx->sendqueue->t >= elapsed) { + delay = ctx->sendqueue->t - elapsed; + } else { + /* a strange situation, but not completely impossible. + * + * this happens, for example, right after + * coap_retransmittimer_execute, when a retransmission + * was *just not yet* due, and the clock ticked before + * our coap_ticks was called. + * + * not trying to retransmit anything now, as it might + * cause uncontrollable recursion; let's just try again + * with the next main loop run. + * */ + delay = 0; + } + + printf("scheduling for %d ticks\n", delay); + sys_timeout(delay, coap_retransmittimer_execute, (void*)ctx); + ctx->timer_configured = 1; + } +} + +coap_pdu_t * +coap_pdu_from_pbuf(struct pbuf *pbuf) +{ + if (pbuf == NULL) return NULL; + + LWIP_ASSERT("Can only deal with contiguous PBUFs", pbuf->tot_len == pbuf->len); + LWIP_ASSERT("coap_read needs to receive an exclusive copy of the incoming pbuf", pbuf->ref == 1); + + coap_pdu_t *result = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t)); + if (!result) { + pbuf_free(pbuf); + return NULL; + } + + memset(result, 0, sizeof(coap_pdu_t)); + + result->max_size = pbuf->tot_len; + result->length = pbuf->tot_len; + result->hdr = pbuf->payload; + result->pbuf = pbuf; + + return result; +} + +void +coap_pdu_clear(coap_pdu_t *pdu, size_t size) { + assert(pdu); + + /* the pdu itself is not wiped as opposed to the other implementations, + * because we have to rely on the pbuf to be set there. */ + pdu->hdr = pdu->pbuf->payload; + pdu->max_size = size; + pdu->hdr->version = COAP_DEFAULT_VERSION; + pdu->hdr->token_length = 0; + + /* data is NULL unless explicitly set by coap_add_data() */ + pdu->length = sizeof(coap_hdr_t); +} + +coap_pdu_t * +coap_pdu_init(unsigned char type, unsigned char code, + unsigned short id, size_t size) { + coap_pdu_t *pdu; + struct pbuf *p; + assert(size <= COAP_MAX_PDU_SIZE); + /* Size must be large enough to fit the header. */ + if (size < sizeof(coap_hdr_t) || size > COAP_MAX_PDU_SIZE) + return NULL; + + p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM); + if (p != NULL) { + u8_t header_error = pbuf_header(p, sizeof(coap_pdu_t)); + /* we could catch that case and allocate larger memory in advance, but then + * again, we'd run into greater trouble with incoming packages anyway */ + LWIP_ASSERT("CoAP PDU header does not fit in transport header", header_error == 0); + pdu = p->payload; + } else { + pdu = NULL; + } + if (pdu) { + pdu->pbuf = p; + coap_pdu_clear(pdu, size); + pdu->hdr->id = id; + pdu->hdr->type = type; + pdu->hdr->code = code; + } + return pdu; +} + +coap_pdu_t * +coap_new_pdu(void) { + coap_pdu_t *pdu; + + pdu = coap_pdu_init(0, 0, ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE); + +#ifndef NDEBUG + if (!pdu) + coap_log(LOG_CRIT, "coap_new_pdu: cannot allocate memory for new PDU\n"); +#endif + return pdu; +} + +void +coap_delete_pdu(coap_pdu_t *pdu) { + if (pdu != NULL) /* accepting double free as the other implementation accept that too */ + pbuf_free(pdu->pbuf); +} diff --git a/platform/coap_lwip.h b/platform/coap_lwip.h new file mode 100644 index 0000000000..52187cfeb3 --- /dev/null +++ b/platform/coap_lwip.h @@ -0,0 +1,64 @@ +/* + * coap_lwip.h + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ + +#ifndef INCLUDE_COAP_COAP_LWIP_H_ +#define INCLUDE_COAP_COAP_LWIP_H_ + +#include +#include +#include +#include +#include +#include + +/* lwIP provides ms in sys_now */ +#define COAP_TICKS_PER_SECOND 1000 + +typedef uint32_t coap_tick_t; +typedef uint32_t coap_time_t; +typedef int32_t coap_tick_diff_t; + +static inline void coap_ticks_impl(coap_tick_t *t) { + *t = sys_now(); +} + +static inline void coap_clock_init_impl(void) { +} + +#define coap_clock_init coap_clock_init_impl +#define coap_ticks coap_ticks_impl + +static inline coap_time_t coap_ticks_to_rt(coap_tick_t t) { + return t / COAP_TICKS_PER_SECOND; +} + +static void coap_retransmittimer_execute(void *arg); +static void coap_retransmittimer_restart(coap_context_t *ctx); + +/* no initialization needed with lwip (or, more precisely: lwip must be + * completely initialized anyway by the time coap gets active) */ +static inline void coap_memory_init(void) {} + +/* It would be nice to check that size equals the size given at the memp + * declaration, but i currently don't see a standard way to check that without + * sourcing the custom memp pools and becoming dependent of its syntax + */ +#define coap_malloc_type(type, size) memp_malloc(MEMP_##type) +#define coap_free_type(type, p) memp_free(MEMP_##type, p) + +/* Those are just here to make uri.c happy where string allocation has not been + * made conditional. + */ +static inline void *coap_malloc(size_t size) { + LWIP_ASSERT("coap_malloc must not be used in lwIP", 0); +} + +static inline void coap_free(void *pointer) { + LWIP_ASSERT("coap_free must not be used in lwIP", 0); +} + +#endif /* INCLUDE_COAP_COAP_LWIP_H_ */ diff --git a/src/coap_io_lwip.c b/platform/coap_lwip_io.c similarity index 78% rename from src/coap_io_lwip.c rename to platform/coap_lwip_io.c index 125344737f..bab0fc2334 100644 --- a/src/coap_io_lwip.c +++ b/platform/coap_lwip_io.c @@ -4,12 +4,13 @@ * 2014 chrysn * * 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" #include "mem.h" +#include "coap_config.h" #include "coap_io.h" +#include "coap_lwip_io.h" void coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target) { @@ -40,6 +41,35 @@ struct pbuf *coap_packet_extract_pbuf(coap_packet_t *packet) return ret; } +coap_tid_t +coap_send_impl(coap_context_t *context, + const coap_endpoint_t *local_interface, + const coap_address_t *dst, + coap_pdu_t *pdu) { + coap_tid_t id = COAP_INVALID_TID; + uint8_t err; + char *data_backup; + + if ( !context || !dst || !pdu ) + { + return id; + } + + data_backup = pdu->data; + + /* FIXME: we can't check this here with the existing infrastructure, but we + * should actually check that the pdu is not held by anyone but us. the + * respective pbuf is already exclusively owned by the pdu. */ + + pbuf_realloc(pdu->pbuf, pdu->length); + + coap_transaction_id(dst, pdu, &id); + + udp_sendto(context->endpoint->pcb, pdu->pbuf, + &dst->addr, dst->port); + + return id; +} /** Callback from lwIP when a package was received. * diff --git a/platform/coap_lwip_io.h b/platform/coap_lwip_io.h new file mode 100644 index 0000000000..430ba5341a --- /dev/null +++ b/platform/coap_lwip_io.h @@ -0,0 +1,73 @@ +/* + * coap_lwip_io.h + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ + +#ifndef PLATFORM_COAP_LWIP_IO_H_ +#define PLATFORM_COAP_LWIP_IO_H_ + +#include +#include + +#define CUSTOM_PDU_FIELDS struct pbuf *pbuf; /**< lwIP PBUF. The package data will always reside + * inside the pbuf's payload, but this pointer + * has to be kept because no exact offset can be + * given. This field must not be accessed from + * outside, because the pbuf's reference count + * is checked to be 1 when the pbuf is assigned + * to the pdu, and the pbuf stays exclusive to + * this pdu. */ + +/* + * This is only included in coap_io.h instead of .c in order to be available for + * sizeof in lwippools.h. + * Simple carry-over of the incoming pbuf that is later turned into a node. + * + * Source address data is currently side-banded via ip_current_dest_addr & co + * as the packets have limited lifetime anyway. + */ +struct coap_packet_t { + struct pbuf *pbuf; + const coap_endpoint_t *local_interface; + uint16_t srcport; +}; + +/** + * Abstraction of virtual endpoint that can be attached to coap_context_t. The + * tuple (handle, addr) must uniquely identify this endpoint. + */ +typedef struct coap_endpoint_t { + struct udp_pcb *pcb; + /**< @FIXME this was added in a hurry, not sure it confirms to the overall model --chrysn */ + struct coap_context_t *context; + coap_address_t addr; /**< local interface address */ + int ifindex; + int flags; +} coap_endpoint_t; + +/** + * Get the pbuf of a packet. The caller takes over responsibility for freeing + * the pbuf. + */ +struct pbuf *coap_packet_extract_pbuf(coap_packet_t *packet); + +/** + * Creates a CoAP PDU from an lwIP @p pbuf, whose reference is passed on to this + * function. + * + * The pbuf is checked for being contiguous, and for having only one reference. + * The reference is stored in the PDU and will be freed when the PDU is freed. + * + * (For now, these are fatal errors; in future, a new pbuf might be allocated, + * the data copied and the passed pbuf freed). + * + * This behaves like coap_pdu_init(0, 0, 0, pbuf->tot_len), and afterwards + * copying the contents of the pbuf to the pdu. + * + * @return A pointer to the new PDU object or @c NULL on error. + */ +coap_pdu_t * coap_pdu_from_pbuf(struct pbuf *pbuf); + +#endif /* PLATFORM_COAP_LWIP_IO_H_ */ diff --git a/platform/coap_posix.c b/platform/coap_posix.c new file mode 100644 index 0000000000..bdc231f9ef --- /dev/null +++ b/platform/coap_posix.c @@ -0,0 +1,8 @@ +/* + * coap_posix.c + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ + + diff --git a/platform/coap_posix.h b/platform/coap_posix.h new file mode 100644 index 0000000000..df64ebfa3a --- /dev/null +++ b/platform/coap_posix.h @@ -0,0 +1,57 @@ +/* + * coap_posix.h + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ + +#ifndef INCLUDE_COAP_COAP_POSIX_H_ +#define INCLUDE_COAP_COAP_POSIX_H_ + +/** + * This data type represents internal timer ticks with COAP_TICKS_PER_SECOND + * resolution. + */ +typedef unsigned long coap_tick_t; + +/** + * CoAP time in seconds since epoch. + */ +typedef time_t coap_time_t; + +/** + * This data type is used to represent the difference between two clock_tick_t + * values. This data type must have the same size in memory as coap_tick_t to + * allow wrapping. + */ +typedef long coap_tick_diff_t; + +/** Use ms resolution on POSIX systems */ +#define COAP_TICKS_PER_SECOND 1000 + +/** + * Initializes the internal clock. + */ +static inline void coap_clock_init(void) { +} + +/** + * Sets @p t to the internal time with COAP_TICKS_PER_SECOND resolution. + */ +void coap_ticks(coap_tick_t *t); + +/** + * Helper function that converts coap ticks to wallclock time. On POSIX, this + * function returns the number of seconds since the epoch. On other systems, it + * may be the calculated number of seconds since last reboot or so. + * + * @param t Internal system ticks. + * + * @return The number of seconds that has passed since a specific reference + * point (seconds since epoch on POSIX). + */ +static inline coap_time_t coap_ticks_to_rt(coap_tick_t t) { + return t / COAP_TICKS_PER_SECOND; +} + +#endif /* INCLUDE_COAP_COAP_POSIX_H_ */ diff --git a/platform/coap_posix_io.c b/platform/coap_posix_io.c new file mode 100644 index 0000000000..8a3d189471 --- /dev/null +++ b/platform/coap_posix_io.c @@ -0,0 +1,401 @@ +/* + * coap_posix_io.h + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ +#ifdef HAVE_SYS_SELECT_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_SYS_UIO_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#include "debug.h" +#include "mem.h" +#include "coap_io.h" + +#if defined(WITH_POSIX) != defined(HAVE_NETINET_IN_H) +/* define struct in6_pktinfo and struct in_pktinfo if not available + FIXME: check with configure + */ +struct in6_pktinfo { + struct in6_addr ipi6_addr; /* src/dst IPv6 address */ + unsigned int ipi6_ifindex; /* send/recv interface index */ +}; + +struct in_pktinfo { + int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; +#endif + +#if defined(WITH_POSIX) && !defined(SOL_IP) +/* Solaris expects level IPPROTO_IP for ancillary data. */ +#define SOL_IP IPPROTO_IP +#endif + +#ifdef __GNUC__ +#define UNUSED_PARAM __attribute__ ((unused)) +#else /* not a GCC */ +#define UNUSED_PARAM +#endif /* GCC */ + +#define SIN6(A) ((struct sockaddr_in6 *)(A)) + +static inline struct coap_endpoint_t * +coap_malloc_posix_endpoint(void) +{ + return (struct coap_endpoint_t *) coap_malloc(sizeof(struct coap_endpoint_t)); +} + +static inline void +coap_free_posix_endpoint(struct coap_endpoint_t *ep) +{ + coap_free(ep); +} + +coap_endpoint_t * +coap_new_endpoint(const coap_address_t *addr, int flags) +{ + int sockfd = socket(addr->addr.sa.sa_family, SOCK_DGRAM, 0); + int on = 1; + struct coap_endpoint_t *ep; + + if (sockfd < 0) { + coap_log(LOG_WARNING, "coap_new_endpoint: socket"); + return NULL; + } + + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) + coap_log(LOG_WARNING, "coap_new_endpoint: setsockopt SO_REUSEADDR"); + + on = 1; + switch (addr->addr.sa.sa_family) { + case AF_INET: + if (setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) < 0) + coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IP_PKTINFO\n"); + break; + case AF_INET6: +#ifdef IPV6_RECVPKTINFO + if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) + coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_RECVPKTINFO\n"); +#else /* IPV6_RECVPKTINFO */ + if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) < 0) + coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_PKTINFO\n"); +#endif /* IPV6_RECVPKTINFO */ + break; + default: + coap_log(LOG_ALERT, "coap_new_endpoint: unsupported sa_family\n"); + } + + if (bind(sockfd, &addr->addr.sa, addr->size) < 0) { + coap_log(LOG_WARNING, "coap_new_endpoint: bind"); + close(sockfd); + return NULL; + } + + ep = coap_malloc_posix_endpoint(); + if (!ep) { + coap_log(LOG_WARNING, "coap_new_endpoint: malloc"); + close(sockfd); + return NULL; + } + + memset(ep, 0, sizeof(struct coap_endpoint_t)); + ep->handle.fd = sockfd; + ep->flags = flags; + memcpy(&ep->addr, addr, sizeof(coap_address_t)); + +#ifndef NDEBUG + if (LOG_DEBUG <= coap_get_log_level()) { +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN 40 +#endif + unsigned char addr_str[INET6_ADDRSTRLEN + 8]; + + if (coap_print_addr(addr, addr_str, INET6_ADDRSTRLEN + 8)) { + debug("created %sendpoint %s\n", + ep->flags & COAP_ENDPOINT_DTLS ? "DTLS " : "", addr_str); + } + } +#endif /* NDEBUG */ + + return (coap_endpoint_t *) ep; +} + +void +coap_free_endpoint(coap_endpoint_t *ep) +{ + if (ep) { + if (ep->handle.fd >= 0) + close(ep->handle.fd); + coap_free_posix_endpoint((struct coap_endpoint_t *) ep); + } +} + +static coap_packet_t * +coap_malloc_packet(void) +{ + coap_packet_t *packet; + const size_t need = sizeof(coap_packet_t) + COAP_MAX_PDU_SIZE; + + packet = (coap_packet_t *) coap_malloc(need); + if (packet) { + memset(packet, 0, need); + } + return packet; +} + +void +coap_free_packet(coap_packet_t *packet) +{ + coap_free(packet); +} + +static inline size_t +coap_get_max_packetlength(const coap_packet_t *packet UNUSED_PARAM) +{ + return COAP_MAX_PDU_SIZE; +} + +void +coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target) +{ + target->handle = packet->interface->handle; + memcpy(&target->addr, &packet->dst, sizeof(target->addr)); + target->ifindex = packet->ifindex; + target->flags = 0; /* FIXME */ +} +void +coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target) +{ + memcpy(target, &packet->src, sizeof(coap_address_t)); +} +void +coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, + size_t *length) +{ + *address = packet->payload; + *length = packet->length; +} + +ssize_t +coap_network_send(struct coap_context_t *context UNUSED_PARAM, + const coap_endpoint_t *local_interface, + const coap_address_t *dst, unsigned char *data, + size_t datalen) +{ + + struct coap_endpoint_t *ep = (struct coap_endpoint_t *) local_interface; + + /* a buffer large enough to hold all protocol address types */ + char buf[CMSG_LEN(sizeof(struct sockaddr_storage))]; + struct msghdr mhdr; + struct iovec iov[1]; + + assert(local_interface); + + iov[0].iov_base = data; + iov[0].iov_len = datalen; + + memset(&mhdr, 0, sizeof(struct msghdr)); + mhdr.msg_name = (void *) &dst->addr; + mhdr.msg_namelen = dst->size; + + mhdr.msg_iov = iov; + mhdr.msg_iovlen = 1; + + switch (dst->addr.sa.sa_family) { + case AF_INET6: { + struct cmsghdr *cmsg; + struct in6_pktinfo *pktinfo; + + mhdr.msg_control = buf; + mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); + + cmsg = CMSG_FIRSTHDR(&mhdr); + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + + pktinfo = (struct in6_pktinfo *) CMSG_DATA(cmsg); + memset(pktinfo, 0, sizeof(struct in6_pktinfo)); + + pktinfo->ipi6_ifindex = ep->ifindex; + memcpy(&pktinfo->ipi6_addr, &local_interface->addr.addr.sin6.sin6_addr, + local_interface->addr.size); + break; + } + case AF_INET: { + struct cmsghdr *cmsg; + struct in_pktinfo *pktinfo; + + mhdr.msg_control = buf; + mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); + + cmsg = CMSG_FIRSTHDR(&mhdr); + cmsg->cmsg_level = SOL_IP; + cmsg->cmsg_type = IP_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); + + pktinfo = (struct in_pktinfo *) CMSG_DATA(cmsg); + memset(pktinfo, 0, sizeof(struct in_pktinfo)); + + pktinfo->ipi_ifindex = ep->ifindex; + memcpy(&pktinfo->ipi_spec_dst, &local_interface->addr.addr.sin.sin_addr, + local_interface->addr.size); + break; + } + default: + /* error */ + coap_log(LOG_WARNING, "protocol not supported\n"); + return -1; + } + + return sendmsg(ep->handle.fd, &mhdr, 0); +} + +/** + * Checks if a message with destination address @p dst matches the + * local interface with address @p local. This function returns @c 1 + * if @p dst is a valid match, and @c 0 otherwise. + */ +static inline int +is_local_if(const coap_address_t *local, const coap_address_t *dst) +{ + return coap_address_isany(local) || coap_address_equals(dst, local); +} + +ssize_t +coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) +{ + ssize_t len = -1; + + char msg_control[CMSG_LEN(sizeof(struct sockaddr_storage))]; + struct msghdr mhdr; + struct iovec iov[1]; + + assert(ep); + assert(packet); + + *packet = coap_malloc_packet(); + + if (!*packet) { + warn("coap_network_read: insufficient memory, drop packet\n"); + return -1; + } + + coap_address_init(&(*packet)->dst); /* the local interface address */ + coap_address_init(&(*packet)->src); /* the remote peer */ + + iov[0].iov_base = (*packet)->payload; + iov[0].iov_len = coap_get_max_packetlength(*packet); + + memset(&mhdr, 0, sizeof(struct msghdr)); + + mhdr.msg_name = &(*packet)->src.addr.st; + mhdr.msg_namelen = sizeof((*packet)->src.addr.st); + + mhdr.msg_iov = iov; + mhdr.msg_iovlen = 1; + + mhdr.msg_control = msg_control; + mhdr.msg_controllen = sizeof(msg_control); + assert(sizeof(msg_control) == CMSG_LEN(sizeof(struct sockaddr_storage))); + + len = recvmsg(ep->handle.fd, &mhdr, 0); + + if (len < 0) { + coap_log(LOG_WARNING, "coap_network_read: %s\n", strerror(errno)); + goto error; + } else { + struct cmsghdr *cmsg; + + coap_log(LOG_DEBUG, "received %d bytes on fd %d\n", (int )len, + ep->handle.fd); + + /* use getsockname() to get the local port */ + (*packet)->dst.size = sizeof((*packet)->dst.addr); + if (getsockname(ep->handle.fd, &(*packet)->dst.addr.sa, + &(*packet)->dst.size) < 0) { + coap_log(LOG_DEBUG, "cannot determine local port\n"); + goto error; + } + + (*packet)->length = len; + + /* Walk through ancillary data records until the local interface + * is found where the data was received. */ + for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) { + + /* get the local interface for IPv6 */ + if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { + union + { + unsigned char *c; + struct in6_pktinfo *p; + } u; + u.c = CMSG_DATA(cmsg); + (*packet)->ifindex = (int) (u.p->ipi6_ifindex); + + memcpy(&(*packet)->dst.addr.sin6.sin6_addr, &u.p->ipi6_addr, + sizeof(struct in6_addr)); + + (*packet)->src.size = mhdr.msg_namelen; + assert((*packet)->src.size == sizeof(struct sockaddr_in6)); + + (*packet)->src.addr.sin6.sin6_family = SIN6(mhdr.msg_name)->sin6_family; + (*packet)->src.addr.sin6.sin6_addr = SIN6(mhdr.msg_name)->sin6_addr; + (*packet)->src.addr.sin6.sin6_port = SIN6(mhdr.msg_name)->sin6_port; + + break; + } + + /* local interface for IPv4 */ + if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) { + union + { + unsigned char *c; + struct in_pktinfo *p; + } u; + + u.c = CMSG_DATA(cmsg); + (*packet)->ifindex = u.p->ipi_ifindex; + + memcpy(&(*packet)->dst.addr.sin.sin_addr, &u.p->ipi_addr, + sizeof(struct in_addr)); + + (*packet)->src.size = mhdr.msg_namelen; + memcpy(&(*packet)->src.addr.st, mhdr.msg_name, (*packet)->src.size); + + break; + } + } + + if (!is_local_if(&ep->addr, &(*packet)->dst)) { + coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n"); + goto error; + } + } + + (*packet)->interface = ep; + + return len; + error: coap_free_packet(*packet); + *packet = NULL; + return -1; +} + +#undef SIN6 diff --git a/platform/coap_posix_io.h b/platform/coap_posix_io.h new file mode 100644 index 0000000000..33029e2c1f --- /dev/null +++ b/platform/coap_posix_io.h @@ -0,0 +1,38 @@ +/* + * coap_posix.io.h + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ + +#ifndef _COAP_POSIX_IO_H_ +#define _COAP_POSIX_IO_H_ + +/** + * Abstraction of virtual endpoint that can be attached to coap_context_t. The + * tuple (handle, addr) must uniquely identify this endpoint. + */ +typedef struct coap_endpoint_t { + union { + int fd; /**< on POSIX systems */ + void *conn; /**< opaque connection (e.g. uip_conn in Contiki) */ + } handle; /**< opaque handle to identify this endpoint */ + coap_address_t addr; /**< local interface address */ + int ifindex; + int flags; +} coap_endpoint_t; + +struct coap_packet_t { + coap_if_handle_t hnd; /**< the interface handle */ + coap_address_t src; /**< the packet's source address */ + coap_address_t dst; /**< the packet's destination address */ + const coap_endpoint_t *interface; + + int ifindex; + void *session; /**< opaque session data */ + + size_t length; /**< length of payload */ + unsigned char payload[]; /**< payload */ +}; + +#endif /* _COAP_POSIX_IO_H_ */ diff --git a/include/coap/lwippools.h b/platform/lwippools.h similarity index 100% rename from include/coap/lwippools.h rename to platform/lwippools.h diff --git a/src/coap_io.c b/src/coap_io.c deleted file mode 100644 index d21dd4914a..0000000000 --- a/src/coap_io.c +++ /dev/null @@ -1,557 +0,0 @@ -/* coap_io.h -- Default network I/O functions for libcoap - * - * Copyright (C) 2012,2014 Olaf Bergmann - * - * This file is part of the CoAP library libcoap. Please see - * README for terms of use. - */ - -#include "coap_config.h" - -#ifdef HAVE_STDIO_H -# include -#endif - -#ifdef HAVE_SYS_SELECT_H -# include -#endif -#ifdef HAVE_SYS_SOCKET_H -# include -#endif -#ifdef HAVE_NETINET_IN_H -# include -#endif -#ifdef HAVE_SYS_UIO_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif -#include - -#ifdef WITH_CONTIKI -# include "uip.h" -#endif - -#include "debug.h" -#include "mem.h" -#include "coap_io.h" - -#ifdef WITH_POSIX -struct coap_packet_t { - coap_if_handle_t hnd; /**< the interface handle */ - coap_address_t src; /**< the packet's source address */ - coap_address_t dst; /**< the packet's destination address */ - const coap_endpoint_t *interface; - - int ifindex; - void *session; /**< opaque session data */ - - size_t length; /**< length of payload */ - unsigned char payload[]; /**< payload */ -}; -#endif - -#ifndef CUSTOM_COAP_NETWORK_ENDPOINT - -#ifdef WITH_CONTIKI -static int ep_initialized = 0; - -static inline struct coap_endpoint_t * -coap_malloc_contiki_endpoint() { - static struct coap_endpoint_t ep; - - if (ep_initialized) { - return NULL; - } else { - ep_initialized = 1; - return &ep; - } -} - -static inline void -coap_free_contiki_endpoint(struct coap_endpoint_t *ep) { - ep_initialized = 0; -} - -coap_endpoint_t * -coap_new_endpoint(const coap_address_t *addr, int flags) { - struct coap_endpoint_t *ep = coap_malloc_contiki_endpoint(); - - if (ep) { - memset(ep, 0, sizeof(struct coap_endpoint_t)); - ep->handle.conn = udp_new(NULL, 0, NULL); - - if (!ep->handle.conn) { - coap_free_endpoint(ep); - return NULL; - } - - coap_address_init(&ep->addr); - uip_ipaddr_copy(&ep->addr.addr, &addr->addr); - ep->addr.port = addr->port; - udp_bind((struct uip_udp_conn *)ep->handle.conn, addr->port); - } - return ep; -} - -void -coap_free_endpoint(coap_endpoint_t *ep) { - if (ep) { - if (ep->handle.conn) { - uip_udp_remove((struct uip_udp_conn *)ep->handle.conn); - } - coap_free_contiki_endpoint(ep); - } -} - -#else /* WITH_CONTIKI */ -static inline struct coap_endpoint_t * -coap_malloc_posix_endpoint(void) { - return (struct coap_endpoint_t *)coap_malloc(sizeof(struct coap_endpoint_t)); -} - -static inline void -coap_free_posix_endpoint(struct coap_endpoint_t *ep) { - coap_free(ep); -} - -coap_endpoint_t * -coap_new_endpoint(const coap_address_t *addr, int flags) { - int sockfd = socket(addr->addr.sa.sa_family, SOCK_DGRAM, 0); - int on = 1; - struct coap_endpoint_t *ep; - - if (sockfd < 0) { - coap_log(LOG_WARNING, "coap_new_endpoint: socket"); - return NULL; - } - - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) - coap_log(LOG_WARNING, "coap_new_endpoint: setsockopt SO_REUSEADDR"); - - on = 1; - switch(addr->addr.sa.sa_family) { - case AF_INET: - if (setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) < 0) - coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IP_PKTINFO\n"); - break; - case AF_INET6: -#ifdef IPV6_RECVPKTINFO - if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) - coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_RECVPKTINFO\n"); -#else /* IPV6_RECVPKTINFO */ - if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) < 0) - coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_PKTINFO\n"); -#endif /* IPV6_RECVPKTINFO */ - break; - default: - coap_log(LOG_ALERT, "coap_new_endpoint: unsupported sa_family\n"); - } - - if (bind(sockfd, &addr->addr.sa, addr->size) < 0) { - coap_log(LOG_WARNING, "coap_new_endpoint: bind"); - close (sockfd); - return NULL; - } - - ep = coap_malloc_posix_endpoint(); - if (!ep) { - coap_log(LOG_WARNING, "coap_new_endpoint: malloc"); - close(sockfd); - return NULL; - } - - memset(ep, 0, sizeof(struct coap_endpoint_t)); - ep->handle.fd = sockfd; - ep->flags = flags; - memcpy(&ep->addr, addr, sizeof(coap_address_t)); - -#ifndef NDEBUG - if (LOG_DEBUG <= coap_get_log_level()) { -#ifndef INET6_ADDRSTRLEN -#define INET6_ADDRSTRLEN 40 -#endif - unsigned char addr_str[INET6_ADDRSTRLEN+8]; - - if (coap_print_addr(addr, addr_str, INET6_ADDRSTRLEN+8)) { - debug("created %sendpoint %s\n", - ep->flags & COAP_ENDPOINT_DTLS ? "DTLS " : "", - addr_str); - } - } -#endif /* NDEBUG */ - - return (coap_endpoint_t *)ep; -} - -void -coap_free_endpoint(coap_endpoint_t *ep) { - if(ep) { - if (ep->handle.fd >= 0) - close(ep->handle.fd); - coap_free_posix_endpoint((struct coap_endpoint_t *)ep); - } -} - -#endif /* WITH_CONTIKI */ -#endif /* CUSTOM_COAP_NETWORK_ENDPOINT */ - -#ifndef CUSTOM_COAP_NETWORK_SEND - -#if defined(WITH_POSIX) != defined(HAVE_NETINET_IN_H) -/* define struct in6_pktinfo and struct in_pktinfo if not available - FIXME: check with configure -*/ -struct in6_pktinfo { - struct in6_addr ipi6_addr; /* src/dst IPv6 address */ - unsigned int ipi6_ifindex; /* send/recv interface index */ -}; - -struct in_pktinfo { - int ipi_ifindex; - struct in_addr ipi_spec_dst; - struct in_addr ipi_addr; -}; -#endif - -#if defined(WITH_POSIX) && !defined(SOL_IP) -/* Solaris expects level IPPROTO_IP for ancillary data. */ -#define SOL_IP IPPROTO_IP -#endif - -#ifdef __GNUC__ -#define UNUSED_PARAM __attribute__ ((unused)) -#else /* not a GCC */ -#define UNUSED_PARAM -#endif /* GCC */ - -ssize_t -coap_network_send(struct coap_context_t *context UNUSED_PARAM, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - unsigned char *data, - size_t datalen) { - - struct coap_endpoint_t *ep = - (struct coap_endpoint_t *)local_interface; - -#ifndef WITH_CONTIKI - /* a buffer large enough to hold all protocol address types */ - char buf[CMSG_LEN(sizeof(struct sockaddr_storage))]; - struct msghdr mhdr; - struct iovec iov[1]; - - assert(local_interface); - - iov[0].iov_base = data; - iov[0].iov_len = datalen; - - memset(&mhdr, 0, sizeof(struct msghdr)); - mhdr.msg_name = (void *)&dst->addr; - mhdr.msg_namelen = dst->size; - - mhdr.msg_iov = iov; - mhdr.msg_iovlen = 1; - - switch (dst->addr.sa.sa_family) { - case AF_INET6: { - struct cmsghdr *cmsg; - struct in6_pktinfo *pktinfo; - - mhdr.msg_control = buf; - mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); - - cmsg = CMSG_FIRSTHDR(&mhdr); - cmsg->cmsg_level = IPPROTO_IPV6; - cmsg->cmsg_type = IPV6_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); - - pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg); - memset(pktinfo, 0, sizeof(struct in6_pktinfo)); - - pktinfo->ipi6_ifindex = ep->ifindex; - memcpy(&pktinfo->ipi6_addr, - &local_interface->addr.addr.sin6.sin6_addr, - local_interface->addr.size); - break; - } - case AF_INET: { - struct cmsghdr *cmsg; - struct in_pktinfo *pktinfo; - - mhdr.msg_control = buf; - mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); - - cmsg = CMSG_FIRSTHDR(&mhdr); - cmsg->cmsg_level = SOL_IP; - cmsg->cmsg_type = IP_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); - - pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); - memset(pktinfo, 0, sizeof(struct in_pktinfo)); - - pktinfo->ipi_ifindex = ep->ifindex; - memcpy(&pktinfo->ipi_spec_dst, - &local_interface->addr.addr.sin.sin_addr, - local_interface->addr.size); - break; - } - default: - /* error */ - coap_log(LOG_WARNING, "protocol not supported\n"); - return -1; - } - - return sendmsg(ep->handle.fd, &mhdr, 0); -#else /* WITH_CONTIKI */ - /* FIXME: untested */ - /* FIXME: is there a way to check if send was successful? */ - uip_udp_packet_sendto((struct uip_udp_conn *)ep->handle.conn, data, datalen, - &dst->addr, dst->port); - return datalen; -#endif /* WITH_CONTIKI */ -} - -#endif /* CUSTOM_COAP_NETWORK_SEND */ - -#ifndef CUSTOM_COAP_NETWORK_READ - -#define SIN6(A) ((struct sockaddr_in6 *)(A)) - -#ifdef WITH_POSIX -static coap_packet_t * -coap_malloc_packet(void) { - coap_packet_t *packet; - const size_t need = sizeof(coap_packet_t) + COAP_MAX_PDU_SIZE; - - packet = (coap_packet_t *)coap_malloc(need); - if (packet) { - memset(packet, 0, need); - } - return packet; -} - -void -coap_free_packet(coap_packet_t *packet) { - coap_free(packet); -} -#endif /* WITH_POSIX */ -#ifdef WITH_CONTIKI -static inline coap_packet_t * -coap_malloc_packet(void) { - return (coap_packet_t *)coap_malloc_type(COAP_PACKET, 0); -} - -void -coap_free_packet(coap_packet_t *packet) { - coap_free_type(COAP_PACKET, packet); -} -#endif /* WITH_CONTIKI */ - -static inline size_t -coap_get_max_packetlength(const coap_packet_t *packet UNUSED_PARAM) { - return COAP_MAX_PDU_SIZE; -} - -void -coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target) -{ - target->handle = packet->interface->handle; - memcpy(&target->addr, &packet->dst, sizeof(target->addr)); - target->ifindex = packet->ifindex; - target->flags = 0; /* FIXME */ -} -void -coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target) -{ - memcpy(target, &packet->src, sizeof(coap_address_t)); -} -void -coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length) -{ - *address = packet->payload; - *length = packet->length; -} - -/** - * Checks if a message with destination address @p dst matches the - * local interface with address @p local. This function returns @c 1 - * if @p dst is a valid match, and @c 0 otherwise. - */ -static inline int -is_local_if(const coap_address_t *local, const coap_address_t *dst) { - return coap_address_isany(local) || coap_address_equals(dst, local); -} - -ssize_t -coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) { - ssize_t len = -1; - -#ifdef WITH_POSIX - char msg_control[CMSG_LEN(sizeof(struct sockaddr_storage))]; - struct msghdr mhdr; - struct iovec iov[1]; -#endif /* WITH_POSIX */ - - assert(ep); - assert(packet); - - *packet = coap_malloc_packet(); - - if (!*packet) { - warn("coap_network_read: insufficient memory, drop packet\n"); - return -1; - } - - coap_address_init(&(*packet)->dst); /* the local interface address */ - coap_address_init(&(*packet)->src); /* the remote peer */ - -#ifdef WITH_POSIX - iov[0].iov_base = (*packet)->payload; - iov[0].iov_len = coap_get_max_packetlength(*packet); - - memset(&mhdr, 0, sizeof(struct msghdr)); - - mhdr.msg_name = &(*packet)->src.addr.st; - mhdr.msg_namelen = sizeof((*packet)->src.addr.st); - - mhdr.msg_iov = iov; - mhdr.msg_iovlen = 1; - - mhdr.msg_control = msg_control; - mhdr.msg_controllen = sizeof(msg_control); - assert(sizeof(msg_control) == CMSG_LEN(sizeof(struct sockaddr_storage))); - - len = recvmsg(ep->handle.fd, &mhdr, 0); - - if (len < 0) { - coap_log(LOG_WARNING, "coap_network_read: %s\n", strerror(errno)); - goto error; - } else { - struct cmsghdr *cmsg; - - coap_log(LOG_DEBUG, "received %d bytes on fd %d\n", (int)len, ep->handle.fd); - - /* use getsockname() to get the local port */ - (*packet)->dst.size = sizeof((*packet)->dst.addr); - if (getsockname(ep->handle.fd, &(*packet)->dst.addr.sa, &(*packet)->dst.size) < 0) { - coap_log(LOG_DEBUG, "cannot determine local port\n"); - goto error; - } - - (*packet)->length = len; - - /* Walk through ancillary data records until the local interface - * is found where the data was received. */ - for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) { - - /* get the local interface for IPv6 */ - if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { - union { - unsigned char *c; - struct in6_pktinfo *p; - } u; - u.c = CMSG_DATA(cmsg); - (*packet)->ifindex = (int)(u.p->ipi6_ifindex); - - memcpy(&(*packet)->dst.addr.sin6.sin6_addr, - &u.p->ipi6_addr, sizeof(struct in6_addr)); - - (*packet)->src.size = mhdr.msg_namelen; - assert((*packet)->src.size == sizeof(struct sockaddr_in6)); - - (*packet)->src.addr.sin6.sin6_family = SIN6(mhdr.msg_name)->sin6_family; - (*packet)->src.addr.sin6.sin6_addr = SIN6(mhdr.msg_name)->sin6_addr; - (*packet)->src.addr.sin6.sin6_port = SIN6(mhdr.msg_name)->sin6_port; - - break; - } - - /* local interface for IPv4 */ - if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) { - union { - unsigned char *c; - struct in_pktinfo *p; - } u; - - u.c = CMSG_DATA(cmsg); - (*packet)->ifindex = u.p->ipi_ifindex; - - memcpy(&(*packet)->dst.addr.sin.sin_addr, - &u.p->ipi_addr, sizeof(struct in_addr)); - - (*packet)->src.size = mhdr.msg_namelen; - memcpy(&(*packet)->src.addr.st, mhdr.msg_name, (*packet)->src.size); - - break; - } - } - - if (!is_local_if(&ep->addr, &(*packet)->dst)) { - coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n"); - goto error; - } - } -#endif /* WITH_POSIX */ -#ifdef WITH_CONTIKI - /* FIXME: untested, make this work */ -#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) -#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN]) - - if(uip_newdata()) { - uip_ipaddr_copy(&(*packet)->src.addr, &UIP_IP_BUF->srcipaddr); - (*packet)->src.port = UIP_UDP_BUF->srcport; - uip_ipaddr_copy(&(*packet)->dst.addr, &UIP_IP_BUF->destipaddr); - (*packet)->dst.port = UIP_UDP_BUF->destport; - - if (!is_local_if(&ep->addr, &(*packet)->dst)) { - coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n"); - goto error; - } - - len = uip_datalen(); - - if (len > coap_get_max_packetlength(*packet)) { - /* FIXME: we might want to send back a response */ - warn("discarded oversized packet\n"); - return -1; - } - - ((char *)uip_appdata)[len] = 0; -#ifndef NDEBUG - if (LOG_DEBUG <= coap_get_log_level()) { -#ifndef INET6_ADDRSTRLEN -#define INET6_ADDRSTRLEN 40 -#endif - unsigned char addr_str[INET6_ADDRSTRLEN+8]; - - if (coap_print_addr(&(*packet)->src, addr_str, INET6_ADDRSTRLEN+8)) { - debug("received %zd bytes from %s\n", len, addr_str); - } - } -#endif /* NDEBUG */ - - (*packet)->length = len; - memcpy(&(*packet)->payload, uip_appdata, len); - } - -#undef UIP_IP_BUF -#undef UIP_UDP_BUF -#endif /* WITH_CONTIKI */ -#ifdef WITH_LWIP -#error "coap_network_read() not implemented on this platform" -#endif - - (*packet)->interface = ep; - - return len; - error: - coap_free_packet(*packet); - *packet = NULL; - return -1; -} - -#undef SIN6 - -#endif /* CUSTOM_COAP_NETWORK_READ */ diff --git a/src/mem.c b/src/mem.c index 95950c92eb..b44aa62fdc 100644 --- a/src/mem.c +++ b/src/mem.c @@ -3,7 +3,7 @@ * Copyright (C) 2014--2015 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ @@ -40,82 +40,4 @@ coap_free_type(coap_memory_tag_t type UNUSED_PARAM, void *p) { free(p); } -#else /* HAVE_MALLOC */ - -#ifdef WITH_CONTIKI - -#define COAP_MAX_STRING_SIZE 12 -#define COAP_MAX_STRINGS 8 - -struct coap_string_t { - char data[COAP_MAX_STRING_SIZE]; -}; - -#include "coap_config.h" -#include "net.h" -#include "pdu.h" -#include "coap_io.h" -#include "resource.h" - -#define COAP_MAX_PACKET_SIZE (sizeof(coap_packet_t) + COAP_MAX_PDU_SIZE) -#define COAP_MAX_PACKETS 2 - -typedef union { - coap_pdu_t packet; /* try to convince the compiler to word-align this structure */ - char buf[COAP_MAX_PACKET_SIZE]; -} coap_packetbuf_t; - -MEMB(string_storage, struct coap_string_t, COAP_MAX_STRINGS); -MEMB(packet_storage, coap_packetbuf_t, COAP_MAX_PACKETS); -MEMB(node_storage, coap_queue_t, COAP_PDU_MAXCNT); -MEMB(pdu_storage, coap_pdu_t, COAP_PDU_MAXCNT); -MEMB(pdu_buf_storage, coap_packetbuf_t, COAP_PDU_MAXCNT); -MEMB(resource_storage, coap_resource_t, COAP_MAX_RESOURCES); -MEMB(attribute_storage, coap_attr_t, COAP_MAX_ATTRIBUTES); - -static struct memb * -get_container(coap_memory_tag_t type) { - switch(type) { - case COAP_PACKET: return &packet_storage; - case COAP_NODE: return &node_storage; - case COAP_PDU: return &pdu_storage; - case COAP_PDU_BUF: return &pdu_buf_storage; - case COAP_RESOURCE: return &resource_storage; - case COAP_RESOURCEATTR: return &attribute_storage; - default: - return &string_storage; - } -} - -void -coap_memory_init(void) { - memb_init(&string_storage); - memb_init(&packet_storage); - memb_init(&node_storage); - memb_init(&pdu_storage); - memb_init(&pdu_buf_storage); - memb_init(&resource_storage); - memb_init(&attribute_storage); -} - -void * -coap_malloc_type(coap_memory_tag_t type, size_t size) { - struct memb *container = get_container(type); - - assert(container); - - if (size > container->size) { - debug("coap_malloc_type: Requested memory exceeds maximum object size\n"); - return NULL; - } - - return memb_alloc(container); -} - -void -coap_free_type(coap_memory_tag_t type, void *object) { - memb_free(get_container(type), object); -} -#endif /* WITH_CONTIKI */ - #endif /* HAVE_MALLOC */ diff --git a/src/net.c b/src/net.c index b5f24dba6b..933e22ea09 100644 --- a/src/net.c +++ b/src/net.c @@ -19,7 +19,9 @@ #elif HAVE_SYS_UNISTD_H #include #endif +#ifdef HAVE_SYS_TYPES_H #include +#endif #ifdef HAVE_SYS_SOCKET_H #include #endif @@ -30,18 +32,6 @@ #include #endif -#ifdef WITH_LWIP -#include -#include -#include -#endif - -#ifdef ST_NODE -#include "net_common.h" -#include "coap_io.h" -struct mbuf *coap_packet_extract_mbuf(coap_packet_t *packet); -#endif - #include "debug.h" #include "mem.h" #include "str.h" @@ -119,81 +109,7 @@ struct mbuf *coap_packet_extract_mbuf(coap_packet_t *packet); /** creates a Qx.FRAC_BITS from COAP_DEFAULT_ACK_TIMEOUT */ #define ACK_TIMEOUT Q(FRAC_BITS, COAP_DEFAULT_ACK_TIMEOUT) -#if defined(WITH_POSIX) - -time_t clock_offset; - -static inline coap_queue_t * -coap_malloc_node(void) { - return (coap_queue_t *)coap_malloc_type(COAP_NODE, sizeof(coap_queue_t)); -} - -static inline void -coap_free_node(coap_queue_t *node) { - coap_free_type(COAP_NODE, node); -} -#endif /* WITH_POSIX */ -#ifdef WITH_LWIP - -#include - -static void coap_retransmittimer_execute(void *arg); -static void coap_retransmittimer_restart(coap_context_t *ctx); - -static inline coap_queue_t * -coap_malloc_node() { - return (coap_queue_t *)memp_malloc(MEMP_COAP_NODE); -} - -static inline void -coap_free_node(coap_queue_t *node) { - memp_free(MEMP_COAP_NODE, node); -} - -#endif /* WITH_LWIP */ -#ifdef ST_NODE -systime_t clock_offset; - -static inline coap_queue_t * -coap_malloc_node(void) { - return (coap_queue_t *)coap_malloc_type(COAP_NODE, sizeof(coap_queue_t)); -} - -static inline void -coap_free_node(coap_queue_t *node) { - coap_free_type(COAP_NODE, node); -} -#endif /* ST_NODE */ -#ifdef WITH_CONTIKI -# ifndef DEBUG -# define DEBUG DEBUG_PRINT -# endif /* DEBUG */ - -#include "mem.h" -#include "net/ip/uip-debug.h" - -clock_time_t clock_offset; - -#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) -#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN]) - -void coap_resources_init(); - -unsigned char initialized = 0; -coap_context_t the_coap_context; - -PROCESS(coap_retransmit_process, "message retransmit process"); - -static inline coap_queue_t * -coap_malloc_node() { - return (coap_queue_t *)coap_malloc_type(COAP_NODE, 0); -} - -static inline void -coap_free_node(coap_queue_t *node) { - coap_free_type(COAP_NODE, node); -} -#endif /* WITH_CONTIKI */ +coap_time_t clock_offset; unsigned int coap_adjust_basetime(coap_context_t *ctx, coap_tick_t now) { @@ -275,7 +191,7 @@ coap_delete_node(coap_queue_t *node) { return 0; coap_delete_pdu(node->pdu); - coap_free_node(node); + coap_free_type(COAP_NODE, node); return 1; } @@ -292,7 +208,7 @@ coap_delete_all(coap_queue_t *queue) { coap_queue_t * coap_new_node(void) { coap_queue_t *node; - node = coap_malloc_node(); + node = (coap_queue_t *)coap_malloc_type(COAP_NODE, sizeof(coap_queue_t)); if ( ! node ) { #ifndef NDEBUG @@ -353,40 +269,17 @@ is_wkc(coap_key_t k) { coap_context_t * coap_new_context(void) { -#ifndef WITH_CONTIKI coap_context_t *c = coap_malloc_type(COAP_CONTEXT, sizeof( coap_context_t ) ); -#endif /* not WITH_CONTIKI */ -#ifdef WITH_CONTIKI - coap_context_t *c; - - if (initialized) - return NULL; -#endif /* WITH_CONTIKI */ coap_clock_init(); -#ifdef WITH_LWIP - prng_init(LWIP_RAND()); -#endif /* WITH_LWIP */ -#if defined(WITH_POSIX) || defined(ST_NODE) + prng_init(clock_offset); -#endif /* WITH_POSIX */ -#ifndef WITH_CONTIKI if (!c) { -#ifndef NDEBUG coap_log(LOG_EMERG, "coap_init: malloc:\n"); -#endif return NULL; } -#endif /* not WITH_CONTIKI */ -#ifdef WITH_CONTIKI - coap_resources_init(); - coap_memory_init(); - c = &the_coap_context; - initialized = 1; -#endif /* WITH_CONTIKI */ - - memset(c, 0, sizeof( coap_context_t ) ); + memset(c, 0, sizeof(coap_context_t)); /* initialize message id */ prng((unsigned char *)&c->message_id, sizeof(unsigned short)); @@ -404,11 +297,6 @@ coap_new_context(void) { coap_register_option(c, COAP_OPTION_BLOCK2); coap_register_option(c, COAP_OPTION_BLOCK1); - //c->endpoint = coap_new_endpoint(listen_addr, COAP_ENDPOINT_NOSEC); -// if (c->endpoint == NULL) { -// goto onerror; -// } - #ifdef WITH_LWIP c->endpoint->context = c; #endif @@ -416,31 +304,13 @@ coap_new_context(void) { c->sockfd = c->endpoint->handle.fd; #endif /* WITH_POSIX */ -#if defined(WITH_POSIX) || defined(WITH_CONTIKI) || defined(ST_NODE) +//#if defined(WITH_POSIX) || defined(WITH_CONTIKI) || defined(ST_NODE) c->network_send = coap_network_send; c->network_read = coap_network_read; c->network_peek = coap_network_peek; -#endif /* WITH_POSIX or WITH_CONTIKI */ - -#ifdef WITH_CONTIKI - process_start(&coap_retransmit_process, (char *)c); - - PROCESS_CONTEXT_BEGIN(&coap_retransmit_process); -#ifndef WITHOUT_OBSERVE - etimer_set(&c->notify_timer, COAP_RESOURCE_CHECK_TIME * COAP_TICKS_PER_SECOND); -#endif /* WITHOUT_OBSERVE */ - /* the retransmit timer must be initialized to some large value */ - etimer_set(&the_coap_context.retransmit_timer, 0xFFFF); - PROCESS_CONTEXT_END(&coap_retransmit_process); -#endif /* WITH_CONTIKI */ +//#endif /* WITH_POSIX or WITH_CONTIKI */ return c; - -// onerror: - if (c) { - coap_free(c); - } - return NULL; } void @@ -459,13 +329,7 @@ coap_free_context(coap_context_t *context) { //coap_delete_all_resources(context); //coap_free_endpoint(context->endpoint); -#ifndef WITH_CONTIKI coap_free_type(COAP_CONTEXT, context); -#endif/* not WITH_CONTIKI */ -#ifdef WITH_CONTIKI - memset(&the_coap_context, 0, sizeof(coap_context_t)); - initialized = 0; -#endif /* WITH_CONTIKI */ } int @@ -585,37 +449,6 @@ coap_send_impl(coap_context_t *context, return id; } #endif /* WITH_POSIX */ -#ifdef WITH_LWIP -coap_tid_t -coap_send_impl(coap_context_t *context, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - coap_pdu_t *pdu) { - coap_tid_t id = COAP_INVALID_TID; - uint8_t err; - char *data_backup; - - if ( !context || !dst || !pdu ) - { - return id; - } - - data_backup = pdu->data; - - /* FIXME: we can't check this here with the existing infrastructure, but we - * should actually check that the pdu is not held by anyone but us. the - * respective pbuf is already exclusively owned by the pdu. */ - - pbuf_realloc(pdu->pbuf, pdu->length); - - coap_transaction_id(dst, pdu, &id); - - udp_sendto(context->endpoint->pcb, pdu->pbuf, - &dst->addr, dst->port); - - return id; -} -#endif /* WITH_LWIP */ coap_tid_t coap_send_impl(coap_context_t *context, const coap_endpoint_t *local_interface, @@ -726,7 +559,7 @@ coap_send_confirmed(coap_context_t *context, node->id = coap_send_impl(context, local_interface, dst, pdu); if (COAP_INVALID_TID == node->id) { debug("coap_send_confirmed: error sending pdu\n"); - coap_free_node(node); + coap_free_type(COAP_NODE, node); return COAP_INVALID_TID; } @@ -839,17 +672,13 @@ coap_read(coap_context_t *ctx, coap_endpoint_t *endpoint) { coap_packet_t *packet; int result = -1; /* the value to be returned */ -#if defined(WITH_POSIX) || defined(WITH_CONTIKI) || defined(ST_NODE) bytes_read = ctx->network_read(endpoint, &packet); -#endif /* WITH_POSIX or WITH_CONTIKI */ if ( bytes_read < 0 ) { //warn("coap_read: recvfrom"); } else { -#if defined(WITH_POSIX) || defined(WITH_CONTIKI) || defined(ST_NODE) result = coap_handle_message(ctx, packet); coap_free_packet(packet); -#endif /* WITH_POSIX or WITH_CONTIKI */ } return result; @@ -1602,132 +1431,3 @@ int coap_can_exit( coap_context_t *context ) { return !context || (context->sendqueue == NULL); } - -#ifdef WITH_CONTIKI - -/*---------------------------------------------------------------------------*/ -/* CoAP message retransmission */ -/*---------------------------------------------------------------------------*/ -PROCESS_THREAD(coap_retransmit_process, ev, data) -{ - coap_tick_t now; - coap_queue_t *nextpdu; - - PROCESS_BEGIN(); - - debug("Started retransmit process\r\n"); - - while(1) { - PROCESS_YIELD(); - if (ev == PROCESS_EVENT_TIMER) { - if (etimer_expired(&the_coap_context.retransmit_timer)) { - - nextpdu = coap_peek_next(&the_coap_context); - - coap_ticks(&now); - while (nextpdu && nextpdu->t <= now) { - coap_retransmit(&the_coap_context, coap_pop_next(&the_coap_context)); - nextpdu = coap_peek_next(&the_coap_context); - } - - /* need to set timer to some value even if no nextpdu is available */ - etimer_set(&the_coap_context.retransmit_timer, - nextpdu ? nextpdu->t - now : 0xFFFF); - } -#ifndef WITHOUT_OBSERVE - if (etimer_expired(&the_coap_context.notify_timer)) { - coap_check_notify(&the_coap_context); - etimer_reset(&the_coap_context.notify_timer); - } -#endif /* WITHOUT_OBSERVE */ - } - } - - PROCESS_END(); -} -/*---------------------------------------------------------------------------*/ - -#endif /* WITH_CONTIKI */ - -#ifdef WITH_LWIP -/* FIXME: retransmits that are not required any more due to incoming packages - * do *not* get cleared at the moment, the wakeup when the transmission is due - * is silently accepted. this is mainly due to the fact that the required - * checks are similar in two places in the code (when receiving ACK and RST) - * and that they cause more than one patch chunk, as it must be first checked - * whether the sendqueue item to be dropped is the next one pending, and later - * the restart function has to be called. nothing insurmountable, but it can - * also be implemented when things have stabilized, and the performance - * penality is minimal - * - * also, this completely ignores COAP_RESOURCE_CHECK_TIME. - * */ - -static void coap_retransmittimer_execute(void *arg) -{ - coap_context_t *ctx = (coap_context_t*)arg; - coap_tick_t now; - coap_tick_t elapsed; - coap_queue_t *nextinqueue; - - ctx->timer_configured = 0; - - coap_ticks(&now); - - elapsed = now - ctx->sendqueue_basetime; /* that's positive for sure, and unless we haven't been called for a complete wrapping cycle, did not wrap */ - - nextinqueue = coap_peek_next(ctx); - while (nextinqueue != NULL) - { - if (nextinqueue->t > elapsed) { - nextinqueue->t -= elapsed; - break; - } else { - elapsed -= nextinqueue->t; - coap_retransmit(ctx, coap_pop_next(ctx)); - nextinqueue = coap_peek_next(ctx); - } - } - - ctx->sendqueue_basetime = now; - - coap_retransmittimer_restart(ctx); -} - -static void coap_retransmittimer_restart(coap_context_t *ctx) -{ - coap_tick_t now, elapsed, delay; - - if (ctx->timer_configured) - { - printf("clearing\n"); - sys_untimeout(coap_retransmittimer_execute, (void*)ctx); - ctx->timer_configured = 0; - } - if (ctx->sendqueue != NULL) - { - coap_ticks(&now); - elapsed = now - ctx->sendqueue_basetime; - if (ctx->sendqueue->t >= elapsed) { - delay = ctx->sendqueue->t - elapsed; - } else { - /* a strange situation, but not completely impossible. - * - * this happens, for example, right after - * coap_retransmittimer_execute, when a retransmission - * was *just not yet* due, and the clock ticked before - * our coap_ticks was called. - * - * not trying to retransmit anything now, as it might - * cause uncontrollable recursion; let's just try again - * with the next main loop run. - * */ - delay = 0; - } - - printf("scheduling for %d ticks\n", delay); - sys_timeout(delay, coap_retransmittimer_execute, (void*)ctx); - ctx->timer_configured = 1; - } -} -#endif diff --git a/src/option.c b/src/option.c index 6cc68dd70b..994b832e5e 100644 --- a/src/option.c +++ b/src/option.c @@ -410,6 +410,7 @@ coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta, return l + length; } +#if defined(ST_NODE) size_t coap_opt_setheader_to_mbuf(coap_pdu_t *pdu, unsigned short type, size_t length) { size_t skip = 0; @@ -466,8 +467,6 @@ coap_opt_setheader_to_mbuf(coap_pdu_t *pdu, unsigned short type, size_t length) return skip + 1; } - - size_t coap_opt_encode_to_mbuf(coap_pdu_t *pdu, unsigned short type, const unsigned char *val, size_t length) { @@ -495,3 +494,5 @@ coap_opt_encode_to_mbuf(coap_pdu_t *pdu, unsigned short type, return l + length; } + +#endif diff --git a/src/pdu.c b/src/pdu.c index fefe030510..8b1b7670eb 100644 --- a/src/pdu.c +++ b/src/pdu.c @@ -30,126 +30,49 @@ #include "mbuf.h" #endif +#ifndef WITH_CUSTOM_PDU_HANDLING + void coap_pdu_clear(coap_pdu_t *pdu, size_t size) { assert(pdu); -#if defined(WITH_LWIP) - /* the pdu itself is not wiped as opposed to the other implementations, - * because we have to rely on the pbuf to be set there. */ - pdu->hdr = pdu->pbuf->payload; -#else pdu->max_delta = 0; + pdu->max_size = size; + pdu->length = sizeof(coap_hdr_t); + /* data is NULL unless explicitly set by coap_add_data() */ pdu->data = NULL; -#endif -#if defined(ST_NODE) - pdu->hdr = pdu->mbuf->payload; -#else + memset(pdu->hdr, 0, size); -#endif - pdu->max_size = size; pdu->hdr->version = COAP_DEFAULT_VERSION; pdu->hdr->token_length = 0; - - /* data is NULL unless explicitly set by coap_add_data() */ - pdu->length = sizeof(coap_hdr_t); -} - -#ifdef WITH_LWIP -coap_pdu_t * -coap_pdu_from_pbuf(struct pbuf *pbuf) -{ - if (pbuf == NULL) return NULL; - - LWIP_ASSERT("Can only deal with contiguous PBUFs", pbuf->tot_len == pbuf->len); - LWIP_ASSERT("coap_read needs to receive an exclusive copy of the incoming pbuf", pbuf->ref == 1); - - coap_pdu_t *result = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t)); - if (!result) { - pbuf_free(pbuf); - return NULL; - } - - memset(result, 0, sizeof(coap_pdu_t)); - - result->max_size = pbuf->tot_len; - result->length = pbuf->tot_len; - result->hdr = pbuf->payload; - result->pbuf = pbuf; - - return result; -} -#endif -#ifdef ST_NODE -coap_pdu_t * -coap_pdu_from_mbuf(struct mbuf *mbuf) -{ - coap_pdu_t *result = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t)); - - memset(result, 0, sizeof(coap_pdu_t)); - - result->max_size = mbuf->tot_len; - result->length = mbuf->tot_len; - result->hdr = (coap_hdr_t *)((unsigned char *)mbuf->payload); - result->mbuf = mbuf; - - return result; } -#endif coap_pdu_t * coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t size) { coap_pdu_t *pdu; -#ifdef WITH_LWIP - struct pbuf *p; -#endif + assert(size <= COAP_MAX_PDU_SIZE); /* Size must be large enough to fit the header. */ if (size < sizeof(coap_hdr_t) || size > COAP_MAX_PDU_SIZE) return NULL; /* size must be large enough for hdr */ -#ifdef WITH_POSIX - pdu = coap_malloc(sizeof(coap_pdu_t) + size); -#endif -#ifdef WITH_CONTIKI - pdu = (coap_pdu_t *)memb_alloc(&pdu_storage); -#endif -#ifdef WITH_LWIP - p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM); - if (p != NULL) { - u8_t header_error = pbuf_header(p, sizeof(coap_pdu_t)); - /* we could catch that case and allocate larger memory in advance, but then - * again, we'd run into greater trouble with incoming packages anyway */ - LWIP_ASSERT("CoAP PDU header does not fit in transport header", header_error == 0); - pdu = p->payload; - } else { - pdu = NULL; - } -#endif -#ifdef ST_NODE pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t)); -#endif - if (pdu) { -#ifdef WITH_LWIP - pdu->pbuf = p; -#endif -#ifdef ST_NODE - memset(pdu, 0, sizeof(coap_pdu_t)); /* MWAS: for st-node payload is in separate memory area */ - pdu->mbuf = mbuf_new(); - if (!pdu->mbuf) { - coap_free(pdu); - return NULL; - } - pdu->mbuf->len = sizeof(coap_hdr_t); - pdu->mbuf->tot_len = sizeof(coap_hdr_t); -#endif - coap_pdu_clear(pdu, size); - pdu->hdr->id = id; - pdu->hdr->type = type; - pdu->hdr->code = code; + if (!pdu) + return NULL; + + pdu->hdr = coap_malloc_type(COAP_PDU_BUF, size); + if (!pdu->hdr) { + coap_free_type(COAP_PDU, pdu); + return NULL; } + + coap_pdu_clear(pdu, size); + pdu->hdr->id = id; + pdu->hdr->type = type; + pdu->hdr->code = code; + return pdu; } @@ -157,11 +80,7 @@ coap_pdu_t * coap_new_pdu(void) { coap_pdu_t *pdu; -#ifndef WITH_CONTIKI pdu = coap_pdu_init(0, 0, ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE); -#else /* WITH_CONTIKI */ - pdu = coap_pdu_init(0, 0, uip_ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE); -#endif /* WITH_CONTIKI */ #ifndef NDEBUG if (!pdu) @@ -172,31 +91,16 @@ coap_new_pdu(void) { void coap_delete_pdu(coap_pdu_t *pdu) { -#if defined(WITH_POSIX) || defined(WITH_CONTIKI) if (pdu != NULL) { if (pdu->hdr != NULL) { coap_free_type(COAP_PDU_BUF, pdu->hdr); } coap_free_type(COAP_PDU, pdu); } -#endif -#ifdef WITH_LWIP - if (pdu != NULL) /* accepting double free as the other implementation accept that too */ - pbuf_free(pdu->pbuf); -#endif -#ifdef WITH_CONTIKI - memb_free(&pdu_storage, pdu); -#endif -#ifdef ST_NODE - if (pdu != NULL) { - if (pdu->mbuf != NULL) { - mbuf_free(pdu->mbuf); - } - coap_free_type(COAP_PDU, pdu); - } -#endif } +#endif /* WITH_CUSTOM_PDU_HANDLING */ + int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data) { const size_t HEADERLENGTH = len + 4; diff --git a/src/resource.c b/src/resource.c index 4ce73a4cd9..333aba1ddc 100644 --- a/src/resource.c +++ b/src/resource.c @@ -14,53 +14,6 @@ #include "resource.h" #include "subscribe.h" -#ifdef WITH_LWIP -/* mem.h is only needed for the string free calls for - * COAP_ATTR_FLAGS_RELEASE_NAME / COAP_ATTR_FLAGS_RELEASE_VALUE / - * COAP_RESOURCE_FLAGS_RELEASE_URI. not sure what those lines should actually - * do on lwip. */ - -#include - -#define COAP_MALLOC_TYPE(Type) \ - ((coap_##Type##_t *)memp_malloc(MEMP_COAP_##Type)) -#define COAP_FREE_TYPE(Type, Object) memp_free(MEMP_COAP_##Type, Object) - -#endif - -#ifdef WITH_POSIX - -#define COAP_MALLOC_TYPE(Type) \ - ((coap_##Type##_t *)coap_malloc(sizeof(coap_##Type##_t))) -#define COAP_FREE_TYPE(Type, Object) coap_free(Object) - -#endif /* WITH_POSIX */ -#ifdef WITH_CONTIKI -#include "memb.h" - -#define COAP_MALLOC_TYPE(Type) \ - ((coap_##Type##_t *)memb_alloc(&(Type##_storage))) -#define COAP_FREE_TYPE(Type, Object) memb_free(&(Type##_storage), (Object)) - -MEMB(subscription_storage, coap_subscription_t, COAP_MAX_SUBSCRIBERS); - -void -coap_resources_init() { - memb_init(&subscription_storage); -} - -static inline coap_subscription_t * -coap_malloc_subscription() { - return memb_alloc(&subscription_storage); -} - -static inline void -coap_free_subscription(coap_subscription_t *subscription) { - memb_free(&subscription_storage, subscription); -} - -#endif /* WITH_CONTIKI */ - #define min(a,b) ((a) < (b) ? (a) : (b)) /* Helper functions for conditional output of character sequences into @@ -287,11 +240,7 @@ coap_resource_t * coap_resource_init(const unsigned char *uri, size_t len, int flags) { coap_resource_t *r; -#ifdef WITH_LWIP - r = (coap_resource_t *)memp_malloc(MEMP_COAP_RESOURCE); -#else r = (coap_resource_t *)coap_malloc_type(COAP_RESOURCE, sizeof(coap_resource_t)); -#endif if (r) { memset(r, 0, sizeof(coap_resource_t)); @@ -321,13 +270,7 @@ coap_add_attr(coap_resource_t *resource, if (!resource || !name) return NULL; -#ifdef WITH_LWIP - attr = (coap_attr_t *)memp_malloc(MEMP_COAP_RESOURCEATTR); -#endif -#ifndef WITH_LWIP attr = (coap_attr_t *)coap_malloc_type(COAP_RESOURCEATTR, sizeof(coap_attr_t)); -#endif - if (attr) { attr->name.length = nlen; attr->value.length = val ? vlen : 0; @@ -372,12 +315,7 @@ coap_delete_attr(coap_attr_t *attr) { if (attr->flags & COAP_ATTR_FLAGS_RELEASE_VALUE) coap_free(attr->value.s); -#ifdef WITH_LWIP - memp_free(MEMP_COAP_RESOURCEATTR, attr); -#endif -#ifndef WITH_LWIP coap_free_type(COAP_RESOURCEATTR, attr); -#endif } void @@ -410,8 +348,10 @@ void coap_add_resource(coap_context_t *context, coap_resource_t *resource) { RESOURCES_ADD(context->resources, resource); if (!resource->dynamic) { - coap_hash_path(resource->uri.s, resource->uri.length, resource->key); + resource->uri.length = strlen(resource->uri.s); + coap_hash_path(resource->uri.s, resource->uri.length, resource->key); } + debug("Added resource 0x%02x%02x%02x%02x", resource->key[0], resource->key[1], resource->key[2], resource->key[3]); } static void @@ -434,14 +374,9 @@ coap_free_resource(coap_resource_t *resource) { coap_free_type(COAP_SUBSCRIPTION, obs); } -#ifdef WITH_LWIP - memp_free(MEMP_COAP_RESOURCE, resource); -#endif -#ifndef WITH_LWIP if (resource->dynamic) { coap_free_type(COAP_RESOURCE, resource); } -#endif /* WITH_CONTIKI */ } int @@ -506,9 +441,7 @@ coap_delete_resource_by_pattern(coap_context_t *context, const char *pattern) { coap_resource_t * coap_get_resource_from_key(coap_context_t *context, coap_key_t key) { coap_resource_t *result; - RESOURCES_FIND(context->resources, key, result); - return result; } From 53a5004b29fdc746ca908ba08174145528a2674c Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Wed, 8 Jul 2015 18:04:26 +0200 Subject: [PATCH 62/69] Platforms refactoring --- include/coap/address.h | 119 ------------------------------------- include/coap/pdu.h | 2 +- platform/coap_contiki_io.h | 44 +++++++++----- platform/coap_lwip_io.h | 47 +++++++++++---- platform/coap_posix_io.h | 59 ++++++++++++++++++ src/debug.c | 27 +++++---- src/pdu.c | 2 +- 7 files changed, 139 insertions(+), 161 deletions(-) diff --git a/include/coap/address.h b/include/coap/address.h index d692fb3f26..b0c8df1741 100644 --- a/include/coap/address.h +++ b/include/coap/address.h @@ -28,123 +28,6 @@ #include #include -#ifdef HAVE_NETINET_IN_H -#include -#endif - -#ifdef HAVE_NETINET_IN_H -#include -#endif - -#ifdef WITH_LWIP -#include - -typedef struct coap_address_t { - uint16_t port; - ip_addr_t addr; -} coap_address_t; - -/* FIXME oversimplification: just assuming it's an ipv4 address instead of - * looking up the appropraite lwip function */ - -#define _coap_address_equals_impl(A, B) \ - ((A)->addr.addr == (B)->addr.addr \ - && A->port == B->port) - -/** @todo implementation of _coap_address_isany_impl() for Contiki */ -#define _coap_address_isany_impl(A) 0 - -/* FIXME sure there is something in lwip */ -#define _coap_is_mcast_impl(Address) 0 -#endif /* WITH_LWIP */ - -#ifdef ST_NODE -#include "net_common.h" - -typedef struct coap_address_t { - uint16_t port; - ipaddr_t addr; -} coap_address_t; - -#define _coap_address_equals_impl(A, B) ((memcmp(&(A)->addr, &(B)->addr, sizeof(ipaddr_t)) == 0) && A->port == B->port) - -/* Multicast IPv4 addresses start with 0b1110 */ -#define _coap_is_mcast_impl(Address) ((Address)->addr.u8[0] && 0xF0 == 0xE0) - -#define _coap_address_isany_impl(A) 0 - -#endif /* ST_NODE */ -#ifdef WITH_CONTIKI -#include "uip.h" - -typedef struct coap_address_t { - uip_ipaddr_t addr; - unsigned short port; -} coap_address_t; - -#define _coap_address_equals_impl(A,B) \ - ((A)->port == (B)->port \ - && uip_ipaddr_cmp(&((A)->addr),&((B)->addr))) - -/** @todo implementation of _coap_address_isany_impl() for Contiki */ -#define _coap_address_isany_impl(A) 0 - -#define _coap_is_mcast_impl(Address) uip_is_addr_mcast(&((Address)->addr)) -#endif /* WITH_CONTIKI */ - -#ifdef WITH_POSIX -/** multi-purpose address abstraction */ -typedef struct coap_address_t { - socklen_t size; /**< size of addr */ - union { - struct sockaddr sa; - struct sockaddr_storage st; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - } addr; -} coap_address_t; - -/** - * Compares given address objects @p a and @p b. This function returns @c 1 if - * addresses are equal, @c 0 otherwise. The parameters @p a and @p b must not be - * @c NULL; - */ -int coap_address_equals(const coap_address_t *a, const coap_address_t *b); - -static inline int -_coap_address_isany_impl(const coap_address_t *a) { - /* need to compare only relevant parts of sockaddr_in6 */ - switch (a->addr.sa.sa_family) { - case AF_INET: - return a->addr.sin.sin_addr.s_addr == INADDR_ANY; - case AF_INET6: - return memcmp(&in6addr_any, - &a->addr.sin6.sin6_addr, - sizeof(in6addr_any)) == 0; - default: - ; - } - - return 0; -} - -static inline int -_coap_is_mcast_impl(const coap_address_t *a) { - if (!a) - return 0; - - switch (a->addr.sa.sa_family) { - case AF_INET: - return IN_MULTICAST(a->addr.sin.sin_addr.s_addr); - case AF_INET6: - return IN6_IS_ADDR_MULTICAST(&a->addr.sin6.sin6_addr); - default: /* fall through and signal error */ - ; - } - return 0; -} -#endif /* WITH_POSIX */ - /** * Resets the given coap_address_t object @p addr to its default values. In * particular, the member size must be initialized to the available size for @@ -162,7 +45,6 @@ coap_address_init(coap_address_t *addr) { #endif } -#ifndef WITH_POSIX /** * Compares given address objects @p a and @p b. This function returns @c 1 if * addresses are equal, @c 0 otherwise. The parameters @p a and @p b must not be @@ -173,7 +55,6 @@ coap_address_equals(const coap_address_t *a, const coap_address_t *b) { assert(a); assert(b); return _coap_address_equals_impl(a, b); } -#endif /** * Copy given address from @p src to @p dest. diff --git a/include/coap/pdu.h b/include/coap/pdu.h index d9e1d8d1ba..b9daf7505d 100644 --- a/include/coap/pdu.h +++ b/include/coap/pdu.h @@ -255,7 +255,7 @@ typedef struct { * Header structure for CoAP PDUs */ -typedef struct { +typedef struct coap_pdu_t { size_t max_size; /**< allocated storage for options and data */ coap_hdr_t *hdr; /**< Address of the first byte of the CoAP message. * This may or may not equal (coap_hdr_t*)(pdu+1) diff --git a/platform/coap_contiki_io.h b/platform/coap_contiki_io.h index 8aaf121db5..333021aceb 100644 --- a/platform/coap_contiki_io.h +++ b/platform/coap_contiki_io.h @@ -8,20 +8,21 @@ #ifndef _COAP_CONTIKI_IO_H_ #define _COAP_CONTIKI_IO_H_ -/* - * This is only included in coap_io.h instead of .c in order to be available for - * sizeof in mem.c. - */ -struct coap_packet_t { - coap_if_handle_t hnd; /**< the interface handle */ - coap_address_t src; /**< the packet's source address */ - coap_address_t dst; /**< the packet's destination address */ - const coap_endpoint_t *interface; - int ifindex; - void *session; /**< opaque session data */ - size_t length; /**< length of payload */ - unsigned char payload[]; /**< payload */ -}; +#include "uip.h" + +typedef struct coap_address_t { + uip_ipaddr_t addr; + unsigned short port; +} coap_address_t; + +#define _coap_address_equals_impl(A,B) \ + ((A)->port == (B)->port \ + && uip_ipaddr_cmp(&((A)->addr),&((B)->addr))) + +/** @todo implementation of _coap_address_isany_impl() for Contiki */ +#define _coap_address_isany_impl(A) 0 + +#define _coap_is_mcast_impl(Address) uip_is_addr_mcast(&((Address)->addr)) /** * Abstraction of virtual endpoint that can be attached to coap_context_t. The @@ -37,4 +38,19 @@ typedef struct coap_endpoint_t { int flags; } coap_endpoint_t; +/* + * This is only included in coap_io.h instead of .c in order to be available for + * sizeof in mem.c. + */ +struct coap_packet_t { + coap_if_handle_t hnd; /**< the interface handle */ + coap_address_t src; /**< the packet's source address */ + coap_address_t dst; /**< the packet's destination address */ + const coap_endpoint_t *interface; + int ifindex; + void *session; /**< opaque session data */ + size_t length; /**< length of payload */ + unsigned char payload[]; /**< payload */ +}; + #endif /* _COAP_CONTIKI_IO_H_ */ diff --git a/platform/coap_lwip_io.h b/platform/coap_lwip_io.h index 430ba5341a..16169f15e5 100644 --- a/platform/coap_lwip_io.h +++ b/platform/coap_lwip_io.h @@ -10,6 +10,26 @@ #include #include +#include + +typedef struct coap_address_t { + uint16_t port; + ip_addr_t addr; +} coap_address_t; + +/* FIXME oversimplification: just assuming it's an ipv4 address instead of + * looking up the appropraite lwip function */ + +#define _coap_address_equals_impl(A, B) \ + ((A)->addr.addr == (B)->addr.addr \ + && A->port == B->port) + +/** @todo implementation of _coap_address_isany_impl() for Contiki */ +#define _coap_address_isany_impl(A) 0 + +/* FIXME sure there is something in lwip */ +#define _coap_is_mcast_impl(Address) 0 + #define CUSTOM_PDU_FIELDS struct pbuf *pbuf; /**< lwIP PBUF. The package data will always reside * inside the pbuf's payload, but this pointer @@ -20,6 +40,20 @@ * to the pdu, and the pbuf stays exclusive to * this pdu. */ +/** + * Abstraction of virtual endpoint that can be attached to coap_context_t. The + * tuple (handle, addr) must uniquely identify this endpoint. + */ +typedef struct coap_endpoint_t { + struct udp_pcb *pcb; + /**< @FIXME this was added in a hurry, not sure it confirms to the overall model --chrysn */ + struct coap_context_t *context; + coap_address_t addr; /**< local interface address */ + int ifindex; + int flags; +} coap_endpoint_t; + + /* * This is only included in coap_io.h instead of .c in order to be available for * sizeof in lwippools.h. @@ -34,19 +68,6 @@ struct coap_packet_t { uint16_t srcport; }; -/** - * Abstraction of virtual endpoint that can be attached to coap_context_t. The - * tuple (handle, addr) must uniquely identify this endpoint. - */ -typedef struct coap_endpoint_t { - struct udp_pcb *pcb; - /**< @FIXME this was added in a hurry, not sure it confirms to the overall model --chrysn */ - struct coap_context_t *context; - coap_address_t addr; /**< local interface address */ - int ifindex; - int flags; -} coap_endpoint_t; - /** * Get the pbuf of a packet. The caller takes over responsibility for freeing * the pbuf. diff --git a/platform/coap_posix_io.h b/platform/coap_posix_io.h index 33029e2c1f..5e3f4a01b2 100644 --- a/platform/coap_posix_io.h +++ b/platform/coap_posix_io.h @@ -8,6 +8,65 @@ #ifndef _COAP_POSIX_IO_H_ #define _COAP_POSIX_IO_H_ +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +/** multi-purpose address abstraction */ +typedef struct coap_address_t { + socklen_t size; /**< size of addr */ + union { + struct sockaddr sa; + struct sockaddr_storage st; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } addr; +} coap_address_t; + +/** + * Compares given address objects @p a and @p b. This function returns @c 1 if + * addresses are equal, @c 0 otherwise. The parameters @p a and @p b must not be + * @c NULL; + */ +int coap_address_equals(const coap_address_t *a, const coap_address_t *b); + +static inline int +_coap_address_isany_impl(const coap_address_t *a) { + /* need to compare only relevant parts of sockaddr_in6 */ + switch (a->addr.sa.sa_family) { + case AF_INET: + return a->addr.sin.sin_addr.s_addr == INADDR_ANY; + case AF_INET6: + return memcmp(&in6addr_any, + &a->addr.sin6.sin6_addr, + sizeof(in6addr_any)) == 0; + default: + ; + } + + return 0; +} + +static inline int +_coap_is_mcast_impl(const coap_address_t *a) { + if (!a) + return 0; + + switch (a->addr.sa.sa_family) { + case AF_INET: + return IN_MULTICAST(a->addr.sin.sin_addr.s_addr); + case AF_INET6: + return IN6_IS_ADDR_MULTICAST(&a->addr.sin6.sin6_addr); + default: /* fall through and signal error */ + ; + } + return 0; +} + /** * Abstraction of virtual endpoint that can be attached to coap_context_t. The * tuple (handle, addr) must uniquely identify this endpoint. diff --git a/src/debug.c b/src/debug.c index 5e1570e2a2..4539af5d62 100644 --- a/src/debug.c +++ b/src/debug.c @@ -3,7 +3,7 @@ * Copyright (C) 2010--2012,2014--2015 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" @@ -29,6 +29,7 @@ #include #endif +#include "coap_time.h" #include "block.h" #include "debug.h" #include "encode.h" @@ -51,7 +52,7 @@ const char *coap_package_version(void) { return PACKAGE_STRING; } -coap_log_t +coap_log_t coap_get_log_level(void) { return maxlog; } @@ -63,7 +64,7 @@ coap_set_log_level(coap_log_t level) { /* this array has the same order as the type log_t */ static char *loglevels[] = { - "EMRG", "ALRT", "CRIT", "ERR", "WARN", "NOTE", "INFO", "DEBG" + "EMRG", "ALRT", "CRIT", "ERR", "WARN", "NOTE", "INFO", "DEBG" }; #ifdef HAVE_TIME_H @@ -81,7 +82,7 @@ print_timestamp(char *s, size_t len, coap_tick_t t) { static inline size_t print_timestamp(char *s, size_t len, coap_tick_t t) { #ifdef HAVE_SNPRINTF - return snprintf(s, len, "%u.%03u", + return snprintf(s, len, "%u.%03u", (unsigned int)coap_ticks_to_rt(t), (unsigned int)(t % COAP_TICKS_PER_SECOND)); #else /* HAVE_SNPRINTF */ @@ -95,12 +96,12 @@ print_timestamp(char *s, size_t len, coap_tick_t t) { #ifndef NDEBUG #ifndef HAVE_STRNLEN -/** - * A length-safe strlen() fake. - * +/** + * A length-safe strlen() fake. + * * @param s The string to count characters != 0. * @param maxlen The maximum length of @p s. - * + * * @return The length of @p s. */ static inline size_t @@ -161,7 +162,7 @@ coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t le unsigned char *p = buf; switch (addr->addr.sa.sa_family) { - case AF_INET: + case AF_INET: addrptr = &addr->addr.sin.sin_addr; port = ntohs(addr->addr.sin.sin_port); break; @@ -190,7 +191,7 @@ coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t le if (addr->addr.sa.sa_family == AF_INET6) { if (p < buf + len) { *p++ = ']'; - } else + } else return 0; } @@ -449,7 +450,7 @@ coap_show_pdu(const coap_pdu_t *pdu) { } fprintf(COAP_DEBUG_FD, " ]"); - + if (coap_get_data((coap_pdu_t *)pdu, &data_len, &data)) { fprintf(COAP_DEBUG_FD, " :: "); @@ -474,7 +475,7 @@ coap_show_pdu(const coap_pdu_t *pdu) { #endif /* NDEBUG */ -void +void coap_log_impl(coap_log_t level, const char *format, ...) { char timebuf[32]; coap_tick_t now; @@ -483,7 +484,7 @@ coap_log_impl(coap_log_t level, const char *format, ...) { if (maxlog < level) return; - + log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD; coap_ticks(&now); diff --git a/src/pdu.c b/src/pdu.c index 8b1b7670eb..6015f21117 100644 --- a/src/pdu.c +++ b/src/pdu.c @@ -30,7 +30,7 @@ #include "mbuf.h" #endif -#ifndef WITH_CUSTOM_PDU_HANDLING +#ifndef CUSTOM_COAP_PDU_HANDLING void coap_pdu_clear(coap_pdu_t *pdu, size_t size) { From f2fdcf6c17fd3c6cd970bd3b918a4bd5edd9b364 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Wed, 8 Jul 2015 18:04:35 +0200 Subject: [PATCH 63/69] New client --- client/client.c | 600 ++++++++++++++++++++++++++++++++++++++++++++++++ client/client.h | 104 +++++++++ 2 files changed, 704 insertions(+) create mode 100644 client/client.c create mode 100644 client/client.h diff --git a/client/client.c b/client/client.c new file mode 100644 index 0000000000..16e659a8f9 --- /dev/null +++ b/client/client.c @@ -0,0 +1,600 @@ +#include +#include +#include +#include + +#include "utils.h" +#include "clock.h" +//#include "mbuf.h" + +#include "coap/debug.h" +#include "coap/coap_list.h" +#include "coap/net.h" +#include "coap/address.h" +#include "coap/resource.h" +#include "coap/block.h" +#include "coap/pdu.h" +#include "coap/mem.h" +//#include "coap_utils.h" + +#include "client.h" + +extern int resolve_address(const str *addr, coap_address_t *dst); + +static int check_token(coap_request_t *request, coap_pdu_t *received) +{ + return received->hdr->token_length == request->token_length && + memcmp(received->hdr->token, request->token, request->token_length) == 0; +} + +static int order_opts(void *a, void *b) +{ + if (!a || !b) + return a < b ? -1 : 1; + + if (COAP_OPTION_KEY(*(coap_option *)a) < COAP_OPTION_KEY(*(coap_option * )b)) + return -1; + + return COAP_OPTION_KEY(*(coap_option *)a) == COAP_OPTION_KEY(*(coap_option * )b); +} + +coap_list_t * +new_option_node(unsigned short key, unsigned int length, unsigned char *data) +{ + coap_list_t *node; + + node = coap_malloc(sizeof(coap_list_t) + sizeof(coap_option) + length); + + if (node) { + coap_option *option = (coap_option *) (node->data); + COAP_OPTION_KEY(*option) = key; + COAP_OPTION_LENGTH(*option) = length; + memcpy(COAP_OPTION_DATA(*option), data, length); + } else { + critical("new_option_node: malloc\n"); + } + + return node; +} + +static void set_blocksize(coap_request_t *request) +{ + unsigned char buf[4]; /* hack: temporarily take encoded bytes */ + unsigned short opt; + + if (request->method != COAP_REQUEST_DELETE) { + opt = (request->method == COAP_REQUEST_GET ? COAP_OPTION_BLOCK2 : COAP_OPTION_BLOCK1); + coap_insert(&request->optlist, new_option_node(opt, coap_encode_var_bytes(buf, (request->block.num << 4 | request->block.szx)), buf)); + } +} + +int coap_request_set_uri(coap_request_t *request, const char *arg, int is_proxy_uri) +{ + unsigned char portbuf[2]; + unsigned char _buf[128]; + unsigned char *buf = _buf; + size_t buflen; + int res; + + if (is_proxy_uri) { /* create Proxy-Uri from argument */ + size_t len = strlen(arg); + while (len > 270) { + coap_insert(&request->optlist, new_option_node(COAP_OPTION_PROXY_URI, 270, (unsigned char *) arg)); + len -= 270; + arg += 270; + } + coap_insert(&request->optlist, new_option_node(COAP_OPTION_PROXY_URI, len, (unsigned char *) arg)); + + } else { /* split arg into Uri-* options */ + if (coap_split_uri(arg, strlen(arg), &request->uri) < 0) { + return 0; + } + + if (request->uri.port != COAP_DEFAULT_PORT) { + coap_insert(&request->optlist, new_option_node(COAP_OPTION_URI_PORT, coap_encode_var_bytes(portbuf, request->uri.port), portbuf)); + } + + if (request->uri.path.length) { + buflen = sizeof(_buf); + res = coap_split_path(request->uri.path.s, request->uri.path.length, buf, &buflen); + while (res--) { + coap_insert(&request->optlist, new_option_node(COAP_OPTION_URI_PATH, COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf))); + buf += COAP_OPT_SIZE(buf); + } + } + + if (request->uri.query.length) { + buflen = sizeof(_buf); + buf = _buf; + res = coap_split_query(request->uri.query.s, request->uri.query.length, buf, &buflen); + while (res--) { + coap_insert(&request->optlist, new_option_node(COAP_OPTION_URI_QUERY, COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf))); + buf += COAP_OPT_SIZE(buf); + } + } + } + return 1; +} + +//coap_tid_t clear_obs(coap_client_t *client, const coap_address_t *remote) +//{ +// coap_pdu_t *pdu; +// coap_list_t *option; +// coap_tid_t tid = COAP_INVALID_TID; +// unsigned char buf[2]; +// +// /* create bare PDU w/o any option */ +// pdu = coap_pdu_init(COAP_MESSAGE_CON, COAP_REQUEST_GET, coap_new_message_id(client->coap), COAP_MAX_PDU_SIZE); +// +// if (!pdu) { +// return tid; +// } +// +// if (!coap_add_token(pdu, the_token.length, the_token.s)) { +// error("cannot add token"); +// goto error; +// } +// +// for (option = optlist; option; option = option->next) { +// if (COAP_OPTION_KEY(*(coap_option *)option->data) == COAP_OPTION_URI_HOST) { +// if (!coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option * )option->data), COAP_OPTION_LENGTH(*(coap_option * )option->data), +// COAP_OPTION_DATA(*(coap_option * )option->data))) { +// goto error; +// } +// break; +// } +// } +// +// if (!coap_add_option(pdu, COAP_OPTION_OBSERVE, coap_encode_var_bytes(buf, COAP_OBSERVE_CANCEL), buf)) { +// error("cannot add option Observe: %u", COAP_OBSERVE_CANCEL); +// goto error; +// } +// +// for (option = optlist; option; option = option->next) { +// switch (COAP_OPTION_KEY(*(coap_option * )option->data)) { +// case COAP_OPTION_URI_PORT: +// case COAP_OPTION_URI_PATH: +// case COAP_OPTION_URI_QUERY: +// if (!coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option * )option->data), COAP_OPTION_LENGTH(*(coap_option * )option->data), +// COAP_OPTION_DATA(*(coap_option * )option->data))) { +// goto error; +// } +// break; +// default: +// ; +// } +// } +// +// coap_show_pdu(pdu); +// +// if (pdu->hdr->type == COAP_MESSAGE_CON) +// tid = coap_send_confirmed(client->coap, client->ep, remote, pdu); +// else +// tid = coap_send(client->coap, client->ep, remote, pdu); +// +// if (tid == COAP_INVALID_TID) { +// debug("clear_obs: error sending new request"); +// coap_delete_pdu(pdu); +// } else if (pdu->hdr->type != COAP_MESSAGE_CON) +// coap_delete_pdu(pdu); +// +// return tid; +// error: +// +// coap_delete_pdu(pdu); +// return tid; +//} + +/** + * Create PDU from request. + */ +static coap_pdu_t *create_pdu(coap_request_t *request) +{ + coap_pdu_t *pdu; + + pdu = coap_new_pdu(); + if (!pdu) { + critical("Failed to create request"); + return NULL; + } + + pdu->hdr->type = request->type; + pdu->hdr->id = coap_new_message_id(request->client->coap); + pdu->hdr->code = request->method; + pdu->hdr->token_length = request->token_length; + coap_add_token(pdu, pdu->hdr->token_length, request->token); + + return pdu; +} + +static int send_request(coap_client_t *client, coap_request_t *request, coap_response_t *response, coap_address_t *dst, coap_pdu_t *pdu) +{ + coap_tid_t tid; + + // We add request to the hash map before sending it. This is because it may + // happen that the current thread will be preempted by network thread when an + // acknowledgment is received. Since the response handler lookups the request this + // could lead to bad things. + + coap_request_t *found = NULL; + HASH_FIND(hh, client->requests, request->token, request->token_length, found); + + if (!found) { + HASH_ADD_KEYPTR(hh, client->requests, request->token, request->token_length, request); + request->client = client; + request->response = response; + response->code = 0; + } + + // Send request + if (pdu->hdr->type == COAP_MESSAGE_CON) { + tid = coap_send_confirmed(client->coap, client->ep, dst, pdu); + } else { + tid = coap_send(client->coap, client->ep, dst, pdu); + } + + if (tid == COAP_INVALID_TID) { + coap_delete_pdu(pdu); + HASH_DEL(client->requests, request); + return 0; + } + + if (pdu->hdr->type != COAP_MESSAGE_CON) { + coap_delete_pdu(pdu); + return 0; + } + +#ifndef NDEBUG + char toks[request->token_length*2 + 1]; + memset(toks, 0, sizeof(toks)); + htos(request->token, request->token_length, toks, sizeof(toks)); + info("Request sent (id:%d tk:%s)", tid, toks); +#endif + + return 1; +} + +static int +request_block(coap_request_t *request) +{ + unsigned char buf[4]; + coap_list_t *option; + + coap_pdu_t *pdu = create_pdu(request); + if (!pdu) { + return 0; + } + + //debug("found the M bit, block size is %u, block nr. %u\n", COAP_OPT_BLOCK_SZX(block_opt), coap_opt_block_num(block_opt)); + + /* add URI components from optlist */ + for (option = request->optlist; option; option = option->next) { + switch (COAP_OPTION_KEY(*(coap_option * )option->data)) { + case COAP_OPTION_URI_HOST: + case COAP_OPTION_URI_PORT: + case COAP_OPTION_URI_PATH: + case COAP_OPTION_URI_QUERY: + coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option * )option->data), COAP_OPTION_LENGTH(*(coap_option * )option->data), + COAP_OPTION_DATA(*(coap_option * )option->data)); + break; + default: + break; /* skip other options */ + } + } + + /* finally add updated block option from response, clear M bit */ + /* blocknr = (blocknr & 0xfffffff7) + 0x10; */ + debug("query block %d\n", request->block.num); + coap_add_option(pdu, request->block_type, coap_encode_var_bytes(buf, (request->block.num << 4) | request->block.szx), buf); + + return send_request(request->client, request, request->response, &request->dst, pdu); +} + +static void handle_205(coap_client_t *client, coap_request_t *request, coap_pdu_t *received) +{ + coap_opt_t *opt; + coap_opt_iterator_t oi; + + coap_option_iterator_init(received, &oi, COAP_OPT_ALL); + + while ((opt = coap_option_next(&oi))) { + switch (oi.type) { + case COAP_OPTION_CONTENT_FORMAT: + request->response->content_type = *(uint8_t *)coap_opt_value(opt); + break; + case COAP_OPTION_OBSERVE: + break; + case COAP_OPTION_BLOCK2: { + request->block.szx = COAP_OPT_BLOCK_SZX(opt); + if (COAP_OPT_BLOCK_MORE(opt)) { + request->block.m = 1; + } + request->block.num = coap_opt_block_num(opt); + + info("Received block (NUM:%d, M:%d)\n", request->block.num, request->block.m); + /* TODO: check if we are looking at the correct block number */ + if (coap_has_data(received) && client->block_write) { + client->block_write(request->response, received, &request->block); + } + break; + } + default: + break; + } + } + + if (request->block.m) { + request->block_type = COAP_OPTION_BLOCK2; + request->block.num += 1; + request_block(request); + } else { + //request->response->data = coap_get_mbuf(received); + request->response->code = received->hdr->code; + // copy received data + if (coap_has_data(received)) { + size_t len; + unsigned char *data; + coap_get_data(received, &len, &data); + request->response->data = coap_malloc(len); + if (request->response->data) { + memcpy(request->response->data, data, len); + request->response->length = len; + } + } + if (request->cb) { + request->cb(request, request->response); + coap_client_delete_request(request); + } + } +} + +static void response_handler( + struct coap_context_t *ctx, + const coap_endpoint_t *ep, + const coap_address_t *remote, + coap_pdu_t *sent, + coap_pdu_t *received, + const coap_tid_t id) +{ + coap_client_t *client = (coap_client_t *)ctx->pdata; + + assert(client); + + char toks[received->hdr->token_length*2 + 1]; + memset(toks, 0, sizeof(toks)); + htos(received->hdr->token, received->hdr->token_length, toks, sizeof(toks)); + + coap_request_t *request = NULL; + HASH_FIND(hh, client->requests, received->hdr->token, received->hdr->token_length, request); + if (!request) { + warn("Request not found (tk:%s)", toks); + return; + } + + debug("Received response (id:%d, tk:%s code:%d)\n", id, toks, received->hdr->code); + + /* check if this is a response to our original request */ + if (!check_token(request, received)) { + /* drop if this was just some message, or send RST in case of notification */ + if (!sent && (received->hdr->type == COAP_MESSAGE_CON || received->hdr->type == COAP_MESSAGE_NON)) { + coap_send_rst(ctx, ep, remote, received); + } + warn("Token mismatch"); + return; + } + + if (received->hdr->type == COAP_MESSAGE_RST) { + warn("Received RST\n"); + return; + } + + switch (received->hdr->code) { + /* 2.05 Content - send in response to GET request */ + case COAP_RESPONSE_CODE(205): + handle_205(client, request, received); + break; + default: + request->response->code = received->hdr->code; + if (request->cb) { + request->cb(request, request->response); + coap_client_delete_request(request); + } + break; + } +} + +void coap_client_init(coap_client_t *client, coap_context_t *ctx, coap_endpoint_t *ep) +{ + client->coap = ctx; + client->ep = ep; + client->requests = NULL; + + ctx->pdata = client; + + coap_register_option(client->coap, COAP_OPTION_BLOCK2); + coap_register_response_handler(client->coap, response_handler); +} + +void coap_client_deinit(coap_client_t *client) +{ + UNUSED(client); + //TODO: cancel subscriptions +} + +void coap_client_delete_request(coap_request_t *r) +{ + debug("Deleting request [%p]", r); + + if (r->client) { + HASH_DEL(r->client->requests, r); + } + + if (r->optlist != NULL) { + coap_delete_list(r->optlist); + r->optlist = NULL; + } + + if (r->data) { + //mbuf_free((mbuf_t *)r->data); + coap_free(r->data); + r->data = NULL; + } + + if (r->response) { + if (r->response->data) { + coap_free(r->response->data); + //mbuf_free((mbuf_t *)r->response->data); + } + coap_free(r->response); + r->response = NULL; + } + + coap_cancel_all_messages(r->client->coap, &r->dst, r->token, r->token_length); + coap_free(r); +} + + +/** + * Send given request. + */ +int +coap_client_send_request( + coap_client_t *client, + coap_request_t *request, + coap_response_t *response, + coap_address_t *dst) +{ + request->client = client; + request->response = response; + + if (&request->dst != dst) { + memcpy(&request->dst, dst, sizeof(coap_address_t)); + } + + coap_pdu_t *pdu = create_pdu(request); + if (!pdu) { + return 0; + } + + if (request->block_type) { + set_blocksize(request); + } + + // add options if present + if (request->optlist) { + coap_list_t *opt; + /* sort options for delta encoding */ + LL_SORT(request->optlist, order_opts); + + LL_FOREACH(request->optlist, opt) { + coap_option *o = (coap_option *) (opt->data); + coap_add_option(pdu, COAP_OPTION_KEY(*o), COAP_OPTION_LENGTH(*o), COAP_OPTION_DATA(*o)); + } + } + + if (request->data) { + if (request->block_type > 0) { + client->block_read(request, pdu, &request->block); + } else { + coap_add_data(pdu, request->length, request->data); + } + } + + return send_request(request->client, request, request->response, dst, pdu); +} + +coap_request_t *coap_client_new_request(unsigned char method, unsigned char type) +{ + coap_request_t *req = coap_malloc(sizeof(coap_request_t)); + if (!req) { + return NULL; + } + + memset(req, 0, sizeof(coap_request_t)); + + req->method = method; + req->type = type; + req->token_length = AUTO_TOKEN_LENGTH; + prng(req->token, req->token_length); + + return req; +} + +static coap_request_t *make_request( + coap_client_t *client, + const char *uri, + unsigned char method, + unsigned char type, + void *data, + size_t len, + coap_client_cb_t cb) +{ + coap_request_t *req = coap_client_new_request(method, type); + if (!req) + return NULL; + + if (!coap_request_set_uri(req, uri, FALSE)) { + goto error; + } + + resolve_address(&req->uri.host, &req->dst); + req->dst.port = req->uri.port; + + coap_response_t *resp = coap_malloc(sizeof(coap_response_t)); + if (!resp) { + goto error; + } + memset(resp, 0, sizeof(coap_response_t)); + + req->data = data; + req->length = len; + req->cb = cb; + + if (coap_client_send_request(client, req, resp, &req->dst)) { + return req; + } + +error: + if (req) { + coap_client_delete_request(req); + } + return NULL; +} + +/** + * + * Request a GET operation on a given resource. + * + * This function uses CON message type for the request. + * + * @param client + * @param uri + * @param cb + * + */ +coap_request_t *coap_client_get(coap_client_t *client, const char *uri, coap_client_cb_t cb) +{ + return make_request(client, uri, COAP_REQUEST_GET, COAP_MESSAGE_CON, NULL, 0, cb); +} + +coap_request_t *coap_client_put(coap_client_t *client, const char *uri, void *data, size_t len, coap_client_cb_t cb) +{ + return make_request(client, uri, COAP_REQUEST_PUT, COAP_MESSAGE_CON, data, len, cb); +} + +coap_request_t *coap_client_post(coap_client_t *client, const char *uri, void *data, size_t len, coap_client_cb_t cb) +{ + return make_request(client, uri, COAP_REQUEST_POST, COAP_MESSAGE_CON, data, len, cb); +} + +/* +response_t *coap_client_subscribe(coap_client_t *client, const char *uri, notification_cb_t cb) +{ + return NULL; +} + +response_t *coap_client_unsubscribe(coap_client_t *client, const char *uri) +{ + return NULL; +} +*/ diff --git a/client/client.h b/client/client.h new file mode 100644 index 0000000000..2b22aa736f --- /dev/null +++ b/client/client.h @@ -0,0 +1,104 @@ +/* + * client.h + * + * Created on: Apr 13, 2015 + * Author: wojtek + */ + +#ifndef uthash_fatal +#define uthash_fatal(msg) return -1; +#endif + +#include "uthash.h" +#include "coap/net.h" +#include "coap/block.h" +#include "coap_list.h" + +#ifndef COAP_CLIENT_CLIENT_H_ +#define COAP_CLIENT_CLIENT_H_ + +typedef enum { + BLOCK = 1, + SUBSCRIBE = 2, + UNSUBSCRIBE = 4, +} request_flags_t; + +#define AUTO_TOKEN_LENGTH 4 +#define MAX_TOKEN_LENGTH 8 + +struct _coap_request_t; +struct _coap_response_t; + +typedef int (*coap_client_cb_t)(struct _coap_request_t *, struct _coap_response_t*); + +typedef struct { + coap_context_t *coap; + coap_endpoint_t *ep; + struct _coap_request_t *requests; + + int (*block_write)(struct _coap_response_t *response, coap_pdu_t *pdu, coap_block_t *block); + int (*block_read)(struct _coap_request_t *request, coap_pdu_t *pdu, coap_block_t *block); + +} coap_client_t; + +// This is a future object. +typedef struct _coap_response_t { + uint8_t code; /* response code */ + uint8_t content_type; /* response content type */ + void *data; /* response payload data */ + size_t length; /* response lenght */ +} coap_response_t; + +typedef struct _coap_request_t { + coap_endpoint_t *ep; + coap_client_t *client; + coap_address_t dst; + coap_list_t *optlist; + coap_uri_t uri; + + uint8_t method; + uint8_t type; + uint8_t token[MAX_TOKEN_LENGTH]; + uint8_t token_length; + + void *data; + size_t length; + + int block_type; + coap_block_t block; + + coap_response_t *response; + coap_client_cb_t cb; + + void *pdata; + + UT_hash_handle hh; +} coap_request_t; + +int coap_request_set_uri(coap_request_t *request, const char *arg, int is_proxy_uri); + +static inline void coap_request_set_token(coap_request_t *request, uint8_t *token, int length) +{ + memcpy(request->token, token, MIN(length, MAX_TOKEN_LENGTH)); +} + +static inline coap_request_t *coap_client_find_request(coap_client_t *client, uint8_t *token, int token_length) +{ + coap_request_t *found = NULL; + HASH_FIND(hh, client->requests, token, token_length, found); + return found; +} + +void coap_client_init(coap_client_t *client, coap_context_t *ctx, coap_endpoint_t *ep); +void coap_client_deinit(coap_client_t *client); + +coap_request_t *coap_client_new_request(unsigned char method, unsigned char type); +void coap_client_delete_request(coap_request_t *r); + +int coap_client_send_request(coap_client_t *client, coap_request_t *request, coap_response_t *response, coap_address_t *dst); + +coap_request_t *coap_client_get(coap_client_t *client, const char *uri, coap_client_cb_t cb); +coap_request_t *coap_client_put(coap_client_t *client, const char *uri, void *data, size_t len, coap_client_cb_t cb); +coap_request_t *coap_client_post(coap_client_t *client, const char *uri, void *data, size_t len, coap_client_cb_t cb); + +#endif /* COAP_CLIENT_CLIENT_H_ */ From 568c49c9a4050e8e07e14525432f8fbca25fa615 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Wed, 8 Jul 2015 18:30:52 +0200 Subject: [PATCH 64/69] Platforms refactoring --- .gitignore | 20 +- ChangeLog | 24 -- TODO | 61 ---- client/client.c | 11 +- include/coap/address.h | 9 + include/coap/coap_io.h | 41 +-- include/coap/net.h | 26 +- include/coap/pdu.h | 1 - libcoap-1.map | 116 ------- libcoap-1.pc.in | 11 - libcoap-1.sym | 111 ------ platform/coap_contiki_io.c | 74 ++-- platform/coap_contiki_io.h | 16 +- platform/coap_lwip_io.c | 159 +++++---- platform/coap_lwip_io.h | 8 + platform/coap_posix.c | 37 ++ platform/coap_posix.h | 14 +- platform/coap_posix_io.c | 213 ++++++------ platform/coap_posix_io.h | 94 ++++- src/address.c | 36 -- src/async.c | 16 +- src/debug.c | 8 +- src/mem.c | 43 --- src/net.c | 696 ++++++++++++++++++------------------- 24 files changed, 761 insertions(+), 1084 deletions(-) delete mode 100644 TODO delete mode 100644 libcoap-1.map delete mode 100644 libcoap-1.pc.in delete mode 100644 libcoap-1.sym delete mode 100644 src/mem.c diff --git a/.gitignore b/.gitignore index e78516a113..b996f3d294 100644 --- a/.gitignore +++ b/.gitignore @@ -1,19 +1,3 @@ -# libcoap submodule -*.*~ -*.o -*.lst -*.sym -*.eep -*.elf -*.hex -*.bin -*.lss -*.map -*.log -*.swp -*.pyc - - # .gitignore for libcoap # ignoring autogenerated files and directories by autoreconf @@ -48,6 +32,7 @@ src/.dirstamp src/.libs/ src/*.o src/*.lo +src/*.lst # the doc/ folder doc/Doxyfile @@ -77,6 +62,7 @@ tests/.deps tests/testdriver tests/*.o -.project +#eclipse project files .cproject +.project .settings diff --git a/ChangeLog b/ChangeLog index 66619f5f96..59ed9e309f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -43,30 +43,6 @@ wrapper functions for malloc() and free(), while on Contiki and LWIP distinct arrays are used for each type. -2014-06-22 Maciej Wasilak - - Remove all occurences of WITH_POSIX, WITH_LWIP and WITH_CONTIKI - from following files: - * address.h - * async.c - * block.c - * coap_net.c - * coap_net.h - * coap_time.h - * debug.c - * debug.h - * encode.c - * encode.h - * option.c - * option.h - * pdu.c - * pdu.h - * prng.h - * resource.c - * resource.h - * t_list.h - * uri.c - 2014-03-09 Olaf Bergmann * net.c (coap_cancel): Removed 7.31 again and implemented new diff --git a/TODO b/TODO deleted file mode 100644 index 503ea7a03e..0000000000 --- a/TODO +++ /dev/null @@ -1,61 +0,0 @@ -This is a simple file for all kinds of stuff related on devlopment for -libcoap. Please append (and remove) any issue you think its worthy. - -Classification of issues: - Critical -> Break the library in some kind or a missing feature, maybe not - directly but later - Serious -> No regression on the user side, more likly on the libcoap - development - Minor -> Things that are nice to have, but they are not time critical - -================= -* CRITICAL ISSUES -================= --> Remove the #include "coap_config.h" directive from the public header files. --> Remove #ifdef HAVE_ASSERT_H and so on from the public headers. --> Use coap.h as the only header to include from the public view. --> DTLS functionality - -> Adding DTLS functions based on openssl - -> Bill Benett has starting some improvements here, please contact him - first before starting something --> Proxy functionality - -> A coap-server should be able to act as proxy server - -================ -* SERIOUS ISSUES -================ --> Create some development rules like: - --> How to submit patches? What about pull requests? - --> How to implement/change platform related code? --> Adding some documentation for classical users on how to use the libcoap --> Clean up the various inclusion for #ifdef __cplusplus #extern "C" {} --> Adding additional config options (like --with-pdu-size) --> Split of the platform related code into [foo]_platform.c files --> In general, improving the online doxygen documentation like creating some - additional information for doxygen (startpage, development information, - ...) --> In special, improving ... - Adding prams and return explanation in: - include/coap/coap_io.h - include/coap/option.h - include/coap/net.h - include/coap/resource.h - include/coap/str.h - include/coap/subscribe.h - include/coap/uri.h - Adding @brief directive - include/coap/block.h - include/coap/coap_io.h - include/coap/debug.h - include/coap/encode.h - include/coap/net.h - include/coap/str.h - include/coap/subscribe.h - include/coap/uri.h - -============== -* MINOR ISSUES -============== --> Remove the not needed Makefile.in.old files --> Adding a logo for libcoap - diff --git a/client/client.c b/client/client.c index 16e659a8f9..cda2e91bea 100644 --- a/client/client.c +++ b/client/client.c @@ -4,7 +4,7 @@ #include #include "utils.h" -#include "clock.h" +//#include "clock.h" //#include "mbuf.h" #include "coap/debug.h" @@ -247,7 +247,7 @@ static int send_request(coap_client_t *client, coap_request_t *request, coap_res #ifndef NDEBUG char toks[request->token_length*2 + 1]; memset(toks, 0, sizeof(toks)); - htos(request->token, request->token_length, toks, sizeof(toks)); +// htos(request->token, request->token_length, toks, sizeof(toks)); info("Request sent (id:%d tk:%s)", tid, toks); #endif @@ -362,7 +362,7 @@ static void response_handler( char toks[received->hdr->token_length*2 + 1]; memset(toks, 0, sizeof(toks)); - htos(received->hdr->token, received->hdr->token_length, toks, sizeof(toks)); +// htos(received->hdr->token, received->hdr->token_length, toks, sizeof(toks)); coap_request_t *request = NULL; HASH_FIND(hh, client->requests, received->hdr->token, received->hdr->token_length, request); @@ -533,12 +533,11 @@ static coap_request_t *make_request( if (!req) return NULL; - if (!coap_request_set_uri(req, uri, FALSE)) { + if (!coap_request_set_uri(req, uri, 0)) { goto error; } - resolve_address(&req->uri.host, &req->dst); - req->dst.port = req->uri.port; + coap_address(req->uri.host.s, req->uri.port, &req->dst); coap_response_t *resp = coap_malloc(sizeof(coap_response_t)); if (!resp) { diff --git a/include/coap/address.h b/include/coap/address.h index b0c8df1741..2a1da28d90 100644 --- a/include/coap/address.h +++ b/include/coap/address.h @@ -85,4 +85,13 @@ coap_is_mcast(const coap_address_t *a) { return a && _coap_is_mcast_impl(a); } +/** + * Fill an address structure with given address and port. + * + */ +static inline int +coap_address(const char *address, unsigned short port, coap_address_t *result) { + assert(result); + return _coap_address_impl(address, port, result); +} #endif /* _COAP_ADDRESS_H_ */ diff --git a/include/coap/coap_io.h b/include/coap/coap_io.h index 6d7daa5283..06cf872bf9 100644 --- a/include/coap/coap_io.h +++ b/include/coap/coap_io.h @@ -9,8 +9,6 @@ #ifndef _COAP_IO_H_ #define _COAP_IO_H_ -#include "coap_config.h" - #ifdef HAVE_ASSERT_H #include #else @@ -24,27 +22,24 @@ # include #endif -#include "address.h" - /** Invalid interface handle */ #define COAP_IF_INVALID -1 #define COAP_ENDPOINT_NOSEC 0x00 #define COAP_ENDPOINT_DTLS 0x01 +#include + +struct coap_address_t; struct coap_context_t; struct coap_packet_t; - -/** - * Abstract handle that is used to identify a local network interface. - */ -typedef int coap_if_handle_t; +struct coap_endpoint_t; typedef struct coap_packet_t coap_packet_t; -coap_endpoint_t *coap_new_endpoint(const coap_address_t *addr, int flags); +struct coap_endpoint_t *coap_new_endpoint(const struct coap_address_t *addr, int flags); -void coap_free_endpoint(coap_endpoint_t *ep); +void coap_free_endpoint(struct coap_endpoint_t *ep); /** * Function interface for data transmission. This function returns the number of @@ -53,16 +48,14 @@ void coap_free_endpoint(coap_endpoint_t *ep); * @param context The calling CoAP context. * @param local_interface The local interface to send the data. * @param dst The address of the receiver. - * @param data The data to send. - * @param datalen The actual length of @p data. + * @param pdu The pdu which should be send. * * @return The number of bytes written on success, or a value * less than zero on error. */ -ssize_t coap_network_send(struct coap_context_t *context, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - unsigned char *data, size_t datalen); +typedef ssize_t (*coap_network_send_t)(struct coap_context_t *context, + const struct coap_endpoint_t *local_interface, + const struct coap_address_t *dst, const coap_pdu_t *pdu); /** * Function interface for reading data. This function returns the number of @@ -77,15 +70,7 @@ ssize_t coap_network_send(struct coap_context_t *context, * @return The number of bytes received on success, or a value less than * zero on error. */ -ssize_t coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet); - -/** - * Function interface for checking data availability. - * - * @param ep The endpoint that should be checked. - * @return The number of bytes present in @p ep receive queue. - */ -ssize_t coap_network_peek(coap_endpoint_t *ep); +typedef ssize_t (*coap_network_read_t)(struct coap_endpoint_t *ep, coap_packet_t **packet); #ifndef coap_mcast_interface # define coap_mcast_interface(Local) 0 @@ -106,12 +91,12 @@ void coap_free_packet(coap_packet_t *packet); * This is usually used to copy a packet's data into a node's local_if member. */ void coap_packet_populate_endpoint(coap_packet_t *packet, - coap_endpoint_t *target); + struct coap_endpoint_t *target); /** * Given an incoming packet, copy its source address into an address struct. */ -void coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target); +void coap_packet_copy_source(coap_packet_t *packet, struct coap_address_t *target); /** * Given a packet, set msg and msg_len to an address and length of the packet's diff --git a/include/coap/net.h b/include/coap/net.h index a3b0516982..7a1e7d4e96 100644 --- a/include/coap/net.h +++ b/include/coap/net.h @@ -111,21 +111,6 @@ typedef struct coap_context_t { coap_tick_t sendqueue_basetime; coap_queue_t *sendqueue; void *pdata; -#ifdef WITH_POSIX - int sockfd; /**< send/receive socket */ -#endif /* WITH_POSIX */ - -#ifdef WITH_CONTIKI - struct uip_udp_conn *conn; /**< uIP connection object */ - struct etimer retransmit_timer; /**< fires when the next packet must be sent */ - struct etimer notify_timer; /**< used to check resources periodically */ -#endif /* WITH_CONTIKI */ - -#ifdef WITH_LWIP - uint8_t timer_configured; /**< Set to 1 when a retransmission is - * scheduled using lwIP timers for this - * context, otherwise 0. */ -#endif /* WITH_LWIP */ /** * The last message id that was used is stored in this field. The initial @@ -142,14 +127,9 @@ typedef struct coap_context_t { coap_response_handler_t response_handler; - ssize_t (*network_send)(struct coap_context_t *context, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - unsigned char *data, size_t datalen); - - ssize_t (*network_read)(coap_endpoint_t *ep, coap_packet_t **packet); - - ssize_t (*network_peek)(coap_endpoint_t *ep); +#ifdef CUSTOM_CONTEXT_FIELDS + CUSTOM_CONTEXT_FIELDS +#endif } coap_context_t; diff --git a/include/coap/pdu.h b/include/coap/pdu.h index b9daf7505d..6159b11e93 100644 --- a/include/coap/pdu.h +++ b/include/coap/pdu.h @@ -14,7 +14,6 @@ #ifndef _PDU_H_ #define _PDU_H_ -#include "coap_config.h" #include "uri.h" #include diff --git a/libcoap-1.map b/libcoap-1.map deleted file mode 100644 index b065371d96..0000000000 --- a/libcoap-1.map +++ /dev/null @@ -1,116 +0,0 @@ -VER_1 { -global: - coap_add_attr; - coap_add_block; - coap_add_data; - coap_add_observer; - coap_add_option; - coap_add_option_later; - coap_add_resource; - coap_address_equals; - coap_add_token; - coap_adjust_basetime; - coap_cancel_all_messages; - coap_can_exit; - coap_check_notify; - coap_check_option; - coap_clock_init; - coap_clone_uri; - coap_decode_var_bytes; - coap_delete_all; - coap_delete_all_resources; - coap_delete_attr; - coap_delete_node; - coap_delete_observer; - coap_delete_pdu; - coap_delete_resource; - coap_delete_string; - coap_dispatch; - coap_encode_var_bytes; - coap_find_async; - coap_find_attr; - coap_find_observer; - coap_find_transaction; - coap_fls; - coap_free_async; - coap_free_context; - coap_free_endpoint; - coap_free_packet; - coap_free_type; - coap_get_block; - coap_get_data; - coap_get_log_level; - coap_get_resource_from_key; - coap_handle_failed_notify; - coap_handle_message; - coap_hash_impl; - coap_hash_path; - coap_hash_request_uri; - coap_insert_node; - coap_log_impl; - coap_malloc_type; - coap_memory_init; - coap_network_read; - coap_network_send; - coap_new_context; - coap_new_endpoint; - coap_new_error_response; - coap_new_node; - coap_new_pdu; - coap_new_string; - coap_new_uri; - coap_opt_block_num; - coap_opt_delta; - coap_opt_encode; - coap_option_check_critical; - coap_option_filter_get; - coap_option_filter_set; - coap_option_filter_unset; - coap_option_iterator_init; - coap_option_next; - coap_opt_length; - coap_opt_parse; - coap_opt_setheader; - coap_opt_size; - coap_opt_value; - coap_package_name; - coap_package_version; - coap_packet_copy_source; - coap_packet_get_memmapped; - coap_packet_populate_endpoint; - coap_pdu_clear; - coap_pdu_init; - coap_pdu_parse; - coap_peek_next; - coap_pop_next; - coap_print_addr; - coap_print_link; - coap_print_wellknown; - coap_read; - coap_register_async; - coap_remove_async; - coap_remove_from_queue; - coap_resource_init; - coap_response_phrase; - coap_retransmit; - coap_send; - coap_send_ack; - coap_send_confirmed; - coap_send_error; - coap_send_message_type; - coap_set_log_level; - coap_show_pdu; - coap_split_path; - coap_split_query; - coap_split_uri; - coap_subscription_init; - coap_ticks; - coap_ticks; - coap_ticks_to_rt; - coap_touch_observer; - coap_transaction_id; - coap_wellknown_response; - coap_write_block_opt; -local: - *; -}; diff --git a/libcoap-1.pc.in b/libcoap-1.pc.in deleted file mode 100644 index 4a031891f8..0000000000 --- a/libcoap-1.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: @PACKAGE_NAME@ -Description: C-Implementation of CoAP. -Version: @PACKAGE_VERSION@ -URL: @PACKAGE_URL@ -Libs: -L${libdir} -lcoap -Cflags: -I${includedir}/coap diff --git a/libcoap-1.sym b/libcoap-1.sym deleted file mode 100644 index 7f465feb28..0000000000 --- a/libcoap-1.sym +++ /dev/null @@ -1,111 +0,0 @@ -coap_add_attr -coap_add_block -coap_add_data -coap_add_observer -coap_add_option -coap_add_option_later -coap_add_resource -coap_address_equals -coap_add_token -coap_adjust_basetime -coap_cancel_all_messages -coap_can_exit -coap_check_notify -coap_check_option -coap_clock_init -coap_clone_uri -coap_decode_var_bytes -coap_delete_all -coap_delete_all_resources -coap_delete_attr -coap_delete_node -coap_delete_observer -coap_delete_pdu -coap_delete_resource -coap_delete_string -coap_dispatch -coap_encode_var_bytes -coap_find_async -coap_find_attr -coap_find_observer -coap_find_transaction -coap_fls -coap_free_async -coap_free_context -coap_free_endpoint -coap_free_packet -coap_free_type -coap_get_block -coap_get_data -coap_get_log_level -coap_get_resource_from_key -coap_handle_failed_notify -coap_handle_message -coap_hash_impl -coap_hash_path -coap_hash_request_uri -coap_insert_node -coap_log_impl -coap_malloc_type -coap_memory_init -coap_network_read -coap_network_send -coap_new_context -coap_new_endpoint -coap_new_error_response -coap_new_node -coap_new_pdu -coap_new_string -coap_new_uri -coap_opt_block_num -coap_opt_delta -coap_opt_encode -coap_option_check_critical -coap_option_filter_get -coap_option_filter_set -coap_option_filter_unset -coap_option_iterator_init -coap_option_next -coap_opt_length -coap_opt_parse -coap_opt_setheader -coap_opt_size -coap_opt_value -coap_package_name -coap_package_version -coap_packet_copy_source -coap_packet_get_memmapped -coap_packet_populate_endpoint -coap_pdu_clear -coap_pdu_init -coap_pdu_parse -coap_peek_next -coap_pop_next -coap_print_addr -coap_print_link -coap_print_wellknown -coap_read -coap_register_async -coap_remove_async -coap_remove_from_queue -coap_resource_init -coap_response_phrase -coap_retransmit -coap_send -coap_send_ack -coap_send_confirmed -coap_send_error -coap_send_message_type -coap_set_log_level -coap_show_pdu -coap_split_path -coap_split_query -coap_split_uri -coap_subscription_init -coap_ticks -coap_ticks -coap_ticks_to_rt -coap_touch_observer -coap_transaction_id -coap_wellknown_response -coap_write_block_opt diff --git a/platform/coap_contiki_io.c b/platform/coap_contiki_io.c index 29e5529e9d..4d72dd4220 100644 --- a/platform/coap_contiki_io.c +++ b/platform/coap_contiki_io.c @@ -39,37 +39,6 @@ coap_free_contiki_endpoint(struct coap_endpoint_t *ep) { ep_initialized = 0; } -coap_endpoint_t * -coap_new_endpoint(const coap_address_t *addr, int flags) { - struct coap_endpoint_t *ep = coap_malloc_contiki_endpoint(); - - if (ep) { - memset(ep, 0, sizeof(struct coap_endpoint_t)); - ep->handle.conn = udp_new(NULL, 0, NULL); - - if (!ep->handle.conn) { - coap_free_endpoint(ep); - return NULL; - } - - coap_address_init(&ep->addr); - uip_ipaddr_copy(&ep->addr.addr, &addr->addr); - ep->addr.port = addr->port; - udp_bind((struct uip_udp_conn *)ep->handle.conn, addr->port); - } - return ep; -} - -void -coap_free_endpoint(coap_endpoint_t *ep) { - if (ep) { - if (ep->handle.conn) { - uip_udp_remove((struct uip_udp_conn *)ep->handle.conn); - } - coap_free_contiki_endpoint(ep); - } -} - static inline coap_packet_t * coap_malloc_packet(void) { return (coap_packet_t *)coap_malloc_type(COAP_PACKET, 0); @@ -88,7 +57,7 @@ coap_get_max_packetlength(const coap_packet_t *packet UNUSED_PARAM) { void coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target) { - target->handle = packet->interface->handle; + target->conn = packet->interface->conn; memcpy(&target->addr, &packet->dst, sizeof(target->addr)); target->ifindex = packet->ifindex; target->flags = 0; /* FIXME */ @@ -111,13 +80,15 @@ ssize_t coap_network_send(struct coap_context_t *context, const coap_endpoint_t *local_interface, const coap_address_t *dst, - unsigned char *data, - size_t datalen) { + const coap_pdu_t *pdu) { struct coap_endpoint_t *ep = (struct coap_endpoint_t *)local_interface; - uip_udp_packet_sendto((struct uip_udp_conn *)ep->handle.conn, data, datalen, + unsigned char *data = pdu->hdr; + size_t datalen = pdu->length; + + uip_udp_packet_sendto((struct uip_udp_conn *)ep->conn, data, datalen, &dst->addr, dst->port); return datalen; } @@ -194,3 +165,36 @@ coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) { *packet = NULL; return -1; } + +coap_endpoint_t * +coap_new_endpoint(const coap_address_t *addr, int flags) { + struct coap_endpoint_t *ep = coap_malloc_contiki_endpoint(); + + if (ep) { + memset(ep, 0, sizeof(struct coap_endpoint_t)); + ep->conn = udp_new(NULL, 0, NULL); + + if (!ep->conn) { + coap_free_endpoint(ep); + return NULL; + } + + coap_address_init(&ep->addr); + uip_ipaddr_copy(&ep->addr.addr, &addr->addr); + ep->addr.port = addr->port; + ep->network_send = coap_network_send; + ep->network_read = coap_network_read; + udp_bind((struct uip_udp_conn *)ep->conn, addr->port); + } + return ep; +} + +void +coap_free_endpoint(coap_endpoint_t *ep) { + if (ep) { + if (ep->conn) { + uip_udp_remove((struct uip_udp_conn *)ep->conn); + } + coap_free_contiki_endpoint(ep); + } +} diff --git a/platform/coap_contiki_io.h b/platform/coap_contiki_io.h index 333021aceb..6cf7f41a14 100644 --- a/platform/coap_contiki_io.h +++ b/platform/coap_contiki_io.h @@ -10,6 +10,15 @@ #include "uip.h" +#define CUSTOM_CONTEXT_FIELDS \ + struct uip_udp_conn *conn; \ + struct etimer retransmit_timer; \ + struct etimer notify_timer; + +/**< uIP connection object */ +/**< fires when the next packet must be sent */ +/**< used to check resources periodically */ + typedef struct coap_address_t { uip_ipaddr_t addr; unsigned short port; @@ -29,10 +38,9 @@ typedef struct coap_address_t { * tuple (handle, addr) must uniquely identify this endpoint. */ typedef struct coap_endpoint_t { - union { - int fd; /**< on POSIX systems */ - void *conn; /**< opaque connection (e.g. uip_conn in Contiki) */ - } handle; /**< opaque handle to identify this endpoint */ + coap_network_read_t network_read; + coap_network_send_t network_send; + void *conn; /**< opaque connection (e.g. uip_conn in Contiki) */ coap_address_t addr; /**< local interface address */ int ifindex; int flags; diff --git a/platform/coap_lwip_io.c b/platform/coap_lwip_io.c index bab0fc2334..12c8e91eec 100644 --- a/platform/coap_lwip_io.c +++ b/platform/coap_lwip_io.c @@ -12,46 +12,73 @@ #include "coap_io.h" #include "coap_lwip_io.h" -void coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target) -{ - printf("FIXME no endpoint populated\n"); +void +coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target) { + printf("FIXME no endpoint populated\n"); } -void coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target) -{ - target->port = packet->srcport; - memcpy(&target->addr, ip_current_src_addr(), sizeof(ip_addr_t)); + +void +coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target) { + target->port = packet->srcport; + memcpy(&target->addr, ip_current_src_addr(), sizeof(ip_addr_t)); } -void coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length) -{ - LWIP_ASSERT("Can only deal with contiguous PBUFs to read the initial details", packet->pbuf->tot_len == packet->pbuf->len); - *address = packet->pbuf->payload; - *length = packet->pbuf->tot_len; + +void +coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, + size_t *length) { + LWIP_ASSERT("Can only deal with contiguous PBUFs to read the initial details", + packet->pbuf->tot_len == packet->pbuf->len); + *address = packet->pbuf->payload; + *length = packet->pbuf->tot_len; } -void coap_free_packet(coap_packet_t *packet) -{ - if (packet->pbuf) - pbuf_free(packet->pbuf); - coap_free_type(COAP_PACKET, packet); + +void +coap_free_packet(coap_packet_t *packet) { + if (packet->pbuf) + pbuf_free(packet->pbuf); + coap_free_type(COAP_PACKET, packet); } -struct pbuf *coap_packet_extract_pbuf(coap_packet_t *packet) -{ - struct pbuf *ret = packet->pbuf; - packet->pbuf = NULL; - return ret; +struct pbuf * +coap_packet_extract_pbuf(coap_packet_t *packet) { + struct pbuf *ret = packet->pbuf; + packet->pbuf = NULL; + return ret; } -coap_tid_t -coap_send_impl(coap_context_t *context, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - coap_pdu_t *pdu) { +/** Callback from lwIP when a package was received. + * + * The current implemntation deals this to coap_handle_message immedately, but + * other mechanisms (as storing the package in a queue and later fetching it + * when coap_read is called) can be envisioned. + * + * It handles everything coap_read does on other implementations. + */ +static void +coap_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, + u16_t port) { + coap_endpoint_t *ep = (coap_endpoint_t*) arg; + coap_packet_t *packet = coap_malloc_type(COAP_PACKET, + sizeof(coap_packet_t)); + /* this is fatal because due to the short life of the packet, never should there be more than one coap_packet_t required */ + LWIP_ASSERT("Insufficient coap_packet_t resources.", packet != NULL); + packet->pbuf = p; + packet->srcport = port; + + /** FIXME derive the context without changing endopint definition */ + coap_handle_message(ep->context, packet); + coap_free_packet(packet); +} + +static coap_tid_t +coap_network_send(struct coap_context_t *context, const coap_endpoint_t *ep, + const coap_address_t *dst, unsigned char *data, + size_t datalen) { coap_tid_t id = COAP_INVALID_TID; uint8_t err; char *data_backup; - if ( !context || !dst || !pdu ) - { + if (!context || !dst || !pdu) { return id; } @@ -65,63 +92,47 @@ coap_send_impl(coap_context_t *context, coap_transaction_id(dst, pdu, &id); - udp_sendto(context->endpoint->pcb, pdu->pbuf, - &dst->addr, dst->port); + udp_sendto(ep->pcb, pdu->pbuf, &dst->addr, dst->port); return id; } -/** Callback from lwIP when a package was received. - * - * The current implemntation deals this to coap_handle_message immedately, but - * other mechanisms (as storing the package in a queue and later fetching it - * when coap_read is called) can be envisioned. - * - * It handles everything coap_read does on other implementations. - */ -static void coap_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port) -{ - coap_endpoint_t *ep = (coap_endpoint_t*)arg; - coap_packet_t *packet = coap_malloc_type(COAP_PACKET, sizeof(coap_packet_t)); - /* this is fatal because due to the short life of the packet, never should there be more than one coap_packet_t required */ - LWIP_ASSERT("Insufficient coap_packet_t resources.", packet != NULL); - packet->pbuf = p; - packet->srcport = port; - - /** FIXME derive the context without changing endopint definition */ - coap_handle_message(ep->context, packet); - - coap_free_packet(packet); -} +coap_endpoint_t * +coap_new_endpoint(const coap_address_t *addr, int flags) { + coap_endpoint_t *result; + err_t err; -coap_endpoint_t *coap_new_endpoint(const coap_address_t *addr, int flags) { - coap_endpoint_t *result; - err_t err; + LWIP_ASSERT("Flags not supported for LWIP endpoints", + flags == COAP_ENDPOINT_NOSEC); - LWIP_ASSERT("Flags not supported for LWIP endpoints", flags == COAP_ENDPOINT_NOSEC); + result = coap_malloc_type(COAP_ENDPOINT, sizeof(coap_endpoint_t)); + if (!result) + return NULL; - result = coap_malloc_type(COAP_ENDPOINT, sizeof(coap_endpoint_t)); - if (!result) return NULL; + result->pcb = udp_new(); + if (result->pcb == NULL) + goto error; - result->pcb = udp_new(); - if (result->pcb == NULL) goto error; + udp_recv(result->pcb, coap_recv, (void*) result); + err = udp_bind(result->pcb, &addr->addr, addr->port); + if (err) { + udp_remove(result->pcb); + goto error; + } - udp_recv(result->pcb, coap_recv, (void*)result); - err = udp_bind(result->pcb, &addr->addr, addr->port); - if (err) { - udp_remove(result->pcb); - goto error; - } + result->cbs.network_send = coap_network_send; + // FIXME!!!! + result->cbs.network_read = NULL; - return result; + return result; error: - coap_free_type(COAP_ENDPOINT, result); - return NULL; + coap_free_type(COAP_ENDPOINT, result); + return NULL; } -void coap_free_endpoint(coap_endpoint_t *ep) -{ - udp_remove(ep->pcb); - coap_free_type(COAP_ENDPOINT, ep); +void +coap_free_endpoint(coap_endpoint_t *ep) { + udp_remove(ep->pcb); + coap_free_type(COAP_ENDPOINT, ep); } diff --git a/platform/coap_lwip_io.h b/platform/coap_lwip_io.h index 16169f15e5..f01772c31a 100644 --- a/platform/coap_lwip_io.h +++ b/platform/coap_lwip_io.h @@ -12,6 +12,12 @@ #include #include +/**< Set to 1 when a retransmission is + * scheduled using lwIP timers for this + * context, otherwise 0. */ +#define CUSTOM_CONTEXT_FIELDS \ + uint8_t timer_configured; + typedef struct coap_address_t { uint16_t port; ip_addr_t addr; @@ -45,6 +51,8 @@ typedef struct coap_address_t { * tuple (handle, addr) must uniquely identify this endpoint. */ typedef struct coap_endpoint_t { + coap_network_read_t network_read; + coap_network_send_t network_send; struct udp_pcb *pcb; /**< @FIXME this was added in a hurry, not sure it confirms to the overall model --chrysn */ struct coap_context_t *context; diff --git a/platform/coap_posix.c b/platform/coap_posix.c index bdc231f9ef..b96e816d8e 100644 --- a/platform/coap_posix.c +++ b/platform/coap_posix.c @@ -5,4 +5,41 @@ * Author: wojtek */ +#include +#include +#include +#ifdef HAVE_ASSERT_H +#include +#else /* HAVE_ASSERT_H */ +#define assert(...) +#endif /* HAVE_ASSERT_H */ + +#ifdef HAVE_MALLOC +#include +#endif + +#ifdef __GNUC__ +#define UNUSED_PARAM __attribute__((unused)) +#else +#define UNUSED_PARAM +#endif /* __GNUC__ */ + +void +coap_platform_init(void) { + prng_init(time(NULL)); +} + +void +coap_memory_init(void) { +} + +void * +coap_malloc_type(coap_memory_tag_t type UNUSED_PARAM, size_t size) { + return malloc(size); +} + +void +coap_free_type(coap_memory_tag_t type UNUSED_PARAM, void *p) { + free(p); +} diff --git a/platform/coap_posix.h b/platform/coap_posix.h index df64ebfa3a..17f842c694 100644 --- a/platform/coap_posix.h +++ b/platform/coap_posix.h @@ -8,6 +8,8 @@ #ifndef INCLUDE_COAP_COAP_POSIX_H_ #define INCLUDE_COAP_COAP_POSIX_H_ +#include + /** * This data type represents internal timer ticks with COAP_TICKS_PER_SECOND * resolution. @@ -29,16 +31,14 @@ typedef long coap_tick_diff_t; /** Use ms resolution on POSIX systems */ #define COAP_TICKS_PER_SECOND 1000 -/** - * Initializes the internal clock. - */ -static inline void coap_clock_init(void) { -} - /** * Sets @p t to the internal time with COAP_TICKS_PER_SECOND resolution. */ -void coap_ticks(coap_tick_t *t); +static inline void coap_ticks(coap_tick_t *t) { + struct timespec spec; + clock_gettime(CLOCK_MONOTONIC, &spec); + *t = (coap_tick_t)spec.tv_sec*1000 + (coap_tick_t)(spec.tv_nsec / 1.0e6); +} /** * Helper function that converts coap ticks to wallclock time. On POSIX, this diff --git a/platform/coap_posix_io.c b/platform/coap_posix_io.c index 8a3d189471..44970969df 100644 --- a/platform/coap_posix_io.c +++ b/platform/coap_posix_io.c @@ -4,6 +4,8 @@ * Created on: Jun 11, 2015 * Author: wojtek */ +#include "coap_config.h" + #ifdef HAVE_SYS_SELECT_H #include #endif @@ -19,13 +21,15 @@ #ifdef HAVE_UNISTD_H #include #endif -#include +#include +#include +#include #include "debug.h" #include "mem.h" #include "coap_io.h" -#if defined(WITH_POSIX) != defined(HAVE_NETINET_IN_H) +#ifndef HAVE_NETINET_IN_H /* define struct in6_pktinfo and struct in_pktinfo if not available FIXME: check with configure */ @@ -54,98 +58,8 @@ struct in_pktinfo { #define SIN6(A) ((struct sockaddr_in6 *)(A)) -static inline struct coap_endpoint_t * -coap_malloc_posix_endpoint(void) -{ - return (struct coap_endpoint_t *) coap_malloc(sizeof(struct coap_endpoint_t)); -} - -static inline void -coap_free_posix_endpoint(struct coap_endpoint_t *ep) -{ - coap_free(ep); -} - -coap_endpoint_t * -coap_new_endpoint(const coap_address_t *addr, int flags) -{ - int sockfd = socket(addr->addr.sa.sa_family, SOCK_DGRAM, 0); - int on = 1; - struct coap_endpoint_t *ep; - - if (sockfd < 0) { - coap_log(LOG_WARNING, "coap_new_endpoint: socket"); - return NULL; - } - - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) - coap_log(LOG_WARNING, "coap_new_endpoint: setsockopt SO_REUSEADDR"); - - on = 1; - switch (addr->addr.sa.sa_family) { - case AF_INET: - if (setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) < 0) - coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IP_PKTINFO\n"); - break; - case AF_INET6: -#ifdef IPV6_RECVPKTINFO - if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) - coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_RECVPKTINFO\n"); -#else /* IPV6_RECVPKTINFO */ - if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) < 0) - coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_PKTINFO\n"); -#endif /* IPV6_RECVPKTINFO */ - break; - default: - coap_log(LOG_ALERT, "coap_new_endpoint: unsupported sa_family\n"); - } - - if (bind(sockfd, &addr->addr.sa, addr->size) < 0) { - coap_log(LOG_WARNING, "coap_new_endpoint: bind"); - close(sockfd); - return NULL; - } - - ep = coap_malloc_posix_endpoint(); - if (!ep) { - coap_log(LOG_WARNING, "coap_new_endpoint: malloc"); - close(sockfd); - return NULL; - } - - memset(ep, 0, sizeof(struct coap_endpoint_t)); - ep->handle.fd = sockfd; - ep->flags = flags; - memcpy(&ep->addr, addr, sizeof(coap_address_t)); - -#ifndef NDEBUG - if (LOG_DEBUG <= coap_get_log_level()) { -#ifndef INET6_ADDRSTRLEN -#define INET6_ADDRSTRLEN 40 -#endif - unsigned char addr_str[INET6_ADDRSTRLEN + 8]; - - if (coap_print_addr(addr, addr_str, INET6_ADDRSTRLEN + 8)) { - debug("created %sendpoint %s\n", - ep->flags & COAP_ENDPOINT_DTLS ? "DTLS " : "", addr_str); - } - } -#endif /* NDEBUG */ - - return (coap_endpoint_t *) ep; -} - -void -coap_free_endpoint(coap_endpoint_t *ep) -{ - if (ep) { - if (ep->handle.fd >= 0) - close(ep->handle.fd); - coap_free_posix_endpoint((struct coap_endpoint_t *) ep); - } -} -static coap_packet_t * +coap_packet_t * coap_malloc_packet(void) { coap_packet_t *packet; @@ -164,7 +78,7 @@ coap_free_packet(coap_packet_t *packet) coap_free(packet); } -static inline size_t +size_t coap_get_max_packetlength(const coap_packet_t *packet UNUSED_PARAM) { return COAP_MAX_PDU_SIZE; @@ -173,7 +87,7 @@ coap_get_max_packetlength(const coap_packet_t *packet UNUSED_PARAM) void coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target) { - target->handle = packet->interface->handle; + target->fd = packet->interface->fd; memcpy(&target->addr, &packet->dst, sizeof(target->addr)); target->ifindex = packet->ifindex; target->flags = 0; /* FIXME */ @@ -191,14 +105,16 @@ coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, *length = packet->length; } -ssize_t -coap_network_send(struct coap_context_t *context UNUSED_PARAM, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, unsigned char *data, - size_t datalen) +static ssize_t +coap_network_send(struct coap_context_t *context, + const struct coap_endpoint_t *local_interface, + const struct coap_address_t *dst, + const coap_pdu_t *pdu) { struct coap_endpoint_t *ep = (struct coap_endpoint_t *) local_interface; + unsigned char *data = (unsigned char *)pdu->hdr; + size_t datalen = pdu->length; /* a buffer large enough to hold all protocol address types */ char buf[CMSG_LEN(sizeof(struct sockaddr_storage))]; @@ -264,7 +180,8 @@ coap_network_send(struct coap_context_t *context UNUSED_PARAM, return -1; } - return sendmsg(ep->handle.fd, &mhdr, 0); + return sendmsg(ep->fd, &mhdr, 0); +// return sendto(ep->fd, data, datalen, 0, (const struct sockaddr *)&dst->addr, dst->size); } /** @@ -278,7 +195,7 @@ is_local_if(const coap_address_t *local, const coap_address_t *dst) return coap_address_isany(local) || coap_address_equals(dst, local); } -ssize_t +static ssize_t coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) { ssize_t len = -1; @@ -315,20 +232,20 @@ coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) mhdr.msg_controllen = sizeof(msg_control); assert(sizeof(msg_control) == CMSG_LEN(sizeof(struct sockaddr_storage))); - len = recvmsg(ep->handle.fd, &mhdr, 0); + len = recvmsg(ep->fd, &mhdr, 0); if (len < 0) { - coap_log(LOG_WARNING, "coap_network_read: %s\n", strerror(errno)); + //coap_log(LOG_WARNING, "coap_network_read: %s\n", strerror(errno)); goto error; } else { struct cmsghdr *cmsg; coap_log(LOG_DEBUG, "received %d bytes on fd %d\n", (int )len, - ep->handle.fd); + ep->fd); /* use getsockname() to get the local port */ (*packet)->dst.size = sizeof((*packet)->dst.addr); - if (getsockname(ep->handle.fd, &(*packet)->dst.addr.sa, + if (getsockname(ep->fd, &(*packet)->dst.addr.sa, &(*packet)->dst.size) < 0) { coap_log(LOG_DEBUG, "cannot determine local port\n"); goto error; @@ -398,4 +315,88 @@ coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) return -1; } +coap_endpoint_t * +coap_new_endpoint(const coap_address_t *addr, int flags) +{ + int sockfd = socket(addr->addr.sa.sa_family, SOCK_DGRAM, 0); + int on = 1; + struct coap_endpoint_t *ep; + + if (sockfd < 0) { + coap_log(LOG_WARNING, "coap_new_endpoint: socket"); + return NULL; + } + + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) + coap_log(LOG_WARNING, "coap_new_endpoint: setsockopt SO_REUSEADDR"); + + fcntl(sockfd, F_SETFL, O_NONBLOCK); + + on = 1; + switch (addr->addr.sa.sa_family) { + case AF_INET: + if (setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) < 0) + coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IP_PKTINFO\n"); + break; + case AF_INET6: +#ifdef IPV6_RECVPKTINFO + if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) + coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_RECVPKTINFO\n"); +#else /* IPV6_RECVPKTINFO */ + if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) < 0) + coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_PKTINFO\n"); +#endif /* IPV6_RECVPKTINFO */ + break; + default: + coap_log(LOG_ALERT, "coap_new_endpoint: unsupported sa_family\n"); + } + + if (bind(sockfd, &addr->addr.sa, addr->size) < 0) { + coap_log(LOG_WARNING, "coap_new_endpoint: bind"); + close(sockfd); + return NULL; + } + + ep = coap_malloc_type(COAP_ENDPOINT, sizeof(struct coap_endpoint_t)); + if (!ep) { + coap_log(LOG_WARNING, "coap_new_endpoint: malloc"); + close(sockfd); + return NULL; + } + + memset(ep, 0, sizeof(struct coap_endpoint_t)); + ep->fd = sockfd; + ep->flags = flags; + ep->network_send = coap_network_send; + ep->network_read = coap_network_read; + + memcpy(&ep->addr, addr, sizeof(coap_address_t)); + +#ifndef NDEBUG + if (LOG_DEBUG <= coap_get_log_level()) { +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN 40 +#endif + unsigned char addr_str[INET6_ADDRSTRLEN + 8]; + + if (coap_print_addr(addr, addr_str, INET6_ADDRSTRLEN + 8)) { + debug("created %sendpoint %s\n", + ep->flags & COAP_ENDPOINT_DTLS ? "DTLS " : "", addr_str); + } + } +#endif /* NDEBUG */ + + return (coap_endpoint_t *) ep; +} + +void +coap_free_endpoint(coap_endpoint_t *ep) +{ + if (ep) { + if (ep->fd >= 0) + close(ep->fd); + coap_free_type(COAP_ENDPOINT, (struct coap_endpoint_t *) ep); + } +} + #undef SIN6 diff --git a/platform/coap_posix_io.h b/platform/coap_posix_io.h index 5e3f4a01b2..a96ca2e41a 100644 --- a/platform/coap_posix_io.h +++ b/platform/coap_posix_io.h @@ -16,6 +16,24 @@ #include #endif +#ifdef HAVE_ASSERT_H +#include +#endif + +#include +#include +#include +#include + +#define CUSTOM_CONTEXT_FIELDS \ + int sockfd; /**< send/receive socket */ + +/** + * Abstract handle that is used to identify a local network interface. + */ +typedef int coap_if_handle_t; + + /** multi-purpose address abstraction */ typedef struct coap_address_t { socklen_t size; /**< size of addr */ @@ -27,12 +45,69 @@ typedef struct coap_address_t { } addr; } coap_address_t; -/** - * Compares given address objects @p a and @p b. This function returns @c 1 if - * addresses are equal, @c 0 otherwise. The parameters @p a and @p b must not be - * @c NULL; - */ -int coap_address_equals(const coap_address_t *a, const coap_address_t *b); +static inline int +_coap_address_impl(const char *address, unsigned short port, coap_address_t *result) +{ + struct addrinfo *res, *ainfo; + struct addrinfo hints; + int error, len = -1; + + memset((char *)result, 0, sizeof(coap_address_t)); + memset((char *)&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_DGRAM; + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; + + error = getaddrinfo(address, NULL, &hints, &res); + + if (error != 0) { + return error; + } + + for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) { + switch (ainfo->ai_family) { + case AF_INET6: + case AF_INET: + result->size = ainfo->ai_addrlen; + memcpy(&result->addr, ainfo->ai_addr, result->size); + if (ainfo->ai_family == AF_INET) + result->addr.sin.sin_port = htons(port); + else + result->addr.sin6.sin6_port = htons(port); + goto finish; + default: + ; + } + } + +finish: + freeaddrinfo(res); + return len; +} + +static inline int +_coap_address_equals_impl(const coap_address_t *a, const coap_address_t *b) { + assert(a); assert(b); + + if (a->size != b->size || a->addr.sa.sa_family != b->addr.sa.sa_family) + return 0; + + /* need to compare only relevant parts of sockaddr_in6 */ + switch (a->addr.sa.sa_family) { + case AF_INET: + return + a->addr.sin.sin_port == b->addr.sin.sin_port && + memcmp(&a->addr.sin.sin_addr, &b->addr.sin.sin_addr, + sizeof(struct in_addr)) == 0; + case AF_INET6: + return a->addr.sin6.sin6_port == b->addr.sin6.sin6_port && + memcmp(&a->addr.sin6.sin6_addr, &b->addr.sin6.sin6_addr, + sizeof(struct in6_addr)) == 0; + default: /* fall through and signal error */ + ; + } + return 0; +} static inline int _coap_address_isany_impl(const coap_address_t *a) { @@ -72,13 +147,12 @@ _coap_is_mcast_impl(const coap_address_t *a) { * tuple (handle, addr) must uniquely identify this endpoint. */ typedef struct coap_endpoint_t { - union { - int fd; /**< on POSIX systems */ - void *conn; /**< opaque connection (e.g. uip_conn in Contiki) */ - } handle; /**< opaque handle to identify this endpoint */ + int fd; /**< on POSIX systems */ coap_address_t addr; /**< local interface address */ int ifindex; int flags; + coap_network_read_t network_read; + coap_network_send_t network_send; } coap_endpoint_t; struct coap_packet_t { diff --git a/src/address.c b/src/address.c index e237881a7a..60e6724765 100644 --- a/src/address.c +++ b/src/address.c @@ -6,43 +6,7 @@ * README for terms of use. */ -#ifdef WITH_POSIX -#include -#include -#include - -#include "address.h" - -int -coap_address_equals(const coap_address_t *a, const coap_address_t *b) { - assert(a); assert(b); - - if (a->size != b->size || a->addr.sa.sa_family != b->addr.sa.sa_family) - return 0; - - /* need to compare only relevant parts of sockaddr_in6 */ - switch (a->addr.sa.sa_family) { - case AF_INET: - return - a->addr.sin.sin_port == b->addr.sin.sin_port && - memcmp(&a->addr.sin.sin_addr, &b->addr.sin.sin_addr, - sizeof(struct in_addr)) == 0; - case AF_INET6: - return a->addr.sin6.sin6_port == b->addr.sin6.sin6_port && - memcmp(&a->addr.sin6.sin6_addr, &b->addr.sin6.sin6_addr, - sizeof(struct in6_addr)) == 0; - default: /* fall through and signal error */ - ; - } - return 0; -} - -#else /* WITH_POSIX */ - /* make compilers happy that do not like empty modules */ static inline void dummy() { } - -#endif /* not WITH_POSIX */ - diff --git a/src/async.c b/src/async.c index 24da89309f..8c3a174865 100644 --- a/src/async.c +++ b/src/async.c @@ -3,10 +3,10 @@ * Copyright (C) 2010,2011 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ -/** +/** * @file async.c * @brief state management for asynchronous messages */ @@ -38,7 +38,7 @@ coap_register_async(coap_context_t *context, coap_address_t *peer, } /* store information for handling the asynchronous task */ - s = (coap_async_state_t *)coap_malloc(sizeof(coap_async_state_t) + + s = (coap_async_state_t *)coap_malloc(sizeof(coap_async_state_t) + request->hdr->token_length); if (!s) { coap_log(LOG_CRIT, "coap_register_async: insufficient memory\n"); @@ -60,7 +60,7 @@ coap_register_async(coap_context_t *context, coap_address_t *peer, s->tokenlen = request->hdr->token_length; memcpy(s->token, request->hdr->token, request->hdr->token_length); } - + memcpy(&s->id, &id, sizeof(coap_tid_t)); coap_touch_async(s); @@ -73,12 +73,12 @@ coap_register_async(coap_context_t *context, coap_address_t *peer, coap_async_state_t * coap_find_async(coap_context_t *context, coap_tid_t id) { coap_async_state_t *tmp; - LL_SEARCH_SCALAR(context->async_state,tmp,id,id); + LL_SEARCH_SCALAR(context->async_state,tmp,id,id); return tmp; } int -coap_remove_async(coap_context_t *context, coap_tid_t id, +coap_remove_async(coap_context_t *context, coap_tid_t id, coap_async_state_t **s) { coap_async_state_t *tmp = coap_find_async(context, id); @@ -89,11 +89,11 @@ coap_remove_async(coap_context_t *context, coap_tid_t id, return tmp != NULL; } -void +void coap_free_async(coap_async_state_t *s) { if (s && (s->flags & COAP_ASYNC_RELEASE_DATA) != 0) coap_free(s->appdata); - coap_free(s); + coap_free(s); } #else diff --git a/src/debug.c b/src/debug.c index 4539af5d62..d1b96f33fd 100644 --- a/src/debug.c +++ b/src/debug.c @@ -7,6 +7,7 @@ */ #include "coap_config.h" +#include "coap_posix_io.h" #if defined(HAVE_STRNLEN) && defined(__GNUC__) && !defined(_GNU_SOURCE) #define _GNU_SOURCE 1 @@ -42,7 +43,7 @@ #include "net/ip/uip-debug.h" #endif -static coap_log_t maxlog = LOG_WARNING; /* default maximum log level */ +static coap_log_t maxlog = LOG_DEBUG; /* default maximum log level */ const char *coap_package_name(void) { return PACKAGE_NAME; @@ -476,7 +477,7 @@ coap_show_pdu(const coap_pdu_t *pdu) { #endif /* NDEBUG */ void -coap_log_impl(coap_log_t level, const char *format, ...) { +coap_log_impl(const char *file, int line, coap_log_t level, const char *format, ...) { char timebuf[32]; coap_tick_t now; va_list ap; @@ -485,7 +486,8 @@ coap_log_impl(coap_log_t level, const char *format, ...) { if (maxlog < level) return; - log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD; + //log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD; + log_fd = stderr; coap_ticks(&now); if (print_timestamp(timebuf,sizeof(timebuf), now)) diff --git a/src/mem.c b/src/mem.c deleted file mode 100644 index b44aa62fdc..0000000000 --- a/src/mem.c +++ /dev/null @@ -1,43 +0,0 @@ -/* mem.c -- CoAP memory handling - * - * Copyright (C) 2014--2015 Olaf Bergmann - * - * This file is part of the CoAP library libcoap. Please see - * README for terms of use. - */ - - -#include "coap_config.h" -#include "mem.h" -#include "debug.h" - -#ifdef HAVE_ASSERT_H -#include -#else /* HAVE_ASSERT_H */ -#define assert(...) -#endif /* HAVE_ASSERT_H */ - -#ifdef HAVE_MALLOC -#include - -void -coap_memory_init(void) { -} - -#ifdef __GNUC__ -#define UNUSED_PARAM __attribute__((unused)) -#else -#define UNUSED_PARAM -#endif /* __GNUC__ */ - -void * -coap_malloc_type(coap_memory_tag_t type UNUSED_PARAM, size_t size) { - return malloc(size); -} - -void -coap_free_type(coap_memory_tag_t type UNUSED_PARAM, void *p) { - free(p); -} - -#endif /* HAVE_MALLOC */ diff --git a/src/net.c b/src/net.c index 17f9f1f5de..9fd790740c 100644 --- a/src/net.c +++ b/src/net.c @@ -109,8 +109,6 @@ /** creates a Qx.FRAC_BITS from COAP_DEFAULT_ACK_TIMEOUT */ #define ACK_TIMEOUT Q(FRAC_BITS, COAP_DEFAULT_ACK_TIMEOUT) -coap_time_t clock_offset; - unsigned int coap_adjust_basetime(coap_context_t *ctx, coap_tick_t now) { unsigned int result = 0; @@ -128,16 +126,16 @@ coap_adjust_basetime(coap_context_t *ctx, coap_tick_t now) { coap_queue_t *q = ctx->sendqueue; coap_tick_t t = 0; - while (q && (t + q->t < (coap_tick_t)delta)) { - t += q->t; - q->t = 0; - result++; - q = q->next; + while (q && (t + q->t < (coap_tick_t) delta)) { + t += q->t; + q->t = 0; + result++; + q = q->next; } /* finally adjust the first element that has not expired */ if (q) { - q->t = (coap_tick_t)delta - t; + q->t = (coap_tick_t) delta - t; } } } @@ -151,11 +149,11 @@ coap_adjust_basetime(coap_context_t *ctx, coap_tick_t now) { int coap_insert_node(coap_queue_t **queue, coap_queue_t *node) { coap_queue_t *p, *q; - if ( !queue || !node ) + if (!queue || !node) return 0; /* set queue head if empty */ - if ( !*queue ) { + if (!*queue) { *queue = node; return 1; } @@ -165,20 +163,20 @@ coap_insert_node(coap_queue_t **queue, coap_queue_t *node) { if (node->t < q->t) { node->next = q; *queue = node; - q->t -= node->t; /* make q->t relative to node->t */ + q->t -= node->t; /* make q->t relative to node->t */ return 1; } /* search for right place to insert */ do { - node->t -= q->t; /* make node-> relative to q->t */ + node->t -= q->t; /* make node-> relative to q->t */ p = q; q = q->next; } while (q && q->t <= node->t); /* insert new item */ if (q) { - q->t -= node->t; /* make q->t relative to node->t */ + q->t -= node->t; /* make q->t relative to node->t */ } node->next = q; p->next = node; @@ -187,7 +185,7 @@ coap_insert_node(coap_queue_t **queue, coap_queue_t *node) { int coap_delete_node(coap_queue_t *node) { - if ( !node ) + if (!node) return 0; coap_delete_pdu(node->pdu); @@ -198,19 +196,19 @@ coap_delete_node(coap_queue_t *node) { void coap_delete_all(coap_queue_t *queue) { - if ( !queue ) + if (!queue) return; - coap_delete_all( queue->next ); - coap_delete_node( queue ); + coap_delete_all(queue->next); + coap_delete_node(queue); } coap_queue_t * coap_new_node(void) { coap_queue_t *node; - node = (coap_queue_t *)coap_malloc_type(COAP_NODE, sizeof(coap_queue_t)); + node = (coap_queue_t *) coap_malloc_type(COAP_NODE, sizeof(coap_queue_t)); - if ( ! node ) { + if (!node) { #ifndef NDEBUG coap_log(LOG_WARNING, "coap_new_node: malloc\n"); #endif @@ -222,18 +220,18 @@ coap_new_node(void) { } coap_queue_t * -coap_peek_next( coap_context_t *context ) { - if ( !context || !context->sendqueue ) +coap_peek_next(coap_context_t *context) { + if (!context || !context->sendqueue) return NULL; return context->sendqueue; } coap_queue_t * -coap_pop_next( coap_context_t *context ) { +coap_pop_next(coap_context_t *context) { coap_queue_t *next; - if ( !context || !context->sendqueue ) + if (!context || !context->sendqueue) return NULL; next = context->sendqueue; @@ -260,7 +258,7 @@ is_wkc(coap_key_t k) { static unsigned char _initialized = 0; if (!_initialized) { _initialized = coap_hash_path((unsigned char *)COAP_DEFAULT_URI_WELLKNOWN, - sizeof(COAP_DEFAULT_URI_WELLKNOWN) - 1, wkc); + sizeof(COAP_DEFAULT_URI_WELLKNOWN) - 1, wkc); } return memcmp(k, wkc, sizeof(coap_key_t)) == 0; } @@ -269,10 +267,7 @@ is_wkc(coap_key_t k) { coap_context_t * coap_new_context(void) { - coap_context_t *c = coap_malloc_type(COAP_CONTEXT, sizeof( coap_context_t ) ); - coap_clock_init(); - - prng_init(clock_offset); + coap_context_t *c = coap_malloc_type(COAP_CONTEXT, sizeof(coap_context_t)); if (!c) { coap_log(LOG_EMERG, "coap_init: malloc:\n"); @@ -282,7 +277,7 @@ coap_new_context(void) { memset(c, 0, sizeof(coap_context_t)); /* initialize message id */ - prng((unsigned char *)&c->message_id, sizeof(unsigned short)); + prng((unsigned char * )&c->message_id, sizeof(unsigned short)); /* register the critical options that we know */ coap_register_option(c, COAP_OPTION_IF_MATCH); @@ -300,15 +295,6 @@ coap_new_context(void) { #ifdef WITH_LWIP c->endpoint->context = c; #endif -#ifdef WITH_POSIX - c->sockfd = c->endpoint->handle.fd; -#endif /* WITH_POSIX */ - -//#if defined(WITH_POSIX) || defined(WITH_CONTIKI) || defined(ST_NODE) - c->network_send = coap_network_send; - c->network_read = coap_network_read; - c->network_peek = coap_network_peek; -//#endif /* WITH_POSIX or WITH_CONTIKI */ return c; } @@ -333,9 +319,8 @@ coap_free_context(coap_context_t *context) { } int -coap_option_check_critical(coap_context_t *ctx, - coap_pdu_t *pdu, - coap_opt_filter_t unknown) { +coap_option_check_critical(coap_context_t *ctx, coap_pdu_t *pdu, + coap_opt_filter_t unknown) { coap_opt_iterator_t opt_iter; int ok = 1; @@ -350,8 +335,8 @@ coap_option_check_critical(coap_context_t *ctx, * the largest known option, we know that everything beyond is * bad. */ - if (opt_iter.type & 0x01 && - coap_option_getb(ctx->known_options, opt_iter.type) < 1) { + if (opt_iter.type & 0x01 + && coap_option_getb(ctx->known_options, opt_iter.type) < 1) { debug("unknown critical option %d\n", opt_iter.type); ok = 0; @@ -360,7 +345,7 @@ coap_option_check_critical(coap_context_t *ctx, * coap_option_setb() will return -1 and we are safe to leave * this loop. */ if (coap_option_setb(unknown, opt_iter.type) == -1) - break; + break; } } @@ -369,7 +354,7 @@ coap_option_check_critical(coap_context_t *ctx, void coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, - coap_tid_t *id) { + coap_tid_t *id) { coap_key_t h; memset(h, 0, sizeof(coap_key_t)); @@ -378,44 +363,42 @@ coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, #ifdef WITH_POSIX switch (peer->addr.sa.sa_family) { - case AF_INET: + case AF_INET: coap_hash((const unsigned char *)&peer->addr.sin.sin_port, - sizeof(peer->addr.sin.sin_port), h); + sizeof(peer->addr.sin.sin_port), h); coap_hash((const unsigned char *)&peer->addr.sin.sin_addr, - sizeof(peer->addr.sin.sin_addr), h); + sizeof(peer->addr.sin.sin_addr), h); break; - case AF_INET6: + case AF_INET6: coap_hash((const unsigned char *)&peer->addr.sin6.sin6_port, - sizeof(peer->addr.sin6.sin6_port), h); + sizeof(peer->addr.sin6.sin6_port), h); coap_hash((const unsigned char *)&peer->addr.sin6.sin6_addr, - sizeof(peer->addr.sin6.sin6_addr), h); + sizeof(peer->addr.sin6.sin6_addr), h); break; - default: + default: return; } #endif #if defined(WITH_LWIP) || defined(WITH_CONTIKI) || defined(ST_NODE) - /* FIXME: with lwip, we can do better */ - coap_hash((const unsigned char *)&peer->port, sizeof(peer->port), h); - coap_hash((const unsigned char *)&peer->addr, sizeof(peer->addr), h); + /* FIXME: with lwip, we can do better */ + coap_hash((const unsigned char * )&peer->port, sizeof(peer->port), h); + coap_hash((const unsigned char * )&peer->addr, sizeof(peer->addr), h); #endif /* WITH_LWIP || WITH_CONTIKI */ - coap_hash((const unsigned char *)&pdu->hdr->id, sizeof(unsigned short), h); + coap_hash((const unsigned char * )&pdu->hdr->id, sizeof(unsigned short), h); *id = (((h[0] << 8) | h[1]) ^ ((h[2] << 8) | h[3])) & INT_MAX; } coap_tid_t -coap_send_ack(coap_context_t *context, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - coap_pdu_t *request) { +coap_send_ack(coap_context_t *context, const coap_endpoint_t *local_interface, + const coap_address_t *dst, coap_pdu_t *request) { coap_pdu_t *response; coap_tid_t result = COAP_INVALID_TID; if (request && request->hdr->type == COAP_MESSAGE_CON) { response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->hdr->id, - sizeof(coap_pdu_t)); + sizeof(coap_pdu_t)); if (response) { result = coap_send(context, local_interface, dst, response); coap_delete_pdu(response); @@ -424,27 +407,25 @@ coap_send_ack(coap_context_t *context, return result; } -#if defined(WITH_POSIX) || defined(WITH_CONTIKI) -static coap_tid_t -coap_send_impl(coap_context_t *context, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - coap_pdu_t *pdu) { +coap_tid_t +coap_send(coap_context_t *context, const coap_endpoint_t *local_interface, + const coap_address_t *dst, coap_pdu_t *pdu) { + ssize_t bytes_written; coap_tid_t id = COAP_INVALID_TID; - if ( !context || !dst || !pdu ) + if (!context || !dst || !pdu) return id; /* Do not send error responses for requests that were received via * IP multicast. */ if (coap_is_mcast(&local_interface->addr) && - COAP_RESPONSE_CLASS(pdu->hdr->code) > 2) { + COAP_RESPONSE_CLASS(pdu->hdr->code) > 2) { return COAP_DROPPED_RESPONSE; } - bytes_written = context->network_send(context, local_interface, dst, - (unsigned char *)pdu->hdr, pdu->length); + bytes_written = local_interface->network_send(context, local_interface, dst, + pdu); if (bytes_written >= 0) { coap_transaction_id(dst, pdu, &id); @@ -454,28 +435,12 @@ coap_send_impl(coap_context_t *context, return id; } -#endif /* WITH_POSIX */ - -coap_tid_t coap_send_impl(coap_context_t *context, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - coap_pdu_t *pdu); - -coap_tid_t -coap_send(coap_context_t *context, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - coap_pdu_t *pdu) { - return coap_send_impl(context, local_interface, dst, pdu); -} coap_tid_t -coap_send_error(coap_context_t *context, - coap_pdu_t *request, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - unsigned char code, - coap_opt_filter_t opts) { +coap_send_error(coap_context_t *context, coap_pdu_t *request, + const coap_endpoint_t *local_interface, + const coap_address_t *dst, unsigned char code, + coap_opt_filter_t opts) { coap_pdu_t *response; coap_tid_t result = COAP_INVALID_TID; @@ -493,10 +458,9 @@ coap_send_error(coap_context_t *context, coap_tid_t coap_send_message_type(coap_context_t *context, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - coap_pdu_t *request, - unsigned char type) { + const coap_endpoint_t *local_interface, + const coap_address_t *dst, coap_pdu_t *request, + unsigned char type) { coap_pdu_t *response; coap_tid_t result = COAP_INVALID_TID; @@ -549,9 +513,8 @@ calc_timeout(unsigned char r) { coap_tid_t coap_send_confirmed(coap_context_t *context, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - coap_pdu_t *pdu) { + const coap_endpoint_t *local_interface, + const coap_address_t *dst, coap_pdu_t *pdu) { coap_queue_t *node; coap_tick_t now; unsigned char r; @@ -562,14 +525,14 @@ coap_send_confirmed(coap_context_t *context, return COAP_INVALID_TID; } - node->id = coap_send_impl(context, local_interface, dst, pdu); + node->id = coap_send(context, local_interface, dst, pdu); if (COAP_INVALID_TID == node->id) { debug("coap_send_confirmed: error sending pdu\n"); coap_free_type(COAP_NODE, node); return COAP_INVALID_TID; } - prng((unsigned char *)&r,sizeof(r)); + prng((unsigned char * )&r, sizeof(r)); /* add timeout in range [ACK_TIMEOUT...ACK_TIMEOUT * ACK_RANDOM_FACTOR] */ node->timeout = calc_timeout(r); @@ -604,11 +567,11 @@ coap_send_confirmed(coap_context_t *context, #endif #ifdef WITH_CONTIKI - { /* (re-)initialize retransmission timer */ + { /* (re-)initialize retransmission timer */ coap_queue_t *nextpdu; nextpdu = coap_peek_next(context); - assert(nextpdu); /* we have just inserted a node */ + assert(nextpdu); /* we have just inserted a node */ /* must set timer within the context of the retransmit process */ PROCESS_CONTEXT_BEGIN(&coap_retransmit_process); @@ -635,11 +598,10 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) { coap_retransmittimer_restart(context); #endif - debug("** retransmission #%d of transaction %d\n", - node->retransmit_cnt, node->id); + debug("** retransmission #%d of transaction %d\n", node->retransmit_cnt, + node->id); - node->id = coap_send_impl(context, &node->local_if, - &node->remote, node->pdu); + node->id = coap_send(context, &node->local_if, &node->remote, node->pdu); debug("** done (%d)\n", node->id); @@ -654,7 +616,7 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) { #ifndef WITHOUT_OBSERVE /* Check if subscriptions exist that should be canceled after - COAP_MAX_NOTIFY_FAILURES */ + COAP_MAX_NOTIFY_FAILURES */ if (node->pdu->hdr->code >= 64) { str token = { 0, NULL }; @@ -666,21 +628,22 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) { #endif /* WITHOUT_OBSERVE */ /* And finally delete the node */ - coap_delete_node( node ); + coap_delete_node(node); return COAP_INVALID_TID; } -void coap_dispatch(coap_context_t *context, coap_queue_t *rcvd); +void +coap_dispatch(coap_context_t *context, coap_queue_t *rcvd); int coap_read(coap_context_t *ctx, coap_endpoint_t *endpoint) { ssize_t bytes_read = -1; coap_packet_t *packet; - int result = -1; /* the value to be returned */ + int result = -1; /* the value to be returned */ - bytes_read = ctx->network_read(endpoint, &packet); + bytes_read = endpoint->network_read(endpoint, &packet); - if ( bytes_read < 0 ) { + if (bytes_read < 0) { //warn("coap_read: recvfrom"); } else { result = coap_handle_message(ctx, packet); @@ -691,28 +654,30 @@ coap_read(coap_context_t *ctx, coap_endpoint_t *endpoint) { } int -coap_handle_message(coap_context_t *ctx, - coap_packet_t *packet) { - /* const coap_address_t *remote, */ - /* unsigned char *msg, size_t msg_len) { */ +coap_handle_message(coap_context_t *ctx, coap_packet_t *packet) { + /* const coap_address_t *remote, */ + /* unsigned char *msg, size_t msg_len) { */ unsigned char *msg; size_t msg_len; coap_queue_t *node; /* the negated result code */ - enum result_t { RESULT_OK, RESULT_ERR_EARLY, RESULT_ERR }; + enum result_t { + RESULT_OK, RESULT_ERR_EARLY, RESULT_ERR + }; int result = RESULT_ERR_EARLY; coap_packet_get_memmapped(packet, &msg, &msg_len); if (msg_len < sizeof(coap_hdr_t)) { - debug("coap_handle_message: discarded invalid frame\n" ); + debug("coap_handle_message: discarded invalid frame\n"); goto error_early; } /* check version identifier */ if (((*msg >> 6) & 0x03) != COAP_DEFAULT_VERSION) { - debug("coap_handle_message: unknown protocol version %d\n", (*msg >> 6) & 0x03); + debug("coap_handle_message: unknown protocol version %d\n", + (*msg >> 6) & 0x03); goto error_early; } @@ -756,13 +721,13 @@ coap_handle_message(coap_context_t *ctx, #define INET6_ADDRSTRLEN 40 #endif /** @FIXME get debug to work again ** - unsigned char addr[INET6_ADDRSTRLEN+8], localaddr[INET6_ADDRSTRLEN+8]; - if (coap_print_addr(remote, addr, INET6_ADDRSTRLEN+8) && - coap_print_addr(&packet->dst, localaddr, INET6_ADDRSTRLEN+8) ) - debug("** received %d bytes from %s on interface %s:\n", - (int)msg_len, addr, localaddr); + unsigned char addr[INET6_ADDRSTRLEN+8], localaddr[INET6_ADDRSTRLEN+8]; + if (coap_print_addr(remote, addr, INET6_ADDRSTRLEN+8) && + coap_print_addr(&packet->dst, localaddr, INET6_ADDRSTRLEN+8) ) + debug("** received %d bytes from %s on interface %s:\n", + (int)msg_len, addr, localaddr); - */ + */ //coap_show_pdu(node->pdu); } #endif @@ -770,28 +735,28 @@ coap_handle_message(coap_context_t *ctx, coap_dispatch(ctx, node); return -RESULT_OK; - error: + error: /* FIXME: send back RST? */ coap_delete_node(node); return -result; - error_early: - return -result; + error_early: return -result; } int -coap_remove_from_queue(coap_queue_t **queue, coap_tid_t id, coap_queue_t **node) { +coap_remove_from_queue(coap_queue_t **queue, coap_tid_t id, + coap_queue_t **node) { coap_queue_t *p, *q; - if ( !queue || !*queue) + if (!queue || !*queue) return 0; /* replace queue head if PDU's time is less than head's time */ - if ( id == (*queue)->id ) { /* found transaction */ + if (id == (*queue)->id) { /* found transaction */ *node = *queue; *queue = (*queue)->next; - if (*queue) { /* adjust relative time of new queue head */ + if (*queue) { /* adjust relative time of new queue head */ (*queue)->t += (*node)->t; } (*node)->next = NULL; @@ -805,11 +770,11 @@ coap_remove_from_queue(coap_queue_t **queue, coap_tid_t id, coap_queue_t **node) do { p = q; q = q->next; - } while ( q && id != q->id ); + } while (q && id != q->id); - if ( q ) { /* found transaction */ + if (q) { /* found transaction */ p->next = q->next; - if (p->next) { /* must update relative time of p->next */ + if (p->next) { /* must update relative time of p->next */ p->next->t += q->t; } q->next = NULL; @@ -824,23 +789,22 @@ coap_remove_from_queue(coap_queue_t **queue, coap_tid_t id, coap_queue_t **node) } static inline int -token_match(const unsigned char *a, size_t alen, - const unsigned char *b, size_t blen) { +token_match(const unsigned char *a, size_t alen, const unsigned char *b, + size_t blen) { return alen == blen && (alen == 0 || memcmp(a, b, alen) == 0); } void coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst, - const unsigned char *token, size_t token_length) { + const unsigned char *token, size_t token_length) { /* cancel all messages in sendqueue that are for dst * and use the specified token */ coap_queue_t *p, *q; - while (context->sendqueue && - coap_address_equals(dst, &context->sendqueue->remote) && - token_match(token, token_length, - context->sendqueue->pdu->hdr->token, - context->sendqueue->pdu->hdr->token_length)) { + while (context->sendqueue + && coap_address_equals(dst, &context->sendqueue->remote) + && token_match(token, token_length, context->sendqueue->pdu->hdr->token, + context->sendqueue->pdu->hdr->token_length)) { q = context->sendqueue; context->sendqueue = q->next; debug("**** removed transaction %d\n", q->id); @@ -855,9 +819,9 @@ coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst, /* when q is not NULL, it does not match (dst, token), so we can skip it */ while (q) { - if (coap_address_equals(dst, &q->remote) && - token_match(token, token_length, - q->pdu->hdr->token, q->pdu->hdr->token_length)) { + if (coap_address_equals(dst, &q->remote) + && token_match(token, token_length, q->pdu->hdr->token, + q->pdu->hdr->token_length)) { p->next = q->next; debug("**** removed transaction %d\n", q->id); coap_delete_node(q); @@ -879,13 +843,13 @@ coap_find_transaction(coap_queue_t *queue, coap_tid_t id) { coap_pdu_t * coap_new_error_response(coap_pdu_t *request, unsigned char code, - coap_opt_filter_t opts) { + coap_opt_filter_t opts) { coap_opt_iterator_t opt_iter; coap_pdu_t *response; size_t size = sizeof(coap_hdr_t) + request->hdr->token_length; int type; coap_opt_t *option; - unsigned short opt_type = 0; /* used for calculating delta-storage */ + unsigned short opt_type = 0; /* used for calculating delta-storage */ #if COAP_ERROR_PHRASE_LENGTH > 0 char *phrase = coap_response_phrase(code); @@ -898,9 +862,9 @@ coap_new_error_response(coap_pdu_t *request, unsigned char code, assert(request); /* cannot send ACK if original request was not confirmable */ - type = request->hdr->type == COAP_MESSAGE_CON - ? COAP_MESSAGE_ACK - : COAP_MESSAGE_NON; + type = request->hdr->type == COAP_MESSAGE_CON ? + COAP_MESSAGE_ACK : + COAP_MESSAGE_NON; /* Estimate how much space we need for options to copy from * request. We always need the Token, for 4.02 the unknown critical @@ -910,10 +874,10 @@ coap_new_error_response(coap_pdu_t *request, unsigned char code, coap_option_iterator_init(request, &opt_iter, opts); /* Add size of each unknown critical option. As known critical - options as well as elective options are not copied, the delta - value might grow. + options as well as elective options are not copied, the delta + value might grow. */ - while((option = coap_option_next(&opt_iter))) { + while ((option = coap_option_next(&opt_iter))) { unsigned short delta = opt_iter.type - opt_type; /* calculate space required to encode (opt_iter.type - opt_type) */ if (delta < 13) { @@ -929,14 +893,14 @@ coap_new_error_response(coap_pdu_t *request, unsigned char code, size += coap_opt_length(option); switch (*option & 0x0f) { - case 0x0e: - size++; - /* fall through */ - case 0x0d: - size++; - break; - default: - ; + case 0x0e: + size++; + /* fall through */ + case 0x0d: + size++; + break; + default: + ; } opt_type = opt_iter.type; @@ -947,7 +911,7 @@ coap_new_error_response(coap_pdu_t *request, unsigned char code, if (response) { /* copy token */ if (!coap_add_token(response, request->hdr->token_length, - request->hdr->token)) { + request->hdr->token)) { debug("cannot add token to error response\n"); coap_delete_pdu(response); return NULL; @@ -955,15 +919,14 @@ coap_new_error_response(coap_pdu_t *request, unsigned char code, /* copy all options */ coap_option_iterator_init(request, &opt_iter, opts); - while((option = coap_option_next(&opt_iter))) - coap_add_option(response, opt_iter.type, - COAP_OPT_LENGTH(option), - COAP_OPT_VALUE(option)); + while ((option = coap_option_next(&opt_iter))) + coap_add_option(response, opt_iter.type, COAP_OPT_LENGTH(option), + COAP_OPT_VALUE(option)); #if COAP_ERROR_PHRASE_LENGTH > 0 /* note that diagnostic messages do not need a Content-Format option. */ if (phrase) - coap_add_data(response, strlen(phrase), (unsigned char *)phrase); + coap_add_data(response, strlen(phrase), (unsigned char *) phrase); #endif } @@ -979,8 +942,8 @@ get_wkc_len(coap_context_t *context, coap_opt_t *query_filter) { unsigned char buf[1]; size_t len = 0; - if (coap_print_wellknown(context, buf, &len, UINT_MAX, query_filter) - & COAP_PRINT_STATUS_ERROR) { + if (coap_print_wellknown(context, buf, &len, UINT_MAX, + query_filter) & COAP_PRINT_STATUS_ERROR) { warn("cannot determine length of /.well-known/core\n"); return 0; } @@ -999,22 +962,23 @@ coap_wellknown_response(coap_context_t *context, coap_pdu_t *request) { size_t len, wkc_len; unsigned char buf[2]; int result = 0; - int need_block2 = 0; /* set to 1 if Block2 option is required */ + int need_block2 = 0; /* set to 1 if Block2 option is required */ coap_block_t block; coap_opt_t *query_filter; size_t offset = 0; - resp = coap_pdu_init(request->hdr->type == COAP_MESSAGE_CON - ? COAP_MESSAGE_ACK - : COAP_MESSAGE_NON, - COAP_RESPONSE_CODE(205), - request->hdr->id, COAP_MAX_PDU_SIZE); + resp = coap_pdu_init(request->hdr->type == COAP_MESSAGE_CON ? + COAP_MESSAGE_ACK : + COAP_MESSAGE_NON, + COAP_RESPONSE_CODE(205), request->hdr->id, + COAP_MAX_PDU_SIZE); if (!resp) { debug("coap_wellknown_response: cannot create PDU\n"); return NULL; } - if (!coap_add_token(resp, request->hdr->token_length, request->hdr->token)) { + if (!coap_add_token(resp, request->hdr->token_length, + request->hdr->token)) { debug("coap_wellknown_response: cannot add token\n"); goto error; } @@ -1026,7 +990,7 @@ coap_wellknown_response(coap_context_t *context, coap_pdu_t *request) { if (coap_get_block(request, COAP_OPTION_BLOCK2, &block)) { debug("create block\n"); offset = block.num << (block.szx + 4); - if (block.szx > 6) { /* invalid, MUST lead to 4.00 Bad Request */ + if (block.szx > 6) { /* invalid, MUST lead to 4.00 Bad Request */ resp->hdr->code = COAP_RESPONSE_CODE(400); return resp; } else if (block.szx > COAP_MAX_BLOCK_SZX) { @@ -1041,33 +1005,34 @@ coap_wellknown_response(coap_context_t *context, coap_pdu_t *request) { * and data. We do this before adding the Content-Format option to * avoid sending error responses with that option but no actual * content. */ - if (resp->max_size <= (size_t)resp->length + 3) { + if (resp->max_size <= (size_t) resp->length + 3) { debug("coap_wellknown_response: insufficient storage space\n"); goto error; } /* Add Content-Format. As we have checked for available storage, * nothing should go wrong here. */ - assert(coap_encode_var_bytes(buf, - COAP_MEDIATYPE_APPLICATION_LINK_FORMAT) == 1); - coap_add_option(resp, COAP_OPTION_CONTENT_FORMAT, - coap_encode_var_bytes(buf, - COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), buf); + assert( + coap_encode_var_bytes(buf, COAP_MEDIATYPE_APPLICATION_LINK_FORMAT) == 1); + coap_add_option(resp, COAP_OPTION_CONTENT_FORMAT, coap_encode_var_bytes(buf, + COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), + buf); /* check if Block2 option is required even if not requested */ - if (!need_block2 && (resp->max_size - (size_t)resp->length < wkc_len)) { + if (!need_block2 && (resp->max_size - (size_t) resp->length < wkc_len)) { assert(resp->length <= resp->max_size); const size_t payloadlen = resp->max_size - resp->length; /* yes, need block-wise transfer */ block.num = 0; - block.m = 0; /* the M bit is set by coap_write_block_opt() */ + block.m = 0; /* the M bit is set by coap_write_block_opt() */ block.szx = COAP_MAX_BLOCK_SZX; while (payloadlen < SZX_TO_BYTES(block.szx)) { if (block.szx == 0) { - debug("coap_wellknown_response: message to small even for szx == 0\n"); - goto error; + debug( + "coap_wellknown_response: message to small even for szx == 0\n"); + goto error; } else { - block.szx--; + block.szx--; } } @@ -1085,11 +1050,12 @@ coap_wellknown_response(coap_context_t *context, coap_pdu_t *request) { /* Manually set payload of response to let print_wellknown() write, * into our buffer without copying data. */ - resp->data = (unsigned char *)resp->hdr + resp->length; + resp->data = (unsigned char *) resp->hdr + resp->length; *resp->data = COAP_PAYLOAD_START; resp->data++; resp->length++; - len = need_block2 ? SZX_TO_BYTES(block.szx) : resp->max_size - resp->length; + len = need_block2 ? + SZX_TO_BYTES(block.szx) : resp->max_size - resp->length; #ifndef ST_NODE result = coap_print_wellknown(context, resp->data, &len, offset, query_filter); @@ -1104,7 +1070,7 @@ coap_wellknown_response(coap_context_t *context, coap_pdu_t *request) { resp->length += COAP_PRINT_OUTPUT_LENGTH(result); return resp; - error: + error: /* set error code 5.03 and remove all options and data from response */ resp->hdr->code = COAP_RESPONSE_CODE(503); resp->length = sizeof(coap_hdr_t) + resp->hdr->token_length; @@ -1121,11 +1087,11 @@ coap_wellknown_response(coap_context_t *context, coap_pdu_t *request) { * This function returns @c 0 when the token is unknown with this * peer, or a value greater than zero otherwise. */ -/*static*/ int +/*static*/int coap_cancel(coap_context_t *context, const coap_queue_t *sent) { #ifndef WITHOUT_OBSERVE str token = { 0, NULL }; - int num_cancelled = 0; /* the number of observers cancelled */ + int num_cancelled = 0; /* the number of observers cancelled */ /* remove observer for this resource, if any * get token from sent and try to find a matching resource. Uh! @@ -1148,7 +1114,7 @@ coap_cancel(coap_context_t *context, const coap_queue_t *sent) { * Checks for No-Response option in given @p request and * returns @c 1 if @p response should be suppressed * according to draft-tcs-coap-no-response-option-11.txt. - * + * * The value of the No-Response option is encoded as * follows: * @@ -1171,7 +1137,7 @@ coap_cancel(coap_context_t *context, const coap_queue_t *sent) { * @param response The response that is potentially suppressed. * This parameter must not be NULL. * @return @c 1 if the response code matches the No-Response option, - * or @c 0, otherwise. + * or @c 0, otherwise. */ static inline int no_response(coap_pdu_t *request, coap_pdu_t *response) { @@ -1185,11 +1151,12 @@ no_response(coap_pdu_t *request, coap_pdu_t *response) { nores = coap_check_option(request, COAP_OPTION_NORESPONSE, &opt_iter); if (nores) { - val = coap_decode_var_bytes(coap_opt_value(nores), coap_opt_length(nores)); + val = coap_decode_var_bytes(coap_opt_value(nores), + coap_opt_length(nores)); } return (COAP_RESPONSE_CLASS(response->hdr->code) > 0) - && (((1 << (COAP_RESPONSE_CLASS(response->hdr->code) - 1)) & val) > 0); + && (((1 << (COAP_RESPONSE_CLASS(response->hdr->code) - 1)) & val) > 0); } #define WANT_WKC(Pdu,Key) \ @@ -1214,34 +1181,37 @@ handle_request(coap_context_t *context, coap_queue_t *node) { * be the well-known URI. In that case, we generate a default * response, otherwise, we return 4.04 */ - switch(node->pdu->hdr->code) { + switch (node->pdu->hdr->code) { - case COAP_REQUEST_GET: - if (is_wkc(key)) { /* GET request for .well-known/core */ - info("create default response for %s\n", COAP_DEFAULT_URI_WELLKNOWN); - response = coap_wellknown_response(context, node->pdu); + case COAP_REQUEST_GET: + if (is_wkc(key)) { /* GET request for .well-known/core */ + info("create default response for %s\n", + COAP_DEFAULT_URI_WELLKNOWN); + response = coap_wellknown_response(context, node->pdu); - } else { /* GET request for any another resource, return 4.04 */ + } else { /* GET request for any another resource, return 4.04 */ - debug("GET for unknown resource 0x%02x%02x%02x%02x, return 4.04\n", - key[0], key[1], key[2], key[3]); - response = - coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(404), - opt_filter); - } - break; + debug("GET for unknown resource 0x%02x%02x%02x%02x, return 4.04\n", + key[0], key[1], key[2], key[3]); + response = coap_new_error_response(node->pdu, + COAP_RESPONSE_CODE(404), + opt_filter); + } + break; - default: /* any other request type */ + default: /* any other request type */ - debug("unhandled request for unknown resource 0x%02x%02x%02x%02x\r\n", - key[0], key[1], key[2], key[3]); + debug("unhandled request for unknown resource 0x%02x%02x%02x%02x\r\n", + key[0], key[1], key[2], key[3]); - response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), - opt_filter); + response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), + opt_filter); } - - if (response && !no_response(node->pdu, response) && coap_send(context, &node->local_if, - &node->remote, response) == COAP_INVALID_TID) { + + if (response + && !no_response(node->pdu, + response) && coap_send(context, &node->local_if, + &node->remote, response) == COAP_INVALID_TID) { warn("cannot send response for transaction %u\n", node->id); } coap_delete_pdu(response); @@ -1250,22 +1220,23 @@ handle_request(coap_context_t *context, coap_queue_t *node) { } /* the resource was found, check if there is a registered handler */ - if ((size_t)node->pdu->hdr->code - 1 < - sizeof(resource->handler)/sizeof(coap_method_handler_t)) + if ((size_t) node->pdu->hdr->code - 1 + < sizeof(resource->handler) / sizeof(coap_method_handler_t)) h = resource->handler[node->pdu->hdr->code - 1]; if (h) { - debug("call custom handler for resource 0x%02x%02x%02x%02x\n", - key[0], key[1], key[2], key[3]); - response = coap_pdu_init(node->pdu->hdr->type == COAP_MESSAGE_CON - ? COAP_MESSAGE_ACK - : COAP_MESSAGE_NON, - 0, node->pdu->hdr->id, COAP_MAX_PDU_SIZE); + debug("call custom handler for resource 0x%02x%02x%02x%02x\n", key[0], + key[1], key[2], key[3]); + response = coap_pdu_init(node->pdu->hdr->type == COAP_MESSAGE_CON ? + COAP_MESSAGE_ACK : + COAP_MESSAGE_NON, + 0, node->pdu->hdr->id, + COAP_MAX_PDU_SIZE); /* Implementation detail: coap_add_token() immediately returns 0 - if response == NULL */ + if response == NULL */ if (coap_add_token(response, node->pdu->hdr->token_length, - node->pdu->hdr->token)) { + node->pdu->hdr->token)) { str token = { node->pdu->hdr->token_length, node->pdu->hdr->token }; coap_opt_iterator_t opt_iter; coap_opt_t *observe = NULL; @@ -1273,56 +1244,59 @@ handle_request(coap_context_t *context, coap_queue_t *node) { /* check for Observe option */ if (resource->observable) { - observe = coap_check_option(node->pdu, COAP_OPTION_OBSERVE, &opt_iter); - if (observe) { - observe_action = - coap_decode_var_bytes(coap_opt_value(observe), - coap_opt_length(observe)); - - if ((observe_action & COAP_OBSERVE_CANCEL) == 0) { - coap_subscription_t *subscription; - - coap_log(LOG_DEBUG, "create new subscription\n"); - subscription = coap_add_observer(resource, &node->local_if, - &node->remote, &token); - if (subscription) { - subscription->non = node->pdu->hdr->type == COAP_MESSAGE_NON; - coap_touch_observer(context, &node->remote, &token); - } - } - } + observe = coap_check_option(node->pdu, COAP_OPTION_OBSERVE, + &opt_iter); + if (observe) { + observe_action = coap_decode_var_bytes(coap_opt_value(observe), + coap_opt_length(observe)); + + if ((observe_action & COAP_OBSERVE_CANCEL) == 0) { + coap_subscription_t *subscription; + + coap_log(LOG_DEBUG, "create new subscription\n"); + subscription = coap_add_observer(resource, &node->local_if, + &node->remote, &token); + if (subscription) { + subscription->non = node->pdu->hdr->type == COAP_MESSAGE_NON; + coap_touch_observer(context, &node->remote, &token); + } + } + } } - h(context, resource, &node->local_if, &node->remote, - node->pdu, &token, response); + h(context, resource, &node->local_if, &node->remote, node->pdu, &token, + response); if (!no_response(node->pdu, response)) { - if (observe && ((COAP_RESPONSE_CLASS(response->hdr->code) > 2) - || ((observe_action & COAP_OBSERVE_CANCEL) != 0))) { - coap_log(LOG_DEBUG, "removed observer"); - coap_delete_observer(resource, &node->remote, &token); - } - - /* If original request contained a token, and the registered - * application handler made no changes to the response, then - * this is an empty ACK with a token, which is a malformed - * PDU */ - if ((response->hdr->type == COAP_MESSAGE_ACK) - && (response->hdr->code == 0)) { - /* Remove token from otherwise-empty acknowledgment PDU */ - response->hdr->token_length = 0; - response->length = sizeof(coap_hdr_t); - } - - if (response->hdr->type != COAP_MESSAGE_NON || - (response->hdr->code >= 64 - && !coap_mcast_interface(&node->local_if))) { - - if (coap_send(context, &node->local_if, - &node->remote, response) == COAP_INVALID_TID) { - debug("cannot send response for message %d\n", node->pdu->hdr->id); - } - } + // Cancel subscription if handler returned and error or the client + // canceled subscription explicitly + if (observe && ((COAP_RESPONSE_CLASS(response->hdr->code) > 2) + || ((observe_action & COAP_OBSERVE_CANCEL) != 0))) { + coap_log(LOG_DEBUG, "removed observer"); + coap_delete_observer(resource, &node->remote, &token); + } + + /* If original request contained a token, and the registered + * application handler made no changes to the response, then + * this is an empty ACK with a token, which is a malformed + * PDU */ + if ((response->hdr->type == COAP_MESSAGE_ACK) + && (response->hdr->code == 0)) { + /* Remove token from otherwise-empty acknowledgment PDU */ + response->hdr->token_length = 0; + response->length = sizeof(coap_hdr_t); + } + + if (response->hdr->type != COAP_MESSAGE_NON + || (response->hdr->code >= 64 + && !coap_mcast_interface(&node->local_if))) { + + if (coap_send(context, &node->local_if, &node->remote, + response) == COAP_INVALID_TID) { + debug("cannot send response for message %d\n", + node->pdu->hdr->id); + } + } } coap_delete_pdu(response); } else { @@ -1332,22 +1306,23 @@ handle_request(coap_context_t *context, coap_queue_t *node) { if (WANT_WKC(node->pdu, key)) { debug("create default response for %s\n", COAP_DEFAULT_URI_WELLKNOWN); response = coap_wellknown_response(context, node->pdu); - debug("have wellknown response %p\n", (void *)response); + debug("have wellknown response %p\n", (void * )response); } else response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), - opt_filter); + opt_filter); - if (!response || (coap_send(context, &node->local_if, &node->remote, - response) == COAP_INVALID_TID)) { + if (!response + || (coap_send(context, &node->local_if, &node->remote, response) + == COAP_INVALID_TID)) { debug("cannot send response for transaction %u\n", node->id); } coap_delete_pdu(response); } } -/*static inline */ void -handle_response(coap_context_t *context, - coap_queue_t *sent, coap_queue_t *rcvd) { +/*static inline */void +handle_response(coap_context_t *context, coap_queue_t *sent, + coap_queue_t *rcvd) { coap_send_ack(context, &rcvd->local_if, &rcvd->remote, rcvd->pdu); @@ -1355,24 +1330,23 @@ handle_response(coap_context_t *context, * been lost, so we need to stop retransmitting requests with the * same token. */ - coap_cancel_all_messages(context, &rcvd->remote, - rcvd->pdu->hdr->token, - rcvd->pdu->hdr->token_length); + coap_cancel_all_messages(context, &rcvd->remote, rcvd->pdu->hdr->token, + rcvd->pdu->hdr->token_length); /* Call application-specific reponse handler when available. */ if (context->response_handler) { - context->response_handler(context, &rcvd->local_if, - &rcvd->remote, sent ? sent->pdu : NULL, - rcvd->pdu, rcvd->id); + context->response_handler(context, &rcvd->local_if, &rcvd->remote, sent ? + sent->pdu : NULL, + rcvd->pdu, rcvd->id); } } -/*static inline */ int +/*static inline */int #ifdef __GNUC__ handle_locally(coap_context_t *context __attribute__ ((unused)), - coap_queue_t *node __attribute__ ((unused))) { + coap_queue_t *node __attribute__ ((unused))) { #else /* not a GCC */ -handle_locally(coap_context_t *context, coap_queue_t *node) { + handle_locally(coap_context_t *context, coap_queue_t *node) { #endif /* GCC */ /* this function can be used to check if node->pdu is really for us */ return 1; @@ -1397,95 +1371,97 @@ coap_dispatch(coap_context_t *context, coap_queue_t *rcvd) { /* } */ switch (rcvd->pdu->hdr->type) { - case COAP_MESSAGE_ACK: - /* find transaction in sendqueue to stop retransmission */ - coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent); - - if (rcvd->pdu->hdr->code == 0) - goto cleanup; - - /* FIXME: if sent code was >= 64 the message might have been a - * notification. Then, we must flag the observer to be alive - * by setting obs->fail_cnt = 0. */ - if (sent && COAP_RESPONSE_CLASS(sent->pdu->hdr->code) == 2) { - const str token = - { sent->pdu->hdr->token_length, sent->pdu->hdr->token }; - coap_touch_observer(context, &sent->remote, &token); - } - break; - - case COAP_MESSAGE_RST : - /* We have sent something the receiver disliked, so we remove - * not only the transaction but also the subscriptions we might - * have. */ + case COAP_MESSAGE_ACK: + /* find transaction in sendqueue to stop retransmission */ + coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent); + + if (rcvd->pdu->hdr->code == 0) + goto cleanup; + + /* FIXME: if sent code was >= 64 the message might have been a + * notification. Then, we must flag the observer to be alive + * by setting obs->fail_cnt = 0. */ + if (sent && COAP_RESPONSE_CLASS(sent->pdu->hdr->code) == 2) { + const str token = { sent->pdu->hdr->token_length, + sent->pdu->hdr->token }; + coap_touch_observer(context, &sent->remote, &token); + } + break; + + case COAP_MESSAGE_RST: + /* We have sent something the receiver disliked, so we remove + * not only the transaction but also the subscriptions we might + * have. */ #ifndef WITH_CONTIKI - coap_log(LOG_ALERT, "got RST for message %u\n", ntohs(rcvd->pdu->hdr->id)); + coap_log(LOG_ALERT, "got RST for message %u\n", + ntohs(rcvd->pdu->hdr->id)); #else /* WITH_CONTIKI */ - coap_log(LOG_ALERT, "got RST for message %u\n", uip_ntohs(rcvd->pdu->hdr->id)); + coap_log(LOG_ALERT, "got RST for message %u\n", uip_ntohs(rcvd->pdu->hdr->id)); #endif /* WITH_CONTIKI */ - /* find transaction in sendqueue to stop retransmission */ - coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent); - - if (sent) - coap_cancel(context, sent); - goto cleanup; - - case COAP_MESSAGE_NON : /* check for unknown critical options */ - if (coap_option_check_critical(context, rcvd->pdu, opt_filter) == 0) - goto cleanup; - break; - - case COAP_MESSAGE_CON : /* check for unknown critical options */ - if (coap_option_check_critical(context, rcvd->pdu, opt_filter) == 0) { - - /* FIXME: send response only if we have received a request. Otherwise, - * send RST. */ - response = - coap_new_error_response(rcvd->pdu, COAP_RESPONSE_CODE(402), opt_filter); - - if (!response) - warn("coap_dispatch: cannot create error reponse\n"); - else { - if (coap_send(context, &rcvd->local_if, &rcvd->remote, response) - == COAP_INVALID_TID) { - warn("coap_dispatch: error sending reponse\n"); - } - coap_delete_pdu(response); - } - - goto cleanup; - } - default: break; + /* find transaction in sendqueue to stop retransmission */ + coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent); + + if (sent) + coap_cancel(context, sent); + goto cleanup; + + case COAP_MESSAGE_NON: /* check for unknown critical options */ + if (coap_option_check_critical(context, rcvd->pdu, opt_filter) == 0) + goto cleanup; + break; + + case COAP_MESSAGE_CON: /* check for unknown critical options */ + if (coap_option_check_critical(context, rcvd->pdu, opt_filter) == 0) { + + /* FIXME: send response only if we have received a request. Otherwise, + * send RST. */ + response = coap_new_error_response(rcvd->pdu, + COAP_RESPONSE_CODE(402), + opt_filter); + + if (!response) + warn("coap_dispatch: cannot create error reponse\n"); + else { + if (coap_send(context, &rcvd->local_if, &rcvd->remote, + response) == COAP_INVALID_TID) { + warn("coap_dispatch: error sending reponse\n"); + } + coap_delete_pdu(response); + } + + goto cleanup; + } + default: + break; } /* Pass message to upper layer if a specific handler was * registered for a request that should be handled locally. */ if (handle_locally(context, rcvd)) { if (COAP_MESSAGE_IS_REQUEST(rcvd->pdu->hdr)) - handle_request(context, rcvd); + handle_request(context, rcvd); else if (COAP_MESSAGE_IS_RESPONSE(rcvd->pdu->hdr)) - handle_response(context, sent, rcvd); + handle_response(context, sent, rcvd); else { - debug("dropped message with invalid code (%d.%02d)\n", - COAP_RESPONSE_CLASS(rcvd->pdu->hdr->code), - rcvd->pdu->hdr->code & 0x1f); - - if (!coap_is_mcast(&rcvd->local_if.addr)) { - coap_send_message_type(context, &rcvd->local_if, &rcvd->remote, - rcvd->pdu, COAP_MESSAGE_RST); - } + debug("dropped message with invalid code (%d.%02d)\n", + COAP_RESPONSE_CLASS(rcvd->pdu->hdr->code), + rcvd->pdu->hdr->code & 0x1f); + + if (!coap_is_mcast(&rcvd->local_if.addr)) { + coap_send_message_type(context, &rcvd->local_if, &rcvd->remote, + rcvd->pdu, COAP_MESSAGE_RST); + } } } - cleanup: - coap_delete_node(sent); + cleanup: coap_delete_node(sent); coap_delete_node(rcvd); } } int -coap_can_exit( coap_context_t *context ) { +coap_can_exit(coap_context_t *context) { return !context || (context->sendqueue == NULL); } From e0bfe33892e116f6be932eb142c936b645af58bc Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Mon, 14 Sep 2015 15:58:37 +0200 Subject: [PATCH 65/69] Before rename --- client/client.c | 4 +- include/coap/address.h | 9 + include/coap/debug.h | 35 +++ include/coap/pdu.h | 4 + include/coap/uthash.h | 2 +- platform/coap_posix_io.c | 4 +- platform/coap_posix_io.h | 2 + src/coap_io.c | 573 --------------------------------------- src/debug.c | 504 ---------------------------------- src/net.c | 6 + src/resource.c | 2 +- 11 files changed, 62 insertions(+), 1083 deletions(-) delete mode 100644 src/coap_io.c delete mode 100644 src/debug.c diff --git a/client/client.c b/client/client.c index cda2e91bea..67833e744d 100644 --- a/client/client.c +++ b/client/client.c @@ -3,7 +3,7 @@ #include #include -#include "utils.h" +//#include "utils.h" //#include "clock.h" //#include "mbuf.h" @@ -417,7 +417,7 @@ void coap_client_init(coap_client_t *client, coap_context_t *ctx, coap_endpoint_ void coap_client_deinit(coap_client_t *client) { - UNUSED(client); + (void)client; //TODO: cancel subscriptions } diff --git a/include/coap/address.h b/include/coap/address.h index 2a1da28d90..2ef0847b50 100644 --- a/include/coap/address.h +++ b/include/coap/address.h @@ -94,4 +94,13 @@ coap_address(const char *address, unsigned short port, coap_address_t *result) { assert(result); return _coap_address_impl(address, port, result); } + +/** + * Returns size of a given address object. + */ +static inline int +coap_address_size(const coap_address_t *a) { + assert(a); + return _coap_address_size_impl(a); +} #endif /* _COAP_ADDRESS_H_ */ diff --git a/include/coap/debug.h b/include/coap/debug.h index 5248d03a5c..bec083c9f4 100644 --- a/include/coap/debug.h +++ b/include/coap/debug.h @@ -35,6 +35,32 @@ typedef enum { } coap_log_t; #endif +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/** Returns a textual description of the message type @p t. */ +static const char * +msg_type_string(uint8_t t) { + static const char * const types[] = { "CON", "NON", "ACK", "RST", "???" }; + + return types[min(t, sizeof(types)/sizeof(char *) - 1)]; +} + +/** Returns a textual description of the method or response code. */ +static const char * +msg_code_string(uint8_t c) { + static const char * const methods[] = { "0.00", "GET", "POST", "PUT", "DELETE", "PATCH" }; + static char buf[5]; + + if (c < sizeof(methods)/sizeof(char *)) { + return methods[c]; + } else { + snprintf(buf, sizeof(buf), "%u.%02u", c >> 5, c & 0x1f); + return buf; + } +} + /** Returns the current log level. */ coap_log_t coap_get_log_level(void); @@ -61,9 +87,18 @@ void coap_log_impl(const char *file, int line, coap_log_t level, const char *for #ifndef NDEBUG /* A set of convenience macros for common log levels. */ +#ifndef info #define info(...) coap_log(LOG_INFO, __VA_ARGS__) +#endif + +#ifndef warn #define warn(...) coap_log(LOG_WARNING, __VA_ARGS__) +#endif + +#ifndef debug #define debug(...) coap_log(LOG_DEBUG, __VA_ARGS__) +#endif + #define critical(...) coap_log(LOG_CRIT, __VA_ARGS__) #include "pdu.h" diff --git a/include/coap/pdu.h b/include/coap/pdu.h index 6159b11e93..4615865814 100644 --- a/include/coap/pdu.h +++ b/include/coap/pdu.h @@ -31,6 +31,10 @@ #define COAP_DEFAULT_PORT 5683 /* CoAP default UDP port */ #endif +#ifndef COAP_SECURE_PORT +#define COAP_SECURE_PORT 5684 /* CoAP DTLS-secured UDP port */ +#endif + #ifndef COAP_DEFAULT_MAX_AGE #define COAP_DEFAULT_MAX_AGE 60 /* default maximum object lifetime in seconds */ #endif diff --git a/include/coap/uthash.h b/include/coap/uthash.h index 796f88cc43..ed36537468 100644 --- a/include/coap/uthash.h +++ b/include/coap/uthash.h @@ -76,7 +76,7 @@ typedef unsigned char uint8_t; #define UTHASH_VERSION 1.9.9 #ifndef uthash_fatal -#define uthash_fatal(msg) return//exit(-1) /* fatal error (out of memory,etc) */ +#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ #endif #ifndef uthash_malloc #define uthash_malloc(sz) malloc(sz) /* malloc fcn */ diff --git a/platform/coap_posix_io.c b/platform/coap_posix_io.c index 44970969df..93a1e4a745 100644 --- a/platform/coap_posix_io.c +++ b/platform/coap_posix_io.c @@ -90,13 +90,14 @@ coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target) target->fd = packet->interface->fd; memcpy(&target->addr, &packet->dst, sizeof(target->addr)); target->ifindex = packet->ifindex; - target->flags = 0; /* FIXME */ + target->flags = packet->interface->flags; } void coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target) { memcpy(target, &packet->src, sizeof(coap_address_t)); } + void coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length) @@ -181,7 +182,6 @@ coap_network_send(struct coap_context_t *context, } return sendmsg(ep->fd, &mhdr, 0); -// return sendto(ep->fd, data, datalen, 0, (const struct sockaddr *)&dst->addr, dst->size); } /** diff --git a/platform/coap_posix_io.h b/platform/coap_posix_io.h index a96ca2e41a..351da5dd79 100644 --- a/platform/coap_posix_io.h +++ b/platform/coap_posix_io.h @@ -142,6 +142,8 @@ _coap_is_mcast_impl(const coap_address_t *a) { return 0; } +#define _coap_address_size_impl(a) (a->size) + /** * Abstraction of virtual endpoint that can be attached to coap_context_t. The * tuple (handle, addr) must uniquely identify this endpoint. diff --git a/src/coap_io.c b/src/coap_io.c deleted file mode 100644 index 057462f58c..0000000000 --- a/src/coap_io.c +++ /dev/null @@ -1,573 +0,0 @@ -/* coap_io.h -- Default network I/O functions for libcoap - * - * Copyright (C) 2012,2014 Olaf Bergmann - * - * This file is part of the CoAP library libcoap. Please see - * README for terms of use. - */ - -#include "coap_config.h" - -#ifdef HAVE_STDIO_H -# include -#endif - -#ifdef HAVE_SYS_SELECT_H -# include -#endif -#ifdef HAVE_SYS_SOCKET_H -# include -#endif -#ifdef HAVE_NETINET_IN_H -# include -#endif -#ifdef HAVE_SYS_UIO_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif -#include - -#ifdef WITH_CONTIKI -# include "uip.h" -#endif - -#include "debug.h" -#include "mem.h" -#include "coap_io.h" - -#ifdef WITH_POSIX -struct coap_packet_t { - coap_if_handle_t hnd; /**< the interface handle */ - coap_address_t src; /**< the packet's source address */ - coap_address_t dst; /**< the packet's destination address */ - const coap_endpoint_t *interface; - - int ifindex; - void *session; /**< opaque session data */ - - size_t length; /**< length of payload */ - unsigned char payload[]; /**< payload */ -}; -#endif - -#ifndef CUSTOM_COAP_NETWORK_ENDPOINT - -#ifdef WITH_CONTIKI -static int ep_initialized = 0; - -static inline struct coap_endpoint_t * -coap_malloc_contiki_endpoint() { - static struct coap_endpoint_t ep; - - if (ep_initialized) { - return NULL; - } else { - ep_initialized = 1; - return &ep; - } -} - -static inline void -coap_free_contiki_endpoint(struct coap_endpoint_t *ep) { - ep_initialized = 0; -} - -coap_endpoint_t * -coap_new_endpoint(const coap_address_t *addr, int flags) { - struct coap_endpoint_t *ep = coap_malloc_contiki_endpoint(); - - if (ep) { - memset(ep, 0, sizeof(struct coap_endpoint_t)); - ep->handle.conn = udp_new(NULL, 0, NULL); - - if (!ep->handle.conn) { - coap_free_endpoint(ep); - return NULL; - } - - coap_address_init(&ep->addr); - uip_ipaddr_copy(&ep->addr.addr, &addr->addr); - ep->addr.port = addr->port; - udp_bind((struct uip_udp_conn *)ep->handle.conn, addr->port); - } - return ep; -} - -void -coap_free_endpoint(coap_endpoint_t *ep) { - if (ep) { - if (ep->handle.conn) { - uip_udp_remove((struct uip_udp_conn *)ep->handle.conn); - } - coap_free_contiki_endpoint(ep); - } -} - -#else /* WITH_CONTIKI */ -static inline struct coap_endpoint_t * -coap_malloc_posix_endpoint(void) { - return (struct coap_endpoint_t *)coap_malloc(sizeof(struct coap_endpoint_t)); -} - -static inline void -coap_free_posix_endpoint(struct coap_endpoint_t *ep) { - coap_free(ep); -} - -coap_endpoint_t * -coap_new_endpoint(const coap_address_t *addr, int flags) { - int sockfd = socket(addr->addr.sa.sa_family, SOCK_DGRAM, 0); - int on = 1; - struct coap_endpoint_t *ep; - - if (sockfd < 0) { - coap_log(LOG_WARNING, "coap_new_endpoint: socket"); - return NULL; - } - - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) - coap_log(LOG_WARNING, "coap_new_endpoint: setsockopt SO_REUSEADDR"); - - on = 1; - switch(addr->addr.sa.sa_family) { - case AF_INET: - if (setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) < 0) - coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IP_PKTINFO\n"); - break; - case AF_INET6: -#ifdef IPV6_RECVPKTINFO - if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) - coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_RECVPKTINFO\n"); -#else /* IPV6_RECVPKTINFO */ - if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) < 0) - coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_PKTINFO\n"); -#endif /* IPV6_RECVPKTINFO */ - break; - default: - coap_log(LOG_ALERT, "coap_new_endpoint: unsupported sa_family\n"); - } - - if (bind(sockfd, &addr->addr.sa, addr->size) < 0) { - coap_log(LOG_WARNING, "coap_new_endpoint: bind"); - close (sockfd); - return NULL; - } - - ep = coap_malloc_posix_endpoint(); - if (!ep) { - coap_log(LOG_WARNING, "coap_new_endpoint: malloc"); - close(sockfd); - return NULL; - } - - memset(ep, 0, sizeof(struct coap_endpoint_t)); - ep->handle.fd = sockfd; - ep->flags = flags; - memcpy(&ep->addr, addr, sizeof(coap_address_t)); - -#ifndef NDEBUG - if (LOG_DEBUG <= coap_get_log_level()) { -#ifndef INET6_ADDRSTRLEN -#define INET6_ADDRSTRLEN 40 -#endif - unsigned char addr_str[INET6_ADDRSTRLEN+8]; - - if (coap_print_addr(addr, addr_str, INET6_ADDRSTRLEN+8)) { - debug("created %sendpoint %s\n", - ep->flags & COAP_ENDPOINT_DTLS ? "DTLS " : "", - addr_str); - } - } -#endif /* NDEBUG */ - - return (coap_endpoint_t *)ep; -} - -void -coap_free_endpoint(coap_endpoint_t *ep) { - if(ep) { - if (ep->handle.fd >= 0) - close(ep->handle.fd); - coap_free_posix_endpoint((struct coap_endpoint_t *)ep); - } -} - -#endif /* WITH_CONTIKI */ -#endif /* CUSTOM_COAP_NETWORK_ENDPOINT */ - -#ifndef CUSTOM_COAP_NETWORK_SEND - -#if defined(WITH_POSIX) != defined(HAVE_NETINET_IN_H) -/* define struct in6_pktinfo and struct in_pktinfo if not available - FIXME: check with configure -*/ -struct in6_pktinfo { - struct in6_addr ipi6_addr; /* src/dst IPv6 address */ - unsigned int ipi6_ifindex; /* send/recv interface index */ -}; - -struct in_pktinfo { - int ipi_ifindex; - struct in_addr ipi_spec_dst; - struct in_addr ipi_addr; -}; -#endif - -#if defined(WITH_POSIX) && !defined(SOL_IP) -/* Solaris expects level IPPROTO_IP for ancillary data. */ -#define SOL_IP IPPROTO_IP -#endif - -#ifdef __GNUC__ -#define UNUSED_PARAM __attribute__ ((unused)) -#else /* not a GCC */ -#define UNUSED_PARAM -#endif /* GCC */ - -ssize_t -coap_network_send(struct coap_context_t *context UNUSED_PARAM, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - unsigned char *data, - size_t datalen) { - - struct coap_endpoint_t *ep = - (struct coap_endpoint_t *)local_interface; - -#ifndef WITH_CONTIKI - /* a buffer large enough to hold all protocol address types */ - char buf[CMSG_LEN(sizeof(struct sockaddr_storage))]; - struct msghdr mhdr; - struct iovec iov[1]; - - assert(local_interface); - - iov[0].iov_base = data; - iov[0].iov_len = datalen; - - memset(&mhdr, 0, sizeof(struct msghdr)); - mhdr.msg_name = (void *)&dst->addr; - mhdr.msg_namelen = dst->size; - - mhdr.msg_iov = iov; - mhdr.msg_iovlen = 1; - - switch (dst->addr.sa.sa_family) { - case AF_INET6: { - struct cmsghdr *cmsg; - struct in6_pktinfo *pktinfo; - - mhdr.msg_control = buf; - mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); - - cmsg = CMSG_FIRSTHDR(&mhdr); - cmsg->cmsg_level = IPPROTO_IPV6; - cmsg->cmsg_type = IPV6_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); - - pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg); - memset(pktinfo, 0, sizeof(struct in6_pktinfo)); - - pktinfo->ipi6_ifindex = ep->ifindex; - if (coap_is_mcast(&local_interface->addr)) { - /* We cannot send with multicast address as source address - * and hence let the kernel pick the outgoing interface. */ - pktinfo->ipi6_ifindex = 0; - memset(&pktinfo->ipi6_addr, 0, sizeof(pktinfo->ipi6_addr)); - } else { - pktinfo->ipi6_ifindex = ep->ifindex; - memcpy(&pktinfo->ipi6_addr, - &local_interface->addr.addr.sin6.sin6_addr, - local_interface->addr.size); - } - break; - } - case AF_INET: { - struct cmsghdr *cmsg; - struct in_pktinfo *pktinfo; - - mhdr.msg_control = buf; - mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); - - cmsg = CMSG_FIRSTHDR(&mhdr); - cmsg->cmsg_level = SOL_IP; - cmsg->cmsg_type = IP_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); - - pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); - memset(pktinfo, 0, sizeof(struct in_pktinfo)); - - if (coap_is_mcast(&local_interface->addr)) { - /* We cannot send with multicast address as source address - * and hence let the kernel pick the outgoing interface. */ - pktinfo->ipi_ifindex = 0; - memset(&pktinfo->ipi_spec_dst, 0, sizeof(pktinfo->ipi_spec_dst)); - } else { - pktinfo->ipi_ifindex = ep->ifindex; - memcpy(&pktinfo->ipi_spec_dst, - &local_interface->addr.addr.sin.sin_addr, - local_interface->addr.size); - } - break; - } - default: - /* error */ - coap_log(LOG_WARNING, "protocol not supported\n"); - return -1; - } - - return sendmsg(ep->handle.fd, &mhdr, 0); -#else /* WITH_CONTIKI */ - /* FIXME: untested */ - /* FIXME: is there a way to check if send was successful? */ - uip_udp_packet_sendto((struct uip_udp_conn *)ep->handle.conn, data, datalen, - &dst->addr, dst->port); - return datalen; -#endif /* WITH_CONTIKI */ -} - -#endif /* CUSTOM_COAP_NETWORK_SEND */ - -#ifndef CUSTOM_COAP_NETWORK_READ - -#define SIN6(A) ((struct sockaddr_in6 *)(A)) - -#ifdef WITH_POSIX -static coap_packet_t * -coap_malloc_packet(void) { - coap_packet_t *packet; - const size_t need = sizeof(coap_packet_t) + COAP_MAX_PDU_SIZE; - - packet = (coap_packet_t *)coap_malloc(need); - if (packet) { - memset(packet, 0, need); - } - return packet; -} - -void -coap_free_packet(coap_packet_t *packet) { - coap_free(packet); -} -#endif /* WITH_POSIX */ -#ifdef WITH_CONTIKI -static inline coap_packet_t * -coap_malloc_packet(void) { - return (coap_packet_t *)coap_malloc_type(COAP_PACKET, 0); -} - -void -coap_free_packet(coap_packet_t *packet) { - coap_free_type(COAP_PACKET, packet); -} -#endif /* WITH_CONTIKI */ - -static inline size_t -coap_get_max_packetlength(const coap_packet_t *packet UNUSED_PARAM) { - return COAP_MAX_PDU_SIZE; -} - -void -coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target) -{ - target->handle = packet->interface->handle; - memcpy(&target->addr, &packet->dst, sizeof(target->addr)); - target->ifindex = packet->ifindex; - target->flags = 0; /* FIXME */ -} -void -coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target) -{ - memcpy(target, &packet->src, sizeof(coap_address_t)); -} -void -coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length) -{ - *address = packet->payload; - *length = packet->length; -} - -/** - * Checks if a message with destination address @p dst matches the - * local interface with address @p local. This function returns @c 1 - * if @p dst is a valid match, and @c 0 otherwise. - */ -static inline int -is_local_if(const coap_address_t *local, const coap_address_t *dst) { - return coap_address_isany(local) || coap_address_equals(dst, local) || - coap_is_mcast(dst); -} - -ssize_t -coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) { - ssize_t len = -1; - -#ifdef WITH_POSIX - char msg_control[CMSG_LEN(sizeof(struct sockaddr_storage))]; - struct msghdr mhdr; - struct iovec iov[1]; -#endif /* WITH_POSIX */ - - assert(ep); - assert(packet); - - *packet = coap_malloc_packet(); - - if (!*packet) { - warn("coap_network_read: insufficient memory, drop packet\n"); - return -1; - } - - coap_address_init(&(*packet)->dst); /* the local interface address */ - coap_address_init(&(*packet)->src); /* the remote peer */ - -#ifdef WITH_POSIX - iov[0].iov_base = (*packet)->payload; - iov[0].iov_len = coap_get_max_packetlength(*packet); - - memset(&mhdr, 0, sizeof(struct msghdr)); - - mhdr.msg_name = &(*packet)->src.addr.st; - mhdr.msg_namelen = sizeof((*packet)->src.addr.st); - - mhdr.msg_iov = iov; - mhdr.msg_iovlen = 1; - - mhdr.msg_control = msg_control; - mhdr.msg_controllen = sizeof(msg_control); - assert(sizeof(msg_control) == CMSG_LEN(sizeof(struct sockaddr_storage))); - - len = recvmsg(ep->handle.fd, &mhdr, 0); - - if (len < 0) { - coap_log(LOG_WARNING, "coap_network_read: %s\n", strerror(errno)); - goto error; - } else { - struct cmsghdr *cmsg; - - coap_log(LOG_DEBUG, "received %d bytes on fd %d\n", (int)len, ep->handle.fd); - - /* use getsockname() to get the local port */ - (*packet)->dst.size = sizeof((*packet)->dst.addr); - if (getsockname(ep->handle.fd, &(*packet)->dst.addr.sa, &(*packet)->dst.size) < 0) { - coap_log(LOG_DEBUG, "cannot determine local port\n"); - goto error; - } - - (*packet)->length = len; - - /* Walk through ancillary data records until the local interface - * is found where the data was received. */ - for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) { - - /* get the local interface for IPv6 */ - if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { - union { - unsigned char *c; - struct in6_pktinfo *p; - } u; - u.c = CMSG_DATA(cmsg); - (*packet)->ifindex = (int)(u.p->ipi6_ifindex); - - memcpy(&(*packet)->dst.addr.sin6.sin6_addr, - &u.p->ipi6_addr, sizeof(struct in6_addr)); - - (*packet)->src.size = mhdr.msg_namelen; - assert((*packet)->src.size == sizeof(struct sockaddr_in6)); - - (*packet)->src.addr.sin6.sin6_family = SIN6(mhdr.msg_name)->sin6_family; - (*packet)->src.addr.sin6.sin6_addr = SIN6(mhdr.msg_name)->sin6_addr; - (*packet)->src.addr.sin6.sin6_port = SIN6(mhdr.msg_name)->sin6_port; - - break; - } - - /* local interface for IPv4 */ - if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) { - union { - unsigned char *c; - struct in_pktinfo *p; - } u; - - u.c = CMSG_DATA(cmsg); - (*packet)->ifindex = u.p->ipi_ifindex; - - memcpy(&(*packet)->dst.addr.sin.sin_addr, - &u.p->ipi_addr, sizeof(struct in_addr)); - - (*packet)->src.size = mhdr.msg_namelen; - memcpy(&(*packet)->src.addr.st, mhdr.msg_name, (*packet)->src.size); - - break; - } - } - - if (!is_local_if(&ep->addr, &(*packet)->dst)) { - coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n"); - goto error; - } - } -#endif /* WITH_POSIX */ -#ifdef WITH_CONTIKI - /* FIXME: untested, make this work */ -#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) -#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN]) - - if(uip_newdata()) { - uip_ipaddr_copy(&(*packet)->src.addr, &UIP_IP_BUF->srcipaddr); - (*packet)->src.port = UIP_UDP_BUF->srcport; - uip_ipaddr_copy(&(*packet)->dst.addr, &UIP_IP_BUF->destipaddr); - (*packet)->dst.port = UIP_UDP_BUF->destport; - - if (!is_local_if(&ep->addr, &(*packet)->dst)) { - coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n"); - goto error; - } - - len = uip_datalen(); - - if (len > coap_get_max_packetlength(*packet)) { - /* FIXME: we might want to send back a response */ - warn("discarded oversized packet\n"); - return -1; - } - - ((char *)uip_appdata)[len] = 0; -#ifndef NDEBUG - if (LOG_DEBUG <= coap_get_log_level()) { -#ifndef INET6_ADDRSTRLEN -#define INET6_ADDRSTRLEN 40 -#endif - unsigned char addr_str[INET6_ADDRSTRLEN+8]; - - if (coap_print_addr(&(*packet)->src, addr_str, INET6_ADDRSTRLEN+8)) { - debug("received %zd bytes from %s\n", len, addr_str); - } - } -#endif /* NDEBUG */ - - (*packet)->length = len; - memcpy(&(*packet)->payload, uip_appdata, len); - } - -#undef UIP_IP_BUF -#undef UIP_UDP_BUF -#endif /* WITH_CONTIKI */ -#ifdef WITH_LWIP -#error "coap_network_read() not implemented on this platform" -#endif - - (*packet)->interface = ep; - - return len; - error: - coap_free_packet(*packet); - *packet = NULL; - return -1; -} - -#undef SIN6 - -#endif /* CUSTOM_COAP_NETWORK_READ */ diff --git a/src/debug.c b/src/debug.c deleted file mode 100644 index d1b96f33fd..0000000000 --- a/src/debug.c +++ /dev/null @@ -1,504 +0,0 @@ -/* debug.c -- debug utilities - * - * Copyright (C) 2010--2012,2014--2015 Olaf Bergmann - * - * This file is part of the CoAP library libcoap. Please see - * README for terms of use. - */ - -#include "coap_config.h" -#include "coap_posix_io.h" - -#if defined(HAVE_STRNLEN) && defined(__GNUC__) && !defined(_GNU_SOURCE) -#define _GNU_SOURCE 1 -#endif - -#if defined(HAVE_ASSERT_H) && !defined(assert) -# include -#endif - -#include -#include -#include -#include - -#ifdef HAVE_ARPA_INET_H -#include -#endif - -#ifdef HAVE_TIME_H -#include -#endif - -#include "coap_time.h" -#include "block.h" -#include "debug.h" -#include "encode.h" -#include "net.h" - -#ifdef WITH_CONTIKI -# ifndef DEBUG -# define DEBUG DEBUG_PRINT -# endif /* DEBUG */ -#include "net/ip/uip-debug.h" -#endif - -static coap_log_t maxlog = LOG_DEBUG; /* default maximum log level */ - -const char *coap_package_name(void) { - return PACKAGE_NAME; -} - -const char *coap_package_version(void) { - return PACKAGE_STRING; -} - -coap_log_t -coap_get_log_level(void) { - return maxlog; -} - -void -coap_set_log_level(coap_log_t level) { - maxlog = level; -} - -/* this array has the same order as the type log_t */ -static char *loglevels[] = { - "EMRG", "ALRT", "CRIT", "ERR", "WARN", "NOTE", "INFO", "DEBG" -}; - -#ifdef HAVE_TIME_H - -static inline size_t -print_timestamp(char *s, size_t len, coap_tick_t t) { - struct tm *tmp; - time_t now = coap_ticks_to_rt(t); - tmp = localtime(&now); - return strftime(s, len, "%b %d %H:%M:%S", tmp); -} - -#else /* alternative implementation: just print the timestamp */ - -static inline size_t -print_timestamp(char *s, size_t len, coap_tick_t t) { -#ifdef HAVE_SNPRINTF - return snprintf(s, len, "%u.%03u", - (unsigned int)coap_ticks_to_rt(t), - (unsigned int)(t % COAP_TICKS_PER_SECOND)); -#else /* HAVE_SNPRINTF */ - /* @todo do manual conversion of timestamp */ - return 0; -#endif /* HAVE_SNPRINTF */ -} - -#endif /* HAVE_TIME_H */ - -#ifndef NDEBUG - -#ifndef HAVE_STRNLEN -/** - * A length-safe strlen() fake. - * - * @param s The string to count characters != 0. - * @param maxlen The maximum length of @p s. - * - * @return The length of @p s. - */ -static inline size_t -strnlen(const char *s, size_t maxlen) { - size_t n = 0; - while(*s++ && n < maxlen) - ++n; - return n; -} -#endif /* HAVE_STRNLEN */ - -static unsigned int -print_readable( const unsigned char *data, unsigned int len, - unsigned char *result, unsigned int buflen, int encode_always ) { - const unsigned char hex[] = "0123456789ABCDEF"; - unsigned int cnt = 0; - assert(data || len == 0); - - if (buflen == 0) { /* there is nothing we can do here but return */ - return 0; - } - - while (len) { - if (!encode_always && isprint(*data)) { - if (cnt+1 < buflen) { /* keep one byte for terminating zero */ - *result++ = *data; - ++cnt; - } else { - break; - } - } else { - if (cnt+4 < buflen) { /* keep one byte for terminating zero */ - *result++ = '\\'; - *result++ = 'x'; - *result++ = hex[(*data & 0xf0) >> 4]; - *result++ = hex[*data & 0x0f]; - cnt += 4; - } else - break; - } - - ++data; --len; - } - - *result = '\0'; /* add a terminating zero */ - return cnt; -} - -#ifndef min -#define min(a,b) ((a) < (b) ? (a) : (b)) -#endif - -size_t -coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t len) { -#ifdef HAVE_ARPA_INET_H - const void *addrptr = NULL; - in_port_t port; - unsigned char *p = buf; - - switch (addr->addr.sa.sa_family) { - case AF_INET: - addrptr = &addr->addr.sin.sin_addr; - port = ntohs(addr->addr.sin.sin_port); - break; - case AF_INET6: - if (len < 7) /* do not proceed if buffer is even too short for [::]:0 */ - return 0; - - *p++ = '['; - - addrptr = &addr->addr.sin6.sin6_addr; - port = ntohs(addr->addr.sin6.sin6_port); - - break; - default: - memcpy(buf, "(unknown address type)", min(22, len)); - return min(22, len); - } - - if (inet_ntop(addr->addr.sa.sa_family, addrptr, (char *)p, len) == 0) { - perror("coap_print_addr"); - return 0; - } - - p += strnlen((char *)p, len); - - if (addr->addr.sa.sa_family == AF_INET6) { - if (p < buf + len) { - *p++ = ']'; - } else - return 0; - } - - p += snprintf((char *)p, buf + len - p + 1, ":%d", port); - - return buf + len - p; -#else /* HAVE_ARPA_INET_H */ -# if WITH_CONTIKI - unsigned char *p = buf; - uint8_t i; -# if WITH_UIP6 - const unsigned char hex[] = "0123456789ABCDEF"; - - if (len < 41) - return 0; - - *p++ = '['; - - for (i=0; i < 16; i += 2) { - if (i) { - *p++ = ':'; - } - *p++ = hex[(addr->addr.u8[i] & 0xf0) >> 4]; - *p++ = hex[(addr->addr.u8[i] & 0x0f)]; - *p++ = hex[(addr->addr.u8[i+1] & 0xf0) >> 4]; - *p++ = hex[(addr->addr.u8[i+1] & 0x0f)]; - } - *p++ = ']'; -# else /* WITH_UIP6 */ -# warning "IPv4 network addresses will not be included in debug output" - - if (len < 21) - return 0; -# endif /* WITH_UIP6 */ - if (buf + len - p < 6) - return 0; - -#ifdef HAVE_SNPRINTF - p += snprintf((char *)p, buf + len - p + 1, ":%d", uip_htons(addr->port)); -#else /* HAVE_SNPRINTF */ - /* @todo manual conversion of port number */ -#endif /* HAVE_SNPRINTF */ - - return p - buf; -# else /* WITH_CONTIKI */ - /* TODO: output addresses manually */ -# warning "inet_ntop() not available, network addresses will not be included in debug output" -# endif /* WITH_CONTIKI */ - return 0; -#endif -} - -#ifdef WITH_CONTIKI -# define fprintf(fd, ...) PRINTF(__VA_ARGS__) -# define fflush(...) - -# ifdef HAVE_VPRINTF -# define vfprintf(fd, ...) vprintf(__VA_ARGS__) -# else /* HAVE_VPRINTF */ -# define vfprintf(fd, ...) PRINTF(__VA_ARGS__) -# endif /* HAVE_VPRINTF */ -#endif /* WITH_CONTIKI */ - -/** Returns a textual description of the message type @p t. */ -static const char * -msg_type_string(uint8_t t) { - static char *types[] = { "CON", "NON", "ACK", "RST", "???" }; - - return types[min(t, sizeof(types)/sizeof(char *) - 1)]; -} - -/** Returns a textual description of the method or response code. */ -static const char * -msg_code_string(uint8_t c) { - static char *methods[] = { "0.00", "GET", "POST", "PUT", "DELETE", "PATCH" }; - static char buf[5]; - - if (c < sizeof(methods)/sizeof(char *)) { - return methods[c]; - } else { - snprintf(buf, sizeof(buf), "%u.%02u", c >> 5, c & 0x1f); - return buf; - } -} - -/** Returns a textual description of the option name. */ -static const char * -msg_option_string(uint16_t option_type) { - struct option_desc_t { - uint16_t type; - const char *name; - }; - - static struct option_desc_t options[] = { - { COAP_OPTION_IF_MATCH, "If-Match" }, - { COAP_OPTION_URI_HOST, "Uri-Host" }, - { COAP_OPTION_ETAG, "ETag" }, - { COAP_OPTION_IF_NONE_MATCH, "If-None-Match" }, - { COAP_OPTION_OBSERVE, "Observe" }, - { COAP_OPTION_URI_PORT, "Uri-Port" }, - { COAP_OPTION_LOCATION_PATH, "Location-Path" }, - { COAP_OPTION_URI_PATH, "Uri-Path" }, - { COAP_OPTION_CONTENT_FORMAT, "Content-Format" }, - { COAP_OPTION_MAXAGE, "Max-Age" }, - { COAP_OPTION_URI_QUERY, "Uri-Query" }, - { COAP_OPTION_ACCEPT, "Accept" }, - { COAP_OPTION_LOCATION_QUERY, "Location-Query" }, - { COAP_OPTION_BLOCK2, "Block2" }, - { COAP_OPTION_BLOCK1, "Block1" }, - { COAP_OPTION_PROXY_URI, "Proxy-Uri" }, - { COAP_OPTION_PROXY_SCHEME, "Proxy-Scheme" }, - { COAP_OPTION_SIZE1, "Size1" }, - { COAP_OPTION_NORESPONSE, "No-Response" } - }; - - static char buf[6]; - size_t i; - - /* search option_type in list of known options */ - for (i = 0; i < sizeof(options)/sizeof(struct option_desc_t); i++) { - if (option_type == options[i].type) { - return options[i].name; - } - } - - /* unknown option type, just print to buf */ - snprintf(buf, sizeof(buf), "%u", option_type); - return buf; -} - -static unsigned int -print_content_format(unsigned int format_type, - unsigned char *result, unsigned int buflen) { - struct desc_t { - unsigned int type; - const char *name; - }; - - static struct desc_t formats[] = { - { COAP_MEDIATYPE_TEXT_PLAIN, "text/plain" }, - { COAP_MEDIATYPE_APPLICATION_LINK_FORMAT, "application/link-format" }, - { COAP_MEDIATYPE_APPLICATION_XML, "application/xml" }, - { COAP_MEDIATYPE_APPLICATION_OCTET_STREAM, "application/octet-stream" }, - { COAP_MEDIATYPE_APPLICATION_EXI, "application/exi" }, - { COAP_MEDIATYPE_APPLICATION_JSON, "application/json" }, - { COAP_MEDIATYPE_APPLICATION_CBOR, "application/cbor" } - }; - - size_t i; - - /* search format_type in list of known content formats */ - for (i = 0; i < sizeof(formats)/sizeof(struct desc_t); i++) { - if (format_type == formats[i].type) { - return snprintf((char *)result, buflen, "%s", formats[i].name); - } - } - - /* unknown content format, just print numeric value to buf */ - return snprintf((char *)result, buflen, "%d", format_type); -} - -/** - * Returns 1 if the given @p content_format is either unknown or known - * to carry binary data. The return value @c 0 hence indicates - * printable data which is also assumed if @p content_format is @c 01. - */ -static inline int -is_binary(int content_format) { - return !(content_format == -1 || - content_format == COAP_MEDIATYPE_TEXT_PLAIN || - content_format == COAP_MEDIATYPE_APPLICATION_LINK_FORMAT || - content_format == COAP_MEDIATYPE_APPLICATION_XML || - content_format == COAP_MEDIATYPE_APPLICATION_JSON); -} - -void -coap_show_pdu(const coap_pdu_t *pdu) { - unsigned char buf[COAP_MAX_PDU_SIZE]; /* need some space for output creation */ - size_t buf_len = 0; /* takes the number of bytes written to buf */ - int encode = 0, have_options = 0, i; - coap_opt_iterator_t opt_iter; - coap_opt_t *option; - int content_format = -1; - size_t data_len; - unsigned char *data; - - fprintf(COAP_DEBUG_FD, "v:%d t:%s c:%s i:%04x {", - pdu->hdr->version, msg_type_string(pdu->hdr->type), - msg_code_string(pdu->hdr->code), ntohs(pdu->hdr->id)); - - for (i = 0; i < pdu->hdr->token_length; i++) { - fprintf(COAP_DEBUG_FD, "%02x", pdu->hdr->token[i]); - } - fprintf(COAP_DEBUG_FD, "}"); - - /* show options, if any */ - coap_option_iterator_init((coap_pdu_t *)pdu, &opt_iter, COAP_OPT_ALL); - - fprintf(COAP_DEBUG_FD, " ["); - while ((option = coap_option_next(&opt_iter))) { - if (!have_options) { - have_options = 1; - } else { - fprintf(COAP_DEBUG_FD, ","); - } - - switch (opt_iter.type) { - case COAP_OPTION_CONTENT_FORMAT: - content_format = (int)coap_decode_var_bytes(COAP_OPT_VALUE(option), - COAP_OPT_LENGTH(option)); - - buf_len = print_content_format(content_format, buf, sizeof(buf)); - break; - - case COAP_OPTION_BLOCK1: - case COAP_OPTION_BLOCK2: - /* split block option into number/more/size where more is the - * letter M if set, the _ otherwise */ - buf_len = snprintf((char *)buf, sizeof(buf), "%u/%c/%u", - coap_opt_block_num(option), /* block number */ - COAP_OPT_BLOCK_MORE(option) ? 'M' : '_', /* M bit */ - (2 << (COAP_OPT_BLOCK_SZX(option) + 4))); /* block size */ - - break; - - case COAP_OPTION_URI_PORT: - case COAP_OPTION_MAXAGE: - case COAP_OPTION_OBSERVE: - case COAP_OPTION_SIZE1: - /* show values as unsigned decimal value */ - buf_len = snprintf((char *)buf, sizeof(buf), "%u", - coap_decode_var_bytes(COAP_OPT_VALUE(option), - COAP_OPT_LENGTH(option))); - break; - - default: - /* generic output function for all other option types */ - if (opt_iter.type == COAP_OPTION_URI_PATH || - opt_iter.type == COAP_OPTION_PROXY_URI || - opt_iter.type == COAP_OPTION_URI_HOST || - opt_iter.type == COAP_OPTION_LOCATION_PATH || - opt_iter.type == COAP_OPTION_LOCATION_QUERY || - opt_iter.type == COAP_OPTION_URI_QUERY) { - encode = 0; - } else { - encode = 1; - } - - buf_len = print_readable(COAP_OPT_VALUE(option), - COAP_OPT_LENGTH(option), - buf, sizeof(buf), encode); - } - - fprintf(COAP_DEBUG_FD, " %s:%.*s", msg_option_string(opt_iter.type), - (int)buf_len, buf); - } - - fprintf(COAP_DEBUG_FD, " ]"); - - if (coap_get_data((coap_pdu_t *)pdu, &data_len, &data)) { - - fprintf(COAP_DEBUG_FD, " :: "); - - if (is_binary(content_format)) { - fprintf(COAP_DEBUG_FD, "<<"); - while (data_len--) { - fprintf(COAP_DEBUG_FD, "%02x", *data++); - } - fprintf(COAP_DEBUG_FD, ">>"); - } else { - if (print_readable(data, data_len, buf, sizeof(buf), 0)) { - fprintf(COAP_DEBUG_FD, "'%s'", buf); - } - } - } - - fprintf(COAP_DEBUG_FD, "\n"); - fflush(COAP_DEBUG_FD); -} - - -#endif /* NDEBUG */ - -void -coap_log_impl(const char *file, int line, coap_log_t level, const char *format, ...) { - char timebuf[32]; - coap_tick_t now; - va_list ap; - FILE *log_fd; - - if (maxlog < level) - return; - - //log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD; - log_fd = stderr; - - coap_ticks(&now); - if (print_timestamp(timebuf,sizeof(timebuf), now)) - fprintf(log_fd, "%s ", timebuf); - - if (level <= LOG_DEBUG) - fprintf(log_fd, "%s ", loglevels[level]); - - va_start(ap, format); - vfprintf(log_fd, format, ap); - va_end(ap); - fflush(log_fd); -} - diff --git a/src/net.c b/src/net.c index 9fd790740c..5c6a2b5f6e 100644 --- a/src/net.c +++ b/src/net.c @@ -1172,6 +1172,10 @@ handle_request(coap_context_t *context, coap_queue_t *node) { coap_option_filter_clear(opt_filter); + char *uri = coap_get_uri(node->pdu); + debug("%s %s", msg_code_string(node->pdu->hdr->code), uri); + coap_free_type(COAP_STRING, uri); + /* try to find the resource from the request URI */ coap_hash_request_uri(node->pdu, key); resource = coap_get_resource_from_key(context, key); @@ -1267,6 +1271,8 @@ handle_request(coap_context_t *context, coap_queue_t *node) { h(context, resource, &node->local_if, &node->remote, node->pdu, &token, response); + debug("%s %d", msg_type_string(response->hdr->type), COAP_RESPONSE_CODE2(response->hdr->code)); + if (!no_response(node->pdu, response)) { // Cancel subscription if handler returned and error or the client // canceled subscription explicitly diff --git a/src/resource.c b/src/resource.c index 333aba1ddc..e6387e2805 100644 --- a/src/resource.c +++ b/src/resource.c @@ -351,7 +351,7 @@ coap_add_resource(coap_context_t *context, coap_resource_t *resource) { resource->uri.length = strlen(resource->uri.s); coap_hash_path(resource->uri.s, resource->uri.length, resource->key); } - debug("Added resource 0x%02x%02x%02x%02x", resource->key[0], resource->key[1], resource->key[2], resource->key[3]); + debug("Added resource 0x%02x%02x%02x%02x\n", resource->key[0], resource->key[1], resource->key[2], resource->key[3]); } static void From 42609a9579e73023674eec31704f635d97e00786 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Mon, 14 Sep 2015 16:10:53 +0200 Subject: [PATCH 66/69] Renamed files to match fbo branch --- doc/libcoap_style_eclipse.xml | 167 ++++++ .../{coap_contiki.c => contiki/platform.c} | 0 .../{coap_contiki.h => contiki/platform.h} | 0 .../platform_io.c} | 0 .../platform_io.h} | 0 platform/{ => lwip}/lwippools.h | 0 platform/{coap_lwip.c => lwip/platform.c} | 0 platform/{coap_lwip.h => lwip/platform.h} | 0 .../{coap_lwip_io.c => lwip/platform_io.c} | 3 +- .../{coap_lwip_io.h => lwip/platform_io.h} | 0 platform/{coap_posix.c => posix/platform.c} | 0 platform/{coap_posix.h => posix/platform.h} | 0 .../{coap_posix_io.c => posix/platform_io.c} | 0 .../{coap_posix_io.h => posix/platform_io.h} | 0 src/coap_debug.c | 478 ++++++++++++++++++ 15 files changed, 647 insertions(+), 1 deletion(-) create mode 100644 doc/libcoap_style_eclipse.xml rename platform/{coap_contiki.c => contiki/platform.c} (100%) rename platform/{coap_contiki.h => contiki/platform.h} (100%) rename platform/{coap_contiki_io.c => contiki/platform_io.c} (100%) rename platform/{coap_contiki_io.h => contiki/platform_io.h} (100%) rename platform/{ => lwip}/lwippools.h (100%) rename platform/{coap_lwip.c => lwip/platform.c} (100%) rename platform/{coap_lwip.h => lwip/platform.h} (100%) rename platform/{coap_lwip_io.c => lwip/platform_io.c} (99%) rename platform/{coap_lwip_io.h => lwip/platform_io.h} (100%) rename platform/{coap_posix.c => posix/platform.c} (100%) rename platform/{coap_posix.h => posix/platform.h} (100%) rename platform/{coap_posix_io.c => posix/platform_io.c} (100%) rename platform/{coap_posix_io.h => posix/platform_io.h} (100%) create mode 100644 src/coap_debug.c diff --git a/doc/libcoap_style_eclipse.xml b/doc/libcoap_style_eclipse.xml new file mode 100644 index 0000000000..2a20f111a1 --- /dev/null +++ b/doc/libcoap_style_eclipse.xml @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/coap_contiki.c b/platform/contiki/platform.c similarity index 100% rename from platform/coap_contiki.c rename to platform/contiki/platform.c diff --git a/platform/coap_contiki.h b/platform/contiki/platform.h similarity index 100% rename from platform/coap_contiki.h rename to platform/contiki/platform.h diff --git a/platform/coap_contiki_io.c b/platform/contiki/platform_io.c similarity index 100% rename from platform/coap_contiki_io.c rename to platform/contiki/platform_io.c diff --git a/platform/coap_contiki_io.h b/platform/contiki/platform_io.h similarity index 100% rename from platform/coap_contiki_io.h rename to platform/contiki/platform_io.h diff --git a/platform/lwippools.h b/platform/lwip/lwippools.h similarity index 100% rename from platform/lwippools.h rename to platform/lwip/lwippools.h diff --git a/platform/coap_lwip.c b/platform/lwip/platform.c similarity index 100% rename from platform/coap_lwip.c rename to platform/lwip/platform.c diff --git a/platform/coap_lwip.h b/platform/lwip/platform.h similarity index 100% rename from platform/coap_lwip.h rename to platform/lwip/platform.h diff --git a/platform/coap_lwip_io.c b/platform/lwip/platform_io.c similarity index 99% rename from platform/coap_lwip_io.c rename to platform/lwip/platform_io.c index 12c8e91eec..4167ede9f3 100644 --- a/platform/coap_lwip_io.c +++ b/platform/lwip/platform_io.c @@ -7,10 +7,11 @@ * README for terms of use. */ +#include "platform_io.h" + #include "mem.h" #include "coap_config.h" #include "coap_io.h" -#include "coap_lwip_io.h" void coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target) { diff --git a/platform/coap_lwip_io.h b/platform/lwip/platform_io.h similarity index 100% rename from platform/coap_lwip_io.h rename to platform/lwip/platform_io.h diff --git a/platform/coap_posix.c b/platform/posix/platform.c similarity index 100% rename from platform/coap_posix.c rename to platform/posix/platform.c diff --git a/platform/coap_posix.h b/platform/posix/platform.h similarity index 100% rename from platform/coap_posix.h rename to platform/posix/platform.h diff --git a/platform/coap_posix_io.c b/platform/posix/platform_io.c similarity index 100% rename from platform/coap_posix_io.c rename to platform/posix/platform_io.c diff --git a/platform/coap_posix_io.h b/platform/posix/platform_io.h similarity index 100% rename from platform/coap_posix_io.h rename to platform/posix/platform_io.h diff --git a/src/coap_debug.c b/src/coap_debug.c new file mode 100644 index 0000000000..1df63e763a --- /dev/null +++ b/src/coap_debug.c @@ -0,0 +1,478 @@ +/* debug.c -- debug utilities + * + * Copyright (C) 2010--2012,2014--2015 Olaf Bergmann + * + * This file is part of the CoAP library libcoap. Please see + * README for terms of use. + */ + +#include "coap_config.h" +#include "coap_posix_io.h" + +#if defined(HAVE_STRNLEN) && defined(__GNUC__) && !defined(_GNU_SOURCE) +#define _GNU_SOURCE 1 +#endif + +#if defined(HAVE_ASSERT_H) && !defined(assert) +# include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#ifdef HAVE_TIME_H +#include +#endif + +#include "coap_time.h" +#include "block.h" +#include "coap/debug.h" +#include "encode.h" +#include "net.h" + +#ifdef WITH_CONTIKI +# ifndef DEBUG +# define DEBUG DEBUG_PRINT +# endif /* DEBUG */ +#include "net/ip/uip-debug.h" +#endif + +static coap_log_t maxlog = LOG_DEBUG; /* default maximum log level */ + +const char *coap_package_name(void) { + return PACKAGE_NAME; +} + +const char *coap_package_version(void) { + return PACKAGE_STRING; +} + +coap_log_t +coap_get_log_level(void) { + return maxlog; +} + +void +coap_set_log_level(coap_log_t level) { + maxlog = level; +} + +/* this array has the same order as the type log_t */ +static char *loglevels[] = { + "EMRG", "ALRT", "CRIT", "ERR", "WARN", "NOTE", "INFO", "DEBG" +}; + +#ifdef HAVE_TIME_H + +static inline size_t +print_timestamp(char *s, size_t len, coap_tick_t t) { + struct tm *tmp; + time_t now = coap_ticks_to_rt(t); + tmp = localtime(&now); + return strftime(s, len, "%b %d %H:%M:%S", tmp); +} + +#else /* alternative implementation: just print the timestamp */ + +static inline size_t +print_timestamp(char *s, size_t len, coap_tick_t t) { +#ifdef HAVE_SNPRINTF + return snprintf(s, len, "%u.%03u", + (unsigned int)coap_ticks_to_rt(t), + (unsigned int)(t % COAP_TICKS_PER_SECOND)); +#else /* HAVE_SNPRINTF */ + /* @todo do manual conversion of timestamp */ + return 0; +#endif /* HAVE_SNPRINTF */ +} + +#endif /* HAVE_TIME_H */ + +#ifndef NDEBUG + +#ifndef HAVE_STRNLEN +/** + * A length-safe strlen() fake. + * + * @param s The string to count characters != 0. + * @param maxlen The maximum length of @p s. + * + * @return The length of @p s. + */ +static inline size_t +strnlen(const char *s, size_t maxlen) { + size_t n = 0; + while(*s++ && n < maxlen) + ++n; + return n; +} +#endif /* HAVE_STRNLEN */ + +static unsigned int +print_readable( const unsigned char *data, unsigned int len, + unsigned char *result, unsigned int buflen, int encode_always ) { + const unsigned char hex[] = "0123456789ABCDEF"; + unsigned int cnt = 0; + assert(data || len == 0); + + if (buflen == 0) { /* there is nothing we can do here but return */ + return 0; + } + + while (len) { + if (!encode_always && isprint(*data)) { + if (cnt+1 < buflen) { /* keep one byte for terminating zero */ + *result++ = *data; + ++cnt; + } else { + break; + } + } else { + if (cnt+4 < buflen) { /* keep one byte for terminating zero */ + *result++ = '\\'; + *result++ = 'x'; + *result++ = hex[(*data & 0xf0) >> 4]; + *result++ = hex[*data & 0x0f]; + cnt += 4; + } else + break; + } + + ++data; --len; + } + + *result = '\0'; /* add a terminating zero */ + return cnt; +} + +size_t +coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t len) { +#ifdef HAVE_ARPA_INET_H + const void *addrptr = NULL; + in_port_t port; + unsigned char *p = buf; + + switch (addr->addr.sa.sa_family) { + case AF_INET: + addrptr = &addr->addr.sin.sin_addr; + port = ntohs(addr->addr.sin.sin_port); + break; + case AF_INET6: + if (len < 7) /* do not proceed if buffer is even too short for [::]:0 */ + return 0; + + *p++ = '['; + + addrptr = &addr->addr.sin6.sin6_addr; + port = ntohs(addr->addr.sin6.sin6_port); + + break; + default: + memcpy(buf, "(unknown address type)", min(22, len)); + return min(22, len); + } + + if (inet_ntop(addr->addr.sa.sa_family, addrptr, (char *)p, len) == 0) { + perror("coap_print_addr"); + return 0; + } + + p += strnlen((char *)p, len); + + if (addr->addr.sa.sa_family == AF_INET6) { + if (p < buf + len) { + *p++ = ']'; + } else + return 0; + } + + p += snprintf((char *)p, buf + len - p + 1, ":%d", port); + + return buf + len - p; +#else /* HAVE_ARPA_INET_H */ +# if WITH_CONTIKI + unsigned char *p = buf; + uint8_t i; +# if WITH_UIP6 + const unsigned char hex[] = "0123456789ABCDEF"; + + if (len < 41) + return 0; + + *p++ = '['; + + for (i=0; i < 16; i += 2) { + if (i) { + *p++ = ':'; + } + *p++ = hex[(addr->addr.u8[i] & 0xf0) >> 4]; + *p++ = hex[(addr->addr.u8[i] & 0x0f)]; + *p++ = hex[(addr->addr.u8[i+1] & 0xf0) >> 4]; + *p++ = hex[(addr->addr.u8[i+1] & 0x0f)]; + } + *p++ = ']'; +# else /* WITH_UIP6 */ +# warning "IPv4 network addresses will not be included in debug output" + + if (len < 21) + return 0; +# endif /* WITH_UIP6 */ + if (buf + len - p < 6) + return 0; + +#ifdef HAVE_SNPRINTF + p += snprintf((char *)p, buf + len - p + 1, ":%d", uip_htons(addr->port)); +#else /* HAVE_SNPRINTF */ + /* @todo manual conversion of port number */ +#endif /* HAVE_SNPRINTF */ + + return p - buf; +# else /* WITH_CONTIKI */ + /* TODO: output addresses manually */ +# warning "inet_ntop() not available, network addresses will not be included in debug output" +# endif /* WITH_CONTIKI */ + return 0; +#endif +} + +#ifdef WITH_CONTIKI +# define fprintf(fd, ...) PRINTF(__VA_ARGS__) +# define fflush(...) + +# ifdef HAVE_VPRINTF +# define vfprintf(fd, ...) vprintf(__VA_ARGS__) +# else /* HAVE_VPRINTF */ +# define vfprintf(fd, ...) PRINTF(__VA_ARGS__) +# endif /* HAVE_VPRINTF */ +#endif /* WITH_CONTIKI */ + +/** Returns a textual description of the option name. */ +static const char * +msg_option_string(uint16_t option_type) { + struct option_desc_t { + uint16_t type; + const char *name; + }; + + static struct option_desc_t options[] = { + { COAP_OPTION_IF_MATCH, "If-Match" }, + { COAP_OPTION_URI_HOST, "Uri-Host" }, + { COAP_OPTION_ETAG, "ETag" }, + { COAP_OPTION_IF_NONE_MATCH, "If-None-Match" }, + { COAP_OPTION_OBSERVE, "Observe" }, + { COAP_OPTION_URI_PORT, "Uri-Port" }, + { COAP_OPTION_LOCATION_PATH, "Location-Path" }, + { COAP_OPTION_URI_PATH, "Uri-Path" }, + { COAP_OPTION_CONTENT_FORMAT, "Content-Format" }, + { COAP_OPTION_MAXAGE, "Max-Age" }, + { COAP_OPTION_URI_QUERY, "Uri-Query" }, + { COAP_OPTION_ACCEPT, "Accept" }, + { COAP_OPTION_LOCATION_QUERY, "Location-Query" }, + { COAP_OPTION_BLOCK2, "Block2" }, + { COAP_OPTION_BLOCK1, "Block1" }, + { COAP_OPTION_PROXY_URI, "Proxy-Uri" }, + { COAP_OPTION_PROXY_SCHEME, "Proxy-Scheme" }, + { COAP_OPTION_SIZE1, "Size1" }, + { COAP_OPTION_NORESPONSE, "No-Response" } + }; + + static char buf[6]; + size_t i; + + /* search option_type in list of known options */ + for (i = 0; i < sizeof(options)/sizeof(struct option_desc_t); i++) { + if (option_type == options[i].type) { + return options[i].name; + } + } + + /* unknown option type, just print to buf */ + snprintf(buf, sizeof(buf), "%u", option_type); + return buf; +} + +static unsigned int +print_content_format(unsigned int format_type, + unsigned char *result, unsigned int buflen) { + struct desc_t { + unsigned int type; + const char *name; + }; + + static struct desc_t formats[] = { + { COAP_MEDIATYPE_TEXT_PLAIN, "text/plain" }, + { COAP_MEDIATYPE_APPLICATION_LINK_FORMAT, "application/link-format" }, + { COAP_MEDIATYPE_APPLICATION_XML, "application/xml" }, + { COAP_MEDIATYPE_APPLICATION_OCTET_STREAM, "application/octet-stream" }, + { COAP_MEDIATYPE_APPLICATION_EXI, "application/exi" }, + { COAP_MEDIATYPE_APPLICATION_JSON, "application/json" }, + { COAP_MEDIATYPE_APPLICATION_CBOR, "application/cbor" } + }; + + size_t i; + + /* search format_type in list of known content formats */ + for (i = 0; i < sizeof(formats)/sizeof(struct desc_t); i++) { + if (format_type == formats[i].type) { + return snprintf((char *)result, buflen, "%s", formats[i].name); + } + } + + /* unknown content format, just print numeric value to buf */ + return snprintf((char *)result, buflen, "%d", format_type); +} + +/** + * Returns 1 if the given @p content_format is either unknown or known + * to carry binary data. The return value @c 0 hence indicates + * printable data which is also assumed if @p content_format is @c 01. + */ +static inline int +is_binary(int content_format) { + return !(content_format == -1 || + content_format == COAP_MEDIATYPE_TEXT_PLAIN || + content_format == COAP_MEDIATYPE_APPLICATION_LINK_FORMAT || + content_format == COAP_MEDIATYPE_APPLICATION_XML || + content_format == COAP_MEDIATYPE_APPLICATION_JSON); +} + +void +coap_show_pdu(const coap_pdu_t *pdu) { + unsigned char buf[COAP_MAX_PDU_SIZE]; /* need some space for output creation */ + size_t buf_len = 0; /* takes the number of bytes written to buf */ + int encode = 0, have_options = 0, i; + coap_opt_iterator_t opt_iter; + coap_opt_t *option; + int content_format = -1; + size_t data_len; + unsigned char *data; + + fprintf(COAP_DEBUG_FD, "v:%d t:%s c:%s i:%04x {", + pdu->hdr->version, msg_type_string(pdu->hdr->type), + msg_code_string(pdu->hdr->code), ntohs(pdu->hdr->id)); + + for (i = 0; i < pdu->hdr->token_length; i++) { + fprintf(COAP_DEBUG_FD, "%02x", pdu->hdr->token[i]); + } + fprintf(COAP_DEBUG_FD, "}"); + + /* show options, if any */ + coap_option_iterator_init((coap_pdu_t *)pdu, &opt_iter, COAP_OPT_ALL); + + fprintf(COAP_DEBUG_FD, " ["); + while ((option = coap_option_next(&opt_iter))) { + if (!have_options) { + have_options = 1; + } else { + fprintf(COAP_DEBUG_FD, ","); + } + + switch (opt_iter.type) { + case COAP_OPTION_CONTENT_FORMAT: + content_format = (int)coap_decode_var_bytes(COAP_OPT_VALUE(option), + COAP_OPT_LENGTH(option)); + + buf_len = print_content_format(content_format, buf, sizeof(buf)); + break; + + case COAP_OPTION_BLOCK1: + case COAP_OPTION_BLOCK2: + /* split block option into number/more/size where more is the + * letter M if set, the _ otherwise */ + buf_len = snprintf((char *)buf, sizeof(buf), "%u/%c/%u", + coap_opt_block_num(option), /* block number */ + COAP_OPT_BLOCK_MORE(option) ? 'M' : '_', /* M bit */ + (2 << (COAP_OPT_BLOCK_SZX(option) + 4))); /* block size */ + + break; + + case COAP_OPTION_URI_PORT: + case COAP_OPTION_MAXAGE: + case COAP_OPTION_OBSERVE: + case COAP_OPTION_SIZE1: + /* show values as unsigned decimal value */ + buf_len = snprintf((char *)buf, sizeof(buf), "%u", + coap_decode_var_bytes(COAP_OPT_VALUE(option), + COAP_OPT_LENGTH(option))); + break; + + default: + /* generic output function for all other option types */ + if (opt_iter.type == COAP_OPTION_URI_PATH || + opt_iter.type == COAP_OPTION_PROXY_URI || + opt_iter.type == COAP_OPTION_URI_HOST || + opt_iter.type == COAP_OPTION_LOCATION_PATH || + opt_iter.type == COAP_OPTION_LOCATION_QUERY || + opt_iter.type == COAP_OPTION_URI_QUERY) { + encode = 0; + } else { + encode = 1; + } + + buf_len = print_readable(COAP_OPT_VALUE(option), + COAP_OPT_LENGTH(option), + buf, sizeof(buf), encode); + } + + fprintf(COAP_DEBUG_FD, " %s:%.*s", msg_option_string(opt_iter.type), + (int)buf_len, buf); + } + + fprintf(COAP_DEBUG_FD, " ]"); + + if (coap_get_data((coap_pdu_t *)pdu, &data_len, &data)) { + + fprintf(COAP_DEBUG_FD, " :: "); + + if (is_binary(content_format)) { + fprintf(COAP_DEBUG_FD, "<<"); + while (data_len--) { + fprintf(COAP_DEBUG_FD, "%02x", *data++); + } + fprintf(COAP_DEBUG_FD, ">>"); + } else { + if (print_readable(data, data_len, buf, sizeof(buf), 0)) { + fprintf(COAP_DEBUG_FD, "'%s'", buf); + } + } + } + + fprintf(COAP_DEBUG_FD, "\n"); + fflush(COAP_DEBUG_FD); +} + + +#endif /* NDEBUG */ + +void +coap_log_impl(const char *file, int line, coap_log_t level, const char *format, ...) { + char timebuf[32]; + coap_tick_t now; + va_list ap; + FILE *log_fd; + + if (maxlog < level) + return; + + //log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD; + log_fd = stderr; + + coap_ticks(&now); + if (print_timestamp(timebuf,sizeof(timebuf), now)) + fprintf(log_fd, "%s ", timebuf); + + if (level <= LOG_DEBUG) + fprintf(log_fd, "%s ", loglevels[level]); + + va_start(ap, format); + vfprintf(log_fd, format, ap); + va_end(ap); + fflush(log_fd); +} + From 93d0d501ff0ede4d2ee66a2e7e0ad5da3602e859 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Tue, 15 Sep 2015 16:17:15 +0200 Subject: [PATCH 67/69] Applied builds.patch --- Makefile.am | 2 +- examples/client.c | 6 +- examples/coap-rd.c | 6 +- examples/coap-server.c | 6 +- include/coap/coap_context.h | 8 --- include/coap/coap_io.h | 50 +++++++++++++---- include/coap/debug.h | 2 + include/coap/net.h | 4 +- platform/posix/libev/libev.la | 41 -------------- platform/posix/platform_io.c | 103 +++------------------------------- platform/posix/platform_io.h | 28 +-------- src/coap_context.c | 4 +- src/coap_debug.c | 4 +- src/coap_io.c | 4 +- src/net.c | 7 +-- src/pdu.c | 2 +- src/resource.c | 11 ++-- 17 files changed, 78 insertions(+), 210 deletions(-) delete mode 100644 platform/posix/libev/libev.la diff --git a/Makefile.am b/Makefile.am index 4c456c4fb4..e5bd8d514d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -59,7 +59,7 @@ libcoap_@LIBCOAP_API_VERSION@_la_SOURCES = \ src/block.c \ src/coap_io.c \ src/coap_context.c \ - src/debug.c \ + src/coap_debug.c \ src/encode.c \ src/hashkey.c \ src/mem.c \ diff --git a/examples/client.c b/examples/client.c index d355d7a9d0..015e9b81da 100644 --- a/examples/client.c +++ b/examples/client.c @@ -1207,15 +1207,15 @@ main(int argc, char **argv) { while ( !(ready && coap_can_exit(ctx)) ) { FD_ZERO(&readfds); - FD_SET( ctx->endpoint->handle.fd, &readfds ); + FD_SET( ctx->endpoint->fd, &readfds ); tv.tv_sec = wait_seconds; - result = select(ctx->endpoint->handle.fd + 1, &readfds, 0, 0, &tv); + result = select(ctx->endpoint->fd + 1, &readfds, 0, 0, &tv); if ( result < 0 ) { /* error */ perror("select"); } else if ( result > 0 ) { /* read from socket */ - if ( FD_ISSET( ctx->endpoint->handle.fd, &readfds ) ) { + if ( FD_ISSET( ctx->endpoint->fd, &readfds ) ) { coap_read( ctx ); /* read received data */ /* coap_dispatch( ctx ); /\* and dispatch PDUs from receivequeue *\/ */ } diff --git a/examples/coap-rd.c b/examples/coap-rd.c index 78f440670d..c7eff9feb4 100644 --- a/examples/coap-rd.c +++ b/examples/coap-rd.c @@ -657,7 +657,7 @@ join(coap_context_t *ctx, char *group_name) { } } - result = setsockopt(ctx->endpoint->handle.fd, + result = setsockopt(ctx->endpoint->fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq, sizeof(mreq) ); if ( result < 0 ) @@ -720,7 +720,7 @@ main(int argc, char **argv) { while ( !quit ) { FD_ZERO(&readfds); - FD_SET( ctx->endpoint->handle.fd, &readfds ); + FD_SET( ctx->endpoint->fd, &readfds ); coap_ticks(&now); @@ -733,7 +733,7 @@ main(int argc, char **argv) { if (errno != EINTR) perror("select"); } else if ( result > 0 ) { /* read from socket */ - if ( FD_ISSET( ctx->endpoint->handle.fd, &readfds ) ) { + if ( FD_ISSET( ctx->endpoint->fd, &readfds ) ) { coap_read( ctx ); /* read received data */ /* coap_dispatch( ctx ); /\* and dispatch PDUs from receivequeue *\/ */ } diff --git a/examples/coap-server.c b/examples/coap-server.c index 31bfc785a9..1799e64e7f 100644 --- a/examples/coap-server.c +++ b/examples/coap-server.c @@ -430,7 +430,7 @@ join(coap_context_t *ctx, char *group_name){ } } - result = setsockopt(ctx->endpoint->handle.fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, + result = setsockopt(ctx->endpoint->fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq, sizeof(mreq)); if (result < 0) perror("join: setsockopt"); @@ -495,7 +495,7 @@ main(int argc, char **argv) { while ( !quit ) { FD_ZERO(&readfds); - FD_SET( ctx->endpoint->handle.fd, &readfds ); + FD_SET( ctx->endpoint->fd, &readfds ); coap_ticks(&now); @@ -508,7 +508,7 @@ main(int argc, char **argv) { if (errno != EINTR) perror("select"); } else if ( result > 0 ) { /* read from socket */ - if ( FD_ISSET( ctx->endpoint->handle.fd, &readfds ) ) { + if ( FD_ISSET( ctx->endpoint->fd, &readfds ) ) { coap_read( ctx ); /* read received data */ /* coap_dispatch( ctx ); /\* and dispatch PDUs from receivequeue *\/ */ } diff --git a/include/coap/coap_context.h b/include/coap/coap_context.h index b8689f93a8..d3bf9159c0 100644 --- a/include/coap/coap_context.h +++ b/include/coap/coap_context.h @@ -76,14 +76,6 @@ typedef struct coap_context_t { unsigned int observe; coap_response_handler_t response_handler; - - ssize_t (*network_send)(struct coap_context_t *context, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - unsigned char *data, size_t datalen); - - ssize_t (*network_read)(coap_endpoint_t *ep, coap_packet_t **packet); - } coap_context_t; /** diff --git a/include/coap/coap_io.h b/include/coap/coap_io.h index 7aa3feeed2..8beafbe69a 100644 --- a/include/coap/coap_io.h +++ b/include/coap/coap_io.h @@ -28,18 +28,21 @@ #define COAP_ENDPOINT_NOSEC 0x00 #define COAP_ENDPOINT_DTLS 0x01 +#include "pdu.h" #include "platform_io.h" -struct coap_address_t; struct coap_context_t; -struct coap_packet_t; -struct coap_endpoint_t; +typedef struct coap_context_t coap_context_t; +struct coap_packet_t; typedef struct coap_packet_t coap_packet_t; -struct coap_endpoint_t *coap_new_endpoint(const struct coap_address_t *addr, int flags); +struct coap_endpoint_t; +typedef struct coap_endpoint_t coap_endpoint_t; + +coap_endpoint_t *coap_new_endpoint(const coap_address_t *addr, int flags); -void coap_free_endpoint(struct coap_endpoint_t *ep); +void coap_free_endpoint(coap_endpoint_t *ep); /** * Function interface for data transmission. This function returns the number of @@ -53,9 +56,9 @@ void coap_free_endpoint(struct coap_endpoint_t *ep); * @return The number of bytes written on success, or a value * less than zero on error. */ -typedef ssize_t (*coap_network_send_t)(struct coap_context_t *context, - const struct coap_endpoint_t *local_interface, - const struct coap_address_t *dst, const coap_pdu_t *pdu); +typedef ssize_t (*coap_network_send_t)(coap_context_t *context, + const coap_endpoint_t *local_interface, + const coap_address_t *dst, const coap_pdu_t *pdu); /** * Function interface for reading data. This function returns the number of @@ -70,7 +73,32 @@ typedef ssize_t (*coap_network_send_t)(struct coap_context_t *context, * @return The number of bytes received on success, or a value less than * zero on error. */ -typedef ssize_t (*coap_network_read_t)(struct coap_endpoint_t *ep, coap_packet_t **packet); +typedef ssize_t (*coap_network_read_t)(coap_endpoint_t *ep, coap_packet_t **packet); + +/** + * Abstraction of virtual endpoint that can be attached to coap_context_t. The + * tuple (handle, addr) must uniquely identify this endpoint. + */ +struct coap_endpoint_t { + coap_address_t addr; /**< local interface address */ + int ifindex; + int flags; + coap_network_read_t network_read; + coap_network_send_t network_send; + PLATFORM_ENDPOINT_PROPERTIES +}; + +struct coap_packet_t { + coap_address_t src; /**< the packet's source address */ + coap_address_t dst; /**< the packet's destination address */ + const coap_endpoint_t *interface; + + int ifindex; + void *session; /**< opaque session data */ + + size_t length; /**< length of payload */ + unsigned char payload[]; /**< payload */ +}; #ifndef coap_mcast_interface # define coap_mcast_interface(Local) 0 @@ -91,12 +119,12 @@ void coap_free_packet(coap_packet_t *packet); * This is usually used to copy a packet's data into a node's local_if member. */ void coap_packet_populate_endpoint(coap_packet_t *packet, - struct coap_endpoint_t *target); + coap_endpoint_t *target); /** * Given an incoming packet, copy its source address into an address struct. */ -void coap_packet_copy_source(coap_packet_t *packet, struct coap_address_t *target); +void coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target); /** * Given a packet, set msg and msg_len to an address and length of the packet's diff --git a/include/coap/debug.h b/include/coap/debug.h index cba503ff32..af88c8b62d 100644 --- a/include/coap/debug.h +++ b/include/coap/debug.h @@ -17,6 +17,8 @@ #define COAP_ERR_FD stderr #endif +#include + #ifdef HAVE_SYSLOG_H #include typedef short coap_log_t; diff --git a/include/coap/net.h b/include/coap/net.h index 19ebb3d6a4..d81cf0fae9 100644 --- a/include/coap/net.h +++ b/include/coap/net.h @@ -120,7 +120,7 @@ coap_queue_t *coap_pop_next( coap_context_t *context ); /** * Creates a new coap_context_t object that will hold the CoAP stack status. */ -coap_context_t *coap_new_context(void); +coap_context_t *coap_new_context(const coap_address_t *listen_addr); /** * Returns a new message id and updates @p context->message_id accordingly. The @@ -305,7 +305,7 @@ coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node); * returned and a new node with the parsed PDU is added to the receive queue in * the specified context object. */ -int coap_read(coap_context_t *context, coap_endpoint_t *endpoint); +int coap_read(coap_context_t *context); /** * Parses and interprets a CoAP message with context @p ctx. This function diff --git a/platform/posix/libev/libev.la b/platform/posix/libev/libev.la deleted file mode 100644 index a7afa4daae..0000000000 --- a/platform/posix/libev/libev.la +++ /dev/null @@ -1,41 +0,0 @@ -# libev.la - a libtool library file -# Generated by libtool (GNU libtool) 2.4.6 -# -# Please DO NOT delete this file! -# It is necessary for linking the library. - -# The name that we can dlopen(3). -dlname='libev.4.dylib' - -# Names of this library. -library_names='libev.4.dylib libev.dylib' - -# The name of the static archive. -old_library='libev.a' - -# Linker flags that cannot go in dependency_libs. -inherited_linker_flags=' ' - -# Libraries that this one depends upon. -dependency_libs='' - -# Names of additional weak libraries provided by this library -weak_library_names='' - -# Version information for libev. -current=4 -age=0 -revision=0 - -# Is this an already installed library? -installed=no - -# Should we warn about portability when linking against -modules? -shouldnotlink=no - -# Files to dlopen/dlpreopen -dlopen='' -dlpreopen='' - -# Directory that this library needs to be installed in: -libdir='/usr/local/lib' diff --git a/platform/posix/platform_io.c b/platform/posix/platform_io.c index aa4bbb3723..c497a9f6b0 100644 --- a/platform/posix/platform_io.c +++ b/platform/posix/platform_io.c @@ -1,3 +1,4 @@ +#include "coap_config.h" #include "coap_io.h" #include "debug.h" @@ -8,6 +9,8 @@ #define SOL_IP IPPROTO_IP #endif +#define SIN6(A) ((struct sockaddr_in6 *)(A)) + #if !defined(HAVE_NETINET_IN_H) /* define struct in6_pktinfo and struct in_pktinfo if not available FIXME: check with configure @@ -24,96 +27,8 @@ struct in_pktinfo { }; #endif -static struct coap_endpoint_t * -coap_malloc_posix_endpoint(void) { - return (struct coap_endpoint_t *)coap_malloc(sizeof(struct coap_endpoint_t)); -} - -static void -coap_free_posix_endpoint(struct coap_endpoint_t *ep) { - coap_free(ep); -} - -coap_endpoint_t * -coap_new_endpoint(const coap_address_t *addr, int flags) { - int sockfd = socket(addr->addr.sa.sa_family, SOCK_DGRAM, 0); - int on = 1; - struct coap_endpoint_t *ep; - - if (sockfd < 0) { - coap_log(LOG_WARNING, "coap_new_endpoint: socket"); - return NULL; - } - - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) - coap_log(LOG_WARNING, "coap_new_endpoint: setsockopt SO_REUSEADDR"); - - on = 1; - switch(addr->addr.sa.sa_family) { - case AF_INET: - if (setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) < 0) - coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IP_PKTINFO\n"); - break; - case AF_INET6: -#ifdef IPV6_RECVPKTINFO - if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) - coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_RECVPKTINFO\n"); -#else /* IPV6_RECVPKTINFO */ - if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) < 0) - coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_PKTINFO\n"); -#endif /* IPV6_RECVPKTINFO */ - break; - default: - coap_log(LOG_ALERT, "coap_new_endpoint: unsupported sa_family\n"); - } - - if (bind(sockfd, &addr->addr.sa, addr->size) < 0) { - coap_log(LOG_WARNING, "coap_new_endpoint: bind"); - close (sockfd); - return NULL; - } - - ep = coap_malloc_posix_endpoint(); - if (!ep) { - coap_log(LOG_WARNING, "coap_new_endpoint: malloc"); - close(sockfd); - return NULL; - } - - memset(ep, 0, sizeof(struct coap_endpoint_t)); - ep->handle.fd = sockfd; - ep->flags = flags; - memcpy(&ep->addr, addr, sizeof(coap_address_t)); - -#ifndef NDEBUG - if (LOG_DEBUG <= coap_get_log_level()) { -#ifndef INET6_ADDRSTRLEN -#define INET6_ADDRSTRLEN 40 -#endif - unsigned char addr_str[INET6_ADDRSTRLEN+8]; - - if (coap_print_addr(addr, addr_str, INET6_ADDRSTRLEN+8)) { - debug("created %sendpoint %s\n", - ep->flags & COAP_ENDPOINT_DTLS ? "DTLS " : "", - addr_str); - } - } -#endif /* NDEBUG */ - - return (coap_endpoint_t *)ep; -} - -void -coap_free_endpoint(coap_endpoint_t *ep) { - if(ep) { - if (ep->handle.fd >= 0) - close(ep->handle.fd); - coap_free_posix_endpoint((struct coap_endpoint_t *)ep); - } -} - ssize_t -coap_network_send(struct coap_context_t *context UNUSED_PARAM, +coap_network_send(struct coap_context_t *context, const coap_endpoint_t *local_interface, const coap_address_t *dst, unsigned char *data, @@ -202,7 +117,7 @@ coap_network_send(struct coap_context_t *context UNUSED_PARAM, return -1; } - return sendmsg(ep->handle.fd, &mhdr, 0); + return sendmsg(ep->fd, &mhdr, 0); } coap_packet_t * @@ -258,7 +173,7 @@ coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) { mhdr.msg_controllen = sizeof(msg_control); assert(sizeof(msg_control) == CMSG_LEN(sizeof(struct sockaddr_storage))); - len = recvmsg(ep->handle.fd, &mhdr, 0); + len = recvmsg(ep->fd, &mhdr, 0); if (len < 0) { coap_log(LOG_WARNING, "coap_network_read: %s\n", strerror(errno)); @@ -266,11 +181,11 @@ coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) { } else { struct cmsghdr *cmsg; - coap_log(LOG_DEBUG, "received %d bytes on fd %d\n", (int)len, ep->handle.fd); + coap_log(LOG_DEBUG, "received %d bytes on fd %d\n", (int)len, ep->fd); /* use getsockname() to get the local port */ (*packet)->dst.size = sizeof((*packet)->dst.addr); - if (getsockname(ep->handle.fd, &(*packet)->dst.addr.sa, &(*packet)->dst.size) < 0) { + if (getsockname(ep->fd, &(*packet)->dst.addr.sa, &(*packet)->dst.size) < 0) { coap_log(LOG_DEBUG, "cannot determine local port\n"); goto error; } @@ -353,8 +268,6 @@ coap_new_endpoint(const coap_address_t *addr, int flags) if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) coap_log(LOG_WARNING, "coap_new_endpoint: setsockopt SO_REUSEADDR"); - fcntl(sockfd, F_SETFL, O_NONBLOCK); - on = 1; switch (addr->addr.sa.sa_family) { case AF_INET: diff --git a/platform/posix/platform_io.h b/platform/posix/platform_io.h index f1b5a436cb..fc16b47aed 100644 --- a/platform/posix/platform_io.h +++ b/platform/posix/platform_io.h @@ -23,31 +23,9 @@ #include -/** - * Abstraction of virtual endpoint that can be attached to coap_context_t. The - * tuple (handle, addr) must uniquely identify this endpoint. - */ -typedef struct coap_endpoint_t { - int fd; /**< on POSIX systems */ - coap_address_t addr; /**< local interface address */ - int ifindex; - int flags; - coap_network_read_t network_read; - coap_network_send_t network_send; -} coap_endpoint_t; - -struct coap_packet_t { - coap_if_handle_t hnd; /**< the interface handle */ - coap_address_t src; /**< the packet's source address */ - coap_address_t dst; /**< the packet's destination address */ - const coap_endpoint_t *interface; - - int ifindex; - void *session; /**< opaque session data */ - - size_t length; /**< length of payload */ - unsigned char payload[]; /**< payload */ -}; +#include "address.h" +#define PLATFORM_ENDPOINT_PROPERTIES \ + int fd; #endif /* _PLATFORM_IO_H_ */ diff --git a/src/coap_context.c b/src/coap_context.c index eda8748471..6efa841bb1 100644 --- a/src/coap_context.c +++ b/src/coap_context.c @@ -32,6 +32,7 @@ #include "block.h" #include "net.h" #include "coap_timer.h" +#include "coap_io.h" #ifdef WITH_CONTIKI // TODO Should be more abstracted. E.g. CONTEXT_SINGLETON unsigned char initialized = 0; @@ -127,9 +128,6 @@ coap_new_context( goto onerror; } - c->network_send = coap_network_send; - c->network_read = coap_network_read; - # ifndef WITHOUT_OBSERVE c->notify_timer = coap_new_timer(notify_timer_cb, (void *)c); coap_timer_set(c->notify_timer, COAP_RESOURCE_CHECK_TIME * COAP_TICKS_PER_SECOND); diff --git a/src/coap_debug.c b/src/coap_debug.c index 1df63e763a..6aa54498b0 100644 --- a/src/coap_debug.c +++ b/src/coap_debug.c @@ -7,7 +7,7 @@ */ #include "coap_config.h" -#include "coap_posix_io.h" +#include "coap_io.h" #if defined(HAVE_STRNLEN) && defined(__GNUC__) && !defined(_GNU_SOURCE) #define _GNU_SOURCE 1 @@ -32,7 +32,7 @@ #include "coap_time.h" #include "block.h" -#include "coap/debug.h" +#include "debug.h" #include "encode.h" #include "net.h" diff --git a/src/coap_io.c b/src/coap_io.c index e1d8c0202c..d5edb603fe 100644 --- a/src/coap_io.c +++ b/src/coap_io.c @@ -15,14 +15,14 @@ #include "platform_io.h" size_t -coap_get_max_packetlength(const coap_packet_t *packet UNUSED_PARAM) { +coap_get_max_packetlength(const coap_packet_t *packet) { return COAP_MAX_PDU_SIZE; } void coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target) { - target->handle = packet->interface->handle; + *target = *packet->interface; memcpy(&target->addr, &packet->dst, sizeof(target->addr)); target->ifindex = packet->ifindex; target->flags = 0; /* FIXME */ diff --git a/src/net.c b/src/net.c index 59ee91a2b4..70bdc64384 100644 --- a/src/net.c +++ b/src/net.c @@ -477,7 +477,6 @@ coap_send_confirmed(coap_context_t *context, if (node == context->sendqueue) { coap_timer_set(context->retransmit_timer, node->t); } -#endif /* WITH_CONTIKI */ return node->id; } @@ -528,12 +527,12 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) { void coap_dispatch(coap_context_t *context, coap_queue_t *rcvd); int -coap_read(coap_context_t *ctx, coap_endpoint_t *endpoint) { +coap_read(coap_context_t *ctx) { ssize_t bytes_read = -1; coap_packet_t *packet; int result = -1; /* the value to be returned */ - bytes_read = endpoint->network_read(endpoint, &packet); + bytes_read = ctx->endpoint->network_read(ctx->endpoint, &packet); if (bytes_read < 0) { //warn("coap_read: recvfrom"); @@ -597,8 +596,6 @@ coap_handle_message(coap_context_t *ctx, coap_ticks(&node->t); - node->local_if = *packet->interface; - coap_packet_populate_endpoint(packet, &node->local_if); coap_packet_copy_source(packet, &node->remote); diff --git a/src/pdu.c b/src/pdu.c index 6dbe4058b6..4279806005 100644 --- a/src/pdu.c +++ b/src/pdu.c @@ -106,7 +106,7 @@ coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data) { return 0; pdu->hdr->token_length = len; - if (len) + if (len) { memcpy(pdu->hdr->token, data, len); } pdu->max_delta = 0; diff --git a/src/resource.c b/src/resource.c index 1fa35ed305..6bcc96f7cf 100644 --- a/src/resource.c +++ b/src/resource.c @@ -350,11 +350,12 @@ coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key) { void coap_add_resource(coap_context_t *context, coap_resource_t *resource) { RESOURCES_ADD(context->resources, resource); - if (!resource->dynamic) { - resource->uri.length = strlen(resource->uri.s); - coap_hash_path(resource->uri.s, resource->uri.length, resource->key); - } - debug("Added resource 0x%02x%02x%02x%02x\n", resource->key[0], resource->key[1], resource->key[2], resource->key[3]); +// FIXME don't know what this dynamic stuff is, but it ain't working +// if (!resource->dynamic) { +// resource->uri.length = strlen(resource->uri.s); +// coap_hash_path(resource->uri.s, resource->uri.length, resource->key); +// } +// debug("Added resource 0x%02x%02x%02x%02x\n", resource->key[0], resource->key[1], resource->key[2], resource->key[3]); } static void From 60c613ad7d7cf2280a4393872f6511890549ca8e Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Tue, 15 Sep 2015 16:27:41 +0200 Subject: [PATCH 68/69] Fixed multiline make (?) --- Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index e5bd8d514d..2802174329 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,8 +29,8 @@ EXTRA_DIST = \ # FIXME Only add for posix AM_CFLAGS = -I @top_builddir@/include/coap/ \ - -I @top_builddir@/platform/@PLATFORM@/ - $(WARNING_CFLAGS) -std=c99 + -I @top_builddir@/platform/@PLATFORM@/ \ + $(WARNING_CFLAGS) -std=c99 # FIXME Only add for posix SUBDIRS = . platform/posix/libev $(DOC_DIR) tests examples From 6d18483cacd08b505e724f4bd1042276e3f1df86 Mon Sep 17 00:00:00 2001 From: Wojciech Bober Date: Tue, 15 Sep 2015 17:57:31 +0200 Subject: [PATCH 69/69] Fixed example/client --- examples/client.c | 42 +++++++++++++++++------------ include/coap/coap_context.h | 4 ++- include/coap/debug.h | 5 ++-- include/coap/net.h | 7 +---- include/coap/resource.h | 4 +-- platform/posix/platform_io.c | 16 +++++------ src/coap_context.c | 51 ++++++------------------------------ src/coap_io.c | 2 +- src/net.c | 16 +++++------ 9 files changed, 59 insertions(+), 88 deletions(-) diff --git a/examples/client.c b/examples/client.c index 015e9b81da..5cedb36782 100644 --- a/examples/client.c +++ b/examples/client.c @@ -978,9 +978,9 @@ cmdline_method(char *arg) { return i; /* note that we do not prevent illegal methods */ } -static coap_context_t * -get_context(const char *node, const char *port) { - coap_context_t *ctx = NULL; +static coap_endpoint_t * +create_endpoint(const char *node, const char *port) { + coap_endpoint_t *ep = NULL; int s; struct addrinfo hints; struct addrinfo *result, *rp; @@ -1005,24 +1005,25 @@ get_context(const char *node, const char *port) { addr.size = rp->ai_addrlen; memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen); - ctx = coap_new_context(&addr); - if (ctx) { + ep = coap_new_endpoint(&addr, 0); + if (ep) { /* TODO: output address:port for successful binding */ goto finish; } } } - fprintf(stderr, "no context available for interface '%s'\n", node); + fprintf(stderr, "failed to create endpoint for interface '%s'\n", node); finish: freeaddrinfo(result); - return ctx; + return ep; } int main(int argc, char **argv) { coap_context_t *ctx = NULL; + coap_endpoint_t *ep = NULL; coap_address_t dst; static char addr[INET6_ADDRSTRLEN]; void *addrptr = NULL; @@ -1146,18 +1147,24 @@ main(int argc, char **argv) { addrptr = &dst.addr.sin.sin_addr; /* create context for IPv4 */ - ctx = get_context(node_str[0] == 0 ? "0.0.0.0" : node_str, port_str); + ep = create_endpoint(node_str[0] == 0 ? "0.0.0.0" : node_str, port_str); break; case AF_INET6: addrptr = &dst.addr.sin6.sin6_addr; /* create context for IPv6 */ - ctx = get_context(node_str[0] == 0 ? "::" : node_str, port_str); + ep = create_endpoint(node_str[0] == 0 ? "::" : node_str, port_str); break; default: ; } + if (!ep) { + coap_log(LOG_EMERG, "cannot create endpoint\n"); + return -1; + } + + ctx = coap_new_context(); if (!ctx) { coap_log(LOG_EMERG, "cannot create context\n"); return -1; @@ -1195,9 +1202,9 @@ main(int argc, char **argv) { #endif if (pdu->hdr->type == COAP_MESSAGE_CON) - tid = coap_send_confirmed(ctx, ctx->endpoint, &dst, pdu); + tid = coap_send_confirmed(ctx, ep, &dst, pdu); else - tid = coap_send(ctx, ctx->endpoint, &dst, pdu); + tid = coap_send(ctx, ep, &dst, pdu); if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID) coap_delete_pdu(pdu); @@ -1207,16 +1214,16 @@ main(int argc, char **argv) { while ( !(ready && coap_can_exit(ctx)) ) { FD_ZERO(&readfds); - FD_SET( ctx->endpoint->fd, &readfds ); + FD_SET(ep->fd, &readfds ); tv.tv_sec = wait_seconds; - result = select(ctx->endpoint->fd + 1, &readfds, 0, 0, &tv); + result = select(ep->fd + 1, &readfds, 0, 0, &tv); if ( result < 0 ) { /* error */ perror("select"); } else if ( result > 0 ) { /* read from socket */ - if ( FD_ISSET( ctx->endpoint->fd, &readfds ) ) { - coap_read( ctx ); /* read received data */ + if ( FD_ISSET(ep->fd, &readfds ) ) { + coap_read( ctx, ep ); /* read received data */ /* coap_dispatch( ctx ); /\* and dispatch PDUs from receivequeue *\/ */ } } else { /* timeout */ @@ -1227,7 +1234,7 @@ main(int argc, char **argv) { } if (obs_wait && obs_wait <= now) { debug("clear observation relationship\n"); - clear_obs(ctx, ctx->endpoint, &dst); /* FIXME: handle error case COAP_TID_INVALID */ + clear_obs(ctx, ep, &dst); /* FIXME: handle error case COAP_TID_INVALID */ /* make sure that the obs timer does not fire again */ obs_wait = 0; @@ -1239,7 +1246,8 @@ main(int argc, char **argv) { close_output(); coap_delete_list(optlist); - coap_free_context( ctx ); + coap_free_context(ctx); + coap_free_endpoint(ep); return 0; } diff --git a/include/coap/coap_context.h b/include/coap/coap_context.h index d3bf9159c0..1bbaac830c 100644 --- a/include/coap/coap_context.h +++ b/include/coap/coap_context.h @@ -53,7 +53,9 @@ typedef struct coap_context_t { * to sendqueue_basetime. */ coap_tick_t sendqueue_basetime; coap_queue_t *sendqueue; +#if 0 coap_endpoint_t *endpoint; /**< the endpoint used for listening */ +#endif #ifdef WITH_CONTIKI struct uip_udp_conn *conn; /**< uIP connection object */ @@ -81,7 +83,7 @@ typedef struct coap_context_t { /** * Creates a new coap_context_t object that will hold the CoAP stack status. */ -coap_context_t *coap_new_context(const coap_address_t *listen_addr); +coap_context_t *coap_new_context(void); /** * CoAP stack context must be released with coap_free_context(). This function diff --git a/include/coap/debug.h b/include/coap/debug.h index af88c8b62d..f8e8d3a324 100644 --- a/include/coap/debug.h +++ b/include/coap/debug.h @@ -39,8 +39,9 @@ typedef enum { #define min(a,b) ((a) < (b) ? (a) : (b)) #endif +#include /** Returns a textual description of the message type @p t. */ -static const char * +static inline const char * msg_type_string(uint8_t t) { static const char * const types[] = { "CON", "NON", "ACK", "RST", "???" }; @@ -48,7 +49,7 @@ msg_type_string(uint8_t t) { } /** Returns a textual description of the method or response code. */ -static const char * +static inline const char * msg_code_string(uint8_t c) { static const char * const methods[] = { "0.00", "GET", "POST", "PUT", "DELETE", "PATCH" }; static char buf[5]; diff --git a/include/coap/net.h b/include/coap/net.h index d81cf0fae9..6adcdb33bc 100644 --- a/include/coap/net.h +++ b/include/coap/net.h @@ -117,11 +117,6 @@ coap_queue_t *coap_peek_next( coap_context_t *context ); */ coap_queue_t *coap_pop_next( coap_context_t *context ); -/** - * Creates a new coap_context_t object that will hold the CoAP stack status. - */ -coap_context_t *coap_new_context(const coap_address_t *listen_addr); - /** * Returns a new message id and updates @p context->message_id accordingly. The * message id is returned in network byte order to make it easier to read in @@ -305,7 +300,7 @@ coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node); * returned and a new node with the parsed PDU is added to the receive queue in * the specified context object. */ -int coap_read(coap_context_t *context); +int coap_read(coap_context_t *context, coap_endpoint_t *ep); /** * Parses and interprets a CoAP message with context @p ctx. This function diff --git a/include/coap/resource.h b/include/coap/resource.h index d3d039d012..30c3199c67 100644 --- a/include/coap/resource.h +++ b/include/coap/resource.h @@ -66,7 +66,7 @@ typedef struct coap_resource_t { * been notified of the last change */ unsigned int observable:1; /**< can be observed */ unsigned int cacheable:1; /**< can be cached */ - unsigned int dynamic:1; /**< should be freed */ + unsigned int dynamic:1; /**< should be freed */ /** * Used to store handlers for the four coap methods @c GET, @c POST, @c PUT, @@ -151,7 +151,7 @@ void coap_delete_all_resources(coap_context_t *context); */ void coap_delete_resource_by_pattern(coap_context_t *context, const char *pattern); -/** +/** * Registers a new attribute with the given @p resource. As the * attributes str fields will point to @p name and @p val the * caller must ensure that these pointers are valid during the diff --git a/platform/posix/platform_io.c b/platform/posix/platform_io.c index c497a9f6b0..f9c35e6f95 100644 --- a/platform/posix/platform_io.c +++ b/platform/posix/platform_io.c @@ -9,7 +9,7 @@ #define SOL_IP IPPROTO_IP #endif -#define SIN6(A) ((struct sockaddr_in6 *)(A)) +#define SIN6(A) ((struct sockaddr_in6 *)(A)) #if !defined(HAVE_NETINET_IN_H) /* define struct in6_pktinfo and struct in_pktinfo if not available @@ -27,12 +27,10 @@ struct in_pktinfo { }; #endif -ssize_t +static ssize_t coap_network_send(struct coap_context_t *context, const coap_endpoint_t *local_interface, - const coap_address_t *dst, - unsigned char *data, - size_t datalen) { + const coap_address_t *dst, const coap_pdu_t *pdu) { struct coap_endpoint_t *ep = (struct coap_endpoint_t *)local_interface; @@ -41,10 +39,12 @@ coap_network_send(struct coap_context_t *context, struct msghdr mhdr; struct iovec iov[1]; + (void)context; + assert(local_interface); - iov[0].iov_base = data; - iov[0].iov_len = datalen; + iov[0].iov_base = pdu->hdr; + iov[0].iov_len = pdu->length; memset(&mhdr, 0, sizeof(struct msghdr)); mhdr.msg_name = (void *)&dst->addr; @@ -138,7 +138,7 @@ coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target) memcpy(target, &packet->src, sizeof(coap_address_t)); } -ssize_t +static ssize_t coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) { ssize_t len = -1; char msg_control[CMSG_LEN(sizeof(struct sockaddr_storage))]; diff --git a/src/coap_context.c b/src/coap_context.c index 6efa841bb1..b9bf0cbfca 100644 --- a/src/coap_context.c +++ b/src/coap_context.c @@ -34,11 +34,6 @@ #include "coap_timer.h" #include "coap_io.h" -#ifdef WITH_CONTIKI // TODO Should be more abstracted. E.g. CONTEXT_SINGLETON -unsigned char initialized = 0; -coap_context_t the_coap_context; -#endif - #ifndef WITHOUT_OBSERVE static void notify_timer_cb(void *data) { coap_context_t *c = data; @@ -65,46 +60,21 @@ static void retransmit_timer_cb(void *data) { } } -coap_context_t * -coap_new_context( - const coap_address_t *listen_addr) { - coap_timer_init(); -#ifndef WITH_CONTIKI - coap_context_t *c = coap_malloc_type(COAP_CONTEXT, sizeof( coap_context_t ) ); -#endif /* not WITH_CONTIKI */ -#ifdef WITH_CONTIKI - coap_context_t *c; - - if (initialized) - return NULL; -#endif /* WITH_CONTIKI */ - - if (!listen_addr) { - coap_log(LOG_EMERG, "no listen address specified\n"); - return NULL; - } +coap_context_t* +coap_new_context(void) { + //FIXME: move this to coap_platform_init()? + coap_timer_init(); coap_clock_init(); - coap_tick_t now; coap_ticks(&now); - prng_init((ptrdiff_t)listen_addr ^ now); + prng_init((ptrdiff_t)now); -#ifndef WITH_CONTIKI + coap_context_t *c = coap_malloc_type(COAP_CONTEXT, sizeof( coap_context_t ) ); if (!c) { -#ifndef NDEBUG coap_log(LOG_EMERG, "coap_init: malloc:\n"); -#endif return NULL; } -#endif /* not WITH_CONTIKI */ -#ifdef WITH_CONTIKI - coap_memory_init(); - - c = &the_coap_context; - initialized = 1; -#endif /* WITH_CONTIKI */ - memset(c, 0, sizeof( coap_context_t ) ); /* initialize message id */ @@ -123,10 +93,12 @@ coap_new_context( coap_register_option(c, COAP_OPTION_BLOCK2); coap_register_option(c, COAP_OPTION_BLOCK1); +#if 0 c->endpoint = coap_new_endpoint(listen_addr, COAP_ENDPOINT_NOSEC); if (c->endpoint == NULL) { goto onerror; } +#endif # ifndef WITHOUT_OBSERVE c->notify_timer = coap_new_timer(notify_timer_cb, (void *)c); @@ -156,13 +128,6 @@ coap_free_context(coap_context_t *context) { #endif coap_delete_all_resources(context); - - coap_free_endpoint(context->endpoint); -#ifdef WITH_CONTIKI - memset(&the_coap_context, 0, sizeof(coap_context_t)); - initialized = 0; -#else coap_free_type(COAP_CONTEXT, context); -#endif /* WITH_CONTIKI */ } diff --git a/src/coap_io.c b/src/coap_io.c index d5edb603fe..df0b78a20e 100644 --- a/src/coap_io.c +++ b/src/coap_io.c @@ -3,7 +3,7 @@ * Copyright (C) 2012,2014 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" diff --git a/src/net.c b/src/net.c index 70bdc64384..03827d59ee 100644 --- a/src/net.c +++ b/src/net.c @@ -3,7 +3,7 @@ * Copyright (C) 2010--2015 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" @@ -189,7 +189,7 @@ coap_delete_node(coap_queue_t *node) { return 0; coap_delete_pdu(node->pdu); - coap_free_node(node); + coap_free_type(COAP_NODE, node); return 1; } @@ -245,14 +245,14 @@ coap_pop_next( coap_context_t *context ) { #ifdef COAP_DEFAULT_WKC_HASHKEY /** Checks if @p Key is equal to the pre-defined hash key for.well-known/core. */ -int +static int is_wkc(coap_key_t k) { return (memcmp(k, COAP_DEFAULT_WKC_HASHKEY, sizeof(coap_key_t)) == 0); } #else /* Implements a singleton to store a hash key for the .wellknown/core * resources. */ -int +static int is_wkc(coap_key_t k) { static coap_key_t wkc; static unsigned char _initialized = 0; @@ -363,7 +363,7 @@ coap_send_error(coap_context_t *context, coap_pdu_t *request, result = coap_send(context, local_interface, dst, response); coap_delete_pdu(response); } - + return result; } @@ -377,7 +377,7 @@ coap_send_message_type(coap_context_t *context, coap_tid_t result = COAP_INVALID_TID; if (request) { - response = coap_pdu_init(type, 0, request->hdr->id, sizeof(coap_pdu_t)); + response = coap_pdu_init(type, 0, request->hdr->id, sizeof(coap_pdu_t)); if (response) { result = coap_send(context, local_interface, dst, response); coap_delete_pdu(response); @@ -527,12 +527,12 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) { void coap_dispatch(coap_context_t *context, coap_queue_t *rcvd); int -coap_read(coap_context_t *ctx) { +coap_read(coap_context_t *ctx, coap_endpoint_t *ep) { ssize_t bytes_read = -1; coap_packet_t *packet; int result = -1; /* the value to be returned */ - bytes_read = ctx->endpoint->network_read(ctx->endpoint, &packet); + bytes_read = ep->network_read(ep, &packet); if (bytes_read < 0) { //warn("coap_read: recvfrom");