1138269Snik/*
2138269SnikCopyright 2004 Michiel Boland.  All rights reserved.
3138269Snik
4138269SnikRedistribution and use in source and binary forms, with or without
5138269Snikmodification, are permitted provided that the following conditions
6138269Snikare met:
7138269Snik
8138269Snik1. Redistributions of source code must retain the above copyright
9138269Sniknotice, this list of conditions and the following disclaimer.
10138269Snik
11138269Snik2. Redistributions in binary form must reproduce the above copyright
12138269Sniknotice, this list of conditions and the following disclaimer in the
13138269Snikdocumentation and/or other materials provided with the distribution.
14138269Snik
15138269SnikTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16138269SnikOR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17138269SnikWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18138269SnikARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
19138269SnikLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
20138269SnikOR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21138269SnikOF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
22138269SnikBUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23138269SnikWHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
24138269SnikOR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25138269SnikEVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26138269Snik
27138269Snik$FreeBSD$
28138269Snik
29138269Snik*/
30138269Snik
31138269Snik#include <sys/types.h>
32138269Snik#include <sys/socket.h>
33138269Snik#include <netinet/in.h>
34138269Snik#include <fcntl.h>
35138269Snik#include <poll.h>
36138269Snik#include <unistd.h>
37138269Snik#include <signal.h>
38222485Srwatson#include <stdio.h>
39138269Snik#include <stdlib.h>
40138269Snik#include <string.h>
41138269Snik
42138269Snik/*
43138269Snik * The following code sets up two connected TCP sockets that send data to each
44138269Snik * other until the window is closed. Then one of the sockets is closed, which
45138269Snik * will generate a RST once the TCP at the other socket does a window probe.
46138269Snik *
47138269Snik * All versions of FreeBSD prior to 11/26/2004 will ignore this RST into a 0
48138269Snik * window, causing the connection (and application) to hang indefinitely.
49138269Snik * On patched versions of FreeBSD (and other operating systems), the RST
50138269Snik * will be accepted and the program will exit in a few seconds.
51138269Snik */
52138269Snik
53138269Snik/*
54138269Snik * If the alarm fired then we've hung and the test failed.
55138269Snik */
56138269Snikvoid
57138269Snikdo_alrm(int s)
58138269Snik{
59138269Snik	printf("not ok 1 - tcpfullwindowrst\n");
60138269Snik	exit(0);
61138269Snik}
62138269Snik
63138269Snikint
64138269Snikmain(void)
65138269Snik{
66138269Snik	int o, s, t, u, do_t, do_u;
67138269Snik	struct pollfd pfd[2];
68138269Snik	struct sockaddr_in sa;
69138269Snik	char buf[4096];
70138269Snik
71138269Snik	printf("1..1\n");
72138269Snik	signal(SIGALRM, do_alrm);
73138269Snik	alarm(20);
74138269Snik
75138269Snik	s = socket(AF_INET, SOCK_STREAM, 0);
76138269Snik	if (s == -1)
77138269Snik		return 1;
78138269Snik	o = 1;
79138269Snik	setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &o, sizeof o);
80138269Snik	memset(&sa, 0, sizeof sa);
81138269Snik	sa.sin_family = AF_INET;
82138269Snik	sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
83138269Snik	sa.sin_port = htons(3737);
84138269Snik	if (bind(s, (struct sockaddr *) &sa, sizeof sa) == -1)
85138269Snik		return 1;
86138269Snik	if (listen(s, 1) == -1)
87138269Snik		return 1;
88138269Snik	t = socket(AF_INET, SOCK_STREAM, 0);
89138269Snik	if (t == -1)
90138269Snik		return 1;
91138269Snik	if (connect(t, (struct sockaddr *) &sa, sizeof sa) == -1)
92138269Snik		return 1;
93138269Snik	u = accept(s, 0, 0);
94138269Snik	if (u == -1)
95138269Snik		return 1;
96138269Snik	close(s);
97138269Snik	fcntl(t, F_SETFL, fcntl(t, F_GETFL) | O_NONBLOCK);
98138269Snik	fcntl(u, F_SETFL, fcntl(t, F_GETFL) | O_NONBLOCK);
99138269Snik	do_t = 1;
100138269Snik	do_u = 1;
101138269Snik	pfd[0].fd = t;
102138269Snik	pfd[0].events = POLLOUT;
103138269Snik	pfd[1].fd = u;
104138269Snik	pfd[1].events = POLLOUT;
105138269Snik	while (do_t || do_u) {
106138269Snik		if (poll(pfd, 2, 1000) == 0) {
107138269Snik			if (do_t) {
108138269Snik				close(t);
109138269Snik				pfd[0].fd = -1;
110138269Snik				do_t = 0;
111138269Snik			}
112138269Snik			continue;
113138269Snik		}
114138269Snik		if (pfd[0].revents & POLLOUT) {
115138269Snik			if (write(t, buf, sizeof buf) == -1) {
116138269Snik				close(t);
117138269Snik				pfd[0].fd = -1;
118138269Snik				do_t = 0;
119138269Snik			}
120138269Snik		}
121138269Snik		if (pfd[1].revents & POLLOUT) {
122138269Snik			if (write(u, buf, sizeof buf) == -1) {
123138269Snik				close(u);
124138269Snik				pfd[1].fd = -1;
125138269Snik				do_u = 0;
126138269Snik			}
127138269Snik		}
128138269Snik	}
129138269Snik
130138269Snik	printf("ok 1 - tcpfullwindowrst\n");
131138269Snik	return 0;
132138269Snik}
133