accept_fd_leak.c revision 132295
1132295Srwatson/*-
2132295Srwatson * Copyright (c) 2004 Robert N. M. Watson
3132295Srwatson * All rights reserved.
4132295Srwatson *
5132295Srwatson * Redistribution and use in source and binary forms, with or without
6132295Srwatson * modification, are permitted provided that the following conditions
7132295Srwatson * are met:
8132295Srwatson * 1. Redistributions of source code must retain the above copyright
9132295Srwatson *    notice, this list of conditions and the following disclaimer.
10132295Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11132295Srwatson *    notice, this list of conditions and the following disclaimer in the
12132295Srwatson *    documentation and/or other materials provided with the distribution.
13132295Srwatson *
14132295Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15132295Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16132295Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17132295Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18132295Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19132295Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20132295Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21132295Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22132295Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23132295Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24132295Srwatson * SUCH DAMAGE.
25132295Srwatson *
26132295Srwatson * $FreeBSD: head/tools/regression/sockets/accept_fd_leak/accept_fd_leak.c 132295 2004-07-17 16:56:46Z rwatson $
27132295Srwatson */
28132295Srwatson
29132295Srwatson#include <sys/types.h>
30132295Srwatson#include <sys/socket.h>
31132295Srwatson
32132295Srwatson#include <netinet/in.h>
33132295Srwatson
34132295Srwatson#include <errno.h>
35132295Srwatson#include <fcntl.h>
36132295Srwatson#include <stdio.h>
37132295Srwatson#include <stdlib.h>
38132295Srwatson#include <string.h>
39132295Srwatson#include <unistd.h>
40132295Srwatson
41132295Srwatson#define	LOOPS	500
42132295Srwatson
43132295Srwatson/*
44132295Srwatson * This test is intended to detect a leak of a file descriptor in the process
45132295Srwatson * following a failed non-blocking accept.  It measures an available fd
46132295Srwatson * baseline, then performs 1000 failing accepts, then checks to see what the
47132295Srwatson * next fd is.  It relies on sequential fd allocation, and will test for it
48132295Srwatson * briefly before beginning (not 100% reliable, but a good start).
49132295Srwatson */
50132295Srwatsonint
51132295Srwatsonmain(int argc, char *argv[])
52132295Srwatson{
53132295Srwatson	struct sockaddr_in sin;
54132295Srwatson	socklen_t size;
55132295Srwatson	int fd1, fd2, fd3, i, s;
56132295Srwatson
57132295Srwatson	/*
58132295Srwatson	 * Check for sequential fd allocation, and give up early if not.
59132295Srwatson	 */
60132295Srwatson	fd1 = dup(STDIN_FILENO);
61132295Srwatson	fd2 = dup(STDIN_FILENO);
62132295Srwatson	if (fd2 != fd1 + 1) {
63132295Srwatson		fprintf(stderr, "Non-sequential fd allocation!\n");
64132295Srwatson		exit(-1);
65132295Srwatson	}
66132295Srwatson
67132295Srwatson	s = socket(PF_INET, SOCK_STREAM, 0);
68132295Srwatson	if (s == -1) {
69132295Srwatson		perror("socket");
70132295Srwatson		exit(-1);
71132295Srwatson	}
72132295Srwatson
73132295Srwatson	bzero(&sin, sizeof(sin));
74132295Srwatson	sin.sin_len = sizeof(sin);
75132295Srwatson	sin.sin_family = AF_INET;
76132295Srwatson	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
77132295Srwatson	sin.sin_port = htons(8080);
78132295Srwatson
79132295Srwatson	if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
80132295Srwatson		perror("bind");
81132295Srwatson		exit(-1);
82132295Srwatson	}
83132295Srwatson
84132295Srwatson	if (listen(s, -1) != 0) {
85132295Srwatson		perror("listen");
86132295Srwatson		exit(-1);
87132295Srwatson	}
88132295Srwatson
89132295Srwatson	i = fcntl(s, F_GETFL);
90132295Srwatson	if (i == -1) {
91132295Srwatson		perror("F_GETFL");
92132295Srwatson		exit(-1);
93132295Srwatson	}
94132295Srwatson	i |= O_NONBLOCK;
95132295Srwatson	if (fcntl(s, F_SETFL, i) != 0) {
96132295Srwatson		perror("F_SETFL");
97132295Srwatson		exit(-1);
98132295Srwatson	}
99132295Srwatson	i = fcntl(s, F_GETFL);
100132295Srwatson	if (i == -1) {
101132295Srwatson		perror("F_GETFL");
102132295Srwatson		exit(-1);
103132295Srwatson	}
104132295Srwatson	if ((i & O_NONBLOCK) != O_NONBLOCK) {
105132295Srwatson		fprintf(stderr, "Failed to set O_NONBLOCK (i=%d)\n", i);
106132295Srwatson		exit(-1);
107132295Srwatson	}
108132295Srwatson
109132295Srwatson	for (i = 0; i < LOOPS; i++) {
110132295Srwatson		if (accept(s, (struct sockaddr *)&sin, &size) != -1) {
111132295Srwatson			fprintf(stderr, "accept succeeded!\n");
112132295Srwatson			exit(-1);
113132295Srwatson		}
114132295Srwatson		if (errno != EAGAIN) {
115132295Srwatson			perror("accept");
116132295Srwatson			exit(-1);
117132295Srwatson		}
118132295Srwatson	}
119132295Srwatson
120132295Srwatson	/*
121132295Srwatson	 * Allocate a file descriptor and make sure it's fd2+2.  2 because
122132295Srwatson	 * we allocate an fd for the socket.
123132295Srwatson	 */
124132295Srwatson	fd3 = dup(STDIN_FILENO);
125132295Srwatson	if (fd3 != fd2 + 2) {
126132295Srwatson		fprintf(stderr, "TEST FAILED (%d, %d, %d)\n", fd1, fd2, fd3);
127132295Srwatson		exit(-1);
128132295Srwatson	}
129132295Srwatson
130132295Srwatson	return (0);
131132295Srwatson}
132