From c0f10ca664e0c6ab10a30d6155fa9db6d9279ce1 Mon Sep 17 00:00:00 2001 From: Assar Westerlund Date: Tue, 27 Jul 1999 21:16:54 +0000 Subject: [PATCH] support IPv6 git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@6606 ec53bebd-3082-4978-b11e-865c3cabbd6b --- lib/roken/mini_inetd.c | 144 ++++++++++++++++++++++++++++++++++------- 1 file changed, 119 insertions(+), 25 deletions(-) diff --git a/lib/roken/mini_inetd.c b/lib/roken/mini_inetd.c index 47cac8c8a..faaf2edee 100644 --- a/lib/roken/mini_inetd.c +++ b/lib/roken/mini_inetd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan + * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -49,6 +49,9 @@ RCSID("$Id$"); #ifdef HAVE_SYS_TYPES_H #include #endif +#ifdef HAVE_SYS_TIME_H +#include +#endif #ifdef HAVE_SYS_SOCKET_H #include #endif @@ -65,32 +68,33 @@ RCSID("$Id$"); #include -void -mini_inetd (int port) +static void +socket_set_reuseaddr (int sock, int val) +{ +#if defined(SO_REUSEADDR) && defined(HAVE_SETSOCKOPT) + if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&val, + sizeof(val)) < 0){ + perror("setsockopt"); + exit(1); + } +#endif +} + +static int +listen_v4 (int port) { struct sockaddr_in sa; int s; - int s2; s = socket(AF_INET, SOCK_STREAM, 0); if(s < 0) { perror("socket"); exit(1); } -#if defined(SO_REUSEADDR) && defined(HAVE_SETSOCKOPT) - { - int one = 1; - - if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&one, - sizeof(one)) < 0){ - perror("setsockopt"); - exit(1); - } - } -#endif + socket_set_reuseaddr (s, 1); memset(&sa, 0, sizeof(sa)); - sa.sin_family = AF_INET; - sa.sin_port = port; + sa.sin_family = AF_INET; + sa.sin_port = port; sa.sin_addr.s_addr = INADDR_ANY; if(bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0){ perror("bind"); @@ -100,14 +104,104 @@ mini_inetd (int port) perror("listen"); exit(1); } - s2 = accept(s, NULL, 0); - if(s2 < 0){ - perror("accept"); + return s; +} + +#ifdef HAVE_IPV6 +static int +listen_v6 (int port) +{ + struct sockaddr_in6 sa; + int s; + + s = socket(AF_INET6, SOCK_STREAM, 0); + if(s < 0) { + perror("socket"); exit(1); } - close(s); - dup2(s2, STDIN_FILENO); - dup2(s2, STDOUT_FILENO); - /* dup2(s2, STDERR_FILENO); */ - close(s2); + socket_set_reuseaddr (s, 1); + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = port; + sa.sin6_addr = in6addr_any; + if(bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0){ + perror("bind"); + exit(1); + } + if(listen(s, SOMAXCONN) < 0){ + perror("listen"); + exit(1); + } + return s; +} +#endif /* HAVE_IPV6 */ + +/* + * accept a connection on `s' and pretend it's served by inetd. + */ + +static void +accept_it (int s) +{ + int s2; + + s2 = accept(s, NULL, 0); + if(s2 < 0){ + perror("accept"); + exit(1); + } + close(s); + dup2(s2, STDIN_FILENO); + dup2(s2, STDOUT_FILENO); + /* dup2(s2, STDERR_FILENO); */ + close(s2); +} + +/* + * Listen on `port' emulating inetd. + */ + +void +mini_inetd (int port) +{ + int ret; + int max_fd = -1; + int sock_v4 = -1; + int sock_v6 = -1; + fd_set read_set; + + FD_ZERO(&read_set); + + sock_v4 = listen_v4 (port); + if (sock_v4 >= 0) { + max_fd = max(max_fd, sock_v4); + FD_SET(sock_v4, &read_set); + } +#ifdef HAVE_IPV6 + sock_v6 = listen_v6 (port); + if (sock_v6 >= 0) { + max_fd = max(max_fd, sock_v4); + FD_SET(sock_v6, &read_set); + } +#endif + + do { + fd_set rset = read_set; + + ret = select (max_fd + 1, &rset, NULL, NULL, NULL); + if (ret < 0 && ret != EINTR) { + perror ("select"); + exit (1); + } + } while (ret <= 0); + + if (sock_v4 > 0 && FD_ISSET (sock_v4, &read_set)) { + accept_it (sock_v4); + return; + } + if (sock_v6 > 0 && FD_ISSET (sock_v6, &read_set)) { + accept_it (sock_v6); + return; + } + abort (); }