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