1 /* coap_session.c -- Session management for libcoap
2 *
3 * Copyright (C) 2017 Jean-Claue Michelou <jcm@spinetix.com>
4 * Copyright (C) 2022-2023 Jon Shallow <supjps-libcoap@jpshallow.com>
5 *
6 * SPDX-License-Identifier: BSD-2-Clause
7 *
8 * This file is part of the CoAP library libcoap. Please see
9 * README for terms of use.
10 */
11
12 /**
13 * @file coap_session.c
14 * @brief Session handling functions
15 */
16
17 #include "coap3/coap_internal.h"
18
19 #ifndef COAP_SESSION_C_
20 #define COAP_SESSION_C_
21
22 #include <stdio.h>
23
24 #ifdef COAP_EPOLL_SUPPORT
25 #include <sys/epoll.h>
26 #include <sys/timerfd.h>
27 #endif /* COAP_EPOLL_SUPPORT */
28
29 #ifndef _WIN32
30 #include <unistd.h>
31 #include <sys/ioctl.h>
32 #include <net/if.h>
33 #include <arpa/inet.h>
34 #else
35 #include <Iphlpapi.h>
36 #endif /* !(_WIN32) */
37
38 #ifdef COAP_SUPPORT_SOCKET_BROADCAST
39 #ifndef _WIN32
40
loopback_packet_check(const char * src_buf)41 static int32_t loopback_packet_check(const char *src_buf) {
42 const char addr_perface[] = "::ffff:";
43 char tmp_buf[INET6_ADDRSTRLEN] = {0};
44 int ret;
45 void *tmp_addr_ptr = NULL;
46 struct ifreq buf[COAP_INTERFACE_MAX];
47 struct ifconf ifc = {0};
48
49 int fd = socket(AF_INET, SOCK_DGRAM, 0);
50 if (fd < 0) {
51 coap_log_debug("socket fail\n");
52 return 1;
53 }
54 ifc.ifc_len = sizeof(buf);
55 ifc.ifc_buf = (char *)buf;
56 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0) {
57 coap_log_debug("ioctl fail, errno = %d\n", errno);
58 goto L_IS_LOOPBACK;
59 }
60 int interface_num = ifc.ifc_len / sizeof(struct ifreq);
61 for (int i = 0; i < interface_num && i < COAP_INTERFACE_MAX; i++) {
62 coap_log_debug("interface name: %s\n", buf[i].ifr_name);
63 if (ioctl(fd, SIOCGIFADDR, (char *)&buf[i]) < 0) {
64 coap_log_debug("ioctl fail, errno = %d\n", errno);
65 goto L_IS_LOOPBACK;
66 }
67 tmp_addr_ptr = &((struct sockaddr_in *)&(buf[i].ifr_addr))->sin_addr;
68 inet_ntop(AF_INET, tmp_addr_ptr, tmp_buf, INET_ADDRSTRLEN);
69 if (memcmp(src_buf, addr_perface, strlen(addr_perface)) == 0 &&
70 strlen(src_buf) == strlen(tmp_buf) + strlen(addr_perface)) {
71 ret = memcmp(src_buf + strlen(addr_perface), tmp_buf, strlen(src_buf) - strlen(addr_perface));
72 } else {
73 if (strlen(src_buf) == strlen(tmp_buf)) {
74 ret = memcmp(src_buf, tmp_buf, strlen(src_buf));
75 } else {
76 ret = 1;
77 }
78 }
79 if (ret == 0) {
80 goto L_IS_LOOPBACK;
81 }
82 }
83 close(fd);
84 return 0;
85 L_IS_LOOPBACK:
86 close(fd);
87 return 1;
88 }
89 #else
loopback_packet_compare_ip(const char * src_buf,const char * addr_perface,const char * tmp_buf)90 static int loopback_packet_compare_ip(const char *src_buf, const char *addr_perface, const char *tmp_buf) {
91 int ret;
92 if (memcmp(src_buf, addr_perface, strlen(addr_perface)) == 0 &&
93 strlen(src_buf) == strlen(tmp_buf) + strlen(addr_perface)) {
94 ret = memcmp(src_buf + strlen(addr_perface), tmp_buf, strlen(src_buf) - strlen(addr_perface));
95 } else {
96 if (strlen(src_buf) == strlen(tmp_buf)) {
97 ret = memcmp(src_buf, tmp_buf, strlen(src_buf));
98 } else {
99 ret = 1;
100 }
101 }
102 return ret;
103 }
104
loopback_packet_check(const char * src_buf)105 static int32_t loopback_packet_check(const char *src_buf) {
106 const char addr_perface[] = "::ffff:";
107 char tmp_buf[INET6_ADDRSTRLEN] = { 0 };
108 int ret;
109 IP_ADAPTER_INFO *adapter_info = NULL;
110 IP_ADAPTER_INFO *adapter = NULL;
111 ULONG adapter_info_len = sizeof(IP_ADAPTER_INFO);
112 adapter_info = (IP_ADAPTER_INFO *)malloc(adapter_info_len);
113 if (adapter_info == NULL) {
114 coap_log_err("adapter_info malloc failed\n");
115 return 1;
116 }
117 if (GetAdaptersInfo(adapter_info, &adapter_info_len) == ERROR_BUFFER_OVERFLOW) {
118 free(adapter_info);
119 adapter_info = (IP_ADAPTER_INFO *)malloc(adapter_info_len);
120 if (adapter_info == NULL) {
121 coap_log_err("adapter_info malloc failed\n");
122 return 1;
123 }
124 }
125 int32_t err = GetAdaptersInfo(adapter_info, &adapter_info_len);
126 if (err != NO_ERROR) {
127 coap_log_err("GetAdaptersInfo failed with error: %d\n", err);
128 goto L_IS_LOOPBACK;
129 }
130 adapter = adapter_info;
131 while (adapter != NULL) {
132 PIP_ADDR_STRING pip_addr = &adapter->IpAddressList;
133 while (pip_addr != NULL) {
134 if (strcpy_s(tmp_buf, INET6_ADDRSTRLEN, pip_addr->IpAddress.String) != 0) {
135 goto L_IS_LOOPBACK;
136 }
137 ret = loopback_packet_compare_ip(src_buf, addr_perface, tmp_buf);
138 if (ret == 0) {
139 goto L_IS_LOOPBACK;
140 }
141 pip_addr = pip_addr->Next;
142 }
143 adapter = adapter->Next;
144 }
145 free(adapter_info);
146 return 0;
147 L_IS_LOOPBACK:
148 free(adapter_info);
149 return 1;
150 }
151 #endif /* END OF _WIN32 */
152
is_loopback_packet(const coap_packet_t * packet)153 static int32_t is_loopback_packet(const coap_packet_t *packet) {
154 char src_buf[INET6_ADDRSTRLEN] = {0};
155 coap_address_ntop(&(packet->addr_info.remote), src_buf, INET6_ADDRSTRLEN);
156 return loopback_packet_check(src_buf);
157 }
158 #endif /* END OF COAP_SUPPORT_SOCKET_BROADCAST */
159
160 coap_fixed_point_t
coap_multi_fixed_fixed(coap_fixed_point_t fp1,coap_fixed_point_t fp2)161 coap_multi_fixed_fixed(coap_fixed_point_t fp1, coap_fixed_point_t fp2) {
162 coap_fixed_point_t res;
163 uint32_t fr = fp1.fractional_part * fp2.fractional_part;
164
165 res.integer_part = fp1.integer_part * fp2.integer_part + fr/1000;
166 res.fractional_part = fr % 1000;
167 return res;
168 }
169
170 coap_fixed_point_t
coap_multi_fixed_uint(coap_fixed_point_t fp1,uint32_t u2)171 coap_multi_fixed_uint(coap_fixed_point_t fp1, uint32_t u2) {
172 coap_fixed_point_t res;
173 uint32_t fr = fp1.fractional_part * u2;
174
175 res.integer_part = fp1.integer_part * u2 + fr/1000;
176 res.fractional_part = fr % 1000;
177 return res;
178 }
179
180 coap_fixed_point_t
coap_add_fixed_fixed(coap_fixed_point_t fp1,coap_fixed_point_t fp2)181 coap_add_fixed_fixed(coap_fixed_point_t fp1, coap_fixed_point_t fp2) {
182 coap_fixed_point_t res;
183 uint32_t fr = fp1.fractional_part + fp2.fractional_part;
184
185 res.integer_part = fp1.integer_part + fp2.integer_part + fr/1000;
186 res.fractional_part = fr % 1000;
187 return res;
188 }
189
190 coap_fixed_point_t
coap_add_fixed_uint(coap_fixed_point_t fp1,uint32_t u2)191 coap_add_fixed_uint(coap_fixed_point_t fp1, uint32_t u2) {
192 coap_fixed_point_t res = fp1;
193
194 res.integer_part += u2;
195 return res;
196 }
197
198 coap_fixed_point_t
coap_sub_fixed_uint(coap_fixed_point_t fp1,uint32_t u2)199 coap_sub_fixed_uint(coap_fixed_point_t fp1, uint32_t u2) {
200 coap_fixed_point_t res = fp1;
201
202 res.integer_part -= u2;
203 return res;
204 }
205
206 coap_fixed_point_t
coap_div_fixed_uint(coap_fixed_point_t fp1,uint32_t u2)207 coap_div_fixed_uint(coap_fixed_point_t fp1, uint32_t u2) {
208 coap_fixed_point_t res;
209 uint32_t num = (fp1.integer_part * 1000 + fp1.fractional_part) / u2;
210
211 res.integer_part = num / 1000;
212 res.fractional_part = num % 1000;
213 return res;
214 }
215
216 #if COAP_Q_BLOCK_SUPPORT
217 coap_fixed_point_t
coap_get_non_timeout_random(coap_session_t * session)218 coap_get_non_timeout_random(coap_session_t *session) {
219 coap_fixed_point_t res;
220 uint8_t ran;
221
222 coap_prng(&ran, sizeof(ran));
223 res = coap_sub_fixed_uint(COAP_ACK_RANDOM_FACTOR(session), 1);
224 res = coap_multi_fixed_uint(res, ran);
225 res = coap_div_fixed_uint(res, 0xff);
226 res = coap_add_fixed_fixed(COAP_NON_TIMEOUT(session), res);
227 return res;
228 }
229
230 coap_tick_t
coap_get_non_timeout_random_ticks(coap_session_t * session)231 coap_get_non_timeout_random_ticks(coap_session_t *session) {
232 coap_fixed_point_t res = coap_get_non_timeout_random(session);
233 coap_tick_t ticks = (res.integer_part * COAP_TICKS_PER_SECOND +
234 res.fractional_part * COAP_TICKS_PER_SECOND / 1000);
235
236 return ticks;
237 }
238
239 /*
240 * Save away derived Congestion Control parameters for speed of access.
241 * They will get updated whenever a component variable is updated.
242 */
243
244 /*
245 * NON_PROBING_WAIT = NON_TIMEOUT * ((2 ** NON_MAX_RETRANSMIT) - 1) *
246 * ACK_RANDOM_FACTOR + (2 * MAX_LATENCY) + NON_TIMEOUT_RANDOM
247 *
248 * Do not include NON_TIMEOUT_RANDOM as that changes
249 */
250 static void
coap_session_fix_non_probing_wait_base(coap_session_t * s)251 coap_session_fix_non_probing_wait_base(coap_session_t *s) {
252 coap_fixed_point_t res;
253
254 res = coap_multi_fixed_uint(COAP_NON_TIMEOUT(s),
255 ((1 << (COAP_NON_MAX_RETRANSMIT(s) + 1)) -1));
256 res = coap_multi_fixed_fixed(res, COAP_ACK_RANDOM_FACTOR(s));
257 res = coap_add_fixed_uint(res, 2 * COAP_DEFAULT_MAX_LATENCY);
258 COAP_NON_PROBING_WAIT_BASE(s) = res;
259 }
260
261 /*
262 * NON_PARTIAL_TIMEOUT = NON_TIMEOUT * ((2 ** NON_MAX_RETRANSMIT) - 1) *
263 * ACK_RANDOM_FACTOR + (2 * MAX_LATENCY) + NON_TIMEOUT
264 */
265 static void
coap_session_fix_non_partial_timeout(coap_session_t * s)266 coap_session_fix_non_partial_timeout(coap_session_t *s) {
267 coap_fixed_point_t res;
268
269 res = coap_multi_fixed_uint(COAP_NON_TIMEOUT(s),
270 ((1 << (COAP_NON_MAX_RETRANSMIT(s) + 1)) -1));
271 res = coap_multi_fixed_fixed(res, COAP_ACK_RANDOM_FACTOR(s));
272 res = coap_add_fixed_uint(res, 2 * COAP_DEFAULT_MAX_LATENCY);
273 res = coap_add_fixed_fixed(res, COAP_NON_TIMEOUT(s));
274 COAP_NON_PARTIAL_TIMEOUT(s) = res;
275 }
276 #endif /* COAP_Q_BLOCK_SUPPORT */
277
278 void
coap_session_set_ack_timeout(coap_session_t * session,coap_fixed_point_t value)279 coap_session_set_ack_timeout(coap_session_t *session, coap_fixed_point_t value) {
280 if (value.integer_part > 0 && value.fractional_part < 1000) {
281 session->ack_timeout = value;
282 coap_log_debug("***%s: session ack_timeout set to %u.%03u\n",
283 coap_session_str(session), session->ack_timeout.integer_part,
284 session->ack_timeout.fractional_part);
285 }
286 }
287
288 void
coap_session_set_ack_random_factor(coap_session_t * session,coap_fixed_point_t value)289 coap_session_set_ack_random_factor(coap_session_t *session,
290 coap_fixed_point_t value) {
291 if (value.integer_part > 0 && value.fractional_part < 1000) {
292 session->ack_random_factor = value;
293 coap_log_debug("***%s: session ack_random_factor set to %u.%03u\n",
294 coap_session_str(session), session->ack_random_factor.integer_part,
295 session->ack_random_factor.fractional_part);
296 #if COAP_Q_BLOCK_SUPPORT
297 coap_session_fix_non_probing_wait_base(session);
298 coap_session_fix_non_partial_timeout(session);
299 #endif /* COAP_Q_BLOCK_SUPPORT */
300 }
301 return;
302 }
303
304 void
coap_session_set_max_retransmit(coap_session_t * session,uint16_t value)305 coap_session_set_max_retransmit(coap_session_t *session, uint16_t value) {
306 if (value > 0) {
307 session->max_retransmit = value;
308 coap_log_debug("***%s: session max_retransmit set to %u\n",
309 coap_session_str(session), session->max_retransmit);
310 }
311 }
312
313 void
coap_session_set_nstart(coap_session_t * session,uint16_t value)314 coap_session_set_nstart(coap_session_t *session, uint16_t value) {
315 if (value > 0) {
316 session->nstart = value;
317 coap_log_debug("***%s: session nstart set to %u\n",
318 coap_session_str(session), session->nstart);
319 }
320 }
321
322 void
coap_session_set_default_leisure(coap_session_t * session,coap_fixed_point_t value)323 coap_session_set_default_leisure(coap_session_t *session,
324 coap_fixed_point_t value) {
325 if (value.integer_part > 0 && value.fractional_part < 1000) {
326 session->default_leisure = value;
327 coap_log_debug("***%s: session default_leisure set to %u.%03u\n",
328 coap_session_str(session), session->default_leisure.integer_part,
329 session->default_leisure.fractional_part);
330 }
331 }
332
333 void
coap_session_set_probing_rate(coap_session_t * session,uint32_t value)334 coap_session_set_probing_rate(coap_session_t *session, uint32_t value) {
335 if (value > 0) {
336 session->probing_rate = value;
337 coap_log_debug("***%s: session probing_rate set to %" PRIu32 "\n",
338 coap_session_str(session), session->probing_rate);
339 }
340 }
341
342 void
coap_session_set_max_payloads(coap_session_t * session,uint16_t value)343 coap_session_set_max_payloads(coap_session_t *session, uint16_t value) {
344 #if COAP_Q_BLOCK_SUPPORT
345 if (value > 0) {
346 session->max_payloads = value;
347 coap_log_debug("***%s: session max_payloads set to %u\n",
348 coap_session_str(session), session->max_payloads);
349 coap_session_fix_non_probing_wait_base(session);
350 coap_session_fix_non_partial_timeout(session);
351 }
352 #else /* ! COAP_Q_BLOCK_SUPPORT */
353 (void)session;
354 (void)value;
355 #endif /* ! COAP_Q_BLOCK_SUPPORT */
356 }
357
358 void
coap_session_set_non_max_retransmit(coap_session_t * session,uint16_t value)359 coap_session_set_non_max_retransmit(coap_session_t *session, uint16_t value) {
360 #if COAP_Q_BLOCK_SUPPORT
361 if (value > 0) {
362 session->non_max_retransmit = value;
363 coap_log_debug("***%s: session non_max_retransmit set to %u\n",
364 coap_session_str(session), session->non_max_retransmit);
365 coap_session_fix_non_probing_wait_base(session);
366 coap_session_fix_non_partial_timeout(session);
367 }
368 #else /* ! COAP_Q_BLOCK_SUPPORT */
369 (void)session;
370 (void)value;
371 #endif /* ! COAP_Q_BLOCK_SUPPORT */
372 }
373
374 void
coap_session_set_non_timeout(coap_session_t * session,coap_fixed_point_t value)375 coap_session_set_non_timeout(coap_session_t *session,
376 coap_fixed_point_t value) {
377 #if COAP_Q_BLOCK_SUPPORT
378 if (value.integer_part > 0 && value.fractional_part < 1000) {
379 session->non_timeout = value;
380 coap_log_debug("***%s: session non_timeout set to %u.%03u\n",
381 coap_session_str(session), session->non_timeout.integer_part,
382 session->non_timeout.fractional_part);
383 coap_session_fix_non_probing_wait_base(session);
384 coap_session_fix_non_partial_timeout(session);
385 }
386 #else /* ! COAP_Q_BLOCK_SUPPORT */
387 (void)session;
388 (void)value;
389 #endif /* ! COAP_Q_BLOCK_SUPPORT */
390 }
391
392 void
coap_session_set_non_receive_timeout(coap_session_t * session,coap_fixed_point_t value)393 coap_session_set_non_receive_timeout(coap_session_t *session,
394 coap_fixed_point_t value) {
395 #if COAP_Q_BLOCK_SUPPORT
396 if (value.integer_part > 0 && value.fractional_part < 1000)
397 session->non_receive_timeout = value;
398 coap_log_debug("***%s: session non_receive_timeout set to %u.%03u\n",
399 coap_session_str(session),
400 session->non_receive_timeout.integer_part,
401 session->non_receive_timeout.fractional_part);
402 #else /* ! COAP_Q_BLOCK_SUPPORT */
403 (void)session;
404 (void)value;
405 #endif /* ! COAP_Q_BLOCK_SUPPORT */
406 }
407
408 coap_fixed_point_t
coap_session_get_ack_timeout(const coap_session_t * session)409 coap_session_get_ack_timeout(const coap_session_t *session) {
410 return session->ack_timeout;
411 }
412
413 coap_fixed_point_t
coap_session_get_ack_random_factor(const coap_session_t * session)414 coap_session_get_ack_random_factor(const coap_session_t *session) {
415 return session->ack_random_factor;
416 }
417
418 uint16_t
coap_session_get_max_retransmit(const coap_session_t * session)419 coap_session_get_max_retransmit(const coap_session_t *session) {
420 return session->max_retransmit;
421 }
422
423 uint16_t
coap_session_get_nstart(const coap_session_t * session)424 coap_session_get_nstart(const coap_session_t *session) {
425 return session->nstart;
426 }
427
428 coap_fixed_point_t
coap_session_get_default_leisure(const coap_session_t * session)429 coap_session_get_default_leisure(const coap_session_t *session) {
430 return session->default_leisure;
431 }
432
433 uint32_t
coap_session_get_probing_rate(const coap_session_t * session)434 coap_session_get_probing_rate(const coap_session_t *session) {
435 return session->probing_rate;
436 }
437
438 uint16_t
coap_session_get_max_payloads(const coap_session_t * session)439 coap_session_get_max_payloads(const coap_session_t *session) {
440 #if COAP_Q_BLOCK_SUPPORT
441 return session->max_payloads;
442 #else /* ! COAP_Q_BLOCK_SUPPORT */
443 (void)session;
444 return COAP_DEFAULT_MAX_PAYLOADS;
445 #endif /* ! COAP_Q_BLOCK_SUPPORT */
446 }
447
448 uint16_t
coap_session_get_non_max_retransmit(const coap_session_t * session)449 coap_session_get_non_max_retransmit(const coap_session_t *session) {
450 #if COAP_Q_BLOCK_SUPPORT
451 return session->non_max_retransmit;
452 #else /* ! COAP_Q_BLOCK_SUPPORT */
453 (void)session;
454 return COAP_DEFAULT_NON_MAX_RETRANSMIT;
455 #endif /* ! COAP_Q_BLOCK_SUPPORT */
456 }
457
458 coap_fixed_point_t
coap_session_get_non_timeout(const coap_session_t * session)459 coap_session_get_non_timeout(const coap_session_t *session) {
460 #if COAP_Q_BLOCK_SUPPORT
461 return session->non_timeout;
462 #else /* ! COAP_Q_BLOCK_SUPPORT */
463 (void)session;
464 return COAP_DEFAULT_NON_TIMEOUT;
465 #endif /* ! COAP_Q_BLOCK_SUPPORT */
466 }
467
468 coap_fixed_point_t
coap_session_get_non_receive_timeout(const coap_session_t * session)469 coap_session_get_non_receive_timeout(const coap_session_t *session) {
470 #if COAP_Q_BLOCK_SUPPORT
471 return session->non_receive_timeout;
472 #else /* ! COAP_Q_BLOCK_SUPPORT */
473 (void)session;
474 return COAP_DEFAULT_NON_RECEIVE_TIMEOUT;
475 #endif /* ! COAP_Q_BLOCK_SUPPORT */
476 }
477
478 coap_session_t *
coap_session_reference(coap_session_t * session)479 coap_session_reference(coap_session_t *session) {
480 ++session->ref;
481 return session;
482 }
483
484 void
coap_session_release(coap_session_t * session)485 coap_session_release(coap_session_t *session) {
486 if (session) {
487 #ifndef __COVERITY__
488 assert(session->ref > 0);
489 if (session->ref > 0)
490 --session->ref;
491 if (session->ref == 0 && session->type == COAP_SESSION_TYPE_CLIENT)
492 coap_session_free(session);
493 #else /* __COVERITY__ */
494 /* Coverity scan is fooled by the reference counter leading to
495 * false positives for USE_AFTER_FREE. */
496 --session->ref;
497 __coverity_negative_sink__(session->ref);
498 /* Indicate that resources are released properly. */
499 if (session->ref == 0 && session->type == COAP_SESSION_TYPE_CLIENT) {
500 __coverity_free__(session);
501 }
502 #endif /* __COVERITY__ */
503 }
504 }
505
506 void
coap_session_set_app_data(coap_session_t * session,void * app_data)507 coap_session_set_app_data(coap_session_t *session, void *app_data) {
508 assert(session);
509 session->app = app_data;
510 }
511
512 void *
coap_session_get_app_data(const coap_session_t * session)513 coap_session_get_app_data(const coap_session_t *session) {
514 assert(session);
515 return session->app;
516 }
517
518 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)519 coap_make_session(coap_proto_t proto, coap_session_type_t type,
520 const coap_addr_hash_t *addr_hash,
521 const coap_address_t *local_addr,
522 const coap_address_t *remote_addr, int ifindex,
523 coap_context_t *context, coap_endpoint_t *endpoint) {
524 coap_session_t *session = (coap_session_t *)coap_malloc_type(COAP_SESSION,
525 sizeof(coap_session_t));
526 #if ! COAP_SERVER_SUPPORT
527 (void)endpoint;
528 #endif /* ! COAP_SERVER_SUPPORT */
529 if (!session)
530 return NULL;
531 memset(session, 0, sizeof(*session));
532 session->proto = proto;
533 session->type = type;
534 if (addr_hash)
535 memcpy(&session->addr_hash, addr_hash, sizeof(session->addr_hash));
536 else
537 memset(&session->addr_hash, 0, sizeof(session->addr_hash));
538 if (local_addr)
539 coap_address_copy(&session->addr_info.local, local_addr);
540 else
541 coap_address_init(&session->addr_info.local);
542 if (remote_addr)
543 coap_address_copy(&session->addr_info.remote, remote_addr);
544 else
545 coap_address_init(&session->addr_info.remote);
546 session->ifindex = ifindex;
547 session->context = context;
548 #if COAP_SERVER_SUPPORT
549 session->endpoint = endpoint;
550 if (endpoint)
551 session->mtu = endpoint->default_mtu;
552 else
553 #endif /* COAP_SERVER_SUPPORT */
554 session->mtu = COAP_DEFAULT_MTU;
555 session->block_mode = context->block_mode;
556 if (proto == COAP_PROTO_DTLS) {
557 session->tls_overhead = 29;
558 if (session->tls_overhead >= session->mtu) {
559 session->tls_overhead = session->mtu;
560 coap_log_err("DTLS overhead exceeds MTU\n");
561 }
562 }
563 session->ack_timeout = COAP_DEFAULT_ACK_TIMEOUT;
564 session->ack_random_factor = COAP_DEFAULT_ACK_RANDOM_FACTOR;
565 session->max_retransmit = COAP_DEFAULT_MAX_RETRANSMIT;
566 session->nstart = COAP_DEFAULT_NSTART;
567 session->default_leisure = COAP_DEFAULT_DEFAULT_LEISURE;
568 session->probing_rate = COAP_DEFAULT_PROBING_RATE;
569 #if COAP_Q_BLOCK_SUPPORT
570 session->max_payloads = COAP_DEFAULT_MAX_PAYLOADS;
571 session->non_max_retransmit = COAP_DEFAULT_NON_MAX_RETRANSMIT;
572 session->non_timeout = COAP_DEFAULT_NON_TIMEOUT;
573 session->non_receive_timeout = COAP_DEFAULT_NON_RECEIVE_TIMEOUT;
574 coap_session_fix_non_probing_wait_base(session);
575 coap_session_fix_non_partial_timeout(session);
576 #endif /* COAP_Q_BLOCK_SUPPORT */
577 session->dtls_event = -1;
578 session->last_ping_mid = COAP_INVALID_MID;
579 session->last_ack_mid = COAP_INVALID_MID;
580 session->last_con_mid = COAP_INVALID_MID;
581 session->max_token_size = context->max_token_size; /* RFC8974 */
582 if (session->type != COAP_SESSION_TYPE_CLIENT)
583 session->max_token_checked = COAP_EXT_T_CHECKED;
584
585 /* Randomly initialize */
586 /* TCP/TLS have no notion of mid */
587 if (COAP_PROTO_NOT_RELIABLE(session->proto))
588 coap_prng((unsigned char *)&session->tx_mid, sizeof(session->tx_mid));
589 coap_prng((unsigned char *)&session->tx_rtag, sizeof(session->tx_rtag));
590
591 return session;
592 }
593
594 void
coap_session_mfree(coap_session_t * session)595 coap_session_mfree(coap_session_t *session) {
596 coap_queue_t *q, *tmp;
597 coap_lg_xmit_t *lq, *ltmp;
598
599 #if COAP_CLIENT_SUPPORT
600 coap_lg_crcv_t *lg_crcv, *etmp;
601
602 /* Need to do this before (D)TLS and socket is closed down */
603 LL_FOREACH_SAFE(session->lg_crcv, lg_crcv, etmp) {
604 if (lg_crcv->observe_set && session->no_observe_cancel == 0) {
605 /* Need to close down observe */
606 if (coap_cancel_observe(session, lg_crcv->app_token, COAP_MESSAGE_NON)) {
607 /* Need to delete node we set up for NON */
608 coap_queue_t *queue = session->context->sendqueue;
609
610 while (queue) {
611 if (queue->session == session) {
612 coap_delete_node(queue);
613 break;
614 }
615 queue = queue->next;
616 }
617 }
618 }
619 LL_DELETE(session->lg_crcv, lg_crcv);
620 coap_block_delete_lg_crcv(session, lg_crcv);
621 }
622 #endif /* COAP_CLIENT_SUPPORT */
623
624 if (session->partial_pdu)
625 coap_delete_pdu(session->partial_pdu);
626 session->sock.lfunc[COAP_LAYER_SESSION].l_close(session);
627 if (session->psk_identity)
628 coap_delete_bin_const(session->psk_identity);
629 if (session->psk_key)
630 coap_delete_bin_const(session->psk_key);
631 if (session->psk_hint)
632 coap_delete_bin_const(session->psk_hint);
633
634 #if COAP_SERVER_SUPPORT
635 coap_cache_entry_t *cp, *ctmp;
636 HASH_ITER(hh, session->context->cache, cp, ctmp) {
637 /* cp->session is NULL if not session based */
638 if (cp->session == session) {
639 coap_delete_cache_entry(session->context, cp);
640 }
641 }
642 #endif /* COAP_SERVER_SUPPORT */
643 LL_FOREACH_SAFE(session->delayqueue, q, tmp) {
644 if (q->pdu->type==COAP_MESSAGE_CON && session->context &&
645 session->context->nack_handler) {
646 coap_check_update_token(session, q->pdu);
647 session->context->nack_handler(session, q->pdu,
648 session->proto == COAP_PROTO_DTLS ?
649 COAP_NACK_TLS_FAILED : COAP_NACK_NOT_DELIVERABLE,
650 q->id);
651 }
652 coap_delete_node(q);
653 }
654 LL_FOREACH_SAFE(session->lg_xmit, lq, ltmp) {
655 LL_DELETE(session->lg_xmit, lq);
656 coap_block_delete_lg_xmit(session, lq);
657 }
658 #if COAP_SERVER_SUPPORT
659 coap_lg_srcv_t *sq, *stmp;
660
661 LL_FOREACH_SAFE(session->lg_srcv, sq, stmp) {
662 LL_DELETE(session->lg_srcv, sq);
663 coap_block_delete_lg_srcv(session, sq);
664 }
665 #endif /* COAP_SERVER_SUPPORT */
666 #if COAP_OSCORE_SUPPORT
667 coap_delete_oscore_associations(session);
668 #endif /* COAP_OSCORE_SUPPORT */
669 #if COAP_WS_SUPPORT
670 coap_free_type(COAP_STRING, session->ws);
671 coap_delete_str_const(session->ws_host);
672 #endif /* COAP_WS_SUPPORT */
673 }
674
675 void
coap_session_free(coap_session_t * session)676 coap_session_free(coap_session_t *session) {
677 if (!session)
678 return;
679 assert(session->ref == 0);
680 if (session->ref)
681 return;
682 /* Make sure nothing gets deleted under our feet */
683 coap_session_reference(session);
684 coap_session_mfree(session);
685 #if COAP_SERVER_SUPPORT
686 if (session->endpoint) {
687 if (session->endpoint->sessions)
688 SESSIONS_DELETE(session->endpoint->sessions, session);
689 } else
690 #endif /* COAP_SERVER_SUPPORT */
691 #if COAP_CLIENT_SUPPORT
692 if (session->context) {
693 if (session->context->sessions)
694 SESSIONS_DELETE(session->context->sessions, session);
695 }
696 #endif /* COAP_CLIENT_SUPPORT */
697 coap_delete_bin_const(session->last_token);
698 coap_log_debug("***%s: session %p: closed\n", coap_session_str(session),
699 (void *)session);
700
701 assert(session->ref == 1);
702 coap_free_type(COAP_SESSION, session);
703 }
704
705 static size_t
coap_session_max_pdu_size_internal(const coap_session_t * session,size_t max_with_header)706 coap_session_max_pdu_size_internal(const coap_session_t *session,
707 size_t max_with_header) {
708 #if COAP_DISABLE_TCP
709 (void)session;
710 return max_with_header > 4 ? max_with_header - 4 : 0;
711 #else /* !COAP_DISABLE_TCP */
712 if (COAP_PROTO_NOT_RELIABLE(session->proto))
713 return max_with_header > 4 ? max_with_header - 4 : 0;
714 /* we must assume there is no token to be on the safe side */
715 if (max_with_header <= 2)
716 return 0;
717 else if (max_with_header <= COAP_MAX_MESSAGE_SIZE_TCP0 + 2)
718 return max_with_header - 2;
719 else if (max_with_header <= COAP_MAX_MESSAGE_SIZE_TCP8 + 3)
720 return max_with_header - 3;
721 else if (max_with_header <= COAP_MAX_MESSAGE_SIZE_TCP16 + 4)
722 return max_with_header - 4;
723 else
724 return max_with_header - 6;
725 #endif /* !COAP_DISABLE_TCP */
726 }
727
728 size_t
coap_session_max_pdu_rcv_size(const coap_session_t * session)729 coap_session_max_pdu_rcv_size(const coap_session_t *session) {
730 if (session->csm_rcv_mtu)
731 return coap_session_max_pdu_size_internal(session,
732 (size_t)(session->csm_rcv_mtu));
733
734 return coap_session_max_pdu_size_internal(session,
735 (size_t)(session->mtu - session->tls_overhead));
736 }
737
738 size_t
coap_session_max_pdu_size(const coap_session_t * session)739 coap_session_max_pdu_size(const coap_session_t *session) {
740 size_t max_with_header;
741
742 #if COAP_CLIENT_SUPPORT
743 /*
744 * Delay if session->doing_first is set.
745 * E.g. Reliable and CSM not in yet for checking block support
746 */
747 coap_session_t *session_rw;
748
749 /*
750 * Need to do this to not get a compiler warning about const parameters
751 * but need to maintain source code backward compatibility
752 */
753 memcpy(&session_rw, &session, sizeof(session_rw));
754 if (coap_client_delay_first(session_rw) == 0) {
755 coap_log_debug("coap_client_delay_first: timeout\n");
756 /* Have to go with the defaults */
757 }
758 #endif /* COAP_CLIENT_SUPPORT */
759
760 max_with_header = (size_t)(session->mtu - session->tls_overhead);
761
762 return coap_session_max_pdu_size_internal(session, max_with_header);
763 }
764
765 void
coap_session_set_mtu(coap_session_t * session,unsigned mtu)766 coap_session_set_mtu(coap_session_t *session, unsigned mtu) {
767 #if defined(WITH_CONTIKI) || defined(WITH_LWIP)
768 if (mtu > COAP_DEFAULT_MAX_PDU_RX_SIZE)
769 mtu = COAP_DEFAULT_MAX_PDU_RX_SIZE;
770 #endif
771 if (mtu < 64)
772 mtu = 64;
773 session->mtu = mtu;
774 if (session->tls_overhead >= session->mtu) {
775 session->tls_overhead = session->mtu;
776 coap_log_err("DTLS overhead exceeds MTU\n");
777 }
778 }
779
780 ssize_t
coap_session_delay_pdu(coap_session_t * session,coap_pdu_t * pdu,coap_queue_t * node)781 coap_session_delay_pdu(coap_session_t *session, coap_pdu_t *pdu,
782 coap_queue_t *node) {
783 if (node) {
784 coap_queue_t *removed = NULL;
785 coap_remove_from_queue(&session->context->sendqueue, session, node->id, &removed);
786 assert(removed == node);
787 coap_session_release(node->session);
788 node->session = NULL;
789 node->t = 0;
790 } else {
791 if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
792 coap_queue_t *q = NULL;
793 /* Check same mid is not getting re-used in violation of RFC7252 */
794 LL_FOREACH(session->delayqueue, q) {
795 if (q->id == pdu->mid) {
796 coap_log_err("** %s: mid=0x%04x: already in-use - dropped\n",
797 coap_session_str(session), pdu->mid);
798 return COAP_INVALID_MID;
799 }
800 }
801 }
802 node = coap_new_node();
803 if (node == NULL)
804 return COAP_INVALID_MID;
805 node->id = pdu->mid;
806 node->pdu = pdu;
807 if (pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto)) {
808 uint8_t r;
809 coap_prng(&r, sizeof(r));
810 /* add timeout in range [ACK_TIMEOUT...ACK_TIMEOUT * ACK_RANDOM_FACTOR] */
811 node->timeout = coap_calc_timeout(session, r);
812 }
813 }
814 LL_APPEND(session->delayqueue, node);
815 coap_log_debug("** %s: mid=0x%04x: delayed\n",
816 coap_session_str(session), node->id);
817 return COAP_PDU_DELAYED;
818 }
819
820 #if !COAP_DISABLE_TCP
821 void
coap_session_send_csm(coap_session_t * session)822 coap_session_send_csm(coap_session_t *session) {
823 coap_pdu_t *pdu;
824 uint8_t buf[4];
825 assert(COAP_PROTO_RELIABLE(session->proto));
826 coap_log_debug("***%s: sending CSM\n", coap_session_str(session));
827 session->state = COAP_SESSION_STATE_CSM;
828 session->partial_write = 0;
829 if (session->mtu == 0)
830 session->mtu = COAP_DEFAULT_MTU; /* base value */
831 pdu = coap_pdu_init(COAP_MESSAGE_CON, COAP_SIGNALING_CODE_CSM, 0, 20);
832 if (pdu == NULL
833 || coap_add_option_internal(pdu, COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE,
834 coap_encode_var_safe(buf, sizeof(buf),
835 session->context->csm_max_message_size), buf) == 0
836 || coap_add_option_internal(pdu, COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER,
837 coap_encode_var_safe(buf, sizeof(buf),
838 0), buf) == 0
839 || (session->max_token_size > COAP_TOKEN_DEFAULT_MAX &&
840 coap_add_option_internal(pdu,
841 COAP_SIGNALING_OPTION_EXTENDED_TOKEN_LENGTH,
842 coap_encode_var_safe(buf, sizeof(buf),
843 session->max_token_size),
844 buf) == 0)
845 || coap_pdu_encode_header(pdu, session->proto) == 0
846 ) {
847 coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE);
848 } else {
849 ssize_t bytes_written;
850
851 pdu->session = session;
852 bytes_written = coap_session_send_pdu(session, pdu);
853 if (bytes_written != (ssize_t)pdu->used_size + pdu->hdr_size) {
854 coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE);
855 } else {
856 session->csm_rcv_mtu = session->context->csm_max_message_size;
857 if (session->csm_rcv_mtu > COAP_BERT_BASE)
858 session->csm_bert_loc_support = 1;
859 else
860 session->csm_bert_loc_support = 0;
861 }
862 }
863 if (pdu)
864 coap_delete_pdu(pdu);
865 }
866 #endif /* !COAP_DISABLE_TCP */
867
868 coap_mid_t
coap_session_send_ping(coap_session_t * session)869 coap_session_send_ping(coap_session_t *session) {
870 coap_pdu_t *ping = NULL;
871
872 if (session->state != COAP_SESSION_STATE_ESTABLISHED ||
873 session->con_active)
874 return COAP_INVALID_MID;
875 if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
876 uint16_t mid = coap_new_message_id(session);
877 ping = coap_pdu_init(COAP_MESSAGE_CON, 0, mid, 0);
878 }
879 #if !COAP_DISABLE_TCP
880 else {
881 ping = coap_pdu_init(COAP_MESSAGE_CON, COAP_SIGNALING_CODE_PING, 0, 1);
882 }
883 #endif /* !COAP_DISABLE_TCP */
884 if (!ping)
885 return COAP_INVALID_MID;
886 return coap_send_internal(session, ping);
887 }
888
889 void
coap_session_connected(coap_session_t * session)890 coap_session_connected(coap_session_t *session) {
891 if (session->state != COAP_SESSION_STATE_ESTABLISHED) {
892 coap_log_debug("***%s: session connected\n",
893 coap_session_str(session));
894 if (session->state == COAP_SESSION_STATE_CSM) {
895 coap_handle_event(session->context, COAP_EVENT_SESSION_CONNECTED, session);
896 if (session->doing_first)
897 session->doing_first = 0;
898 }
899 }
900
901 session->state = COAP_SESSION_STATE_ESTABLISHED;
902 session->partial_write = 0;
903
904 if (session->proto==COAP_PROTO_DTLS) {
905 session->tls_overhead = coap_dtls_get_overhead(session);
906 if (session->tls_overhead >= session->mtu) {
907 session->tls_overhead = session->mtu;
908 coap_log_err("DTLS overhead exceeds MTU\n");
909 }
910 }
911
912 while (session->delayqueue && session->state == COAP_SESSION_STATE_ESTABLISHED) {
913 ssize_t bytes_written;
914 coap_queue_t *q = session->delayqueue;
915 if (q->pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto)) {
916 if (session->con_active >= COAP_NSTART(session))
917 break;
918 session->con_active++;
919 }
920 /* Take entry off the queue */
921 session->delayqueue = q->next;
922 q->next = NULL;
923
924 coap_log_debug("** %s: mid=0x%04x: transmitted after delay\n",
925 coap_session_str(session), (int)q->pdu->mid);
926 bytes_written = coap_session_send_pdu(session, q->pdu);
927 if (q->pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto)) {
928 if (coap_wait_ack(session->context, session, q) >= 0)
929 q = NULL;
930 }
931 if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
932 if (q)
933 coap_delete_node(q);
934 if (bytes_written < 0)
935 break;
936 } else {
937 if (bytes_written <= 0 || (size_t)bytes_written < q->pdu->used_size + q->pdu->hdr_size) {
938 q->next = session->delayqueue;
939 session->delayqueue = q;
940 if (bytes_written > 0)
941 session->partial_write = (size_t)bytes_written;
942 break;
943 } else {
944 coap_delete_node(q);
945 }
946 }
947 }
948 }
949
950 #if COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_DEBUG
951 static const char *
coap_nack_name(coap_nack_reason_t reason)952 coap_nack_name(coap_nack_reason_t reason) {
953 switch (reason) {
954 case COAP_NACK_TOO_MANY_RETRIES:
955 return "COAP_NACK_TOO_MANY_RETRIES";
956 case COAP_NACK_NOT_DELIVERABLE:
957 return "COAP_NACK_NOT_DELIVERABLE";
958 case COAP_NACK_RST:
959 return "COAP_NACK_RST";
960 case COAP_NACK_TLS_FAILED:
961 return "COAP_NACK_TLS_FAILED";
962 case COAP_NACK_ICMP_ISSUE:
963 return "COAP_NACK_ICMP_ISSUE";
964 case COAP_NACK_BAD_RESPONSE:
965 return "COAP_NACK_BAD_RESPONSE";
966 case COAP_NACK_TLS_LAYER_FAILED:
967 return "COAP_NACK_TLS_LAYER_FAILED";
968 case COAP_NACK_WS_LAYER_FAILED:
969 return "COAP_NACK_WS_LAYER_FAILED";
970 case COAP_NACK_WS_FAILED:
971 return "COAP_NACK_WS_FAILED";
972 default:
973 return "???";
974 }
975 }
976 #endif /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_DEBUG */
977
978 void
coap_session_disconnected(coap_session_t * session,coap_nack_reason_t reason)979 coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason) {
980 #if !COAP_DISABLE_TCP
981 coap_session_state_t state = session->state;
982 #endif /* !COAP_DISABLE_TCP */
983 coap_lg_xmit_t *lq, *ltmp;
984 #if COAP_SERVER_SUPPORT
985 coap_lg_srcv_t *sq, *stmp;
986 #endif /* COAP_SERVER_SUPPORT */
987 #if COAP_CLIENT_SUPPORT
988 coap_lg_crcv_t *cq, *etmp;
989 #endif /* COAP_CLIENT_SUPPORT */
990
991 if (reason == COAP_NACK_ICMP_ISSUE) {
992 if (session->context->nack_handler) {
993 int sent_nack = 0;
994 coap_queue_t *q = session->context->sendqueue;
995 while (q) {
996 if (q->session == session) {
997 /* Take the first one */
998 coap_bin_const_t token = q->pdu->actual_token;
999
1000 coap_check_update_token(session, q->pdu);
1001 session->context->nack_handler(session, q->pdu, reason, q->id);
1002 coap_update_token(q->pdu, token.length, token.s);
1003 sent_nack = 1;
1004 break;
1005 }
1006 q = q->next;
1007 }
1008 #if COAP_CLIENT_SUPPORT
1009 if (!sent_nack && session->lg_crcv) {
1010 /* Take the first one */
1011 session->context->nack_handler(session, &session->lg_crcv->pdu, reason,
1012 session->lg_crcv->pdu.mid);
1013 sent_nack = 1;
1014 }
1015 #endif /* COAP_CLIENT_SUPPORT */
1016 if (!sent_nack) {
1017 /* Unable to determine which request ICMP issue was for */
1018 session->context->nack_handler(session, NULL, reason, 0);
1019 }
1020 }
1021 coap_log_debug("***%s: session issue (%s)\n",
1022 coap_session_str(session), coap_nack_name(reason));
1023 return;
1024 }
1025 coap_log_debug("***%s: session disconnected (%s)\n",
1026 coap_session_str(session), coap_nack_name(reason));
1027 #if COAP_SERVER_SUPPORT
1028 coap_delete_observers(session->context, session);
1029 #endif /* COAP_SERVER_SUPPORT */
1030
1031 if (session->proto == COAP_PROTO_UDP)
1032 session->state = COAP_SESSION_STATE_ESTABLISHED;
1033 else
1034 session->state = COAP_SESSION_STATE_NONE;
1035
1036 session->con_active = 0;
1037
1038 if (session->partial_pdu) {
1039 coap_delete_pdu(session->partial_pdu);
1040 session->partial_pdu = NULL;
1041 }
1042 session->partial_read = 0;
1043
1044 while (session->delayqueue) {
1045 coap_queue_t *q = session->delayqueue;
1046 session->delayqueue = q->next;
1047 q->next = NULL;
1048 coap_log_debug("** %s: mid=0x%04x: not transmitted after disconnect\n",
1049 coap_session_str(session), q->id);
1050 if (q && q->pdu->type == COAP_MESSAGE_CON
1051 && session->context->nack_handler) {
1052 coap_check_update_token(session, q->pdu);
1053 session->context->nack_handler(session, q->pdu, reason, q->id);
1054 }
1055 if (q)
1056 coap_delete_node(q);
1057 }
1058
1059 #if COAP_CLIENT_SUPPORT
1060 /* Need to do this before (D)TLS and socket is closed down */
1061 LL_FOREACH_SAFE(session->lg_crcv, cq, etmp) {
1062 LL_DELETE(session->lg_crcv, cq);
1063 coap_block_delete_lg_crcv(session, cq);
1064 }
1065 #endif /* COAP_CLIENT_SUPPORT */
1066 LL_FOREACH_SAFE(session->lg_xmit, lq, ltmp) {
1067 LL_DELETE(session->lg_xmit, lq);
1068 coap_block_delete_lg_xmit(session, lq);
1069 }
1070 #if COAP_SERVER_SUPPORT
1071 LL_FOREACH_SAFE(session->lg_srcv, sq, stmp) {
1072 LL_DELETE(session->lg_srcv, sq);
1073 coap_block_delete_lg_srcv(session, sq);
1074 }
1075 #endif /* COAP_SERVER_SUPPORT */
1076 coap_cancel_session_messages(session->context, session, reason);
1077
1078 #if !COAP_DISABLE_TCP
1079 if (COAP_PROTO_RELIABLE(session->proto)) {
1080 if (coap_netif_available(session)) {
1081 coap_handle_event(session->context,
1082 state == COAP_SESSION_STATE_CONNECTING ?
1083 COAP_EVENT_TCP_FAILED : COAP_EVENT_TCP_CLOSED, session);
1084 }
1085 if (state != COAP_SESSION_STATE_NONE) {
1086 coap_handle_event(session->context,
1087 state == COAP_SESSION_STATE_ESTABLISHED ?
1088 COAP_EVENT_SESSION_CLOSED : COAP_EVENT_SESSION_FAILED, session);
1089 }
1090 if (session->doing_first)
1091 session->doing_first = 0;
1092 }
1093 #endif /* !COAP_DISABLE_TCP */
1094 session->sock.lfunc[COAP_LAYER_SESSION].l_close(session);
1095 }
1096
1097 #if COAP_SERVER_SUPPORT
1098 static void
coap_make_addr_hash(coap_addr_hash_t * addr_hash,coap_proto_t proto,const coap_addr_tuple_t * addr_info)1099 coap_make_addr_hash(coap_addr_hash_t *addr_hash, coap_proto_t proto,
1100 const coap_addr_tuple_t *addr_info) {
1101 memset(addr_hash, 0, sizeof(coap_addr_hash_t));
1102 coap_address_copy(&addr_hash->remote, &addr_info->remote);
1103 addr_hash->lport = coap_address_get_port(&addr_info->local);
1104 addr_hash->proto = proto;
1105 }
1106
1107 coap_session_t *
coap_endpoint_get_session(coap_endpoint_t * endpoint,const coap_packet_t * packet,coap_tick_t now)1108 coap_endpoint_get_session(coap_endpoint_t *endpoint,
1109 const coap_packet_t *packet, coap_tick_t now) {
1110 coap_session_t *session;
1111 coap_session_t *rtmp;
1112 unsigned int num_idle = 0;
1113 unsigned int num_hs = 0;
1114 coap_session_t *oldest = NULL;
1115 coap_session_t *oldest_hs = NULL;
1116 coap_addr_hash_t addr_hash;
1117 #ifdef COAP_SUPPORT_SOCKET_BROADCAST
1118 if (is_loopback_packet(packet) == 1) {
1119 coap_log_debug("coap_endpoint_get_session: drop loopback packet");
1120 return NULL;
1121 }
1122 #endif
1123 coap_make_addr_hash(&addr_hash, endpoint->proto, &packet->addr_info);
1124 SESSIONS_FIND(endpoint->sessions, addr_hash, session);
1125 if (session) {
1126 /* Maybe mcast or unicast IP address which is not in the hash */
1127 coap_address_copy(&session->addr_info.local, &packet->addr_info.local);
1128 session->ifindex = packet->ifindex;
1129 session->last_rx_tx = now;
1130 return session;
1131 }
1132
1133 SESSIONS_ITER(endpoint->sessions, session, rtmp) {
1134 if (session->ref == 0 && session->delayqueue == NULL) {
1135 if (session->type == COAP_SESSION_TYPE_SERVER) {
1136 ++num_idle;
1137 if (oldest==NULL || session->last_rx_tx < oldest->last_rx_tx)
1138 oldest = session;
1139
1140 if (session->state == COAP_SESSION_STATE_HANDSHAKE) {
1141 ++num_hs;
1142 /* See if this is a partial (D)TLS session set up
1143 which needs to be cleared down to prevent DOS */
1144 if ((session->last_rx_tx + COAP_PARTIAL_SESSION_TIMEOUT_TICKS) < now) {
1145 if (oldest_hs == NULL ||
1146 session->last_rx_tx < oldest_hs->last_rx_tx)
1147 oldest_hs = session;
1148 }
1149 }
1150 } else if (session->type == COAP_SESSION_TYPE_HELLO) {
1151 ++num_hs;
1152 /* See if this is a partial (D)TLS session set up for Client Hello
1153 which needs to be cleared down to prevent DOS */
1154 if ((session->last_rx_tx + COAP_PARTIAL_SESSION_TIMEOUT_TICKS) < now) {
1155 if (oldest_hs == NULL ||
1156 session->last_rx_tx < oldest_hs->last_rx_tx)
1157 oldest_hs = session;
1158 }
1159 }
1160 }
1161 }
1162
1163 if (endpoint->context->max_idle_sessions > 0 &&
1164 num_idle >= endpoint->context->max_idle_sessions) {
1165 coap_handle_event(oldest->context, COAP_EVENT_SERVER_SESSION_DEL, oldest);
1166 coap_session_free(oldest);
1167 } else if (oldest_hs) {
1168 coap_log_warn("***%s: Incomplete session timed out\n",
1169 coap_session_str(oldest_hs));
1170 coap_handle_event(oldest_hs->context, COAP_EVENT_SERVER_SESSION_DEL, oldest_hs);
1171 coap_session_free(oldest_hs);
1172 }
1173
1174 if (num_hs > (endpoint->context->max_handshake_sessions ?
1175 endpoint->context->max_handshake_sessions :
1176 COAP_DEFAULT_MAX_HANDSHAKE_SESSIONS)) {
1177 /* Maxed out on number of sessions in (D)TLS negotiation state */
1178 coap_log_debug("Oustanding sessions in COAP_SESSION_STATE_HANDSHAKE too "
1179 "large. New request ignored\n");
1180 return NULL;
1181 }
1182
1183 if (endpoint->proto == COAP_PROTO_DTLS) {
1184 /*
1185 * Need to check that this actually is a Client Hello before wasting
1186 * time allocating and then freeing off session.
1187 */
1188
1189 /*
1190 * Generic header structure of the DTLS record layer.
1191 * typedef struct __attribute__((__packed__)) {
1192 * uint8_t content_type; content type of the included message
1193 * uint16_t version; Protocol version
1194 * uint16_t epoch; counter for cipher state changes
1195 * uint8_t sequence_number[6]; sequence number
1196 * uint16_t length; length of the following fragment
1197 * uint8_t handshake; If content_type == DTLS_CT_HANDSHAKE
1198 * } dtls_record_handshake_t;
1199 */
1200 #define OFF_CONTENT_TYPE 0 /* offset of content_type in dtls_record_handshake_t */
1201 #define DTLS_CT_ALERT 21 /* Content Type Alert */
1202 #define DTLS_CT_HANDSHAKE 22 /* Content Type Handshake */
1203 #define OFF_HANDSHAKE_TYPE 13 /* offset of handshake in dtls_record_handshake_t */
1204 #define DTLS_HT_CLIENT_HELLO 1 /* Client Hello handshake type */
1205
1206 const uint8_t *payload = (const uint8_t *)packet->payload;
1207 size_t length = packet->length;
1208 if (length < (OFF_HANDSHAKE_TYPE + 1)) {
1209 coap_log_debug("coap_dtls_hello: ContentType %d Short Packet (%zu < %d) dropped\n",
1210 payload[OFF_CONTENT_TYPE], length,
1211 OFF_HANDSHAKE_TYPE + 1);
1212 return NULL;
1213 }
1214 if (payload[OFF_CONTENT_TYPE] != DTLS_CT_HANDSHAKE ||
1215 payload[OFF_HANDSHAKE_TYPE] != DTLS_HT_CLIENT_HELLO) {
1216 /* only log if not a late alert */
1217 if (payload[OFF_CONTENT_TYPE] != DTLS_CT_ALERT)
1218 coap_log_debug("coap_dtls_hello: ContentType %d Handshake %d dropped\n",
1219 payload[OFF_CONTENT_TYPE], payload[OFF_HANDSHAKE_TYPE]);
1220 return NULL;
1221 }
1222 }
1223
1224 session = coap_make_session(endpoint->proto, COAP_SESSION_TYPE_SERVER,
1225 &addr_hash, &packet->addr_info.local,
1226 &packet->addr_info.remote,
1227 packet->ifindex, endpoint->context, endpoint);
1228 if (session) {
1229 session->last_rx_tx = now;
1230 memcpy(session->sock.lfunc, endpoint->sock.lfunc,
1231 sizeof(session->sock.lfunc));
1232 if (endpoint->proto == COAP_PROTO_UDP)
1233 session->state = COAP_SESSION_STATE_ESTABLISHED;
1234 else if (endpoint->proto == COAP_PROTO_DTLS) {
1235 session->type = COAP_SESSION_TYPE_HELLO;
1236 }
1237 SESSIONS_ADD(endpoint->sessions, session);
1238 coap_log_debug("***%s: session %p: new incoming session\n",
1239 coap_session_str(session), (void *)session);
1240 coap_handle_event(session->context, COAP_EVENT_SERVER_SESSION_NEW, session);
1241 }
1242 return session;
1243 }
1244
1245 coap_session_t *
coap_session_new_dtls_session(coap_session_t * session,coap_tick_t now)1246 coap_session_new_dtls_session(coap_session_t *session,
1247 coap_tick_t now) {
1248 if (session) {
1249 session->last_rx_tx = now;
1250 session->type = COAP_SESSION_TYPE_SERVER;
1251 coap_dtls_establish(session);
1252 }
1253 return session;
1254 }
1255 #endif /* COAP_SERVER_SUPPORT */
1256
1257 #if COAP_CLIENT_SUPPORT
1258 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)1259 coap_session_create_client(coap_context_t *ctx,
1260 const coap_address_t *local_if,
1261 const coap_address_t *server,
1262 coap_proto_t proto) {
1263 coap_session_t *session = NULL;
1264 int default_port = COAP_DEFAULT_PORT;
1265
1266 assert(server);
1267
1268 switch (proto) {
1269 case COAP_PROTO_UDP:
1270 default_port = COAP_DEFAULT_PORT;
1271 break;
1272 case COAP_PROTO_DTLS:
1273 if (!coap_dtls_is_supported()) {
1274 coap_log_crit("coap_new_client_session*: DTLS not supported\n");
1275 return NULL;
1276 }
1277 default_port = COAPS_DEFAULT_PORT;
1278 break;
1279 case COAP_PROTO_TCP:
1280 if (!coap_tcp_is_supported()) {
1281 coap_log_crit("coap_new_client_session*: TCP not supported\n");
1282 return NULL;
1283 }
1284 default_port = COAP_DEFAULT_PORT;
1285 break;
1286 case COAP_PROTO_TLS:
1287 if (!coap_tls_is_supported()) {
1288 coap_log_crit("coap_new_client_session*: TLS not supported\n");
1289 return NULL;
1290 }
1291 default_port = COAPS_DEFAULT_PORT;
1292 break;
1293 case COAP_PROTO_WS:
1294 if (!coap_ws_is_supported()) {
1295 coap_log_crit("coap_new_client_session*: WS not supported\n");
1296 return NULL;
1297 }
1298 default_port = 80;
1299 break;
1300 case COAP_PROTO_WSS:
1301 if (!coap_wss_is_supported()) {
1302 coap_log_crit("coap_new_client_session*: WSS not supported\n");
1303 return NULL;
1304 }
1305 default_port = 443;
1306 break;
1307 case COAP_PROTO_NONE:
1308 case COAP_PROTO_LAST:
1309 default:
1310 assert(0);
1311 return NULL;
1312 }
1313 session = coap_make_session(proto, COAP_SESSION_TYPE_CLIENT, NULL,
1314 local_if, server, 0, ctx, NULL);
1315 if (!session)
1316 goto error;
1317
1318 coap_session_reference(session);
1319 session->sock.session = session;
1320 memcpy(&session->sock.lfunc, coap_layers_coap[proto],
1321 sizeof(session->sock.lfunc));
1322
1323 if (COAP_PROTO_NOT_RELIABLE(proto)) {
1324 coap_session_t *s, *rtmp;
1325 if (!coap_netif_dgrm_connect(session, local_if, server, default_port)) {
1326 goto error;
1327 }
1328 /* Check that this is not a duplicate 4-tuple */
1329 SESSIONS_ITER_SAFE(ctx->sessions, s, rtmp) {
1330 if (COAP_PROTO_NOT_RELIABLE(s->proto) &&
1331 coap_address_equals(&session->addr_info.local,
1332 &s->addr_info.local) &&
1333 coap_address_equals(&session->addr_info.remote,
1334 &s->addr_info.remote)) {
1335 coap_log_warn("***%s: session %p: duplicate - already exists\n",
1336 coap_session_str(session), (void *)session);
1337 goto error;
1338 }
1339 }
1340 #ifdef WITH_CONTIKI
1341 session->sock.context = ctx;
1342 #endif /* WITH_CONTIKI */
1343 #if !COAP_DISABLE_TCP
1344 } else if (COAP_PROTO_RELIABLE(proto)) {
1345 if (!coap_netif_strm_connect1(session, local_if, server, default_port)) {
1346 goto error;
1347 }
1348 #endif /* !COAP_DISABLE_TCP */
1349 }
1350
1351 #ifdef COAP_EPOLL_SUPPORT
1352 session->sock.session = session;
1353 coap_epoll_ctl_add(&session->sock,
1354 EPOLLIN |
1355 ((session->sock.flags & COAP_SOCKET_WANT_CONNECT) ?
1356 EPOLLOUT : 0),
1357 __func__);
1358 #endif /* COAP_EPOLL_SUPPORT */
1359
1360 session->sock.flags |= COAP_SOCKET_NOT_EMPTY | COAP_SOCKET_WANT_READ;
1361 if (local_if)
1362 session->sock.flags |= COAP_SOCKET_BOUND;
1363 #if COAP_SERVER_SUPPORT
1364 if (ctx->proxy_uri_resource)
1365 session->proxy_session = 1;
1366 #endif /* COAP_SERVER_SUPPORT */
1367 SESSIONS_ADD(ctx->sessions, session);
1368 return session;
1369
1370 error:
1371 /*
1372 * Need to add in the session as coap_session_release()
1373 * will call SESSIONS_DELETE in coap_session_free().
1374 */
1375 if (session)
1376 SESSIONS_ADD(ctx->sessions, session);
1377 coap_session_release(session);
1378 return NULL;
1379 }
1380
1381 static void
coap_session_check_connect(coap_session_t * session)1382 coap_session_check_connect(coap_session_t *session) {
1383 if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
1384 session->sock.lfunc[COAP_LAYER_SESSION].l_establish(session);
1385 }
1386 #if !COAP_DISABLE_TCP
1387 if (COAP_PROTO_RELIABLE(session->proto)) {
1388 if (session->sock.flags & COAP_SOCKET_WANT_CONNECT) {
1389 session->state = COAP_SESSION_STATE_CONNECTING;
1390 if (session->state != COAP_SESSION_STATE_ESTABLISHED &&
1391 session->state != COAP_SESSION_STATE_NONE &&
1392 session->type == COAP_SESSION_TYPE_CLIENT) {
1393 session->doing_first = 1;
1394 }
1395 } else {
1396 /* Initial connect worked immediately */
1397 session->sock.lfunc[COAP_LAYER_SESSION].l_establish(session);
1398 }
1399 }
1400 #endif /* !COAP_DISABLE_TCP */
1401 coap_ticks(&session->last_rx_tx);
1402 }
1403 #endif /* COAP_CLIENT_SUPPORT */
1404
1405 void
coap_session_establish(coap_session_t * session)1406 coap_session_establish(coap_session_t *session) {
1407 if (COAP_PROTO_NOT_RELIABLE(session->proto))
1408 coap_session_connected(session);
1409 #if !COAP_DISABLE_TCP
1410 if (COAP_PROTO_RELIABLE(session->proto))
1411 coap_session_send_csm(session);
1412 #endif /* !COAP_DISABLE_TCP */
1413 }
1414
1415 #if COAP_CLIENT_SUPPORT
1416 coap_session_t *
coap_new_client_session(coap_context_t * ctx,const coap_address_t * local_if,const coap_address_t * server,coap_proto_t proto)1417 coap_new_client_session(coap_context_t *ctx,
1418 const coap_address_t *local_if,
1419 const coap_address_t *server,
1420 coap_proto_t proto) {
1421 coap_session_t *session = coap_session_create_client(ctx, local_if, server,
1422 proto);
1423 if (session) {
1424 coap_log_debug("***%s: session %p: created outgoing session\n",
1425 coap_session_str(session), (void *)session);
1426 coap_session_check_connect(session);
1427 }
1428 return session;
1429 }
1430
1431 coap_session_t *
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)1432 coap_new_client_session_psk(coap_context_t *ctx,
1433 const coap_address_t *local_if,
1434 const coap_address_t *server,
1435 coap_proto_t proto, const char *identity,
1436 const uint8_t *key, unsigned key_len) {
1437 coap_dtls_cpsk_t setup_data;
1438
1439 memset(&setup_data, 0, sizeof(setup_data));
1440 setup_data.version = COAP_DTLS_CPSK_SETUP_VERSION;
1441
1442 if (identity) {
1443 setup_data.psk_info.identity.s = (const uint8_t *)identity;
1444 setup_data.psk_info.identity.length = strlen(identity);
1445 }
1446
1447 if (key && key_len > 0) {
1448 setup_data.psk_info.key.s = key;
1449 setup_data.psk_info.key.length = key_len;
1450 }
1451
1452 return coap_new_client_session_psk2(ctx, local_if, server,
1453 proto, &setup_data);
1454 }
1455
1456 coap_session_t *
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)1457 coap_new_client_session_psk2(coap_context_t *ctx,
1458 const coap_address_t *local_if,
1459 const coap_address_t *server,
1460 coap_proto_t proto,
1461 coap_dtls_cpsk_t *setup_data) {
1462 coap_session_t *session = coap_session_create_client(ctx, local_if,
1463 server, proto);
1464
1465 if (!session)
1466 return NULL;
1467
1468 session->cpsk_setup_data = *setup_data;
1469 if (setup_data->psk_info.identity.s) {
1470 session->psk_identity =
1471 coap_new_bin_const(setup_data->psk_info.identity.s,
1472 setup_data->psk_info.identity.length);
1473 if (!session->psk_identity) {
1474 coap_log_warn("Cannot store session Identity (PSK)\n");
1475 coap_session_release(session);
1476 return NULL;
1477 }
1478 } else if (coap_dtls_is_supported() || coap_tls_is_supported()) {
1479 coap_log_warn("Identity (PSK) not defined\n");
1480 coap_session_release(session);
1481 return NULL;
1482 }
1483
1484 if (setup_data->psk_info.key.s && setup_data->psk_info.key.length > 0) {
1485 session->psk_key = coap_new_bin_const(setup_data->psk_info.key.s,
1486 setup_data->psk_info.key.length);
1487 if (!session->psk_key) {
1488 coap_log_warn("Cannot store session pre-shared key (PSK)\n");
1489 coap_session_release(session);
1490 return NULL;
1491 }
1492 } else if (coap_dtls_is_supported() || coap_tls_is_supported()) {
1493 coap_log_warn("Pre-shared key (PSK) not defined\n");
1494 coap_session_release(session);
1495 return NULL;
1496 }
1497
1498 if (coap_dtls_is_supported() || coap_tls_is_supported()) {
1499 if (!coap_dtls_context_set_cpsk(ctx, setup_data)) {
1500 coap_session_release(session);
1501 return NULL;
1502 }
1503 }
1504 coap_log_debug("***%s: new outgoing session\n",
1505 coap_session_str(session));
1506 coap_session_check_connect(session);
1507 return session;
1508 }
1509 #endif /* COAP_CLIENT_SUPPORT */
1510
1511 int
coap_session_refresh_psk_hint(coap_session_t * session,const coap_bin_const_t * psk_hint)1512 coap_session_refresh_psk_hint(coap_session_t *session,
1513 const coap_bin_const_t *psk_hint
1514 ) {
1515 /* We may be refreshing the hint with the same hint */
1516 coap_bin_const_t *old_psk_hint = session->psk_hint;
1517
1518 if (psk_hint && psk_hint->s) {
1519 if (session->psk_hint) {
1520 if (coap_binary_equal(session->psk_hint, psk_hint))
1521 return 1;
1522 }
1523 session->psk_hint = coap_new_bin_const(psk_hint->s,
1524 psk_hint->length);
1525 if (!session->psk_hint) {
1526 coap_log_err("No memory to store identity hint (PSK)\n");
1527 if (old_psk_hint)
1528 coap_delete_bin_const(old_psk_hint);
1529 return 0;
1530 }
1531 } else {
1532 session->psk_hint = NULL;
1533 }
1534 if (old_psk_hint)
1535 coap_delete_bin_const(old_psk_hint);
1536
1537 return 1;
1538 }
1539
1540 int
coap_session_refresh_psk_key(coap_session_t * session,const coap_bin_const_t * psk_key)1541 coap_session_refresh_psk_key(coap_session_t *session,
1542 const coap_bin_const_t *psk_key
1543 ) {
1544 /* We may be refreshing the key with the same key */
1545 coap_bin_const_t *old_psk_key = session->psk_key;
1546
1547 if (psk_key && psk_key->s) {
1548 if (session->psk_key) {
1549 if (coap_binary_equal(session->psk_key, psk_key))
1550 return 1;
1551 }
1552 session->psk_key = coap_new_bin_const(psk_key->s, psk_key->length);
1553 if (!session->psk_key) {
1554 coap_log_err("No memory to store pre-shared key (PSK)\n");
1555 if (old_psk_key)
1556 coap_delete_bin_const(old_psk_key);
1557 return 0;
1558 }
1559 } else {
1560 session->psk_key = NULL;
1561 }
1562 if (old_psk_key)
1563 coap_delete_bin_const(old_psk_key);
1564
1565 return 1;
1566 }
1567
1568 int
coap_session_refresh_psk_identity(coap_session_t * session,const coap_bin_const_t * psk_identity)1569 coap_session_refresh_psk_identity(coap_session_t *session,
1570 const coap_bin_const_t *psk_identity
1571 ) {
1572 /* We may be refreshing the identity with the same identity */
1573 coap_bin_const_t *old_psk_identity = session->psk_identity;
1574
1575 if (psk_identity && psk_identity->s) {
1576 if (session->psk_identity) {
1577 if (coap_binary_equal(session->psk_identity, psk_identity))
1578 return 1;
1579 }
1580 session->psk_identity = coap_new_bin_const(psk_identity->s,
1581 psk_identity->length);
1582 if (!session->psk_identity) {
1583 coap_log_err("No memory to store pre-shared key identity (PSK)\n");
1584 if (old_psk_identity)
1585 coap_delete_bin_const(old_psk_identity);
1586 return 0;
1587 }
1588 } else {
1589 session->psk_identity = NULL;
1590 }
1591 if (old_psk_identity)
1592 coap_delete_bin_const(old_psk_identity);
1593
1594 return 1;
1595 }
1596
1597 #if COAP_SERVER_SUPPORT
1598 const coap_bin_const_t *
coap_session_get_psk_hint(const coap_session_t * session)1599 coap_session_get_psk_hint(const coap_session_t *session) {
1600 if (session)
1601 return session->psk_hint;
1602 return NULL;
1603 }
1604 #endif /* COAP_SERVER_SUPPORT */
1605
1606 const coap_bin_const_t *
coap_session_get_psk_identity(const coap_session_t * session)1607 coap_session_get_psk_identity(const coap_session_t *session) {
1608 const coap_bin_const_t *psk_identity = NULL;
1609 if (session) {
1610 psk_identity = session->psk_identity;
1611 if (psk_identity == NULL) {
1612 psk_identity = &session->cpsk_setup_data.psk_info.identity;
1613 }
1614 }
1615 return psk_identity;
1616 }
1617
1618 const coap_bin_const_t *
coap_session_get_psk_key(const coap_session_t * session)1619 coap_session_get_psk_key(const coap_session_t *session) {
1620 if (session)
1621 return session->psk_key;
1622 return NULL;
1623 }
1624
1625 #if COAP_CLIENT_SUPPORT
1626 coap_session_t *
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)1627 coap_new_client_session_pki(coap_context_t *ctx,
1628 const coap_address_t *local_if,
1629 const coap_address_t *server,
1630 coap_proto_t proto,
1631 coap_dtls_pki_t *setup_data) {
1632 coap_session_t *session;
1633
1634 if (coap_dtls_is_supported() || coap_tls_is_supported()) {
1635 if (!setup_data) {
1636 return NULL;
1637 } else {
1638 if (setup_data->version != COAP_DTLS_PKI_SETUP_VERSION) {
1639 coap_log_err("coap_new_client_session_pki: Wrong version of setup_data\n");
1640 return NULL;
1641 }
1642 }
1643
1644 }
1645 session = coap_session_create_client(ctx, local_if, server, proto);
1646
1647 if (!session) {
1648 return NULL;
1649 }
1650
1651 if (coap_dtls_is_supported() || coap_tls_is_supported()) {
1652 /* we know that setup_data is not NULL */
1653 if (!coap_dtls_context_set_pki(ctx, setup_data, COAP_DTLS_ROLE_CLIENT)) {
1654 coap_session_release(session);
1655 return NULL;
1656 }
1657 }
1658 coap_log_debug("***%s: new outgoing session\n",
1659 coap_session_str(session));
1660 coap_session_check_connect(session);
1661 return session;
1662 }
1663 #endif /* ! COAP_CLIENT_SUPPORT */
1664
1665 #if COAP_SERVER_SUPPORT
1666 #if !COAP_DISABLE_TCP
1667 coap_session_t *
coap_new_server_session(coap_context_t * ctx,coap_endpoint_t * ep)1668 coap_new_server_session(coap_context_t *ctx, coap_endpoint_t *ep) {
1669 coap_session_t *session;
1670 session = coap_make_session(ep->proto, COAP_SESSION_TYPE_SERVER,
1671 NULL, NULL, NULL, 0, ctx, ep);
1672 if (!session)
1673 goto error;
1674
1675 memcpy(session->sock.lfunc, ep->sock.lfunc, sizeof(session->sock.lfunc));
1676 if (!coap_netif_strm_accept(ep, session))
1677 goto error;
1678
1679 coap_make_addr_hash(&session->addr_hash, session->proto, &session->addr_info);
1680
1681 #ifdef COAP_EPOLL_SUPPORT
1682 session->sock.session = session;
1683 coap_epoll_ctl_add(&session->sock,
1684 EPOLLIN,
1685 __func__);
1686 #endif /* COAP_EPOLL_SUPPORT */
1687 SESSIONS_ADD(ep->sessions, session);
1688 if (session) {
1689 coap_log_debug("***%s: session %p: new incoming session\n",
1690 coap_session_str(session), (void *)session);
1691 coap_handle_event(session->context, COAP_EVENT_TCP_CONNECTED, session);
1692 coap_handle_event(session->context, COAP_EVENT_SERVER_SESSION_NEW, session);
1693 session->state = COAP_SESSION_STATE_CONNECTING;
1694 session->sock.lfunc[COAP_LAYER_SESSION].l_establish(session);
1695 }
1696 return session;
1697
1698 error:
1699 /*
1700 * Need to add in the session as coap_session_release()
1701 * will call SESSIONS_DELETE in coap_session_free().
1702 */
1703 if (session) {
1704 SESSIONS_ADD(ep->sessions, session);
1705 coap_session_free(session);
1706 }
1707 return NULL;
1708 }
1709 #endif /* !COAP_DISABLE_TCP */
1710 #endif /* COAP_SERVER_SUPPORT */
1711
1712 void
coap_session_init_token(coap_session_t * session,size_t len,const uint8_t * data)1713 coap_session_init_token(coap_session_t *session, size_t len,
1714 const uint8_t *data) {
1715 session->tx_token = coap_decode_var_bytes8(data, len);
1716 }
1717
1718 void
coap_session_new_token(coap_session_t * session,size_t * len,uint8_t * data)1719 coap_session_new_token(coap_session_t *session, size_t *len,
1720 uint8_t *data) {
1721 *len = coap_encode_var_safe8(data,
1722 sizeof(session->tx_token), ++session->tx_token);
1723 }
1724
1725 uint16_t
coap_new_message_id(coap_session_t * session)1726 coap_new_message_id(coap_session_t *session) {
1727 if (COAP_PROTO_NOT_RELIABLE(session->proto))
1728 return ++session->tx_mid;
1729 /* TCP/TLS have no notion of mid */
1730 return 0;
1731 }
1732
1733 const coap_address_t *
coap_session_get_addr_remote(const coap_session_t * session)1734 coap_session_get_addr_remote(const coap_session_t *session) {
1735 if (session)
1736 return &session->addr_info.remote;
1737 return NULL;
1738 }
1739
1740 const coap_address_t *
coap_session_get_addr_local(const coap_session_t * session)1741 coap_session_get_addr_local(const coap_session_t *session) {
1742 if (session)
1743 return &session->addr_info.local;
1744 return NULL;
1745 }
1746
1747 const coap_address_t *
coap_session_get_addr_mcast(const coap_session_t * session)1748 coap_session_get_addr_mcast(const coap_session_t *session) {
1749 #if COAP_CLIENT_SUPPORT
1750 if (session && session->type == COAP_SESSION_TYPE_CLIENT &&
1751 session->sock.flags & COAP_SOCKET_MULTICAST)
1752 return &session->sock.mcast_addr;
1753 #else /* ! COAP_CLIENT_SUPPORT */
1754 (void)session;
1755 #endif /* ! COAP_CLIENT_SUPPORT */
1756 return NULL;
1757 }
1758
1759 coap_context_t *
coap_session_get_context(const coap_session_t * session)1760 coap_session_get_context(const coap_session_t *session) {
1761 if (session)
1762 return session->context;
1763 return NULL;
1764 }
1765
1766 coap_proto_t
coap_session_get_proto(const coap_session_t * session)1767 coap_session_get_proto(const coap_session_t *session) {
1768 if (session)
1769 return session->proto;
1770 return 0;
1771 }
1772
1773 coap_session_type_t
coap_session_get_type(const coap_session_t * session)1774 coap_session_get_type(const coap_session_t *session) {
1775 if (session)
1776 return session->type;
1777 return 0;
1778 }
1779
1780 #if COAP_CLIENT_SUPPORT
1781 int
coap_session_set_type_client(coap_session_t * session)1782 coap_session_set_type_client(coap_session_t *session) {
1783 #if COAP_SERVER_SUPPORT
1784 if (session && session->type == COAP_SESSION_TYPE_SERVER) {
1785 coap_session_reference(session);
1786 session->type = COAP_SESSION_TYPE_CLIENT;
1787 return 1;
1788 }
1789 #else /* ! COAP_SERVER_SUPPORT */
1790 (void)session;
1791 #endif /* ! COAP_SERVER_SUPPORT */
1792 return 0;
1793 }
1794 #endif /* COAP_CLIENT_SUPPORT */
1795
1796 coap_session_state_t
coap_session_get_state(const coap_session_t * session)1797 coap_session_get_state(const coap_session_t *session) {
1798 if (session)
1799 return session->state;
1800 return 0;
1801 }
1802
1803 int
coap_session_get_ifindex(const coap_session_t * session)1804 coap_session_get_ifindex(const coap_session_t *session) {
1805 if (session)
1806 return session->ifindex;
1807 return -1;
1808 }
1809
1810 void *
coap_session_get_tls(const coap_session_t * session,coap_tls_library_t * tls_lib)1811 coap_session_get_tls(const coap_session_t *session,
1812 coap_tls_library_t *tls_lib) {
1813 if (session)
1814 return coap_dtls_get_tls(session, tls_lib);
1815 return NULL;
1816 }
1817
1818 static const char *
coap_proto_name(coap_proto_t proto)1819 coap_proto_name(coap_proto_t proto) {
1820 switch (proto) {
1821 case COAP_PROTO_UDP:
1822 return "UDP ";
1823 case COAP_PROTO_DTLS:
1824 return "DTLS";
1825 case COAP_PROTO_TCP:
1826 return "TCP ";
1827 case COAP_PROTO_TLS:
1828 return "TLS ";
1829 case COAP_PROTO_WS:
1830 return "WS ";
1831 case COAP_PROTO_WSS:
1832 return "WSS ";
1833 case COAP_PROTO_NONE:
1834 case COAP_PROTO_LAST:
1835 default:
1836 return "????" ;
1837 break;
1838 }
1839 return NULL;
1840 }
1841
1842 #if COAP_SERVER_SUPPORT
1843 coap_endpoint_t *
coap_new_endpoint(coap_context_t * context,const coap_address_t * listen_addr,coap_proto_t proto)1844 coap_new_endpoint(coap_context_t *context, const coap_address_t *listen_addr, coap_proto_t proto) {
1845 coap_endpoint_t *ep = NULL;
1846
1847 assert(context);
1848 assert(listen_addr);
1849 assert(proto != COAP_PROTO_NONE);
1850
1851 if (proto == COAP_PROTO_DTLS && !coap_dtls_is_supported()) {
1852 coap_log_crit("coap_new_endpoint: DTLS not supported\n");
1853 goto error;
1854 }
1855
1856 if (proto == COAP_PROTO_TLS && !coap_tls_is_supported()) {
1857 coap_log_crit("coap_new_endpoint: TLS not supported\n");
1858 goto error;
1859 }
1860
1861 if (proto == COAP_PROTO_TCP && !coap_tcp_is_supported()) {
1862 coap_log_crit("coap_new_endpoint: TCP not supported\n");
1863 goto error;
1864 }
1865
1866 if (proto == COAP_PROTO_WS && !coap_ws_is_supported()) {
1867 coap_log_crit("coap_new_endpoint: WS not supported\n");
1868 goto error;
1869 }
1870
1871 if (proto == COAP_PROTO_WSS && !coap_wss_is_supported()) {
1872 coap_log_crit("coap_new_endpoint: WSS not supported\n");
1873 goto error;
1874 }
1875
1876 if (proto == COAP_PROTO_DTLS || proto == COAP_PROTO_TLS ||
1877 proto == COAP_PROTO_WSS) {
1878 if (!coap_dtls_context_check_keys_enabled(context)) {
1879 coap_log_info("coap_new_endpoint: one of coap_context_set_psk() or "
1880 "coap_context_set_pki() not called\n");
1881 goto error;
1882 }
1883 }
1884
1885 ep = coap_malloc_endpoint();
1886 if (!ep) {
1887 coap_log_warn("coap_new_endpoint: malloc");
1888 goto error;
1889 }
1890
1891 memset(ep, 0, sizeof(coap_endpoint_t));
1892 ep->context = context;
1893 ep->proto = proto;
1894 ep->sock.endpoint = ep;
1895 assert(proto < COAP_PROTO_LAST);
1896 memcpy(&ep->sock.lfunc, coap_layers_coap[proto], sizeof(ep->sock.lfunc));
1897
1898 if (COAP_PROTO_NOT_RELIABLE(proto)) {
1899 if (!coap_netif_dgrm_listen(ep, listen_addr))
1900 goto error;
1901 #ifdef WITH_CONTIKI
1902 ep->sock.context = context;
1903 #endif /* WITH_CONTIKI */
1904 #if !COAP_DISABLE_TCP
1905 } else if (COAP_PROTO_RELIABLE(proto)) {
1906 if (!coap_netif_strm_listen(ep, listen_addr))
1907 goto error;
1908 #endif /* !COAP_DISABLE_TCP */
1909 } else {
1910 coap_log_crit("coap_new_endpoint: protocol not supported\n");
1911 goto error;
1912 }
1913
1914 if (COAP_LOG_DEBUG <= coap_get_log_level()) {
1915 #ifndef INET6_ADDRSTRLEN
1916 #define INET6_ADDRSTRLEN 40
1917 #endif
1918 unsigned char addr_str[INET6_ADDRSTRLEN + 8];
1919
1920 if (coap_print_addr(&ep->bind_addr, addr_str, INET6_ADDRSTRLEN + 8)) {
1921 coap_log_debug("created %s endpoint %s\n", coap_proto_name(ep->proto),
1922 addr_str);
1923 }
1924 }
1925
1926 ep->default_mtu = COAP_DEFAULT_MTU;
1927
1928 #ifdef COAP_EPOLL_SUPPORT
1929 ep->sock.endpoint = ep;
1930 coap_epoll_ctl_add(&ep->sock,
1931 EPOLLIN,
1932 __func__);
1933 #endif /* COAP_EPOLL_SUPPORT */
1934
1935 LL_PREPEND(context->endpoint, ep);
1936 return ep;
1937
1938 error:
1939 coap_free_endpoint(ep);
1940 return NULL;
1941 }
1942
1943 void
coap_endpoint_set_default_mtu(coap_endpoint_t * ep,unsigned mtu)1944 coap_endpoint_set_default_mtu(coap_endpoint_t *ep, unsigned mtu) {
1945 ep->default_mtu = (uint16_t)mtu;
1946 }
1947
1948 void
coap_free_endpoint(coap_endpoint_t * ep)1949 coap_free_endpoint(coap_endpoint_t *ep) {
1950 if (ep) {
1951 coap_session_t *session, *rtmp;
1952
1953 SESSIONS_ITER_SAFE(ep->sessions, session, rtmp) {
1954 assert(session->ref == 0);
1955 if (session->ref == 0) {
1956 coap_session_free(session);
1957 }
1958 }
1959 if (coap_netif_available_ep(ep)) {
1960 /*
1961 * ep->sock.endpoint is set in coap_new_endpoint().
1962 * ep->sock.session is never set.
1963 *
1964 * session->sock.session is set for both clients and servers (when a
1965 * new session is accepted), but does not affect the endpoint.
1966 *
1967 * So, it is safe to call coap_netif_close_ep() after all the sessions
1968 * have been freed above as we are only working with the endpoint sock.
1969 */
1970 #ifdef COAP_EPOLL_SUPPORT
1971 assert(ep->sock.session == NULL);
1972 #endif /* COAP_EPOLL_SUPPORT */
1973 coap_netif_close_ep(ep);
1974 }
1975
1976 if (ep->context && ep->context->endpoint) {
1977 LL_DELETE(ep->context->endpoint, ep);
1978 }
1979 coap_mfree_endpoint(ep);
1980 }
1981 }
1982 #endif /* COAP_SERVER_SUPPORT */
1983
1984 coap_session_t *
coap_session_get_by_peer(const coap_context_t * ctx,const coap_address_t * remote_addr,int ifindex)1985 coap_session_get_by_peer(const coap_context_t *ctx,
1986 const coap_address_t *remote_addr,
1987 int ifindex) {
1988 coap_session_t *s, *rtmp;
1989 #if COAP_CLIENT_SUPPORT
1990 SESSIONS_ITER(ctx->sessions, s, rtmp) {
1991 if (s->ifindex == ifindex) {
1992 if (s->sock.flags & COAP_SOCKET_MULTICAST) {
1993 if (coap_address_equals(&s->sock.mcast_addr, remote_addr))
1994 return s;
1995 } else if (coap_address_equals(&s->addr_info.remote, remote_addr))
1996 return s;
1997 }
1998 }
1999 #endif /* COAP_CLIENT_SUPPORT */
2000 #if COAP_SERVER_SUPPORT
2001 coap_endpoint_t *ep;
2002
2003 LL_FOREACH(ctx->endpoint, ep) {
2004 SESSIONS_ITER(ep->sessions, s, rtmp) {
2005 if (s->ifindex == ifindex && coap_address_equals(&s->addr_info.remote,
2006 remote_addr))
2007 return s;
2008 }
2009 }
2010 #endif /* COAP_SERVER_SUPPORT */
2011 return NULL;
2012 }
2013
2014 #ifndef INET6_ADDRSTRLEN
2015 #define INET6_ADDRSTRLEN 46
2016 #endif
2017 const char *
coap_session_str(const coap_session_t * session)2018 coap_session_str(const coap_session_t *session) {
2019 static char szSession[2 * (INET6_ADDRSTRLEN + 8) + 24];
2020 char *p = szSession, *end = szSession + sizeof(szSession);
2021 if (coap_print_addr(&session->addr_info.local,
2022 (unsigned char *)p, end - p) > 0)
2023 p += strlen(p);
2024 if (p + 6 < end) {
2025 strcpy(p, " <-> ");
2026 p += 5;
2027 }
2028 if (p + 1 < end) {
2029 if (coap_print_addr(&session->addr_info.remote,
2030 (unsigned char *)p, end - p) > 0)
2031 p += strlen(p);
2032 }
2033 if (session->ifindex > 0 && p + 1 < end)
2034 p += snprintf(p, end - p, " (if%d)", session->ifindex);
2035 if (p + 6 < end) {
2036 strcpy(p, " ");
2037 p++;
2038 strcpy(p, coap_proto_name(session->proto));
2039 }
2040
2041 return szSession;
2042 }
2043
2044 #if COAP_SERVER_SUPPORT
2045 const char *
coap_endpoint_str(const coap_endpoint_t * endpoint)2046 coap_endpoint_str(const coap_endpoint_t *endpoint) {
2047 static char szEndpoint[128];
2048 char *p = szEndpoint, *end = szEndpoint + sizeof(szEndpoint);
2049 if (coap_print_addr(&endpoint->bind_addr, (unsigned char *)p, end - p) > 0)
2050 p += strlen(p);
2051 if (p + 6 < end) {
2052 if (endpoint->proto == COAP_PROTO_UDP) {
2053 strcpy(p, " UDP");
2054 p += 4;
2055 } else if (endpoint->proto == COAP_PROTO_DTLS) {
2056 strcpy(p, " DTLS");
2057 p += 5;
2058 } else {
2059 strcpy(p, " NONE");
2060 p += 5;
2061 }
2062 }
2063
2064 return szEndpoint;
2065 }
2066 #endif /* COAP_SERVER_SUPPORT */
2067 #if COAP_CLIENT_SUPPORT
2068 void
coap_session_set_no_observe_cancel(coap_session_t * session)2069 coap_session_set_no_observe_cancel(coap_session_t *session) {
2070 session->no_observe_cancel = 1;
2071 }
2072 #endif /* COAP_CLIENT_SUPPORT */
2073 #endif /* COAP_SESSION_C_ */
2074