1 #include <sys/types.h>
2 #include <sys/event.h>
3 #include <sys/socket.h>
4 #include <sys/time.h>
5 
6 #include <arpa/inet.h>
7 #include <netinet/in.h>
8 
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 
16 #define EVENT_MAX	128
17 
18 static void	mainloop(int, const struct sockaddr_in *);
19 
20 static void
21 usage(const char *cmd)
22 {
23 	fprintf(stderr, "%s -p port [-i n_instance] [-r]\n", cmd);
24 	exit(1);
25 }
26 
27 static int
28 create_socket(const struct sockaddr_in *in, int reuseport)
29 {
30 	int serv_s, on, flags;
31 
32 	serv_s = socket(AF_INET, SOCK_STREAM, 0);
33 	if (serv_s < 0) {
34 		fprintf(stderr, "socket failed: %d\n", errno);
35 		exit(1);
36 	}
37 
38 	on = 1;
39 	if (!reuseport) {
40 		if (setsockopt(serv_s, SOL_SOCKET, SO_REUSEADDR,
41 		    &on, sizeof(on)) < 0) {
42 			fprintf(stderr, "setsockopt(REUSEADDR) failed: %d\n",
43 			    errno);
44 			exit(1);
45 		}
46 	} else {
47 		if (setsockopt(serv_s, SOL_SOCKET, SO_REUSEPORT,
48 		    &on, sizeof(on)) < 0) {
49 			fprintf(stderr, "setsockopt(REUSEPORT) failed: %d\n",
50 			    errno);
51 			exit(1);
52 		}
53 	}
54 
55 	flags = fcntl(serv_s, F_GETFL, 0);
56 	if (flags < 0) {
57 		fprintf(stderr, "fcntl(F_GETFL) failed: %d\n", errno);
58 		exit(1);
59 	}
60 	if (fcntl(serv_s, F_SETFL, flags | O_NONBLOCK) < 0) {
61 		fprintf(stderr, "fcntl(F_SETFL) failed: %d\n", errno);
62 		exit(1);
63 	}
64 
65 	if (bind(serv_s, (const struct sockaddr *)in, sizeof(*in)) < 0) {
66 		fprintf(stderr, "bind failed: %d\n", errno);
67 		exit(1);
68 	}
69 
70 	if (listen(serv_s, -1) < 0) {
71 		fprintf(stderr, "listen failed: %d\n", errno);
72 		exit(1);
73 	}
74 	return serv_s;
75 }
76 
77 int
78 main(int argc, char *argv[])
79 {
80 	struct sockaddr_in in;
81 	int opt, ninst, serv_s, i, reuseport;
82 
83 	memset(&in, 0, sizeof(in));
84 	in.sin_family = AF_INET;
85 	in.sin_addr.s_addr = INADDR_ANY;
86 
87 	ninst = 1;
88 	reuseport = 0;
89 
90 	while ((opt = getopt(argc, argv, "p:i:r")) != -1) {
91 		switch (opt) {
92 		case 'p':
93 			in.sin_port = htons(atoi(optarg));
94 			break;
95 
96 		case 'i':
97 			ninst = atoi(optarg);
98 			break;
99 
100 		case 'r':
101 			reuseport = 1;
102 			break;
103 
104 		default:
105 			usage(argv[0]);
106 		}
107 	}
108 
109 	if (ninst < 1 || in.sin_port == 0)
110 		usage(argv[0]);
111 
112 	serv_s = -1;
113 	if (!reuseport)
114 		serv_s = create_socket(&in, 0);
115 
116 	for (i = 1; i < ninst; ++i) {
117 		pid_t pid;
118 
119 		pid = fork();
120 		if (pid == 0) {
121 			mainloop(serv_s, &in);
122 			exit(0);
123 		} else if (pid < 0) {
124 			fprintf(stderr, "fork failed: %d\n", errno);
125 		}
126 	}
127 
128 	mainloop(serv_s, &in);
129 	exit(0);
130 }
131 
132 static void
133 mainloop(int serv_s, const struct sockaddr_in *in)
134 {
135 	struct kevent change_evt0[EVENT_MAX];
136 	int kq, nchange;
137 
138 	if (serv_s < 0)
139 		serv_s = create_socket(in, 1);
140 
141 	kq = kqueue();
142 	if (kq < 0) {
143 		fprintf(stderr, "kqueue failed: %d\n", errno);
144 		exit(1);
145 	}
146 
147 	EV_SET(&change_evt0[0], serv_s, EVFILT_READ, EV_ADD, 0, 0, NULL);
148 	nchange = 1;
149 
150 	for (;;) {
151 		const struct kevent *change_evt = NULL;
152 		struct kevent evt[EVENT_MAX];
153 		int i, nevt;
154 
155 		if (nchange > 0)
156 			change_evt = change_evt0;
157 
158 		nevt = kevent(kq, change_evt, nchange, evt, EVENT_MAX, NULL);
159 		if (nevt < 0) {
160 			fprintf(stderr, "kevent failed: %d\n", errno);
161 			exit(1);
162 		}
163 		nchange = 0;
164 
165 		for (i = 0; i < nevt; ++i) {
166 			if (evt[i].ident == (u_int)serv_s) {
167 				while (nchange < EVENT_MAX) {
168 					int s;
169 
170 					s = accept(serv_s, NULL, NULL);
171 					if (s < 0)
172 						break;
173 					EV_SET(&change_evt0[nchange], s,
174 					    EVFILT_READ, EV_ADD, 0, 0, NULL);
175 					++nchange;
176 				}
177 			} else {
178 				close(evt[i].ident);
179 			}
180 		}
181 	}
182 	/* NEVER REACHED */
183 }
184