netutils/libcoap : introduce libcoap 4.1.1
authorJin-Seong Kim <jseong82.kim@samsung.com>
Mon, 15 May 2017 07:16:08 +0000 (16:16 +0900)
committerEunBong Song <eunb.song@samsung.com>
Tue, 11 Jul 2017 01:26:55 +0000 (10:26 +0900)
This commit is to introduce libcoap 4.1.1
 source path - apps/netutils/libcoap
 header path - apps/include/netutils/libcoap

Change-Id: I6f3d4e8ec163813e68fe539a6fb8ebc288ab8b00
Signed-off-by: Jin-Seong Kim <jseong82.kim@samsung.com>
Signed-off-by: EunBong Song <eunb.song@samsung.com>
43 files changed:
apps/include/netutils/libcoap/address.h [new file with mode: 0644]
apps/include/netutils/libcoap/async.h [new file with mode: 0644]
apps/include/netutils/libcoap/bits.h [new file with mode: 0644]
apps/include/netutils/libcoap/block.h [new file with mode: 0644]
apps/include/netutils/libcoap/coap.h [new file with mode: 0644]
apps/include/netutils/libcoap/coap_list.h [new file with mode: 0644]
apps/include/netutils/libcoap/coap_time.h [new file with mode: 0644]
apps/include/netutils/libcoap/config.h [new file with mode: 0644]
apps/include/netutils/libcoap/debug.h [new file with mode: 0644]
apps/include/netutils/libcoap/encode.h [new file with mode: 0644]
apps/include/netutils/libcoap/hashkey.h [new file with mode: 0644]
apps/include/netutils/libcoap/lwippools.h [new file with mode: 0644]
apps/include/netutils/libcoap/mem.h [new file with mode: 0644]
apps/include/netutils/libcoap/net.h [new file with mode: 0644]
apps/include/netutils/libcoap/option.h [new file with mode: 0644]
apps/include/netutils/libcoap/pdu.h [new file with mode: 0644]
apps/include/netutils/libcoap/prng.h [new file with mode: 0644]
apps/include/netutils/libcoap/resource.h [new file with mode: 0644]
apps/include/netutils/libcoap/str.h [new file with mode: 0644]
apps/include/netutils/libcoap/subscribe.h [new file with mode: 0644]
apps/include/netutils/libcoap/t_list.h [new file with mode: 0644]
apps/include/netutils/libcoap/uri.h [new file with mode: 0644]
apps/include/netutils/libcoap/uthash.h [new file with mode: 0644]
apps/include/netutils/libcoap/utlist.h [new file with mode: 0644]
apps/netutils/libcoap/Kconfig [new file with mode: 0644]
apps/netutils/libcoap/LICENSE.BSD [new file with mode: 0644]
apps/netutils/libcoap/LICENSE.GPL [new file with mode: 0644]
apps/netutils/libcoap/Make.defs [new file with mode: 0644]
apps/netutils/libcoap/Makefile [new file with mode: 0644]
apps/netutils/libcoap/README [new file with mode: 0644]
apps/netutils/libcoap/async.c [new file with mode: 0644]
apps/netutils/libcoap/block.c [new file with mode: 0644]
apps/netutils/libcoap/coap_list.c [new file with mode: 0644]
apps/netutils/libcoap/debug.c [new file with mode: 0644]
apps/netutils/libcoap/encode.c [new file with mode: 0644]
apps/netutils/libcoap/hashkey.c [new file with mode: 0644]
apps/netutils/libcoap/net.c [new file with mode: 0644]
apps/netutils/libcoap/option.c [new file with mode: 0644]
apps/netutils/libcoap/pdu.c [new file with mode: 0644]
apps/netutils/libcoap/resource.c [new file with mode: 0644]
apps/netutils/libcoap/str.c [new file with mode: 0644]
apps/netutils/libcoap/subscribe.c [new file with mode: 0644]
apps/netutils/libcoap/uri.c [new file with mode: 0644]

