tcpsockclosebeforeaccept.c revision 157425
1/*-
2 * Copyright (c) 2006 Robert N. M. Watson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/tools/regression/netinet/tcpsockclosebeforeaccept/tcpsockclosebeforeaccept.c 157425 2006-04-03 10:08:35Z rwatson $
27 */
28
29/*
30 * TCP regression test which opens a loopback TCP session, and closes it
31 * before the remote endpoint (server) can accept it.
32 */
33
34#include <sys/types.h>
35#include <sys/socket.h>
36
37#include <netinet/in.h>
38
39#include <err.h>
40#include <errno.h>
41#include <signal.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <unistd.h>
46
47#define	TCP_PORT	9001
48
49static void
50tcp_server(pid_t partner)
51{
52	int error, listen_fd, accept_fd;
53	struct sockaddr_in sin;
54
55	listen_fd = socket(PF_INET, SOCK_STREAM, 0);
56	if (listen_fd < 0) {
57		error = errno;
58		(void)kill(partner, SIGKILL);
59		errno = error;
60		err(-1, "tcp_server: socket");
61	}
62
63	bzero(&sin, sizeof(sin));
64	sin.sin_family = AF_INET;
65	sin.sin_len = sizeof(sin);
66	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
67	sin.sin_port = htons(TCP_PORT);
68
69	if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
70		error = errno;
71		(void)kill(partner, SIGKILL);
72		errno = error;
73		err(-1, "tcp_server: bind");
74	}
75
76	if (listen(listen_fd, -1) < 0) {
77		error = errno;
78		(void)kill(partner, SIGKILL);
79		errno = error;
80		err(-1, "tcp_server: listen");
81	}
82
83	sleep(10);
84
85	accept_fd = accept(listen_fd, NULL, NULL);
86	if (accept_fd < 0) {
87		error = errno;
88		(void)kill(partner, SIGKILL);
89		errno = error;
90		err(-1, "tcp_server: accept");
91	}
92	close(accept_fd);
93	close(listen_fd);
94}
95
96static void
97tcp_client(pid_t partner)
98{
99	struct sockaddr_in sin;
100	int error, sock;
101
102	sleep(1);
103
104	sock = socket(PF_INET, SOCK_STREAM, 0);
105	if (sock < 0) {
106		error = errno;
107		(void)kill(partner, SIGKILL);
108		errno = error;
109		err(-1, "socket");
110	}
111
112	bzero(&sin, sizeof(sin));
113	sin.sin_family = AF_INET;
114	sin.sin_len = sizeof(sin);
115	sin.sin_addr.s_addr = ntohl(INADDR_LOOPBACK);
116	sin.sin_port = htons(TCP_PORT);
117
118	if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
119		error = errno;
120		(void)kill(partner, SIGKILL);
121		errno = error;
122		err(-1, "connect");
123	}
124
125	close(sock);
126}
127
128int
129main(int argc, char *argv[])
130{
131	pid_t child_pid, parent_pid;
132
133	if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
134		err(-1, "signal");
135
136	parent_pid = getpid();
137	child_pid = fork();
138	if (child_pid < 0)
139		err(-1, "fork");
140	if (child_pid == 0) {
141		child_pid = getpid();
142		tcp_server(parent_pid);
143	} else
144		tcp_client(child_pid);
145
146	return (0);
147}
148