summaryrefslogtreecommitdiff
path: root/sysdep/unix/io.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdep/unix/io.c')
-rw-r--r--sysdep/unix/io.c94
1 files changed, 70 insertions, 24 deletions
diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c
index f91b5278..6e3f1e4d 100644
--- a/sysdep/unix/io.c
+++ b/sysdep/unix/io.c
@@ -17,10 +17,10 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/fcntl.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <unistd.h>
+#include <fcntl.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/icmp6.h>
@@ -121,7 +121,7 @@ static list near_timers, far_timers;
static bird_clock_t first_far_timer = TIME_INFINITY;
/* now must be different from 0, because 0 is a special value in timer->expires */
-bird_clock_t now = 1, now_real;
+bird_clock_t now = 1, now_real, boot_time;
static void
update_times_plain(void)
@@ -538,6 +538,11 @@ sk_free(resource *r)
if (s->fd >= 0)
{
close(s->fd);
+
+ /* FIXME: we should call sk_stop() for SKF_THREAD sockets */
+ if (s->flags & SKF_THREAD)
+ return;
+
if (s == current_sock)
current_sock = sk_next(s);
if (s == stored_sock)
@@ -598,7 +603,7 @@ sock_new(pool *p)
sock *s = ralloc(p, &sk_class);
s->pool = p;
// s->saddr = s->daddr = IPA_NONE;
- s->tos = s->ttl = -1;
+ s->tos = s->priority = s->ttl = -1;
s->fd = -1;
return s;
}
@@ -673,7 +678,7 @@ get_sockaddr(struct sockaddr_in *sa, ip_addr *a, struct iface **ifa, unsigned *p
#ifdef IPV6
/* PKTINFO handling is also standardized in IPv6 */
-#define CMSG_RX_SPACE CMSG_SPACE(sizeof(struct in6_pktinfo))
+#define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)))
#define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in6_pktinfo))
/*
@@ -685,15 +690,26 @@ get_sockaddr(struct sockaddr_in *sa, ip_addr *a, struct iface **ifa, unsigned *p
#ifndef IPV6_RECVPKTINFO
#define IPV6_RECVPKTINFO IPV6_PKTINFO
#endif
+/*
+ * Same goes for IPV6_HOPLIMIT -> IPV6_RECVHOPLIMIT.
+ */
+#ifndef IPV6_RECVHOPLIMIT
+#define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
+#endif
static char *
sysio_register_cmsgs(sock *s)
{
int ok = 1;
+
if ((s->flags & SKF_LADDR_RX) &&
- setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0)
+ (setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0))
return "IPV6_RECVPKTINFO";
+ if ((s->flags & SKF_TTL_RX) &&
+ (setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &ok, sizeof(ok)) < 0))
+ return "IPV6_RECVHOPLIMIT";
+
return NULL;
}
@@ -702,25 +718,34 @@ sysio_process_rx_cmsgs(sock *s, struct msghdr *msg)
{
struct cmsghdr *cm;
struct in6_pktinfo *pi = NULL;
-
- if (!(s->flags & SKF_LADDR_RX))
- return;
+ int *hlim = NULL;
for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
+ {
+ if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO)
+ pi = (struct in6_pktinfo *) CMSG_DATA(cm);
+
+ if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_HOPLIMIT)
+ hlim = (int *) CMSG_DATA(cm);
+ }
+
+ if (s->flags & SKF_LADDR_RX)
+ {
+ if (pi)
{
- if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO)
- pi = (struct in6_pktinfo *) CMSG_DATA(cm);
+ get_inaddr(&s->laddr, &pi->ipi6_addr);
+ s->lifindex = pi->ipi6_ifindex;
}
-
- if (!pi)
+ else
{
s->laddr = IPA_NONE;
s->lifindex = 0;
- return;
}
+ }
+
+ if (s->flags & SKF_TTL_RX)
+ s->ttl = hlim ? *hlim : -1;
- get_inaddr(&s->laddr, &pi->ipi6_addr);
- s->lifindex = pi->ipi6_ifindex;
return;
}
@@ -783,21 +808,28 @@ sk_setup(sock *s)
ERR("fcntl(O_NONBLOCK)");
if (s->type == SK_UNIX)
return NULL;
-#ifndef IPV6
+
+#ifdef IPV6
+ if ((s->tos >= 0) && setsockopt(fd, SOL_IPV6, IPV6_TCLASS, &s->tos, sizeof(s->tos)) < 0)
+ WARN("IPV6_TCLASS");
+#else
if ((s->tos >= 0) && setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0)
WARN("IP_TOS");
#endif
+ if (s->priority >= 0)
+ sk_set_priority(s, s->priority);
+
#ifdef IPV6
int v = 1;
if ((s->flags & SKF_V6ONLY) && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &v, sizeof(v)) < 0)
WARN("IPV6_V6ONLY");
#endif
- if (s->ttl >= 0)
- err = sk_set_ttl_int(s);
+ if ((s->ttl >= 0) && (err = sk_set_ttl_int(s)))
+ goto bad;
- sysio_register_cmsgs(s);
+ err = sysio_register_cmsgs(s);
bad:
return err;
}
@@ -1154,6 +1186,15 @@ sk_open(sock *s)
port = s->sport;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
ERR("SO_REUSEADDR");
+
+#ifdef CONFIG_NO_IFACE_BIND
+ /* Workaround missing ability to bind to an iface */
+ if ((type == SK_UDP) && s->iface && ipa_zero(s->saddr))
+ {
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0)
+ ERR("SO_REUSEPORT");
+ }
+#endif
}
fill_in_sockaddr(&sa, s->saddr, s->iface, port);
if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
@@ -1204,7 +1245,8 @@ sk_open(sock *s)
#endif
}
- sk_insert(s);
+ if (!(s->flags & SKF_THREAD))
+ sk_insert(s);
return 0;
bad:
@@ -1392,7 +1434,9 @@ sk_send_full(sock *s, unsigned len, struct iface *ifa,
}
*/
-static int
+ /* sk_read() and sk_write() are called from BFD's event loop */
+
+int
sk_read(sock *s)
{
switch (s->type)
@@ -1469,7 +1513,7 @@ sk_read(sock *s)
}
}
-static int
+int
sk_write(sock *s)
{
switch (s->type)
@@ -1487,7 +1531,8 @@ sk_write(sock *s)
default:
if (s->ttx != s->tpos && sk_maybe_write(s) > 0)
{
- s->tx_hook(s);
+ if (s->tx_hook)
+ s->tx_hook(s);
return 1;
}
return 0;
@@ -1530,6 +1575,7 @@ io_init(void)
krt_io_init();
init_times();
update_times();
+ boot_time = now;
srandom((int) now_real);
}
@@ -1557,7 +1603,7 @@ io_loop(void)
tm_shot();
continue;
}
- timo.tv_sec = events ? 0 : tout - now;
+ timo.tv_sec = events ? 0 : MIN(tout - now, 3);
timo.tv_usec = 0;
if (sock_recalc_fdsets_p)