diff --git a/apps/include/netutils/libcoap/address.h b/apps/include/netutils/libcoap/address.h
new file mode 100644 (file)
index 0000000..bfabf81
--- /dev/null
@@ -0,0 +1,164 @@
+/* address.h -- representation of network addresses
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+/**
+ * @file address.h
+ * @brief representation of network addresses
+ */
+
+#ifndef _COAP_ADDRESS_H_
+#define _COAP_ADDRESS_H_
+
+#include "config.h"
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#else
+#ifndef assert
+#warning "assertions are disabled"
+#define assert(x)
+#endif
+#endif
+
+#include <string.h>
+#include <stdint.h>
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <sys/socket.h>
+#endif
+
+#ifdef WITH_LWIP
+#include <net/lwip/ipv4/ip_addr.h>
+
+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:
+#ifdef IN6_IS_ADDR_MULTICAST
+               return IN6_IS_ADDR_MULTICAST(&a->addr.sin6.sin6_addr);
+#else
+               return 0;
+#endif
+       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 storing addresses.
+ *
+ * @param addr The coap_address_t object to initialize.
+ */
+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
+}
+
+/**
+ * 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;
+ */
+static inline int coap_address_equals(const coap_address_t *a, const coap_address_t *b)
+{
+       assert(a);
+       assert(b);
+       return _coap_address_equals_impl(a, b);
+}
+
+/**
+ * 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 coap_is_mcast(const coap_address_t *a)
+{
+       return a && _coap_is_mcast_impl(a);
+}
+
+#endif                                                 /* _COAP_ADDRESS_H_ */
diff --git a/apps/include/netutils/libcoap/async.h b/apps/include/netutils/libcoap/async.h
new file mode 100644 (file)
index 0000000..25892d8
--- /dev/null
@@ -0,0 +1,145 @@
+/* async.h -- state management for asynchronous messages
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+/**
+ * @file async.h
+ * @brief state management for asynchronous messages
+ */
+
+#ifndef _COAP_ASYNC_H_
+#define _COAP_ASYNC_H_
+
+#include "config.h"
+#include "net.h"
+
+#ifndef WITHOUT_ASYNC
+
+/**
+ * @defgroup coap_async Asynchronous Messaging
+ * @{
+ * Structure for managing asynchronous state of CoAP resources. A
+ * coap_resource_t object holds a list of coap_async_state_t objects
+ * that can be used to generate a separate response in case a result
+ * of an operation cannot be delivered in time, or the resource has
+ * been explicitly subscribed to with the option @c observe.
+ */
+typedef struct coap_async_state_t {
+       unsigned char flags;/**< holds the flags to control behaviour */
+
+       /**
+        * Holds the internal time when the object was registered with a
+        * resource. This field will be updated whenever
+        * coap_register_async() is called for a specific resource.
+        */
+       coap_tick_t created;
+
+       /**
+        * This field can be used to register opaque application data with
+        * the asynchronous state object. */
+       void *appdata;
+
+       unsigned short message_id;      /**< id of last message seen */
+       coap_tid_t id;          /**< transaction id */
+
+       struct coap_async_state_t *next;
+       /**< internally used for linking */
+
+       coap_address_t peer;    /**< the peer to notify */
+       size_t tokenlen;        /**< length of the token */
+       unsigned char token[];  /**< the token to use in a response */
+} coap_async_state_t;
+
+/* Definitions for Async Status Flags These flags can be used to
+ * control the behaviour of asynchronous response generation. */
+#define COAP_ASYNC_CONFIRM   0x01 /**< send confirmable response */
+#define COAP_ASYNC_SEPARATE  0x02 /**< send separate response */
+#define COAP_ASYNC_OBSERVED  0x04 /**< the resource is being observed */
+
+/** release application data on destruction */
+#define COAP_ASYNC_RELEASE_DATA  0x08
+
+/**
+ * Allocates a new coap_async_state_t object and fills its fields
+ * according to the given @p request. The @p flags are used to control
+ * generation of empty ACK responses to stop retransmissions and to
+ * release registered @p data when the resource is deleted by
+ * coap_free_async().  This function returns a pointer to the registered
+ * coap_async_t object or @c NULL on error. Note that this function will
+ * return @c NULL in case that an object with the same identifier is
+ * already registered.
+ *
+ * @param context  The context to use.
+ * @param peer     The remote peer that is to be asynchronously notified.
+ * @param request  The request that is handled asynchronously.
+ * @param flags    Flags to control state management.
+ * @param data     Opaque application data to register. Note that the
+ *                 storage occupied by @p data is released on destruction
+ *                 only if flag COAP_ASYNC_RELEASE_DATA is set.
+ *
+ * @return A pointer to the registered coap_async_state_t object or
+ * @c NULL in case of an error.
+ */
+coap_async_state_t *coap_register_async(coap_context_t *context, coap_address_t *peer, coap_pdu_t *request, unsigned char flags, void *data);
+
+/**
+ * Removes the state object identified by @p id from @p context. The
+ * removed object is returned in @p s, if found. Otherwise, @p s is
+ * undefined. This function returns @c 1 if the object was removed, @c
+ * 0 otherwise. Note that the storage allocated for the stored object
+ * is not released by this functions. You will have to call
+ * coap_free_async() to do so.
+ *
+ * @param context The context where the async object is registered.
+ * @param id      The identifier of the asynchronous transaction.
+ * @param s       Will be set to the object identified by @p id
+ * after removal.
+ *
+ * @return @c 1 if object was removed and @p s updated, or @c 0 if no
+ * object was found with the given id. @p s is valid only if the
+ * return value is @c 1.
+ */
+int coap_remove_async(coap_context_t *context, coap_tid_t id, coap_async_state_t **s);
+
+/**
+ * Releases the memory that was allocated by coap_async_state_init()
+ * for the object @p s. The registered application data will be
+ * released automatically if COAP_ASYNC_RELEASE_DATA is set.
+ *
+ * @param s The object to delete.
+ */
+void coap_free_async(coap_async_state_t *state);
+
+/**
+ * Retrieves the object identified by @p id from the list of asynchronous
+ * transactions that are registered with @p context. This function returns
+ * a pointer to that object or @c NULL if not found.
+ *
+ * @param context The context where the asynchronous objects are
+ * registered with.
+ * @param id      The id of the object to retrieve.
+ *
+ * @return A pointer to the object identified by @p id or @c NULL if
+ * not found.
+ */
+coap_async_state_t *coap_find_async(coap_context_t *context, coap_tid_t id);
+
+/**
+ * Updates the time stamp of @p s.
+ *
+ * @param s The state object to update.
+ */
+static inline void coap_touch_async(coap_async_state_t *s)
+{
+       coap_ticks(&s->created);
+}
+
+/** @} */
+
+#endif                                                 /*  WITHOUT_ASYNC */
+
+#endif                                                 /* _COAP_ASYNC_H_ */
diff --git a/apps/include/netutils/libcoap/bits.h b/apps/include/netutils/libcoap/bits.h
new file mode 100644 (file)
index 0000000..f97c290
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * bits.h -- bit vector manipulation
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+/**
+ * @file bits.h
+ * @brief bit vector manipulation
+ */
+
+#ifndef _BITS_H_
+#define _BITS_H_
+
+#include <sys/types.h>
+#include <stdint.h>
+
+/**
+ * Sets the bit @p bit in bit-vector @p vec. This function returns @c
+ * 1 if bit was set or @c -1 on error (i.e. when the given bit does
+ * not fit in the vector).
+ *
+ * @param vec  The bit-vector to change.
+ * @param size The size of @p vec in bytes.
+ * @param bit  The bit to set in @p vec.
+ *
+ * @return @c -1 if @p bit does not fit into @p vec, @c 1 otherwise.
+ */
+inline static int bits_setb(uint8_t *vec, size_t size, uint8_t bit)
+{
+       if (size <= (bit >> 3)) {
+               return -1;
+       }
+
+       *(vec + (bit >> 3)) |= (uint8_t)(1 << (bit & 0x07));
+       return 1;
+}
+
+/**
+ * Clears the bit @p bit from bit-vector @p vec. This function returns
+ * @c 1 if bit was cleared or @c -1 on error (i.e. when the given bit
+ * does not fit in the vector).
+ *
+ * @param vec  The bit-vector to change.
+ * @param size The size of @p vec in bytes.
+ * @param bit  The bit to clear from @p vec.
+ *
+ * @return @c -1 if @p bit does not fit into @p vec, @c 1 otherwise.
+ */
+inline static int bits_clrb(uint8_t *vec, size_t size, uint8_t bit)
+{
+       if (size <= (bit >> 3)) {
+               return -1;
+       }
+
+       *(vec + (bit >> 3)) &= (uint8_t)(~(1 << (bit & 0x07)));
+       return 1;
+}
+
+/**
+ * Gets the status of bit @p bit from bit-vector @p vec. This function returns
+ * @c 1 if the bit is set, @c 0 otherwise (even in case of an error)..
+ *
+ * @param vec  The bit-vector to read from..
+ * @param size The size of @p vec in bytes.
+ * @param bit  The bit to get from @p vec.
+ *
+ * @return @c 1 if the bit is set, @c 0 otherwise.
+ */
+inline static int bits_getb(const uint8_t *vec, size_t size, uint8_t bit)
+{
+       if (size <= (bit >> 3)) {
+               return -1;
+       }
+
+       return (*(vec + (bit >> 3)) & (1 << (bit & 0x07))) != 0;
+}
+
+#endif                                                 /* _BITS_H_ */
diff --git a/apps/include/netutils/libcoap/block.h b/apps/include/netutils/libcoap/block.h
new file mode 100644 (file)
index 0000000..eb58e8e
--- /dev/null
@@ -0,0 +1,136 @@
+/* block.h -- block transfer
+ *
+ * Copyright (C) 2010--2012,2014 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#ifndef _COAP_BLOCK_H_
+#define _COAP_BLOCK_H_
+
+#include "option.h"
+#include "encode.h"
+#include "pdu.h"
+
+/**
+ * @defgroup block Block Transfer
+ * @{
+ */
+
+#ifndef COAP_MAX_BLOCK_SZX
+/**
+ * The largest value for the SZX component in a Block option. Note
+ * that 1 << (COAP_MAX_BLOCK_SZX + 4) should not exceed
+ * COAP_MAX_PDU_SIZE.
+ */
+#define COAP_MAX_BLOCK_SZX      4
+#endif                                                 /* COAP_MAX_BLOCK_SZX */
+
+#if (COAP_MAX_PDU_SIZE - 6) < (1 << (COAP_MAX_BLOCK_SZX + 4))
+#error "COAP_MAX_BLOCK_SZX too large"
+#endif
+
+/**
+ * Structure of Block options.
+ */
+typedef struct {
+       unsigned int num: 20;   /**< block number */
+       unsigned int m: 1;      /**< 1 if more blocks follow, 0 otherwise */
+       unsigned int szx: 3;            /**< block size */
+} coap_block_t;
+
+/**
+ * Returns the value of the least significant byte of a Block option @p opt.
+ * For zero-length options (i.e. num == m == szx == 0), COAP_OPT_BLOCK_LAST
+ * returns @c NULL.
+ */
+#define COAP_OPT_BLOCK_LAST(opt) \
+  (COAP_OPT_LENGTH(opt) ? (COAP_OPT_VALUE(opt) + (COAP_OPT_LENGTH(opt)-1)) : 0)
+
+/** Returns the value of the More-bit of a Block option @p opt. */
+#define COAP_OPT_BLOCK_MORE(opt) \
+  (COAP_OPT_LENGTH(opt) ? (*COAP_OPT_BLOCK_LAST(opt) & 0x08) : 0)
+
+/** Returns the value of the SZX-field of a Block option @p opt. */
+#define COAP_OPT_BLOCK_SZX(opt)  \
+  (COAP_OPT_LENGTH(opt) ? (*COAP_OPT_BLOCK_LAST(opt) & 0x07) : 0)
+
+/**
+ * Returns the value of field @c num in the given block option @p
+ * block_opt.
+ */
+unsigned int coap_opt_block_num(const coap_opt_t *block_opt);
+
+/**
+ * Checks if more than @p num blocks are required to deliver @p data_len
+ * bytes of data for a block size of 1 << (@p szx + 4).
+ */
+static inline int coap_more_blocks(size_t data_len, unsigned int num, unsigned short szx)
+{
+       return ((num + 1) << (szx + 4)) < data_len;
+}
+
+/** Sets the More-bit in @p block_opt */
+static inline void coap_opt_block_set_m(coap_opt_t *block_opt, int m)
+{
+       if (m) {
+               *(COAP_OPT_VALUE(block_opt) + (COAP_OPT_LENGTH(block_opt) - 1)) |= 0x08;
+       } else {
+               *(COAP_OPT_VALUE(block_opt) + (COAP_OPT_LENGTH(block_opt) - 1)) &= ~0x08;
+       }
+}
+
+/**
+ * Initializes @p block from @p pdu. @p type must be either COAP_OPTION_BLOCK1
+ * or COAP_OPTION_BLOCK2. When option @p type was found in @p pdu, @p block
+ * is initialized with values from this option and the function returns the
+ * value @c 1. Otherwise, @c 0 is returned.
+ *
+ * @param pdu   The pdu to search for option @p type.
+ * @param type  The option to search for (must be COAP_OPTION_BLOCK1 or
+ *              COAP_OPTION_BLOCK2)
+ * @param block The block structure to initilize.
+ * @return @c 1 on success, @c 0 otherwise.
+ */
+int coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block);
+
+/**
+ * Writes a block option of type @p type to message @p pdu. If the
+ * requested block size is too large to fit in @p pdu, it is reduced
+ * accordingly. An exception is made for the final block when less
+ * space is required. The actual length of the resource is specified
+ * in @p data_length.
+ *
+ * This function may change *block to reflect the values written to
+ * @p pdu. As the function takes into consideration the remaining space
+ * @p pdu, no more options should be added after coap_write_block_opt()
+ * has returned.
+ *
+ * @param block      The block structure to use. On return, this object
+ *                   is updated according to the values that have been
+ *                   written to @p pdu.
+ * @param type       COAP_OPTION_BLOCK1 or COAP_OPTION_BLOCK2
+ * @param pdu        The message where the block option should be
+ *                   written.
+ * @param data_length The length of the actual data that will be added
+ *                   the @p pdu by calling coap_add_block().
+ * @return @c 1 on success, or a negative value on error.
+ */
+int coap_write_block_opt(coap_block_t *block, unsigned short type, coap_pdu_t *pdu, size_t data_length);
+
+/**
+ * Adds the @p block_num block of size 1 << (@p block_szx + 4) from
+ * source @p data to @p pdu.
+ *
+ * @param pdu    The message to add the block
+ * @param len    The length of @p data.
+ * @param data   The source data to fill the block with
+ * @param block_num The actual block number
+ * @param block_szx Encoded size of block @p block_number
+ * @return @c 1 on success, @c 0 otherwise.
+ */
+int coap_add_block(coap_pdu_t *pdu, unsigned int len, const unsigned char *data, unsigned int block_num, unsigned char block_szx);
+/**@}*/
+
+#endif                                                 /* _COAP_BLOCK_H_ */
diff --git a/apps/include/netutils/libcoap/coap.h b/apps/include/netutils/libcoap/coap.h
new file mode 100644 (file)
index 0000000..e3c7128
--- /dev/null
@@ -0,0 +1,34 @@
+/* coap.h -- main header file for CoAP stack
+ *
+ * Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#ifndef _COAP_H_
+#define _COAP_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "config.h"
+#include "debug.h"
+#include "mem.h"
+#include "coap_list.h"
+#include "pdu.h"
+#include "option.h"
+#include "net.h"
+#include "encode.h"
+#include "str.h"
+#include "uri.h"
+#include "async.h"
+#include "resource.h"
+#include "subscribe.h"
+#include "block.h"
+
+#ifdef __cplusplus
+}
+#endif
+#endif                                                 /* _COAP_H_ */
diff --git a/apps/include/netutils/libcoap/coap_list.h b/apps/include/netutils/libcoap/coap_list.h
new file mode 100644 (file)
index 0000000..5f0e735
--- /dev/null
@@ -0,0 +1,44 @@
+/* coap_list.h -- CoAP list structures
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#ifndef _COAP_LIST_H_
+#define _COAP_LIST_H_
+
+struct coap_linkedlistnode {
+       struct coap_linkedlistnode *next;
+       void *data;
+
+       /**
+        * Callback function that is called from coap_delete to release
+        * additional memory allocated by data Set to NULL if you do not
+        * need this. Note that data is free'd automatically. */
+       void (*delete_func)(void *);
+};
+
+typedef struct coap_linkedlistnode 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, int (*order)(void *, void *));
+
+/* 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);
+
+/**
+ * Creates a new list node and adds the given data object. The memory allocated
+ * by data will be released by coap_delete() with the new node. Returns the
+ * new list node.
+ */
+coap_list_t *coap_new_listnode(void *data, void (*delete_func)(void *));
+
+#endif                                                 /* _COAP_LIST_H_ */
diff --git a/apps/include/netutils/libcoap/coap_time.h b/apps/include/netutils/libcoap/coap_time.h
new file mode 100644 (file)
index 0000000..b352979
--- /dev/null
@@ -0,0 +1,164 @@
+/* coap_time.h -- Clock Handling
+ *
+ * Copyright (C) 2010--2013 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+/**
+ * @file coap_time.h
+ * @brief Clock Handling
+ */
+
+#ifndef _COAP_TIME_H_
+#define _COAP_TIME_H_
+
+/*
+** Make sure we can call this stuff from C++.
+*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "config.h"
+
+/**
+ * @defgroup clock Clock Handling
+ * Default implementation of internal clock. You should redefine this if
+ * you do not have time() and gettimeofday().
+ * @{
+ */
+
+#ifdef WITH_LWIP
+
+#include <stdint.h>
+#include <net/lwip/sys.h>
+
+/* 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 */
+
+#ifndef coap_clock_init
+static inline void
+coap_clock_init_impl(void)
+{
+#ifdef HAVE_TIME_H
+       clock_offset = time(NULL);
+#else
+#ifdef __GNUC__
+       /* Issue a warning when using gcc. Other prepropressors do
+        *  not seem to have a similar feature. */
+#warning "cannot initialize clock"
+#endif
+       clock_offset = 0;
+#endif
+}
+#define coap_clock_init coap_clock_init_impl
+#endif                                                 /* coap_clock_init */
+
+#ifndef coap_ticks
+static inline void
+coap_ticks_impl(coap_tick_t *t)
+{
+#ifdef HAVE_SYS_TIME_H
+       struct timeval tv;
+       gettimeofday(&tv, NULL);
+       *t = (tv.tv_sec - clock_offset) * COAP_TICKS_PER_SECOND + (tv.tv_usec * COAP_TICKS_PER_SECOND / 1000000);
+#else
+#error "clock not implemented"
+#endif
+}
+#define coap_ticks coap_ticks_impl
+#endif                                                 /* coap_ticks */
+
+/**
+ * Returns @c 1 if and only if @p a is less than @p b where less is
+ * defined on a signed data type.
+ */
+static inline int coap_time_lt(coap_tick_t a, coap_tick_t b)
+{
+       return ((coap_tick_diff_t)(a - b)) < 0;
+}
+
+/**
+ * Returns @c 1 if and only if @p a is less than or equal @p b where
+ * less is defined on a signed data type.
+ */
+static inline int coap_time_le(coap_tick_t a, coap_tick_t b)
+{
+       return a == b || coap_time_lt(a, b);
+}
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif                                                 /* _COAP_TIME_H_ */
diff --git a/apps/include/netutils/libcoap/config.h b/apps/include/netutils/libcoap/config.h
new file mode 100644 (file)
index 0000000..4ddafa7
--- /dev/null
@@ -0,0 +1,135 @@
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/********************************************************
+ *  User defined configuration (via Kconfig)
+ *********************************************************/
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `coap' library (-lcoap). */
+/* #undef HAVE_LIBCOAP */
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+   to 0 otherwise. */
+#define HAVE_MALLOC 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strnlen' function. */
+#define HAVE_STRNLEN 1
+
+/* Define to 1 if you have the `strrchr' function. */
+#define HAVE_STRRCHR 1
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/unistd.h> header file. */
+#define HAVE_SYS_UNISTD_H 1
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the address where bug reports for this package should be sent. */
+#define 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. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "4.1.1"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* 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 <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef ssize_t */
diff --git a/apps/include/netutils/libcoap/debug.h b/apps/include/netutils/libcoap/debug.h
new file mode 100644 (file)
index 0000000..593f867
--- /dev/null
@@ -0,0 +1,74 @@
+/* debug.h -- debug utilities
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#ifndef _COAP_DEBUG_H_
+#define _COAP_DEBUG_H_
+
+#include "config.h"
+
+#ifndef COAP_DEBUG_FD
+#define COAP_DEBUG_FD stdout
+#endif
+
+#ifndef COAP_ERR_FD
+#define COAP_ERR_FD stderr
+#endif
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+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
+                        } coap_log_t;
+#endif
+
+/** Returns the current log level. */
+coap_log_t coap_get_log_level(void);
+
+/** Sets the log level to the specified value. */
+void coap_set_log_level(coap_log_t level);
+
+/**
+ * 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
+
+/* 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__)
+
+#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/apps/include/netutils/libcoap/encode.h b/apps/include/netutils/libcoap/encode.h
new file mode 100644 (file)
index 0000000..f5b3ac0
--- /dev/null
@@ -0,0 +1,58 @@
+/* encode.h -- encoding and decoding of CoAP data types
+ *
+ * Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#ifndef _COAP_ENCODE_H_
+#define _COAP_ENCODE_H_
+
+#include <tinyara/config.h>
+
+#ifdef __TINYARA__
+#include <string.h>
+#else
+#if (BSD >= 199103) || defined(WITH_CONTIKI)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#endif /*__TINYARA__*/
+
+#define Nn 8                                   /* duplicate definition of N if built on sky motes */
+#define E 4
+#define HIBIT (1 << (Nn - 1))
+#define EMASK ((1 << E) - 1)
+#define MMASK ((1 << Nn) - 1 - EMASK)
+#define MAX_VALUE ( (1 << Nn) - (1 << E) ) * (1 << ((1 << E) - 1))
+
+#define COAP_PSEUDOFP_DECODE_8_4(r) (r < HIBIT ? r : (r & MMASK) << (r & EMASK))
+
+#ifndef HAVE_FLS
+/* include this only if fls() is not available */
+extern int coap_fls(unsigned int i);
+#else
+#define coap_fls(i) fls(i)
+#endif
+
+/* ls and s must be integer variables */
+#define COAP_PSEUDOFP_ENCODE_8_4_DOWN(v,ls) (v < HIBIT ? v : (ls = coap_fls(v) - Nn, (v >> ls) & MMASK) + ls)
+#define COAP_PSEUDOFP_ENCODE_8_4_UP(v,ls,s) (v < HIBIT ? v : (ls = coap_fls(v) - Nn, (s = (((v + ((1<<E<<ls)-1)) >> ls) & MMASK)), s == 0 ? HIBIT + ls + 1 : s + ls))
+
+/**
+ * Decodes multiple-length byte sequences. buf points to an input byte
+ * sequence of length len. Returns the decoded value.
+ */
+unsigned int coap_decode_var_bytes(unsigned char *buf, unsigned int len);
+
+/**
+ * Encodes multiple-length byte sequences. buf points to an output
+ * buffer of sufficient length to store the encoded bytes. val is
+ * the value to encode. Returns the number of bytes used to encode
+ * val or 0 on error.
+ */
+unsigned int coap_encode_var_bytes(unsigned char *buf, unsigned int val);
+
+#endif                                                 /* _COAP_ENCODE_H_ */
diff --git a/apps/include/netutils/libcoap/hashkey.h b/apps/include/netutils/libcoap/hashkey.h
new file mode 100644 (file)
index 0000000..bb68fd3
--- /dev/null
@@ -0,0 +1,57 @@
+/* hashkey.h -- definition of hash key type and helper functions
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+/**
+ * @file hashkey.h
+ * @brief definition of hash key type and helper functions
+ */
+
+#ifndef _COAP_HASHKEY_H_
+#define _COAP_HASHKEY_H_
+
+#include "str.h"
+
+typedef unsigned char coap_key_t[4];
+
+#ifndef coap_hash
+/**
+ * Calculates a fast hash over the given string @p s of length @p len
+ * and stores the result into @p h. Depending on the exact
+ * implementation, this function cannot be used as one-way function to
+ * check message integrity or simlar.
+ *
+ * @param s   The string used for hash calculation.
+ * @param len The length of @p s.
+ * @param h   The result buffer to store the calculated hash key.
+ */
+void coap_hash_impl(const unsigned char *s, unsigned int len, coap_key_t h);
+
+#define coap_hash(String,Length,Result) \
+  coap_hash_impl((String),(Length),(Result))
+
+/* This is used to control the pre-set hash-keys for resources. */
+#define __COAP_DEFAULT_HASH
+#else
+#undef __COAP_DEFAULT_HASH
+#endif                                                 /* coap_hash */
+
+/**
+ * Calls coap_hash() with given @c str object as parameter.
+ *
+ * @param Str Must contain a pointer to a coap string object.
+ * @param H   A coap_key_t object to store the result.
+ *
+ * @hideinitializer
+ */
+#define coap_str_hash(Str,H) {                 \
+    assert(Str);                               \
+    memset((H), 0, sizeof(coap_key_t));                \
+    coap_hash((H), (Str)->s, (Str)->length);   \
+  }
+
+#endif                                                 /* _COAP_HASHKEY_H_ */
diff --git a/apps/include/netutils/libcoap/lwippools.h b/apps/include/netutils/libcoap/lwippools.h
new file mode 100644 (file)
index 0000000..4c9c8e3
--- /dev/null
@@ -0,0 +1,35 @@
+/** Memory pool definitions for the libcoap when used with lwIP (which has its
+ * own mechanism for quickly allocating chunks of data with known sizes). Has
+ * to be findable by lwIP (ie. an #include <lwippools.h> must either directly
+ * include this or include something more generic which includes this), and
+ * MEMP_USE_CUSTOM_POOLS has to be set in lwipopts.h. */
+
+#include <net.h>
+#include <subscribe.h>
+#include <resource.h>
+
+#ifndef MEMP_NUM_COAPCONTEXT
+#define MEMP_NUM_COAPCONTEXT 1
+#endif
+
+#ifndef MEMP_NUM_COAPNODE
+#define MEMP_NUM_COAPNODE 4
+#endif
+
+#ifndef MEMP_NUM_COAP_SUBSCRIPTION
+#define MEMP_NUM_COAP_SUBSCRIPTION 4
+#endif
+
+#ifndef MEMP_NUM_COAPRESOURCE
+#define MEMP_NUM_COAPRESOURCE 10
+#endif
+
+#ifndef MEMP_NUM_COAPRESOURCEATTR
+#define MEMP_NUM_COAPRESOURCEATTR 20
+#endif
+
+LWIP_MEMPOOL(COAP_CONTEXT, MEMP_NUM_COAPCONTEXT, sizeof(coap_context_t), "COAP_CONTEXT")
+LWIP_MEMPOOL(COAP_NODE, MEMP_NUM_COAPNODE, sizeof(coap_queue_t), "COAP_NODE")
+LWIP_MEMPOOL(COAP_subscription, MEMP_NUM_COAP_SUBSCRIPTION, sizeof(coap_subscription_t), "COAP_subscription")
+LWIP_MEMPOOL(COAP_RESOURCE, MEMP_NUM_COAPRESOURCE, sizeof(coap_resource_t), "COAP_RESOURCE")
+LWIP_MEMPOOL(COAP_RESOURCEATTR, MEMP_NUM_COAPRESOURCEATTR, sizeof(coap_attr_t), "COAP_RESOURCEATTR")
diff --git a/apps/include/netutils/libcoap/mem.h b/apps/include/netutils/libcoap/mem.h
new file mode 100644 (file)
index 0000000..5728a53
--- /dev/null
@@ -0,0 +1,18 @@
+/* mem.h -- CoAP memory handling
+ *          Currently, this is just a dummy for malloc/free
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * 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 <stdlib.h>
+
+#define coap_malloc(size) malloc(size)
+#define coap_free(size) free(size)
+
+#endif                                                 /* _COAP_MEM_H_ */
diff --git a/apps/include/netutils/libcoap/net.h b/apps/include/netutils/libcoap/net.h
new file mode 100644 (file)
index 0000000..61f8ba8
--- /dev/null
@@ -0,0 +1,450 @@
+/* net.h -- CoAP network interface
+ *
+ * Copyright (C) 2010--2013 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * 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 <assert.h>
+#else
+#ifndef assert
+#warning "assertions are disabled"
+#define assert(x)
+#endif
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef WITH_LWIP
+#include <net/lwip/ipv4/ip_addr.h>
+#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);
+
+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 */
+
+       /**
+        * 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.
+ */
+int coap_read(coap_context_t *context);
+
+/**
+ * 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/apps/include/netutils/libcoap/option.h b/apps/include/netutils/libcoap/option.h
new file mode 100644 (file)
index 0000000..d4cf80d
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * option.h -- helpers for handling options in CoAP PDUs
+ *
+ * Copyright (C) 2010-2013 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+/**
+ * @file option.h
+ * @brief helpers for handling options in CoAP PDUs
+ */
+
+#ifndef _OPTION_H_
+#define _OPTION_H_
+
+#include "bits.h"
+#include "pdu.h"
+
+/**
+ * Use byte-oriented access methods here because sliding a complex
+ * struct coap_opt_t over the data buffer may cause bus error on
+ * certain platforms.
+ */
+typedef unsigned char coap_opt_t;
+#define PCHAR(p) ((coap_opt_t *)(p))
+
+/** Representation of CoAP options. */
+typedef struct {
+       unsigned short delta;
+       size_t length;
+       unsigned char *value;
+} coap_option_t;
+
+/**
+ * Parses the option pointed to by @p opt into @p result. This
+ * function returns the number of bytes that have been parsed, or @c 0
+ * on error. An error is signaled when illegal delta or length values
+ * are encountered or when option parsing would result in reading past
+ * the option (i.e. beyond opt + length).
+ *
+ * @param opt    The beginning of the option to parse.
+ * @param length The maximum length of @p opt.
+ * @param result A pointer to the coap_option_t structure that is
+ *               filled with actual values iff coap_opt_parse() > 0.
+ * @return The number of bytes parsed or @c 0 on error.
+ */
+size_t coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result);
+
+/**
+ * Returns the size of the given option, taking into account a
+ * possible option jump.
+ *
+ * @param opt An option jump or the beginning of the option.
+ * @return The number of bytes between @p opt and the end of
+ *         the option starting at @p opt. In case of an error,
+ *         this function returns @c 0 as options need at least
+ *         one byte storage space.
+ */
+size_t coap_opt_size(const coap_opt_t *opt);
+
+/** @deprecated { Use coap_opt_size() instead. } */
+#define COAP_OPT_SIZE(opt) coap_opt_size(opt)
+
+/**
+ * Calculates the beginning of the PDU's option section.
+ *
+ * @param pdu The PDU containing the options.
+ * @return A pointer to the first option if available, or @c NULL otherwise.
+ */
+coap_opt_t *options_start(coap_pdu_t *pdu);
+
+/**
+ * Interprets @p opt as pointer to a CoAP option and advances to
+ * the next byte past this option.
+ * @hideinitializer
+ */
+#define options_next(opt) \
+  ((coap_opt_t *)((unsigned char *)(opt) + COAP_OPT_SIZE(opt)))
+
+/**
+ * @defgroup opt_filter Option Filters
+ * @{
+ */
+
+/**
+ * Fixed-size bit-vector we use for option filtering. It is large
+ * enough to hold the highest option number known at build time (20 in
+ * the core spec).
+ */
+typedef unsigned char coap_opt_filter_t[(COAP_MAX_OPT >> 3) + 1];
+
+/** Pre-defined filter that includes all options. */
+#define COAP_OPT_ALL NULL
+
+/**
+ * Clears filter @p f.
+ *
+ * @param f The filter to clear.
+ */
+static inline void coap_option_filter_clear(coap_opt_filter_t f)
+{
+       memset(f, 0, sizeof(coap_opt_filter_t));
+}
+
+/**
+ * Sets the corresponding bit for @p type in @p filter. This function
+ * returns @c 1 if bit was set or @c -1 on error (i.e. when the given
+ * type does not fit in the filter).
+ *
+ * @param filter The filter object to change.
+ * @param type   The type for which the bit should be set.
+ *
+ * @return @c 1 if bit was set, @c -1 otherwise.
+ */
+inline static int coap_option_setb(coap_opt_filter_t filter, unsigned short type)
+{
+       return bits_setb((uint8_t *) filter, sizeof(coap_opt_filter_t), type);
+}
+
+/**
+ * Clears the corresponding bit for @p type in @p filter. This function
+ * returns @c 1 if bit was cleared or @c -1 on error (i.e. when the given
+ * type does not fit in the filter).
+ *
+ * @param filter The filter object to change.
+ * @param type   The type for which the bit should be cleared.
+ *
+ * @return @c 1 if bit was set, @c -1 otherwise.
+ */
+inline static int coap_option_clrb(coap_opt_filter_t filter, unsigned short type)
+{
+       return bits_clrb((uint8_t *) filter, sizeof(coap_opt_filter_t), type);
+}
+
+/**
+ * Gets the corresponding bit for @p type in @p filter. This function
+ * returns @c 1 if the bit is set @c 0 if not, or @c -1 on error (i.e.
+ * when the given type does not fit in the filter).
+ *
+ * @param filter The filter object to read bit from..
+ * @param type   The type for which the bit should be read.
+ *
+ * @return @c 1 if bit was set, @c 0 if not, @c -1 on error.
+ */
+inline static int coap_option_getb(const coap_opt_filter_t filter, unsigned short type)
+{
+       return bits_getb((uint8_t *) filter, sizeof(coap_opt_filter_t), type);
+}
+
+/**
+ * Iterator to run through PDU options. This object must be
+ * initialized with coap_option_iterator_init(). Call
+ * coap_option_next() to walk through the list of options until
+ * coap_option_next() returns @c NULL.
+ *
+ * @code
+ * coap_opt_t *option;
+ * coap_opt_iterator_t opt_iter;
+ * coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
+ *
+ * while ((option = coap_option_next(&opt_iter))) {
+ *   ... do something with option ...
+ * }
+ * @endcode
+ */
+typedef struct {
+       size_t length;          /**< remaining length of PDU */
+       unsigned short type;    /**< decoded option type */
+       unsigned int bad: 1;            /**< iterator object is ok if not set */
+       unsigned int filtered: 1; /**< denotes whether or not filter is used */
+       coap_opt_t *next_option;/**< pointer to the unparsed next option */
+       coap_opt_filter_t filter;
+       /**< option filter */
+} coap_opt_iterator_t;
+
+/**
+ * Initializes the given option iterator @p oi to point to the
+ * beginning of the @p pdu's option list. This function returns @p oi
+ * on success, @c NULL otherwise (i.e. when no options exist).
+ * Note that a length check on the option list must be performed before
+ * coap_option_iterator_init() is called.
+ *
+ * @param pdu  The PDU the options of which should be walked through.
+ * @param oi   An iterator object that will be initilized.
+ * @param filter An optional option type filter.
+ *               With @p type != @c COAP_OPT_ALL, coap_option_next()
+ *               will return only options matching this bitmask.
+ *               Fence-post options @c 14, @c 28, @c 42, ... are always
+ *               skipped.
+ *
+ * @return The iterator object @p oi on success, @c NULL otherwise.
+ */
+coap_opt_iterator_t *coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter);
+
+/**
+ * Updates the iterator @p oi to point to the next option. This
+ * function returns a pointer to that option or @c NULL if no more
+ * options exist. The contents of @p oi will be updated. In
+ * particular, @c oi->n specifies the current option's ordinal number
+ * (counted from @c 1), @c oi->type is the option's type code, and @c
+ * oi->option points to the beginning of the current option
+ * itself. When advanced past the last option, @c oi->option will be
+ * @c NULL.
+ *
+ * Note that options are skipped whose corresponding bits in the
+ * filter specified with coap_option_iterator_init() are @c 0. Options
+ * with type codes that do not fit in this filter hence will always be
+ * returned.
+ *
+ * @param oi The option iterator to update.
+ *
+ * @return The next option or @c NULL if no more options exist.
+ */
+coap_opt_t *coap_option_next(coap_opt_iterator_t *oi);
+
+/**
+ * Retrieves the first option of type @p type from @p pdu. @p oi must
+ * point to a coap_opt_iterator_t object that will be initialized by
+ * this function to filter only options with code @p type. This
+ * function returns the first option with this type, or @c NULL if not
+ * found.
+ *
+ * @param pdu  The PDU to parse for options.
+ * @param type The option type code to search for.
+ * @param oi   An iterator object to use.
+ *
+ * @return A pointer to the first option of type @p type, or @c NULL
+ *         if not found.
+ */
+coap_opt_t *coap_check_option(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi);
+
+/**
+ * Encodes the given delta and length values into @p opt. This
+ * function returns the number of bytes that were required to encode
+ * @p delta and @p length or @c 0 on error. Note that the result
+ * indicates by how many bytes @p opt must be advanced to encode the
+ * option value.
+ *
+ * @param opt    The option buffer space where @p delta and @p length are
+ *               written
+ * @param maxlen The maximum length of @p opt
+ * @param delta The actual delta value to encode.
+ * @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);
+
+/**
+ * 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
+ * especially when @p opt does not provide sufficient space to store
+ * the option value, delta, and option jumps when required.
+ *
+ * @param opt   The option buffer space where @p val is written
+ * @param n     Maximum length of @p opt.
+ * @param delta The option delta.
+ * @param val   The option value to copy into @p opt.
+ * @param len   The actual length of @p val.
+ * @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);
+
+/**
+ * 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
+ * function must ensure that it does not read over the boundaries
+ * of @p opt (e.g. by calling coap_opt_check_delta().
+ *
+ * @param opt The option to examine
+ * @return The number of bytes read or @c 0 on error.
+ */
+unsigned short coap_opt_delta(const coap_opt_t *opt);
+
+/** @deprecated { Use coap_opt_delta() instead. } */
+#define COAP_OPT_DELTA(opt) coap_opt_delta(opt)
+
+/** @deprecated { Use coap_opt_encode() instead. } */
+#define COAP_OPT_SETDELTA(opt,val)                     \
+  coap_opt_encode((opt), COAP_MAX_PDU_SIZE, (val), NULL, 0)
+
+/**
+ * Returns the length of the given option. @p opt must point to an
+ * option jump or the beginning of the option. This function returns
+ * @c 0 when @p opt is not an option or the actual length of @p opt
+ * (which can be @c 0 as well).
+ *
+ * @note {The rationale for using @c 0 in case of an error is that in
+ * most contexts, the result of this function is used to skip the next
+ * coap_opt_length() bytes. }
+ *
+ * @param opt  The option whose length should be returned.
+ * @return The option's length or @c 0 when undefined.
+ */
+unsigned short coap_opt_length(const coap_opt_t *opt);
+
+/** @deprecated { Use coap_opt_length() instead. } */
+#define COAP_OPT_LENGTH(opt) coap_opt_length(opt)
+
+/**
+ * Returns a pointer to the value of the given option. @p opt must
+ * point to an option jump or the beginning of the option. This
+ * function returns @c NULL if @p opt is not a valid option.
+ *
+ * @param opt  The option whose value should be returned.
+ * @return A pointer to the option value or @c NULL on error.
+ */
+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)
+
+/** @} */
+
+#endif                                                 /* _OPTION_H_ */
diff --git a/apps/include/netutils/libcoap/pdu.h b/apps/include/netutils/libcoap/pdu.h
new file mode 100644 (file)
index 0000000..fe8eadf
--- /dev/null
@@ -0,0 +1,342 @@
+/* pdu.h -- CoAP message structure
+ *
+ * Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#ifndef _PDU_H_
+#define _PDU_H_
+
+#include "config.h"
+#include "coap_list.h"
+#include "uri.h"
+
+#ifdef WITH_LWIP
+#include <net/lwip/pbuf.h>
+#endif
+
+/* pre-defined constants that reflect defaults for CoAP */
+
+#define COAP_DEFAULT_RESPONSE_TIMEOUT  2       /* response timeout in seconds */
+#define COAP_DEFAULT_MAX_RETRANSMIT    4       /* max number of retransmissions */
+#define COAP_DEFAULT_PORT           5683       /* CoAP default UDP port */
+#define COAP_DEFAULT_MAX_AGE          60       /* default maximum object lifetime in seconds */
+#ifndef COAP_MAX_PDU_SIZE
+#define COAP_MAX_PDU_SIZE           1400       /* maximum size of a CoAP PDU */
+#endif                                                 /* COAP_MAX_PDU_SIZE */
+
+#define COAP_DEFAULT_VERSION           1       /* version of CoAP supported */
+#define COAP_DEFAULT_SCHEME        "coap"      /* the default scheme for CoAP URIs */
+
+/** well-known resources URI */
+#define COAP_DEFAULT_URI_WELLKNOWN ".well-known/core"
+
+#ifdef __COAP_DEFAULT_HASH
+/* pre-calculated hash key for the default well-known URI */
+#define COAP_DEFAULT_WKC_HASHKEY   "\345\130\144\245"
+#endif
+
+/* CoAP message types */
+
+#define COAP_MESSAGE_CON               0       /* confirmable message (requires ACK/RST) */
+#define COAP_MESSAGE_NON               1       /* non-confirmable message (one-shot message) */
+#define COAP_MESSAGE_ACK               2       /* used to acknowledge confirmable messages */
+#define COAP_MESSAGE_RST               3       /* indicates error in received messages */
+
+/* CoAP request methods */
+
+#define COAP_REQUEST_GET       1
+#define COAP_REQUEST_POST      2
+#define COAP_REQUEST_PUT       3
+#define COAP_REQUEST_DELETE    4
+
+/* CoAP option types (be sure to update check_critical when adding options */
+
+#define COAP_OPTION_IF_MATCH      1    /* C, opaque, 0-8 B, (none) */
+#define COAP_OPTION_URI_HOST      3    /* C, String, 1-255 B, destination address */
+#define COAP_OPTION_ETAG          4    /* E, opaque, 1-8 B, (none) */
+#define COAP_OPTION_IF_NONE_MATCH 5    /* empty, 0 B, (none) */
+#define COAP_OPTION_URI_PORT      7    /* C, uint, 0-2 B, destination port */
+#define COAP_OPTION_LOCATION_PATH 8    /* E, String, 0-255 B, - */
+#define COAP_OPTION_URI_PATH     11    /* C, String, 0-255 B, (none) */
+#define COAP_OPTION_CONTENT_FORMAT 12  /* E, uint, 0-2 B, (none) */
+#define COAP_OPTION_CONTENT_TYPE COAP_OPTION_CONTENT_FORMAT
+#define COAP_OPTION_MAXAGE       14    /* E, uint, 0--4 B, 60 Seconds */
+#define COAP_OPTION_URI_QUERY    15    /* C, String, 1-255 B, (none) */
+#define COAP_OPTION_ACCEPT       17    /* C, uint,   0-2 B, (none) */
+#define COAP_OPTION_LOCATION_QUERY 20  /* E, String,   0-255 B, (none) */
+#define COAP_OPTION_PROXY_URI    35    /* C, String, 1-1034 B, (none) */
+#define COAP_OPTION_PROXY_SCHEME 39    /* C, String, 1-255 B, (none) */
+#define COAP_OPTION_SIZE1        60    /* E, uint, 0-4 B, (none) */
+
+/* option types from draft-ietf-coap-observe-09 */
+
+#define COAP_OPTION_OBSERVE       6    /* E, empty/uint, 0 B/0-3 B, (none) */
+#define COAP_OPTION_SUBSCRIPTION  COAP_OPTION_OBSERVE
+
+/* selected option types from draft-core-block-04 */
+
+#define COAP_OPTION_BLOCK2       23    /* C, uint, 0--3 B, (none) */
+#define COAP_OPTION_BLOCK1       27    /* C, uint, 0--3 B, (none) */
+
+#define COAP_MAX_OPT             63    /**< the highest option number we know */
+
+/* CoAP result codes (HTTP-Code / 100 * 40 + HTTP-Code % 100) */
+
+/* As of draft-ietf-core-coap-04, response codes are encoded to base
+ * 32, i.e.  the three upper bits determine the response class while
+ * the remaining five fine-grained information specific to that class.
+ */
+#define COAP_RESPONSE_CODE(N) (((N)/100 << 5) | (N)%100)
+
+/* Determines the class of response code C */
+#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.
+ */
+char *coap_response_phrase(unsigned char code);
+
+#define COAP_ERROR_PHRASE_LENGTH 32    /**< maximum length of error phrase */
+
+#else
+#define coap_response_phrase(x) ((char *)NULL)
+
+#define COAP_ERROR_PHRASE_LENGTH 0 /**< maximum length of error phrase */
+#endif                                                 /* SHORT_ERROR_RESPONSE */
+
+/* The following definitions exist for backwards compatibility */
+#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 */
+#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 */
+#endif
+#define COAP_RESPONSE_X_242    COAP_RESPONSE_CODE(402) /* Critical Option not supported */
+
+/* CoAP media type encoding */
+
+#define COAP_MEDIATYPE_TEXT_PLAIN                     0        /* text/plain (UTF-8) */
+#define COAP_MEDIATYPE_APPLICATION_LINK_FORMAT       40        /* application/link-format */
+#define COAP_MEDIATYPE_APPLICATION_XML               41        /* application/xml */
+#define COAP_MEDIATYPE_APPLICATION_OCTET_STREAM      42        /* application/octet-stream */
+#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  */
+
+/* Note that identifiers for registered media types are in the range 0-65535. We
+ * use an unallocated type here and hope for the best. */
+#define COAP_MEDIATYPE_ANY                         0xff        /* any media type */
+
+/* CoAP transaction id */
+/*typedef unsigned short coap_tid_t; */
+typedef int coap_tid_t;
+#define COAP_INVALID_TID -1
+
+#ifdef WORDS_BIGENDIAN
+typedef struct {
+       unsigned int version: 2;                /* protocol version */
+       unsigned int type: 2;           /* type flag */
+       unsigned int token_length: 4;   /* length of Token */
+       unsigned int code: 8;           /* request method (value 1--10) or response code (value 40-255) */
+       unsigned short id;                      /* message id */
+       unsigned char token[];          /* the actual token, if any */
+} coap_hdr_t;
+#else
+typedef struct {
+       unsigned int token_length: 4;   /* length of Token */
+       unsigned int type: 2;           /* type flag */
+       unsigned int version: 2;                /* protocol version */
+       unsigned int code: 8;           /* request method (value 1--10) or response code (value 40-255) */
+       unsigned short id;                      /* transaction id (network byte order!) */
+       unsigned char token[];          /* the actual token, if any */
+} coap_hdr_t;
+#endif
+
+#define COAP_MESSAGE_IS_EMPTY(MSG)    ((MSG)->code == 0)
+#define COAP_MESSAGE_IS_REQUEST(MSG)  (!COAP_MESSAGE_IS_EMPTY(MSG)     \
+                                      && ((MSG)->code < 32))
+#define COAP_MESSAGE_IS_RESPONSE(MSG) ((MSG)->code >= 64 && (MSG)->code <= 191)
+
+#define COAP_OPT_LONG 0x0F             /* OC == 0b1111 indicates that the option list in a
+                                                                * CoAP message is limited by 0b11110000 marker */
+
+#define COAP_OPT_END 0xF0              /* end marker */
+
+#define COAP_PAYLOAD_START 0xFF        /* payload marker */
+
+/**
+ * Structures for more convenient handling of options. (To be used with ordered
+ * coap_list_t.) The option's data will be added to the end of the coap_option
+ * structure (see macro COAP_OPTION_DATA).
+ */
+typedef struct {
+       unsigned short key;                     /* the option key (no delta coding) */
+       unsigned int length;
+} coap_option;
+
+#define COAP_OPTION_KEY(option) (option).key
+#define COAP_OPTION_LENGTH(option) (option).length
+#define COAP_OPTION_DATA(option) ((unsigned char *)&(option) + sizeof(coap_option))
+
+/** Header structure for CoAP PDUs */
+
+typedef struct {
+       size_t max_size;/**< allocated storage for options and data */
+
+       coap_hdr_t *hdr;
+       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
+
+} 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
+ * 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
+
+/**
+ * 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).
+ * @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, 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
+ * pointer to a coap_pdu_t object created e.g. by coap_pdu_init().
+ */
+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.
+ */
+coap_pdu_t *coap_new_pdu(void);
+
+void coap_delete_pdu(coap_pdu_t *);
+
+/**
+ * Parses @p data into the CoAP PDU structure given in @p result. This
+ * function returns @c 0 on error or a number greater than zero on
+ * success.
+ *
+ * @param data   The raw data to parse as CoAP PDU
+ * @param length The actual size of @p data
+ * @param result The PDU structure to fill. Note that the structure must
+ *               provide space for at least @p length bytes to hold the
+ *               entire CoAP PDU.
+ * @return A value greater than zero on success or @c 0 on error.
+ */
+int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *result);
+
+/**
+ * Adds token of length @p len to @p pdu. Adding the token destroys
+ * any following contents of the pdu. Hence options and data must be
+ * added after coap_add_token() has been called. In @p pdu, length is
+ * set to @p len + @c 4, and max_delta is set to @c 0.  This funtion
+ * returns @c 0 on error or a value greater than zero on success.
+ *
+ * @param pdu  The PDU where the token is to be added.
+ * @param len  The length of the new token.
+ * @param data The token to add.
+ * @return A value greater than zero on success, or @c 0 on error.
+ */
+int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data);
+
+/**
+ * Adds option of given type to pdu that is passed as first
+ * parameter. coap_add_option() destroys the PDU's data, so
+ * coap_add_data() must be called after all options have been added.
+ * As coap_add_token() destroys the options following the token,
+ * 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, unsigned int len, const unsigned char *data);
+
+/**
+ * Adds option of given type to pdu that is passed as first
+ * parameter, but does not write a value. It works like coap_add_option with
+ * respect to calling sequence (i.e. after token and before data).
+ * This function returns a memory address to which the option data has to be
+ * written before the PDU can be sent, or @c NULL on error.
+ */
+unsigned char *coap_add_option_later(coap_pdu_t *pdu, unsigned short type, unsigned int len);
+
+/**
+ * Adds given data to the pdu that is passed as first parameter. Note
+ * that the PDU's data is destroyed by coap_add_option(). coap_add_data()
+ * must be called only once per PDU, otherwise the result is undefined.
+ */
+int coap_add_data(coap_pdu_t *pdu, unsigned int len, const unsigned char *data);
+
+/**
+ * Retrieves the length and data pointer of specified PDU. Returns 0 on error
+ * or 1 if *len and *data have correct values. Note that these values are
+ * destroyed with the pdu.
+ */
+int coap_get_data(coap_pdu_t *pdu, size_t *len, unsigned char **data);
+
+#endif                                                 /* _PDU_H_ */
diff --git a/apps/include/netutils/libcoap/prng.h b/apps/include/netutils/libcoap/prng.h
new file mode 100644 (file)
index 0000000..1e303c6
--- /dev/null
@@ -0,0 +1,86 @@
+/* prng.h -- Pseudo Random Numbers
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+/**
+ * @file prng.h
+ * @brief Pseudo Random Numbers
+ */
+
+#ifndef _COAP_PRNG_H_
+#define _COAP_PRNG_H_
+
+#include "config.h"
+
+/**
+ * @defgroup prng Pseudo Random Numbers
+ * @{
+ */
+
+#ifndef WITH_CONTIKI
+#include <stdlib.h>
+
+/**
+ * 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)
+{
+       while (len--) {
+               *buf++ = rand() & 0xFF;
+       }
+       return 1;
+}
+#else                                                  /* WITH_CONTIKI */
+#include <string.h>
+
+/**
+ * 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.
+ *
+ * @hideinitializer
+ */
+#define prng(Buf,Length) coap_prng_impl((Buf), (Length))
+#endif
+
+#ifndef prng_init
+/**
+ * Called to set the PRNG seed. You may want to re-define this to
+ * allow for a better PRNG.
+ *
+ * @hideinitializer
+ */
+#define prng_init(Value) srand((unsigned long)(Value))
+#endif
+
+/** @} */
+
+#endif                                                 /* _COAP_PRNG_H_ */
diff --git a/apps/include/netutils/libcoap/resource.h b/apps/include/netutils/libcoap/resource.h
new file mode 100644 (file)
index 0000000..14f46c3
--- /dev/null
@@ -0,0 +1,312 @@
+/* resource.h -- generic resource handling
+ *
+ * Copyright (C) 2010,2011,2014 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+/**
+ * @file resource.h
+ * @brief generic resource handling
+ */
+
+#ifndef _COAP_RESOURCE_H_
+#define _COAP_RESOURCE_H_
+
+#include "config.h"
+#include "t_list.h"
+
+#if defined(HAVE_ASSERT_H) && !defined(assert)
+#include <assert.h>
+#endif
+
+#ifndef COAP_RESOURCE_CHECK_TIME
+/** The interval in seconds to check if resources have changed. */
+#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 "net.h"
+#include "subscribe.h"
+
+/** Definition of message handler function (@sa coap_resource_t). */
+typedef void (*coap_method_handler_t)
+(coap_context_t *, struct coap_resource_t *, coap_address_t *, coap_pdu_t *, str * /* token */ , coap_pdu_t * /* response */);
+
+#define COAP_ATTR_FLAGS_RELEASE_NAME  0x1
+#define COAP_ATTR_FLAGS_RELEASE_VALUE 0x2
+
+typedef struct coap_attr_t {
+       struct coap_attr_t *next;
+       str name;
+       str value;
+       int flags;
+} 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 */
+
+       /**
+        * 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
+        * generate a 4.05 response if no handler is available.
+        */
+       coap_method_handler_t handler[4];
+
+       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 */
+
+       /**
+        * Request URI for this resource. This field will point into the
+        * static memory. */
+       str uri;
+       int flags;
+
+} coap_resource_t;
+
+/**
+ * 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);
+
+/**
+ * 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
+ * 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.
+ * @param val       The attribute's value or @c NULL if none.
+ * @param vlen      Length of @p val if specified.
+ * @param flags     Flags for memory management (in particular release of memory)
+ *
+ * @return A pointer to the new attribute or @c NULL on error.
+ */
+coap_attr_t *coap_add_attr(coap_resource_t *resource, const unsigned char *name, size_t nlen, const unsigned char *val, size_t vlen, int flags);
+
+/**
+ * Returns @p resource's coap_attr_t object with given @p name if
+ * found, @c NULL otherwise.
+ *
+ * @param resource  The resource to search for attribute @p name.
+ * @param name      Name of the requested attribute.
+ * @param nlen      Actual length of @p name.
+ * @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);
+
+/**
+ * Deletes an attribute
+ *
+ * @param attr  Pointer to a previously created attribute
+ *
+ */
+void coap_delete_attr(coap_attr_t *attr);
+
+/**
+ * Status word to encode the result of conditional print or copy
+ * operations such as coap_print_link(). The lower 28 bits of
+ * coap_print_status_t are used to encode the number of characters
+ * that has actually been printed, bits 28 to 31 encode the status.
+ * When COAP_PRINT_STATUS_ERROR is set, an error occurred during
+ * output. In this case, the other bits are undefined.
+ * COAP_PRINT_STATUS_TRUNC indicates that the output is truncated,
+ * i.e. the printing would have exceeded the current buffer.
+ */
+typedef unsigned int coap_print_status_t;
+
+#define COAP_PRINT_STATUS_MASK  0xF0000000u
+#define COAP_PRINT_OUTPUT_LENGTH(v) ((v) & ~COAP_PRINT_STATUS_MASK)
+#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 buf      The output buffer to write the description 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
+ *         have actually been output into @p buffer. The flag
+ *         COAP_PRINT_STATUS_TRUNC indicates that the output has been
+ *         truncated.
+ */
+coap_print_status_t coap_print_link(const coap_resource_t *resource, unsigned char *buf, size_t *len, size_t *offset);
+
+/**
+ * Registers the specified @p handler as message handler for the request type
+ * @p method
+ *
+ * @param resource The resource for which the handler shall be registered.
+ * @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)
+{
+       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);
+
+/**
+ * Calculates the hash key for the resource requested by the
+ * Uri-Options of @p request.  This function calls coap_hash() for
+ * 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
+ */
+
+/**
+ * Adds the specified peer as observer for @p resource. The
+ * subscription is identified by the given @p token. This function
+ * returns the registered subscription information if the @p observer
+ * has been added, or @c NULL on error.
+ *
+ * @param resource The observed resource.
+ * @param observer The remote peer that wants to received status updates.
+ * @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
+ *        @c NULL on error.
+ */
+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.
+ *
+ * @param resource The observed resource.
+ * @param peer The address to search for.
+ * @param token The token that identifies this subscription or @c NULL for any
+ *              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);
+
+/**
+ * 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
+ *   the subscription
+ */
+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
+ * the allocated storage.
+ *
+ * @param resource The observed resource.
+ * @param observer The observer's address.
+ * @param token    The token that identifies this subscription or @c NULL for any
+ *                 token.
+ */
+void 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.
+ */
+void coap_check_notify(coap_context_t *context);
+
+/** @} */
+
+#endif                                                 /* _COAP_RESOURCE_H_ */
diff --git a/apps/include/netutils/libcoap/str.h b/apps/include/netutils/libcoap/str.h
new file mode 100644 (file)
index 0000000..0c21329
--- /dev/null
@@ -0,0 +1,30 @@
+/* str.h -- strings to be used in the CoAP library
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#ifndef _COAP_STR_H_
+#define _COAP_STR_H_
+
+#include <string.h>
+
+typedef struct {
+       size_t length;                          /* length of string */
+       unsigned char *s;                       /* string data */
+} str;
+
+#define COAP_SET_STR(st,l,v) { (st)->length = (l), (st)->s = (v); }
+
+/**
+ * Returns a new string object with at least size bytes storage
+ * allocated.  The string must be released using coap_delete_string();
+ */
+str *coap_new_string(size_t size);
+
+/** Deletes the given string and releases any memory allocated. */
+void coap_delete_string(str *);
+
+#endif                                                 /* _COAP_STR_H_ */
diff --git a/apps/include/netutils/libcoap/subscribe.h b/apps/include/netutils/libcoap/subscribe.h
new file mode 100644 (file)
index 0000000..19166c4
--- /dev/null
@@ -0,0 +1,189 @@
+/* subscribe.h -- subscription handling for CoAP
+ *                see draft-hartke-coap-observe-03
+ *
+ * Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * 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 "config.h"
+#include "address.h"
+
+/**
+ * @defgroup observe Resource observation
+ * @{
+ */
+
+#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_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 */
+       /* @todo CON/NON flag, block size */
+} coap_subscription_t;
+
+void coap_subscription_init(coap_subscription_t *);
+
+#if 0
+#include "uthash.h"
+#include "uri.h"
+#include "list.h"
+#include "pdu.h"
+#include "net.h"
+
+#if 0
+typedef unsigned long coap_key_t;
+
+/** Used to indicate that a hashkey is invalid. */
+#define COAP_INVALID_HASHKEY ((coap_key_t)-1)
+
+typedef struct {
+       coap_uri_t *uri;                        /* unique identifier; memory is released by coap_delete_resource() */
+       UT_hash_handle hh;              /**< hash handle (for internal use only) */
+       str *name;                                      /* display name of the resource */
+       unsigned char mediatype;        /* media type for resource representation */
+       unsigned int dirty: 1;          /* set to 1 if resource has changed */
+       unsigned int writable: 1;       /* set to 1 if resource can be changed using PUT */
+
+       /* cache-control */
+       unsigned char etag[4];          /* version identifier for this resource
+                                                                * (zero terminated, first byte is zero if not set). */
+       unsigned int maxage;            /* maximum cache time (zero means no Max-age option) */
+
+       /**
+        * Callback function that copies the resource representation into the provided data
+        * buffer (PDU payload). finished is set to 1 to indicate that this was the last block
+        * of buflen data for this resource representation, 0 means that data is not finished
+        * and a subsequent call with offset updated by buflen would yield more data (i.e.
+        * the M-bit of CoAP's block option must be set if offset and buflen are selected
+        * accordingly.
+        * When called, buflen must be set to the maximum length of buf that is to be filled
+        * with the mediatype representation of the resource identified by uri.
+        * The mediatype must be set to the requested mediatype of COAP_MEDIATYPE_ANY if
+        * none was given. On return, the mediatype will be set to the type that is
+        * actually used.
+        * The return value indicates the result code that should be used in a response to
+        * this function.
+        */
+       int (*data)(coap_uri_t *uri, unsigned char *mediatype, unsigned int offset, unsigned char *buf, unsigned int *buflen, int *finished);
+} coap_resource_t;
+#endif
+
+typedef struct {
+       coap_key_t resource;            /* hash key for subscribed resource */
+       time_t expires;                         /* expiry time of subscription */
+
+       coap_address_t subscriber;      /**< subscriber's address */
+
+       str token;                      /**< subscription token */
+} coap_subscription_t;
+
+#define COAP_RESOURCE(node) ((coap_resource_t *)(node)->data)
+#define COAP_SUBSCRIPTION(node) ((coap_subscription_t *)(node)->data)
+
+/** Checks subscribed resources for updates and notifies subscribers of changes. */
+void coap_check_resource_list(coap_context_t *context);
+
+/** Removes expired subscriptions. */
+void coap_check_subscriptions(coap_context_t *context);
+
+#if 0
+/**
+ * Adds specified resource to the resource observation list. Returns a
+ * unique key for the resource. The alloceted memory is released when
+ * the resource is destroyed with coap_delete_resource().
+ */
+coap_key_t coap_add_resource(coap_context_t *context, coap_resource_t *);
+
+/**
+ * Deletes the resource that is identified by key. Returns 1 if the resource was
+ * removed, 0 on error (e.g. if no such resource exists).
+ */
+int coap_delete_resource(coap_context_t *context, coap_key_t key);
+#endif
+/**
+ * Creates a new subscription object filled with the given data. The storage
+ * allocated for this object must be released using coap_free(). */
+coap_subscription_t *coap_new_subscription(coap_context_t *context, const coap_uri_t *resource, const struct sockaddr *subscriber, socklen_t addrlen, time_t expiry);
+
+/**
+ * Adds the given subsription object to the observer list.
+ * @param context The CoAP context
+ * @param subscription A new subscription oobject created with coap_new_subscription()
+ * @return A unique hash key for this resource or COAP_INVALID_HASHKEY on error.
+ * The storage allocated for the subscription object is released when it is
+ * removed from the subscription list, unless the function has returned
+ * COAP_INVALID_HASHKEY. In this case, the storage must be released by the
+ * caller of this function.
+*/
+coap_key_t coap_add_subscription(coap_context_t *context, coap_subscription_t *subscription);
+
+/**
+ * Returns the subscription from subscriber for the resource identified
+ * by hashkey. When token is not NULL the subscription must have the
+ * same token.
+ * @param context The CoAP context
+ * @param hashkey The unique key that identifies the subscription
+ * @param subscriber The subscriber's transport address
+ * @param token If not NULL, this specifies a token given by the
+ *              subscriber to identify its subscription.
+ * @return The requested subscription object or NULL when not found.
+ */
+coap_subscription_t *coap_find_subscription(coap_context_t *context, coap_key_t hashkey, struct sockaddr *subscriber, str *token);
+/**
+ * Removes a subscription from the subscription list stored in context and
+ * releases the storage that was allocated for this subscription.
+ * @param context The CoAP context.
+ * @param haskey The unique key that identifies the subscription to remove.
+ * @return 1 if a subscription was removed, 0 otherwise.
+ */
+int coap_delete_subscription(coap_context_t *context, coap_key_t hashkey, struct sockaddr *subscriber);
+
+/** Returns a unique hash for the specified URI or COAP_INVALID_HASHKEY on error. */
+coap_key_t coap_uri_hash(const coap_uri_t *uri);
+
+/** Returns a unique hash for the specified subscription or COAP_INVALID_HASHKEY on error. */
+coap_key_t coap_subscription_hash(coap_subscription_t *subscription);
+#if 0
+/** Returns the resource identified by key or NULL if not found. */
+coap_resource_t *coap_get_resource_from_key(coap_context_t *ctx, coap_key_t key);
+
+/** Returns the resource identified by uri or NULL if not found. */
+coap_resource_t *coap_get_resource(coap_context_t *ctx, coap_uri_t *uri);
+#endif
+
+#endif
+
+/** @} */
+
+#endif                                                 /* _COAP_SUBSCRIBE_H_ */
diff --git a/apps/include/netutils/libcoap/t_list.h b/apps/include/netutils/libcoap/t_list.h
new file mode 100644 (file)
index 0000000..af0e35f
--- /dev/null
@@ -0,0 +1,146 @@
+/* t_list -- tinydtls lists
+ *
+ * Copyright (C) 2012 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * @file t_list.h
+ * @brief Wrappers for list structures and functions
+ */
+
+#ifndef _DTLS_LIST_H_
+#define _DTLS_LIST_H_
+
+#ifndef WITH_CONTIKI
+#include "uthash.h"
+#include "utlist.h"
+
+/* We define list structures and utility functions to be compatible
+ * with Contiki list structures. The Contiki list API is part of the
+ * Contiki operating system, and therefore the following licensing
+ * terms apply (taken from contiki/core/lib/list.h):
+ *
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $ Id: list.h,v 1.5 2010/09/13 13:31:00 adamdunkels Exp $
+ */
+
+typedef void **list_t;
+struct list {
+       struct list *next;
+};
+
+#define LIST_CONCAT(s1, s2) s1##s2
+
+#define LIST_STRUCT(name)                      \
+  void *LIST_CONCAT(name, _list);              \
+  list_t name
+
+#define LIST_STRUCT_INIT(struct_ptr, name)  {                          \
+    (struct_ptr)->name = &((struct_ptr)->LIST_CONCAT(name,_list));     \
+    (struct_ptr)->LIST_CONCAT(name,_list) = NULL;                      \
+  }
+
+static inline void *list_head(list_t the_list)
+{
+       return *the_list;
+}
+
+static inline void list_remove(list_t the_list, void *item)
+{
+       if (list_head(the_list)) {
+               LL_DELETE(*(struct list **)the_list, (struct list *)item);
+       }
+}
+
+static inline void list_add(list_t the_list, void *item)
+{
+       list_remove(the_list, item);
+       LL_APPEND(*(struct list **)the_list, (struct list *)item);
+}
+
+static inline void list_push(list_t the_list, void *item)
+{
+       LL_PREPEND(*(struct list **)the_list, (struct list *)item);
+}
+
+static inline void *list_pop(list_t the_list)
+{
+       struct list *l;
+       l = (struct list *)*the_list;
+       if (l) {
+               list_remove(the_list, l);
+       }
+
+       return l;
+}
+
+static inline void list_insert(list_t the_list, void *previtem, void *newitem)
+{
+       if (previtem == NULL) {
+               list_push(the_list, newitem);
+       } else {
+               ((struct list *)newitem)->next = ((struct list *)previtem)->next;
+               ((struct list *)previtem)->next = (struct list *)newitem;
+       }
+}
+
+static inline void *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/apps/include/netutils/libcoap/uri.h b/apps/include/netutils/libcoap/uri.h
new file mode 100644 (file)
index 0000000..264a216
--- /dev/null
@@ -0,0 +1,166 @@
+/* uri.h -- helper functions for URI treatment
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#ifndef _COAP_URI_H_
+#define _COAP_URI_H_
+
+#include "hashkey.h"
+#include "str.h"
+
+/** Representation of parsed URI. Components may be filled from a
+ * string with coap_split_uri() and can be used as input for
+ * option-creation functions. */
+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.
+                                  Use coap_split_path() to create Uri-Path options */
+       str query;                      /**<  The query part if present */
+} coap_uri_t;
+
+/**
+ * Creates a new coap_uri_t object from the specified URI. Returns the new
+ * object or NULL on error. The memory allocated by the new coap_uri_t
+ * must be released using coap_free().
+ * @param uri The URI path to copy.
+ * @para length The length of uri.
+ *
+ * @return New URI object or NULL on error.
+ */
+coap_uri_t *coap_new_uri(const unsigned char *uri, unsigned int length);
+
+/**
+ * Clones the specified coap_uri_t object. Thie function allocates sufficient
+ * memory to hold the coap_uri_t structure and its contents. The object must
+ * 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
+ * @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);
+
+/**
+ * @defgroup uri_parse URI Parsing Functions
+ *
+ * CoAP PDUs contain normalized URIs with their path and query split into
+ * multiple segments. The functions in this module help splitting strings.
+ * @{
+ */
+
+/**
+ * Iterator to for tokenizing a URI path or query. This structure must
+ * be initialized with coap_parse_iterator_init(). Call
+ * coap_parse_next() to walk through the tokens.
+ *
+ * @code
+ * unsigned char *token;
+ * coap_parse_iterator_t pi;
+ * coap_parse_iterator_init(uri.path.s, uri.path.length, '/', "?#", 2, &pi);
+ *
+ * while ((token = coap_parse_next(&pi))) {
+ *   ... do something with token ...
+ * }
+ * @endcode
+ */
+typedef struct {
+       size_t n;               /**< number of remaining characters in buffer */
+       unsigned char separator;/**< segment separators */
+       unsigned char *delim;   /**< delimiters where to split the string */
+       size_t dlen;            /**< length of separator */
+       unsigned char *pos;             /**< current position in buffer */
+       size_t segment_length;  /**< length of current segment */
+} coap_parse_iterator_t;
+
+/**
+ * Initializes the given iterator @p pi.
+ *
+ * @param s         The string to tokenize.
+ * @param n         The length of @p s.
+ * @param separator The separator character that delimits tokens.
+ * @param delim     A set of characters that delimit @s.
+ * @param dlen      The length of @p delim.
+ * @param pi        The iterator object to initialize.
+ *
+ * @return The initialized iterator object @p pi.
+ */
+coap_parse_iterator_t *coap_parse_iterator_init(unsigned char *s, size_t n, unsigned char separator, unsigned char *delim, size_t dlen, coap_parse_iterator_t *pi);
+
+/**
+ * Updates the iterator @p pi to point to the next token. This
+ * function returns a pointer to that token or @c NULL if no more
+ * tokens exist. The contents of @p pi will be updated. In particular,
+ * @c pi->segment_length specifies the length of the current token, @c
+ * pi->pos points to its beginning.
+ *
+ * @param pi The iterator to update.
+ *
+ * @return The next token or @c NULL if no more tokens exist.
+ */
+unsigned char *coap_parse_next(coap_parse_iterator_t *pi);
+
+/**
+ * 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.
+ * @return @c 0 on success, or < 0 on error.
+ *
+ * @note The host name part will be converted to lower case by this
+ * function.
+ */
+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 length The actual length of @p s.
+ * @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, 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 length The actual length of @p s.
+ * @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, unsigned char *buf, size_t *buflen);
+
+/** @} */
+
+#endif                                                 /* _COAP_URI_H_ */
diff --git a/apps/include/netutils/libcoap/uthash.h b/apps/include/netutils/libcoap/uthash.h
new file mode 100644 (file)
index 0000000..bc053e5
--- /dev/null
@@ -0,0 +1,971 @@
+/*
+Copyright (c) 2003-2010, Troy D. Hanson     http://uthash.sourceforge.net
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER
+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.
+*/
+
+#ifndef UTHASH_H
+#define UTHASH_H
+
+#include <string.h>                            /* memcmp,strlen */
+#include <stddef.h>                            /* ptrdiff_t */
+
+/* These macros use decltype or the earlier __typeof GNU extension.
+   As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+   when compiling c++ source) this code uses whatever method is needed
+   or, for VS2008 where neither is available, uses casting workarounds. */
+#ifdef _MSC_VER                                        /* MS compiler */
+#if _MSC_VER >= 1600 && defined(__cplusplus)   /* VS2010 or newer in C++ mode */
+#define DECLTYPE(x) (decltype(x))
+#else                                                  /* VS2008 or older (or VS2010 in C mode) */
+#define NO_DECLTYPE
+#define DECLTYPE(x)
+#endif
+#else                                                  /* GNU, Sun and other compilers */
+#define DECLTYPE(x) (__typeof(x))
+#endif
+
+#ifdef NO_DECLTYPE
+#define DECLTYPE_ASSIGN(dst,src)                                                 \
+do {                                                                             \
+  char **_da_dst = (char**)(&(dst));                                             \
+  *_da_dst = (char*)(src);                                                       \
+} while(0)
+#else
+#define DECLTYPE_ASSIGN(dst,src)                                                 \
+do {                                                                             \
+  (dst) = DECLTYPE(dst)(src);                                                    \
+} while(0)
+#endif
+
+/* a number of the hash function use uint32_t which isn't defined on win32 */
+#ifdef _MSC_VER
+typedef unsigned int uint32_t;
+#else
+#include <inttypes.h>                  /* uint32_t */
+#endif
+
+#define UTHASH_VERSION 1.9.3
+
+#ifndef uthash_fatal
+#define uthash_fatal(msg) 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                        */
+
+#define uthash_noexpand_fyi(tbl)       /* can be defined to log noexpand  */
+#define uthash_expand_fyi(tbl) /* can be defined to log expands   */
+
+/* initial number of buckets */
+#define HASH_INITIAL_NUM_BUCKETS 32    /* initial number of buckets        */
+#define HASH_INITIAL_NUM_BUCKETS_LOG2 5        /* lg2 of initial number of buckets */
+#define HASH_BKT_CAPACITY_THRESH 10    /* expand when bucket count reaches */
+
+/* calculate the element whose hash handle address is hhe */
+#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
+
+#define HASH_FIND(hh,head,keyptr,keylen,out)                                     \
+do {                                                                             \
+  unsigned _hf_bkt,_hf_hashv;                                                    \
+  out=NULL;                                                                      \
+  if (head) {                                                                    \
+     HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt);   \
+     if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) {                           \
+       HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ],  \
+                        keyptr,keylen,out);                                      \
+     }                                                                           \
+  }                                                                              \
+} while (0)
+
+#ifdef HASH_BLOOM
+#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM)
+#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0)
+#define HASH_BLOOM_MAKE(tbl)                                                     \
+do {                                                                             \
+  (tbl)->bloom_nbits = HASH_BLOOM;                                               \
+  (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN);                 \
+  if (!((tbl)->bloom_bv))  { uthash_fatal( "out of memory"); }                   \
+  memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN);                                \
+  (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE;                                       \
+} while (0);
+
+#define HASH_BLOOM_FREE(tbl)                                                     \
+do {                                                                             \
+  uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN);                              \
+} while (0);
+
+#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8)))
+#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8)))
+
+#define HASH_BLOOM_ADD(tbl,hashv)                                                \
+  HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
+
+#define HASH_BLOOM_TEST(tbl,hashv)                                               \
+  HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
+
+#else
+#define HASH_BLOOM_MAKE(tbl)
+#define HASH_BLOOM_FREE(tbl)
+#define HASH_BLOOM_ADD(tbl,hashv)
+#define HASH_BLOOM_TEST(tbl,hashv) (1)
+#endif
+
+#define HASH_MAKE_TABLE(hh,head)                                                 \
+do {                                                                             \
+  (head)->hh.tbl = (UT_hash_table*)uthash_malloc(                                \
+                  sizeof(UT_hash_table));                                        \
+  if (!((head)->hh.tbl))  { uthash_fatal( "out of memory"); }                    \
+  memset((head)->hh.tbl, 0, sizeof(UT_hash_table));                              \
+  (head)->hh.tbl->tail = &((head)->hh);                                          \
+  (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS;                        \
+  (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2;              \
+  (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head);                    \
+  (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc(                      \
+          HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket));               \
+  if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); }             \
+  memset((head)->hh.tbl->buckets, 0,                                             \
+          HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket));               \
+  HASH_BLOOM_MAKE((head)->hh.tbl);                                               \
+  (head)->hh.tbl->signature = HASH_SIGNATURE;                                    \
+} while(0)
+
+#define HASH_ADD(hh,head,fieldname,keylen_in,add)                                \
+        HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add)
+
+#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add)                            \
+do {                                                                             \
+ unsigned _ha_bkt;                                                               \
+ (add)->hh.next = NULL;                                                          \
+ (add)->hh.key = (char*)keyptr;                                                  \
+ (add)->hh.keylen = keylen_in;                                                   \
+ if (!(head)) {                                                                  \
+    head = (add);                                                                \
+    (head)->hh.prev = NULL;                                                      \
+    HASH_MAKE_TABLE(hh,head);                                                    \
+ } else {                                                                        \
+    (head)->hh.tbl->tail->next = (add);                                          \
+    (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail);         \
+    (head)->hh.tbl->tail = &((add)->hh);                                         \
+ }                                                                               \
+ (head)->hh.tbl->num_items++;                                                    \
+ (add)->hh.tbl = (head)->hh.tbl;                                                 \
+ HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets,                         \
+         (add)->hh.hashv, _ha_bkt);                                              \
+ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh);                   \
+ HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv);                                 \
+ HASH_EMIT_KEY(hh,head,keyptr,keylen_in);                                        \
+ HASH_FSCK(hh,head);                                                             \
+} while(0)
+
+#define HASH_TO_BKT( hashv, num_bkts, bkt )                                      \
+do {                                                                             \
+  bkt = ((hashv) & ((num_bkts) - 1));                                            \
+} while(0)
+
+/* delete "delptr" from the hash table.
+ * "the usual" patch-up process for the app-order doubly-linked-list.
+ * The use of _hd_hh_del below deserves special explanation.
+ * These used to be expressed using (delptr) but that led to a bug
+ * if someone used the same symbol for the head and deletee, like
+ *  HASH_DELETE(hh,users,users);
+ * We want that to work, but by changing the head (users) below
+ * we were forfeiting our ability to further refer to the deletee (users)
+ * in the patch-up process. Solution: use scratch space to
+ * copy the deletee pointer, then the latter references are via that
+ * scratch pointer rather than through the repointed (users) symbol.
+ */
+#define HASH_DELETE(hh,head,delptr)                                              \
+do {                                                                             \
+    unsigned _hd_bkt;                                                            \
+    struct UT_hash_handle *_hd_hh_del;                                           \
+    if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) )  {         \
+        uthash_free((head)->hh.tbl->buckets,                                     \
+                    (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+        HASH_BLOOM_FREE((head)->hh.tbl);                                         \
+        uthash_free((head)->hh.tbl, sizeof(UT_hash_table));                      \
+        head = NULL;                                                             \
+    } else {                                                                     \
+        _hd_hh_del = &((delptr)->hh);                                            \
+        if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) {     \
+            (head)->hh.tbl->tail =                                               \
+                (UT_hash_handle*)((char*)((delptr)->hh.prev) +                   \
+                (head)->hh.tbl->hho);                                            \
+        }                                                                        \
+        if ((delptr)->hh.prev) {                                                 \
+            ((UT_hash_handle*)((char*)((delptr)->hh.prev) +                      \
+                    (head)->hh.tbl->hho))->next = (delptr)->hh.next;             \
+        } else {                                                                 \
+            DECLTYPE_ASSIGN(head,(delptr)->hh.next);                             \
+        }                                                                        \
+        if (_hd_hh_del->next) {                                                  \
+            ((UT_hash_handle*)((char*)_hd_hh_del->next +                         \
+                    (head)->hh.tbl->hho))->prev =                                \
+                    _hd_hh_del->prev;                                            \
+        }                                                                        \
+        HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt);   \
+        HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del);        \
+        (head)->hh.tbl->num_items--;                                             \
+    }                                                                            \
+    HASH_FSCK(hh,head);                                                          \
+} while (0)
+
+/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
+#define HASH_FIND_STR(head,findstr,out)                                          \
+    HASH_FIND(hh,head,findstr,strlen(findstr),out)
+#define HASH_ADD_STR(head,strfield,add)                                          \
+    HASH_ADD(hh,head,strfield,strlen(add->strfield),add)
+#define HASH_FIND_INT(head,findint,out)                                          \
+    HASH_FIND(hh,head,findint,sizeof(int),out)
+#define HASH_ADD_INT(head,intfield,add)                                          \
+    HASH_ADD(hh,head,intfield,sizeof(int),add)
+#define HASH_FIND_PTR(head,findptr,out)                                          \
+    HASH_FIND(hh,head,findptr,sizeof(void *),out)
+#define HASH_ADD_PTR(head,ptrfield,add)                                          \
+    HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
+#define HASH_DEL(head,delptr)                                                    \
+    HASH_DELETE(hh,head,delptr)
+
+/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
+ * 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_FSCK(hh,head)                                                       \
+do {                                                                             \
+    unsigned _bkt_i;                                                             \
+    unsigned _count, _bkt_count;                                                 \
+    char *_prev;                                                                 \
+    struct UT_hash_handle *_thh;                                                 \
+    if (head) {                                                                  \
+        _count = 0;                                                              \
+        for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) {       \
+            _bkt_count = 0;                                                      \
+            _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head;                      \
+            _prev = NULL;                                                        \
+            while (_thh) {                                                       \
+               if (_prev != (char*)(_thh->hh_prev)) {                            \
+                   HASH_OOPS("invalid hh_prev %p, actual %p\n",                  \
+                    _thh->hh_prev, _prev );                                      \
+               }                                                                 \
+               _bkt_count++;                                                     \
+               _prev = (char*)(_thh);                                            \
+               _thh = _thh->hh_next;                                             \
+            }                                                                    \
+            _count += _bkt_count;                                                \
+            if ((head)->hh.tbl->buckets[_bkt_i].count !=  _bkt_count) {          \
+               HASH_OOPS("invalid bucket count %d, actual %d\n",                 \
+                (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count);              \
+            }                                                                    \
+        }                                                                        \
+        if (_count != (head)->hh.tbl->num_items) {                               \
+            HASH_OOPS("invalid hh item count %d, actual %d\n",                   \
+                (head)->hh.tbl->num_items, _count );                             \
+        }                                                                        \
+        /* traverse hh in app order; check next/prev integrity, count */         \
+        _count = 0;                                                              \
+        _prev = NULL;                                                            \
+        _thh =  &(head)->hh;                                                     \
+        while (_thh) {                                                           \
+           _count++;                                                             \
+           if (_prev !=(char*)(_thh->prev)) {                                    \
+              HASH_OOPS("invalid prev %p, actual %p\n",                          \
+                    _thh->prev, _prev );                                         \
+           }                                                                     \
+           _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh);                    \
+           _thh = ( _thh->next ?  (UT_hash_handle*)((char*)(_thh->next) +        \
+                                  (head)->hh.tbl->hho) : NULL );                 \
+        }                                                                        \
+        if (_count != (head)->hh.tbl->num_items) {                               \
+            HASH_OOPS("invalid app item count %d, actual %d\n",                  \
+                (head)->hh.tbl->num_items, _count );                             \
+        }                                                                        \
+    }                                                                            \
+} while (0)
+#else
+#define HASH_FSCK(hh,head)
+#endif
+
+/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
+ * the descriptor to which this macro is defined for tuning the hash function.
+ * The app can #include <unistd.h> to get the prototype for write(2). */
+#ifdef HASH_EMIT_KEYS
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)                                   \
+do {                                                                             \
+    unsigned _klen = fieldlen;                                                   \
+    write(HASH_EMIT_KEYS, &_klen, sizeof(_klen));                                \
+    write(HASH_EMIT_KEYS, keyptr, fieldlen);                                     \
+} while (0)
+#else
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)
+#endif
+
+/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
+#ifdef HASH_FUNCTION
+#define HASH_FCN HASH_FUNCTION
+#else
+#define HASH_FCN HASH_JEN
+#endif
+
+/* The Bernstein hash function, used in Perl prior to v5.6 */
+#define HASH_BER(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  unsigned _hb_keylen=keylen;                                                    \
+  char *_hb_key=(char*)(key);                                                    \
+  (hashv) = 0;                                                                   \
+  while (_hb_keylen--)  { (hashv) = ((hashv) * 33) + *_hb_key++; }               \
+  bkt = (hashv) & (num_bkts-1);                                                  \
+} while (0)
+
+/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
+ * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
+#define HASH_SAX(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  unsigned _sx_i;                                                                \
+  char *_hs_key=(char*)(key);                                                    \
+  hashv = 0;                                                                     \
+  for(_sx_i=0; _sx_i < keylen; _sx_i++)                                          \
+      hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i];                     \
+  bkt = hashv & (num_bkts-1);                                                    \
+} while (0)
+
+#define HASH_FNV(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  unsigned _fn_i;                                                                \
+  char *_hf_key=(char*)(key);                                                    \
+  hashv = 2166136261UL;                                                          \
+  for(_fn_i=0; _fn_i < keylen; _fn_i++)                                          \
+      hashv = (hashv * 16777619) ^ _hf_key[_fn_i];                               \
+  bkt = hashv & (num_bkts-1);                                                    \
+} while(0);
+
+#define HASH_OAT(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  unsigned _ho_i;                                                                \
+  char *_ho_key=(char*)(key);                                                    \
+  hashv = 0;                                                                     \
+  for(_ho_i=0; _ho_i < keylen; _ho_i++) {                                        \
+      hashv += _ho_key[_ho_i];                                                   \
+      hashv += (hashv << 10);                                                    \
+      hashv ^= (hashv >> 6);                                                     \
+  }                                                                              \
+  hashv += (hashv << 3);                                                         \
+  hashv ^= (hashv >> 11);                                                        \
+  hashv += (hashv << 15);                                                        \
+  bkt = hashv & (num_bkts-1);                                                    \
+} while(0)
+
+#define HASH_JEN_MIX(a,b,c)                                                      \
+do {                                                                             \
+  a -= b; a -= c; a ^= ( c >> 13 );                                              \
+  b -= c; b -= a; b ^= ( a << 8 );                                               \
+  c -= a; c -= b; c ^= ( b >> 13 );                                              \
+  a -= b; a -= c; a ^= ( c >> 12 );                                              \
+  b -= c; b -= a; b ^= ( a << 16 );                                              \
+  c -= a; c -= b; c ^= ( b >> 5 );                                               \
+  a -= b; a -= c; a ^= ( c >> 3 );                                               \
+  b -= c; b -= a; b ^= ( a << 10 );                                              \
+  c -= a; c -= b; c ^= ( b >> 15 );                                              \
+} while (0)
+
+#define HASH_JEN(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  unsigned _hj_i,_hj_j,_hj_k;                                                    \
+  char *_hj_key=(char*)(key);                                                    \
+  hashv = 0xfeedbeef;                                                            \
+  _hj_i = _hj_j = 0x9e3779b9;                                                    \
+  _hj_k = keylen;                                                                \
+  while (_hj_k >= 12) {                                                          \
+    _hj_i +=    (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 )                      \
+        + ( (unsigned)_hj_key[2] << 16 )                                         \
+        + ( (unsigned)_hj_key[3] << 24 ) );                                      \
+    _hj_j +=    (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 )                      \
+        + ( (unsigned)_hj_key[6] << 16 )                                         \
+        + ( (unsigned)_hj_key[7] << 24 ) );                                      \
+    hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 )                         \
+        + ( (unsigned)_hj_key[10] << 16 )                                        \
+        + ( (unsigned)_hj_key[11] << 24 ) );                                     \
+                                                                                 \
+     HASH_JEN_MIX(_hj_i, _hj_j, hashv);                                          \
+                                                                                 \
+     _hj_key += 12;                                                              \
+     _hj_k -= 12;                                                                \
+  }                                                                              \
+  hashv += keylen;                                                               \
+  switch ( _hj_k ) {                                                             \
+     case 11: hashv += ( (unsigned)_hj_key[10] << 24 );                          \
+     case 10: hashv += ( (unsigned)_hj_key[9] << 16 );                           \
+     case 9:  hashv += ( (unsigned)_hj_key[8] << 8 );                            \
+     case 8:  _hj_j += ( (unsigned)_hj_key[7] << 24 );                           \
+     case 7:  _hj_j += ( (unsigned)_hj_key[6] << 16 );                           \
+     case 6:  _hj_j += ( (unsigned)_hj_key[5] << 8 );                            \
+     case 5:  _hj_j += _hj_key[4];                                               \
+     case 4:  _hj_i += ( (unsigned)_hj_key[3] << 24 );                           \
+     case 3:  _hj_i += ( (unsigned)_hj_key[2] << 16 );                           \
+     case 2:  _hj_i += ( (unsigned)_hj_key[1] << 8 );                            \
+     case 1:  _hj_i += _hj_key[0];                                               \
+  }                                                                              \
+  HASH_JEN_MIX(_hj_i, _hj_j, hashv);                                             \
+  bkt = hashv & (num_bkts-1);                                                    \
+} while(0)
+
+/* The Paul Hsieh hash function */
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__)             \
+  || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)             \
+                       +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+#define HASH_SFH(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  char *_sfh_key=(char*)(key);                                                   \
+  uint32_t _sfh_tmp, _sfh_len = keylen;                                          \
+                                                                                 \
+  int _sfh_rem = _sfh_len & 3;                                                   \
+  _sfh_len >>= 2;                                                                \
+  hashv = 0xcafebabe;                                                            \
+                                                                                 \
+  /* Main loop */                                                                \
+  for (;_sfh_len > 0; _sfh_len--) {                                              \
+    hashv    += get16bits (_sfh_key);                                            \
+    _sfh_tmp       = (get16bits (_sfh_key+2) << 11) ^ hashv;                     \
+    hashv     = (hashv << 16) ^ _sfh_tmp;                                        \
+    _sfh_key += 2*sizeof (uint16_t);                                             \
+    hashv    += hashv >> 11;                                                     \
+  }                                                                              \
+                                                                                 \
+  /* Handle end cases */                                                         \
+  switch (_sfh_rem) {                                                            \
+    case 3: hashv += get16bits (_sfh_key);                                       \
+            hashv ^= hashv << 16;                                                \
+            hashv ^= _sfh_key[sizeof (uint16_t)] << 18;                          \
+            hashv += hashv >> 11;                                                \
+            break;                                                               \
+    case 2: hashv += get16bits (_sfh_key);                                       \
+            hashv ^= hashv << 11;                                                \
+            hashv += hashv >> 17;                                                \
+            break;                                                               \
+    case 1: hashv += *_sfh_key;                                                  \
+            hashv ^= hashv << 10;                                                \
+            hashv += hashv >> 1;                                                 \
+  }                                                                              \
+                                                                                 \
+    /* Force "avalanching" of final 127 bits */                                  \
+    hashv ^= hashv << 3;                                                         \
+    hashv += hashv >> 5;                                                         \
+    hashv ^= hashv << 4;                                                         \
+    hashv += hashv >> 17;                                                        \
+    hashv ^= hashv << 25;                                                        \
+    hashv += hashv >> 6;                                                         \
+    bkt = hashv & (num_bkts-1);                                                  \
+} while(0);
+
+#ifdef HASH_USING_NO_STRICT_ALIASING
+/* The MurmurHash exploits some CPU's (e.g. x86) tolerance for unaligned reads.
+ * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
+ * So MurmurHash comes in two versions, the faster unaligned one and the slower
+ * aligned one. We only use the faster one on CPU's where we know it's safe.
+ *
+ * Note the preprocessor built-in defines can be emitted using:
+ *
+ *   gcc -m64 -dM -E - < /dev/null                  (on gcc)
+ *   cc -## a.c (where a.c is a simple test file)   (Sun Studio)
+ */
+#if (defined(__i386__) || defined(__x86_64__))
+#define HASH_MUR HASH_MUR_UNALIGNED
+#else
+#define HASH_MUR HASH_MUR_ALIGNED
+#endif
+
+/* Appleby's MurmurHash fast version for unaligned-tolerant archs like i386 */
+#define HASH_MUR_UNALIGNED(key,keylen,num_bkts,hashv,bkt)                        \
+do {                                                                             \
+  const unsigned int _mur_m = 0x5bd1e995;                                        \
+  const int _mur_r = 24;                                                         \
+  hashv = 0xcafebabe ^ keylen;                                                   \
+  char *_mur_key = (char *)(key);                                                \
+  uint32_t _mur_tmp, _mur_len = keylen;                                          \
+                                                                                 \
+  for (;_mur_len >= 4; _mur_len-=4) {                                            \
+    _mur_tmp = *(uint32_t *)_mur_key;                                            \
+    _mur_tmp *= _mur_m;                                                          \
+    _mur_tmp ^= _mur_tmp >> _mur_r;                                              \
+    _mur_tmp *= _mur_m;                                                          \
+    hashv *= _mur_m;                                                             \
+    hashv ^= _mur_tmp;                                                           \
+    _mur_key += 4;                                                               \
+  }                                                                              \
+                                                                                 \
+  switch(_mur_len)                                                               \
+  {                                                                              \
+    case 3: hashv ^= _mur_key[2] << 16;                                          \
+    case 2: hashv ^= _mur_key[1] << 8;                                           \
+    case 1: hashv ^= _mur_key[0];                                                \
+            hashv *= _mur_m;                                                     \
+  };                                                                             \
+                                                                                 \
+  hashv ^= hashv >> 13;                                                          \
+  hashv *= _mur_m;                                                               \
+  hashv ^= hashv >> 15;                                                          \
+                                                                                 \
+  bkt = hashv & (num_bkts-1);                                                    \
+} while(0)
+
+/* Appleby's MurmurHash version for alignment-sensitive archs like Sparc */
+#define HASH_MUR_ALIGNED(key,keylen,num_bkts,hashv,bkt)                          \
+do {                                                                             \
+  const unsigned int _mur_m = 0x5bd1e995;                                        \
+  const int _mur_r = 24;                                                         \
+  hashv = 0xcafebabe ^ (keylen);                                                 \
+  char *_mur_key = (char *)(key);                                                \
+  uint32_t _mur_len = keylen;                                                    \
+  int _mur_align = (int)_mur_key & 3;                                            \
+                                                                                 \
+  if (_mur_align && (_mur_len >= 4)) {                                           \
+    unsigned _mur_t = 0, _mur_d = 0;                                             \
+    switch(_mur_align) {                                                         \
+      case 1: _mur_t |= _mur_key[2] << 16;                                       \
+      case 2: _mur_t |= _mur_key[1] << 8;                                        \
+      case 3: _mur_t |= _mur_key[0];                                             \
+    }                                                                            \
+    _mur_t <<= (8 * _mur_align);                                                 \
+    _mur_key += 4-_mur_align;                                                    \
+    _mur_len -= 4-_mur_align;                                                    \
+    int _mur_sl = 8 * (4-_mur_align);                                            \
+    int _mur_sr = 8 * _mur_align;                                                \
+                                                                                 \
+    for (;_mur_len >= 4; _mur_len-=4) {                                          \
+      _mur_d = *(unsigned *)_mur_key;                                            \
+      _mur_t = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl);                        \
+      unsigned _mur_k = _mur_t;                                                  \
+      _mur_k *= _mur_m;                                                          \
+      _mur_k ^= _mur_k >> _mur_r;                                                \
+      _mur_k *= _mur_m;                                                          \
+      hashv *= _mur_m;                                                           \
+      hashv ^= _mur_k;                                                           \
+      _mur_t = _mur_d;                                                           \
+      _mur_key += 4;                                                             \
+    }                                                                            \
+    _mur_d = 0;                                                                  \
+    if(_mur_len >= _mur_align) {                                                 \
+      switch(_mur_align) {                                                       \
+        case 3: _mur_d |= _mur_key[2] << 16;                                     \
+        case 2: _mur_d |= _mur_key[1] << 8;                                      \
+        case 1: _mur_d |= _mur_key[0];                                           \
+      }                                                                          \
+      unsigned _mur_k = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl);               \
+      _mur_k *= _mur_m;                                                          \
+      _mur_k ^= _mur_k >> _mur_r;                                                \
+      _mur_k *= _mur_m;                                                          \
+      hashv *= _mur_m;                                                           \
+      hashv ^= _mur_k;                                                           \
+      _mur_k += _mur_align;                                                      \
+      _mur_len -= _mur_align;                                                    \
+                                                                                 \
+      switch(_mur_len)                                                           \
+      {                                                                          \
+        case 3: hashv ^= _mur_key[2] << 16;                                      \
+        case 2: hashv ^= _mur_key[1] << 8;                                       \
+        case 1: hashv ^= _mur_key[0];                                            \
+                hashv *= _mur_m;                                                 \
+      }                                                                          \
+    } else {                                                                     \
+      switch(_mur_len)                                                           \
+      {                                                                          \
+        case 3: _mur_d ^= _mur_key[2] << 16;                                     \
+        case 2: _mur_d ^= _mur_key[1] << 8;                                      \
+        case 1: _mur_d ^= _mur_key[0];                                           \
+        case 0: hashv ^= (_mur_t >> _mur_sr) | (_mur_d << _mur_sl);              \
+        hashv *= _mur_m;                                                         \
+      }                                                                          \
+    }                                                                            \
+                                                                                 \
+    hashv ^= hashv >> 13;                                                        \
+    hashv *= _mur_m;                                                             \
+    hashv ^= hashv >> 15;                                                        \
+  } else {                                                                       \
+    for (;_mur_len >= 4; _mur_len-=4) {                                          \
+      unsigned _mur_k = *(unsigned*)_mur_key;                                    \
+      _mur_k *= _mur_m;                                                          \
+      _mur_k ^= _mur_k >> _mur_r;                                                \
+      _mur_k *= _mur_m;                                                          \
+      hashv *= _mur_m;                                                           \
+      hashv ^= _mur_k;                                                           \
+      _mur_key += 4;                                                             \
+    }                                                                            \
+    switch(_mur_len)                                                             \
+    {                                                                            \
+      case 3: hashv ^= _mur_key[2] << 16;                                        \
+      case 2: hashv ^= _mur_key[1] << 8;                                         \
+      case 1: hashv ^= _mur_key[0];                                              \
+      hashv *= _mur_m;                                                           \
+    }                                                                            \
+                                                                                 \
+    hashv ^= hashv >> 13;                                                        \
+    hashv *= _mur_m;                                                             \
+    hashv ^= hashv >> 15;                                                        \
+  }                                                                              \
+  bkt = hashv & (num_bkts-1);                                                    \
+} while(0)
+#endif                                                 /* HASH_USING_NO_STRICT_ALIASING */
+
+/* key comparison function; return 0 if keys equal */
+#define HASH_KEYCMP(a,b,len) memcmp(a,b,len)
+
+/* iterate over items in a known bucket to find desired item */
+#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out)                       \
+do {                                                                             \
+ if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head));          \
+ else out=NULL;                                                                  \
+ while (out) {                                                                   \
+    if (out->hh.keylen == keylen_in) {                                           \
+        if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break;             \
+    }                                                                            \
+    if (out->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,out->hh.hh_next)); \
+    else out = NULL;                                                             \
+ }                                                                               \
+} while(0)
+
+/* add an item to a bucket  */
+#define HASH_ADD_TO_BKT(head,addhh)                                              \
+do {                                                                             \
+ head.count++;                                                                   \
+ (addhh)->hh_next = head.hh_head;                                                \
+ (addhh)->hh_prev = NULL;                                                        \
+ if (head.hh_head) { (head).hh_head->hh_prev = (addhh); }                        \
+ (head).hh_head=addhh;                                                           \
+ if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH)             \
+     && (addhh)->tbl->noexpand != 1) {                                           \
+       HASH_EXPAND_BUCKETS((addhh)->tbl);                                        \
+ }                                                                               \
+} while(0)
+
+/* remove an item from a given bucket */
+#define HASH_DEL_IN_BKT(hh,head,hh_del)                                          \
+    (head).count--;                                                              \
+    if ((head).hh_head == hh_del) {                                              \
+      (head).hh_head = hh_del->hh_next;                                          \
+    }                                                                            \
+    if (hh_del->hh_prev) {                                                       \
+        hh_del->hh_prev->hh_next = hh_del->hh_next;                              \
+    }                                                                            \
+    if (hh_del->hh_next) {                                                       \
+        hh_del->hh_next->hh_prev = hh_del->hh_prev;                              \
+    }
+
+/* Bucket expansion has the effect of doubling the number of buckets
+ * and redistributing the items into the new buckets. Ideally the
+ * items will distribute more or less evenly into the new buckets
+ * (the extent to which this is true is a measure of the quality of
+ * the hash function as it applies to the key domain).
+ *
+ * With the items distributed into more buckets, the chain length
+ * (item count) in each bucket is reduced. Thus by expanding buckets
+ * the hash keeps a bound on the chain length. This bounded chain
+ * length is the essence of how a hash provides constant time lookup.
+ *
+ * The calculation of tbl->ideal_chain_maxlen below deserves some
+ * explanation. First, keep in mind that we're calculating the ideal
+ * maximum chain length based on the *new* (doubled) bucket count.
+ * In fractions this is just n/b (n=number of items,b=new num buckets).
+ * Since the ideal chain length is an integer, we want to calculate
+ * ceil(n/b). We don't depend on floating point arithmetic in this
+ * hash, so to calculate ceil(n/b) with integers we could write
+ *
+ *      ceil(n/b) = (n/b) + ((n%b)?1:0)
+ *
+ * and in fact a previous version of this hash did just that.
+ * But now we have improved things a bit by recognizing that b is
+ * always a power of two. We keep its base 2 log handy (call it lb),
+ * so now we can write this with a bit shift and logical AND:
+ *
+ *      ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
+ *
+ */
+#define HASH_EXPAND_BUCKETS(tbl)                                                 \
+do {                                                                             \
+    unsigned _he_bkt;                                                            \
+    unsigned _he_bkt_i;                                                          \
+    struct UT_hash_handle *_he_thh, *_he_hh_nxt;                                 \
+    UT_hash_bucket *_he_new_buckets, *_he_newbkt;                                \
+    _he_new_buckets = (UT_hash_bucket*)uthash_malloc(                            \
+             2 * tbl->num_buckets * sizeof(struct UT_hash_bucket));              \
+    if (!_he_new_buckets) { uthash_fatal( "out of memory"); }                    \
+    memset(_he_new_buckets, 0,                                                   \
+            2 * tbl->num_buckets * sizeof(struct UT_hash_bucket));               \
+    tbl->ideal_chain_maxlen =                                                    \
+       (tbl->num_items >> (tbl->log2_num_buckets+1)) +                           \
+       ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0);                    \
+    tbl->nonideal_items = 0;                                                     \
+    for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++)                \
+    {                                                                            \
+        _he_thh = tbl->buckets[ _he_bkt_i ].hh_head;                             \
+        while (_he_thh) {                                                        \
+           _he_hh_nxt = _he_thh->hh_next;                                        \
+           HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt);            \
+           _he_newbkt = &(_he_new_buckets[ _he_bkt ]);                           \
+           if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) {                \
+             tbl->nonideal_items++;                                              \
+             _he_newbkt->expand_mult = _he_newbkt->count /                       \
+                                        tbl->ideal_chain_maxlen;                 \
+           }                                                                     \
+           _he_thh->hh_prev = NULL;                                              \
+           _he_thh->hh_next = _he_newbkt->hh_head;                               \
+           if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev =               \
+                _he_thh;                                                         \
+           _he_newbkt->hh_head = _he_thh;                                        \
+           _he_thh = _he_hh_nxt;                                                 \
+        }                                                                        \
+    }                                                                            \
+    uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+    tbl->num_buckets *= 2;                                                       \
+    tbl->log2_num_buckets++;                                                     \
+    tbl->buckets = _he_new_buckets;                                              \
+    tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ?         \
+        (tbl->ineff_expands+1) : 0;                                              \
+    if (tbl->ineff_expands > 1) {                                                \
+        tbl->noexpand=1;                                                         \
+        uthash_noexpand_fyi(tbl);                                                \
+    }                                                                            \
+    uthash_expand_fyi(tbl);                                                      \
+} while(0)
+
+/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
+/* Note that HASH_SORT assumes the hash handle name to be hh.
+ * HASH_SRT was added to allow the hash handle name to be passed in. */
+#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)
+#define HASH_SRT(hh,head,cmpfcn)                                                 \
+do {                                                                             \
+  unsigned _hs_i;                                                                \
+  unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize;               \
+  struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail;            \
+  if (head) {                                                                    \
+      _hs_insize = 1;                                                            \
+      _hs_looping = 1;                                                           \
+      _hs_list = &((head)->hh);                                                  \
+      while (_hs_looping) {                                                      \
+          _hs_p = _hs_list;                                                      \
+          _hs_list = NULL;                                                       \
+          _hs_tail = NULL;                                                       \
+          _hs_nmerges = 0;                                                       \
+          while (_hs_p) {                                                        \
+              _hs_nmerges++;                                                     \
+              _hs_q = _hs_p;                                                     \
+              _hs_psize = 0;                                                     \
+              for ( _hs_i = 0; _hs_i  < _hs_insize; _hs_i++ ) {                  \
+                  _hs_psize++;                                                   \
+                  _hs_q = (UT_hash_handle*)((_hs_q->next) ?                      \
+                          ((void*)((char*)(_hs_q->next) +                        \
+                          (head)->hh.tbl->hho)) : NULL);                         \
+                  if (! (_hs_q) ) break;                                         \
+              }                                                                  \
+              _hs_qsize = _hs_insize;                                            \
+              while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) {           \
+                  if (_hs_psize == 0) {                                          \
+                      _hs_e = _hs_q;                                             \
+                      _hs_q = (UT_hash_handle*)((_hs_q->next) ?                  \
+                              ((void*)((char*)(_hs_q->next) +                    \
+                              (head)->hh.tbl->hho)) : NULL);                     \
+                      _hs_qsize--;                                               \
+                  } else if ( (_hs_qsize == 0) || !(_hs_q) ) {                   \
+                      _hs_e = _hs_p;                                             \
+                      _hs_p = (UT_hash_handle*)((_hs_p->next) ?                  \
+                              ((void*)((char*)(_hs_p->next) +                    \
+                              (head)->hh.tbl->hho)) : NULL);                     \
+                      _hs_psize--;                                               \
+                  } else if ((                                                   \
+                      cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \
+                             DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \
+                             ) <= 0) {                                           \
+                      _hs_e = _hs_p;                                             \
+                      _hs_p = (UT_hash_handle*)((_hs_p->next) ?                  \
+                              ((void*)((char*)(_hs_p->next) +                    \
+                              (head)->hh.tbl->hho)) : NULL);                     \
+                      _hs_psize--;                                               \
+                  } else {                                                       \
+                      _hs_e = _hs_q;                                             \
+                      _hs_q = (UT_hash_handle*)((_hs_q->next) ?                  \
+                              ((void*)((char*)(_hs_q->next) +                    \
+                              (head)->hh.tbl->hho)) : NULL);                     \
+                      _hs_qsize--;                                               \
+                  }                                                              \
+                  if ( _hs_tail ) {                                              \
+                      _hs_tail->next = ((_hs_e) ?                                \
+                            ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL);          \
+                  } else {                                                       \
+                      _hs_list = _hs_e;                                          \
+                  }                                                              \
+                  _hs_e->prev = ((_hs_tail) ?                                    \
+                     ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL);              \
+                  _hs_tail = _hs_e;                                              \
+              }                                                                  \
+              _hs_p = _hs_q;                                                     \
+          }                                                                      \
+          _hs_tail->next = NULL;                                                 \
+          if ( _hs_nmerges <= 1 ) {                                              \
+              _hs_looping=0;                                                     \
+              (head)->hh.tbl->tail = _hs_tail;                                   \
+              DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list));      \
+          }                                                                      \
+          _hs_insize *= 2;                                                       \
+      }                                                                          \
+      HASH_FSCK(hh,head);                                                        \
+ }                                                                               \
+} while (0)
+
+/* This function selects items from one hash into another hash.
+ * The end result is that the selected items have dual presence
+ * in both hashes. There is no copy of the items made; rather
+ * they are added into the new hash through a secondary hash
+ * hash handle that must be present in the structure. */
+#define HASH_SELECT(hh_dst, dst, hh_src, src, cond)                              \
+do {                                                                             \
+  unsigned _src_bkt, _dst_bkt;                                                   \
+  void *_last_elt=NULL, *_elt;                                                   \
+  UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL;                         \
+  ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst));                 \
+  if (src) {                                                                     \
+    for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) {     \
+      for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head;                \
+          _src_hh;                                                               \
+          _src_hh = _src_hh->hh_next) {                                          \
+          _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh);                       \
+          if (cond(_elt)) {                                                      \
+            _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho);               \
+            _dst_hh->key = _src_hh->key;                                         \
+            _dst_hh->keylen = _src_hh->keylen;                                   \
+            _dst_hh->hashv = _src_hh->hashv;                                     \
+            _dst_hh->prev = _last_elt;                                           \
+            _dst_hh->next = NULL;                                                \
+            if (_last_elt_hh) { _last_elt_hh->next = _elt; }                     \
+            if (!dst) {                                                          \
+              DECLTYPE_ASSIGN(dst,_elt);                                         \
+              HASH_MAKE_TABLE(hh_dst,dst);                                       \
+            } else {                                                             \
+              _dst_hh->tbl = (dst)->hh_dst.tbl;                                  \
+            }                                                                    \
+            HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt);    \
+            HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh);            \
+            (dst)->hh_dst.tbl->num_items++;                                      \
+            _last_elt = _elt;                                                    \
+            _last_elt_hh = _dst_hh;                                              \
+          }                                                                      \
+      }                                                                          \
+    }                                                                            \
+  }                                                                              \
+  HASH_FSCK(hh_dst,dst);                                                         \
+} while (0)
+
+#define HASH_CLEAR(hh,head)                                                      \
+do {                                                                             \
+  if (head) {                                                                    \
+    uthash_free((head)->hh.tbl->buckets,                                         \
+                (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket));      \
+    uthash_free((head)->hh.tbl, sizeof(UT_hash_table));                          \
+    (head)=NULL;                                                                 \
+  }                                                                              \
+} while(0)
+
+#ifdef NO_DECLTYPE
+#define HASH_ITER(hh,head,el,tmp)                                                \
+for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL);       \
+  el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL))
+#else
+#define HASH_ITER(hh,head,el,tmp)                                                \
+for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL);                 \
+  el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL))
+#endif
+
+/* obtain a count of items in the hash */
+#define HASH_COUNT(head) HASH_CNT(hh,head)
+#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0)
+
+typedef struct UT_hash_bucket {
+       struct UT_hash_handle *hh_head;
+       unsigned count;
+
+       /* expand_mult is normally set to 0. In this situation, the max chain length
+        * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
+        * the bucket's chain exceeds this length, bucket expansion is triggered).
+        * However, setting expand_mult to a non-zero value delays bucket expansion
+        * (that would be triggered by additions to this particular bucket)
+        * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
+        * (The multiplier is simply expand_mult+1). The whole idea of this
+        * multiplier is to reduce bucket expansions, since they are expensive, in
+        * situations where we know that a particular bucket tends to be overused.
+        * It is better to let its chain length grow to a longer yet-still-bounded
+        * value, than to do an O(n) bucket expansion too often.
+        */
+       unsigned expand_mult;
+
+} UT_hash_bucket;
+
+/* random signature used only to find hash tables in external analysis */
+#define HASH_SIGNATURE 0xa0111fe1
+#define HASH_BLOOM_SIGNATURE 0xb12220f2
+
+typedef struct UT_hash_table {
+       UT_hash_bucket *buckets;
+       unsigned num_buckets, log2_num_buckets;
+       unsigned num_items;
+       struct UT_hash_handle *tail;    /* tail hh in app order, for fast append    */
+       ptrdiff_t hho;                          /* hash handle offset (byte pos of hash handle in element */
+
+       /* in an ideal situation (all buckets used equally), no bucket would have
+        * more than ceil(#items/#buckets) items. that's the ideal chain length. */
+       unsigned ideal_chain_maxlen;
+
+       /* nonideal_items is the number of items in the hash whose chain position
+        * exceeds the ideal chain maxlen. these items pay the penalty for an uneven
+        * hash distribution; reaching them in a chain traversal takes >ideal steps */
+       unsigned nonideal_items;
+
+       /* ineffective expands occur when a bucket doubling was performed, but
+        * afterward, more than half the items in the hash had nonideal chain
+        * positions. If this happens on two consecutive expansions we inhibit any
+        * further expansion, as it's not helping; this happens when the hash
+        * function isn't a good fit for the key domain. When expansion is inhibited
+        * the hash will still work, albeit no longer in constant time. */
+       unsigned ineff_expands, noexpand;
+
+       uint32_t signature;                     /* used only to find hash tables in external analysis */
+#ifdef HASH_BLOOM
+       uint32_t bloom_sig;                     /* used only to test bloom exists in external analysis */
+       uint8_t *bloom_bv;
+       char bloom_nbits;
+#endif
+
+} UT_hash_table;
+
+typedef struct UT_hash_handle {
+       struct UT_hash_table *tbl;
+       void *prev;                                     /* prev element in app order      */
+       void *next;                                     /* next element in app order      */
+       struct UT_hash_handle *hh_prev; /* previous hh in bucket order    */
+       struct UT_hash_handle *hh_next; /* next hh in bucket order        */
+       void *key;                                      /* ptr to enclosing struct's key  */
+       unsigned keylen;                        /* enclosing struct's key len     */
+       unsigned hashv;                         /* result of hash-fcn(key)        */
+} UT_hash_handle;
+
+#endif                                                 /* UTHASH_H */
diff --git a/apps/include/netutils/libcoap/utlist.h b/apps/include/netutils/libcoap/utlist.h
new file mode 100644 (file)
index 0000000..6ec3ef8
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+Copyright (c) 2007-2010, Troy D. Hanson   http://uthash.sourceforge.net
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER
+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.
+*/
+
+#ifndef UTLIST_H
+#define UTLIST_H
+
+#define UTLIST_VERSION 1.9.1
+
+/*
+ * This file contains macros to manipulate singly and doubly-linked lists.
+ *
+ * 1. LL_ macros:  singly-linked lists.
+ * 2. DL_ macros:  doubly-linked lists.
+ * 3. CDL_ macros: circular doubly-linked lists.
+ *
+ * To use singly-linked lists, your structure must have a "next" pointer.
+ * To use doubly-linked lists, your structure must "prev" and "next" pointers.
+ * Either way, the pointer to the head of the list must be initialized to NULL.
+ *
+ * ----------------.EXAMPLE -------------------------
+ * struct item {
+ *      int id;
+ *      struct item *prev, *next;
+ * }
+ *
+ * struct item *list = NULL:
+ *
+ * int main() {
+ *      struct item *item;
+ *      ... allocate and populate item ...
+ *      DL_APPEND(list, item);
+ * }
+ * --------------------------------------------------
+ *
+ * For doubly-linked lists, the append and delete macros are O(1)
+ * For singly-linked lists, append and delete are O(n) but prepend is O(1)
+ * The sort macro is O(n log(n)) for all types of single/double/circular lists.
+ */
+
+/* These macros use decltype or the earlier __typeof GNU extension.
+   As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+   when compiling c++ code), this code uses whatever method is needed
+   or, for VS2008 where neither is available, uses casting workarounds. */
+#ifdef _MSC_VER                                        /* MS compiler */
+#if _MSC_VER >= 1600 && __cplusplus    /* VS2010 and newer in C++ mode */
+#define LDECLTYPE(x) decltype(x)
+#else                                                  /* VS2008 or older (or VS2010 in C mode) */
+#define NO_DECLTYPE
+#define LDECLTYPE(x) char*
+#endif
+#else                                                  /* GNU, Sun and other compilers */
+#define LDECLTYPE(x) __typeof(x)
+#endif
+
+/* for VS2008 we use some workarounds to get around the lack of decltype,
+ * namely, we always reassign our tmp variable to the list head if we need
+ * to dereference its prev/next pointers, and save/restore the real head.*/
+#ifdef NO_DECLTYPE
+#define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); }
+#define _NEXT(elt,list) ((char*)((list)->next))
+#define _NEXTASGN(elt,list,to) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); }
+#define _PREV(elt,list) ((char*)((list)->prev))
+#define _PREVASGN(elt,list,to) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); }
+#define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; }
+#define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); }
+#else
+#define _SV(elt,list)
+#define _NEXT(elt,list) ((elt)->next)
+#define _NEXTASGN(elt,list,to) ((elt)->next)=(to)
+#define _PREV(elt,list) ((elt)->prev)
+#define _PREVASGN(elt,list,to) ((elt)->prev)=(to)
+#define _RS(list)
+#define _CASTASGN(a,b) (a)=(b)
+#endif
+
+/******************************************************************************
+ * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort    *
+ * Unwieldy variable names used here to avoid shadowing passed-in variables.  *
+ *****************************************************************************/
+#define LL_SORT(list, cmp)                                                                     \
+do {                                                                                           \
+  LDECLTYPE(list) _ls_p;                                                                       \
+  LDECLTYPE(list) _ls_q;                                                                       \
+  LDECLTYPE(list) _ls_e;                                                                       \
+  LDECLTYPE(list) _ls_tail;                                                                    \
+  LDECLTYPE(list) _ls_oldhead;                                                                 \
+  LDECLTYPE(list) _tmp;                                                                        \
+  int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \
+  if (list) {                                                                                  \
+    _ls_insize = 1;                                                                            \
+    _ls_looping = 1;                                                                           \
+    while (_ls_looping) {                                                                      \
+      _CASTASGN(_ls_p,list);                                                                   \
+      _CASTASGN(_ls_oldhead,list);                                                             \
+      list = NULL;                                                                             \
+      _ls_tail = NULL;                                                                         \
+      _ls_nmerges = 0;                                                                         \
+      while (_ls_p) {                                                                          \
+        _ls_nmerges++;                                                                         \
+        _ls_q = _ls_p;                                                                         \
+        _ls_psize = 0;                                                                         \
+        for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \
+          _ls_psize++;                                                                         \
+          _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list);                               \
+          if (!_ls_q) break;                                                                   \
+        }                                                                                      \
+        _ls_qsize = _ls_insize;                                                                \
+        while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \
+          if (_ls_psize == 0) {                                                                \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
+          } else if (_ls_qsize == 0 || !_ls_q) {                                               \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
+          } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
+          } else {                                                                             \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
+          }                                                                                    \
+          if (_ls_tail) {                                                                      \
+            _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list);                     \
+          } else {                                                                             \
+            _CASTASGN(list,_ls_e);                                                             \
+          }                                                                                    \
+          _ls_tail = _ls_e;                                                                    \
+        }                                                                                      \
+        _ls_p = _ls_q;                                                                         \
+      }                                                                                        \
+      _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list);                            \
+      if (_ls_nmerges <= 1) {                                                                  \
+        _ls_looping=0;                                                                         \
+      }                                                                                        \
+      _ls_insize *= 2;                                                                         \
+    }                                                                                          \
+  } else _tmp=NULL; /* quiet gcc unused variable warning */                                    \
+} while (0)
+
+#define DL_SORT(list, cmp)                                                                     \
+do {                                                                                           \
+  LDECLTYPE(list) _ls_p;                                                                       \
+  LDECLTYPE(list) _ls_q;                                                                       \
+  LDECLTYPE(list) _ls_e;                                                                       \
+  LDECLTYPE(list) _ls_tail;                                                                    \
+  LDECLTYPE(list) _ls_oldhead;                                                                 \
+  LDECLTYPE(list) _tmp;                                                                        \
+  int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \
+  if (list) {                                                                                  \
+    _ls_insize = 1;                                                                            \
+    _ls_looping = 1;                                                                           \
+    while (_ls_looping) {                                                                      \
+      _CASTASGN(_ls_p,list);                                                                   \
+      _CASTASGN(_ls_oldhead,list);                                                             \
+      list = NULL;                                                                             \
+      _ls_tail = NULL;                                                                         \
+      _ls_nmerges = 0;                                                                         \
+      while (_ls_p) {                                                                          \
+        _ls_nmerges++;                                                                         \
+        _ls_q = _ls_p;                                                                         \
+        _ls_psize = 0;                                                                         \
+        for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \
+          _ls_psize++;                                                                         \
+          _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list);                               \
+          if (!_ls_q) break;                                                                   \
+        }                                                                                      \
+        _ls_qsize = _ls_insize;                                                                \
+        while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \
+          if (_ls_psize == 0) {                                                                \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
+          } else if (_ls_qsize == 0 || !_ls_q) {                                               \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
+          } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
+          } else {                                                                             \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
+          }                                                                                    \
+          if (_ls_tail) {                                                                      \
+            _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list);                     \
+          } else {                                                                             \
+            _CASTASGN(list,_ls_e);                                                             \
+          }                                                                                    \
+          _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list);                          \
+          _ls_tail = _ls_e;                                                                    \
+        }                                                                                      \
+        _ls_p = _ls_q;                                                                         \
+      }                                                                                        \
+      _CASTASGN(list->prev, _ls_tail);                                                         \
+      _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list);                            \
+      if (_ls_nmerges <= 1) {                                                                  \
+        _ls_looping=0;                                                                         \
+      }                                                                                        \
+      _ls_insize *= 2;                                                                         \
+    }                                                                                          \
+  } else _tmp=NULL; /* quiet gcc unused variable warning */                                    \
+} while (0)
+
+#define CDL_SORT(list, cmp)                                                                    \
+do {                                                                                           \
+  LDECLTYPE(list) _ls_p;                                                                       \
+  LDECLTYPE(list) _ls_q;                                                                       \
+  LDECLTYPE(list) _ls_e;                                                                       \
+  LDECLTYPE(list) _ls_tail;                                                                    \
+  LDECLTYPE(list) _ls_oldhead;                                                                 \
+  LDECLTYPE(list) _tmp;                                                                        \
+  LDECLTYPE(list) _tmp2;                                                                       \
+  int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \
+  if (list) {                                                                                  \
+    _ls_insize = 1;                                                                            \
+    _ls_looping = 1;                                                                           \
+    while (_ls_looping) {                                                                      \
+      _CASTASGN(_ls_p,list);                                                                   \
+      _CASTASGN(_ls_oldhead,list);                                                             \
+      list = NULL;                                                                             \
+      _ls_tail = NULL;                                                                         \
+      _ls_nmerges = 0;                                                                         \
+      while (_ls_p) {                                                                          \
+        _ls_nmerges++;                                                                         \
+        _ls_q = _ls_p;                                                                         \
+        _ls_psize = 0;                                                                         \
+        for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \
+          _ls_psize++;                                                                         \
+          _SV(_ls_q,list);                                                                     \
+          if (_NEXT(_ls_q,list) == _ls_oldhead) {                                              \
+            _ls_q = NULL;                                                                      \
+          } else {                                                                             \
+            _ls_q = _NEXT(_ls_q,list);                                                         \
+          }                                                                                    \
+          _RS(list);                                                                           \
+          if (!_ls_q) break;                                                                   \
+        }                                                                                      \
+        _ls_qsize = _ls_insize;                                                                \
+        while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \
+          if (_ls_psize == 0) {                                                                \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
+            if (_ls_q == _ls_oldhead) { _ls_q = NULL; }                                        \
+          } else if (_ls_qsize == 0 || !_ls_q) {                                               \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
+            if (_ls_p == _ls_oldhead) { _ls_p = NULL; }                                        \
+          } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
+            if (_ls_p == _ls_oldhead) { _ls_p = NULL; }                                        \
+          } else {                                                                             \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
+            if (_ls_q == _ls_oldhead) { _ls_q = NULL; }                                        \
+          }                                                                                    \
+          if (_ls_tail) {                                                                      \
+            _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list);                     \
+          } else {                                                                             \
+            _CASTASGN(list,_ls_e);                                                             \
+          }                                                                                    \
+          _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list);                          \
+          _ls_tail = _ls_e;                                                                    \
+        }                                                                                      \
+        _ls_p = _ls_q;                                                                         \
+      }                                                                                        \
+      _CASTASGN(list->prev,_ls_tail);                                                          \
+      _CASTASGN(_tmp2,list);                                                                   \
+      _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp2); _RS(list);                           \
+      if (_ls_nmerges <= 1) {                                                                  \
+        _ls_looping=0;                                                                         \
+      }                                                                                        \
+      _ls_insize *= 2;                                                                         \
+    }                                                                                          \
+  } else _tmp=NULL; /* quiet gcc unused variable warning */                                    \
+} while (0)
+
+/******************************************************************************
+ * singly linked list macros (non-circular)                                   *
+ *****************************************************************************/
+#define LL_PREPEND(head,add)                                                                   \
+do {                                                                                           \
+  (add)->next = head;                                                                          \
+  head = add;                                                                                  \
+} while (0)
+
+#define LL_APPEND(head,add)                                                                    \
+do {                                                                                           \
+  LDECLTYPE(head) _tmp;                                                                        \
+  (add)->next=NULL;                                                                            \
+  if (head) {                                                                                  \
+    _tmp = head;                                                                               \
+    while (_tmp->next) { _tmp = _tmp->next; }                                                  \
+    _tmp->next=(add);                                                                          \
+  } else {                                                                                     \
+    (head)=(add);                                                                              \
+  }                                                                                            \
+} while (0)
+
+#define LL_DELETE(head,del)                                                                    \
+do {                                                                                           \
+  LDECLTYPE(head) _tmp;                                                                        \
+  if ((head) == (del)) {                                                                       \
+    (head)=(head)->next;                                                                       \
+  } else {                                                                                     \
+    _tmp = head;                                                                               \
+    while (_tmp->next && (_tmp->next != (del))) {                                              \
+      _tmp = _tmp->next;                                                                       \
+    }                                                                                          \
+    if (_tmp->next) {                                                                          \
+      _tmp->next = ((del)->next);                                                              \
+    }                                                                                          \
+  }                                                                                            \
+} while (0)
+
+/* Here are VS2008 replacements for LL_APPEND and LL_DELETE */
+#define LL_APPEND_VS2008(head,add)                                                             \
+do {                                                                                           \
+  if (head) {                                                                                  \
+    (add)->next = head;     /* use add->next as a temp variable */                             \
+    while ((add)->next->next) { (add)->next = (add)->next->next; }                             \
+    (add)->next->next=(add);                                                                   \
+  } else {                                                                                     \
+    (head)=(add);                                                                              \
+  }                                                                                            \
+  (add)->next=NULL;                                                                            \
+} while (0)
+
+#define LL_DELETE_VS2008(head,del)                                                             \
+do {                                                                                           \
+  if ((head) == (del)) {                                                                       \
+    (head)=(head)->next;                                                                       \
+  } else {                                                                                     \
+    char *_tmp = (char*)(head);                                                                \
+    while (head->next && (head->next != (del))) {                                              \
+      head = head->next;                                                                       \
+    }                                                                                          \
+    if (head->next) {                                                                          \
+      head->next = ((del)->next);                                                              \
+    }                                                                                          \
+    {                                                                                          \
+      char **_head_alias = (char**)&(head);                                                    \
+      *_head_alias = _tmp;                                                                     \
+    }                                                                                          \
+  }                                                                                            \
+} while (0)
+#ifdef NO_DECLTYPE
+#undef LL_APPEND
+#define LL_APPEND LL_APPEND_VS2008
+#undef LL_DELETE
+#define LL_DELETE LL_DELETE_VS2008
+#endif
+/* end VS2008 replacements */
+
+#define LL_FOREACH(head,el)                                                                    \
+    for(el=head;el;el=el->next)
+
+#define LL_FOREACH_SAFE(head,el,tmp)                                                           \
+  for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
+
+#define LL_SEARCH_SCALAR(head,out,field,val)                                                   \
+do {                                                                                           \
+    LL_FOREACH(head,out) {                                                                     \
+      if ((out)->field == (val)) break;                                                        \
+    }                                                                                          \
+} while(0)
+
+#define LL_SEARCH(head,out,elt,cmp)                                                            \
+do {                                                                                           \
+    LL_FOREACH(head,out) {                                                                     \
+      if ((cmp(out,elt))==0) break;                                                            \
+    }                                                                                          \
+} while(0)
+
+/******************************************************************************
+ * doubly linked list macros (non-circular)                                   *
+ *****************************************************************************/
+#define DL_PREPEND(head,add)                                                                   \
+do {                                                                                           \
+ (add)->next = head;                                                                           \
+ if (head) {                                                                                   \
+   (add)->prev = (head)->prev;                                                                 \
+   (head)->prev = (add);                                                                       \
+ } else {                                                                                      \
+   (add)->prev = (add);                                                                        \
+ }                                                                                             \
+ (head) = (add);                                                                               \
+} while (0)
+
+#define DL_APPEND(head,add)                                                                    \
+do {                                                                                           \
+  if (head) {                                                                                  \
+      (add)->prev = (head)->prev;                                                              \
+      (head)->prev->next = (add);                                                              \
+      (head)->prev = (add);                                                                    \
+      (add)->next = NULL;                                                                      \
+  } else {                                                                                     \
+      (head)=(add);                                                                            \
+      (head)->prev = (head);                                                                   \
+      (head)->next = NULL;                                                                     \
+  }                                                                                            \
+} while (0);
+
+#define DL_DELETE(head,del)                                                                    \
+do {                                                                                           \
+  if ((del)->prev == (del)) {                                                                  \
+      (head)=NULL;                                                                             \
+  } else if ((del)==(head)) {                                                                  \
+      (del)->next->prev = (del)->prev;                                                         \
+      (head) = (del)->next;                                                                    \
+  } else {                                                                                     \
+      (del)->prev->next = (del)->next;                                                         \
+      if ((del)->next) {                                                                       \
+          (del)->next->prev = (del)->prev;                                                     \
+      } else {                                                                                 \
+          (head)->prev = (del)->prev;                                                          \
+      }                                                                                        \
+  }                                                                                            \
+} while (0);
+
+#define DL_FOREACH(head,el)                                                                    \
+    for(el=head;el;el=el->next)
+
+/* this version is safe for deleting the elements during iteration */
+#define DL_FOREACH_SAFE(head,el,tmp)                                                           \
+  for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
+
+/* these are identical to their singly-linked list counterparts */
+#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR
+#define DL_SEARCH LL_SEARCH
+
+/******************************************************************************
+ * circular doubly linked list macros                                         *
+ *****************************************************************************/
+#define CDL_PREPEND(head,add)                                                                  \
+do {                                                                                           \
+ if (head) {                                                                                   \
+   (add)->prev = (head)->prev;                                                                 \
+   (add)->next = (head);                                                                       \
+   (head)->prev = (add);                                                                       \
+   (add)->prev->next = (add);                                                                  \
+ } else {                                                                                      \
+   (add)->prev = (add);                                                                        \
+   (add)->next = (add);                                                                        \
+ }                                                                                             \
+(head)=(add);                                                                                  \
+} while (0)
+
+#define CDL_DELETE(head,del)                                                                   \
+do {                                                                                           \
+  if ( ((head)==(del)) && ((head)->next == (head))) {                                          \
+      (head) = 0L;                                                                             \
+  } else {                                                                                     \
+     (del)->next->prev = (del)->prev;                                                          \
+     (del)->prev->next = (del)->next;                                                          \
+     if ((del) == (head)) (head)=(del)->next;                                                  \
+  }                                                                                            \
+} while (0);
+
+#define CDL_FOREACH(head,el)                                                                   \
+    for(el=head;el;el=(el->next==head ? 0L : el->next))
+
+#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2)                                                    \
+  for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL);                                        \
+      (el) && ((tmp2)=(el)->next, 1);                                                          \
+      ((el) = (((el)==(tmp1)) ? 0L : (tmp2))))
+
+#define CDL_SEARCH_SCALAR(head,out,field,val)                                                  \
+do {                                                                                           \
+    CDL_FOREACH(head,out) {                                                                    \
+      if ((out)->field == (val)) break;                                                        \
+    }                                                                                          \
+} while(0)
+
+#define CDL_SEARCH(head,out,elt,cmp)                                                           \
+do {                                                                                           \
+    CDL_FOREACH(head,out) {                                                                    \
+      if ((cmp(out,elt))==0) break;                                                            \
+    }                                                                                          \
+} while(0)
+
+#endif                                                 /* UTLIST_H */
diff --git a/apps/netutils/libcoap/Kconfig b/apps/netutils/libcoap/Kconfig
new file mode 100644 (file)
index 0000000..2495aed
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# For a description of the syntax of this configuration file,
+# see kconfig-language at https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt
+#
+
+config NETUTILS_LIBCOAP
+       bool "libcoap 4.1.1"
+       default n
+       ---help---
+               Enable support for the libcoap library 
+
+if NETUTILS_LIBCOAP
+config NETUTILS_LIBCOAP_DEBUG
+       bool "Enable CoAP Debugging Log"
+       default y
+    ---help---
+               Enables CoAP logs
+endif
diff --git a/apps/netutils/libcoap/LICENSE.BSD b/apps/netutils/libcoap/LICENSE.BSD
new file mode 100644 (file)
index 0000000..2fc333a
--- /dev/null
@@ -0,0 +1,26 @@
+Copyright (c) 2010--2011, Olaf Bergmann
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  o Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  o 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.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+HOLDER 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.
\ No newline at end of file
diff --git a/apps/netutils/libcoap/LICENSE.GPL b/apps/netutils/libcoap/LICENSE.GPL
new file mode 100644 (file)
index 0000000..d8cf7d4
--- /dev/null
@@ -0,0 +1,280 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
diff --git a/apps/netutils/libcoap/Make.defs b/apps/netutils/libcoap/Make.defs
new file mode 100644 (file)
index 0000000..0eb52c3
--- /dev/null
@@ -0,0 +1,56 @@
+###########################################################################
+#
+# Copyright 2017 Samsung Electronics All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+# either express or implied. See the License for the specific
+# language governing permissions and limitations under the License.
+#
+###########################################################################
+# apps/netutils/libcoap/Make.defs
+# Adds selected applications to apps/ build
+#
+#   Copyright (C) 2016 Gregory Nutt. All rights reserved.
+#   Author: Gregory Nutt <gnutt@nuttx.org>
+#
+# 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 NuttX 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 COPYRIGHT HOLDERS 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
+# COPYRIGHT OWNER 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.
+#
+############################################################################
+
+ifeq ($(CONFIG_NETUTILS_LIBCOAP),y)
+CONFIGURED_APPS += netutils/libcoap
+endif
+
diff --git a/apps/netutils/libcoap/Makefile b/apps/netutils/libcoap/Makefile
new file mode 100644 (file)
index 0000000..d3eac39
--- /dev/null
@@ -0,0 +1,139 @@
+###########################################################################
+#
+# Copyright 2016 Samsung Electronics All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+# either express or implied. See the License for the specific
+# language governing permissions and limitations under the License.
+#
+###########################################################################
+############################################################################
+# apps/netutils/libcoap/Makefile
+#
+#   Copyright (C) 2014 Gregory Nutt. All rights reserved.
+#   Author: Gregory Nutt <gnutt@nuttx.org>
+#
+# 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 NuttX 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 COPYRIGHT HOLDERS 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
+# COPYRIGHT OWNER 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.
+#
+############################################################################
+
+-include $(TOPDIR)/.config
+-include $(TOPDIR)/Make.defs
+include $(APPDIR)/Make.defs
+
+# libcoap
+
+ASRCS =
+CSRCS =
+
+CSRCS += async.c
+CSRCS += block.c
+CSRCS += coap_list.c
+CSRCS += debug.c
+CSRCS += encode.c
+CSRCS += hashkey.c
+CSRCS += net.c
+CSRCS += option.c
+CSRCS += pdu.c
+CSRCS += resource.c
+CSRCS += str.c
+CSRCS += subscribe.c
+CSRCS += uri.c
+
+AOBJS = $(ASRCS:.S=$(OBJEXT))
+COBJS = $(CSRCS:.c=$(OBJEXT))
+
+SRCS = $(ASRCS) $(CSRCS)
+OBJS = $(AOBJS) $(COBJS)
+
+# libcoap flags
+CFLAGS += -DWITH_POSIX
+CFLAGS += -D__TINYARA__
+ifeq ($(CONFIG_NETUTILS_LIBCOAP_DEBUG),n)
+CFLAGS += -DNDEBUG
+endif
+CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(APPDIR)$(DELIM)include$(DELIM)netutils$(DELIM)libcoap}
+
+ifeq ($(CONFIG_WINDOWS_NATIVE),y)
+  BIN = ..\..\libapps$(LIBEXT)
+else
+ifeq ($(WINTOOL),y)
+  BIN = ..\\..\\libapps$(LIBEXT)
+else
+  BIN = ../../libapps$(LIBEXT)
+endif
+endif
+
+ROOTDEPPATH = --dep-path .
+
+# Common build
+
+VPATH =
+
+all: .built
+.PHONY: context depend clean distclean
+
+$(AOBJS): %$(OBJEXT): %.S
+       $(call ASSEMBLE, $<, $@)
+
+$(COBJS): %$(OBJEXT): %.c
+       $(call COMPILE, $<, $@)
+
+.built: $(OBJS)
+       $(call ARCHIVE, $(BIN), $(OBJS))
+       $(Q) touch .built
+
+install:
+
+context:
+
+.depend: Makefile $(SRCS)
+       $(Q) $(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep
+       $(Q) touch $@
+
+depend: .depend
+
+clean:
+       $(call DELFILE, .built)
+       $(call CLEAN)
+
+distclean: clean
+       $(call DELFILE, Make.dep)
+       $(call DELFILE, .depend)
+
+-include Make.dep
+.PHONY: preconfig
+preconfig:
diff --git a/apps/netutils/libcoap/README b/apps/netutils/libcoap/README
new file mode 100644 (file)
index 0000000..ec0905e
--- /dev/null
@@ -0,0 +1,25 @@
+libcoap: A C implementation of IETF Core Application protocol
+
+Copyright (C) 2010--2013 by Olaf Bergmann <bergmann@tzi.org>
+
+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, bandwidth, or network packet sizes. This
+protocol, CoAP, is developed in the IETF working group "Constrained
+RESTful Environments (core)", see <http://6lowapp.net>.
+
+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 revised BSD license.
+Please refer to LICENSE.BSD for further details.
+
diff --git a/apps/netutils/libcoap/async.c b/apps/netutils/libcoap/async.c
new file mode 100644 (file)
index 0000000..eec79bd
--- /dev/null
@@ -0,0 +1,101 @@
+/* async.c -- state management for asynchronous messages
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+/**
+ * @file async.c
+ * @brief state management for asynchronous messages
+ */
+
+#ifndef WITHOUT_ASYNC
+
+#include "config.h"
+
+#include "utlist.h"
+
+#include "mem.h"
+#include "debug.h"
+#include "async.h"
+
+coap_async_state_t *coap_register_async(coap_context_t *context, coap_address_t *peer, coap_pdu_t *request, unsigned char flags, void *data)
+{
+       coap_async_state_t *s;
+       coap_tid_t id;
+
+       coap_transaction_id(peer, request, &id);
+       LL_SEARCH_SCALAR(context->async_state, s, id, id);
+
+       if (s != NULL) {
+               /* We must return NULL here as the caller must know that he is
+                * responsible for releasing @p data. */
+               debug("asynchronous state for transaction %d already registered\n", id);
+               return NULL;
+       }
+
+       /* store information for handling the asynchronous task */
+       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");
+               return NULL;
+       }
+
+       memset(s, 0, sizeof(coap_async_state_t) + request->hdr->token_length);
+
+       /* set COAP_ASYNC_CONFIRM according to request's type */
+       s->flags = flags & ~COAP_ASYNC_CONFIRM;
+       if (request->hdr->type == COAP_MESSAGE_CON) {
+               s->flags |= COAP_ASYNC_CONFIRM;
+       }
+
+       s->appdata = data;
+
+       memcpy(&s->peer, peer, sizeof(coap_address_t));
+
+       if (request->hdr->token_length) {
+               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);
+
+       LL_PREPEND(context->async_state, s);
+
+       return s;
+}
+
+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);
+       return tmp;
+}
+
+int 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);
+
+       if (tmp) {
+               LL_DELETE(context->async_state, tmp);
+       }
+
+       *s = tmp;
+       return tmp != NULL;
+}
+
+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);
+}
+
+#else
+void does_not_exist();                 /* make some compilers happy */
+#endif                                                 /* WITHOUT_ASYNC */
diff --git a/apps/netutils/libcoap/block.c b/apps/netutils/libcoap/block.c
new file mode 100644 (file)
index 0000000..5424bb9
--- /dev/null
@@ -0,0 +1,127 @@
+/* block.c -- block transfer
+ *
+ * Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#include "config.h"
+
+#if defined(HAVE_ASSERT_H) && !defined(assert)
+#include <assert.h>
+#endif
+
+#include "debug.h"
+#include "block.h"
+
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+#ifndef WITHOUT_BLOCK
+unsigned int coap_opt_block_num(const coap_opt_t *block_opt)
+{
+       unsigned int num = 0;
+       unsigned short len;
+
+       len = coap_opt_length(block_opt);
+
+       if (len == 0) {
+               return 0;
+       }
+
+       if (len > 1) {
+               num = coap_decode_var_bytes(COAP_OPT_VALUE(block_opt), COAP_OPT_LENGTH(block_opt) - 1);
+       }
+
+       return (num << 4) | ((*COAP_OPT_BLOCK_LAST(block_opt) & 0xF0) >> 4);
+}
+
+int coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block)
+{
+       coap_opt_iterator_t opt_iter;
+       coap_opt_t *option;
+
+       assert(block);
+       memset(block, 0, sizeof(coap_block_t));
+
+       if (pdu && (option = coap_check_option(pdu, type, &opt_iter))) {
+               block->szx = COAP_OPT_BLOCK_SZX(option);
+               if (COAP_OPT_BLOCK_MORE(option)) {
+                       block->m = 1;
+               }
+               block->num = coap_opt_block_num(option);
+               return 1;
+       }
+
+       return 0;
+}
+
+int coap_write_block_opt(coap_block_t *block, unsigned short type, coap_pdu_t *pdu, size_t data_length)
+{
+       size_t start, want, avail;
+       unsigned char buf[3];
+
+       assert(pdu);
+
+       /* Block2 */
+       if (type != COAP_OPTION_BLOCK2) {
+               warn("coap_write_block_opt: skipped unknown option\n");
+               return -1;
+       }
+
+       start = block->num << (block->szx + 4);
+       if (data_length <= start) {
+               debug("illegal block requested\n");
+               return -2;
+       }
+
+       avail = pdu->max_size - pdu->length - 4;
+       want = 1 << (block->szx + 4);
+
+       /* check if entire block fits in message */
+       if (want <= avail) {
+               block->m = want < data_length - start;
+       } else {
+               /* Sender has requested a block that is larger than the remaining
+                * space in pdu. This is ok if the remaining data fits into the pdu
+                * anyway. The block size needs to be adjusted only if there is more
+                * data left that cannot be delivered in this message. */
+
+               if (data_length - start <= avail) {
+
+                       /* it's the final block and everything fits in the message */
+                       block->m = 0;
+               } else {
+                       unsigned char szx;
+
+                       /* we need to decrease the block size */
+                       if (avail < 16) {       /* bad luck, this is the smallest block size */
+                               debug("not enough space, even the smallest block does not fit");
+                               return -3;
+                       }
+                       debug("decrease block size for %d to %d\n", avail, coap_fls(avail) - 5);
+                       szx = block->szx;
+                       block->szx = coap_fls(avail) - 5;
+                       block->m = 1;
+                       block->num <<= szx - block->szx;
+               }
+       }
+
+       /* to re-encode the block option */
+       coap_add_option(pdu, type, coap_encode_var_bytes(buf, ((block->num << 4) | (block->m << 3) | block->szx)), buf);
+
+       return 1;
+}
+
+int coap_add_block(coap_pdu_t *pdu, unsigned int len, const unsigned char *data, unsigned int block_num, unsigned char block_szx)
+{
+       size_t start;
+       start = block_num << (block_szx + 4);
+
+       if (len <= start) {
+               return 0;
+       }
+
+       return coap_add_data(pdu, min(len - start, (unsigned int)(1 << (block_szx + 4))), data + start);
+}
+#endif                                                 /* WITHOUT_BLOCK  */
diff --git a/apps/netutils/libcoap/coap_list.c b/apps/netutils/libcoap/coap_list.c
new file mode 100644 (file)
index 0000000..1b2bd47
--- /dev/null
@@ -0,0 +1,90 @@
+/* coap_list.c -- CoAP list structures
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "debug.h"
+#include "mem.h"
+#include "coap_list.h"
+
+int coap_insert(coap_list_t **queue, coap_list_t *node, int (*order)(void *, void *node))
+{
+       coap_list_t *p, *q;
+       if (!queue || !node) {
+               return 0;
+       }
+
+       /* set queue head if empty */
+       if (!*queue) {
+               *queue = node;
+               return 1;
+       }
+
+       /* replace queue head if new node has to be added before the existing queue head */
+       q = *queue;
+       if (order(node->data, q->data) < 0) {
+               node->next = q;
+               *queue = node;
+               return 1;
+       }
+
+       /* search for right place to insert */
+       do {
+               p = q;
+               q = q->next;
+       } while (q && order(node->data, q->data) >= 0);
+
+       /* insert new item */
+       node->next = q;
+       p->next = node;
+       return 1;
+}
+
+int coap_delete(coap_list_t *node)
+{
+       if (!node) {
+               return 0;
+       }
+
+       if (node->delete_func) {
+               node->delete_func(node->data);
+       }
+       coap_free(node->data);
+       coap_free(node);
+
+       return 1;
+}
+
+void coap_delete_list(coap_list_t *queue)
+{
+       if (!queue) {
+               return;
+       }
+
+       coap_delete_list(queue->next);
+       coap_delete(queue);
+}
+
+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
+               return NULL;
+       }
+
+       memset(node, 0, sizeof(coap_list_t));
+       node->data = data;
+       node->delete_func = delete_func;
+       return node;
+}
diff --git a/apps/netutils/libcoap/debug.c b/apps/netutils/libcoap/debug.c
new file mode 100644 (file)
index 0000000..c889e23
--- /dev/null
@@ -0,0 +1,366 @@
+/* debug.c -- debug utilities
+ *
+ * Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#include "config.h"
+
+#if defined(HAVE_ASSERT_H) && !defined(assert)
+#include <assert.h>
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+
+#include "debug.h"
+#include "net.h"
+
+#ifdef WITH_CONTIKI
+#ifndef DEBUG
+#define DEBUG DEBUG_PRINT
+#endif                                                 /* DEBUG */
+#include "net/uip-debug.h"
+#endif
+
+static coap_log_t maxlog = LOG_WARNING;        /* default maximum log level */
+
+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 = clock_offset + (t / COAP_TICKS_PER_SECOND);
+       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)(clock_offset + (t / COAP_TICKS_PER_SECOND)), (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 */
+
+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 || len == 0) {
+               return 0;
+       }
+
+       while (len) {
+               if (!encode_always && isprint(*data)) {
+                       if (cnt == buflen) {
+                               break;
+                       }
+                       *result++ = *data;
+                       ++cnt;
+               } else {
+                       if (cnt + 4 < buflen) {
+                               *result++ = '\\';
+                               *result++ = 'x';
+                               *result++ = hex[(*data & 0xf0) >> 4];
+                               *result++ = hex[*data & 0x0f];
+                               cnt += 4;
+                       } else {
+                               break;
+                       }
+               }
+
+               ++data;
+               --len;
+       }
+
+       *result = '\0';
+       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
+}
+
+#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 */
+       int encode = 0, have_options = 0;
+       coap_opt_iterator_t opt_iter;
+       coap_opt_t *option;
+
+       fprintf(COAP_DEBUG_FD, "v:%d t:%d tkl:%d c:%d id:%u", pdu->hdr->version, pdu->hdr->type, pdu->hdr->token_length, pdu->hdr->code, ntohs(pdu->hdr->id));
+
+       /* show options, if any */
+       coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL);
+
+       while ((option = coap_option_next(&opt_iter))) {
+               if (!have_options) {
+                       have_options = 1;
+                       fprintf(COAP_DEBUG_FD, " o: [");
+               } else {
+                       fprintf(COAP_DEBUG_FD, ",");
+               }
+
+               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_PATH || opt_iter.type == COAP_OPTION_URI_QUERY) {
+                       encode = 0;
+               } else {
+                       encode = 1;
+               }
+
+               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, buf, sizeof(buf), 0);
+               fprintf(COAP_DEBUG_FD, " d:%s", buf);
+       }
+       fprintf(COAP_DEBUG_FD, "\n");
+       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 */
+
+#ifndef WITH_CONTIKI
+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);
+}
+#else                                                  /* 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);
+}
+#endif                                                 /* WITH_CONTIKI */
diff --git a/apps/netutils/libcoap/encode.c b/apps/netutils/libcoap/encode.c
new file mode 100644 (file)
index 0000000..0ff9a36
--- /dev/null
@@ -0,0 +1,51 @@
+/* encode.c -- encoding and decoding of CoAP data types
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#ifndef NDEBUG
+#include <stdio.h>
+#endif
+
+#include "config.h"
+#include "encode.h"
+
+/* Carsten suggested this when fls() is not available: */
+int coap_fls(unsigned int i)
+{
+       int n;
+       for (n = 0; i; n++) {
+               i >>= 1;
+       }
+       return n;
+}
+
+unsigned int coap_decode_var_bytes(unsigned char *buf, unsigned int len)
+{
+       unsigned int i, n = 0;
+       for (i = 0; i < len; ++i) {
+               n = (n << 8) + buf[i];
+       }
+
+       return n;
+}
+
+unsigned int coap_encode_var_bytes(unsigned char *buf, unsigned int val)
+{
+       unsigned int n, i;
+
+       for (n = 0, i = val; i && n < sizeof(val); ++n) {
+               i >>= 8;
+       }
+
+       i = n;
+       while (i--) {
+               buf[i] = val & 0xff;
+               val >>= 8;
+       }
+
+       return n;
+}
diff --git a/apps/netutils/libcoap/hashkey.c b/apps/netutils/libcoap/hashkey.c
new file mode 100644 (file)
index 0000000..8d67e7a
--- /dev/null
@@ -0,0 +1,28 @@
+/* hashkey.c -- definition of hash key type and helper functions
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#include "hashkey.h"
+
+/* Caution: When changing this, update COAP_DEFAULT_WKC_HASHKEY
+ * accordingly (see int coap_hash_path());
+ */
+void coap_hash_impl(const unsigned char *s, unsigned int len, coap_key_t h)
+{
+       size_t j;
+
+       while (len--) {
+               j = sizeof(coap_key_t) - 1;
+
+               while (j) {
+                       h[j] = ((h[j] << 7) | (h[j - 1] >> 1)) + h[j];
+                       --j;
+               }
+
+               h[0] = (h[0] << 7) + h[0] + *s++;
+       }
+}
diff --git a/apps/netutils/libcoap/net.c b/apps/netutils/libcoap/net.c
new file mode 100644 (file)
index 0000000..f5ff6f4
--- /dev/null
@@ -0,0 +1,1635 @@
+/* net.c -- CoAP network interface
+ *
+ * Copyright (C) 2010--2014 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#include "config.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#elif HAVE_SYS_UNISTD_H
+#include <sys/unistd.h>
+#endif
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef WITH_LWIP
+#include <lwip/pbuf.h>
+#include <lwip/udp.h>
+#include <lwip/timers.h>
+#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 "net.h"
+
+#if defined(WITH_POSIX)
+
+time_t clock_offset;
+
+static inline coap_queue_t *coap_malloc_node(void)
+{
+       return (coap_queue_t *) coap_malloc(sizeof(coap_queue_t));
+}
+
+static inline void coap_free_node(coap_queue_t *node)
+{
+       coap_free(node);
+}
+#endif                                                 /* WITH_POSIX */
+#ifdef WITH_LWIP
+
+#include <lwip/memp.h>
+
+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 WITH_CONTIKI
+#ifndef DEBUG
+#define DEBUG DEBUG_PRINT
+#endif                                                 /* DEBUG */
+
+#include "memb.h"
+#include "net/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();
+void coap_pdu_resources_init();
+
+unsigned char initialized = 0;
+coap_context_t the_coap_context;
+
+MEMB(node_storage, coap_queue_t, COAP_PDU_MAXCNT);
+
+PROCESS(coap_retransmit_process, "message retransmit process");
+
+static inline coap_queue_t *coap_malloc_node()
+{
+       return (coap_queue_t *) memb_alloc(&node_storage);
+}
+
+static inline void coap_free_node(coap_queue_t *node)
+{
+       memb_free(&node_storage, node);
+}
+#endif                                                 /* WITH_CONTIKI */
+#ifdef WITH_LWIP
+
+/** Callback to udp_recv when using lwIP. Gets called by lwIP on arriving
+ * packages, places a reference in context->pending_package, and calls
+ * coap_read to process the package. Thus, coap_read needs not be called in
+ * lwIP main loops. (When modifying this for thread-like operation, ie. if you
+ * remove the coap_read call from this, make sure that coap_read gets a chance
+ * to run before this callback is entered the next time.)
+ */
+static void received_package(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
+{
+       struct coap_context_t *context = (coap_context_t *) arg;
+
+       LWIP_ASSERT("pending_package was not cleared.", context->pending_package == NULL);
+
+       context->pending_package = p;   /* we don't free it, coap_read has to do that */
+       context->pending_address.addr = addr->addr;     /* FIXME: this has to become address-type independent, probably there'll be an lwip function for that */
+       context->pending_port = port;
+
+       coap_read(context);
+}
+
+#endif                                                 /* WITH_LWIP */
+
+int print_wellknown(coap_context_t *, unsigned char *, 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()
+{
+       coap_queue_t *node;
+       node = coap_malloc_node();
+
+       if (!node) {
+#ifndef NDEBUG
+               coap_log(LOG_WARNING, "coap_new_node: malloc\n");
+#endif
+               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)
+{
+#ifdef WITH_POSIX
+       coap_context_t *c = coap_malloc(sizeof(coap_context_t));
+       int reuse = 1;
+#endif                                                 /* WITH_POSIX */
+#ifdef WITH_LWIP
+       coap_context_t *c = memp_malloc(MEMP_COAP_CONTEXT);
+#endif                                                 /* WITH_LWIP */
+#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_clock_init();
+#ifdef WITH_LWIP
+       prng_init(LWIP_RAND());
+#else                                                  /* WITH_LWIP */
+       prng_init((unsigned long)listen_addr ^ clock_offset);
+#endif                                                 /* WITH_LWIP */
+
+#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_pdu_resources_init();
+
+       c = &the_coap_context;
+       initialized = 1;
+#endif                                                 /* WITH_CONTIKI */
+
+       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);
+
+#ifdef WITH_POSIX
+       c->sockfd = socket(listen_addr->addr.sa.sa_family, SOCK_DGRAM, 0);
+       if (c->sockfd < 0) {
+#ifndef NDEBUG
+               coap_log(LOG_EMERG, "coap_new_context: socket\n");
+#endif                                                 /* WITH_POSIX */
+               goto onerror;
+       }
+
+       if (setsockopt(c->sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {
+#ifndef NDEBUG
+               coap_log(LOG_WARNING, "setsockopt SO_REUSEADDR\n");
+#endif
+       }
+
+       if (bind(c->sockfd, &listen_addr->addr.sa, listen_addr->size) < 0) {
+#ifndef NDEBUG
+               coap_log(LOG_EMERG, "coap_new_context: bind\n");
+#endif
+               goto onerror;
+       }
+
+       return c;
+
+onerror:
+       if (c->sockfd >= 0) {
+               close(c->sockfd);
+       }
+       coap_free(c);
+       return NULL;
+
+#endif                                                 /* WITH_POSIX */
+#ifdef WITH_CONTIKI
+       c->conn = udp_new(NULL, 0, NULL);
+       udp_bind(c->conn, listen_addr->port);
+
+       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);
+       return c;
+#endif                                                 /* WITH_CONTIKI */
+#ifdef WITH_LWIP
+       c->pcb = udp_new();
+       /* hard assert: this is not expected to fail dynamically */
+       LWIP_ASSERT("Failed to allocate PCB for CoAP", c->pcb != NULL);
+
+       udp_recv(c->pcb, received_package, (void *)c);
+       udp_bind(c->pcb, &listen_addr->addr, listen_addr->port);
+
+       c->timer_configured = 0;
+
+       return c;
+#endif
+}
+
+void coap_free_context(coap_context_t *context)
+{
+#if defined(WITH_POSIX) || defined(WITH_LWIP)
+       coap_resource_t *res;
+#ifndef COAP_RESOURCES_NOHASH
+       coap_resource_t *rtmp;
+#endif
+#endif                                                 /* WITH_POSIX || WITH_LWIP */
+       if (!context) {
+               return;
+       }
+
+       coap_delete_all(context->recvqueue);
+       coap_delete_all(context->sendqueue);
+
+#ifdef WITH_LWIP
+       context->sendqueue = NULL;
+       coap_retransmittimer_restart(context);
+#endif
+
+#if defined(WITH_POSIX) || defined(WITH_LWIP)
+#ifdef COAP_RESOURCES_NOHASH
+       LL_FOREACH(context->resources, res) {
+#else
+       HASH_ITER(hh, context->resources, res, rtmp) {
+#endif
+               coap_delete_resource(context, res->key);
+       }
+#endif                                                 /* WITH_POSIX || WITH_LWIP */
+
+#ifdef WITH_POSIX
+       /* coap_delete_list(context->subscriptions); */
+       close(context->sockfd);
+       coap_free(context);
+#endif
+#ifdef WITH_LWIP
+       udp_remove(context->pcb);
+       memp_free(MEMP_COAP_CONTEXT, context);
+#endif
+#ifdef WITH_CONTIKI
+       memset(&the_coap_context, 0, sizeof(coap_context_t));
+       initialized = 0;
+#endif                                                 /* WITH_CONTIKI */
+}
+
+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. */
+
+#ifdef WITH_POSIX
+       switch (peer->addr.sa.sa_family) {
+       case AF_INET:
+               coap_hash((const unsigned char *)&peer->addr.sa, peer->size, h);
+               break;
+       case AF_INET6:
+               coap_hash((const unsigned char *)&peer->addr.sin6.sin6_port, sizeof(peer->addr.sin6.sin6_port), h);
+               coap_hash((const unsigned char *)&peer->addr.sin6.sin6_addr, sizeof(peer->addr.sin6.sin6_addr), h);
+               break;
+       default:
+               return;
+       }
+#endif
+#if defined(WITH_LWIP) || defined(WITH_CONTIKI)
+       /* 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);
+
+       *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;
+}
+
+#ifdef WITH_POSIX
+/* releases space allocated by PDU if free_pdu is set */
+coap_tid_t coap_send_impl(coap_context_t *context, const coap_address_t *dst, coap_pdu_t *pdu)
+{
+       ssize_t bytes_written;
+       coap_tid_t id = COAP_INVALID_TID;
+
+       if (!context || !dst || !pdu) {
+               return id;
+       }
+
+       bytes_written = sendto(context->sockfd, pdu->hdr, pdu->length, 0, &dst->addr.sa, dst->size);
+
+       if (bytes_written >= 0) {
+               coap_transaction_id(dst, pdu, &id);
+       } else {
+               coap_log(LOG_CRIT, "coap_send: sendto\n");
+       }
+
+       return id;
+}
+#endif                                                 /* WITH_POSIX */
+#ifdef WITH_CONTIKI
+/* releases space allocated by PDU if free_pdu is set */
+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;
+       }
+
+       /* FIXME: is there a way to check if send was successful? */
+       uip_udp_packet_sendto(context->conn, pdu->hdr, pdu->length, &dst->addr, dst->port);
+
+       coap_transaction_id(dst, pdu, &id);
+
+       return id;
+}
+#endif                                                 /* WITH_CONTIKI */
+#ifdef WITH_LWIP
+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;
+       struct pbuf *p;
+       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. */
+
+       p = pdu->pbuf;
+       LWIP_ASSERT("The PDU header is not where it is expected", pdu->hdr == p->payload + sizeof(coap_pdu_t));
+
+       err = pbuf_header(p, -sizeof(coap_pdu_t));
+       if (err) {
+               debug("coap_send_impl: pbuf_header failed\n");
+               pbuf_free(p);
+               return id;
+       }
+
+       coap_transaction_id(dst, pdu, &id);
+
+       pbuf_realloc(p, pdu->length);
+
+       udp_sendto(context->pcb, p, &dst->addr, dst->port);
+
+       pbuf_header(p, -(ptrdiff_t)((uint8_t *) pdu - (uint8_t *) p->payload) - sizeof(coap_pdu_t));    /* FIXME hack around udp_sendto not restoring; see http://lists.gnu.org/archive/html/lwip-users/2013-06/msg00008.html. for udp over ip over ethernet, this was -42; as we're doing ppp too, this has to be calculated generically */
+
+       err = pbuf_header(p, sizeof(coap_pdu_t));
+       LWIP_ASSERT("Cannot undo pbuf_header", err == 0);
+
+       /* restore destroyed pdu data */
+       LWIP_ASSERT("PDU not restored", p->payload == pdu);
+       pdu->max_size = p->tot_len - sizeof(coap_pdu_t);        /* reduced after pbuf_realloc */
+       pdu->hdr = p->payload + sizeof(coap_pdu_t);
+       pdu->max_delta = 0;                     /* won't be used any more */
+       pdu->length = pdu->max_size;
+       pdu->data = data_backup;
+       pdu->pbuf = p;
+
+       return id;
+}
+#endif                                                 /* WITH_LWIP */
+
+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);
+
+#ifdef WITH_LWIP
+       if (node == context->sendqueue) {       /* don't bother with timer stuff if there are earlier retransmits */
+               coap_retransmittimer_restart(context);
+       }
+#endif
+
+#ifdef WITH_CONTIKI
+       {                                                       /* (re-)initialize retransmission timer */
+               coap_queue_t *nextpdu;
+
+               nextpdu = coap_peek_next(context);
+               assert(nextpdu);                /* we have just inserted a node */
+
+               /* must set timer within the context of the retransmit process */
+               PROCESS_CONTEXT_BEGIN(&coap_retransmit_process);
+               etimer_set(&context->retransmit_timer, nextpdu->t);
+               PROCESS_CONTEXT_END(&coap_retransmit_process);
+       }
+#endif                                                 /* WITH_CONTIKI */
+
+       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);
+#ifdef WITH_LWIP
+               if (node == context->sendqueue) {       /* don't bother with timer stuff if there are earlier retransmits */
+                       coap_retransmittimer_restart(context);
+               }
+#endif
+
+               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 */
+
+#ifndef WITH_CONTIKI
+       debug("** removed transaction %d\n", ntohs(node->id));
+#endif
+
+#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)
+{
+#ifdef WITH_POSIX
+       static char buf[COAP_MAX_PDU_SIZE];
+#endif
+#if defined(WITH_LWIP) || defined(WITH_CONTIKI)
+       char *buf;
+#endif
+       coap_hdr_t *pdu;
+       ssize_t bytes_read = -1;
+       coap_address_t src, dst;
+       coap_queue_t *node;
+
+#ifdef WITH_CONTIKI
+       buf = uip_appdata;
+#endif                                                 /* WITH_CONTIKI */
+#ifdef WITH_LWIP
+       LWIP_ASSERT("No package pending", ctx->pending_package != NULL);
+       LWIP_ASSERT("Can only deal with contiguous PBUFs to read the initial details", ctx->pending_package->tot_len == ctx->pending_package->len);
+       buf = ctx->pending_package->payload;
+#endif                                                 /* WITH_LWIP */
+
+       pdu = (coap_hdr_t *) buf;
+
+       coap_address_init(&src);
+
+#ifdef WITH_POSIX
+       bytes_read = recvfrom(ctx->sockfd, buf, sizeof(buf), 0, &src.addr.sa, &src.size);
+#endif                                                 /* WITH_POSIX */
+#ifdef WITH_CONTIKI
+       if (uip_newdata()) {
+               uip_ipaddr_copy(&src.addr, &UIP_IP_BUF->srcipaddr);
+               src.port = UIP_UDP_BUF->srcport;
+               uip_ipaddr_copy(&dst.addr, &UIP_IP_BUF->destipaddr);
+               dst.port = UIP_UDP_BUF->destport;
+
+               bytes_read = uip_datalen();
+               ((char *)uip_appdata)[bytes_read] = 0;
+               PRINTF("Server received %d bytes from [", (int)bytes_read);
+               PRINT6ADDR(&src.addr);
+               PRINTF("]:%d\n", uip_ntohs(src.port));
+       }
+#endif                                                 /* WITH_CONTIKI */
+#ifdef WITH_LWIP
+       /* FIXME: use lwip address operation functions */
+       src.addr.addr = ctx->pending_address.addr;
+       src.port = ctx->pending_port;
+       bytes_read = ctx->pending_package->tot_len;
+#endif                                                 /* WITH_LWIP */
+
+       if (bytes_read < 0) {
+               warn("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;
+       }
+
+       if (pdu->version != COAP_DEFAULT_VERSION) {
+               debug("coap_read: unknown protocol version\n");
+               goto error_early;
+       }
+
+       node = coap_new_node();
+       if (!node) {
+               goto error_early;
+       }
+
+#ifdef WITH_LWIP
+       node->pdu = coap_pdu_from_pbuf(ctx->pending_package);
+       ctx->pending_package = NULL;
+#else
+       node->pdu = coap_pdu_init(0, 0, 0, bytes_read);
+#endif
+       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 *)buf, 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);
+
+#ifndef NDEBUG
+       if (LOG_DEBUG <= coap_get_log_level()) {
+#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);
+       }
+#endif
+
+       return 0;
+
+error:
+       /* FIXME: send back RST? */
+       coap_delete_node(node);
+       return -1;
+error_early:
+#ifdef WITH_LWIP
+       /* even if there was an error, clean up */
+       pbuf_free(ctx->pending_package);
+       ctx->pending_package = NULL;
+#endif
+       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;
+
+       debug("cancel_all_messages\n");
+       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)
+{
+       unsigned char buf[1];
+       size_t len = 0;
+
+       if (print_wellknown(context, buf, &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;
+}
+
+#define SZX_TO_BYTES(SZX) ((size_t)(1 << ((SZX) + 4)))
+
+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->data, &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;
+}
+
+#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 */
+                               info("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 };
+
+                       h(context, resource, &node->remote, node->pdu, &token, response);
+                       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)
+{
+
+       /* Call application-specific reponse handler when available.  If
+        * not, we must acknowledge confirmable messages. */
+       if (context->response_handler) {
+               context->response_handler(context, &rcvd->remote, sent ? sent->pdu : NULL, rcvd->pdu, rcvd->id);
+       } else {
+               /* send ACK if rcvd is confirmable (i.e. a separate response) */
+               coap_send_ack(context, &rcvd->remote, rcvd->pdu);
+       }
+}
+
+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;
+}
+
+/**
+ * This function handles RST messages received for the message passed
+ * in @p sent.
+ */
+static void coap_handle_rst(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 };
+
+       /* 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);
+
+#ifndef WITH_CONTIKI
+#ifdef COAP_RESOURCES_NOHASH
+       LL_FOREACH(context->resources, r) {
+#else
+       HASH_ITER(hh, context->resources, r, tmp) {
+#endif
+               coap_delete_observer(r, &sent->remote, &token);
+               coap_cancel_all_messages(context, &sent->remote, token.s, token.length);
+       }
+#else                                                  /* WITH_CONTIKI */
+       r = (coap_resource_t *) resource_storage.mem;
+       for (i = 0; i < resource_storage.num; ++i, ++r) {
+               if (resource_storage.count[i]) {
+                       coap_delete_observer(r, &sent->remote, &token);
+                       coap_cancel_all_messages(context, &sent->remote, token.s, token.length);
+               }
+       }
+#endif                                                 /* WITH_CONTIKI */
+#endif                                                 /* WITOUT_OBSERVE */
+}
+
+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. */
+
+                       coap_log(LOG_ALERT, "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_handle_rst(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\n");
+                               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);
+}
+
+#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/apps/netutils/libcoap/option.c b/apps/netutils/libcoap/option.c
new file mode 100644 (file)
index 0000000..6d6275a
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * option.c -- helpers for handling options in CoAP PDUs
+ *
+ * Copyright (C) 2010-2013 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#include "config.h"
+
+#if defined(HAVE_ASSERT_H) && !defined(assert)
+#include <assert.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "option.h"
+#include "debug.h"
+
+coap_opt_t *options_start(coap_pdu_t *pdu)
+{
+
+       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 {
+               return NULL;
+       }
+}
+
+size_t coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result)
+{
+
+       const coap_opt_t *opt_start = opt;      /* store where parsing starts  */
+
+       assert(opt);
+       assert(result);
+
+#define ADVANCE_OPT(o,e,step) if ((e) < step) {                        \
+    debug("cannot advance opt past end\n");                    \
+    return 0;                                                  \
+  } else {                                                     \
+    (e) -= step;                                               \
+    (o) = ((unsigned char *)(o)) + step;                       \
+  }
+
+       if (length < 1) {
+               return 0;
+       }
+
+       result->delta = (*opt & 0xf0) >> 4;
+       result->length = *opt & 0x0f;
+
+       switch (result->delta) {
+       case 15:
+               if (*opt != COAP_PAYLOAD_START) {
+                       debug("ignored reserved option delta 15\n");
+               }
+               return 0;
+       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. */
+               ADVANCE_OPT(opt, length, 1);
+               result->delta = ((*opt & 0xff) << 8) + 269;
+               if (result->delta < 269) {
+                       debug("delta too large\n");
+                       return 0;
+               }
+               /* fall through */
+       case 13:
+               ADVANCE_OPT(opt, length, 1);
+               result->delta += *opt & 0xff;
+               break;
+
+       default:
+               ;
+       }
+
+       switch (result->length) {
+       case 15:
+               debug("found reserved option length 15\n");
+               return 0;
+       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. */
+               ADVANCE_OPT(opt, length, 1);
+               result->length = ((*opt & 0xff) << 8) + 269;
+               /* fall through */
+       case 13:
+               ADVANCE_OPT(opt, length, 1);
+               result->length += *opt & 0xff;
+               break;
+
+       default:
+               ;
+       }
+
+       ADVANCE_OPT(opt, length, 1);
+       /* opt now points to value, if present */
+
+       result->value = (unsigned char *)opt;
+       if (length < result->length) {
+               debug("invalid option length\n");
+               return 0;
+       }
+#undef ADVANCE_OPT
+
+       return (opt + result->length) - opt_start;
+}
+
+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->hdr);
+       assert(oi);
+
+       memset(oi, 0, sizeof(coap_opt_iterator_t));
+
+       oi->next_option = (unsigned char *)pdu->hdr + sizeof(coap_hdr_t)
+                                         + pdu->hdr->token_length;
+       if ((unsigned char *)pdu->hdr + pdu->length <= oi->next_option) {
+               oi->bad = 1;
+               return NULL;
+       }
+
+       assert((sizeof(coap_hdr_t) + pdu->hdr->token_length) <= pdu->length);
+
+       oi->length = pdu->length - (sizeof(coap_hdr_t) + pdu->hdr->token_length);
+
+       if (filter) {
+               memcpy(oi->filter, filter, sizeof(coap_opt_filter_t));
+               oi->filtered = 1;
+       }
+       return oi;
+}
+
+static inline int opt_finished(coap_opt_iterator_t *oi)
+{
+       assert(oi);
+
+       if (oi->bad || oi->length == 0 || !oi->next_option || *oi->next_option == COAP_PAYLOAD_START) {
+               oi->bad = 1;
+       }
+
+       return oi->bad;
+}
+
+coap_opt_t *coap_option_next(coap_opt_iterator_t *oi)
+{
+       coap_option_t option;
+       coap_opt_t *current_opt = NULL;
+       size_t optsize;
+       int b;                                          /* to store result of coap_option_getb() */
+
+       assert(oi);
+
+       if (opt_finished(oi)) {
+               return NULL;
+       }
+
+       while (1) {
+               /* oi->option always points to the next option to deliver; as
+                * 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;
+                       return NULL;
+               }
+
+               /* 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
+                */
+               if (!oi->filtered || (b = coap_option_getb(oi->filter, oi->type)) > 0) {
+                       break;
+               } else if (b < 0) {             /* filter too small, cannot proceed */
+                       oi->bad = 1;
+                       return NULL;
+               }
+       }
+
+       return current_opt;
+}
+
+coap_opt_t *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);
+
+       coap_option_iterator_init(pdu, oi, f);
+
+       return coap_option_next(oi);
+}
+
+unsigned short coap_opt_delta(const coap_opt_t *opt)
+{
+       unsigned short n;
+
+       n = (*opt++ & 0xf0) >> 4;
+
+       switch (n) {
+       case 15:                                        /* error */
+               warn("coap_opt_delta: illegal option delta\n");
+
+               /* This case usually should not happen, hence we do not have a
+                * proper way to indicate an error. */
+               return 0;
+       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. */
+               n = ((*opt++ & 0xff) << 8) + 269;
+               /* fall through */
+       case 13:
+               n += *opt & 0xff;
+               break;
+       default:                                        /* n already contains the actual delta value */
+               ;
+       }
+
+       return n;
+}
+
+unsigned short coap_opt_length(const coap_opt_t *opt)
+{
+       unsigned short length;
+
+       length = *opt & 0x0f;
+       switch (*opt & 0xf0) {
+       case 0xf0:
+               debug("illegal option delta\n");
+               return 0;
+       case 0xe0:
+               ++opt;
+               /* fall through to skip another byte */
+       case 0xd0:
+               ++opt;
+               /* fall through to skip another byte */
+       default:
+               ++opt;
+       }
+
+       switch (length) {
+       case 0x0f:
+               debug("illegal option length\n");
+               return 0;
+       case 0x0e:
+               length = (*opt++ << 8) + 269;
+               /* fall through */
+       case 0x0d:
+               length += *opt++;
+               break;
+       default:
+               ;
+       }
+       return length;
+}
+
+unsigned char *coap_opt_value(coap_opt_t *opt)
+{
+       size_t ofs = 1;
+
+       switch (*opt & 0xf0) {
+       case 0xf0:
+               debug("illegal option delta\n");
+               return 0;
+       case 0xe0:
+               ++ofs;
+               /* fall through */
+       case 0xd0:
+               ++ofs;
+               break;
+       default:
+               ;
+       }
+
+       switch (*opt & 0x0f) {
+       case 0x0f:
+               debug("illegal option length\n");
+               return 0;
+       case 0x0e:
+               ++ofs;
+               /* fall through */
+       case 0x0d:
+               ++ofs;
+               break;
+       default:
+               ;
+       }
+
+       return (unsigned char *)opt + ofs;
+}
+
+size_t coap_opt_size(const coap_opt_t *opt)
+{
+       coap_option_t option;
+
+       /* we must assume that opt is encoded correctly */
+       return coap_opt_parse(opt, (size_t) - 1, &option);
+}
+
+size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, unsigned short delta, size_t length)
+{
+       size_t skip = 0;
+
+       assert(opt);
+
+       if (maxlen == 0) {              /* need at least one byte */
+               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;
+       }
+
+       return skip + 1;
+}
+
+size_t coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta, const unsigned char *val, size_t length)
+{
+       size_t l = 1;
+
+       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;
+
+       if (maxlen < length) {
+               debug("coap_opt_encode: option too large for buffer\n");
+               return 0;
+       }
+
+       if (val) {                              /* better be safe here */
+               memcpy(opt, val, length);
+       }
+
+       return l + length;
+}
diff --git a/apps/netutils/libcoap/pdu.c b/apps/netutils/libcoap/pdu.c
new file mode 100644 (file)
index 0000000..a1e8be3
--- /dev/null
@@ -0,0 +1,426 @@
+/* pdu.c -- CoAP message structure
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#include "config.h"
+
+#if defined(HAVE_ASSERT_H) && !defined(assert)
+#include <assert.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include "debug.h"
+#include "pdu.h"
+#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);
+
+       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;
+
+       /* 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
+
+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
+
+       pdu = NULL;                                     /* to prevent stooped compilng due to warning */
+       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
+       if (pdu) {
+               coap_pdu_clear(pdu, size);
+               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(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) {
+               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)
+{
+#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
+}
+
+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) {
+               return 0;
+       }
+
+       pdu->hdr->token_length = len;
+       if (len) {
+               memcpy(pdu->hdr->token, data, len);
+       }
+       pdu->max_delta = 0;
+       pdu->length = HEADERLENGTH;
+       pdu->data = NULL;
+
+       return 1;
+}
+
+/** @FIXME de-duplicate code with coap_add_option_later */
+size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data)
+{
+       size_t optsize;
+       coap_opt_t *opt;
+
+       assert(pdu);
+       pdu->data = NULL;
+
+       if (type < pdu->max_delta) {
+               warn("coap_add_option: options are not in correct order\n");
+               return 0;
+       }
+
+       opt = (unsigned char *)pdu->hdr + pdu->length;
+
+       /* encode option and check length */
+       optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, type - pdu->max_delta, data, len);
+
+       if (!optsize) {
+               warn("coap_add_option: cannot add option\n");
+               /* error */
+               return 0;
+       } else {
+               pdu->max_delta = type;
+               pdu->length += optsize;
+       }
+
+       return optsize;
+}
+
+/** @FIXME de-duplicate code with coap_add_option */
+unsigned char *coap_add_option_later(coap_pdu_t *pdu, unsigned short type, unsigned int len)
+{
+       size_t optsize;
+       coap_opt_t *opt;
+
+       assert(pdu);
+       pdu->data = NULL;
+
+       if (type < pdu->max_delta) {
+               warn("coap_add_option: options are not in correct order\n");
+               return NULL;
+       }
+
+       opt = (unsigned char *)pdu->hdr + pdu->length;
+
+       /* encode option and check length */
+       optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, type - pdu->max_delta, NULL, len);
+
+       if (!optsize) {
+               warn("coap_add_option: cannot add option\n");
+               /* error */
+               return NULL;
+       } else {
+               pdu->max_delta = type;
+               pdu->length += optsize;
+       }
+
+       return ((unsigned char *)opt) + optsize - len;
+}
+
+int coap_add_data(coap_pdu_t *pdu, unsigned int len, const unsigned char *data)
+{
+       assert(pdu);
+       assert(pdu->data == NULL);
+
+       if (len == 0) {
+               return 1;
+       }
+
+       if (pdu->length + len + 1 > pdu->max_size) {
+               warn("coap_add_data: cannot add: data too large for PDU\n");
+               assert(pdu->data == NULL);
+               return 0;
+       }
+
+       pdu->data = (unsigned char *)pdu->hdr + pdu->length;
+       *pdu->data = COAP_PAYLOAD_START;
+       pdu->data++;
+
+       memcpy(pdu->data, data, len);
+       pdu->length += len + 1;
+       return 1;
+}
+
+int coap_get_data(coap_pdu_t *pdu, size_t *len, unsigned char **data)
+{
+       assert(pdu);
+       assert(len);
+       assert(data);
+
+       if (pdu->data) {
+               *len = (unsigned char *)pdu->hdr + pdu->length - pdu->data;
+               *data = pdu->data;
+       } else {                                        /* no data, clear everything */
+               *len = 0;
+               *data = NULL;
+       }
+
+       return *data != NULL;
+}
+
+#ifndef SHORT_ERROR_RESPONSE
+typedef struct {
+       unsigned char code;
+       char *phrase;
+} error_desc_t;
+
+/* 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"},
+       {COAP_RESPONSE_CODE(66), "2.02 Deleted"},
+       {COAP_RESPONSE_CODE(67), "2.03 Valid"},
+       {COAP_RESPONSE_CODE(68), "2.04 Changed"},
+       {COAP_RESPONSE_CODE(69), "2.05 Content"},
+       {COAP_RESPONSE_CODE(400), "Bad Request"},
+       {COAP_RESPONSE_CODE(401), "Unauthorized"},
+       {COAP_RESPONSE_CODE(402), "Bad Option"},
+       {COAP_RESPONSE_CODE(403), "Forbidden"},
+       {COAP_RESPONSE_CODE(404), "Not Found"},
+       {COAP_RESPONSE_CODE(405), "Method Not Allowed"},
+       {COAP_RESPONSE_CODE(408), "Request Entity Incomplete"},
+       {COAP_RESPONSE_CODE(413), "Request Entity Too Large"},
+       {COAP_RESPONSE_CODE(415), "Unsupported Media Type"},
+       {COAP_RESPONSE_CODE(500), "Internal Server Error"},
+       {COAP_RESPONSE_CODE(501), "Not Implemented"},
+       {COAP_RESPONSE_CODE(502), "Bad Gateway"},
+       {COAP_RESPONSE_CODE(503), "Service Unavailable"},
+       {COAP_RESPONSE_CODE(504), "Gateway Timeout"},
+       {COAP_RESPONSE_CODE(505), "Proxying Not Supported"},
+       {0, NULL}                                       /* end marker */
+};
+
+char *coap_response_phrase(unsigned char code)
+{
+       int i;
+       for (i = 0; coap_error[i].code; ++i) {
+               if (coap_error[i].code == code) {
+                       return coap_error[i].phrase;
+               }
+       }
+       return NULL;
+}
+#endif
+
+/**
+ * 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.
+ */
+static size_t next_option_safe(coap_opt_t **optp, size_t *length)
+{
+       coap_option_t option;
+       size_t optsize;
+
+       assert(optp);
+       assert(*optp);
+       assert(length);
+
+       optsize = coap_opt_parse(*optp, *length, &option);
+       if (optsize) {
+               assert(optsize <= *length);
+
+               *optp += optsize;
+               *length -= optsize;
+       }
+
+       return optsize;
+}
+
+int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu)
+{
+       coap_opt_t *opt;
+
+       assert(data);
+       assert(pdu);
+
+       if (pdu->max_size < length) {
+               debug("insufficient space to store parsed PDU\n");
+               return 0;
+       }
+
+       if (length < sizeof(coap_hdr_t)) {
+               debug("discarded invalid PDU\n");
+       }
+
+       pdu->hdr->version = data[0] >> 6;
+       pdu->hdr->type = (data[0] >> 4) & 0x03;
+       pdu->hdr->token_length = data[0] & 0x0f;
+       pdu->hdr->code = data[1];
+       pdu->data = NULL;
+
+       /* sanity checks */
+       if (pdu->hdr->code == 0) {
+               if (length != sizeof(coap_hdr_t) || pdu->hdr->token_length) {
+                       debug("coap_pdu_parse: empty message is not empty\n");
+                       goto discard;
+               }
+       }
+
+       if (length < sizeof(coap_hdr_t) + pdu->hdr->token_length || pdu->hdr->token_length > 8) {
+               debug("coap_pdu_parse: invalid Token\n");
+               goto discard;
+       }
+
+       /* Copy message id in network byte order, so we can easily write the
+        * response back to the network. */
+       memcpy(&pdu->hdr->id, data + 2, 2);
+
+       /* 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. */
+
+       /* skip header + token */
+       length -= (pdu->hdr->token_length + sizeof(coap_hdr_t));
+       opt = (unsigned char *)(pdu->hdr + 1) + pdu->hdr->token_length;
+
+       while (length && *opt != COAP_PAYLOAD_START) {
+
+               if (!next_option_safe(&opt, (size_t *)&length)) {
+                       debug("coap_pdu_parse: drop\n");
+                       goto discard;
+               }
+       }
+
+       /* end of packet or start marker */
+       if (length) {
+               assert(*opt == COAP_PAYLOAD_START);
+               opt++;
+               length--;
+
+               if (!length) {
+                       debug("coap_pdu_parse: message ending in payload start marker\n");
+                       goto discard;
+               }
+
+               debug("set data to %p (pdu ends at %p)\n", (unsigned char *)opt, (unsigned char *)pdu->hdr + pdu->length);
+               pdu->data = (unsigned char *)opt;
+       }
+
+       return 1;
+
+discard:
+       return 0;
+}
diff --git a/apps/netutils/libcoap/resource.c b/apps/netutils/libcoap/resource.c
new file mode 100644 (file)
index 0000000..5935c59
--- /dev/null
@@ -0,0 +1,860 @@
+/* resource.c -- generic resource handling
+ *
+ * Copyright (C) 2010--2014 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#include "config.h"
+#include "net.h"
+#include "debug.h"
+#include "resource.h"
+#include "subscribe.h"
+
+#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 <lwip/memp.h>
+
+#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)); \
+    }                                                                  \
+  }
+
+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;
+       }
+
+       if (match_substring) {
+               unsigned char *next_token = text->s;
+               size_t remaining_length = text->length;
+               while (remaining_length) {
+                       size_t token_length;
+                       unsigned char *token = next_token;
+                       next_token = memchr(token, ' ', remaining_length);
+
+                       if (next_token) {
+                               token_length = next_token - token;
+                               remaining_length -= (token_length + 1);
+                               next_token++;
+                       } else {
+                               token_length = remaining_length;
+                               remaining_length = 0;
+                       }
+
+                       if ((match_prefix || pattern->length == token_length) && memcmp(token, pattern->s, pattern->length) == 0) {
+                               return 1;
+                       }
+               }
+               return 0;
+       }
+
+       return (match_prefix || pattern->length == text->length) && 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.
+ * @param query_filter A filter query according to <a href="http://tools.ietf.org/html/draft-ietf-core-link-format-11#section-4.1">Link Format</a>
+ *
+ * @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
+ *         truncated.
+ */
+#if defined(__GNUC__) && defined(WITHOUT_QUERY_FILTER)
+coap_print_status_t 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 */
+coap_print_status_t print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen, size_t offset, coap_opt_t *query_filter)
+{
+#endif                                                 /* GCC */
+       coap_resource_t *r;
+       unsigned char *p = buf;
+       const unsigned char *bufend = buf + *buflen;
+       size_t left, written = 0;
+       coap_print_status_t result;
+       const size_t old_offset = offset;
+       int subsequent_resource = 0;
+#ifndef COAP_RESOURCES_NOHASH
+       coap_resource_t *tmp;
+#endif
+#ifndef WITHOUT_QUERY_FILTER
+       str resource_param = { 0, NULL }, query_pattern = {
+               0, NULL
+       };
+       int flags = 0;                          /* MATCH_SUBSTRING, MATCH_PREFIX, MATCH_URI */
+#define MATCH_URI       0x01
+#define MATCH_PREFIX    0x02
+#define MATCH_SUBSTRING 0x04
+       static const str _rt_attributes[] = {
+               {2, (unsigned char *)"rt"},
+               {2, (unsigned char *)"if"},
+               {3, (unsigned char *)"rel"},
+               {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) {
+               resource_param.s = COAP_OPT_VALUE(query_filter);
+               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 && 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 && memcmp(resource_param.s, rt_attributes->s, rt_attributes->length) == 0) {
+                                       flags |= MATCH_SUBSTRING;
+                                       break;
+                               }
+                       }
+
+                       /* rest is query-pattern */
+                       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 = COAP_OPT_LENGTH(query_filter) - (resource_param.length + 1);
+
+                       if ((query_pattern.s[0] == '/') && ((flags & MATCH_URI) == MATCH_URI)) {
+                               query_pattern.s++;
+                               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;
+                               }
+                       } else {                        /* match attribute */
+                               coap_attr_t *attr;
+                               str unquoted_val;
+                               attr = coap_find_attr(r, resource_param.s, resource_param.length);
+                               if (!attr) {
+                                       continue;
+                               }
+                               if (attr->value.s[0] == '"') {  /* if attribute has a quoted value, remove double quotes */
+                                       unquoted_val.length = attr->value.length - 2;
+                                       unquoted_val.s = attr->value.s + 1;
+                               } else {
+                                       unquoted_val = attr->value;
+                               }
+                               if (!(match(&unquoted_val, &query_pattern, (flags & MATCH_PREFIX) != 0, (flags & MATCH_SUBSTRING) != 0))) {
+                                       continue;
+                               }
+                       }
+               }
+#endif                                                 /* WITHOUT_QUERY_FILTER */
+
+               if (!subsequent_resource) {     /* this is the first resource  */
+                       subsequent_resource = 1;
+               } else {
+                       PRINT_COND_WITH_OFFSET(p, bufend, offset, ',', written);
+               }
+
+               left = bufend - p;              /* calculate available space */
+               result = coap_print_link(r, p, &left, &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. */
+               p += COAP_PRINT_OUTPUT_LENGTH(result);
+               written += left;
+       }
+
+       *buflen = written;
+       result = p - buf;
+       if (result + old_offset - offset < *buflen) {
+               result |= COAP_PRINT_STATUS_TRUNC;
+       }
+       return result;
+}
+
+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
+       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, const unsigned char *name, size_t nlen, const unsigned char *val, size_t vlen, int flags)
+{
+       coap_attr_t *attr;
+
+       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
+
+       if (attr) {
+               attr->name.length = nlen;
+               attr->value.length = val ? vlen : 0;
+
+               attr->name.s = (unsigned char *)name;
+               attr->value.s = (unsigned char *)val;
+
+               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, 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 && memcmp(attr->name.s, name, nlen) == 0) {
+                       return attr;
+               }
+       }
+
+       return NULL;
+}
+
+void coap_delete_attr(coap_attr_t *attr)
+{
+       if (!attr) {
+               return;
+       }
+       if (attr->flags & COAP_ATTR_FLAGS_RELEASE_NAME) {
+               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
+}
+
+void coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key)
+{
+       coap_opt_iterator_t opt_iter;
+       coap_opt_filter_t filter;
+       coap_opt_t *option;
+
+       memset(key, 0, sizeof(coap_key_t));
+
+       coap_option_filter_clear(filter);
+       coap_option_setb(filter, COAP_OPTION_URI_PATH);
+
+       coap_option_iterator_init((coap_pdu_t *) request, &opt_iter, filter);
+       while ((option = coap_option_next(&opt_iter))) {
+               coap_hash(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option), 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) {
+               return 0;
+       }
+
+#if defined(WITH_POSIX) || defined(WITH_LWIP)
+#ifdef COAP_RESOURCES_NOHASH
+       LL_DELETE(context->resources, resource);
+#else
+       HASH_DELETE(hh, context->resources, resource);
+#endif
+
+       /* delete registered attributes */
+       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);
+       }
+
+#ifdef WITH_POSIX
+       coap_free(resource);
+#endif
+#ifdef WITH_LWIP
+       memp_free(MEMP_COAP_RESOURCE, resource);
+#endif
+#else                                                  /* not (WITH_POSIX || WITH_LWIP) */
+       /* 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;
+       LL_FOREACH(context->resources, resource) {
+               /* if you think you can outspart the compiler and speed things up by (eg by
+                * casting to uint32* and comparing alues), increment this counter: 1 */
+               if (memcmp(key, resource->key, sizeof(coap_key_t)) == 0) {
+                       return resource;
+               }
+       }
+       return NULL;
+#else
+       HASH_FIND(hh, context->resources, key, sizeof(coap_key_t), resource);
+
+       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 */
+}
+
+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);
+
+#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(p, bufend, *offset, ';', *len);
+
+               COPY_COND_WITH_OFFSET(p, bufend, *offset, attr->name.s, attr->name.length, *len);
+
+               if (attr->value.s) {
+                       PRINT_COND_WITH_OFFSET(p, bufend, *offset, '=', *len);
+
+                       COPY_COND_WITH_OFFSET(p, bufend, *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;
+       }
+
+       return result;
+}
+
+#ifndef WITHOUT_OBSERVE
+coap_subscription_t *coap_find_observer(coap_resource_t *resource, const coap_address_t *peer, const str *token)
+{
+       coap_subscription_t *s;
+
+       assert(resource);
+       assert(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 && memcmp(token->s, s->token, token->length) == 0))) {
+                       return s;
+               }
+       }
+
+       return NULL;
+}
+
+coap_subscription_t *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. */
+       s = coap_find_observer(resource, observer, token);
+
+       /* We are done if subscription was found. */
+       if (s) {
+               return s;
+       }
+
+       /* s points to a different subscription, so we have to create
+        * another one. */
+       s = COAP_MALLOC_TYPE(subscription);
+
+       if (!s) {
+               return NULL;
+       }
+
+       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));
+       }
+
+       /* add subscriber to resource */
+       list_add(resource->subscribers, s);
+
+       return s;
+}
+
+void coap_touch_observer(coap_context_t *context, const coap_address_t *observer, const str *token)
+{
+       coap_resource_t *r;
+       coap_subscription_t *s;
+
+#ifndef WITH_CONTIKI
+#ifdef COAP_RESOURCES_NOHASH
+       LL_FOREACH(context->resources, r) {
+#else
+       coap_resource_t *tmp;
+       HASH_ITER(hh, context->resources, r, tmp) {
+#endif
+               s = coap_find_observer(r, observer, token);
+               if (s) {
+                       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 */
+}
+
+void coap_delete_observer(coap_resource_t *resource, const coap_address_t *observer, const str *token)
+{
+       coap_subscription_t *s;
+
+       s = coap_find_observer(resource, observer, token);
+
+       if (s) {
+               list_remove(resource->subscribers, s);
+
+               COAP_FREE_TYPE(subscription, s);
+       }
+}
+
+static void coap_notify_observers(coap_context_t *context, coap_resource_t *r)
+{
+       coap_method_handler_t h;
+       coap_subscription_t *obs;
+       str token;
+       coap_pdu_t *response;
+
+       if (r->observable && (r->dirty || r->partiallydirty)) {
+               r->partiallydirty = 0;
+
+               /* retrieve GET handler, prepare response */
+               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 */
+                       {
+                               continue;
+                       }
+
+                       coap_tid_t tid = COAP_INVALID_TID;
+                       obs->dirty = 0;
+                       /* initialize response */
+                       response = coap_pdu_init(COAP_MESSAGE_CON, 0, 0, COAP_MAX_PDU_SIZE);
+                       if (!response) {
+                               obs->dirty = 1;
+                               r->partiallydirty = 1;
+                               debug("coap_check_notify: pdu init failed, resource stays partially dirty\n");
+                               continue;
+                       }
+
+                       if (!coap_add_token(response, obs->token_length, obs->token)) {
+                               obs->dirty = 1;
+                               r->partiallydirty = 1;
+                               debug("coap_check_notify: cannot add token, resource stays partially dirty\n");
+                               coap_delete_pdu(response);
+                               continue;
+                       }
+
+                       token.length = obs->token_length;
+                       token.s = obs->token;
+
+                       response->hdr->id = coap_new_message_id(context);
+                       if (obs->non && obs->non_cnt < COAP_OBS_MAX_NON) {
+                               response->hdr->type = COAP_MESSAGE_NON;
+                       } else {
+                               response->hdr->type = COAP_MESSAGE_CON;
+                       }
+                       /* fill with observer-specific data */
+                       h(context, r, &obs->subscriber, NULL, &token, response);
+
+                       if (response->hdr->type == COAP_MESSAGE_CON) {
+                               tid = coap_send_confirmed(context, &obs->subscriber, response);
+                               obs->non_cnt = 0;
+                       } else {
+                               tid = coap_send(context, &obs->subscriber, response);
+                               obs->non_cnt++;
+                       }
+
+                       if (COAP_INVALID_TID == tid || response->hdr->type != COAP_MESSAGE_CON) {
+                               coap_delete_pdu(response);
+                       }
+                       if (COAP_INVALID_TID == tid) {
+                               debug("coap_check_notify: sending failed, resource stays partially dirty\n");
+                               obs->dirty = 1;
+                               r->partiallydirty = 1;
+                       }
+
+               }
+
+               /* Increment value for next Observe use. */
+               context->observe++;
+       }
+       r->dirty = 0;
+}
+
+void coap_check_notify(coap_context_t *context)
+{
+       coap_resource_t *r;
+#ifndef WITH_CONTIKI
+
+#ifdef COAP_RESOURCES_NOHASH
+       LL_FOREACH(context->resources, r) {
+#else
+       coap_resource_t *tmp;
+       HASH_ITER(hh, context->resources, r, tmp) {
+#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 */
+}
+
+/**
+ * Checks the failure counter for (peer, token) and removes peer from
+ * the list of observers for the given resource when COAP_OBS_MAX_FAIL
+ * is reached.
+ *
+ * @param context  The CoAP context to use
+ * @param resource The resource to check for (peer, token)
+ * @param peer     The observer's address
+ * @param token    The token that has been used for subscription.
+ */
+static void coap_remove_failed_observers(coap_context_t *context, coap_resource_t *resource, const coap_address_t *peer, const str *token)
+{
+       coap_subscription_t *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) {
+                               obs->fail_cnt++;
+                       } else {
+                               list_remove(resource->subscribers, obs);
+                               obs->fail_cnt = 0;
+
+#ifndef NDEBUG
+                               if (LOG_DEBUG <= coap_get_log_level()) {
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 40
+#endif
+                                       unsigned char addr[INET6_ADDRSTRLEN + 8];
+
+                                       if (coap_print_addr(&obs->subscriber, addr, INET6_ADDRSTRLEN + 8)) {
+                                               debug("** removed observer %s\n", addr);
+                                       }
+                               }
+#endif
+                               coap_cancel_all_messages(context, &obs->subscriber, obs->token, obs->token_length);
+
+                               COAP_FREE_TYPE(subscription, obs);
+                       }
+               }
+               break;                                  /* break loop if observer was found */
+       }
+}
+
+void 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
+       coap_resource_t *tmp;
+       HASH_ITER(hh, context->resources, r, tmp) {
+#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/apps/netutils/libcoap/str.c b/apps/netutils/libcoap/str.c
new file mode 100644 (file)
index 0000000..7521c80
--- /dev/null
@@ -0,0 +1,35 @@
+/* str.c -- strings to be used in the CoAP library
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include "debug.h"
+#include "mem.h"
+#include "str.h"
+
+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
+               return NULL;
+       }
+
+       memset(s, 0, sizeof(str));
+       s->s = ((unsigned char *)s) + sizeof(str);
+       return s;
+}
+
+void coap_delete_string(str *s)
+{
+       coap_free(s);
+}
diff --git a/apps/netutils/libcoap/subscribe.c b/apps/netutils/libcoap/subscribe.c
new file mode 100644 (file)
index 0000000..784ff94
--- /dev/null
@@ -0,0 +1,381 @@
+/* subscribe.c -- subscription handling for CoAP
+ *                see draft-ietf-coap-observe-09
+ *
+ * Copyright (C) 2010--2013 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#include "config.h"
+
+#if defined(HAVE_ASSERT_H) && !defined(assert)
+#include <assert.h>
+#endif
+
+#include <stdio.h>
+#include <limits.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+/* #include "resource.h" */
+
+#include "mem.h"
+#include "encode.h"
+#include "debug.h"
+#include "subscribe.h"
+
+void coap_subscription_init(coap_subscription_t *s)
+{
+       assert(s);
+       memset(s, 0, sizeof(coap_subscription_t));
+}
+
+#if 0
+#define HMASK (ULONG_MAX >> 1)
+
+void notify(coap_context_t *context, coap_resource_t *res, coap_subscription_t *sub, unsigned int duration, int code)
+{
+#if 0
+       coap_pdu_t *pdu;
+       int ls, finished = 0;
+       unsigned char ct, d;
+       unsigned int length;
+#ifndef NDEBUG
+       char addr[INET6_ADDRSTRLEN];
+#endif
+
+       if (!context || !res || !sub || !(pdu = coap_new_pdu())) {
+               return;
+       }
+
+       pdu->hdr->type = COAP_MESSAGE_CON;
+       pdu->hdr->id = rand();          /* use a random transaction id */
+       pdu->hdr->code = code;
+
+       /* FIXME: content-type and data (how about block?) */
+       if (res->uri->host.length) {
+               coap_add_option(pdu, COAP_OPTION_URI_HOST, res->uri->host.length, res->uri->host.s);
+       }
+
+       if (res->uri->path.length) {
+               coap_add_option(pdu, COAP_OPTION_URI_PATH, res->uri->path.length, res->uri->path.s);
+       }
+
+       d = COAP_PSEUDOFP_ENCODE_8_4_DOWN(duration, ls);
+
+       coap_add_option(pdu, COAP_OPTION_SUBSCRIPTION, 1, &d);
+
+       if (sub->token.length) {
+               coap_add_option(pdu, COAP_OPTION_TOKEN, sub->token.length, sub->token.s);
+       }
+
+       if (res->uri->query.length) {
+               coap_add_option(pdu, COAP_OPTION_URI_QUERY, res->uri->query.length, res->uri->query.s);
+       }
+
+       if (res->data) {
+               length = (unsigned char *)pdu->hdr + COAP_MAX_PDU_SIZE - pdu->data;
+               ct = res->mediatype;
+               res->data(res->uri, &ct, 0, pdu->data, &length, &finished);
+               pdu->length += length;
+
+               /* TODO: add block option if not finished */
+               /* TODO: add mediatype */
+       }
+#ifndef NDEBUG
+       if (inet_ntop(sub->subscriber.addr.sa.sa_family, &sub->subscriber.addr, addr, sizeof(addr))) {
+               debug("*** notify for %s to [%s]\n", res->uri->path.s, addr);
+       }
+#endif
+       if (pdu && coap_send_confirmed(context, &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
+}
+
+void coap_check_resource_list(coap_context_t *context)
+{
+       coap_resource_t *res, *tmp;
+       coap_list_t *sub;
+       coap_key_t key;
+       time_t now;
+
+       if (!context || !context->resources /* || !context->subscribers */) {
+               return;
+       }
+
+       time(&now);                                     /* FIXME: use coap_ticks() */
+
+       HASH_ITER(hh, context->resources, res, tmp) {
+               if (res->dirty) {
+                       debug("FIXME: notify subscribers\n");
+#if 0
+                       key = coap_uri_hash(COAP_RESOURCE(res)->uri);
+
+                       /* is subscribed? */
+                       for (sub = context->subscriptions; sub; sub = sub->next) {
+                               if (COAP_SUBSCRIPTION(sub)->resource == key) {
+                                       /* notify subscriber */
+                                       notify(context, COAP_RESOURCE(res), COAP_SUBSCRIPTION(sub), COAP_SUBSCRIPTION(sub)->expires - now, COAP_RESPONSE_200);
+                               }
+
+                       }
+
+                       COAP_RESOURCE(res)->dirty = 0;
+#endif
+               }
+       }
+}
+
+#if 0
+coap_resource_t *coap_get_resource_from_key(coap_context_t *ctx, coap_key_t key)
+{
+       coap_list_t *node;
+
+       if (ctx) {
+               /* TODO: use hash table for resources with key to access */
+               for (node = ctx->resources; node; node = node->next) {
+                       printf("check %ux\n", coap_uri_hash(COAP_RESOURCE(node)->uri));
+                       if (key == coap_uri_hash(COAP_RESOURCE(node)->uri)) {
+                               printf("found\n");
+                               return COAP_RESOURCE(node);
+                       }
+               }
+       }
+
+       printf("not found\n");
+       return NULL;
+}
+
+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]);
+       }
+       printf("\n");
+#endif
+       return uri ? coap_get_resource_from_key(ctx, coap_uri_hash(uri)) : NULL;
+}
+#endif
+
+void coap_check_subscriptions(coap_context_t *context)
+{
+       time_t now;
+       coap_list_t *node;
+#ifndef NDEBUG
+       char addr[INET6_ADDRSTRLEN];
+#endif
+
+       if (!context) {
+               return;
+       }
+
+       time(&now);
+
+       node = context->subscriptions;
+       while (node && COAP_SUBSCRIPTION(node)->expires < now) {
+#ifndef NDEBUG
+               if (inet_ntop(COAP_SUBSCRIPTION(node)->subscriber.addr.sa.sa_family, &COAP_SUBSCRIPTION(node)->subscriber.addr, addr, sizeof(addr))) {
+
+                       debug("** removed expired subscription from [%s]\n", addr);
+               }
+#endif
+#if 0
+               notify(context, coap_get_resource_from_key(context, COAP_SUBSCRIPTION(node)->resource), COAP_SUBSCRIPTION(node), 0, COAP_RESPONSE_400);
+#endif
+               context->subscriptions = node->next;
+               coap_delete(node);
+               node = context->subscriptions;
+       }
+}
+
+void coap_free_resource(void *res)
+{
+       if (res) {
+#if 0
+               coap_free(((coap_resource_t *) res)->uri);
+               coap_delete_string(((coap_resource_t *) res)->name);
+#endif
+       }
+}
+
+#if 0
+/**
+ * Deletes the resource that is identified by key. Returns 1 if the resource was
+ * removed, 0 on error (e.g. if no such resource exists).
+ */
+int coap_delete_resource(coap_context_t *context, coap_key_t key)
+{
+       coap_list_t *prev, *node;
+
+       if (!context || key == COAP_INVALID_HASHKEY) {
+               return 0;
+       }
+
+       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 {
+                               prev->next = node->next;
+                       }
+
+                       coap_delete(node);
+                       return 1;
+               }
+       }
+       return 0;
+}
+#endif
+
+coap_subscription_t *coap_new_subscription(coap_context_t *context, const coap_uri_t *resource, const struct sockaddr *addr, socklen_t addrlen, time_t expiry)
+{
+       coap_subscription_t *result;
+
+       if (!context || !resource || !addr || !(result = coap_malloc(sizeof(coap_subscription_t)))) {
+               return NULL;
+       }
+
+       result->resource = coap_uri_hash(resource);
+       result->expires = expiry;
+       memcpy(&result->subscriber.addr.sa, addr, addrlen);
+
+       memset(&result->token, 0, sizeof(str));
+
+       return result;
+
+}
+
+coap_list_t *coap_list_push_first(coap_list_t **list, void *data, void (*delete_func)(void *))
+{
+       coap_list_t *node;
+       node = coap_new_listnode(data, delete_func);
+       if (!node || !list) {
+               return NULL;
+       }
+
+       if (!*list) {
+               *list = node;
+       } else {
+               node->next = *list;
+               *list = node;
+       }
+
+       return node;
+}
+
+int _order_subscription(void *a, void *b)
+{
+       if (!a || !b) {
+               return a < b ? -1 : 1;
+       }
+
+       return ((coap_subscription_t *) a)->expires < ((coap_subscription_t *) b)->expires ? -1 : 1;
+}
+
+coap_key_t coap_subscription_hash(coap_subscription_t *subscription)
+{
+       if (!subscription) {
+               return COAP_INVALID_HASHKEY;
+       }
+
+       return _hash2(subscription->resource, (unsigned char *)&subscription->subscriber, sizeof(subscription->subscriber));
+}
+
+coap_key_t coap_add_subscription(coap_context_t *context, coap_subscription_t *subscription)
+{
+       coap_list_t *node;
+       if (!context || !subscription) {
+               return COAP_INVALID_HASHKEY;
+       }
+
+       if (!(node = coap_new_listnode(subscription, NULL))) {
+               return COAP_INVALID_HASHKEY;
+       }
+
+       if (!coap_insert(&context->subscriptions, node, _order_subscription)) {
+               coap_free(node);                /* do not call coap_delete(), so subscription object will survive */
+               return COAP_INVALID_HASHKEY;
+       }
+
+       return coap_subscription_hash(subscription);
+}
+
+coap_subscription_t *coap_find_subscription(coap_context_t *context, coap_key_t hashkey, struct sockaddr *addr, str *token)
+{
+#if 0
+       coap_list_t *node;
+#endif
+
+       if (!context || !addr || hashkey == COAP_INVALID_HASHKEY) {
+               return NULL;
+       }
+
+       /* FIXME: I do not like the way subscriptions work right now. To be fixed. */
+
+#if 0
+       for (node = context->subscriptions; node; node = node->next) {
+               if (COAP_SUBSCRIPTION(node)->resource == hashkey) {
+
+                       if (token) {            /* do not proceed if tokens do not match */
+                               if (token->length != COAP_SUBSCRIPTION(node)->token.length || memcmp(token->s, COAP_SUBSCRIPTION(node)->token.s, token->length) != 0) {
+                                       continue;
+                               }
+                       }
+
+                       if (subscriber->sin6_port == COAP_SUBSCRIPTION(node)->subscriber.sin6_port && memcmp(&subscriber->sin6_addr, &COAP_SUBSCRIPTION(node)->subscriber.sin6_addr, sizeof(struct in6_addr)) == 0) {
+                               return COAP_SUBSCRIPTION(node);
+                       }
+               }
+       }
+#endif
+       return NULL;
+}
+
+int coap_delete_subscription(coap_context_t *context, coap_key_t key, struct sockaddr *addr)
+{
+#if 0
+       coap_list_t *prev, *node;
+#endif
+
+       if (!context || !addr || key == COAP_INVALID_HASHKEY) {
+               return 0;
+       }
+
+       /* FIXME: I do not like the way subscriptions work right now. To be fixed. */
+
+#if 0
+       for (prev = NULL, node = context->subscriptions; node; prev = node, node = node->next) {
+               if (COAP_SUBSCRIPTION(node)->resource == key) {
+                       if (subscriber->sin6_port == COAP_SUBSCRIPTION(node)->subscriber.sin6_port && memcmp(&subscriber->sin6_addr, &COAP_SUBSCRIPTION(node)->subscriber.sin6_addr, sizeof(struct in6_addr)) == 0) {
+
+                               if (!prev) {
+                                       context->subscriptions = node->next;
+                                       coap_free(COAP_SUBSCRIPTION(node)->token.s);
+                                       coap_delete(node);
+                               } else {
+                                       prev->next = node->next;
+                                       coap_free(COAP_SUBSCRIPTION(node)->token.s);
+                                       coap_delete(node);
+                               }
+                               return 1;
+                       }
+               }
+       }
+#endif
+
+       return 0;
+}
+#endif
diff --git a/apps/netutils/libcoap/uri.c b/apps/netutils/libcoap/uri.c
new file mode 100644 (file)
index 0000000..0ee922c
--- /dev/null
@@ -0,0 +1,538 @@
+/* uri.c -- helper functions for URI treatment
+ *
+ * Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#include "config.h"
+
+#if defined(HAVE_ASSERT_H) && !defined(assert)
+#include <assert.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "mem.h"
+#include "debug.h"
+#include "pdu.h"
+#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
+ * 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;
+}
+
+int coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri)
+{
+       unsigned char *p, *q;
+       int secure = 0, res = 0;
+
+       if (!str_var || !uri) {
+               return -1;
+       }
+
+       memset(uri, 0, sizeof(coap_uri_t));
+       uri->port = COAP_DEFAULT_PORT;
+
+       /* search for scheme */
+       p = str_var;
+       if (*p == '/') {
+               q = p;
+               goto path;
+       }
+
+       q = (unsigned char *)COAP_DEFAULT_SCHEME;
+       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) {
+               res = -1;
+               goto error;
+       }
+
+       /* There might be an additional 's', indicating the secure version: */
+       if (len && (secure = tolower(*p) == 's')) {
+               ++p;
+               --len;
+       }
+
+       q = (unsigned char *)"://";
+       while (len && *q && tolower(*p) == *q) {
+               ++p;
+               ++q;
+               --len;
+       }
+
+       if (*q) {
+               res = -2;
+               goto error;
+       }
+
+       /* p points to beginning of Uri-Host */
+       q = p;
+       if (len && *p == '[') {         /* IPv6 address reference */
+               ++p;
+
+               while (len && *q != ']') {
+                       ++q;
+                       --len;
+               }
+
+               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;
+                       --len;
+               }
+
+               if (p == q) {
+                       res = -3;
+                       goto error;
+               }
+
+               COAP_SET_STR(&uri->host, q - p, p);
+       }
+
+       /* check for Uri-Port */
+       if (len && *q == ':') {
+               p = ++q;
+               --len;
+
+               while (len && isdigit(*q)) {
+                       ++q;
+                       --len;
+               }
+
+               if (p < q) {                    /* explicit port number given */
+                       int uri_port = 0;
+
+                       while (p < q) {
+                               uri_port = uri_port * 10 + (*p++ - '0');
+                       }
+
+                       uri->port = uri_port;
+               }
+       }
+
+path:                                                  /* at this point, p must point to an absolute path */
+
+       if (!len) {
+               goto end;
+       }
+
+       if (*q == '/') {
+               p = ++q;
+               --len;
+
+               while (len && *q != '?') {
+                       ++q;
+                       --len;
+               }
+
+               if (p < q) {
+                       COAP_SET_STR(&uri->path, q - p, p);
+                       p = q;
+               }
+       }
+
+       /* Uri_Query */
+       if (len && *p == '?') {
+               ++p;
+               --len;
+               COAP_SET_STR(&uri->query, len, p);
+               len = 0;
+       }
+
+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).
+ *
+ * @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.
+ */
+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;
+       }
+}
+
+/**
+ * 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.
+ */
+int check_segment(const unsigned char *s, size_t length)
+{
+
+       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;
+}
+
+/**
+ * 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
+ * parameter will be set according to the size of the decoded string.
+ * 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.
+ */
+int make_decoded_option(const unsigned char *s, size_t length, unsigned char *buf, size_t buflen)
+{
+       int res;
+       size_t written;
+
+       if (!buflen) {
+               debug("make_decoded_option(): buflen is 0!\n");
+               return -1;
+       }
+
+       res = check_segment(s, length);
+       if (res < 0) {
+               return -1;
+       }
+
+       /* write option header using delta 0 and length res */
+       written = coap_opt_setheader(buf, buflen, 0, res);
+
+       assert(written <= buflen);
+
+       if (!written) {                 /* encoding error */
+               return -1;
+       }
+
+       buf += written;                         /* advance past option type/length */
+       buflen -= written;
+
+       if (buflen < (size_t) res) {
+               debug("buffer too small for option\n");
+               return -1;
+       }
+
+       decode_segment(s, length, buf);
+
+       return written + res;
+}
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+typedef void (*segment_handler_t)(unsigned char *, size_t, void *);
+
+/**
+ * Splits the given string into segments. You should call one of the
+ * macros coap_split_path() or coap_split_query() instead.
+ *
+ * @param parse_iter The iterator used for tokenizing.
+ * @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.
+ */
+size_t coap_split_path_impl(coap_parse_iterator_t *parse_iter, segment_handler_t h, void *data)
+{
+       unsigned char *seg;
+       size_t length;
+
+       assert(parse_iter);
+       assert(h);
+
+       length = parse_iter->n;
+
+       while ((seg = coap_parse_next(parse_iter))) {
+
+               /* any valid path segment is handled here: */
+               h(seg, parse_iter->segment_length, data);
+       }
+
+       return length - (parse_iter->n - parse_iter->segment_length);
+}
+
+struct cnt_str {
+       str buf;
+       int n;
+};
+
+void write_option(unsigned char *s, size_t len, void *data)
+{
+       struct cnt_str *state = (struct cnt_str *)data;
+       int res;
+       assert(state);
+
+       /* skip empty segments and those that consist of only one or two dots */
+       if (memcmp(s, "..", min(len, 2)) == 0) {
+               return;
+       }
+
+       res = make_decoded_option(s, len, state->buf.s, state->buf.length);
+       if (res > 0) {
+               state->buf.s += res;
+               state->buf.length -= res;
+               state->n++;
+       }
+}
+
+int coap_split_path(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen)
+{
+       struct cnt_str tmp = { {*buflen, buf}, 0 };
+       coap_parse_iterator_t pi;
+
+       coap_parse_iterator_init((unsigned char *)s, length, '/', (unsigned char *)"?#", 2, &pi);
+       coap_split_path_impl(&pi, write_option, &tmp);
+
+       *buflen = *buflen - tmp.buf.length;
+       return tmp.n;
+}
+
+int coap_split_query(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen)
+{
+       struct cnt_str tmp = { {*buflen, buf}, 0 };
+       coap_parse_iterator_t pi;
+
+       coap_parse_iterator_init((unsigned char *)s, length, '&', (unsigned char *)"#", 1, &pi);
+
+       coap_split_path_impl(&pi, write_option, &tmp);
+
+       *buflen = tmp.buf.length;
+       return tmp.n;
+}
+
+#define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
+
+coap_uri_t *coap_new_uri(const unsigned char *uri, unsigned int length)
+{
+       unsigned char *result;
+
+       result = coap_malloc(length + 1 + sizeof(coap_uri_t));
+
+       if (!result) {
+               return NULL;
+       }
+
+       memcpy(URI_DATA(result), uri, length);
+       URI_DATA(result)[length] = '\0';        /* make it zero-terminated */
+
+       if (coap_split_uri(URI_DATA(result), length, (coap_uri_t *) result) < 0) {
+               free(result);
+               return NULL;
+       }
+       return (coap_uri_t *) result;
+}
+
+coap_uri_t *coap_clone_uri(const coap_uri_t *uri)
+{
+       coap_uri_t *result;
+
+       if (!uri) {
+               return NULL;
+       }
+
+       result = (coap_uri_t *) coap_malloc(uri->query.length + uri->host.length + uri->path.length + sizeof(coap_uri_t) + 1);
+
+       if (!result) {
+               return NULL;
+       }
+
+       memset(result, 0, sizeof(coap_uri_t));
+
+       result->port = uri->port;
+
+       if (uri->host.length) {
+               result->host.s = URI_DATA(result);
+               result->host.length = uri->host.length;
+
+               memcpy(result->host.s, uri->host.s, uri->host.length);
+       }
+
+       if (uri->path.length) {
+               result->path.s = URI_DATA(result) + uri->host.length;
+               result->path.length = uri->path.length;
+
+               memcpy(result->path.s, uri->path.s, uri->path.length);
+       }
+
+       if (uri->query.length) {
+               result->query.s = URI_DATA(result) + uri->host.length + uri->path.length;
+               result->query.length = uri->query.length;
+
+               memcpy(result->query.s, uri->query.s, uri->query.length);
+       }
+
+       return result;
+}
+
+/* hash URI path segments */
+
+/* The function signature of coap_hash() is different from
+ * segment_handler_t hence we use this wrapper as safe typecast. */
+static inline void hash_segment(unsigned char *s, size_t len, void *data)
+{
+       coap_hash(s, len, data);
+}
+
+int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key)
+{
+       coap_parse_iterator_t pi;
+
+       if (!path) {
+               return 0;
+       }
+
+       memset(key, 0, sizeof(coap_key_t));
+
+       coap_parse_iterator_init((unsigned char *)path, len, '/', (unsigned char *)"?#", 2, &pi);
+       coap_split_path_impl(&pi, hash_segment, key);
+
+       return 1;
+}
+
+/* iterator functions */
+
+coap_parse_iterator_t *coap_parse_iterator_init(unsigned char *s, size_t n, unsigned char separator, unsigned char *delim, size_t dlen, coap_parse_iterator_t *pi)
+{
+       assert(pi);
+       assert(separator);
+
+       pi->separator = separator;
+       pi->delim = delim;
+       pi->dlen = dlen;
+       pi->pos = s;
+       pi->n = n;
+       pi->segment_length = 0;
+
+       return pi;
+}
+
+unsigned char *coap_parse_next(coap_parse_iterator_t *pi)
+{
+       unsigned char *p;
+
+       if (!pi) {
+               return NULL;
+       }
+
+       /* proceed to the next segment */
+       pi->n -= pi->segment_length;
+       pi->pos += pi->segment_length;
+       pi->segment_length = 0;
+
+       /* last segment? */
+       if (!pi->n || strnchr(pi->delim, pi->dlen, *pi->pos)) {
+               pi->pos = NULL;
+               return NULL;
+       }
+
+       /* skip following separator (the first segment might not have one) */
+       if (*pi->pos == pi->separator) {
+               ++pi->pos;
+               --pi->n;
+       }
+
+       p = pi->pos;
+
+       while (pi->segment_length < pi->n && *p != pi->separator && !strnchr(pi->delim, pi->dlen, *p)) {
+               ++p;
+               ++pi->segment_length;
+       }
+
+       if (!pi->n) {
+               pi->pos = NULL;
+               pi->segment_length = 0;
+       }
+
+       return pi->pos;
+}