monotone

monotone Mtn Source Tree

Root/unix/tester-check-net.c

1/* Copyright (C) 2008 Zack Weinberg <zackw@panix.com>
2
3 This program is made available under the GNU GPL version 2.0 or
4 greater. See the accompanying file COPYING for details.
5
6 This program is distributed WITHOUT ANY WARRANTY; without even the
7 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 PURPOSE. */
9
10/* The test suite runs this program to decide whether or not to include
11 network tests. It determines whether it is possible to create a
12 listening socket on a randomly chosen port on the loopback interface,
13 connect to that socket from another process, and ping-pong a byte.
14
15 Will exit successfully, with no output, if everything works; otherwise,
16 will exit unsuccessfully and produce diagnostics on stderr. */
17
18#include "config.h"
19#if defined HAVE_SOCKET && defined HAVE_NETINET_IN_H
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <signal.h>
25#include <errno.h>
26
27#include <sys/types.h>
28#include <sys/wait.h>
29#include <unistd.h>
30
31#include <sys/socket.h>
32#include <netinet/in.h>
33
34static int synchronizer[2];
35static const char *who;
36static unsigned short port;
37
38static void sigalrm(int unused)
39{
40 fprintf(stderr, "%s: timeout\n", who);
41 exit(1);
42}
43
44static void prep_timeout(const char *w)
45{
46 who = w;
47 signal(SIGALRM, sigalrm);
48 alarm(5);
49}
50
51/* "b_or_c" should be either "bind" or "connect". Conveniently, they have
52 the same signature. */
53static int get_socket(int (*b_or_c)(int, const struct sockaddr *, socklen_t))
54{
55 int sfd;
56
57 /* try IPv4 first */
58 {
59 struct sockaddr_in sin;
60 memset(&sin, 0, sizeof sin);
61 sin.sin_family = AF_INET;
62 sin.sin_port = htons(port);
63 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
64
65 sfd = socket(PF_INET, SOCK_STREAM, 0);
66 if (sfd >= 0)
67 {
68 if (b_or_c(sfd, (struct sockaddr *)&sin, sizeof sin) == 0)
69 return sfd;
70 close(sfd);
71 }
72 }
73
74 /* if that didn't work, and we have library support for it, try IPv6 too */
75#ifdef AF_INET6
76 {
77 struct sockaddr_in6 sin6;
78 memset(&sin6, 0, sizeof sin6);
79 sin6.sin6_family = AF_INET6;
80 sin6.sin6_port = htons(port);
81 sin6.sin6_addr = in6addr_loopback;
82
83 sfd = socket(PF_INET6, SOCK_STREAM, 0);
84 if (sfd >= 0)
85 {
86 if (b_or_c(sfd, (struct sockaddr *)&sin6, sizeof sin6) == 0)
87 return sfd;
88 close(sfd);
89 }
90 }
91#endif
92
93 fprintf(stderr, "socket/connect/bind: %s\n", strerror(errno));
94 return -1;
95}
96
97static int server(void)
98{
99 int sfd, cfd, n;
100 char buf;
101
102 prep_timeout("server");
103
104 sfd = get_socket(bind);
105 if (sfd < 0)
106 return 1;
107
108 if (listen(sfd, 1))
109 {
110 fprintf(stderr, "server: listen: %s\n", strerror(errno));
111 close(sfd);
112 return 1;
113 }
114
115 /* Client process may proceed. */
116 n = write(synchronizer[1], "x", 1);
117 if (n != 1)
118 {
119 fprintf(stderr, "server: semaphore write: %s\n",
120 n == 0 ? "unexpected EOF" : strerror(errno));
121 close(sfd);
122 return 1;
123 }
124
125 cfd = accept(sfd, 0, 0); /* don't care _who_ connects */
126 if (cfd < 0)
127 {
128 fprintf(stderr, "server: accept: %s\n", strerror(errno));
129 close(sfd);
130 return 1;
131 }
132
133 n = read(cfd, &buf, 1);
134 if (n != 1)
135 {
136 fprintf(stderr, "server: socket read: %s\n",
137 n == 0 ? "unexpected EOF" : strerror(errno));
138 close(cfd);
139 close(sfd);
140 return 1;
141 }
142 if (buf != 'x')
143 {
144 fprintf(stderr, "server: socket read: got '%c' exp 'x'\n", buf);
145 close(cfd);
146 close(sfd);
147 return 1;
148 }
149 n = write(cfd, "x", 1);
150 if (n != 1)
151 {
152 fprintf(stderr, "server: socket write: %s\n",
153 n == 0 ? "unexpected EOF" : strerror(errno));
154 close(cfd);
155 close(sfd);
156 return 1;
157 }
158
159 close(cfd);
160 close(sfd);
161 return 0;
162}
163
164static int client(void)
165{
166 int sfd, n;
167 char buf;
168
169 prep_timeout("client");
170
171 /* wait for server setup */
172 n = read(synchronizer[0], &buf, 1);
173 if (n != 1)
174 {
175 fprintf(stderr, "client: semaphore read: %s\n",
176 n == 0 ? "unexpected EOF" : strerror(errno));
177 return 1;
178 }
179
180 sfd = get_socket(connect);
181 if (sfd < 0)
182 return 1;
183
184 n = write(sfd, "x", 1);
185 if (n != 1)
186 {
187 fprintf(stderr, "client: socket write: %s\n",
188 n == 0 ? "unexpected EOF" : strerror(errno));
189 close(sfd);
190 return 1;
191 }
192
193 n = read(sfd, &buf, 1);
194 if (n != 1)
195 {
196 fprintf(stderr, "client: socket read: %s\n",
197 n == 0 ? "unexpected EOF" : strerror(errno));
198 close(sfd);
199 return 1;
200 }
201 if (buf != 'x')
202 {
203 fprintf(stderr, "client: socket read: got '%c' exp 'x'\n", buf);
204 close(sfd);
205 return 1;
206 }
207
208 close(sfd);
209 return 0;
210}
211
212int main(void)
213{
214 pid_t child, p;
215 int status;
216
217 /* Pick a random port in the high half of the range, thus
218 unlikely to be used for anything. */
219 srand(time(0));
220 do
221 {
222 port = rand();
223 }
224 while (port < 32767);
225
226 if (pipe(synchronizer))
227 {
228 fprintf(stderr, "setup: pipe: %s\n", strerror(errno));
229 return 2;
230 }
231
232 child = fork();
233 if (child < 0)
234 {
235 fprintf(stderr, "setup: fork: %s\n", strerror(errno));
236 return 2;
237 }
238
239 if (child == 0)
240 return client();
241
242 if (server())
243 return 1;
244
245 p = wait(&status);
246 if (p < 0)
247 {
248 fprintf(stderr, "teardown: wait: %s\n", strerror(errno));
249 return 2;
250 }
251 if (p != child)
252 {
253 fprintf(stderr, "teardown: unexpected child %d != %d\n", p, child);
254 return 2;
255 }
256 if (!WIFEXITED(status))
257 {
258 fprintf(stderr, "teardown: child crash, status %d\n", status);
259 return 2;
260 }
261
262 return WEXITSTATUS(status);
263}
264
265#else /* no socket, or no netinet/in.h */
266
267int main(void)
268{
269 fprintf(stderr, "socket headers are missing, cannot test networking\n");
270 return 1;
271}
272
273#endif
274
275/*
276 Local Variables:
277 mode: C
278 fill-column: 76
279 c-file-style: "gnu"
280 indent-tabs-mode: nil
281 End:
282 vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:
283 */

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status