• 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 * Copyright (c) 2021 Huawei Device Co., Ltd. All rights reserved.
5 *
6 * This file is part of the CoAP library libcoap. Please see
7 * README for terms of use.
8 */
9 
10 #include "coap_internal.h"
11 
12 #ifndef COAP_SESSION_C_
13 #define COAP_SESSION_C_
14 
15 #include <stdio.h>
16 
17 #ifdef COAP_EPOLL_SUPPORT
18 #include <sys/epoll.h>
19 #include <sys/timerfd.h>
20 #endif /* COAP_EPOLL_SUPPORT */
21 #include <errno.h>
22 #include <unistd.h>
23 #include <net/if.h>
24 #include <sys/ioctl.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 
28 void
coap_session_set_max_retransmit(coap_session_t * session,unsigned int value)29 coap_session_set_max_retransmit (coap_session_t *session, unsigned int value) {
30   if (value > 0)
31     session->max_retransmit = value;
32   coap_log(LOG_DEBUG, "***%s: session max_retransmit set to %d\n",
33            coap_session_str(session), session->max_retransmit);
34   return;
35 }
36 
37 void
coap_session_set_ack_timeout(coap_session_t * session,coap_fixed_point_t value)38 coap_session_set_ack_timeout (coap_session_t *session, coap_fixed_point_t value) {
39   if (value.integer_part > 0 && value.fractional_part < 1000)
40     session->ack_timeout = value;
41   coap_log(LOG_DEBUG, "***%s: session ack_timeout set to %d.%03d\n",
42            coap_session_str(session), session->ack_timeout.integer_part,
43            session->ack_timeout.fractional_part);
44   return;
45 }
46 
47 void
coap_session_set_ack_random_factor(coap_session_t * session,coap_fixed_point_t value)48 coap_session_set_ack_random_factor (coap_session_t *session,
49                                     coap_fixed_point_t value) {
50   if (value.integer_part > 0 && value.fractional_part < 1000)
51     session->ack_random_factor = value;
52   coap_log(LOG_DEBUG, "***%s: session ack_random_factor set to %d.%03d\n",
53            coap_session_str(session), session->ack_random_factor.integer_part,
54            session->ack_random_factor.fractional_part);
55   return;
56 }
57 
58 unsigned int
coap_session_get_max_transmit(coap_session_t * session)59 coap_session_get_max_transmit (coap_session_t *session) {
60   return session->max_retransmit;
61 }
62 
63 coap_fixed_point_t
coap_session_get_ack_timeout(coap_session_t * session)64 coap_session_get_ack_timeout (coap_session_t *session) {
65   return session->ack_timeout;
66 }
67 
68 coap_fixed_point_t
coap_session_get_ack_random_factor(coap_session_t * session)69 coap_session_get_ack_random_factor (coap_session_t *session) {
70   return session->ack_random_factor;
71 }
72 
73 coap_session_t *
coap_session_reference(coap_session_t * session)74 coap_session_reference(coap_session_t *session) {
75   ++session->ref;
76   return session;
77 }
78 
79 void
coap_session_release(coap_session_t * session)80 coap_session_release(coap_session_t *session) {
81   if (session) {
82     assert(session->ref > 0);
83     if (session->ref > 0)
84       --session->ref;
85     if (session->ref == 0 && session->type == COAP_SESSION_TYPE_CLIENT)
86       coap_session_free(session);
87   }
88 }
89 
90 void
coap_session_set_app_data(coap_session_t * session,void * app_data)91 coap_session_set_app_data(coap_session_t *session, void *app_data) {
92   assert(session);
93   session->app = app_data;
94 }
95 
96 void *
coap_session_get_app_data(const coap_session_t * session)97 coap_session_get_app_data(const coap_session_t *session) {
98   assert(session);
99   return session->app;
100 }
101 
102 static coap_session_t *
coap_make_session(coap_proto_t proto,coap_session_type_t type,const coap_address_t * local_if,const coap_address_t * local_addr,const coap_address_t * remote_addr,int ifindex,coap_context_t * context,coap_endpoint_t * endpoint)103 coap_make_session(coap_proto_t proto, coap_session_type_t type,
104   const coap_address_t *local_if, const coap_address_t *local_addr,
105   const coap_address_t *remote_addr, int ifindex, coap_context_t *context,
106   coap_endpoint_t *endpoint) {
107   coap_session_t *session = (coap_session_t*)coap_malloc_type(COAP_SESSION, sizeof(coap_session_t));
108   if (!session)
109     return NULL;
110   memset(session, 0, sizeof(*session));
111   session->proto = proto;
112   session->type = type;
113   if (local_if)
114     coap_address_copy(&session->local_if, local_if);
115   else
116     coap_address_init(&session->local_if);
117   if (local_addr)
118     coap_address_copy(&session->addr_info.local, local_addr);
119   else
120     coap_address_init(&session->addr_info.local);
121   if (remote_addr)
122     coap_address_copy(&session->addr_info.remote, remote_addr);
123   else
124     coap_address_init(&session->addr_info.remote);
125   session->ifindex = ifindex;
126   session->context = context;
127   session->endpoint = endpoint;
128   if (endpoint)
129     session->mtu = endpoint->default_mtu;
130   else
131     session->mtu = COAP_DEFAULT_MTU;
132   if (proto == COAP_PROTO_DTLS) {
133     session->tls_overhead = 29;
134     if (session->tls_overhead >= session->mtu) {
135       session->tls_overhead = session->mtu;
136       coap_log(LOG_ERR, "DTLS overhead exceeds MTU\n");
137     }
138   }
139   session->max_retransmit = COAP_DEFAULT_MAX_RETRANSMIT;
140   session->ack_timeout = COAP_DEFAULT_ACK_TIMEOUT;
141   session->ack_random_factor = COAP_DEFAULT_ACK_RANDOM_FACTOR;
142   session->dtls_event = -1;
143   session->last_ping_mid = COAP_INVALID_TID;
144 
145   /* initialize message id */
146   prng((unsigned char *)&session->tx_mid, sizeof(session->tx_mid));
147 
148   return session;
149 }
150 
coap_session_mfree(coap_session_t * session)151 void coap_session_mfree(coap_session_t *session) {
152   coap_queue_t *q, *tmp;
153 
154   if (session->partial_pdu)
155     coap_delete_pdu(session->partial_pdu);
156   if (session->proto == COAP_PROTO_DTLS)
157     coap_dtls_free_session(session);
158   else if (session->proto == COAP_PROTO_TLS)
159     coap_tls_free_session(session);
160   if (session->sock.flags != COAP_SOCKET_EMPTY)
161     coap_socket_close(&session->sock);
162   if (session->psk_identity)
163     coap_free(session->psk_identity);
164   if (session->psk_key)
165     coap_free(session->psk_key);
166 
167   LL_FOREACH_SAFE(session->delayqueue, q, tmp) {
168     if (q->pdu->type==COAP_MESSAGE_CON && session->context && session->context->nack_handler)
169       session->context->nack_handler(session->context, session, q->pdu, session->proto == COAP_PROTO_DTLS ? COAP_NACK_TLS_FAILED : COAP_NACK_NOT_DELIVERABLE, q->id);
170     coap_delete_node(q);
171   }
172 }
173 
coap_session_free(coap_session_t * session)174 void coap_session_free(coap_session_t *session) {
175   if (!session)
176     return;
177   assert(session->ref == 0);
178   if (session->ref)
179     return;
180   coap_session_mfree(session);
181   if (session->endpoint) {
182     if (session->endpoint->sessions)
183       SESSIONS_DELETE(session->endpoint->sessions, session);
184   } else if (session->context) {
185     if (session->context->sessions)
186       SESSIONS_DELETE(session->context->sessions, session);
187   }
188   coap_log(LOG_DEBUG, "***%s: session closed\n", coap_session_str(session));
189 
190   coap_free_type(COAP_SESSION, session);
191 }
192 
coap_session_max_pdu_size(const coap_session_t * session)193 size_t coap_session_max_pdu_size(const coap_session_t *session) {
194   size_t max_with_header = (size_t)(session->mtu - session->tls_overhead);
195   if (COAP_PROTO_NOT_RELIABLE(session->proto))
196     return max_with_header > 4 ? max_with_header - 4 : 0;
197   /* we must assume there is no token to be on the safe side */
198   if (max_with_header <= 2)
199     return 0;
200   else if (max_with_header <= COAP_MAX_MESSAGE_SIZE_TCP0 + 2)
201     return max_with_header - 2;
202   else if (max_with_header <= COAP_MAX_MESSAGE_SIZE_TCP8 + 3)
203     return max_with_header - 3;
204   else if (max_with_header <= COAP_MAX_MESSAGE_SIZE_TCP16 + 4)
205     return max_with_header - 4;
206   else
207     return max_with_header - 6;
208 }
209 
coap_session_set_mtu(coap_session_t * session,unsigned mtu)210 void coap_session_set_mtu(coap_session_t *session, unsigned mtu) {
211 #if defined(WITH_CONTIKI) || defined(WITH_LWIP)
212   if (mtu > COAP_MAX_MESSAGE_SIZE_TCP16 + 4)
213     mtu = COAP_MAX_MESSAGE_SIZE_TCP16 + 4;
214 #endif
215   session->mtu = mtu;
216   if (session->tls_overhead >= session->mtu) {
217     session->tls_overhead = session->mtu;
218     coap_log(LOG_ERR, "DTLS overhead exceeds MTU\n");
219   }
220 }
221 
coap_session_send(coap_session_t * session,const uint8_t * data,size_t datalen)222 ssize_t coap_session_send(coap_session_t *session, const uint8_t *data, size_t datalen) {
223   ssize_t bytes_written;
224 
225   coap_socket_t *sock = &session->sock;
226   if (sock->flags == COAP_SOCKET_EMPTY) {
227     assert(session->endpoint != NULL);
228     sock = &session->endpoint->sock;
229   }
230 
231   bytes_written = coap_socket_send(sock, session, data, datalen);
232   if (bytes_written == (ssize_t)datalen) {
233     coap_ticks(&session->last_rx_tx);
234     coap_log(LOG_DEBUG, "*  %s: sent %zd bytes\n",
235              coap_session_str(session), datalen);
236   } else {
237     coap_log(LOG_DEBUG, "*  %s: failed to send %zd bytes\n",
238              coap_session_str(session), datalen);
239   }
240   return bytes_written;
241 }
242 
coap_session_write(coap_session_t * session,const uint8_t * data,size_t datalen)243 ssize_t coap_session_write(coap_session_t *session, const uint8_t *data, size_t datalen) {
244   ssize_t bytes_written = coap_socket_write(&session->sock, data, datalen);
245   if (bytes_written > 0) {
246     coap_ticks(&session->last_rx_tx);
247     coap_log(LOG_DEBUG, "*  %s: sent %zd bytes\n",
248              coap_session_str(session), datalen);
249   } else if (bytes_written < 0) {
250     coap_log(LOG_DEBUG,  "*   %s: failed to send %zd bytes\n",
251              coap_session_str(session), datalen );
252   }
253   return bytes_written;
254 }
255 
256 ssize_t
coap_session_delay_pdu(coap_session_t * session,coap_pdu_t * pdu,coap_queue_t * node)257 coap_session_delay_pdu(coap_session_t *session, coap_pdu_t *pdu,
258                        coap_queue_t *node)
259 {
260   if ( node ) {
261     coap_queue_t *removed = NULL;
262     coap_remove_from_queue(&session->context->sendqueue, session, node->id, &removed);
263     assert(removed == node);
264     coap_session_release(node->session);
265     node->session = NULL;
266     node->t = 0;
267   } else {
268     coap_queue_t *q = NULL;
269     /* Check that the same tid is not getting re-used in violation of RFC7252 */
270     LL_FOREACH(session->delayqueue, q) {
271       if (q->id == pdu->tid) {
272         coap_log(LOG_ERR, "**  %s: tid=%d: already in-use - dropped\n", coap_session_str(session), pdu->tid);
273         return COAP_INVALID_TID;
274       }
275     }
276     node = coap_new_node();
277     if (node == NULL)
278       return COAP_INVALID_TID;
279     node->id = pdu->tid;
280     node->pdu = pdu;
281     if (pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto)) {
282       uint8_t r;
283       prng(&r, sizeof(r));
284       /* add timeout in range [ACK_TIMEOUT...ACK_TIMEOUT * ACK_RANDOM_FACTOR] */
285       node->timeout = coap_calc_timeout(session, r);
286     }
287   }
288   LL_APPEND(session->delayqueue, node);
289   coap_log(LOG_DEBUG, "** %s: tid=%d: delayed\n",
290            coap_session_str(session), node->id);
291   return COAP_PDU_DELAYED;
292 }
293 
coap_session_send_csm(coap_session_t * session)294 void coap_session_send_csm(coap_session_t *session) {
295   coap_pdu_t *pdu;
296   uint8_t buf[4];
297   assert(COAP_PROTO_RELIABLE(session->proto));
298   coap_log(LOG_DEBUG, "***%s: sending CSM\n", coap_session_str(session));
299   session->state = COAP_SESSION_STATE_CSM;
300   session->partial_write = 0;
301   if (session->mtu == 0)
302     session->mtu = COAP_DEFAULT_MTU;  /* base value */
303   pdu = coap_pdu_init(COAP_MESSAGE_CON, COAP_SIGNALING_CSM, 0, 16);
304   if ( pdu == NULL
305     || coap_add_option(pdu, COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE,
306          coap_encode_var_safe(buf, sizeof(buf),
307                                 COAP_DEFAULT_MAX_PDU_RX_SIZE), buf) == 0
308     || coap_pdu_encode_header(pdu, session->proto) == 0
309   ) {
310     coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE);
311   } else {
312     ssize_t bytes_written = coap_session_send_pdu(session, pdu);
313     if (bytes_written != (ssize_t)pdu->used_size + pdu->hdr_size)
314       coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE);
315   }
316   if (pdu)
317     coap_delete_pdu(pdu);
318 }
319 
coap_session_send_ping(coap_session_t * session)320 coap_tid_t coap_session_send_ping(coap_session_t *session) {
321   coap_pdu_t *ping;
322   if (session->state != COAP_SESSION_STATE_ESTABLISHED)
323     return COAP_INVALID_TID;
324   if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
325     uint16_t tid = coap_new_message_id (session);
326     ping = coap_pdu_init(COAP_MESSAGE_CON, 0, tid, 0);
327   }
328   else {
329     ping = coap_pdu_init(COAP_MESSAGE_CON, COAP_SIGNALING_PING, 0, 1);
330   }
331   if (!ping)
332     return COAP_INVALID_TID;
333   return coap_send(session, ping);
334 }
335 
coap_session_connected(coap_session_t * session)336 void coap_session_connected(coap_session_t *session) {
337   if (session->state != COAP_SESSION_STATE_ESTABLISHED) {
338     coap_log(LOG_DEBUG, "***%s: session connected\n",
339              coap_session_str(session));
340     if (session->state == COAP_SESSION_STATE_CSM)
341       coap_handle_event(session->context, COAP_EVENT_SESSION_CONNECTED, session);
342   }
343 
344   session->state = COAP_SESSION_STATE_ESTABLISHED;
345   session->partial_write = 0;
346 
347   if ( session->proto==COAP_PROTO_DTLS) {
348     session->tls_overhead = coap_dtls_get_overhead(session);
349     if (session->tls_overhead >= session->mtu) {
350       session->tls_overhead = session->mtu;
351       coap_log(LOG_ERR, "DTLS overhead exceeds MTU\n");
352     }
353   }
354 
355   while (session->delayqueue && session->state == COAP_SESSION_STATE_ESTABLISHED) {
356     ssize_t bytes_written;
357     coap_queue_t *q = session->delayqueue;
358     if (q->pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto)) {
359       if (session->con_active >= COAP_DEFAULT_NSTART)
360         break;
361       session->con_active++;
362     }
363     /* Take entry off the queue */
364     session->delayqueue = q->next;
365     q->next = NULL;
366 
367     coap_log(LOG_DEBUG, "** %s: tid=%d: transmitted after delay\n",
368              coap_session_str(session), (int)q->pdu->tid);
369     bytes_written = coap_session_send_pdu(session, q->pdu);
370     if (q->pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto)) {
371       if (coap_wait_ack(session->context, session, q) >= 0)
372         q = NULL;
373     }
374     if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
375       if (q)
376         coap_delete_node(q);
377       if (bytes_written < 0)
378         break;
379     } else {
380       if (bytes_written <= 0 || (size_t)bytes_written < q->pdu->used_size + q->pdu->hdr_size) {
381         q->next = session->delayqueue;
382         session->delayqueue = q;
383         if (bytes_written > 0)
384           session->partial_write = (size_t)bytes_written;
385         break;
386       } else {
387         coap_delete_node(q);
388       }
389     }
390   }
391 }
392 
coap_session_disconnected(coap_session_t * session,coap_nack_reason_t reason)393 void coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason) {
394   (void)reason;
395   coap_session_state_t state = session->state;
396 
397   coap_log(LOG_DEBUG, "***%s: session disconnected (reason %d)\n",
398            coap_session_str(session), reason);
399 #ifndef WITHOUT_OBSERVE
400   coap_delete_observers( session->context, session );
401 #endif
402 
403   if ( session->tls) {
404     if (session->proto == COAP_PROTO_DTLS)
405       coap_dtls_free_session(session);
406     else if (session->proto == COAP_PROTO_TLS)
407       coap_tls_free_session(session);
408     session->tls = NULL;
409   }
410 
411   if (session->proto == COAP_PROTO_UDP)
412     session->state = COAP_SESSION_STATE_ESTABLISHED;
413   else
414     session->state = COAP_SESSION_STATE_NONE;
415 
416   session->con_active = 0;
417 
418   if (session->partial_pdu) {
419     coap_delete_pdu(session->partial_pdu);
420     session->partial_pdu = NULL;
421   }
422   session->partial_read = 0;
423 
424   while (session->delayqueue) {
425     coap_queue_t *q = session->delayqueue;
426     session->delayqueue = q->next;
427     q->next = NULL;
428     coap_log(LOG_DEBUG, "** %s: tid=%d: not transmitted after disconnect\n",
429              coap_session_str(session), q->id);
430     if (q->pdu->type==COAP_MESSAGE_CON
431       && COAP_PROTO_NOT_RELIABLE(session->proto)
432       && reason == COAP_NACK_ICMP_ISSUE)
433     {
434       /* Make sure that we try a re-transmit later on ICMP error */
435       if (coap_wait_ack(session->context, session, q) >= 0)
436         q = NULL;
437     }
438     if (q && q->pdu->type == COAP_MESSAGE_CON
439       && session->context->nack_handler)
440     {
441       session->context->nack_handler(session->context, session, q->pdu,
442                                      reason, q->id);
443     }
444     if (q)
445       coap_delete_node(q);
446   }
447   if (reason != COAP_NACK_ICMP_ISSUE)
448     coap_cancel_session_messages(session->context, session, reason);
449 
450   if ( COAP_PROTO_RELIABLE(session->proto) ) {
451     if (session->sock.flags != COAP_SOCKET_EMPTY) {
452       coap_socket_close(&session->sock);
453       coap_handle_event(session->context,
454         state == COAP_SESSION_STATE_CONNECTING ?
455         COAP_EVENT_TCP_FAILED : COAP_EVENT_TCP_CLOSED, session);
456     }
457     if (state != COAP_SESSION_STATE_NONE) {
458       coap_handle_event(session->context,
459         state == COAP_SESSION_STATE_ESTABLISHED ?
460         COAP_EVENT_SESSION_CLOSED : COAP_EVENT_SESSION_FAILED, session);
461     }
462   }
463 }
464 
loopback_packet_check(const char * srcbuf)465 static int32_t loopback_packet_check(const char *srcbuf) {
466   const char addr_perface[] = "::ffff:";
467   char tmpbuf[INET6_ADDRSTRLEN] = {0};
468   int ret;
469   void *tmp_addr_ptr = NULL;
470   struct ifreq buf[COAP_INTERFACE_MAX];
471   struct ifconf ifc = {0};
472 
473   int fd = socket(AF_INET, SOCK_DGRAM, 0);
474   if (fd < 0) {
475     coap_log(LOG_DEBUG, "socket() fail\n");
476     return 1;
477   }
478   ifc.ifc_len = sizeof(buf);
479   ifc.ifc_buf = (char *)buf;
480   if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0) {
481     coap_log(LOG_DEBUG, "ioctl fail, errno = %d\n", errno);
482     goto L_IS_LOOPBACK;
483   }
484   int interfaceNum = ifc.ifc_len / sizeof(struct ifreq);
485   for (int i = 0; i < interfaceNum && i < COAP_INTERFACE_MAX; i++) {
486     coap_log(LOG_DEBUG, "interface name: %s\n", buf[i].ifr_name);
487     /* get IP of this interface */
488     if (ioctl(fd, SIOCGIFADDR, (char *)&buf[i]) < 0) {
489       coap_log(LOG_DEBUG, "ioctl fail, errno = %d\n", errno);
490       goto L_IS_LOOPBACK;
491     }
492     tmp_addr_ptr = &((struct sockaddr_in *)&(buf[i].ifr_addr))->sin_addr;
493     inet_ntop(AF_INET, tmp_addr_ptr, tmpbuf, INET_ADDRSTRLEN);
494     if (memcmp(srcbuf, addr_perface, strlen(addr_perface)) == 0 &&
495         strlen(srcbuf) == strlen(tmpbuf) + strlen(addr_perface)) {
496       ret = memcmp(srcbuf + strlen(addr_perface), tmpbuf, strlen(srcbuf) - strlen(addr_perface));
497     } else {
498       if (strlen(srcbuf) == strlen(tmpbuf)) {
499         ret = memcmp(srcbuf, tmpbuf, strlen(srcbuf));
500       } else {
501         ret = 1;
502       }
503     }
504     if (ret == 0) {
505       goto L_IS_LOOPBACK;
506     }
507   }
508   close(fd);
509   return 0;
510 L_IS_LOOPBACK:
511   close(fd);
512   return 1;
513 }
514 
is_loopback_packet(const coap_packet_t * packet)515 static int32_t is_loopback_packet(const coap_packet_t *packet) {
516   char srcbuf[INET6_ADDRSTRLEN] = {0};
517 
518   coap_address_ntop(&(packet->addr_info.remote), srcbuf, INET6_ADDRSTRLEN);
519 
520   return loopback_packet_check(srcbuf);
521 }
522 
523 coap_session_t *
coap_endpoint_get_session(coap_endpoint_t * endpoint,const coap_packet_t * packet,coap_tick_t now)524 coap_endpoint_get_session(coap_endpoint_t *endpoint,
525   const coap_packet_t *packet, coap_tick_t now) {
526   coap_session_t *session;
527   coap_session_t *rtmp;
528   unsigned int num_idle = 0;
529   unsigned int num_hs = 0;
530   coap_session_t *oldest = NULL;
531   coap_session_t *oldest_hs = NULL;
532 
533   if (is_loopback_packet(packet) == 1) {
534       coap_log(LOG_DEBUG, "drop loopback packet.");
535     return NULL;
536   }
537 
538   SESSIONS_FIND(endpoint->sessions, packet->addr_info, session);
539   if (session) {
540     session->last_rx_tx = now;
541     return session;
542   }
543 
544   SESSIONS_ITER(endpoint->sessions, session, rtmp) {
545     if (session->ref == 0 && session->delayqueue == NULL) {
546       if (session->type == COAP_SESSION_TYPE_SERVER) {
547         ++num_idle;
548         if (oldest==NULL || session->last_rx_tx < oldest->last_rx_tx)
549           oldest = session;
550 
551         if (session->state == COAP_SESSION_STATE_HANDSHAKE) {
552           ++num_hs;
553           /* See if this is a partial (D)TLS session set up
554              which needs to be cleared down to prevent DOS */
555           if ((session->last_rx_tx + COAP_PARTIAL_SESSION_TIMEOUT_TICKS) < now) {
556             if (oldest_hs == NULL ||
557                 session->last_rx_tx < oldest_hs->last_rx_tx)
558               oldest_hs = session;
559           }
560         }
561       }
562       else if (session->type == COAP_SESSION_TYPE_HELLO) {
563         ++num_hs;
564         /* See if this is a partial (D)TLS session set up for Client Hello
565            which needs to be cleared down to prevent DOS */
566         if ((session->last_rx_tx + COAP_PARTIAL_SESSION_TIMEOUT_TICKS) < now) {
567           if (oldest_hs == NULL ||
568               session->last_rx_tx < oldest_hs->last_rx_tx)
569             oldest_hs = session;
570         }
571       }
572     }
573   }
574 
575   if (endpoint->context->max_idle_sessions > 0 &&
576       num_idle >= endpoint->context->max_idle_sessions) {
577     coap_session_free(oldest);
578   }
579   else if (oldest_hs) {
580     coap_log(LOG_WARNING, "***%s: Incomplete session timed out\n",
581              coap_session_str(oldest_hs));
582     coap_session_free(oldest_hs);
583   }
584 
585   if (num_hs > (endpoint->context->max_handshake_sessions ?
586               endpoint->context->max_handshake_sessions :
587               COAP_DEFAULT_MAX_HANDSHAKE_SESSIONS)) {
588     /* Maxed out on number of sessions in (D)TLS negotiation state */
589     coap_log(LOG_DEBUG,
590              "Oustanding sessions in COAP_SESSION_STATE_HANDSHAKE too "
591              "large.  New request ignored\n");
592     return NULL;
593   }
594 
595   if (endpoint->proto == COAP_PROTO_DTLS) {
596     /*
597      * Need to check that this actually is a Client Hello before wasting
598      * time allocating and then freeing off session.
599      */
600 
601     /*
602      * Generic header structure of the DTLS record layer.
603      * typedef struct __attribute__((__packed__)) {
604      *   uint8_t content_type;           content type of the included message
605      *   uint16_t version;               Protocol version
606      *   uint16_t epoch;                 counter for cipher state changes
607      *   uint8_t sequence_number[6];     sequence number
608      *   uint16_t length;                length of the following fragment
609      *   uint8_t handshake;              If content_type == DTLS_CT_HANDSHAKE
610      * } dtls_record_handshake_t;
611      */
612 #define OFF_CONTENT_TYPE      0  /* offset of content_type in dtls_record_handshake_t */
613 #define DTLS_CT_ALERT        21  /* Content Type Alert */
614 #define DTLS_CT_HANDSHAKE    22  /* Content Type Handshake */
615 #define OFF_HANDSHAKE_TYPE   13  /* offset of handshake in dtls_record_handshake_t */
616 #define DTLS_HT_CLIENT_HELLO  1  /* Client Hello handshake type */
617 
618 #ifdef WITH_LWIP
619     const uint8_t *payload = (const uint8_t*)packet->pbuf->payload;
620     size_t length = packet->pbuf->len;
621 #else /* ! WITH_LWIP */
622     const uint8_t *payload = (const uint8_t*)packet->payload;
623     size_t length = packet->length;
624 #endif /* ! WITH_LWIP */
625     if (length < (OFF_HANDSHAKE_TYPE + 1)) {
626       coap_log(LOG_DEBUG,
627          "coap_dtls_hello: ContentType %d Short Packet (%zu < %d) dropped\n",
628          payload[OFF_CONTENT_TYPE], length,
629          OFF_HANDSHAKE_TYPE + 1);
630       return NULL;
631     }
632     if (payload[OFF_CONTENT_TYPE] != DTLS_CT_HANDSHAKE ||
633         payload[OFF_HANDSHAKE_TYPE] != DTLS_HT_CLIENT_HELLO) {
634       /* only log if not a late alert */
635       if (payload[OFF_CONTENT_TYPE] != DTLS_CT_ALERT)
636         coap_log(LOG_DEBUG,
637          "coap_dtls_hello: ContentType %d Handshake %d dropped\n",
638          payload[OFF_CONTENT_TYPE], payload[OFF_HANDSHAKE_TYPE]);
639       return NULL;
640     }
641   }
642   session = coap_make_session(endpoint->proto, COAP_SESSION_TYPE_SERVER,
643                               NULL, &packet->addr_info.local,
644                               &packet->addr_info.remote,
645                               packet->ifindex, endpoint->context, endpoint);
646   if (session) {
647     session->last_rx_tx = now;
648     if (endpoint->proto == COAP_PROTO_UDP)
649       session->state = COAP_SESSION_STATE_ESTABLISHED;
650     else if (endpoint->proto == COAP_PROTO_DTLS) {
651       session->type = COAP_SESSION_TYPE_HELLO;
652     }
653     SESSIONS_ADD(endpoint->sessions, session);
654     coap_log(LOG_DEBUG, "***%s: new incoming session\n",
655              coap_session_str(session));
656   }
657   return session;
658 }
659 
660 coap_session_t *
coap_session_new_dtls_session(coap_session_t * session,coap_tick_t now)661 coap_session_new_dtls_session(coap_session_t *session,
662   coap_tick_t now) {
663   if (session) {
664     session->last_rx_tx = now;
665     session->type = COAP_SESSION_TYPE_SERVER;
666     session->tls = coap_dtls_new_server_session(session);
667     if (session->tls) {
668       session->state = COAP_SESSION_STATE_HANDSHAKE;
669     } else {
670       coap_session_free(session);
671       session = NULL;
672     }
673   }
674   return session;
675 }
676 
677 #ifdef COAP_EPOLL_SUPPORT
678 static void
coap_epoll_ctl_add(coap_socket_t * sock,uint32_t events,const char * func)679 coap_epoll_ctl_add(coap_socket_t *sock,
680                    uint32_t events,
681                    const char *func
682 ) {
683   int ret;
684   struct epoll_event event;
685   coap_context_t *context;
686 
687   if (sock == NULL)
688     return;
689 
690   context = sock->session ? sock->session->context :
691                             sock->endpoint ? sock->endpoint->context : NULL;
692   if (context == NULL)
693     return;
694 
695   /* Needed if running 32bit as ptr is only 32bit */
696   memset(&event, 0, sizeof(event));
697   event.events = events;
698   event.data.ptr = sock;
699 
700   ret = epoll_ctl(context->epfd, EPOLL_CTL_ADD, sock->fd, &event);
701   if (ret == -1) {
702      coap_log(LOG_ERR,
703               "%s: epoll_ctl ADD failed: %s (%d)\n",
704               func,
705               coap_socket_strerror(), errno);
706   }
707 }
708 #endif /* COAP_EPOLL_SUPPORT */
709 
710 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)711 coap_session_create_client(
712   coap_context_t *ctx,
713   const coap_address_t *local_if,
714   const coap_address_t *server,
715   coap_proto_t proto
716 ) {
717   coap_session_t *session = NULL;
718 
719   assert(server);
720   assert(proto != COAP_PROTO_NONE);
721 
722   session = coap_make_session(proto, COAP_SESSION_TYPE_CLIENT, local_if,
723     local_if, server, 0, ctx, NULL);
724   if (!session)
725     goto error;
726 
727   coap_session_reference(session);
728 
729   if (proto == COAP_PROTO_UDP || proto == COAP_PROTO_DTLS) {
730     if (!coap_socket_connect_udp(&session->sock, &session->local_if, server,
731       proto == COAP_PROTO_DTLS ? COAPS_DEFAULT_PORT : COAP_DEFAULT_PORT,
732       &session->addr_info.local, &session->addr_info.remote)) {
733       goto error;
734     }
735   } else if (proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS) {
736     if (!coap_socket_connect_tcp1(&session->sock, &session->local_if, server,
737       proto == COAP_PROTO_TLS ? COAPS_DEFAULT_PORT : COAP_DEFAULT_PORT,
738       &session->addr_info.local, &session->addr_info.remote)) {
739       goto error;
740     }
741   }
742 
743   session->sock.session = session;
744 #ifdef COAP_EPOLL_SUPPORT
745   coap_epoll_ctl_add(&session->sock,
746                      EPOLLIN |
747                       ((session->sock.flags & COAP_SOCKET_WANT_CONNECT) ?
748                        EPOLLOUT : 0),
749                    __func__);
750 #endif /* COAP_EPOLL_SUPPORT */
751 
752   session->sock.flags |= COAP_SOCKET_NOT_EMPTY | COAP_SOCKET_WANT_READ;
753   if (local_if)
754     session->sock.flags |= COAP_SOCKET_BOUND;
755   SESSIONS_ADD(ctx->sessions, session);
756   return session;
757 
758 error:
759   coap_session_release(session);
760   return NULL;
761 }
762 
763 static coap_session_t *
coap_session_connect(coap_session_t * session)764 coap_session_connect(coap_session_t *session) {
765   if (session->proto == COAP_PROTO_UDP) {
766     session->state = COAP_SESSION_STATE_ESTABLISHED;
767   } else if (session->proto == COAP_PROTO_DTLS) {
768     session->tls = coap_dtls_new_client_session(session);
769     if (session->tls) {
770       session->state = COAP_SESSION_STATE_HANDSHAKE;
771     } else {
772       /* Need to free session object. As a new session may not yet
773        * have been referenced, we call coap_session_reference() first
774        * before trying to release the object.
775        */
776       coap_session_reference(session);
777       coap_session_release(session);
778       return NULL;
779     }
780   } else if (session->proto == COAP_PROTO_TCP || session->proto == COAP_PROTO_TLS) {
781     if (session->sock.flags & COAP_SOCKET_WANT_CONNECT) {
782       session->state = COAP_SESSION_STATE_CONNECTING;
783     } else if (session->proto == COAP_PROTO_TLS) {
784       int connected = 0;
785       session->tls = coap_tls_new_client_session(session, &connected);
786       if (session->tls) {
787         session->state = COAP_SESSION_STATE_HANDSHAKE;
788         if (connected)
789           coap_session_send_csm(session);
790       } else {
791         /* Need to free session object. As a new session may not yet
792          * have been referenced, we call coap_session_reference()
793          * first before trying to release the object.
794          */
795         coap_session_reference(session);
796         coap_session_release(session);
797         return NULL;
798       }
799     } else {
800       coap_session_send_csm(session);
801     }
802   }
803   coap_ticks(&session->last_rx_tx);
804   return session;
805 }
806 
807 static coap_session_t *
coap_session_accept(coap_session_t * session)808 coap_session_accept(coap_session_t *session) {
809   if (session->proto == COAP_PROTO_TCP || session->proto == COAP_PROTO_TLS)
810     coap_handle_event(session->context, COAP_EVENT_TCP_CONNECTED, session);
811   if (session->proto == COAP_PROTO_TCP) {
812     coap_session_send_csm(session);
813   } else if (session->proto == COAP_PROTO_TLS) {
814     int connected = 0;
815     session->tls = coap_tls_new_server_session(session, &connected);
816     if (session->tls) {
817       session->state = COAP_SESSION_STATE_HANDSHAKE;
818       if (connected) {
819         coap_handle_event(session->context, COAP_EVENT_DTLS_CONNECTED, session);
820         coap_session_send_csm(session);
821       }
822     } else {
823       /* Need to free session object. As a new session may not yet
824        * have been referenced, we call coap_session_reference() first
825        * before trying to release the object.
826        */
827       coap_session_reference(session);
828       coap_session_release(session);
829       session = NULL;
830     }
831   }
832   return session;
833 }
834 
coap_new_client_session(struct coap_context_t * ctx,const coap_address_t * local_if,const coap_address_t * server,coap_proto_t proto)835 coap_session_t *coap_new_client_session(
836   struct coap_context_t *ctx,
837   const coap_address_t *local_if,
838   const coap_address_t *server,
839   coap_proto_t proto
840 ) {
841   coap_session_t *session = coap_session_create_client(ctx, local_if, server, proto);
842   if (session) {
843     coap_log(LOG_DEBUG, "***%s: new outgoing session\n",
844              coap_session_str(session));
845     session = coap_session_connect(session);
846   }
847   return session;
848 }
849 
coap_new_client_session_psk(struct 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)850 coap_session_t *coap_new_client_session_psk(
851   struct coap_context_t *ctx,
852   const coap_address_t *local_if,
853   const coap_address_t *server,
854   coap_proto_t proto,
855   const char *identity,
856   const uint8_t *key,
857   unsigned key_len
858 ) {
859   coap_session_t *session = coap_session_create_client(ctx, local_if, server, proto);
860 
861   if (!session)
862     return NULL;
863 
864   if (identity && (strlen(identity) > 0)) {
865     size_t identity_len = strlen(identity);
866     session->psk_identity = (uint8_t*)coap_malloc(identity_len);
867     if (session->psk_identity) {
868       memcpy(session->psk_identity, identity, identity_len);
869       session->psk_identity_len = identity_len;
870     } else {
871       coap_log(LOG_WARNING, "Cannot store session PSK identity\n");
872       coap_session_release(session);
873       return NULL;
874     }
875   }
876   else if (coap_dtls_is_supported()) {
877     coap_log(LOG_WARNING, "PSK identity not defined\n");
878     coap_session_release(session);
879     return NULL;
880   }
881 
882   if (key && key_len > 0) {
883     session->psk_key = (uint8_t*)coap_malloc(key_len);
884     if (session->psk_key) {
885       memcpy(session->psk_key, key, key_len);
886       session->psk_key_len = key_len;
887     } else {
888       coap_log(LOG_WARNING, "Cannot store session PSK key\n");
889       coap_session_release(session);
890       return NULL;
891     }
892   }
893   else if (coap_dtls_is_supported()) {
894     coap_log(LOG_WARNING, "PSK key not defined\n");
895     coap_session_release(session);
896     return NULL;
897   }
898 
899   if (coap_dtls_is_supported()) {
900     if (!coap_dtls_context_set_psk(ctx, NULL, COAP_DTLS_ROLE_CLIENT)) {
901       coap_session_release(session);
902       return NULL;
903     }
904   }
905   coap_log(LOG_DEBUG, "***%s: new outgoing session\n",
906            coap_session_str(session));
907   return coap_session_connect(session);
908 }
909 
coap_new_client_session_pki(struct 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)910 coap_session_t *coap_new_client_session_pki(
911   struct coap_context_t *ctx,
912   const coap_address_t *local_if,
913   const coap_address_t *server,
914   coap_proto_t proto,
915   coap_dtls_pki_t* setup_data
916 ) {
917   coap_session_t *session;
918 
919   if (coap_dtls_is_supported()) {
920     if (!setup_data) {
921       return NULL;
922     } else {
923       if (setup_data->version != COAP_DTLS_PKI_SETUP_VERSION) {
924         coap_log(LOG_ERR,
925                  "coap_new_client_session_pki: Wrong version of setup_data\n");
926         return NULL;
927       }
928     }
929 
930   }
931   session = coap_session_create_client(ctx, local_if, server, proto);
932 
933   if (!session) {
934     return NULL;
935   }
936 
937   if (coap_dtls_is_supported()) {
938     /* we know that setup_data is not NULL */
939     if (!coap_dtls_context_set_pki(ctx, setup_data, COAP_DTLS_ROLE_CLIENT)) {
940       coap_session_release(session);
941       return NULL;
942     }
943   }
944   coap_log(LOG_DEBUG, "***%s: new outgoing session\n",
945            coap_session_str(session));
946   return coap_session_connect(session);
947 }
948 
949 
coap_new_server_session(struct coap_context_t * ctx,coap_endpoint_t * ep)950 coap_session_t *coap_new_server_session(
951   struct coap_context_t *ctx,
952   coap_endpoint_t *ep
953 ) {
954   coap_session_t *session;
955   session = coap_make_session( ep->proto, COAP_SESSION_TYPE_SERVER,
956                                &ep->bind_addr, NULL, NULL, 0, ctx, ep );
957   if (!session)
958     goto error;
959 
960   if (!coap_socket_accept_tcp(&ep->sock, &session->sock,
961                               &session->addr_info.local,
962                               &session->addr_info.remote))
963     goto error;
964   session->sock.flags |= COAP_SOCKET_NOT_EMPTY | COAP_SOCKET_CONNECTED
965                        | COAP_SOCKET_WANT_READ;
966   session->sock.session = session;
967 #ifdef COAP_EPOLL_SUPPORT
968   coap_epoll_ctl_add(&session->sock,
969                      EPOLLIN,
970                    __func__);
971 #endif /* COAP_EPOLL_SUPPORT */
972   SESSIONS_ADD(ep->sessions, session);
973   if (session) {
974     coap_log(LOG_DEBUG, "***%s: new incoming session\n",
975              coap_session_str(session));
976     session = coap_session_accept(session);
977   }
978   return session;
979 
980 error:
981   coap_session_free(session);
982   return NULL;
983 }
984 
985 #ifndef WITH_LWIP
986 coap_endpoint_t *
coap_new_endpoint(coap_context_t * context,const coap_address_t * listen_addr,coap_proto_t proto)987 coap_new_endpoint(coap_context_t *context, const coap_address_t *listen_addr, coap_proto_t proto) {
988   struct coap_endpoint_t *ep = NULL;
989 
990   assert(context);
991   assert(listen_addr);
992   assert(proto != COAP_PROTO_NONE);
993 
994   if (proto == COAP_PROTO_DTLS && !coap_dtls_is_supported()) {
995     coap_log(LOG_CRIT, "coap_new_endpoint: DTLS not supported\n");
996     goto error;
997   }
998 
999   if (proto == COAP_PROTO_TLS && !coap_tls_is_supported()) {
1000     coap_log(LOG_CRIT, "coap_new_endpoint: TLS not supported\n");
1001     goto error;
1002   }
1003 
1004   if (proto == COAP_PROTO_DTLS || proto == COAP_PROTO_TLS) {
1005     if (!coap_dtls_context_check_keys_enabled(context)) {
1006       coap_log(LOG_INFO,
1007                "coap_new_endpoint: one of coap_context_set_psk() or "
1008                "coap_context_set_pki() not called\n");
1009       goto error;
1010     }
1011   }
1012 
1013   ep = coap_malloc_endpoint();
1014   if (!ep) {
1015     coap_log(LOG_WARNING, "coap_new_endpoint: malloc");
1016     goto error;
1017   }
1018 
1019   memset(ep, 0, sizeof(struct coap_endpoint_t));
1020   ep->context = context;
1021   ep->proto = proto;
1022 
1023   if (proto==COAP_PROTO_TCP || proto==COAP_PROTO_TLS) {
1024     if (!coap_socket_bind_tcp(&ep->sock, listen_addr, &ep->bind_addr))
1025       goto error;
1026     ep->sock.flags |= COAP_SOCKET_WANT_ACCEPT;
1027   } else if (proto==COAP_PROTO_UDP || proto==COAP_PROTO_DTLS) {
1028     if (!coap_socket_bind_udp(&ep->sock, listen_addr, &ep->bind_addr))
1029       goto error;
1030     ep->sock.flags |= COAP_SOCKET_WANT_READ;
1031   } else {
1032     coap_log(LOG_CRIT, "coap_new_endpoint: protocol not supported\n");
1033     goto error;
1034   }
1035 
1036   if (LOG_DEBUG <= coap_get_log_level()) {
1037 #ifndef INET6_ADDRSTRLEN
1038 #define INET6_ADDRSTRLEN 40
1039 #endif
1040     unsigned char addr_str[INET6_ADDRSTRLEN + 8];
1041 
1042     if (coap_print_addr(&ep->bind_addr, addr_str, INET6_ADDRSTRLEN + 8)) {
1043       coap_log(LOG_DEBUG, "created %s endpoint %s\n",
1044           ep->proto == COAP_PROTO_TLS ? "TLS "
1045         : ep->proto == COAP_PROTO_TCP ? "TCP "
1046         : ep->proto == COAP_PROTO_DTLS ? "DTLS" : "UDP ",
1047         addr_str);
1048     }
1049   }
1050 
1051   ep->sock.flags |= COAP_SOCKET_NOT_EMPTY | COAP_SOCKET_BOUND;
1052 
1053   ep->default_mtu = COAP_DEFAULT_MTU;
1054 
1055   ep->sock.endpoint = ep;
1056 #ifdef COAP_EPOLL_SUPPORT
1057   coap_epoll_ctl_add(&ep->sock,
1058                      EPOLLIN,
1059                    __func__);
1060 #endif /* COAP_EPOLL_SUPPORT */
1061 
1062   LL_PREPEND(context->endpoint, ep);
1063   return ep;
1064 
1065 error:
1066   coap_free_endpoint(ep);
1067   return NULL;
1068 }
1069 
coap_endpoint_set_default_mtu(coap_endpoint_t * ep,unsigned mtu)1070 void coap_endpoint_set_default_mtu(coap_endpoint_t *ep, unsigned mtu) {
1071   ep->default_mtu = (uint16_t)mtu;
1072 }
1073 
1074 void
coap_free_endpoint(coap_endpoint_t * ep)1075 coap_free_endpoint(coap_endpoint_t *ep) {
1076   if (ep) {
1077     coap_session_t *session, *rtmp;
1078 
1079     if (ep->sock.flags != COAP_SOCKET_EMPTY)
1080       coap_socket_close(&ep->sock);
1081 
1082     SESSIONS_ITER_SAFE(ep->sessions, session, rtmp) {
1083       assert(session->ref == 0);
1084       if (session->ref == 0) {
1085         coap_session_free(session);
1086       }
1087     }
1088 
1089     if (ep->context && ep->context->endpoint) {
1090       LL_DELETE(ep->context->endpoint, ep);
1091     }
1092     coap_mfree_endpoint(ep);
1093   }
1094 }
1095 #endif /* WITH_LWIP */
1096 
1097 coap_session_t *
coap_session_get_by_peer(coap_context_t * ctx,const coap_address_t * remote_addr,int ifindex)1098 coap_session_get_by_peer(coap_context_t *ctx,
1099   const coap_address_t *remote_addr,
1100   int ifindex) {
1101   coap_session_t *s, *rtmp;
1102   coap_endpoint_t *ep;
1103   SESSIONS_ITER(ctx->sessions, s, rtmp) {
1104     if (s->ifindex == ifindex && coap_address_equals(&s->addr_info.remote,
1105                                                      remote_addr))
1106       return s;
1107   }
1108   LL_FOREACH(ctx->endpoint, ep) {
1109     SESSIONS_ITER(ep->sessions, s, rtmp) {
1110       if (s->ifindex == ifindex && coap_address_equals(&s->addr_info.remote,
1111                                                        remote_addr))
1112         return s;
1113     }
1114   }
1115   return NULL;
1116 }
1117 
coap_session_str(const coap_session_t * session)1118 const char *coap_session_str(const coap_session_t *session) {
1119   static char szSession[256];
1120   char *p = szSession, *end = szSession + sizeof(szSession);
1121   if (coap_print_addr(&session->addr_info.local,
1122                       (unsigned char*)p, end - p) > 0)
1123     p += strlen(p);
1124   if (p + 6 < end) {
1125     strcpy(p, " <-> ");
1126     p += 5;
1127   }
1128   if (p + 1 < end) {
1129     if (coap_print_addr(&session->addr_info.remote,
1130                         (unsigned char*)p, end - p) > 0)
1131       p += strlen(p);
1132   }
1133   if (session->ifindex > 0 && p + 1 < end)
1134     p += snprintf(p, end - p, " (if%d)", session->ifindex);
1135   if (p + 6 < end) {
1136     if (session->proto == COAP_PROTO_UDP) {
1137       strcpy(p, " UDP ");
1138       p += 4;
1139     } else if (session->proto == COAP_PROTO_DTLS) {
1140       strcpy(p, " DTLS");
1141       p += 5;
1142     } else if (session->proto == COAP_PROTO_TCP) {
1143       strcpy(p, " TCP ");
1144       p += 4;
1145     } else if (session->proto == COAP_PROTO_TLS) {
1146       strcpy(p, " TLS ");
1147       p += 4;
1148     } else {
1149       strcpy(p, " NONE");
1150       p += 5;
1151     }
1152   }
1153 
1154   return szSession;
1155 }
1156 
coap_endpoint_str(const coap_endpoint_t * endpoint)1157 const char *coap_endpoint_str(const coap_endpoint_t *endpoint) {
1158   static char szEndpoint[128];
1159   char *p = szEndpoint, *end = szEndpoint + sizeof(szEndpoint);
1160   if (coap_print_addr(&endpoint->bind_addr, (unsigned char*)p, end - p) > 0)
1161     p += strlen(p);
1162   if (p + 6 < end) {
1163     if (endpoint->proto == COAP_PROTO_UDP) {
1164       strcpy(p, " UDP");
1165       p += 4;
1166     } else if (endpoint->proto == COAP_PROTO_DTLS) {
1167       strcpy(p, " DTLS");
1168       p += 5;
1169     } else {
1170       strcpy(p, " NONE");
1171       p += 5;
1172     }
1173   }
1174 
1175   return szEndpoint;
1176 }
1177 
1178 #endif  /* COAP_SESSION_C_ */
1179