X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/blobdiff_plain/bf302d900e1658e664e4e7c05bb2748c4677dfc6..136f3f44e25317d5423b4bc0b075b297e6d00c93:/server/peer.c diff --git a/server/peer.c b/server/peer.c index f723cccb..dab3bfcf 100644 --- a/server/peer.c +++ b/server/peer.c @@ -36,22 +36,11 @@ udpsocket udpsock[NADDRFAM]; static sym_table byname; static addrmap byaddr; static unsigned nmobile; - -/*----- Tunnel table ------------------------------------------------------*/ - -const tunnel_ops *tunnels[] = { -#ifdef TUN_LINUX - &tun_linux, -#endif -#ifdef TUN_BSD - &tun_bsd, -#endif -#ifdef TUN_UNET - &tun_unet, -#endif - &tun_slip, - 0 -}, *tun_default; +static struct tunnel_node { + struct tunnel_node *next; + const tunnel_ops *tops; +} *tunnels, **tunnels_tail = &tunnels; +const tunnel_ops *dflttun; /*----- Main code ---------------------------------------------------------*/ @@ -820,14 +809,14 @@ const addr *p_addr(peer *p) { return (&p->spec.sa); } * * Arguments: @struct addrinfo *ailist@ = addresses to bind to * - * Returns: --- + * Returns: Zero on success, @-1@ on failure. * - * Use: Initializes the peer system; creates the socket. + * Use: Binds to the main UDP sockets. */ -void p_bind(struct addrinfo *ailist) +int p_bind(struct addrinfo *ailist) { - int fd; + int fd = -1; int len = PKBUFSZ; int yes = 1; int i; @@ -853,13 +842,13 @@ void p_bind(struct addrinfo *ailist) if ((fd = socket(ai->ai_family, SOCK_DGRAM, 0)) < 0) { a_warn("PEER", "-", "udp-socket", "%s", aftab[i].name, "create-failed", "?ERRNO", A_END); - exit(EXIT_FAILURE); + goto fail; } if (i == AFIX_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes))) { a_warn("PEER", "-", "udp-socket", "%s", aftab[i].name, "set-v6only-failed", "?ERRNO", A_END); - exit(EXIT_FAILURE); + goto fail; } assert(ai->ai_addrlen <= sizeof(a)); memcpy(&a, ai->ai_addr, ai->ai_addrlen); @@ -867,13 +856,13 @@ void p_bind(struct addrinfo *ailist) if (bind(fd, &a.sa, addrsz(&a))) { a_warn("PEER", "-", "udp-socket", "%s", aftab[i].name, "bind-failed", "?ERRNO", A_END); - exit(EXIT_FAILURE); + goto fail; } if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len)) || setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &len, sizeof(len))) { a_warn("PEER", "-", "udp-socket", "%s", aftab[i].name, "set-buffers-failed", "?ERRNO", A_END); - exit(EXIT_FAILURE); + goto fail; } fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); if (port) @@ -883,15 +872,22 @@ void p_bind(struct addrinfo *ailist) if (getsockname(fd, &a.sa, &sz)) { a_warn("PEER", "-", "udp-socket", "%s", aftab[i].name, "read-local-address-failed", "?ERRNO", A_END); - exit(EXIT_FAILURE); + goto fail; } udpsock[i].port = lastport = getport(&a); } T( trace(T_PEER, "peer: created %s socket", aftab[i].name); ) sel_initfile(&sel, &udpsock[i].sf, fd, SEL_READ, p_read, 0); sel_addfile(&udpsock[i].sf); + fd = -1; } + return (0); + +fail: + if (fd != -1) close(fd); + p_unbind(); + return (-1); } /* --- @p_unbind@ --- * @@ -935,6 +931,102 @@ void p_init(void) am_create(&byaddr); } +/* --- @p_addtun@ --- * + * + * Arguments: @const tunnel_ops *tops@ = tunnel ops to add + * + * Returns: Zero on success, @-1@ on failure. + * + * Use: Adds a tunnel class to the list of known classes, if it + * initializes properly. If there is no current default tunnel, + * then this one is made the default. + * + * Does nothing if the tunnel class is already known. So adding + * a bunch of tunnels takes quadratic time, but there will be + * too few to care about. + */ + +int p_addtun(const tunnel_ops *tops) +{ + struct tunnel_node *tn; + + for (tn = tunnels; tn; tn = tn->next) + if (tn->tops == tops) return (0); + if (tops->init()) return (-1); + tn = CREATE(struct tunnel_node); + tn->next = 0; tn->tops = tops; + *tunnels_tail = tn; tunnels_tail = &tn->next; + if (!dflttun) dflttun = tops; + return (0); +} + +/* --- @p_setdflttun@ --- * + * + * Arguments: @const tunnel_ops *tops@ = tunnel ops to set + * + * Returns: --- + * + * Use: Sets the default tunnel. It must already be registered. The + * old default is forgotten. + */ + +void p_setdflttun(const tunnel_ops *tops) + { dflttun = tops; } + +/* --- @p_dflttun@ --- * + * + * Arguments: --- + * + * Returns: A pointer to the current default tunnel operations, or null + * if no tunnels are defined. + */ + +const tunnel_ops *p_dflttun(void) { return (dflttun); } + +/* --- @p_findtun@ --- * + * + * Arguments: @const char *name@ = tunnel name + * + * Returns: Pointer to the tunnel operations, or null. + * + * Use: Finds the operations for a named tunnel class. + */ + +const tunnel_ops *p_findtun(const char *name) +{ + const struct tunnel_node *tn; + + for (tn = tunnels; tn; tn = tn->next) + if (mystrieq(tn->tops->name, name) == 0) return (tn->tops); + return (0); +} + +/* --- @p_mktuniter@ --- * + * + * Arguments: @tuniter *i@ = pointer to iterator to initialize + * + * Returns: --- + * + * Use: Initializes a tunnel iterator. + */ + +void p_mktuniter(tun_iter *i) { i->next = tunnels; } + +/* --- @p_nexttun@ --- * + * + * Arguments: @tuniter *i@ = pointer to iterator + * + * Returns: Pointer to the next tunnel's operations, or null. + */ + +const tunnel_ops *p_nexttun(tun_iter *i) +{ + const struct tunnel_node *tn = i->next; + + if (!tn) return (0); + else { i->next = tn->next; return (tn->tops); } +} + /* --- @p_keepalive@ --- * * * Arguments: @struct timeval *now@ = the current time @@ -1145,7 +1237,7 @@ void p_destroy(peer *p, int bye) T( trace(T_PEER, "peer: destroying peer `%s'", p->spec.name); ) - if (bye && (p->spec.f&PSF_EPHEM)) { + if (bye) { b = p_txstart(p, MSG_MISC | MISC_BYE); buf_init(&bb, buf_t, sizeof(buf_t)); assert(BOK(&bb)); buf_flip(&bb);