- Parameterize out the number of accept/connect attempts

- Randomize the bind port to allow 2+ consecutive calls in < 10 minutes, and
  to also not fail if (for instance) there's a server already listening on port
  8080
- Don't leak the listening socket / fds into the child process
- Fix warnings:
-- Remove argc/argv (-Wunused)
-- Mark sig __unused (-Wunused)
-- Mark quit static (-Wmissing-variable-declarations)

MFC after: 1 week
Sponsored by: EMC / Isilon Storage Division
This commit is contained in:
Enji Cooper 2015-04-10 09:21:07 +00:00
parent b6e1ffd447
commit 41119c8725
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=281358
2 changed files with 35 additions and 19 deletions

View File

@ -4,8 +4,6 @@
PROG= accept_fd_leak
MAN=
regress:
./accept_fd_leak
WARNS?= 6
.include <bsd.prog.mk>

View File

@ -26,7 +26,7 @@
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/wait.h>
@ -41,13 +41,16 @@
#include <string.h>
#include <unistd.h>
#define BIND_ATTEMPTS 10
#define LOOPS 500
#define NUM_ATTEMPTS 1000
volatile int quit;
static volatile int quit;
static void
child_died(int sig)
child_died(int sig __unused)
{
quit = 1;
}
@ -59,13 +62,12 @@ child_died(int sig)
* briefly before beginning (not 100% reliable, but a good start).
*/
int
main(int argc, char *argv[])
main(void)
{
struct sockaddr_in sin;
socklen_t size;
pid_t child;
int fd1, fd2, fd3, i, s;
int status;
int fd1, fd2, fd3, i, listen_port, s, status;
printf("1..2\n");
@ -85,10 +87,22 @@ main(int argc, char *argv[])
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sin.sin_port = htons(8080);
if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) != 0)
errx(-1, "bind: %s", strerror(errno));
srandomdev();
for (i = 0; i < BIND_ATTEMPTS; i++) {
/* Pick a random unprivileged port 1025-65535 */
listen_port = MAX((int)random() % 65535, 1025);
sin.sin_port = htons(listen_port);
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == 0)
break;
warn("bind with %d failed", listen_port);
usleep(1000);
}
if (i >= BIND_ATTEMPTS) {
printf("Bail out!\n");
exit(1);
}
if (listen(s, -1) != 0)
errx(-1, "listen: %s", strerror(errno));
@ -134,16 +148,20 @@ main(int argc, char *argv[])
errx(-1, "fork: %s", strerror(errno));
/*
* Child process does 1000 connect's.
* Child process does `NUM_ATTEMPTS` connects.
*/
if (child == 0) {
close(fd1);
close(fd2);
close(s);
bzero(&sin, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sin.sin_port = htons(8080);
sin.sin_port = htons(listen_port);
for (i = 0; i < 1000; i++) {
for (i = 0; i < NUM_ATTEMPTS; i++) {
s = socket(PF_INET, SOCK_STREAM, 0);
if (s == -1)
errx(-1, "socket: %s", strerror(errno));
@ -167,9 +185,9 @@ main(int argc, char *argv[])
errx(-1, "ioctl(F_GETFL): %s", strerror(errno));
if (i & O_NONBLOCK)
errx(-1, "Failed to clear O_NONBLOCK (i=0x%x)\n", i);
/* Do 1000 accept's with an invalid pointer. */
for (i = 0; !quit && i < 1000; i++) {
/* Do `NUM_ATTEMPTS` accepts with an invalid pointer. */
for (i = 0; !quit && i < NUM_ATTEMPTS; i++) {
size = sizeof(sin);
if (accept(s, (struct sockaddr *)(uintptr_t)(0x100),
&size) != -1)
@ -182,7 +200,7 @@ main(int argc, char *argv[])
errx(-1, "waitpid: %s", strerror(errno));
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
warnx("child process died");
/*
* Allocate a file descriptor and make sure it's fd2+2. 2 because
* we allocate an fd for the socket.