diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2013-11-23 11:50:34 +0100 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2013-11-23 11:50:34 +0100 |
commit | 736e143fa50607fcd88132291e96089b899af979 (patch) | |
tree | c0fcd5fb3174bae8a39b3a32dfe582b2ccb6df17 /sysdep/unix/io.c | |
parent | 094d2bdb79e1ffa0a02761fd651aa0f0b6b0c585 (diff) | |
parent | 2b3d52aa421ae1c31e30107beefd82fddbb42854 (diff) |
Merge branch 'master' into add-path
Conflicts:
filter/filter.c
nest/proto.c
nest/rt-table.c
proto/bgp/bgp.h
proto/bgp/config.Y
Diffstat (limited to 'sysdep/unix/io.c')
-rw-r--r-- | sysdep/unix/io.c | 94 |
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) |