diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-09-11 16:48:21 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-09-11 16:48:21 +0200 |
commit | 223b9417b3789e60f3a91510661b00a92c0db027 (patch) | |
tree | 2616985d865a3ddbc8653db23f1b106e9e39a039 | |
parent | d2fe2ba08dd84cd7e94d1ae3e2e9c12ca2b4d561 (diff) | |
download | busybox-w32-223b9417b3789e60f3a91510661b00a92c0db027.tar.gz busybox-w32-223b9417b3789e60f3a91510661b00a92c0db027.tar.bz2 busybox-w32-223b9417b3789e60f3a91510661b00a92c0db027.zip |
inetd: close new udp fd in "udp nowait" case
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/inetd.c | 66 |
1 files changed, 55 insertions, 11 deletions
diff --git a/networking/inetd.c b/networking/inetd.c index 873fd9528..fc6847bb5 100644 --- a/networking/inetd.c +++ b/networking/inetd.c | |||
@@ -357,10 +357,26 @@ struct BUG_G_too_big { | |||
357 | config_filename = "/etc/inetd.conf"; \ | 357 | config_filename = "/etc/inetd.conf"; \ |
358 | } while (0) | 358 | } while (0) |
359 | 359 | ||
360 | #if 1 | ||
361 | # define dbg(...) ((void)0) | ||
362 | #else | ||
363 | # define dbg(...) \ | ||
364 | do { \ | ||
365 | int dbg_fd = open("inetd_debug.log", O_WRONLY | O_CREAT | O_APPEND, 0666); \ | ||
366 | if (dbg_fd >= 0) { \ | ||
367 | fdprintf(dbg_fd, "%d: ", getpid()); \ | ||
368 | fdprintf(dbg_fd, __VA_ARGS__); \ | ||
369 | close(dbg_fd); \ | ||
370 | } \ | ||
371 | } while (0) | ||
372 | #endif | ||
373 | |||
360 | static void maybe_close(int fd) | 374 | static void maybe_close(int fd) |
361 | { | 375 | { |
362 | if (fd >= 0) | 376 | if (fd >= 0) { |
363 | close(fd); | 377 | close(fd); |
378 | dbg("closed fd:%d\n", fd); | ||
379 | } | ||
364 | } | 380 | } |
365 | 381 | ||
366 | // TODO: move to libbb? | 382 | // TODO: move to libbb? |
@@ -464,7 +480,9 @@ static void remove_fd_from_set(int fd) | |||
464 | { | 480 | { |
465 | if (fd >= 0) { | 481 | if (fd >= 0) { |
466 | FD_CLR(fd, &allsock); | 482 | FD_CLR(fd, &allsock); |
483 | dbg("stopped listening on fd:%d\n", fd); | ||
467 | maxsock = -1; | 484 | maxsock = -1; |
485 | dbg("maxsock:%d\n", maxsock); | ||
468 | } | 486 | } |
469 | } | 487 | } |
470 | 488 | ||
@@ -472,8 +490,10 @@ static void add_fd_to_set(int fd) | |||
472 | { | 490 | { |
473 | if (fd >= 0) { | 491 | if (fd >= 0) { |
474 | FD_SET(fd, &allsock); | 492 | FD_SET(fd, &allsock); |
493 | dbg("started listening on fd:%d\n", fd); | ||
475 | if (maxsock >= 0 && fd > maxsock) { | 494 | if (maxsock >= 0 && fd > maxsock) { |
476 | prev_maxsock = maxsock = fd; | 495 | prev_maxsock = maxsock = fd; |
496 | dbg("maxsock:%d\n", maxsock); | ||
477 | if ((rlim_t)fd > rlim_ofile_cur - FD_MARGIN) | 497 | if ((rlim_t)fd > rlim_ofile_cur - FD_MARGIN) |
478 | bump_nofile(); | 498 | bump_nofile(); |
479 | } | 499 | } |
@@ -492,6 +512,7 @@ static void recalculate_maxsock(void) | |||
492 | maxsock = fd; | 512 | maxsock = fd; |
493 | fd++; | 513 | fd++; |
494 | } | 514 | } |
515 | dbg("recalculated maxsock:%d\n", maxsock); | ||
495 | prev_maxsock = maxsock; | 516 | prev_maxsock = maxsock; |
496 | if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN) | 517 | if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN) |
497 | bump_nofile(); | 518 | bump_nofile(); |
@@ -549,8 +570,13 @@ static void prepare_socket_fd(servtab_t *sep) | |||
549 | rearm_alarm(); | 570 | rearm_alarm(); |
550 | return; | 571 | return; |
551 | } | 572 | } |
552 | if (sep->se_socktype == SOCK_STREAM) | 573 | |
574 | if (sep->se_socktype == SOCK_STREAM) { | ||
553 | listen(fd, global_queuelen); | 575 | listen(fd, global_queuelen); |
576 | dbg("new sep->se_fd:%d (stream)\n", fd); | ||
577 | } else { | ||
578 | dbg("new sep->se_fd:%d (!stream)\n", fd); | ||
579 | } | ||
554 | 580 | ||
555 | add_fd_to_set(fd); | 581 | add_fd_to_set(fd); |
556 | sep->se_fd = fd; | 582 | sep->se_fd = fd; |
@@ -1012,7 +1038,7 @@ static void reread_config_file(int sig UNUSED_PARAM) | |||
1012 | * new config file doesnt have them. */ | 1038 | * new config file doesnt have them. */ |
1013 | block_CHLD_HUP_ALRM(&omask); | 1039 | block_CHLD_HUP_ALRM(&omask); |
1014 | sepp = &serv_list; | 1040 | sepp = &serv_list; |
1015 | while ((sep = *sepp)) { | 1041 | while ((sep = *sepp) != NULL) { |
1016 | if (sep->se_checked) { | 1042 | if (sep->se_checked) { |
1017 | sepp = &sep->se_next; | 1043 | sepp = &sep->se_next; |
1018 | continue; | 1044 | continue; |
@@ -1206,11 +1232,13 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1206 | } | 1232 | } |
1207 | continue; | 1233 | continue; |
1208 | } | 1234 | } |
1235 | dbg("ready_fd_cnt:%d\n", ready_fd_cnt); | ||
1209 | 1236 | ||
1210 | for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) { | 1237 | for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) { |
1211 | if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable)) | 1238 | if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable)) |
1212 | continue; | 1239 | continue; |
1213 | 1240 | ||
1241 | dbg("ready fd:%d\n", sep->se_fd); | ||
1214 | ready_fd_cnt--; | 1242 | ready_fd_cnt--; |
1215 | ctrl = sep->se_fd; | 1243 | ctrl = sep->se_fd; |
1216 | accepted_fd = -1; | 1244 | accepted_fd = -1; |
@@ -1218,6 +1246,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1218 | if (!sep->se_wait) { | 1246 | if (!sep->se_wait) { |
1219 | if (sep->se_socktype == SOCK_STREAM) { | 1247 | if (sep->se_socktype == SOCK_STREAM) { |
1220 | ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL); | 1248 | ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL); |
1249 | dbg("accepted_fd:%d\n", accepted_fd); | ||
1221 | if (ctrl < 0) { | 1250 | if (ctrl < 0) { |
1222 | if (errno != EINTR) | 1251 | if (errno != EINTR) |
1223 | bb_perror_msg("accept (for %s)", sep->se_service); | 1252 | bb_perror_msg("accept (for %s)", sep->se_service); |
@@ -1238,19 +1267,22 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1238 | * (can create many copies of same child, etc). | 1267 | * (can create many copies of same child, etc). |
1239 | * Parent must create and use new socket instead. */ | 1268 | * Parent must create and use new socket instead. */ |
1240 | new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0); | 1269 | new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0); |
1270 | dbg("new_udp_fd:%d\n", new_udp_fd); | ||
1241 | if (new_udp_fd < 0) { /* error: eat packet, forget about it */ | 1271 | if (new_udp_fd < 0) { /* error: eat packet, forget about it */ |
1242 | udp_err: | 1272 | udp_err: |
1243 | recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT); | 1273 | recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT); |
1244 | continue; | 1274 | continue; |
1245 | } | 1275 | } |
1246 | setsockopt_reuseaddr(new_udp_fd); | 1276 | setsockopt_reuseaddr(new_udp_fd); |
1247 | /* TODO: better do bind after vfork in parent, | 1277 | /* TODO: better do bind after fork in parent, |
1248 | * so that we don't have two wildcard bound sockets | 1278 | * so that we don't have two wildcard bound sockets |
1249 | * even for a brief moment? */ | 1279 | * even for a brief moment? */ |
1250 | if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) { | 1280 | if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) { |
1281 | dbg("bind(new_udp_fd) failed\n"); | ||
1251 | close(new_udp_fd); | 1282 | close(new_udp_fd); |
1252 | goto udp_err; | 1283 | goto udp_err; |
1253 | } | 1284 | } |
1285 | dbg("bind(new_udp_fd) succeeded\n"); | ||
1254 | } | 1286 | } |
1255 | } | 1287 | } |
1256 | 1288 | ||
@@ -1278,6 +1310,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1278 | sep->se_count = 0; | 1310 | sep->se_count = 0; |
1279 | rearm_alarm(); /* will revive it in RETRYTIME sec */ | 1311 | rearm_alarm(); /* will revive it in RETRYTIME sec */ |
1280 | restore_sigmask(&omask); | 1312 | restore_sigmask(&omask); |
1313 | maybe_close(new_udp_fd); | ||
1281 | maybe_close(accepted_fd); | 1314 | maybe_close(accepted_fd); |
1282 | continue; /* -> check next fd in fd set */ | 1315 | continue; /* -> check next fd in fd set */ |
1283 | } | 1316 | } |
@@ -1298,17 +1331,18 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1298 | bb_perror_msg("vfork"+1); | 1331 | bb_perror_msg("vfork"+1); |
1299 | sleep(1); | 1332 | sleep(1); |
1300 | restore_sigmask(&omask); | 1333 | restore_sigmask(&omask); |
1334 | maybe_close(new_udp_fd); | ||
1301 | maybe_close(accepted_fd); | 1335 | maybe_close(accepted_fd); |
1302 | continue; /* -> check next fd in fd set */ | 1336 | continue; /* -> check next fd in fd set */ |
1303 | } | 1337 | } |
1304 | if (pid == 0) | 1338 | if (pid == 0) |
1305 | pid--; /* -1: "we did fork and we are child" */ | 1339 | pid--; /* -1: "we did fork and we are child" */ |
1306 | } | 1340 | } |
1307 | /* if pid == 0 here, we never forked */ | 1341 | /* if pid == 0 here, we didn't fork */ |
1308 | 1342 | ||
1309 | if (pid > 0) { /* parent */ | 1343 | if (pid > 0) { /* parent */ |
1310 | if (sep->se_wait) { | 1344 | if (sep->se_wait) { |
1311 | /* tcp wait: we passed listening socket to child, | 1345 | /* wait: we passed socket to child, |
1312 | * will wait for child to terminate */ | 1346 | * will wait for child to terminate */ |
1313 | sep->se_wait = pid; | 1347 | sep->se_wait = pid; |
1314 | remove_fd_from_set(sep->se_fd); | 1348 | remove_fd_from_set(sep->se_fd); |
@@ -1317,17 +1351,19 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1317 | /* udp nowait: child connected the socket, | 1351 | /* udp nowait: child connected the socket, |
1318 | * we created and will use new, unconnected one */ | 1352 | * we created and will use new, unconnected one */ |
1319 | xmove_fd(new_udp_fd, sep->se_fd); | 1353 | xmove_fd(new_udp_fd, sep->se_fd); |
1354 | dbg("moved new_udp_fd:%d to sep->se_fd:%d\n", new_udp_fd, sep->se_fd); | ||
1320 | } | 1355 | } |
1321 | restore_sigmask(&omask); | 1356 | restore_sigmask(&omask); |
1322 | maybe_close(accepted_fd); | 1357 | maybe_close(accepted_fd); |
1323 | continue; /* -> check next fd in fd set */ | 1358 | continue; /* -> check next fd in fd set */ |
1324 | } | 1359 | } |
1325 | 1360 | ||
1326 | /* we are either child or didn't vfork at all */ | 1361 | /* we are either child or didn't fork at all */ |
1327 | #ifdef INETD_BUILTINS_ENABLED | 1362 | #ifdef INETD_BUILTINS_ENABLED |
1328 | if (sep->se_builtin) { | 1363 | if (sep->se_builtin) { |
1329 | if (pid) { /* "pid" is -1: we did vfork */ | 1364 | if (pid) { /* "pid" is -1: we did fork */ |
1330 | close(sep->se_fd); /* listening socket */ | 1365 | close(sep->se_fd); /* listening socket */ |
1366 | dbg("closed sep->se_fd:%d\n", sep->se_fd); | ||
1331 | logmode = LOGMODE_NONE; /* make xwrite etc silent */ | 1367 | logmode = LOGMODE_NONE; /* make xwrite etc silent */ |
1332 | } | 1368 | } |
1333 | restore_sigmask(&omask); | 1369 | restore_sigmask(&omask); |
@@ -1335,7 +1371,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1335 | sep->se_builtin->bi_stream_fn(ctrl, sep); | 1371 | sep->se_builtin->bi_stream_fn(ctrl, sep); |
1336 | else | 1372 | else |
1337 | sep->se_builtin->bi_dgram_fn(ctrl, sep); | 1373 | sep->se_builtin->bi_dgram_fn(ctrl, sep); |
1338 | if (pid) /* we did vfork */ | 1374 | if (pid) /* we did fork */ |
1339 | _exit(EXIT_FAILURE); | 1375 | _exit(EXIT_FAILURE); |
1340 | maybe_close(accepted_fd); | 1376 | maybe_close(accepted_fd); |
1341 | continue; /* -> check next fd in fd set */ | 1377 | continue; /* -> check next fd in fd set */ |
@@ -1345,9 +1381,14 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1345 | setsid(); | 1381 | setsid(); |
1346 | /* "nowait" udp */ | 1382 | /* "nowait" udp */ |
1347 | if (new_udp_fd >= 0) { | 1383 | if (new_udp_fd >= 0) { |
1348 | len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family); | 1384 | len_and_sockaddr *lsa; |
1385 | int r; | ||
1386 | |||
1387 | close(new_udp_fd); | ||
1388 | dbg("closed new_udp_fd:%d\n", new_udp_fd); | ||
1389 | lsa = xzalloc_lsa(sep->se_family); | ||
1349 | /* peek at the packet and remember peer addr */ | 1390 | /* peek at the packet and remember peer addr */ |
1350 | int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT, | 1391 | r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT, |
1351 | &lsa->u.sa, &lsa->len); | 1392 | &lsa->u.sa, &lsa->len); |
1352 | if (r < 0) | 1393 | if (r < 0) |
1353 | goto do_exit1; | 1394 | goto do_exit1; |
@@ -1355,6 +1396,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1355 | * only packets from this peer will be recv'ed, | 1396 | * only packets from this peer will be recv'ed, |
1356 | * and bare write()/send() will work on it */ | 1397 | * and bare write()/send() will work on it */ |
1357 | connect(ctrl, &lsa->u.sa, lsa->len); | 1398 | connect(ctrl, &lsa->u.sa, lsa->len); |
1399 | dbg("connected ctrl:%d to remote peer\n", ctrl); | ||
1358 | free(lsa); | 1400 | free(lsa); |
1359 | } | 1401 | } |
1360 | /* prepare env and exec program */ | 1402 | /* prepare env and exec program */ |
@@ -1391,6 +1433,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1391 | */ | 1433 | */ |
1392 | xmove_fd(ctrl, STDIN_FILENO); | 1434 | xmove_fd(ctrl, STDIN_FILENO); |
1393 | xdup2(STDIN_FILENO, STDOUT_FILENO); | 1435 | xdup2(STDIN_FILENO, STDOUT_FILENO); |
1436 | dbg("moved ctrl:%d to fd 0,1[,2]\n", ctrl); | ||
1394 | /* manpages of inetd I managed to find either say | 1437 | /* manpages of inetd I managed to find either say |
1395 | * that stderr is also redirected to the network, | 1438 | * that stderr is also redirected to the network, |
1396 | * or do not talk about redirection at all (!) */ | 1439 | * or do not talk about redirection at all (!) */ |
@@ -1403,6 +1446,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1403 | maybe_close(sep2->se_fd); | 1446 | maybe_close(sep2->se_fd); |
1404 | sigaction_set(SIGPIPE, &saved_pipe_handler); | 1447 | sigaction_set(SIGPIPE, &saved_pipe_handler); |
1405 | restore_sigmask(&omask); | 1448 | restore_sigmask(&omask); |
1449 | dbg("execing:'%s'\n", sep->se_program); | ||
1406 | BB_EXECVP(sep->se_program, sep->se_argv); | 1450 | BB_EXECVP(sep->se_program, sep->se_argv); |
1407 | bb_perror_msg("can't execute '%s'", sep->se_program); | 1451 | bb_perror_msg("can't execute '%s'", sep->se_program); |
1408 | do_exit1: | 1452 | do_exit1: |