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