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