IDF release/v4.0 08219f3cf

This commit is contained in:
me-no-dev
2020-01-25 14:51:58 +00:00
parent 8c723be135
commit 41ba143063
858 changed files with 37940 additions and 49396 deletions

View File

@ -12,8 +12,8 @@
* @brief Representation of network addresses
*/
#ifndef _COAP_ADDRESS_H_
#define _COAP_ADDRESS_H_
#ifndef COAP_ADDRESS_H_
#define COAP_ADDRESS_H_
#include <assert.h>
#include <stdint.h>
@ -21,7 +21,8 @@
#include <sys/types.h>
#include "libcoap.h"
#ifdef WITH_LWIP
#if defined(WITH_LWIP)
#include <lwip/ip_addr.h>
typedef struct coap_address_t {
@ -29,19 +30,21 @@ typedef struct coap_address_t {
ip_addr_t addr;
} coap_address_t;
#define _coap_address_equals_impl(A, B) (!!ip_addr_cmp(&(A)->addr,&(B)->addr))
#define _coap_address_equals_impl(A, B) \
((A)->port == (B)->port \
&& (!!ip_addr_cmp(&(A)->addr,&(B)->addr)))
#define _coap_address_isany_impl(A) ip_addr_isany(&(A)->addr)
#define _coap_is_mcast_impl(Address) ip_addr_ismulticast(&(Address)->addr)
#endif /* WITH_LWIP */
#ifdef WITH_CONTIKI
#elif defined(WITH_CONTIKI)
#include "uip.h"
typedef struct coap_address_t {
uip_ipaddr_t addr;
unsigned short port;
uint16_t port;
} coap_address_t;
#define _coap_address_equals_impl(A,B) \
@ -52,15 +55,14 @@ typedef struct coap_address_t {
#define _coap_address_isany_impl(A) 0
#define _coap_is_mcast_impl(Address) uip_is_addr_mcast(&((Address)->addr))
#endif /* WITH_CONTIKI */
#ifdef WITH_POSIX
/** multi-purpose address abstraction */
#else /* WITH_LWIP || WITH_CONTIKI */
/** 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;
@ -73,7 +75,7 @@ typedef struct coap_address_t {
*/
int coap_address_equals(const coap_address_t *a, const coap_address_t *b);
static inline int
COAP_STATIC_INLINE int
_coap_address_isany_impl(const coap_address_t *a) {
/* need to compare only relevant parts of sockaddr_in6 */
switch (a->addr.sa.sa_family) {
@ -89,7 +91,7 @@ _coap_address_isany_impl(const coap_address_t *a) {
return 0;
}
#endif /* WITH_POSIX */
#endif /* WITH_LWIP || WITH_CONTIKI */
/**
* Resets the given coap_address_t object @p addr to its default values. In
@ -98,23 +100,45 @@ _coap_address_isany_impl(const coap_address_t *a) {
*
* @param addr The coap_address_t object to initialize.
*/
static inline void
COAP_STATIC_INLINE void
coap_address_init(coap_address_t *addr) {
assert(addr);
memset(addr, 0, sizeof(coap_address_t));
#ifdef WITH_POSIX
#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
/* lwip and Contiki have constant address sizes and doesn't need the .size part */
addr->size = sizeof(addr->addr);
#endif
}
#ifndef WITH_POSIX
/* Convenience function to copy IPv6 addresses without garbage. */
COAP_STATIC_INLINE void
coap_address_copy( coap_address_t *dst, const coap_address_t *src ) {
#if defined(WITH_LWIP) || defined(WITH_CONTIKI)
memcpy( dst, src, sizeof( coap_address_t ) );
#else
memset( dst, 0, sizeof( coap_address_t ) );
dst->size = src->size;
if ( src->addr.sa.sa_family == AF_INET6 ) {
dst->addr.sin6.sin6_family = src->addr.sin6.sin6_family;
dst->addr.sin6.sin6_addr = src->addr.sin6.sin6_addr;
dst->addr.sin6.sin6_port = src->addr.sin6.sin6_port;
dst->addr.sin6.sin6_scope_id = src->addr.sin6.sin6_scope_id;
} else if ( src->addr.sa.sa_family == AF_INET ) {
dst->addr.sin = src->addr.sin;
} else {
memcpy( &dst->addr, &src->addr, src->size );
}
#endif
}
#if defined(WITH_LWIP) || defined(WITH_CONTIKI)
/**
* 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_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);
@ -126,27 +150,28 @@ coap_address_equals(const coap_address_t *a, const coap_address_t *b) {
* function returns @c 1 if this is the case, @c 0 otherwise. The parameters @p
* a must not be @c NULL;
*/
static inline int
COAP_STATIC_INLINE int
coap_address_isany(const coap_address_t *a) {
assert(a);
return _coap_address_isany_impl(a);
}
#ifdef WITH_POSIX
#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
/**
* Checks if given address @p a denotes a multicast address. This function
* returns @c 1 if @p a is multicast, @c 0 otherwise.
*/
int coap_is_mcast(const coap_address_t *a);
#else /* WITH_POSIX */
#else /* !WITH_LWIP && !WITH_CONTIKI */
/**
* 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_STATIC_INLINE int
coap_is_mcast(const coap_address_t *a) {
return a && _coap_is_mcast_impl(a);
}
#endif /* WITH_POSIX */
#endif /* !WITH_LWIP && !WITH_CONTIKI */
#endif /* _COAP_ADDRESS_H_ */
#endif /* COAP_ADDRESS_H_ */

View File

@ -12,8 +12,8 @@
* @brief State management for asynchronous messages
*/
#ifndef _COAP_ASYNC_H_
#define _COAP_ASYNC_H_
#ifndef COAP_ASYNC_H_
#define COAP_ASYNC_H_
#include "net.h"
@ -43,12 +43,12 @@ typedef struct coap_async_state_t {
* asynchronous state object.
*/
void *appdata;
unsigned short message_id; /**< id of last message seen */
uint16_t message_id; /**< id of last message seen */
coap_session_t *session; /**< transaction session */
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 */
uint8_t token[8]; /**< the token to use in a response */
} coap_async_state_t;
/* Definitions for Async Status Flags These flags can be used to control the
@ -71,7 +71,7 @@ typedef struct coap_async_state_t {
* is already registered.
*
* @param context The context to use.
* @param peer The remote peer that is to be asynchronously notified.
* @param session The session that is used for asynchronous transmissions.
* @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
@ -83,7 +83,7 @@ typedef struct coap_async_state_t {
*/
coap_async_state_t *
coap_register_async(coap_context_t *context,
coap_address_t *peer,
coap_session_t *session,
coap_pdu_t *request,
unsigned char flags,
void *data);
@ -96,6 +96,7 @@ coap_register_async(coap_context_t *context,
* functions. You will have to call coap_free_async() to do so.
*
* @param context The context where the async object is registered.
* @param session The session that is used for asynchronous transmissions.
* @param id The identifier of the asynchronous transaction.
* @param s Will be set to the object identified by @p id after removal.
*
@ -104,6 +105,7 @@ coap_register_async(coap_context_t *context,
* return value is @c 1.
*/
int coap_remove_async(coap_context_t *context,
coap_session_t *session,
coap_tid_t id,
coap_async_state_t **s);
@ -124,23 +126,24 @@ coap_free_async(coap_async_state_t *state);
*
* @param context The context where the asynchronous objects are registered
* with.
* @param session The session that is used for asynchronous transmissions.
* @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);
coap_async_state_t *coap_find_async(coap_context_t *context, coap_session_t *session, coap_tid_t id);
/**
* Updates the time stamp of @p s.
*
* @param s The state object to update.
*/
static inline void
COAP_STATIC_INLINE void
coap_touch_async(coap_async_state_t *s) { coap_ticks(&s->created); }
/** @} */
#endif /* WITHOUT_ASYNC */
#endif /* _COAP_ASYNC_H_ */
#endif /* COAP_ASYNC_H_ */

View File

@ -12,8 +12,8 @@
* @brief Bit vector manipulation
*/
#ifndef _COAP_BITS_H_
#define _COAP_BITS_H_
#ifndef COAP_BITS_H_
#define COAP_BITS_H_
#include <stdint.h>
@ -28,9 +28,9 @@
*
* @return @c -1 if @p bit does not fit into @p vec, @c 1 otherwise.
*/
inline static int
COAP_STATIC_INLINE int
bits_setb(uint8_t *vec, size_t size, uint8_t bit) {
if (size <= (bit >> 3))
if (size <= ((size_t)bit >> 3))
return -1;
*(vec + (bit >> 3)) |= (uint8_t)(1 << (bit & 0x07));
@ -48,9 +48,9 @@ bits_setb(uint8_t *vec, size_t size, uint8_t bit) {
*
* @return @c -1 if @p bit does not fit into @p vec, @c 1 otherwise.
*/
inline static int
COAP_STATIC_INLINE int
bits_clrb(uint8_t *vec, size_t size, uint8_t bit) {
if (size <= (bit >> 3))
if (size <= ((size_t)bit >> 3))
return -1;
*(vec + (bit >> 3)) &= (uint8_t)(~(1 << (bit & 0x07)));
@ -67,12 +67,12 @@ bits_clrb(uint8_t *vec, size_t size, uint8_t bit) {
*
* @return @c 1 if the bit is set, @c 0 otherwise.
*/
inline static int
COAP_STATIC_INLINE int
bits_getb(const uint8_t *vec, size_t size, uint8_t bit) {
if (size <= (bit >> 3))
if (size <= ((size_t)bit >> 3))
return -1;
return (*(vec + (bit >> 3)) & (1 << (bit & 0x07))) != 0;
}
#endif /* _COAP_BITS_H_ */
#endif /* COAP_BITS_H_ */

View File

@ -7,24 +7,27 @@
* of use.
*/
#ifndef _COAP_BLOCK_H_
#define _COAP_BLOCK_H_
#ifndef COAP_BLOCK_H_
#define COAP_BLOCK_H_
#include "encode.h"
#include "option.h"
#include "pdu.h"
struct coap_resource_t;
struct coap_session_t;
/**
* @defgroup block Block Transfer
* API functions for handling PDUs using CoAP BLOCK options
* @{
*/
#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.
* The largest value for the SZX component in a Block option.
*/
#define COAP_MAX_BLOCK_SZX 4
#define COAP_MAX_BLOCK_SZX 6
#endif /* COAP_MAX_BLOCK_SZX */
/**
@ -42,15 +45,15 @@ typedef struct {
* returns @c NULL.
*/
#define COAP_OPT_BLOCK_LAST(opt) \
(COAP_OPT_LENGTH(opt) ? (COAP_OPT_VALUE(opt) + (COAP_OPT_LENGTH(opt)-1)) : 0)
(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)
(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)
(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.
@ -61,19 +64,21 @@ 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) {
COAP_STATIC_INLINE int
coap_more_blocks(size_t data_len, unsigned int num, uint16_t szx) {
return ((num+1) << (szx + 4)) < data_len;
}
#if 0
/** Sets the More-bit in @p block_opt */
static inline void
COAP_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;
*(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;
*(coap_opt_value(block_opt) + (coap_opt_length(block_opt) - 1)) &= ~0x08;
}
#endif
/**
* Initializes @p block from @p pdu. @p type must be either COAP_OPTION_BLOCK1
@ -88,7 +93,7 @@ coap_opt_block_set_m(coap_opt_t *block_opt, int m) {
*
* @return @c 1 on success, @c 0 otherwise.
*/
int coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block);
int coap_get_block(coap_pdu_t *pdu, uint16_t type, coap_block_t *block);
/**
* Writes a block option of type @p type to message @p pdu. If the requested
@ -111,7 +116,7 @@ int coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block);
* @return @c 1 on success, or a negative value on error.
*/
int coap_write_block_opt(coap_block_t *block,
unsigned short type,
uint16_t type,
coap_pdu_t *pdu,
size_t data_length);
@ -129,9 +134,40 @@ int coap_write_block_opt(coap_block_t *block,
*/
int coap_add_block(coap_pdu_t *pdu,
unsigned int len,
const unsigned char *data,
const uint8_t *data,
unsigned int block_num,
unsigned char block_szx);
/**
* Adds the appropriate part of @p data to the @p response pdu. If blocks are
* required, then the appropriate block will be added to the PDU and sent.
* Adds a ETAG option that is the hash of the entire data if the data is to be
* split into blocks
* Used by a GET request handler.
*
* @param resource The resource the data is associated with.
* @param session The coap session.
* @param request The requesting pdu.
* @param response The response pdu.
* @param token The token taken from the (original) requesting pdu.
* @param media_type The format of the data.
* @param maxage The maxmimum life of the data. If @c -1, then there
* is no maxage.
* @param length The total length of the data.
* @param data The entire data block to transmit.
*
*/
void
coap_add_data_blocked_response(struct coap_resource_t *resource,
struct coap_session_t *session,
coap_pdu_t *request,
coap_pdu_t *response,
const coap_binary_t *token,
uint16_t media_type,
int maxage,
size_t length,
const uint8_t* data);
/**@}*/
#endif /* _COAP_BLOCK_H_ */
#endif /* COAP_BLOCK_H_ */

View File

@ -17,19 +17,21 @@
#ifndef _COAP_H_
#define _COAP_H_
#include "libcoap.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "libcoap.h"
#include "address.h"
#include "async.h"
#include "bits.h"
#include "block.h"
#include "coap_dtls.h"
#include "coap_event.h"
#include "coap_io.h"
#include "coap_time.h"
#include "debug.h"
#include "coap_debug.h"
#include "encode.h"
#include "mem.h"
#include "net.h"
@ -40,8 +42,6 @@ extern "C" {
#include "str.h"
#include "subscribe.h"
#include "uri.h"
#include "uthash.h"
#include "utlist.h"
#ifdef __cplusplus
}

View File

@ -17,19 +17,21 @@
#ifndef _COAP_H_
#define _COAP_H_
#include "libcoap.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "libcoap.h"
#include "address.h"
#include "async.h"
#include "bits.h"
#include "block.h"
#include "coap_dtls.h"
#include "coap_event.h"
#include "coap_io.h"
#include "coap_time.h"
#include "debug.h"
#include "coap_debug.h"
#include "encode.h"
#include "mem.h"
#include "net.h"
@ -40,8 +42,6 @@ extern "C" {
#include "str.h"
#include "subscribe.h"
#include "uri.h"
#include "uthash.h"
#include "utlist.h"
#ifdef __cplusplus
}

View File

@ -1,167 +0,0 @@
/*
* coap_io.h -- Default network I/O functions for libcoap
*
* Copyright (C) 2012-2013 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see README for terms
* of use.
*/
#ifndef _COAP_IO_H_
#define _COAP_IO_H_
#include <assert.h>
#include <sys/types.h>
#include "address.h"
/**
* Abstract handle that is used to identify a local network interface.
*/
typedef int coap_if_handle_t;
/** Invalid interface handle */
#define COAP_IF_INVALID -1
struct coap_packet_t;
typedef struct coap_packet_t coap_packet_t;
struct coap_context_t;
/**
* Abstraction of virtual endpoint that can be attached to coap_context_t. The
* tuple (handle, addr) must uniquely identify this endpoint.
*/
typedef struct coap_endpoint_t {
#if defined(WITH_POSIX) || defined(WITH_CONTIKI)
union {
int fd; /**< on POSIX systems */
void *conn; /**< opaque connection (e.g. uip_conn in Contiki) */
} handle; /**< opaque handle to identify this endpoint */
#endif /* WITH_POSIX or WITH_CONTIKI */
#ifdef WITH_LWIP
struct udp_pcb *pcb;
/**< @FIXME --chrysn
* this was added in a hurry, not sure it confirms to the overall model */
struct coap_context_t *context;
#endif /* WITH_LWIP */
coap_address_t addr; /**< local interface address */
int ifindex;
int flags;
} coap_endpoint_t;
#define COAP_ENDPOINT_NOSEC 0x00
#define COAP_ENDPOINT_DTLS 0x01
coap_endpoint_t *coap_new_endpoint(const coap_address_t *addr, int flags);
void coap_free_endpoint(coap_endpoint_t *ep);
/**
* Function interface for data transmission. This function returns the number of
* bytes that have been transmitted, or a value less than zero on error.
*
* @param context The calling CoAP context.
* @param local_interface The local interface to send the data.
* @param dst The address of the receiver.
* @param data The data to send.
* @param datalen The actual length of @p data.
*
* @return The number of bytes written on success, or a value
* less than zero on error.
*/
ssize_t coap_network_send(struct coap_context_t *context,
const coap_endpoint_t *local_interface,
const coap_address_t *dst,
unsigned char *data, size_t datalen);
/**
* Function interface for reading data. This function returns the number of
* bytes that have been read, or a value less than zero on error. In case of an
* error, @p *packet is set to NULL.
*
* @param ep The endpoint that is used for reading data from the network.
* @param packet A result parameter where a pointer to the received packet
* structure is stored. The caller must call coap_free_packet to
* release the storage used by this packet.
*
* @return The number of bytes received on success, or a value less than
* zero on error.
*/
ssize_t coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet);
#ifndef coap_mcast_interface
# define coap_mcast_interface(Local) 0
#endif
/**
* Releases the storage allocated for @p packet.
*/
void coap_free_packet(coap_packet_t *packet);
/**
* Populate the coap_endpoint_t *target from the incoming packet's destination
* data.
*
* This is usually used to copy a packet's data into a node's local_if member.
*/
void coap_packet_populate_endpoint(coap_packet_t *packet,
coap_endpoint_t *target);
/**
* Given an incoming packet, copy its source address into an address struct.
*/
void coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target);
/**
* Given a packet, set msg and msg_len to an address and length of the packet's
* data in memory.
* */
void coap_packet_get_memmapped(coap_packet_t *packet,
unsigned char **address,
size_t *length);
#ifdef WITH_LWIP
/**
* Get the pbuf of a packet. The caller takes over responsibility for freeing
* the pbuf.
*/
struct pbuf *coap_packet_extract_pbuf(coap_packet_t *packet);
#endif
#ifdef WITH_CONTIKI
/*
* This is only included in coap_io.h instead of .c in order to be available for
* sizeof in mem.c.
*/
struct coap_packet_t {
coap_if_handle_t hnd; /**< the interface handle */
coap_address_t src; /**< the packet's source address */
coap_address_t dst; /**< the packet's destination address */
const coap_endpoint_t *interface;
int ifindex;
void *session; /**< opaque session data */
size_t length; /**< length of payload */
unsigned char payload[]; /**< payload */
};
#endif
#ifdef WITH_LWIP
/*
* This is only included in coap_io.h instead of .c in order to be available for
* sizeof in lwippools.h.
* Simple carry-over of the incoming pbuf that is later turned into a node.
*
* Source address data is currently side-banded via ip_current_dest_addr & co
* as the packets have limited lifetime anyway.
*/
struct coap_packet_t {
struct pbuf *pbuf;
const coap_endpoint_t *local_interface;
uint16_t srcport;
};
#endif
#endif /* _COAP_IO_H_ */

View File

@ -1,85 +0,0 @@
/*
* debug.h -- debug utilities
*
* 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.
*/
#ifndef _COAP_DEBUG_H_
#define _COAP_DEBUG_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_ERR,
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);
/** Returns a zero-terminated string with the name of this library. */
const char *coap_package_name(void);
/** Returns a zero-terminated string with the library version. */
const char *coap_package_version(void);
/**
* Writes the given text to @c COAP_ERR_FD (for @p level <= @c LOG_CRIT) or @c
* COAP_DEBUG_FD (for @p level >= @c LOG_WARNING). The text is output only when
* @p level is below or equal to the log level that set by coap_set_log_level().
*/
void coap_log_impl(coap_log_t level, const char *format, ...);
#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 /* NDEBUG */
#endif /* _COAP_DEBUG_H_ */

View File

@ -1,52 +0,0 @@
/*
* 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_
#if (BSD >= 199103) || defined(WITH_CONTIKI)
# include <string.h>
#else
# include <strings.h>
#endif
#define Nn 8 /* duplicate definition of N if built on sky motes */
#define ENCODE_HEADER_SIZE 4
#define HIBIT (1 << (Nn - 1))
#define EMASK ((1 << ENCODE_HEADER_SIZE) - 1)
#define MMASK ((1 << Nn) - 1 - EMASK)
#define MAX_VALUE ( (1 << Nn) - (1 << ENCODE_HEADER_SIZE) ) * (1 << ((1 << ENCODE_HEADER_SIZE) - 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<<ENCODE_HEADER_SIZE<<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_ */

View File

@ -1,26 +0,0 @@
/*
* libcoap.h -- platform specific header file for CoAP stack
*
* Copyright (C) 2015 Carsten Schoenert <c.schoenert@t-online.de>
*
* This file is part of the CoAP library libcoap. Please see README for terms
* of use.
*/
#ifndef _LIBCOAP_H_
#define _LIBCOAP_H_
/* The non posix embedded platforms like Contiki, TinyOS, RIOT, ... doesn't have
* a POSIX compatible header structure so we have to slightly do some platform
* related things. Currently there is only Contiki available so we check for a
* CONTIKI environment and do *not* include the POSIX related network stuff. If
* there are other platforms in future there need to be analogous environments.
*
* The CONTIKI variable is within the Contiki build environment! */
#if !defined (CONTIKI)
#include <netinet/in.h>
#include <sys/socket.h>
#endif /* CONTIKI */
#endif /* _LIBCOAP_H_ */

View File

@ -1,521 +0,0 @@
/*
* net.h -- CoAP network interface
*
* Copyright (C) 2010-2015 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_
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#ifdef WITH_LWIP
#include <lwip/ip_addr.h>
#endif
#include "coap_io.h"
#include "coap_time.h"
#include "option.h"
#include "pdu.h"
#include "prng.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_endpoint_t local_if; /**< the local address interface */
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_endpoint_t *local_interface,
const coap_address_t *remote,
coap_pdu_t *sent,
coap_pdu_t *received,
const coap_tid_t id);
#define COAP_MID_CACHE_SIZE 3
typedef struct {
unsigned char flags[COAP_MID_CACHE_SIZE];
coap_key_t item[COAP_MID_CACHE_SIZE];
} coap_mid_cache_t;
/** The CoAP stack's global state is stored in a coap_context_t object */
typedef struct coap_context_t {
coap_opt_filter_t known_options;
struct coap_resource_t *resources; /**< hash table or list of known resources */
#ifndef WITHOUT_ASYNC
/**
* list of asynchronous transactions */
struct coap_async_state_t *async_state;
#endif /* WITHOUT_ASYNC */
/**
* The time stamp in the first element of the sendqeue is relative
* to sendqueue_basetime. */
coap_tick_t sendqueue_basetime;
coap_queue_t *sendqueue;
coap_endpoint_t *endpoint; /**< the endpoint used for listening */
#ifdef WITH_POSIX
int sockfd; /**< send/receive socket */
#endif /* WITH_POSIX */
#ifdef WITH_CONTIKI
struct uip_udp_conn *conn; /**< uIP connection object */
struct etimer retransmit_timer; /**< fires when the next packet must be sent */
struct etimer notify_timer; /**< used to check resources periodically */
#endif /* WITH_CONTIKI */
#ifdef WITH_LWIP
uint8_t timer_configured; /**< Set to 1 when a retransmission is
* scheduled using lwIP timers for this
* context, otherwise 0. */
#endif /* WITH_LWIP */
/**
* The last message id that was used is stored in this field. The initial
* 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;
ssize_t (*network_send)(struct coap_context_t *context,
const coap_endpoint_t *local_interface,
const coap_address_t *dst,
unsigned char *data, size_t datalen);
ssize_t (*network_read)(coap_endpoint_t *ep, coap_packet_t **packet);
} coap_context_t;
/**
* Registers a new message handler that is called whenever a response was
* received that matches an ongoing transaction.
*
* @param context The context to register the handler for.
* @param handler The response handler to register.
*/
static inline void
coap_register_response_handler(coap_context_t *context,
coap_response_handler_t handler) {
context->response_handler = handler;
}
/**
* Registers the option type @p type with the given context object @p ctx.
*
* @param ctx The context to use.
* @param type The option type to register.
*/
inline static void
coap_register_option(coap_context_t *ctx, unsigned char type) {
coap_option_setb(ctx->known_options, type);
}
/**
* Set sendqueue_basetime in the given context object @p ctx to @p now. This
* function returns the number of elements in the queue head that have timed
* out.
*/
unsigned int coap_adjust_basetime(coap_context_t *ctx, coap_tick_t now);
/**
* Returns the next pdu to send without removing from sendqeue.
*/
coap_queue_t *coap_peek_next( coap_context_t *context );
/**
* Returns the next pdu to send and removes it from the sendqeue.
*/
coap_queue_t *coap_pop_next( coap_context_t *context );
/**
* Creates a new coap_context_t object that will hold the CoAP stack status.
*/
coap_context_t *coap_new_context(const coap_address_t *listen_addr);
/**
* Returns a new message id and updates @p context->message_id accordingly. The
* message id is returned in network byte order to make it easier to read in
* tracing tools.
*
* @param context The current coap_context_t object.
*
* @return Incremented message id in network byte order.
*/
static inline unsigned short
coap_new_message_id(coap_context_t *context) {
context->message_id++;
#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(). This function
* clears all entries from the receive queue and send queue and deletes the
* resources that have been registered with @p context, and frees the attached
* endpoints.
*/
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 local_interface The local network interface where the outbound
* packet is sent.
* @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_endpoint_t *local_interface,
const coap_address_t *dst,
coap_pdu_t *pdu);
/**
* Creates a new ACK PDU with specified error @p code. The options specified by
* the filter expression @p opts will be copied from the original request
* contained in @p request. Unless @c 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 local_interface The local network interface where the outbound packet
* is sent.
* @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_endpoint_t *local_interface,
const coap_address_t *dst,
coap_pdu_t *pdu);
/**
* Sends an error response with code @p code for request @p request to @p dst.
* @p opts will be passed to coap_new_error_response() to copy marked options
* from the request. This function returns the transaction id if the message was
* sent, or @c COAP_INVALID_TID otherwise.
*
* @param context The context to use.
* @param request The original request to respond to.
* @param local_interface The local network interface where the outbound packet
* is sent.
* @param dst The remote peer that sent the request.
* @param code The response 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_endpoint_t *local_interface,
const coap_address_t *dst,
unsigned char code,
coap_opt_filter_t opts);
/**
* Helper funktion to create and send a message with @p type (usually ACK or
* RST). This function returns @c COAP_INVALID_TID when the message was not
* sent, a valid transaction id otherwise.
*
* @param context The CoAP context.
* @param local_interface The local network interface where the outbound packet
* is sent.
* @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_endpoint_t *local_interface,
const coap_address_t *dst,
coap_pdu_t *request,
unsigned char type);
/**
* Sends an ACK message with code @c 0 for the specified @p request to @p dst.
* This function returns the corresponding transaction id if the message was
* sent or @c COAP_INVALID_TID on error.
*
* @param context The context to use.
* @param local_interface The local network interface where the outbound packet
* is sent.
* @param dst The destination address.
* @param request The request to be acknowledged.
*
* @return The transaction id if ACK was sent or @c
* COAP_INVALID_TID on error.
*/
coap_tid_t coap_send_ack(coap_context_t *context,
const coap_endpoint_t *local_interface,
const coap_address_t *dst,
coap_pdu_t *request);
/**
* Sends an RST message with code @c 0 for the specified @p request to @p dst.
* This function returns the corresponding transaction id if the message was
* sent or @c COAP_INVALID_TID on error.
*
* @param context The context to use.
* @param local_interface The local network interface where the outbound packet
* is sent.
* @param dst The destination address.
* @param request The request to be reset.
*
* @return The transaction id if RST was sent or @c
* COAP_INVALID_TID on error.
*/
static inline coap_tid_t
coap_send_rst(coap_context_t *context,
const coap_endpoint_t *local_interface,
const coap_address_t *dst,
coap_pdu_t *request) {
return coap_send_message_type(context,
local_interface,
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);
/**
* Parses and interprets a CoAP message with context @p ctx. This function
* returns @c 0 if the message was handled, or a value less than zero on
* error.
*
* @param ctx The current CoAP context.
* @param packet The received packet.
*
* @return @c 0 if message was handled successfully, or less than zero on
* error.
*/
int coap_handle_message(coap_context_t *ctx,
coap_packet_t *packet);
/**
* Calculates a unique transaction id from given arguments @p peer and @p pdu.
* The id is returned in @p id.
*
* @param peer The remote party who sent @p pdu.
* @param pdu The message that initiated the transaction.
* @param id Set to the new id.
*/
void coap_transaction_id(const coap_address_t *peer,
const coap_pdu_t *pdu,
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 the queue.
*
* @param queue The transaction queue to be searched.
* @param 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, coap_queue_t *rcvd);
/**
* 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);
/**
* Creates a new response for given @p request with the contents of @c
* .well-known/core. The result is NULL on error or a newly allocated PDU that
* must be released by coap_delete_pdu().
*
* @param context The current coap context to use.
* @param request The request for @c .well-known/core .
*
* @return A new 2.05 response for @c .well-known/core or NULL on error.
*/
coap_pdu_t *coap_wellknown_response(coap_context_t *context,
coap_pdu_t *request);
#endif /* _COAP_NET_H_ */

View File

@ -1,388 +0,0 @@
/*
* pdu.h -- CoAP message structure
*
* 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.
*/
/**
* @file pdu.h
* @brief Pre-defined constants that reflect defaults for CoAP
*/
#ifndef _COAP_PDU_H_
#define _COAP_PDU_H_
#include "uri.h"
#ifdef WITH_LWIP
#include <lwip/pbuf.h>
#endif
#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 RFC 7641 */
#define COAP_OPTION_OBSERVE 6 /* E, empty/uint, 0 B/0-3 B, (none) */
#define COAP_OPTION_SUBSCRIPTION COAP_OPTION_OBSERVE
/* selected option types from RFC 7959 */
#define COAP_OPTION_BLOCK2 23 /* C, uint, 0--3 B, (none) */
#define COAP_OPTION_BLOCK1 27 /* C, uint, 0--3 B, (none) */
/* selected option types from RFC 7967 */
#define COAP_OPTION_NORESPONSE 258 /* N, uint, 0--1 B, 0 */
#define COAP_MAX_OPT 65535 /**< 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 */
#define COAP_MEDIATYPE_APPLICATION_CBOR 60 /* application/cbor */
/* 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_tid_t is used to store CoAP transaction id, i.e. a hash value
* built from the remote transport address and the message id of a
* CoAP PDU. Valid transaction ids are greater or equal zero.
*/
typedef int coap_tid_t;
/** Indicates an invalid transaction id. */
#define COAP_INVALID_TID -1
/**
* Indicates that a response is suppressed. This will occur for error
* responses if the request was received via IP multicast.
*/
#define COAP_DROPPED_RESPONSE -2
#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)
#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; /**< Address of the first byte of the CoAP message.
* This may or may not equal (coap_hdr_t*)(pdu+1)
* depending on the memory management
* implementation. */
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 package data will always reside
* inside the pbuf's payload, but this pointer
* has to be kept because no exact offset can be
* given. This field must not be accessed from
* outside, because the pbuf's reference count
* is checked to be 1 when the pbuf is assigned
* to the pdu, and the pbuf stays exclusive to
* this pdu. */
#endif
} 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, and for having only one reference.
* The reference is stored in the PDU and will be freed when the PDU is freed.
*
* (For now, these are fatal errors; in future, a new pbuf might be allocated,
* the data copied and the passed pbuf freed).
*
* This behaves like coap_pdu_init(0, 0, 0, pbuf->tot_len), and afterwards
* copying the contents of the pbuf to the pdu.
*
* @return A pointer to the new PDU object or @c NULL on error.
*/
coap_pdu_t * coap_pdu_from_pbuf(struct pbuf *pbuf);
#endif
/**
* Creates a new CoAP PDU of given @p size (must be large enough to hold the
* basic CoAP message header (coap_hdr_t). The function returns a pointer to the
* 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 /* _COAP_PDU_H_ */

View File

@ -1,408 +0,0 @@
/*
* resource.h -- generic resource handling
*
* Copyright (C) 2010,2011,2014,2015 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 <assert.h>
#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 */
#ifdef COAP_RESOURCES_NOHASH
# include "utlist.h"
#else
# include "uthash.h"
#endif
#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 *,
const coap_endpoint_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;
/** The URI passed to coap_resource_init() is free'd by coap_delete_resource(). */
#define COAP_RESOURCE_FLAGS_RELEASE_URI 0x1
/**
* Notifications will be sent non-confirmable by default. RFC 7641 Section 4.5
* https://tools.ietf.org/html/rfc7641#section-4.5
*/
#define COAP_RESOURCE_FLAGS_NOTIFY_NON 0x0
/**
* Notifications will be sent confirmable by default. RFC 7641 Section 4.5
* https://tools.ietf.org/html/rfc7641#section-4.5
*/
#define COAP_RESOURCE_FLAGS_NOTIFY_CON 0x2
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 */
#ifdef COAP_RESOURCES_NOHASH
struct coap_resource_t *next;
#else
UT_hash_handle hh;
#endif
coap_attr_t *link_attr; /**< attributes to be included with the link format */
coap_subscription_t *subscribers; /**< list of observers for this resource */
/**
* Request URI for this resource. This field will point into the static
* memory.
*/
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);
/**
* Sets the notification message type of resource @p r to given
* @p mode which must be one of @c COAP_RESOURCE_FLAGS_NOTIFY_NON
* or @c COAP_RESOURCE_FLAGS_NOTIFY_CON.
*/
static inline void
coap_resource_set_mode(coap_resource_t *r, int mode) {
r->flags = (r->flags & !COAP_RESOURCE_FLAGS_NOTIFY_CON) | mode;
}
/**
* 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);
/**
* Deletes all resources from given @p context and frees their storage.
*
* @param context The CoAP context with the resources to be deleted.
*/
void coap_delete_all_resources(coap_context_t *context);
/**
* 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 local_interface The local network interface where the observer is
* attached to.
* @param observer The remote peer that wants to received status updates.
* @param token The token that identifies this subscription.
* @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_endpoint_t *local_interface,
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. The result is @c 1 if an observation relationship with @p
* observer and @p token existed, @c 0 otherwise.
*
* @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.
* @return @c 1 if the observer has been deleted, @c 0 otherwise.
*/
int coap_delete_observer(coap_resource_t *resource,
const coap_address_t *observer,
const str *token);
/**
* Checks for all known resources, if they are dirty and notifies subscribed
* observers.
*/
void coap_check_notify(coap_context_t *context);
#ifdef COAP_RESOURCES_NOHASH
#define RESOURCES_ADD(r, obj) \
LL_PREPEND((r), (obj))
#define RESOURCES_DELETE(r, obj) \
LL_DELETE((r), (obj))
#define RESOURCES_ITER(r,tmp) \
coap_resource_t *tmp; \
LL_FOREACH((r), tmp)
#define RESOURCES_FIND(r, k, res) { \
coap_resource_t *tmp; \
(res) = tmp = NULL; \
LL_FOREACH((r), tmp) { \
if (memcmp((k), tmp->key, sizeof(coap_key_t)) == 0) { \
(res) = tmp; \
break; \
} \
} \
}
#else /* COAP_RESOURCES_NOHASH */
#define RESOURCES_ADD(r, obj) \
HASH_ADD(hh, (r), key, sizeof(coap_key_t), (obj))
#define RESOURCES_DELETE(r, obj) \
HASH_DELETE(hh, (r), (obj))
#define RESOURCES_ITER(r,tmp) \
coap_resource_t *tmp, *rtmp; \
HASH_ITER(hh, (r), tmp, rtmp)
#define RESOURCES_FIND(r, k, res) { \
HASH_FIND(hh, (r), (k), sizeof(coap_key_t), (res)); \
}
#endif /* COAP_RESOURCES_NOHASH */
/** @} */
coap_print_status_t coap_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 *);
#endif /* _COAP_RESOURCE_H_ */

View File

@ -1,33 +0,0 @@
/*
* 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_ */

View File

@ -1,963 +0,0 @@
/*
Copyright (c) 2003-2014, Troy D. Hanson http://troydhanson.github.com/uthash/
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 */
#include <stdlib.h> /* exit() */
/* 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. */
#if defined(_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
#elif defined(__BORLANDC__) || defined(__LCC__) || defined(__WATCOMC__)
#define NO_DECLTYPE
#define DECLTYPE(x)
#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 Pre VS2010 */
#if defined (_WIN32)
#if defined(_MSC_VER) && _MSC_VER >= 1600
#include <stdint.h>
#elif defined(__WATCOMC__)
#include <stdint.h>
#else
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
#endif
#else
#include <stdint.h>
#endif
#define UTHASH_VERSION 1.9.9
#ifndef uthash_fatal
#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */
#endif
#ifndef uthash_malloc
#define uthash_malloc(sz) malloc(sz) /* malloc fcn */
#endif
#ifndef uthash_free
#define uthash_free(ptr,sz) free(ptr) /* free fcn */
#endif
#ifndef uthash_noexpand_fyi
#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */
#endif
#ifndef uthash_expand_fyi
#define uthash_expand_fyi(tbl) /* can be defined to log expands */
#endif
/* 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 { \
out=NULL; \
if (head) { \
unsigned _hf_bkt,_hf_hashv; \
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)
#define HASH_BLOOM_BYTELEN 0
#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_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \
do { \
replaced=NULL; \
HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced); \
if (replaced!=NULL) { \
HASH_DELETE(hh,head,replaced); \
}; \
HASH_ADD(hh,head,fieldname,keylen_in,add); \
} while(0)
#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 = (unsigned)(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 { \
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 { \
unsigned _hd_bkt; \
_hd_hh_del = &((delptr)->hh); \
if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \
(head)->hh.tbl->tail = \
(UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \
(head)->hh.tbl->hho); \
} \
if ((delptr)->hh.prev) { \
((UT_hash_handle*)((ptrdiff_t)((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*)((ptrdiff_t)_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,(unsigned)strlen(findstr),out)
#define HASH_ADD_STR(head,strfield,add) \
HASH_ADD(hh,head,strfield[0],strlen(add->strfield),add)
#define HASH_REPLACE_STR(head,strfield,add,replaced) \
HASH_REPLACE(hh,head,strfield[0],(unsigned)strlen(add->strfield),add,replaced)
#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_REPLACE_INT(head,intfield,add,replaced) \
HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced)
#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_REPLACE_PTR(head,ptrfield,add,replaced) \
HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced)
#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 { \
struct UT_hash_handle *_thh; \
if (head) { \
unsigned _bkt_i; \
unsigned _count; \
char *_prev; \
_count = 0; \
for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \
unsigned _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 %u, actual %u\n", \
(head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \
} \
} \
if (_count != (head)->hh.tbl->num_items) { \
HASH_OOPS("invalid hh item count %u, actual %u\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 %u, actual %u\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. Note (x<<5+x)=x*33. */
#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) << 5) + (hashv)) + *_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)
/* FNV-1a variation */
#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 ^ _hf_key[_fn_i]; \
hashv = hashv * 16777619; \
} \
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; \
unsigned char *_hj_key=(unsigned char*)(key); \
hashv = 0xfeedbeef; \
_hj_i = _hj_j = 0x9e3779b9; \
_hj_k = (unsigned)(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]; \
/* case 0: nothing left to add */ \
default: /* make gcc -Wswitch-default happy */ \
; \
} \
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 { \
unsigned char *_sfh_key=(unsigned 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 = (uint32_t)(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 ^= (uint32_t)(_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 (x86,x86_64) tolerance for unaligned reads.
* For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
* MurmurHash uses the faster approach only 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__) || defined(_M_IX86))
#define MUR_GETBLOCK(p,i) p[i]
#else /* non intel */
#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0)
#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1)
#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2)
#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3)
#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL))
#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__))
#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24))
#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16))
#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8))
#else /* assume little endian non-intel */
#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24))
#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16))
#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8))
#endif
#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \
(MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \
(MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \
MUR_ONE_THREE(p))))
#endif
#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r))))
#define MUR_FMIX(_h) \
do { \
_h ^= _h >> 16; \
_h *= 0x85ebca6b; \
_h ^= _h >> 13; \
_h *= 0xc2b2ae35l; \
_h ^= _h >> 16; \
} while(0)
#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \
do { \
const uint8_t *_mur_data = (const uint8_t*)(key); \
const int _mur_nblocks = (keylen) / 4; \
uint32_t _mur_h1 = 0xf88D5353; \
uint32_t _mur_c1 = 0xcc9e2d51; \
uint32_t _mur_c2 = 0x1b873593; \
uint32_t _mur_k1 = 0; \
const uint8_t *_mur_tail; \
const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \
int _mur_i; \
for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \
_mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \
_mur_k1 *= _mur_c1; \
_mur_k1 = MUR_ROTL32(_mur_k1,15); \
_mur_k1 *= _mur_c2; \
\
_mur_h1 ^= _mur_k1; \
_mur_h1 = MUR_ROTL32(_mur_h1,13); \
_mur_h1 = _mur_h1*5+0xe6546b64; \
} \
_mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \
_mur_k1=0; \
switch((keylen) & 3) { \
case 3: _mur_k1 ^= _mur_tail[2] << 16; \
case 2: _mur_k1 ^= _mur_tail[1] << 8; \
case 1: _mur_k1 ^= _mur_tail[0]; \
_mur_k1 *= _mur_c1; \
_mur_k1 = MUR_ROTL32(_mur_k1,15); \
_mur_k1 *= _mur_c2; \
_mur_h1 ^= _mur_k1; \
} \
_mur_h1 ^= (keylen); \
MUR_FMIX(_mur_h1); \
hashv = _mur_h1; \
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; \
if (_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; \
if (_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; \
} \
if (_hs_e) { \
_hs_e->prev = ((_hs_tail) ? \
ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \
} \
_hs_tail = _hs_e; \
} \
_hs_p = _hs_q; \
} \
if (_hs_tail){ \
_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)); \
HASH_BLOOM_FREE((head)->hh.tbl); \
uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
(head)=NULL; \
} \
} while(0)
#define HASH_OVERHEAD(hh,head) \
((head) ? ( \
(size_t)((((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \
((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \
(sizeof(UT_hash_table)) + \
(HASH_BLOOM_BYTELEN)))) : 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 */

View File

@ -12,8 +12,8 @@
* @brief Representation of network addresses
*/
#ifndef _COAP_ADDRESS_H_
#define _COAP_ADDRESS_H_
#ifndef COAP_ADDRESS_H_
#define COAP_ADDRESS_H_
#include <assert.h>
#include <stdint.h>
@ -21,7 +21,8 @@
#include <sys/types.h>
#include "libcoap.h"
#ifdef WITH_LWIP
#if defined(WITH_LWIP)
#include <lwip/ip_addr.h>
typedef struct coap_address_t {
@ -29,19 +30,21 @@ typedef struct coap_address_t {
ip_addr_t addr;
} coap_address_t;
#define _coap_address_equals_impl(A, B) (!!ip_addr_cmp(&(A)->addr,&(B)->addr))
#define _coap_address_equals_impl(A, B) \
((A)->port == (B)->port \
&& (!!ip_addr_cmp(&(A)->addr,&(B)->addr)))
#define _coap_address_isany_impl(A) ip_addr_isany(&(A)->addr)
#define _coap_is_mcast_impl(Address) ip_addr_ismulticast(&(Address)->addr)
#endif /* WITH_LWIP */
#ifdef WITH_CONTIKI
#elif defined(WITH_CONTIKI)
#include "uip.h"
typedef struct coap_address_t {
uip_ipaddr_t addr;
unsigned short port;
uint16_t port;
} coap_address_t;
#define _coap_address_equals_impl(A,B) \
@ -52,15 +55,14 @@ typedef struct coap_address_t {
#define _coap_address_isany_impl(A) 0
#define _coap_is_mcast_impl(Address) uip_is_addr_mcast(&((Address)->addr))
#endif /* WITH_CONTIKI */
#ifdef WITH_POSIX
/** multi-purpose address abstraction */
#else /* WITH_LWIP || WITH_CONTIKI */
/** 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;
@ -73,7 +75,7 @@ typedef struct coap_address_t {
*/
int coap_address_equals(const coap_address_t *a, const coap_address_t *b);
static inline int
COAP_STATIC_INLINE int
_coap_address_isany_impl(const coap_address_t *a) {
/* need to compare only relevant parts of sockaddr_in6 */
switch (a->addr.sa.sa_family) {
@ -89,7 +91,7 @@ _coap_address_isany_impl(const coap_address_t *a) {
return 0;
}
#endif /* WITH_POSIX */
#endif /* WITH_LWIP || WITH_CONTIKI */
/**
* Resets the given coap_address_t object @p addr to its default values. In
@ -98,23 +100,45 @@ _coap_address_isany_impl(const coap_address_t *a) {
*
* @param addr The coap_address_t object to initialize.
*/
static inline void
COAP_STATIC_INLINE void
coap_address_init(coap_address_t *addr) {
assert(addr);
memset(addr, 0, sizeof(coap_address_t));
#ifdef WITH_POSIX
#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
/* lwip and Contiki have constant address sizes and doesn't need the .size part */
addr->size = sizeof(addr->addr);
#endif
}
#ifndef WITH_POSIX
/* Convenience function to copy IPv6 addresses without garbage. */
COAP_STATIC_INLINE void
coap_address_copy( coap_address_t *dst, const coap_address_t *src ) {
#if defined(WITH_LWIP) || defined(WITH_CONTIKI)
memcpy( dst, src, sizeof( coap_address_t ) );
#else
memset( dst, 0, sizeof( coap_address_t ) );
dst->size = src->size;
if ( src->addr.sa.sa_family == AF_INET6 ) {
dst->addr.sin6.sin6_family = src->addr.sin6.sin6_family;
dst->addr.sin6.sin6_addr = src->addr.sin6.sin6_addr;
dst->addr.sin6.sin6_port = src->addr.sin6.sin6_port;
dst->addr.sin6.sin6_scope_id = src->addr.sin6.sin6_scope_id;
} else if ( src->addr.sa.sa_family == AF_INET ) {
dst->addr.sin = src->addr.sin;
} else {
memcpy( &dst->addr, &src->addr, src->size );
}
#endif
}
#if defined(WITH_LWIP) || defined(WITH_CONTIKI)
/**
* 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_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);
@ -126,27 +150,28 @@ coap_address_equals(const coap_address_t *a, const coap_address_t *b) {
* function returns @c 1 if this is the case, @c 0 otherwise. The parameters @p
* a must not be @c NULL;
*/
static inline int
COAP_STATIC_INLINE int
coap_address_isany(const coap_address_t *a) {
assert(a);
return _coap_address_isany_impl(a);
}
#ifdef WITH_POSIX
#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
/**
* Checks if given address @p a denotes a multicast address. This function
* returns @c 1 if @p a is multicast, @c 0 otherwise.
*/
int coap_is_mcast(const coap_address_t *a);
#else /* WITH_POSIX */
#else /* !WITH_LWIP && !WITH_CONTIKI */
/**
* 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_STATIC_INLINE int
coap_is_mcast(const coap_address_t *a) {
return a && _coap_is_mcast_impl(a);
}
#endif /* WITH_POSIX */
#endif /* !WITH_LWIP && !WITH_CONTIKI */
#endif /* _COAP_ADDRESS_H_ */
#endif /* COAP_ADDRESS_H_ */

View File

@ -12,8 +12,8 @@
* @brief State management for asynchronous messages
*/
#ifndef _COAP_ASYNC_H_
#define _COAP_ASYNC_H_
#ifndef COAP_ASYNC_H_
#define COAP_ASYNC_H_
#include "net.h"
@ -43,12 +43,12 @@ typedef struct coap_async_state_t {
* asynchronous state object.
*/
void *appdata;
unsigned short message_id; /**< id of last message seen */
uint16_t message_id; /**< id of last message seen */
coap_session_t *session; /**< transaction session */
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 */
uint8_t token[8]; /**< the token to use in a response */
} coap_async_state_t;
/* Definitions for Async Status Flags These flags can be used to control the
@ -71,7 +71,7 @@ typedef struct coap_async_state_t {
* is already registered.
*
* @param context The context to use.
* @param peer The remote peer that is to be asynchronously notified.
* @param session The session that is used for asynchronous transmissions.
* @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
@ -83,7 +83,7 @@ typedef struct coap_async_state_t {
*/
coap_async_state_t *
coap_register_async(coap_context_t *context,
coap_address_t *peer,
coap_session_t *session,
coap_pdu_t *request,
unsigned char flags,
void *data);
@ -96,6 +96,7 @@ coap_register_async(coap_context_t *context,
* functions. You will have to call coap_free_async() to do so.
*
* @param context The context where the async object is registered.
* @param session The session that is used for asynchronous transmissions.
* @param id The identifier of the asynchronous transaction.
* @param s Will be set to the object identified by @p id after removal.
*
@ -104,6 +105,7 @@ coap_register_async(coap_context_t *context,
* return value is @c 1.
*/
int coap_remove_async(coap_context_t *context,
coap_session_t *session,
coap_tid_t id,
coap_async_state_t **s);
@ -124,23 +126,24 @@ coap_free_async(coap_async_state_t *state);
*
* @param context The context where the asynchronous objects are registered
* with.
* @param session The session that is used for asynchronous transmissions.
* @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);
coap_async_state_t *coap_find_async(coap_context_t *context, coap_session_t *session, coap_tid_t id);
/**
* Updates the time stamp of @p s.
*
* @param s The state object to update.
*/
static inline void
COAP_STATIC_INLINE void
coap_touch_async(coap_async_state_t *s) { coap_ticks(&s->created); }
/** @} */
#endif /* WITHOUT_ASYNC */
#endif /* _COAP_ASYNC_H_ */
#endif /* COAP_ASYNC_H_ */

View File

@ -12,8 +12,8 @@
* @brief Bit vector manipulation
*/
#ifndef _COAP_BITS_H_
#define _COAP_BITS_H_
#ifndef COAP_BITS_H_
#define COAP_BITS_H_
#include <stdint.h>
@ -28,9 +28,9 @@
*
* @return @c -1 if @p bit does not fit into @p vec, @c 1 otherwise.
*/
inline static int
COAP_STATIC_INLINE int
bits_setb(uint8_t *vec, size_t size, uint8_t bit) {
if (size <= (bit >> 3))
if (size <= ((size_t)bit >> 3))
return -1;
*(vec + (bit >> 3)) |= (uint8_t)(1 << (bit & 0x07));
@ -48,9 +48,9 @@ bits_setb(uint8_t *vec, size_t size, uint8_t bit) {
*
* @return @c -1 if @p bit does not fit into @p vec, @c 1 otherwise.
*/
inline static int
COAP_STATIC_INLINE int
bits_clrb(uint8_t *vec, size_t size, uint8_t bit) {
if (size <= (bit >> 3))
if (size <= ((size_t)bit >> 3))
return -1;
*(vec + (bit >> 3)) &= (uint8_t)(~(1 << (bit & 0x07)));
@ -67,12 +67,12 @@ bits_clrb(uint8_t *vec, size_t size, uint8_t bit) {
*
* @return @c 1 if the bit is set, @c 0 otherwise.
*/
inline static int
COAP_STATIC_INLINE int
bits_getb(const uint8_t *vec, size_t size, uint8_t bit) {
if (size <= (bit >> 3))
if (size <= ((size_t)bit >> 3))
return -1;
return (*(vec + (bit >> 3)) & (1 << (bit & 0x07))) != 0;
}
#endif /* _COAP_BITS_H_ */
#endif /* COAP_BITS_H_ */

View File

@ -7,24 +7,27 @@
* of use.
*/
#ifndef _COAP_BLOCK_H_
#define _COAP_BLOCK_H_
#ifndef COAP_BLOCK_H_
#define COAP_BLOCK_H_
#include "encode.h"
#include "option.h"
#include "pdu.h"
struct coap_resource_t;
struct coap_session_t;
/**
* @defgroup block Block Transfer
* API functions for handling PDUs using CoAP BLOCK options
* @{
*/
#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.
* The largest value for the SZX component in a Block option.
*/
#define COAP_MAX_BLOCK_SZX 4
#define COAP_MAX_BLOCK_SZX 6
#endif /* COAP_MAX_BLOCK_SZX */
/**
@ -42,15 +45,15 @@ typedef struct {
* returns @c NULL.
*/
#define COAP_OPT_BLOCK_LAST(opt) \
(COAP_OPT_LENGTH(opt) ? (COAP_OPT_VALUE(opt) + (COAP_OPT_LENGTH(opt)-1)) : 0)
(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)
(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)
(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.
@ -61,19 +64,21 @@ 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) {
COAP_STATIC_INLINE int
coap_more_blocks(size_t data_len, unsigned int num, uint16_t szx) {
return ((num+1) << (szx + 4)) < data_len;
}
#if 0
/** Sets the More-bit in @p block_opt */
static inline void
COAP_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;
*(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;
*(coap_opt_value(block_opt) + (coap_opt_length(block_opt) - 1)) &= ~0x08;
}
#endif
/**
* Initializes @p block from @p pdu. @p type must be either COAP_OPTION_BLOCK1
@ -88,7 +93,7 @@ coap_opt_block_set_m(coap_opt_t *block_opt, int m) {
*
* @return @c 1 on success, @c 0 otherwise.
*/
int coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block);
int coap_get_block(coap_pdu_t *pdu, uint16_t type, coap_block_t *block);
/**
* Writes a block option of type @p type to message @p pdu. If the requested
@ -111,7 +116,7 @@ int coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block);
* @return @c 1 on success, or a negative value on error.
*/
int coap_write_block_opt(coap_block_t *block,
unsigned short type,
uint16_t type,
coap_pdu_t *pdu,
size_t data_length);
@ -129,9 +134,40 @@ int coap_write_block_opt(coap_block_t *block,
*/
int coap_add_block(coap_pdu_t *pdu,
unsigned int len,
const unsigned char *data,
const uint8_t *data,
unsigned int block_num,
unsigned char block_szx);
/**
* Adds the appropriate part of @p data to the @p response pdu. If blocks are
* required, then the appropriate block will be added to the PDU and sent.
* Adds a ETAG option that is the hash of the entire data if the data is to be
* split into blocks
* Used by a GET request handler.
*
* @param resource The resource the data is associated with.
* @param session The coap session.
* @param request The requesting pdu.
* @param response The response pdu.
* @param token The token taken from the (original) requesting pdu.
* @param media_type The format of the data.
* @param maxage The maxmimum life of the data. If @c -1, then there
* is no maxage.
* @param length The total length of the data.
* @param data The entire data block to transmit.
*
*/
void
coap_add_data_blocked_response(struct coap_resource_t *resource,
struct coap_session_t *session,
coap_pdu_t *request,
coap_pdu_t *response,
const coap_binary_t *token,
uint16_t media_type,
int maxage,
size_t length,
const uint8_t* data);
/**@}*/
#endif /* _COAP_BLOCK_H_ */
#endif /* COAP_BLOCK_H_ */

View File

@ -0,0 +1,209 @@
/*
* coap_debug.h -- debug utilities
*
* 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.
*/
#ifndef COAP_DEBUG_H_
#define COAP_DEBUG_H_
/**
* @defgroup logging Logging Support
* API functions for logging support
* @{
*/
#ifndef COAP_DEBUG_FD
/**
* Used for output for @c LOG_DEBUG to @c LOG_ERR.
*/
#define COAP_DEBUG_FD stdout
#endif
#ifndef COAP_ERR_FD
/**
* Used for output for @c LOG_CRIT to @c LOG_EMERG.
*/
#define COAP_ERR_FD stderr
#endif
#ifdef HAVE_SYSLOG_H
#include <syslog.h>
/**
* Logging type. One of LOG_* from @b syslog.
*/
typedef short coap_log_t;
#else
/** Pre-defined log levels akin to what is used in \b syslog. */
typedef enum {
LOG_EMERG=0, /**< Emergency */
LOG_ALERT, /**< Alert */
LOG_CRIT, /**< Critical */
LOG_ERR, /**< Error */
LOG_WARNING, /**< Warning */
LOG_NOTICE, /**< Notice */
LOG_INFO, /**< Information */
LOG_DEBUG /**< Debug */
} coap_log_t;
#endif
/**
* Get the current logging level.
*
* @return One of the LOG_* values.
*/
coap_log_t coap_get_log_level(void);
/**
* Sets the log level to the specified value.
*
* @param level One of the LOG_* values.
*/
void coap_set_log_level(coap_log_t level);
/**
* Logging call-back handler definition.
*
* @param level One of the LOG_* values.
* @param message Zero-terminated string message to log.
*/
typedef void (*coap_log_handler_t) (coap_log_t level, const char *message);
/**
* Add a custom log callback handler.
*
* @param handler The logging handler to use or @p NULL to use default handler.
*/
void coap_set_log_handler(coap_log_handler_t handler);
/**
* Get the library package name.
*
* @return Zero-terminated string with the name of this library.
*/
const char *coap_package_name(void);
/**
* Get the library package version.
*
* @return Zero-terminated string with the library version.
*/
const char *coap_package_version(void);
/**
* Writes the given text to @c COAP_ERR_FD (for @p level <= @c LOG_CRIT) or @c
* COAP_DEBUG_FD (for @p level >= @c LOG_ERR). The text is output only when
* @p level is below or equal to the log level that set by coap_set_log_level().
*
* Internal function.
*
* @param level One of the LOG_* values.
& @param format The format string to use.
*/
#if (defined(__GNUC__))
void coap_log_impl(coap_log_t level,
const char *format, ...) __attribute__ ((format(printf, 2, 3)));
#else
void coap_log_impl(coap_log_t level, const char *format, ...);
#endif
#ifndef coap_log
/**
* Logging function.
* 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_ERR). The text is output only when
* @p level is below or equal to the log level that set by coap_set_log_level().
*
* @param level One of the LOG_* values.
*/
#define coap_log(level, ...) do { \
if ((int)((level))<=(int)coap_get_log_level()) \
coap_log_impl((level), __VA_ARGS__); \
} while(0)
#endif
#include "pdu.h"
/**
* Defines the output mode for the coap_show_pdu() function.
*
* @param use_fprintf @p 1 if the output is to use fprintf() (the default)
* @p 0 if the output is to use coap_log().
*/
void coap_set_show_pdu_output(int use_fprintf);
/**
* Display the contents of the specified @p pdu.
* Note: The output method of coap_show_pdu() is dependent on the setting of
* coap_set_show_pdu_output().
*
* @param level The required minimum logging level.
* @param pdu The PDU to decode.
*/
void coap_show_pdu(coap_log_t level, const coap_pdu_t *pdu);
/**
* Display the current (D)TLS library linked with and built for version.
*
* @param level The required minimum logging level.
*/
void coap_show_tls_version(coap_log_t level);
/**
* Build a string containing the current (D)TLS library linked with and
* built for version.
*
* @param buffer The buffer to put the string into.
* @param bufsize The size of the buffer to put the string into.
*
* @return A pointer to the provided buffer.
*/
char *coap_string_tls_version(char *buffer, size_t bufsize);
struct coap_address_t;
/**
* Print the address into the defined buffer.
*
* Internal Function.
*
* @param address The address to print.
* @param buffer The buffer to print into.
* @param size The size of the buffer to print into.
*
* @return The amount written into the buffer.
*/
size_t coap_print_addr(const struct coap_address_t *address,
unsigned char *buffer, size_t size);
/** @} */
/**
* Set the packet loss level for testing. This can be in one of two forms.
*
* Percentage : 0% to 100%. Use the specified probability.
* 0% is send all packets, 100% is drop all packets.
*
* List: A comma separated list of numbers or number ranges that are the
* packets to drop.
*
* @param loss_level The defined loss level (percentage or list).
*
* @return @c 1 If loss level set, @c 0 if there is an error.
*/
int coap_debug_set_packet_loss(const char *loss_level);
/**
* Check to see whether a packet should be sent or not.
*
* Internal function
*
* @return @c 1 if packet is to be sent, @c 0 if packet is to be dropped.
*/
int coap_debug_send_packet(void);
#endif /* COAP_DEBUG_H_ */

View File

@ -0,0 +1,609 @@
/*
* coap_dtls.h -- (Datagram) Transport Layer Support for libcoap
*
* Copyright (C) 2016 Olaf Bergmann <bergmann@tzi.org>
* Copyright (C) 2017 Jean-Claude Michelou <jcm@spinetix.com>
*
* This file is part of the CoAP library libcoap. Please see README for terms
* of use.
*/
#ifndef COAP_DTLS_H_
#define COAP_DTLS_H_
#include "net.h"
#include "coap_session.h"
#include "pdu.h"
/**
* @defgroup dtls DTLS Support
* API functions for interfacing with DTLS libraries.
* @{
*/
/**
* Check whether DTLS is available.
*
* @return @c 1 if support for DTLS is enabled, or @c 0 otherwise.
*/
int coap_dtls_is_supported(void);
/**
* Check whether TLS is available.
*
* @return @c 1 if support for TLS is enabled, or @c 0 otherwise.
*/
int coap_tls_is_supported(void);
#define COAP_TLS_LIBRARY_NOTLS 0 /**< No DTLS library */
#define COAP_TLS_LIBRARY_TINYDTLS 1 /**< Using TinyDTLS library */
#define COAP_TLS_LIBRARY_OPENSSL 2 /**< Using OpenSSL library */
#define COAP_TLS_LIBRARY_GNUTLS 3 /**< Using GnuTLS library */
/**
* The structure used for returning the underlying (D)TLS library
* information.
*/
typedef struct coap_tls_version_t {
uint64_t version; /**< (D)TLS runtime Library Version */
int type; /**< Library type. One of COAP_TLS_LIBRARY_* */
uint64_t built_version; /**< (D)TLS Built against Library Version */
} coap_tls_version_t;
/**
* Determine the type and version of the underlying (D)TLS library.
*
* @return The version and type of library libcoap was compiled against.
*/
coap_tls_version_t *coap_get_tls_library_version(void);
struct coap_dtls_pki_t;
/**
* Additional Security setup handler that can be set up by
* coap_context_set_pki().
* Invoked when libcoap has done the validation checks at the TLS level,
* but the application needs to do some additional checks/changes/updates.
*
* @param tls_session The security session definition - e.g. SSL * for OpenSSL.
* NULL if server call-back.
* This will be dependent on the underlying TLS library -
* see coap_get_tls_library_version()
* @param setup_data A structure containing setup data originally passed into
* coap_context_set_pki() or coap_new_client_session_pki().
*
* @return @c 1 if successful, else @c 0.
*/
typedef int (*coap_dtls_security_setup_t)(void* tls_session,
struct coap_dtls_pki_t *setup_data);
/**
* CN Validation call-back that can be set up by coap_context_set_pki().
* Invoked when libcoap has done the validation checks at the TLS level,
* but the application needs to check that the CN is allowed.
* CN is the SubjectAltName in the cert, if not present, then the leftmost
* Common Name (CN) component of the subject name.
*
* @param cn The determined CN from the certificate
* @param asn1_public_cert The ASN.1 DER encoded X.509 certificate
* @param asn1_length The ASN.1 length
* @param coap_session The CoAP session associated with the certificate update
* @param depth Depth in cert chain. If 0, then client cert, else a CA
* @param validated TLS layer can find no issues if 1
* @param arg The same as was passed into coap_context_set_pki()
* in setup_data->cn_call_back_arg
*
* @return @c 1 if accepted, else @c 0 if to be rejected.
*/
typedef int (*coap_dtls_cn_callback_t)(const char *cn,
const uint8_t *asn1_public_cert,
size_t asn1_length,
coap_session_t *coap_session,
unsigned depth,
int validated,
void *arg);
/**
* The enum used for determining the provided PKI ASN.1 (DER) Private Key
* formats.
*/
typedef enum coap_asn1_privatekey_type_t {
COAP_ASN1_PKEY_NONE, /**< NONE */
COAP_ASN1_PKEY_RSA, /**< RSA type */
COAP_ASN1_PKEY_RSA2, /**< RSA2 type */
COAP_ASN1_PKEY_DSA, /**< DSA type */
COAP_ASN1_PKEY_DSA1, /**< DSA1 type */
COAP_ASN1_PKEY_DSA2, /**< DSA2 type */
COAP_ASN1_PKEY_DSA3, /**< DSA3 type */
COAP_ASN1_PKEY_DSA4, /**< DSA4 type */
COAP_ASN1_PKEY_DH, /**< DH type */
COAP_ASN1_PKEY_DHX, /**< DHX type */
COAP_ASN1_PKEY_EC, /**< EC type */
COAP_ASN1_PKEY_HMAC, /**< HMAC type */
COAP_ASN1_PKEY_CMAC, /**< CMAC type */
COAP_ASN1_PKEY_TLS1_PRF, /**< TLS1_PRF type */
COAP_ASN1_PKEY_HKDF /**< HKDF type */
} coap_asn1_privatekey_type_t;
/**
* The enum used for determining the PKI key formats.
*/
typedef enum coap_pki_key_t {
COAP_PKI_KEY_PEM = 0, /**< The PKI key type is PEM */
COAP_PKI_KEY_ASN1, /**< The PKI key type is ASN.1 (DER) */
} coap_pki_key_t;
/**
* The structure that holds the PKI PEM definitions.
*/
typedef struct coap_pki_key_pem_t {
const char *ca_file; /**< File location of Common CA in PEM format */
const char *public_cert; /**< File location of Public Cert in PEM format */
const char *private_key; /**< File location of Private Key in PEM format */
} coap_pki_key_pem_t;
/**
* The structure that holds the PKI ASN.1 (DER) definitions.
*/
typedef struct coap_pki_key_asn1_t {
const uint8_t *ca_cert; /**< ASN1 (DER) Common CA Cert */
const uint8_t *public_cert; /**< ASN1 (DER) Public Cert */
const uint8_t *private_key; /**< ASN1 (DER) Private Key */
size_t ca_cert_len; /**< ASN1 CA Cert length */
size_t public_cert_len; /**< ASN1 Public Cert length */
size_t private_key_len; /**< ASN1 Private Key length */
coap_asn1_privatekey_type_t private_key_type; /**< Private Key Type */
} coap_pki_key_asn1_t;
/**
* The structure that holds the PKI key information.
*/
typedef struct coap_dtls_key_t {
coap_pki_key_t key_type; /**< key format type */
union {
coap_pki_key_pem_t pem; /**< for PEM keys */
coap_pki_key_asn1_t asn1; /**< for ASN.1 (DER) keys */
} key;
} coap_dtls_key_t;
/**
* Server Name Indication (SNI) Validation call-back that can be set up by
* coap_context_set_pki().
* Invoked if the SNI is not previously seen and prior to sending a certificate
* set back to the client so that the appropriate certificate set can be used
* based on the requesting SNI.
*
* @param sni The requested SNI
* @param arg The same as was passed into coap_context_set_pki()
* in setup_data->sni_call_back_arg
*
* @return New set of certificates to use, or @c NULL if SNI is to be rejected.
*/
typedef coap_dtls_key_t *(*coap_dtls_sni_callback_t)(const char *sni,
void* arg);
#define COAP_DTLS_PKI_SETUP_VERSION 1 /**< Latest PKI setup version */
/**
* The structure used for defining the PKI setup data to be used.
*/
typedef struct coap_dtls_pki_t {
uint8_t version; /** Set to 1 to support this version of the struct */
/* Options to enable different TLS functionality in libcoap */
uint8_t verify_peer_cert; /**< 1 if peer cert is to be verified */
uint8_t require_peer_cert; /**< 1 if peer cert is required */
uint8_t allow_self_signed; /**< 1 if self signed certs are allowed */
uint8_t allow_expired_certs; /**< 1 if expired certs are allowed */
uint8_t cert_chain_validation; /**< 1 if to check cert_chain_verify_depth */
uint8_t cert_chain_verify_depth; /**< recommended depth is 3 */
uint8_t check_cert_revocation; /**< 1 if revocation checks wanted */
uint8_t allow_no_crl; /**< 1 ignore if CRL not there */
uint8_t allow_expired_crl; /**< 1 if expired crl is allowed */
uint8_t reserved[6]; /**< Reserved - must be set to 0 for
future compatibility */
/* Size of 6 chosen to align to next
* parameter, so if newly defined option
* it can use one of the reserverd slot so
* no need to change
* COAP_DTLS_PKI_SETUP_VERSION and just
* decrement the reserved[] count.
*/
/** CN check call-back function.
* If not NULL, is called when the TLS connection has passed the configured
* TLS options above for the application to verify if the CN is valid.
*/
coap_dtls_cn_callback_t validate_cn_call_back;
void *cn_call_back_arg; /**< Passed in to the CN call-back function */
/** SNI check call-back function.
* If not @p NULL, called if the SNI is not previously seen and prior to
* sending a certificate set back to the client so that the appropriate
* certificate set can be used based on the requesting SNI.
*/
coap_dtls_sni_callback_t validate_sni_call_back;
void *sni_call_back_arg; /**< Passed in to the sni call-back function */
/** Additional Security call-back handler that is invoked when libcoap has
* done the standerd, defined validation checks at the TLS level,
* If not @p NULL, called from within the TLS Client Hello connection
* setup.
*/
coap_dtls_security_setup_t additional_tls_setup_call_back;
char* client_sni; /**< If not NULL, SNI to use in client TLS setup.
Owned by the client app and must remain valid
during the call to coap_new_client_session_pki() */
coap_dtls_key_t pki_key; /**< PKI key definition */
} coap_dtls_pki_t;
/** @} */
/**
* @defgroup dtls_internal DTLS Support (Internal)
* Internal API functions for interfacing with DTLS libraries.
* @{
*/
/**
* Creates a new DTLS context for the given @p coap_context. This function
* returns a pointer to a new DTLS context object or @c NULL on error.
*
* Internal function.
*
* @param coap_context The CoAP context where the DTLS object shall be used.
*
* @return A DTLS context object or @c NULL on error.
*/
void *
coap_dtls_new_context(struct coap_context_t *coap_context);
typedef enum coap_dtls_role_t {
COAP_DTLS_ROLE_CLIENT, /**< Internal function invoked for client */
COAP_DTLS_ROLE_SERVER /**< Internal function invoked for server */
} coap_dtls_role_t;
/**
* Set the DTLS context's default PSK information.
* This does the PSK specifics following coap_dtls_new_context().
* If @p COAP_DTLS_ROLE_SERVER, then identity hint will also get set.
* If @p COAP_DTLS_ROLE_SERVER, then the information will get put into the
* TLS library's context (from which sessions are derived).
* If @p COAP_DTLS_ROLE_CLIENT, then the information will get put into the
* TLS library's session.
*
* Internal function.
*
* @param coap_context The CoAP context.
* @param identity_hint The default PSK server identity hint sent to a client.
* Required parameter. If @p NULL, will be set to "".
* Empty string is a valid hint.
* This parameter is ignored if COAP_DTLS_ROLE_CLIENT
* @param role One of @p COAP_DTLS_ROLE_CLIENT or @p COAP_DTLS_ROLE_SERVER
*
* @return @c 1 if successful, else @c 0.
*/
int
coap_dtls_context_set_psk(struct coap_context_t *coap_context,
const char *identity_hint,
coap_dtls_role_t role);
/**
* Set the DTLS context's default server PKI information.
* This does the PKI specifics following coap_dtls_new_context().
* If @p COAP_DTLS_ROLE_SERVER, then the information will get put into the
* TLS library's context (from which sessions are derived).
* If @p COAP_DTLS_ROLE_CLIENT, then the information will get put into the
* TLS library's session.
*
* Internal function.
*
* @param coap_context The CoAP context.
* @param setup_data Setup information defining how PKI is to be setup.
* Required parameter. If @p NULL, PKI will not be
* set up.
* @param role One of @p COAP_DTLS_ROLE_CLIENT or @p COAP_DTLS_ROLE_SERVER
*
* @return @c 1 if successful, else @c 0.
*/
int
coap_dtls_context_set_pki(struct coap_context_t *coap_context,
coap_dtls_pki_t *setup_data,
coap_dtls_role_t role);
/**
* Set the dtls context's default Root CA information for a client or server.
*
* Internal function.
*
* @param coap_context The current coap_context_t object.
* @param ca_file If not @p NULL, is the full path name of a PEM encoded
* file containing all the Root CAs to be used.
* @param ca_dir If not @p NULL, points to a directory containing PEM
* encoded files containing all the Root CAs to be used.
*
* @return @c 1 if successful, else @c 0.
*/
int
coap_dtls_context_set_pki_root_cas(struct coap_context_t *coap_context,
const char *ca_file,
const char *ca_dir);
/**
* Check whether one of the coap_dtls_context_set_{psk|pki}() functions have
* been called.
*
* Internal function.
*
* @param coap_context The current coap_context_t object.
*
* @return @c 1 if coap_dtls_context_set_{psk|pki}() called, else @c 0.
*/
int coap_dtls_context_check_keys_enabled(struct coap_context_t *coap_context);
/**
* Releases the storage allocated for @p dtls_context.
*
* Internal function.
*
* @param dtls_context The DTLS context as returned by coap_dtls_new_context().
*/
void coap_dtls_free_context(void *dtls_context);
/**
* Create a new client-side session. This should send a HELLO to the server.
*
* Internal function.
*
* @param coap_session The CoAP session.
*
* @return Opaque handle to underlying TLS library object containing security
* parameters for the session.
*/
void *coap_dtls_new_client_session(coap_session_t *coap_session);
/**
* Create a new DTLS server-side session.
* Called after coap_dtls_hello() has returned @c 1, signalling that a validated
* HELLO was received from a client.
* This should send a HELLO to the server.
*
* Internal function.
*
* @param coap_session The CoAP session.
*
* @return Opaque handle to underlying TLS library object containing security
* parameters for the DTLS session.
*/
void *coap_dtls_new_server_session(coap_session_t *coap_session);
/**
* Terminates the DTLS session (may send an ALERT if necessary) then frees the
* underlying TLS library object containing security parameters for the session.
*
* Internal function.
*
* @param coap_session The CoAP session.
*/
void coap_dtls_free_session(coap_session_t *coap_session);
/**
* Notify of a change in the CoAP session's MTU, for example after
* a PMTU update.
*
* Internal function.
*
* @param coap_session The CoAP session.
*/
void coap_dtls_session_update_mtu(coap_session_t *coap_session);
/**
* Send data to a DTLS peer.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param data pointer to data.
* @param data_len Number of bytes to send.
*
* @return @c 0 if this would be blocking, @c -1 if there is an error or the
* number of cleartext bytes sent.
*/
int coap_dtls_send(coap_session_t *coap_session,
const uint8_t *data,
size_t data_len);
/**
* Check if timeout is handled per CoAP session or per CoAP context.
*
* Internal function.
*
* @return @c 1 of timeout and retransmit is per context, @c 0 if it is
* per session.
*/
int coap_dtls_is_context_timeout(void);
/**
* Do all pending retransmits and get next timeout
*
* Internal function.
*
* @param dtls_context The DTLS context.
*
* @return @c 0 if no event is pending or date of the next retransmit.
*/
coap_tick_t coap_dtls_get_context_timeout(void *dtls_context);
/**
* Get next timeout for this session.
*
* Internal function.
*
* @param coap_session The CoAP session.
*
* @return @c 0 If no event is pending or date of the next retransmit.
*/
coap_tick_t coap_dtls_get_timeout(coap_session_t *coap_session);
/**
* Handle a DTLS timeout expiration.
*
* Internal function.
*
* @param coap_session The CoAP session.
*/
void coap_dtls_handle_timeout(coap_session_t *coap_session);
/**
* Handling incoming data from a DTLS peer.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param data Encrypted datagram.
* @param data_len Encrypted datagram size.
*
* @return Result of coap_handle_dgram on the decrypted CoAP PDU
* or @c -1 for error.
*/
int coap_dtls_receive(coap_session_t *coap_session,
const uint8_t *data,
size_t data_len);
/**
* Handling client HELLO messages from a new candiate peer.
* Note that session->tls is empty.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param data Encrypted datagram.
* @param data_len Encrypted datagram size.
*
* @return @c 0 if a cookie verification message has been sent, @c 1 if the
* HELLO contains a valid cookie and a server session should be created,
* @c -1 if the message is invalid.
*/
int coap_dtls_hello(coap_session_t *coap_session,
const uint8_t *data,
size_t data_len);
/**
* Get DTLS overhead over cleartext PDUs.
*
* Internal function.
*
* @param coap_session The CoAP session.
*
* @return Maximum number of bytes added by DTLS layer.
*/
unsigned int coap_dtls_get_overhead(coap_session_t *coap_session);
/**
* Create a new TLS client-side session.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param connected Updated with whether the connection is connected yet or not.
* @c 0 is not connected, @c 1 is connected.
*
* @return Opaque handle to underlying TLS library object containing security
* parameters for the session.
*/
void *coap_tls_new_client_session(coap_session_t *coap_session, int *connected);
/**
* Create a TLS new server-side session.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param connected Updated with whether the connection is connected yet or not.
* @c 0 is not connected, @c 1 is connected.
*
* @return Opaque handle to underlying TLS library object containing security
* parameters for the session.
*/
void *coap_tls_new_server_session(coap_session_t *coap_session, int *connected);
/**
* Terminates the TLS session (may send an ALERT if necessary) then frees the
* underlying TLS library object containing security parameters for the session.
*
* Internal function.
*
* @param coap_session The CoAP session.
*/
void coap_tls_free_session( coap_session_t *coap_session );
/**
* Send data to a TLS peer, with implicit flush.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param data Pointer to data.
* @param data_len Number of bytes to send.
*
* @return @c 0 if this should be retried, @c -1 if there is an error
* or the number of cleartext bytes sent.
*/
ssize_t coap_tls_write(coap_session_t *coap_session,
const uint8_t *data,
size_t data_len
);
/**
* Read some data from a TLS peer.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param data Pointer to data.
* @param data_len Maximum number of bytes to read.
*
* @return @c 0 if this should be retried, @c -1 if there is an error
* or the number of cleartext bytes read.
*/
ssize_t coap_tls_read(coap_session_t *coap_session,
uint8_t *data,
size_t data_len
);
/**
* Initialize the underlying (D)TLS Library layer.
*
* Internal function.
*
*/
void coap_dtls_startup(void);
/** @} */
/**
* @ingroup logging
* Sets the (D)TLS logging level to the specified @p level.
* Note: coap_log_level() will influence output if at a specified level.
*
* @param level The logging level to use - LOG_*
*/
void coap_dtls_set_log_level(int level);
/**
* @ingroup logging
* Get the current (D)TLS logging.
*
* @return The current log level (one of LOG_*).
*/
int coap_dtls_get_log_level(void);
#endif /* COAP_DTLS_H */

View File

@ -0,0 +1,102 @@
/*
* coap_event.h -- libcoap Event API
*
* Copyright (C) 2016 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see README for terms
* of use.
*/
#ifndef COAP_EVENT_H_
#define COAP_EVENT_H_
#include "libcoap.h"
struct coap_context_t;
struct coap_session_t;
/**
* @defgroup events Event API
* API functions for event delivery from lower-layer library functions.
* @{
*/
/**
* Scalar type to represent different events, e.g. DTLS events or
* retransmission timeouts.
*/
typedef unsigned int coap_event_t;
/**
* (D)TLS events for COAP_PROTO_DTLS and COAP_PROTO_TLS
*/
#define COAP_EVENT_DTLS_CLOSED 0x0000
#define COAP_EVENT_DTLS_CONNECTED 0x01DE
#define COAP_EVENT_DTLS_RENEGOTIATE 0x01DF
#define COAP_EVENT_DTLS_ERROR 0x0200
/**
* TCP events for COAP_PROTO_TCP and COAP_PROTO_TLS
*/
#define COAP_EVENT_TCP_CONNECTED 0x1001
#define COAP_EVENT_TCP_CLOSED 0x1002
#define COAP_EVENT_TCP_FAILED 0x1003
/**
* CSM exchange events for reliable protocols only
*/
#define COAP_EVENT_SESSION_CONNECTED 0x2001
#define COAP_EVENT_SESSION_CLOSED 0x2002
#define COAP_EVENT_SESSION_FAILED 0x2003
/**
* Type for event handler functions that can be registered with a CoAP
* context using the unction coap_set_event_handler(). When called by
* the library, the first argument will be the coap_context_t object
* where the handler function has been registered. The second argument
* is the event type that may be complemented by event-specific data
* passed as the third argument.
*/
typedef int (*coap_event_handler_t)(struct coap_context_t *,
coap_event_t event,
struct coap_session_t *session);
/**
* Registers the function @p hnd as callback for events from the given
* CoAP context @p context. Any event handler that has previously been
* registered with @p context will be overwritten by this operation.
*
* @param context The CoAP context to register the event handler with.
* @param hnd The event handler to be registered. @c NULL if to be
* de-registered.
*/
void coap_register_event_handler(struct coap_context_t *context,
coap_event_handler_t hnd);
/**
* Registers the function @p hnd as callback for events from the given
* CoAP context @p context. Any event handler that has previously been
* registered with @p context will be overwritten by this operation.
*
* @deprecated Use coap_register_event_handler() instead.
*
* @param context The CoAP context to register the event handler with.
* @param hnd The event handler to be registered.
*/
COAP_DEPRECATED
void coap_set_event_handler(struct coap_context_t *context,
coap_event_handler_t hnd);
/**
* Clears the event handler registered with @p context.
*
* @deprecated Use coap_register_event_handler() instead with NULL for hnd.
*
* @param context The CoAP context whose event handler is to be removed.
*/
COAP_DEPRECATED
void coap_clear_event_handler(struct coap_context_t *context);
/** @} */
#endif /* COAP_EVENT_H */

View File

@ -1,5 +1,5 @@
/*
* hashkey.h -- definition of hash key type and helper functions
* coap_hashkey.h -- definition of hash key type and helper functions
*
* Copyright (C) 2010-2011 Olaf Bergmann <bergmann@tzi.org>
*
@ -8,13 +8,15 @@
*/
/**
* @file hashkey.h
* @file coap_hashkey.h
* @brief definition of hash key type and helper functions
*/
#ifndef _COAP_HASHKEY_H_
#define _COAP_HASHKEY_H_
#ifndef COAP_HASHKEY_H_
#define COAP_HASHKEY_H_
#include "libcoap.h"
#include "uthash.h"
#include "str.h"
typedef unsigned char coap_key_t[4];
@ -35,13 +37,13 @@ void coap_hash_impl(const unsigned char *s, unsigned int len, coap_key_t h);
coap_hash_impl((String),(Length),(Result))
/* This is used to control the pre-set hash-keys for resources. */
#define __COAP_DEFAULT_HASH
#define COAP_DEFAULT_HASH
#else
#undef __COAP_DEFAULT_HASH
#undef COAP_DEFAULT_HASH
#endif /* coap_hash */
/**
* Calls coap_hash() with given @c str object as parameter.
* Calls coap_hash() with given @c coap_string_t 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.
@ -54,4 +56,4 @@ void coap_hash_impl(const unsigned char *s, unsigned int len, coap_key_t h);
coap_hash((Str)->s, (Str)->length, (H)); \
}
#endif /* _COAP_HASHKEY_H_ */
#endif /* COAP_HASHKEY_H_ */

View File

@ -0,0 +1,213 @@
/*
* coap_io.h -- Default network I/O functions for libcoap
*
* Copyright (C) 2012-2013 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see README for terms
* of use.
*/
#ifndef COAP_IO_H_
#define COAP_IO_H_
#include <assert.h>
#include <sys/types.h>
#include "address.h"
#ifndef COAP_RXBUFFER_SIZE
#define COAP_RXBUFFER_SIZE 1472
#endif /* COAP_RXBUFFER_SIZE */
#ifdef _WIN32
typedef SOCKET coap_fd_t;
#define coap_closesocket closesocket
#define COAP_SOCKET_ERROR SOCKET_ERROR
#define COAP_INVALID_SOCKET INVALID_SOCKET
#else
typedef int coap_fd_t;
#define coap_closesocket close
#define COAP_SOCKET_ERROR (-1)
#define COAP_INVALID_SOCKET (-1)
#endif
struct coap_packet_t;
struct coap_session_t;
struct coap_pdu_t;
typedef uint16_t coap_socket_flags_t;
typedef struct coap_socket_t {
#if defined(WITH_LWIP)
struct udp_pcb *pcb;
#elif defined(WITH_CONTIKI)
void *conn;
#else
coap_fd_t fd;
#endif /* WITH_LWIP */
coap_socket_flags_t flags;
} coap_socket_t;
/**
* coap_socket_flags_t values
*/
#define COAP_SOCKET_EMPTY 0x0000 /**< the socket is not used */
#define COAP_SOCKET_NOT_EMPTY 0x0001 /**< the socket is not empty */
#define COAP_SOCKET_BOUND 0x0002 /**< the socket is bound */
#define COAP_SOCKET_CONNECTED 0x0004 /**< the socket is connected */
#define COAP_SOCKET_WANT_READ 0x0010 /**< non blocking socket is waiting for reading */
#define COAP_SOCKET_WANT_WRITE 0x0020 /**< non blocking socket is waiting for writing */
#define COAP_SOCKET_WANT_ACCEPT 0x0040 /**< non blocking server socket is waiting for accept */
#define COAP_SOCKET_WANT_CONNECT 0x0080 /**< non blocking client socket is waiting for connect */
#define COAP_SOCKET_CAN_READ 0x0100 /**< non blocking socket can now read without blocking */
#define COAP_SOCKET_CAN_WRITE 0x0200 /**< non blocking socket can now write without blocking */
#define COAP_SOCKET_CAN_ACCEPT 0x0400 /**< non blocking server socket can now accept without blocking */
#define COAP_SOCKET_CAN_CONNECT 0x0800 /**< non blocking client socket can now connect without blocking */
#define COAP_SOCKET_MULTICAST 0x1000 /**< socket is used for multicast communication */
struct coap_endpoint_t *coap_malloc_endpoint( void );
void coap_mfree_endpoint( struct coap_endpoint_t *ep );
int
coap_socket_connect_udp(coap_socket_t *sock,
const coap_address_t *local_if,
const coap_address_t *server,
int default_port,
coap_address_t *local_addr,
coap_address_t *remote_addr);
int
coap_socket_bind_udp(coap_socket_t *sock,
const coap_address_t *listen_addr,
coap_address_t *bound_addr );
int
coap_socket_connect_tcp1(coap_socket_t *sock,
const coap_address_t *local_if,
const coap_address_t *server,
int default_port,
coap_address_t *local_addr,
coap_address_t *remote_addr);
int
coap_socket_connect_tcp2(coap_socket_t *sock,
coap_address_t *local_addr,
coap_address_t *remote_addr);
int
coap_socket_bind_tcp(coap_socket_t *sock,
const coap_address_t *listen_addr,
coap_address_t *bound_addr);
int
coap_socket_accept_tcp(coap_socket_t *server,
coap_socket_t *new_client,
coap_address_t *local_addr,
coap_address_t *remote_addr);
void coap_socket_close(coap_socket_t *sock);
ssize_t
coap_socket_send( coap_socket_t *sock, struct coap_session_t *session,
const uint8_t *data, size_t data_len );
ssize_t
coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len);
ssize_t
coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len);
#ifdef WITH_LWIP
ssize_t
coap_socket_send_pdu( coap_socket_t *sock, struct coap_session_t *session,
struct coap_pdu_t *pdu );
#endif
const char *coap_socket_strerror( void );
/**
* Function interface for data transmission. This function returns the number of
* bytes that have been transmitted, or a value less than zero on error.
*
* @param sock Socket to send data with
* @param session Addressing information for unconnected sockets, or NULL
* @param data The data to send.
* @param datalen The actual length of @p data.
*
* @return The number of bytes written on success, or a value
* less than zero on error.
*/
ssize_t coap_network_send( coap_socket_t *sock, const struct coap_session_t *session, const uint8_t *data, size_t datalen );
/**
* Function interface for reading data. This function returns the number of
* bytes that have been read, or a value less than zero on error. In case of an
* error, @p *packet is set to NULL.
*
* @param sock Socket to read data from
* @param packet Received packet metadata and payload. src and dst should be preset.
*
* @return The number of bytes received on success, or a value less than
* zero on error.
*/
ssize_t coap_network_read( coap_socket_t *sock, struct coap_packet_t *packet );
#ifndef coap_mcast_interface
# define coap_mcast_interface(Local) 0
#endif
/**
* Given a packet, set msg and msg_len to an address and length of the packet's
* data in memory.
* */
void coap_packet_get_memmapped(struct coap_packet_t *packet,
unsigned char **address,
size_t *length);
void coap_packet_set_addr( struct coap_packet_t *packet, const coap_address_t *src,
const coap_address_t *dst );
#ifdef WITH_LWIP
/**
* Get the pbuf of a packet. The caller takes over responsibility for freeing
* the pbuf.
*/
struct pbuf *coap_packet_extract_pbuf(struct coap_packet_t *packet);
#endif
#if defined(WITH_LWIP)
/*
* This is only included in coap_io.h instead of .c in order to be available for
* sizeof in lwippools.h.
* Simple carry-over of the incoming pbuf that is later turned into a node.
*
* Source address data is currently side-banded via ip_current_dest_addr & co
* as the packets have limited lifetime anyway.
*/
struct coap_packet_t {
struct pbuf *pbuf;
const struct coap_endpoint_t *local_interface;
coap_address_t src; /**< the packet's source address */
coap_address_t dst; /**< the packet's destination address */
int ifindex; /**< the interface index */
// uint16_t srcport;
};
#else
struct coap_packet_t {
coap_address_t src; /**< the packet's source address */
coap_address_t dst; /**< the packet's destination address */
int ifindex; /**< the interface index */
size_t length; /**< length of payload */
unsigned char payload[COAP_RXBUFFER_SIZE]; /**< payload */
};
#endif
typedef struct coap_packet_t coap_packet_t;
typedef enum {
COAP_NACK_TOO_MANY_RETRIES,
COAP_NACK_NOT_DELIVERABLE,
COAP_NACK_RST,
COAP_NACK_TLS_FAILED
} coap_nack_reason_t;
#endif /* COAP_IO_H_ */

View File

@ -0,0 +1,493 @@
/* coap_session.h -- Session management for libcoap
*
* Copyright (C) 2017 Jean-Claue Michelou <jcm@spinetix.com>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#ifndef COAP_SESSION_H_
#define COAP_SESSION_H_
#include "coap_io.h"
#include "coap_time.h"
#include "pdu.h"
struct coap_endpoint_t;
struct coap_context_t;
struct coap_queue_t;
/**
* Abstraction of a fixed point number that can be used where necessary instead
* of a float. 1,000 fractional bits equals one integer
*/
typedef struct coap_fixed_point_t {
uint16_t integer_part; /**< Integer part of fixed point variable */
uint16_t fractional_part; /**< Fractional part of fixed point variable
1/1000 (3 points) precision */
} coap_fixed_point_t;
#define COAP_DEFAULT_SESSION_TIMEOUT 300
#define COAP_PARTIAL_SESSION_TIMEOUT_TICKS (30 * COAP_TICKS_PER_SECOND)
#define COAP_DEFAULT_MAX_HANDSHAKE_SESSIONS 100
#define COAP_PROTO_NOT_RELIABLE(p) ((p)==COAP_PROTO_UDP || (p)==COAP_PROTO_DTLS)
#define COAP_PROTO_RELIABLE(p) ((p)==COAP_PROTO_TCP || (p)==COAP_PROTO_TLS)
typedef uint8_t coap_session_type_t;
/**
* coap_session_type_t values
*/
#define COAP_SESSION_TYPE_CLIENT 1 /**< client-side */
#define COAP_SESSION_TYPE_SERVER 2 /**< server-side */
#define COAP_SESSION_TYPE_HELLO 3 /**< server-side ephemeral session for responding to a client hello */
typedef uint8_t coap_session_state_t;
/**
* coap_session_state_t values
*/
#define COAP_SESSION_STATE_NONE 0
#define COAP_SESSION_STATE_CONNECTING 1
#define COAP_SESSION_STATE_HANDSHAKE 2
#define COAP_SESSION_STATE_CSM 3
#define COAP_SESSION_STATE_ESTABLISHED 4
typedef struct coap_session_t {
struct coap_session_t *next;
coap_proto_t proto; /**< protocol used */
coap_session_type_t type; /**< client or server side socket */
coap_session_state_t state; /**< current state of relationaship with peer */
unsigned ref; /**< reference count from queues */
unsigned tls_overhead; /**< overhead of TLS layer */
unsigned mtu; /**< path or CSM mtu */
coap_address_t local_if; /**< optional local interface address */
coap_address_t remote_addr; /**< remote address and port */
coap_address_t local_addr; /**< local address and port */
int ifindex; /**< interface index */
coap_socket_t sock; /**< socket object for the session, if any */
struct coap_endpoint_t *endpoint; /**< session's endpoint */
struct coap_context_t *context; /**< session's context */
void *tls; /**< security parameters */
uint16_t tx_mid; /**< the last message id that was used in this session */
uint8_t con_active; /**< Active CON request sent */
struct coap_queue_t *delayqueue; /**< list of delayed messages waiting to be sent */
size_t partial_write; /**< if > 0 indicates number of bytes already written from the pdu at the head of sendqueue */
uint8_t read_header[8]; /**< storage space for header of incoming message header */
size_t partial_read; /**< if > 0 indicates number of bytes already read for an incoming message */
coap_pdu_t *partial_pdu; /**< incomplete incoming pdu */
coap_tick_t last_rx_tx;
coap_tick_t last_tx_rst;
coap_tick_t last_ping;
coap_tick_t last_pong;
coap_tick_t csm_tx;
uint8_t *psk_identity;
size_t psk_identity_len;
uint8_t *psk_key;
size_t psk_key_len;
void *app; /**< application-specific data */
unsigned int max_retransmit; /**< maximum re-transmit count (default 4) */
coap_fixed_point_t ack_timeout; /**< timeout waiting for ack (default 2 secs) */
coap_fixed_point_t ack_random_factor; /**< ack random factor backoff (default 1.5) */
unsigned int dtls_timeout_count; /**< dtls setup retry counter */
int dtls_event; /**< Tracking any (D)TLS events on this sesison */
} coap_session_t;
/**
* Increment reference counter on a session.
*
* @param session The CoAP session.
* @return same as session
*/
coap_session_t *coap_session_reference(coap_session_t *session);
/**
* Decrement reference counter on a session.
* Note that the session may be deleted as a result and should not be used
* after this call.
*
* @param session The CoAP session.
*/
void coap_session_release(coap_session_t *session);
/**
* Stores @p data with the given session. This function overwrites any value
* that has previously been stored with @p session.
*/
void coap_session_set_app_data(coap_session_t *session, void *data);
/**
* Returns any application-specific data that has been stored with @p
* session using the function coap_session_set_app_data(). This function will
* return @c NULL if no data has been stored.
*/
void *coap_session_get_app_data(const coap_session_t *session);
/**
* Notify session that it has failed.
*
* @param session The CoAP session.
* @param reason The reason why the session was disconnected.
*/
void coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason);
/**
* Notify session transport has just connected and CSM exchange can now start.
*
* @param session The CoAP session.
*/
void coap_session_send_csm(coap_session_t *session);
/**
* Notify session that it has just connected or reconnected.
*
* @param session The CoAP session.
*/
void coap_session_connected(coap_session_t *session);
/**
* Set the session MTU. This is the maximum message size that can be sent,
* excluding IP and UDP overhead.
*
* @param session The CoAP session.
* @param mtu maximum message size
*/
void coap_session_set_mtu(coap_session_t *session, unsigned mtu);
/**
* Get maximum acceptable PDU size
*
* @param session The CoAP session.
* @return maximum PDU size, not including header (but including token).
*/
size_t coap_session_max_pdu_size(const coap_session_t *session);
/**
* Creates a new client session to the designated server.
* @param ctx The CoAP context.
* @param local_if Address of local interface. It is recommended to use NULL to let the operating system choose a suitable local interface. If an address is specified, the port number should be zero, which means that a free port is automatically selected.
* @param server The server's address. If the port number is zero, the default port for the protocol will be used.
* @param proto Protocol.
*
* @return A new CoAP session or NULL if failed. Call coap_session_release to free.
*/
coap_session_t *coap_new_client_session(
struct coap_context_t *ctx,
const coap_address_t *local_if,
const coap_address_t *server,
coap_proto_t proto
);
/**
* Creates a new client session to the designated server with PSK credentials
* @param ctx The CoAP context.
* @param local_if Address of local interface. It is recommended to use NULL to let the operating system choose a suitable local interface. If an address is specified, the port number should be zero, which means that a free port is automatically selected.
* @param server The server's address. If the port number is zero, the default port for the protocol will be used.
* @param proto Protocol.
* @param identity PSK client identity
* @param key PSK shared key
* @param key_len PSK shared key length
*
* @return A new CoAP session or NULL if failed. Call coap_session_release to free.
*/
coap_session_t *coap_new_client_session_psk(
struct coap_context_t *ctx,
const coap_address_t *local_if,
const coap_address_t *server,
coap_proto_t proto,
const char *identity,
const uint8_t *key,
unsigned key_len
);
struct coap_dtls_pki_t;
/**
* Creates a new client session to the designated server with PKI credentials
* @param ctx The CoAP context.
* @param local_if Address of local interface. It is recommended to use NULL to
* let the operating system choose a suitable local interface.
* If an address is specified, the port number should be zero,
* which means that a free port is automatically selected.
* @param server The server's address. If the port number is zero, the default
* port for the protocol will be used.
* @param proto CoAP Protocol.
* @param setup_data PKI parameters.
*
* @return A new CoAP session or NULL if failed. Call coap_session_release()
* to free.
*/
coap_session_t *coap_new_client_session_pki(
struct coap_context_t *ctx,
const coap_address_t *local_if,
const coap_address_t *server,
coap_proto_t proto,
struct coap_dtls_pki_t *setup_data
);
/**
* Creates a new server session for the specified endpoint.
* @param ctx The CoAP context.
* @param ep An endpoint where an incoming connection request is pending.
*
* @return A new CoAP session or NULL if failed. Call coap_session_release to free.
*/
coap_session_t *coap_new_server_session(
struct coap_context_t *ctx,
struct coap_endpoint_t *ep
);
/**
* Function interface for datagram data transmission. This function returns
* the number of bytes that have been transmitted, or a value less than zero
* on error.
*
* @param session Session to send data on.
* @param data The data to send.
* @param datalen The actual length of @p data.
*
* @return The number of bytes written on success, or a value
* less than zero on error.
*/
ssize_t coap_session_send(coap_session_t *session,
const uint8_t *data, size_t datalen);
/**
* Function interface for stream data transmission. This function returns
* the number of bytes that have been transmitted, or a value less than zero
* on error. The number of bytes written may be less than datalen because of
* congestion control.
*
* @param session Session to send data on.
* @param data The data to send.
* @param datalen The actual length of @p data.
*
* @return The number of bytes written on success, or a value
* less than zero on error.
*/
ssize_t coap_session_write(coap_session_t *session,
const uint8_t *data, size_t datalen);
/**
* Send a pdu according to the session's protocol. This function returns
* the number of bytes that have been transmitted, or a value less than zero
* on error.
*
* @param session Session to send pdu on.
* @param pdu The pdu to send.
*
* @return The number of bytes written on success, or a value
* less than zero on error.
*/
ssize_t coap_session_send_pdu(coap_session_t *session, coap_pdu_t *pdu);
/**
* @ingroup logging
* Get session description.
*
* @param session The CoAP session.
* @return description string.
*/
const char *coap_session_str(const coap_session_t *session);
ssize_t
coap_session_delay_pdu(coap_session_t *session, coap_pdu_t *pdu,
struct coap_queue_t *node);
/**
* Abstraction of virtual endpoint that can be attached to coap_context_t. The
* tuple (handle, addr) must uniquely identify this endpoint.
*/
typedef struct coap_endpoint_t {
struct coap_endpoint_t *next;
struct coap_context_t *context; /**< endpoint's context */
coap_proto_t proto; /**< protocol used on this interface */
uint16_t default_mtu; /**< default mtu for this interface */
coap_socket_t sock; /**< socket object for the interface, if any */
coap_address_t bind_addr; /**< local interface address */
coap_session_t *sessions; /**< list of active sessions */
coap_session_t hello; /**< special session of DTLS hello messages */
} coap_endpoint_t;
/**
* Create a new endpoint for communicating with peers.
*
* @param context The coap context that will own the new endpoint
* @param listen_addr Address the endpoint will listen for incoming requests on or originate outgoing requests from. Use NULL to specify that no incoming request will be accepted and use a random endpoint.
* @param proto Protocol used on this endpoint
*/
coap_endpoint_t *coap_new_endpoint(struct coap_context_t *context, const coap_address_t *listen_addr, coap_proto_t proto);
/**
* Set the endpoint's default MTU. This is the maximum message size that can be
* sent, excluding IP and UDP overhead.
*
* @param endpoint The CoAP endpoint.
* @param mtu maximum message size
*/
void coap_endpoint_set_default_mtu(coap_endpoint_t *endpoint, unsigned mtu);
void coap_free_endpoint(coap_endpoint_t *ep);
/**
* @ingroup logging
* Get endpoint description.
*
* @param endpoint The CoAP endpoint.
* @return description string.
*/
const char *coap_endpoint_str(const coap_endpoint_t *endpoint);
/**
* Lookup the server session for the packet received on an endpoint, or create
* a new one.
*
* @param endpoint Active endpoint the packet was received on.
* @param packet Received packet.
* @param now The current time in ticks.
* @return The CoAP session.
*/
coap_session_t *coap_endpoint_get_session(coap_endpoint_t *endpoint,
const struct coap_packet_t *packet, coap_tick_t now);
/**
* Create a new DTLS session for the @p endpoint.
*
* @ingroup dtls_internal
*
* @param endpoint Endpoint to add DTLS session to
* @param packet Received packet information to base session on.
* @param now The current time in ticks.
*
* @return Created CoAP session or @c NULL if error.
*/
coap_session_t *coap_endpoint_new_dtls_session(coap_endpoint_t *endpoint,
const struct coap_packet_t *packet, coap_tick_t now);
coap_session_t *coap_session_get_by_peer(struct coap_context_t *ctx,
const struct coap_address_t *remote_addr, int ifindex);
void coap_session_free(coap_session_t *session);
void coap_session_mfree(coap_session_t *session);
/**
* @defgroup cc Rate Control
* The transmission parameters for CoAP rate control ("Congestion
* Control" in stream-oriented protocols) are defined in
* https://tools.ietf.org/html/rfc7252#section-4.8
* @{
*/
/**
* Number of seconds when to expect an ACK or a response to an
* outstanding CON message.
* RFC 7252, Section 4.8 Default value of ACK_TIMEOUT is 2
*/
#define COAP_DEFAULT_ACK_TIMEOUT ((coap_fixed_point_t){2,0})
/**
* A factor that is used to randomize the wait time before a message
* is retransmitted to prevent synchronization effects.
* RFC 7252, Section 4.8 Default value of ACK_RANDOM_FACTOR is 1.5
*/
#define COAP_DEFAULT_ACK_RANDOM_FACTOR ((coap_fixed_point_t){1,500})
/**
* Number of message retransmissions before message sending is stopped
* RFC 7252, Section 4.8 Default value of MAX_RETRANSMIT is 4
*/
#define COAP_DEFAULT_MAX_RETRANSMIT 4
/**
* The number of simultaneous outstanding interactions that a client
* maintains to a given server.
* RFC 7252, Section 4.8 Default value of NSTART is 1
*/
#define COAP_DEFAULT_NSTART 1
/** @} */
/**
* Set the CoAP maximum retransmit count before failure
*
* Number of message retransmissions before message sending is stopped
*
* @param session The CoAP session.
* @param value The value to set to. The default is 4 and should not normally
* get changed.
*/
void coap_session_set_max_retransmit(coap_session_t *session,
unsigned int value);
/**
* Set the CoAP initial ack response timeout before the next re-transmit
*
* Number of seconds when to expect an ACK or a response to an
* outstanding CON message.
*
* @param session The CoAP session.
* @param value The value to set to. The default is 2 and should not normally
* get changed.
*/
void coap_session_set_ack_timeout(coap_session_t *session,
coap_fixed_point_t value);
/**
* Set the CoAP ack randomize factor
*
* A factor that is used to randomize the wait time before a message
* is retransmitted to prevent synchronization effects.
*
* @param session The CoAP session.
* @param value The value to set to. The default is 1.5 and should not normally
* get changed.
*/
void coap_session_set_ack_random_factor(coap_session_t *session,
coap_fixed_point_t value);
/**
* Get the CoAP maximum retransmit before failure
*
* Number of message retransmissions before message sending is stopped
*
* @param session The CoAP session.
*
* @return Current maximum retransmit value
*/
unsigned int coap_session_get_max_transmit(coap_session_t *session);
/**
* Get the CoAP initial ack response timeout before the next re-transmit
*
* Number of seconds when to expect an ACK or a response to an
* outstanding CON message.
*
* @param session The CoAP session.
*
* @return Current ack response timeout value
*/
coap_fixed_point_t coap_session_get_ack_timeout(coap_session_t *session);
/**
* Get the CoAP ack randomize factor
*
* A factor that is used to randomize the wait time before a message
* is retransmitted to prevent synchronization effects.
*
* @param session The CoAP session.
*
* @return Current ack randomize value
*/
coap_fixed_point_t coap_session_get_ack_random_factor(coap_session_t *session);
/**
* Send a ping message for the session.
* @param session The CoAP session.
*
* @return COAP_INVALID_TID if there is an error
*/
coap_tid_t coap_session_send_ping(coap_session_t *session);
#endif /* COAP_SESSION_H */

View File

@ -1,7 +1,7 @@
/*
* coap_time.h -- Clock Handling
*
* Copyright (C) 2010-2013 Olaf Bergmann <bergmann@tzi.org>
* Copyright (C) 2010-2019 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see README for terms
* of use.
@ -12,8 +12,8 @@
* @brief Clock Handling
*/
#ifndef _COAP_TIME_H_
#define _COAP_TIME_H_
#ifndef COAP_TIME_H_
#define COAP_TIME_H_
/**
* @defgroup clock Clock Handling
@ -21,7 +21,7 @@
* @{
*/
#ifdef WITH_LWIP
#if defined(WITH_LWIP)
#include <stdint.h>
#include <lwip/sys.h>
@ -33,22 +33,22 @@ typedef uint32_t coap_tick_t;
typedef uint32_t coap_time_t;
typedef int32_t coap_tick_diff_t;
static inline void coap_ticks_impl(coap_tick_t *t) {
COAP_STATIC_INLINE void coap_ticks_impl(coap_tick_t *t) {
*t = sys_now();
}
static inline void coap_clock_init_impl(void) {
COAP_STATIC_INLINE void coap_clock_init_impl(void) {
}
#define coap_clock_init coap_clock_init_impl
#define coap_ticks coap_ticks_impl
static inline coap_time_t coap_ticks_to_rt(coap_tick_t t) {
COAP_STATIC_INLINE coap_time_t coap_ticks_to_rt(coap_tick_t t) {
return t / COAP_TICKS_PER_SECOND;
}
#endif
#ifdef WITH_CONTIKI
#elif defined(WITH_CONTIKI)
#include "clock.h"
typedef clock_time_t coap_tick_t;
@ -63,25 +63,26 @@ typedef int coap_tick_diff_t;
#define COAP_TICKS_PER_SECOND CLOCK_SECOND
static inline void coap_clock_init(void) {
COAP_STATIC_INLINE void coap_clock_init(void) {
clock_init();
}
static inline void coap_ticks(coap_tick_t *t) {
COAP_STATIC_INLINE void coap_ticks(coap_tick_t *t) {
*t = clock_time();
}
static inline coap_time_t coap_ticks_to_rt(coap_tick_t t) {
COAP_STATIC_INLINE coap_time_t coap_ticks_to_rt(coap_tick_t t) {
return t / COAP_TICKS_PER_SECOND;
}
#endif /* WITH_CONTIKI */
#ifdef WITH_POSIX
#else
#include <stdint.h>
/**
* This data type represents internal timer ticks with COAP_TICKS_PER_SECOND
* resolution.
*/
typedef unsigned long coap_tick_t;
typedef uint64_t coap_tick_t;
/**
* CoAP time in seconds since epoch.
@ -93,10 +94,10 @@ typedef time_t coap_time_t;
* values. This data type must have the same size in memory as coap_tick_t to
* allow wrapping.
*/
typedef long coap_tick_diff_t;
typedef int64_t coap_tick_diff_t;
/** Use ms resolution on POSIX systems */
#define COAP_TICKS_PER_SECOND 1000
#define COAP_TICKS_PER_SECOND ((coap_tick_t)(1000U))
/**
* Initializes the internal clock.
@ -119,13 +120,32 @@ void coap_ticks(coap_tick_t *t);
* point (seconds since epoch on POSIX).
*/
coap_time_t coap_ticks_to_rt(coap_tick_t t);
#endif /* WITH_POSIX */
/**
* Helper function that converts coap ticks to POSIX wallclock time in us.
*
* @param t Internal system ticks.
*
* @return The number of seconds that has passed since a specific reference
* point (seconds since epoch on POSIX).
*/
uint64_t coap_ticks_to_rt_us(coap_tick_t t);
/**
* Helper function that converts POSIX wallclock time in us to coap ticks.
*
* @param t POSIX time is us
*
* @return coap ticks
*/
coap_tick_t coap_ticks_from_rt_us(uint64_t t);
#endif
/**
* 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) {
COAP_STATIC_INLINE int coap_time_lt(coap_tick_t a, coap_tick_t b) {
return ((coap_tick_diff_t)(a - b)) < 0;
}
@ -133,10 +153,10 @@ static inline int coap_time_lt(coap_tick_t a, coap_tick_t b) {
* 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) {
COAP_STATIC_INLINE int coap_time_le(coap_tick_t a, coap_tick_t b) {
return a == b || coap_time_lt(a,b);
}
/** @} */
#endif /* _COAP_TIME_H_ */
#endif /* COAP_TIME_H_ */

View File

@ -0,0 +1,96 @@
/*
* 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_
#if (BSD >= 199103) || defined(WITH_CONTIKI) || defined(_WIN32)
# include <string.h>
#else
# include <strings.h>
#endif
#include <stdint.h>
#define Nn 8 /* duplicate definition of N if built on sky motes */
#define ENCODE_HEADER_SIZE 4
#define HIBIT (1 << (Nn - 1))
#define EMASK ((1 << ENCODE_HEADER_SIZE) - 1)
#define MMASK ((1 << Nn) - 1 - EMASK)
#define MAX_VALUE ( (1 << Nn) - (1 << ENCODE_HEADER_SIZE) ) * (1 << ((1 << ENCODE_HEADER_SIZE) - 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
#ifndef HAVE_FLSLL
/* include this only if flsll() is not available */
extern int coap_flsll(long long i);
#else
#define coap_flsll(i) flsll(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<<ENCODE_HEADER_SIZE<<ls)-1)) >> ls) & MMASK)), s == 0 ? HIBIT + ls + 1 : s + ls))
/**
* Decodes multiple-length byte sequences. @p buf points to an input byte
* sequence of length @p length. Returns the decoded value.
*
* @param buf The input byte sequence to decode from
* @param length The length of the input byte sequence
*
* @return The decoded value
*/
unsigned int coap_decode_var_bytes(const uint8_t *buf, unsigned int length);
/**
* Encodes multiple-length byte sequences. @p buf points to an output buffer of
* sufficient length to store the encoded bytes. @p value is the value to
* encode.
* Returns the number of bytes used to encode @p value or 0 on error.
*
* @param buf The output buffer to decode into
* @param length The output buffer size to encode into (must be sufficient)
* @param value The value to encode into the buffer
*
* @return The number of bytes used to encode @p value or @c 0 on error.
*/
unsigned int coap_encode_var_safe(uint8_t *buf,
size_t length,
unsigned int value);
/**
* @deprecated Use coap_encode_var_safe() instead.
* Provided for backward compatibility. As @p value has a
* maximum value of 0xffffffff, and buf is usually defined as an array, it
* is unsafe to continue to use this variant if buf[] is less than buf[4].
*
* For example
* char buf[1],oops;
* ..
* coap_encode_var_bytes(buf, 0xfff);
* would cause oops to get overwritten. This error can only be found by code
* inspection.
* coap_encode_var_safe(buf, sizeof(buf), 0xfff);
* would catch this error at run-time and should be used instead.
*/
COAP_STATIC_INLINE COAP_DEPRECATED int
coap_encode_var_bytes(uint8_t *buf, unsigned int value
) {
return (int)coap_encode_var_safe(buf, sizeof(value), value);
}
#endif /* COAP_ENCODE_H_ */

View File

@ -0,0 +1,58 @@
/*
* libcoap.h -- platform specific header file for CoAP stack
*
* Copyright (C) 2015 Carsten Schoenert <c.schoenert@t-online.de>
*
* This file is part of the CoAP library libcoap. Please see README for terms
* of use.
*/
#ifndef COAP_LIBCOAP_H_
#define COAP_LIBCOAP_H_
/* The non posix embedded platforms like Contiki, TinyOS, RIOT, ... doesn't have
* a POSIX compatible header structure so we have to slightly do some platform
* related things. Currently there is only Contiki available so we check for a
* CONTIKI environment and do *not* include the POSIX related network stuff. If
* there are other platforms in future there need to be analogous environments.
*
* The CONTIKI variable is within the Contiki build environment! */
#if defined(_WIN32)
#pragma comment(lib,"Ws2_32.lib")
#include <ws2tcpip.h>
typedef SSIZE_T ssize_t;
typedef USHORT in_port_t;
#elif !defined (CONTIKI)
#include <netinet/in.h>
#include <sys/socket.h>
#endif /* CONTIKI */
#ifndef COAP_STATIC_INLINE
# if defined(__cplusplus)
# define COAP_STATIC_INLINE inline
# else
# if defined(_MSC_VER)
# define COAP_STATIC_INLINE static __inline
# else
# define COAP_STATIC_INLINE static inline
# endif
# endif
#endif
#ifndef COAP_DEPRECATED
# if defined(__cplusplus)
# define COAP_DEPRECATED __attribute__ ((deprecated))
# else
# if defined(_MSC_VER)
# define COAP_DEPRECATED __declspec(deprecated)
# else
# define COAP_DEPRECATED __attribute__ ((deprecated))
# endif
# endif
#endif
void coap_startup(void);
void coap_cleanup(void);
#endif /* COAP_LIBCOAP_H_ */

View File

@ -3,7 +3,7 @@
* of use.
*/
/** Memory pool definitions for the libcoap when used with lwIP (which has its
/* 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
@ -35,6 +35,10 @@
#define MEMP_NUM_COAPPDU MEMP_NUM_COAPNODE
#endif
#ifndef MEMP_NUM_COAPSESSION
#define MEMP_NUM_COAPSESSION 2
#endif
#ifndef MEMP_NUM_COAP_SUBSCRIPTION
#define MEMP_NUM_COAP_SUBSCRIPTION 4
#endif
@ -47,11 +51,31 @@
#define MEMP_NUM_COAPRESOURCEATTR 20
#endif
#ifndef MEMP_NUM_COAPOPTLIST
#define MEMP_NUM_COAPOPTLIST 1
#endif
#ifndef MEMP_LEN_COAPOPTLIST
#define MEMP_LEN_COAPOPTLIST 12
#endif
#ifndef MEMP_NUM_COAPSTRING
#define MEMP_NUM_COAPSTRING 10
#endif
#ifndef MEMP_LEN_COAPSTRING
#define MEMP_LEN_COAPSTRING 32
#endif
LWIP_MEMPOOL(COAP_CONTEXT, MEMP_NUM_COAPCONTEXT, sizeof(coap_context_t), "COAP_CONTEXT")
LWIP_MEMPOOL(COAP_ENDPOINT, MEMP_NUM_COAPENDPOINT, sizeof(coap_endpoint_t), "COAP_ENDPOINT")
LWIP_MEMPOOL(COAP_PACKET, MEMP_NUM_COAPPACKET, sizeof(coap_packet_t), "COAP_PACKET")
LWIP_MEMPOOL(COAP_NODE, MEMP_NUM_COAPNODE, sizeof(coap_queue_t), "COAP_NODE")
LWIP_MEMPOOL(COAP_PDU, MEMP_NUM_COAPPDU, sizeof(coap_pdu_t), "COAP_PDU")
LWIP_MEMPOOL(COAP_SESSION, MEMP_NUM_COAPSESSION, sizeof(coap_session_t), "COAP_SESSION")
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")
LWIP_MEMPOOL(COAP_OPTLIST, MEMP_NUM_COAPOPTLIST, sizeof(coap_optlist_t)+MEMP_LEN_COAPOPTLIST, "COAP_OPTLIST")
LWIP_MEMPOOL(COAP_STRING, MEMP_NUM_COAPSTRING, sizeof(coap_string_t)+MEMP_LEN_COAPSTRING, "COAP_STRING")

View File

@ -7,8 +7,8 @@
* of use.
*/
#ifndef _COAP_MEM_H_
#define _COAP_MEM_H_
#ifndef COAP_MEM_H_
#define COAP_MEM_H_
#include <stdlib.h>
@ -37,7 +37,12 @@ typedef enum {
COAP_PDU,
COAP_PDU_BUF,
COAP_RESOURCE,
COAP_RESOURCEATTR
COAP_RESOURCEATTR,
#ifdef HAVE_LIBTINYDTLS
COAP_DTLS_SESSION,
#endif
COAP_SESSION,
COAP_OPTLIST,
} coap_memory_tag_t;
#ifndef WITH_LWIP
@ -67,14 +72,14 @@ void coap_free_type(coap_memory_tag_t type, void *p);
/**
* Wrapper function to coap_malloc_type() for backwards compatibility.
*/
static inline void *coap_malloc(size_t size) {
COAP_STATIC_INLINE void *coap_malloc(size_t size) {
return coap_malloc_type(COAP_STRING, size);
}
/**
* Wrapper function to coap_free_type() for backwards compatibility.
*/
static inline void coap_free(void *object) {
COAP_STATIC_INLINE void coap_free(void *object) {
coap_free_type(COAP_STRING, object);
}
@ -86,7 +91,7 @@ static inline void coap_free(void *object) {
/* no initialization needed with lwip (or, more precisely: lwip must be
* completely initialized anyway by the time coap gets active) */
static inline void coap_memory_init(void) {}
COAP_STATIC_INLINE void coap_memory_init(void) {}
/* It would be nice to check that size equals the size given at the memp
* declaration, but i currently don't see a standard way to check that without
@ -98,14 +103,14 @@ static inline void coap_memory_init(void) {}
/* Those are just here to make uri.c happy where string allocation has not been
* made conditional.
*/
static inline void *coap_malloc(size_t size) {
COAP_STATIC_INLINE void *coap_malloc(size_t size) {
LWIP_ASSERT("coap_malloc must not be used in lwIP", 0);
}
static inline void coap_free(void *pointer) {
COAP_STATIC_INLINE void coap_free(void *pointer) {
LWIP_ASSERT("coap_free must not be used in lwIP", 0);
}
#endif /* WITH_LWIP */
#endif /* _COAP_MEM_H_ */
#endif /* COAP_MEM_H_ */

View File

@ -0,0 +1,742 @@
/*
* net.h -- CoAP network interface
*
* Copyright (C) 2010-2015 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_
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <sys/time.h>
#endif
#include <time.h>
#ifdef WITH_LWIP
#include <lwip/ip_addr.h>
#endif
#include "coap_io.h"
#include "coap_dtls.h"
#include "coap_event.h"
#include "coap_time.h"
#include "option.h"
#include "pdu.h"
#include "prng.h"
#include "coap_session.h"
struct coap_queue_t;
/**
* Queue entry
*/
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_session_t *session; /**< the CoAP session */
coap_tid_t id; /**< CoAP transaction id */
coap_pdu_t *pdu; /**< the CoAP PDU to send */
} coap_queue_t;
/**
* Adds @p node to given @p queue, ordered by variable t in @p node.
*
* @param queue Queue to add to.
* @param node Node entry to add to Queue.
*
* @return @c 1 added to queue, @c 0 failure.
*/
int coap_insert_node(coap_queue_t **queue, coap_queue_t *node);
/**
* Destroys specified @p node.
*
* @param node Node entry to remove.
*
* @return @c 1 node deleted from queue, @c 0 failure.
*/
int coap_delete_node(coap_queue_t *node);
/**
* Removes all items from given @p queue and frees the allocated storage.
*
* @param queue The queue to delete.
*/
void coap_delete_all(coap_queue_t *queue);
/**
* Creates a new node suitable for adding to the CoAP sendqueue.
*
* @return New node entry, or @c NULL if failure.
*/
coap_queue_t *coap_new_node(void);
struct coap_resource_t;
struct coap_context_t;
#ifndef WITHOUT_ASYNC
struct coap_async_state_t;
#endif
/**
* Response handler that is used as call-back in coap_context_t.
*
* @param context CoAP session.
* @param session CoAP session.
* @param sent The PDU that was transmitted.
* @param received The PDU that was received.
* @param id CoAP transaction ID.
*/
typedef void (*coap_response_handler_t)(struct coap_context_t *context,
coap_session_t *session,
coap_pdu_t *sent,
coap_pdu_t *received,
const coap_tid_t id);
/**
* Negative Acknowedge handler that is used as call-back in coap_context_t.
*
* @param context CoAP session.
* @param session CoAP session.
* @param sent The PDU that was transmitted.
* @param reason The reason for the NACK.
* @param id CoAP transaction ID.
*/
typedef void (*coap_nack_handler_t)(struct coap_context_t *context,
coap_session_t *session,
coap_pdu_t *sent,
coap_nack_reason_t reason,
const coap_tid_t id);
/**
* Recieved Ping handler that is used as call-back in coap_context_t.
*
* @param context CoAP session.
* @param session CoAP session.
* @param received The PDU that was received.
* @param id CoAP transaction ID.
*/
typedef void (*coap_ping_handler_t)(struct coap_context_t *context,
coap_session_t *session,
coap_pdu_t *received,
const coap_tid_t id);
/**
* Recieved Pong handler that is used as call-back in coap_context_t.
*
* @param context CoAP session.
* @param session CoAP session.
* @param received The PDU that was received.
* @param id CoAP transaction ID.
*/
typedef void (*coap_pong_handler_t)(struct coap_context_t *context,
coap_session_t *session,
coap_pdu_t *received,
const coap_tid_t id);
/**
* The CoAP stack's global state is stored in a coap_context_t object.
*/
typedef struct coap_context_t {
coap_opt_filter_t known_options;
struct coap_resource_t *resources; /**< hash table or list of known
resources */
struct coap_resource_t *unknown_resource; /**< can be used for handling
unknown resources */
#ifndef WITHOUT_ASYNC
/**
* list of asynchronous transactions */
struct coap_async_state_t *async_state;
#endif /* WITHOUT_ASYNC */
/**
* The time stamp in the first element of the sendqeue is relative
* to sendqueue_basetime. */
coap_tick_t sendqueue_basetime;
coap_queue_t *sendqueue;
coap_endpoint_t *endpoint; /**< the endpoints used for listening */
coap_session_t *sessions; /**< client sessions */
#ifdef WITH_CONTIKI
struct uip_udp_conn *conn; /**< uIP connection object */
struct etimer retransmit_timer; /**< fires when the next packet must be sent */
struct etimer notify_timer; /**< used to check resources periodically */
#endif /* WITH_CONTIKI */
#ifdef WITH_LWIP
uint8_t timer_configured; /**< Set to 1 when a retransmission is
* scheduled using lwIP timers for this
* context, otherwise 0. */
#endif /* WITH_LWIP */
/**
* The last message id that was used is stored in this field. The initial
* 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().
*/
uint16_t message_id;
coap_response_handler_t response_handler;
coap_nack_handler_t nack_handler;
coap_ping_handler_t ping_handler;
coap_pong_handler_t pong_handler;
/**
* Callback function that is used to signal events to the
* application. This field is set by coap_set_event_handler().
*/
coap_event_handler_t handle_event;
ssize_t (*network_send)(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data, size_t datalen);
ssize_t (*network_read)(coap_socket_t *sock, struct coap_packet_t *packet);
size_t(*get_client_psk)(const coap_session_t *session, const uint8_t *hint, size_t hint_len, uint8_t *identity, size_t *identity_len, size_t max_identity_len, uint8_t *psk, size_t max_psk_len);
size_t(*get_server_psk)(const coap_session_t *session, const uint8_t *identity, size_t identity_len, uint8_t *psk, size_t max_psk_len);
size_t(*get_server_hint)(const coap_session_t *session, uint8_t *hint, size_t max_hint_len);
void *dtls_context;
uint8_t *psk_hint;
size_t psk_hint_len;
uint8_t *psk_key;
size_t psk_key_len;
unsigned int session_timeout; /**< Number of seconds of inactivity after which an unused session will be closed. 0 means use default. */
unsigned int max_idle_sessions; /**< Maximum number of simultaneous unused sessions per endpoint. 0 means no maximum. */
unsigned int max_handshake_sessions; /**< Maximum number of simultaneous negotating sessions per endpoint. 0 means use default. */
unsigned int ping_timeout; /**< Minimum inactivity time before sending a ping message. 0 means disabled. */
unsigned int csm_timeout; /**< Timeout for waiting for a CSM from the remote side. 0 means disabled. */
void *app; /**< application-specific data */
} 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.
*/
COAP_STATIC_INLINE void
coap_register_response_handler(coap_context_t *context,
coap_response_handler_t handler) {
context->response_handler = handler;
}
/**
* Registers a new message handler that is called whenever a confirmable
* message (request or response) is dropped after all retries have been
* exhausted, or a rst message was received, or a network or TLS level
* event was received that indicates delivering the message is not possible.
*
* @param context The context to register the handler for.
* @param handler The nack handler to register.
*/
COAP_STATIC_INLINE void
coap_register_nack_handler(coap_context_t *context,
coap_nack_handler_t handler) {
context->nack_handler = handler;
}
/**
* Registers a new message handler that is called whenever a CoAP Ping
* message is received.
*
* @param context The context to register the handler for.
* @param handler The ping handler to register.
*/
COAP_STATIC_INLINE void
coap_register_ping_handler(coap_context_t *context,
coap_ping_handler_t handler) {
context->ping_handler = handler;
}
/**
* Registers a new message handler that is called whenever a CoAP Pong
* message is received.
*
* @param context The context to register the handler for.
* @param handler The pong handler to register.
*/
COAP_STATIC_INLINE void
coap_register_pong_handler(coap_context_t *context,
coap_pong_handler_t handler) {
context->pong_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.
*/
COAP_STATIC_INLINE void
coap_register_option(coap_context_t *ctx, uint16_t 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);
/**
* Set the context's default PSK hint and/or key for a server.
*
* @param context The current coap_context_t object.
* @param hint The default PSK server hint sent to a client. If @p NULL, PSK
* authentication is disabled. Empty string is a valid hint.
* @param key The default PSK key. If @p NULL, PSK authentication will fail.
* @param key_len The default PSK key's length. If @p 0, PSK authentication will
* fail.
*
* @return @c 1 if successful, else @c 0.
*/
int coap_context_set_psk( coap_context_t *context, const char *hint,
const uint8_t *key, size_t key_len );
/**
* Set the context's default PKI information for a server.
*
* @param context The current coap_context_t object.
* @param setup_data If @p NULL, PKI authentication will fail. Certificate
* information required.
*
* @return @c 1 if successful, else @c 0.
*/
int
coap_context_set_pki(coap_context_t *context,
coap_dtls_pki_t *setup_data);
/**
* Set the context's default Root CA information for a client or server.
*
* @param context The current coap_context_t object.
* @param ca_file If not @p NULL, is the full path name of a PEM encoded
* file containing all the Root CAs to be used.
* @param ca_dir If not @p NULL, points to a directory containing PEM
* encoded files containing all the Root CAs to be used.
*
* @return @c 1 if successful, else @c 0.
*/
int
coap_context_set_pki_root_cas(coap_context_t *context,
const char *ca_file,
const char *ca_dir);
/**
* Set the context keepalive timer for sessions.
* A keepalive message will be sent after if a session has been inactive,
* i.e. no packet sent or received, for the given number of seconds.
* For reliable protocols, a PING message will be sent. If a PONG has not
* been received before the next PING is due to be sent, the session will
* considered as disconnected.
*
* @param context The coap_context_t object.
* @param seconds Number of seconds for the inactivity timer, or zero
* to disable CoAP-level keepalive messages.
*
* @return 1 if successful, else 0
*/
void coap_context_set_keepalive(coap_context_t *context, unsigned int seconds);
/**
* Returns a new message id and updates @p session->tx_mid accordingly. The
* message id is returned in network byte order to make it easier to read in
* tracing tools.
*
* @param session The current coap_session_t object.
*
* @return Incremented message id in network byte order.
*/
COAP_STATIC_INLINE uint16_t
coap_new_message_id(coap_session_t *session) {
return ++session->tx_mid;
}
/**
* CoAP stack context must be released with coap_free_context(). This function
* clears all entries from the receive queue and send queue and deletes the
* resources that have been registered with @p context, and frees the attached
* endpoints.
*
* @param context The current coap_context_t object to free off.
*/
void coap_free_context(coap_context_t *context);
/**
* Stores @p data with the given CoAP context. This function
* overwrites any value that has previously been stored with @p
* context.
*
* @param context The CoAP context.
* @param data The data to store with wih the context. Note that this data
* must be valid during the lifetime of @p context.
*/
void coap_set_app_data(coap_context_t *context, void *data);
/**
* Returns any application-specific data that has been stored with @p
* context using the function coap_set_app_data(). This function will
* return @c NULL if no data has been stored.
*
* @param context The CoAP context.
*
* @return The data previously stored or @c NULL if not data stored.
*/
void *coap_get_app_data(const coap_context_t *context);
/**
* 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 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 session The CoAP session.
* @param request The original request to respond to.
* @param code The response 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_session_t *session,
coap_pdu_t *request,
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 session The CoAP session.
* @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_session_t *session, 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 session The CoAP session.
* @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_session_t *session, 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 session The CoAP session.
* @param request The request to be reset.
*
* @return The transaction id if RST was sent or @c
* COAP_INVALID_TID on error.
*/
COAP_STATIC_INLINE coap_tid_t
coap_send_rst(coap_session_t *session, coap_pdu_t *request) {
return coap_send_message_type(session, request, COAP_MESSAGE_RST);
}
/**
* Sends a CoAP message to given peer. The memory that is
* allocated by pdu will be released by coap_send().
* The caller must not use the pdu after calling coap_send().
*
* @param session The CoAP session.
* @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_session_t *session, coap_pdu_t *pdu );
/**
* Handles retransmissions of confirmable messages
*
* @param context The CoAP context.
* @param node The node to retransmit.
*
* @return The message id of the sent message or @c
* COAP_INVALID_TID on error.
*/
coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node);
/**
* For applications with their own message loop, send all pending retransmits and
* return the list of sockets with events to wait for and the next timeout
* The application should call coap_read, then coap_write again when any condition below is true:
* - data is available on any of the sockets with the COAP_SOCKET_WANT_READ
* - an incoming connection is pending in the listen queue and the COAP_SOCKET_WANT_ACCEPT flag is set
* - at least some data can be written without blocking on any of the sockets with the COAP_SOCKET_WANT_WRITE flag set
* - a connection event occured (success or failure) and the COAP_SOCKET_WANT_CONNECT flag is set
* - the timeout has expired
* Before calling coap_read or coap_write again, the application should position COAP_SOCKET_CAN_READ and COAP_SOCKET_CAN_WRITE flags as applicable.
*
* @param ctx The CoAP context
* @param sockets array of socket descriptors, filled on output
* @param max_sockets size of socket array.
* @param num_sockets pointer to the number of valid entries in the socket arrays on output
* @param now Current time.
*
* @return timeout as maxmimum number of milliseconds that the application should wait for network events or 0 if the application should wait forever.
*/
unsigned int
coap_write(coap_context_t *ctx,
coap_socket_t *sockets[],
unsigned int max_sockets,
unsigned int *num_sockets,
coap_tick_t now
);
/**
* For applications with their own message loop, reads all data from the network.
*
* @param ctx The CoAP context
* @param now Current time
*/
void coap_read(coap_context_t *ctx, coap_tick_t now);
/**
* The main message processing loop.
*
* @param ctx The CoAP context
* @param timeout_ms Minimum number of milliseconds to wait for new messages before returning. If zero the call will block until at least one packet is sent or received.
*
* @return number of milliseconds spent or @c -1 if there was an error
*/
int coap_run_once( coap_context_t *ctx, unsigned int timeout_ms );
/**
* Parses and interprets a CoAP datagram with context @p ctx. This function
* returns @c 0 if the datagram was handled, or a value less than zero on
* error.
*
* @param ctx The current CoAP context.
* @param session The current CoAP session.
* @param data The received packet'd data.
* @param data_len The received packet'd data length.
*
* @return @c 0 if message was handled successfully, or less than zero on
* error.
*/
int coap_handle_dgram(coap_context_t *ctx, coap_session_t *session, uint8_t *data, size_t data_len);
/**
* Invokes the event handler of @p context for the given @p event and
* @p data.
*
* @param context The CoAP context whose event handler is to be called.
* @param event The event to deliver.
* @param session The session related to @p event.
* @return The result from the associated event handler or 0 if none was
* registered.
*/
int coap_handle_event(coap_context_t *context,
coap_event_t event,
coap_session_t *session);
/**
* 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 session The session to look for.
* @param id The transaction 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_session_t *session,
coap_tid_t id,
coap_queue_t **node);
coap_tid_t
coap_wait_ack( coap_context_t *context, coap_session_t *session,
coap_queue_t *node);
/**
* Retrieves transaction from the queue.
*
* @param queue The transaction queue to be searched.
* @param session The session to find.
* @param id The transaction id to find.
*
* @return A pointer to the transaction object or @c NULL if not found.
*/
coap_queue_t *coap_find_transaction(coap_queue_t *queue, coap_session_t *session, coap_tid_t id);
/**
* Cancels all outstanding messages for session @p session that have the specified
* token.
*
* @param context The context in use.
* @param session Session 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,
coap_session_t *session,
const uint8_t *token,
size_t token_length);
/**
* Cancels all outstanding messages for session @p session.
*
* @param context The context in use.
* @param session Session of the messages to remove.
* @param reason The reasion for the session cancellation
*/
void
coap_cancel_session_messages(coap_context_t *context,
coap_session_t *session,
coap_nack_reason_t reason);
/**
* Dispatches the PDUs from the receive queue in given context.
*/
void coap_dispatch(coap_context_t *context, coap_session_t *session,
coap_pdu_t *pdu);
/**
* 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);
/**
* Creates a new response for given @p request with the contents of @c
* .well-known/core. The result is NULL on error or a newly allocated PDU that
* must be either sent with coap_sent() or released by coap_delete_pdu().
*
* @param context The current coap context to use.
* @param session The CoAP session.
* @param request The request for @c .well-known/core .
*
* @return A new 2.05 response for @c .well-known/core or NULL on error.
*/
coap_pdu_t *coap_wellknown_response(coap_context_t *context,
coap_session_t *session,
coap_pdu_t *request);
/**
* Calculates the initial timeout based on the session CoAP transmission
* parameters 'ack_timeout', 'ack_random_factor', and COAP_TICKS_PER_SECOND.
* The calculation requires 'ack_timeout' and 'ack_random_factor' to be in
* Qx.FRAC_BITS fixed point notation, whereas the passed parameter @p r
* is interpreted as the fractional part of a Q0.MAX_BITS random value.
*
* @param session session timeout is associated with
* @param r random value as fractional part of a Q0.MAX_BITS fixed point
* value
* @return COAP_TICKS_PER_SECOND * 'ack_timeout' *
* (1 + ('ack_random_factor' - 1) * r)
*/
unsigned int coap_calc_timeout(coap_session_t *session, unsigned char r);
#endif /* COAP_NET_H_ */

View File

@ -12,8 +12,8 @@
* @brief Helpers for handling options in CoAP PDUs
*/
#ifndef _COAP_OPTION_H_
#define _COAP_OPTION_H_
#ifndef COAP_OPTION_H_
#define COAP_OPTION_H_
#include "bits.h"
#include "pdu.h"
@ -22,14 +22,16 @@
* 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;
typedef uint8_t coap_opt_t;
#define PCHAR(p) ((coap_opt_t *)(p))
/** Representation of CoAP options. */
/**
* Representation of CoAP options.
*/
typedef struct {
unsigned short delta;
uint16_t delta;
size_t length;
unsigned char *value;
const uint8_t *value;
} coap_option_t;
/**
@ -59,27 +61,9 @@ size_t coap_opt_parse(const coap_opt_t *opt,
*/
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
* API functions for access option filters
* @{
*/
@ -106,7 +90,7 @@ coap_opt_t *options_start(coap_pdu_t *pdu);
#endif /* (COAP_OPT_FILTER_SHORT + COAP_OPT_FILTER_LONG > 16) */
/** The number of elements in coap_opt_filter_t. */
#define COAP_OPT_FILTER_SIZE \
#define COAP_OPT_FILTER_SIZE \
(((COAP_OPT_FILTER_SHORT + 1) >> 1) + COAP_OPT_FILTER_LONG) +1
/**
@ -142,7 +126,7 @@ typedef uint16_t coap_opt_filter_t[COAP_OPT_FILTER_SIZE];
*
* @param f The filter to clear.
*/
static inline void
COAP_STATIC_INLINE void
coap_option_filter_clear(coap_opt_filter_t f) {
memset(f, 0, sizeof(coap_opt_filter_t));
}
@ -157,7 +141,7 @@ coap_option_filter_clear(coap_opt_filter_t f) {
*
* @return @c 1 if bit was set, @c 0 otherwise.
*/
int coap_option_filter_set(coap_opt_filter_t filter, unsigned short type);
int coap_option_filter_set(coap_opt_filter_t filter, uint16_t type);
/**
* Clears the corresponding entry for @p type in @p filter. This
@ -169,7 +153,7 @@ int coap_option_filter_set(coap_opt_filter_t filter, unsigned short type);
*
* @return @c 1 if bit was set, @c 0 otherwise.
*/
int coap_option_filter_unset(coap_opt_filter_t filter, unsigned short type);
int coap_option_filter_unset(coap_opt_filter_t filter, uint16_t type);
/**
* Checks if @p type is contained in @p filter. This function returns
@ -181,7 +165,7 @@ int coap_option_filter_unset(coap_opt_filter_t filter, unsigned short type);
*
* @return @c 1 if @p type was found, @c 0 otherwise, or @c -1 on error.
*/
int coap_option_filter_get(const coap_opt_filter_t filter, unsigned short type);
int coap_option_filter_get(coap_opt_filter_t filter, uint16_t type);
/**
* Sets the corresponding bit for @p type in @p filter. This function returns @c
@ -195,8 +179,8 @@ int coap_option_filter_get(const coap_opt_filter_t filter, unsigned short type);
*
* @return @c 1 if bit was set, @c -1 otherwise.
*/
inline static int
coap_option_setb(coap_opt_filter_t filter, unsigned short type) {
COAP_STATIC_INLINE int
coap_option_setb(coap_opt_filter_t filter, uint16_t type) {
return coap_option_filter_set(filter, type) ? 1 : -1;
}
@ -212,8 +196,8 @@ coap_option_setb(coap_opt_filter_t filter, unsigned short type) {
*
* @return @c 1 if bit was set, @c -1 otherwise.
*/
inline static int
coap_option_clrb(coap_opt_filter_t filter, unsigned short type) {
COAP_STATIC_INLINE int
coap_option_clrb(coap_opt_filter_t filter, uint16_t type) {
return coap_option_filter_unset(filter, type) ? 1 : -1;
}
@ -229,8 +213,8 @@ coap_option_clrb(coap_opt_filter_t filter, unsigned short type) {
*
* @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) {
COAP_STATIC_INLINE int
coap_option_getb(coap_opt_filter_t filter, uint16_t type) {
return coap_option_filter_get(filter, type);
}
@ -252,7 +236,7 @@ coap_option_getb(const coap_opt_filter_t filter, unsigned short type) {
*/
typedef struct {
size_t length; /**< remaining length of PDU */
unsigned short type; /**< decoded option type */
uint16_t 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 */
@ -275,7 +259,7 @@ typedef struct {
*
* @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 *coap_option_iterator_init(const coap_pdu_t *pdu,
coap_opt_iterator_t *oi,
const coap_opt_filter_t filter);
@ -311,7 +295,7 @@ coap_opt_t *coap_option_next(coap_opt_iterator_t *oi);
* not found.
*/
coap_opt_t *coap_check_option(coap_pdu_t *pdu,
unsigned short type,
uint16_t type,
coap_opt_iterator_t *oi);
/**
@ -330,9 +314,20 @@ coap_opt_t *coap_check_option(coap_pdu_t *pdu,
*/
size_t coap_opt_setheader(coap_opt_t *opt,
size_t maxlen,
unsigned short delta,
uint16_t delta,
size_t length);
/**
* Compute storage bytes needed for an option with given @p delta and
* @p length
*
* @param delta The option delta.
* @param length The option length.
*
* @return The number of bytes required to encode this option.
*/
size_t coap_opt_encode_size(uint16_t 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
@ -350,8 +345,8 @@ size_t coap_opt_setheader(coap_opt_t *opt,
*/
size_t coap_opt_encode(coap_opt_t *opt,
size_t n,
unsigned short delta,
const unsigned char *val,
uint16_t delta,
const uint8_t *val,
size_t length);
/**
@ -364,14 +359,7 @@ size_t coap_opt_encode(coap_opt_t *opt,
*
* @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)
uint16_t coap_opt_delta(const coap_opt_t *opt);
/**
* Returns the length of the given option. @p opt must point to an option jump
@ -386,10 +374,7 @@ unsigned short coap_opt_delta(const coap_opt_t *opt);
*
* @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)
uint16_t coap_opt_length(const coap_opt_t *opt);
/**
* Returns a pointer to the value of the given option. @p opt must point to an
@ -400,11 +385,77 @@ unsigned short coap_opt_length(const coap_opt_t *opt);
*
* @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)
const uint8_t *coap_opt_value(const coap_opt_t *opt);
/** @} */
#endif /* _OPTION_H_ */
/**
* Representation of chained list of CoAP options to install.
*
* @code
* coap_optlist_t *optlist_chain = NULL;
* coap_pdu_t *pdu = coap_new_pdu(session);
*
* ... other set up code ...
* coap_insert_optlist(&optlist_chain, coap_new_optlist(COAP_OPTION_OBSERVE,
* COAP_OBSERVE_ESTABLISH, NULL));
*
* coap_add_optlist_pdu(pdu, &optlist_chain);
* ... other code ...
* coap_delete_optlist(optlist_chain);
* @endcode
*/
typedef struct coap_optlist_t {
struct coap_optlist_t *next; /**< next entry in the optlist chain */
uint16_t number; /**< the option number (no delta coding) */
size_t length; /**< the option value length */
uint8_t *data; /**< the option data */
} coap_optlist_t;
/**
* Create a new optlist entry.
*
* @param number The option number (COAP_OPTION_*)
* @param length The option length
* @param data The option value data
*
* @return A pointer to the new optlist entry, or @c NULL if error
*/
coap_optlist_t *coap_new_optlist(uint16_t number,
size_t length,
const uint8_t *data);
/**
* The current optlist of @p optlist_chain is first sorted (as per RFC7272
* ordering requirements) and then added to the @p pdu.
*
* @param pdu The pdu to add the options to from the chain list
* @param optlist_chain The chained list of optlist to add to the pdu
*
* @return @c 1 if succesful or @c 0 if failure;
*/
int coap_add_optlist_pdu(coap_pdu_t *pdu, coap_optlist_t** optlist_chain);
/**
* Adds @p optlist to the given @p optlist_chain. The optlist_chain variable
* be set to NULL before the initial call to coap_insert_optlist().
* The optlist_chain will need to be deleted using coap_delete_optlist()
* when no longer required.
*
* @param optlist_chain The chain to add optlist to
* @param optlist The optlist to add to the queue
*
* @return @c 1 if successful, @c 0 otherwise.
*/
int coap_insert_optlist(coap_optlist_t **optlist_chain,
coap_optlist_t *optlist);
/**
* Removes all entries from the @p optlist_chain, freeing off their
* memory usage.
*
* @param optlist_chain The optlist chain to remove all the entries from
*/
void coap_delete_optlist(coap_optlist_t *optlist_chain);
#endif /* COAP_OPTION_H_ */

View File

@ -0,0 +1,543 @@
/*
* pdu.h -- CoAP message structure
*
* 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.
*/
/**
* @file pdu.h
* @brief Pre-defined constants that reflect defaults for CoAP
*/
#ifndef COAP_PDU_H_
#define COAP_PDU_H_
#include "uri.h"
struct coap_session_t;
#ifdef WITH_LWIP
#include <lwip/pbuf.h>
#endif
#include <stdint.h>
#define COAP_DEFAULT_PORT 5683 /* CoAP default UDP/TCP port */
#define COAPS_DEFAULT_PORT 5684 /* CoAP default UDP/TCP port for secure transmission */
#define COAP_DEFAULT_MAX_AGE 60 /* default maximum object lifetime in seconds */
#ifndef COAP_DEFAULT_MTU
#define COAP_DEFAULT_MTU 1152
#endif /* COAP_DEFAULT_MTU */
/* TCP Message format constants, do not modify */
#define COAP_MESSAGE_SIZE_OFFSET_TCP8 13
#define COAP_MESSAGE_SIZE_OFFSET_TCP16 269 /* 13 + 256 */
#define COAP_MESSAGE_SIZE_OFFSET_TCP32 65805 /* 269 + 65536 */
/* Derived message size limits */
#define COAP_MAX_MESSAGE_SIZE_TCP0 (COAP_MESSAGE_SIZE_OFFSET_TCP8-1) /* 12 */
#define COAP_MAX_MESSAGE_SIZE_TCP8 (COAP_MESSAGE_SIZE_OFFSET_TCP16-1) /* 268 */
#define COAP_MAX_MESSAGE_SIZE_TCP16 (COAP_MESSAGE_SIZE_OFFSET_TCP32-1) /* 65804 */
#define COAP_MAX_MESSAGE_SIZE_TCP32 (COAP_MESSAGE_SIZE_OFFSET_TCP32+0xFFFFFFFF)
#ifndef COAP_DEFAULT_MAX_PDU_RX_SIZE
#if defined(WITH_CONTIKI) || defined(WITH_LWIP)
#define COAP_DEFAULT_MAX_PDU_RX_SIZE (COAP_MAX_MESSAGE_SIZE_TCP16+4)
#else
/* 8 MiB max-message-size plus some space for options */
#define COAP_DEFAULT_MAX_PDU_RX_SIZE (8*1024*1024+256)
#endif
#endif /* COAP_DEFAULT_MAX_PDU_RX_SIZE */
#ifndef COAP_DEBUG_BUF_SIZE
#if defined(WITH_CONTIKI) || defined(WITH_LWIP)
#define COAP_DEBUG_BUF_SIZE 128
#else /* defined(WITH_CONTIKI) || defined(WITH_LWIP) */
/* 1024 derived from RFC7252 4.6. Message Size max payload */
#define COAP_DEBUG_BUF_SIZE (8 + 1024 * 2)
#endif /* defined(WITH_CONTIKI) || defined(WITH_LWIP) */
#endif /* COAP_DEBUG_BUF_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"
/* 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
#define COAP_REQUEST_FETCH 5 /* RFC 8132 */
#define COAP_REQUEST_PATCH 6 /* RFC 8132 */
#define COAP_REQUEST_IPATCH 7 /* RFC 8132 */
/*
* CoAP option types (be sure to update coap_option_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_SIZE2 28 /* E, uint, 0-4 B, (none) */
#define COAP_OPTION_PROXY_URI 35 /* C, String, 1-1034 B, (none) */
#define COAP_OPTION_PROXY_SCHEME 39 /* C, String, 1-255 B, (none) */
#define COAP_OPTION_SIZE1 60 /* E, uint, 0-4 B, (none) */
/* option types from RFC 7641 */
#define COAP_OPTION_OBSERVE 6 /* E, empty/uint, 0 B/0-3 B, (none) */
#define COAP_OPTION_SUBSCRIPTION COAP_OPTION_OBSERVE
/* selected option types from RFC 7959 */
#define COAP_OPTION_BLOCK2 23 /* C, uint, 0--3 B, (none) */
#define COAP_OPTION_BLOCK1 27 /* C, uint, 0--3 B, (none) */
/* selected option types from RFC 7967 */
#define COAP_OPTION_NORESPONSE 258 /* N, uint, 0--1 B, 0 */
#define COAP_MAX_OPT 65535 /**< 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.
*/
const 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 */
#define COAP_SIGNALING_CODE(N) (((N)/100 << 5) | (N)%100)
#define COAP_SIGNALING_CSM COAP_SIGNALING_CODE(701)
#define COAP_SIGNALING_PING COAP_SIGNALING_CODE(702)
#define COAP_SIGNALING_PONG COAP_SIGNALING_CODE(703)
#define COAP_SIGNALING_RELEASE COAP_SIGNALING_CODE(704)
#define COAP_SIGNALING_ABORT COAP_SIGNALING_CODE(705)
/* Applies to COAP_SIGNALING_CSM */
#define COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE 2
#define COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER 4
/* Applies to COAP_SIGNALING_PING / COAP_SIGNALING_PONG */
#define COAP_SIGNALING_OPTION_CUSTODY 2
/* Applies to COAP_SIGNALING_RELEASE */
#define COAP_SIGNALING_OPTION_ALTERNATIVE_ADDRESS 2
#define COAP_SIGNALING_OPTION_HOLD_OFF 4
/* Applies to COAP_SIGNALING_ABORT */
#define COAP_SIGNALING_OPTION_BAD_CSM_OPTION 2
/* 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 */
#define COAP_MEDIATYPE_APPLICATION_CBOR 60 /* application/cbor */
/* Content formats from RFC 8152 */
#define COAP_MEDIATYPE_APPLICATION_COSE_SIGN 98 /* application/cose; cose-type="cose-sign" */
#define COAP_MEDIATYPE_APPLICATION_COSE_SIGN1 18 /* application/cose; cose-type="cose-sign1" */
#define COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT 96 /* application/cose; cose-type="cose-encrypt" */
#define COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT0 16 /* application/cose; cose-type="cose-encrypt0" */
#define COAP_MEDIATYPE_APPLICATION_COSE_MAC 97 /* application/cose; cose-type="cose-mac" */
#define COAP_MEDIATYPE_APPLICATION_COSE_MAC0 17 /* application/cose; cose-type="cose-mac0" */
#define COAP_MEDIATYPE_APPLICATION_COSE_KEY 101 /* application/cose-key */
#define COAP_MEDIATYPE_APPLICATION_COSE_KEY_SET 102 /* application/cose-key-set */
/* Content formats from RFC 8428 */
#define COAP_MEDIATYPE_APPLICATION_SENML_JSON 110 /* application/senml+json */
#define COAP_MEDIATYPE_APPLICATION_SENSML_JSON 111 /* application/sensml+json */
#define COAP_MEDIATYPE_APPLICATION_SENML_CBOR 112 /* application/senml+cbor */
#define COAP_MEDIATYPE_APPLICATION_SENSML_CBOR 113 /* application/sensml+cbor */
#define COAP_MEDIATYPE_APPLICATION_SENML_EXI 114 /* application/senml-exi */
#define COAP_MEDIATYPE_APPLICATION_SENSML_EXI 115 /* application/sensml-exi */
#define COAP_MEDIATYPE_APPLICATION_SENML_XML 310 /* application/senml+xml */
#define COAP_MEDIATYPE_APPLICATION_SENSML_XML 311 /* application/sensml+xml */
/* 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_tid_t is used to store CoAP transaction id, i.e. a hash value
* built from the remote transport address and the message id of a
* CoAP PDU. Valid transaction ids are greater or equal zero.
*/
typedef int coap_tid_t;
/** Indicates an invalid transaction id. */
#define COAP_INVALID_TID -1
/**
* Indicates that a response is suppressed. This will occur for error
* responses if the request was received via IP multicast.
*/
#define COAP_DROPPED_RESPONSE -2
#define COAP_PDU_DELAYED -3
#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 */
/**
* @deprecated Use coap_optlist_t instead.
*
* Structures for more convenient handling of options. (To be used with ordered
* coap_list_t.) The option's data will be added to the end of the coap_option
* structure (see macro COAP_OPTION_DATA).
*/
COAP_DEPRECATED typedef struct {
uint16_t 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))
/**
* structure for CoAP PDUs
* token, if any, follows the fixed size header, then options until
* payload marker (0xff), then the payload if stored inline.
* Memory layout is:
* <---header--->|<---token---><---options--->0xff<---payload--->
* header is addressed with a negative offset to token, its maximum size is
* max_hdr_size.
* options starts at token + token_length
* payload starts at data, its length is used_size - (data - token)
*/
typedef struct coap_pdu_t {
uint8_t type; /**< message type */
uint8_t code; /**< request method (value 1--10) or response code (value 40-255) */
uint8_t max_hdr_size; /**< space reserved for protocol-specific header */
uint8_t hdr_size; /**< actaul size used for protocol-specific header */
uint8_t token_length; /**< length of Token */
uint16_t tid; /**< transaction id, if any, in regular host byte order */
uint16_t max_delta; /**< highest option number */
size_t alloc_size; /**< allocated storage for token, options and payload */
size_t used_size; /**< used bytes of storage for token, options and payload */
size_t max_size; /**< maximum size for token, options and payload, or zero for variable size pdu */
uint8_t *token; /**< first byte of token, if any, or options */
uint8_t *data; /**< first byte of payload, if any */
#ifdef WITH_LWIP
struct pbuf *pbuf; /**< lwIP PBUF. The package data will always reside
* inside the pbuf's payload, but this pointer
* has to be kept because no exact offset can be
* given. This field must not be accessed from
* outside, because the pbuf's reference count
* is checked to be 1 when the pbuf is assigned
* to the pdu, and the pbuf stays exclusive to
* this pdu. */
#endif
} coap_pdu_t;
#define COAP_PDU_IS_EMPTY(pdu) ((pdu)->code == 0)
#define COAP_PDU_IS_REQUEST(pdu) (!COAP_PDU_IS_EMPTY(pdu) && (pdu)->code < 32)
#define COAP_PDU_IS_RESPONSE(pdu) ((pdu)->code >= 64 && (pdu)->code < 224)
#define COAP_PDU_IS_SIGNALING(pdu) ((pdu)->code >= 224)
#define COAP_PDU_MAX_UDP_HEADER_SIZE 4
#define COAP_PDU_MAX_TCP_HEADER_SIZE 6
#ifdef WITH_LWIP
/**
* Creates a CoAP PDU from an lwIP @p pbuf, whose reference is passed on to this
* function.
*
* The pbuf is checked for being contiguous, and for having only one reference.
* The reference is stored in the PDU and will be freed when the PDU is freed.
*
* (For now, these are fatal errors; in future, a new pbuf might be allocated,
* the data copied and the passed pbuf freed).
*
* This behaves like coap_pdu_init(0, 0, 0, pbuf->tot_len), and afterwards
* copying the contents of the pbuf to the pdu.
*
* @return A pointer to the new PDU object or @c NULL on error.
*/
coap_pdu_t * coap_pdu_from_pbuf(struct pbuf *pbuf);
#endif
typedef uint8_t coap_proto_t;
/**
* coap_proto_t values
*/
#define COAP_PROTO_NONE 0
#define COAP_PROTO_UDP 1
#define COAP_PROTO_DTLS 2
#define COAP_PROTO_TCP 3
#define COAP_PROTO_TLS 4
/**
* Creates a new CoAP PDU with at least enough storage space for the given
* @p size maximum message size. 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() if coap_send() is not
* called.
*
* @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 tid The transcation id to set or 0 if unknown / not applicable.
* @param size The maximum allowed number of byte for the message.
* @return A pointer to the new PDU object or @c NULL on error.
*/
coap_pdu_t *
coap_pdu_init(uint8_t type, uint8_t code, uint16_t tid, size_t size);
/**
* Dynamically grows the size of @p pdu to @p new_size. The new size
* must not exceed the PDU's configure maximum size. On success, this
* function returns 1, otherwise 0.
*
* @param pdu The PDU to resize.
* @param new_size The new size in bytes.
* @return 1 if the operation succeeded, 0 otherwise.
*/
int coap_pdu_resize(coap_pdu_t *pdu, size_t new_size);
/**
* Clears any contents from @p pdu and resets @c used_size,
* and @c data pointers. @c max_size is set to @p size, any
* 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.
*/
coap_pdu_t *coap_new_pdu(const struct coap_session_t *session);
/**
* Dispose of an CoAP PDU and frees associated storage.
* Not that in general you should not call this function directly.
* When a PDU is sent with coap_send(), coap_delete_pdu() will be
* called automatically for you.
*/
void coap_delete_pdu(coap_pdu_t *);
/**
* Interprets @p data to determine the number of bytes in the header.
* This function returns @c 0 on error or a number greater than zero on success.
*
* @param proto Session's protocol
* @param data The first byte of raw data to parse as CoAP PDU.
*
* @return A value greater than zero on success or @c 0 on error.
*/
size_t coap_pdu_parse_header_size(coap_proto_t proto,
const uint8_t *data);
/**
* Parses @p data to extract the message size.
* @p length must be at least coap_pdu_parse_header_size(proto, data).
* This function returns @c 0 on error or a number greater than zero on success.
*
* @param proto Session's protocol
* @param data The raw data to parse as CoAP PDU.
* @param length The actual size of @p data.
*
* @return A value greater than zero on success or @c 0 on error.
*/
size_t coap_pdu_parse_size(coap_proto_t proto,
const uint8_t *data,
size_t length);
/**
* Decode the protocol specific header for the specified PDU.
* @param pdu A newly received PDU.
* @param proto The target wire protocol.
* @return 1 for success or 0 on error.
*/
int coap_pdu_parse_header(coap_pdu_t *pdu, coap_proto_t proto);
/**
* Verify consistency in the given CoAP PDU structure and locate the data.
* This function returns @c 0 on error or a number greater than zero on
* success.
* This function only parses the token and options, up to the payload start
* marker.
*
* @param pdu The PDU structure to.
*
* @return 1 on success or @c 0 on error.
*/
int coap_pdu_parse_opt(coap_pdu_t *pdu);
/**
* Parses @p data into the CoAP PDU structure given in @p result.
* The target pdu must be large enough to
* This function returns @c 0 on error or a number greater than zero on success.
*
* @param proto Session's protocol
* @param data The raw data to parse as CoAP PDU.
* @param length The actual size of @p data.
* @param pdu The PDU structure to fill. Note that the structure must
* provide space to hold at least the token and options
* part of the message.
*
* @return 1 on success or @c 0 on error.
*/
int coap_pdu_parse(coap_proto_t proto,
const uint8_t *data,
size_t length,
coap_pdu_t *pdu);
/**
* 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 function
* 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 uint8_t *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,
uint16_t type,
size_t len,
const uint8_t *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.
*/
uint8_t *coap_add_option_later(coap_pdu_t *pdu,
uint16_t type,
size_t 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,
size_t len,
const uint8_t *data);
/**
* Adds given data to the pdu that is passed as first parameter but does not
* copyt it. Note that the PDU's data is destroyed by coap_add_option().
* coap_add_data() must be have been called once for this PDU, otherwise the
* result is undefined.
* The actual data must be copied at the returned location.
*/
uint8_t *coap_add_data_after(coap_pdu_t *pdu, size_t len);
/**
* 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(const coap_pdu_t *pdu,
size_t *len,
uint8_t **data);
/**
* Compose the protocol specific header for the specified PDU.
* @param pdu A newly composed PDU.
* @param proto The target wire protocol.
* @return Number of header bytes prepended before pdu->token or 0 on error.
*/
size_t coap_pdu_encode_header(coap_pdu_t *pdu, coap_proto_t proto);
#endif /* COAP_PDU_H_ */

View File

@ -12,31 +12,16 @@
* @brief Pseudo Random Numbers
*/
#ifndef _COAP_PRNG_H_
#define _COAP_PRNG_H_
#ifndef COAP_PRNG_H_
#define COAP_PRNG_H_
/**
* @defgroup prng Pseudo Random Numbers
* API functions for gerating pseudo random numbers
* @{
*/
#if defined(WITH_POSIX) || (defined(WITH_LWIP) && !defined(LWIP_RAND))
#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;
}
#endif /* WITH_POSIX */
#ifdef WITH_CONTIKI
#if defined(WITH_CONTIKI)
#include <string.h>
/**
@ -44,9 +29,9 @@ coap_prng_impl(unsigned char *buf, size_t len) {
* prng(). You might want to change prng() to use a better PRNG on your specific
* platform.
*/
static inline int
COAP_STATIC_INLINE int
contiki_prng_impl(unsigned char *buf, size_t len) {
unsigned short v = random_rand();
uint16_t v = random_rand();
while (len > sizeof(v)) {
memcpy(buf, &v, sizeof(v));
len -= sizeof(v);
@ -59,11 +44,9 @@ contiki_prng_impl(unsigned char *buf, size_t len) {
}
#define prng(Buf,Length) contiki_prng_impl((Buf), (Length))
#define prng_init(Value) random_init((unsigned short)(Value))
#endif /* WITH_CONTIKI */
#if defined(WITH_LWIP) && defined(LWIP_RAND)
static inline int
#define prng_init(Value) random_init((uint16_t)(Value))
#elif defined(WITH_LWIP) && defined(LWIP_RAND)
COAP_STATIC_INLINE int
lwip_prng_impl(unsigned char *buf, size_t len) {
u32_t v = LWIP_RAND();
while (len > sizeof(v)) {
@ -79,8 +62,46 @@ lwip_prng_impl(unsigned char *buf, size_t len) {
#define prng(Buf,Length) lwip_prng_impl((Buf), (Length))
#define prng_init(Value)
#elif defined(_WIN32)
#define prng_init(Value)
errno_t __cdecl rand_s( _Out_ unsigned int* _RandomValue );
/**
* 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.
*/
COAP_STATIC_INLINE int
coap_prng_impl( unsigned char *buf, size_t len ) {
while ( len != 0 ) {
uint32_t r = 0;
size_t i;
if ( rand_s( &r ) != 0 )
return 0;
for ( i = 0; i < len && i < 4; i++ ) {
*buf++ = (uint8_t)r;
r >>= 8;
}
len -= i;
}
return 1;
}
#else
#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.
*/
COAP_STATIC_INLINE int
coap_prng_impl( unsigned char *buf, size_t len ) {
while ( len-- )
*buf++ = rand() & 0xFF;
return 1;
}
#endif
#endif /* WITH_LWIP */
#ifndef prng
/**
@ -103,4 +124,4 @@ lwip_prng_impl(unsigned char *buf, size_t len) {
/** @} */
#endif /* _COAP_PRNG_H_ */
#endif /* COAP_PRNG_H_ */

View File

@ -0,0 +1,524 @@
/*
* resource.h -- generic resource handling
*
* Copyright (C) 2010,2011,2014,2015 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 <assert.h>
#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 */
#include "uthash.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_session_t *,
coap_pdu_t *,
coap_binary_t * /* token */,
coap_string_t * /* query string */,
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;
coap_str_const_t *name;
coap_str_const_t *value;
int flags;
} coap_attr_t;
/** The URI passed to coap_resource_init() is free'd by coap_delete_resource(). */
#define COAP_RESOURCE_FLAGS_RELEASE_URI 0x1
/**
* Notifications will be sent non-confirmable by default. RFC 7641 Section 4.5
* https://tools.ietf.org/html/rfc7641#section-4.5
*/
#define COAP_RESOURCE_FLAGS_NOTIFY_NON 0x0
/**
* Notifications will be sent confirmable by default. RFC 7641 Section 4.5
* https://tools.ietf.org/html/rfc7641#section-4.5
*/
#define COAP_RESOURCE_FLAGS_NOTIFY_CON 0x2
typedef struct coap_resource_t {
unsigned int dirty:1; /**< set to 1 if resource has changed */
unsigned int partiallydirty:1; /**< set to 1 if some subscribers have not yet
* been notified of the last change */
unsigned int observable:1; /**< can be observed */
unsigned int cacheable:1; /**< can be cached */
unsigned int is_unknown:1; /**< resource created for unknown handler */
/**
* Used to store handlers for the seven coap methods @c GET, @c POST, @c PUT,
* @c DELETE, @c FETCH, @c PATCH and @c IPATCH.
* 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[7];
UT_hash_handle hh;
coap_attr_t *link_attr; /**< attributes to be included with the link format */
coap_subscription_t *subscribers; /**< list of observers for this resource */
/**
* Request URI Path for this resource. This field will point into static
* or allocated memory which must remain there for the duration of the
* resource.
*/
coap_str_const_t *uri_path; /**< the key used for hash lookup for this resource */
int flags;
/**
* The next value for the Observe option. This field must be increased each
* time the resource changes. Only the lower 24 bits are sent.
*/
unsigned int observe;
/**
* This pointer is under user control. It can be used to store context for
* the coap handler.
*/
void *user_data;
} coap_resource_t;
/**
* Creates a new resource object and initializes the link field to the string
* @p uri_path. This function returns the new coap_resource_t object.
*
* If the string is going to be freed off by coap_delete_resource() when
* COAP_RESOURCE_FLAGS_RELEASE_URI is set in @p flags, then either the 's'
* variable of coap_str_const_t has to point to constant text, or point to data
* within the allocated coap_str_const_t parameter.
*
* @param uri_path The string URI path of the new resource.
* @param flags Flags for memory management (in particular release of
* memory). Possible values:@n
*
* COAP_RESOURCE_FLAGS_RELEASE_URI
* If this flag is set, the URI passed to
* coap_resource_init() is free'd by
* coap_delete_resource()@n
*
* COAP_RESOURCE_FLAGS_NOTIFY_CON
* If this flag is set, coap-observe notifications
* will be sent confirmable by default.@n
*
* COAP_RESOURCE_FLAGS_NOTIFY_NON (default)
* If this flag is set, coap-observe notifications
* will be sent non-confirmable by default.@n
*
* If flags is set to 0 then the
* COAP_RESOURCE_FLAGS_NOTIFY_NON is considered.
*
* @return A pointer to the new object or @c NULL on error.
*/
coap_resource_t *coap_resource_init(coap_str_const_t *uri_path,
int flags);
/**
* Creates a new resource object for the unknown resource handler with support
* for PUT.
*
* In the same way that additional handlers can be added to the resource
* created by coap_resource_init() by using coap_register_handler(), POST,
* GET, DELETE etc. handlers can be added to this resource. It is the
* responsibility of the application to manage the unknown resources by either
* creating new resources with coap_resource_init() (which should have a
* DELETE handler specified for the resource removal) or by maintaining an
* active resource list.
*
* Note: There can only be one unknown resource handler per context - attaching
* a new one overrides the previous definition.
*
* Note: It is not possible to observe the unknown resource with a GET request
* - a separate resource needs to be reated by the PUT (or POST) handler,
* and make that resource observable.
*
* This function returns the new coap_resource_t object.
*
* @param put_handler The PUT handler to register with @p resource for
* unknown Uri-Path.
*
* @return A pointer to the new object or @c NULL on error.
*/
coap_resource_t *coap_resource_unknown_init(coap_method_handler_t put_handler);
/**
* Sets the notification message type of resource @p resource to given
* @p mode
* @param resource The resource to update.
* @param mode Must be one of @c COAP_RESOURCE_FLAGS_NOTIFY_NON
* or @c COAP_RESOURCE_FLAGS_NOTIFY_CON.
*/
COAP_STATIC_INLINE void
coap_resource_set_mode(coap_resource_t *resource, int mode) {
resource->flags = (resource->flags &
~(COAP_RESOURCE_FLAGS_NOTIFY_CON|COAP_RESOURCE_FLAGS_NOTIFY_NON)) |
(mode & (COAP_RESOURCE_FLAGS_NOTIFY_CON|COAP_RESOURCE_FLAGS_NOTIFY_NON));
}
/**
* Sets the user_data. The user_data is exclusively used by the library-user
* and can be used as context in the handler functions.
*
* @param r Resource to attach the data to
* @param data Data to attach to the user_data field. This pointer is only used for
* storage, the data remains under user control
*/
COAP_STATIC_INLINE void
coap_resource_set_userdata(coap_resource_t *r, void *data) {
r->user_data = data;
}
/**
* Gets the user_data. The user_data is exclusively used by the library-user
* and can be used as context in the handler functions.
*
* @param r Resource to retrieve the user_darta from
*
* @return The user_data pointer
*/
COAP_STATIC_INLINE void *
coap_resource_get_userdata(coap_resource_t *r) {
return r->user_data;
}
/**
* Registers the given @p resource for @p context. The resource must have been
* created by coap_resource_init() or coap_resource_unknown_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 resource. The storage allocated for that
* resource is freed, and removed from the context.
*
* @param context The context where the resources are stored.
* @param resource 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_resource_t *resource);
/**
* Deletes all resources from given @p context and frees their storage.
*
* @param context The CoAP context with the resources to be deleted.
*/
void coap_delete_all_resources(coap_context_t *context);
/**
* Registers a new attribute with the given @p resource. As the
* attribute's coap_str_const_ fields will point to @p name and @p value the
* caller must ensure that these pointers are valid during the
* attribute's lifetime.
* If the @p name and/or @p value string is going to be freed off at attribute
* removal time by the setting of COAP_ATTR_FLAGS_RELEASE_NAME or
* COAP_ATTR_FLAGS_RELEASE_VALUE in @p flags, then either the 's'
* variable of coap_str_const_t has to point to constant text, or point to data
* within the allocated coap_str_const_t parameter.
*
* @param resource The resource to register the attribute with.
* @param name The attribute's name as a string.
* @param value The attribute's value as a string or @c NULL if none.
* @param flags Flags for memory management (in particular release of
* memory). Possible values:@n
*
* COAP_ATTR_FLAGS_RELEASE_NAME
* If this flag is set, the name passed to
* coap_add_attr_release() is free'd
* when the attribute is deleted@n
*
* COAP_ATTR_FLAGS_RELEASE_VALUE
* If this flag is set, the value passed to
* coap_add_attr_release() is free'd
* when the attribute is deleted@n
*
* @return A pointer to the new attribute or @c NULL on error.
*/
coap_attr_t *coap_add_attr(coap_resource_t *resource,
coap_str_const_t *name,
coap_str_const_t *value,
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 as a string.
* @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,
coap_str_const_t *name);
/**
* Deletes an attribute.
* Note: This is for internal use only, as it is not deleted from its chain.
*
* @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.
*/
void coap_register_handler(coap_resource_t *resource,
unsigned char method,
coap_method_handler_t handler);
/**
* Returns the resource identified by the unique string @p uri_path. If no
* resource was found, this function returns @c NULL.
*
* @param context The context to look for this resource.
* @param uri_path The unique string uri of the resource.
*
* @return A pointer to the resource or @c NULL if not found.
*/
coap_resource_t *coap_get_resource_from_uri_path(coap_context_t *context,
coap_str_const_t *uri_path);
/**
* @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 session The observer's session
* @param token The token that identifies this subscription.
* @param query The query string, if any. subscription will
take ownership of the string.
* @param has_block2 If Option Block2 defined.
* @param block2 Contents of Block2 if Block 2 defined.
* @return A pointer to the added/updated subscription
* information or @c NULL on error.
*/
coap_subscription_t *coap_add_observer(coap_resource_t *resource,
coap_session_t *session,
const coap_binary_t *token,
coap_string_t *query,
int has_block2,
coap_block_t block2);
/**
* Returns a subscription object for given @p peer.
*
* @param resource The observed resource.
* @param session The observer's session
* @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,
coap_session_t *session,
const coap_binary_t *token);
/**
* Marks an observer as alive.
*
* @param context The CoAP context to use.
* @param session The observer's session
* @param token The corresponding token that has been used for the
* subscription.
*/
void coap_touch_observer(coap_context_t *context,
coap_session_t *session,
const coap_binary_t *token);
/**
* Removes any subscription for @p observer from @p resource and releases the
* allocated storage. The result is @c 1 if an observation relationship with @p
* observer and @p token existed, @c 0 otherwise.
*
* @param resource The observed resource.
* @param session The observer's session.
* @param token The token that identifies this subscription or @c NULL for
* any token.
* @return @c 1 if the observer has been deleted, @c 0 otherwise.
*/
int coap_delete_observer(coap_resource_t *resource,
coap_session_t *session,
const coap_binary_t *token);
/**
* Removes any subscription for @p session and releases the allocated storage.
*
* @param context The CoAP context to use.
* @param session The observer's session.
*/
void coap_delete_observers(coap_context_t *context, coap_session_t *session);
/**
* Checks for all known resources, if they are dirty and notifies subscribed
* observers.
*/
void coap_check_notify(coap_context_t *context);
#define RESOURCES_ADD(r, obj) \
HASH_ADD(hh, (r), uri_path->s[0], (obj)->uri_path->length, (obj))
#define RESOURCES_DELETE(r, obj) \
HASH_DELETE(hh, (r), (obj))
#define RESOURCES_ITER(r,tmp) \
coap_resource_t *tmp, *rtmp; \
HASH_ITER(hh, (r), tmp, rtmp)
#define RESOURCES_FIND(r, k, res) { \
HASH_FIND(hh, (r), (k)->s, (k)->length, (res)); \
}
/** @} */
coap_print_status_t coap_print_wellknown(coap_context_t *,
unsigned char *,
size_t *, size_t,
coap_opt_t *);
void
coap_handle_failed_notify(coap_context_t *,
coap_session_t *,
const coap_binary_t *);
/**
* Set whether a @p resource is observable. If the resource is observable
* and the client has set the COAP_OPTION_OBSERVE in a request packet, then
* whenever the state of the resource changes (a call to
* coap_resource_trigger_observe()), an Observer response will get sent.
*
* @param resource The CoAP resource to use.
* @param mode @c 1 if Observable is to be set, @c 0 otherwise.
*
*/
COAP_STATIC_INLINE void
coap_resource_set_get_observable(coap_resource_t *resource, int mode) {
resource->observable = mode ? 1 : 0;
}
/**
* Initiate the sending of an Observe packet for all observers of @p resource,
* optionally matching @p query if not NULL
*
* @param resource The CoAP resource to use.
* @param query The Query to match against or NULL
*
* @return @c 1 if the Observe has been triggered, @c 0 otherwise.
*/
int
coap_resource_notify_observers(coap_resource_t *resource,
const coap_string_t *query);
/**
* Get the UriPath from a @p resource.
*
* @param resource The CoAP resource to check.
*
* @return The UriPath if it exists or @c NULL otherwise.
*/
COAP_STATIC_INLINE coap_str_const_t*
coap_resource_get_uri_path(coap_resource_t *resource) {
if (resource)
return resource->uri_path;
return NULL;
}
/**
* @deprecated use coap_resource_notify_observers() instead.
*/
COAP_DEPRECATED int
coap_resource_set_dirty(coap_resource_t *r,
const coap_string_t *query);
#endif /* COAP_RESOURCE_H_ */

View File

@ -0,0 +1,121 @@
/*
* 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>
/**
* @defgroup string String handling support
* API functions for handling strings
* @{
*/
/**
* Coap string data definition
*/
typedef struct coap_string_t {
size_t length; /**< length of string */
uint8_t *s; /**< string data */
} coap_string_t;
/**
* Coap string data definition with const data
*/
typedef struct coap_str_const_t {
size_t length; /**< length of string */
const uint8_t *s; /**< string data */
} coap_str_const_t;
#define COAP_SET_STR(st,l,v) { (st)->length = (l), (st)->s = (v); }
/**
* Coap binary data definition
*/
typedef struct coap_binary_t {
size_t length; /**< length of binary data */
uint8_t *s; /**< binary data */
} coap_binary_t;
/**
* Returns a new string object with at least size+1 bytes storage allocated.
* The string must be released using coap_delete_string().
*
* @param size The size to allocate for the binary string data.
*
* @return A pointer to the new object or @c NULL on error.
*/
coap_string_t *coap_new_string(size_t size);
/**
* Deletes the given string and releases any memory allocated.
*
* @param string The string to free off.
*/
void coap_delete_string(coap_string_t *string);
/**
* Returns a new const string object with at least size+1 bytes storage
* allocated, and the provided data copied into the string object.
* The string must be released using coap_delete_str_const().
*
* @param data The data to put in the new string object.
* @param size The size to allocate for the binary string data.
*
* @return A pointer to the new object or @c NULL on error.
*/
coap_str_const_t *coap_new_str_const(const uint8_t *data, size_t size);
/**
* Deletes the given const string and releases any memory allocated.
*
* @param string The string to free off.
*/
void coap_delete_str_const(coap_str_const_t *string);
/**
* Take the specified byte array (text) and create a coap_str_const_t *
*
* WARNING: The byte array must be in the local scope and not a
* parameter in the function call as sizeof() will return the size of the
* pointer, not the size of the byte array, leading to unxepected results.
*
* @param string The const byte array to convert to a coap_str_const_t *
*/
#ifdef __cplusplus
namespace libcoap {
struct CoAPStrConst : coap_str_const_t {
operator coap_str_const_t *() { return this; }
};
}
#define coap_make_str_const(CStr) \
libcoap::CoAPStrConst{sizeof(CStr)-1, reinterpret_cast<const uint8_t *>(CStr)}
#else /* __cplusplus */
#define coap_make_str_const(string) \
(&(coap_str_const_t){sizeof(string)-1,(const uint8_t *)(string)})
#endif /* __cplusplus */
/**
* Compares the two strings for equality
*
* @param string1 The first string.
* @param string2 The second string.
*
* @return @c 1 if the strings are equal
* @c 0 otherwise.
*/
#define coap_string_equal(string1,string2) \
((string1)->length == (string2)->length && ((string1)->length == 0 || \
memcmp((string1)->s, (string2)->s, (string1)->length) == 0))
/** @} */
#endif /* COAP_STR_H_ */

View File

@ -1,6 +1,6 @@
/*
* subscribe.h -- subscription handling for CoAP
* see draft-ietf-core-observe-16
* see RFC7641
*
* Copyright (C) 2010-2012,2014-2015 Olaf Bergmann <bergmann@tzi.org>
*
@ -9,14 +9,16 @@
*/
#ifndef _COAP_SUBSCRIBE_H_
#define _COAP_SUBSCRIBE_H_
#ifndef COAP_SUBSCRIBE_H_
#define COAP_SUBSCRIBE_H_
#include "address.h"
#include "coap_io.h"
#include "block.h"
/**
* @defgroup observe Resource observation
* API functions for interfacing with the observe handling (RFC7641)
* @{
*/
@ -53,20 +55,22 @@
/** Subscriber information */
typedef struct coap_subscription_t {
struct coap_subscription_t *next; /**< next element in linked list */
coap_endpoint_t local_if; /**< local communication interface */
coap_address_t subscriber; /**< address and port of subscriber */
coap_session_t *session; /**< subscriber session */
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 partially
* dirty flag is set too) */
unsigned int has_block2:1; /**< GET request had Block2 definition */
coap_block_t block2; /**< GET request Block2 definition */
size_t token_length; /**< actual length of token */
unsigned char token[8]; /**< token used for subscription */
coap_string_t *query; /**< query string used for subscription, if any */
} coap_subscription_t;
void coap_subscription_init(coap_subscription_t *);
/** @} */
#endif /* _COAP_SUBSCRIBE_H_ */
#endif /* COAP_SUBSCRIBE_H_ */

View File

@ -7,24 +7,48 @@
* of use.
*/
#ifndef _COAP_URI_H_
#define _COAP_URI_H_
#ifndef COAP_URI_H_
#define COAP_URI_H_
#include <stdint.h>
#include "hashkey.h"
#include "str.h"
struct coap_pdu_t;
/**
* The scheme specifiers. Secure schemes have an odd numeric value,
* others are even.
*/
enum coap_uri_scheme_t {
COAP_URI_SCHEME_COAP=0,
COAP_URI_SCHEME_COAPS=1,
COAP_URI_SCHEME_COAP_TCP=2,
COAP_URI_SCHEME_COAPS_TCP=3
};
/** This mask can be used to check if a parsed URI scheme is secure. */
#define COAP_URI_SCHEME_SECURE_MASK 0x01
/**
* 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_str_const_t host; /**< host part of the URI */
uint16_t port; /**< The port in host byte order */
coap_str_const_t path; /**< Beginning of the first path segment.
Use coap_split_path() to create Uri-Path options */
coap_str_const_t query; /**< The query part if present */
/** The parsed scheme specifier. */
enum coap_uri_scheme_t scheme;
} coap_uri_t;
static inline int
coap_uri_scheme_is_secure(const coap_uri_t *uri) {
return uri && ((uri->scheme & COAP_URI_SCHEME_SECURE_MASK) != 0);
}
/**
* 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
@ -35,7 +59,7 @@ typedef struct {
*
* @return New URI object or NULL on error.
*/
coap_uri_t *coap_new_uri(const unsigned char *uri, unsigned int length);
coap_uri_t *coap_new_uri(const uint8_t *uri, unsigned int length);
/**
* Clones the specified coap_uri_t object. Thie function allocates sufficient
@ -43,18 +67,6 @@ coap_uri_t *coap_new_uri(const unsigned char *uri, unsigned int length);
* be released with coap_free(). */
coap_uri_t *coap_clone_uri(const coap_uri_t *uri);
/**
* Calculates a hash over the given path and stores the result in
* @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
*
@ -69,53 +81,67 @@ int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key);
* 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.
*
*/
int coap_split_uri(const unsigned char *str_var, size_t len, coap_uri_t *uri);
int coap_split_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri);
/**
* Splits the given URI path into segments. Each segment is preceded
* by an option pseudo-header with delta-value 0 and the actual length
* of the respective segment after percent-decoding.
*
* @param s The path string to split.
*
* @param s The path string to split.
* @param length The actual length of @p s.
* @param buf Result buffer for parsed segments.
* @param buf Result buffer for parsed segments.
* @param buflen Maximum length of @p buf. Will be set to the actual number
* of bytes written into buf on success.
*
*
* @return The number of segments created or @c -1 on error.
*/
int coap_split_path(const unsigned char *s,
int coap_split_path(const uint8_t *s,
size_t length,
unsigned char *buf,
size_t *buflen);
/**
/**
* Splits the given URI query into segments. Each segment is preceded
* by an option pseudo-header with delta-value 0 and the actual length
* of the respective query term.
*
* @param s The query string to split.
*
* @param s The query string to split.
* @param length The actual length of @p s.
* @param buf Result buffer for parsed segments.
* @param buf Result buffer for parsed segments.
* @param buflen Maximum length of @p buf. Will be set to the actual number
* of bytes written into buf on success.
*
*
* @return The number of segments created or @c -1 on error.
*
* @bug This function does not reserve additional space for delta > 12.
*/
int coap_split_query(const unsigned char *s,
int coap_split_query(const uint8_t *s,
size_t length,
unsigned char *buf,
size_t *buflen);
/**
* Extract query string from request PDU according to escape rules in 6.5.8.
* @param request Request PDU.
* @return Reconstructed and escaped query string part.
*/
coap_string_t *coap_get_query(const struct coap_pdu_t *request);
/**
* Extract uri_path string from request PDU
* @param request Request PDU.
* @return Reconstructed and escaped uri path string part.
*/
coap_string_t *coap_get_uri_path(const struct coap_pdu_t *request);
/** @} */
#endif /* _COAP_URI_H_ */
#endif /* COAP_URI_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -18,10 +18,13 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
#ifdef WITH_POSIX
#include "coap_config_posix.h"
/* Always enabled in ESP-IDF */
#ifndef WITH_POSIX
#define WITH_POSIX
#endif
#include "coap_config_posix.h"
#define HAVE_STDIO_H
#define HAVE_ASSERT_H

View File

@ -25,17 +25,14 @@
#define HAVE_SYS_SOCKET_H
#define HAVE_MALLOC
#define HAVE_ARPA_INET_H
#define HAVE_TIME_H
#define IP_PKTINFO IP_MULTICAST_IF
#define IPV6_PKTINFO IPV6_V6ONLY
#define PACKAGE_NAME "libcoap-posix"
#define PACKAGE_VERSION "?"
#define CUSTOM_COAP_NETWORK_ENDPOINT
#define CUSTOM_COAP_NETWORK_SEND
#define CUSTOM_COAP_NETWORK_READ
#endif
#define COAP_BAD_RECVMSG
#endif /* WITH_POSIX */
#endif /* COAP_CONFIG_POSIX_H_ */

View File

@ -0,0 +1,209 @@
/*
* coap_debug.h -- debug utilities
*
* 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.
*/
#ifndef COAP_DEBUG_H_
#define COAP_DEBUG_H_
/**
* @defgroup logging Logging Support
* API functions for logging support
* @{
*/
#ifndef COAP_DEBUG_FD
/**
* Used for output for @c LOG_DEBUG to @c LOG_ERR.
*/
#define COAP_DEBUG_FD stdout
#endif
#ifndef COAP_ERR_FD
/**
* Used for output for @c LOG_CRIT to @c LOG_EMERG.
*/
#define COAP_ERR_FD stderr
#endif
#ifdef HAVE_SYSLOG_H
#include <syslog.h>
/**
* Logging type. One of LOG_* from @b syslog.
*/
typedef short coap_log_t;
#else
/** Pre-defined log levels akin to what is used in \b syslog. */
typedef enum {
LOG_EMERG=0, /**< Emergency */
LOG_ALERT, /**< Alert */
LOG_CRIT, /**< Critical */
LOG_ERR, /**< Error */
LOG_WARNING, /**< Warning */
LOG_NOTICE, /**< Notice */
LOG_INFO, /**< Information */
LOG_DEBUG /**< Debug */
} coap_log_t;
#endif
/**
* Get the current logging level.
*
* @return One of the LOG_* values.
*/
coap_log_t coap_get_log_level(void);
/**
* Sets the log level to the specified value.
*
* @param level One of the LOG_* values.
*/
void coap_set_log_level(coap_log_t level);
/**
* Logging call-back handler definition.
*
* @param level One of the LOG_* values.
* @param message Zero-terminated string message to log.
*/
typedef void (*coap_log_handler_t) (coap_log_t level, const char *message);
/**
* Add a custom log callback handler.
*
* @param handler The logging handler to use or @p NULL to use default handler.
*/
void coap_set_log_handler(coap_log_handler_t handler);
/**
* Get the library package name.
*
* @return Zero-terminated string with the name of this library.
*/
const char *coap_package_name(void);
/**
* Get the library package version.
*
* @return Zero-terminated string with the library version.
*/
const char *coap_package_version(void);
/**
* Writes the given text to @c COAP_ERR_FD (for @p level <= @c LOG_CRIT) or @c
* COAP_DEBUG_FD (for @p level >= @c LOG_ERR). The text is output only when
* @p level is below or equal to the log level that set by coap_set_log_level().
*
* Internal function.
*
* @param level One of the LOG_* values.
& @param format The format string to use.
*/
#if (defined(__GNUC__))
void coap_log_impl(coap_log_t level,
const char *format, ...) __attribute__ ((format(printf, 2, 3)));
#else
void coap_log_impl(coap_log_t level, const char *format, ...);
#endif
#ifndef coap_log
/**
* Logging function.
* 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_ERR). The text is output only when
* @p level is below or equal to the log level that set by coap_set_log_level().
*
* @param level One of the LOG_* values.
*/
#define coap_log(level, ...) do { \
if ((int)((level))<=(int)coap_get_log_level()) \
coap_log_impl((level), __VA_ARGS__); \
} while(0)
#endif
#include "pdu.h"
/**
* Defines the output mode for the coap_show_pdu() function.
*
* @param use_fprintf @p 1 if the output is to use fprintf() (the default)
* @p 0 if the output is to use coap_log().
*/
void coap_set_show_pdu_output(int use_fprintf);
/**
* Display the contents of the specified @p pdu.
* Note: The output method of coap_show_pdu() is dependent on the setting of
* coap_set_show_pdu_output().
*
* @param level The required minimum logging level.
* @param pdu The PDU to decode.
*/
void coap_show_pdu(coap_log_t level, const coap_pdu_t *pdu);
/**
* Display the current (D)TLS library linked with and built for version.
*
* @param level The required minimum logging level.
*/
void coap_show_tls_version(coap_log_t level);
/**
* Build a string containing the current (D)TLS library linked with and
* built for version.
*
* @param buffer The buffer to put the string into.
* @param bufsize The size of the buffer to put the string into.
*
* @return A pointer to the provided buffer.
*/
char *coap_string_tls_version(char *buffer, size_t bufsize);
struct coap_address_t;
/**
* Print the address into the defined buffer.
*
* Internal Function.
*
* @param address The address to print.
* @param buffer The buffer to print into.
* @param size The size of the buffer to print into.
*
* @return The amount written into the buffer.
*/
size_t coap_print_addr(const struct coap_address_t *address,
unsigned char *buffer, size_t size);
/** @} */
/**
* Set the packet loss level for testing. This can be in one of two forms.
*
* Percentage : 0% to 100%. Use the specified probability.
* 0% is send all packets, 100% is drop all packets.
*
* List: A comma separated list of numbers or number ranges that are the
* packets to drop.
*
* @param loss_level The defined loss level (percentage or list).
*
* @return @c 1 If loss level set, @c 0 if there is an error.
*/
int coap_debug_set_packet_loss(const char *loss_level);
/**
* Check to see whether a packet should be sent or not.
*
* Internal function
*
* @return @c 1 if packet is to be sent, @c 0 if packet is to be dropped.
*/
int coap_debug_send_packet(void);
#endif /* COAP_DEBUG_H_ */

View File

@ -0,0 +1,609 @@
/*
* coap_dtls.h -- (Datagram) Transport Layer Support for libcoap
*
* Copyright (C) 2016 Olaf Bergmann <bergmann@tzi.org>
* Copyright (C) 2017 Jean-Claude Michelou <jcm@spinetix.com>
*
* This file is part of the CoAP library libcoap. Please see README for terms
* of use.
*/
#ifndef COAP_DTLS_H_
#define COAP_DTLS_H_
#include "net.h"
#include "coap_session.h"
#include "pdu.h"
/**
* @defgroup dtls DTLS Support
* API functions for interfacing with DTLS libraries.
* @{
*/
/**
* Check whether DTLS is available.
*
* @return @c 1 if support for DTLS is enabled, or @c 0 otherwise.
*/
int coap_dtls_is_supported(void);
/**
* Check whether TLS is available.
*
* @return @c 1 if support for TLS is enabled, or @c 0 otherwise.
*/
int coap_tls_is_supported(void);
#define COAP_TLS_LIBRARY_NOTLS 0 /**< No DTLS library */
#define COAP_TLS_LIBRARY_TINYDTLS 1 /**< Using TinyDTLS library */
#define COAP_TLS_LIBRARY_OPENSSL 2 /**< Using OpenSSL library */
#define COAP_TLS_LIBRARY_GNUTLS 3 /**< Using GnuTLS library */
/**
* The structure used for returning the underlying (D)TLS library
* information.
*/
typedef struct coap_tls_version_t {
uint64_t version; /**< (D)TLS runtime Library Version */
int type; /**< Library type. One of COAP_TLS_LIBRARY_* */
uint64_t built_version; /**< (D)TLS Built against Library Version */
} coap_tls_version_t;
/**
* Determine the type and version of the underlying (D)TLS library.
*
* @return The version and type of library libcoap was compiled against.
*/
coap_tls_version_t *coap_get_tls_library_version(void);
struct coap_dtls_pki_t;
/**
* Additional Security setup handler that can be set up by
* coap_context_set_pki().
* Invoked when libcoap has done the validation checks at the TLS level,
* but the application needs to do some additional checks/changes/updates.
*
* @param tls_session The security session definition - e.g. SSL * for OpenSSL.
* NULL if server call-back.
* This will be dependent on the underlying TLS library -
* see coap_get_tls_library_version()
* @param setup_data A structure containing setup data originally passed into
* coap_context_set_pki() or coap_new_client_session_pki().
*
* @return @c 1 if successful, else @c 0.
*/
typedef int (*coap_dtls_security_setup_t)(void* tls_session,
struct coap_dtls_pki_t *setup_data);
/**
* CN Validation call-back that can be set up by coap_context_set_pki().
* Invoked when libcoap has done the validation checks at the TLS level,
* but the application needs to check that the CN is allowed.
* CN is the SubjectAltName in the cert, if not present, then the leftmost
* Common Name (CN) component of the subject name.
*
* @param cn The determined CN from the certificate
* @param asn1_public_cert The ASN.1 DER encoded X.509 certificate
* @param asn1_length The ASN.1 length
* @param coap_session The CoAP session associated with the certificate update
* @param depth Depth in cert chain. If 0, then client cert, else a CA
* @param validated TLS layer can find no issues if 1
* @param arg The same as was passed into coap_context_set_pki()
* in setup_data->cn_call_back_arg
*
* @return @c 1 if accepted, else @c 0 if to be rejected.
*/
typedef int (*coap_dtls_cn_callback_t)(const char *cn,
const uint8_t *asn1_public_cert,
size_t asn1_length,
coap_session_t *coap_session,
unsigned depth,
int validated,
void *arg);
/**
* The enum used for determining the provided PKI ASN.1 (DER) Private Key
* formats.
*/
typedef enum coap_asn1_privatekey_type_t {
COAP_ASN1_PKEY_NONE, /**< NONE */
COAP_ASN1_PKEY_RSA, /**< RSA type */
COAP_ASN1_PKEY_RSA2, /**< RSA2 type */
COAP_ASN1_PKEY_DSA, /**< DSA type */
COAP_ASN1_PKEY_DSA1, /**< DSA1 type */
COAP_ASN1_PKEY_DSA2, /**< DSA2 type */
COAP_ASN1_PKEY_DSA3, /**< DSA3 type */
COAP_ASN1_PKEY_DSA4, /**< DSA4 type */
COAP_ASN1_PKEY_DH, /**< DH type */
COAP_ASN1_PKEY_DHX, /**< DHX type */
COAP_ASN1_PKEY_EC, /**< EC type */
COAP_ASN1_PKEY_HMAC, /**< HMAC type */
COAP_ASN1_PKEY_CMAC, /**< CMAC type */
COAP_ASN1_PKEY_TLS1_PRF, /**< TLS1_PRF type */
COAP_ASN1_PKEY_HKDF /**< HKDF type */
} coap_asn1_privatekey_type_t;
/**
* The enum used for determining the PKI key formats.
*/
typedef enum coap_pki_key_t {
COAP_PKI_KEY_PEM = 0, /**< The PKI key type is PEM */
COAP_PKI_KEY_ASN1, /**< The PKI key type is ASN.1 (DER) */
} coap_pki_key_t;
/**
* The structure that holds the PKI PEM definitions.
*/
typedef struct coap_pki_key_pem_t {
const char *ca_file; /**< File location of Common CA in PEM format */
const char *public_cert; /**< File location of Public Cert in PEM format */
const char *private_key; /**< File location of Private Key in PEM format */
} coap_pki_key_pem_t;
/**
* The structure that holds the PKI ASN.1 (DER) definitions.
*/
typedef struct coap_pki_key_asn1_t {
const uint8_t *ca_cert; /**< ASN1 (DER) Common CA Cert */
const uint8_t *public_cert; /**< ASN1 (DER) Public Cert */
const uint8_t *private_key; /**< ASN1 (DER) Private Key */
size_t ca_cert_len; /**< ASN1 CA Cert length */
size_t public_cert_len; /**< ASN1 Public Cert length */
size_t private_key_len; /**< ASN1 Private Key length */
coap_asn1_privatekey_type_t private_key_type; /**< Private Key Type */
} coap_pki_key_asn1_t;
/**
* The structure that holds the PKI key information.
*/
typedef struct coap_dtls_key_t {
coap_pki_key_t key_type; /**< key format type */
union {
coap_pki_key_pem_t pem; /**< for PEM keys */
coap_pki_key_asn1_t asn1; /**< for ASN.1 (DER) keys */
} key;
} coap_dtls_key_t;
/**
* Server Name Indication (SNI) Validation call-back that can be set up by
* coap_context_set_pki().
* Invoked if the SNI is not previously seen and prior to sending a certificate
* set back to the client so that the appropriate certificate set can be used
* based on the requesting SNI.
*
* @param sni The requested SNI
* @param arg The same as was passed into coap_context_set_pki()
* in setup_data->sni_call_back_arg
*
* @return New set of certificates to use, or @c NULL if SNI is to be rejected.
*/
typedef coap_dtls_key_t *(*coap_dtls_sni_callback_t)(const char *sni,
void* arg);
#define COAP_DTLS_PKI_SETUP_VERSION 1 /**< Latest PKI setup version */
/**
* The structure used for defining the PKI setup data to be used.
*/
typedef struct coap_dtls_pki_t {
uint8_t version; /** Set to 1 to support this version of the struct */
/* Options to enable different TLS functionality in libcoap */
uint8_t verify_peer_cert; /**< 1 if peer cert is to be verified */
uint8_t require_peer_cert; /**< 1 if peer cert is required */
uint8_t allow_self_signed; /**< 1 if self signed certs are allowed */
uint8_t allow_expired_certs; /**< 1 if expired certs are allowed */
uint8_t cert_chain_validation; /**< 1 if to check cert_chain_verify_depth */
uint8_t cert_chain_verify_depth; /**< recommended depth is 3 */
uint8_t check_cert_revocation; /**< 1 if revocation checks wanted */
uint8_t allow_no_crl; /**< 1 ignore if CRL not there */
uint8_t allow_expired_crl; /**< 1 if expired crl is allowed */
uint8_t reserved[6]; /**< Reserved - must be set to 0 for
future compatibility */
/* Size of 6 chosen to align to next
* parameter, so if newly defined option
* it can use one of the reserverd slot so
* no need to change
* COAP_DTLS_PKI_SETUP_VERSION and just
* decrement the reserved[] count.
*/
/** CN check call-back function.
* If not NULL, is called when the TLS connection has passed the configured
* TLS options above for the application to verify if the CN is valid.
*/
coap_dtls_cn_callback_t validate_cn_call_back;
void *cn_call_back_arg; /**< Passed in to the CN call-back function */
/** SNI check call-back function.
* If not @p NULL, called if the SNI is not previously seen and prior to
* sending a certificate set back to the client so that the appropriate
* certificate set can be used based on the requesting SNI.
*/
coap_dtls_sni_callback_t validate_sni_call_back;
void *sni_call_back_arg; /**< Passed in to the sni call-back function */
/** Additional Security call-back handler that is invoked when libcoap has
* done the standerd, defined validation checks at the TLS level,
* If not @p NULL, called from within the TLS Client Hello connection
* setup.
*/
coap_dtls_security_setup_t additional_tls_setup_call_back;
char* client_sni; /**< If not NULL, SNI to use in client TLS setup.
Owned by the client app and must remain valid
during the call to coap_new_client_session_pki() */
coap_dtls_key_t pki_key; /**< PKI key definition */
} coap_dtls_pki_t;
/** @} */
/**
* @defgroup dtls_internal DTLS Support (Internal)
* Internal API functions for interfacing with DTLS libraries.
* @{
*/
/**
* Creates a new DTLS context for the given @p coap_context. This function
* returns a pointer to a new DTLS context object or @c NULL on error.
*
* Internal function.
*
* @param coap_context The CoAP context where the DTLS object shall be used.
*
* @return A DTLS context object or @c NULL on error.
*/
void *
coap_dtls_new_context(struct coap_context_t *coap_context);
typedef enum coap_dtls_role_t {
COAP_DTLS_ROLE_CLIENT, /**< Internal function invoked for client */
COAP_DTLS_ROLE_SERVER /**< Internal function invoked for server */
} coap_dtls_role_t;
/**
* Set the DTLS context's default PSK information.
* This does the PSK specifics following coap_dtls_new_context().
* If @p COAP_DTLS_ROLE_SERVER, then identity hint will also get set.
* If @p COAP_DTLS_ROLE_SERVER, then the information will get put into the
* TLS library's context (from which sessions are derived).
* If @p COAP_DTLS_ROLE_CLIENT, then the information will get put into the
* TLS library's session.
*
* Internal function.
*
* @param coap_context The CoAP context.
* @param identity_hint The default PSK server identity hint sent to a client.
* Required parameter. If @p NULL, will be set to "".
* Empty string is a valid hint.
* This parameter is ignored if COAP_DTLS_ROLE_CLIENT
* @param role One of @p COAP_DTLS_ROLE_CLIENT or @p COAP_DTLS_ROLE_SERVER
*
* @return @c 1 if successful, else @c 0.
*/
int
coap_dtls_context_set_psk(struct coap_context_t *coap_context,
const char *identity_hint,
coap_dtls_role_t role);
/**
* Set the DTLS context's default server PKI information.
* This does the PKI specifics following coap_dtls_new_context().
* If @p COAP_DTLS_ROLE_SERVER, then the information will get put into the
* TLS library's context (from which sessions are derived).
* If @p COAP_DTLS_ROLE_CLIENT, then the information will get put into the
* TLS library's session.
*
* Internal function.
*
* @param coap_context The CoAP context.
* @param setup_data Setup information defining how PKI is to be setup.
* Required parameter. If @p NULL, PKI will not be
* set up.
* @param role One of @p COAP_DTLS_ROLE_CLIENT or @p COAP_DTLS_ROLE_SERVER
*
* @return @c 1 if successful, else @c 0.
*/
int
coap_dtls_context_set_pki(struct coap_context_t *coap_context,
coap_dtls_pki_t *setup_data,
coap_dtls_role_t role);
/**
* Set the dtls context's default Root CA information for a client or server.
*
* Internal function.
*
* @param coap_context The current coap_context_t object.
* @param ca_file If not @p NULL, is the full path name of a PEM encoded
* file containing all the Root CAs to be used.
* @param ca_dir If not @p NULL, points to a directory containing PEM
* encoded files containing all the Root CAs to be used.
*
* @return @c 1 if successful, else @c 0.
*/
int
coap_dtls_context_set_pki_root_cas(struct coap_context_t *coap_context,
const char *ca_file,
const char *ca_dir);
/**
* Check whether one of the coap_dtls_context_set_{psk|pki}() functions have
* been called.
*
* Internal function.
*
* @param coap_context The current coap_context_t object.
*
* @return @c 1 if coap_dtls_context_set_{psk|pki}() called, else @c 0.
*/
int coap_dtls_context_check_keys_enabled(struct coap_context_t *coap_context);
/**
* Releases the storage allocated for @p dtls_context.
*
* Internal function.
*
* @param dtls_context The DTLS context as returned by coap_dtls_new_context().
*/
void coap_dtls_free_context(void *dtls_context);
/**
* Create a new client-side session. This should send a HELLO to the server.
*
* Internal function.
*
* @param coap_session The CoAP session.
*
* @return Opaque handle to underlying TLS library object containing security
* parameters for the session.
*/
void *coap_dtls_new_client_session(coap_session_t *coap_session);
/**
* Create a new DTLS server-side session.
* Called after coap_dtls_hello() has returned @c 1, signalling that a validated
* HELLO was received from a client.
* This should send a HELLO to the server.
*
* Internal function.
*
* @param coap_session The CoAP session.
*
* @return Opaque handle to underlying TLS library object containing security
* parameters for the DTLS session.
*/
void *coap_dtls_new_server_session(coap_session_t *coap_session);
/**
* Terminates the DTLS session (may send an ALERT if necessary) then frees the
* underlying TLS library object containing security parameters for the session.
*
* Internal function.
*
* @param coap_session The CoAP session.
*/
void coap_dtls_free_session(coap_session_t *coap_session);
/**
* Notify of a change in the CoAP session's MTU, for example after
* a PMTU update.
*
* Internal function.
*
* @param coap_session The CoAP session.
*/
void coap_dtls_session_update_mtu(coap_session_t *coap_session);
/**
* Send data to a DTLS peer.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param data pointer to data.
* @param data_len Number of bytes to send.
*
* @return @c 0 if this would be blocking, @c -1 if there is an error or the
* number of cleartext bytes sent.
*/
int coap_dtls_send(coap_session_t *coap_session,
const uint8_t *data,
size_t data_len);
/**
* Check if timeout is handled per CoAP session or per CoAP context.
*
* Internal function.
*
* @return @c 1 of timeout and retransmit is per context, @c 0 if it is
* per session.
*/
int coap_dtls_is_context_timeout(void);
/**
* Do all pending retransmits and get next timeout
*
* Internal function.
*
* @param dtls_context The DTLS context.
*
* @return @c 0 if no event is pending or date of the next retransmit.
*/
coap_tick_t coap_dtls_get_context_timeout(void *dtls_context);
/**
* Get next timeout for this session.
*
* Internal function.
*
* @param coap_session The CoAP session.
*
* @return @c 0 If no event is pending or date of the next retransmit.
*/
coap_tick_t coap_dtls_get_timeout(coap_session_t *coap_session);
/**
* Handle a DTLS timeout expiration.
*
* Internal function.
*
* @param coap_session The CoAP session.
*/
void coap_dtls_handle_timeout(coap_session_t *coap_session);
/**
* Handling incoming data from a DTLS peer.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param data Encrypted datagram.
* @param data_len Encrypted datagram size.
*
* @return Result of coap_handle_dgram on the decrypted CoAP PDU
* or @c -1 for error.
*/
int coap_dtls_receive(coap_session_t *coap_session,
const uint8_t *data,
size_t data_len);
/**
* Handling client HELLO messages from a new candiate peer.
* Note that session->tls is empty.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param data Encrypted datagram.
* @param data_len Encrypted datagram size.
*
* @return @c 0 if a cookie verification message has been sent, @c 1 if the
* HELLO contains a valid cookie and a server session should be created,
* @c -1 if the message is invalid.
*/
int coap_dtls_hello(coap_session_t *coap_session,
const uint8_t *data,
size_t data_len);
/**
* Get DTLS overhead over cleartext PDUs.
*
* Internal function.
*
* @param coap_session The CoAP session.
*
* @return Maximum number of bytes added by DTLS layer.
*/
unsigned int coap_dtls_get_overhead(coap_session_t *coap_session);
/**
* Create a new TLS client-side session.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param connected Updated with whether the connection is connected yet or not.
* @c 0 is not connected, @c 1 is connected.
*
* @return Opaque handle to underlying TLS library object containing security
* parameters for the session.
*/
void *coap_tls_new_client_session(coap_session_t *coap_session, int *connected);
/**
* Create a TLS new server-side session.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param connected Updated with whether the connection is connected yet or not.
* @c 0 is not connected, @c 1 is connected.
*
* @return Opaque handle to underlying TLS library object containing security
* parameters for the session.
*/
void *coap_tls_new_server_session(coap_session_t *coap_session, int *connected);
/**
* Terminates the TLS session (may send an ALERT if necessary) then frees the
* underlying TLS library object containing security parameters for the session.
*
* Internal function.
*
* @param coap_session The CoAP session.
*/
void coap_tls_free_session( coap_session_t *coap_session );
/**
* Send data to a TLS peer, with implicit flush.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param data Pointer to data.
* @param data_len Number of bytes to send.
*
* @return @c 0 if this should be retried, @c -1 if there is an error
* or the number of cleartext bytes sent.
*/
ssize_t coap_tls_write(coap_session_t *coap_session,
const uint8_t *data,
size_t data_len
);
/**
* Read some data from a TLS peer.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param data Pointer to data.
* @param data_len Maximum number of bytes to read.
*
* @return @c 0 if this should be retried, @c -1 if there is an error
* or the number of cleartext bytes read.
*/
ssize_t coap_tls_read(coap_session_t *coap_session,
uint8_t *data,
size_t data_len
);
/**
* Initialize the underlying (D)TLS Library layer.
*
* Internal function.
*
*/
void coap_dtls_startup(void);
/** @} */
/**
* @ingroup logging
* Sets the (D)TLS logging level to the specified @p level.
* Note: coap_log_level() will influence output if at a specified level.
*
* @param level The logging level to use - LOG_*
*/
void coap_dtls_set_log_level(int level);
/**
* @ingroup logging
* Get the current (D)TLS logging.
*
* @return The current log level (one of LOG_*).
*/
int coap_dtls_get_log_level(void);
#endif /* COAP_DTLS_H */

View File

@ -0,0 +1,102 @@
/*
* coap_event.h -- libcoap Event API
*
* Copyright (C) 2016 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see README for terms
* of use.
*/
#ifndef COAP_EVENT_H_
#define COAP_EVENT_H_
#include "libcoap.h"
struct coap_context_t;
struct coap_session_t;
/**
* @defgroup events Event API
* API functions for event delivery from lower-layer library functions.
* @{
*/
/**
* Scalar type to represent different events, e.g. DTLS events or
* retransmission timeouts.
*/
typedef unsigned int coap_event_t;
/**
* (D)TLS events for COAP_PROTO_DTLS and COAP_PROTO_TLS
*/
#define COAP_EVENT_DTLS_CLOSED 0x0000
#define COAP_EVENT_DTLS_CONNECTED 0x01DE
#define COAP_EVENT_DTLS_RENEGOTIATE 0x01DF
#define COAP_EVENT_DTLS_ERROR 0x0200
/**
* TCP events for COAP_PROTO_TCP and COAP_PROTO_TLS
*/
#define COAP_EVENT_TCP_CONNECTED 0x1001
#define COAP_EVENT_TCP_CLOSED 0x1002
#define COAP_EVENT_TCP_FAILED 0x1003
/**
* CSM exchange events for reliable protocols only
*/
#define COAP_EVENT_SESSION_CONNECTED 0x2001
#define COAP_EVENT_SESSION_CLOSED 0x2002
#define COAP_EVENT_SESSION_FAILED 0x2003
/**
* Type for event handler functions that can be registered with a CoAP
* context using the unction coap_set_event_handler(). When called by
* the library, the first argument will be the coap_context_t object
* where the handler function has been registered. The second argument
* is the event type that may be complemented by event-specific data
* passed as the third argument.
*/
typedef int (*coap_event_handler_t)(struct coap_context_t *,
coap_event_t event,
struct coap_session_t *session);
/**
* Registers the function @p hnd as callback for events from the given
* CoAP context @p context. Any event handler that has previously been
* registered with @p context will be overwritten by this operation.
*
* @param context The CoAP context to register the event handler with.
* @param hnd The event handler to be registered. @c NULL if to be
* de-registered.
*/
void coap_register_event_handler(struct coap_context_t *context,
coap_event_handler_t hnd);
/**
* Registers the function @p hnd as callback for events from the given
* CoAP context @p context. Any event handler that has previously been
* registered with @p context will be overwritten by this operation.
*
* @deprecated Use coap_register_event_handler() instead.
*
* @param context The CoAP context to register the event handler with.
* @param hnd The event handler to be registered.
*/
COAP_DEPRECATED
void coap_set_event_handler(struct coap_context_t *context,
coap_event_handler_t hnd);
/**
* Clears the event handler registered with @p context.
*
* @deprecated Use coap_register_event_handler() instead with NULL for hnd.
*
* @param context The CoAP context whose event handler is to be removed.
*/
COAP_DEPRECATED
void coap_clear_event_handler(struct coap_context_t *context);
/** @} */
#endif /* COAP_EVENT_H */

View File

@ -1,5 +1,5 @@
/*
* hashkey.h -- definition of hash key type and helper functions
* coap_hashkey.h -- definition of hash key type and helper functions
*
* Copyright (C) 2010-2011 Olaf Bergmann <bergmann@tzi.org>
*
@ -8,13 +8,15 @@
*/
/**
* @file hashkey.h
* @file coap_hashkey.h
* @brief definition of hash key type and helper functions
*/
#ifndef _COAP_HASHKEY_H_
#define _COAP_HASHKEY_H_
#ifndef COAP_HASHKEY_H_
#define COAP_HASHKEY_H_
#include "libcoap.h"
#include "uthash.h"
#include "str.h"
typedef unsigned char coap_key_t[4];
@ -35,13 +37,13 @@ void coap_hash_impl(const unsigned char *s, unsigned int len, coap_key_t h);
coap_hash_impl((String),(Length),(Result))
/* This is used to control the pre-set hash-keys for resources. */
#define __COAP_DEFAULT_HASH
#define COAP_DEFAULT_HASH
#else
#undef __COAP_DEFAULT_HASH
#undef COAP_DEFAULT_HASH
#endif /* coap_hash */
/**
* Calls coap_hash() with given @c str object as parameter.
* Calls coap_hash() with given @c coap_string_t 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.
@ -54,4 +56,4 @@ void coap_hash_impl(const unsigned char *s, unsigned int len, coap_key_t h);
coap_hash((Str)->s, (Str)->length, (H)); \
}
#endif /* _COAP_HASHKEY_H_ */
#endif /* COAP_HASHKEY_H_ */

View File

@ -7,148 +7,175 @@
* of use.
*/
#ifndef _COAP_IO_H_
#define _COAP_IO_H_
#ifndef COAP_IO_H_
#define COAP_IO_H_
#include <assert.h>
#include <sys/types.h>
#include "address.h"
/**
* Abstract handle that is used to identify a local network interface.
*/
typedef int coap_if_handle_t;
#ifndef COAP_RXBUFFER_SIZE
#define COAP_RXBUFFER_SIZE 1472
#endif /* COAP_RXBUFFER_SIZE */
/** Invalid interface handle */
#define COAP_IF_INVALID -1
#ifdef _WIN32
typedef SOCKET coap_fd_t;
#define coap_closesocket closesocket
#define COAP_SOCKET_ERROR SOCKET_ERROR
#define COAP_INVALID_SOCKET INVALID_SOCKET
#else
typedef int coap_fd_t;
#define coap_closesocket close
#define COAP_SOCKET_ERROR (-1)
#define COAP_INVALID_SOCKET (-1)
#endif
struct coap_packet_t;
typedef struct coap_packet_t coap_packet_t;
struct coap_session_t;
struct coap_pdu_t;
struct coap_context_t;
typedef uint16_t coap_socket_flags_t;
typedef struct coap_socket_t {
#if defined(WITH_LWIP)
struct udp_pcb *pcb;
#elif defined(WITH_CONTIKI)
void *conn;
#else
coap_fd_t fd;
#endif /* WITH_LWIP */
coap_socket_flags_t flags;
} coap_socket_t;
/**
* Abstraction of virtual endpoint that can be attached to coap_context_t. The
* tuple (handle, addr) must uniquely identify this endpoint.
* coap_socket_flags_t values
*/
typedef struct coap_endpoint_t {
#if defined(WITH_POSIX) || defined(WITH_CONTIKI)
union {
int fd; /**< on POSIX systems */
void *conn; /**< opaque connection (e.g. uip_conn in Contiki) */
} handle; /**< opaque handle to identify this endpoint */
#endif /* WITH_POSIX or WITH_CONTIKI */
#define COAP_SOCKET_EMPTY 0x0000 /**< the socket is not used */
#define COAP_SOCKET_NOT_EMPTY 0x0001 /**< the socket is not empty */
#define COAP_SOCKET_BOUND 0x0002 /**< the socket is bound */
#define COAP_SOCKET_CONNECTED 0x0004 /**< the socket is connected */
#define COAP_SOCKET_WANT_READ 0x0010 /**< non blocking socket is waiting for reading */
#define COAP_SOCKET_WANT_WRITE 0x0020 /**< non blocking socket is waiting for writing */
#define COAP_SOCKET_WANT_ACCEPT 0x0040 /**< non blocking server socket is waiting for accept */
#define COAP_SOCKET_WANT_CONNECT 0x0080 /**< non blocking client socket is waiting for connect */
#define COAP_SOCKET_CAN_READ 0x0100 /**< non blocking socket can now read without blocking */
#define COAP_SOCKET_CAN_WRITE 0x0200 /**< non blocking socket can now write without blocking */
#define COAP_SOCKET_CAN_ACCEPT 0x0400 /**< non blocking server socket can now accept without blocking */
#define COAP_SOCKET_CAN_CONNECT 0x0800 /**< non blocking client socket can now connect without blocking */
#define COAP_SOCKET_MULTICAST 0x1000 /**< socket is used for multicast communication */
struct coap_endpoint_t *coap_malloc_endpoint( void );
void coap_mfree_endpoint( struct coap_endpoint_t *ep );
int
coap_socket_connect_udp(coap_socket_t *sock,
const coap_address_t *local_if,
const coap_address_t *server,
int default_port,
coap_address_t *local_addr,
coap_address_t *remote_addr);
int
coap_socket_bind_udp(coap_socket_t *sock,
const coap_address_t *listen_addr,
coap_address_t *bound_addr );
int
coap_socket_connect_tcp1(coap_socket_t *sock,
const coap_address_t *local_if,
const coap_address_t *server,
int default_port,
coap_address_t *local_addr,
coap_address_t *remote_addr);
int
coap_socket_connect_tcp2(coap_socket_t *sock,
coap_address_t *local_addr,
coap_address_t *remote_addr);
int
coap_socket_bind_tcp(coap_socket_t *sock,
const coap_address_t *listen_addr,
coap_address_t *bound_addr);
int
coap_socket_accept_tcp(coap_socket_t *server,
coap_socket_t *new_client,
coap_address_t *local_addr,
coap_address_t *remote_addr);
void coap_socket_close(coap_socket_t *sock);
ssize_t
coap_socket_send( coap_socket_t *sock, struct coap_session_t *session,
const uint8_t *data, size_t data_len );
ssize_t
coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len);
ssize_t
coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len);
#ifdef WITH_LWIP
struct udp_pcb *pcb;
/**< @FIXME --chrysn
* this was added in a hurry, not sure it confirms to the overall model */
struct coap_context_t *context;
#endif /* WITH_LWIP */
ssize_t
coap_socket_send_pdu( coap_socket_t *sock, struct coap_session_t *session,
struct coap_pdu_t *pdu );
#endif
coap_address_t addr; /**< local interface address */
int ifindex;
int flags;
} coap_endpoint_t;
#define COAP_ENDPOINT_NOSEC 0x00
#define COAP_ENDPOINT_DTLS 0x01
coap_endpoint_t *coap_new_endpoint(const coap_address_t *addr, int flags);
void coap_free_endpoint(coap_endpoint_t *ep);
const char *coap_socket_strerror( void );
/**
* Function interface for data transmission. This function returns the number of
* bytes that have been transmitted, or a value less than zero on error.
*
* @param context The calling CoAP context.
* @param local_interface The local interface to send the data.
* @param dst The address of the receiver.
* @param sock Socket to send data with
* @param session Addressing information for unconnected sockets, or NULL
* @param data The data to send.
* @param datalen The actual length of @p data.
*
* @return The number of bytes written on success, or a value
* less than zero on error.
*/
ssize_t coap_network_send(struct coap_context_t *context,
const coap_endpoint_t *local_interface,
const coap_address_t *dst,
unsigned char *data, size_t datalen);
ssize_t coap_network_send( coap_socket_t *sock, const struct coap_session_t *session, const uint8_t *data, size_t datalen );
/**
* Function interface for reading data. This function returns the number of
* bytes that have been read, or a value less than zero on error. In case of an
* error, @p *packet is set to NULL.
*
* @param ep The endpoint that is used for reading data from the network.
* @param packet A result parameter where a pointer to the received packet
* structure is stored. The caller must call coap_free_packet to
* release the storage used by this packet.
* @param sock Socket to read data from
* @param packet Received packet metadata and payload. src and dst should be preset.
*
* @return The number of bytes received on success, or a value less than
* zero on error.
*/
ssize_t coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet);
ssize_t coap_network_read( coap_socket_t *sock, struct coap_packet_t *packet );
#ifndef coap_mcast_interface
# define coap_mcast_interface(Local) 0
#endif
/**
* Releases the storage allocated for @p packet.
*/
void coap_free_packet(coap_packet_t *packet);
/**
* Populate the coap_endpoint_t *target from the incoming packet's destination
* data.
*
* This is usually used to copy a packet's data into a node's local_if member.
*/
void coap_packet_populate_endpoint(coap_packet_t *packet,
coap_endpoint_t *target);
/**
* Given an incoming packet, copy its source address into an address struct.
*/
void coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target);
/**
* Given a packet, set msg and msg_len to an address and length of the packet's
* data in memory.
* */
void coap_packet_get_memmapped(coap_packet_t *packet,
void coap_packet_get_memmapped(struct coap_packet_t *packet,
unsigned char **address,
size_t *length);
void coap_packet_set_addr( struct coap_packet_t *packet, const coap_address_t *src,
const coap_address_t *dst );
#ifdef WITH_LWIP
/**
* Get the pbuf of a packet. The caller takes over responsibility for freeing
* the pbuf.
*/
struct pbuf *coap_packet_extract_pbuf(coap_packet_t *packet);
struct pbuf *coap_packet_extract_pbuf(struct coap_packet_t *packet);
#endif
#ifdef WITH_CONTIKI
/*
* This is only included in coap_io.h instead of .c in order to be available for
* sizeof in mem.c.
*/
struct coap_packet_t {
coap_if_handle_t hnd; /**< the interface handle */
coap_address_t src; /**< the packet's source address */
coap_address_t dst; /**< the packet's destination address */
const coap_endpoint_t *interface;
int ifindex;
void *session; /**< opaque session data */
size_t length; /**< length of payload */
unsigned char payload[]; /**< payload */
};
#endif
#ifdef WITH_LWIP
#if defined(WITH_LWIP)
/*
* This is only included in coap_io.h instead of .c in order to be available for
* sizeof in lwippools.h.
@ -159,9 +186,28 @@ struct coap_packet_t {
*/
struct coap_packet_t {
struct pbuf *pbuf;
const coap_endpoint_t *local_interface;
uint16_t srcport;
const struct coap_endpoint_t *local_interface;
coap_address_t src; /**< the packet's source address */
coap_address_t dst; /**< the packet's destination address */
int ifindex; /**< the interface index */
// uint16_t srcport;
};
#else
struct coap_packet_t {
coap_address_t src; /**< the packet's source address */
coap_address_t dst; /**< the packet's destination address */
int ifindex; /**< the interface index */
size_t length; /**< length of payload */
unsigned char payload[COAP_RXBUFFER_SIZE]; /**< payload */
};
#endif
typedef struct coap_packet_t coap_packet_t;
#endif /* _COAP_IO_H_ */
typedef enum {
COAP_NACK_TOO_MANY_RETRIES,
COAP_NACK_NOT_DELIVERABLE,
COAP_NACK_RST,
COAP_NACK_TLS_FAILED
} coap_nack_reason_t;
#endif /* COAP_IO_H_ */

View File

@ -0,0 +1,493 @@
/* coap_session.h -- Session management for libcoap
*
* Copyright (C) 2017 Jean-Claue Michelou <jcm@spinetix.com>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#ifndef COAP_SESSION_H_
#define COAP_SESSION_H_
#include "coap_io.h"
#include "coap_time.h"
#include "pdu.h"
struct coap_endpoint_t;
struct coap_context_t;
struct coap_queue_t;
/**
* Abstraction of a fixed point number that can be used where necessary instead
* of a float. 1,000 fractional bits equals one integer
*/
typedef struct coap_fixed_point_t {
uint16_t integer_part; /**< Integer part of fixed point variable */
uint16_t fractional_part; /**< Fractional part of fixed point variable
1/1000 (3 points) precision */
} coap_fixed_point_t;
#define COAP_DEFAULT_SESSION_TIMEOUT 300
#define COAP_PARTIAL_SESSION_TIMEOUT_TICKS (30 * COAP_TICKS_PER_SECOND)
#define COAP_DEFAULT_MAX_HANDSHAKE_SESSIONS 100
#define COAP_PROTO_NOT_RELIABLE(p) ((p)==COAP_PROTO_UDP || (p)==COAP_PROTO_DTLS)
#define COAP_PROTO_RELIABLE(p) ((p)==COAP_PROTO_TCP || (p)==COAP_PROTO_TLS)
typedef uint8_t coap_session_type_t;
/**
* coap_session_type_t values
*/
#define COAP_SESSION_TYPE_CLIENT 1 /**< client-side */
#define COAP_SESSION_TYPE_SERVER 2 /**< server-side */
#define COAP_SESSION_TYPE_HELLO 3 /**< server-side ephemeral session for responding to a client hello */
typedef uint8_t coap_session_state_t;
/**
* coap_session_state_t values
*/
#define COAP_SESSION_STATE_NONE 0
#define COAP_SESSION_STATE_CONNECTING 1
#define COAP_SESSION_STATE_HANDSHAKE 2
#define COAP_SESSION_STATE_CSM 3
#define COAP_SESSION_STATE_ESTABLISHED 4
typedef struct coap_session_t {
struct coap_session_t *next;
coap_proto_t proto; /**< protocol used */
coap_session_type_t type; /**< client or server side socket */
coap_session_state_t state; /**< current state of relationaship with peer */
unsigned ref; /**< reference count from queues */
unsigned tls_overhead; /**< overhead of TLS layer */
unsigned mtu; /**< path or CSM mtu */
coap_address_t local_if; /**< optional local interface address */
coap_address_t remote_addr; /**< remote address and port */
coap_address_t local_addr; /**< local address and port */
int ifindex; /**< interface index */
coap_socket_t sock; /**< socket object for the session, if any */
struct coap_endpoint_t *endpoint; /**< session's endpoint */
struct coap_context_t *context; /**< session's context */
void *tls; /**< security parameters */
uint16_t tx_mid; /**< the last message id that was used in this session */
uint8_t con_active; /**< Active CON request sent */
struct coap_queue_t *delayqueue; /**< list of delayed messages waiting to be sent */
size_t partial_write; /**< if > 0 indicates number of bytes already written from the pdu at the head of sendqueue */
uint8_t read_header[8]; /**< storage space for header of incoming message header */
size_t partial_read; /**< if > 0 indicates number of bytes already read for an incoming message */
coap_pdu_t *partial_pdu; /**< incomplete incoming pdu */
coap_tick_t last_rx_tx;
coap_tick_t last_tx_rst;
coap_tick_t last_ping;
coap_tick_t last_pong;
coap_tick_t csm_tx;
uint8_t *psk_identity;
size_t psk_identity_len;
uint8_t *psk_key;
size_t psk_key_len;
void *app; /**< application-specific data */
unsigned int max_retransmit; /**< maximum re-transmit count (default 4) */
coap_fixed_point_t ack_timeout; /**< timeout waiting for ack (default 2 secs) */
coap_fixed_point_t ack_random_factor; /**< ack random factor backoff (default 1.5) */
unsigned int dtls_timeout_count; /**< dtls setup retry counter */
int dtls_event; /**< Tracking any (D)TLS events on this sesison */
} coap_session_t;
/**
* Increment reference counter on a session.
*
* @param session The CoAP session.
* @return same as session
*/
coap_session_t *coap_session_reference(coap_session_t *session);
/**
* Decrement reference counter on a session.
* Note that the session may be deleted as a result and should not be used
* after this call.
*
* @param session The CoAP session.
*/
void coap_session_release(coap_session_t *session);
/**
* Stores @p data with the given session. This function overwrites any value
* that has previously been stored with @p session.
*/
void coap_session_set_app_data(coap_session_t *session, void *data);
/**
* Returns any application-specific data that has been stored with @p
* session using the function coap_session_set_app_data(). This function will
* return @c NULL if no data has been stored.
*/
void *coap_session_get_app_data(const coap_session_t *session);
/**
* Notify session that it has failed.
*
* @param session The CoAP session.
* @param reason The reason why the session was disconnected.
*/
void coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason);
/**
* Notify session transport has just connected and CSM exchange can now start.
*
* @param session The CoAP session.
*/
void coap_session_send_csm(coap_session_t *session);
/**
* Notify session that it has just connected or reconnected.
*
* @param session The CoAP session.
*/
void coap_session_connected(coap_session_t *session);
/**
* Set the session MTU. This is the maximum message size that can be sent,
* excluding IP and UDP overhead.
*
* @param session The CoAP session.
* @param mtu maximum message size
*/
void coap_session_set_mtu(coap_session_t *session, unsigned mtu);
/**
* Get maximum acceptable PDU size
*
* @param session The CoAP session.
* @return maximum PDU size, not including header (but including token).
*/
size_t coap_session_max_pdu_size(const coap_session_t *session);
/**
* Creates a new client session to the designated server.
* @param ctx The CoAP context.
* @param local_if Address of local interface. It is recommended to use NULL to let the operating system choose a suitable local interface. If an address is specified, the port number should be zero, which means that a free port is automatically selected.
* @param server The server's address. If the port number is zero, the default port for the protocol will be used.
* @param proto Protocol.
*
* @return A new CoAP session or NULL if failed. Call coap_session_release to free.
*/
coap_session_t *coap_new_client_session(
struct coap_context_t *ctx,
const coap_address_t *local_if,
const coap_address_t *server,
coap_proto_t proto
);
/**
* Creates a new client session to the designated server with PSK credentials
* @param ctx The CoAP context.
* @param local_if Address of local interface. It is recommended to use NULL to let the operating system choose a suitable local interface. If an address is specified, the port number should be zero, which means that a free port is automatically selected.
* @param server The server's address. If the port number is zero, the default port for the protocol will be used.
* @param proto Protocol.
* @param identity PSK client identity
* @param key PSK shared key
* @param key_len PSK shared key length
*
* @return A new CoAP session or NULL if failed. Call coap_session_release to free.
*/
coap_session_t *coap_new_client_session_psk(
struct coap_context_t *ctx,
const coap_address_t *local_if,
const coap_address_t *server,
coap_proto_t proto,
const char *identity,
const uint8_t *key,
unsigned key_len
);
struct coap_dtls_pki_t;
/**
* Creates a new client session to the designated server with PKI credentials
* @param ctx The CoAP context.
* @param local_if Address of local interface. It is recommended to use NULL to
* let the operating system choose a suitable local interface.
* If an address is specified, the port number should be zero,
* which means that a free port is automatically selected.
* @param server The server's address. If the port number is zero, the default
* port for the protocol will be used.
* @param proto CoAP Protocol.
* @param setup_data PKI parameters.
*
* @return A new CoAP session or NULL if failed. Call coap_session_release()
* to free.
*/
coap_session_t *coap_new_client_session_pki(
struct coap_context_t *ctx,
const coap_address_t *local_if,
const coap_address_t *server,
coap_proto_t proto,
struct coap_dtls_pki_t *setup_data
);
/**
* Creates a new server session for the specified endpoint.
* @param ctx The CoAP context.
* @param ep An endpoint where an incoming connection request is pending.
*
* @return A new CoAP session or NULL if failed. Call coap_session_release to free.
*/
coap_session_t *coap_new_server_session(
struct coap_context_t *ctx,
struct coap_endpoint_t *ep
);
/**
* Function interface for datagram data transmission. This function returns
* the number of bytes that have been transmitted, or a value less than zero
* on error.
*
* @param session Session to send data on.
* @param data The data to send.
* @param datalen The actual length of @p data.
*
* @return The number of bytes written on success, or a value
* less than zero on error.
*/
ssize_t coap_session_send(coap_session_t *session,
const uint8_t *data, size_t datalen);
/**
* Function interface for stream data transmission. This function returns
* the number of bytes that have been transmitted, or a value less than zero
* on error. The number of bytes written may be less than datalen because of
* congestion control.
*
* @param session Session to send data on.
* @param data The data to send.
* @param datalen The actual length of @p data.
*
* @return The number of bytes written on success, or a value
* less than zero on error.
*/
ssize_t coap_session_write(coap_session_t *session,
const uint8_t *data, size_t datalen);
/**
* Send a pdu according to the session's protocol. This function returns
* the number of bytes that have been transmitted, or a value less than zero
* on error.
*
* @param session Session to send pdu on.
* @param pdu The pdu to send.
*
* @return The number of bytes written on success, or a value
* less than zero on error.
*/
ssize_t coap_session_send_pdu(coap_session_t *session, coap_pdu_t *pdu);
/**
* @ingroup logging
* Get session description.
*
* @param session The CoAP session.
* @return description string.
*/
const char *coap_session_str(const coap_session_t *session);
ssize_t
coap_session_delay_pdu(coap_session_t *session, coap_pdu_t *pdu,
struct coap_queue_t *node);
/**
* Abstraction of virtual endpoint that can be attached to coap_context_t. The
* tuple (handle, addr) must uniquely identify this endpoint.
*/
typedef struct coap_endpoint_t {
struct coap_endpoint_t *next;
struct coap_context_t *context; /**< endpoint's context */
coap_proto_t proto; /**< protocol used on this interface */
uint16_t default_mtu; /**< default mtu for this interface */
coap_socket_t sock; /**< socket object for the interface, if any */
coap_address_t bind_addr; /**< local interface address */
coap_session_t *sessions; /**< list of active sessions */
coap_session_t hello; /**< special session of DTLS hello messages */
} coap_endpoint_t;
/**
* Create a new endpoint for communicating with peers.
*
* @param context The coap context that will own the new endpoint
* @param listen_addr Address the endpoint will listen for incoming requests on or originate outgoing requests from. Use NULL to specify that no incoming request will be accepted and use a random endpoint.
* @param proto Protocol used on this endpoint
*/
coap_endpoint_t *coap_new_endpoint(struct coap_context_t *context, const coap_address_t *listen_addr, coap_proto_t proto);
/**
* Set the endpoint's default MTU. This is the maximum message size that can be
* sent, excluding IP and UDP overhead.
*
* @param endpoint The CoAP endpoint.
* @param mtu maximum message size
*/
void coap_endpoint_set_default_mtu(coap_endpoint_t *endpoint, unsigned mtu);
void coap_free_endpoint(coap_endpoint_t *ep);
/**
* @ingroup logging
* Get endpoint description.
*
* @param endpoint The CoAP endpoint.
* @return description string.
*/
const char *coap_endpoint_str(const coap_endpoint_t *endpoint);
/**
* Lookup the server session for the packet received on an endpoint, or create
* a new one.
*
* @param endpoint Active endpoint the packet was received on.
* @param packet Received packet.
* @param now The current time in ticks.
* @return The CoAP session.
*/
coap_session_t *coap_endpoint_get_session(coap_endpoint_t *endpoint,
const struct coap_packet_t *packet, coap_tick_t now);
/**
* Create a new DTLS session for the @p endpoint.
*
* @ingroup dtls_internal
*
* @param endpoint Endpoint to add DTLS session to
* @param packet Received packet information to base session on.
* @param now The current time in ticks.
*
* @return Created CoAP session or @c NULL if error.
*/
coap_session_t *coap_endpoint_new_dtls_session(coap_endpoint_t *endpoint,
const struct coap_packet_t *packet, coap_tick_t now);
coap_session_t *coap_session_get_by_peer(struct coap_context_t *ctx,
const struct coap_address_t *remote_addr, int ifindex);
void coap_session_free(coap_session_t *session);
void coap_session_mfree(coap_session_t *session);
/**
* @defgroup cc Rate Control
* The transmission parameters for CoAP rate control ("Congestion
* Control" in stream-oriented protocols) are defined in
* https://tools.ietf.org/html/rfc7252#section-4.8
* @{
*/
/**
* Number of seconds when to expect an ACK or a response to an
* outstanding CON message.
* RFC 7252, Section 4.8 Default value of ACK_TIMEOUT is 2
*/
#define COAP_DEFAULT_ACK_TIMEOUT ((coap_fixed_point_t){2,0})
/**
* A factor that is used to randomize the wait time before a message
* is retransmitted to prevent synchronization effects.
* RFC 7252, Section 4.8 Default value of ACK_RANDOM_FACTOR is 1.5
*/
#define COAP_DEFAULT_ACK_RANDOM_FACTOR ((coap_fixed_point_t){1,500})
/**
* Number of message retransmissions before message sending is stopped
* RFC 7252, Section 4.8 Default value of MAX_RETRANSMIT is 4
*/
#define COAP_DEFAULT_MAX_RETRANSMIT 4
/**
* The number of simultaneous outstanding interactions that a client
* maintains to a given server.
* RFC 7252, Section 4.8 Default value of NSTART is 1
*/
#define COAP_DEFAULT_NSTART 1
/** @} */
/**
* Set the CoAP maximum retransmit count before failure
*
* Number of message retransmissions before message sending is stopped
*
* @param session The CoAP session.
* @param value The value to set to. The default is 4 and should not normally
* get changed.
*/
void coap_session_set_max_retransmit(coap_session_t *session,
unsigned int value);
/**
* Set the CoAP initial ack response timeout before the next re-transmit
*
* Number of seconds when to expect an ACK or a response to an
* outstanding CON message.
*
* @param session The CoAP session.
* @param value The value to set to. The default is 2 and should not normally
* get changed.
*/
void coap_session_set_ack_timeout(coap_session_t *session,
coap_fixed_point_t value);
/**
* Set the CoAP ack randomize factor
*
* A factor that is used to randomize the wait time before a message
* is retransmitted to prevent synchronization effects.
*
* @param session The CoAP session.
* @param value The value to set to. The default is 1.5 and should not normally
* get changed.
*/
void coap_session_set_ack_random_factor(coap_session_t *session,
coap_fixed_point_t value);
/**
* Get the CoAP maximum retransmit before failure
*
* Number of message retransmissions before message sending is stopped
*
* @param session The CoAP session.
*
* @return Current maximum retransmit value
*/
unsigned int coap_session_get_max_transmit(coap_session_t *session);
/**
* Get the CoAP initial ack response timeout before the next re-transmit
*
* Number of seconds when to expect an ACK or a response to an
* outstanding CON message.
*
* @param session The CoAP session.
*
* @return Current ack response timeout value
*/
coap_fixed_point_t coap_session_get_ack_timeout(coap_session_t *session);
/**
* Get the CoAP ack randomize factor
*
* A factor that is used to randomize the wait time before a message
* is retransmitted to prevent synchronization effects.
*
* @param session The CoAP session.
*
* @return Current ack randomize value
*/
coap_fixed_point_t coap_session_get_ack_random_factor(coap_session_t *session);
/**
* Send a ping message for the session.
* @param session The CoAP session.
*
* @return COAP_INVALID_TID if there is an error
*/
coap_tid_t coap_session_send_ping(coap_session_t *session);
#endif /* COAP_SESSION_H */

View File

@ -1,7 +1,7 @@
/*
* coap_time.h -- Clock Handling
*
* Copyright (C) 2010-2013 Olaf Bergmann <bergmann@tzi.org>
* Copyright (C) 2010-2019 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see README for terms
* of use.
@ -12,8 +12,8 @@
* @brief Clock Handling
*/
#ifndef _COAP_TIME_H_
#define _COAP_TIME_H_
#ifndef COAP_TIME_H_
#define COAP_TIME_H_
/**
* @defgroup clock Clock Handling
@ -21,7 +21,7 @@
* @{
*/
#ifdef WITH_LWIP
#if defined(WITH_LWIP)
#include <stdint.h>
#include <lwip/sys.h>
@ -33,22 +33,22 @@ typedef uint32_t coap_tick_t;
typedef uint32_t coap_time_t;
typedef int32_t coap_tick_diff_t;
static inline void coap_ticks_impl(coap_tick_t *t) {
COAP_STATIC_INLINE void coap_ticks_impl(coap_tick_t *t) {
*t = sys_now();
}
static inline void coap_clock_init_impl(void) {
COAP_STATIC_INLINE void coap_clock_init_impl(void) {
}
#define coap_clock_init coap_clock_init_impl
#define coap_ticks coap_ticks_impl
static inline coap_time_t coap_ticks_to_rt(coap_tick_t t) {
COAP_STATIC_INLINE coap_time_t coap_ticks_to_rt(coap_tick_t t) {
return t / COAP_TICKS_PER_SECOND;
}
#endif
#ifdef WITH_CONTIKI
#elif defined(WITH_CONTIKI)
#include "clock.h"
typedef clock_time_t coap_tick_t;
@ -63,25 +63,26 @@ typedef int coap_tick_diff_t;
#define COAP_TICKS_PER_SECOND CLOCK_SECOND
static inline void coap_clock_init(void) {
COAP_STATIC_INLINE void coap_clock_init(void) {
clock_init();
}
static inline void coap_ticks(coap_tick_t *t) {
COAP_STATIC_INLINE void coap_ticks(coap_tick_t *t) {
*t = clock_time();
}
static inline coap_time_t coap_ticks_to_rt(coap_tick_t t) {
COAP_STATIC_INLINE coap_time_t coap_ticks_to_rt(coap_tick_t t) {
return t / COAP_TICKS_PER_SECOND;
}
#endif /* WITH_CONTIKI */
#ifdef WITH_POSIX
#else
#include <stdint.h>
/**
* This data type represents internal timer ticks with COAP_TICKS_PER_SECOND
* resolution.
*/
typedef unsigned long coap_tick_t;
typedef uint64_t coap_tick_t;
/**
* CoAP time in seconds since epoch.
@ -93,10 +94,10 @@ typedef time_t coap_time_t;
* values. This data type must have the same size in memory as coap_tick_t to
* allow wrapping.
*/
typedef long coap_tick_diff_t;
typedef int64_t coap_tick_diff_t;
/** Use ms resolution on POSIX systems */
#define COAP_TICKS_PER_SECOND 1000
#define COAP_TICKS_PER_SECOND ((coap_tick_t)(1000U))
/**
* Initializes the internal clock.
@ -119,13 +120,32 @@ void coap_ticks(coap_tick_t *t);
* point (seconds since epoch on POSIX).
*/
coap_time_t coap_ticks_to_rt(coap_tick_t t);
#endif /* WITH_POSIX */
/**
* Helper function that converts coap ticks to POSIX wallclock time in us.
*
* @param t Internal system ticks.
*
* @return The number of seconds that has passed since a specific reference
* point (seconds since epoch on POSIX).
*/
uint64_t coap_ticks_to_rt_us(coap_tick_t t);
/**
* Helper function that converts POSIX wallclock time in us to coap ticks.
*
* @param t POSIX time is us
*
* @return coap ticks
*/
coap_tick_t coap_ticks_from_rt_us(uint64_t t);
#endif
/**
* 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) {
COAP_STATIC_INLINE int coap_time_lt(coap_tick_t a, coap_tick_t b) {
return ((coap_tick_diff_t)(a - b)) < 0;
}
@ -133,10 +153,10 @@ static inline int coap_time_lt(coap_tick_t a, coap_tick_t b) {
* 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) {
COAP_STATIC_INLINE int coap_time_le(coap_tick_t a, coap_tick_t b) {
return a == b || coap_time_lt(a,b);
}
/** @} */
#endif /* _COAP_TIME_H_ */
#endif /* COAP_TIME_H_ */

View File

@ -1,85 +0,0 @@
/*
* debug.h -- debug utilities
*
* 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.
*/
#ifndef _COAP_DEBUG_H_
#define _COAP_DEBUG_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_ERR,
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);
/** Returns a zero-terminated string with the name of this library. */
const char *coap_package_name(void);
/** Returns a zero-terminated string with the library version. */
const char *coap_package_version(void);
/**
* Writes the given text to @c COAP_ERR_FD (for @p level <= @c LOG_CRIT) or @c
* COAP_DEBUG_FD (for @p level >= @c LOG_WARNING). The text is output only when
* @p level is below or equal to the log level that set by coap_set_log_level().
*/
void coap_log_impl(coap_log_t level, const char *format, ...);
#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 /* NDEBUG */
#endif /* _COAP_DEBUG_H_ */

View File

@ -7,15 +7,17 @@
* of use.
*/
#ifndef _COAP_ENCODE_H_
#define _COAP_ENCODE_H_
#ifndef COAP_ENCODE_H_
#define COAP_ENCODE_H_
#if (BSD >= 199103) || defined(WITH_CONTIKI)
#if (BSD >= 199103) || defined(WITH_CONTIKI) || defined(_WIN32)
# include <string.h>
#else
# include <strings.h>
#endif
#include <stdint.h>
#define Nn 8 /* duplicate definition of N if built on sky motes */
#define ENCODE_HEADER_SIZE 4
#define HIBIT (1 << (Nn - 1))
@ -32,21 +34,63 @@ extern int coap_fls(unsigned int i);
#define coap_fls(i) fls(i)
#endif
#ifndef HAVE_FLSLL
/* include this only if flsll() is not available */
extern int coap_flsll(long long i);
#else
#define coap_flsll(i) flsll(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<<ENCODE_HEADER_SIZE<<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.
* Decodes multiple-length byte sequences. @p buf points to an input byte
* sequence of length @p length. Returns the decoded value.
*
* @param buf The input byte sequence to decode from
* @param length The length of the input byte sequence
*
* @return The decoded value
*/
unsigned int coap_decode_var_bytes(unsigned char *buf,unsigned int len);
unsigned int coap_decode_var_bytes(const uint8_t *buf, unsigned int length);
/**
* Encodes multiple-length byte sequences. buf points to an output buffer of
* sufficient length to store the encoded bytes. val is the value to encode.
* Returns the number of bytes used to encode val or 0 on error.
* Encodes multiple-length byte sequences. @p buf points to an output buffer of
* sufficient length to store the encoded bytes. @p value is the value to
* encode.
* Returns the number of bytes used to encode @p value or 0 on error.
*
* @param buf The output buffer to decode into
* @param length The output buffer size to encode into (must be sufficient)
* @param value The value to encode into the buffer
*
* @return The number of bytes used to encode @p value or @c 0 on error.
*/
unsigned int coap_encode_var_bytes(unsigned char *buf, unsigned int val);
unsigned int coap_encode_var_safe(uint8_t *buf,
size_t length,
unsigned int value);
#endif /* _COAP_ENCODE_H_ */
/**
* @deprecated Use coap_encode_var_safe() instead.
* Provided for backward compatibility. As @p value has a
* maximum value of 0xffffffff, and buf is usually defined as an array, it
* is unsafe to continue to use this variant if buf[] is less than buf[4].
*
* For example
* char buf[1],oops;
* ..
* coap_encode_var_bytes(buf, 0xfff);
* would cause oops to get overwritten. This error can only be found by code
* inspection.
* coap_encode_var_safe(buf, sizeof(buf), 0xfff);
* would catch this error at run-time and should be used instead.
*/
COAP_STATIC_INLINE COAP_DEPRECATED int
coap_encode_var_bytes(uint8_t *buf, unsigned int value
) {
return (int)coap_encode_var_safe(buf, sizeof(value), value);
}
#endif /* COAP_ENCODE_H_ */

View File

@ -7,8 +7,8 @@
* of use.
*/
#ifndef _LIBCOAP_H_
#define _LIBCOAP_H_
#ifndef COAP_LIBCOAP_H_
#define COAP_LIBCOAP_H_
/* The non posix embedded platforms like Contiki, TinyOS, RIOT, ... doesn't have
* a POSIX compatible header structure so we have to slightly do some platform
@ -18,9 +18,41 @@
*
* The CONTIKI variable is within the Contiki build environment! */
#if !defined (CONTIKI)
#if defined(_WIN32)
#pragma comment(lib,"Ws2_32.lib")
#include <ws2tcpip.h>
typedef SSIZE_T ssize_t;
typedef USHORT in_port_t;
#elif !defined (CONTIKI)
#include <netinet/in.h>
#include <sys/socket.h>
#endif /* CONTIKI */
#endif /* _LIBCOAP_H_ */
#ifndef COAP_STATIC_INLINE
# if defined(__cplusplus)
# define COAP_STATIC_INLINE inline
# else
# if defined(_MSC_VER)
# define COAP_STATIC_INLINE static __inline
# else
# define COAP_STATIC_INLINE static inline
# endif
# endif
#endif
#ifndef COAP_DEPRECATED
# if defined(__cplusplus)
# define COAP_DEPRECATED __attribute__ ((deprecated))
# else
# if defined(_MSC_VER)
# define COAP_DEPRECATED __declspec(deprecated)
# else
# define COAP_DEPRECATED __attribute__ ((deprecated))
# endif
# endif
#endif
void coap_startup(void);
void coap_cleanup(void);
#endif /* COAP_LIBCOAP_H_ */

View File

@ -3,7 +3,7 @@
* of use.
*/
/** Memory pool definitions for the libcoap when used with lwIP (which has its
/* 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
@ -35,6 +35,10 @@
#define MEMP_NUM_COAPPDU MEMP_NUM_COAPNODE
#endif
#ifndef MEMP_NUM_COAPSESSION
#define MEMP_NUM_COAPSESSION 2
#endif
#ifndef MEMP_NUM_COAP_SUBSCRIPTION
#define MEMP_NUM_COAP_SUBSCRIPTION 4
#endif
@ -47,11 +51,31 @@
#define MEMP_NUM_COAPRESOURCEATTR 20
#endif
#ifndef MEMP_NUM_COAPOPTLIST
#define MEMP_NUM_COAPOPTLIST 1
#endif
#ifndef MEMP_LEN_COAPOPTLIST
#define MEMP_LEN_COAPOPTLIST 12
#endif
#ifndef MEMP_NUM_COAPSTRING
#define MEMP_NUM_COAPSTRING 10
#endif
#ifndef MEMP_LEN_COAPSTRING
#define MEMP_LEN_COAPSTRING 32
#endif
LWIP_MEMPOOL(COAP_CONTEXT, MEMP_NUM_COAPCONTEXT, sizeof(coap_context_t), "COAP_CONTEXT")
LWIP_MEMPOOL(COAP_ENDPOINT, MEMP_NUM_COAPENDPOINT, sizeof(coap_endpoint_t), "COAP_ENDPOINT")
LWIP_MEMPOOL(COAP_PACKET, MEMP_NUM_COAPPACKET, sizeof(coap_packet_t), "COAP_PACKET")
LWIP_MEMPOOL(COAP_NODE, MEMP_NUM_COAPNODE, sizeof(coap_queue_t), "COAP_NODE")
LWIP_MEMPOOL(COAP_PDU, MEMP_NUM_COAPPDU, sizeof(coap_pdu_t), "COAP_PDU")
LWIP_MEMPOOL(COAP_SESSION, MEMP_NUM_COAPSESSION, sizeof(coap_session_t), "COAP_SESSION")
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")
LWIP_MEMPOOL(COAP_OPTLIST, MEMP_NUM_COAPOPTLIST, sizeof(coap_optlist_t)+MEMP_LEN_COAPOPTLIST, "COAP_OPTLIST")
LWIP_MEMPOOL(COAP_STRING, MEMP_NUM_COAPSTRING, sizeof(coap_string_t)+MEMP_LEN_COAPSTRING, "COAP_STRING")

View File

@ -7,8 +7,8 @@
* of use.
*/
#ifndef _COAP_MEM_H_
#define _COAP_MEM_H_
#ifndef COAP_MEM_H_
#define COAP_MEM_H_
#include <stdlib.h>
@ -37,7 +37,12 @@ typedef enum {
COAP_PDU,
COAP_PDU_BUF,
COAP_RESOURCE,
COAP_RESOURCEATTR
COAP_RESOURCEATTR,
#ifdef HAVE_LIBTINYDTLS
COAP_DTLS_SESSION,
#endif
COAP_SESSION,
COAP_OPTLIST,
} coap_memory_tag_t;
#ifndef WITH_LWIP
@ -67,14 +72,14 @@ void coap_free_type(coap_memory_tag_t type, void *p);
/**
* Wrapper function to coap_malloc_type() for backwards compatibility.
*/
static inline void *coap_malloc(size_t size) {
COAP_STATIC_INLINE void *coap_malloc(size_t size) {
return coap_malloc_type(COAP_STRING, size);
}
/**
* Wrapper function to coap_free_type() for backwards compatibility.
*/
static inline void coap_free(void *object) {
COAP_STATIC_INLINE void coap_free(void *object) {
coap_free_type(COAP_STRING, object);
}
@ -86,7 +91,7 @@ static inline void coap_free(void *object) {
/* no initialization needed with lwip (or, more precisely: lwip must be
* completely initialized anyway by the time coap gets active) */
static inline void coap_memory_init(void) {}
COAP_STATIC_INLINE void coap_memory_init(void) {}
/* It would be nice to check that size equals the size given at the memp
* declaration, but i currently don't see a standard way to check that without
@ -98,14 +103,14 @@ static inline void coap_memory_init(void) {}
/* Those are just here to make uri.c happy where string allocation has not been
* made conditional.
*/
static inline void *coap_malloc(size_t size) {
COAP_STATIC_INLINE void *coap_malloc(size_t size) {
LWIP_ASSERT("coap_malloc must not be used in lwIP", 0);
}
static inline void coap_free(void *pointer) {
COAP_STATIC_INLINE void coap_free(void *pointer) {
LWIP_ASSERT("coap_free must not be used in lwIP", 0);
}
#endif /* WITH_LWIP */
#endif /* _COAP_MEM_H_ */
#endif /* COAP_MEM_H_ */

View File

@ -7,13 +7,15 @@
* of use.
*/
#ifndef _COAP_NET_H_
#define _COAP_NET_H_
#ifndef COAP_NET_H_
#define COAP_NET_H_
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <sys/time.h>
#endif
#include <time.h>
#ifdef WITH_LWIP
@ -21,35 +23,61 @@
#endif
#include "coap_io.h"
#include "coap_dtls.h"
#include "coap_event.h"
#include "coap_time.h"
#include "option.h"
#include "pdu.h"
#include "prng.h"
#include "coap_session.h"
struct coap_queue_t;
/**
* Queue entry
*/
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_endpoint_t local_if; /**< the local address interface */
coap_address_t remote; /**< remote address */
coap_tid_t id; /**< unique transaction id */
coap_session_t *session; /**< the CoAP session */
coap_tid_t id; /**< CoAP transaction id */
coap_pdu_t *pdu; /**< the CoAP PDU to send */
} coap_queue_t;
/** Adds node to given queue, ordered by node->t. */
/**
* Adds @p node to given @p queue, ordered by variable t in @p node.
*
* @param queue Queue to add to.
* @param node Node entry to add to Queue.
*
* @return @c 1 added to queue, @c 0 failure.
*/
int coap_insert_node(coap_queue_t **queue, coap_queue_t *node);
/** Destroys specified node. */
/**
* Destroys specified @p node.
*
* @param node Node entry to remove.
*
* @return @c 1 node deleted from queue, @c 0 failure.
*/
int coap_delete_node(coap_queue_t *node);
/** Removes all items from given queue and frees the allocated storage. */
/**
* Removes all items from given @p queue and frees the allocated storage.
*
* @param queue The queue to delete.
*/
void coap_delete_all(coap_queue_t *queue);
/** Creates a new node suitable for adding to the CoAP sendqueue. */
/**
* Creates a new node suitable for adding to the CoAP sendqueue.
*
* @return New node entry, or @c NULL if failure.
*/
coap_queue_t *coap_new_node(void);
struct coap_resource_t;
@ -58,24 +86,71 @@ struct coap_context_t;
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_endpoint_t *local_interface,
const coap_address_t *remote,
/**
* Response handler that is used as call-back in coap_context_t.
*
* @param context CoAP session.
* @param session CoAP session.
* @param sent The PDU that was transmitted.
* @param received The PDU that was received.
* @param id CoAP transaction ID.
*/
typedef void (*coap_response_handler_t)(struct coap_context_t *context,
coap_session_t *session,
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;
/**
* Negative Acknowedge handler that is used as call-back in coap_context_t.
*
* @param context CoAP session.
* @param session CoAP session.
* @param sent The PDU that was transmitted.
* @param reason The reason for the NACK.
* @param id CoAP transaction ID.
*/
typedef void (*coap_nack_handler_t)(struct coap_context_t *context,
coap_session_t *session,
coap_pdu_t *sent,
coap_nack_reason_t reason,
const coap_tid_t id);
/** The CoAP stack's global state is stored in a coap_context_t object */
/**
* Recieved Ping handler that is used as call-back in coap_context_t.
*
* @param context CoAP session.
* @param session CoAP session.
* @param received The PDU that was received.
* @param id CoAP transaction ID.
*/
typedef void (*coap_ping_handler_t)(struct coap_context_t *context,
coap_session_t *session,
coap_pdu_t *received,
const coap_tid_t id);
/**
* Recieved Pong handler that is used as call-back in coap_context_t.
*
* @param context CoAP session.
* @param session CoAP session.
* @param received The PDU that was received.
* @param id CoAP transaction ID.
*/
typedef void (*coap_pong_handler_t)(struct coap_context_t *context,
coap_session_t *session,
coap_pdu_t *received,
const coap_tid_t id);
/**
* The CoAP stack's global state is stored in a coap_context_t object.
*/
typedef struct coap_context_t {
coap_opt_filter_t known_options;
struct coap_resource_t *resources; /**< hash table or list of known resources */
struct coap_resource_t *resources; /**< hash table or list of known
resources */
struct coap_resource_t *unknown_resource; /**< can be used for handling
unknown resources */
#ifndef WITHOUT_ASYNC
/**
@ -88,11 +163,8 @@ typedef struct coap_context_t {
* to sendqueue_basetime. */
coap_tick_t sendqueue_basetime;
coap_queue_t *sendqueue;
coap_endpoint_t *endpoint; /**< the endpoint used for listening */
#ifdef WITH_POSIX
int sockfd; /**< send/receive socket */
#endif /* WITH_POSIX */
coap_endpoint_t *endpoint; /**< the endpoints used for listening */
coap_session_t *sessions; /**< client sessions */
#ifdef WITH_CONTIKI
struct uip_udp_conn *conn; /**< uIP connection object */
@ -111,23 +183,40 @@ typedef struct coap_context_t {
* 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;
uint16_t message_id;
coap_response_handler_t response_handler;
coap_nack_handler_t nack_handler;
coap_ping_handler_t ping_handler;
coap_pong_handler_t pong_handler;
ssize_t (*network_send)(struct coap_context_t *context,
const coap_endpoint_t *local_interface,
const coap_address_t *dst,
unsigned char *data, size_t datalen);
/**
* Callback function that is used to signal events to the
* application. This field is set by coap_set_event_handler().
*/
coap_event_handler_t handle_event;
ssize_t (*network_read)(coap_endpoint_t *ep, coap_packet_t **packet);
ssize_t (*network_send)(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data, size_t datalen);
ssize_t (*network_read)(coap_socket_t *sock, struct coap_packet_t *packet);
size_t(*get_client_psk)(const coap_session_t *session, const uint8_t *hint, size_t hint_len, uint8_t *identity, size_t *identity_len, size_t max_identity_len, uint8_t *psk, size_t max_psk_len);
size_t(*get_server_psk)(const coap_session_t *session, const uint8_t *identity, size_t identity_len, uint8_t *psk, size_t max_psk_len);
size_t(*get_server_hint)(const coap_session_t *session, uint8_t *hint, size_t max_hint_len);
void *dtls_context;
uint8_t *psk_hint;
size_t psk_hint_len;
uint8_t *psk_key;
size_t psk_key_len;
unsigned int session_timeout; /**< Number of seconds of inactivity after which an unused session will be closed. 0 means use default. */
unsigned int max_idle_sessions; /**< Maximum number of simultaneous unused sessions per endpoint. 0 means no maximum. */
unsigned int max_handshake_sessions; /**< Maximum number of simultaneous negotating sessions per endpoint. 0 means use default. */
unsigned int ping_timeout; /**< Minimum inactivity time before sending a ping message. 0 means disabled. */
unsigned int csm_timeout; /**< Timeout for waiting for a CSM from the remote side. 0 means disabled. */
void *app; /**< application-specific data */
} coap_context_t;
/**
@ -137,20 +226,61 @@ typedef struct coap_context_t {
* @param context The context to register the handler for.
* @param handler The response handler to register.
*/
static inline void
COAP_STATIC_INLINE void
coap_register_response_handler(coap_context_t *context,
coap_response_handler_t handler) {
context->response_handler = handler;
}
/**
* Registers a new message handler that is called whenever a confirmable
* message (request or response) is dropped after all retries have been
* exhausted, or a rst message was received, or a network or TLS level
* event was received that indicates delivering the message is not possible.
*
* @param context The context to register the handler for.
* @param handler The nack handler to register.
*/
COAP_STATIC_INLINE void
coap_register_nack_handler(coap_context_t *context,
coap_nack_handler_t handler) {
context->nack_handler = handler;
}
/**
* Registers a new message handler that is called whenever a CoAP Ping
* message is received.
*
* @param context The context to register the handler for.
* @param handler The ping handler to register.
*/
COAP_STATIC_INLINE void
coap_register_ping_handler(coap_context_t *context,
coap_ping_handler_t handler) {
context->ping_handler = handler;
}
/**
* Registers a new message handler that is called whenever a CoAP Pong
* message is received.
*
* @param context The context to register the handler for.
* @param handler The pong handler to register.
*/
COAP_STATIC_INLINE void
coap_register_pong_handler(coap_context_t *context,
coap_pong_handler_t handler) {
context->pong_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_STATIC_INLINE void
coap_register_option(coap_context_t *ctx, uint16_t type) {
coap_option_setb(ctx->known_options, type);
}
@ -177,22 +307,77 @@ coap_queue_t *coap_pop_next( coap_context_t *context );
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
* Set the context's default PSK hint and/or key for a server.
*
* @param context The current coap_context_t object.
* @param hint The default PSK server hint sent to a client. If @p NULL, PSK
* authentication is disabled. Empty string is a valid hint.
* @param key The default PSK key. If @p NULL, PSK authentication will fail.
* @param key_len The default PSK key's length. If @p 0, PSK authentication will
* fail.
*
* @return @c 1 if successful, else @c 0.
*/
int coap_context_set_psk( coap_context_t *context, const char *hint,
const uint8_t *key, size_t key_len );
/**
* Set the context's default PKI information for a server.
*
* @param context The current coap_context_t object.
* @param setup_data If @p NULL, PKI authentication will fail. Certificate
* information required.
*
* @return @c 1 if successful, else @c 0.
*/
int
coap_context_set_pki(coap_context_t *context,
coap_dtls_pki_t *setup_data);
/**
* Set the context's default Root CA information for a client or server.
*
* @param context The current coap_context_t object.
* @param ca_file If not @p NULL, is the full path name of a PEM encoded
* file containing all the Root CAs to be used.
* @param ca_dir If not @p NULL, points to a directory containing PEM
* encoded files containing all the Root CAs to be used.
*
* @return @c 1 if successful, else @c 0.
*/
int
coap_context_set_pki_root_cas(coap_context_t *context,
const char *ca_file,
const char *ca_dir);
/**
* Set the context keepalive timer for sessions.
* A keepalive message will be sent after if a session has been inactive,
* i.e. no packet sent or received, for the given number of seconds.
* For reliable protocols, a PING message will be sent. If a PONG has not
* been received before the next PING is due to be sent, the session will
* considered as disconnected.
*
* @param context The coap_context_t object.
* @param seconds Number of seconds for the inactivity timer, or zero
* to disable CoAP-level keepalive messages.
*
* @return 1 if successful, else 0
*/
void coap_context_set_keepalive(coap_context_t *context, unsigned int seconds);
/**
* Returns a new message id and updates @p session->tx_mid 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.
* @param session The current coap_session_t object.
*
* @return Incremented message id in network byte order.
*/
static inline unsigned short
coap_new_message_id(coap_context_t *context) {
context->message_id++;
#ifndef WITH_CONTIKI
return htons(context->message_id);
#else /* WITH_CONTIKI */
return uip_htons(context->message_id);
#endif
COAP_STATIC_INLINE uint16_t
coap_new_message_id(coap_session_t *session) {
return ++session->tx_mid;
}
/**
@ -200,28 +385,32 @@ coap_new_message_id(coap_context_t *context) {
* clears all entries from the receive queue and send queue and deletes the
* resources that have been registered with @p context, and frees the attached
* endpoints.
*
* @param context The current coap_context_t object to free off.
*/
void coap_free_context(coap_context_t *context);
/**
* Stores @p data with the given CoAP context. This function
* overwrites any value that has previously been stored with @p
* context.
*
* @param context The CoAP context.
* @param data The data to store with wih the context. Note that this data
* must be valid during the lifetime of @p context.
*/
void coap_set_app_data(coap_context_t *context, void *data);
/**
* 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.
* Returns any application-specific data that has been stored with @p
* context using the function coap_set_app_data(). This function will
* return @c NULL if no data has been stored.
*
* @param context The CoAP context to use.
* @param local_interface The local network interface where the outbound
* packet is sent.
* @param dst The address to send to.
* @param pdu The CoAP PDU to send.
* @param context The CoAP context.
*
* @return The message id of the sent message or @c
* COAP_INVALID_TID on error.
* @return The data previously stored or @c NULL if not data stored.
*/
coap_tid_t coap_send_confirmed(coap_context_t *context,
const coap_endpoint_t *local_interface,
const coap_address_t *dst,
coap_pdu_t *pdu);
void *coap_get_app_data(const coap_context_t *context);
/**
* Creates a new ACK PDU with specified error @p code. The options specified by
@ -244,36 +433,14 @@ 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 local_interface The local network interface where the outbound packet
* is sent.
* @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_endpoint_t *local_interface,
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 session The CoAP session.
* @param request The original request to respond to.
* @param local_interface The local network interface where the outbound packet
* is sent.
* @param dst The remote peer that sent the request.
* @param code The response code.
* @param opts A filter that specifies the options to copy from the
* @p request.
@ -281,10 +448,8 @@ coap_tid_t coap_send(coap_context_t *context,
* @return The transaction id if the message was sent, or @c
* COAP_INVALID_TID otherwise.
*/
coap_tid_t coap_send_error(coap_context_t *context,
coap_tid_t coap_send_error(coap_session_t *session,
coap_pdu_t *request,
const coap_endpoint_t *local_interface,
const coap_address_t *dst,
unsigned char code,
coap_opt_filter_t opts);
@ -293,104 +458,143 @@ coap_tid_t coap_send_error(coap_context_t *context,
* 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 local_interface The local network interface where the outbound packet
* is sent.
* @param dst Where to send the context.
* @param session The CoAP session.
* @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_endpoint_t *local_interface,
const coap_address_t *dst,
coap_pdu_t *request,
unsigned char type);
coap_send_message_type(coap_session_t *session, coap_pdu_t *request, unsigned char type);
/**
* Sends an ACK message with code @c 0 for the specified @p request to @p dst.
* This function returns the corresponding transaction id if the message was
* sent or @c COAP_INVALID_TID on error.
*
* @param context The context to use.
* @param local_interface The local network interface where the outbound packet
* is sent.
* @param dst The destination address.
* @param session The CoAP session.
* @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_endpoint_t *local_interface,
const coap_address_t *dst,
coap_pdu_t *request);
coap_tid_t coap_send_ack(coap_session_t *session, coap_pdu_t *request);
/**
* Sends an RST message with code @c 0 for the specified @p request to @p dst.
* This function returns the corresponding transaction id if the message was
* sent or @c COAP_INVALID_TID on error.
*
* @param context The context to use.
* @param local_interface The local network interface where the outbound packet
* is sent.
* @param dst The destination address.
* @param session The CoAP session.
* @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_endpoint_t *local_interface,
const coap_address_t *dst,
coap_pdu_t *request) {
return coap_send_message_type(context,
local_interface,
dst, request,
COAP_MESSAGE_RST);
COAP_STATIC_INLINE coap_tid_t
coap_send_rst(coap_session_t *session, coap_pdu_t *request) {
return coap_send_message_type(session, request, COAP_MESSAGE_RST);
}
/**
* Sends a CoAP message to given peer. The memory that is
* allocated by pdu will be released by coap_send().
* The caller must not use the pdu after calling coap_send().
*
* @param session The CoAP session.
* @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_session_t *session, coap_pdu_t *pdu );
/**
* Handles retransmissions of confirmable messages
*
* @param context The CoAP context.
* @param node The node to retransmit.
*
* @return The message id of the sent message or @c
* COAP_INVALID_TID on error.
*/
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);
* For applications with their own message loop, send all pending retransmits and
* return the list of sockets with events to wait for and the next timeout
* The application should call coap_read, then coap_write again when any condition below is true:
* - data is available on any of the sockets with the COAP_SOCKET_WANT_READ
* - an incoming connection is pending in the listen queue and the COAP_SOCKET_WANT_ACCEPT flag is set
* - at least some data can be written without blocking on any of the sockets with the COAP_SOCKET_WANT_WRITE flag set
* - a connection event occured (success or failure) and the COAP_SOCKET_WANT_CONNECT flag is set
* - the timeout has expired
* Before calling coap_read or coap_write again, the application should position COAP_SOCKET_CAN_READ and COAP_SOCKET_CAN_WRITE flags as applicable.
*
* @param ctx The CoAP context
* @param sockets array of socket descriptors, filled on output
* @param max_sockets size of socket array.
* @param num_sockets pointer to the number of valid entries in the socket arrays on output
* @param now Current time.
*
* @return timeout as maxmimum number of milliseconds that the application should wait for network events or 0 if the application should wait forever.
*/
unsigned int
coap_write(coap_context_t *ctx,
coap_socket_t *sockets[],
unsigned int max_sockets,
unsigned int *num_sockets,
coap_tick_t now
);
/**
* Parses and interprets a CoAP message with context @p ctx. This function
* returns @c 0 if the message was handled, or a value less than zero on
* For applications with their own message loop, reads all data from the network.
*
* @param ctx The CoAP context
* @param now Current time
*/
void coap_read(coap_context_t *ctx, coap_tick_t now);
/**
* The main message processing loop.
*
* @param ctx The CoAP context
* @param timeout_ms Minimum number of milliseconds to wait for new messages before returning. If zero the call will block until at least one packet is sent or received.
*
* @return number of milliseconds spent or @c -1 if there was an error
*/
int coap_run_once( coap_context_t *ctx, unsigned int timeout_ms );
/**
* Parses and interprets a CoAP datagram with context @p ctx. This function
* returns @c 0 if the datagram was handled, or a value less than zero on
* error.
*
* @param ctx The current CoAP context.
* @param packet The received packet.
* @param session The current CoAP session.
* @param data The received packet'd data.
* @param data_len The received packet'd data length.
*
* @return @c 0 if message was handled successfully, or less than zero on
* error.
*/
int coap_handle_message(coap_context_t *ctx,
coap_packet_t *packet);
int coap_handle_dgram(coap_context_t *ctx, coap_session_t *session, uint8_t *data, size_t data_len);
/**
* Calculates a unique transaction id from given arguments @p peer and @p pdu.
* The id is returned in @p id.
* Invokes the event handler of @p context for the given @p event and
* @p data.
*
* @param peer The remote party who sent @p pdu.
* @param pdu The message that initiated the transaction.
* @param id Set to the new id.
* @param context The CoAP context whose event handler is to be called.
* @param event The event to deliver.
* @param session The session related to @p event.
* @return The result from the associated event handler or 0 if none was
* registered.
*/
void coap_transaction_id(const coap_address_t *peer,
const coap_pdu_t *pdu,
coap_tid_t *id);
int coap_handle_event(coap_context_t *context,
coap_event_t event,
coap_session_t *session);
/**
* 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
@ -400,64 +604,64 @@ void coap_transaction_id(const coap_address_t *peer,
* 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 session The session to look for.
* @param id The transaction 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_session_t *session,
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;
}
coap_tid_t
coap_wait_ack( coap_context_t *context, coap_session_t *session,
coap_queue_t *node);
/**
* Retrieves transaction from the queue.
*
* @param queue The transaction queue to be searched.
* @param id Unique key of the transaction to find.
* @param session The session to find.
* @param id The transaction id to find.
*
* @return A pointer to the transaction object or NULL if not found.
* @return A pointer to the transaction object or @c NULL if not found.
*/
coap_queue_t *coap_find_transaction(coap_queue_t *queue, coap_tid_t id);
coap_queue_t *coap_find_transaction(coap_queue_t *queue, coap_session_t *session, coap_tid_t id);
/**
* Cancels all outstanding messages for peer @p dst that have the specified
* Cancels all outstanding messages for session @p session that have the specified
* token.
*
* @param context The context in use.
* @param dst Destination address of the messages to remove.
* @param session Session 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,
coap_session_t *session,
const uint8_t *token,
size_t token_length);
/**
* Cancels all outstanding messages for session @p session.
*
* @param context The context in use.
* @param session Session of the messages to remove.
* @param reason The reasion for the session cancellation
*/
void
coap_cancel_session_messages(coap_context_t *context,
coap_session_t *session,
coap_nack_reason_t reason);
/**
* Dispatches the PDUs from the receive queue in given context.
*/
void coap_dispatch(coap_context_t *context, coap_queue_t *rcvd);
void coap_dispatch(coap_context_t *context, coap_session_t *session,
coap_pdu_t *pdu);
/**
* Returns 1 if there are no messages to send or to dispatch in the context's
@ -492,7 +696,7 @@ void coap_ticks(coap_tick_t *);
}
}
}
* @endcode
@endcode
*
* @param ctx The context where all known options are registered.
* @param pdu The PDU to check.
@ -508,14 +712,31 @@ int coap_option_check_critical(coap_context_t *ctx,
/**
* Creates a new response for given @p request with the contents of @c
* .well-known/core. The result is NULL on error or a newly allocated PDU that
* must be released by coap_delete_pdu().
* must be either sent with coap_sent() or released by coap_delete_pdu().
*
* @param context The current coap context to use.
* @param session The CoAP session.
* @param request The request for @c .well-known/core .
*
* @return A new 2.05 response for @c .well-known/core or NULL on error.
*/
coap_pdu_t *coap_wellknown_response(coap_context_t *context,
coap_session_t *session,
coap_pdu_t *request);
#endif /* _COAP_NET_H_ */
/**
* Calculates the initial timeout based on the session CoAP transmission
* parameters 'ack_timeout', 'ack_random_factor', and COAP_TICKS_PER_SECOND.
* The calculation requires 'ack_timeout' and 'ack_random_factor' to be in
* Qx.FRAC_BITS fixed point notation, whereas the passed parameter @p r
* is interpreted as the fractional part of a Q0.MAX_BITS random value.
*
* @param session session timeout is associated with
* @param r random value as fractional part of a Q0.MAX_BITS fixed point
* value
* @return COAP_TICKS_PER_SECOND * 'ack_timeout' *
* (1 + ('ack_random_factor' - 1) * r)
*/
unsigned int coap_calc_timeout(coap_session_t *session, unsigned char r);
#endif /* COAP_NET_H_ */

View File

@ -12,8 +12,8 @@
* @brief Helpers for handling options in CoAP PDUs
*/
#ifndef _COAP_OPTION_H_
#define _COAP_OPTION_H_
#ifndef COAP_OPTION_H_
#define COAP_OPTION_H_
#include "bits.h"
#include "pdu.h"
@ -22,14 +22,16 @@
* 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;
typedef uint8_t coap_opt_t;
#define PCHAR(p) ((coap_opt_t *)(p))
/** Representation of CoAP options. */
/**
* Representation of CoAP options.
*/
typedef struct {
unsigned short delta;
uint16_t delta;
size_t length;
unsigned char *value;
const uint8_t *value;
} coap_option_t;
/**
@ -59,27 +61,9 @@ size_t coap_opt_parse(const coap_opt_t *opt,
*/
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
* API functions for access option filters
* @{
*/
@ -106,7 +90,7 @@ coap_opt_t *options_start(coap_pdu_t *pdu);
#endif /* (COAP_OPT_FILTER_SHORT + COAP_OPT_FILTER_LONG > 16) */
/** The number of elements in coap_opt_filter_t. */
#define COAP_OPT_FILTER_SIZE \
#define COAP_OPT_FILTER_SIZE \
(((COAP_OPT_FILTER_SHORT + 1) >> 1) + COAP_OPT_FILTER_LONG) +1
/**
@ -142,7 +126,7 @@ typedef uint16_t coap_opt_filter_t[COAP_OPT_FILTER_SIZE];
*
* @param f The filter to clear.
*/
static inline void
COAP_STATIC_INLINE void
coap_option_filter_clear(coap_opt_filter_t f) {
memset(f, 0, sizeof(coap_opt_filter_t));
}
@ -157,7 +141,7 @@ coap_option_filter_clear(coap_opt_filter_t f) {
*
* @return @c 1 if bit was set, @c 0 otherwise.
*/
int coap_option_filter_set(coap_opt_filter_t filter, unsigned short type);
int coap_option_filter_set(coap_opt_filter_t filter, uint16_t type);
/**
* Clears the corresponding entry for @p type in @p filter. This
@ -169,7 +153,7 @@ int coap_option_filter_set(coap_opt_filter_t filter, unsigned short type);
*
* @return @c 1 if bit was set, @c 0 otherwise.
*/
int coap_option_filter_unset(coap_opt_filter_t filter, unsigned short type);
int coap_option_filter_unset(coap_opt_filter_t filter, uint16_t type);
/**
* Checks if @p type is contained in @p filter. This function returns
@ -181,7 +165,7 @@ int coap_option_filter_unset(coap_opt_filter_t filter, unsigned short type);
*
* @return @c 1 if @p type was found, @c 0 otherwise, or @c -1 on error.
*/
int coap_option_filter_get(const coap_opt_filter_t filter, unsigned short type);
int coap_option_filter_get(coap_opt_filter_t filter, uint16_t type);
/**
* Sets the corresponding bit for @p type in @p filter. This function returns @c
@ -195,8 +179,8 @@ int coap_option_filter_get(const coap_opt_filter_t filter, unsigned short type);
*
* @return @c 1 if bit was set, @c -1 otherwise.
*/
inline static int
coap_option_setb(coap_opt_filter_t filter, unsigned short type) {
COAP_STATIC_INLINE int
coap_option_setb(coap_opt_filter_t filter, uint16_t type) {
return coap_option_filter_set(filter, type) ? 1 : -1;
}
@ -212,8 +196,8 @@ coap_option_setb(coap_opt_filter_t filter, unsigned short type) {
*
* @return @c 1 if bit was set, @c -1 otherwise.
*/
inline static int
coap_option_clrb(coap_opt_filter_t filter, unsigned short type) {
COAP_STATIC_INLINE int
coap_option_clrb(coap_opt_filter_t filter, uint16_t type) {
return coap_option_filter_unset(filter, type) ? 1 : -1;
}
@ -229,8 +213,8 @@ coap_option_clrb(coap_opt_filter_t filter, unsigned short type) {
*
* @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) {
COAP_STATIC_INLINE int
coap_option_getb(coap_opt_filter_t filter, uint16_t type) {
return coap_option_filter_get(filter, type);
}
@ -252,7 +236,7 @@ coap_option_getb(const coap_opt_filter_t filter, unsigned short type) {
*/
typedef struct {
size_t length; /**< remaining length of PDU */
unsigned short type; /**< decoded option type */
uint16_t 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 */
@ -275,7 +259,7 @@ typedef struct {
*
* @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 *coap_option_iterator_init(const coap_pdu_t *pdu,
coap_opt_iterator_t *oi,
const coap_opt_filter_t filter);
@ -311,7 +295,7 @@ coap_opt_t *coap_option_next(coap_opt_iterator_t *oi);
* not found.
*/
coap_opt_t *coap_check_option(coap_pdu_t *pdu,
unsigned short type,
uint16_t type,
coap_opt_iterator_t *oi);
/**
@ -330,9 +314,20 @@ coap_opt_t *coap_check_option(coap_pdu_t *pdu,
*/
size_t coap_opt_setheader(coap_opt_t *opt,
size_t maxlen,
unsigned short delta,
uint16_t delta,
size_t length);
/**
* Compute storage bytes needed for an option with given @p delta and
* @p length
*
* @param delta The option delta.
* @param length The option length.
*
* @return The number of bytes required to encode this option.
*/
size_t coap_opt_encode_size(uint16_t 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
@ -350,8 +345,8 @@ size_t coap_opt_setheader(coap_opt_t *opt,
*/
size_t coap_opt_encode(coap_opt_t *opt,
size_t n,
unsigned short delta,
const unsigned char *val,
uint16_t delta,
const uint8_t *val,
size_t length);
/**
@ -364,14 +359,7 @@ size_t coap_opt_encode(coap_opt_t *opt,
*
* @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)
uint16_t coap_opt_delta(const coap_opt_t *opt);
/**
* Returns the length of the given option. @p opt must point to an option jump
@ -386,10 +374,7 @@ unsigned short coap_opt_delta(const coap_opt_t *opt);
*
* @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)
uint16_t coap_opt_length(const coap_opt_t *opt);
/**
* Returns a pointer to the value of the given option. @p opt must point to an
@ -400,11 +385,77 @@ unsigned short coap_opt_length(const coap_opt_t *opt);
*
* @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)
const uint8_t *coap_opt_value(const coap_opt_t *opt);
/** @} */
#endif /* _OPTION_H_ */
/**
* Representation of chained list of CoAP options to install.
*
* @code
* coap_optlist_t *optlist_chain = NULL;
* coap_pdu_t *pdu = coap_new_pdu(session);
*
* ... other set up code ...
* coap_insert_optlist(&optlist_chain, coap_new_optlist(COAP_OPTION_OBSERVE,
* COAP_OBSERVE_ESTABLISH, NULL));
*
* coap_add_optlist_pdu(pdu, &optlist_chain);
* ... other code ...
* coap_delete_optlist(optlist_chain);
* @endcode
*/
typedef struct coap_optlist_t {
struct coap_optlist_t *next; /**< next entry in the optlist chain */
uint16_t number; /**< the option number (no delta coding) */
size_t length; /**< the option value length */
uint8_t *data; /**< the option data */
} coap_optlist_t;
/**
* Create a new optlist entry.
*
* @param number The option number (COAP_OPTION_*)
* @param length The option length
* @param data The option value data
*
* @return A pointer to the new optlist entry, or @c NULL if error
*/
coap_optlist_t *coap_new_optlist(uint16_t number,
size_t length,
const uint8_t *data);
/**
* The current optlist of @p optlist_chain is first sorted (as per RFC7272
* ordering requirements) and then added to the @p pdu.
*
* @param pdu The pdu to add the options to from the chain list
* @param optlist_chain The chained list of optlist to add to the pdu
*
* @return @c 1 if succesful or @c 0 if failure;
*/
int coap_add_optlist_pdu(coap_pdu_t *pdu, coap_optlist_t** optlist_chain);
/**
* Adds @p optlist to the given @p optlist_chain. The optlist_chain variable
* be set to NULL before the initial call to coap_insert_optlist().
* The optlist_chain will need to be deleted using coap_delete_optlist()
* when no longer required.
*
* @param optlist_chain The chain to add optlist to
* @param optlist The optlist to add to the queue
*
* @return @c 1 if successful, @c 0 otherwise.
*/
int coap_insert_optlist(coap_optlist_t **optlist_chain,
coap_optlist_t *optlist);
/**
* Removes all entries from the @p optlist_chain, freeing off their
* memory usage.
*
* @param optlist_chain The optlist chain to remove all the entries from
*/
void coap_delete_optlist(coap_optlist_t *optlist_chain);
#endif /* COAP_OPTION_H_ */

View File

@ -12,20 +12,54 @@
* @brief Pre-defined constants that reflect defaults for CoAP
*/
#ifndef _COAP_PDU_H_
#define _COAP_PDU_H_
#ifndef COAP_PDU_H_
#define COAP_PDU_H_
#include "uri.h"
struct coap_session_t;
#ifdef WITH_LWIP
#include <lwip/pbuf.h>
#endif
#define COAP_DEFAULT_PORT 5683 /* CoAP default UDP port */
#include <stdint.h>
#define COAP_DEFAULT_PORT 5683 /* CoAP default UDP/TCP port */
#define COAPS_DEFAULT_PORT 5684 /* CoAP default UDP/TCP port for secure transmission */
#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 */
#ifndef COAP_DEFAULT_MTU
#define COAP_DEFAULT_MTU 1152
#endif /* COAP_DEFAULT_MTU */
/* TCP Message format constants, do not modify */
#define COAP_MESSAGE_SIZE_OFFSET_TCP8 13
#define COAP_MESSAGE_SIZE_OFFSET_TCP16 269 /* 13 + 256 */
#define COAP_MESSAGE_SIZE_OFFSET_TCP32 65805 /* 269 + 65536 */
/* Derived message size limits */
#define COAP_MAX_MESSAGE_SIZE_TCP0 (COAP_MESSAGE_SIZE_OFFSET_TCP8-1) /* 12 */
#define COAP_MAX_MESSAGE_SIZE_TCP8 (COAP_MESSAGE_SIZE_OFFSET_TCP16-1) /* 268 */
#define COAP_MAX_MESSAGE_SIZE_TCP16 (COAP_MESSAGE_SIZE_OFFSET_TCP32-1) /* 65804 */
#define COAP_MAX_MESSAGE_SIZE_TCP32 (COAP_MESSAGE_SIZE_OFFSET_TCP32+0xFFFFFFFF)
#ifndef COAP_DEFAULT_MAX_PDU_RX_SIZE
#if defined(WITH_CONTIKI) || defined(WITH_LWIP)
#define COAP_DEFAULT_MAX_PDU_RX_SIZE (COAP_MAX_MESSAGE_SIZE_TCP16+4)
#else
/* 8 MiB max-message-size plus some space for options */
#define COAP_DEFAULT_MAX_PDU_RX_SIZE (8*1024*1024+256)
#endif
#endif /* COAP_DEFAULT_MAX_PDU_RX_SIZE */
#ifndef COAP_DEBUG_BUF_SIZE
#if defined(WITH_CONTIKI) || defined(WITH_LWIP)
#define COAP_DEBUG_BUF_SIZE 128
#else /* defined(WITH_CONTIKI) || defined(WITH_LWIP) */
/* 1024 derived from RFC7252 4.6. Message Size max payload */
#define COAP_DEBUG_BUF_SIZE (8 + 1024 * 2)
#endif /* defined(WITH_CONTIKI) || defined(WITH_LWIP) */
#endif /* COAP_DEBUG_BUF_SIZE */
#define COAP_DEFAULT_VERSION 1 /* version of CoAP supported */
#define COAP_DEFAULT_SCHEME "coap" /* the default scheme for CoAP URIs */
@ -33,11 +67,6 @@
/** 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) */
@ -51,8 +80,14 @@
#define COAP_REQUEST_POST 2
#define COAP_REQUEST_PUT 3
#define COAP_REQUEST_DELETE 4
#define COAP_REQUEST_FETCH 5 /* RFC 8132 */
#define COAP_REQUEST_PATCH 6 /* RFC 8132 */
#define COAP_REQUEST_IPATCH 7 /* RFC 8132 */
/* CoAP option types (be sure to update check_critical when adding options */
/*
* CoAP option types (be sure to update coap_option_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 */
@ -67,6 +102,7 @@
#define COAP_OPTION_URI_QUERY 15 /* C, String, 1-255 B, (none) */
#define COAP_OPTION_ACCEPT 17 /* C, uint, 0-2 B, (none) */
#define COAP_OPTION_LOCATION_QUERY 20 /* E, String, 0-255 B, (none) */
#define COAP_OPTION_SIZE2 28 /* E, uint, 0-4 B, (none) */
#define COAP_OPTION_PROXY_URI 35 /* C, String, 1-1034 B, (none) */
#define COAP_OPTION_PROXY_SCHEME 39 /* C, String, 1-255 B, (none) */
#define COAP_OPTION_SIZE1 60 /* E, uint, 0-4 B, (none) */
@ -109,7 +145,7 @@
* @return A zero-terminated string describing the error, or @c NULL if not
* found.
*/
char *coap_response_phrase(unsigned char code);
const char *coap_response_phrase(unsigned char code);
#define COAP_ERROR_PHRASE_LENGTH 32 /**< maximum length of error phrase */
@ -140,6 +176,24 @@ char *coap_response_phrase(unsigned char code);
#endif
#define COAP_RESPONSE_X_242 COAP_RESPONSE_CODE(402) /* Critical Option not supported */
#define COAP_SIGNALING_CODE(N) (((N)/100 << 5) | (N)%100)
#define COAP_SIGNALING_CSM COAP_SIGNALING_CODE(701)
#define COAP_SIGNALING_PING COAP_SIGNALING_CODE(702)
#define COAP_SIGNALING_PONG COAP_SIGNALING_CODE(703)
#define COAP_SIGNALING_RELEASE COAP_SIGNALING_CODE(704)
#define COAP_SIGNALING_ABORT COAP_SIGNALING_CODE(705)
/* Applies to COAP_SIGNALING_CSM */
#define COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE 2
#define COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER 4
/* Applies to COAP_SIGNALING_PING / COAP_SIGNALING_PONG */
#define COAP_SIGNALING_OPTION_CUSTODY 2
/* Applies to COAP_SIGNALING_RELEASE */
#define COAP_SIGNALING_OPTION_ALTERNATIVE_ADDRESS 2
#define COAP_SIGNALING_OPTION_HOLD_OFF 4
/* Applies to COAP_SIGNALING_ABORT */
#define COAP_SIGNALING_OPTION_BAD_CSM_OPTION 2
/* CoAP media type encoding */
#define COAP_MEDIATYPE_TEXT_PLAIN 0 /* text/plain (UTF-8) */
@ -151,6 +205,27 @@ char *coap_response_phrase(unsigned char code);
#define COAP_MEDIATYPE_APPLICATION_JSON 50 /* application/json */
#define COAP_MEDIATYPE_APPLICATION_CBOR 60 /* application/cbor */
/* Content formats from RFC 8152 */
#define COAP_MEDIATYPE_APPLICATION_COSE_SIGN 98 /* application/cose; cose-type="cose-sign" */
#define COAP_MEDIATYPE_APPLICATION_COSE_SIGN1 18 /* application/cose; cose-type="cose-sign1" */
#define COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT 96 /* application/cose; cose-type="cose-encrypt" */
#define COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT0 16 /* application/cose; cose-type="cose-encrypt0" */
#define COAP_MEDIATYPE_APPLICATION_COSE_MAC 97 /* application/cose; cose-type="cose-mac" */
#define COAP_MEDIATYPE_APPLICATION_COSE_MAC0 17 /* application/cose; cose-type="cose-mac0" */
#define COAP_MEDIATYPE_APPLICATION_COSE_KEY 101 /* application/cose-key */
#define COAP_MEDIATYPE_APPLICATION_COSE_KEY_SET 102 /* application/cose-key-set */
/* Content formats from RFC 8428 */
#define COAP_MEDIATYPE_APPLICATION_SENML_JSON 110 /* application/senml+json */
#define COAP_MEDIATYPE_APPLICATION_SENSML_JSON 111 /* application/sensml+json */
#define COAP_MEDIATYPE_APPLICATION_SENML_CBOR 112 /* application/senml+cbor */
#define COAP_MEDIATYPE_APPLICATION_SENSML_CBOR 113 /* application/sensml+cbor */
#define COAP_MEDIATYPE_APPLICATION_SENML_EXI 114 /* application/senml-exi */
#define COAP_MEDIATYPE_APPLICATION_SENSML_EXI 115 /* application/sensml-exi */
#define COAP_MEDIATYPE_APPLICATION_SENML_XML 310 /* application/senml+xml */
#define COAP_MEDIATYPE_APPLICATION_SENSML_XML 311 /* application/sensml+xml */
/* 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 */
@ -171,32 +246,7 @@ typedef int coap_tid_t;
*/
#define COAP_DROPPED_RESPONSE -2
#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)
#define COAP_PDU_DELAYED -3
#define COAP_OPT_LONG 0x0F /* OC == 0b1111 indicates that the option list
* in a CoAP message is limited by 0b11110000
@ -207,12 +257,14 @@ typedef struct {
#define COAP_PAYLOAD_START 0xFF /* payload marker */
/**
* @deprecated Use coap_optlist_t instead.
*
* Structures for more convenient handling of options. (To be used with ordered
* coap_list_t.) The option's data will be added to the end of the coap_option
* structure (see macro COAP_OPTION_DATA).
*/
typedef struct {
unsigned short key; /* the option key (no delta coding) */
COAP_DEPRECATED typedef struct {
uint16_t key; /* the option key (no delta coding) */
unsigned int length;
} coap_option;
@ -221,35 +273,49 @@ typedef struct {
#define COAP_OPTION_DATA(option) ((unsigned char *)&(option) + sizeof(coap_option))
/**
* Header structure for CoAP PDUs
* structure for CoAP PDUs
* token, if any, follows the fixed size header, then options until
* payload marker (0xff), then the payload if stored inline.
* Memory layout is:
* <---header--->|<---token---><---options--->0xff<---payload--->
* header is addressed with a negative offset to token, its maximum size is
* max_hdr_size.
* options starts at token + token_length
* payload starts at data, its length is used_size - (data - token)
*/
typedef struct {
size_t max_size; /**< allocated storage for options and data */
coap_hdr_t *hdr; /**< Address of the first byte of the CoAP message.
* This may or may not equal (coap_hdr_t*)(pdu+1)
* depending on the memory management
* implementation. */
unsigned short max_delta; /**< highest option number */
unsigned short length; /**< PDU length (including header, options, data) */
unsigned char *data; /**< payload */
typedef struct coap_pdu_t {
uint8_t type; /**< message type */
uint8_t code; /**< request method (value 1--10) or response code (value 40-255) */
uint8_t max_hdr_size; /**< space reserved for protocol-specific header */
uint8_t hdr_size; /**< actaul size used for protocol-specific header */
uint8_t token_length; /**< length of Token */
uint16_t tid; /**< transaction id, if any, in regular host byte order */
uint16_t max_delta; /**< highest option number */
size_t alloc_size; /**< allocated storage for token, options and payload */
size_t used_size; /**< used bytes of storage for token, options and payload */
size_t max_size; /**< maximum size for token, options and payload, or zero for variable size pdu */
uint8_t *token; /**< first byte of token, if any, or options */
uint8_t *data; /**< first byte of payload, if any */
#ifdef WITH_LWIP
struct pbuf *pbuf; /**< lwIP PBUF. The package data will always reside
* inside the pbuf's payload, but this pointer
* has to be kept because no exact offset can be
* given. This field must not be accessed from
* outside, because the pbuf's reference count
* is checked to be 1 when the pbuf is assigned
* to the pdu, and the pbuf stays exclusive to
* this pdu. */
* inside the pbuf's payload, but this pointer
* has to be kept because no exact offset can be
* given. This field must not be accessed from
* outside, because the pbuf's reference count
* is checked to be 1 when the pbuf is assigned
* to the pdu, and the pbuf stays exclusive to
* this pdu. */
#endif
} coap_pdu_t;
/**
* Options in coap_pdu_t are accessed with the macro COAP_OPTION.
*/
#define COAP_OPTION(node) ((coap_option *)(node)->options)
#define COAP_PDU_IS_EMPTY(pdu) ((pdu)->code == 0)
#define COAP_PDU_IS_REQUEST(pdu) (!COAP_PDU_IS_EMPTY(pdu) && (pdu)->code < 32)
#define COAP_PDU_IS_RESPONSE(pdu) ((pdu)->code >= 64 && (pdu)->code < 224)
#define COAP_PDU_IS_SIGNALING(pdu) ((pdu)->code >= 224)
#define COAP_PDU_MAX_UDP_HEADER_SIZE 4
#define COAP_PDU_MAX_TCP_HEADER_SIZE 6
#ifdef WITH_LWIP
/**
@ -270,29 +336,47 @@ typedef struct {
coap_pdu_t * coap_pdu_from_pbuf(struct pbuf *pbuf);
#endif
typedef uint8_t coap_proto_t;
/**
* 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
* coap_proto_t values
*/
#define COAP_PROTO_NONE 0
#define COAP_PROTO_UDP 1
#define COAP_PROTO_DTLS 2
#define COAP_PROTO_TCP 3
#define COAP_PROTO_TLS 4
/**
* Creates a new CoAP PDU with at least enough storage space for the given
* @p size maximum message size. 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().
* for the result must be released with coap_delete_pdu() if coap_send() is not
* called.
*
* @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.
*
* @param tid The transcation id to set or 0 if unknown / not applicable.
* @param size The maximum allowed number of byte for the 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);
coap_pdu_init(uint8_t type, uint8_t code, uint16_t tid, 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
* Dynamically grows the size of @p pdu to @p new_size. The new size
* must not exceed the PDU's configure maximum size. On success, this
* function returns 1, otherwise 0.
*
* @param pdu The PDU to resize.
* @param new_size The new size in bytes.
* @return 1 if the operation succeeded, 0 otherwise.
*/
int coap_pdu_resize(coap_pdu_t *pdu, size_t new_size);
/**
* Clears any contents from @p pdu and resets @c used_size,
* and @c data pointers. @c max_size is set to @p size, any
* 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().
*/
@ -300,37 +384,90 @@ 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);
coap_pdu_t *coap_new_pdu(const struct coap_session_t *session);
/**
* Dispose of an CoAP PDU and frees associated storage.
* Not that in general you should not call this function directly.
* When a PDU is sent with coap_send(), coap_delete_pdu() will be
* called automatically for you.
*/
void coap_delete_pdu(coap_pdu_t *);
/**
* Parses @p data into the CoAP PDU structure given in @p result.
* Interprets @p data to determine the number of bytes in the header.
* This function returns @c 0 on error or a number greater than zero on success.
*
* @param proto Session's protocol
* @param data The first byte of raw data to parse as CoAP PDU.
*
* @return A value greater than zero on success or @c 0 on error.
*/
size_t coap_pdu_parse_header_size(coap_proto_t proto,
const uint8_t *data);
/**
* Parses @p data to extract the message size.
* @p length must be at least coap_pdu_parse_header_size(proto, data).
* This function returns @c 0 on error or a number greater than zero on success.
*
* @param proto Session's protocol
* @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);
size_t coap_pdu_parse_size(coap_proto_t proto,
const uint8_t *data,
size_t length);
/**
* Decode the protocol specific header for the specified PDU.
* @param pdu A newly received PDU.
* @param proto The target wire protocol.
* @return 1 for success or 0 on error.
*/
int coap_pdu_parse_header(coap_pdu_t *pdu, coap_proto_t proto);
/**
* Verify consistency in the given CoAP PDU structure and locate the data.
* This function returns @c 0 on error or a number greater than zero on
* success.
* This function only parses the token and options, up to the payload start
* marker.
*
* @param pdu The PDU structure to.
*
* @return 1 on success or @c 0 on error.
*/
int coap_pdu_parse_opt(coap_pdu_t *pdu);
/**
* Parses @p data into the CoAP PDU structure given in @p result.
* The target pdu must be large enough to
* This function returns @c 0 on error or a number greater than zero on success.
*
* @param proto Session's protocol
* @param data The raw data to parse as CoAP PDU.
* @param length The actual size of @p data.
* @param pdu The PDU structure to fill. Note that the structure must
* provide space to hold at least the token and options
* part of the message.
*
* @return 1 on success or @c 0 on error.
*/
int coap_pdu_parse(coap_proto_t proto,
const uint8_t *data,
size_t length,
coap_pdu_t *pdu);
/**
* 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
* length is set to @p len + @c 4, and max_delta is set to @c 0. This function
* returns @c 0 on error or a value greater than zero on success.
*
* @param pdu The PDU where the token is to be added.
@ -341,7 +478,7 @@ int coap_pdu_parse(unsigned char *data,
*/
int coap_add_token(coap_pdu_t *pdu,
size_t len,
const unsigned char *data);
const uint8_t *data);
/**
* Adds option of given type to pdu that is passed as first
@ -352,9 +489,9 @@ int coap_add_token(coap_pdu_t *pdu,
* 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);
uint16_t type,
size_t len,
const uint8_t *data);
/**
* Adds option of given type to pdu that is passed as first parameter, but does
@ -363,9 +500,9 @@ size_t coap_add_option(coap_pdu_t *pdu,
* 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);
uint8_t *coap_add_option_later(coap_pdu_t *pdu,
uint16_t type,
size_t len);
/**
* Adds given data to the pdu that is passed as first parameter. Note that the
@ -373,16 +510,34 @@ unsigned char *coap_add_option_later(coap_pdu_t *pdu,
* only once per PDU, otherwise the result is undefined.
*/
int coap_add_data(coap_pdu_t *pdu,
unsigned int len,
const unsigned char *data);
size_t len,
const uint8_t *data);
/**
* Adds given data to the pdu that is passed as first parameter but does not
* copyt it. Note that the PDU's data is destroyed by coap_add_option().
* coap_add_data() must be have been called once for this PDU, otherwise the
* result is undefined.
* The actual data must be copied at the returned location.
*/
uint8_t *coap_add_data_after(coap_pdu_t *pdu, size_t len);
/**
* 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,
int coap_get_data(const coap_pdu_t *pdu,
size_t *len,
unsigned char **data);
uint8_t **data);
#endif /* _COAP_PDU_H_ */
/**
* Compose the protocol specific header for the specified PDU.
* @param pdu A newly composed PDU.
* @param proto The target wire protocol.
* @return Number of header bytes prepended before pdu->token or 0 on error.
*/
size_t coap_pdu_encode_header(coap_pdu_t *pdu, coap_proto_t proto);
#endif /* COAP_PDU_H_ */

View File

@ -12,31 +12,16 @@
* @brief Pseudo Random Numbers
*/
#ifndef _COAP_PRNG_H_
#define _COAP_PRNG_H_
#ifndef COAP_PRNG_H_
#define COAP_PRNG_H_
/**
* @defgroup prng Pseudo Random Numbers
* API functions for gerating pseudo random numbers
* @{
*/
#if defined(WITH_POSIX) || (defined(WITH_LWIP) && !defined(LWIP_RAND))
#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;
}
#endif /* WITH_POSIX */
#ifdef WITH_CONTIKI
#if defined(WITH_CONTIKI)
#include <string.h>
/**
@ -44,9 +29,9 @@ coap_prng_impl(unsigned char *buf, size_t len) {
* prng(). You might want to change prng() to use a better PRNG on your specific
* platform.
*/
static inline int
COAP_STATIC_INLINE int
contiki_prng_impl(unsigned char *buf, size_t len) {
unsigned short v = random_rand();
uint16_t v = random_rand();
while (len > sizeof(v)) {
memcpy(buf, &v, sizeof(v));
len -= sizeof(v);
@ -59,11 +44,9 @@ contiki_prng_impl(unsigned char *buf, size_t len) {
}
#define prng(Buf,Length) contiki_prng_impl((Buf), (Length))
#define prng_init(Value) random_init((unsigned short)(Value))
#endif /* WITH_CONTIKI */
#if defined(WITH_LWIP) && defined(LWIP_RAND)
static inline int
#define prng_init(Value) random_init((uint16_t)(Value))
#elif defined(WITH_LWIP) && defined(LWIP_RAND)
COAP_STATIC_INLINE int
lwip_prng_impl(unsigned char *buf, size_t len) {
u32_t v = LWIP_RAND();
while (len > sizeof(v)) {
@ -79,8 +62,46 @@ lwip_prng_impl(unsigned char *buf, size_t len) {
#define prng(Buf,Length) lwip_prng_impl((Buf), (Length))
#define prng_init(Value)
#elif defined(_WIN32)
#define prng_init(Value)
errno_t __cdecl rand_s( _Out_ unsigned int* _RandomValue );
/**
* 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.
*/
COAP_STATIC_INLINE int
coap_prng_impl( unsigned char *buf, size_t len ) {
while ( len != 0 ) {
uint32_t r = 0;
size_t i;
if ( rand_s( &r ) != 0 )
return 0;
for ( i = 0; i < len && i < 4; i++ ) {
*buf++ = (uint8_t)r;
r >>= 8;
}
len -= i;
}
return 1;
}
#else
#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.
*/
COAP_STATIC_INLINE int
coap_prng_impl( unsigned char *buf, size_t len ) {
while ( len-- )
*buf++ = rand() & 0xFF;
return 1;
}
#endif
#endif /* WITH_LWIP */
#ifndef prng
/**
@ -103,4 +124,4 @@ lwip_prng_impl(unsigned char *buf, size_t len) {
/** @} */
#endif /* _COAP_PRNG_H_ */
#endif /* COAP_PRNG_H_ */

View File

@ -12,8 +12,8 @@
* @brief Generic resource handling
*/
#ifndef _COAP_RESOURCE_H_
#define _COAP_RESOURCE_H_
#ifndef COAP_RESOURCE_H_
#define COAP_RESOURCE_H_
# include <assert.h>
@ -22,13 +22,7 @@
#define COAP_RESOURCE_CHECK_TIME 2
#endif /* COAP_RESOURCE_CHECK_TIME */
#ifdef COAP_RESOURCES_NOHASH
# include "utlist.h"
#else
# include "uthash.h"
#endif
#include "hashkey.h"
#include "uthash.h"
#include "async.h"
#include "str.h"
#include "pdu.h"
@ -41,10 +35,10 @@
typedef void (*coap_method_handler_t)
(coap_context_t *,
struct coap_resource_t *,
const coap_endpoint_t *,
coap_address_t *,
coap_session_t *,
coap_pdu_t *,
str * /* token */,
coap_binary_t * /* token */,
coap_string_t * /* query string */,
coap_pdu_t * /* response */);
#define COAP_ATTR_FLAGS_RELEASE_NAME 0x1
@ -52,8 +46,8 @@ typedef void (*coap_method_handler_t)
typedef struct coap_attr_t {
struct coap_attr_t *next;
str name;
str value;
coap_str_const_t *name;
coap_str_const_t *value;
int flags;
} coap_attr_t;
@ -78,63 +72,152 @@ typedef struct coap_resource_t {
* been notified of the last change */
unsigned int observable:1; /**< can be observed */
unsigned int cacheable:1; /**< can be cached */
unsigned int is_unknown:1; /**< resource created for unknown handler */
/**
* 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
* Used to store handlers for the seven coap methods @c GET, @c POST, @c PUT,
* @c DELETE, @c FETCH, @c PATCH and @c IPATCH.
* 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_method_handler_t handler[7];
coap_key_t key; /**< the actual key bytes for this resource */
#ifdef COAP_RESOURCES_NOHASH
struct coap_resource_t *next;
#else
UT_hash_handle hh;
#endif
coap_attr_t *link_attr; /**< attributes to be included with the link format */
coap_subscription_t *subscribers; /**< list of observers for this resource */
/**
* Request URI for this resource. This field will point into the static
* memory.
* Request URI Path for this resource. This field will point into static
* or allocated memory which must remain there for the duration of the
* resource.
*/
str uri;
coap_str_const_t *uri_path; /**< the key used for hash lookup for this resource */
int flags;
/**
* The next value for the Observe option. This field must be increased each
* time the resource changes. Only the lower 24 bits are sent.
*/
unsigned int observe;
/**
* This pointer is under user control. It can be used to store context for
* the coap handler.
*/
void *user_data;
} 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.
* @p uri_path. 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).
* If the string is going to be freed off by coap_delete_resource() when
* COAP_RESOURCE_FLAGS_RELEASE_URI is set in @p flags, then either the 's'
* variable of coap_str_const_t has to point to constant text, or point to data
* within the allocated coap_str_const_t parameter.
*
* @return A pointer to the new object or @c NULL on error.
* @param uri_path The string URI path of the new resource.
* @param flags Flags for memory management (in particular release of
* memory). Possible values:@n
*
* COAP_RESOURCE_FLAGS_RELEASE_URI
* If this flag is set, the URI passed to
* coap_resource_init() is free'd by
* coap_delete_resource()@n
*
* COAP_RESOURCE_FLAGS_NOTIFY_CON
* If this flag is set, coap-observe notifications
* will be sent confirmable by default.@n
*
* COAP_RESOURCE_FLAGS_NOTIFY_NON (default)
* If this flag is set, coap-observe notifications
* will be sent non-confirmable by default.@n
*
* If flags is set to 0 then the
* COAP_RESOURCE_FLAGS_NOTIFY_NON is considered.
*
* @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);
coap_resource_t *coap_resource_init(coap_str_const_t *uri_path,
int flags);
/**
* Sets the notification message type of resource @p r to given
* @p mode which must be one of @c COAP_RESOURCE_FLAGS_NOTIFY_NON
* or @c COAP_RESOURCE_FLAGS_NOTIFY_CON.
* Creates a new resource object for the unknown resource handler with support
* for PUT.
*
* In the same way that additional handlers can be added to the resource
* created by coap_resource_init() by using coap_register_handler(), POST,
* GET, DELETE etc. handlers can be added to this resource. It is the
* responsibility of the application to manage the unknown resources by either
* creating new resources with coap_resource_init() (which should have a
* DELETE handler specified for the resource removal) or by maintaining an
* active resource list.
*
* Note: There can only be one unknown resource handler per context - attaching
* a new one overrides the previous definition.
*
* Note: It is not possible to observe the unknown resource with a GET request
* - a separate resource needs to be reated by the PUT (or POST) handler,
* and make that resource observable.
*
* This function returns the new coap_resource_t object.
*
* @param put_handler The PUT handler to register with @p resource for
* unknown Uri-Path.
*
* @return A pointer to the new object or @c NULL on error.
*/
static inline void
coap_resource_set_mode(coap_resource_t *r, int mode) {
r->flags = (r->flags & !COAP_RESOURCE_FLAGS_NOTIFY_CON) | mode;
coap_resource_t *coap_resource_unknown_init(coap_method_handler_t put_handler);
/**
* Sets the notification message type of resource @p resource to given
* @p mode
* @param resource The resource to update.
* @param mode Must be one of @c COAP_RESOURCE_FLAGS_NOTIFY_NON
* or @c COAP_RESOURCE_FLAGS_NOTIFY_CON.
*/
COAP_STATIC_INLINE void
coap_resource_set_mode(coap_resource_t *resource, int mode) {
resource->flags = (resource->flags &
~(COAP_RESOURCE_FLAGS_NOTIFY_CON|COAP_RESOURCE_FLAGS_NOTIFY_NON)) |
(mode & (COAP_RESOURCE_FLAGS_NOTIFY_CON|COAP_RESOURCE_FLAGS_NOTIFY_NON));
}
/**
* Sets the user_data. The user_data is exclusively used by the library-user
* and can be used as context in the handler functions.
*
* @param r Resource to attach the data to
* @param data Data to attach to the user_data field. This pointer is only used for
* storage, the data remains under user control
*/
COAP_STATIC_INLINE void
coap_resource_set_userdata(coap_resource_t *r, void *data) {
r->user_data = data;
}
/**
* Gets the user_data. The user_data is exclusively used by the library-user
* and can be used as context in the handler functions.
*
* @param r Resource to retrieve the user_darta from
*
* @return The user_data pointer
*/
COAP_STATIC_INLINE void *
coap_resource_get_userdata(coap_resource_t *r) {
return r->user_data;
}
/**
* 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().
* created by coap_resource_init() or coap_resource_unknown_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.
@ -142,16 +225,16 @@ coap_resource_set_mode(coap_resource_t *r, int mode) {
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.
* Deletes a resource identified by @p resource. The storage allocated for that
* resource is freed, and removed from the context.
*
* @param context The context where the resources are stored.
* @param key The unique key for the resource to delete.
* @param resource 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);
int coap_delete_resource(coap_context_t *context, coap_resource_t *resource);
/**
* Deletes all resources from given @p context and frees their storage.
@ -162,25 +245,37 @@ void coap_delete_all_resources(coap_context_t *context);
/**
* Registers a new attribute with the given @p resource. As the
* attributes str fields will point to @p name and @p val the
* attribute's coap_str_const_ fields will point to @p name and @p value the
* caller must ensure that these pointers are valid during the
* attribute's lifetime.
* If the @p name and/or @p value string is going to be freed off at attribute
* removal time by the setting of COAP_ATTR_FLAGS_RELEASE_NAME or
* COAP_ATTR_FLAGS_RELEASE_VALUE in @p flags, then either the 's'
* variable of coap_str_const_t has to point to constant text, or point to data
* within the allocated coap_str_const_t parameter.
*
* @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 name The attribute's name as a string.
* @param value The attribute's value as a string or @c NULL if none.
* @param flags Flags for memory management (in particular release of
* memory).
* memory). Possible values:@n
*
* COAP_ATTR_FLAGS_RELEASE_NAME
* If this flag is set, the name passed to
* coap_add_attr_release() is free'd
* when the attribute is deleted@n
*
* COAP_ATTR_FLAGS_RELEASE_VALUE
* If this flag is set, the value passed to
* coap_add_attr_release() is free'd
* when the attribute is deleted@n
*
* @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,
coap_str_const_t *name,
coap_str_const_t *value,
int flags);
/**
@ -188,17 +283,16 @@ coap_attr_t *coap_add_attr(coap_resource_t *resource,
* 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.
* @param name Name of the requested attribute as a string.
* @return The first attribute with specified @p name or @c NULL if none
* was found.
*/
coap_attr_t *coap_find_attr(coap_resource_t *resource,
const unsigned char *name,
size_t nlen);
coap_str_const_t *name);
/**
* Deletes an attribute.
* Note: This is for internal use only, as it is not deleted from its chain.
*
* @param attr Pointer to a previously created attribute.
*
@ -255,35 +349,21 @@ coap_print_status_t coap_print_link(const coap_resource_t *resource,
* @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;
}
void coap_register_handler(coap_resource_t *resource,
unsigned char method,
coap_method_handler_t handler);
/**
* Returns the resource identified by the unique string @p key. If no resource
* was found, this function returns @c NULL.
* Returns the resource identified by the unique string @p uri_path. 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.
* @param uri_path The unique string uri 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);
coap_resource_t *coap_get_resource_from_uri_path(coap_context_t *context,
coap_str_const_t *uri_path);
/**
* @addtogroup observe
@ -296,42 +376,46 @@ void coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key);
* error.
*
* @param resource The observed resource.
* @param local_interface The local network interface where the observer is
* attached to.
* @param observer The remote peer that wants to received status updates.
* @param session The observer's session
* @param token The token that identifies this subscription.
* @param query The query string, if any. subscription will
take ownership of the string.
* @param has_block2 If Option Block2 defined.
* @param block2 Contents of Block2 if Block 2 defined.
* @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_endpoint_t *local_interface,
const coap_address_t *observer,
const str *token);
coap_session_t *session,
const coap_binary_t *token,
coap_string_t *query,
int has_block2,
coap_block_t block2);
/**
* Returns a subscription object for given @p peer.
*
* @param resource The observed resource.
* @param peer The address to search for.
* @param session The observer's session
* @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);
coap_session_t *session,
const coap_binary_t *token);
/**
* Marks an observer as alive.
*
* @param context The CoAP context to use.
* @param observer The transport address of the observer.
* @param session The observer's session
* @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);
coap_session_t *session,
const coap_binary_t *token);
/**
* Removes any subscription for @p observer from @p resource and releases the
@ -339,14 +423,22 @@ void coap_touch_observer(coap_context_t *context,
* observer and @p token existed, @c 0 otherwise.
*
* @param resource The observed resource.
* @param observer The observer's address.
* @param session The observer's session.
* @param token The token that identifies this subscription or @c NULL for
* any token.
* @return @c 1 if the observer has been deleted, @c 0 otherwise.
*/
int coap_delete_observer(coap_resource_t *resource,
const coap_address_t *observer,
const str *token);
coap_session_t *session,
const coap_binary_t *token);
/**
* Removes any subscription for @p session and releases the allocated storage.
*
* @param context The CoAP context to use.
* @param session The observer's session.
*/
void coap_delete_observers(coap_context_t *context, coap_session_t *session);
/**
* Checks for all known resources, if they are dirty and notifies subscribed
@ -354,32 +446,8 @@ int coap_delete_observer(coap_resource_t *resource,
*/
void coap_check_notify(coap_context_t *context);
#ifdef COAP_RESOURCES_NOHASH
#define RESOURCES_ADD(r, obj) \
LL_PREPEND((r), (obj))
#define RESOURCES_DELETE(r, obj) \
LL_DELETE((r), (obj))
#define RESOURCES_ITER(r,tmp) \
coap_resource_t *tmp; \
LL_FOREACH((r), tmp)
#define RESOURCES_FIND(r, k, res) { \
coap_resource_t *tmp; \
(res) = tmp = NULL; \
LL_FOREACH((r), tmp) { \
if (memcmp((k), tmp->key, sizeof(coap_key_t)) == 0) { \
(res) = tmp; \
break; \
} \
} \
}
#else /* COAP_RESOURCES_NOHASH */
#define RESOURCES_ADD(r, obj) \
HASH_ADD(hh, (r), key, sizeof(coap_key_t), (obj))
HASH_ADD(hh, (r), uri_path->s[0], (obj)->uri_path->length, (obj))
#define RESOURCES_DELETE(r, obj) \
HASH_DELETE(hh, (r), (obj))
@ -389,11 +457,9 @@ void coap_check_notify(coap_context_t *context);
HASH_ITER(hh, (r), tmp, rtmp)
#define RESOURCES_FIND(r, k, res) { \
HASH_FIND(hh, (r), (k), sizeof(coap_key_t), (res)); \
HASH_FIND(hh, (r), (k)->s, (k)->length, (res)); \
}
#endif /* COAP_RESOURCES_NOHASH */
/** @} */
coap_print_status_t coap_print_wellknown(coap_context_t *,
@ -401,8 +467,58 @@ coap_print_status_t coap_print_wellknown(coap_context_t *,
size_t *, size_t,
coap_opt_t *);
void coap_handle_failed_notify(coap_context_t *,
const coap_address_t *,
const str *);
void
coap_handle_failed_notify(coap_context_t *,
coap_session_t *,
const coap_binary_t *);
#endif /* _COAP_RESOURCE_H_ */
/**
* Set whether a @p resource is observable. If the resource is observable
* and the client has set the COAP_OPTION_OBSERVE in a request packet, then
* whenever the state of the resource changes (a call to
* coap_resource_trigger_observe()), an Observer response will get sent.
*
* @param resource The CoAP resource to use.
* @param mode @c 1 if Observable is to be set, @c 0 otherwise.
*
*/
COAP_STATIC_INLINE void
coap_resource_set_get_observable(coap_resource_t *resource, int mode) {
resource->observable = mode ? 1 : 0;
}
/**
* Initiate the sending of an Observe packet for all observers of @p resource,
* optionally matching @p query if not NULL
*
* @param resource The CoAP resource to use.
* @param query The Query to match against or NULL
*
* @return @c 1 if the Observe has been triggered, @c 0 otherwise.
*/
int
coap_resource_notify_observers(coap_resource_t *resource,
const coap_string_t *query);
/**
* Get the UriPath from a @p resource.
*
* @param resource The CoAP resource to check.
*
* @return The UriPath if it exists or @c NULL otherwise.
*/
COAP_STATIC_INLINE coap_str_const_t*
coap_resource_get_uri_path(coap_resource_t *resource) {
if (resource)
return resource->uri_path;
return NULL;
}
/**
* @deprecated use coap_resource_notify_observers() instead.
*/
COAP_DEPRECATED int
coap_resource_set_dirty(coap_resource_t *r,
const coap_string_t *query);
#endif /* COAP_RESOURCE_H_ */

View File

@ -7,27 +7,115 @@
* of use.
*/
#ifndef _COAP_STR_H_
#define _COAP_STR_H_
#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;
/**
* @defgroup string String handling support
* API functions for handling strings
* @{
*/
/**
* Coap string data definition
*/
typedef struct coap_string_t {
size_t length; /**< length of string */
uint8_t *s; /**< string data */
} coap_string_t;
/**
* Coap string data definition with const data
*/
typedef struct coap_str_const_t {
size_t length; /**< length of string */
const uint8_t *s; /**< string data */
} coap_str_const_t;
#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();
* Coap binary data definition
*/
str *coap_new_string(size_t size);
typedef struct coap_binary_t {
size_t length; /**< length of binary data */
uint8_t *s; /**< binary data */
} coap_binary_t;
/**
* Returns a new string object with at least size+1 bytes storage allocated.
* The string must be released using coap_delete_string().
*
* @param size The size to allocate for the binary string data.
*
* @return A pointer to the new object or @c NULL on error.
*/
coap_string_t *coap_new_string(size_t size);
/**
* Deletes the given string and releases any memory allocated.
*
* @param string The string to free off.
*/
void coap_delete_string(str *);
void coap_delete_string(coap_string_t *string);
#endif /* _COAP_STR_H_ */
/**
* Returns a new const string object with at least size+1 bytes storage
* allocated, and the provided data copied into the string object.
* The string must be released using coap_delete_str_const().
*
* @param data The data to put in the new string object.
* @param size The size to allocate for the binary string data.
*
* @return A pointer to the new object or @c NULL on error.
*/
coap_str_const_t *coap_new_str_const(const uint8_t *data, size_t size);
/**
* Deletes the given const string and releases any memory allocated.
*
* @param string The string to free off.
*/
void coap_delete_str_const(coap_str_const_t *string);
/**
* Take the specified byte array (text) and create a coap_str_const_t *
*
* WARNING: The byte array must be in the local scope and not a
* parameter in the function call as sizeof() will return the size of the
* pointer, not the size of the byte array, leading to unxepected results.
*
* @param string The const byte array to convert to a coap_str_const_t *
*/
#ifdef __cplusplus
namespace libcoap {
struct CoAPStrConst : coap_str_const_t {
operator coap_str_const_t *() { return this; }
};
}
#define coap_make_str_const(CStr) \
libcoap::CoAPStrConst{sizeof(CStr)-1, reinterpret_cast<const uint8_t *>(CStr)}
#else /* __cplusplus */
#define coap_make_str_const(string) \
(&(coap_str_const_t){sizeof(string)-1,(const uint8_t *)(string)})
#endif /* __cplusplus */
/**
* Compares the two strings for equality
*
* @param string1 The first string.
* @param string2 The second string.
*
* @return @c 1 if the strings are equal
* @c 0 otherwise.
*/
#define coap_string_equal(string1,string2) \
((string1)->length == (string2)->length && ((string1)->length == 0 || \
memcmp((string1)->s, (string2)->s, (string1)->length) == 0))
/** @} */
#endif /* COAP_STR_H_ */

View File

@ -1,6 +1,6 @@
/*
* subscribe.h -- subscription handling for CoAP
* see draft-ietf-core-observe-16
* see RFC7641
*
* Copyright (C) 2010-2012,2014-2015 Olaf Bergmann <bergmann@tzi.org>
*
@ -9,14 +9,16 @@
*/
#ifndef _COAP_SUBSCRIBE_H_
#define _COAP_SUBSCRIBE_H_
#ifndef COAP_SUBSCRIBE_H_
#define COAP_SUBSCRIBE_H_
#include "address.h"
#include "coap_io.h"
#include "block.h"
/**
* @defgroup observe Resource observation
* API functions for interfacing with the observe handling (RFC7641)
* @{
*/
@ -53,20 +55,22 @@
/** Subscriber information */
typedef struct coap_subscription_t {
struct coap_subscription_t *next; /**< next element in linked list */
coap_endpoint_t local_if; /**< local communication interface */
coap_address_t subscriber; /**< address and port of subscriber */
coap_session_t *session; /**< subscriber session */
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 partially
* dirty flag is set too) */
unsigned int has_block2:1; /**< GET request had Block2 definition */
coap_block_t block2; /**< GET request Block2 definition */
size_t token_length; /**< actual length of token */
unsigned char token[8]; /**< token used for subscription */
coap_string_t *query; /**< query string used for subscription, if any */
} coap_subscription_t;
void coap_subscription_init(coap_subscription_t *);
/** @} */
#endif /* _COAP_SUBSCRIBE_H_ */
#endif /* COAP_SUBSCRIBE_H_ */

View File

@ -7,24 +7,48 @@
* of use.
*/
#ifndef _COAP_URI_H_
#define _COAP_URI_H_
#ifndef COAP_URI_H_
#define COAP_URI_H_
#include <stdint.h>
#include "hashkey.h"
#include "str.h"
struct coap_pdu_t;
/**
* The scheme specifiers. Secure schemes have an odd numeric value,
* others are even.
*/
enum coap_uri_scheme_t {
COAP_URI_SCHEME_COAP=0,
COAP_URI_SCHEME_COAPS=1,
COAP_URI_SCHEME_COAP_TCP=2,
COAP_URI_SCHEME_COAPS_TCP=3
};
/** This mask can be used to check if a parsed URI scheme is secure. */
#define COAP_URI_SCHEME_SECURE_MASK 0x01
/**
* 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_str_const_t host; /**< host part of the URI */
uint16_t port; /**< The port in host byte order */
coap_str_const_t path; /**< Beginning of the first path segment.
Use coap_split_path() to create Uri-Path options */
coap_str_const_t query; /**< The query part if present */
/** The parsed scheme specifier. */
enum coap_uri_scheme_t scheme;
} coap_uri_t;
static inline int
coap_uri_scheme_is_secure(const coap_uri_t *uri) {
return uri && ((uri->scheme & COAP_URI_SCHEME_SECURE_MASK) != 0);
}
/**
* 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
@ -35,7 +59,7 @@ typedef struct {
*
* @return New URI object or NULL on error.
*/
coap_uri_t *coap_new_uri(const unsigned char *uri, unsigned int length);
coap_uri_t *coap_new_uri(const uint8_t *uri, unsigned int length);
/**
* Clones the specified coap_uri_t object. Thie function allocates sufficient
@ -43,18 +67,6 @@ coap_uri_t *coap_new_uri(const unsigned char *uri, unsigned int length);
* be released with coap_free(). */
coap_uri_t *coap_clone_uri(const coap_uri_t *uri);
/**
* Calculates a hash over the given path and stores the result in
* @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
*
@ -69,53 +81,67 @@ int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key);
* 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.
*
*/
int coap_split_uri(const unsigned char *str_var, size_t len, coap_uri_t *uri);
int coap_split_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri);
/**
* Splits the given URI path into segments. Each segment is preceded
* by an option pseudo-header with delta-value 0 and the actual length
* of the respective segment after percent-decoding.
*
* @param s The path string to split.
*
* @param s The path string to split.
* @param length The actual length of @p s.
* @param buf Result buffer for parsed segments.
* @param buf Result buffer for parsed segments.
* @param buflen Maximum length of @p buf. Will be set to the actual number
* of bytes written into buf on success.
*
*
* @return The number of segments created or @c -1 on error.
*/
int coap_split_path(const unsigned char *s,
int coap_split_path(const uint8_t *s,
size_t length,
unsigned char *buf,
size_t *buflen);
/**
/**
* Splits the given URI query into segments. Each segment is preceded
* by an option pseudo-header with delta-value 0 and the actual length
* of the respective query term.
*
* @param s The query string to split.
*
* @param s The query string to split.
* @param length The actual length of @p s.
* @param buf Result buffer for parsed segments.
* @param buf Result buffer for parsed segments.
* @param buflen Maximum length of @p buf. Will be set to the actual number
* of bytes written into buf on success.
*
*
* @return The number of segments created or @c -1 on error.
*
* @bug This function does not reserve additional space for delta > 12.
*/
int coap_split_query(const unsigned char *s,
int coap_split_query(const uint8_t *s,
size_t length,
unsigned char *buf,
size_t *buflen);
/**
* Extract query string from request PDU according to escape rules in 6.5.8.
* @param request Request PDU.
* @return Reconstructed and escaped query string part.
*/
coap_string_t *coap_get_query(const struct coap_pdu_t *request);
/**
* Extract uri_path string from request PDU
* @param request Request PDU.
* @return Reconstructed and escaped uri path string part.
*/
coap_string_t *coap_get_uri_path(const struct coap_pdu_t *request);
/** @} */
#endif /* _COAP_URI_H_ */
#endif /* COAP_URI_H_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff