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