libcoap  4.3.0beta
coap_session.c
Go to the documentation of this file.
1 /* session.c -- Session management for libcoap
2 *
3 * Copyright (C) 2017 Jean-Claue Michelou <jcm@spinetix.com>
4 *
5 * This file is part of the CoAP library libcoap. Please see
6 * README for terms of use.
7 */
8 
9 #include "coap_internal.h"
10 
11 #ifndef COAP_SESSION_C_
12 #define COAP_SESSION_C_
13 
14 #include <stdio.h>
15 
16 #ifdef COAP_EPOLL_SUPPORT
17 #include <sys/epoll.h>
18 #include <sys/timerfd.h>
19 #endif /* COAP_EPOLL_SUPPORT */
20 #include <errno.h>
21 
22 void
23 coap_session_set_max_retransmit (coap_session_t *session, unsigned int value) {
24  if (value > 0)
25  session->max_retransmit = value;
26  coap_log(LOG_DEBUG, "***%s: session max_retransmit set to %d\n",
27  coap_session_str(session), session->max_retransmit);
28  return;
29 }
30 
31 void
33  if (value.integer_part > 0 && value.fractional_part < 1000)
34  session->ack_timeout = value;
35  coap_log(LOG_DEBUG, "***%s: session ack_timeout set to %d.%03d\n",
36  coap_session_str(session), session->ack_timeout.integer_part,
37  session->ack_timeout.fractional_part);
38  return;
39 }
40 
41 void
43  coap_fixed_point_t value) {
44  if (value.integer_part > 0 && value.fractional_part < 1000)
45  session->ack_random_factor = value;
46  coap_log(LOG_DEBUG, "***%s: session ack_random_factor set to %d.%03d\n",
49  return;
50 }
51 
52 unsigned int
54  return session->max_retransmit;
55 }
56 
59  return session->ack_timeout;
60 }
61 
64  return session->ack_random_factor;
65 }
66 
69  ++session->ref;
70  return session;
71 }
72 
73 void
75  if (session) {
76 #ifndef __COVERITY__
77  assert(session->ref > 0);
78  if (session->ref > 0)
79  --session->ref;
80  if (session->ref == 0 && session->type == COAP_SESSION_TYPE_CLIENT)
81  coap_session_free(session);
82 #else /* __COVERITY__ */
83  /* Coverity scan is fooled by the reference counter leading to
84  * false positives for USE_AFTER_FREE. */
85  --session->ref;
86  __coverity_negative_sink__(session->ref);
87  /* Indicate that resources are released properly. */
88  if (session->ref == 0 && session->type == COAP_SESSION_TYPE_CLIENT) {
89  __coverity_free__(session);
90  }
91 #endif /* __COVERITY__ */
92  }
93 }
94 
95 void
96 coap_session_set_app_data(coap_session_t *session, void *app_data) {
97  assert(session);
98  session->app = app_data;
99 }
100 
101 void *
103  assert(session);
104  return session->app;
105 }
106 
107 static coap_session_t *
109  const coap_address_t *local_if, const coap_address_t *local_addr,
110  const coap_address_t *remote_addr, int ifindex, coap_context_t *context,
111  coap_endpoint_t *endpoint) {
113  if (!session)
114  return NULL;
115  memset(session, 0, sizeof(*session));
116  session->proto = proto;
117  session->type = type;
118  if (local_if)
119  coap_address_copy(&session->local_if, local_if);
120  else
121  coap_address_init(&session->local_if);
122  if (local_addr)
123  coap_address_copy(&session->addr_info.local, local_addr);
124  else
125  coap_address_init(&session->addr_info.local);
126  if (remote_addr)
127  coap_address_copy(&session->addr_info.remote, remote_addr);
128  else
130  session->ifindex = ifindex;
131  session->context = context;
132  session->endpoint = endpoint;
133  if (endpoint)
134  session->mtu = endpoint->default_mtu;
135  else
136  session->mtu = COAP_DEFAULT_MTU;
137  if (proto == COAP_PROTO_DTLS) {
138  session->tls_overhead = 29;
139  if (session->tls_overhead >= session->mtu) {
140  session->tls_overhead = session->mtu;
141  coap_log(LOG_ERR, "DTLS overhead exceeds MTU\n");
142  }
143  }
147  session->dtls_event = -1;
148  session->last_ping_mid = COAP_INVALID_TID;
149 
150  /* initialize message id */
151  coap_prng((unsigned char *)&session->tx_mid, sizeof(session->tx_mid));
152 
153  return session;
154 }
155 
157  coap_queue_t *q, *tmp;
158  coap_cache_entry_t *cp, *ctmp;
159 
160  if (session->partial_pdu)
161  coap_delete_pdu(session->partial_pdu);
162  if (session->proto == COAP_PROTO_DTLS)
163  coap_dtls_free_session(session);
164 #if !COAP_DISABLE_TCP
165  else if (session->proto == COAP_PROTO_TLS)
166  coap_tls_free_session(session);
167 #endif /* !COAP_DISABLE_TCP */
168  if (session->sock.flags != COAP_SOCKET_EMPTY)
169  coap_socket_close(&session->sock);
170  if (session->psk_identity)
171  coap_free(session->psk_identity);
172  if (session->psk_key)
173  coap_free(session->psk_key);
174  if (session->psk_hint)
175  coap_free(session->psk_hint);
176 
177  HASH_ITER(hh, session->context->cache, cp, ctmp) {
178  /* cp->session is NULL if not session based */
179  if (cp->session == session) {
180  coap_delete_cache_entry(session->context, cp);
181  }
182  }
183  LL_FOREACH_SAFE(session->delayqueue, q, tmp) {
184  if (q->pdu->type==COAP_MESSAGE_CON && session->context && session->context->nack_handler)
185  session->context->nack_handler(session->context, session, q->pdu, session->proto == COAP_PROTO_DTLS ? COAP_NACK_TLS_FAILED : COAP_NACK_NOT_DELIVERABLE, q->id);
186  coap_delete_node(q);
187  }
188 }
189 
191  if (!session)
192  return;
193  assert(session->ref == 0);
194  if (session->ref)
195  return;
196  coap_session_mfree(session);
197  if (session->endpoint) {
198  if (session->endpoint->sessions)
199  SESSIONS_DELETE(session->endpoint->sessions, session);
200  } else if (session->context) {
201  if (session->context->sessions)
202  SESSIONS_DELETE(session->context->sessions, session);
203  }
204  coap_log(LOG_DEBUG, "***%s: session closed\n", coap_session_str(session));
205 
206  coap_free_type(COAP_SESSION, session);
207 }
208 
210  size_t max_with_header = (size_t)(session->mtu - session->tls_overhead);
211 #if COAP_DISABLE_TCP
212  return max_with_header > 4 ? max_with_header - 4 : 0;
213 #else /* !COAP_DISABLE_TCP */
214  if (COAP_PROTO_NOT_RELIABLE(session->proto))
215  return max_with_header > 4 ? max_with_header - 4 : 0;
216  /* we must assume there is no token to be on the safe side */
217  if (max_with_header <= 2)
218  return 0;
219  else if (max_with_header <= COAP_MAX_MESSAGE_SIZE_TCP0 + 2)
220  return max_with_header - 2;
221  else if (max_with_header <= COAP_MAX_MESSAGE_SIZE_TCP8 + 3)
222  return max_with_header - 3;
223  else if (max_with_header <= COAP_MAX_MESSAGE_SIZE_TCP16 + 4)
224  return max_with_header - 4;
225  else
226  return max_with_header - 6;
227 #endif /* !COAP_DISABLE_TCP */
228 }
229 
230 void coap_session_set_mtu(coap_session_t *session, unsigned mtu) {
231 #if defined(WITH_CONTIKI) || defined(WITH_LWIP)
232  if (mtu > COAP_MAX_MESSAGE_SIZE_TCP16 + 4)
233  mtu = COAP_MAX_MESSAGE_SIZE_TCP16 + 4;
234 #endif
235  session->mtu = mtu;
236  if (session->tls_overhead >= session->mtu) {
237  session->tls_overhead = session->mtu;
238  coap_log(LOG_ERR, "DTLS overhead exceeds MTU\n");
239  }
240 }
241 
242 ssize_t coap_session_send(coap_session_t *session, const uint8_t *data, size_t datalen) {
243  ssize_t bytes_written;
244 
245  coap_socket_t *sock = &session->sock;
246  if (sock->flags == COAP_SOCKET_EMPTY) {
247  assert(session->endpoint != NULL);
248  sock = &session->endpoint->sock;
249  }
250 
251  bytes_written = coap_socket_send(sock, session, data, datalen);
252  if (bytes_written == (ssize_t)datalen) {
253  coap_ticks(&session->last_rx_tx);
254  coap_log(LOG_DEBUG, "* %s: sent %zd bytes\n",
255  coap_session_str(session), datalen);
256  } else {
257  coap_log(LOG_DEBUG, "* %s: failed to send %zd bytes\n",
258  coap_session_str(session), datalen);
259  }
260  return bytes_written;
261 }
262 
263 ssize_t coap_session_write(coap_session_t *session, const uint8_t *data, size_t datalen) {
264  ssize_t bytes_written = coap_socket_write(&session->sock, data, datalen);
265  if (bytes_written > 0) {
266  coap_ticks(&session->last_rx_tx);
267  coap_log(LOG_DEBUG, "* %s: sent %zd bytes\n",
268  coap_session_str(session), datalen);
269  } else if (bytes_written < 0) {
270  coap_log(LOG_DEBUG, "* %s: failed to send %zd bytes\n",
271  coap_session_str(session), datalen );
272  }
273  return bytes_written;
274 }
275 
276 ssize_t
278  coap_queue_t *node)
279 {
280  if ( node ) {
281  coap_queue_t *removed = NULL;
282  coap_remove_from_queue(&session->context->sendqueue, session, node->id, &removed);
283  assert(removed == node);
285  node->session = NULL;
286  node->t = 0;
287  } else {
288  coap_queue_t *q = NULL;
289  /* Check that the same tid is not getting re-used in violation of RFC7252 */
290  LL_FOREACH(session->delayqueue, q) {
291  if (q->id == pdu->tid) {
292  coap_log(LOG_ERR, "** %s: mid=0x%x: already in-use - dropped\n", coap_session_str(session), pdu->tid);
293  return COAP_INVALID_TID;
294  }
295  }
296  node = coap_new_node();
297  if (node == NULL)
298  return COAP_INVALID_TID;
299  node->id = pdu->tid;
300  node->pdu = pdu;
301  if (pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto)) {
302  uint8_t r;
303  coap_prng(&r, sizeof(r));
304  /* add timeout in range [ACK_TIMEOUT...ACK_TIMEOUT * ACK_RANDOM_FACTOR] */
305  node->timeout = coap_calc_timeout(session, r);
306  }
307  }
308  LL_APPEND(session->delayqueue, node);
309  coap_log(LOG_DEBUG, "** %s: mid=0x%x: delayed\n",
310  coap_session_str(session), node->id);
311  return COAP_PDU_DELAYED;
312 }
313 
314 #if !COAP_DISABLE_TCP
316  coap_pdu_t *pdu;
317  uint8_t buf[4];
318  assert(COAP_PROTO_RELIABLE(session->proto));
319  coap_log(LOG_DEBUG, "***%s: sending CSM\n", coap_session_str(session));
320  session->state = COAP_SESSION_STATE_CSM;
321  session->partial_write = 0;
322  if (session->mtu == 0)
323  session->mtu = COAP_DEFAULT_MTU; /* base value */
325  if ( pdu == NULL
327  coap_encode_var_safe(buf, sizeof(buf),
328  COAP_DEFAULT_MAX_PDU_RX_SIZE), buf) == 0
330  coap_encode_var_safe(buf, sizeof(buf),
331  0), buf) == 0
332  || coap_pdu_encode_header(pdu, session->proto) == 0
333  ) {
335  } else {
336  ssize_t bytes_written = coap_session_send_pdu(session, pdu);
337  if (bytes_written != (ssize_t)pdu->used_size + pdu->hdr_size)
339  }
340  if (pdu)
341  coap_delete_pdu(pdu);
342 }
343 #endif /* !COAP_DISABLE_TCP */
344 
346  coap_pdu_t *ping = NULL;
347  if (session->state != COAP_SESSION_STATE_ESTABLISHED)
348  return COAP_INVALID_TID;
349  if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
350  uint16_t tid = coap_new_message_id (session);
351  ping = coap_pdu_init(COAP_MESSAGE_CON, 0, tid, 0);
352  }
353 #if !COAP_DISABLE_TCP
354  else {
356  }
357 #endif /* !COAP_DISABLE_TCP */
358  if (!ping)
359  return COAP_INVALID_TID;
360  return coap_send(session, ping);
361 }
362 
364  if (session->state != COAP_SESSION_STATE_ESTABLISHED) {
365  coap_log(LOG_DEBUG, "***%s: session connected\n",
366  coap_session_str(session));
367  if (session->state == COAP_SESSION_STATE_CSM)
369  }
370 
372  session->partial_write = 0;
373 
374  if ( session->proto==COAP_PROTO_DTLS) {
375  session->tls_overhead = coap_dtls_get_overhead(session);
376  if (session->tls_overhead >= session->mtu) {
377  session->tls_overhead = session->mtu;
378  coap_log(LOG_ERR, "DTLS overhead exceeds MTU\n");
379  }
380  }
381 
382  while (session->delayqueue && session->state == COAP_SESSION_STATE_ESTABLISHED) {
383  ssize_t bytes_written;
384  coap_queue_t *q = session->delayqueue;
385  if (q->pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto)) {
386  if (session->con_active >= COAP_DEFAULT_NSTART)
387  break;
388  session->con_active++;
389  }
390  /* Take entry off the queue */
391  session->delayqueue = q->next;
392  q->next = NULL;
393 
394  coap_log(LOG_DEBUG, "** %s: mid=0x%x: transmitted after delay\n",
395  coap_session_str(session), (int)q->pdu->tid);
396  bytes_written = coap_session_send_pdu(session, q->pdu);
397  if (q->pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto)) {
398  if (coap_wait_ack(session->context, session, q) >= 0)
399  q = NULL;
400  }
401  if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
402  if (q)
403  coap_delete_node(q);
404  if (bytes_written < 0)
405  break;
406  } else {
407  if (bytes_written <= 0 || (size_t)bytes_written < q->pdu->used_size + q->pdu->hdr_size) {
408  q->next = session->delayqueue;
409  session->delayqueue = q;
410  if (bytes_written > 0)
411  session->partial_write = (size_t)bytes_written;
412  break;
413  } else {
414  coap_delete_node(q);
415  }
416  }
417  }
418 }
419 
421  (void)reason;
422 #if !COAP_DISABLE_TCP
423  coap_session_state_t state = session->state;
424 #endif /* !COAP_DISABLE_TCP */
425 
426  coap_log(LOG_DEBUG, "***%s: session disconnected (reason %d)\n",
427  coap_session_str(session), reason);
428 #ifndef WITHOUT_OBSERVE
429  coap_delete_observers( session->context, session );
430 #endif
431 
432  if ( session->tls) {
433  if (session->proto == COAP_PROTO_DTLS)
434  coap_dtls_free_session(session);
435 #if !COAP_DISABLE_TCP
436  else if (session->proto == COAP_PROTO_TLS)
437  coap_tls_free_session(session);
438 #endif /* !COAP_DISABLE_TCP */
439  session->tls = NULL;
440  }
441 
442  if (session->proto == COAP_PROTO_UDP)
444  else
445  session->state = COAP_SESSION_STATE_NONE;
446 
447  session->con_active = 0;
448 
449  if (session->partial_pdu) {
450  coap_delete_pdu(session->partial_pdu);
451  session->partial_pdu = NULL;
452  }
453  session->partial_read = 0;
454 
455  while (session->delayqueue) {
456  coap_queue_t *q = session->delayqueue;
457  session->delayqueue = q->next;
458  q->next = NULL;
459  coap_log(LOG_DEBUG, "** %s: mid=0x%x: not transmitted after disconnect\n",
460  coap_session_str(session), q->id);
461  if (q->pdu->type==COAP_MESSAGE_CON
462  && COAP_PROTO_NOT_RELIABLE(session->proto)
463  && reason == COAP_NACK_ICMP_ISSUE)
464  {
465  /* Make sure that we try a re-transmit later on ICMP error */
466  if (coap_wait_ack(session->context, session, q) >= 0)
467  q = NULL;
468  }
469  if (q && q->pdu->type == COAP_MESSAGE_CON
470  && session->context->nack_handler)
471  {
472  session->context->nack_handler(session->context, session, q->pdu,
473  reason, q->id);
474  }
475  if (q)
476  coap_delete_node(q);
477  }
478  if (reason != COAP_NACK_ICMP_ISSUE)
479  coap_cancel_session_messages(session->context, session, reason);
480 
481 #if !COAP_DISABLE_TCP
482  if (COAP_PROTO_RELIABLE(session->proto)) {
483  if (session->sock.flags != COAP_SOCKET_EMPTY) {
484  coap_socket_close(&session->sock);
485  coap_handle_event(session->context,
488  }
489  if (state != COAP_SESSION_STATE_NONE) {
490  coap_handle_event(session->context,
493  }
494  }
495 #endif /* !COAP_DISABLE_TCP */
496 }
497 
500  const coap_packet_t *packet, coap_tick_t now) {
501  coap_session_t *session;
502  coap_session_t *rtmp;
503  unsigned int num_idle = 0;
504  unsigned int num_hs = 0;
505  coap_session_t *oldest = NULL;
506  coap_session_t *oldest_hs = NULL;
507 
508  SESSIONS_FIND(endpoint->sessions, packet->addr_info, session);
509  if (session) {
510  session->ifindex = packet->ifindex;
511  session->last_rx_tx = now;
512  return session;
513  }
514 
515  SESSIONS_ITER(endpoint->sessions, session, rtmp) {
516  if (session->ref == 0 && session->delayqueue == NULL) {
517  if (session->type == COAP_SESSION_TYPE_SERVER) {
518  ++num_idle;
519  if (oldest==NULL || session->last_rx_tx < oldest->last_rx_tx)
520  oldest = session;
521 
522  if (session->state == COAP_SESSION_STATE_HANDSHAKE) {
523  ++num_hs;
524  /* See if this is a partial (D)TLS session set up
525  which needs to be cleared down to prevent DOS */
526  if ((session->last_rx_tx + COAP_PARTIAL_SESSION_TIMEOUT_TICKS) < now) {
527  if (oldest_hs == NULL ||
528  session->last_rx_tx < oldest_hs->last_rx_tx)
529  oldest_hs = session;
530  }
531  }
532  }
533  else if (session->type == COAP_SESSION_TYPE_HELLO) {
534  ++num_hs;
535  /* See if this is a partial (D)TLS session set up for Client Hello
536  which needs to be cleared down to prevent DOS */
537  if ((session->last_rx_tx + COAP_PARTIAL_SESSION_TIMEOUT_TICKS) < now) {
538  if (oldest_hs == NULL ||
539  session->last_rx_tx < oldest_hs->last_rx_tx)
540  oldest_hs = session;
541  }
542  }
543  }
544  }
545 
546  if (endpoint->context->max_idle_sessions > 0 &&
547  num_idle >= endpoint->context->max_idle_sessions) {
548  coap_session_free(oldest);
549  }
550  else if (oldest_hs) {
551  coap_log(LOG_WARNING, "***%s: Incomplete session timed out\n",
552  coap_session_str(oldest_hs));
553  coap_session_free(oldest_hs);
554  }
555 
556  if (num_hs > (endpoint->context->max_handshake_sessions ?
557  endpoint->context->max_handshake_sessions :
559  /* Maxed out on number of sessions in (D)TLS negotiation state */
561  "Oustanding sessions in COAP_SESSION_STATE_HANDSHAKE too "
562  "large. New request ignored\n");
563  return NULL;
564  }
565 
566  if (endpoint->proto == COAP_PROTO_DTLS) {
567  /*
568  * Need to check that this actually is a Client Hello before wasting
569  * time allocating and then freeing off session.
570  */
571 
572  /*
573  * Generic header structure of the DTLS record layer.
574  * typedef struct __attribute__((__packed__)) {
575  * uint8_t content_type; content type of the included message
576  * uint16_t version; Protocol version
577  * uint16_t epoch; counter for cipher state changes
578  * uint8_t sequence_number[6]; sequence number
579  * uint16_t length; length of the following fragment
580  * uint8_t handshake; If content_type == DTLS_CT_HANDSHAKE
581  * } dtls_record_handshake_t;
582  */
583 #define OFF_CONTENT_TYPE 0 /* offset of content_type in dtls_record_handshake_t */
584 #define DTLS_CT_ALERT 21 /* Content Type Alert */
585 #define DTLS_CT_HANDSHAKE 22 /* Content Type Handshake */
586 #define OFF_HANDSHAKE_TYPE 13 /* offset of handshake in dtls_record_handshake_t */
587 #define DTLS_HT_CLIENT_HELLO 1 /* Client Hello handshake type */
588 
589 #ifdef WITH_LWIP
590  const uint8_t *payload = (const uint8_t*)packet->pbuf->payload;
591  size_t length = packet->pbuf->len;
592 #else /* ! WITH_LWIP */
593  const uint8_t *payload = (const uint8_t*)packet->payload;
594  size_t length = packet->length;
595 #endif /* ! WITH_LWIP */
596  if (length < (OFF_HANDSHAKE_TYPE + 1)) {
598  "coap_dtls_hello: ContentType %d Short Packet (%zu < %d) dropped\n",
599  payload[OFF_CONTENT_TYPE], length,
600  OFF_HANDSHAKE_TYPE + 1);
601  return NULL;
602  }
603  if (payload[OFF_CONTENT_TYPE] != DTLS_CT_HANDSHAKE ||
605  /* only log if not a late alert */
606  if (payload[OFF_CONTENT_TYPE] != DTLS_CT_ALERT)
608  "coap_dtls_hello: ContentType %d Handshake %d dropped\n",
609  payload[OFF_CONTENT_TYPE], payload[OFF_HANDSHAKE_TYPE]);
610  return NULL;
611  }
612  }
613  session = coap_make_session(endpoint->proto, COAP_SESSION_TYPE_SERVER,
614  NULL, &packet->addr_info.local,
615  &packet->addr_info.remote,
616  packet->ifindex, endpoint->context, endpoint);
617  if (session) {
618  session->last_rx_tx = now;
619  if (endpoint->proto == COAP_PROTO_UDP)
621  else if (endpoint->proto == COAP_PROTO_DTLS) {
622  session->type = COAP_SESSION_TYPE_HELLO;
623  }
624  SESSIONS_ADD(endpoint->sessions, session);
625  coap_log(LOG_DEBUG, "***%s: new incoming session\n",
626  coap_session_str(session));
627  }
628  return session;
629 }
630 
633  coap_tick_t now) {
634  if (session) {
635  session->last_rx_tx = now;
636  session->type = COAP_SESSION_TYPE_SERVER;
637  session->tls = coap_dtls_new_server_session(session);
638  if (session->tls) {
640  } else {
641  coap_session_free(session);
642  session = NULL;
643  }
644  }
645  return session;
646 }
647 
648 #ifdef COAP_EPOLL_SUPPORT
649 static void
650 coap_epoll_ctl_add(coap_socket_t *sock,
651  uint32_t events,
652  const char *func
653 ) {
654  int ret;
655  struct epoll_event event;
656  coap_context_t *context;
657 
658  if (sock == NULL)
659  return;
660 
661  context = sock->session ? sock->session->context :
662  sock->endpoint ? sock->endpoint->context : NULL;
663  if (context == NULL)
664  return;
665 
666  /* Needed if running 32bit as ptr is only 32bit */
667  memset(&event, 0, sizeof(event));
668  event.events = events;
669  event.data.ptr = sock;
670 
671  ret = epoll_ctl(context->epfd, EPOLL_CTL_ADD, sock->fd, &event);
672  if (ret == -1) {
674  "%s: epoll_ctl ADD failed: %s (%d)\n",
675  func,
676  coap_socket_strerror(), errno);
677  }
678 }
679 #endif /* COAP_EPOLL_SUPPORT */
680 
681 static coap_session_t *
683  coap_context_t *ctx,
684  const coap_address_t *local_if,
685  const coap_address_t *server,
686  coap_proto_t proto
687 ) {
688  coap_session_t *session = NULL;
689 
690  assert(server);
691 
692  switch(proto) {
693  case COAP_PROTO_UDP:
694  break;
695  case COAP_PROTO_DTLS:
696  if (!coap_dtls_is_supported()) {
697  coap_log(LOG_CRIT, "coap_new_client_session*: DTLS not supported\n");
698  return NULL;
699  }
700  break;
701  case COAP_PROTO_TCP:
702  if (!coap_tcp_is_supported()) {
703  coap_log(LOG_CRIT, "coap_new_client_session*: TCP not supported\n");
704  return NULL;
705  }
706  break;
707  case COAP_PROTO_TLS:
708  if (!coap_tls_is_supported()) {
709  coap_log(LOG_CRIT, "coap_new_client_session*: TLS not supported\n");
710  return NULL;
711  }
712  break;
713  case COAP_PROTO_NONE:
714  default:
715  assert(0);
716  break;
717  }
718  session = coap_make_session(proto, COAP_SESSION_TYPE_CLIENT, local_if,
719  local_if, server, 0, ctx, NULL);
720  if (!session)
721  goto error;
722 
723  coap_session_reference(session);
724 
725  if (proto == COAP_PROTO_UDP || proto == COAP_PROTO_DTLS) {
726  if (!coap_socket_connect_udp(&session->sock, &session->local_if, server,
728  &session->addr_info.local, &session->addr_info.remote)) {
729  goto error;
730  }
731 #if !COAP_DISABLE_TCP
732  } else if (proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS) {
733  if (!coap_socket_connect_tcp1(&session->sock, &session->local_if, server,
735  &session->addr_info.local, &session->addr_info.remote)) {
736  goto error;
737  }
738 #endif /* !COAP_DISABLE_TCP */
739  }
740 
741  session->sock.session = session;
742 #ifdef COAP_EPOLL_SUPPORT
743  coap_epoll_ctl_add(&session->sock,
744  EPOLLIN |
745  ((session->sock.flags & COAP_SOCKET_WANT_CONNECT) ?
746  EPOLLOUT : 0),
747  __func__);
748 #endif /* COAP_EPOLL_SUPPORT */
749 
751  if (local_if)
752  session->sock.flags |= COAP_SOCKET_BOUND;
753  SESSIONS_ADD(ctx->sessions, session);
754  return session;
755 
756 error:
757  coap_session_release(session);
758  return NULL;
759 }
760 
761 static coap_session_t *
763  if (session->proto == COAP_PROTO_UDP) {
765  } else if (session->proto == COAP_PROTO_DTLS) {
766  session->tls = coap_dtls_new_client_session(session);
767  if (session->tls) {
769  } else {
770  /* Need to free session object. As a new session may not yet
771  * have been referenced, we call coap_session_reference() first
772  * before trying to release the object.
773  */
774  coap_session_reference(session);
775  coap_session_release(session);
776  return NULL;
777  }
778 #if !COAP_DISABLE_TCP
779  } else {
780  if (session->proto == COAP_PROTO_TCP || session->proto == COAP_PROTO_TLS) {
781  if (session->sock.flags & COAP_SOCKET_WANT_CONNECT) {
783  } else if (session->proto == COAP_PROTO_TLS) {
784  int connected = 0;
785  session->tls = coap_tls_new_client_session(session, &connected);
786  if (session->tls) {
788  if (connected)
789  coap_session_send_csm(session);
790  } else {
791  /* Need to free session object. As a new session may not yet
792  * have been referenced, we call coap_session_reference()
793  * first before trying to release the object.
794  */
795  coap_session_reference(session);
796  coap_session_release(session);
797  return NULL;
798  }
799  } else {
800  coap_session_send_csm(session);
801  }
802  }
803 #endif /* !COAP_DISABLE_TCP */
804  }
805  coap_ticks(&session->last_rx_tx);
806  return session;
807 }
808 
809 static coap_session_t *
811 #if !COAP_DISABLE_TCP
812  if (session->proto == COAP_PROTO_TCP || session->proto == COAP_PROTO_TLS)
814  if (session->proto == COAP_PROTO_TCP) {
815  coap_session_send_csm(session);
816  } else if (session->proto == COAP_PROTO_TLS) {
817  int connected = 0;
818  session->tls = coap_tls_new_server_session(session, &connected);
819  if (session->tls) {
821  if (connected) {
823  coap_session_send_csm(session);
824  }
825  } else {
826  /* Need to free session object. As a new session may not yet
827  * have been referenced, we call coap_session_reference() first
828  * before trying to release the object.
829  */
830  coap_session_reference(session);
831  coap_session_release(session);
832  session = NULL;
833  }
834  }
835 #endif /* COAP_DISABLE_TCP */
836  return session;
837 }
838 
840  struct coap_context_t *ctx,
841  const coap_address_t *local_if,
842  const coap_address_t *server,
843  coap_proto_t proto
844 ) {
845  coap_session_t *session = coap_session_create_client(ctx, local_if, server, proto);
846  if (session) {
847  coap_log(LOG_DEBUG, "***%s: new outgoing session\n",
848  coap_session_str(session));
849  session = coap_session_connect(session);
850  }
851  return session;
852 }
853 
855  struct coap_context_t *ctx,
856  const coap_address_t *local_if,
857  const coap_address_t *server,
858  coap_proto_t proto,
859  const char *identity,
860  const uint8_t *key,
861  unsigned key_len
862 ) {
863  coap_dtls_cpsk_t setup_data;
864 
865  memset (&setup_data, 0, sizeof(setup_data));
866 
867  if (identity) {
868  setup_data.psk_info.identity.s = (const uint8_t *)identity;
869  setup_data.psk_info.identity.length = strlen(identity);
870  }
871 
872  if (key && key_len > 0) {
873  setup_data.psk_info.key.s = key;
874  setup_data.psk_info.key.length = key_len;
875  }
876 
877  return coap_new_client_session_psk2(ctx, local_if, server,
878  proto, &setup_data);
879 }
880 
882  struct coap_context_t *ctx,
883  const coap_address_t *local_if,
884  const coap_address_t *server,
885  coap_proto_t proto,
886  coap_dtls_cpsk_t *setup_data
887 ) {
888  coap_session_t *session = coap_session_create_client(ctx, local_if,
889  server, proto);
890 
891  if (!session)
892  return NULL;
893 
894  session->cpsk_setup_data = *setup_data;
895  if (setup_data->psk_info.identity.s) {
896  session->psk_identity =
898  setup_data->psk_info.identity.length);
899  if (!session->psk_identity) {
900  coap_log(LOG_WARNING, "Cannot store session Identity (PSK)\n");
901  coap_session_release(session);
902  return NULL;
903  }
904  }
905  else if (coap_dtls_is_supported()) {
906  coap_log(LOG_WARNING, "Identity (PSK) not defined\n");
907  coap_session_release(session);
908  return NULL;
909  }
910 
911  if (setup_data->psk_info.key.s && setup_data->psk_info.key.length > 0) {
912  session->psk_key = coap_new_bin_const(setup_data->psk_info.key.s,
913  setup_data->psk_info.key.length);
914  if (!session->psk_key) {
915  coap_log(LOG_WARNING, "Cannot store session pre-shared key (PSK)\n");
916  coap_session_release(session);
917  return NULL;
918  }
919  }
920  else if (coap_dtls_is_supported()) {
921  coap_log(LOG_WARNING, "Pre-shared key (PSK) not defined\n");
922  coap_session_release(session);
923  return NULL;
924  }
925 
926  if (coap_dtls_is_supported()) {
927  if (!coap_dtls_context_set_cpsk(ctx, setup_data)) {
928  coap_session_release(session);
929  return NULL;
930  }
931  }
932  coap_log(LOG_DEBUG, "***%s: new outgoing session\n",
933  coap_session_str(session));
934  return coap_session_connect(session);
935 }
936 
938  const coap_bin_const_t *psk_hint
939 ) {
940  /* We may be refreshing the hint with the same hint */
941  coap_bin_const_t *old_psk_hint = session->psk_hint;
942 
943  if (psk_hint && psk_hint->s) {
944  if (session->psk_hint) {
945  if (coap_binary_equal(session->psk_hint, psk_hint))
946  return 1;
947  }
948  session->psk_hint = coap_new_bin_const(psk_hint->s,
949  psk_hint->length);
950  if (!session->psk_hint) {
951  coap_log(LOG_ERR, "No memory to store identity hint (PSK)\n");
952  if (old_psk_hint)
953  coap_delete_bin_const(old_psk_hint);
954  return 0;
955  }
956  }
957  else {
958  session->psk_hint = NULL;
959  }
960  if (old_psk_hint)
961  coap_delete_bin_const(old_psk_hint);
962 
963  return 1;
964 }
965 
967  const coap_bin_const_t *psk_key
968 ) {
969  /* We may be refreshing the key with the same key */
970  coap_bin_const_t *old_psk_key = session->psk_key;
971 
972  if (psk_key && psk_key->s) {
973  if (session->psk_key) {
974  if (coap_binary_equal(session->psk_key, psk_key))
975  return 1;
976  }
977  session->psk_key = coap_new_bin_const(psk_key->s, psk_key->length);
978  if (!session->psk_key) {
979  coap_log(LOG_ERR, "No memory to store pre-shared key (PSK)\n");
980  if (old_psk_key)
981  coap_delete_bin_const(old_psk_key);
982  return 0;
983  }
984  }
985  else {
986  session->psk_key = NULL;
987  }
988  if (old_psk_key)
989  coap_delete_bin_const(old_psk_key);
990 
991  return 1;
992 }
993 
995  struct coap_context_t *ctx,
996  const coap_address_t *local_if,
997  const coap_address_t *server,
998  coap_proto_t proto,
999  coap_dtls_pki_t* setup_data
1000 ) {
1001  coap_session_t *session;
1002 
1003  if (coap_dtls_is_supported()) {
1004  if (!setup_data) {
1005  return NULL;
1006  } else {
1007  if (setup_data->version != COAP_DTLS_PKI_SETUP_VERSION) {
1008  coap_log(LOG_ERR,
1009  "coap_new_client_session_pki: Wrong version of setup_data\n");
1010  return NULL;
1011  }
1012  }
1013 
1014  }
1015  session = coap_session_create_client(ctx, local_if, server, proto);
1016 
1017  if (!session) {
1018  return NULL;
1019  }
1020 
1021  if (coap_dtls_is_supported()) {
1022  /* we know that setup_data is not NULL */
1023  if (!coap_dtls_context_set_pki(ctx, setup_data, COAP_DTLS_ROLE_CLIENT)) {
1024  coap_session_release(session);
1025  return NULL;
1026  }
1027  }
1028  coap_log(LOG_DEBUG, "***%s: new outgoing session\n",
1029  coap_session_str(session));
1030  return coap_session_connect(session);
1031 }
1032 
1033 
1035  struct coap_context_t *ctx,
1036  coap_endpoint_t *ep
1037 ) {
1038  coap_session_t *session;
1040  &ep->bind_addr, NULL, NULL, 0, ctx, ep );
1041  if (!session)
1042  goto error;
1043 
1044 #if !COAP_DISABLE_TCP
1045  if (!coap_socket_accept_tcp(&ep->sock, &session->sock,
1046  &session->addr_info.local,
1047  &session->addr_info.remote))
1048  goto error;
1049 #endif /* !COAP_DISABLE_TCP */
1052  session->sock.session = session;
1053 #ifdef COAP_EPOLL_SUPPORT
1054  coap_epoll_ctl_add(&session->sock,
1055  EPOLLIN,
1056  __func__);
1057 #endif /* COAP_EPOLL_SUPPORT */
1058  SESSIONS_ADD(ep->sessions, session);
1059  if (session) {
1060  coap_log(LOG_DEBUG, "***%s: new incoming session\n",
1061  coap_session_str(session));
1062  session = coap_session_accept(session);
1063  }
1064  return session;
1065 
1066 error:
1067  coap_session_free(session);
1068  return NULL;
1069 }
1070 
1071 #ifndef WITH_LWIP
1073 coap_new_endpoint(coap_context_t *context, const coap_address_t *listen_addr, coap_proto_t proto) {
1074  coap_endpoint_t *ep = NULL;
1075 
1076  assert(context);
1077  assert(listen_addr);
1078  assert(proto != COAP_PROTO_NONE);
1079 
1080  if (proto == COAP_PROTO_DTLS && !coap_dtls_is_supported()) {
1081  coap_log(LOG_CRIT, "coap_new_endpoint: DTLS not supported\n");
1082  goto error;
1083  }
1084 
1085  if (proto == COAP_PROTO_TLS && !coap_tls_is_supported()) {
1086  coap_log(LOG_CRIT, "coap_new_endpoint: TLS not supported\n");
1087  goto error;
1088  }
1089 
1090  if (proto == COAP_PROTO_TCP && !coap_tcp_is_supported()) {
1091  coap_log(LOG_CRIT, "coap_new_endpoint: TCP not supported\n");
1092  goto error;
1093  }
1094 
1095  if (proto == COAP_PROTO_DTLS || proto == COAP_PROTO_TLS) {
1096  if (!coap_dtls_context_check_keys_enabled(context)) {
1098  "coap_new_endpoint: one of coap_context_set_psk() or "
1099  "coap_context_set_pki() not called\n");
1100  goto error;
1101  }
1102  }
1103 
1104  ep = coap_malloc_endpoint();
1105  if (!ep) {
1106  coap_log(LOG_WARNING, "coap_new_endpoint: malloc");
1107  goto error;
1108  }
1109 
1110  memset(ep, 0, sizeof(coap_endpoint_t));
1111  ep->context = context;
1112  ep->proto = proto;
1113 
1114  if (proto==COAP_PROTO_UDP || proto==COAP_PROTO_DTLS) {
1115  if (!coap_socket_bind_udp(&ep->sock, listen_addr, &ep->bind_addr))
1116  goto error;
1118 #if !COAP_DISABLE_TCP
1119  } else if (proto==COAP_PROTO_TCP || proto==COAP_PROTO_TLS) {
1120  if (!coap_socket_bind_tcp(&ep->sock, listen_addr, &ep->bind_addr))
1121  goto error;
1123 #endif /* !COAP_DISABLE_TCP */
1124  } else {
1125  coap_log(LOG_CRIT, "coap_new_endpoint: protocol not supported\n");
1126  goto error;
1127  }
1128 
1129  if (LOG_DEBUG <= coap_get_log_level()) {
1130 #ifndef INET6_ADDRSTRLEN
1131 #define INET6_ADDRSTRLEN 40
1132 #endif
1133  unsigned char addr_str[INET6_ADDRSTRLEN + 8];
1134 
1135  if (coap_print_addr(&ep->bind_addr, addr_str, INET6_ADDRSTRLEN + 8)) {
1136  coap_log(LOG_DEBUG, "created %s endpoint %s\n",
1137  ep->proto == COAP_PROTO_TLS ? "TLS "
1138  : ep->proto == COAP_PROTO_TCP ? "TCP "
1139  : ep->proto == COAP_PROTO_DTLS ? "DTLS" : "UDP ",
1140  addr_str);
1141  }
1142  }
1143 
1145 
1147 
1148  ep->sock.endpoint = ep;
1149 #ifdef COAP_EPOLL_SUPPORT
1150  coap_epoll_ctl_add(&ep->sock,
1151  EPOLLIN,
1152  __func__);
1153 #endif /* COAP_EPOLL_SUPPORT */
1154 
1155  LL_PREPEND(context->endpoint, ep);
1156  return ep;
1157 
1158 error:
1159  coap_free_endpoint(ep);
1160  return NULL;
1161 }
1162 
1164  ep->default_mtu = (uint16_t)mtu;
1165 }
1166 
1167 void
1169  if (ep) {
1170  coap_session_t *session, *rtmp;
1171 
1172  SESSIONS_ITER_SAFE(ep->sessions, session, rtmp) {
1173  assert(session->ref == 0);
1174  if (session->ref == 0) {
1175  coap_session_free(session);
1176  }
1177  }
1178  if (ep->sock.flags != COAP_SOCKET_EMPTY) {
1179  /*
1180  * ep->sock.endpoint is set in coap_new_endpoint().
1181  * ep->sock.session is never set.
1182  *
1183  * session->sock.session is set for both clients and servers (when a
1184  * new session is accepted), but does not affect the endpoint.
1185  *
1186  * So, it is safe to call coap_socket_close() after all the sessions
1187  * have been freed above as we are only working with the endpoint sock.
1188  */
1189 #ifdef COAP_EPOLL_SUPPORT
1190  assert(ep->sock.session == NULL);
1191 #endif /* COAP_EPOLL_SUPPORT */
1192  coap_socket_close(&ep->sock);
1193  }
1194 
1195  if (ep->context && ep->context->endpoint) {
1196  LL_DELETE(ep->context->endpoint, ep);
1197  }
1198  coap_mfree_endpoint(ep);
1199  }
1200 }
1201 #endif /* WITH_LWIP */
1202 
1205  const coap_address_t *remote_addr,
1206  int ifindex) {
1207  coap_session_t *s, *rtmp;
1208  coap_endpoint_t *ep;
1209  SESSIONS_ITER(ctx->sessions, s, rtmp) {
1210  if (s->ifindex == ifindex && coap_address_equals(&s->addr_info.remote,
1211  remote_addr))
1212  return s;
1213  }
1214  LL_FOREACH(ctx->endpoint, ep) {
1215  SESSIONS_ITER(ep->sessions, s, rtmp) {
1216  if (s->ifindex == ifindex && coap_address_equals(&s->addr_info.remote,
1217  remote_addr))
1218  return s;
1219  }
1220  }
1221  return NULL;
1222 }
1223 
1224 const char *coap_session_str(const coap_session_t *session) {
1225  static char szSession[2 * (INET6_ADDRSTRLEN + 8) + 24];
1226  char *p = szSession, *end = szSession + sizeof(szSession);
1227  if (coap_print_addr(&session->addr_info.local,
1228  (unsigned char*)p, end - p) > 0)
1229  p += strlen(p);
1230  if (p + 6 < end) {
1231  strcpy(p, " <-> ");
1232  p += 5;
1233  }
1234  if (p + 1 < end) {
1235  if (coap_print_addr(&session->addr_info.remote,
1236  (unsigned char*)p, end - p) > 0)
1237  p += strlen(p);
1238  }
1239  if (session->ifindex > 0 && p + 1 < end)
1240  p += snprintf(p, end - p, " (if%d)", session->ifindex);
1241  if (p + 6 < end) {
1242  if (session->proto == COAP_PROTO_UDP) {
1243  strcpy(p, " UDP ");
1244  p += 4;
1245  } else if (session->proto == COAP_PROTO_DTLS) {
1246  strcpy(p, " DTLS");
1247  p += 5;
1248  } else if (session->proto == COAP_PROTO_TCP) {
1249  strcpy(p, " TCP ");
1250  p += 4;
1251  } else if (session->proto == COAP_PROTO_TLS) {
1252  strcpy(p, " TLS ");
1253  p += 4;
1254  } else {
1255  strcpy(p, " NONE");
1256  p += 5;
1257  }
1258  }
1259 
1260  return szSession;
1261 }
1262 
1263 const char *coap_endpoint_str(const coap_endpoint_t *endpoint) {
1264  static char szEndpoint[128];
1265  char *p = szEndpoint, *end = szEndpoint + sizeof(szEndpoint);
1266  if (coap_print_addr(&endpoint->bind_addr, (unsigned char*)p, end - p) > 0)
1267  p += strlen(p);
1268  if (p + 6 < end) {
1269  if (endpoint->proto == COAP_PROTO_UDP) {
1270  strcpy(p, " UDP");
1271  p += 4;
1272  } else if (endpoint->proto == COAP_PROTO_DTLS) {
1273  strcpy(p, " DTLS");
1274  p += 5;
1275  } else {
1276  strcpy(p, " NONE");
1277  p += 5;
1278  }
1279  }
1280 
1281  return szEndpoint;
1282 }
1283 
1284 #endif /* COAP_SESSION_C_ */
void coap_address_init(coap_address_t *addr)
Resets the given coap_address_t object addr to its default values.
Definition: address.c:98
int coap_address_equals(const coap_address_t *a, const coap_address_t *b)
Compares given address objects a and b.
Definition: address.c:58
COAP_STATIC_INLINE void coap_address_copy(coap_address_t *dst, const coap_address_t *src)
Definition: address.h:150
void coap_dtls_free_session(struct coap_dtls_context_t *dtls_context, struct coap_dtls_session_t *session)
Pulls together all the internal only header files.
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:236
void coap_socket_close(coap_socket_t *sock)
Definition: coap_io.c:347
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:1465
ssize_t coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len)
Definition: coap_io.c:406
int coap_socket_bind_udp(coap_socket_t *sock, const coap_address_t *listen_addr, coap_address_t *bound_addr)
Definition: coap_io.c:152
const char * coap_socket_strerror(void)
Definition: coap_io.c:1459
void coap_mfree_endpoint(coap_endpoint_t *ep)
Definition: coap_io.c:147
coap_endpoint_t * coap_malloc_endpoint(void)
Definition: coap_io.c:142
#define COAP_SOCKET_WANT_ACCEPT
non blocking server socket is waiting for accept
Definition: coap_io.h:85
#define COAP_SOCKET_NOT_EMPTY
the socket is not empty
Definition: coap_io.h:80
#define COAP_SOCKET_BOUND
the socket is bound
Definition: coap_io.h:81
#define COAP_SOCKET_WANT_READ
non blocking socket is waiting for reading
Definition: coap_io.h:83
coap_nack_reason_t
Definition: coap_io.h:214
@ COAP_NACK_NOT_DELIVERABLE
Definition: coap_io.h:216
@ COAP_NACK_TLS_FAILED
Definition: coap_io.h:218
@ COAP_NACK_ICMP_ISSUE
Definition: coap_io.h:219
#define COAP_SOCKET_WANT_CONNECT
non blocking client socket is waiting for connect
Definition: coap_io.h:86
#define COAP_SOCKET_CONNECTED
the socket is connected
Definition: coap_io.h:82
#define COAP_SOCKET_EMPTY
coap_socket_flags_t values
Definition: coap_io.h:79
int coap_dtls_context_set_pki(coap_context_t *ctx UNUSED, const coap_dtls_pki_t *setup_data UNUSED, const coap_dtls_role_t role UNUSED)
Definition: coap_notls.c:39
void * coap_dtls_new_client_session(coap_session_t *session UNUSED)
Definition: coap_notls.c:105
void * coap_tls_new_client_session(coap_session_t *session UNUSED, int *connected UNUSED)
Definition: coap_notls.c:159
void * coap_tls_new_server_session(coap_session_t *session UNUSED, int *connected UNUSED)
Definition: coap_notls.c:163
int coap_dtls_context_set_cpsk(coap_context_t *ctx UNUSED, coap_dtls_cpsk_t *setup_data UNUSED)
Definition: coap_notls.c:55
void * coap_dtls_new_server_session(coap_session_t *session UNUSED)
Definition: coap_notls.c:101
int coap_dtls_context_check_keys_enabled(coap_context_t *ctx UNUSED)
Definition: coap_notls.c:69
void coap_tls_free_session(coap_session_t *coap_session UNUSED)
Definition: coap_notls.c:167
unsigned int coap_dtls_get_overhead(coap_session_t *session UNUSED)
Definition: coap_notls.c:155
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_t * coap_endpoint_get_session(coap_endpoint_t *endpoint, const coap_packet_t *packet, coap_tick_t now)
Definition: coap_session.c:499
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:102
void coap_free_endpoint(coap_endpoint_t *ep)
ssize_t coap_session_delay_pdu(coap_session_t *session, coap_pdu_t *pdu, coap_queue_t *node)
Definition: coap_session.c:277
void coap_session_set_app_data(coap_session_t *session, void *app_data)
Stores data with the given session.
Definition: coap_session.c:96
void coap_session_set_mtu(coap_session_t *session, unsigned mtu)
Set the session MTU.
Definition: coap_session.c:230
int coap_session_refresh_psk_hint(coap_session_t *session, const coap_bin_const_t *psk_hint)
Definition: coap_session.c:937
#define DTLS_HT_CLIENT_HELLO
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:315
#define OFF_HANDSHAKE_TYPE
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:854
size_t coap_session_max_pdu_size(const coap_session_t *session)
Get maximum acceptable PDU size.
Definition: coap_session.c:209
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:242
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
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:108
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_t * coap_session_reference(coap_session_t *session)
Increment reference counter on a session.
Definition: coap_session.c:68
coap_session_t * coap_new_client_session_psk2(struct coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_dtls_cpsk_t *setup_data)
Creates a new client session to the designated server with PSK credentials.
Definition: coap_session.c:881
#define DTLS_CT_HANDSHAKE
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:682
coap_session_t * coap_session_get_by_peer(coap_context_t *ctx, const coap_address_t *remote_addr, int ifindex)
void coap_endpoint_set_default_mtu(coap_endpoint_t *ep, unsigned mtu)
Set the endpoint's default MTU.
void coap_session_release(coap_session_t *session)
Decrement reference counter on a session.
Definition: coap_session.c:74
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
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
int coap_session_refresh_psk_key(coap_session_t *session, const coap_bin_const_t *psk_key)
Definition: coap_session.c:966
#define OFF_CONTENT_TYPE
void coap_session_connected(coap_session_t *session)
Notify session that it has just connected or reconnected.
Definition: coap_session.c:363
void coap_session_free(coap_session_t *session)
Definition: coap_session.c:190
coap_tid_t coap_session_send_ping(coap_session_t *session)
Send a ping message for the session.
Definition: coap_session.c:345
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.
void coap_session_mfree(coap_session_t *session)
Definition: coap_session.c:156
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:994
static coap_session_t * coap_session_accept(coap_session_t *session)
Definition: coap_session.c:810
static coap_session_t * coap_session_connect(coap_session_t *session)
Definition: coap_session.c:762
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.
void coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason)
Notify session that it has failed.
Definition: coap_session.c:420
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:839
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:263
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
#define INET6_ADDRSTRLEN
#define DTLS_CT_ALERT
#define SESSIONS_ADD(e, obj)
Definition: coap_session.h:631
#define SESSIONS_ITER_SAFE(e, el, rtmp)
Definition: coap_session.h:640
#define COAP_PARTIAL_SESSION_TIMEOUT_TICKS
Definition: coap_session.h:36
#define COAP_SESSION_STATE_HANDSHAKE
Definition: coap_session.h:56
uint8_t coap_session_state_t
Definition: coap_session.h:50
#define COAP_SESSION_STATE_CSM
Definition: coap_session.h:57
#define SESSIONS_DELETE(e, obj)
Definition: coap_session.h:634
#define COAP_DEFAULT_MAX_HANDSHAKE_SESSIONS
Definition: coap_session.h:37
uint8_t coap_session_type_t
Definition: coap_session.h:42
#define COAP_SESSION_TYPE_CLIENT
coap_session_type_t values
Definition: coap_session.h:46
#define COAP_SESSION_TYPE_HELLO
server-side ephemeral session for responding to a client hello
Definition: coap_session.h:48
#define COAP_PROTO_NOT_RELIABLE(p)
Definition: coap_session.h:39
#define COAP_SESSION_STATE_CONNECTING
Definition: coap_session.h:55
#define COAP_PROTO_RELIABLE(p)
Definition: coap_session.h:40
#define COAP_SESSION_STATE_NONE
coap_session_state_t values
Definition: coap_session.h:54
#define COAP_SESSION_STATE_ESTABLISHED
Definition: coap_session.h:58
#define SESSIONS_ITER(e, el, rtmp)
Definition: coap_session.h:637
#define COAP_SESSION_TYPE_SERVER
server-side
Definition: coap_session.h:47
#define SESSIONS_FIND(e, k, res)
Definition: coap_session.h:643
int coap_tcp_is_supported(void)
Check whether TCP is available.
Definition: coap_tcp.c:31
void coap_delete_cache_entry(coap_context_t *ctx, coap_cache_entry_t *cache_entry)
Remove a cache-entry from the hash list and free off all the appropriate contents apart from app_data...
Definition: coap_cache.c:203
#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:462
#define COAP_DEFAULT_MAX_RETRANSMIT
Number of message retransmissions before message sending is stopped RFC 7252, Section 4....
Definition: coap_session.h:470
#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:453
#define COAP_DEFAULT_NSTART
The number of simultaneous outstanding interactions that a client maintains to a given server.
Definition: coap_session.h:477
void coap_ticks(coap_tick_t *t)
Sets t to the internal time with COAP_TICKS_PER_SECOND resolution.
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition: coap_time.h:120
int coap_prng(void *buf, size_t len)
Fills buf with len random bytes using the default pseudo random number generator.
Definition: coap_prng.c:85
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:632
@ COAP_DTLS_ROLE_CLIENT
Internal function invoked for client.
Definition: coap_dtls.h:482
int coap_tls_is_supported(void)
Check whether TLS is available.
Definition: coap_notls.c:26
#define COAP_DTLS_PKI_SETUP_VERSION
Latest PKI setup version.
Definition: coap_dtls.h:240
int coap_dtls_is_supported(void)
Returns 1 if support for DTLS is enabled, or 0 otherwise.
unsigned int coap_encode_var_safe(uint8_t *buf, size_t length, unsigned int val)
Encodes multiple-length byte sequences.
Definition: encode.c:38
#define COAP_EVENT_TCP_CLOSED
Definition: coap_event.h:39
#define COAP_EVENT_SESSION_CONNECTED
CSM exchange events for reliable protocols only.
Definition: coap_event.h:45
#define COAP_EVENT_SESSION_FAILED
Definition: coap_event.h:47
#define COAP_EVENT_TCP_FAILED
Definition: coap_event.h:40
#define COAP_EVENT_SESSION_CLOSED
Definition: coap_event.h:46
#define COAP_EVENT_DTLS_CONNECTED
Definition: coap_event.h:31
#define COAP_EVENT_TCP_CONNECTED
TCP events for COAP_PROTO_TCP and COAP_PROTO_TLS.
Definition: coap_event.h:38
coap_log_t coap_get_log_level(void)
Get the current logging level.
Definition: coap_debug.c:61
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:167
const char * coap_session_str(const coap_session_t *session)
Get session description.
const char * coap_endpoint_str(const coap_endpoint_t *endpoint)
Get endpoint description.
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:150
@ LOG_ERR
Error.
Definition: coap_debug.h:53
@ LOG_CRIT
Critical.
Definition: coap_debug.h:52
@ LOG_INFO
Information.
Definition: coap_debug.h:56
@ LOG_WARNING
Warning.
Definition: coap_debug.h:54
@ LOG_DEBUG
Debug.
Definition: coap_debug.h:57
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:821
void coap_delete_bin_const(coap_bin_const_t *s)
Deletes the given const binary data and releases any memory allocated.
Definition: str.c:102
#define coap_binary_equal(binary1, binary2)
Compares the two binary data for equality.
Definition: str.h:192
coap_bin_const_t * coap_new_bin_const(const uint8_t *data, size_t size)
Take the specified byte array (text) and create a coap_bin_const_t * Returns a new const binary objec...
Definition: str.c:93
int coap_socket_bind_tcp(coap_socket_t *sock, const coap_address_t *listen_addr, coap_address_t *bound_addr)
Create a new TCP socket and then listen for new incoming TCP sessions.
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)
Create a new TCP socket and initiate the connection.
int coap_socket_accept_tcp(coap_socket_t *server, coap_socket_t *new_client, coap_address_t *local_addr, coap_address_t *remote_addr)
Accept a new incoming TCP session.
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.
COAP_STATIC_INLINE void coap_free(void *object)
Wrapper function to coap_free_type() for backwards compatibility.
Definition: mem.h:100
@ COAP_SESSION
Definition: mem.h:44
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
int coap_delete_node(coap_queue_t *node)
Destroys specified node.
Definition: net.c:223
coap_queue_t * coap_new_node(void)
Creates a new node suitable for adding to the CoAP sendqueue.
Definition: net.c:252
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:1785
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:2884
coap_tid_t coap_wait_ack(coap_context_t *context, coap_session_t *session, coap_queue_t *node)
Definition: net.c:928
unsigned int coap_calc_timeout(coap_session_t *session, unsigned char r)
Calculates the initial timeout based on the session CoAP transmission parameters 'ack_timeout',...
Definition: net.c:902
ssize_t coap_session_send_pdu(coap_session_t *session, coap_pdu_t *pdu)
Send a pdu according to the session's protocol.
Definition: net.c:715
coap_tid_t coap_send(coap_session_t *session, coap_pdu_t *pdu)
Sends a CoAP message to given peer.
Definition: net.c:1006
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:1835
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:400
void coap_delete_pdu(coap_pdu_t *pdu)
Dispose of an CoAP PDU and frees associated storage.
Definition: pdu.c:127
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
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:344
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:797
#define COAP_PROTO_NONE
coap_proto_t values
Definition: pdu.h:343
#define COAP_PROTO_TCP
Definition: pdu.h:346
#define COAP_DEFAULT_PORT
Definition: pdu.h:26
#define COAP_PDU_DELAYED
Definition: pdu.h:255
#define COAP_SIGNALING_CSM
Definition: pdu.h:182
#define COAP_PROTO_TLS
Definition: pdu.h:347
#define COAP_MAX_MESSAGE_SIZE_TCP8
Definition: pdu.h:44
#define COAP_DEFAULT_MAX_PDU_RX_SIZE
Definition: pdu.h:53
#define COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER
Definition: pdu.h:190
#define COAP_MAX_MESSAGE_SIZE_TCP0
Definition: pdu.h:43
uint8_t coap_proto_t
Definition: pdu.h:339
#define COAP_MESSAGE_CON
Definition: pdu.h:74
#define COAPS_DEFAULT_PORT
Definition: pdu.h:27
#define COAP_PROTO_DTLS
Definition: pdu.h:345
int coap_tid_t
coap_tid_t is used to store CoAP transaction id, i.e.
Definition: pdu.h:244
#define COAP_DEFAULT_MTU
Definition: pdu.h:30
#define COAP_SIGNALING_PING
Definition: pdu.h:183
#define COAP_MAX_MESSAGE_SIZE_TCP16
Definition: pdu.h:45
#define COAP_PROTO_UDP
Definition: pdu.h:344
#define COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE
Definition: pdu.h:189
#define COAP_INVALID_TID
Indicates an invalid transaction id.
Definition: pdu.h:247
coap_address_t remote
remote address and port
Definition: coap_io.h:49
coap_address_t local
local address and port
Definition: coap_io.h:50
multi-purpose address abstraction
Definition: address.h:94
CoAP binary data definition with const data.
Definition: str.h:56
size_t length
length of binary data
Definition: str.h:57
const uint8_t * s
read-only binary data
Definition: str.h:58
coap_session_t * session
The CoAP stack's global state is stored in a coap_context_t object.
Definition: net.h:141
coap_session_t * sessions
client sessions
Definition: net.h:162
coap_nack_handler_t nack_handler
Definition: net.h:177
unsigned int max_handshake_sessions
Maximum number of simultaneous negotating sessions per endpoint.
Definition: net.h:201
coap_queue_t * sendqueue
Definition: net.h:160
coap_cache_entry_t * cache
CoAP cache-entry cache.
Definition: net.h:206
coap_endpoint_t * endpoint
the endpoints used for listening
Definition: net.h:161
unsigned int max_idle_sessions
Maximum number of simultaneous unused sessions per endpoint.
Definition: net.h:200
coap_bin_const_t key
Definition: coap_dtls.h:310
coap_bin_const_t identity
Definition: coap_dtls.h:309
The structure used for defining the Client PSK setup data to be used.
Definition: coap_dtls.h:339
coap_dtls_cpsk_info_t psk_info
Client PSK definition.
Definition: coap_dtls.h:368
The structure used for defining the PKI setup data to be used.
Definition: coap_dtls.h:245
uint8_t version
Definition: coap_dtls.h:246
Abstraction of virtual endpoint that can be attached to coap_context_t.
struct coap_context_t * context
endpoint's context
uint16_t default_mtu
default mtu for this interface
struct coap_session_t * sessions
hash table or list of active sessions
coap_address_t bind_addr
local interface address
coap_socket_t sock
socket object for the interface, if any
coap_proto_t proto
protocol used on this interface
Abstraction of a fixed point number that can be used where necessary instead of a float.
Definition: coap_session.h:29
uint16_t fractional_part
Fractional part of fixed point variable 1/1000 (3 points) precision.
Definition: coap_session.h:31
uint16_t integer_part
Integer part of fixed point variable.
Definition: coap_session.h:30
size_t length
length of payload
Definition: coap_io.h:208
coap_addr_tuple_t addr_info
local and remote addresses
Definition: coap_io.h:206
unsigned char payload[COAP_RXBUFFER_SIZE]
payload
Definition: coap_io.h:209
int ifindex
the interface index
Definition: coap_io.h:207
structure for CoAP PDUs token, if any, follows the fixed size header, then options until payload mark...
Definition: pdu.h:287
uint8_t type
message type
Definition: pdu.h:288
uint16_t tid
transaction id, if any, in regular host byte order
Definition: pdu.h:293
uint8_t hdr_size
actual size used for protocol-specific header
Definition: pdu.h:291
size_t used_size
used bytes of storage for token, options and payload
Definition: pdu.h:296
Queue entry.
Definition: net.h:36
coap_session_t * session
the CoAP session
Definition: net.h:42
coap_pdu_t * pdu
the CoAP PDU to send
Definition: net.h:44
unsigned int timeout
the randomized timeout value
Definition: net.h:41
struct coap_queue_t * next
Definition: net.h:37
coap_tick_t t
when to send PDU for the next time
Definition: net.h:38
coap_tid_t id
CoAP transaction id.
Definition: net.h:43
coap_bin_const_t * psk_key
If client, this field contains the current pre-shared key for server; When this field is NULL,...
Definition: coap_session.h:100
coap_endpoint_t * endpoint
session's endpoint
Definition: coap_session.h:72
coap_tick_t last_rx_tx
Definition: coap_session.h:84
coap_socket_t sock
socket object for the session, if any
Definition: coap_session.h:71
unsigned int max_retransmit
maximum re-transmit count (default 4)
Definition: coap_session.h:119
coap_pdu_t * partial_pdu
incomplete incoming pdu
Definition: coap_session.h:83
unsigned tls_overhead
overhead of TLS layer
Definition: coap_session.h:65
coap_bin_const_t * psk_identity
If client, this field contains the current identity for server; When this field is NULL,...
Definition: coap_session.h:91
coap_session_state_t state
current state of relationaship with peer
Definition: coap_session.h:63
coap_addr_tuple_t addr_info
key: remote/local address info
Definition: coap_session.h:69
coap_proto_t proto
protocol used
Definition: coap_session.h:61
uint16_t tx_mid
the last message id that was used in this session
Definition: coap_session.h:75
coap_bin_const_t * psk_hint
If client, this field contains the server provided identity hint.
Definition: coap_session.h:109
coap_dtls_cpsk_t cpsk_setup_data
client provided PSK initial setup data
Definition: coap_session.h:89
struct coap_queue_t * delayqueue
list of delayed messages waiting to be sent
Definition: coap_session.h:79
struct coap_context_t * context
session's context
Definition: coap_session.h:73
size_t partial_read
if > 0 indicates number of bytes already read for an incoming message
Definition: coap_session.h:82
int dtls_event
Tracking any (D)TLS events on this sesison.
Definition: coap_session.h:123
void * tls
security parameters
Definition: coap_session.h:74
coap_fixed_point_t ack_random_factor
ack random factor backoff (default 1.5)
Definition: coap_session.h:121
uint8_t con_active
Active CON request sent.
Definition: coap_session.h:76
void * app
application-specific data
Definition: coap_session.h:118
coap_address_t local_if
optional local interface address
Definition: coap_session.h:67
coap_fixed_point_t ack_timeout
timeout waiting for ack (default 2 secs)
Definition: coap_session.h:120
coap_session_type_t type
client or server side socket
Definition: coap_session.h:62
uint64_t mtu
path or CSM mtu
Definition: coap_session.h:66
coap_tid_t last_ping_mid
the last keepalive message id that was used in this session
Definition: coap_session.h:78
size_t partial_write
if > 0 indicates number of bytes already written from the pdu at the head of sendqueue
Definition: coap_session.h:80
int ifindex
interface index
Definition: coap_session.h:70
coap_endpoint_t * endpoint
Definition: coap_io.h:69
coap_fd_t fd
Definition: coap_io.h:59
struct coap_session_t * session
Definition: coap_io.h:65
coap_socket_flags_t flags
Definition: coap_io.h:64
unsigned int uint32_t
Definition: uthash.h:78
#define HASH_ITER(hh, head, el, tmp)
Definition: uthash.h:1031
unsigned char uint8_t
Definition: uthash.h:79
#define LL_DELETE(head, del)
Definition: utlist.h:385
#define LL_FOREACH(head, el)
Definition: utlist.h:413
#define LL_PREPEND(head, add)
Definition: utlist.h:314
#define LL_APPEND(head, add)
Definition: utlist.h:338
#define LL_FOREACH_SAFE(head, el, tmp)
Definition: utlist.h:419