1 /* session.c -- Session management for libcoap
2 *
3 * Copyright (C) 2017 Jean-Claue Michelou <jcm@spinetix.com>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 *
7 * This file is part of the CoAP library libcoap. Please see
8 * README for terms of use.
9 */
10
11 #include "coap3/coap_internal.h"
12
13 #ifndef COAP_SESSION_C_
14 #define COAP_SESSION_C_
15
16 #include <stdio.h>
17
18 #ifdef COAP_EPOLL_SUPPORT
19 #include <sys/epoll.h>
20 #include <sys/timerfd.h>
21 #endif /* COAP_EPOLL_SUPPORT */
22 #include <errno.h>
23 #ifdef LWIP_STACK
24 #include <lwip/sockets.h>
25 #else
26 #include <unistd.h>
27 #include <sys/ioctl.h>
28 #endif
29 #include <net/if.h>
30 #include <arpa/inet.h>
31
32 void
coap_session_set_max_retransmit(coap_session_t * session,unsigned int value)33 coap_session_set_max_retransmit (coap_session_t *session, unsigned int value) {
34 if (value > 0)
35 session->max_retransmit = value;
36 coap_log(LOG_DEBUG, "***%s: session max_retransmit set to %d\n",
37 coap_session_str(session), session->max_retransmit);
38 return;
39 }
40
41 void
coap_session_set_ack_timeout(coap_session_t * session,coap_fixed_point_t value)42 coap_session_set_ack_timeout (coap_session_t *session, coap_fixed_point_t value) {
43 if (value.integer_part > 0 && value.fractional_part < 1000)
44 session->ack_timeout = value;
45 coap_log(LOG_DEBUG, "***%s: session ack_timeout set to %d.%03d\n",
46 coap_session_str(session), session->ack_timeout.integer_part,
47 session->ack_timeout.fractional_part);
48 return;
49 }
50
51 void
coap_session_set_ack_random_factor(coap_session_t * session,coap_fixed_point_t value)52 coap_session_set_ack_random_factor (coap_session_t *session,
53 coap_fixed_point_t value) {
54 if (value.integer_part > 0 && value.fractional_part < 1000)
55 session->ack_random_factor = value;
56 coap_log(LOG_DEBUG, "***%s: session ack_random_factor set to %d.%03d\n",
57 coap_session_str(session), session->ack_random_factor.integer_part,
58 session->ack_random_factor.fractional_part);
59 return;
60 }
61
62 unsigned int
coap_session_get_max_retransmit(const coap_session_t * session)63 coap_session_get_max_retransmit (const coap_session_t *session) {
64 return session->max_retransmit;
65 }
66
67 coap_fixed_point_t
coap_session_get_ack_timeout(const coap_session_t * session)68 coap_session_get_ack_timeout (const coap_session_t *session) {
69 return session->ack_timeout;
70 }
71
72 coap_fixed_point_t
coap_session_get_ack_random_factor(const coap_session_t * session)73 coap_session_get_ack_random_factor (const coap_session_t *session) {
74 return session->ack_random_factor;
75 }
76
77 coap_session_t *
coap_session_reference(coap_session_t * session)78 coap_session_reference(coap_session_t *session) {
79 ++session->ref;
80 return session;
81 }
82
83 void
coap_session_release(coap_session_t * session)84 coap_session_release(coap_session_t *session) {
85 if (session) {
86 #ifndef __COVERITY__
87 assert(session->ref > 0);
88 if (session->ref > 0)
89 --session->ref;
90 if (session->ref == 0 && session->type == COAP_SESSION_TYPE_CLIENT)
91 coap_session_free(session);
92 #else /* __COVERITY__ */
93 /* Coverity scan is fooled by the reference counter leading to
94 * false positives for USE_AFTER_FREE. */
95 --session->ref;
96 __coverity_negative_sink__(session->ref);
97 /* Indicate that resources are released properly. */
98 if (session->ref == 0 && session->type == COAP_SESSION_TYPE_CLIENT) {
99 __coverity_free__(session);
100 }
101 #endif /* __COVERITY__ */
102 }
103 }
104
105 void
coap_session_set_app_data(coap_session_t * session,void * app_data)106 coap_session_set_app_data(coap_session_t *session, void *app_data) {
107 assert(session);
108 session->app = app_data;
109 }
110
111 void *
coap_session_get_app_data(const coap_session_t * session)112 coap_session_get_app_data(const coap_session_t *session) {
113 assert(session);
114 return session->app;
115 }
116
117 static coap_session_t *
coap_make_session(coap_proto_t proto,coap_session_type_t type,const coap_addr_hash_t * addr_hash,const coap_address_t * local_addr,const coap_address_t * remote_addr,int ifindex,coap_context_t * context,coap_endpoint_t * endpoint)118 coap_make_session(coap_proto_t proto, coap_session_type_t type,
119 const coap_addr_hash_t *addr_hash, const coap_address_t *local_addr,
120 const coap_address_t *remote_addr, int ifindex, coap_context_t *context,
121 coap_endpoint_t *endpoint) {
122 coap_session_t *session = (coap_session_t*)coap_malloc_type(COAP_SESSION, sizeof(coap_session_t));
123 if (!session)
124 return NULL;
125 memset(session, 0, sizeof(*session));
126 session->proto = proto;
127 session->type = type;
128 if (addr_hash)
129 memcpy(&session->addr_hash, addr_hash, sizeof(session->addr_hash));
130 else
131 memset(&session->addr_hash, 0, sizeof(session->addr_hash));
132 if (local_addr)
133 coap_address_copy(&session->addr_info.local, local_addr);
134 else
135 coap_address_init(&session->addr_info.local);
136 if (remote_addr)
137 coap_address_copy(&session->addr_info.remote, remote_addr);
138 else
139 coap_address_init(&session->addr_info.remote);
140 session->ifindex = ifindex;
141 session->context = context;
142 session->endpoint = endpoint;
143 session->block_mode = context->block_mode;
144 if (endpoint)
145 session->mtu = endpoint->default_mtu;
146 else
147 session->mtu = COAP_DEFAULT_MTU;
148 if (proto == COAP_PROTO_DTLS) {
149 session->tls_overhead = 29;
150 if (session->tls_overhead >= session->mtu) {
151 session->tls_overhead = session->mtu;
152 coap_log(LOG_ERR, "DTLS overhead exceeds MTU\n");
153 }
154 }
155 session->max_retransmit = COAP_DEFAULT_MAX_RETRANSMIT;
156 session->ack_timeout = COAP_DEFAULT_ACK_TIMEOUT;
157 session->ack_random_factor = COAP_DEFAULT_ACK_RANDOM_FACTOR;
158 session->dtls_event = -1;
159 session->last_ping_mid = COAP_INVALID_MID;
160
161 /* initialize message id */
162 coap_prng((unsigned char *)&session->tx_mid, sizeof(session->tx_mid));
163
164 return session;
165 }
166
coap_session_mfree(coap_session_t * session)167 void coap_session_mfree(coap_session_t *session) {
168 coap_queue_t *q, *tmp;
169 coap_cache_entry_t *cp, *ctmp;
170 coap_lg_xmit_t *lq, *ltmp;
171 coap_lg_crcv_t *cq, *etmp;
172 coap_lg_srcv_t *sq, *stmp;
173
174 /* Need to do this before (D)TLS and socket is closed down */
175 LL_FOREACH_SAFE(session->lg_crcv, cq, etmp) {
176 if (cq->observe_set) {
177 /* Need to close down observe */
178 if (coap_cancel_observe(session, cq->app_token, COAP_MESSAGE_NON)) {
179 /* Need to delete node we set up for NON */
180 coap_queue_t *queue = session->context->sendqueue;
181
182 while (queue) {
183 if (queue->session == session) {
184 coap_delete_node(queue);
185 break;
186 }
187 queue = queue->next;
188 }
189 }
190 }
191 LL_DELETE(session->lg_crcv, cq);
192 coap_block_delete_lg_crcv(session, cq);
193 }
194
195 if (session->partial_pdu)
196 coap_delete_pdu(session->partial_pdu);
197 if (session->proto == COAP_PROTO_DTLS)
198 coap_dtls_free_session(session);
199 #if !COAP_DISABLE_TCP
200 else if (session->proto == COAP_PROTO_TLS)
201 coap_tls_free_session(session);
202 #endif /* !COAP_DISABLE_TCP */
203 if (session->sock.flags != COAP_SOCKET_EMPTY)
204 coap_socket_close(&session->sock);
205 if (session->psk_identity)
206 coap_free(session->psk_identity);
207 if (session->psk_key)
208 coap_free(session->psk_key);
209 if (session->psk_hint)
210 coap_free(session->psk_hint);
211
212 HASH_ITER(hh, session->context->cache, cp, ctmp) {
213 /* cp->session is NULL if not session based */
214 if (cp->session == session) {
215 coap_delete_cache_entry(session->context, cp);
216 }
217 }
218 LL_FOREACH_SAFE(session->delayqueue, q, tmp) {
219 if (q->pdu->type==COAP_MESSAGE_CON && session->context && session->context->nack_handler)
220 session->context->nack_handler(session, q->pdu, session->proto == COAP_PROTO_DTLS ? COAP_NACK_TLS_FAILED : COAP_NACK_NOT_DELIVERABLE, q->id);
221 coap_delete_node(q);
222 }
223 LL_FOREACH_SAFE(session->lg_xmit, lq, ltmp) {
224 LL_DELETE(session->lg_xmit, lq);
225 coap_block_delete_lg_xmit(session, lq);
226 }
227 LL_FOREACH_SAFE(session->lg_srcv, sq, stmp) {
228 LL_DELETE(session->lg_srcv, sq);
229 coap_block_delete_lg_srcv(session, sq);
230 }
231 }
232
coap_session_free(coap_session_t * session)233 void coap_session_free(coap_session_t *session) {
234 if (!session)
235 return;
236 assert(session->ref == 0);
237 if (session->ref)
238 return;
239 coap_session_mfree(session);
240 if (session->endpoint) {
241 if (session->endpoint->sessions)
242 SESSIONS_DELETE(session->endpoint->sessions, session);
243 } else if (session->context) {
244 if (session->context->sessions)
245 SESSIONS_DELETE(session->context->sessions, session);
246 }
247 coap_log(LOG_DEBUG, "***%s: session closed\n", coap_session_str(session));
248
249 coap_free_type(COAP_SESSION, session);
250 }
251
coap_session_max_pdu_size(const coap_session_t * session)252 size_t coap_session_max_pdu_size(const coap_session_t *session) {
253 size_t max_with_header = (size_t)(session->mtu - session->tls_overhead);
254 #if COAP_DISABLE_TCP
255 return max_with_header > 4 ? max_with_header - 4 : 0;
256 #else /* !COAP_DISABLE_TCP */
257 if (COAP_PROTO_NOT_RELIABLE(session->proto))
258 return max_with_header > 4 ? max_with_header - 4 : 0;
259 /* we must assume there is no token to be on the safe side */
260 if (max_with_header <= 2)
261 return 0;
262 else if (max_with_header <= COAP_MAX_MESSAGE_SIZE_TCP0 + 2)
263 return max_with_header - 2;
264 else if (max_with_header <= COAP_MAX_MESSAGE_SIZE_TCP8 + 3)
265 return max_with_header - 3;
266 else if (max_with_header <= COAP_MAX_MESSAGE_SIZE_TCP16 + 4)
267 return max_with_header - 4;
268 else
269 return max_with_header - 6;
270 #endif /* !COAP_DISABLE_TCP */
271 }
272
coap_session_set_mtu(coap_session_t * session,unsigned mtu)273 void coap_session_set_mtu(coap_session_t *session, unsigned mtu) {
274 #if defined(WITH_CONTIKI) || defined(WITH_LWIP)
275 if (mtu > COAP_MAX_MESSAGE_SIZE_TCP16 + 4)
276 mtu = COAP_MAX_MESSAGE_SIZE_TCP16 + 4;
277 #endif
278 session->mtu = mtu;
279 if (session->tls_overhead >= session->mtu) {
280 session->tls_overhead = session->mtu;
281 coap_log(LOG_ERR, "DTLS overhead exceeds MTU\n");
282 }
283 }
284
coap_session_send(coap_session_t * session,const uint8_t * data,size_t datalen)285 ssize_t coap_session_send(coap_session_t *session, const uint8_t *data, size_t datalen) {
286 ssize_t bytes_written;
287
288 coap_socket_t *sock = &session->sock;
289 if (sock->flags == COAP_SOCKET_EMPTY) {
290 assert(session->endpoint != NULL);
291 sock = &session->endpoint->sock;
292 }
293
294 bytes_written = coap_socket_send(sock, session, data, datalen);
295 if (bytes_written == (ssize_t)datalen) {
296 coap_ticks(&session->last_rx_tx);
297 coap_log(LOG_DEBUG, "* %s: sent %zd bytes\n",
298 coap_session_str(session), datalen);
299 } else {
300 coap_log(LOG_DEBUG, "* %s: failed to send %zd bytes\n",
301 coap_session_str(session), datalen);
302 }
303 return bytes_written;
304 }
305
coap_session_write(coap_session_t * session,const uint8_t * data,size_t datalen)306 ssize_t coap_session_write(coap_session_t *session, const uint8_t *data, size_t datalen) {
307 ssize_t bytes_written = coap_socket_write(&session->sock, data, datalen);
308 if (bytes_written > 0) {
309 coap_ticks(&session->last_rx_tx);
310 coap_log(LOG_DEBUG, "* %s: sent %zd bytes\n",
311 coap_session_str(session), datalen);
312 } else if (bytes_written < 0) {
313 coap_log(LOG_DEBUG, "* %s: failed to send %zd bytes\n",
314 coap_session_str(session), datalen );
315 }
316 return bytes_written;
317 }
318
319 ssize_t
coap_session_delay_pdu(coap_session_t * session,coap_pdu_t * pdu,coap_queue_t * node)320 coap_session_delay_pdu(coap_session_t *session, coap_pdu_t *pdu,
321 coap_queue_t *node)
322 {
323 if ( node ) {
324 coap_queue_t *removed = NULL;
325 coap_remove_from_queue(&session->context->sendqueue, session, node->id, &removed);
326 assert(removed == node);
327 coap_session_release(node->session);
328 node->session = NULL;
329 node->t = 0;
330 } else {
331 coap_queue_t *q = NULL;
332 /* Check that the same mid is not getting re-used in violation of RFC7252 */
333 LL_FOREACH(session->delayqueue, q) {
334 if (q->id == pdu->mid) {
335 coap_log(LOG_ERR, "** %s: mid=0x%x: already in-use - dropped\n",
336 coap_session_str(session), pdu->mid);
337 return COAP_INVALID_MID;
338 }
339 }
340 node = coap_new_node();
341 if (node == NULL)
342 return COAP_INVALID_MID;
343 node->id = pdu->mid;
344 node->pdu = pdu;
345 if (pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto)) {
346 uint8_t r;
347 coap_prng(&r, sizeof(r));
348 /* add timeout in range [ACK_TIMEOUT...ACK_TIMEOUT * ACK_RANDOM_FACTOR] */
349 node->timeout = coap_calc_timeout(session, r);
350 }
351 }
352 LL_APPEND(session->delayqueue, node);
353 coap_log(LOG_DEBUG, "** %s: mid=0x%x: delayed\n",
354 coap_session_str(session), node->id);
355 return COAP_PDU_DELAYED;
356 }
357
358 #if !COAP_DISABLE_TCP
coap_session_send_csm(coap_session_t * session)359 void coap_session_send_csm(coap_session_t *session) {
360 coap_pdu_t *pdu;
361 uint8_t buf[4];
362 assert(COAP_PROTO_RELIABLE(session->proto));
363 coap_log(LOG_DEBUG, "***%s: sending CSM\n", coap_session_str(session));
364 session->state = COAP_SESSION_STATE_CSM;
365 session->partial_write = 0;
366 if (session->mtu == 0)
367 session->mtu = COAP_DEFAULT_MTU; /* base value */
368 pdu = coap_pdu_init(COAP_MESSAGE_CON, COAP_SIGNALING_CODE_CSM, 0, 20);
369 if ( pdu == NULL
370 || coap_add_option(pdu, COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE,
371 coap_encode_var_safe(buf, sizeof(buf),
372 COAP_DEFAULT_MAX_PDU_RX_SIZE), buf) == 0
373 || coap_add_option(pdu, COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER,
374 coap_encode_var_safe(buf, sizeof(buf),
375 0), buf) == 0
376 || coap_pdu_encode_header(pdu, session->proto) == 0
377 ) {
378 coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE);
379 } else {
380 ssize_t bytes_written = coap_session_send_pdu(session, pdu);
381 if (bytes_written != (ssize_t)pdu->used_size + pdu->hdr_size)
382 coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE);
383 }
384 if (pdu)
385 coap_delete_pdu(pdu);
386 }
387 #endif /* !COAP_DISABLE_TCP */
388
coap_session_send_ping(coap_session_t * session)389 coap_mid_t coap_session_send_ping(coap_session_t *session) {
390 coap_pdu_t *ping = NULL;
391 if (session->state != COAP_SESSION_STATE_ESTABLISHED)
392 return COAP_INVALID_MID;
393 if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
394 uint16_t mid = coap_new_message_id (session);
395 ping = coap_pdu_init(COAP_MESSAGE_CON, 0, mid, 0);
396 }
397 #if !COAP_DISABLE_TCP
398 else {
399 ping = coap_pdu_init(COAP_MESSAGE_CON, COAP_SIGNALING_CODE_PING, 0, 1);
400 }
401 #endif /* !COAP_DISABLE_TCP */
402 if (!ping)
403 return COAP_INVALID_MID;
404 return coap_send_internal(session, ping);
405 }
406
coap_session_connected(coap_session_t * session)407 void coap_session_connected(coap_session_t *session) {
408 if (session->state != COAP_SESSION_STATE_ESTABLISHED) {
409 coap_log(LOG_DEBUG, "***%s: session connected\n",
410 coap_session_str(session));
411 if (session->state == COAP_SESSION_STATE_CSM)
412 coap_handle_event(session->context, COAP_EVENT_SESSION_CONNECTED, session);
413 }
414
415 session->state = COAP_SESSION_STATE_ESTABLISHED;
416 session->partial_write = 0;
417
418 if ( session->proto==COAP_PROTO_DTLS) {
419 session->tls_overhead = coap_dtls_get_overhead(session);
420 if (session->tls_overhead >= session->mtu) {
421 session->tls_overhead = session->mtu;
422 coap_log(LOG_ERR, "DTLS overhead exceeds MTU\n");
423 }
424 }
425
426 while (session->delayqueue && session->state == COAP_SESSION_STATE_ESTABLISHED) {
427 ssize_t bytes_written;
428 coap_queue_t *q = session->delayqueue;
429 if (q->pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto)) {
430 if (session->con_active >= COAP_DEFAULT_NSTART)
431 break;
432 session->con_active++;
433 }
434 /* Take entry off the queue */
435 session->delayqueue = q->next;
436 q->next = NULL;
437
438 coap_log(LOG_DEBUG, "** %s: mid=0x%x: transmitted after delay\n",
439 coap_session_str(session), (int)q->pdu->mid);
440 bytes_written = coap_session_send_pdu(session, q->pdu);
441 if (q->pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto)) {
442 if (coap_wait_ack(session->context, session, q) >= 0)
443 q = NULL;
444 }
445 if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
446 if (q)
447 coap_delete_node(q);
448 if (bytes_written < 0)
449 break;
450 } else {
451 if (bytes_written <= 0 || (size_t)bytes_written < q->pdu->used_size + q->pdu->hdr_size) {
452 q->next = session->delayqueue;
453 session->delayqueue = q;
454 if (bytes_written > 0)
455 session->partial_write = (size_t)bytes_written;
456 break;
457 } else {
458 coap_delete_node(q);
459 }
460 }
461 }
462 }
463
coap_session_disconnected(coap_session_t * session,coap_nack_reason_t reason)464 void coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason) {
465 #if !COAP_DISABLE_TCP
466 coap_session_state_t state = session->state;
467 #endif /* !COAP_DISABLE_TCP */
468
469 coap_log(LOG_DEBUG, "***%s: session disconnected (reason %d)\n",
470 coap_session_str(session), reason);
471 coap_delete_observers( session->context, session );
472
473 if ( session->tls) {
474 if (session->proto == COAP_PROTO_DTLS)
475 coap_dtls_free_session(session);
476 #if !COAP_DISABLE_TCP
477 else if (session->proto == COAP_PROTO_TLS)
478 coap_tls_free_session(session);
479 #endif /* !COAP_DISABLE_TCP */
480 session->tls = NULL;
481 }
482
483 if (session->proto == COAP_PROTO_UDP)
484 session->state = COAP_SESSION_STATE_ESTABLISHED;
485 else
486 session->state = COAP_SESSION_STATE_NONE;
487
488 session->con_active = 0;
489
490 if (session->partial_pdu) {
491 coap_delete_pdu(session->partial_pdu);
492 session->partial_pdu = NULL;
493 }
494 session->partial_read = 0;
495
496 while (session->delayqueue) {
497 coap_queue_t *q = session->delayqueue;
498 session->delayqueue = q->next;
499 q->next = NULL;
500 coap_log(LOG_DEBUG, "** %s: mid=0x%x: not transmitted after disconnect\n",
501 coap_session_str(session), q->id);
502 if (q->pdu->type==COAP_MESSAGE_CON
503 && COAP_PROTO_NOT_RELIABLE(session->proto)
504 && reason == COAP_NACK_ICMP_ISSUE)
505 {
506 /* Make sure that we try a re-transmit later on ICMP error */
507 if (coap_wait_ack(session->context, session, q) >= 0) {
508 if (session->context->nack_handler) {
509 session->context->nack_handler(session, q->pdu, reason, q->id);
510 }
511 q = NULL;
512 }
513 }
514 if (q && q->pdu->type == COAP_MESSAGE_CON
515 && session->context->nack_handler)
516 {
517 session->context->nack_handler(session, q->pdu, reason, q->id);
518 }
519 if (q)
520 coap_delete_node(q);
521 }
522 if (reason != COAP_NACK_ICMP_ISSUE) {
523 coap_cancel_session_messages(session->context, session, reason);
524 }
525 else if (session->context->nack_handler) {
526 coap_queue_t *q = session->context->sendqueue;
527 while (q) {
528 if (q->session == session) {
529 session->context->nack_handler(session, q->pdu, reason, q->id);
530 }
531 q = q->next;
532 }
533 }
534
535 #if !COAP_DISABLE_TCP
536 if (COAP_PROTO_RELIABLE(session->proto)) {
537 if (session->sock.flags != COAP_SOCKET_EMPTY) {
538 coap_socket_close(&session->sock);
539 coap_handle_event(session->context,
540 state == COAP_SESSION_STATE_CONNECTING ?
541 COAP_EVENT_TCP_FAILED : COAP_EVENT_TCP_CLOSED, session);
542 }
543 if (state != COAP_SESSION_STATE_NONE) {
544 coap_handle_event(session->context,
545 state == COAP_SESSION_STATE_ESTABLISHED ?
546 COAP_EVENT_SESSION_CLOSED : COAP_EVENT_SESSION_FAILED, session);
547 }
548 }
549 #endif /* !COAP_DISABLE_TCP */
550 }
551
loopback_packet_check(const char * srcbuf)552 static int32_t loopback_packet_check(const char *srcbuf) {
553 const char addr_perface[] = "::ffff:";
554 char tmpbuf[INET6_ADDRSTRLEN] = {0};
555 int ret;
556 void *tmp_addr_ptr = NULL;
557 struct ifreq buf[COAP_INTERFACE_MAX];
558 struct ifconf ifc = {0};
559
560 int fd = socket(AF_INET, SOCK_DGRAM, 0);
561 if (fd < 0) {
562 coap_log(LOG_DEBUG, "socket() fail\n");
563 return 1;
564 }
565 ifc.ifc_len = sizeof(buf);
566 ifc.ifc_buf = (char *)buf;
567 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0) {
568 coap_log(LOG_DEBUG, "ioctl fail, errno = %d\n", errno);
569 goto L_IS_LOOPBACK;
570 }
571 int interfaceNum = ifc.ifc_len / sizeof(struct ifreq);
572 for (int i = 0; i < interfaceNum && i < COAP_INTERFACE_MAX; i++) {
573 coap_log(LOG_DEBUG, "interface name: %s\n", buf[i].ifr_name);
574 /* get IP of this interface */
575 if (ioctl(fd, SIOCGIFADDR, (char *)&buf[i]) < 0) {
576 coap_log(LOG_DEBUG, "ioctl fail, errno = %d\n", errno);
577 goto L_IS_LOOPBACK;
578 }
579 tmp_addr_ptr = &((struct sockaddr_in *)&(buf[i].ifr_addr))->sin_addr;
580 inet_ntop(AF_INET, tmp_addr_ptr, tmpbuf, INET_ADDRSTRLEN);
581 if (memcmp(srcbuf, addr_perface, strlen(addr_perface)) == 0 &&
582 strlen(srcbuf) == strlen(tmpbuf) + strlen(addr_perface)) {
583 ret = memcmp(srcbuf + strlen(addr_perface), tmpbuf, strlen(srcbuf) - strlen(addr_perface));
584 } else {
585 if (strlen(srcbuf) == strlen(tmpbuf)) {
586 ret = memcmp(srcbuf, tmpbuf, strlen(srcbuf));
587 } else {
588 ret = 1;
589 }
590 }
591 if (ret == 0) {
592 goto L_IS_LOOPBACK;
593 }
594 }
595 close(fd);
596 return 0;
597 L_IS_LOOPBACK:
598 close(fd);
599 return 1;
600 }
601
is_loopback_packet(const coap_packet_t * packet)602 static int32_t is_loopback_packet(const coap_packet_t *packet) {
603 char srcbuf[INET6_ADDRSTRLEN] = {0};
604
605 coap_address_ntop(&(packet->addr_info.remote), srcbuf, INET6_ADDRSTRLEN);
606
607 return loopback_packet_check(srcbuf);
608 }
609
610 static void
coap_make_addr_hash(coap_addr_hash_t * addr_hash,coap_proto_t proto,const coap_addr_tuple_t * addr_info)611 coap_make_addr_hash(coap_addr_hash_t *addr_hash, coap_proto_t proto,
612 const coap_addr_tuple_t *addr_info) {
613 memset(addr_hash, 0, sizeof(coap_addr_hash_t));
614 coap_address_copy(&addr_hash->remote, &addr_info->remote);
615 addr_hash->lport = coap_address_get_port(&addr_info->local);
616 addr_hash->proto = proto;
617 }
618
619 coap_session_t *
coap_endpoint_get_session(coap_endpoint_t * endpoint,const coap_packet_t * packet,coap_tick_t now)620 coap_endpoint_get_session(coap_endpoint_t *endpoint,
621 const coap_packet_t *packet, coap_tick_t now) {
622 coap_session_t *session;
623 coap_session_t *rtmp;
624 unsigned int num_idle = 0;
625 unsigned int num_hs = 0;
626 coap_session_t *oldest = NULL;
627 coap_session_t *oldest_hs = NULL;
628 coap_addr_hash_t addr_hash;
629
630 if (is_loopback_packet(packet) == 1) {
631 coap_log(LOG_DEBUG, "drop loopback packet.");
632 return NULL;
633 }
634
635 coap_make_addr_hash(&addr_hash, endpoint->proto, &packet->addr_info);
636 SESSIONS_FIND(endpoint->sessions, addr_hash, session);
637 if (session) {
638 /* Maybe mcast or unicast IP address which is not in the hash */
639 coap_address_copy(&session->addr_info.local, &packet->addr_info.local);
640 session->ifindex = packet->ifindex;
641 session->last_rx_tx = now;
642 return session;
643 }
644
645 SESSIONS_ITER(endpoint->sessions, session, rtmp) {
646 if (session->ref == 0 && session->delayqueue == NULL) {
647 if (session->type == COAP_SESSION_TYPE_SERVER) {
648 ++num_idle;
649 if (oldest==NULL || session->last_rx_tx < oldest->last_rx_tx)
650 oldest = session;
651
652 if (session->state == COAP_SESSION_STATE_HANDSHAKE) {
653 ++num_hs;
654 /* See if this is a partial (D)TLS session set up
655 which needs to be cleared down to prevent DOS */
656 if ((session->last_rx_tx + COAP_PARTIAL_SESSION_TIMEOUT_TICKS) < now) {
657 if (oldest_hs == NULL ||
658 session->last_rx_tx < oldest_hs->last_rx_tx)
659 oldest_hs = session;
660 }
661 }
662 }
663 else if (session->type == COAP_SESSION_TYPE_HELLO) {
664 ++num_hs;
665 /* See if this is a partial (D)TLS session set up for Client Hello
666 which needs to be cleared down to prevent DOS */
667 if ((session->last_rx_tx + COAP_PARTIAL_SESSION_TIMEOUT_TICKS) < now) {
668 if (oldest_hs == NULL ||
669 session->last_rx_tx < oldest_hs->last_rx_tx)
670 oldest_hs = session;
671 }
672 }
673 }
674 }
675
676 if (endpoint->context->max_idle_sessions > 0 &&
677 num_idle >= endpoint->context->max_idle_sessions) {
678 coap_session_free(oldest);
679 }
680 else if (oldest_hs) {
681 coap_log(LOG_WARNING, "***%s: Incomplete session timed out\n",
682 coap_session_str(oldest_hs));
683 coap_session_free(oldest_hs);
684 }
685
686 if (num_hs > (endpoint->context->max_handshake_sessions ?
687 endpoint->context->max_handshake_sessions :
688 COAP_DEFAULT_MAX_HANDSHAKE_SESSIONS)) {
689 /* Maxed out on number of sessions in (D)TLS negotiation state */
690 coap_log(LOG_DEBUG,
691 "Oustanding sessions in COAP_SESSION_STATE_HANDSHAKE too "
692 "large. New request ignored\n");
693 return NULL;
694 }
695
696 if (endpoint->proto == COAP_PROTO_DTLS) {
697 /*
698 * Need to check that this actually is a Client Hello before wasting
699 * time allocating and then freeing off session.
700 */
701
702 /*
703 * Generic header structure of the DTLS record layer.
704 * typedef struct __attribute__((__packed__)) {
705 * uint8_t content_type; content type of the included message
706 * uint16_t version; Protocol version
707 * uint16_t epoch; counter for cipher state changes
708 * uint8_t sequence_number[6]; sequence number
709 * uint16_t length; length of the following fragment
710 * uint8_t handshake; If content_type == DTLS_CT_HANDSHAKE
711 * } dtls_record_handshake_t;
712 */
713 #define OFF_CONTENT_TYPE 0 /* offset of content_type in dtls_record_handshake_t */
714 #define DTLS_CT_ALERT 21 /* Content Type Alert */
715 #define DTLS_CT_HANDSHAKE 22 /* Content Type Handshake */
716 #define OFF_HANDSHAKE_TYPE 13 /* offset of handshake in dtls_record_handshake_t */
717 #define DTLS_HT_CLIENT_HELLO 1 /* Client Hello handshake type */
718
719 #ifdef WITH_LWIP
720 const uint8_t *payload = (const uint8_t*)packet->pbuf->payload;
721 size_t length = packet->pbuf->len;
722 #else /* ! WITH_LWIP */
723 const uint8_t *payload = (const uint8_t*)packet->payload;
724 size_t length = packet->length;
725 #endif /* ! WITH_LWIP */
726 if (length < (OFF_HANDSHAKE_TYPE + 1)) {
727 coap_log(LOG_DEBUG,
728 "coap_dtls_hello: ContentType %d Short Packet (%zu < %d) dropped\n",
729 payload[OFF_CONTENT_TYPE], length,
730 OFF_HANDSHAKE_TYPE + 1);
731 return NULL;
732 }
733 if (payload[OFF_CONTENT_TYPE] != DTLS_CT_HANDSHAKE ||
734 payload[OFF_HANDSHAKE_TYPE] != DTLS_HT_CLIENT_HELLO) {
735 /* only log if not a late alert */
736 if (payload[OFF_CONTENT_TYPE] != DTLS_CT_ALERT)
737 coap_log(LOG_DEBUG,
738 "coap_dtls_hello: ContentType %d Handshake %d dropped\n",
739 payload[OFF_CONTENT_TYPE], payload[OFF_HANDSHAKE_TYPE]);
740 return NULL;
741 }
742 }
743 session = coap_make_session(endpoint->proto, COAP_SESSION_TYPE_SERVER,
744 &addr_hash, &packet->addr_info.local,
745 &packet->addr_info.remote,
746 packet->ifindex, endpoint->context, endpoint);
747 if (session) {
748 session->last_rx_tx = now;
749 if (endpoint->proto == COAP_PROTO_UDP)
750 session->state = COAP_SESSION_STATE_ESTABLISHED;
751 else if (endpoint->proto == COAP_PROTO_DTLS) {
752 session->type = COAP_SESSION_TYPE_HELLO;
753 }
754 SESSIONS_ADD(endpoint->sessions, session);
755 coap_log(LOG_DEBUG, "***%s: new incoming session\n",
756 coap_session_str(session));
757 }
758 return session;
759 }
760
761 coap_session_t *
coap_session_new_dtls_session(coap_session_t * session,coap_tick_t now)762 coap_session_new_dtls_session(coap_session_t *session,
763 coap_tick_t now) {
764 if (session) {
765 session->last_rx_tx = now;
766 session->type = COAP_SESSION_TYPE_SERVER;
767 session->tls = coap_dtls_new_server_session(session);
768 if (session->tls) {
769 session->state = COAP_SESSION_STATE_HANDSHAKE;
770 } else {
771 coap_session_free(session);
772 session = NULL;
773 }
774 }
775 return session;
776 }
777
778 #ifdef COAP_EPOLL_SUPPORT
779 static void
coap_epoll_ctl_add(coap_socket_t * sock,uint32_t events,const char * func)780 coap_epoll_ctl_add(coap_socket_t *sock,
781 uint32_t events,
782 const char *func
783 ) {
784 int ret;
785 struct epoll_event event;
786 coap_context_t *context;
787
788 if (sock == NULL)
789 return;
790
791 context = sock->session ? sock->session->context :
792 sock->endpoint ? sock->endpoint->context : NULL;
793 if (context == NULL)
794 return;
795
796 /* Needed if running 32bit as ptr is only 32bit */
797 memset(&event, 0, sizeof(event));
798 event.events = events;
799 event.data.ptr = sock;
800
801 ret = epoll_ctl(context->epfd, EPOLL_CTL_ADD, sock->fd, &event);
802 if (ret == -1) {
803 coap_log(LOG_ERR,
804 "%s: epoll_ctl ADD failed: %s (%d)\n",
805 func,
806 coap_socket_strerror(), errno);
807 }
808 }
809 #endif /* COAP_EPOLL_SUPPORT */
810
811 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)812 coap_session_create_client(
813 coap_context_t *ctx,
814 const coap_address_t *local_if,
815 const coap_address_t *server,
816 coap_proto_t proto
817 ) {
818 coap_session_t *session = NULL;
819
820 assert(server);
821
822 switch(proto) {
823 case COAP_PROTO_UDP:
824 break;
825 case COAP_PROTO_DTLS:
826 if (!coap_dtls_is_supported()) {
827 coap_log(LOG_CRIT, "coap_new_client_session*: DTLS not supported\n");
828 return NULL;
829 }
830 break;
831 case COAP_PROTO_TCP:
832 if (!coap_tcp_is_supported()) {
833 coap_log(LOG_CRIT, "coap_new_client_session*: TCP not supported\n");
834 return NULL;
835 }
836 break;
837 case COAP_PROTO_TLS:
838 if (!coap_tls_is_supported()) {
839 coap_log(LOG_CRIT, "coap_new_client_session*: TLS not supported\n");
840 return NULL;
841 }
842 break;
843 case COAP_PROTO_NONE:
844 default:
845 assert(0);
846 break;
847 }
848 session = coap_make_session(proto, COAP_SESSION_TYPE_CLIENT, NULL,
849 local_if, server, 0, ctx, NULL);
850 if (!session)
851 goto error;
852
853 coap_session_reference(session);
854
855 if (proto == COAP_PROTO_UDP || proto == COAP_PROTO_DTLS) {
856 if (!coap_socket_connect_udp(&session->sock, local_if, server,
857 proto == COAP_PROTO_DTLS ? COAPS_DEFAULT_PORT : COAP_DEFAULT_PORT,
858 &session->addr_info.local, &session->addr_info.remote)) {
859 goto error;
860 }
861 #if !COAP_DISABLE_TCP
862 } else if (proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS) {
863 if (!coap_socket_connect_tcp1(&session->sock, local_if, server,
864 proto == COAP_PROTO_TLS ? COAPS_DEFAULT_PORT : COAP_DEFAULT_PORT,
865 &session->addr_info.local, &session->addr_info.remote)) {
866 goto error;
867 }
868 #endif /* !COAP_DISABLE_TCP */
869 }
870
871 #ifdef COAP_EPOLL_SUPPORT
872 session->sock.session = session;
873 coap_epoll_ctl_add(&session->sock,
874 EPOLLIN |
875 ((session->sock.flags & COAP_SOCKET_WANT_CONNECT) ?
876 EPOLLOUT : 0),
877 __func__);
878 #endif /* COAP_EPOLL_SUPPORT */
879
880 session->sock.flags |= COAP_SOCKET_NOT_EMPTY | COAP_SOCKET_WANT_READ;
881 if (local_if)
882 session->sock.flags |= COAP_SOCKET_BOUND;
883 SESSIONS_ADD(ctx->sessions, session);
884 return session;
885
886 error:
887 coap_session_release(session);
888 return NULL;
889 }
890
891 static coap_session_t *
coap_session_connect(coap_session_t * session)892 coap_session_connect(coap_session_t *session) {
893 if (session->proto == COAP_PROTO_UDP) {
894 session->state = COAP_SESSION_STATE_ESTABLISHED;
895 } else if (session->proto == COAP_PROTO_DTLS) {
896 session->tls = coap_dtls_new_client_session(session);
897 if (session->tls) {
898 session->state = COAP_SESSION_STATE_HANDSHAKE;
899 } else {
900 /* Need to free session object. As a new session may not yet
901 * have been referenced, we call coap_session_reference() first
902 * before trying to release the object.
903 */
904 coap_session_reference(session);
905 coap_session_release(session);
906 return NULL;
907 }
908 #if !COAP_DISABLE_TCP
909 } else {
910 if (session->proto == COAP_PROTO_TCP || session->proto == COAP_PROTO_TLS) {
911 if (session->sock.flags & COAP_SOCKET_WANT_CONNECT) {
912 session->state = COAP_SESSION_STATE_CONNECTING;
913 } else if (session->proto == COAP_PROTO_TLS) {
914 int connected = 0;
915 session->tls = coap_tls_new_client_session(session, &connected);
916 if (session->tls) {
917 session->state = COAP_SESSION_STATE_HANDSHAKE;
918 if (connected)
919 coap_session_send_csm(session);
920 } else {
921 /* Need to free session object. As a new session may not yet
922 * have been referenced, we call coap_session_reference()
923 * first before trying to release the object.
924 */
925 coap_session_reference(session);
926 coap_session_release(session);
927 return NULL;
928 }
929 } else {
930 coap_session_send_csm(session);
931 }
932 }
933 #endif /* !COAP_DISABLE_TCP */
934 }
935 coap_ticks(&session->last_rx_tx);
936 return session;
937 }
938
939 static coap_session_t *
coap_session_accept(coap_session_t * session)940 coap_session_accept(coap_session_t *session) {
941 #if !COAP_DISABLE_TCP
942 if (session->proto == COAP_PROTO_TCP || session->proto == COAP_PROTO_TLS)
943 coap_handle_event(session->context, COAP_EVENT_TCP_CONNECTED, session);
944 if (session->proto == COAP_PROTO_TCP) {
945 coap_session_send_csm(session);
946 } else if (session->proto == COAP_PROTO_TLS) {
947 int connected = 0;
948 session->tls = coap_tls_new_server_session(session, &connected);
949 if (session->tls) {
950 session->state = COAP_SESSION_STATE_HANDSHAKE;
951 if (connected) {
952 coap_handle_event(session->context, COAP_EVENT_DTLS_CONNECTED, session);
953 coap_session_send_csm(session);
954 }
955 } else {
956 /* Need to free session object. As a new session may not yet
957 * have been referenced, we call coap_session_reference() first
958 * before trying to release the object.
959 */
960 coap_session_reference(session);
961 coap_session_release(session);
962 session = NULL;
963 }
964 }
965 #endif /* COAP_DISABLE_TCP */
966 return session;
967 }
968
coap_new_client_session(coap_context_t * ctx,const coap_address_t * local_if,const coap_address_t * server,coap_proto_t proto)969 coap_session_t *coap_new_client_session(
970 coap_context_t *ctx,
971 const coap_address_t *local_if,
972 const coap_address_t *server,
973 coap_proto_t proto
974 ) {
975 coap_session_t *session = coap_session_create_client(ctx, local_if, server, proto);
976 if (session) {
977 coap_log(LOG_DEBUG, "***%s: new outgoing session\n",
978 coap_session_str(session));
979 session = coap_session_connect(session);
980 }
981 return session;
982 }
983
coap_new_client_session_psk(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)984 coap_session_t *coap_new_client_session_psk(
985 coap_context_t *ctx,
986 const coap_address_t *local_if,
987 const coap_address_t *server,
988 coap_proto_t proto,
989 const char *identity,
990 const uint8_t *key,
991 unsigned key_len
992 ) {
993 coap_dtls_cpsk_t setup_data;
994
995 memset (&setup_data, 0, sizeof(setup_data));
996
997 if (identity) {
998 setup_data.psk_info.identity.s = (const uint8_t *)identity;
999 setup_data.psk_info.identity.length = strlen(identity);
1000 }
1001
1002 if (key && key_len > 0) {
1003 setup_data.psk_info.key.s = key;
1004 setup_data.psk_info.key.length = key_len;
1005 }
1006
1007 return coap_new_client_session_psk2(ctx, local_if, server,
1008 proto, &setup_data);
1009 }
1010
coap_new_client_session_psk2(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)1011 coap_session_t *coap_new_client_session_psk2(
1012 coap_context_t *ctx,
1013 const coap_address_t *local_if,
1014 const coap_address_t *server,
1015 coap_proto_t proto,
1016 coap_dtls_cpsk_t *setup_data
1017 ) {
1018 coap_session_t *session = coap_session_create_client(ctx, local_if,
1019 server, proto);
1020
1021 if (!session)
1022 return NULL;
1023
1024 session->cpsk_setup_data = *setup_data;
1025 if (setup_data->psk_info.identity.s) {
1026 session->psk_identity =
1027 coap_new_bin_const(setup_data->psk_info.identity.s,
1028 setup_data->psk_info.identity.length);
1029 if (!session->psk_identity) {
1030 coap_log(LOG_WARNING, "Cannot store session Identity (PSK)\n");
1031 coap_session_release(session);
1032 return NULL;
1033 }
1034 }
1035 else if (coap_dtls_is_supported()) {
1036 coap_log(LOG_WARNING, "Identity (PSK) not defined\n");
1037 coap_session_release(session);
1038 return NULL;
1039 }
1040
1041 if (setup_data->psk_info.key.s && setup_data->psk_info.key.length > 0) {
1042 session->psk_key = coap_new_bin_const(setup_data->psk_info.key.s,
1043 setup_data->psk_info.key.length);
1044 if (!session->psk_key) {
1045 coap_log(LOG_WARNING, "Cannot store session pre-shared key (PSK)\n");
1046 coap_session_release(session);
1047 return NULL;
1048 }
1049 }
1050 else if (coap_dtls_is_supported()) {
1051 coap_log(LOG_WARNING, "Pre-shared key (PSK) not defined\n");
1052 coap_session_release(session);
1053 return NULL;
1054 }
1055
1056 if (coap_dtls_is_supported()) {
1057 if (!coap_dtls_context_set_cpsk(ctx, setup_data)) {
1058 coap_session_release(session);
1059 return NULL;
1060 }
1061 }
1062 coap_log(LOG_DEBUG, "***%s: new outgoing session\n",
1063 coap_session_str(session));
1064 return coap_session_connect(session);
1065 }
1066
coap_session_refresh_psk_hint(coap_session_t * session,const coap_bin_const_t * psk_hint)1067 int coap_session_refresh_psk_hint(coap_session_t *session,
1068 const coap_bin_const_t *psk_hint
1069 ) {
1070 /* We may be refreshing the hint with the same hint */
1071 coap_bin_const_t *old_psk_hint = session->psk_hint;
1072
1073 if (psk_hint && psk_hint->s) {
1074 if (session->psk_hint) {
1075 if (coap_binary_equal(session->psk_hint, psk_hint))
1076 return 1;
1077 }
1078 session->psk_hint = coap_new_bin_const(psk_hint->s,
1079 psk_hint->length);
1080 if (!session->psk_hint) {
1081 coap_log(LOG_ERR, "No memory to store identity hint (PSK)\n");
1082 if (old_psk_hint)
1083 coap_delete_bin_const(old_psk_hint);
1084 return 0;
1085 }
1086 }
1087 else {
1088 session->psk_hint = NULL;
1089 }
1090 if (old_psk_hint)
1091 coap_delete_bin_const(old_psk_hint);
1092
1093 return 1;
1094 }
1095
coap_session_refresh_psk_key(coap_session_t * session,const coap_bin_const_t * psk_key)1096 int coap_session_refresh_psk_key(coap_session_t *session,
1097 const coap_bin_const_t *psk_key
1098 ) {
1099 /* We may be refreshing the key with the same key */
1100 coap_bin_const_t *old_psk_key = session->psk_key;
1101
1102 if (psk_key && psk_key->s) {
1103 if (session->psk_key) {
1104 if (coap_binary_equal(session->psk_key, psk_key))
1105 return 1;
1106 }
1107 session->psk_key = coap_new_bin_const(psk_key->s, psk_key->length);
1108 if (!session->psk_key) {
1109 coap_log(LOG_ERR, "No memory to store pre-shared key (PSK)\n");
1110 if (old_psk_key)
1111 coap_delete_bin_const(old_psk_key);
1112 return 0;
1113 }
1114 }
1115 else {
1116 session->psk_key = NULL;
1117 }
1118 if (old_psk_key)
1119 coap_delete_bin_const(old_psk_key);
1120
1121 return 1;
1122 }
1123
1124 const coap_bin_const_t *
coap_session_get_psk_hint(const coap_session_t * session)1125 coap_session_get_psk_hint(const coap_session_t *session) {
1126 if (session)
1127 return session->psk_hint;
1128 return NULL;
1129 }
1130
1131 const coap_bin_const_t *
coap_session_get_psk_key(const coap_session_t * session)1132 coap_session_get_psk_key(const coap_session_t *session) {
1133 if (session)
1134 return session->psk_key;
1135 return NULL;
1136 }
1137
coap_new_client_session_pki(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)1138 coap_session_t *coap_new_client_session_pki(
1139 coap_context_t *ctx,
1140 const coap_address_t *local_if,
1141 const coap_address_t *server,
1142 coap_proto_t proto,
1143 coap_dtls_pki_t* setup_data
1144 ) {
1145 coap_session_t *session;
1146
1147 if (coap_dtls_is_supported()) {
1148 if (!setup_data) {
1149 return NULL;
1150 } else {
1151 if (setup_data->version != COAP_DTLS_PKI_SETUP_VERSION) {
1152 coap_log(LOG_ERR,
1153 "coap_new_client_session_pki: Wrong version of setup_data\n");
1154 return NULL;
1155 }
1156 }
1157
1158 }
1159 session = coap_session_create_client(ctx, local_if, server, proto);
1160
1161 if (!session) {
1162 return NULL;
1163 }
1164
1165 if (coap_dtls_is_supported()) {
1166 /* we know that setup_data is not NULL */
1167 if (!coap_dtls_context_set_pki(ctx, setup_data, COAP_DTLS_ROLE_CLIENT)) {
1168 coap_session_release(session);
1169 return NULL;
1170 }
1171 }
1172 coap_log(LOG_DEBUG, "***%s: new outgoing session\n",
1173 coap_session_str(session));
1174 return coap_session_connect(session);
1175 }
1176
coap_new_server_session(coap_context_t * ctx,coap_endpoint_t * ep)1177 coap_session_t *coap_new_server_session(
1178 coap_context_t *ctx,
1179 coap_endpoint_t *ep
1180 ) {
1181 coap_session_t *session;
1182 session = coap_make_session( ep->proto, COAP_SESSION_TYPE_SERVER,
1183 NULL, NULL, NULL, 0, ctx, ep );
1184 if (!session)
1185 goto error;
1186
1187 #if !COAP_DISABLE_TCP
1188 if (!coap_socket_accept_tcp(&ep->sock, &session->sock,
1189 &session->addr_info.local,
1190 &session->addr_info.remote))
1191 goto error;
1192 coap_make_addr_hash(&session->addr_hash, session->proto, &session->addr_info);
1193
1194 #endif /* !COAP_DISABLE_TCP */
1195 session->sock.flags |= COAP_SOCKET_NOT_EMPTY | COAP_SOCKET_CONNECTED
1196 | COAP_SOCKET_WANT_READ;
1197 #ifdef COAP_EPOLL_SUPPORT
1198 session->sock.session = session;
1199 coap_epoll_ctl_add(&session->sock,
1200 EPOLLIN,
1201 __func__);
1202 #endif /* COAP_EPOLL_SUPPORT */
1203 SESSIONS_ADD(ep->sessions, session);
1204 if (session) {
1205 coap_log(LOG_DEBUG, "***%s: new incoming session\n",
1206 coap_session_str(session));
1207 session = coap_session_accept(session);
1208 }
1209 return session;
1210
1211 error:
1212 coap_session_free(session);
1213 return NULL;
1214 }
1215
1216 void
coap_session_init_token(coap_session_t * session,size_t len,const uint8_t * data)1217 coap_session_init_token(coap_session_t *session, size_t len,
1218 const uint8_t *data) {
1219 session->tx_token = coap_decode_var_bytes8(data, len);
1220 }
1221
coap_session_new_token(coap_session_t * session,size_t * len,uint8_t * data)1222 void coap_session_new_token(coap_session_t *session, size_t *len,
1223 uint8_t *data) {
1224 *len = coap_encode_var_safe8(data,
1225 sizeof(session->tx_token), ++session->tx_token);
1226 }
1227
1228 uint16_t
coap_new_message_id(coap_session_t * session)1229 coap_new_message_id(coap_session_t *session) {
1230 return ++session->tx_mid;
1231 }
1232
1233 const coap_address_t *
coap_session_get_addr_remote(const coap_session_t * session)1234 coap_session_get_addr_remote(const coap_session_t *session) {
1235 if (session)
1236 return &session->addr_info.remote;
1237 return NULL;
1238 }
1239
1240 const coap_address_t *
coap_session_get_addr_local(const coap_session_t * session)1241 coap_session_get_addr_local(const coap_session_t *session) {
1242 if (session)
1243 return &session->addr_info.local;
1244 return NULL;
1245 }
1246
1247 coap_context_t *
coap_session_get_context(const coap_session_t * session)1248 coap_session_get_context(const coap_session_t *session) {
1249 if (session)
1250 return session->context;
1251 return NULL;
1252 }
1253
1254 coap_proto_t
coap_session_get_proto(const coap_session_t * session)1255 coap_session_get_proto(const coap_session_t *session) {
1256 if (session)
1257 return session->proto;
1258 return 0;
1259 }
1260
1261 coap_session_type_t
coap_session_get_type(const coap_session_t * session)1262 coap_session_get_type(const coap_session_t *session) {
1263 if (session)
1264 return session->type;
1265 return 0;
1266 }
1267
1268 int
coap_session_set_type_client(coap_session_t * session)1269 coap_session_set_type_client(coap_session_t *session) {
1270 if (session && session->type == COAP_SESSION_TYPE_SERVER) {
1271 coap_session_reference(session);
1272 session->type = COAP_SESSION_TYPE_CLIENT;
1273 return 1;
1274 }
1275 return 0;
1276 }
1277
1278 coap_session_state_t
coap_session_get_state(const coap_session_t * session)1279 coap_session_get_state(const coap_session_t *session) {
1280 if (session)
1281 return session->state;
1282 return 0;
1283 }
1284
coap_session_get_ifindex(const coap_session_t * session)1285 int coap_session_get_ifindex(const coap_session_t *session) {
1286 if (session)
1287 return session->ifindex;
1288 return -1;
1289 }
1290
coap_session_get_tls(const coap_session_t * session,coap_tls_library_t * tls_lib)1291 void *coap_session_get_tls(const coap_session_t *session,
1292 coap_tls_library_t *tls_lib) {
1293 if (session)
1294 return coap_dtls_get_tls(session, tls_lib);
1295 return NULL;
1296 }
1297
1298 #ifndef WITH_LWIP
1299 coap_endpoint_t *
coap_new_endpoint(coap_context_t * context,const coap_address_t * listen_addr,coap_proto_t proto)1300 coap_new_endpoint(coap_context_t *context, const coap_address_t *listen_addr, coap_proto_t proto) {
1301 coap_endpoint_t *ep = NULL;
1302
1303 assert(context);
1304 assert(listen_addr);
1305 assert(proto != COAP_PROTO_NONE);
1306
1307 if (proto == COAP_PROTO_DTLS && !coap_dtls_is_supported()) {
1308 coap_log(LOG_CRIT, "coap_new_endpoint: DTLS not supported\n");
1309 goto error;
1310 }
1311
1312 if (proto == COAP_PROTO_TLS && !coap_tls_is_supported()) {
1313 coap_log(LOG_CRIT, "coap_new_endpoint: TLS not supported\n");
1314 goto error;
1315 }
1316
1317 if (proto == COAP_PROTO_TCP && !coap_tcp_is_supported()) {
1318 coap_log(LOG_CRIT, "coap_new_endpoint: TCP not supported\n");
1319 goto error;
1320 }
1321
1322 if (proto == COAP_PROTO_DTLS || proto == COAP_PROTO_TLS) {
1323 if (!coap_dtls_context_check_keys_enabled(context)) {
1324 coap_log(LOG_INFO,
1325 "coap_new_endpoint: one of coap_context_set_psk() or "
1326 "coap_context_set_pki() not called\n");
1327 goto error;
1328 }
1329 }
1330
1331 ep = coap_malloc_endpoint();
1332 if (!ep) {
1333 coap_log(LOG_WARNING, "coap_new_endpoint: malloc");
1334 goto error;
1335 }
1336
1337 memset(ep, 0, sizeof(coap_endpoint_t));
1338 ep->context = context;
1339 ep->proto = proto;
1340
1341 if (proto==COAP_PROTO_UDP || proto==COAP_PROTO_DTLS) {
1342 if (!coap_socket_bind_udp(&ep->sock, listen_addr, &ep->bind_addr))
1343 goto error;
1344 ep->sock.flags |= COAP_SOCKET_WANT_READ;
1345 #if !COAP_DISABLE_TCP
1346 } else if (proto==COAP_PROTO_TCP || proto==COAP_PROTO_TLS) {
1347 if (!coap_socket_bind_tcp(&ep->sock, listen_addr, &ep->bind_addr))
1348 goto error;
1349 ep->sock.flags |= COAP_SOCKET_WANT_ACCEPT;
1350 #endif /* !COAP_DISABLE_TCP */
1351 } else {
1352 coap_log(LOG_CRIT, "coap_new_endpoint: protocol not supported\n");
1353 goto error;
1354 }
1355
1356 if (LOG_DEBUG <= coap_get_log_level()) {
1357 #ifndef INET6_ADDRSTRLEN
1358 #define INET6_ADDRSTRLEN 40
1359 #endif
1360 unsigned char addr_str[INET6_ADDRSTRLEN + 8];
1361
1362 if (coap_print_addr(&ep->bind_addr, addr_str, INET6_ADDRSTRLEN + 8)) {
1363 coap_log(LOG_DEBUG, "created %s endpoint %s\n",
1364 ep->proto == COAP_PROTO_TLS ? "TLS "
1365 : ep->proto == COAP_PROTO_TCP ? "TCP "
1366 : ep->proto == COAP_PROTO_DTLS ? "DTLS" : "UDP ",
1367 addr_str);
1368 }
1369 }
1370
1371 ep->sock.flags |= COAP_SOCKET_NOT_EMPTY | COAP_SOCKET_BOUND;
1372
1373 ep->default_mtu = COAP_DEFAULT_MTU;
1374
1375 #ifdef COAP_EPOLL_SUPPORT
1376 ep->sock.endpoint = ep;
1377 coap_epoll_ctl_add(&ep->sock,
1378 EPOLLIN,
1379 __func__);
1380 #endif /* COAP_EPOLL_SUPPORT */
1381
1382 LL_PREPEND(context->endpoint, ep);
1383 return ep;
1384
1385 error:
1386 coap_free_endpoint(ep);
1387 return NULL;
1388 }
1389
coap_endpoint_set_default_mtu(coap_endpoint_t * ep,unsigned mtu)1390 void coap_endpoint_set_default_mtu(coap_endpoint_t *ep, unsigned mtu) {
1391 ep->default_mtu = (uint16_t)mtu;
1392 }
1393
1394 void
coap_free_endpoint(coap_endpoint_t * ep)1395 coap_free_endpoint(coap_endpoint_t *ep) {
1396 if (ep) {
1397 coap_session_t *session, *rtmp;
1398
1399 SESSIONS_ITER_SAFE(ep->sessions, session, rtmp) {
1400 assert(session->ref == 0);
1401 if (session->ref == 0) {
1402 coap_session_free(session);
1403 }
1404 }
1405 if (ep->sock.flags != COAP_SOCKET_EMPTY) {
1406 /*
1407 * ep->sock.endpoint is set in coap_new_endpoint().
1408 * ep->sock.session is never set.
1409 *
1410 * session->sock.session is set for both clients and servers (when a
1411 * new session is accepted), but does not affect the endpoint.
1412 *
1413 * So, it is safe to call coap_socket_close() after all the sessions
1414 * have been freed above as we are only working with the endpoint sock.
1415 */
1416 #ifdef COAP_EPOLL_SUPPORT
1417 assert(ep->sock.session == NULL);
1418 #endif /* COAP_EPOLL_SUPPORT */
1419 coap_socket_close(&ep->sock);
1420 }
1421
1422 if (ep->context && ep->context->endpoint) {
1423 LL_DELETE(ep->context->endpoint, ep);
1424 }
1425 coap_mfree_endpoint(ep);
1426 }
1427 }
1428 #endif /* WITH_LWIP */
1429
1430 coap_session_t *
coap_session_get_by_peer(const coap_context_t * ctx,const coap_address_t * remote_addr,int ifindex)1431 coap_session_get_by_peer(const coap_context_t *ctx,
1432 const coap_address_t *remote_addr,
1433 int ifindex) {
1434 coap_session_t *s, *rtmp;
1435 coap_endpoint_t *ep;
1436 SESSIONS_ITER(ctx->sessions, s, rtmp) {
1437 if (s->ifindex == ifindex && coap_address_equals(&s->addr_info.remote,
1438 remote_addr))
1439 return s;
1440 }
1441 LL_FOREACH(ctx->endpoint, ep) {
1442 SESSIONS_ITER(ep->sessions, s, rtmp) {
1443 if (s->ifindex == ifindex && coap_address_equals(&s->addr_info.remote,
1444 remote_addr))
1445 return s;
1446 }
1447 }
1448 return NULL;
1449 }
1450
coap_session_str(const coap_session_t * session)1451 const char *coap_session_str(const coap_session_t *session) {
1452 static char szSession[2 * (INET6_ADDRSTRLEN + 8) + 24];
1453 char *p = szSession, *end = szSession + sizeof(szSession);
1454 if (coap_print_addr(&session->addr_info.local,
1455 (unsigned char*)p, end - p) > 0)
1456 p += strlen(p);
1457 if (p + 6 < end) {
1458 strcpy(p, " <-> ");
1459 p += 5;
1460 }
1461 if (p + 1 < end) {
1462 if (coap_print_addr(&session->addr_info.remote,
1463 (unsigned char*)p, end - p) > 0)
1464 p += strlen(p);
1465 }
1466 if (session->ifindex > 0 && p + 1 < end)
1467 p += snprintf(p, end - p, " (if%d)", session->ifindex);
1468 if (p + 6 < end) {
1469 if (session->proto == COAP_PROTO_UDP) {
1470 strcpy(p, " UDP ");
1471 p += 4;
1472 } else if (session->proto == COAP_PROTO_DTLS) {
1473 strcpy(p, " DTLS");
1474 p += 5;
1475 } else if (session->proto == COAP_PROTO_TCP) {
1476 strcpy(p, " TCP ");
1477 p += 4;
1478 } else if (session->proto == COAP_PROTO_TLS) {
1479 strcpy(p, " TLS ");
1480 p += 4;
1481 } else {
1482 strcpy(p, " NONE");
1483 p += 5;
1484 }
1485 }
1486
1487 return szSession;
1488 }
1489
coap_endpoint_str(const coap_endpoint_t * endpoint)1490 const char *coap_endpoint_str(const coap_endpoint_t *endpoint) {
1491 static char szEndpoint[128];
1492 char *p = szEndpoint, *end = szEndpoint + sizeof(szEndpoint);
1493 if (coap_print_addr(&endpoint->bind_addr, (unsigned char*)p, end - p) > 0)
1494 p += strlen(p);
1495 if (p + 6 < end) {
1496 if (endpoint->proto == COAP_PROTO_UDP) {
1497 strcpy(p, " UDP");
1498 p += 4;
1499 } else if (endpoint->proto == COAP_PROTO_DTLS) {
1500 strcpy(p, " DTLS");
1501 p += 5;
1502 } else {
1503 strcpy(p, " NONE");
1504 p += 5;
1505 }
1506 }
1507
1508 return szEndpoint;
1509 }
1510
1511 #endif /* COAP_SESSION_C_ */
1512