inetd: close new udp fd in "udp nowait" case
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
d2fe2ba08d
commit
223b9417b3
@ -357,10 +357,26 @@ struct BUG_G_too_big {
|
||||
config_filename = "/etc/inetd.conf"; \
|
||||
} while (0)
|
||||
|
||||
#if 1
|
||||
# define dbg(...) ((void)0)
|
||||
#else
|
||||
# define dbg(...) \
|
||||
do { \
|
||||
int dbg_fd = open("inetd_debug.log", O_WRONLY | O_CREAT | O_APPEND, 0666); \
|
||||
if (dbg_fd >= 0) { \
|
||||
fdprintf(dbg_fd, "%d: ", getpid()); \
|
||||
fdprintf(dbg_fd, __VA_ARGS__); \
|
||||
close(dbg_fd); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
static void maybe_close(int fd)
|
||||
{
|
||||
if (fd >= 0)
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
dbg("closed fd:%d\n", fd);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: move to libbb?
|
||||
@ -464,7 +480,9 @@ static void remove_fd_from_set(int fd)
|
||||
{
|
||||
if (fd >= 0) {
|
||||
FD_CLR(fd, &allsock);
|
||||
dbg("stopped listening on fd:%d\n", fd);
|
||||
maxsock = -1;
|
||||
dbg("maxsock:%d\n", maxsock);
|
||||
}
|
||||
}
|
||||
|
||||
@ -472,8 +490,10 @@ static void add_fd_to_set(int fd)
|
||||
{
|
||||
if (fd >= 0) {
|
||||
FD_SET(fd, &allsock);
|
||||
dbg("started listening on fd:%d\n", fd);
|
||||
if (maxsock >= 0 && fd > maxsock) {
|
||||
prev_maxsock = maxsock = fd;
|
||||
dbg("maxsock:%d\n", maxsock);
|
||||
if ((rlim_t)fd > rlim_ofile_cur - FD_MARGIN)
|
||||
bump_nofile();
|
||||
}
|
||||
@ -492,6 +512,7 @@ static void recalculate_maxsock(void)
|
||||
maxsock = fd;
|
||||
fd++;
|
||||
}
|
||||
dbg("recalculated maxsock:%d\n", maxsock);
|
||||
prev_maxsock = maxsock;
|
||||
if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN)
|
||||
bump_nofile();
|
||||
@ -549,8 +570,13 @@ static void prepare_socket_fd(servtab_t *sep)
|
||||
rearm_alarm();
|
||||
return;
|
||||
}
|
||||
if (sep->se_socktype == SOCK_STREAM)
|
||||
|
||||
if (sep->se_socktype == SOCK_STREAM) {
|
||||
listen(fd, global_queuelen);
|
||||
dbg("new sep->se_fd:%d (stream)\n", fd);
|
||||
} else {
|
||||
dbg("new sep->se_fd:%d (!stream)\n", fd);
|
||||
}
|
||||
|
||||
add_fd_to_set(fd);
|
||||
sep->se_fd = fd;
|
||||
@ -1012,7 +1038,7 @@ static void reread_config_file(int sig UNUSED_PARAM)
|
||||
* new config file doesnt have them. */
|
||||
block_CHLD_HUP_ALRM(&omask);
|
||||
sepp = &serv_list;
|
||||
while ((sep = *sepp)) {
|
||||
while ((sep = *sepp) != NULL) {
|
||||
if (sep->se_checked) {
|
||||
sepp = &sep->se_next;
|
||||
continue;
|
||||
@ -1206,11 +1232,13 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
dbg("ready_fd_cnt:%d\n", ready_fd_cnt);
|
||||
|
||||
for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) {
|
||||
if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable))
|
||||
continue;
|
||||
|
||||
dbg("ready fd:%d\n", sep->se_fd);
|
||||
ready_fd_cnt--;
|
||||
ctrl = sep->se_fd;
|
||||
accepted_fd = -1;
|
||||
@ -1218,6 +1246,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
|
||||
if (!sep->se_wait) {
|
||||
if (sep->se_socktype == SOCK_STREAM) {
|
||||
ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL);
|
||||
dbg("accepted_fd:%d\n", accepted_fd);
|
||||
if (ctrl < 0) {
|
||||
if (errno != EINTR)
|
||||
bb_perror_msg("accept (for %s)", sep->se_service);
|
||||
@ -1238,19 +1267,22 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
|
||||
* (can create many copies of same child, etc).
|
||||
* Parent must create and use new socket instead. */
|
||||
new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0);
|
||||
dbg("new_udp_fd:%d\n", new_udp_fd);
|
||||
if (new_udp_fd < 0) { /* error: eat packet, forget about it */
|
||||
udp_err:
|
||||
recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT);
|
||||
continue;
|
||||
}
|
||||
setsockopt_reuseaddr(new_udp_fd);
|
||||
/* TODO: better do bind after vfork in parent,
|
||||
/* TODO: better do bind after fork in parent,
|
||||
* so that we don't have two wildcard bound sockets
|
||||
* even for a brief moment? */
|
||||
if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) {
|
||||
dbg("bind(new_udp_fd) failed\n");
|
||||
close(new_udp_fd);
|
||||
goto udp_err;
|
||||
}
|
||||
dbg("bind(new_udp_fd) succeeded\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1278,6 +1310,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
|
||||
sep->se_count = 0;
|
||||
rearm_alarm(); /* will revive it in RETRYTIME sec */
|
||||
restore_sigmask(&omask);
|
||||
maybe_close(new_udp_fd);
|
||||
maybe_close(accepted_fd);
|
||||
continue; /* -> check next fd in fd set */
|
||||
}
|
||||
@ -1298,17 +1331,18 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
|
||||
bb_perror_msg("vfork"+1);
|
||||
sleep(1);
|
||||
restore_sigmask(&omask);
|
||||
maybe_close(new_udp_fd);
|
||||
maybe_close(accepted_fd);
|
||||
continue; /* -> check next fd in fd set */
|
||||
}
|
||||
if (pid == 0)
|
||||
pid--; /* -1: "we did fork and we are child" */
|
||||
}
|
||||
/* if pid == 0 here, we never forked */
|
||||
/* if pid == 0 here, we didn't fork */
|
||||
|
||||
if (pid > 0) { /* parent */
|
||||
if (sep->se_wait) {
|
||||
/* tcp wait: we passed listening socket to child,
|
||||
/* wait: we passed socket to child,
|
||||
* will wait for child to terminate */
|
||||
sep->se_wait = pid;
|
||||
remove_fd_from_set(sep->se_fd);
|
||||
@ -1317,17 +1351,19 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
|
||||
/* udp nowait: child connected the socket,
|
||||
* we created and will use new, unconnected one */
|
||||
xmove_fd(new_udp_fd, sep->se_fd);
|
||||
dbg("moved new_udp_fd:%d to sep->se_fd:%d\n", new_udp_fd, sep->se_fd);
|
||||
}
|
||||
restore_sigmask(&omask);
|
||||
maybe_close(accepted_fd);
|
||||
continue; /* -> check next fd in fd set */
|
||||
}
|
||||
|
||||
/* we are either child or didn't vfork at all */
|
||||
/* we are either child or didn't fork at all */
|
||||
#ifdef INETD_BUILTINS_ENABLED
|
||||
if (sep->se_builtin) {
|
||||
if (pid) { /* "pid" is -1: we did vfork */
|
||||
if (pid) { /* "pid" is -1: we did fork */
|
||||
close(sep->se_fd); /* listening socket */
|
||||
dbg("closed sep->se_fd:%d\n", sep->se_fd);
|
||||
logmode = LOGMODE_NONE; /* make xwrite etc silent */
|
||||
}
|
||||
restore_sigmask(&omask);
|
||||
@ -1335,7 +1371,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
|
||||
sep->se_builtin->bi_stream_fn(ctrl, sep);
|
||||
else
|
||||
sep->se_builtin->bi_dgram_fn(ctrl, sep);
|
||||
if (pid) /* we did vfork */
|
||||
if (pid) /* we did fork */
|
||||
_exit(EXIT_FAILURE);
|
||||
maybe_close(accepted_fd);
|
||||
continue; /* -> check next fd in fd set */
|
||||
@ -1345,9 +1381,14 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
|
||||
setsid();
|
||||
/* "nowait" udp */
|
||||
if (new_udp_fd >= 0) {
|
||||
len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family);
|
||||
len_and_sockaddr *lsa;
|
||||
int r;
|
||||
|
||||
close(new_udp_fd);
|
||||
dbg("closed new_udp_fd:%d\n", new_udp_fd);
|
||||
lsa = xzalloc_lsa(sep->se_family);
|
||||
/* peek at the packet and remember peer addr */
|
||||
int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT,
|
||||
r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT,
|
||||
&lsa->u.sa, &lsa->len);
|
||||
if (r < 0)
|
||||
goto do_exit1;
|
||||
@ -1355,6 +1396,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
|
||||
* only packets from this peer will be recv'ed,
|
||||
* and bare write()/send() will work on it */
|
||||
connect(ctrl, &lsa->u.sa, lsa->len);
|
||||
dbg("connected ctrl:%d to remote peer\n", ctrl);
|
||||
free(lsa);
|
||||
}
|
||||
/* prepare env and exec program */
|
||||
@ -1391,6 +1433,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
|
||||
*/
|
||||
xmove_fd(ctrl, STDIN_FILENO);
|
||||
xdup2(STDIN_FILENO, STDOUT_FILENO);
|
||||
dbg("moved ctrl:%d to fd 0,1[,2]\n", ctrl);
|
||||
/* manpages of inetd I managed to find either say
|
||||
* that stderr is also redirected to the network,
|
||||
* or do not talk about redirection at all (!) */
|
||||
@ -1403,6 +1446,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
|
||||
maybe_close(sep2->se_fd);
|
||||
sigaction_set(SIGPIPE, &saved_pipe_handler);
|
||||
restore_sigmask(&omask);
|
||||
dbg("execing:'%s'\n", sep->se_program);
|
||||
BB_EXECVP(sep->se_program, sep->se_argv);
|
||||
bb_perror_msg("can't execute '%s'", sep->se_program);
|
||||
do_exit1:
|
||||
|
Loading…
Reference in New Issue
Block a user