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