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