coap_session.c
Go to the documentation of this file.
/* session.c -- 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.
*/
#include "coap_internal.h"
#ifndef COAP_SESSION_C_
#define COAP_SESSION_C_
#include <stdio.h>
#ifdef COAP_EPOLL_SUPPORT
#include <sys/epoll.h>
#include <sys/timerfd.h>
#endif /* COAP_EPOLL_SUPPORT */
#include <errno.h>
void
coap_session_set_max_retransmit (coap_session_t *session, unsigned int value) {
if (value > 0)
session->max_retransmit = value;
coap_log(LOG_DEBUG, "***%s: session max_retransmit set to %d\n",
coap_session_str(session), session->max_retransmit);
return;
}
void
coap_session_set_ack_timeout (coap_session_t *session, coap_fixed_point_t value) {
if (value.integer_part > 0 && value.fractional_part < 1000)
session->ack_timeout = value;
coap_log(LOG_DEBUG, "***%s: session ack_timeout set to %d.%03d\n",
coap_session_str(session), session->ack_timeout.integer_part,
session->ack_timeout.fractional_part);
return;
}
void
coap_session_set_ack_random_factor (coap_session_t *session,
coap_fixed_point_t value) {
if (value.integer_part > 0 && value.fractional_part < 1000)
session->ack_random_factor = value;
coap_log(LOG_DEBUG, "***%s: session ack_random_factor set to %d.%03d\n",
coap_session_str(session), session->ack_random_factor.integer_part,
session->ack_random_factor.fractional_part);
return;
}
unsigned int
coap_session_get_max_transmit (coap_session_t *session) {
return session->max_retransmit;
}
coap_fixed_point_t
coap_session_get_ack_timeout (coap_session_t *session) {
return session->ack_timeout;
}
coap_fixed_point_t
coap_session_get_ack_random_factor (coap_session_t *session) {
return session->ack_random_factor;
}
coap_session_t *
coap_session_reference(coap_session_t *session) {
++session->ref;
return session;
}
void
coap_session_release(coap_session_t *session) {
if (session) {
assert(session->ref > 0);
if (session->ref > 0)
--session->ref;
if (session->ref == 0 && session->type == COAP_SESSION_TYPE_CLIENT)
coap_session_free(session);
}
}
void
coap_session_set_app_data(coap_session_t *session, void *app_data) {
assert(session);
session->app = app_data;
}
void *
coap_session_get_app_data(const coap_session_t *session) {
assert(session);
return session->app;
}
static coap_session_t *
coap_make_session(coap_proto_t proto, coap_session_type_t type,
const coap_address_t *local_if, const coap_address_t *local_addr,
const coap_address_t *remote_addr, int ifindex, coap_context_t *context,
coap_endpoint_t *endpoint) {
coap_session_t *session = (coap_session_t*)coap_malloc_type(COAP_SESSION, sizeof(coap_session_t));
if (!session)
return NULL;
memset(session, 0, sizeof(*session));
session->proto = proto;
session->type = type;
if (local_if)
coap_address_copy(&session->local_if, local_if);
else
coap_address_init(&session->local_if);
if (local_addr)
coap_address_copy(&session->addr_info.local, local_addr);
else
coap_address_init(&session->addr_info.local);
if (remote_addr)
coap_address_copy(&session->addr_info.remote, remote_addr);
else
coap_address_init(&session->addr_info.remote);
session->ifindex = ifindex;
session->context = context;
session->endpoint = endpoint;
if (endpoint)
session->mtu = endpoint->default_mtu;
else
session->mtu = COAP_DEFAULT_MTU;
if (proto == COAP_PROTO_DTLS) {
session->tls_overhead = 29;
if (session->tls_overhead >= session->mtu) {
session->tls_overhead = session->mtu;
coap_log(LOG_ERR, "DTLS overhead exceeds MTU\n");
}
}
session->max_retransmit = COAP_DEFAULT_MAX_RETRANSMIT;
session->ack_timeout = COAP_DEFAULT_ACK_TIMEOUT;
session->ack_random_factor = COAP_DEFAULT_ACK_RANDOM_FACTOR;
session->dtls_event = -1;
session->last_ping_mid = COAP_INVALID_TID;
/* initialize message id */
prng((unsigned char *)&session->tx_mid, sizeof(session->tx_mid));
return session;
}
void coap_session_mfree(coap_session_t *session) {
coap_queue_t *q, *tmp;
if (session->partial_pdu)
coap_delete_pdu(session->partial_pdu);
if (session->proto == COAP_PROTO_DTLS)
coap_dtls_free_session(session);
else if (session->proto == COAP_PROTO_TLS)
coap_tls_free_session(session);
if (session->sock.flags != COAP_SOCKET_EMPTY)
coap_socket_close(&session->sock);
if (session->psk_identity)
coap_free(session->psk_identity);
if (session->psk_key)
coap_free(session->psk_key);
LL_FOREACH_SAFE(session->delayqueue, q, tmp) {
if (q->pdu->type==COAP_MESSAGE_CON && session->context && session->context->nack_handler)
session->context->nack_handler(session->context, session, q->pdu, session->proto == COAP_PROTO_DTLS ? COAP_NACK_TLS_FAILED : COAP_NACK_NOT_DELIVERABLE, q->id);
coap_delete_node(q);
}
}
void coap_session_free(coap_session_t *session) {
if (!session)
return;
assert(session->ref == 0);
if (session->ref)
return;
coap_session_mfree(session);
if (session->endpoint) {
if (session->endpoint->sessions)
SESSIONS_DELETE(session->endpoint->sessions, session);
} else if (session->context) {
if (session->context->sessions)
SESSIONS_DELETE(session->context->sessions, session);
}
coap_log(LOG_DEBUG, "***%s: session closed\n", coap_session_str(session));
coap_free_type(COAP_SESSION, session);
}
size_t coap_session_max_pdu_size(const coap_session_t *session) {
size_t max_with_header = (size_t)(session->mtu - session->tls_overhead);
if (COAP_PROTO_NOT_RELIABLE(session->proto))
return max_with_header > 4 ? max_with_header - 4 : 0;
/* we must assume there is no token to be on the safe side */
if (max_with_header <= 2)
return 0;
else if (max_with_header <= COAP_MAX_MESSAGE_SIZE_TCP0 + 2)
return max_with_header - 2;
else if (max_with_header <= COAP_MAX_MESSAGE_SIZE_TCP8 + 3)
return max_with_header - 3;
else if (max_with_header <= COAP_MAX_MESSAGE_SIZE_TCP16 + 4)
return max_with_header - 4;
else
return max_with_header - 6;
}
void coap_session_set_mtu(coap_session_t *session, unsigned mtu) {
#if defined(WITH_CONTIKI) || defined(WITH_LWIP)
if (mtu > COAP_MAX_MESSAGE_SIZE_TCP16 + 4)
mtu = COAP_MAX_MESSAGE_SIZE_TCP16 + 4;
#endif
session->mtu = mtu;
if (session->tls_overhead >= session->mtu) {
session->tls_overhead = session->mtu;
coap_log(LOG_ERR, "DTLS overhead exceeds MTU\n");
}
}
ssize_t coap_session_send(coap_session_t *session, const uint8_t *data, size_t datalen) {
ssize_t bytes_written;
coap_socket_t *sock = &session->sock;
if (sock->flags == COAP_SOCKET_EMPTY) {
assert(session->endpoint != NULL);
sock = &session->endpoint->sock;
}
bytes_written = coap_socket_send(sock, session, data, datalen);
if (bytes_written == (ssize_t)datalen) {
coap_ticks(&session->last_rx_tx);
coap_log(LOG_DEBUG, "* %s: sent %zd bytes\n",
coap_session_str(session), datalen);
} else {
coap_log(LOG_DEBUG, "* %s: failed to send %zd bytes\n",
coap_session_str(session), datalen);
}
return bytes_written;
}
ssize_t coap_session_write(coap_session_t *session, const uint8_t *data, size_t datalen) {
ssize_t bytes_written = coap_socket_write(&session->sock, data, datalen);
if (bytes_written > 0) {
coap_ticks(&session->last_rx_tx);
coap_log(LOG_DEBUG, "* %s: sent %zd bytes\n",
coap_session_str(session), datalen);
} else if (bytes_written < 0) {
coap_log(LOG_DEBUG, "* %s: failed to send %zd bytes\n",
coap_session_str(session), datalen );
}
return bytes_written;
}
ssize_t
coap_session_delay_pdu(coap_session_t *session, coap_pdu_t *pdu,
coap_queue_t *node)
{
if ( node ) {
coap_queue_t *removed = NULL;
coap_remove_from_queue(&session->context->sendqueue, session, node->id, &removed);
assert(removed == node);
coap_session_release(node->session);
node->session = NULL;
node->t = 0;
} else {
coap_queue_t *q = NULL;
/* Check that the same tid is not getting re-used in violation of RFC7252 */
LL_FOREACH(session->delayqueue, q) {
if (q->id == pdu->tid) {
coap_log(LOG_ERR, "** %s: tid=%d: already in-use - dropped\n", coap_session_str(session), pdu->tid);
return COAP_INVALID_TID;
}
}
node = coap_new_node();
if (node == NULL)
return COAP_INVALID_TID;
node->id = pdu->tid;
node->pdu = pdu;
if (pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto)) {
uint8_t r;
prng(&r, sizeof(r));
/* add timeout in range [ACK_TIMEOUT...ACK_TIMEOUT * ACK_RANDOM_FACTOR] */
node->timeout = coap_calc_timeout(session, r);
}
}
LL_APPEND(session->delayqueue, node);
coap_log(LOG_DEBUG, "** %s: tid=%d: delayed\n",
coap_session_str(session), node->id);
return COAP_PDU_DELAYED;
}
void coap_session_send_csm(coap_session_t *session) {
coap_pdu_t *pdu;
uint8_t buf[4];
assert(COAP_PROTO_RELIABLE(session->proto));
coap_log(LOG_DEBUG, "***%s: sending CSM\n", coap_session_str(session));
session->state = COAP_SESSION_STATE_CSM;
session->partial_write = 0;
if (session->mtu == 0)
session->mtu = COAP_DEFAULT_MTU; /* base value */
pdu = coap_pdu_init(COAP_MESSAGE_CON, COAP_SIGNALING_CSM, 0, 16);
if ( pdu == NULL
|| coap_add_option(pdu, COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE,
coap_encode_var_safe(buf, sizeof(buf),
COAP_DEFAULT_MAX_PDU_RX_SIZE), buf) == 0
|| coap_pdu_encode_header(pdu, session->proto) == 0
) {
coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE);
} else {
ssize_t bytes_written = coap_session_send_pdu(session, pdu);
if (bytes_written != (ssize_t)pdu->used_size + pdu->hdr_size)
coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE);
}
if (pdu)
coap_delete_pdu(pdu);
}
coap_tid_t coap_session_send_ping(coap_session_t *session) {
coap_pdu_t *ping;
if (session->state != COAP_SESSION_STATE_ESTABLISHED)
return COAP_INVALID_TID;
if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
uint16_t tid = coap_new_message_id (session);
ping = coap_pdu_init(COAP_MESSAGE_CON, 0, tid, 0);
}
else {
ping = coap_pdu_init(COAP_MESSAGE_CON, COAP_SIGNALING_PING, 0, 1);
}
if (!ping)
return COAP_INVALID_TID;
return coap_send(session, ping);
}
void coap_session_connected(coap_session_t *session) {
if (session->state != COAP_SESSION_STATE_ESTABLISHED) {
coap_log(LOG_DEBUG, "***%s: session connected\n",
coap_session_str(session));
if (session->state == COAP_SESSION_STATE_CSM)
coap_handle_event(session->context, COAP_EVENT_SESSION_CONNECTED, session);
}
session->state = COAP_SESSION_STATE_ESTABLISHED;
session->partial_write = 0;
if ( session->proto==COAP_PROTO_DTLS) {
session->tls_overhead = coap_dtls_get_overhead(session);
if (session->tls_overhead >= session->mtu) {
session->tls_overhead = session->mtu;
coap_log(LOG_ERR, "DTLS overhead exceeds MTU\n");
}
}
while (session->delayqueue && session->state == COAP_SESSION_STATE_ESTABLISHED) {
ssize_t bytes_written;
coap_queue_t *q = session->delayqueue;
if (q->pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto)) {
if (session->con_active >= COAP_DEFAULT_NSTART)
break;
session->con_active++;
}
/* Take entry off the queue */
session->delayqueue = q->next;
q->next = NULL;
coap_log(LOG_DEBUG, "** %s: tid=%d: transmitted after delay\n",
coap_session_str(session), (int)q->pdu->tid);
bytes_written = coap_session_send_pdu(session, q->pdu);
if (q->pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto)) {
if (coap_wait_ack(session->context, session, q) >= 0)
q = NULL;
}
if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
if (q)
coap_delete_node(q);
if (bytes_written < 0)
break;
} else {
if (bytes_written <= 0 || (size_t)bytes_written < q->pdu->used_size + q->pdu->hdr_size) {
q->next = session->delayqueue;
session->delayqueue = q;
if (bytes_written > 0)
session->partial_write = (size_t)bytes_written;
break;
} else {
coap_delete_node(q);
}
}
}
}
void coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason) {
(void)reason;
coap_session_state_t state = session->state;
coap_log(LOG_DEBUG, "***%s: session disconnected (reason %d)\n",
coap_session_str(session), reason);
#ifndef WITHOUT_OBSERVE
coap_delete_observers( session->context, session );
#endif
if ( session->tls) {
if (session->proto == COAP_PROTO_DTLS)
coap_dtls_free_session(session);
else if (session->proto == COAP_PROTO_TLS)
coap_tls_free_session(session);
session->tls = NULL;
}
if (session->proto == COAP_PROTO_UDP)
session->state = COAP_SESSION_STATE_ESTABLISHED;
else
session->state = COAP_SESSION_STATE_NONE;
session->con_active = 0;
if (session->partial_pdu) {
coap_delete_pdu(session->partial_pdu);
session->partial_pdu = NULL;
}
session->partial_read = 0;
while (session->delayqueue) {
coap_queue_t *q = session->delayqueue;
session->delayqueue = q->next;
q->next = NULL;
coap_log(LOG_DEBUG, "** %s: tid=%d: not transmitted after disconnect\n",
coap_session_str(session), q->id);
if (q->pdu->type==COAP_MESSAGE_CON
&& COAP_PROTO_NOT_RELIABLE(session->proto)
&& reason == COAP_NACK_ICMP_ISSUE)
{
/* Make sure that we try a re-transmit later on ICMP error */
if (coap_wait_ack(session->context, session, q) >= 0)
q = NULL;
}
if (q && q->pdu->type == COAP_MESSAGE_CON
&& session->context->nack_handler)
{
session->context->nack_handler(session->context, session, q->pdu,
reason, q->id);
}
if (q)
coap_delete_node(q);
}
if (reason != COAP_NACK_ICMP_ISSUE)
coap_cancel_session_messages(session->context, session, reason);
if ( COAP_PROTO_RELIABLE(session->proto) ) {
if (session->sock.flags != COAP_SOCKET_EMPTY) {
coap_socket_close(&session->sock);
coap_handle_event(session->context,
state == COAP_SESSION_STATE_CONNECTING ?
COAP_EVENT_TCP_FAILED : COAP_EVENT_TCP_CLOSED, session);
}
if (state != COAP_SESSION_STATE_NONE) {
coap_handle_event(session->context,
state == COAP_SESSION_STATE_ESTABLISHED ?
COAP_EVENT_SESSION_CLOSED : COAP_EVENT_SESSION_FAILED, session);
}
}
}
coap_session_t *
coap_endpoint_get_session(coap_endpoint_t *endpoint,
const coap_packet_t *packet, coap_tick_t now) {
coap_session_t *session;
coap_session_t *rtmp;
unsigned int num_idle = 0;
unsigned int num_hs = 0;
coap_session_t *oldest = NULL;
coap_session_t *oldest_hs = NULL;
SESSIONS_FIND(endpoint->sessions, packet->addr_info, session);
if (session) {
session->last_rx_tx = now;
return session;
}
SESSIONS_ITER(endpoint->sessions, session, rtmp) {
if (session->ref == 0 && session->delayqueue == NULL) {
if (session->type == COAP_SESSION_TYPE_SERVER) {
++num_idle;
if (oldest==NULL || session->last_rx_tx < oldest->last_rx_tx)
oldest = session;
if (session->state == COAP_SESSION_STATE_HANDSHAKE) {
++num_hs;
/* See if this is a partial (D)TLS session set up
which needs to be cleared down to prevent DOS */
if ((session->last_rx_tx + COAP_PARTIAL_SESSION_TIMEOUT_TICKS) < now) {
if (oldest_hs == NULL ||
session->last_rx_tx < oldest_hs->last_rx_tx)
oldest_hs = session;
}
}
}
else if (session->type == COAP_SESSION_TYPE_HELLO) {
++num_hs;
/* See if this is a partial (D)TLS session set up for Client Hello
which needs to be cleared down to prevent DOS */
if ((session->last_rx_tx + COAP_PARTIAL_SESSION_TIMEOUT_TICKS) < now) {
if (oldest_hs == NULL ||
session->last_rx_tx < oldest_hs->last_rx_tx)
oldest_hs = session;
}
}
}
}
if (endpoint->context->max_idle_sessions > 0 &&
num_idle >= endpoint->context->max_idle_sessions) {
coap_session_free(oldest);
}
else if (oldest_hs) {
coap_log(LOG_WARNING, "***%s: Incomplete session timed out\n",
coap_session_str(oldest_hs));
coap_session_free(oldest_hs);
}
if (num_hs > (endpoint->context->max_handshake_sessions ?
endpoint->context->max_handshake_sessions :
COAP_DEFAULT_MAX_HANDSHAKE_SESSIONS)) {
/* Maxed out on number of sessions in (D)TLS negotiation state */
coap_log(LOG_DEBUG,
"Oustanding sessions in COAP_SESSION_STATE_HANDSHAKE too "
"large. New request ignored\n");
return NULL;
}
if (endpoint->proto == COAP_PROTO_DTLS) {
/*
* Need to check that this actually is a Client Hello before wasting
* time allocating and then freeing off session.
*/
/*
* Generic header structure of the DTLS record layer.
* typedef struct __attribute__((__packed__)) {
* uint8_t content_type; content type of the included message
* uint16_t version; Protocol version
* uint16_t epoch; counter for cipher state changes
* uint8_t sequence_number[6]; sequence number
* uint16_t length; length of the following fragment
* uint8_t handshake; If content_type == DTLS_CT_HANDSHAKE
* } dtls_record_handshake_t;
*/
#define OFF_CONTENT_TYPE 0 /* offset of content_type in dtls_record_handshake_t */
#define DTLS_CT_ALERT 21 /* Content Type Alert */
#define DTLS_CT_HANDSHAKE 22 /* Content Type Handshake */
#define OFF_HANDSHAKE_TYPE 13 /* offset of handshake in dtls_record_handshake_t */
#define DTLS_HT_CLIENT_HELLO 1 /* Client Hello handshake type */
#ifdef WITH_LWIP
const uint8_t *payload = (const uint8_t*)packet->pbuf->payload;
size_t length = packet->pbuf->len;
#else /* ! WITH_LWIP */
const uint8_t *payload = (const uint8_t*)packet->payload;
size_t length = packet->length;
#endif /* ! WITH_LWIP */
if (length < (OFF_HANDSHAKE_TYPE + 1)) {
coap_log(LOG_DEBUG,
"coap_dtls_hello: ContentType %d Short Packet (%zu < %d) dropped\n",
payload[OFF_CONTENT_TYPE], length,
OFF_HANDSHAKE_TYPE + 1);
return NULL;
}
if (payload[OFF_CONTENT_TYPE] != DTLS_CT_HANDSHAKE ||
payload[OFF_HANDSHAKE_TYPE] != DTLS_HT_CLIENT_HELLO) {
/* only log if not a late alert */
if (payload[OFF_CONTENT_TYPE] != DTLS_CT_ALERT)
coap_log(LOG_DEBUG,
"coap_dtls_hello: ContentType %d Handshake %d dropped\n",
payload[OFF_CONTENT_TYPE], payload[OFF_HANDSHAKE_TYPE]);
return NULL;
}
}
session = coap_make_session(endpoint->proto, COAP_SESSION_TYPE_SERVER,
NULL, &packet->addr_info.local,
&packet->addr_info.remote,
packet->ifindex, endpoint->context, endpoint);
if (session) {
session->last_rx_tx = now;
if (endpoint->proto == COAP_PROTO_UDP)
session->state = COAP_SESSION_STATE_ESTABLISHED;
else if (endpoint->proto == COAP_PROTO_DTLS) {
session->type = COAP_SESSION_TYPE_HELLO;
}
SESSIONS_ADD(endpoint->sessions, session);
coap_log(LOG_DEBUG, "***%s: new incoming session\n",
coap_session_str(session));
}
return session;
}
coap_session_t *
coap_session_new_dtls_session(coap_session_t *session,
coap_tick_t now) {
if (session) {
session->last_rx_tx = now;
session->type = COAP_SESSION_TYPE_SERVER;
session->tls = coap_dtls_new_server_session(session);
if (session->tls) {
session->state = COAP_SESSION_STATE_HANDSHAKE;
} else {
coap_session_free(session);
session = NULL;
}
}
return session;
}
#ifdef COAP_EPOLL_SUPPORT
static void
coap_epoll_ctl_add(coap_socket_t *sock,
uint32_t events,
const char *func
) {
int ret;
struct epoll_event event;
coap_context_t *context;
if (sock == NULL)
return;
context = sock->session ? sock->session->context :
sock->endpoint ? sock->endpoint->context : NULL;
if (context == NULL)
return;
/* Needed if running 32bit as ptr is only 32bit */
memset(&event, 0, sizeof(event));
event.events = events;
event.data.ptr = sock;
ret = epoll_ctl(context->epfd, EPOLL_CTL_ADD, sock->fd, &event);
if (ret == -1) {
coap_log(LOG_ERR,
"%s: epoll_ctl ADD failed: %s (%d)\n",
func,
coap_socket_strerror(), errno);
}
}
#endif /* COAP_EPOLL_SUPPORT */
static coap_session_t *
coap_session_create_client(
coap_context_t *ctx,
const coap_address_t *local_if,
const coap_address_t *server,
coap_proto_t proto
) {
coap_session_t *session = NULL;
assert(server);
assert(proto != COAP_PROTO_NONE);
session = coap_make_session(proto, COAP_SESSION_TYPE_CLIENT, local_if,
local_if, server, 0, ctx, NULL);
if (!session)
goto error;
coap_session_reference(session);
if (proto == COAP_PROTO_UDP || proto == COAP_PROTO_DTLS) {
if (!coap_socket_connect_udp(&session->sock, &session->local_if, server,
proto == COAP_PROTO_DTLS ? COAPS_DEFAULT_PORT : COAP_DEFAULT_PORT,
&session->addr_info.local, &session->addr_info.remote)) {
goto error;
}
} else if (proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS) {
if (!coap_socket_connect_tcp1(&session->sock, &session->local_if, server,
proto == COAP_PROTO_TLS ? COAPS_DEFAULT_PORT : COAP_DEFAULT_PORT,
&session->addr_info.local, &session->addr_info.remote)) {
goto error;
}
}
session->sock.session = session;
#ifdef COAP_EPOLL_SUPPORT
coap_epoll_ctl_add(&session->sock,
EPOLLIN |
((session->sock.flags & COAP_SOCKET_WANT_CONNECT) ?
EPOLLOUT : 0),
__func__);
#endif /* COAP_EPOLL_SUPPORT */
session->sock.flags |= COAP_SOCKET_NOT_EMPTY | COAP_SOCKET_WANT_READ;
if (local_if)
session->sock.flags |= COAP_SOCKET_BOUND;
SESSIONS_ADD(ctx->sessions, session);
return session;
error:
coap_session_release(session);
return NULL;
}
static coap_session_t *
coap_session_connect(coap_session_t *session) {
if (session->proto == COAP_PROTO_UDP) {
session->state = COAP_SESSION_STATE_ESTABLISHED;
} else if (session->proto == COAP_PROTO_DTLS) {
session->tls = coap_dtls_new_client_session(session);
if (session->tls) {
session->state = COAP_SESSION_STATE_HANDSHAKE;
} else {
/* Need to free session object. As a new session may not yet
* have been referenced, we call coap_session_reference() first
* before trying to release the object.
*/
coap_session_reference(session);
coap_session_release(session);
return NULL;
}
} else if (session->proto == COAP_PROTO_TCP || session->proto == COAP_PROTO_TLS) {
if (session->sock.flags & COAP_SOCKET_WANT_CONNECT) {
session->state = COAP_SESSION_STATE_CONNECTING;
} else if (session->proto == COAP_PROTO_TLS) {
int connected = 0;
session->tls = coap_tls_new_client_session(session, &connected);
if (session->tls) {
session->state = COAP_SESSION_STATE_HANDSHAKE;
if (connected)
coap_session_send_csm(session);
} else {
/* Need to free session object. As a new session may not yet
* have been referenced, we call coap_session_reference()
* first before trying to release the object.
*/
coap_session_reference(session);
coap_session_release(session);
return NULL;
}
} else {
coap_session_send_csm(session);
}
}
coap_ticks(&session->last_rx_tx);
return session;
}
static coap_session_t *
coap_session_accept(coap_session_t *session) {
if (session->proto == COAP_PROTO_TCP || session->proto == COAP_PROTO_TLS)
coap_handle_event(session->context, COAP_EVENT_TCP_CONNECTED, session);
if (session->proto == COAP_PROTO_TCP) {
coap_session_send_csm(session);
} else if (session->proto == COAP_PROTO_TLS) {
int connected = 0;
session->tls = coap_tls_new_server_session(session, &connected);
if (session->tls) {
session->state = COAP_SESSION_STATE_HANDSHAKE;
if (connected) {
coap_handle_event(session->context, COAP_EVENT_DTLS_CONNECTED, session);
coap_session_send_csm(session);
}
} else {
/* Need to free session object. As a new session may not yet
* have been referenced, we call coap_session_reference() first
* before trying to release the object.
*/
coap_session_reference(session);
coap_session_release(session);
session = NULL;
}
}
return session;
}
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
) {
coap_session_t *session = coap_session_create_client(ctx, local_if, server, proto);
if (session) {
coap_log(LOG_DEBUG, "***%s: new outgoing session\n",
coap_session_str(session));
session = coap_session_connect(session);
}
return session;
}
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
) {
coap_session_t *session = coap_session_create_client(ctx, local_if, server, proto);
if (!session)
return NULL;
if (identity && (strlen(identity) > 0)) {
size_t identity_len = strlen(identity);
session->psk_identity = (uint8_t*)coap_malloc(identity_len);
if (session->psk_identity) {
memcpy(session->psk_identity, identity, identity_len);
session->psk_identity_len = identity_len;
} else {
coap_log(LOG_WARNING, "Cannot store session PSK identity\n");
coap_session_release(session);
return NULL;
}
}
else if (coap_dtls_is_supported()) {
coap_log(LOG_WARNING, "PSK identity not defined\n");
coap_session_release(session);
return NULL;
}
if (key && key_len > 0) {
session->psk_key = (uint8_t*)coap_malloc(key_len);
if (session->psk_key) {
memcpy(session->psk_key, key, key_len);
session->psk_key_len = key_len;
} else {
coap_log(LOG_WARNING, "Cannot store session PSK key\n");
coap_session_release(session);
return NULL;
}
}
else if (coap_dtls_is_supported()) {
coap_log(LOG_WARNING, "PSK key not defined\n");
coap_session_release(session);
return NULL;
}
if (coap_dtls_is_supported()) {
if (!coap_dtls_context_set_psk(ctx, NULL, COAP_DTLS_ROLE_CLIENT)) {
coap_session_release(session);
return NULL;
}
}
coap_log(LOG_DEBUG, "***%s: new outgoing session\n",
coap_session_str(session));
return coap_session_connect(session);
}
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,
coap_dtls_pki_t* setup_data
) {
coap_session_t *session;
if (coap_dtls_is_supported()) {
if (!setup_data) {
return NULL;
} else {
if (setup_data->version != COAP_DTLS_PKI_SETUP_VERSION) {
coap_log(LOG_ERR,
"coap_new_client_session_pki: Wrong version of setup_data\n");
return NULL;
}
}
}
session = coap_session_create_client(ctx, local_if, server, proto);
if (!session) {
return NULL;
}
if (coap_dtls_is_supported()) {
/* we know that setup_data is not NULL */
if (!coap_dtls_context_set_pki(ctx, setup_data, COAP_DTLS_ROLE_CLIENT)) {
coap_session_release(session);
return NULL;
}
}
coap_log(LOG_DEBUG, "***%s: new outgoing session\n",
coap_session_str(session));
return coap_session_connect(session);
}
coap_session_t *coap_new_server_session(
struct coap_context_t *ctx,
coap_endpoint_t *ep
) {
coap_session_t *session;
session = coap_make_session( ep->proto, COAP_SESSION_TYPE_SERVER,
&ep->bind_addr, NULL, NULL, 0, ctx, ep );
if (!session)
goto error;
if (!coap_socket_accept_tcp(&ep->sock, &session->sock,
&session->addr_info.local,
&session->addr_info.remote))
goto error;
session->sock.flags |= COAP_SOCKET_NOT_EMPTY | COAP_SOCKET_CONNECTED
| COAP_SOCKET_WANT_READ;
session->sock.session = session;
#ifdef COAP_EPOLL_SUPPORT
coap_epoll_ctl_add(&session->sock,
EPOLLIN,
__func__);
#endif /* COAP_EPOLL_SUPPORT */
SESSIONS_ADD(ep->sessions, session);
if (session) {
coap_log(LOG_DEBUG, "***%s: new incoming session\n",
coap_session_str(session));
session = coap_session_accept(session);
}
return session;
error:
coap_session_free(session);
return NULL;
}
#ifndef WITH_LWIP
coap_endpoint_t *
coap_new_endpoint(coap_context_t *context, const coap_address_t *listen_addr, coap_proto_t proto) {
struct coap_endpoint_t *ep = NULL;
assert(context);
assert(listen_addr);
assert(proto != COAP_PROTO_NONE);
if (proto == COAP_PROTO_DTLS && !coap_dtls_is_supported()) {
coap_log(LOG_CRIT, "coap_new_endpoint: DTLS not supported\n");
goto error;
}
if (proto == COAP_PROTO_TLS && !coap_tls_is_supported()) {
coap_log(LOG_CRIT, "coap_new_endpoint: TLS not supported\n");
goto error;
}
if (proto == COAP_PROTO_DTLS || proto == COAP_PROTO_TLS) {
if (!coap_dtls_context_check_keys_enabled(context)) {
coap_log(LOG_INFO,
"coap_new_endpoint: one of coap_context_set_psk() or "
"coap_context_set_pki() not called\n");
goto error;
}
}
ep = coap_malloc_endpoint();
if (!ep) {
coap_log(LOG_WARNING, "coap_new_endpoint: malloc");
goto error;
}
memset(ep, 0, sizeof(struct coap_endpoint_t));
ep->context = context;
ep->proto = proto;
if (proto==COAP_PROTO_TCP || proto==COAP_PROTO_TLS) {
if (!coap_socket_bind_tcp(&ep->sock, listen_addr, &ep->bind_addr))
goto error;
ep->sock.flags |= COAP_SOCKET_WANT_ACCEPT;
} else if (proto==COAP_PROTO_UDP || proto==COAP_PROTO_DTLS) {
if (!coap_socket_bind_udp(&ep->sock, listen_addr, &ep->bind_addr))
goto error;
ep->sock.flags |= COAP_SOCKET_WANT_READ;
} else {
coap_log(LOG_CRIT, "coap_new_endpoint: protocol not supported\n");
goto error;
}
if (LOG_DEBUG <= coap_get_log_level()) {
#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN 40
#endif
unsigned char addr_str[INET6_ADDRSTRLEN + 8];
if (coap_print_addr(&ep->bind_addr, addr_str, INET6_ADDRSTRLEN + 8)) {
coap_log(LOG_DEBUG, "created %s endpoint %s\n",
ep->proto == COAP_PROTO_TLS ? "TLS "
: ep->proto == COAP_PROTO_TCP ? "TCP "
: ep->proto == COAP_PROTO_DTLS ? "DTLS" : "UDP ",
addr_str);
}
}
ep->sock.flags |= COAP_SOCKET_NOT_EMPTY | COAP_SOCKET_BOUND;
ep->default_mtu = COAP_DEFAULT_MTU;
ep->sock.endpoint = ep;
#ifdef COAP_EPOLL_SUPPORT
coap_epoll_ctl_add(&ep->sock,
EPOLLIN,
__func__);
#endif /* COAP_EPOLL_SUPPORT */
LL_PREPEND(context->endpoint, ep);
return ep;
error:
coap_free_endpoint(ep);
return NULL;
}
void coap_endpoint_set_default_mtu(coap_endpoint_t *ep, unsigned mtu) {
ep->default_mtu = (uint16_t)mtu;
}
void
coap_free_endpoint(coap_endpoint_t *ep) {
if (ep) {
coap_session_t *session, *rtmp;
if (ep->sock.flags != COAP_SOCKET_EMPTY)
coap_socket_close(&ep->sock);
SESSIONS_ITER_SAFE(ep->sessions, session, rtmp) {
assert(session->ref == 0);
if (session->ref == 0) {
coap_session_free(session);
}
}
if (ep->context) {
LL_DELETE(ep->context->endpoint, ep);
}
coap_mfree_endpoint(ep);
}
}
#endif /* WITH_LWIP */
coap_session_t *
coap_session_get_by_peer(coap_context_t *ctx,
const coap_address_t *remote_addr,
int ifindex) {
coap_session_t *s, *rtmp;
coap_endpoint_t *ep;
SESSIONS_ITER(ctx->sessions, s, rtmp) {
if (s->ifindex == ifindex && coap_address_equals(&s->addr_info.remote,
remote_addr))
return s;
}
LL_FOREACH(ctx->endpoint, ep) {
SESSIONS_ITER(ep->sessions, s, rtmp) {
if (s->ifindex == ifindex && coap_address_equals(&s->addr_info.remote,
remote_addr))
return s;
}
}
return NULL;
}
const char *coap_session_str(const coap_session_t *session) {
static char szSession[256];
char *p = szSession, *end = szSession + sizeof(szSession);
if (coap_print_addr(&session->addr_info.local,
(unsigned char*)p, end - p) > 0)
p += strlen(p);
if (p + 6 < end) {
strcpy(p, " <-> ");
p += 5;
}
if (p + 1 < end) {
if (coap_print_addr(&session->addr_info.remote,
(unsigned char*)p, end - p) > 0)
p += strlen(p);
}
if (session->ifindex > 0 && p + 1 < end)
p += snprintf(p, end - p, " (if%d)", session->ifindex);
if (p + 6 < end) {
if (session->proto == COAP_PROTO_UDP) {
strcpy(p, " UDP ");
p += 4;
} else if (session->proto == COAP_PROTO_DTLS) {
strcpy(p, " DTLS");
p += 5;
} else if (session->proto == COAP_PROTO_TCP) {
strcpy(p, " TCP ");
p += 4;
} else if (session->proto == COAP_PROTO_TLS) {
strcpy(p, " TLS ");
p += 4;
} else {
strcpy(p, " NONE");
p += 5;
}
}
return szSession;
}
const char *coap_endpoint_str(const coap_endpoint_t *endpoint) {
static char szEndpoint[128];
char *p = szEndpoint, *end = szEndpoint + sizeof(szEndpoint);
if (coap_print_addr(&endpoint->bind_addr, (unsigned char*)p, end - p) > 0)
p += strlen(p);
if (p + 6 < end) {
if (endpoint->proto == COAP_PROTO_UDP) {
strcpy(p, " UDP");
p += 4;
} else if (endpoint->proto == COAP_PROTO_DTLS) {
strcpy(p, " DTLS");
p += 5;
} else {
strcpy(p, " NONE");
p += 5;
}
}
return szEndpoint;
}
#endif /* COAP_SESSION_C_ */
coap_pdu_t::type
uint8_t type
message type
Definition: pdu.h:288
coap_session_t::mtu
unsigned mtu
path or CSM mtu
Definition: coap_session.h:65
coap_session_send_csm
void coap_session_send_csm(coap_session_t *session)
Notify session transport has just connected and CSM exchange can now start.
Definition: coap_session.c:288
LL_FOREACH
#define LL_FOREACH(head, el)
Definition: utlist.h:413
coap_context_t::sendqueue
coap_queue_t * sendqueue
Definition: net.h:164
COAP_SOCKET_EMPTY
#define COAP_SOCKET_EMPTY
coap_socket_flags_t values
Definition: coap_io.h:76
coap_session_t::psk_identity
uint8_t * psk_identity
Definition: coap_session.h:87
COAP_DEFAULT_MTU
#define COAP_DEFAULT_MTU
Definition: pdu.h:32
coap_addr_tuple_t::remote
coap_address_t remote
remote address and port
Definition: coap_io.h:50
coap_new_client_session
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.
Definition: coap_session.c:766
coap_session_t::last_rx_tx
coap_tick_t last_rx_tx
Definition: coap_session.h:82
coap_session_t::last_ping_mid
coap_tid_t last_ping_mid
the last keepalive message id that was used in this session
Definition: coap_session.h:76
coap_session_t
Definition: coap_session.h:59
coap_session_t::con_active
uint8_t con_active
Active CON request sent.
Definition: coap_session.h:75
coap_session_t::app
void * app
application-specific data
Definition: coap_session.h:91
coap_session_set_ack_timeout
void coap_session_set_ack_timeout(coap_session_t *session, coap_fixed_point_t value)
Set the CoAP initial ack response timeout before the next re-transmit.
Definition: coap_session.c:32
COAP_SIGNALING_PING
#define COAP_SIGNALING_PING
Definition: pdu.h:181
coap_proto_t
uint8_t coap_proto_t
Definition: pdu.h:339
coap_fixed_point_t
Abstraction of a fixed point number that can be used where necessary instead of a float...
Definition: coap_session.h:28
DTLS_HT_CLIENT_HELLO
#define DTLS_HT_CLIENT_HELLO
COAP_SESSION_TYPE_CLIENT
#define COAP_SESSION_TYPE_CLIENT
coap_session_type_t values
Definition: coap_session.h:45
coap_wait_ack
coap_tid_t coap_wait_ack(coap_context_t *context, coap_session_t *session, coap_queue_t *node)
Definition: net.c:888
COAP_SIGNALING_CSM
#define COAP_SIGNALING_CSM
Definition: pdu.h:180
coap_socket_close
void coap_socket_close(coap_socket_t *sock)
Definition: coap_io.c:631
COAP_DTLS_PKI_SETUP_VERSION
#define COAP_DTLS_PKI_SETUP_VERSION
Latest PKI setup version.
Definition: coap_dtls.h:188
coap_tls_free_session
void coap_tls_free_session(coap_session_t *coap_session UNUSED)
Definition: coap_notls.c:158
coap_session_get_max_transmit
unsigned int coap_session_get_max_transmit(coap_session_t *session)
Get the CoAP maximum retransmit before failure.
Definition: coap_session.c:53
coap_session_get_ack_timeout
coap_fixed_point_t coap_session_get_ack_timeout(coap_session_t *session)
Get the CoAP initial ack response timeout before the next re-transmit.
Definition: coap_session.c:58
coap_session_t::context
struct coap_context_t * context
session&#39;s context
Definition: coap_session.h:72
coap_new_server_session
coap_session_t * coap_new_server_session(struct coap_context_t *ctx, coap_endpoint_t *ep)
Creates a new server session for the specified endpoint.
Definition: coap_session.c:881
coap_session_t::ack_timeout
coap_fixed_point_t ack_timeout
timeout waiting for ack (default 2 secs)
Definition: coap_session.h:93
coap_session_t::tls
void * tls
security parameters
Definition: coap_session.h:73
COAP_DEFAULT_MAX_HANDSHAKE_SESSIONS
#define COAP_DEFAULT_MAX_HANDSHAKE_SESSIONS
Definition: coap_session.h:36
coap_session_get_app_data
void * coap_session_get_app_data(const coap_session_t *session)
Returns any application-specific data that has been stored with session using the function coap_sessi...
Definition: coap_session.c:91
coap_context_t::endpoint
coap_endpoint_t * endpoint
the endpoints used for listening
Definition: net.h:165
COAP_SESSION_STATE_HANDSHAKE
#define COAP_SESSION_STATE_HANDSHAKE
Definition: coap_session.h:55
coap_socket_t
Definition: coap_io.h:54
COAP_SOCKET_CONNECTED
#define COAP_SOCKET_CONNECTED
the socket is connected
Definition: coap_io.h:79
COAP_SOCKET_BOUND
#define COAP_SOCKET_BOUND
the socket is bound
Definition: coap_io.h:78
coap_address_t
multi-purpose address abstraction
Definition: address.h:62
COAP_NACK_NOT_DELIVERABLE
Definition: coap_io.h:228
coap_socket_t::fd
coap_fd_t fd
Definition: coap_io.h:60
coap_session_t::tx_mid
uint16_t tx_mid
the last message id that was used in this session
Definition: coap_session.h:74
coap_dtls_context_check_keys_enabled
int coap_dtls_context_check_keys_enabled(coap_context_t *ctx UNUSED)
Definition: coap_notls.c:63
coap_socket_send
ssize_t coap_socket_send(coap_socket_t *sock, coap_session_t *session, const uint8_t *data, size_t data_len)
Definition: coap_io.c:1657
coap_session_t::ref
unsigned ref
reference count from queues
Definition: coap_session.h:63
coap_tid_t
int coap_tid_t
coap_tid_t is used to store CoAP transaction id, i.e.
Definition: pdu.h:238
LL_PREPEND
#define LL_PREPEND(head, add)
Definition: utlist.h:314
coap_session_set_mtu
void coap_session_set_mtu(coap_session_t *session, unsigned mtu)
Set the session MTU.
Definition: coap_session.c:204
coap_session_send_ping
coap_tid_t coap_session_send_ping(coap_session_t *session)
Send a ping message for the session.
Definition: coap_session.c:314
COAP_NACK_ICMP_ISSUE
Definition: coap_io.h:231
coap_session_t::tls_overhead
unsigned tls_overhead
overhead of TLS layer
Definition: coap_session.h:64
coap_dtls_pki_t::version
uint8_t version
Definition: coap_dtls.h:194
COAP_MAX_MESSAGE_SIZE_TCP8
#define COAP_MAX_MESSAGE_SIZE_TCP8
Definition: pdu.h:42
coap_encode_var_safe
unsigned int coap_encode_var_safe(uint8_t *buf, size_t length, unsigned int val)
Encodes multiple-length byte sequences.
Definition: encode.c:38
coap_session_new_dtls_session
coap_session_t * coap_session_new_dtls_session(coap_session_t *session, coap_tick_t now)
Create a new DTLS session for the session.
Definition: coap_session.c:592
coap_packet_t::ifindex
int ifindex
the interface index
Definition: coap_io.h:219
coap_addr_tuple_t::local
coap_address_t local
local address and port
Definition: coap_io.h:51
COAP_PROTO_DTLS
#define COAP_PROTO_DTLS
Definition: pdu.h:345
coap_socket_accept_tcp
int coap_socket_accept_tcp(coap_socket_t *server, coap_socket_t *new_client, coap_address_t *local_addr, coap_address_t *remote_addr)
Definition: coap_io.c:492
coap_dtls_new_client_session
void * coap_dtls_new_client_session(coap_session_t *session UNUSED)
Definition: coap_notls.c:96
coap_new_endpoint
coap_endpoint_t * coap_new_endpoint(coap_context_t *context, const coap_address_t *listen_addr, coap_proto_t proto)
Create a new endpoint for communicating with peers.
Definition: coap_session.c:918
coap_print_addr
size_t coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t len)
Print the address into the defined buffer.
Definition: coap_debug.c:161
coap_send
coap_tid_t coap_send(coap_session_t *session, coap_pdu_t *pdu)
Sends a CoAP message to given peer.
Definition: net.c:966
coap_endpoint_t::default_mtu
uint16_t default_mtu
default mtu for this interface
Definition: coap_session_internal.h:33
coap_delete_observers
void coap_delete_observers(coap_context_t *context, coap_session_t *session)
Removes any subscription for session and releases the allocated storage.
Definition: resource.c:724
coap_socket_connect_tcp1
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)
Definition: coap_io.c:264
coap_dtls_is_supported
int coap_dtls_is_supported(void)
Check whether DTLS is available.
Definition: coap_notls.c:21
coap_dtls_context_set_pki
int coap_dtls_context_set_pki(coap_context_t *ctx UNUSED, coap_dtls_pki_t *setup_data UNUSED, coap_dtls_role_t role UNUSED)
Definition: coap_notls.c:39
coap_tls_new_server_session
void * coap_tls_new_server_session(coap_session_t *session UNUSED, int *connected UNUSED)
Definition: coap_notls.c:154
coap_new_client_session_pki
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, coap_dtls_pki_t *setup_data)
Creates a new client session to the designated server with PKI credentials.
Definition: coap_session.c:841
coap_packet_t
Definition: coap_io.h:217
coap_session_t::local_if
coap_address_t local_if
optional local interface address
Definition: coap_session.h:66
coap_session_max_pdu_size
size_t coap_session_max_pdu_size(const coap_session_t *session)
Get maximum acceptable PDU size.
Definition: coap_session.c:187
COAP_EVENT_TCP_CONNECTED
#define COAP_EVENT_TCP_CONNECTED
TCP events for COAP_PROTO_TCP and COAP_PROTO_TLS.
Definition: coap_event.h:41
coap_session_send
ssize_t coap_session_send(coap_session_t *session, const uint8_t *data, size_t datalen)
Function interface for datagram data transmission.
Definition: coap_session.c:216
coap_session_t::dtls_event
int dtls_event
Tracking any (D)TLS events on this sesison.
Definition: coap_session.h:96
coap_session_get_by_peer
coap_session_t * coap_session_get_by_peer(coap_context_t *ctx, const coap_address_t *remote_addr, int ifindex)
Definition: coap_session.c:1029
COAP_PDU_DELAYED
#define COAP_PDU_DELAYED
Definition: pdu.h:249
coap_session_set_ack_random_factor
void coap_session_set_ack_random_factor(coap_session_t *session, coap_fixed_point_t value)
Set the CoAP ack randomize factor.
Definition: coap_session.c:42
LOG_DEBUG
Debug.
Definition: coap_debug.h:55
coap_endpoint_set_default_mtu
void coap_endpoint_set_default_mtu(coap_endpoint_t *ep, unsigned mtu)
Set the endpoint&#39;s default MTU.
Definition: coap_session.c:1001
coap_context_t::nack_handler
coap_nack_handler_t nack_handler
Definition: net.h:181
COAP_SOCKET_WANT_ACCEPT
#define COAP_SOCKET_WANT_ACCEPT
non blocking server socket is waiting for accept
Definition: coap_io.h:82
COAP_MAX_MESSAGE_SIZE_TCP16
#define COAP_MAX_MESSAGE_SIZE_TCP16
Definition: pdu.h:43
COAP_EVENT_TCP_FAILED
#define COAP_EVENT_TCP_FAILED
Definition: coap_event.h:43
coap_nack_reason_t
coap_nack_reason_t
Definition: coap_io.h:226
coap_packet_t::payload
unsigned char payload[COAP_RXBUFFER_SIZE]
payload
Definition: coap_io.h:221
COAP_EVENT_SESSION_FAILED
#define COAP_EVENT_SESSION_FAILED
Definition: coap_event.h:50
coap_endpoint_t::context
struct coap_context_t * context
endpoint&#39;s context
Definition: coap_session_internal.h:31
coap_session_reference
coap_session_t * coap_session_reference(coap_session_t *session)
Increment reference counter on a session.
Definition: coap_session.c:68
coap_endpoint_str
const char * coap_endpoint_str(const coap_endpoint_t *endpoint)
Get endpoint description.
Definition: coap_session.c:1088
coap_tls_new_client_session
void * coap_tls_new_client_session(coap_session_t *session UNUSED, int *connected UNUSED)
Definition: coap_notls.c:150
coap_endpoint_t
Abstraction of virtual endpoint that can be attached to coap_context_t.
Definition: coap_session_internal.h:29
coap_session_str
const char * coap_session_str(const coap_session_t *session)
Get session description.
Definition: coap_session.c:1049
coap_new_message_id
COAP_STATIC_INLINE uint16_t coap_new_message_id(coap_session_t *session)
Returns a new message id and updates session->tx_mid accordingly.
Definition: net.h:390
coap_socket_strerror
const char * coap_socket_strerror(void)
Definition: coap_io.c:1651
coap_socket_t::endpoint
struct coap_endpoint_t * endpoint
Definition: coap_io.h:67
COAP_SESSION_STATE_ESTABLISHED
#define COAP_SESSION_STATE_ESTABLISHED
Definition: coap_session.h:57
coap_queue_t::id
coap_tid_t id
CoAP transaction id.
Definition: net.h:45
coap_session_t::max_retransmit
unsigned int max_retransmit
maximum re-transmit count (default 4)
Definition: coap_session.h:92
SESSIONS_ITER_SAFE
#define SESSIONS_ITER_SAFE(e, el, rtmp)
Definition: coap_session.h:489
COAP_DEFAULT_ACK_RANDOM_FACTOR
#define COAP_DEFAULT_ACK_RANDOM_FACTOR
A factor that is used to randomize the wait time before a message is retransmitted to prevent synchro...
Definition: coap_session.h:382
coap_fixed_point_t::fractional_part
uint16_t fractional_part
Fractional part of fixed point variable 1/1000 (3 points) precision.
Definition: coap_session.h:30
COAP_EVENT_SESSION_CONNECTED
#define COAP_EVENT_SESSION_CONNECTED
CSM exchange events for reliable protocols only.
Definition: coap_event.h:48
coap_address_init
void coap_address_init(coap_address_t *addr)
Resets the given coap_address_t object addr to its default values.
Definition: address.c:71
COAP_PROTO_UDP
#define COAP_PROTO_UDP
Definition: pdu.h:344
coap_malloc
COAP_STATIC_INLINE void * coap_malloc(size_t size)
Wrapper function to coap_malloc_type() for backwards compatibility.
Definition: mem.h:75
coap_malloc_endpoint
struct coap_endpoint_t * coap_malloc_endpoint(void)
Definition: coap_io.c:175
coap_tls_is_supported
int coap_tls_is_supported(void)
Check whether TLS is available.
Definition: coap_notls.c:26
coap_queue_t::pdu
coap_pdu_t * pdu
the CoAP PDU to send
Definition: net.h:46
coap_queue_t::t
coap_tick_t t
when to send PDU for the next time
Definition: net.h:40
coap_session_mfree
void coap_session_mfree(coap_session_t *session)
Definition: coap_session.c:145
coap_pdu_encode_header
size_t coap_pdu_encode_header(coap_pdu_t *pdu, coap_proto_t proto)
Compose the protocol specific header for the specified PDU.
Definition: pdu.c:568
OFF_HANDSHAKE_TYPE
#define OFF_HANDSHAKE_TYPE
COAP_PARTIAL_SESSION_TIMEOUT_TICKS
#define COAP_PARTIAL_SESSION_TIMEOUT_TICKS
Definition: coap_session.h:35
COAP_INVALID_TID
#define COAP_INVALID_TID
Indicates an invalid transaction id.
Definition: pdu.h:241
coap_endpoint_get_session
coap_session_t * coap_endpoint_get_session(coap_endpoint_t *endpoint, const coap_packet_t *packet, coap_tick_t now)
Definition: coap_session.c:460
coap_session_set_max_retransmit
void coap_session_set_max_retransmit(coap_session_t *session, unsigned int value)
Set the CoAP maximum retransmit count before failure.
Definition: coap_session.c:23
coap_session_set_app_data
void coap_session_set_app_data(coap_session_t *session, void *app_data)
Stores data with the given session.
Definition: coap_session.c:85
coap_calc_timeout
unsigned int coap_calc_timeout(coap_session_t *session, unsigned char r)
Calculates the initial timeout based on the session CoAP transmission parameters &#39;ack_timeout&#39;, &#39;ack_random_factor&#39;, and COAP_TICKS_PER_SECOND.
Definition: net.c:862
coap_pdu_t
structure for CoAP PDUs token, if any, follows the fixed size header, then options until payload mark...
Definition: pdu.h:287
COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE
#define COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE
Definition: pdu.h:187
coap_session_t::delayqueue
struct coap_queue_t * delayqueue
list of delayed messages waiting to be sent
Definition: coap_session.h:77
coap_session_t::proto
coap_proto_t proto
protocol used
Definition: coap_session.h:60
coap_session_t::addr_info
coap_addr_tuple_t addr_info
key: remote/local address info
Definition: coap_session.h:68
LOG_WARNING
Warning.
Definition: coap_debug.h:52
coap_tick_t
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition: coap_time.h:93
coap_session_accept
static coap_session_t * coap_session_accept(coap_session_t *session)
Definition: coap_session.c:739
coap_free_endpoint
void coap_free_endpoint(coap_endpoint_t *ep)
Definition: coap_session.c:1006
COAP_SOCKET_NOT_EMPTY
#define COAP_SOCKET_NOT_EMPTY
the socket is not empty
Definition: coap_io.h:77
coap_dtls_get_overhead
unsigned int coap_dtls_get_overhead(coap_session_t *session UNUSED)
Definition: coap_notls.c:146
coap_session_t::partial_read
size_t partial_read
if > 0 indicates number of bytes already read for an incoming message
Definition: coap_session.h:80
coap_session_t::partial_pdu
coap_pdu_t * partial_pdu
incomplete incoming pdu
Definition: coap_session.h:81
coap_session_delay_pdu
ssize_t coap_session_delay_pdu(coap_session_t *session, coap_pdu_t *pdu, coap_queue_t *node)
Definition: coap_session.c:251
coap_pdu_t::used_size
size_t used_size
used bytes of storage for token, options and payload
Definition: pdu.h:296
SESSIONS_ADD
#define SESSIONS_ADD(e, obj)
Definition: coap_session.h:480
coap_session_free
void coap_session_free(coap_session_t *session)
Definition: coap_session.c:168
coap_queue_t::next
struct coap_queue_t * next
Definition: net.h:39
DTLS_CT_HANDSHAKE
#define DTLS_CT_HANDSHAKE
coap_session_t::sock
coap_socket_t sock
socket object for the session, if any
Definition: coap_session.h:70
coap_socket_write
ssize_t coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len)
Definition: coap_io.c:690
coap_ticks
void coap_ticks(coap_tick_t *t)
Sets t to the internal time with COAP_TICKS_PER_SECOND resolution.
COAPS_DEFAULT_PORT
#define COAPS_DEFAULT_PORT
Definition: pdu.h:29
INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN
coap_dtls_context_set_psk
int coap_dtls_context_set_psk(coap_context_t *ctx UNUSED, const char *hint UNUSED, coap_dtls_role_t role UNUSED)
Definition: coap_notls.c:55
coap_endpoint_t::proto
coap_proto_t proto
protocol used on this interface
Definition: coap_session_internal.h:32
COAP_MESSAGE_CON
#define COAP_MESSAGE_CON
Definition: pdu.h:72
coap_queue_t::timeout
unsigned int timeout
the randomized timeout value
Definition: net.h:43
COAP_PROTO_TLS
#define COAP_PROTO_TLS
Definition: pdu.h:347
LL_APPEND
#define LL_APPEND(head, add)
Definition: utlist.h:338
coap_session_connect
static coap_session_t * coap_session_connect(coap_session_t *session)
Definition: coap_session.c:695
coap_free
COAP_STATIC_INLINE void coap_free(void *object)
Wrapper function to coap_free_type() for backwards compatibility.
Definition: mem.h:82
LOG_ERR
Error.
Definition: coap_debug.h:51
coap_session_t::type
coap_session_type_t type
client or server side socket
Definition: coap_session.h:61
COAP_DEFAULT_NSTART
#define COAP_DEFAULT_NSTART
The number of simultaneous outstanding interactions that a client maintains to a given server...
Definition: coap_session.h:395
COAP_EVENT_TCP_CLOSED
#define COAP_EVENT_TCP_CLOSED
Definition: coap_event.h:42
coap_session_t::state
coap_session_state_t state
current state of relationaship with peer
Definition: coap_session.h:62
COAP_DTLS_ROLE_CLIENT
Internal function invoked for client.
Definition: coap_dtls.h:267
coap_session_t::psk_identity_len
size_t psk_identity_len
Definition: coap_session.h:88
COAP_SESSION_TYPE_SERVER
#define COAP_SESSION_TYPE_SERVER
server-side
Definition: coap_session.h:46
coap_add_option
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.
Definition: pdu.c:215
coap_session_release
void coap_session_release(coap_session_t *session)
Decrement reference counter on a session.
Definition: coap_session.c:74
COAP_SESSION_TYPE_HELLO
#define COAP_SESSION_TYPE_HELLO
server-side ephemeral session for responding to a client hello
Definition: coap_session.h:47
coap_session_t::ack_random_factor
coap_fixed_point_t ack_random_factor
ack random factor backoff (default 1.5)
Definition: coap_session.h:94
coap_remove_from_queue
int coap_remove_from_queue(coap_queue_t **queue, coap_session_t *session, coap_tid_t id, coap_queue_t **node)
This function removes the element with given id from the list given list.
Definition: net.c:1585
coap_session_t::ifindex
int ifindex
interface index
Definition: coap_session.h:69
COAP_DEFAULT_PORT
#define COAP_DEFAULT_PORT
Definition: pdu.h:28
coap_dtls_free_session
void coap_dtls_free_session(coap_session_t *coap_session UNUSED)
Definition: coap_notls.c:100
coap_session_t::partial_write
size_t partial_write
if > 0 indicates number of bytes already written from the pdu at the head of sendqueue ...
Definition: coap_session.h:78
uint32_t
unsigned int uint32_t
Definition: uthash.h:78
COAP_EVENT_DTLS_CONNECTED
#define COAP_EVENT_DTLS_CONNECTED
Definition: coap_event.h:34
coap_address_equals
int coap_address_equals(const coap_address_t *a, const coap_address_t *b)
Compares given address objects a and b.
Definition: address.c:31
coap_handle_event
int coap_handle_event(coap_context_t *context, coap_event_t event, coap_session_t *session)
Invokes the event handler of context for the given event and data.
Definition: net.c:2542
coap_delete_pdu
void coap_delete_pdu(coap_pdu_t *pdu)
Dispose of an CoAP PDU and frees associated storage.
Definition: pdu.c:127
coap_session_write
ssize_t coap_session_write(coap_session_t *session, const uint8_t *data, size_t datalen)
Function interface for stream data transmission.
Definition: coap_session.c:237
coap_address_copy
COAP_STATIC_INLINE void coap_address_copy(coap_address_t *dst, const coap_address_t *src)
Definition: address.h:108
coap_packet_t::length
size_t length
length of payload
Definition: coap_io.h:220
coap_dtls_new_server_session
void * coap_dtls_new_server_session(coap_session_t *session UNUSED)
Definition: coap_notls.c:92
coap_session_connected
void coap_session_connected(coap_session_t *session)
Notify session that it has just connected or reconnected.
Definition: coap_session.c:330
COAP_DEFAULT_ACK_TIMEOUT
#define COAP_DEFAULT_ACK_TIMEOUT
Number of seconds when to expect an ACK or a response to an outstanding CON message.
Definition: coap_session.h:375
SESSIONS_FIND
#define SESSIONS_FIND(e, k, res)
Definition: coap_session.h:492
COAP_SOCKET_WANT_READ
#define COAP_SOCKET_WANT_READ
non blocking socket is waiting for reading
Definition: coap_io.h:80
LL_FOREACH_SAFE
#define LL_FOREACH_SAFE(head, el, tmp)
Definition: utlist.h:419
COAP_PROTO_RELIABLE
#define COAP_PROTO_RELIABLE(p)
Definition: coap_session.h:39
COAP_SESSION_STATE_CONNECTING
#define COAP_SESSION_STATE_CONNECTING
Definition: coap_session.h:54
COAP_MAX_MESSAGE_SIZE_TCP0
#define COAP_MAX_MESSAGE_SIZE_TCP0
Definition: pdu.h:41
COAP_SESSION
Definition: mem.h:44
coap_dtls_pki_t
The structure used for defining the PKI setup data to be used.
Definition: coap_dtls.h:193
coap_session_create_client
static coap_session_t * coap_session_create_client(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto)
Definition: coap_session.c:642
coap_session_type_t
uint8_t coap_session_type_t
Definition: coap_session.h:41
COAP_SOCKET_WANT_CONNECT
#define COAP_SOCKET_WANT_CONNECT
non blocking client socket is waiting for connect
Definition: coap_io.h:83
coap_malloc_type
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
LL_DELETE
#define LL_DELETE(head, del)
Definition: utlist.h:385
SESSIONS_DELETE
#define SESSIONS_DELETE(e, obj)
Definition: coap_session.h:483
COAP_PROTO_NOT_RELIABLE
#define COAP_PROTO_NOT_RELIABLE(p)
Definition: coap_session.h:38
coap_get_log_level
coap_log_t coap_get_log_level(void)
Get the current logging level.
Definition: coap_debug.c:61
OFF_CONTENT_TYPE
#define OFF_CONTENT_TYPE
coap_context_t::max_handshake_sessions
unsigned int max_handshake_sessions
Maximum number of simultaneous negotating sessions per endpoint.
Definition: net.h:207
COAP_DEFAULT_MAX_PDU_RX_SIZE
#define COAP_DEFAULT_MAX_PDU_RX_SIZE
Definition: pdu.h:51
coap_endpoint_t::sessions
struct coap_session_t * sessions
hash table or list of active sessions
Definition: coap_session_internal.h:36
coap_pdu_t::hdr_size
uint8_t hdr_size
actaul size used for protocol-specific header
Definition: pdu.h:291
COAP_NACK_TLS_FAILED
Definition: coap_io.h:230
coap_session_t::psk_key_len
size_t psk_key_len
Definition: coap_session.h:90
DTLS_CT_ALERT
#define DTLS_CT_ALERT
coap_socket_t::flags
coap_socket_flags_t flags
Definition: coap_io.h:62
coap_session_disconnected
void coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason)
Notify session that it has failed.
Definition: coap_session.c:387
coap_context_t::sessions
coap_session_t * sessions
client sessions
Definition: net.h:166
coap_log
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:129
coap_packet_t::addr_info
coap_addr_tuple_t addr_info
local and remote addresses
Definition: coap_io.h:218
coap_make_session
static coap_session_t * coap_make_session(coap_proto_t proto, coap_session_type_t type, const coap_address_t *local_if, const coap_address_t *local_addr, const coap_address_t *remote_addr, int ifindex, coap_context_t *context, coap_endpoint_t *endpoint)
Definition: coap_session.c:97
coap_endpoint_t::sock
coap_socket_t sock
socket object for the interface, if any
Definition: coap_session_internal.h:34
coap_session_send_pdu
ssize_t coap_session_send_pdu(coap_session_t *session, coap_pdu_t *pdu)
Send a pdu according to the session&#39;s protocol.
Definition: net.c:683
coap_pdu_init
coap_pdu_t * coap_pdu_init(uint8_t type, uint8_t code, uint16_t tid, size_t size)
Creates a new CoAP PDU with at least enough storage space for the given size maximum message size...
Definition: pdu.c:79
coap_socket_connect_udp
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)
Definition: coap_io.c:529
coap_queue_t::session
coap_session_t * session
the CoAP session
Definition: net.h:44
coap_free_type
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
COAP_PROTO_NONE
#define COAP_PROTO_NONE
coap_proto_t values
Definition: pdu.h:343
COAP_EVENT_SESSION_CLOSED
#define COAP_EVENT_SESSION_CLOSED
Definition: coap_event.h:49
coap_new_client_session_psk
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)
Creates a new client session to the designated server with PSK credentials.
Definition: coap_session.c:781
uint8_t
unsigned char uint8_t
Definition: uthash.h:79
coap_cancel_session_messages
void coap_cancel_session_messages(coap_context_t *context, coap_session_t *session, coap_nack_reason_t reason)
Cancels all outstanding messages for session session.
Definition: net.c:1635
coap_session_t::endpoint
struct coap_endpoint_t * endpoint
session&#39;s endpoint
Definition: coap_session.h:71
prng
#define prng(Buf, Length)
Fills Buf with Length bytes of random data.
Definition: prng.h:112
coap_session_get_ack_random_factor
coap_fixed_point_t coap_session_get_ack_random_factor(coap_session_t *session)
Get the CoAP ack randomize factor.
Definition: coap_session.c:63
LOG_CRIT
Critical.
Definition: coap_debug.h:50
coap_socket_bind_udp
int coap_socket_bind_udp(coap_socket_t *sock, const coap_address_t *listen_addr, coap_address_t *bound_addr)
Definition: coap_io.c:185
COAP_SESSION_STATE_NONE
#define COAP_SESSION_STATE_NONE
coap_session_state_t values
Definition: coap_session.h:53
LOG_INFO
Information.
Definition: coap_debug.h:54
SESSIONS_ITER
#define SESSIONS_ITER(e, el, rtmp)
Definition: coap_session.h:486
coap_socket_bind_tcp
int coap_socket_bind_tcp(coap_socket_t *sock, const coap_address_t *listen_addr, coap_address_t *bound_addr)
Definition: coap_io.c:412
coap_fixed_point_t::integer_part
uint16_t integer_part
Integer part of fixed point variable.
Definition: coap_session.h:29
coap_mfree_endpoint
void coap_mfree_endpoint(struct coap_endpoint_t *ep)
Definition: coap_io.c:180
coap_queue_t
Queue entry.
Definition: net.h:38
coap_session_state_t
uint8_t coap_session_state_t
Definition: coap_session.h:49
coap_new_node
coap_queue_t * coap_new_node(void)
Creates a new node suitable for adding to the CoAP sendqueue.
Definition: net.c:248
coap_endpoint_t::bind_addr
coap_address_t bind_addr
local interface address
Definition: coap_session_internal.h:35
COAP_PROTO_TCP
#define COAP_PROTO_TCP
Definition: pdu.h:346
coap_session_t::psk_key
uint8_t * psk_key
Definition: coap_session.h:89
coap_context_t
The CoAP stack&#39;s global state is stored in a coap_context_t object.
Definition: net.h:147
coap_pdu_t::tid
uint16_t tid
transaction id, if any, in regular host byte order
Definition: pdu.h:293
coap_context_t::max_idle_sessions
unsigned int max_idle_sessions
Maximum number of simultaneous unused sessions per endpoint.
Definition: net.h:206
COAP_DEFAULT_MAX_RETRANSMIT
#define COAP_DEFAULT_MAX_RETRANSMIT
Number of message retransmissions before message sending is stopped RFC 7252, Section 4...
Definition: coap_session.h:388
coap_delete_node
int coap_delete_node(coap_queue_t *node)
Destroys specified node.
Definition: net.c:219
coap_socket_t::session
struct coap_session_t * session
Definition: coap_io.h:63
coap_internal.h
Pulls together all the internal only header files.
COAP_SESSION_STATE_CSM
#define COAP_SESSION_STATE_CSM
Definition: coap_session.h:56