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