libcoap 4.3.2rc1
Loading...
Searching...
No Matches
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-2023 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#ifdef COAP_EPOLL_SUPPORT
50#include <sys/epoll.h>
51#include <sys/timerfd.h>
52#ifdef HAVE_LIMITS_H
53#include <limits.h>
54#endif
55#endif /* COAP_EPOLL_SUPPORT */
56
57#if !defined(WITH_CONTIKI) && !defined(RIOT_VERSION) && !(WITH_LWIP)
58/* define generic PKTINFO for IPv4 */
59#if defined(IP_PKTINFO)
60# define GEN_IP_PKTINFO IP_PKTINFO
61#elif defined(IP_RECVDSTADDR)
62# define GEN_IP_PKTINFO IP_RECVDSTADDR
63#else
64# error "Need IP_PKTINFO or IP_RECVDSTADDR to request ancillary data from OS."
65#endif /* IP_PKTINFO */
66
67/* define generic PKTINFO for IPv6 */
68#ifdef IPV6_RECVPKTINFO
69# define GEN_IPV6_PKTINFO IPV6_RECVPKTINFO
70#elif defined(IPV6_PKTINFO)
71# define GEN_IPV6_PKTINFO IPV6_PKTINFO
72#else
73# error "Need IPV6_PKTINFO or IPV6_RECVPKTINFO to request ancillary data from OS."
74#endif /* IPV6_RECVPKTINFO */
75#endif /* !(WITH_CONTIKI || RIOT_VERSION) */
76
77#if COAP_SERVER_SUPPORT
81}
82
83void
86}
87#endif /* COAP_SERVER_SUPPORT */
88
89#if !defined(WITH_CONTIKI) && !defined(WITH_LWIP)
90
91int
93 const coap_address_t *listen_addr,
94 coap_address_t *bound_addr) {
95#ifndef RIOT_VERSION
96 int on = 1, off = 0;
97#else /* ! RIOT_VERSION */
98 struct timeval timeout = {0, 0};
99#endif /* ! RIOT_VERSION */
100#ifdef _WIN32
101 u_long u_on = 1;
102#endif
103
104 sock->fd = socket(listen_addr->addr.sa.sa_family, SOCK_DGRAM, 0);
105
106 if (sock->fd == COAP_INVALID_SOCKET) {
107 coap_log_warn("coap_socket_bind_udp: socket: %s\n", coap_socket_strerror());
108 goto error;
109 }
110#ifndef RIOT_VERSION
111#ifdef _WIN32
112 if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) {
113#else
114 if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) {
115#endif
116 coap_log_warn("coap_socket_bind_udp: ioctl FIONBIO: %s\n", coap_socket_strerror());
117 }
118
119 if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
120 coap_log_warn("coap_socket_bind_udp: setsockopt SO_REUSEADDR: %s\n",
122
123 switch (listen_addr->addr.sa.sa_family) {
124#if COAP_IPV4_SUPPORT
125 case AF_INET:
126 if (setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on),
127 sizeof(on)) == COAP_SOCKET_ERROR)
128 coap_log_alert("coap_socket_bind_udp: setsockopt IP_PKTINFO: %s\n",
130 break;
131#endif /* COAP_IPV4_SUPPORT */
132 case AF_INET6:
133 /* Configure the socket as dual-stacked */
134 if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off),
135 sizeof(off)) == COAP_SOCKET_ERROR)
136 coap_log_alert("coap_socket_bind_udp: setsockopt IPV6_V6ONLY: %s\n",
138#if !defined(ESPIDF_VERSION)
139 if (setsockopt(sock->fd, IPPROTO_IPV6, GEN_IPV6_PKTINFO, OPTVAL_T(&on),
140 sizeof(on)) == COAP_SOCKET_ERROR)
141 coap_log_alert("coap_socket_bind_udp: setsockopt IPV6_PKTINFO: %s\n",
143#endif /* !defined(ESPIDF_VERSION) */
144 setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on), sizeof(on));
145 /* ignore error, because likely cause is that IPv4 is disabled at the os
146 level */
147 break;
148#if COAP_AF_UNIX_SUPPORT
149 case AF_UNIX:
150 break;
151#endif /* COAP_AF_UNIX_SUPPORT */
152 default:
153 coap_log_alert("coap_socket_bind_udp: unsupported sa_family\n");
154 break;
155 }
156#else /* ! RIOT_VERSION */
157 if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVTIMEO, OPTVAL_T(&timeout),
158 (socklen_t)sizeof(timeout)) == COAP_SOCKET_ERROR)
159 coap_log_alert("coap_socket_bind_udp: setsockopt SO_RCVTIMEO: %s\n",
161#endif /* ! RIOT_VERSION */
162
163 if (bind(sock->fd, &listen_addr->addr.sa,
165 listen_addr->addr.sa.sa_family == AF_INET ?
166 (socklen_t)sizeof(struct sockaddr_in) :
167#endif /* COAP_IPV4_SUPPORT */
168 (socklen_t)listen_addr->size) == COAP_SOCKET_ERROR) {
169 coap_log_warn("coap_socket_bind_udp: bind: %s\n",
171 goto error;
172 }
173
174 bound_addr->size = (socklen_t)sizeof(*bound_addr);
175 if (getsockname(sock->fd, &bound_addr->addr.sa, &bound_addr->size) < 0) {
176 coap_log_warn("coap_socket_bind_udp: getsockname: %s\n",
178 goto error;
179 }
180#if defined(RIOT_VERSION) && defined(COAP_SERVER_SUPPORT)
181 if (sock->endpoint &&
182 bound_addr->addr.sa.sa_family == AF_INET6) {
183 bound_addr->addr.sin6.sin6_scope_id =
184 listen_addr->addr.sin6.sin6_scope_id;
185 bound_addr->addr.sin6.sin6_flowinfo = 0;
186 }
187#endif /* RIOT_VERSION && COAP_SERVER_SUPPORT */
188
189 return 1;
190
191error:
192 coap_socket_close(sock);
193 return 0;
194}
195
196#if COAP_CLIENT_SUPPORT
197int
199 const coap_address_t *local_if,
200 const coap_address_t *server,
201 int default_port,
202 coap_address_t *local_addr,
203 coap_address_t *remote_addr) {
204#ifndef RIOT_VERSION
205 int on = 1;
206#if COAP_IPV6_SUPPORT
207 int off = 0;
208#endif /* COAP_IPV6_SUPPORT */
209#else /* ! RIOT_VERSION */
210 struct timeval timeout = {0, 0};
211#endif /* ! RIOT_VERSION */
212#ifdef _WIN32
213 u_long u_on = 1;
214#endif
215 coap_address_t connect_addr;
216#if !defined(RIOT_VERSION)
217 int is_mcast = coap_is_mcast(server);
218#endif /* !defined(RIOT_VERSION) */
219 coap_address_copy(&connect_addr, server);
220
222 sock->fd = socket(connect_addr.addr.sa.sa_family, SOCK_DGRAM, 0);
223
224 if (sock->fd == COAP_INVALID_SOCKET) {
225 coap_log_warn("coap_socket_connect_udp: socket: %s\n",
227 goto error;
228 }
229
230#ifndef RIOT_VERSION
231#ifdef _WIN32
232 if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR)
233#else
234 if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR)
235#endif
236 {
237 coap_log_warn("coap_socket_connect_udp: ioctl FIONBIO: %s\n",
239 }
240#endif /* RIOT_VERSION */
241
242 switch (connect_addr.addr.sa.sa_family) {
243#if COAP_IPV4_SUPPORT
244 case AF_INET:
245 if (connect_addr.addr.sin.sin_port == 0)
246 connect_addr.addr.sin.sin_port = htons(default_port);
247 break;
248#endif /* COAP_IPV4_SUPPORT */
249#if COAP_IPV6_SUPPORT
250 case AF_INET6:
251 if (connect_addr.addr.sin6.sin6_port == 0)
252 connect_addr.addr.sin6.sin6_port = htons(default_port);
253#ifndef RIOT_VERSION
254 /* Configure the socket as dual-stacked */
255 if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off),
256 sizeof(off)) == COAP_SOCKET_ERROR)
257 coap_log_warn("coap_socket_connect_udp: setsockopt IPV6_V6ONLY: %s\n",
259#endif /* RIOT_VERSION */
260#endif /* COAP_IPV6_SUPPORT */
261 break;
262#if COAP_AF_UNIX_SUPPORT
263 case AF_UNIX:
264 break;
265#endif /* COAP_AF_UNIX_SUPPORT */
266 default:
267 coap_log_alert("coap_socket_connect_udp: unsupported sa_family %d\n",
268 connect_addr.addr.sa.sa_family);
269 goto error;;
270 }
271
272 if (local_if && local_if->addr.sa.sa_family) {
273 if (local_if->addr.sa.sa_family != connect_addr.addr.sa.sa_family) {
274 coap_log_warn("coap_socket_connect_udp: local address family != "
275 "remote address family\n");
276 goto error;
277 }
278#ifndef RIOT_VERSION
279 if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
280 coap_log_warn("coap_socket_connect_udp: setsockopt SO_REUSEADDR: %s\n",
282#endif /* RIOT_VERSION */
283 if (bind(sock->fd, &local_if->addr.sa,
285 local_if->addr.sa.sa_family == AF_INET ?
286 (socklen_t)sizeof(struct sockaddr_in) :
287#endif /* COAP_IPV4_SUPPORT */
288 (socklen_t)local_if->size) == COAP_SOCKET_ERROR) {
289 coap_log_warn("coap_socket_connect_udp: bind: %s\n",
291 goto error;
292 }
293#if COAP_AF_UNIX_SUPPORT
294 } else if (connect_addr.addr.sa.sa_family == AF_UNIX) {
295 /* Need to bind to a local address for clarity over endpoints */
296 coap_log_warn("coap_socket_connect_udp: local address required\n");
297 goto error;
298#endif /* COAP_AF_UNIX_SUPPORT */
299 }
300
301 /* special treatment for sockets that are used for multicast communication */
302#if !defined(RIOT_VERSION)
303 if (is_mcast) {
304 if (!(local_if && local_if->addr.sa.sa_family)) {
305 /* Bind to a (unused) port to simplify logging */
306 coap_address_t bind_addr;
307
308 coap_address_init(&bind_addr);
309 bind_addr.addr.sa.sa_family = connect_addr.addr.sa.sa_family;
310 if (bind(sock->fd, &bind_addr.addr.sa,
312 bind_addr.addr.sa.sa_family == AF_INET ?
313 (socklen_t)sizeof(struct sockaddr_in) :
314#endif /* COAP_IPV4_SUPPORT */
315 (socklen_t)bind_addr.size) == COAP_SOCKET_ERROR) {
316 coap_log_warn("coap_socket_connect_udp: bind: %s\n",
318 goto error;
319 }
320 }
321 if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
322 coap_log_warn("coap_socket_connect_udp: getsockname for multicast socket: %s\n",
324 }
325 coap_address_copy(remote_addr, &connect_addr);
326 coap_address_copy(&sock->mcast_addr, &connect_addr);
328 if (coap_is_bcast(server) &&
329 setsockopt(sock->fd, SOL_SOCKET, SO_BROADCAST, OPTVAL_T(&on),
330 sizeof(on)) == COAP_SOCKET_ERROR)
331 coap_log_warn("coap_socket_connect_udp: setsockopt SO_BROADCAST: %s\n",
333 return 1;
334 }
335#else /* defined(RIOT_VERSION) */
336 if (!(local_if && local_if->addr.sa.sa_family)) {
337 /* Bind to a (unused) port to simplify logging */
338 coap_address_t bind_addr;
339
340 coap_address_init(&bind_addr);
341 bind_addr.addr.sa.sa_family = connect_addr.addr.sa.sa_family;
342#if COAP_IPV6_SUPPORT
343 if (bind_addr.addr.sa.sa_family == AF_INET6)
344 bind_addr.addr.sin6.sin6_scope_id = connect_addr.addr.sin6.sin6_scope_id;
345#endif /* COAP_IPV6_SUPPORT */
346 if (bind(sock->fd, &bind_addr.addr.sa,
347 bind_addr.addr.sa.sa_family == AF_INET ?
348 (socklen_t)sizeof(struct sockaddr_in) :
349 (socklen_t)bind_addr.size) == COAP_SOCKET_ERROR) {
350 coap_log_warn("coap_socket_connect_udp: bind: %s\n",
352 goto error;
353 }
354 }
355 if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVTIMEO, OPTVAL_T(&timeout),
356 (socklen_t)sizeof(timeout)) == COAP_SOCKET_ERROR)
357 coap_log_alert("coap_socket_bind_udp: setsockopt SO_RCVTIMEO: %s\n",
359#endif /* defined(RIOT_VERSION) */
360
361 if (connect(sock->fd, &connect_addr.addr.sa, connect_addr.size) == COAP_SOCKET_ERROR) {
362#if COAP_AF_UNIX_SUPPORT
363 if (connect_addr.addr.sa.sa_family == AF_UNIX) {
364 coap_log_warn("coap_socket_connect_udp: connect: %s: %s\n",
365 connect_addr.addr.cun.sun_path, coap_socket_strerror());
366 } else
367#endif /* COAP_AF_UNIX_SUPPORT */
368 {
369 coap_log_warn("coap_socket_connect_udp: connect: %s (%d)\n",
370 coap_socket_strerror(), connect_addr.addr.sa.sa_family);
371 }
372 goto error;
373 }
374
375 if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
376 coap_log_warn("coap_socket_connect_udp: getsockname: %s\n",
378 }
379
380 if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) {
381 coap_log_warn("coap_socket_connect_udp: getpeername: %s\n",
383 }
384
386 return 1;
387
388error:
389 coap_socket_close(sock);
390 return 0;
391}
392#endif /* COAP_CLIENT_SUPPORT */
393
394void
396 if (sock->fd != COAP_INVALID_SOCKET) {
397#ifdef COAP_EPOLL_SUPPORT
398#if COAP_SERVER_SUPPORT
399 coap_context_t *context = sock->session ? sock->session->context :
400 sock->endpoint ? sock->endpoint->context : NULL;
401#else /* COAP_SERVER_SUPPORT */
402 coap_context_t *context = sock->session ? sock->session->context : NULL;
403#endif /* COAP_SERVER_SUPPORT */
404 if (context != NULL) {
405 int ret;
406 struct epoll_event event;
407
408 /* Kernels prior to 2.6.9 expect non NULL event parameter */
409 ret = epoll_ctl(context->epfd, EPOLL_CTL_DEL, sock->fd, &event);
410 if (ret == -1 && errno != ENOENT) {
411 coap_log_err("%s: epoll_ctl DEL failed: %s (%d)\n",
412 "coap_socket_close",
413 coap_socket_strerror(), errno);
414 }
415 }
416#if COAP_SERVER_SUPPORT
417#if COAP_AF_UNIX_SUPPORT
418 if (sock->endpoint &&
419 sock->endpoint->bind_addr.addr.sa.sa_family == AF_UNIX) {
420 /* Clean up Unix endpoint */
421 unlink(sock->endpoint->bind_addr.addr.cun.sun_path);
422 }
423#endif /* COAP_AF_UNIX_SUPPORT */
424 sock->endpoint = NULL;
425#endif /* COAP_SERVER_SUPPORT */
426#if COAP_CLIENT_SUPPORT
427#if COAP_AF_UNIX_SUPPORT
428 if (sock->session && sock->session->type == COAP_SESSION_TYPE_CLIENT &&
429 sock->session->addr_info.local.addr.sa.sa_family == AF_UNIX) {
430 /* Clean up Unix endpoint */
431 unlink(sock->session->addr_info.local.addr.cun.sun_path);
432 }
433#endif /* COAP_AF_UNIX_SUPPORT */
434#endif /* COAP_CLIENT_SUPPORT */
435 sock->session = NULL;
436#endif /* COAP_EPOLL_SUPPORT */
437 coap_closesocket(sock->fd);
438 sock->fd = COAP_INVALID_SOCKET;
439 }
440 sock->flags = COAP_SOCKET_EMPTY;
441}
442
443#ifdef COAP_EPOLL_SUPPORT
444void
446 uint32_t events,
447 const char *func) {
448 int ret;
449 struct epoll_event event;
450 coap_context_t *context;
451
452#if COAP_MAX_LOGGING_LEVEL < _COAP_LOG_ERR
453 (void)func;
454#endif
455
456 if (sock == NULL)
457 return;
458
459#if COAP_SERVER_SUPPORT
460 context = sock->session ? sock->session->context :
461 sock->endpoint ? sock->endpoint->context : NULL;
462#else /* ! COAP_SERVER_SUPPORT */
463 context = sock->session ? sock->session->context : NULL;
464#endif /* ! COAP_SERVER_SUPPORT */
465 if (context == NULL)
466 return;
467
468 /* Needed if running 32bit as ptr is only 32bit */
469 memset(&event, 0, sizeof(event));
470 event.events = events;
471 event.data.ptr = sock;
472
473 ret = epoll_ctl(context->epfd, EPOLL_CTL_ADD, sock->fd, &event);
474 if (ret == -1) {
475 coap_log_err("%s: epoll_ctl ADD failed: %s (%d)\n",
476 func,
477 coap_socket_strerror(), errno);
478 }
479}
480
481void
483 uint32_t events,
484 const char *func) {
485 int ret;
486 struct epoll_event event;
487 coap_context_t *context;
488
489#if COAP_MAX_LOGGING_LEVEL < _COAP_LOG_ERR
490 (void)func;
491#endif
492
493 if (sock == NULL)
494 return;
495
496#if COAP_SERVER_SUPPORT
497 context = sock->session ? sock->session->context :
498 sock->endpoint ? sock->endpoint->context : NULL;
499#else /* COAP_SERVER_SUPPORT */
500 context = sock->session ? sock->session->context : NULL;
501#endif /* COAP_SERVER_SUPPORT */
502 if (context == NULL)
503 return;
504
505 event.events = events;
506 event.data.ptr = sock;
507
508 ret = epoll_ctl(context->epfd, EPOLL_CTL_MOD, sock->fd, &event);
509 if (ret == -1) {
510#if (COAP_MAX_LOGGING_LEVEL < COAP_LOG_ERR)
511 (void)func;
512#endif
513 coap_log_err("%s: epoll_ctl MOD failed: %s (%d)\n",
514 func,
515 coap_socket_strerror(), errno);
516 }
517}
518
519void
521 if (context->eptimerfd != -1) {
522 coap_tick_t now;
523
524 coap_ticks(&now);
525 if (context->next_timeout == 0 || context->next_timeout > now + delay) {
526 struct itimerspec new_value;
527 int ret;
528
529 context->next_timeout = now + delay;
530 memset(&new_value, 0, sizeof(new_value));
531 if (delay == 0) {
532 new_value.it_value.tv_nsec = 1; /* small but not zero */
533 } else {
534 new_value.it_value.tv_sec = delay / COAP_TICKS_PER_SECOND;
535 new_value.it_value.tv_nsec = (delay % COAP_TICKS_PER_SECOND) *
536 1000000;
537 }
538 ret = timerfd_settime(context->eptimerfd, 0, &new_value, NULL);
539 if (ret == -1) {
540 coap_log_err("%s: timerfd_settime failed: %s (%d)\n",
541 "coap_resource_notify_observers",
542 coap_socket_strerror(), errno);
543 }
544#ifdef COAP_DEBUG_WAKEUP_TIMES
545 else {
546 coap_log_debug("****** Next wakeup time %3ld.%09ld\n",
547 new_value.it_value.tv_sec, new_value.it_value.tv_nsec);
548 }
549#endif /* COAP_DEBUG_WAKEUP_TIMES */
550 }
551 }
552}
553
554#endif /* COAP_EPOLL_SUPPORT */
555
556#ifdef _WIN32
557static void
558coap_win_error_to_errno(void) {
559 int w_error = WSAGetLastError();
560 switch (w_error) {
561 case WSA_NOT_ENOUGH_MEMORY:
562 errno = ENOMEM;
563 break;
564 case WSA_INVALID_PARAMETER:
565 errno = EINVAL;
566 break;
567 case WSAEINTR:
568 errno = EINTR;
569 break;
570 case WSAEBADF:
571 errno = EBADF;
572 break;
573 case WSAEACCES:
574 errno = EACCES;
575 break;
576 case WSAEFAULT:
577 errno = EFAULT;
578 break;
579 case WSAEINVAL:
580 errno = EINVAL;
581 break;
582 case WSAEMFILE:
583 errno = EMFILE;
584 break;
585 case WSAEWOULDBLOCK:
586 errno = EWOULDBLOCK;
587 break;
588 case WSAENETDOWN:
589 errno = ENETDOWN;
590 break;
591 case WSAENETUNREACH:
592 errno = ENETUNREACH;
593 break;
594 case WSAENETRESET:
595 errno = ENETRESET;
596 break;
597 case WSAECONNABORTED:
598 errno = ECONNABORTED;
599 break;
600 case WSAECONNRESET:
601 errno = ECONNRESET;
602 break;
603 case WSAENOBUFS:
604 errno = ENOBUFS;
605 break;
606 case WSAETIMEDOUT:
607 errno = ETIMEDOUT;
608 break;
609 case WSAECONNREFUSED:
610 errno = ECONNREFUSED;
611 break;
612 default:
613 coap_log_err("WSAGetLastError: %d mapping to errno failed - please fix\n",
614 w_error);
615 errno = EPERM;
616 break;
617 }
618}
619#endif /* _WIN32 */
620
621/*
622 * strm
623 * return +ve Number of bytes written.
624 * 0 No data written.
625 * -1 Error (error in errno).
626 */
627ssize_t
628coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len) {
629 ssize_t r;
630
632#ifdef _WIN32
633 r = send(sock->fd, (const char *)data, (int)data_len, 0);
634#else
635#ifndef MSG_NOSIGNAL
636#define MSG_NOSIGNAL 0
637#endif /* MSG_NOSIGNAL */
638 r = send(sock->fd, data, data_len, MSG_NOSIGNAL);
639#endif
640 if (r == COAP_SOCKET_ERROR) {
641#ifdef _WIN32
642 coap_win_error_to_errno();
643#endif /* _WIN32 */
644 if (errno==EAGAIN ||
645#if EAGAIN != EWOULDBLOCK
646 errno == EWOULDBLOCK ||
647#endif
648 errno == EINTR) {
650#ifdef COAP_EPOLL_SUPPORT
652 EPOLLOUT |
653 ((sock->flags & COAP_SOCKET_WANT_READ) ?
654 EPOLLIN : 0),
655 __func__);
656#endif /* COAP_EPOLL_SUPPORT */
657 return 0;
658 }
659 if (errno == EPIPE || errno == ECONNRESET) {
660 coap_log_info("coap_socket_write: send: %s\n",
662 } else {
663 coap_log_warn("coap_socket_write: send: %s\n",
665 }
666 return -1;
667 }
668 if (r < (ssize_t)data_len) {
670#ifdef COAP_EPOLL_SUPPORT
672 EPOLLOUT |
673 ((sock->flags & COAP_SOCKET_WANT_READ) ?
674 EPOLLIN : 0),
675 __func__);
676#endif /* COAP_EPOLL_SUPPORT */
677 }
678 return r;
679}
680
681/*
682 * strm
683 * return >=0 Number of bytes read.
684 * -1 Error (error in errno).
685 */
686ssize_t
687coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len) {
688 ssize_t r;
689
690#ifdef _WIN32
691 r = recv(sock->fd, (char *)data, (int)data_len, 0);
692#else
693 r = recv(sock->fd, data, data_len, 0);
694#endif
695 if (r == 0) {
696 /* graceful shutdown */
697 sock->flags &= ~COAP_SOCKET_CAN_READ;
698 errno = ECONNRESET;
699 return -1;
700 } else if (r == COAP_SOCKET_ERROR) {
701 sock->flags &= ~COAP_SOCKET_CAN_READ;
702#ifdef _WIN32
703 coap_win_error_to_errno();
704#endif /* _WIN32 */
705 if (errno==EAGAIN ||
706#if EAGAIN != EWOULDBLOCK
707 errno == EWOULDBLOCK ||
708#endif
709 errno == EINTR) {
710 return 0;
711 }
712 if (errno != ECONNRESET) {
713 coap_log_warn("coap_socket_read: recv: %s\n",
715 }
716 return -1;
717 }
718 if (r < (ssize_t)data_len)
719 sock->flags &= ~COAP_SOCKET_CAN_READ;
720 return r;
721}
722
723#endif /* ! WITH_CONTIKI && ! WITH_LWIP */
724
725#if !defined(WITH_LWIP)
726#if (!defined(WITH_CONTIKI)) != ( defined(HAVE_NETINET_IN_H) || defined(HAVE_WS2TCPIP_H) )
727/* define struct in6_pktinfo and struct in_pktinfo if not available
728 FIXME: check with configure
729*/
730#if !defined(__MINGW32__)
732 struct in6_addr ipi6_addr; /* src/dst IPv6 address */
733 unsigned int ipi6_ifindex; /* send/recv interface index */
734};
735
738 struct in_addr ipi_spec_dst;
739 struct in_addr ipi_addr;
740};
741#endif /* ! __MINGW32__ */
742#endif
743#endif /* ! WITH_LWIP */
744
745#if !defined(WITH_CONTIKI) && !defined(SOL_IP)
746/* Solaris expects level IPPROTO_IP for ancillary data. */
747#define SOL_IP IPPROTO_IP
748#endif
749#ifdef _WIN32
750#define COAP_SOL_IP IPPROTO_IP
751#else /* ! _WIN32 */
752#define COAP_SOL_IP SOL_IP
753#endif /* ! _WIN32 */
754
755#if defined(_WIN32)
756#include <mswsock.h>
757#if !defined(__MINGW32__)
758static __declspec(thread) LPFN_WSARECVMSG lpWSARecvMsg = NULL;
759#endif /* ! __MINGW32__ */
760/* Map struct WSABUF fields to their posix counterpart */
761#define msghdr _WSAMSG
762#define msg_name name
763#define msg_namelen namelen
764#define msg_iov lpBuffers
765#define msg_iovlen dwBufferCount
766#define msg_control Control.buf
767#define msg_controllen Control.len
768#define iovec _WSABUF
769#define iov_base buf
770#define iov_len len
771#define iov_len_t u_long
772#undef CMSG_DATA
773#define CMSG_DATA WSA_CMSG_DATA
774#define ipi_spec_dst ipi_addr
775#if !defined(__MINGW32__)
776#pragma warning( disable : 4116 )
777#endif /* ! __MINGW32__ */
778#else
779#define iov_len_t size_t
780#endif
781
782#if defined(_CYGWIN_ENV)
783#define ipi_spec_dst ipi_addr
784#endif
785
786#if !defined(RIOT_VERSION) && !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
787/*
788 * dgram
789 * return +ve Number of bytes written.
790 * -1 Error error in errno).
791 */
792ssize_t
794 const uint8_t *data, size_t datalen) {
795 ssize_t bytes_written = 0;
796
797 if (!coap_debug_send_packet()) {
798 bytes_written = (ssize_t)datalen;
799 } else if (sock->flags & COAP_SOCKET_CONNECTED) {
800#ifdef _WIN32
801 bytes_written = send(sock->fd, (const char *)data, (int)datalen, 0);
802#else
803 bytes_written = send(sock->fd, data, datalen, 0);
804#endif
805 } else {
806#if defined(_WIN32) && !defined(__MINGW32__)
807 DWORD dwNumberOfBytesSent = 0;
808 int r;
809#endif /* _WIN32 && !__MINGW32__ */
810#ifdef HAVE_STRUCT_CMSGHDR
811 /* a buffer large enough to hold all packet info types, ipv6 is the largest */
812 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
813 struct msghdr mhdr;
814 struct iovec iov[1];
815 const void *addr = &session->addr_info.remote.addr;
816
817 assert(session);
818
819 memcpy(&iov[0].iov_base, &data, sizeof(iov[0].iov_base));
820 iov[0].iov_len = (iov_len_t)datalen;
821
822 memset(buf, 0, sizeof(buf));
823
824 memset(&mhdr, 0, sizeof(struct msghdr));
825 memcpy(&mhdr.msg_name, &addr, sizeof(mhdr.msg_name));
826 mhdr.msg_namelen = session->addr_info.remote.addr.sa.sa_family == AF_INET ?
827 (socklen_t)sizeof(struct sockaddr_in) :
828 session->addr_info.remote.size;
829
830 mhdr.msg_iov = iov;
831 mhdr.msg_iovlen = 1;
832
833 if (!coap_address_isany(&session->addr_info.local) &&
834 !coap_is_mcast(&session->addr_info.local)) {
835 switch (session->addr_info.local.addr.sa.sa_family) {
836#if COAP_IPV6_SUPPORT
837 case AF_INET6: {
838 struct cmsghdr *cmsg;
839
840#if COAP_IPV4_SUPPORT
841 if (IN6_IS_ADDR_V4MAPPED(&session->addr_info.local.addr.sin6.sin6_addr)) {
842#if defined(IP_PKTINFO)
843 struct in_pktinfo *pktinfo;
844 mhdr.msg_control = buf;
845 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
846
847 cmsg = CMSG_FIRSTHDR(&mhdr);
848 cmsg->cmsg_level = COAP_SOL_IP;
849 cmsg->cmsg_type = IP_PKTINFO;
850 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
851
852 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
853
854 pktinfo->ipi_ifindex = session->ifindex;
855 memcpy(&pktinfo->ipi_spec_dst,
856 session->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
857 sizeof(pktinfo->ipi_spec_dst));
858#elif defined(IP_SENDSRCADDR)
859 mhdr.msg_control = buf;
860 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
861
862 cmsg = CMSG_FIRSTHDR(&mhdr);
863 cmsg->cmsg_level = IPPROTO_IP;
864 cmsg->cmsg_type = IP_SENDSRCADDR;
865 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
866
867 memcpy(CMSG_DATA(cmsg),
868 session->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
869 sizeof(struct in_addr));
870#endif /* IP_PKTINFO */
871 } else {
872#endif /* COAP_IPV4_SUPPORT */
873 struct in6_pktinfo *pktinfo;
874 mhdr.msg_control = buf;
875 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
876
877 cmsg = CMSG_FIRSTHDR(&mhdr);
878 cmsg->cmsg_level = IPPROTO_IPV6;
879 cmsg->cmsg_type = IPV6_PKTINFO;
880 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
881
882 pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
883
884 pktinfo->ipi6_ifindex = session->ifindex;
885 memcpy(&pktinfo->ipi6_addr,
886 &session->addr_info.local.addr.sin6.sin6_addr,
887 sizeof(pktinfo->ipi6_addr));
888#if COAP_IPV4_SUPPORT
889 }
890#endif /* COAP_IPV4_SUPPORT */
891 break;
892 }
893#endif /* COAP_IPV6_SUPPORT */
894#if COAP_IPV4_SUPPORT
895 case AF_INET: {
896#if defined(IP_PKTINFO)
897 struct cmsghdr *cmsg;
898 struct in_pktinfo *pktinfo;
899
900 mhdr.msg_control = buf;
901 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
902
903 cmsg = CMSG_FIRSTHDR(&mhdr);
904 cmsg->cmsg_level = COAP_SOL_IP;
905 cmsg->cmsg_type = IP_PKTINFO;
906 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
907
908 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
909
910 pktinfo->ipi_ifindex = session->ifindex;
911 memcpy(&pktinfo->ipi_spec_dst,
912 &session->addr_info.local.addr.sin.sin_addr,
913 sizeof(pktinfo->ipi_spec_dst));
914#elif defined(IP_SENDSRCADDR)
915 struct cmsghdr *cmsg;
916 mhdr.msg_control = buf;
917 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
918
919 cmsg = CMSG_FIRSTHDR(&mhdr);
920 cmsg->cmsg_level = IPPROTO_IP;
921 cmsg->cmsg_type = IP_SENDSRCADDR;
922 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
923
924 memcpy(CMSG_DATA(cmsg),
925 &session->addr_info.local.addr.sin.sin_addr,
926 sizeof(struct in_addr));
927#endif /* IP_PKTINFO */
928 break;
929 }
930#endif /* COAP_IPV4_SUPPORT */
931#if COAP_AF_UNIX_SUPPORT
932 case AF_UNIX:
933 break;
934#endif /* COAP_AF_UNIX_SUPPORT */
935 default:
936 /* error */
937 coap_log_warn("protocol not supported\n");
938 bytes_written = -1;
939 }
940 }
941#endif /* HAVE_STRUCT_CMSGHDR */
942
943#if defined(_WIN32) && !defined(__MINGW32__)
944 r = WSASendMsg(sock->fd, &mhdr, 0 /*dwFlags*/, &dwNumberOfBytesSent, NULL /*lpOverlapped*/,
945 NULL /*lpCompletionRoutine*/);
946 if (r == 0)
947 bytes_written = (ssize_t)dwNumberOfBytesSent;
948 else {
949 bytes_written = -1;
950 coap_win_error_to_errno();
951 }
952#else /* !_WIN32 || __MINGW32__ */
953#ifdef HAVE_STRUCT_CMSGHDR
954 bytes_written = sendmsg(sock->fd, &mhdr, 0);
955#else /* ! HAVE_STRUCT_CMSGHDR */
956 bytes_written = sendto(sock->fd, (const void *)data, datalen, 0,
957 &session->addr_info.remote.addr.sa,
958 session->addr_info.remote.size);
959#endif /* ! HAVE_STRUCT_CMSGHDR */
960#endif /* !_WIN32 || __MINGW32__ */
961 }
962
963 if (bytes_written < 0)
964 coap_log_crit("coap_socket_send: %s\n", coap_socket_strerror());
965
966 return bytes_written;
967}
968#endif /* ! RIOT_VERSION && ! WITH_LWIP && ! WITH_CONTIKI */
969
970#define SIN6(A) ((struct sockaddr_in6 *)(A))
971
972void
973coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length) {
974 *address = packet->payload;
975 *length = packet->length;
976}
977
978#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
979/*
980 * dgram
981 * return +ve Number of bytes written.
982 * -1 Error error in errno).
983 * -2 ICMP error response
984 */
985ssize_t
987 ssize_t len = -1;
988
989 assert(sock);
990 assert(packet);
991
992 if ((sock->flags & COAP_SOCKET_CAN_READ) == 0) {
993 return -1;
994 } else {
995 /* clear has-data flag */
996 sock->flags &= ~COAP_SOCKET_CAN_READ;
997 }
998
999 if (sock->flags & COAP_SOCKET_CONNECTED) {
1000#ifdef _WIN32
1001 len = recv(sock->fd, (char *)packet->payload, COAP_RXBUFFER_SIZE, 0);
1002#else
1003 len = recv(sock->fd, packet->payload, COAP_RXBUFFER_SIZE, 0);
1004#endif
1005 if (len < 0) {
1006#ifdef _WIN32
1007 coap_win_error_to_errno();
1008#endif /* _WIN32 */
1009 if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
1010 /* client-side ICMP destination unreachable, ignore it */
1011 coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
1012 sock->session ?
1013 coap_session_str(sock->session) : "",
1015 return -2;
1016 }
1017 coap_log_warn("** %s: coap_socket_recv: %s\n",
1018 sock->session ?
1019 coap_session_str(sock->session) : "",
1021 goto error;
1022 } else if (len > 0) {
1023 packet->length = (size_t)len;
1024 }
1025 } else {
1026#if defined(_WIN32) && !defined(__MINGW32__)
1027 DWORD dwNumberOfBytesRecvd = 0;
1028 int r;
1029#endif /* _WIN32 && !__MINGW32__ */
1030#ifdef HAVE_STRUCT_CMSGHDR
1031 /* a buffer large enough to hold all packet info types, ipv6 is the largest */
1032 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
1033 struct cmsghdr *cmsg;
1034 struct msghdr mhdr;
1035 struct iovec iov[1];
1036
1037 iov[0].iov_base = packet->payload;
1038 iov[0].iov_len = (iov_len_t)COAP_RXBUFFER_SIZE;
1039
1040 memset(&mhdr, 0, sizeof(struct msghdr));
1041
1042 mhdr.msg_name = (struct sockaddr *)&packet->addr_info.remote.addr;
1043 mhdr.msg_namelen = sizeof(packet->addr_info.remote.addr);
1044
1045 mhdr.msg_iov = iov;
1046 mhdr.msg_iovlen = 1;
1047
1048 mhdr.msg_control = buf;
1049 mhdr.msg_controllen = sizeof(buf);
1050 /* set a big first length incase recvmsg() does not implement updating
1051 msg_control as well as preset the first cmsg with bad data */
1052 cmsg = (struct cmsghdr *)buf;
1053 cmsg->cmsg_len = CMSG_LEN(sizeof(buf));
1054 cmsg->cmsg_level = -1;
1055 cmsg->cmsg_type = -1;
1056
1057#if defined(_WIN32)
1058 if (!lpWSARecvMsg) {
1059 GUID wsaid = WSAID_WSARECVMSG;
1060 DWORD cbBytesReturned = 0;
1061 if (WSAIoctl(sock->fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &wsaid, sizeof(wsaid), &lpWSARecvMsg,
1062 sizeof(lpWSARecvMsg), &cbBytesReturned, NULL, NULL) != 0) {
1063 coap_log_warn("coap_socket_recv: no WSARecvMsg\n");
1064 return -1;
1065 }
1066 }
1067 r = lpWSARecvMsg(sock->fd, &mhdr, &dwNumberOfBytesRecvd, NULL /* LPWSAOVERLAPPED */,
1068 NULL /* LPWSAOVERLAPPED_COMPLETION_ROUTINE */);
1069 if (r == 0)
1070 len = (ssize_t)dwNumberOfBytesRecvd;
1071 else if (r == COAP_SOCKET_ERROR)
1072 coap_win_error_to_errno();
1073#else
1074 len = recvmsg(sock->fd, &mhdr, 0);
1075#endif
1076
1077#else /* ! HAVE_STRUCT_CMSGHDR */
1078 len = recvfrom(sock->fd, (void *)packet->payload, COAP_RXBUFFER_SIZE, 0,
1079 &packet->addr_info.remote.addr.sa,
1080 &packet->addr_info.remote.size);
1081#if defined(RIOT_VERSION) && defined(COAP_SERVER_SUPPORT) && COAP_IPV6_SUPPORT
1082 if (sock->endpoint &&
1083 packet->addr_info.remote.addr.sa.sa_family == AF_INET6) {
1084 packet->addr_info.remote.addr.sin6.sin6_scope_id =
1085 sock->endpoint->bind_addr.addr.sin6.sin6_scope_id;
1086 packet->addr_info.remote.addr.sin6.sin6_flowinfo = 0;
1087 }
1088#endif /* RIOT_VERSION && COAP_SERVER_SUPPORT && COAP_IPV6_SUPPORT */
1089#endif /* ! HAVE_STRUCT_CMSGHDR */
1090
1091 if (len < 0) {
1092#ifdef _WIN32
1093 coap_win_error_to_errno();
1094#endif /* _WIN32 */
1095 if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
1096 /* server-side ICMP destination unreachable, ignore it. The destination address is in msg_name. */
1097 coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
1098 sock->session ?
1099 coap_session_str(sock->session) : "",
1101 return 0;
1102 }
1103 coap_log_warn("coap_socket_recv: %s\n", coap_socket_strerror());
1104 goto error;
1105 } else {
1106#ifdef HAVE_STRUCT_CMSGHDR
1107 int dst_found = 0;
1108
1109 packet->addr_info.remote.size = mhdr.msg_namelen;
1110 packet->length = (size_t)len;
1111
1112 /* Walk through ancillary data records until the local interface
1113 * is found where the data was received. */
1114 for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) {
1115
1116#if COAP_IPV6_SUPPORT
1117 /* get the local interface for IPv6 */
1118 if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
1119 union {
1120 uint8_t *c;
1121 struct in6_pktinfo *p;
1122 } u;
1123 u.c = CMSG_DATA(cmsg);
1124 packet->ifindex = (int)(u.p->ipi6_ifindex);
1125 memcpy(&packet->addr_info.local.addr.sin6.sin6_addr,
1126 &u.p->ipi6_addr, sizeof(struct in6_addr));
1127 dst_found = 1;
1128 break;
1129 }
1130#endif /* COAP_IPV6_SUPPORT */
1131
1132#if COAP_IPV4_SUPPORT
1133 /* local interface for IPv4 */
1134#if defined(IP_PKTINFO)
1135 if (cmsg->cmsg_level == COAP_SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
1136 union {
1137 uint8_t *c;
1138 struct in_pktinfo *p;
1139 } u;
1140 u.c = CMSG_DATA(cmsg);
1141 packet->ifindex = u.p->ipi_ifindex;
1142#if COAP_IPV6_SUPPORT
1143 if (packet->addr_info.local.addr.sa.sa_family == AF_INET6) {
1144 memset(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr, 0, 10);
1145 packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[10] = 0xff;
1146 packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[11] = 0xff;
1147 memcpy(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
1148 &u.p->ipi_addr, sizeof(struct in_addr));
1149 } else
1150#endif /* COAP_IPV6_SUPPORT */
1151 {
1152 memcpy(&packet->addr_info.local.addr.sin.sin_addr,
1153 &u.p->ipi_addr, sizeof(struct in_addr));
1154 }
1155 dst_found = 1;
1156 break;
1157 }
1158#endif /* IP_PKTINFO */
1159#if defined(IP_RECVDSTADDR)
1160 if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) {
1161 packet->ifindex = (int)sock->fd;
1162 memcpy(&packet->addr_info.local.addr.sin.sin_addr,
1163 CMSG_DATA(cmsg), sizeof(struct in_addr));
1164 dst_found = 1;
1165 break;
1166 }
1167#endif /* IP_RECVDSTADDR */
1168#endif /* COAP_IPV4_SUPPORT */
1169 if (!dst_found) {
1170 /* cmsg_level / cmsg_type combination we do not understand
1171 (ignore preset case for bad recvmsg() not updating cmsg) */
1172 if (cmsg->cmsg_level != -1 && cmsg->cmsg_type != -1) {
1173 coap_log_debug("cmsg_level = %d and cmsg_type = %d not supported - fix\n",
1174 cmsg->cmsg_level, cmsg->cmsg_type);
1175 }
1176 }
1177 }
1178 if (!dst_found) {
1179 /* Not expected, but cmsg_level and cmsg_type don't match above and
1180 may need a new case */
1181 packet->ifindex = (int)sock->fd;
1182 if (getsockname(sock->fd, &packet->addr_info.local.addr.sa,
1183 &packet->addr_info.local.size) < 0) {
1184 coap_log_debug("Cannot determine local port\n");
1185 }
1186 }
1187#else /* ! HAVE_STRUCT_CMSGHDR */
1188 packet->length = (size_t)len;
1189 packet->ifindex = 0;
1190 if (getsockname(sock->fd, &packet->addr_info.local.addr.sa,
1191 &packet->addr_info.local.size) < 0) {
1192 coap_log_debug("Cannot determine local port\n");
1193 goto error;
1194 }
1195#if defined(RIOT_VERSION) && defined(COAP_SERVER_SUPPORT) && COAP_IPV6_SUPPORT
1196 if (sock->endpoint &&
1197 packet->addr_info.local.addr.sa.sa_family == AF_INET6) {
1198 packet->addr_info.local.addr.sin6.sin6_scope_id =
1199 sock->endpoint->bind_addr.addr.sin6.sin6_scope_id;
1200 packet->addr_info.local.addr.sin6.sin6_flowinfo = 0;
1201 }
1202#endif /* RIOT_VERSION && COAP_SERVER_SUPPORT && COAP_IPV6_SUPPORT */
1203#endif /* ! HAVE_STRUCT_CMSGHDR */
1204 }
1205 }
1206
1207 if (len >= 0)
1208 return len;
1209error:
1210 return -1;
1211}
1212#endif /* ! WITH_LWIP && ! WITH_CONTIKI */
1213
1214unsigned int
1216#ifndef COAP_EPOLL_SUPPORT
1217 (void)ctx;
1218 (void)now;
1219 coap_log_emerg("coap_io_prepare_epoll() requires libcoap compiled for using epoll\n");
1220 return 0;
1221#else /* COAP_EPOLL_SUPPORT */
1222 coap_socket_t *sockets[1];
1223 unsigned int max_sockets = sizeof(sockets)/sizeof(sockets[0]);
1224 unsigned int num_sockets;
1225 unsigned int timeout;
1226
1227 /* Use the common logic */
1228 timeout = coap_io_prepare_io(ctx, sockets, max_sockets, &num_sockets, now);
1229 /* Save when the next expected I/O is to take place */
1230 ctx->next_timeout = timeout ? now + timeout : 0;
1231 if (ctx->eptimerfd != -1) {
1232 struct itimerspec new_value;
1233 int ret;
1234
1235 memset(&new_value, 0, sizeof(new_value));
1236 coap_ticks(&now);
1237 if (ctx->next_timeout != 0 && ctx->next_timeout > now) {
1238 coap_tick_t rem_timeout = ctx->next_timeout - now;
1239 /* Need to trigger an event on ctx->eptimerfd in the future */
1240 new_value.it_value.tv_sec = rem_timeout / COAP_TICKS_PER_SECOND;
1241 new_value.it_value.tv_nsec = (rem_timeout % COAP_TICKS_PER_SECOND) *
1242 1000000;
1243 }
1244#ifdef COAP_DEBUG_WAKEUP_TIMES
1245 coap_log_debug("****** Next wakeup time %3ld.%09ld\n",
1246 new_value.it_value.tv_sec, new_value.it_value.tv_nsec);
1247#endif /* COAP_DEBUG_WAKEUP_TIMES */
1248 /* reset, or specify a future time for eptimerfd to trigger */
1249 ret = timerfd_settime(ctx->eptimerfd, 0, &new_value, NULL);
1250 if (ret == -1) {
1251 coap_log_err("%s: timerfd_settime failed: %s (%d)\n",
1252 "coap_io_prepare_epoll",
1253 coap_socket_strerror(), errno);
1254 }
1255 }
1256 return timeout;
1257#endif /* COAP_EPOLL_SUPPORT */
1258}
1259
1260/*
1261 * return 0 No i/o pending
1262 * +ve millisecs to next i/o activity
1263 */
1264unsigned int
1266 coap_socket_t *sockets[],
1267 unsigned int max_sockets,
1268 unsigned int *num_sockets,
1269 coap_tick_t now) {
1270 coap_queue_t *nextpdu;
1271 coap_session_t *s, *rtmp;
1272 coap_tick_t timeout = 0;
1273 coap_tick_t s_timeout;
1274#if COAP_SERVER_SUPPORT
1275 int check_dtls_timeouts = 0;
1276#endif /* COAP_SERVER_SUPPORT */
1277#if defined(COAP_EPOLL_SUPPORT) || defined(WITH_LWIP)
1278 (void)sockets;
1279 (void)max_sockets;
1280#endif /* COAP_EPOLL_SUPPORT || WITH_LWIP */
1281
1282 *num_sockets = 0;
1283
1284#if COAP_SERVER_SUPPORT
1285 /* Check to see if we need to send off any Observe requests */
1286 coap_check_notify(ctx);
1287
1288#if COAP_ASYNC_SUPPORT
1289 /* Check to see if we need to send off any Async requests */
1290 timeout = coap_check_async(ctx, now);
1291#endif /* COAP_ASYNC_SUPPORT */
1292#endif /* COAP_SERVER_SUPPORT */
1293
1294 /* Check to see if we need to send off any retransmit request */
1295 nextpdu = coap_peek_next(ctx);
1296 while (nextpdu && now >= ctx->sendqueue_basetime &&
1297 nextpdu->t <= now - ctx->sendqueue_basetime) {
1298 coap_retransmit(ctx, coap_pop_next(ctx));
1299 nextpdu = coap_peek_next(ctx);
1300 }
1301 if (nextpdu && (timeout == 0 ||
1302 nextpdu->t - (now - ctx->sendqueue_basetime) < timeout))
1303 timeout = nextpdu->t - (now - ctx->sendqueue_basetime);
1304
1305 /* Check for DTLS timeouts */
1306 if (ctx->dtls_context) {
1309 if (tls_timeout > 0) {
1310 if (tls_timeout < now + COAP_TICKS_PER_SECOND / 10)
1311 tls_timeout = now + COAP_TICKS_PER_SECOND / 10;
1312 coap_log_debug("** DTLS global timeout set to %dms\n",
1313 (int)((tls_timeout - now) * 1000 / COAP_TICKS_PER_SECOND));
1314 if (timeout == 0 || tls_timeout - now < timeout)
1315 timeout = tls_timeout - now;
1316 }
1317#if COAP_SERVER_SUPPORT
1318 } else {
1319 check_dtls_timeouts = 1;
1320#endif /* COAP_SERVER_SUPPORT */
1321 }
1322 }
1323#if COAP_SERVER_SUPPORT
1324 coap_endpoint_t *ep;
1325 coap_tick_t session_timeout;
1326
1327 if (ctx->session_timeout > 0)
1328 session_timeout = ctx->session_timeout * COAP_TICKS_PER_SECOND;
1329 else
1331
1332 LL_FOREACH(ctx->endpoint, ep) {
1333#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP)
1335 if (*num_sockets < max_sockets)
1336 sockets[(*num_sockets)++] = &ep->sock;
1337 }
1338#endif /* ! COAP_EPOLL_SUPPORT i && ! WITH_LWIP */
1339 SESSIONS_ITER_SAFE(ep->sessions, s, rtmp) {
1340 /* Check whether any idle server sessions should be released */
1341 if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 &&
1342 s->delayqueue == NULL &&
1343 (s->last_rx_tx + session_timeout <= now ||
1347 } else {
1348 if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 &&
1349 s->delayqueue == NULL) {
1350 s_timeout = (s->last_rx_tx + session_timeout) - now;
1351 if (timeout == 0 || s_timeout < timeout)
1352 timeout = s_timeout;
1353 }
1354 /* Make sure the session object is not deleted in any callbacks */
1356 /* Check any DTLS timeouts and expire if appropriate */
1357 if (check_dtls_timeouts && s->state == COAP_SESSION_STATE_HANDSHAKE &&
1358 s->proto == COAP_PROTO_DTLS && s->tls) {
1359 coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now);
1360 while (tls_timeout > 0 && tls_timeout <= now) {
1361 coap_log_debug("** %s: DTLS retransmit timeout\n",
1362 coap_session_str(s));
1364 goto release_1;
1365
1366 if (s->tls)
1367 tls_timeout = coap_dtls_get_timeout(s, now);
1368 else {
1369 tls_timeout = 0;
1370 timeout = 1;
1371 }
1372 }
1373 if (tls_timeout > 0 && (timeout == 0 || tls_timeout - now < timeout))
1374 timeout = tls_timeout - now;
1375 }
1376 /* Check if any server large receives are missing blocks */
1377 if (s->lg_srcv) {
1378 if (coap_block_check_lg_srcv_timeouts(s, now, &s_timeout)) {
1379 if (timeout == 0 || s_timeout < timeout)
1380 timeout = s_timeout;
1381 }
1382 }
1383 /* Check if any server large sending have timed out */
1384 if (s->lg_xmit) {
1385 if (coap_block_check_lg_xmit_timeouts(s, now, &s_timeout)) {
1386 if (timeout == 0 || s_timeout < timeout)
1387 timeout = s_timeout;
1388 }
1389 }
1390#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP)
1392 if (*num_sockets < max_sockets)
1393 sockets[(*num_sockets)++] = &s->sock;
1394 }
1395#endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP */
1396#if COAP_Q_BLOCK_SUPPORT
1397 /*
1398 * Check if any server large transmits have hit MAX_PAYLOAD and need
1399 * restarting
1400 */
1401 if (s->lg_xmit) {
1402 s_timeout = coap_block_check_q_block2_xmit(s, now);
1403 if (timeout == 0 || s_timeout < timeout)
1404 timeout = s_timeout;
1405 }
1406#endif /* COAP_Q_BLOCK_SUPPORT */
1407release_1:
1409 }
1410 }
1411 }
1412#endif /* COAP_SERVER_SUPPORT */
1413#if COAP_CLIENT_SUPPORT
1414 SESSIONS_ITER_SAFE(ctx->sessions, s, rtmp) {
1415 if (s->type == COAP_SESSION_TYPE_CLIENT &&
1417 ctx->ping_timeout > 0) {
1418 if (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND <= now) {
1419 /* Time to send a ping */
1421 /* Some issue - not safe to continue processing */
1422 continue;
1423 if (s->last_ping > 0 && s->last_pong < s->last_ping) {
1425 }
1426 s->last_rx_tx = now;
1427 s->last_ping = now;
1428 }
1429 s_timeout = (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND) - now;
1430 if (timeout == 0 || s_timeout < timeout)
1431 timeout = s_timeout;
1432 }
1433
1434#if !COAP_DISABLE_TCP
1436 s->state == COAP_SESSION_STATE_CSM && ctx->csm_timeout > 0) {
1437 if (s->csm_tx == 0) {
1438 s->csm_tx = now;
1439 } else if (s->csm_tx + ctx->csm_timeout * COAP_TICKS_PER_SECOND <= now) {
1440 /* Make sure the session object is not deleted in the callback */
1444 continue;
1445 }
1446 s_timeout = (s->csm_tx + ctx->csm_timeout * COAP_TICKS_PER_SECOND) - now;
1447 if (timeout == 0 || s_timeout < timeout)
1448 timeout = s_timeout;
1449 }
1450#endif /* !COAP_DISABLE_TCP */
1451
1452 /* Make sure the session object is not deleted in any callbacks */
1454 /* Check any DTLS timeouts and expire if appropriate */
1456 s->proto == COAP_PROTO_DTLS && s->tls) {
1457 coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now);
1458 while (tls_timeout > 0 && tls_timeout <= now) {
1459 coap_log_debug("** %s: DTLS retransmit timeout\n", coap_session_str(s));
1461 goto release_2;
1462
1463 if (s->tls)
1464 tls_timeout = coap_dtls_get_timeout(s, now);
1465 else {
1466 tls_timeout = 0;
1467 timeout = 1;
1468 }
1469 }
1470 if (tls_timeout > 0 && (timeout == 0 || tls_timeout - now < timeout))
1471 timeout = tls_timeout - now;
1472 }
1473
1474 /* Check if any client large receives are missing blocks */
1475 if (s->lg_crcv) {
1476 if (coap_block_check_lg_crcv_timeouts(s, now, &s_timeout)) {
1477 if (timeout == 0 || s_timeout < timeout)
1478 timeout = s_timeout;
1479 }
1480 }
1481 /* Check if any client large sending have timed out */
1482 if (s->lg_xmit) {
1483 if (coap_block_check_lg_xmit_timeouts(s, now, &s_timeout)) {
1484 if (timeout == 0 || s_timeout < timeout)
1485 timeout = s_timeout;
1486 }
1487 }
1488#if COAP_Q_BLOCK_SUPPORT
1489 /*
1490 * Check if any client large transmits have hit MAX_PAYLOAD and need
1491 * restarting
1492 */
1493 if (s->lg_xmit) {
1494 s_timeout = coap_block_check_q_block1_xmit(s, now);
1495 if (timeout == 0 || s_timeout < timeout)
1496 timeout = s_timeout;
1497 }
1498#endif /* COAP_Q_BLOCK_SUPPORT */
1499
1500#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITHLWIP)
1501 assert(s->ref > 1);
1502 if (s->sock.flags & (COAP_SOCKET_WANT_READ |
1505 if (*num_sockets < max_sockets)
1506 sockets[(*num_sockets)++] = &s->sock;
1507 }
1508#endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP */
1509release_2:
1511 }
1512#endif /* COAP_CLIENT_SUPPORT */
1513
1514 return (unsigned int)((timeout * 1000 + COAP_TICKS_PER_SECOND - 1) / COAP_TICKS_PER_SECOND);
1515}
1516
1517#if !defined(WITH_LWIP) && !defined(CONTIKI)
1518int
1519coap_io_process(coap_context_t *ctx, uint32_t timeout_ms) {
1520 return coap_io_process_with_fds(ctx, timeout_ms, 0, NULL, NULL, NULL);
1521}
1522
1523int
1525 int enfds, fd_set *ereadfds, fd_set *ewritefds,
1526 fd_set *eexceptfds) {
1527 coap_fd_t nfds = 0;
1528 coap_tick_t before, now;
1529 unsigned int timeout;
1530#ifndef COAP_EPOLL_SUPPORT
1531 struct timeval tv;
1532 int result;
1533 unsigned int i;
1534#endif /* ! COAP_EPOLL_SUPPORT */
1535
1536 coap_ticks(&before);
1537
1538#ifndef COAP_EPOLL_SUPPORT
1539
1540 timeout = coap_io_prepare_io(ctx, ctx->sockets,
1541 (sizeof(ctx->sockets) / sizeof(ctx->sockets[0])),
1542 &ctx->num_sockets, before);
1543 if (timeout == 0 || timeout_ms < timeout)
1544 timeout = timeout_ms;
1545
1546 if (ereadfds) {
1547 ctx->readfds = *ereadfds;
1548 nfds = enfds;
1549 } else {
1550 FD_ZERO(&ctx->readfds);
1551 }
1552 if (ewritefds) {
1553 ctx->writefds = *ewritefds;
1554 nfds = enfds;
1555 } else {
1556 FD_ZERO(&ctx->writefds);
1557 }
1558 if (eexceptfds) {
1559 ctx->exceptfds = *eexceptfds;
1560 nfds = enfds;
1561 } else {
1562 FD_ZERO(&ctx->exceptfds);
1563 }
1564 for (i = 0; i < ctx->num_sockets; i++) {
1565 if (ctx->sockets[i]->fd + 1 > nfds)
1566 nfds = ctx->sockets[i]->fd + 1;
1567 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_READ)
1568 FD_SET(ctx->sockets[i]->fd, &ctx->readfds);
1569 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_WRITE)
1570 FD_SET(ctx->sockets[i]->fd, &ctx->writefds);
1571#if !COAP_DISABLE_TCP
1572 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT)
1573 FD_SET(ctx->sockets[i]->fd, &ctx->readfds);
1574 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) {
1575 FD_SET(ctx->sockets[i]->fd, &ctx->writefds);
1576 FD_SET(ctx->sockets[i]->fd, &ctx->exceptfds);
1577 }
1578#endif /* !COAP_DISABLE_TCP */
1579 }
1580
1581 if (timeout_ms == COAP_IO_NO_WAIT) {
1582 tv.tv_usec = 0;
1583 tv.tv_sec = 0;
1584 timeout = 1;
1585 } else if (timeout > 0) {
1586 tv.tv_usec = (timeout % 1000) * 1000;
1587 tv.tv_sec = (long)(timeout / 1000);
1588 }
1589
1590 result = select((int)nfds, &ctx->readfds, &ctx->writefds, &ctx->exceptfds,
1591 timeout > 0 ? &tv : NULL);
1592
1593 if (result < 0) { /* error */
1594#ifdef _WIN32
1595 coap_win_error_to_errno();
1596#endif
1597 if (errno != EINTR) {
1599 return -1;
1600 }
1601 }
1602 if (ereadfds) {
1603 *ereadfds = ctx->readfds;
1604 }
1605 if (ewritefds) {
1606 *ewritefds = ctx->writefds;
1607 }
1608 if (eexceptfds) {
1609 *eexceptfds = ctx->exceptfds;
1610 }
1611
1612 if (result > 0) {
1613 for (i = 0; i < ctx->num_sockets; i++) {
1614 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_READ) &&
1615 FD_ISSET(ctx->sockets[i]->fd, &ctx->readfds))
1617#if !COAP_DISABLE_TCP
1618 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT) &&
1619 FD_ISSET(ctx->sockets[i]->fd, &ctx->readfds))
1621 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_WRITE) &&
1622 FD_ISSET(ctx->sockets[i]->fd, &ctx->writefds))
1624 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) &&
1625 (FD_ISSET(ctx->sockets[i]->fd, &ctx->writefds) ||
1626 FD_ISSET(ctx->sockets[i]->fd, &ctx->exceptfds)))
1628#endif /* !COAP_DISABLE_TCP */
1629 }
1630 }
1631
1632 coap_ticks(&now);
1633 coap_io_do_io(ctx, now);
1634
1635#else /* COAP_EPOLL_SUPPORT */
1636 (void)ereadfds;
1637 (void)ewritefds;
1638 (void)eexceptfds;
1639 (void)enfds;
1640
1641 timeout = coap_io_prepare_epoll(ctx, before);
1642
1643 if (timeout == 0 || timeout_ms < timeout)
1644 timeout = timeout_ms;
1645
1646 do {
1647 struct epoll_event events[COAP_MAX_EPOLL_EVENTS];
1648 int etimeout = timeout;
1649
1650 /* Potentially adjust based on what the caller wants */
1651 if (timeout_ms == COAP_IO_NO_WAIT) {
1652 etimeout = 0;
1653 } else if (timeout == COAP_IO_WAIT) {
1654 /* coap_io_prepare_epoll() returned 0 and timeout_ms COAP_IO_WAIT (0) */
1655 etimeout = -1;
1656 } else if (etimeout < 0) {
1657 /* epoll_wait cannot wait longer than this as int timeout parameter */
1658 etimeout = INT_MAX;
1659 }
1660
1661 nfds = epoll_wait(ctx->epfd, events, COAP_MAX_EPOLL_EVENTS, etimeout);
1662 if (nfds < 0) {
1663 if (errno != EINTR) {
1664 coap_log_err("epoll_wait: unexpected error: %s (%d)\n",
1665 coap_socket_strerror(), nfds);
1666 }
1667 break;
1668 }
1669
1670 coap_io_do_epoll(ctx, events, nfds);
1671
1672 /*
1673 * reset to COAP_IO_NO_WAIT (which causes etimeout to become 0)
1674 * incase we have to do another iteration
1675 * (COAP_MAX_EPOLL_EVENTS insufficient)
1676 */
1677 timeout_ms = COAP_IO_NO_WAIT;
1678
1679 /* Keep retrying until less than COAP_MAX_EPOLL_EVENTS are returned */
1680 } while (nfds == COAP_MAX_EPOLL_EVENTS);
1681
1682#endif /* COAP_EPOLL_SUPPORT */
1683#if COAP_SERVER_SUPPORT
1685#endif /* COAP_SERVER_SUPPORT */
1686 coap_ticks(&now);
1687#if COAP_ASYNC_SUPPORT
1688 /* Check to see if we need to send off any Async requests as delay might
1689 have been updated */
1690 coap_check_async(ctx, now);
1691 coap_ticks(&now);
1692#endif /* COAP_ASYNC_SUPPORT */
1693
1694 return (int)(((now - before) * 1000) / COAP_TICKS_PER_SECOND);
1695}
1696#endif /* ! WITH_LWIP && ! WITH_CONTIKI */
1697
1698/*
1699 * return 1 I/O pending
1700 * 0 No I/O pending
1701 */
1702int
1704 coap_session_t *s, *rtmp;
1705#if COAP_SERVER_SUPPORT
1706 coap_endpoint_t *ep;
1707#endif /* COAP_SERVER_SUPPORT */
1708
1709 if (!context)
1710 return 0;
1711 if (coap_io_process(context, COAP_IO_NO_WAIT) < 0)
1712 return 0;
1713
1714 if (context->sendqueue)
1715 return 1;
1716#if COAP_SERVER_SUPPORT
1717 LL_FOREACH(context->endpoint, ep) {
1718 SESSIONS_ITER(ep->sessions, s, rtmp) {
1719 if (s->delayqueue)
1720 return 1;
1721 if (s->lg_xmit)
1722 return 1;
1723 if (s->lg_srcv)
1724 return 1;
1725 }
1726 }
1727#endif /* COAP_SERVER_SUPPORT */
1728#if COAP_CLIENT_SUPPORT
1729 SESSIONS_ITER(context->sessions, s, rtmp) {
1730 if (s->delayqueue)
1731 return 1;
1732 if (s->lg_xmit)
1733 return 1;
1734 if (s->lg_crcv)
1735 return 1;
1736 }
1737#endif /* COAP_CLIENT_SUPPORT */
1738 return 0;
1739}
1740
1741#ifdef _WIN32
1742const char *
1743coap_socket_format_errno(int error) {
1744 static char szError[256];
1745 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
1746 NULL, (DWORD)error, MAKELANGID(LANG_NEUTRAL,
1747 SUBLANG_DEFAULT), (LPSTR)szError, (DWORD)sizeof(szError),
1748 NULL) == 0)
1749 strcpy(szError, "Unknown error");
1750 return szError;
1751}
1752
1753const char *
1755 return coap_socket_format_errno(WSAGetLastError());
1756}
1757#else /* _WIN32 */
1758const char *
1760 return strerror(error);
1761}
1762const char *
1764 return coap_socket_format_errno(errno);
1765}
1766#endif /* _WIN32 */
1767
1768#undef SIN6
int coap_is_bcast(const coap_address_t *a)
Checks if given address a denotes a broadcast address.
void coap_address_init(coap_address_t *addr)
Resets the given coap_address_t object addr to its default values.
int coap_is_mcast(const coap_address_t *a)
Checks if given address a denotes a multicast address.
void coap_address_copy(coap_address_t *dst, const coap_address_t *src)
COAP_STATIC_INLINE int coap_address_isany(const coap_address_t *a)
Checks if given address object a denotes the wildcard address.
int coap_debug_send_packet(void)
Check to see whether a packet should be sent or not.
Pulls together all the internal only header files.
#define COAP_IPV4_SUPPORT
const char * coap_socket_format_errno(int error)
Definition coap_io.c:1759
ssize_t coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len)
Function interface for data stream receiving off a socket.
Definition coap_io.c:687
void coap_socket_close(coap_socket_t *sock)
Function interface to close off a socket.
Definition coap_io.c:395
ssize_t coap_socket_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:793
const char * coap_socket_strerror(void)
Definition coap_io.c:1763
ssize_t coap_socket_recv(coap_socket_t *sock, coap_packet_t *packet)
Function interface for reading data.
Definition coap_io.c:986
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:973
ssize_t coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len)
Function interface for data stream sending off a socket.
Definition coap_io.c:628
int coap_socket_bind_udp(coap_socket_t *sock, const coap_address_t *listen_addr, coap_address_t *bound_addr)
Definition coap_io.c:92
#define MSG_NOSIGNAL
#define iov_len_t
Definition coap_io.c:779
#define COAP_SOL_IP
Definition coap_io.c:752
#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
#define COAP_SOCKET_MULTICAST
socket is used for multicast communication
void coap_epoll_ctl_add(coap_socket_t *sock, uint32_t events, const char *func)
Epoll specific function to add the state of events that epoll is to track for the appropriate file de...
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)
#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
coap_endpoint_t * coap_malloc_endpoint(void)
void coap_epoll_ctl_mod(coap_socket_t *sock, uint32_t events, const char *func)
Epoll specific function to modify the state of events that epoll is tracking on the appropriate file ...
#define COAP_SOCKET_WANT_CONNECT
non blocking client socket is waiting for connect
void coap_mfree_endpoint(coap_endpoint_t *ep)
#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_ENDPOINT
Definition coap_mem.h:44
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().
coap_tick_t coap_dtls_get_timeout(coap_session_t *session COAP_UNUSED, coap_tick_t now COAP_UNUSED)
Definition coap_notls.c:192
coap_tick_t coap_dtls_get_context_timeout(void *dtls_context COAP_UNUSED)
Definition coap_notls.c:187
int coap_dtls_handle_timeout(coap_session_t *session COAP_UNUSED)
Definition coap_notls.c:201
coap_mid_t coap_session_send_ping(coap_session_t *session)
Send a ping message for the session.
#define SESSIONS_ITER_SAFE(e, el, rtmp)
#define SESSIONS_ITER(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 coap_net.c:2035
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:1215
void coap_io_do_epoll(coap_context_t *ctx, struct epoll_event *events, size_t nevents)
Process all the epoll events.
Definition coap_net.c:2092
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:1265
int coap_io_process(coap_context_t *ctx, uint32_t timeout_ms)
The main I/O processing function.
Definition coap_io.c:1519
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:1524
#define COAP_IO_NO_WAIT
Definition coap_net.h:572
#define COAP_IO_WAIT
Definition coap_net.h:571
int coap_io_pending(coap_context_t *context)
Check to see if there is any i/o pending for the context.
Definition coap_io.c:1703
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)
void coap_expire_cache_entries(coap_context_t *context)
Expire coap_cache_entry_t entries.
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition coap_time.h:144
#define COAP_TICKS_PER_SECOND
Use ms resolution on POSIX systems.
Definition coap_time.h:159
coap_queue_t * coap_peek_next(coap_context_t *context)
Returns the next pdu to send without removing from sendqeue.
Definition coap_net.c:246
coap_queue_t * coap_pop_next(coap_context_t *context)
Returns the next pdu to send and removes it from the sendqeue.
Definition coap_net.c:254
coap_mid_t coap_retransmit(coap_context_t *context, coap_queue_t *node)
Handles retransmissions of confirmable messages.
Definition coap_net.c:1606
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 coap_net.c:3914
void coap_ticks(coap_tick_t *)
Returns the current value of an internal tick counter.
int coap_dtls_is_context_timeout(void)
Check if timeout is handled per CoAP session or per CoAP context.
Definition coap_notls.c:182
@ 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_EVENT_KEEPALIVE_FAILURE
Triggered when no response to a keep alive (ping) packet.
Definition coap_event.h:132
#define coap_log_debug(...)
Definition coap_debug.h:120
#define coap_log_alert(...)
Definition coap_debug.h:84
#define coap_log_emerg(...)
Definition coap_debug.h:81
const char * coap_session_str(const coap_session_t *session)
Get session description.
#define coap_log_info(...)
Definition coap_debug.h:108
#define coap_log_warn(...)
Definition coap_debug.h:102
#define coap_log_err(...)
Definition coap_debug.h:96
#define coap_log_crit(...)
Definition coap_debug.h:90
#define COAP_INVALID_MID
Indicates an invalid message id.
Definition coap_pdu.h:258
@ COAP_PROTO_DTLS
Definition coap_pdu.h:307
void coap_session_free(coap_session_t *session)
#define COAP_PROTO_RELIABLE(p)
void coap_session_release(coap_session_t *session)
Decrement reference counter on a session.
void coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason)
Notify session that it has failed.
coap_session_t * coap_session_reference(coap_session_t *session)
Increment reference counter on a session.
@ COAP_SESSION_TYPE_SERVER
server-side
@ COAP_SESSION_TYPE_CLIENT
client-side
@ COAP_SESSION_STATE_HANDSHAKE
@ COAP_SESSION_STATE_CSM
@ COAP_SESSION_STATE_ESTABLISHED
@ COAP_SESSION_STATE_NONE
void coap_check_notify(coap_context_t *context)
Checks all known resources to see if they are dirty and then notifies subscribed observers.
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.
socklen_t size
size of addr
struct sockaddr_in sin
struct coap_sockaddr_un cun
struct sockaddr_in6 sin6
struct sockaddr sa
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.
coap_socket_t * sockets[64]
Track different socket information in coap_io_process_with_fds.
unsigned int csm_timeout
Timeout for waiting for a CSM from the remote side.
unsigned int num_sockets
Number of sockets being tracked.
coap_session_t * sessions
client sessions
fd_set exceptfds
Used for select call in coap_io_process_with_fds()
unsigned int ping_timeout
Minimum inactivity time before sending a ping message.
coap_queue_t * sendqueue
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_address_t bind_addr
local interface address
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
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 relationship with peer
coap_addr_tuple_t addr_info
remote/local address info
coap_proto_t proto
protocol used
unsigned ref
reference count from queues
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
char sun_path[COAP_UNIX_PATH_MAX]
coap_session_t * session
Used to determine session owner.
coap_endpoint_t * endpoint
Used by the epoll logic for a listening endpoint.
coap_address_t mcast_addr
remote address and port (multicast track)
coap_socket_flags_t flags
1 or more of COAP_SOCKET* flag values
struct in6_addr ipi6_addr
Definition coap_io.c:732
unsigned int ipi6_ifindex
Definition coap_io.c:733
struct in_addr ipi_spec_dst
Definition coap_io.c:738
struct in_addr ipi_addr
Definition coap_io.c:739
int ipi_ifindex
Definition coap_io.c:737