libcoap 4.3.1
coap_io.c
Go to the documentation of this file.
1/* coap_io.c -- Default network I/O functions for libcoap
2 *
3 * Copyright (C) 2012,2014,2016-2022 Olaf Bergmann <bergmann@tzi.org> and others
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
16#include "coap3/coap_internal.h"
17
18#ifdef HAVE_STDIO_H
19# include <stdio.h>
20#endif
21
22#ifdef HAVE_SYS_SELECT_H
23# include <sys/select.h>
24#endif
25#ifdef HAVE_SYS_SOCKET_H
26# include <sys/socket.h>
27# define OPTVAL_T(t) (t)
28# define OPTVAL_GT(t) (t)
29#endif
30#ifdef HAVE_SYS_IOCTL_H
31 #include <sys/ioctl.h>
32#endif
33#ifdef HAVE_NETINET_IN_H
34# include <netinet/in.h>
35#endif
36#ifdef HAVE_WS2TCPIP_H
37#include <ws2tcpip.h>
38# define OPTVAL_T(t) (const char*)(t)
39# define OPTVAL_GT(t) (char*)(t)
40# undef CMSG_DATA
41# define CMSG_DATA WSA_CMSG_DATA
42#endif
43#ifdef HAVE_SYS_UIO_H
44# include <sys/uio.h>
45#endif
46#ifdef HAVE_UNISTD_H
47# include <unistd.h>
48#endif
49#include <errno.h>
50#ifdef COAP_EPOLL_SUPPORT
51#include <sys/epoll.h>
52#include <sys/timerfd.h>
53#ifdef HAVE_LIMITS_H
54#include <limits.h>
55#endif
56#endif /* COAP_EPOLL_SUPPORT */
57
58#ifdef WITH_CONTIKI
59# include "uip.h"
60#endif
61
62#if !defined(WITH_CONTIKI) && !defined(RIOT_VERSION)
63 /* define generic PKTINFO for IPv4 */
64#if defined(IP_PKTINFO)
65# define GEN_IP_PKTINFO IP_PKTINFO
66#elif defined(IP_RECVDSTADDR)
67# define GEN_IP_PKTINFO IP_RECVDSTADDR
68#else
69# error "Need IP_PKTINFO or IP_RECVDSTADDR to request ancillary data from OS."
70#endif /* IP_PKTINFO */
71
72/* define generic KTINFO for IPv6 */
73#ifdef IPV6_RECVPKTINFO
74# define GEN_IPV6_PKTINFO IPV6_RECVPKTINFO
75#elif defined(IPV6_PKTINFO)
76# define GEN_IPV6_PKTINFO IPV6_PKTINFO
77#else
78# error "Need IPV6_PKTINFO or IPV6_RECVPKTINFO to request ancillary data from OS."
79#endif /* IPV6_RECVPKTINFO */
80#endif /* !(WITH_CONTIKI || RIOT_VERSION) */
81
82#ifdef WITH_CONTIKI
83static int ep_initialized = 0;
84
87 static coap_endpoint_t ep;
88
89 if (ep_initialized) {
90 return NULL;
91 } else {
92 ep_initialized = 1;
93 return &ep;
94 }
95}
96
97void
99 ep_initialized = 0;
100}
101
102int
104 const coap_address_t *listen_addr,
105 coap_address_t *bound_addr) {
106 sock->conn = udp_new(NULL, 0, NULL);
107
108 if (!sock->conn) {
109 coap_log(LOG_WARNING, "coap_socket_bind_udp");
110 return 0;
111 }
112
113 coap_address_init(bound_addr);
114 uip_ipaddr_copy(&bound_addr->addr, &listen_addr->addr);
115 bound_addr->port = listen_addr->port;
116 udp_bind((struct uip_udp_conn *)sock->conn, bound_addr->port);
117 return 1;
118}
119
120int
122 const coap_address_t *local_if,
123 const coap_address_t *server,
124 int default_port,
125 coap_address_t *local_addr,
126 coap_address_t *remote_addr) {
127 return 0;
128}
129
130ssize_t
131coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len) {
132 return -1;
133}
134
135ssize_t
136coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len) {
137 return -1;
138}
139
141 if (sock->conn)
142 uip_udp_remove((struct uip_udp_conn *)sock->conn);
143 sock->flags = COAP_SOCKET_EMPTY;
144}
145
146#else
147
148#if COAP_SERVER_SUPPORT
152}
153
154void
157}
158#endif /* COAP_SERVER_SUPPORT */
159
160int
162 const coap_address_t *listen_addr,
163 coap_address_t *bound_addr) {
164#ifndef RIOT_VERSION
165 int on = 1, off = 0;
166#endif /* RIOT_VERSION */
167#ifdef _WIN32
168 u_long u_on = 1;
169#endif
170
171 sock->fd = socket(listen_addr->addr.sa.sa_family, SOCK_DGRAM, 0);
172
173 if (sock->fd == COAP_INVALID_SOCKET) {
175 "coap_socket_bind_udp: socket: %s\n", coap_socket_strerror());
176 goto error;
177 }
178#ifndef RIOT_VERSION
179#ifdef _WIN32
180 if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) {
181#else
182 if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) {
183#endif
185 "coap_socket_bind_udp: ioctl FIONBIO: %s\n", coap_socket_strerror());
186 }
187
188#ifndef RIOT_VERSION
189 if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
191 "coap_socket_bind_udp: setsockopt SO_REUSEADDR: %s\n",
193#endif /* RIOT_VERSION */
194
195 switch (listen_addr->addr.sa.sa_family) {
196 case AF_INET:
197 if (setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
199 "coap_socket_bind_udp: setsockopt IP_PKTINFO: %s\n",
201 break;
202 case AF_INET6:
203 /* Configure the socket as dual-stacked */
204 if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off), sizeof(off)) == COAP_SOCKET_ERROR)
206 "coap_socket_bind_udp: setsockopt IPV6_V6ONLY: %s\n",
208#if !defined(ESPIDF_VERSION)
209 if (setsockopt(sock->fd, IPPROTO_IPV6, GEN_IPV6_PKTINFO, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
211 "coap_socket_bind_udp: setsockopt IPV6_PKTINFO: %s\n",
213#endif /* !defined(ESPIDF_VERSION) */
214 setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on), sizeof(on));
215 /* ignore error, because likely cause is that IPv4 is disabled at the os
216 level */
217 break;
218 default:
219 coap_log(LOG_ALERT, "coap_socket_bind_udp: unsupported sa_family\n");
220 break;
221 }
222#endif /* RIOT_VERSION */
223
224 if (bind(sock->fd, &listen_addr->addr.sa,
225 listen_addr->addr.sa.sa_family == AF_INET ?
226 (socklen_t)sizeof(struct sockaddr_in) :
227 (socklen_t)listen_addr->size) == COAP_SOCKET_ERROR) {
228 coap_log(LOG_WARNING, "coap_socket_bind_udp: bind: %s\n",
230 goto error;
231 }
232
233 bound_addr->size = (socklen_t)sizeof(*bound_addr);
234 if (getsockname(sock->fd, &bound_addr->addr.sa, &bound_addr->size) < 0) {
236 "coap_socket_bind_udp: getsockname: %s\n",
238 goto error;
239 }
240
241 return 1;
242
243error:
244 coap_socket_close(sock);
245 return 0;
246}
247
248#if COAP_CLIENT_SUPPORT
249int
251 const coap_address_t *local_if,
252 const coap_address_t *server,
253 int default_port,
254 coap_address_t *local_addr,
255 coap_address_t *remote_addr) {
256#ifndef RIOT_VERSION
257 int on = 1;
258 int off = 0;
259#endif /* RIOT_VERSION */
260#ifdef _WIN32
261 u_long u_on = 1;
262#endif
263 coap_address_t connect_addr;
264 int is_mcast = coap_is_mcast(server);
265 coap_address_copy(&connect_addr, server);
266
268 sock->fd = socket(connect_addr.addr.sa.sa_family, SOCK_DGRAM, 0);
269
270 if (sock->fd == COAP_INVALID_SOCKET) {
271 coap_log(LOG_WARNING, "coap_socket_connect_udp: socket: %s\n",
273 goto error;
274 }
275
276#ifndef RIOT_VERSION
277#ifdef _WIN32
278 if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) {
279#else
280 if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) {
281#endif
282 coap_log(LOG_WARNING, "coap_socket_connect_udp: ioctl FIONBIO: %s\n",
284 }
285#endif /* RIOT_VERSION */
286
287 switch (connect_addr.addr.sa.sa_family) {
288 case AF_INET:
289 if (connect_addr.addr.sin.sin_port == 0)
290 connect_addr.addr.sin.sin_port = htons(default_port);
291 break;
292 case AF_INET6:
293 if (connect_addr.addr.sin6.sin6_port == 0)
294 connect_addr.addr.sin6.sin6_port = htons(default_port);
295#ifndef RIOT_VERSION
296 /* Configure the socket as dual-stacked */
297 if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off), sizeof(off)) == COAP_SOCKET_ERROR)
299 "coap_socket_connect_udp: setsockopt IPV6_V6ONLY: %s\n",
301#endif /* RIOT_VERSION */
302 break;
303 default:
304 coap_log(LOG_ALERT, "coap_socket_connect_udp: unsupported sa_family\n");
305 break;
306 }
307
308 if (local_if && local_if->addr.sa.sa_family) {
309#ifndef RIOT_VERSION
310 if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
312 "coap_socket_connect_udp: setsockopt SO_REUSEADDR: %s\n",
314#endif /* RIOT_VERSION */
315 if (bind(sock->fd, &local_if->addr.sa,
316 local_if->addr.sa.sa_family == AF_INET ?
317 (socklen_t)sizeof(struct sockaddr_in) :
318 (socklen_t)local_if->size) == COAP_SOCKET_ERROR) {
319 coap_log(LOG_WARNING, "coap_socket_connect_udp: bind: %s\n",
321 goto error;
322 }
323 }
324
325 /* special treatment for sockets that are used for multicast communication */
326 if (is_mcast) {
327 if (!(local_if && local_if->addr.sa.sa_family)) {
328 /* Bind to a (unused) port to simplify logging */
329 coap_address_t bind_addr;
330
331 coap_address_init(&bind_addr);
332 bind_addr.addr.sa.sa_family = connect_addr.addr.sa.sa_family;
333 if (bind(sock->fd, &bind_addr.addr.sa,
334 bind_addr.addr.sa.sa_family == AF_INET ?
335 (socklen_t)sizeof(struct sockaddr_in) :
336 (socklen_t)bind_addr.size) == COAP_SOCKET_ERROR) {
337 coap_log(LOG_WARNING, "coap_socket_connect_udp: bind: %s\n",
339 goto error;
340 }
341 }
342 if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
344 "coap_socket_connect_udp: getsockname for multicast socket: %s\n",
346 }
347 coap_address_copy(remote_addr, &connect_addr);
349 return 1;
350 }
351
352 if (connect(sock->fd, &connect_addr.addr.sa, connect_addr.size) == COAP_SOCKET_ERROR) {
353 coap_log(LOG_WARNING, "coap_socket_connect_udp: connect: %s\n",
355 goto error;
356 }
357
358 if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
359 coap_log(LOG_WARNING, "coap_socket_connect_udp: getsockname: %s\n",
361 }
362
363 if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) {
364 coap_log(LOG_WARNING, "coap_socket_connect_udp: getpeername: %s\n",
366 }
367
369 return 1;
370
371error:
372 coap_socket_close(sock);
373 return 0;
374}
375#endif /* COAP_CLIENT_SUPPORT */
376
378 if (sock->fd != COAP_INVALID_SOCKET) {
379#ifdef COAP_EPOLL_SUPPORT
380#if COAP_SERVER_SUPPORT
381 coap_context_t *context = sock->session ? sock->session->context :
382 sock->endpoint ? sock->endpoint->context : NULL;
383#else /* COAP_SERVER_SUPPORT */
384 coap_context_t *context = sock->session ? sock->session->context : NULL;
385#endif /* COAP_SERVER_SUPPORT */
386 if (context != NULL) {
387 int ret;
388 struct epoll_event event;
389
390 /* Kernels prior to 2.6.9 expect non NULL event parameter */
391 ret = epoll_ctl(context->epfd, EPOLL_CTL_DEL, sock->fd, &event);
392 if (ret == -1) {
394 "%s: epoll_ctl DEL failed: %s (%d)\n",
395 "coap_socket_close",
396 coap_socket_strerror(), errno);
397 }
398 }
399 sock->endpoint = NULL;
400 sock->session = NULL;
401#endif /* COAP_EPOLL_SUPPORT */
402 coap_closesocket(sock->fd);
403 sock->fd = COAP_INVALID_SOCKET;
404 }
405 sock->flags = COAP_SOCKET_EMPTY;
406}
407
408#ifdef COAP_EPOLL_SUPPORT
409void
411 uint32_t events,
412 const char *func
413) {
414 int ret;
415 struct epoll_event event;
416 coap_context_t *context;
417
418 if (sock == NULL)
419 return;
420
421#if COAP_SERVER_SUPPORT
422 context = sock->session ? sock->session->context :
423 sock->endpoint ? sock->endpoint->context : NULL;
424#else /* COAP_SERVER_SUPPORT */
425 context = sock->session ? sock->session->context : NULL;
426#endif /* COAP_SERVER_SUPPORT */
427 if (context == NULL)
428 return;
429
430 event.events = events;
431 event.data.ptr = sock;
432
433 ret = epoll_ctl(context->epfd, EPOLL_CTL_MOD, sock->fd, &event);
434 if (ret == -1) {
436 "%s: epoll_ctl MOD failed: %s (%d)\n",
437 func,
438 coap_socket_strerror(), errno);
439 }
440}
441
442void
444{
445 if (context->eptimerfd != -1) {
446 coap_tick_t now;
447
448 coap_ticks(&now);
449 if (context->next_timeout == 0 || context->next_timeout > now + delay) {
450 struct itimerspec new_value;
451 int ret;
452
453 context->next_timeout = now + delay;
454 memset(&new_value, 0, sizeof(new_value));
455 if (delay == 0) {
456 new_value.it_value.tv_nsec = 1; /* small but not zero */
457 }
458 else {
459 new_value.it_value.tv_sec = delay / COAP_TICKS_PER_SECOND;
460 new_value.it_value.tv_nsec = (delay % COAP_TICKS_PER_SECOND) *
461 1000000;
462 }
463 ret = timerfd_settime(context->eptimerfd, 0, &new_value, NULL);
464 if (ret == -1) {
466 "%s: timerfd_settime failed: %s (%d)\n",
467 "coap_resource_notify_observers",
468 coap_socket_strerror(), errno);
469 }
470#ifdef COAP_DEBUG_WAKEUP_TIMES
471 else {
472 coap_log(LOG_INFO, "****** Next wakeup time %3ld.%09ld\n",
473 new_value.it_value.tv_sec, new_value.it_value.tv_nsec);
474 }
475#endif /* COAP_DEBUG_WAKEUP_TIMES */
476 }
477 }
478}
479
480#endif /* COAP_EPOLL_SUPPORT */
481
482ssize_t
483coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len) {
484 ssize_t r;
485
487#ifdef _WIN32
488 r = send(sock->fd, (const char *)data, (int)data_len, 0);
489#else
490#ifndef MSG_NOSIGNAL
491#define MSG_NOSIGNAL 0
492#endif /* MSG_NOSIGNAL */
493 r = send(sock->fd, data, data_len, MSG_NOSIGNAL);
494#endif
495 if (r == COAP_SOCKET_ERROR) {
496#ifdef _WIN32
497 if (WSAGetLastError() == WSAEWOULDBLOCK) {
498#elif EAGAIN != EWOULDBLOCK
499 if (errno==EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
500#else
501 if (errno==EAGAIN || errno == EINTR) {
502#endif
504#ifdef COAP_EPOLL_SUPPORT
506 EPOLLOUT |
507 ((sock->flags & COAP_SOCKET_WANT_READ) ?
508 EPOLLIN : 0),
509 __func__);
510#endif /* COAP_EPOLL_SUPPORT */
511 return 0;
512 }
513 if (errno == EPIPE || errno == ECONNRESET) {
514 coap_log(LOG_INFO, "coap_socket_write: send: %s\n",
516 }
517 else {
518 coap_log(LOG_WARNING, "coap_socket_write: send: %s\n",
520 }
521 return -1;
522 }
523 if (r < (ssize_t)data_len) {
525#ifdef COAP_EPOLL_SUPPORT
527 EPOLLOUT |
528 ((sock->flags & COAP_SOCKET_WANT_READ) ?
529 EPOLLIN : 0),
530 __func__);
531#endif /* COAP_EPOLL_SUPPORT */
532 }
533 return r;
534}
535
536ssize_t
537coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len) {
538 ssize_t r;
539#ifdef _WIN32
540 int error;
541#endif
542
543#ifdef _WIN32
544 r = recv(sock->fd, (char *)data, (int)data_len, 0);
545#else
546 r = recv(sock->fd, data, data_len, 0);
547#endif
548 if (r == 0) {
549 /* graceful shutdown */
550 sock->flags &= ~COAP_SOCKET_CAN_READ;
551 return -1;
552 } else if (r == COAP_SOCKET_ERROR) {
553 sock->flags &= ~COAP_SOCKET_CAN_READ;
554#ifdef _WIN32
555 error = WSAGetLastError();
556 if (error == WSAEWOULDBLOCK) {
557#elif EAGAIN != EWOULDBLOCK
558 if (errno==EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
559#else
560 if (errno==EAGAIN || errno == EINTR) {
561#endif
562 return 0;
563 }
564#ifdef _WIN32
565 if (error != WSAECONNRESET)
566#else
567 if (errno != ECONNRESET)
568#endif
569 coap_log(LOG_WARNING, "coap_socket_read: recv: %s\n",
571 return -1;
572 }
573 if (r < (ssize_t)data_len)
574 sock->flags &= ~COAP_SOCKET_CAN_READ;
575 return r;
576}
577
578#endif /* WITH_CONTIKI */
579
580#if (!defined(WITH_CONTIKI)) != ( defined(HAVE_NETINET_IN_H) || defined(HAVE_WS2TCPIP_H) )
581/* define struct in6_pktinfo and struct in_pktinfo if not available
582 FIXME: check with configure
583*/
585 struct in6_addr ipi6_addr; /* src/dst IPv6 address */
586 unsigned int ipi6_ifindex; /* send/recv interface index */
587};
588
591 struct in_addr ipi_spec_dst;
592 struct in_addr ipi_addr;
593};
594#endif
595
596#if !defined(WITH_CONTIKI) && !defined(SOL_IP)
597/* Solaris expects level IPPROTO_IP for ancillary data. */
598#define SOL_IP IPPROTO_IP
599#endif
600
601#if defined(_WIN32)
602#include <mswsock.h>
603static __declspec(thread) LPFN_WSARECVMSG lpWSARecvMsg = NULL;
604/* Map struct WSABUF fields to their posix counterpart */
605#define msghdr _WSAMSG
606#define msg_name name
607#define msg_namelen namelen
608#define msg_iov lpBuffers
609#define msg_iovlen dwBufferCount
610#define msg_control Control.buf
611#define msg_controllen Control.len
612#define iovec _WSABUF
613#define iov_base buf
614#define iov_len len
615#define iov_len_t u_long
616#undef CMSG_DATA
617#define CMSG_DATA WSA_CMSG_DATA
618#define ipi_spec_dst ipi_addr
619#pragma warning( disable : 4116 )
620#else
621#define iov_len_t size_t
622#endif
623
624#if defined(_CYGWIN_ENV)
625#define ipi_spec_dst ipi_addr
626#endif
627
628#ifndef RIOT_VERSION
629ssize_t
630coap_network_send(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data, size_t datalen) {
631 ssize_t bytes_written = 0;
632
633 if (!coap_debug_send_packet()) {
634 bytes_written = (ssize_t)datalen;
635#ifndef WITH_CONTIKI
636 } else if (sock->flags & COAP_SOCKET_CONNECTED) {
637#ifdef _WIN32
638 bytes_written = send(sock->fd, (const char *)data, (int)datalen, 0);
639#else
640 bytes_written = send(sock->fd, data, datalen, 0);
641#endif
642#endif
643 } else {
644#ifdef _WIN32
645 DWORD dwNumberOfBytesSent = 0;
646 int r;
647#endif
648#ifdef HAVE_STRUCT_CMSGHDR
649 /* a buffer large enough to hold all packet info types, ipv6 is the largest */
650 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
651 struct msghdr mhdr;
652 struct iovec iov[1];
653 const void *addr = &session->addr_info.remote.addr;
654
655 assert(session);
656
657 memcpy (&iov[0].iov_base, &data, sizeof (iov[0].iov_base));
658 iov[0].iov_len = (iov_len_t)datalen;
659
660 memset(buf, 0, sizeof (buf));
661
662 memset(&mhdr, 0, sizeof(struct msghdr));
663 memcpy (&mhdr.msg_name, &addr, sizeof (mhdr.msg_name));
664 mhdr.msg_namelen = session->addr_info.remote.size;
665
666 mhdr.msg_iov = iov;
667 mhdr.msg_iovlen = 1;
668
669 if (!coap_address_isany(&session->addr_info.local) &&
670 !coap_is_mcast(&session->addr_info.local))
671 switch (session->addr_info.local.addr.sa.sa_family) {
672 case AF_INET6:
673 {
674 struct cmsghdr *cmsg;
675
676 if (IN6_IS_ADDR_V4MAPPED(&session->addr_info.local.addr.sin6.sin6_addr)) {
677#if defined(IP_PKTINFO)
678 struct in_pktinfo *pktinfo;
679 mhdr.msg_control = buf;
680 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
681
682 cmsg = CMSG_FIRSTHDR(&mhdr);
683 cmsg->cmsg_level = SOL_IP;
684 cmsg->cmsg_type = IP_PKTINFO;
685 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
686
687 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
688
689 pktinfo->ipi_ifindex = session->ifindex;
690 memcpy(&pktinfo->ipi_spec_dst,
691 session->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
692 sizeof(pktinfo->ipi_spec_dst));
693#elif defined(IP_SENDSRCADDR)
694 mhdr.msg_control = buf;
695 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
696
697 cmsg = CMSG_FIRSTHDR(&mhdr);
698 cmsg->cmsg_level = IPPROTO_IP;
699 cmsg->cmsg_type = IP_SENDSRCADDR;
700 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
701
702 memcpy(CMSG_DATA(cmsg),
703 session->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
704 sizeof(struct in_addr));
705#endif /* IP_PKTINFO */
706 } else {
707 struct in6_pktinfo *pktinfo;
708 mhdr.msg_control = buf;
709 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
710
711 cmsg = CMSG_FIRSTHDR(&mhdr);
712 cmsg->cmsg_level = IPPROTO_IPV6;
713 cmsg->cmsg_type = IPV6_PKTINFO;
714 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
715
716 pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
717
718 pktinfo->ipi6_ifindex = session->ifindex;
719 memcpy(&pktinfo->ipi6_addr,
720 &session->addr_info.local.addr.sin6.sin6_addr,
721 sizeof(pktinfo->ipi6_addr));
722 }
723 break;
724 }
725 case AF_INET:
726 {
727#if defined(IP_PKTINFO)
728 struct cmsghdr *cmsg;
729 struct in_pktinfo *pktinfo;
730
731 mhdr.msg_control = buf;
732 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
733
734 cmsg = CMSG_FIRSTHDR(&mhdr);
735 cmsg->cmsg_level = SOL_IP;
736 cmsg->cmsg_type = IP_PKTINFO;
737 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
738
739 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
740
741 pktinfo->ipi_ifindex = session->ifindex;
742 memcpy(&pktinfo->ipi_spec_dst,
743 &session->addr_info.local.addr.sin.sin_addr,
744 sizeof(pktinfo->ipi_spec_dst));
745#elif defined(IP_SENDSRCADDR)
746 struct cmsghdr *cmsg;
747 mhdr.msg_control = buf;
748 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
749
750 cmsg = CMSG_FIRSTHDR(&mhdr);
751 cmsg->cmsg_level = IPPROTO_IP;
752 cmsg->cmsg_type = IP_SENDSRCADDR;
753 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
754
755 memcpy(CMSG_DATA(cmsg),
756 &session->addr_info.local.addr.sin.sin_addr,
757 sizeof(struct in_addr));
758#endif /* IP_PKTINFO */
759 break;
760 }
761 default:
762 /* error */
763 coap_log(LOG_WARNING, "protocol not supported\n");
764 bytes_written = -1;
765 }
766#endif /* HAVE_STRUCT_CMSGHDR */
767
768#ifdef _WIN32
769 r = WSASendMsg(sock->fd, &mhdr, 0 /*dwFlags*/, &dwNumberOfBytesSent, NULL /*lpOverlapped*/, NULL /*lpCompletionRoutine*/);
770 if (r == 0)
771 bytes_written = (ssize_t)dwNumberOfBytesSent;
772 else
773 bytes_written = -1;
774#else
775#ifdef HAVE_STRUCT_CMSGHDR
776 bytes_written = sendmsg(sock->fd, &mhdr, 0);
777#elif !defined(CONTIKI) /* ! HAVE_STRUCT_CMSGHDR */
778 bytes_written = sendto(sock->fd, data, datalen, 0,
779 &session->addr_info.remote.addr.sa,
780 session->addr_info.remote.size);
781#endif /* ! HAVE_STRUCT_CMSGHDR */
782#endif
783#if defined(WITH_CONTIKI)
784 /* FIXME: untested */
785 /* FIXME: is there a way to check if send was successful? */
786 (void)datalen;
787 (void)data;
788 uip_udp_packet_sendto((struct uip_udp_conn *)sock->conn, data, datalen,
789 &session->addr_info.remote.addr, session->addr_info.remote.port);
790 bytes_written = datalen;
791#endif /* WITH_CONTIKI */
792 }
793
794 if (bytes_written < 0)
795 coap_log(LOG_CRIT, "coap_network_send: %s\n", coap_socket_strerror());
796
797 return bytes_written;
798}
799#endif /* RIOT_VERSION */
800
801#define SIN6(A) ((struct sockaddr_in6 *)(A))
802
803void
804coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length) {
805 *address = packet->payload;
806 *length = packet->length;
807}
808
809#ifndef RIOT_VERSION
810ssize_t
812 ssize_t len = -1;
813
814 assert(sock);
815 assert(packet);
816
817 if ((sock->flags & COAP_SOCKET_CAN_READ) == 0) {
818 return -1;
819 } else {
820 /* clear has-data flag */
821 sock->flags &= ~COAP_SOCKET_CAN_READ;
822 }
823
824#if !defined(WITH_CONTIKI) && !defined(RIOT_VERSION)
825 if (sock->flags & COAP_SOCKET_CONNECTED) {
826#ifdef _WIN32
827 len = recv(sock->fd, (char *)packet->payload, COAP_RXBUFFER_SIZE, 0);
828#else
829 len = recv(sock->fd, packet->payload, COAP_RXBUFFER_SIZE, 0);
830#endif
831 if (len < 0) {
832#ifdef _WIN32
833 if (WSAGetLastError() == WSAECONNRESET ||
834 WSAGetLastError() == WSAECONNREFUSED) {
835#else
836 if (errno == ECONNREFUSED || errno == EHOSTUNREACH) {
837#endif
838 /* client-side ICMP destination unreachable, ignore it */
839 coap_log(LOG_WARNING, "** %s: coap_network_read: ICMP: %s\n",
840 sock->session ?
841 coap_session_str(sock->session) : "",
843 return -2;
844 }
845 coap_log(LOG_WARNING, "** %s: coap_network_read: %s\n",
846 sock->session ?
847 coap_session_str(sock->session) : "",
849 goto error;
850 } else if (len > 0) {
851 packet->length = (size_t)len;
852 }
853 } else {
854#endif /* !(WITH_CONTIKI || RIOT_VERSION) */
855#if defined(_WIN32)
856 DWORD dwNumberOfBytesRecvd = 0;
857 int r;
858#endif
859#if !defined(WITH_CONTIKI)
860#ifdef HAVE_STRUCT_CMSGHDR
861 /* a buffer large enough to hold all packet info types, ipv6 is the largest */
862 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
863 struct cmsghdr *cmsg;
864 struct msghdr mhdr;
865 struct iovec iov[1];
866
867 iov[0].iov_base = packet->payload;
868 iov[0].iov_len = (iov_len_t)COAP_RXBUFFER_SIZE;
869
870 memset(&mhdr, 0, sizeof(struct msghdr));
871
872 mhdr.msg_name = (struct sockaddr*)&packet->addr_info.remote.addr;
873 mhdr.msg_namelen = sizeof(packet->addr_info.remote.addr);
874
875 mhdr.msg_iov = iov;
876 mhdr.msg_iovlen = 1;
877
878 mhdr.msg_control = buf;
879 mhdr.msg_controllen = sizeof(buf);
880 /* set a big first length incase recvmsg() does not implement updating
881 msg_control as well as preset the first cmsg with bad data */
882 cmsg = (struct cmsghdr *)buf;
883 cmsg->cmsg_len = CMSG_LEN(sizeof(buf));
884 cmsg->cmsg_level = -1;
885 cmsg->cmsg_type = -1;
886
887#if defined(_WIN32)
888 if (!lpWSARecvMsg) {
889 GUID wsaid = WSAID_WSARECVMSG;
890 DWORD cbBytesReturned = 0;
891 if (WSAIoctl(sock->fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &wsaid, sizeof(wsaid), &lpWSARecvMsg, sizeof(lpWSARecvMsg), &cbBytesReturned, NULL, NULL) != 0) {
892 coap_log(LOG_WARNING, "coap_network_read: no WSARecvMsg\n");
893 return -1;
894 }
895 }
896 r = lpWSARecvMsg(sock->fd, &mhdr, &dwNumberOfBytesRecvd, NULL /* LPWSAOVERLAPPED */, NULL /* LPWSAOVERLAPPED_COMPLETION_ROUTINE */);
897 if (r == 0)
898 len = (ssize_t)dwNumberOfBytesRecvd;
899#else
900 len = recvmsg(sock->fd, &mhdr, 0);
901#endif
902
903#else /* ! HAVE_STRUCT_CMSGHDR */
904 len = recvfrom(sock->fd, packet->payload, COAP_RXBUFFER_SIZE, 0,
905 &packet->addr_info.remote.addr.sa,
906 &packet->addr_info.remote.size);
907#endif /* ! HAVE_STRUCT_CMSGHDR */
908
909 if (len < 0) {
910#ifdef _WIN32
911 if (WSAGetLastError() == WSAECONNRESET) {
912#else
913 if (errno == ECONNREFUSED) {
914#endif
915 /* server-side ICMP destination unreachable, ignore it. The destination address is in msg_name. */
916 return 0;
917 }
918 coap_log(LOG_WARNING, "coap_network_read: %s\n", coap_socket_strerror());
919 goto error;
920 } else {
921#ifdef HAVE_STRUCT_CMSGHDR
922 int dst_found = 0;
923
924 packet->addr_info.remote.size = mhdr.msg_namelen;
925 packet->length = (size_t)len;
926
927 /* Walk through ancillary data records until the local interface
928 * is found where the data was received. */
929 for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) {
930
931 /* get the local interface for IPv6 */
932 if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
933 union {
934 uint8_t *c;
935 struct in6_pktinfo *p;
936 } u;
937 u.c = CMSG_DATA(cmsg);
938 packet->ifindex = (int)(u.p->ipi6_ifindex);
939 memcpy(&packet->addr_info.local.addr.sin6.sin6_addr,
940 &u.p->ipi6_addr, sizeof(struct in6_addr));
941 dst_found = 1;
942 break;
943 }
944
945 /* local interface for IPv4 */
946#if defined(IP_PKTINFO)
947 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
948 union {
949 uint8_t *c;
950 struct in_pktinfo *p;
951 } u;
952 u.c = CMSG_DATA(cmsg);
953 packet->ifindex = u.p->ipi_ifindex;
954 if (packet->addr_info.local.addr.sa.sa_family == AF_INET6) {
955 memset(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr, 0, 10);
956 packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[10] = 0xff;
957 packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[11] = 0xff;
958 memcpy(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
959 &u.p->ipi_addr, sizeof(struct in_addr));
960 } else {
961 memcpy(&packet->addr_info.local.addr.sin.sin_addr,
962 &u.p->ipi_addr, sizeof(struct in_addr));
963 }
964 dst_found = 1;
965 break;
966 }
967#elif defined(IP_RECVDSTADDR)
968 if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) {
969 packet->ifindex = sock->fd;
970 memcpy(&packet->addr_info.local.addr.sin.sin_addr,
971 CMSG_DATA(cmsg), sizeof(struct in_addr));
972 dst_found = 1;
973 break;
974 }
975#endif /* IP_PKTINFO */
976 if (!dst_found) {
977 /* cmsg_level / cmsg_type combination we do not understand
978 (ignore preset case for bad recvmsg() not updating cmsg) */
979 if (cmsg->cmsg_level != -1 && cmsg->cmsg_type != -1) {
981 "cmsg_level = %d and cmsg_type = %d not supported - fix\n",
982 cmsg->cmsg_level, cmsg->cmsg_type);
983 }
984 }
985 }
986 if (!dst_found) {
987 /* Not expected, but cmsg_level and cmsg_type don't match above and
988 may need a new case */
989 packet->ifindex = (int)sock->fd;
990 if (getsockname(sock->fd, &packet->addr_info.local.addr.sa,
991 &packet->addr_info.local.size) < 0) {
992 coap_log(LOG_DEBUG, "Cannot determine local port\n");
993 }
994 }
995#else /* ! HAVE_STRUCT_CMSGHDR */
996 packet->length = (size_t)len;
997 packet->ifindex = 0;
998 if (getsockname(sock->fd, &packet->addr_info.local.addr.sa,
999 &packet->addr_info.local.size) < 0) {
1000 coap_log(LOG_DEBUG, "Cannot determine local port\n");
1001 goto error;
1002 }
1003#endif /* ! HAVE_STRUCT_CMSGHDR */
1004 }
1005#endif /* !defined(WITH_CONTIKI) && !defined(RIOT_VERSION) */
1006#ifdef WITH_CONTIKI
1007 /* FIXME: untested, make this work */
1008#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
1009#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
1010
1011 if (uip_newdata()) {
1012 uip_ipaddr_copy(&packet->addr_info.remote.addr, &UIP_IP_BUF->srcipaddr);
1013 packet->addr_info.remote.port = UIP_UDP_BUF->srcport;
1014 uip_ipaddr_copy(&(packet)->addr_info.local.addr, &UIP_IP_BUF->destipaddr);
1015 packet->addr_info.local.port = UIP_UDP_BUF->destport;
1016
1017 len = uip_datalen();
1018
1019 if (len > COAP_RXBUFFER_SIZE) {
1020 /* FIXME: we might want to send back a response */
1021 coap_log(LOG_WARNING, "discarded oversized packet\n");
1022 return -1;
1023 }
1024
1025 ((char *)uip_appdata)[len] = 0;
1026 if (LOG_DEBUG <= coap_get_log_level()) {
1027#ifndef INET6_ADDRSTRLEN
1028#define INET6_ADDRSTRLEN 40
1029#endif
1030 unsigned char addr_str[INET6_ADDRSTRLEN + 8];
1031
1032 if (coap_print_addr(&packet->addr_info.remote, addr_str,
1033 INET6_ADDRSTRLEN + 8)) {
1034 coap_log(LOG_DEBUG, "received %zd bytes from %s\n", len, addr_str);
1035 }
1036 }
1037
1038 packet->length = len;
1039 memcpy(&packet->payload, uip_appdata, len);
1040 }
1041
1042#undef UIP_IP_BUF
1043#undef UIP_UDP_BUF
1044#endif /* WITH_CONTIKI */
1045#ifdef RIOT_VERSION
1046 packet->src.size = sizeof(packet->src.addr);
1047 len = recvfrom (sock->fd, packet->payload, COAP_RXBUFFER_SIZE,
1048 0, &packet->src.addr.sa, &packet->src.size);
1049 if (LOG_DEBUG <= coap_get_log_level()) {
1050 unsigned char addr_str[INET6_ADDRSTRLEN + 8];
1051
1052 if (coap_print_addr(&packet->src, addr_str, INET6_ADDRSTRLEN + 8)) {
1053 coap_log(LOG_DEBUG, "received %zd bytes from %s\n", len, addr_str);
1054 }
1055 }
1056#endif /* RIOT_VERSION */
1057#if !defined(WITH_CONTIKI) && !defined(RIOT_VERSION)
1058 }
1059#endif /* !(WITH_CONTIKI || RIOT_VERSION) */
1060
1061 if (len >= 0)
1062 return len;
1063#if !defined(WITH_CONTIKI) && !defined(RIOT_VERSION)
1064error:
1065#endif
1066 return -1;
1067}
1068#endif /* RIOT_VERSION */
1069
1070#if !defined(WITH_CONTIKI)
1071
1072unsigned int
1074#ifndef COAP_EPOLL_SUPPORT
1075 (void)ctx;
1076 (void)now;
1078 "coap_io_prepare_epoll() requires libcoap compiled for using epoll\n");
1079 return 0;
1080#else /* COAP_EPOLL_SUPPORT */
1081 coap_socket_t *sockets[1];
1082 unsigned int max_sockets = sizeof(sockets)/sizeof(sockets[0]);
1083 unsigned int num_sockets;
1084 unsigned int timeout;
1085
1086 /* Use the common logic */
1087 timeout = coap_io_prepare_io(ctx, sockets, max_sockets, &num_sockets, now);
1088 /* Save when the next expected I/O is to take place */
1089 ctx->next_timeout = timeout ? now + timeout : 0;
1090 if (ctx->eptimerfd != -1) {
1091 struct itimerspec new_value;
1092 int ret;
1093
1094 memset(&new_value, 0, sizeof(new_value));
1095 coap_ticks(&now);
1096 if (ctx->next_timeout != 0 && ctx->next_timeout > now) {
1097 coap_tick_t rem_timeout = ctx->next_timeout - now;
1098 /* Need to trigger an event on ctx->eptimerfd in the future */
1099 new_value.it_value.tv_sec = rem_timeout / COAP_TICKS_PER_SECOND;
1100 new_value.it_value.tv_nsec = (rem_timeout % COAP_TICKS_PER_SECOND) *
1101 1000000;
1102 }
1103#ifdef COAP_DEBUG_WAKEUP_TIMES
1104 coap_log(LOG_INFO, "****** Next wakeup time %3ld.%09ld\n",
1105 new_value.it_value.tv_sec, new_value.it_value.tv_nsec);
1106#endif /* COAP_DEBUG_WAKEUP_TIMES */
1107 /* reset, or specify a future time for eptimerfd to trigger */
1108 ret = timerfd_settime(ctx->eptimerfd, 0, &new_value, NULL);
1109 if (ret == -1) {
1111 "%s: timerfd_settime failed: %s (%d)\n",
1112 "coap_io_prepare_epoll",
1113 coap_socket_strerror(), errno);
1114 }
1115 }
1116 return timeout;
1117#endif /* COAP_EPOLL_SUPPORT */
1118}
1119
1120/*
1121 * return 0 No i/o pending
1122 * +ve millisecs to next i/o activity
1123 */
1124unsigned int
1126 coap_socket_t *sockets[],
1127 unsigned int max_sockets,
1128 unsigned int *num_sockets,
1129 coap_tick_t now)
1130{
1131 coap_queue_t *nextpdu;
1132 coap_session_t *s, *rtmp;
1133 coap_tick_t timeout = 0;
1134 coap_tick_t s_timeout;
1135#if COAP_SERVER_SUPPORT
1136 int check_dtls_timeouts = 0;
1137#endif /* COAP_SERVER_SUPPORT */
1138#ifdef COAP_EPOLL_SUPPORT
1139 (void)sockets;
1140 (void)max_sockets;
1141#endif /* COAP_EPOLL_SUPPORT */
1142
1143 *num_sockets = 0;
1144
1145#if COAP_SERVER_SUPPORT
1146 /* Check to see if we need to send off any Observe requests */
1147 coap_check_notify(ctx);
1148#endif /* COAP_SERVER_SUPPORT */
1149
1150#ifndef WITHOUT_ASYNC
1151 /* Check to see if we need to send off any Async requests */
1152 timeout = coap_check_async(ctx, now);
1153#endif /* WITHOUT_ASYNC */
1154
1155 /* Check to see if we need to send off any retransmit request */
1156 nextpdu = coap_peek_next(ctx);
1157 while (nextpdu && now >= ctx->sendqueue_basetime &&
1158 nextpdu->t <= now - ctx->sendqueue_basetime) {
1159 coap_retransmit(ctx, coap_pop_next(ctx));
1160 nextpdu = coap_peek_next(ctx);
1161 }
1162 if (nextpdu && (timeout == 0 ||
1163 nextpdu->t - (now - ctx->sendqueue_basetime) < timeout))
1164 timeout = nextpdu->t - (now - ctx->sendqueue_basetime);
1165
1166 /* Check for DTLS timeouts */
1167 if (ctx->dtls_context) {
1170 if (tls_timeout > 0) {
1171 if (tls_timeout < now + COAP_TICKS_PER_SECOND / 10)
1172 tls_timeout = now + COAP_TICKS_PER_SECOND / 10;
1173 coap_log(LOG_DEBUG, "** DTLS global timeout set to %dms\n",
1174 (int)((tls_timeout - now) * 1000 / COAP_TICKS_PER_SECOND));
1175 if (timeout == 0 || tls_timeout - now < timeout)
1176 timeout = tls_timeout - now;
1177 }
1178#if COAP_SERVER_SUPPORT
1179 } else {
1180 check_dtls_timeouts = 1;
1181#endif /* COAP_SERVER_SUPPORT */
1182 }
1183 }
1184#if COAP_SERVER_SUPPORT
1185 coap_endpoint_t *ep;
1186 coap_tick_t session_timeout;
1187
1188 if (ctx->session_timeout > 0)
1189 session_timeout = ctx->session_timeout * COAP_TICKS_PER_SECOND;
1190 else
1192
1193 LL_FOREACH(ctx->endpoint, ep) {
1194#ifndef COAP_EPOLL_SUPPORT
1196 if (*num_sockets < max_sockets)
1197 sockets[(*num_sockets)++] = &ep->sock;
1198 }
1199#endif /* ! COAP_EPOLL_SUPPORT */
1200 SESSIONS_ITER_SAFE(ep->sessions, s, rtmp) {
1201 /* Check whether any idle server sessions should be released */
1202 if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 &&
1203 s->delayqueue == NULL &&
1204 (s->last_rx_tx + session_timeout <= now ||
1208 } else {
1209 if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 &&
1210 s->delayqueue == NULL) {
1211 s_timeout = (s->last_rx_tx + session_timeout) - now;
1212 if (timeout == 0 || s_timeout < timeout)
1213 timeout = s_timeout;
1214 }
1215 /* Make sure the session object is not deleted in any callbacks */
1217 /* Check any DTLS timeouts and expire if appropriate */
1218 if (check_dtls_timeouts && s->state == COAP_SESSION_STATE_HANDSHAKE &&
1219 s->proto == COAP_PROTO_DTLS && s->tls) {
1220 coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now);
1221 while (tls_timeout > 0 && tls_timeout <= now) {
1222 coap_log(LOG_DEBUG, "** %s: DTLS retransmit timeout\n",
1223 coap_session_str(s));
1225 goto release_1;
1226
1227 if (s->tls)
1228 tls_timeout = coap_dtls_get_timeout(s, now);
1229 else {
1230 tls_timeout = 0;
1231 timeout = 1;
1232 }
1233 }
1234 if (tls_timeout > 0 && (timeout == 0 || tls_timeout - now < timeout))
1235 timeout = tls_timeout - now;
1236 }
1237 /* Check if any server large receives have timed out */
1238 if (s->lg_srcv) {
1239 if (coap_block_check_lg_srcv_timeouts(s, now, &s_timeout)) {
1240 if (timeout == 0 || s_timeout < timeout)
1241 timeout = s_timeout;
1242 }
1243 }
1244 /* Check if any server large sending have timed out */
1245 if (s->lg_xmit) {
1246 if (coap_block_check_lg_xmit_timeouts(s, now, &s_timeout)) {
1247 if (timeout == 0 || s_timeout < timeout)
1248 timeout = s_timeout;
1249 }
1250 }
1251#ifndef COAP_EPOLL_SUPPORT
1253 if (*num_sockets < max_sockets)
1254 sockets[(*num_sockets)++] = &s->sock;
1255 }
1256#endif /* ! COAP_EPOLL_SUPPORT */
1257release_1:
1259 }
1260 }
1261 }
1262#endif /* COAP_SERVER_SUPPORT */
1263#if COAP_CLIENT_SUPPORT
1264 SESSIONS_ITER_SAFE(ctx->sessions, s, rtmp) {
1265 if (s->type == COAP_SESSION_TYPE_CLIENT &&
1267 ctx->ping_timeout > 0) {
1268 if (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND <= now) {
1269 if ((s->last_ping > 0 && s->last_pong < s->last_ping) ||
1271 {
1272 /* Make sure the session object is not deleted in the callback */
1276 continue;
1277 }
1278 s->last_rx_tx = now;
1279 s->last_ping = now;
1280 }
1281 s_timeout = (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND) - now;
1282 if (timeout == 0 || s_timeout < timeout)
1283 timeout = s_timeout;
1284 }
1285
1286#if !COAP_DISABLE_TCP
1288 s->state == COAP_SESSION_STATE_CSM && ctx->csm_timeout > 0) {
1289 if (s->csm_tx == 0) {
1290 s->csm_tx = now;
1291 } else if (s->csm_tx + ctx->csm_timeout * COAP_TICKS_PER_SECOND <= now) {
1292 /* Make sure the session object is not deleted in the callback */
1296 continue;
1297 }
1298 s_timeout = (s->csm_tx + ctx->csm_timeout * COAP_TICKS_PER_SECOND) - now;
1299 if (timeout == 0 || s_timeout < timeout)
1300 timeout = s_timeout;
1301 }
1302#endif /* !COAP_DISABLE_TCP */
1303
1304 /* Make sure the session object is not deleted in any callbacks */
1306 /* Check any DTLS timeouts and expire if appropriate */
1308 s->proto == COAP_PROTO_DTLS && s->tls) {
1309 coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now);
1310 while (tls_timeout > 0 && tls_timeout <= now) {
1311 coap_log(LOG_DEBUG, "** %s: DTLS retransmit timeout\n", coap_session_str(s));
1313 goto release_2;
1314
1315 if (s->tls)
1316 tls_timeout = coap_dtls_get_timeout(s, now);
1317 else {
1318 tls_timeout = 0;
1319 timeout = 1;
1320 }
1321 }
1322 if (tls_timeout > 0 && (timeout == 0 || tls_timeout - now < timeout))
1323 timeout = tls_timeout - now;
1324 }
1325
1326 /* Check if any client large receives have timed out */
1327 if (s->lg_crcv) {
1328 if (coap_block_check_lg_crcv_timeouts(s, now, &s_timeout)) {
1329 if (timeout == 0 || s_timeout < timeout)
1330 timeout = s_timeout;
1331 }
1332 }
1333 /* Check if any client large sending have timed out */
1334 if (s->lg_xmit) {
1335 if (coap_block_check_lg_xmit_timeouts(s, now, &s_timeout)) {
1336 if (timeout == 0 || s_timeout < timeout)
1337 timeout = s_timeout;
1338 }
1339 }
1340
1341#ifndef COAP_EPOLL_SUPPORT
1342 assert(s->ref > 1);
1343 if (s->sock.flags & (COAP_SOCKET_WANT_READ |
1346 if (*num_sockets < max_sockets)
1347 sockets[(*num_sockets)++] = &s->sock;
1348 }
1349#endif /* ! COAP_EPOLL_SUPPORT */
1350release_2:
1352 }
1353#endif /* COAP_CLIENT_SUPPORT */
1354
1355 return (unsigned int)((timeout * 1000 + COAP_TICKS_PER_SECOND - 1) / COAP_TICKS_PER_SECOND);
1356}
1357
1358#ifndef RIOT_VERSION
1359int
1360coap_io_process(coap_context_t *ctx, uint32_t timeout_ms) {
1361 return coap_io_process_with_fds(ctx, timeout_ms, 0, NULL, NULL, NULL);
1362}
1363
1364int
1366 int enfds, fd_set *ereadfds, fd_set *ewritefds,
1367 fd_set *eexceptfds) {
1368#if COAP_CONSTRAINED_STACK
1369# ifndef COAP_EPOLL_SUPPORT
1370 static coap_mutex_t static_mutex = COAP_MUTEX_INITIALIZER;
1371 static fd_set readfds, writefds, exceptfds;
1372 static coap_socket_t *sockets[64];
1373 unsigned int num_sockets = 0;
1374# endif /* ! COAP_EPOLL_SUPPORT */
1375#else /* ! COAP_CONSTRAINED_STACK */
1376# ifndef COAP_EPOLL_SUPPORT
1377 fd_set readfds, writefds, exceptfds;
1378 coap_socket_t *sockets[64];
1379 unsigned int num_sockets = 0;
1380# endif /* ! COAP_EPOLL_SUPPORT */
1381#endif /* ! COAP_CONSTRAINED_STACK */
1382 coap_fd_t nfds = 0;
1383 coap_tick_t before, now;
1384 unsigned int timeout;
1385#ifndef COAP_EPOLL_SUPPORT
1386 struct timeval tv;
1387 int result;
1388 unsigned int i;
1389#endif /* ! COAP_EPOLL_SUPPORT */
1390
1391 coap_ticks(&before);
1392
1393#ifndef COAP_EPOLL_SUPPORT
1394
1395#if COAP_CONSTRAINED_STACK
1396 coap_mutex_lock(&static_mutex);
1397#endif /* COAP_CONSTRAINED_STACK */
1398
1399 timeout = coap_io_prepare_io(ctx, sockets,
1400 (sizeof(sockets) / sizeof(sockets[0])),
1401 &num_sockets, before);
1402 if (timeout == 0 || timeout_ms < timeout)
1403 timeout = timeout_ms;
1404
1405 if (ereadfds) {
1406 readfds = *ereadfds;
1407 nfds = enfds;
1408 }
1409 else {
1410 FD_ZERO(&readfds);
1411 }
1412 if (ewritefds) {
1413 writefds = *ewritefds;
1414 nfds = enfds;
1415 }
1416 else {
1417 FD_ZERO(&writefds);
1418 }
1419 if (eexceptfds) {
1420 exceptfds = *eexceptfds;
1421 nfds = enfds;
1422 }
1423 else {
1424 FD_ZERO(&exceptfds);
1425 }
1426 for (i = 0; i < num_sockets; i++) {
1427 if (sockets[i]->fd + 1 > nfds)
1428 nfds = sockets[i]->fd + 1;
1429 if (sockets[i]->flags & COAP_SOCKET_WANT_READ)
1430 FD_SET(sockets[i]->fd, &readfds);
1431 if (sockets[i]->flags & COAP_SOCKET_WANT_WRITE)
1432 FD_SET(sockets[i]->fd, &writefds);
1433#if !COAP_DISABLE_TCP
1434 if (sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT)
1435 FD_SET(sockets[i]->fd, &readfds);
1436 if (sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) {
1437 FD_SET(sockets[i]->fd, &writefds);
1438 FD_SET(sockets[i]->fd, &exceptfds);
1439 }
1440#endif /* !COAP_DISABLE_TCP */
1441 }
1442
1443 if (timeout_ms == COAP_IO_NO_WAIT) {
1444 tv.tv_usec = 0;
1445 tv.tv_sec = 0;
1446 timeout = 1;
1447 }
1448 else if (timeout > 0) {
1449 tv.tv_usec = (timeout % 1000) * 1000;
1450 tv.tv_sec = (long)(timeout / 1000);
1451 }
1452
1453 result = select((int)nfds, &readfds, &writefds, &exceptfds, timeout > 0 ? &tv : NULL);
1454
1455 if (result < 0) { /* error */
1456#ifdef _WIN32
1457 if (WSAGetLastError() != WSAEINVAL) { /* May happen because of ICMP */
1458#else
1459 if (errno != EINTR) {
1460#endif
1462#if COAP_CONSTRAINED_STACK
1463 coap_mutex_unlock(&static_mutex);
1464#endif /* COAP_CONSTRAINED_STACK */
1465 return -1;
1466 }
1467 }
1468 if (ereadfds) {
1469 *ereadfds = readfds;
1470 }
1471 if (ewritefds) {
1472 *ewritefds = writefds;
1473 }
1474 if (eexceptfds) {
1475 *eexceptfds = exceptfds;
1476 }
1477
1478 if (result > 0) {
1479 for (i = 0; i < num_sockets; i++) {
1480 if ((sockets[i]->flags & COAP_SOCKET_WANT_READ) && FD_ISSET(sockets[i]->fd, &readfds))
1481 sockets[i]->flags |= COAP_SOCKET_CAN_READ;
1482#if !COAP_DISABLE_TCP
1483 if ((sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT) && FD_ISSET(sockets[i]->fd, &readfds))
1484 sockets[i]->flags |= COAP_SOCKET_CAN_ACCEPT;
1485 if ((sockets[i]->flags & COAP_SOCKET_WANT_WRITE) && FD_ISSET(sockets[i]->fd, &writefds))
1486 sockets[i]->flags |= COAP_SOCKET_CAN_WRITE;
1487 if ((sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) && (FD_ISSET(sockets[i]->fd, &writefds) || FD_ISSET(sockets[i]->fd, &exceptfds)))
1488 sockets[i]->flags |= COAP_SOCKET_CAN_CONNECT;
1489#endif /* !COAP_DISABLE_TCP */
1490 }
1491 }
1492
1493#if COAP_CONSTRAINED_STACK
1494 coap_mutex_unlock(&static_mutex);
1495#endif /* COAP_CONSTRAINED_STACK */
1496
1497 coap_ticks(&now);
1498 coap_io_do_io(ctx, now);
1499
1500#else /* COAP_EPOLL_SUPPORT */
1501 (void)ereadfds;
1502 (void)ewritefds;
1503 (void)eexceptfds;
1504 (void)enfds;
1505
1506 timeout = coap_io_prepare_epoll(ctx, before);
1507
1508 if (timeout == 0 || timeout_ms < timeout)
1509 timeout = timeout_ms;
1510
1511 do {
1512 struct epoll_event events[COAP_MAX_EPOLL_EVENTS];
1513 int etimeout = timeout;
1514
1515 /* Potentially adjust based on what the caller wants */
1516 if (timeout_ms == COAP_IO_NO_WAIT) {
1517 etimeout = 0;
1518 }
1519 else if (timeout == COAP_IO_WAIT) {
1520 /* coap_io_prepare_epoll() returned 0 and timeout_ms COAP_IO_WAIT (0) */
1521 etimeout = -1;
1522 }
1523 else if (etimeout < 0) {
1524 /* epoll_wait cannot wait longer than this as int timeout parameter */
1525 etimeout = INT_MAX;
1526 }
1527
1528 nfds = epoll_wait(ctx->epfd, events, COAP_MAX_EPOLL_EVENTS, etimeout);
1529 if (nfds < 0) {
1530 if (errno != EINTR) {
1531 coap_log (LOG_ERR, "epoll_wait: unexpected error: %s (%d)\n",
1532 coap_socket_strerror(), nfds);
1533 }
1534 break;
1535 }
1536
1537 coap_io_do_epoll(ctx, events, nfds);
1538
1539 /*
1540 * reset to COAP_IO_NO_WAIT (which causes etimeout to become 0)
1541 * incase we have to do another iteration
1542 * (COAP_MAX_EPOLL_EVENTS insufficient)
1543 */
1544 timeout_ms = COAP_IO_NO_WAIT;
1545
1546 /* Keep retrying until less than COAP_MAX_EPOLL_EVENTS are returned */
1547 } while (nfds == COAP_MAX_EPOLL_EVENTS);
1548
1549#endif /* COAP_EPOLL_SUPPORT */
1550#if COAP_SERVER_SUPPORT
1552#endif /* COAP_SERVER_SUPPORT */
1553 coap_ticks(&now);
1554#ifndef WITHOUT_ASYNC
1555 /* Check to see if we need to send off any Async requests as delay might
1556 have been updated */
1557 coap_check_async(ctx, now);
1558 coap_ticks(&now);
1559#endif /* WITHOUT_ASYNC */
1560
1561 return (int)(((now - before) * 1000) / COAP_TICKS_PER_SECOND);
1562}
1563#endif /* RIOT_VERSION */
1564
1565#else /* WITH_CONTIKI */
1566int coap_io_process(coap_context_t *ctx, uint32_t timeout_ms) {
1567 coap_tick_t now;
1568
1569 coap_ticks(&now);
1570 /* There is something to read on the endpoint */
1572 /* read in, and send off any responses */
1573 coap_io_do_io(ctx, now); /* read received data */
1574 return -1;
1575}
1576
1577unsigned int
1578coap_io_prepare(coap_context_t *ctx,
1579 coap_socket_t *sockets[],
1580 unsigned int max_sockets,
1581 unsigned int *num_sockets,
1582 coap_tick_t now)
1583{
1584 *num_sockets = 0;
1585 return 0;
1586}
1587#endif /* WITH_CONTIKI */
1588
1589#ifdef _WIN32
1590const char *coap_socket_format_errno(int error) {
1591 static char szError[256];
1592 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD)error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)szError, (DWORD)sizeof(szError), NULL) == 0)
1593 strcpy(szError, "Unknown error");
1594 return szError;
1595}
1596
1597const char *coap_socket_strerror(void) {
1598 return coap_socket_format_errno(WSAGetLastError());
1599}
1600#else /* _WIN32 */
1601const char *coap_socket_format_errno(int error) {
1602 return strerror(error);
1603}
1604const char *coap_socket_strerror(void) {
1605 return coap_socket_format_errno(errno);
1606}
1607#endif /* _WIN32 */
1608
1609ssize_t
1611 const uint8_t *data, size_t data_len) {
1612 return session->context->network_send(sock, session, data, data_len);
1613}
1614
1615#undef SIN6
void coap_address_init(coap_address_t *addr)
Resets the given coap_address_t object addr to its default values.
Definition: coap_address.c:107
int coap_is_mcast(const coap_address_t *a)
Checks if given address a denotes a multicast address.
Definition: coap_address.c:88
COAP_STATIC_INLINE int coap_address_isany(const coap_address_t *a)
Checks if given address object a denotes the wildcard address.
Definition: coap_address.h:190
COAP_STATIC_INLINE void coap_address_copy(coap_address_t *dst, const coap_address_t *src)
Definition: coap_address.h:152
int coap_debug_send_packet(void)
Check to see whether a packet should be sent or not.
Definition: coap_debug.c:1031
Pulls together all the internal only header files.
ssize_t coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len)
Definition: coap_io.c:537
void coap_socket_close(coap_socket_t *sock)
Definition: coap_io.c:377
ssize_t coap_socket_send(coap_socket_t *sock, coap_session_t *session, const uint8_t *data, size_t data_len)
Definition: coap_io.c:1610
const char * coap_socket_strerror(void)
Definition: coap_io.c:1604
void coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length)
Given a packet, set msg and msg_len to an address and length of the packet's data in memory.
Definition: coap_io.c:804
ssize_t coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len)
Definition: coap_io.c:483
#define SOL_IP
Definition: coap_io.c:598
ssize_t coap_network_read(coap_socket_t *sock, coap_packet_t *packet)
Function interface for reading data.
Definition: coap_io.c:811
int coap_socket_bind_udp(coap_socket_t *sock, const coap_address_t *listen_addr, coap_address_t *bound_addr)
Definition: coap_io.c:161
ssize_t coap_network_send(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data, size_t datalen)
Function interface for data transmission.
Definition: coap_io.c:630
#define MSG_NOSIGNAL
#define iov_len_t
Definition: coap_io.c:621
const char * coap_socket_format_errno(int error)
Definition: coap_io.c:1601
#define coap_closesocket
Definition: coap_io.h:48
#define COAP_MAX_EPOLL_EVENTS
Definition: coap_io.h:38
#define COAP_RXBUFFER_SIZE
Definition: coap_io.h:29
#define COAP_SOCKET_ERROR
Definition: coap_io.h:49
@ COAP_NACK_NOT_DELIVERABLE
Definition: coap_io.h:71
int coap_fd_t
Definition: coap_io.h:47
#define COAP_INVALID_SOCKET
Definition: coap_io.h:50
int coap_socket_connect_udp(coap_socket_t *sock, const coap_address_t *local_if, const coap_address_t *server, int default_port, coap_address_t *local_addr, coap_address_t *remote_addr)
void coap_mfree_endpoint(struct coap_endpoint_t *ep)
struct coap_endpoint_t * coap_malloc_endpoint(void)
#define COAP_SOCKET_MULTICAST
socket is used for multicast communication
#define COAP_SOCKET_WANT_ACCEPT
non blocking server socket is waiting for accept
#define COAP_SOCKET_CAN_WRITE
non blocking socket can now write without blocking
void coap_update_epoll_timer(coap_context_t *context, coap_tick_t delay)
Update the epoll timer fd as to when it is to trigger.
#define COAP_SOCKET_WANT_READ
non blocking socket is waiting for reading
#define COAP_SOCKET_CAN_ACCEPT
non blocking server socket can now accept without blocking
#define COAP_SOCKET_WANT_WRITE
non blocking socket is waiting for writing
#define COAP_SOCKET_CAN_CONNECT
non blocking client socket can now connect without blocking
void coap_epoll_ctl_mod(coap_socket_t *sock, uint32_t events, const char *func)
#define COAP_SOCKET_WANT_CONNECT
non blocking client socket is waiting for connect
#define COAP_SOCKET_CAN_READ
non blocking socket can now read without blocking
#define COAP_SOCKET_CONNECTED
the socket is connected
#define COAP_SOCKET_EMPTY
coap_socket_flags_t values
coap_tick_t coap_dtls_get_timeout(coap_session_t *session COAP_UNUSED, coap_tick_t now COAP_UNUSED)
Definition: coap_notls.c:150
coap_tick_t coap_dtls_get_context_timeout(void *dtls_context COAP_UNUSED)
Definition: coap_notls.c:145
int coap_dtls_handle_timeout(coap_session_t *session COAP_UNUSED)
Definition: coap_notls.c:159
coap_mid_t coap_session_send_ping(coap_session_t *session)
Send a ping message for the session.
Definition: coap_session.c:516
#define SESSIONS_ITER_SAFE(e, el, rtmp)
#define COAP_DEFAULT_SESSION_TIMEOUT
void coap_io_do_io(coap_context_t *ctx, coap_tick_t now)
Processes any outstanding read, write, accept or connect I/O as indicated in the coap_socket_t struct...
Definition: net.c:1879
unsigned int coap_io_prepare_epoll(coap_context_t *ctx, coap_tick_t now)
Any now timed out delayed packet is transmitted, along with any packets associated with requested obs...
Definition: coap_io.c:1073
void coap_io_do_epoll(coap_context_t *ctx, struct epoll_event *events, size_t nevents)
Process all the epoll events.
Definition: net.c:1935
unsigned int coap_io_prepare_io(coap_context_t *ctx, coap_socket_t *sockets[], unsigned int max_sockets, unsigned int *num_sockets, coap_tick_t now)
Iterates through all the coap_socket_t structures embedded in endpoints or sessions associated with t...
Definition: coap_io.c:1125
int coap_io_process(coap_context_t *ctx, uint32_t timeout_ms)
The main I/O processing function.
Definition: coap_io.c:1360
int coap_io_process_with_fds(coap_context_t *ctx, uint32_t timeout_ms, int enfds, fd_set *ereadfds, fd_set *ewritefds, fd_set *eexceptfds)
The main message processing loop with additional fds for internal select.
Definition: coap_io.c:1365
#define COAP_IO_NO_WAIT
Definition: net.h:580
#define COAP_IO_WAIT
Definition: net.h:579
int coap_block_check_lg_crcv_timeouts(coap_session_t *session, coap_tick_t now, coap_tick_t *tim_rem)
int coap_block_check_lg_srcv_timeouts(coap_session_t *session, coap_tick_t now, coap_tick_t *tim_rem)
int coap_block_check_lg_xmit_timeouts(coap_session_t *session, coap_tick_t now, coap_tick_t *tim_rem)
Definition: block.c:878
void coap_expire_cache_entries(coap_context_t *context)
Expire coap_cache_entry_t entries.
void coap_ticks(coap_tick_t *t)
Sets t to the internal time with COAP_TICKS_PER_SECOND resolution.
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition: coap_time.h:127
#define COAP_TICKS_PER_SECOND
Use ms resolution on POSIX systems.
Definition: coap_time.h:142
coap_tick_t coap_check_async(coap_context_t *context, coap_tick_t now)
Checks if there are any pending Async requests - if so, send them off.
Definition: net.c:3393
coap_queue_t * coap_peek_next(coap_context_t *context)
Returns the next pdu to send without removing from sendqeue.
Definition: net.c:279
coap_queue_t * coap_pop_next(coap_context_t *context)
Returns the next pdu to send and removes it from the sendqeue.
Definition: net.c:287
coap_mid_t coap_retransmit(coap_context_t *context, coap_queue_t *node)
Handles retransmissions of confirmable messages.
Definition: net.c:1447
int coap_handle_event(coap_context_t *context, coap_event_t event, coap_session_t *session)
Invokes the event handler of context for the given event and data.
Definition: net.c:3352
int coap_dtls_is_context_timeout(void)
Check if timeout is handled per CoAP session or per CoAP context.
Definition: coap_notls.c:141
@ COAP_EVENT_SERVER_SESSION_DEL
Called in the CoAP IO loop if a server session is deleted (e.g., due to inactivity or because the max...
Definition: coap_event.h:94
coap_log_t coap_get_log_level(void)
Get the current logging level.
Definition: coap_debug.c:76
#define LOG_ALERT
Definition: coap_debug.h:63
#define LOG_EMERG
Definition: coap_debug.h:60
#define LOG_DEBUG
Definition: coap_debug.h:81
#define LOG_ERR
Definition: coap_debug.h:69
size_t coap_print_addr(const coap_address_t *addr, unsigned char *buf, size_t len)
Print the address into the defined buffer.
Definition: coap_debug.c:186
#define LOG_CRIT
Definition: coap_debug.h:66
const char * coap_session_str(const coap_session_t *session)
Get session description.
#define LOG_WARNING
Definition: coap_debug.h:72
#define LOG_INFO
Definition: coap_debug.h:78
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:165
#define COAP_INVALID_MID
Indicates an invalid message id.
Definition: pdu.h:246
@ COAP_PROTO_DTLS
Definition: pdu.h:295
void coap_session_free(coap_session_t *session)
Definition: coap_session.c:302
#define COAP_PROTO_RELIABLE(p)
Definition: coap_session.h:37
void coap_session_release(coap_session_t *session)
Decrement reference counter on a session.
Definition: coap_session.c:132
void coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason)
Notify session that it has failed.
Definition: coap_session.c:593
coap_session_t * coap_session_reference(coap_session_t *session)
Increment reference counter on a session.
Definition: coap_session.c:126
@ COAP_SESSION_TYPE_SERVER
server-side
Definition: coap_session.h:45
@ COAP_SESSION_TYPE_CLIENT
client-side
Definition: coap_session.h:44
@ COAP_SESSION_STATE_HANDSHAKE
Definition: coap_session.h:56
@ COAP_SESSION_STATE_CSM
Definition: coap_session.h:57
@ COAP_SESSION_STATE_ESTABLISHED
Definition: coap_session.h:58
@ COAP_SESSION_STATE_NONE
Definition: coap_session.h:54
void coap_check_notify(coap_context_t *context)
Checks all known resources to see if they are dirty and then notifies subscribed observers.
@ COAP_ENDPOINT
Definition: mem.h:43
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
#define INET6_ADDRSTRLEN
Definition: net.c:68
coap_address_t remote
remote address and port
Definition: coap_io.h:56
coap_address_t local
local address and port
Definition: coap_io.h:57
multi-purpose address abstraction
Definition: coap_address.h:96
socklen_t size
size of addr
Definition: coap_address.h:97
struct sockaddr_in sin
Definition: coap_address.h:100
struct sockaddr_in6 sin6
Definition: coap_address.h:101
struct sockaddr sa
Definition: coap_address.h:99
union coap_address_t::@0 addr
The CoAP stack's global state is stored in a coap_context_t object.
coap_tick_t sendqueue_basetime
The time stamp in the first element of the sendqeue is relative to sendqueue_basetime.
unsigned int csm_timeout
Timeout for waiting for a CSM from the remote side.
coap_session_t * sessions
client sessions
unsigned int ping_timeout
Minimum inactivity time before sending a ping message.
ssize_t(* network_send)(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data, size_t datalen)
coap_endpoint_t * endpoint
the endpoints used for listening
unsigned int session_timeout
Number of seconds of inactivity after which an unused session will be closed.
Abstraction of virtual endpoint that can be attached to coap_context_t.
coap_context_t * context
endpoint's context
coap_session_t * sessions
hash table or list of active sessions
coap_socket_t sock
socket object for the interface, if any
size_t length
length of payload
coap_addr_tuple_t addr_info
local and remote addresses
unsigned char payload[COAP_RXBUFFER_SIZE]
payload
int ifindex
the interface index
Queue entry.
coap_tick_t t
when to send PDU for the next time
Abstraction of virtual session that can be attached to coap_context_t (client) or coap_endpoint_t (se...
coap_lg_xmit_t * lg_xmit
list of large transmissions
coap_socket_t sock
socket object for the session, if any
coap_session_state_t state
current state of relationaship with peer
coap_addr_tuple_t addr_info
key: remote/local address info
coap_proto_t proto
protocol used
void * tls
security parameters
coap_queue_t * delayqueue
list of delayed messages waiting to be sent
coap_mid_t last_ping_mid
the last keepalive message id that was used in this session
coap_lg_srcv_t * lg_srcv
Server list of expected large receives.
coap_lg_crcv_t * lg_crcv
Client list of expected large receives.
coap_session_type_t type
client or server side socket
coap_context_t * context
session's context
int ifindex
interface index
coap_session_t * session
coap_endpoint_t * endpoint
coap_socket_flags_t flags
struct in6_addr ipi6_addr
Definition: coap_io.c:585
unsigned int ipi6_ifindex
Definition: coap_io.c:586
struct in_addr ipi_spec_dst
Definition: coap_io.c:591
struct in_addr ipi_addr
Definition: coap_io.c:592
int ipi_ifindex
Definition: coap_io.c:590