• 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(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 
867 #ifdef SUPPORT_OPTIC_ONT
coap_session_skip_csm(coap_session_t * session)868 void coap_session_skip_csm(coap_session_t *session)
869 {
870   assert(COAP_PROTO_RELIABLE(session->proto));
871   coap_log(LOG_DEBUG, "***%s: sending CSM\n", coap_session_str(session));
872   session->state = COAP_SESSION_STATE_ESTABLISHED;
873   session->sock.flags |= COAP_SOCKET_CAN_READ;
874   return;
875 }
876 #endif
877 #endif /* !COAP_DISABLE_TCP */
878 
879 coap_mid_t
coap_session_send_ping(coap_session_t * session)880 coap_session_send_ping(coap_session_t *session) {
881   coap_pdu_t *ping = NULL;
882 
883   if (session->state != COAP_SESSION_STATE_ESTABLISHED ||
884       session->con_active)
885     return COAP_INVALID_MID;
886   if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
887     uint16_t mid = coap_new_message_id(session);
888     ping = coap_pdu_init(COAP_MESSAGE_CON, 0, mid, 0);
889   }
890 #if !COAP_DISABLE_TCP
891   else {
892     ping = coap_pdu_init(COAP_MESSAGE_CON, COAP_SIGNALING_CODE_PING, 0, 1);
893   }
894 #endif /* !COAP_DISABLE_TCP */
895   if (!ping)
896     return COAP_INVALID_MID;
897   return coap_send_internal(session, ping);
898 }
899 
900 void
coap_session_connected(coap_session_t * session)901 coap_session_connected(coap_session_t *session) {
902   if (session->state != COAP_SESSION_STATE_ESTABLISHED) {
903     coap_log_debug("***%s: session connected\n",
904                    coap_session_str(session));
905     if (session->state == COAP_SESSION_STATE_CSM) {
906       coap_handle_event(session->context, COAP_EVENT_SESSION_CONNECTED, session);
907       if (session->doing_first)
908         session->doing_first = 0;
909     }
910   }
911 
912   session->state = COAP_SESSION_STATE_ESTABLISHED;
913   session->partial_write = 0;
914 
915   if (session->proto==COAP_PROTO_DTLS) {
916     session->tls_overhead = coap_dtls_get_overhead(session);
917     if (session->tls_overhead >= session->mtu) {
918       session->tls_overhead = session->mtu;
919       coap_log_err("DTLS overhead exceeds MTU\n");
920     }
921   }
922 
923   while (session->delayqueue && session->state == COAP_SESSION_STATE_ESTABLISHED) {
924     ssize_t bytes_written;
925     coap_queue_t *q = session->delayqueue;
926     if (q->pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto)) {
927       if (session->con_active >= COAP_NSTART(session))
928         break;
929       session->con_active++;
930     }
931     /* Take entry off the queue */
932     session->delayqueue = q->next;
933     q->next = NULL;
934 
935     coap_log_debug("** %s: mid=0x%04x: transmitted after delay\n",
936                    coap_session_str(session), (int)q->pdu->mid);
937     bytes_written = coap_session_send_pdu(session, q->pdu);
938     if (q->pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto)) {
939       if (coap_wait_ack(session->context, session, q) >= 0)
940         q = NULL;
941     }
942     if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
943       if (q)
944         coap_delete_node(q);
945       if (bytes_written < 0)
946         break;
947     } else {
948       if (bytes_written <= 0 || (size_t)bytes_written < q->pdu->used_size + q->pdu->hdr_size) {
949         q->next = session->delayqueue;
950         session->delayqueue = q;
951         if (bytes_written > 0)
952           session->partial_write = (size_t)bytes_written;
953         break;
954       } else {
955         coap_delete_node(q);
956       }
957     }
958   }
959 }
960 
961 #if COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_DEBUG
962 static const char *
coap_nack_name(coap_nack_reason_t reason)963 coap_nack_name(coap_nack_reason_t reason) {
964   switch (reason) {
965   case COAP_NACK_TOO_MANY_RETRIES:
966     return "COAP_NACK_TOO_MANY_RETRIES";
967   case COAP_NACK_NOT_DELIVERABLE:
968     return "COAP_NACK_NOT_DELIVERABLE";
969   case COAP_NACK_RST:
970     return "COAP_NACK_RST";
971   case COAP_NACK_TLS_FAILED:
972     return "COAP_NACK_TLS_FAILED";
973   case COAP_NACK_ICMP_ISSUE:
974     return "COAP_NACK_ICMP_ISSUE";
975   case COAP_NACK_BAD_RESPONSE:
976     return "COAP_NACK_BAD_RESPONSE";
977   case COAP_NACK_TLS_LAYER_FAILED:
978     return "COAP_NACK_TLS_LAYER_FAILED";
979   case COAP_NACK_WS_LAYER_FAILED:
980     return "COAP_NACK_WS_LAYER_FAILED";
981   case COAP_NACK_WS_FAILED:
982     return "COAP_NACK_WS_FAILED";
983   default:
984     return "???";
985   }
986 }
987 #endif /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_DEBUG */
988 
989 void
coap_session_disconnected(coap_session_t * session,coap_nack_reason_t reason)990 coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason) {
991 #if !COAP_DISABLE_TCP
992   coap_session_state_t state = session->state;
993 #endif /* !COAP_DISABLE_TCP */
994   coap_lg_xmit_t *lq, *ltmp;
995 #if COAP_SERVER_SUPPORT
996   coap_lg_srcv_t *sq, *stmp;
997 #endif /* COAP_SERVER_SUPPORT */
998 #if COAP_CLIENT_SUPPORT
999   coap_lg_crcv_t *cq, *etmp;
1000 #endif /* COAP_CLIENT_SUPPORT */
1001 
1002   if (reason == COAP_NACK_ICMP_ISSUE) {
1003     if (session->context->nack_handler) {
1004       int sent_nack = 0;
1005       coap_queue_t *q = session->context->sendqueue;
1006       while (q) {
1007         if (q->session == session) {
1008           /* Take the first one */
1009           coap_bin_const_t token = q->pdu->actual_token;
1010 
1011           coap_check_update_token(session, q->pdu);
1012           session->context->nack_handler(session, q->pdu, reason, q->id);
1013           coap_update_token(q->pdu, token.length, token.s);
1014           sent_nack = 1;
1015           break;
1016         }
1017         q = q->next;
1018       }
1019 #if COAP_CLIENT_SUPPORT
1020       if (!sent_nack && session->lg_crcv) {
1021         /* Take the first one */
1022         session->context->nack_handler(session, &session->lg_crcv->pdu, reason,
1023                                        session->lg_crcv->pdu.mid);
1024         sent_nack = 1;
1025       }
1026 #endif /* COAP_CLIENT_SUPPORT */
1027       if (!sent_nack) {
1028         /* Unable to determine which request ICMP issue was for */
1029         session->context->nack_handler(session, NULL, reason, 0);
1030       }
1031     }
1032     coap_log_debug("***%s: session issue (%s)\n",
1033                    coap_session_str(session), coap_nack_name(reason));
1034     return;
1035   }
1036   coap_log_debug("***%s: session disconnected (%s)\n",
1037                  coap_session_str(session), coap_nack_name(reason));
1038 #if COAP_SERVER_SUPPORT
1039   coap_delete_observers(session->context, session);
1040 #endif /* COAP_SERVER_SUPPORT */
1041 
1042   if (session->proto == COAP_PROTO_UDP)
1043     session->state = COAP_SESSION_STATE_ESTABLISHED;
1044   else
1045     session->state = COAP_SESSION_STATE_NONE;
1046 
1047   session->con_active = 0;
1048 
1049   if (session->partial_pdu) {
1050     coap_delete_pdu(session->partial_pdu);
1051     session->partial_pdu = NULL;
1052   }
1053   session->partial_read = 0;
1054 
1055   while (session->delayqueue) {
1056     coap_queue_t *q = session->delayqueue;
1057     session->delayqueue = q->next;
1058     q->next = NULL;
1059     coap_log_debug("** %s: mid=0x%04x: not transmitted after disconnect\n",
1060                    coap_session_str(session), q->id);
1061     if (q && q->pdu->type == COAP_MESSAGE_CON
1062         && session->context->nack_handler) {
1063       coap_check_update_token(session, q->pdu);
1064       session->context->nack_handler(session, q->pdu, reason, q->id);
1065     }
1066     if (q)
1067       coap_delete_node(q);
1068   }
1069 
1070 #if COAP_CLIENT_SUPPORT
1071   /* Need to do this before (D)TLS and socket is closed down */
1072   LL_FOREACH_SAFE(session->lg_crcv, cq, etmp) {
1073     LL_DELETE(session->lg_crcv, cq);
1074     coap_block_delete_lg_crcv(session, cq);
1075   }
1076 #endif /* COAP_CLIENT_SUPPORT */
1077   LL_FOREACH_SAFE(session->lg_xmit, lq, ltmp) {
1078     LL_DELETE(session->lg_xmit, lq);
1079     coap_block_delete_lg_xmit(session, lq);
1080   }
1081 #if COAP_SERVER_SUPPORT
1082   LL_FOREACH_SAFE(session->lg_srcv, sq, stmp) {
1083     LL_DELETE(session->lg_srcv, sq);
1084     coap_block_delete_lg_srcv(session, sq);
1085   }
1086 #endif /* COAP_SERVER_SUPPORT */
1087   coap_cancel_session_messages(session->context, session, reason);
1088 
1089 #if !COAP_DISABLE_TCP
1090   if (COAP_PROTO_RELIABLE(session->proto)) {
1091     if (coap_netif_available(session)) {
1092       coap_handle_event(session->context,
1093                         state == COAP_SESSION_STATE_CONNECTING ?
1094                         COAP_EVENT_TCP_FAILED : COAP_EVENT_TCP_CLOSED, session);
1095     }
1096     if (state != COAP_SESSION_STATE_NONE) {
1097       coap_handle_event(session->context,
1098                         state == COAP_SESSION_STATE_ESTABLISHED ?
1099                         COAP_EVENT_SESSION_CLOSED : COAP_EVENT_SESSION_FAILED, session);
1100     }
1101     if (session->doing_first)
1102       session->doing_first = 0;
1103   }
1104 #endif /* !COAP_DISABLE_TCP */
1105   session->sock.lfunc[COAP_LAYER_SESSION].l_close(session);
1106 }
1107 
1108 #if COAP_SERVER_SUPPORT
1109 static void
coap_make_addr_hash(coap_addr_hash_t * addr_hash,coap_proto_t proto,const coap_addr_tuple_t * addr_info)1110 coap_make_addr_hash(coap_addr_hash_t *addr_hash, coap_proto_t proto,
1111                     const coap_addr_tuple_t *addr_info) {
1112   memset(addr_hash, 0, sizeof(coap_addr_hash_t));
1113   coap_address_copy(&addr_hash->remote, &addr_info->remote);
1114   addr_hash->lport = coap_address_get_port(&addr_info->local);
1115   addr_hash->proto = proto;
1116 }
1117 
1118 coap_session_t *
coap_endpoint_get_session(coap_endpoint_t * endpoint,const coap_packet_t * packet,coap_tick_t now)1119 coap_endpoint_get_session(coap_endpoint_t *endpoint,
1120                           const coap_packet_t *packet, coap_tick_t now) {
1121   coap_session_t *session;
1122   coap_session_t *rtmp;
1123   unsigned int num_idle = 0;
1124   unsigned int num_hs = 0;
1125   coap_session_t *oldest = NULL;
1126   coap_session_t *oldest_hs = NULL;
1127   coap_addr_hash_t addr_hash;
1128 #ifdef COAP_SUPPORT_SOCKET_BROADCAST
1129   if (is_loopback_packet(packet) == 1) {
1130     coap_log_debug("coap_endpoint_get_session: drop loopback packet");
1131     return NULL;
1132   }
1133 #endif
1134   coap_make_addr_hash(&addr_hash, endpoint->proto, &packet->addr_info);
1135   SESSIONS_FIND(endpoint->sessions, addr_hash, session);
1136   if (session) {
1137     /* Maybe mcast or unicast IP address which is not in the hash */
1138     coap_address_copy(&session->addr_info.local, &packet->addr_info.local);
1139     session->ifindex = packet->ifindex;
1140     session->last_rx_tx = now;
1141     return session;
1142   }
1143 
1144   SESSIONS_ITER(endpoint->sessions, session, rtmp) {
1145     if (session->ref == 0 && session->delayqueue == NULL) {
1146       if (session->type == COAP_SESSION_TYPE_SERVER) {
1147         ++num_idle;
1148         if (oldest==NULL || session->last_rx_tx < oldest->last_rx_tx)
1149           oldest = session;
1150 
1151         if (session->state == COAP_SESSION_STATE_HANDSHAKE) {
1152           ++num_hs;
1153           /* See if this is a partial (D)TLS session set up
1154              which needs to be cleared down to prevent DOS */
1155           if ((session->last_rx_tx + COAP_PARTIAL_SESSION_TIMEOUT_TICKS) < now) {
1156             if (oldest_hs == NULL ||
1157                 session->last_rx_tx < oldest_hs->last_rx_tx)
1158               oldest_hs = session;
1159           }
1160         }
1161       } else if (session->type == COAP_SESSION_TYPE_HELLO) {
1162         ++num_hs;
1163         /* See if this is a partial (D)TLS session set up for Client Hello
1164            which needs to be cleared down to prevent DOS */
1165         if ((session->last_rx_tx + COAP_PARTIAL_SESSION_TIMEOUT_TICKS) < now) {
1166           if (oldest_hs == NULL ||
1167               session->last_rx_tx < oldest_hs->last_rx_tx)
1168             oldest_hs = session;
1169         }
1170       }
1171     }
1172   }
1173 
1174   if (endpoint->context->max_idle_sessions > 0 &&
1175       num_idle >= endpoint->context->max_idle_sessions) {
1176     coap_handle_event(oldest->context, COAP_EVENT_SERVER_SESSION_DEL, oldest);
1177     coap_session_free(oldest);
1178   } else if (oldest_hs) {
1179     coap_log_warn("***%s: Incomplete session timed out\n",
1180                   coap_session_str(oldest_hs));
1181     coap_handle_event(oldest_hs->context, COAP_EVENT_SERVER_SESSION_DEL, oldest_hs);
1182     coap_session_free(oldest_hs);
1183   }
1184 
1185   if (num_hs > (endpoint->context->max_handshake_sessions ?
1186                 endpoint->context->max_handshake_sessions :
1187                 COAP_DEFAULT_MAX_HANDSHAKE_SESSIONS)) {
1188     /* Maxed out on number of sessions in (D)TLS negotiation state */
1189     coap_log_debug("Oustanding sessions in COAP_SESSION_STATE_HANDSHAKE too "
1190                    "large.  New request ignored\n");
1191     return NULL;
1192   }
1193 
1194   if (endpoint->proto == COAP_PROTO_DTLS) {
1195     /*
1196      * Need to check that this actually is a Client Hello before wasting
1197      * time allocating and then freeing off session.
1198      */
1199 
1200     /*
1201      * Generic header structure of the DTLS record layer.
1202      * typedef struct __attribute__((__packed__)) {
1203      *   uint8_t content_type;           content type of the included message
1204      *   uint16_t version;               Protocol version
1205      *   uint16_t epoch;                 counter for cipher state changes
1206      *   uint8_t sequence_number[6];     sequence number
1207      *   uint16_t length;                length of the following fragment
1208      *   uint8_t handshake;              If content_type == DTLS_CT_HANDSHAKE
1209      * } dtls_record_handshake_t;
1210      */
1211 #define OFF_CONTENT_TYPE      0  /* offset of content_type in dtls_record_handshake_t */
1212 #define DTLS_CT_ALERT        21  /* Content Type Alert */
1213 #define DTLS_CT_HANDSHAKE    22  /* Content Type Handshake */
1214 #define OFF_HANDSHAKE_TYPE   13  /* offset of handshake in dtls_record_handshake_t */
1215 #define DTLS_HT_CLIENT_HELLO  1  /* Client Hello handshake type */
1216 
1217     const uint8_t *payload = (const uint8_t *)packet->payload;
1218     size_t length = packet->length;
1219     if (length < (OFF_HANDSHAKE_TYPE + 1)) {
1220       coap_log_debug("coap_dtls_hello: ContentType %d Short Packet (%zu < %d) dropped\n",
1221                      payload[OFF_CONTENT_TYPE], length,
1222                      OFF_HANDSHAKE_TYPE + 1);
1223       return NULL;
1224     }
1225     if (payload[OFF_CONTENT_TYPE] != DTLS_CT_HANDSHAKE ||
1226         payload[OFF_HANDSHAKE_TYPE] != DTLS_HT_CLIENT_HELLO) {
1227       /* only log if not a late alert */
1228       if (payload[OFF_CONTENT_TYPE] != DTLS_CT_ALERT)
1229         coap_log_debug("coap_dtls_hello: ContentType %d Handshake %d dropped\n",
1230                        payload[OFF_CONTENT_TYPE], payload[OFF_HANDSHAKE_TYPE]);
1231       return NULL;
1232     }
1233   }
1234 
1235   session = coap_make_session(endpoint->proto, COAP_SESSION_TYPE_SERVER,
1236                               &addr_hash, &packet->addr_info.local,
1237                               &packet->addr_info.remote,
1238                               packet->ifindex, endpoint->context, endpoint);
1239   if (session) {
1240     session->last_rx_tx = now;
1241     memcpy(session->sock.lfunc, endpoint->sock.lfunc,
1242            sizeof(session->sock.lfunc));
1243     if (endpoint->proto == COAP_PROTO_UDP)
1244       session->state = COAP_SESSION_STATE_ESTABLISHED;
1245     else if (endpoint->proto == COAP_PROTO_DTLS) {
1246       session->type = COAP_SESSION_TYPE_HELLO;
1247     }
1248     SESSIONS_ADD(endpoint->sessions, session);
1249     coap_log_debug("***%s: session %p: new incoming session\n",
1250                    coap_session_str(session), (void *)session);
1251     coap_handle_event(session->context, COAP_EVENT_SERVER_SESSION_NEW, session);
1252   }
1253   return session;
1254 }
1255 
1256 coap_session_t *
coap_session_new_dtls_session(coap_session_t * session,coap_tick_t now)1257 coap_session_new_dtls_session(coap_session_t *session,
1258                               coap_tick_t now) {
1259   if (session) {
1260     session->last_rx_tx = now;
1261     session->type = COAP_SESSION_TYPE_SERVER;
1262     coap_dtls_establish(session);
1263   }
1264   return session;
1265 }
1266 #endif /* COAP_SERVER_SUPPORT */
1267 
coap_session_set_sessions(coap_context_t * ctx,coap_session_t * session)1268 void coap_session_set_sessions(coap_context_t *ctx, coap_session_t *session)
1269 {
1270     if (ctx != NULL) {
1271         ctx->sessions = session;
1272     }
1273 }
1274 
coap_session_get_sessions(coap_context_t * ctx)1275 coap_session_t * coap_session_get_sessions(coap_context_t *ctx)
1276 {
1277     if (ctx != NULL) {
1278         return ctx->sessions;
1279     } else {
1280         return NULL;
1281     }
1282 }
1283 
1284 #if COAP_CLIENT_SUPPORT
1285 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)1286 coap_session_create_client(coap_context_t *ctx,
1287                            const coap_address_t *local_if,
1288                            const coap_address_t *server,
1289                            coap_proto_t proto) {
1290   coap_session_t *session = NULL;
1291   int default_port = COAP_DEFAULT_PORT;
1292 
1293   assert(server);
1294 
1295   switch (proto) {
1296   case COAP_PROTO_UDP:
1297     default_port = COAP_DEFAULT_PORT;
1298     break;
1299   case COAP_PROTO_DTLS:
1300     if (!coap_dtls_is_supported()) {
1301       coap_log_crit("coap_new_client_session*: DTLS not supported\n");
1302       return NULL;
1303     }
1304     default_port = COAPS_DEFAULT_PORT;
1305     break;
1306   case COAP_PROTO_TCP:
1307     if (!coap_tcp_is_supported()) {
1308       coap_log_crit("coap_new_client_session*: TCP not supported\n");
1309       return NULL;
1310     }
1311     default_port = COAP_DEFAULT_PORT;
1312     break;
1313   case COAP_PROTO_TLS:
1314     if (!coap_tls_is_supported()) {
1315       coap_log_crit("coap_new_client_session*: TLS not supported\n");
1316       return NULL;
1317     }
1318     default_port = COAPS_DEFAULT_PORT;
1319     break;
1320   case COAP_PROTO_WS:
1321     if (!coap_ws_is_supported()) {
1322       coap_log_crit("coap_new_client_session*: WS not supported\n");
1323       return NULL;
1324     }
1325     default_port = 80;
1326     break;
1327   case COAP_PROTO_WSS:
1328     if (!coap_wss_is_supported()) {
1329       coap_log_crit("coap_new_client_session*: WSS not supported\n");
1330       return NULL;
1331     }
1332     default_port = 443;
1333     break;
1334   case COAP_PROTO_NONE:
1335   case COAP_PROTO_LAST:
1336   default:
1337     assert(0);
1338     return NULL;
1339   }
1340   session = coap_make_session(proto, COAP_SESSION_TYPE_CLIENT, NULL,
1341                               local_if, server, 0, ctx, NULL);
1342   if (!session)
1343     goto error;
1344 
1345   coap_session_reference(session);
1346   session->sock.session = session;
1347   memcpy(&session->sock.lfunc, coap_layers_coap[proto],
1348          sizeof(session->sock.lfunc));
1349 
1350   if (COAP_PROTO_NOT_RELIABLE(proto)) {
1351     coap_session_t *s, *rtmp;
1352     if (!coap_netif_dgrm_connect(session, local_if, server, default_port)) {
1353       goto error;
1354     }
1355     /* Check that this is not a duplicate 4-tuple */
1356     SESSIONS_ITER_SAFE(ctx->sessions, s, rtmp) {
1357       if (COAP_PROTO_NOT_RELIABLE(s->proto) &&
1358           coap_address_equals(&session->addr_info.local,
1359                               &s->addr_info.local) &&
1360           coap_address_equals(&session->addr_info.remote,
1361                               &s->addr_info.remote)) {
1362         coap_log_warn("***%s: session %p: duplicate - already exists\n",
1363                       coap_session_str(session), (void *)session);
1364         goto error;
1365       }
1366     }
1367 #ifdef WITH_CONTIKI
1368     session->sock.context = ctx;
1369 #endif /* WITH_CONTIKI */
1370 #if !COAP_DISABLE_TCP
1371   } else if (COAP_PROTO_RELIABLE(proto)) {
1372     if (!coap_netif_strm_connect1(session, local_if, server, default_port)) {
1373       goto error;
1374     }
1375 #endif /* !COAP_DISABLE_TCP */
1376   }
1377 
1378 #ifdef COAP_EPOLL_SUPPORT
1379   session->sock.session = session;
1380   coap_epoll_ctl_add(&session->sock,
1381                      EPOLLIN |
1382                      ((session->sock.flags & COAP_SOCKET_WANT_CONNECT) ?
1383                       EPOLLOUT : 0),
1384                      __func__);
1385 #endif /* COAP_EPOLL_SUPPORT */
1386 
1387   session->sock.flags |= COAP_SOCKET_NOT_EMPTY | COAP_SOCKET_WANT_READ;
1388   if (local_if)
1389     session->sock.flags |= COAP_SOCKET_BOUND;
1390 #if COAP_SERVER_SUPPORT
1391   if (ctx->proxy_uri_resource)
1392     session->proxy_session = 1;
1393 #endif /* COAP_SERVER_SUPPORT */
1394   SESSIONS_ADD(ctx->sessions, session);
1395   return session;
1396 
1397 error:
1398   /*
1399    * Need to add in the session as coap_session_release()
1400    * will call SESSIONS_DELETE in coap_session_free().
1401    */
1402   if (session)
1403     SESSIONS_ADD(ctx->sessions, session);
1404   coap_session_release(session);
1405   return NULL;
1406 }
1407 
1408 static void
coap_session_check_connect(coap_session_t * session)1409 coap_session_check_connect(coap_session_t *session) {
1410   if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
1411     session->sock.lfunc[COAP_LAYER_SESSION].l_establish(session);
1412   }
1413 #if !COAP_DISABLE_TCP
1414   if (COAP_PROTO_RELIABLE(session->proto)) {
1415     if (session->sock.flags & COAP_SOCKET_WANT_CONNECT) {
1416       session->state = COAP_SESSION_STATE_CONNECTING;
1417       if (session->state != COAP_SESSION_STATE_ESTABLISHED &&
1418           session->state != COAP_SESSION_STATE_NONE &&
1419           session->type == COAP_SESSION_TYPE_CLIENT) {
1420         session->doing_first = 1;
1421       }
1422     } else {
1423       /* Initial connect worked immediately */
1424       session->sock.lfunc[COAP_LAYER_SESSION].l_establish(session);
1425     }
1426   }
1427 #endif /* !COAP_DISABLE_TCP */
1428   coap_ticks(&session->last_rx_tx);
1429 }
1430 #endif /* COAP_CLIENT_SUPPORT */
1431 
1432 void
coap_session_establish(coap_session_t * session)1433 coap_session_establish(coap_session_t *session) {
1434   if (COAP_PROTO_NOT_RELIABLE(session->proto))
1435     coap_session_connected(session);
1436 #if !COAP_DISABLE_TCP
1437   if (COAP_PROTO_RELIABLE(session->proto))
1438 #ifdef SUPPORT_OPTIC_ONT
1439     coap_session_skip_csm(session);
1440 #else
1441     coap_session_send_csm(session);
1442 #endif
1443 #endif /* !COAP_DISABLE_TCP */
1444 }
1445 
1446 #if COAP_CLIENT_SUPPORT
1447 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)1448 coap_new_client_session(coap_context_t *ctx,
1449                         const coap_address_t *local_if,
1450                         const coap_address_t *server,
1451                         coap_proto_t proto) {
1452   coap_session_t *session = coap_session_create_client(ctx, local_if, server,
1453                                                        proto);
1454   if (session) {
1455     coap_log_debug("***%s: session %p: created outgoing session\n",
1456                    coap_session_str(session), (void *)session);
1457     coap_session_check_connect(session);
1458   }
1459   return session;
1460 }
1461 
1462 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)1463 coap_new_client_session_psk(coap_context_t *ctx,
1464                             const coap_address_t *local_if,
1465                             const coap_address_t *server,
1466                             coap_proto_t proto, const char *identity,
1467                             const uint8_t *key, unsigned key_len) {
1468   coap_dtls_cpsk_t setup_data;
1469 
1470   memset(&setup_data, 0, sizeof(setup_data));
1471   setup_data.version = COAP_DTLS_CPSK_SETUP_VERSION;
1472 
1473   if (identity) {
1474     setup_data.psk_info.identity.s = (const uint8_t *)identity;
1475     setup_data.psk_info.identity.length = strlen(identity);
1476   }
1477 
1478   if (key && key_len > 0) {
1479     setup_data.psk_info.key.s = key;
1480     setup_data.psk_info.key.length = key_len;
1481   }
1482 
1483   return coap_new_client_session_psk2(ctx, local_if, server,
1484                                       proto, &setup_data);
1485 }
1486 
1487 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)1488 coap_new_client_session_psk2(coap_context_t *ctx,
1489                              const coap_address_t *local_if,
1490                              const coap_address_t *server,
1491                              coap_proto_t proto,
1492                              coap_dtls_cpsk_t *setup_data) {
1493   coap_session_t *session = coap_session_create_client(ctx, local_if,
1494                                                        server, proto);
1495 
1496   if (!session)
1497     return NULL;
1498 
1499   session->cpsk_setup_data = *setup_data;
1500   if (setup_data->psk_info.identity.s) {
1501     session->psk_identity =
1502         coap_new_bin_const(setup_data->psk_info.identity.s,
1503                            setup_data->psk_info.identity.length);
1504     if (!session->psk_identity) {
1505       coap_log_warn("Cannot store session Identity (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("Identity (PSK) not defined\n");
1511     coap_session_release(session);
1512     return NULL;
1513   }
1514 
1515   if (setup_data->psk_info.key.s && setup_data->psk_info.key.length > 0) {
1516     session->psk_key = coap_new_bin_const(setup_data->psk_info.key.s,
1517                                           setup_data->psk_info.key.length);
1518     if (!session->psk_key) {
1519       coap_log_warn("Cannot store session pre-shared key (PSK)\n");
1520       coap_session_release(session);
1521       return NULL;
1522     }
1523   } else if (coap_dtls_is_supported() || coap_tls_is_supported()) {
1524     coap_log_warn("Pre-shared key (PSK) not defined\n");
1525     coap_session_release(session);
1526     return NULL;
1527   }
1528 
1529   if (coap_dtls_is_supported() || coap_tls_is_supported()) {
1530     if (!coap_dtls_context_set_cpsk(ctx, setup_data)) {
1531       coap_session_release(session);
1532       return NULL;
1533     }
1534   }
1535   coap_log_debug("***%s: new outgoing session\n",
1536                  coap_session_str(session));
1537   coap_session_check_connect(session);
1538   return session;
1539 }
1540 #endif /* COAP_CLIENT_SUPPORT */
1541 
1542 int
coap_session_refresh_psk_hint(coap_session_t * session,const coap_bin_const_t * psk_hint)1543 coap_session_refresh_psk_hint(coap_session_t *session,
1544                               const coap_bin_const_t *psk_hint
1545                              ) {
1546   /* We may be refreshing the hint with the same hint */
1547   coap_bin_const_t *old_psk_hint = session->psk_hint;
1548 
1549   if (psk_hint && psk_hint->s) {
1550     if (session->psk_hint) {
1551       if (coap_binary_equal(session->psk_hint, psk_hint))
1552         return 1;
1553     }
1554     session->psk_hint = coap_new_bin_const(psk_hint->s,
1555                                            psk_hint->length);
1556     if (!session->psk_hint) {
1557       coap_log_err("No memory to store identity hint (PSK)\n");
1558       if (old_psk_hint)
1559         coap_delete_bin_const(old_psk_hint);
1560       return 0;
1561     }
1562   } else {
1563     session->psk_hint = NULL;
1564   }
1565   if (old_psk_hint)
1566     coap_delete_bin_const(old_psk_hint);
1567 
1568   return 1;
1569 }
1570 
1571 int
coap_session_refresh_psk_key(coap_session_t * session,const coap_bin_const_t * psk_key)1572 coap_session_refresh_psk_key(coap_session_t *session,
1573                              const coap_bin_const_t *psk_key
1574                             ) {
1575   /* We may be refreshing the key with the same key */
1576   coap_bin_const_t *old_psk_key = session->psk_key;
1577 
1578   if (psk_key && psk_key->s) {
1579     if (session->psk_key) {
1580       if (coap_binary_equal(session->psk_key, psk_key))
1581         return 1;
1582     }
1583     session->psk_key = coap_new_bin_const(psk_key->s, psk_key->length);
1584     if (!session->psk_key) {
1585       coap_log_err("No memory to store pre-shared key (PSK)\n");
1586       if (old_psk_key)
1587         coap_delete_bin_const(old_psk_key);
1588       return 0;
1589     }
1590   } else {
1591     session->psk_key = NULL;
1592   }
1593   if (old_psk_key)
1594     coap_delete_bin_const(old_psk_key);
1595 
1596   return 1;
1597 }
1598 
1599 int
coap_session_refresh_psk_identity(coap_session_t * session,const coap_bin_const_t * psk_identity)1600 coap_session_refresh_psk_identity(coap_session_t *session,
1601                                   const coap_bin_const_t *psk_identity
1602                                  ) {
1603   /* We may be refreshing the identity with the same identity */
1604   coap_bin_const_t *old_psk_identity = session->psk_identity;
1605 
1606   if (psk_identity && psk_identity->s) {
1607     if (session->psk_identity) {
1608       if (coap_binary_equal(session->psk_identity, psk_identity))
1609         return 1;
1610     }
1611     session->psk_identity = coap_new_bin_const(psk_identity->s,
1612                                                psk_identity->length);
1613     if (!session->psk_identity) {
1614       coap_log_err("No memory to store pre-shared key identity (PSK)\n");
1615       if (old_psk_identity)
1616         coap_delete_bin_const(old_psk_identity);
1617       return 0;
1618     }
1619   } else {
1620     session->psk_identity = NULL;
1621   }
1622   if (old_psk_identity)
1623     coap_delete_bin_const(old_psk_identity);
1624 
1625   return 1;
1626 }
1627 
1628 #if COAP_SERVER_SUPPORT
1629 const coap_bin_const_t *
coap_session_get_psk_hint(const coap_session_t * session)1630 coap_session_get_psk_hint(const coap_session_t *session) {
1631   if (session)
1632     return session->psk_hint;
1633   return NULL;
1634 }
1635 #endif /* COAP_SERVER_SUPPORT */
1636 
1637 const coap_bin_const_t *
coap_session_get_psk_identity(const coap_session_t * session)1638 coap_session_get_psk_identity(const coap_session_t *session) {
1639   const coap_bin_const_t *psk_identity = NULL;
1640   if (session) {
1641     psk_identity = session->psk_identity;
1642     if (psk_identity == NULL) {
1643       psk_identity = &session->cpsk_setup_data.psk_info.identity;
1644     }
1645   }
1646   return psk_identity;
1647 }
1648 
1649 const coap_bin_const_t *
coap_session_get_psk_key(const coap_session_t * session)1650 coap_session_get_psk_key(const coap_session_t *session) {
1651   if (session)
1652     return session->psk_key;
1653   return NULL;
1654 }
1655 
1656 #if COAP_CLIENT_SUPPORT
1657 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)1658 coap_new_client_session_pki(coap_context_t *ctx,
1659                             const coap_address_t *local_if,
1660                             const coap_address_t *server,
1661                             coap_proto_t proto,
1662                             coap_dtls_pki_t *setup_data) {
1663   coap_session_t *session;
1664 
1665   if (coap_dtls_is_supported() || coap_tls_is_supported()) {
1666     if (!setup_data) {
1667       return NULL;
1668     } else {
1669       if (setup_data->version != COAP_DTLS_PKI_SETUP_VERSION) {
1670         coap_log_err("coap_new_client_session_pki: Wrong version of setup_data\n");
1671         return NULL;
1672       }
1673     }
1674 
1675   }
1676   session = coap_session_create_client(ctx, local_if, server, proto);
1677 
1678   if (!session) {
1679     return NULL;
1680   }
1681 
1682   if (coap_dtls_is_supported() || coap_tls_is_supported()) {
1683     /* we know that setup_data is not NULL */
1684     if (!coap_dtls_context_set_pki(ctx, setup_data, COAP_DTLS_ROLE_CLIENT)) {
1685       coap_session_release(session);
1686       return NULL;
1687     }
1688   }
1689   coap_log_debug("***%s: new outgoing session\n",
1690                  coap_session_str(session));
1691   coap_session_check_connect(session);
1692   return session;
1693 }
1694 #endif /* ! COAP_CLIENT_SUPPORT */
1695 
1696 #if COAP_SERVER_SUPPORT
1697 #if !COAP_DISABLE_TCP
1698 coap_session_t *
coap_new_server_session(coap_context_t * ctx,coap_endpoint_t * ep)1699 coap_new_server_session(coap_context_t *ctx, coap_endpoint_t *ep) {
1700   coap_session_t *session;
1701   session = coap_make_session(ep->proto, COAP_SESSION_TYPE_SERVER,
1702                               NULL, NULL, NULL, 0, ctx, ep);
1703   if (!session)
1704     goto error;
1705 
1706   memcpy(session->sock.lfunc, ep->sock.lfunc, sizeof(session->sock.lfunc));
1707   if (!coap_netif_strm_accept(ep, session))
1708     goto error;
1709 
1710   coap_make_addr_hash(&session->addr_hash, session->proto, &session->addr_info);
1711 
1712 #ifdef COAP_EPOLL_SUPPORT
1713   session->sock.session = session;
1714   coap_epoll_ctl_add(&session->sock,
1715                      EPOLLIN,
1716                      __func__);
1717 #endif /* COAP_EPOLL_SUPPORT */
1718   SESSIONS_ADD(ep->sessions, session);
1719   if (session) {
1720     coap_log_debug("***%s: session %p: new incoming session\n",
1721                    coap_session_str(session), (void *)session);
1722     coap_handle_event(session->context, COAP_EVENT_TCP_CONNECTED, session);
1723     coap_handle_event(session->context, COAP_EVENT_SERVER_SESSION_NEW, session);
1724     session->state = COAP_SESSION_STATE_CONNECTING;
1725     session->sock.lfunc[COAP_LAYER_SESSION].l_establish(session);
1726   }
1727   return session;
1728 
1729 error:
1730   /*
1731    * Need to add in the session as coap_session_release()
1732    * will call SESSIONS_DELETE in coap_session_free().
1733    */
1734   if (session) {
1735     SESSIONS_ADD(ep->sessions, session);
1736     coap_session_free(session);
1737   }
1738   return NULL;
1739 }
1740 #endif /* !COAP_DISABLE_TCP */
1741 #endif /* COAP_SERVER_SUPPORT */
1742 
1743 void
coap_session_init_token(coap_session_t * session,size_t len,const uint8_t * data)1744 coap_session_init_token(coap_session_t *session, size_t len,
1745                         const uint8_t *data) {
1746   session->tx_token = coap_decode_var_bytes8(data, len);
1747 }
1748 
1749 void
coap_session_new_token(coap_session_t * session,size_t * len,uint8_t * data)1750 coap_session_new_token(coap_session_t *session, size_t *len,
1751                        uint8_t *data) {
1752   *len = coap_encode_var_safe8(data,
1753                                sizeof(session->tx_token), ++session->tx_token);
1754 }
1755 
1756 uint16_t
coap_new_message_id(coap_session_t * session)1757 coap_new_message_id(coap_session_t *session) {
1758   if (COAP_PROTO_NOT_RELIABLE(session->proto))
1759     return ++session->tx_mid;
1760   /* TCP/TLS have no notion of mid */
1761   return 0;
1762 }
1763 
1764 uint16_t
coap_get_message_id(coap_session_t * session)1765 coap_get_message_id(coap_session_t *session) {
1766   if (session == NULL) {
1767     return 0;
1768   }
1769 
1770   return session->tx_mid;
1771 }
1772 
1773 const coap_address_t *
coap_session_get_addr_remote(const coap_session_t * session)1774 coap_session_get_addr_remote(const coap_session_t *session) {
1775   if (session)
1776     return &session->addr_info.remote;
1777   return NULL;
1778 }
1779 
1780 const coap_address_t *
coap_session_get_addr_local(const coap_session_t * session)1781 coap_session_get_addr_local(const coap_session_t *session) {
1782   if (session)
1783     return &session->addr_info.local;
1784   return NULL;
1785 }
1786 
1787 const coap_address_t *
coap_session_get_addr_mcast(const coap_session_t * session)1788 coap_session_get_addr_mcast(const coap_session_t *session) {
1789 #if COAP_CLIENT_SUPPORT
1790   if (session && session->type == COAP_SESSION_TYPE_CLIENT &&
1791       session->sock.flags & COAP_SOCKET_MULTICAST)
1792     return &session->sock.mcast_addr;
1793 #else /* ! COAP_CLIENT_SUPPORT */
1794   (void)session;
1795 #endif /* ! COAP_CLIENT_SUPPORT */
1796   return NULL;
1797 }
1798 
1799 coap_context_t *
coap_session_get_context(const coap_session_t * session)1800 coap_session_get_context(const coap_session_t *session) {
1801   if (session)
1802     return session->context;
1803   return NULL;
1804 }
1805 
1806 coap_proto_t
coap_session_get_proto(const coap_session_t * session)1807 coap_session_get_proto(const coap_session_t *session) {
1808   if (session)
1809     return session->proto;
1810   return 0;
1811 }
1812 
1813 coap_session_type_t
coap_session_get_type(const coap_session_t * session)1814 coap_session_get_type(const coap_session_t *session) {
1815   if (session)
1816     return session->type;
1817   return 0;
1818 }
1819 
1820 #if COAP_CLIENT_SUPPORT
1821 int
coap_session_set_type_client(coap_session_t * session)1822 coap_session_set_type_client(coap_session_t *session) {
1823 #if COAP_SERVER_SUPPORT
1824   if (session && session->type == COAP_SESSION_TYPE_SERVER) {
1825     coap_session_reference(session);
1826     session->type = COAP_SESSION_TYPE_CLIENT;
1827     return 1;
1828   }
1829 #else /* ! COAP_SERVER_SUPPORT */
1830   (void)session;
1831 #endif /* ! COAP_SERVER_SUPPORT */
1832   return 0;
1833 }
1834 #endif /* COAP_CLIENT_SUPPORT */
1835 
1836 coap_session_state_t
coap_session_get_state(const coap_session_t * session)1837 coap_session_get_state(const coap_session_t *session) {
1838   if (session)
1839     return session->state;
1840   return 0;
1841 }
1842 
1843 int
coap_session_get_ifindex(const coap_session_t * session)1844 coap_session_get_ifindex(const coap_session_t *session) {
1845   if (session)
1846     return session->ifindex;
1847   return -1;
1848 }
1849 
1850 void *
coap_session_get_tls(const coap_session_t * session,coap_tls_library_t * tls_lib)1851 coap_session_get_tls(const coap_session_t *session,
1852                      coap_tls_library_t *tls_lib) {
1853   if (session)
1854     return coap_dtls_get_tls(session, tls_lib);
1855   return NULL;
1856 }
1857 
1858 static const char *
coap_proto_name(coap_proto_t proto)1859 coap_proto_name(coap_proto_t proto) {
1860   switch (proto) {
1861   case COAP_PROTO_UDP:
1862     return "UDP ";
1863   case COAP_PROTO_DTLS:
1864     return "DTLS";
1865   case COAP_PROTO_TCP:
1866     return "TCP ";
1867   case COAP_PROTO_TLS:
1868     return "TLS ";
1869   case COAP_PROTO_WS:
1870     return "WS  ";
1871   case COAP_PROTO_WSS:
1872     return "WSS ";
1873   case COAP_PROTO_NONE:
1874   case COAP_PROTO_LAST:
1875   default:
1876     return "????" ;
1877     break;
1878   }
1879   return NULL;
1880 }
1881 
1882 #if COAP_SERVER_SUPPORT
1883 coap_endpoint_t *
coap_new_endpoint(coap_context_t * context,const coap_address_t * listen_addr,coap_proto_t proto)1884 coap_new_endpoint(coap_context_t *context, const coap_address_t *listen_addr, coap_proto_t proto) {
1885   coap_endpoint_t *ep = NULL;
1886 
1887   assert(context);
1888   assert(listen_addr);
1889   assert(proto != COAP_PROTO_NONE);
1890 
1891   if (proto == COAP_PROTO_DTLS && !coap_dtls_is_supported()) {
1892     coap_log_crit("coap_new_endpoint: DTLS not supported\n");
1893     goto error;
1894   }
1895 
1896   if (proto == COAP_PROTO_TLS && !coap_tls_is_supported()) {
1897     coap_log_crit("coap_new_endpoint: TLS not supported\n");
1898     goto error;
1899   }
1900 
1901   if (proto == COAP_PROTO_TCP && !coap_tcp_is_supported()) {
1902     coap_log_crit("coap_new_endpoint: TCP not supported\n");
1903     goto error;
1904   }
1905 
1906   if (proto == COAP_PROTO_WS && !coap_ws_is_supported()) {
1907     coap_log_crit("coap_new_endpoint: WS not supported\n");
1908     goto error;
1909   }
1910 
1911   if (proto == COAP_PROTO_WSS && !coap_wss_is_supported()) {
1912     coap_log_crit("coap_new_endpoint: WSS not supported\n");
1913     goto error;
1914   }
1915 
1916   if (proto == COAP_PROTO_DTLS || proto == COAP_PROTO_TLS ||
1917       proto == COAP_PROTO_WSS) {
1918     if (!coap_dtls_context_check_keys_enabled(context)) {
1919       coap_log_info("coap_new_endpoint: one of coap_context_set_psk() or "
1920                     "coap_context_set_pki() not called\n");
1921       goto error;
1922     }
1923   }
1924 
1925   ep = coap_malloc_endpoint();
1926   if (!ep) {
1927     coap_log_warn("coap_new_endpoint: malloc");
1928     goto error;
1929   }
1930 
1931   memset(ep, 0, sizeof(coap_endpoint_t));
1932   ep->context = context;
1933   ep->proto = proto;
1934   ep->sock.endpoint = ep;
1935   assert(proto < COAP_PROTO_LAST);
1936   memcpy(&ep->sock.lfunc, coap_layers_coap[proto], sizeof(ep->sock.lfunc));
1937 
1938   if (COAP_PROTO_NOT_RELIABLE(proto)) {
1939     if (!coap_netif_dgrm_listen(ep, listen_addr))
1940       goto error;
1941 #ifdef WITH_CONTIKI
1942     ep->sock.context = context;
1943 #endif /* WITH_CONTIKI */
1944 #if !COAP_DISABLE_TCP
1945   } else if (COAP_PROTO_RELIABLE(proto)) {
1946     if (!coap_netif_strm_listen(ep, listen_addr))
1947       goto error;
1948 #endif /* !COAP_DISABLE_TCP */
1949   } else {
1950     coap_log_crit("coap_new_endpoint: protocol not supported\n");
1951     goto error;
1952   }
1953 
1954   if (COAP_LOG_DEBUG <= coap_get_log_level()) {
1955 #ifndef INET6_ADDRSTRLEN
1956 #define INET6_ADDRSTRLEN 40
1957 #endif
1958     unsigned char addr_str[INET6_ADDRSTRLEN + 8];
1959 
1960     if (coap_print_addr(&ep->bind_addr, addr_str, INET6_ADDRSTRLEN + 8)) {
1961       coap_log_debug("created %s endpoint %s\n", coap_proto_name(ep->proto),
1962                      addr_str);
1963     }
1964   }
1965 
1966   ep->default_mtu = COAP_DEFAULT_MTU;
1967 
1968 #ifdef COAP_EPOLL_SUPPORT
1969   ep->sock.endpoint = ep;
1970   coap_epoll_ctl_add(&ep->sock,
1971                      EPOLLIN,
1972                      __func__);
1973 #endif /* COAP_EPOLL_SUPPORT */
1974 
1975   LL_PREPEND(context->endpoint, ep);
1976   return ep;
1977 
1978 error:
1979   coap_free_endpoint(ep);
1980   return NULL;
1981 }
1982 
1983 void
coap_endpoint_set_default_mtu(coap_endpoint_t * ep,unsigned mtu)1984 coap_endpoint_set_default_mtu(coap_endpoint_t *ep, unsigned mtu) {
1985   ep->default_mtu = (uint16_t)mtu;
1986 }
1987 
1988 void
coap_free_endpoint(coap_endpoint_t * ep)1989 coap_free_endpoint(coap_endpoint_t *ep) {
1990   if (ep) {
1991     coap_session_t *session, *rtmp;
1992 
1993     SESSIONS_ITER_SAFE(ep->sessions, session, rtmp) {
1994       assert(session->ref == 0);
1995       if (session->ref == 0) {
1996         coap_session_free(session);
1997       }
1998     }
1999     if (coap_netif_available_ep(ep)) {
2000       /*
2001        * ep->sock.endpoint is set in coap_new_endpoint().
2002        * ep->sock.session is never set.
2003        *
2004        * session->sock.session is set for both clients and servers (when a
2005        * new session is accepted), but does not affect the endpoint.
2006        *
2007        * So, it is safe to call coap_netif_close_ep() after all the sessions
2008        * have been freed above as we are only working with the endpoint sock.
2009        */
2010 #ifdef COAP_EPOLL_SUPPORT
2011       assert(ep->sock.session == NULL);
2012 #endif /* COAP_EPOLL_SUPPORT */
2013       coap_netif_close_ep(ep);
2014     }
2015 
2016     if (ep->context && ep->context->endpoint) {
2017       LL_DELETE(ep->context->endpoint, ep);
2018     }
2019     coap_mfree_endpoint(ep);
2020   }
2021 }
2022 #endif /* COAP_SERVER_SUPPORT */
2023 
2024 coap_session_t *
coap_session_get_by_peer(const coap_context_t * ctx,const coap_address_t * remote_addr,int ifindex)2025 coap_session_get_by_peer(const coap_context_t *ctx,
2026                          const coap_address_t *remote_addr,
2027                          int ifindex) {
2028   coap_session_t *s, *rtmp;
2029 #if COAP_CLIENT_SUPPORT
2030   SESSIONS_ITER(ctx->sessions, s, rtmp) {
2031     if (s->ifindex == ifindex) {
2032       if (s->sock.flags & COAP_SOCKET_MULTICAST) {
2033         if (coap_address_equals(&s->sock.mcast_addr, remote_addr))
2034           return s;
2035       } else if (coap_address_equals(&s->addr_info.remote, remote_addr))
2036         return s;
2037     }
2038   }
2039 #endif /* COAP_CLIENT_SUPPORT */
2040 #if COAP_SERVER_SUPPORT
2041   coap_endpoint_t *ep;
2042 
2043   LL_FOREACH(ctx->endpoint, ep) {
2044     SESSIONS_ITER(ep->sessions, s, rtmp) {
2045       if (s->ifindex == ifindex && coap_address_equals(&s->addr_info.remote,
2046                                                        remote_addr))
2047         return s;
2048     }
2049   }
2050 #endif /* COAP_SERVER_SUPPORT */
2051   return NULL;
2052 }
2053 
2054 #ifndef INET6_ADDRSTRLEN
2055 #define INET6_ADDRSTRLEN 46
2056 #endif
2057 const char *
coap_session_str(const coap_session_t * session)2058 coap_session_str(const coap_session_t *session) {
2059   static char szSession[2 * (INET6_ADDRSTRLEN + 8) + 24];
2060   char *p = szSession, *end = szSession + sizeof(szSession);
2061   if (coap_print_addr(&session->addr_info.local,
2062                       (unsigned char *)p, end - p) > 0)
2063     p += strlen(p);
2064   if (p + 6 < end) {
2065     strcpy(p, " <-> ");
2066     p += 5;
2067   }
2068   if (p + 1 < end) {
2069     if (coap_print_addr(&session->addr_info.remote,
2070                         (unsigned char *)p, end - p) > 0)
2071       p += strlen(p);
2072   }
2073   if (session->ifindex > 0 && p + 1 < end)
2074     p += snprintf(p, end - p, " (if%d)", session->ifindex);
2075   if (p + 6 < end) {
2076     strcpy(p, " ");
2077     p++;
2078     strcpy(p, coap_proto_name(session->proto));
2079   }
2080 
2081   return szSession;
2082 }
2083 
2084 #if COAP_SERVER_SUPPORT
2085 const char *
coap_endpoint_str(const coap_endpoint_t * endpoint)2086 coap_endpoint_str(const coap_endpoint_t *endpoint) {
2087   static char szEndpoint[128];
2088   char *p = szEndpoint, *end = szEndpoint + sizeof(szEndpoint);
2089   if (coap_print_addr(&endpoint->bind_addr, (unsigned char *)p, end - p) > 0)
2090     p += strlen(p);
2091   if (p + 6 < end) {
2092     if (endpoint->proto == COAP_PROTO_UDP) {
2093       strcpy(p, " UDP");
2094       p += 4;
2095     } else if (endpoint->proto == COAP_PROTO_DTLS) {
2096       strcpy(p, " DTLS");
2097       p += 5;
2098     } else {
2099       strcpy(p, " NONE");
2100       p += 5;
2101     }
2102   }
2103 
2104   return szEndpoint;
2105 }
2106 #endif /* COAP_SERVER_SUPPORT */
2107 #if COAP_CLIENT_SUPPORT
2108 void
coap_session_set_no_observe_cancel(coap_session_t * session)2109 coap_session_set_no_observe_cancel(coap_session_t *session) {
2110   session->no_observe_cancel = 1;
2111 }
2112 #endif /* COAP_CLIENT_SUPPORT */
2113 #endif  /* COAP_SESSION_C_ */
2114