1132524Ssilby/*
2132524SsilbyCopyright (C) 2004 Michael J. Silbersack. All rights reserved.
3132524Ssilby
4132524SsilbyRedistribution and use in source and binary forms, with or without
5132524Ssilbymodification, are permitted provided that the following conditions
6132524Ssilbyare met:
7132524Ssilby1. Redistributions of source code must retain the above copyright
8132524Ssilby   notice, this list of conditions and the following disclaimer.
9132524Ssilby2. Redistributions in binary form must reproduce the above copyright
10132524Ssilby   notice, this list of conditions and the following disclaimer in the
11132524Ssilby   documentation and/or other materials provided with the distribution.
12132524Ssilby
13132524SsilbyTHIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14132524SsilbyANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15132524SsilbyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16132524SsilbyARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17132524SsilbyFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18132524SsilbyDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19132524SsilbyOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20132524SsilbyHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21132524SsilbyLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22132524SsilbyOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23132524SsilbySUCH DAMAGE.
24132524Ssilby*/
25132524Ssilby
26290914Sngie#include <sys/types.h>
27290914Sngie#include <sys/stat.h>
28290914Sngie#include <sys/wait.h>
29290914Sngie#include <assert.h>
30290914Sngie#include <err.h>
31290914Sngie#include <errno.h>
32132524Ssilby#include <stdio.h>
33290914Sngie#include <stdlib.h>
34290914Sngie#include <string.h>
35132524Ssilby#include <unistd.h>
36132524Ssilby
37132524Ssilby/*
38132524Ssilby * $FreeBSD$
39132524Ssilby * This program tests to make sure that wraparound writes and reads
40132524Ssilby * are working, assuming that 16K socket buffers are used.  In order
41132524Ssilby * to really stress the pipe code with this test, kernel modifications
42132524Ssilby * nay be necessary.
43132524Ssilby */
44132524Ssilby
45132524Ssilbyint main (void)
46132524Ssilby{
47290914Sngie	char buffer[32768], buffer2[32768], go[] = "go", go2[] = "go2";
48290914Sngie	int desc[2], ipc_coord[2];
49290914Sngie	ssize_t error, total;
50290914Sngie	int buggy, i;
51290914Sngie	pid_t new_pid;
52132524Ssilby
53290914Sngie	buggy = 0;
54290914Sngie	total = 0;
55132524Ssilby
56290914Sngie	error = pipe(desc);
57290914Sngie	if (error == -1)
58290914Sngie		err(1, "Couldn't allocate data pipe");
59132524Ssilby
60290914Sngie	error = pipe(ipc_coord);
61290914Sngie	if (error == -1)
62290914Sngie		err(1, "Couldn't allocate IPC coordination pipe");
63132524Ssilby
64290914Sngie	buffer[0] = 'A';
65132524Ssilby
66290914Sngie	for (i = 1; i < (int)sizeof(buffer); i++) {
67290914Sngie		buffer[i] = buffer[i - 1] + 1;
68290914Sngie		if (buffer[i] > 'Z')
69290914Sngie			buffer[i] = 'A';
70132524Ssilby	}
71132524Ssilby
72290914Sngie	new_pid = fork();
73290914Sngie	assert(new_pid != -1);
74132524Ssilby
75290914Sngie#define	SYNC_R(i, _buf) do {	\
76290914Sngie	int _error = errno; \
77290914Sngie	warnx("%d: waiting for synchronization", __LINE__); \
78290914Sngie	if (read(ipc_coord[i], &_buf, sizeof(_buf)) != sizeof(_buf)) \
79290914Sngie		err(1, "failed to synchronize (%s)", (i == 0 ? "parent" : "child")); \
80290914Sngie	errno = _error; \
81290914Sngie	} while(0)
82290914Sngie
83290914Sngie#define	SYNC_W(i, _buf) do {	\
84290914Sngie	int _error = errno; \
85290914Sngie	warnx("%d: sending synchronization", __LINE__); \
86290914Sngie	if (write(ipc_coord[i], &_buf, sizeof(_buf)) != sizeof(_buf)) \
87290914Sngie		err(1, "failed to synchronize (%s)", (i == 0 ? "child" : "parent")); \
88290914Sngie	errno = _error; \
89290914Sngie	} while(0)
90290914Sngie
91290914Sngie#define	WRITE(s) do { 							\
92290914Sngie	ssize_t _size; 							\
93290914Sngie	if ((_size = write(desc[1], &buffer[total], s)) != s)		\
94290914Sngie		warn("short write; wrote %zd, expected %d", _size, s);	\
95290914Sngie	total += _size;							\
96290914Sngie	} while(0)
97290914Sngie
98290914Sngie	if (new_pid == 0) {
99290914Sngie		WRITE(4096);
100290914Sngie		WRITE(4096);
101290914Sngie		WRITE(4000);
102290914Sngie		SYNC_W(0, go2);
103290914Sngie
104290914Sngie		SYNC_R(0, go);
105290914Sngie		WRITE(3000);
106290914Sngie		WRITE(3000);
107290914Sngie		SYNC_W(0, go2);
108290914Sngie
109290914Sngie		_exit(0);
110290914Sngie	}
111290914Sngie
112290914Sngie	SYNC_R(1, go2);
113132524Ssilby	error = read(desc[0], &buffer2, 8192);
114132524Ssilby	total += error;
115290914Sngie	printf("Read %zd bytes\n", error);
116290914Sngie	SYNC_W(1, go);
117290914Sngie	SYNC_R(1, go2);
118132524Ssilby	error = read(desc[0], &buffer2[total], 16384);
119132524Ssilby	total += error;
120290914Sngie	printf("Read %zd bytes, done\n", error);
121132524Ssilby
122290914Sngie	if (memcmp(buffer, buffer2, total) != 0) {
123290914Sngie		for (i = 0; i < total; i++) {
124290914Sngie			if (buffer[i] != buffer2[i]) {
125290914Sngie				buggy = 1;
126290914Sngie				printf("Location %d input: %hhx output: %hhx\n",
127290914Sngie				    i, buffer[i], buffer2[i]);
128290914Sngie			}
129132524Ssilby		}
130132524Ssilby	}
131132524Ssilby
132290914Sngie	waitpid(new_pid, NULL, 0);
133290914Sngie
134290914Sngie	if (buggy)
135290914Sngie		errx(1, "FAILURE");
136290914Sngie
137132524Ssilby	printf("SUCCESS\n");
138132524Ssilby
139290914Sngie	exit(0);
140132524Ssilby}
141