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: |
