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
usage(const char * cmd)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
create_socket(const struct sockaddr_in * in,int reuseport)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
main(int argc,char * argv[])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
mainloop(int serv_s,const struct sockaddr_in * in,int bindcpu)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