inetd: close new udp fd in "udp nowait" case
No binary (build failed)
—
(log yok)
| @@ -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: | |