Remove building with NOCRYPTO option
[minix.git] / minix / tests / test67.c
blob8379fdaed551d248d80f74baec52ba73810237ae
1 #include <arpa/inet.h>
2 #include <netinet/in.h>
3 #include <sys/socket.h>
4 #include <sys/types.h>
5 #include <sys/wait.h>
6 #include <sys/syslimits.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <netdb.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
14 int max_error = 5;
15 #include "common.h"
17 #define CLOEXEC_PORT 3490
18 #define FORK_PORT 3491
20 static int fd = 0;
22 void copy_subtests(void);
23 void test_open_file_cloexec(void);
24 void test_open_file_fork(void);
25 void test_open_socket_cloexec(void);
26 void test_open_socket_fork(void);
27 void start_socket_server(int port);
28 int start_socket_client(int port, int flag);
30 void
31 copy_subtests()
33 char *subtests[] = { "t67a", "t67b" };
34 char copy_cmd[8 + PATH_MAX + 1];
35 int i, no_tests;
37 no_tests = sizeof(subtests) / sizeof(char *);
39 for (i = 0; i < no_tests; i++) {
40 snprintf(copy_cmd, 8 + PATH_MAX, "cp ../%s .", subtests[i]);
41 system(copy_cmd);
45 void
46 test_open_file_cloexec()
48 int flags;
49 pid_t pid;
51 /* Let's create a file with O_CLOEXEC turned on */
52 fd = open("file", O_RDWR|O_CREAT|O_CLOEXEC, 0660);
53 if (fd < 0) e(1);
55 /* Now verify through fcntl the flag is indeed set */
56 flags = fcntl(fd, F_GETFD);
57 if (flags < 0) e(2);
58 if (!(flags & FD_CLOEXEC)) e(3);
60 /* Fork a child and let child exec a test program that verifies
61 * fd is not a valid file */
62 pid = fork();
63 if (pid == -1) e(4);
64 else if (pid == 0) {
65 /* We're the child */
66 char fd_buf[2];
68 /* Verify again O_CLOEXEC is on */
69 flags = fcntl(fd, F_GETFD);
70 if (flags < 0) e(5);
71 if (!(flags & FD_CLOEXEC)) e(6);
73 snprintf(fd_buf, sizeof(fd_buf), "%d", fd);
74 execl("./t67b", "t67b", fd_buf, NULL);
76 /* Should not reach this */
77 exit(1);
78 } else {
79 /* We're the parent */
80 int result;
82 if (waitpid(pid, &result, 0) == -1) e(7);
83 if (WEXITSTATUS(result) != 0) e(8);
85 close(fd);
88 void
89 test_open_file_fork()
91 int flags;
92 pid_t pid;
94 /* Let's create a file with O_CLOEXEC NOT turned on */
95 fd = open("file", O_RDWR|O_CREAT, 0660);
96 if (fd < 0) e(1);
98 /* Now verify through fcntl the flag is indeed not set */
99 flags = fcntl(fd, F_GETFD);
100 if (flags < 0) e(2);
101 if (flags & FD_CLOEXEC) e(3);
103 /* Fork a child and let child exec a test program that verifies
104 * fd is a valid file */
105 pid = fork();
106 if (pid == -1) e(4);
107 else if (pid == 0) {
108 /* We're the child */
109 char fd_buf[2];
111 /* Verify again O_CLOEXEC is off */
112 flags = fcntl(fd, F_GETFD);
113 if (flags < 0) e(5);
114 if (flags & FD_CLOEXEC) e(6);
116 snprintf(fd_buf, sizeof(fd_buf), "%d", fd);
117 execl("./t67a", "t67a", fd_buf, NULL);
119 /* Should not reach this */
120 exit(1);
121 } else {
122 /* We're the parent */
123 int result = 0;
125 if (waitpid(pid, &result, 0) == -1) e(7);
126 if (WEXITSTATUS(result) != 0) e(8);
128 close(fd);
132 start_socket_client(int port, int flag)
134 int fd_sock;
135 struct hostent *he;
136 struct sockaddr_in server;
138 if ((fd_sock = socket(PF_INET, SOCK_STREAM|flag, 0)) < 0) {
139 perror("Error obtaining socket\n");
140 e(1);
143 if ((he = gethostbyname("127.0.0.1")) == NULL) {
144 perror("Error retrieving home\n");
145 e(2);
148 /* Copy server host result */
149 memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length);
150 server.sin_family = AF_INET;
151 server.sin_port = htons(port);
153 /* Normally, we'd zerofill sin_zero, but there is no such thing on
154 * Minix at the moment */
155 #if !defined(__minix)
156 memset(&server.sin_zero, '\0', sizeof(server.sin_zero));
157 #endif
159 if (connect(fd_sock, (struct sockaddr *) &server, sizeof(server)) < 0){
160 perror("Error connecting to server\n");
161 e(3);
164 return fd_sock;
168 void
169 start_socket_server(int port)
171 #if !defined(__minix)
172 int yes = 1;
173 #endif
174 int fd_sock, fd_new;
175 struct sockaddr_in my_addr;
176 struct sockaddr_in other_addr;
177 socklen_t other_size;
178 char buf[1];
180 if ((fd_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
181 perror("Error getting socket\n");
182 e(1);
185 my_addr.sin_family = AF_INET;
186 my_addr.sin_port = htons(port);
187 my_addr.sin_addr.s_addr = INADDR_ANY;
188 /* Normally we'd zerofill sin_zero, but current Minix socket interface
189 * does not support that field */
190 #if !defined(__minix)
191 memset(&my_addr.sin_zero, '\0', sizeof(sin.sin_zero));
192 #endif
194 /* Reuse port number when invoking test often */
195 #if !defined(__minix)
196 if (setsockopt(fd_sock, SOL_SOCKET, SO_REUSEADDR, &yes,
197 sizeof(int)) < 0) {
198 perror("Error setting port reuse option\n");
199 e(2);
201 #endif
203 /* Bind to port */
204 if (bind(fd_sock, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) {
205 perror("Error binding to port\n");
206 e(3);
209 /* Set socket in listening mode */
210 if (listen(fd_sock, 20) < 0) {
211 perror("Error listening for incoming connections");
212 e(4);
215 /* Accept incoming connections */
216 fd_new = accept(fd_sock, (struct sockaddr *) &other_addr, &other_size);
218 if (fd_new < 0) {
219 perror("Error accepting new connections\n");
220 e(5);
223 (void)read(fd_new, buf, sizeof(buf));
224 exit(0);
227 void
228 test_open_socket_cloexec()
230 /* This subtest will start a server and client using TCP. The client will
231 * open the socket with SOCK_CLOEXEC turned on, so that after a fork+exec, the
232 * socket should become invalid.
234 * / |
235 * server |
236 * (accept) |
237 * | | \
238 * | | client
239 * | | (connect)
240 * | | | \
241 * | | | client_fork
242 * | | | (exec t67b)
243 * (read) | | (write)
244 * | | | /
245 * | | (waitpid client_fork)
246 * \ | |
247 * (waitpid server) |
248 * | /
249 * (waitpid client)
253 pid_t pid_server, pid_client;
254 int result;
256 pid_server = fork();
257 if (pid_server < 0) e(1);
258 if (pid_server == 0) {
259 start_socket_server(CLOEXEC_PORT);
260 return; /* Never reached */
263 pid_client = fork();
264 if (pid_client < 0) e(2);
265 if (pid_client == 0) {
266 pid_t pid_client_fork;
267 int sockfd;
269 sockfd = start_socket_client(CLOEXEC_PORT, SOCK_CLOEXEC);
270 if (sockfd < 0) e(4);
272 pid_client_fork = fork();
273 if (pid_client_fork < 0) {
274 e(5);
275 exit(5);
277 if (pid_client_fork == 0) {
278 /* We're a fork of the client. After we exec, the
279 * socket should become invalid due to the SOCK_CLOEXEC
280 * flag.
282 char sockfd_buf[2];
283 int flags;
285 /* Verify O_CLOEXEC is on */
286 flags = fcntl(sockfd, F_GETFD);
287 if (flags < 0) e(5);
288 if (!(flags & FD_CLOEXEC)) e(6);
290 /* t67b will verify that it can't write to sockfd and
291 * that opening a new file will yield a file descriptor
292 * with the same number.
294 snprintf(sockfd_buf, sizeof(sockfd_buf), "%d", sockfd);
295 execl("./t67b", "t67b", sockfd_buf, NULL);
297 /* Should not reach this */
298 exit(1);
299 } else {
300 if (waitpid(pid_client_fork, &result, 0) < 0) e(8);
301 exit(WEXITSTATUS(result)); /* Pass on error to main */
303 exit(0); /* Never reached */
306 if (waitpid(pid_server, &result, 0) < 0) e(3);
307 if (waitpid(pid_client, &result, 0) < 0) e(4);
309 /* Let's inspect client result */
310 if (WEXITSTATUS(result) != 0) e(5);
313 void
314 test_open_socket_fork(void)
316 /* This subtest will start a server and client using TCP. The client will
317 * open the socket with SOCK_CLOEXEC turned off, so that after a fork+exec, the
318 * socket should stay valid.
320 * / |
321 * server |
322 * (accept) |
323 * | | \
324 * | | client
325 * | | (connect)
326 * | | | \
327 * | | | client_fork
328 * | | | (exec t67a)
329 * (read) | | (write)
330 * | | | /
331 * | | (waitpid client_fork)
332 * \ | |
333 * (waitpid server) |
334 * | /
335 * (waitpid client)
339 pid_t pid_server, pid_client;
340 int result;
342 pid_server = fork();
343 if (pid_server < 0) e(1);
344 if (pid_server == 0) {
345 start_socket_server(FORK_PORT);
346 return; /* Never reached */
349 pid_client = fork();
350 if (pid_client < 0) e(2);
351 if (pid_client == 0) {
352 pid_t pid_client_fork;
353 int sockfd;
355 sockfd = start_socket_client(FORK_PORT, 0);
356 if (sockfd < 0) e(4);
358 pid_client_fork = fork();
359 if (pid_client_fork < 0) {
360 e(5);
361 exit(5);
363 if (pid_client_fork == 0) {
364 /* We're a fork of the client. After we exec, the
365 * socket should stay valid due to lack of SOCK_CLOEXEC
366 * flag.
368 char sockfd_buf[2];
369 int flags;
371 /* Verify O_CLOEXEC is off */
372 flags = fcntl(sockfd, F_GETFD);
373 if (flags < 0) e(5);
374 if (flags & FD_CLOEXEC) e(6);
376 /* t67a will verify that it can't write to sockfd and
377 * that opening a new file will yield a file descriptor
378 * with a higher number.
380 snprintf(sockfd_buf, sizeof(sockfd_buf), "%d", sockfd);
381 execl("./t67a", "t67a", sockfd_buf, NULL);
383 /* Should not reach this */
384 exit(1);
385 } else {
386 if (waitpid(pid_client_fork, &result, 0) < 0) e(8);
387 exit(WEXITSTATUS(result)); /* Pass on error to main */
389 exit(0); /* Never reached */
392 if (waitpid(pid_server, &result, 0) < 0) e(3);
393 if (waitpid(pid_client, &result, 0) < 0) e(4);
395 /* Let's inspect client result */
396 if (WEXITSTATUS(result) != 0) e(5);
400 main(int argc, char *argv[])
402 start(67);
403 copy_subtests();
404 test_open_file_fork();
405 test_open_file_cloexec();
406 test_open_socket_fork();
407 test_open_socket_cloexec();
408 quit();
409 return(-1); /* Unreachable */