diff --git a/lib/socket.h b/lib/socket.h index e6229f70..65ba9a20 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -64,6 +64,9 @@ sk_send_buffer_empty(sock *sk) #define SK_IP 5 /* ? - - * - ? ? */ #define SK_IP_MC 6 /* ? - * * * * - */ #define SK_MAGIC 7 /* Internal use by sysdep code */ +#define SK_UNIX_PASSIVE 8 +#define SK_UNIX 9 +#define SK_DELETED 10 /* Set to this if you want to delete socket from err_hook */ /* * Multicast sockets are slightly different from the other ones: diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 943a6a72..aef348ce 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -285,7 +286,7 @@ static void sk_dump(resource *r) { sock *s = (sock *) r; - static char *sk_type_names[] = { "TCP<", "TCP>", "TCP", "UDP", "UDP/MC", "IP", "IP/MC", "MAGIC" }; + static char *sk_type_names[] = { "TCP<", "TCP>", "TCP", "UDP", "UDP/MC", "IP", "IP/MC", "MAGIC", "UNIX<", "UNIX", "DEL!" }; debug("(%s, ud=%p, sa=%08x, sp=%d, da=%08x, dp=%d, tos=%d, ttl=%d, if=%s)\n", sk_type_names[s->type], @@ -398,6 +399,8 @@ sk_setup(sock *s) if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) ERR("fcntl(O_NONBLOCK)"); + if (s->type == SK_UNIX) + return NULL; #ifdef IPV6 if (s->ttl >= 0 && s->type != SK_UDP_MC && s->type != SK_IP_MC && setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0) @@ -431,7 +434,7 @@ sk_alloc_bufs(sock *s) s->tpos = s->ttx = s->tbuf; } -void +static void sk_tcp_connected(sock *s) { s->rx_hook(s, 0); @@ -439,6 +442,35 @@ sk_tcp_connected(sock *s) sk_alloc_bufs(s); } +static int +sk_passive_connected(sock *s, struct sockaddr *sa, int al, int type) +{ + int fd = accept(s->fd, sa, &al); + if (fd >= 0) + { + sock *t = sk_new(s->pool); + char *err; + t->type = type; + t->fd = fd; + add_tail(&sock_list, &t->n); + s->rx_hook(t, 0); + if (err = sk_setup(t)) + { + log(L_ERR "Incoming connection: %s: %m", err); + s->err_hook(s, errno); + return 0; + } + sk_alloc_bufs(t); + return 1; + } + else if (errno != EINTR && errno != EAGAIN) + { + log(L_ERR "accept: %m"); + s->err_hook(s, errno); + } + return 0; +} + int sk_open(sock *s) { @@ -627,6 +659,37 @@ bad: return -1; } +int +sk_open_unix(sock *s, char *name) +{ + int fd; + struct sockaddr_un sa; + char *err; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) + die("sk_open_unix: socket: %m"); + s->fd = fd; + if (err = sk_setup(s)) + goto bad; + unlink(name); + sa.sun_family = AF_UNIX; + strcpy(sa.sun_path, name); + if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) + ERR("bind"); + if (listen(fd, 8)) + ERR("listen"); + sk_alloc_bufs(s); + add_tail(&sock_list, &s->n); + return 0; + +bad: + log(L_ERR "sk_open_unix: %s: %m", err); + close(fd); + s->fd = -1; + return -1; +} + static int sk_maybe_write(sock *s) { @@ -636,6 +699,7 @@ sk_maybe_write(sock *s) { case SK_TCP: case SK_MAGIC: + case SK_UNIX: while (s->ttx != s->tpos) { e = write(s->fd, s->ttx, s->tpos - s->ttx); @@ -723,33 +787,15 @@ sk_read(sock *s) case SK_TCP_PASSIVE: { sockaddr sa; - int al = sizeof(sa); - int fd = accept(s->fd, (struct sockaddr *) &sa, &al); - if (fd >= 0) - { - sock *t = sk_new(s->pool); - char *err; - t->type = SK_TCP; - t->fd = fd; - add_tail(&sock_list, &t->n); - s->rx_hook(t, 0); - if (err = sk_setup(t)) - { - log(L_ERR "Incoming connection: %s: %m", err); - s->err_hook(s, errno); - return 0; - } - sk_alloc_bufs(t); - return 1; - } - else if (errno != EINTR && errno != EAGAIN) - { - log(L_ERR "accept: %m"); - s->err_hook(s, errno); - } - return 0; + return sk_passive_connected(s, (struct sockaddr *) &sa, sizeof(sa), SK_TCP); + } + case SK_UNIX_PASSIVE: + { + struct sockaddr_un sa; + return sk_passive_connected(s, (struct sockaddr *) &sa, sizeof(sa), SK_UNIX); } case SK_TCP: + case SK_UNIX: { int c = read(s->fd, s->rpos, s->rbuf + s->rbsize - s->rpos); @@ -850,7 +896,7 @@ io_loop(void) time_t tout; int hi; sock *s; - node *n; + node *n, *p; /* FIXME: Use poll() if available */ @@ -925,7 +971,7 @@ io_loop(void) } if (hi) { - WALK_LIST(n, sock_list) + WALK_LIST_DELSAFE(n, p, sock_list) { s = SKIP_BACK(sock, n, n); if (FD_ISSET(s->fd, &rd)) @@ -934,11 +980,13 @@ io_loop(void) while (sk_read(s)) ; } - if (FD_ISSET(s->fd, &wr)) + if (s->type != SK_DELETED && FD_ISSET(s->fd, &wr)) { FD_CLR(s->fd, &wr); sk_write(s); } + if (s->type == SK_DELETED) + rfree(s); } } } diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h index e3c9708d..ab724d19 100644 --- a/sysdep/unix/unix.h +++ b/sysdep/unix/unix.h @@ -31,10 +31,13 @@ typedef struct sockaddr_in6 sockaddr; typedef struct sockaddr_in sockaddr; #endif +struct birdsock; + void io_init(void); void io_loop(void); void fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port); void get_sockaddr(sockaddr *sa, ip_addr *a, unsigned *port); +int sk_open_unix(struct birdsock *s, char *name); /* krt.c bits */