1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <sys/sysctl.h>
4 
5 #include <arpa/inet.h>
6 #include <netinet/in.h>
7 
8 #include <err.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 
14 static void	mainloop(int, const struct sockaddr_in *);
15 
16 static void
17 usage(const char *cmd)
18 {
19 	fprintf(stderr, "%s -p port [-i n_instance] [-r]\n", cmd);
20 	exit(1);
21 }
22 
23 static int
24 create_socket(const struct sockaddr_in *in, int reuseport)
25 {
26 	int serv_s, on;
27 
28 	serv_s = socket(AF_INET, SOCK_STREAM, 0);
29 	if (serv_s < 0)
30 		err(1, "socket failed");
31 
32 	on = 1;
33 	if (!reuseport) {
34 		if (setsockopt(serv_s, SOL_SOCKET, SO_REUSEADDR,
35 		    &on, sizeof(on)) < 0)
36 			err(1, "setsockopt(REUSEADDR) failed");
37 	} else {
38 		if (setsockopt(serv_s, SOL_SOCKET, SO_REUSEPORT,
39 		    &on, sizeof(on)) < 0)
40 			err(1, "setsockopt(REUSEPORT) failed");
41 	}
42 
43 	if (bind(serv_s, (const struct sockaddr *)in, sizeof(*in)) < 0)
44 		err(1, "bind failed");
45 
46 	if (listen(serv_s, -1) < 0)
47 		err(1, "listen failed");
48 	return serv_s;
49 }
50 
51 int
52 main(int argc, char *argv[])
53 {
54 	struct sockaddr_in in;
55 	int opt, ninst, serv_s, i, reuseport;
56 	size_t prm_len;
57 
58 	prm_len = sizeof(ninst);
59 	if (sysctlbyname("hw.ncpu", &ninst, &prm_len, NULL, 0) != 0)
60 		err(2, "sysctl hw.ncpu failed");
61 
62 	memset(&in, 0, sizeof(in));
63 	in.sin_family = AF_INET;
64 	in.sin_addr.s_addr = INADDR_ANY;
65 
66 	reuseport = 0;
67 
68 	while ((opt = getopt(argc, argv, "p:i:r")) != -1) {
69 		switch (opt) {
70 		case 'p':
71 			in.sin_port = htons(atoi(optarg));
72 			break;
73 
74 		case 'i':
75 			ninst = atoi(optarg);
76 			break;
77 
78 		case 'r':
79 			reuseport = 1;
80 			break;
81 
82 		default:
83 			usage(argv[0]);
84 		}
85 	}
86 
87 	if (ninst < 1 || in.sin_port == 0)
88 		usage(argv[0]);
89 
90 	serv_s = -1;
91 	if (!reuseport)
92 		serv_s = create_socket(&in, 0);
93 
94 	for (i = 1; i < ninst; ++i) {
95 		pid_t pid;
96 
97 		pid = fork();
98 		if (pid == 0) {
99 			mainloop(serv_s, &in);
100 			exit(0);
101 		} else if (pid < 0) {
102 			err(1, "fork failed");
103 		}
104 	}
105 
106 	mainloop(serv_s, &in);
107 	exit(0);
108 }
109 
110 static void
111 mainloop(int serv_s, const struct sockaddr_in *in)
112 {
113 	if (serv_s < 0)
114 		serv_s = create_socket(in, 1);
115 
116 	for (;;) {
117 		int s;
118 
119 		s = accept(serv_s, NULL, NULL);
120 		if (s >= 0)
121 			close(s);
122 	}
123 	/* NEVER REACHED */
124 }
125