1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <sys/wait.h>
4 
5 #include <arpa/inet.h>
6 #include <netinet/in.h>
7 
8 #include <err.h>
9 #include <errno.h>
10 #include <signal.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 
16 static void
17 usage(const char *cmd)
18 {
19 	fprintf(stderr, "%s -p port\n", cmd);
20 	exit(1);
21 }
22 
23 static void
24 connect_client(int port)
25 {
26 	struct sockaddr_in in;
27 	int s;
28 
29 	s = socket(AF_INET, SOCK_STREAM, 0);
30 	if (s < 0)
31 		err(1, "client socket failed");
32 
33 	memset(&in, 0, sizeof(in));
34 	in.sin_family = AF_INET;
35 	in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
36 	in.sin_port = htons(port);
37 	if (connect(s, (const struct sockaddr *)&in, sizeof(in)) < 0)
38 		err(1, "connect failed");
39 
40 	pause();
41 	exit(0);
42 }
43 
44 int
45 main(int argc, char *argv[])
46 {
47 	struct sockaddr_in in;
48 	int serv_s, s;
49 	int opt, port, dummy, n, status, panic, ex;
50 	pid_t pid;
51 
52 	ex = 1;
53 	panic = 0;
54 
55 	port = 0;
56 	while ((opt = getopt(argc, argv, "p:")) != -1) {
57 		char *endptr;
58 
59 		switch (opt) {
60 		case 'p':
61 			port = strtol(optarg, &endptr, 0);
62 			if (*endptr != '\0')
63 				errx(1, "invalid -p");
64 			break;
65 
66 		default:
67 			usage(argv[0]);
68 		}
69 	}
70 	if (port <= 0)
71 		usage(argv[0]);
72 
73 	serv_s = socket(AF_INET, SOCK_STREAM, 0);
74 	if (serv_s < 0)
75 		err(1, "socket failed");
76 
77 	memset(&in, 0, sizeof(in));
78 	in.sin_family = AF_INET;
79 	in.sin_port = htons(port);
80 	if (bind(serv_s, (const struct sockaddr *)&in, sizeof(in)) < 0)
81 		err(1, "bind failed");
82 
83 	if (listen(serv_s, 0) < 0)
84 		err(1, "listen failed");
85 
86 	pid = fork();
87 	if (pid < 0) {
88 		err(1, "fork failed");
89 	} else if (pid == 0) {
90 		connect_client(port);
91 		abort();
92 	}
93 
94 	s = accept4(serv_s, NULL, NULL, SOCK_NONBLOCK);
95 	if (s < 0) {
96 		warn("accept4 failed");
97 		goto done;
98 	}
99 	panic = 1;
100 
101 	n = read(s, &dummy, sizeof(dummy));
102 	if (n < 0) {
103 		int error = errno;
104 
105 		if (error != EAGAIN) {
106 			warnx("invaid errno %d", error);
107 			goto done;
108 		}
109 	} else {
110 		warnx("read works");
111 		goto done;
112 	}
113 
114 	ex = 0;
115 	panic = 0;
116 	fprintf(stderr, "passed\n");
117 done:
118 	kill(pid, SIGKILL);
119 	waitpid(pid, &status, 0);
120 	if (panic)
121 		abort();
122 	exit(ex);
123 }
124