14ecbd6dmarkm/*
233f661cstas * Copyright (c) 1995 - 2001 Kungliga Tekniska H��gskolan
34ecbd6dmarkm * (Royal Institute of Technology, Stockholm, Sweden).
44ecbd6dmarkm * All rights reserved.
533f661cstas *
64ecbd6dmarkm * Redistribution and use in source and binary forms, with or without
74ecbd6dmarkm * modification, are permitted provided that the following conditions
84ecbd6dmarkm * are met:
933f661cstas *
104ecbd6dmarkm * 1. Redistributions of source code must retain the above copyright
114ecbd6dmarkm *    notice, this list of conditions and the following disclaimer.
1233f661cstas *
134ecbd6dmarkm * 2. Redistributions in binary form must reproduce the above copyright
144ecbd6dmarkm *    notice, this list of conditions and the following disclaimer in the
154ecbd6dmarkm *    documentation and/or other materials provided with the distribution.
1633f661cstas *
174ecbd6dmarkm * 3. Neither the name of the Institute nor the names of its contributors
184ecbd6dmarkm *    may be used to endorse or promote products derived from this software
194ecbd6dmarkm *    without specific prior written permission.
2033f661cstas *
214ecbd6dmarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
224ecbd6dmarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
234ecbd6dmarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
244ecbd6dmarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
254ecbd6dmarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
264ecbd6dmarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
274ecbd6dmarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
284ecbd6dmarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
294ecbd6dmarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
304ecbd6dmarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
314ecbd6dmarkm * SUCH DAMAGE.
324ecbd6dmarkm */
334ecbd6dmarkm
344ecbd6dmarkm#include <config.h>
354ecbd6dmarkm
364ecbd6dmarkm#include <err.h>
37ebfe6dcassar#include "roken.h"
384ecbd6dmarkm
394ecbd6dmarkm/*
404ecbd6dmarkm * accept a connection on `s' and pretend it's served by inetd.
414ecbd6dmarkm */
424ecbd6dmarkm
434ecbd6dmarkmstatic void
4433f661cstasaccept_it (rk_socket_t s, rk_socket_t *ret_socket)
454ecbd6dmarkm{
4633f661cstas    rk_socket_t as;
474ecbd6dmarkm
4833f661cstas    as = accept(s, NULL, NULL);
4933f661cstas    if(rk_IS_BAD_SOCKET(as))
504ecbd6dmarkm	err (1, "accept");
5133f661cstas
5233f661cstas    if (ret_socket) {
5333f661cstas
5433f661cstas	*ret_socket = as;
5533f661cstas
5633f661cstas    } else {
5733f661cstas	int fd = socket_to_fd(as, 0);
5833f661cstas
5933f661cstas	/* We would use _O_RDONLY for the socket_to_fd() call for
6033f661cstas	   STDIN, but there are instances where we assume that STDIN
6133f661cstas	   is a r/w socket. */
6233f661cstas
6333f661cstas	dup2(fd, STDIN_FILENO);
6433f661cstas	dup2(fd, STDOUT_FILENO);
6533f661cstas
6633f661cstas	rk_closesocket(as);
6733f661cstas    }
684ecbd6dmarkm}
694ecbd6dmarkm
7033f661cstas/**
7133f661cstas * Listen on a specified addresses
7233f661cstas *
7333f661cstas * Listens on the specified addresses for incoming connections.  If
7433f661cstas * the \a ret_socket parameter is \a NULL, on return STDIN and STDOUT
7533f661cstas * will be connected to an accepted socket.  If the \a ret_socket
7633f661cstas * parameter is non-NULL, the accepted socket will be returned in
7733f661cstas * *ret_socket.  In the latter case, STDIN and STDOUT will be left
7833f661cstas * unmodified.
7933f661cstas *
8033f661cstas * This function does not return if there is an error or if no
8133f661cstas * connection is established.
8233f661cstas *
8333f661cstas * @param[in] ai Addresses to listen on
8433f661cstas * @param[out] ret_socket If non-NULL receives the accepted socket.
8533f661cstas *
8633f661cstas * @see mini_inetd()
874ecbd6dmarkm */
8833f661cstasROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
8933f661cstasmini_inetd_addrinfo (struct addrinfo *ai, rk_socket_t *ret_socket)
904ecbd6dmarkm{
91a77dba0nectar    int ret;
92a77dba0nectar    struct addrinfo *a;
93fa8b1a9markm    int n, nalloc, i;
9433f661cstas    rk_socket_t *fds;
954ecbd6dmarkm    fd_set orig_read_set, read_set;
9633f661cstas    rk_socket_t max_fd = (rk_socket_t)-1;
974ecbd6dmarkm
98fa8b1a9markm    for (nalloc = 0, a = ai; a != NULL; a = a->ai_next)
99fa8b1a9markm	++nalloc;
1004ecbd6dmarkm
101fa8b1a9markm    fds = malloc (nalloc * sizeof(*fds));
10233f661cstas    if (fds == NULL) {
1034ecbd6dmarkm	errx (1, "mini_inetd: out of memory");
10433f661cstas	UNREACHABLE(return);
10533f661cstas    }
1064ecbd6dmarkm
1074ecbd6dmarkm    FD_ZERO(&orig_read_set);
1084ecbd6dmarkm
109fa8b1a9markm    for (i = 0, a = ai; a != NULL; a = a->ai_next) {
1104ecbd6dmarkm	fds[i] = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
11133f661cstas	if (rk_IS_BAD_SOCKET(fds[i]))
112fa8b1a9markm	    continue;
1134ecbd6dmarkm	socket_set_reuseaddr (fds[i], 1);
11433f661cstas	socket_set_ipv6only(fds[i], 1);
11533f661cstas	if (rk_IS_SOCKET_ERROR(bind (fds[i], a->ai_addr, a->ai_addrlen))) {
11669a91benectar	    warn ("bind af = %d", a->ai_family);
11733f661cstas	    rk_closesocket(fds[i]);
11833f661cstas	    fds[i] = rk_INVALID_SOCKET;
11969a91benectar	    continue;
12069a91benectar	}
12133f661cstas	if (rk_IS_SOCKET_ERROR(listen (fds[i], SOMAXCONN))) {
12269a91benectar	    warn ("listen af = %d", a->ai_family);
12333f661cstas	    rk_closesocket(fds[i]);
12433f661cstas	    fds[i] = rk_INVALID_SOCKET;
12569a91benectar	    continue;
12669a91benectar	}
12733f661cstas#ifndef NO_LIMIT_FD_SETSIZE
128ebfe6dcassar	if (fds[i] >= FD_SETSIZE)
129ebfe6dcassar	    errx (1, "fd too large");
13033f661cstas#endif
1314ecbd6dmarkm	FD_SET(fds[i], &orig_read_set);
1324ecbd6dmarkm	max_fd = max(max_fd, fds[i]);
133fa8b1a9markm	++i;
1344ecbd6dmarkm    }
135fa8b1a9markm    if (i == 0)
136fa8b1a9markm	errx (1, "no sockets");
137fa8b1a9markm    n = i;
1384ecbd6dmarkm
1394ecbd6dmarkm    do {
1404ecbd6dmarkm	read_set = orig_read_set;
1414ecbd6dmarkm
1424ecbd6dmarkm	ret = select (max_fd + 1, &read_set, NULL, NULL, NULL);
14333f661cstas	if (rk_IS_SOCKET_ERROR(ret) && rk_SOCK_ERRNO != EINTR)
1444ecbd6dmarkm	    err (1, "select");
1454ecbd6dmarkm    } while (ret <= 0);
1464ecbd6dmarkm
1474ecbd6dmarkm    for (i = 0; i < n; ++i)
1484ecbd6dmarkm	if (FD_ISSET (fds[i], &read_set)) {
14933f661cstas	    accept_it (fds[i], ret_socket);
15033f661cstas	    for (i = 0; i < n; ++i)
15133f661cstas	      rk_closesocket(fds[i]);
15233f661cstas	    free(fds);
1534ecbd6dmarkm	    return;
1544ecbd6dmarkm	}
1554ecbd6dmarkm    abort ();
1564ecbd6dmarkm}
157a77dba0nectar
15833f661cstas/**
15933f661cstas * Listen on a specified port
16033f661cstas *
16133f661cstas * Listens on the specified port for incoming connections.  If the \a
16233f661cstas * ret_socket parameter is \a NULL, on return STDIN and STDOUT will be
16333f661cstas * connected to an accepted socket.  If the \a ret_socket parameter is
16433f661cstas * non-NULL, the accepted socket will be returned in *ret_socket.  In
16533f661cstas * the latter case, STDIN and STDOUT will be left unmodified.
16633f661cstas *
16733f661cstas * This function does not return if there is an error or if no
16833f661cstas * connection is established.
16933f661cstas *
17033f661cstas * @param[in] port Port to listen on
17133f661cstas * @param[out] ret_socket If non-NULL receives the accepted socket.
17233f661cstas *
17333f661cstas * @see mini_inetd_addrinfo()
17433f661cstas */
17533f661cstasROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
17633f661cstasmini_inetd(int port, rk_socket_t * ret_socket)
177a77dba0nectar{
178a77dba0nectar    int error;
179a77dba0nectar    struct addrinfo *ai, hints;
180a77dba0nectar    char portstr[NI_MAXSERV];
181a77dba0nectar
182a77dba0nectar    memset (&hints, 0, sizeof(hints));
183a77dba0nectar    hints.ai_flags    = AI_PASSIVE;
184a77dba0nectar    hints.ai_socktype = SOCK_STREAM;
185a77dba0nectar    hints.ai_family   = PF_UNSPEC;
186a77dba0nectar
187a77dba0nectar    snprintf (portstr, sizeof(portstr), "%d", ntohs(port));
188a77dba0nectar
189a77dba0nectar    error = getaddrinfo (NULL, portstr, &hints, &ai);
190a77dba0nectar    if (error)
191a77dba0nectar	errx (1, "getaddrinfo: %s", gai_strerror (error));
192a77dba0nectar
19333f661cstas    mini_inetd_addrinfo(ai, ret_socket);
19433f661cstas
195a77dba0nectar    freeaddrinfo(ai);
196a77dba0nectar}
19733f661cstas
198