1 #include <sys/types.h>
2 #include <sys/event.h>
3 #include <sys/ioctl.h>
4 #include <sys/socket.h>
5 #include <sys/time.h>
6 
7 #include <arpa/inet.h>
8 #include <netinet/in.h>
9 
10 #include <errno.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;
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 	on = 1;
56 	if (ioctl(serv_s, FIONBIO, &on, sizeof(on)) < 0) {
57 		fprintf(stderr, "ioctl(FIONBIO) failed: %d\n", errno);
58 		exit(1);
59 	}
60 
61 	if (bind(serv_s, (const struct sockaddr *)in, sizeof(*in)) < 0) {
62 		fprintf(stderr, "bind failed: %d\n", errno);
63 		exit(1);
64 	}
65 
66 	if (listen(serv_s, -1) < 0) {
67 		fprintf(stderr, "listen failed: %d\n", errno);
68 		exit(1);
69 	}
70 	return serv_s;
71 }
72 
73 int
74 main(int argc, char *argv[])
75 {
76 	struct sockaddr_in in;
77 	int opt, ninst, serv_s, i, reuseport;
78 
79 	memset(&in, 0, sizeof(in));
80 	in.sin_family = AF_INET;
81 	in.sin_addr.s_addr = INADDR_ANY;
82 
83 	ninst = 1;
84 	reuseport = 0;
85 
86 	while ((opt = getopt(argc, argv, "p:i:r")) != -1) {
87 		switch (opt) {
88 		case 'p':
89 			in.sin_port = htons(atoi(optarg));
90 			break;
91 
92 		case 'i':
93 			ninst = atoi(optarg);
94 			break;
95 
96 		case 'r':
97 			reuseport = 1;
98 			break;
99 
100 		default:
101 			usage(argv[0]);
102 		}
103 	}
104 
105 	if (ninst < 1 || in.sin_port == 0)
106 		usage(argv[0]);
107 
108 	serv_s = -1;
109 	if (!reuseport)
110 		serv_s = create_socket(&in, 0);
111 
112 	for (i = 1; i < ninst; ++i) {
113 		pid_t pid;
114 
115 		pid = fork();
116 		if (pid == 0) {
117 			mainloop(serv_s, &in);
118 			exit(0);
119 		} else if (pid < 0) {
120 			fprintf(stderr, "fork failed: %d\n", errno);
121 		}
122 	}
123 
124 	mainloop(serv_s, &in);
125 	exit(0);
126 }
127 
128 static void
129 mainloop(int serv_s, const struct sockaddr_in *in)
130 {
131 	struct kevent change_evt0[EVENT_MAX];
132 	int kq, nchange;
133 
134 	if (serv_s < 0)
135 		serv_s = create_socket(in, 1);
136 
137 	kq = kqueue();
138 	if (kq < 0) {
139 		fprintf(stderr, "kqueue failed: %d\n", errno);
140 		exit(1);
141 	}
142 
143 	EV_SET(&change_evt0[0], serv_s, EVFILT_READ, EV_ADD, 0, 0, NULL);
144 	nchange = 1;
145 
146 	for (;;) {
147 		const struct kevent *change_evt = NULL;
148 		struct kevent evt[EVENT_MAX];
149 		int i, nevt;
150 
151 		if (nchange > 0)
152 			change_evt = change_evt0;
153 
154 		nevt = kevent(kq, change_evt, nchange, evt, EVENT_MAX, NULL);
155 		if (nevt < 0) {
156 			fprintf(stderr, "kevent failed: %d\n", errno);
157 			exit(1);
158 		}
159 		nchange = 0;
160 
161 		for (i = 0; i < nevt; ++i) {
162 			if (evt[i].ident == (u_int)serv_s) {
163 				while (nchange < EVENT_MAX) {
164 					int s;
165 
166 					s = accept(serv_s, NULL, NULL);
167 					if (s < 0)
168 						break;
169 					EV_SET(&change_evt0[nchange], s,
170 					    EVFILT_READ, EV_ADD, 0, 0, NULL);
171 					++nchange;
172 				}
173 			} else {
174 				close(evt[i].ident);
175 			}
176 		}
177 	}
178 	/* NEVER REACHED */
179 }
180