mini_inetd.c revision 57416
1/*
2 * Copyright (c) 1995 - 2000 Kungliga Tekniska H�gskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifdef HAVE_CONFIG_H
35#include <config.h>
36RCSID("$Id: mini_inetd.c,v 1.25 2000/01/26 00:54:48 assar Exp $");
37#endif
38
39#include <stdio.h>
40
41#ifdef HAVE_UNISTD_H
42#include <unistd.h>
43#endif
44#ifdef HAVE_SYS_TYPES_H
45#include <sys/types.h>
46#endif
47#ifdef HAVE_SYS_TIME_H
48#include <sys/time.h>
49#endif
50#ifdef HAVE_SYS_SOCKET_H
51#include <sys/socket.h>
52#endif
53#ifdef HAVE_NETINET_IN_H
54#include <netinet/in.h>
55#endif
56#ifdef HAVE_NETINET_IN6_H
57#include <netinet/in6.h>
58#endif
59#ifdef HAVE_NETINET6_IN6_H
60#include <netinet6/in6.h>
61#endif
62
63#include <err.h>
64#include <roken.h>
65
66/*
67 * accept a connection on `s' and pretend it's served by inetd.
68 */
69
70static void
71accept_it (int s)
72{
73    int s2;
74
75    s2 = accept(s, NULL, 0);
76    if(s2 < 0)
77	err (1, "accept");
78    close(s);
79    dup2(s2, STDIN_FILENO);
80    dup2(s2, STDOUT_FILENO);
81    /* dup2(s2, STDERR_FILENO); */
82    close(s2);
83}
84
85/*
86 * Listen on `port' emulating inetd.
87 */
88
89void
90mini_inetd (int port)
91{
92    int error, ret;
93    struct addrinfo *ai, *a, hints;
94    char portstr[NI_MAXSERV];
95    int n, nalloc, i;
96    int *fds;
97    fd_set orig_read_set, read_set;
98    int max_fd = -1;
99
100    memset (&hints, 0, sizeof(hints));
101    hints.ai_flags    = AI_PASSIVE;
102    hints.ai_socktype = SOCK_STREAM;
103
104    snprintf (portstr, sizeof(portstr), "%d", ntohs(port));
105
106    error = getaddrinfo (NULL, portstr, &hints, &ai);
107    if (error)
108	errx (1, "getaddrinfo: %s", gai_strerror (error));
109
110    for (nalloc = 0, a = ai; a != NULL; a = a->ai_next)
111	++nalloc;
112
113    fds = malloc (nalloc * sizeof(*fds));
114    if (fds == NULL)
115	errx (1, "mini_inetd: out of memory");
116
117    FD_ZERO(&orig_read_set);
118
119    for (i = 0, a = ai; a != NULL; a = a->ai_next) {
120	fds[i] = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
121	if (fds[i] < 0) {
122	    warn ("socket");
123	    continue;
124	}
125	socket_set_reuseaddr (fds[i], 1);
126	if (bind (fds[i], a->ai_addr, a->ai_addrlen) < 0)
127	    err (1, "bind");
128	if (listen (fds[i], SOMAXCONN) < 0)
129	    err (1, "listen");
130	FD_SET(fds[i], &orig_read_set);
131	max_fd = max(max_fd, fds[i]);
132	++i;
133    }
134    freeaddrinfo (ai);
135    if (i == 0)
136	errx (1, "no sockets");
137    n = i;
138
139    do {
140	read_set = orig_read_set;
141
142	ret = select (max_fd + 1, &read_set, NULL, NULL, NULL);
143	if (ret < 0 && errno != EINTR)
144	    err (1, "select");
145    } while (ret <= 0);
146
147    for (i = 0; i < n; ++i)
148	if (FD_ISSET (fds[i], &read_set)) {
149	    accept_it (fds[i]);
150	    return;
151	}
152    abort ();
153}
154