|
3 | 3 | #include <signal.h>
|
4 | 4 | #include <sys/wait.h>
|
5 | 5 | #include <sys/socket.h>
|
| 6 | +#include <netdb.h> |
6 | 7 | #include <netinet/in.h>
|
7 |
| -#include <arpa/inet.h> |
8 | 8 |
|
9 | 9 | static const char daemon_usage[] = "git-daemon [--inetd | --port=n]";
|
10 | 10 |
|
@@ -79,15 +79,15 @@ static unsigned int children_deleted = 0;
|
79 | 79 |
|
80 | 80 | struct child {
|
81 | 81 | pid_t pid;
|
82 |
| - int addrlen; |
83 |
| - struct sockaddr_in address; |
| 82 | + socklen_t addrlen; |
| 83 | + struct sockaddr_storage address; |
84 | 84 | } live_child[MAX_CHILDREN];
|
85 | 85 |
|
86 |
| -static void add_child(int idx, pid_t pid, struct sockaddr_in *addr, int addrlen) |
| 86 | +static void add_child(int idx, pid_t pid, struct sockaddr *addr, socklen_t addrlen) |
87 | 87 | {
|
88 | 88 | live_child[idx].pid = pid;
|
89 | 89 | live_child[idx].addrlen = addrlen;
|
90 |
| - live_child[idx].address = *addr; |
| 90 | + memcpy(&live_child[idx].address, addr, addrlen); |
91 | 91 | }
|
92 | 92 |
|
93 | 93 | /*
|
@@ -177,7 +177,7 @@ static void check_max_connections(void)
|
177 | 177 | }
|
178 | 178 | }
|
179 | 179 |
|
180 |
| -static void handle(int incoming, struct sockaddr_in *addr, int addrlen) |
| 180 | +static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen) |
181 | 181 | {
|
182 | 182 | pid_t pid = fork();
|
183 | 183 |
|
@@ -219,37 +219,106 @@ static void child_handler(int signo)
|
219 | 219 |
|
220 | 220 | static int serve(int port)
|
221 | 221 | {
|
222 |
| - int sockfd; |
223 |
| - struct sockaddr_in addr; |
| 222 | + struct addrinfo hints, *ai0, *ai; |
| 223 | + int gai; |
| 224 | + int socknum = 0, *socklist = NULL; |
| 225 | + int maxfd = -1; |
| 226 | + fd_set fds_init, fds; |
| 227 | + char pbuf[NI_MAXSERV]; |
224 | 228 |
|
225 | 229 | signal(SIGCHLD, child_handler);
|
226 |
| - sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_IP); |
227 |
| - if (sockfd < 0) |
228 |
| - die("unable to open socket (%s)", strerror(errno)); |
229 |
| - memset(&addr, 0, sizeof(addr)); |
230 |
| - addr.sin_port = htons(port); |
231 |
| - addr.sin_family = AF_INET; |
232 |
| - if (bind(sockfd, (void *)&addr, sizeof(addr)) < 0) |
233 |
| - die("unable to bind to port %d (%s)", port, strerror(errno)); |
234 |
| - if (listen(sockfd, 5) < 0) |
235 |
| - die("unable to listen to port %d (%s)", port, strerror(errno)); |
| 230 | + |
| 231 | + sprintf(pbuf, "%d", port); |
| 232 | + memset(&hints, 0, sizeof(hints)); |
| 233 | + hints.ai_family = AF_UNSPEC; |
| 234 | + hints.ai_socktype = SOCK_STREAM; |
| 235 | + hints.ai_protocol = IPPROTO_TCP; |
| 236 | + hints.ai_flags = AI_PASSIVE; |
| 237 | + |
| 238 | + gai = getaddrinfo(NULL, pbuf, &hints, &ai0); |
| 239 | + if (gai) |
| 240 | + die("getaddrinfo() failed: %s\n", gai_strerror(gai)); |
| 241 | + |
| 242 | + FD_ZERO(&fds_init); |
| 243 | + |
| 244 | + for (ai = ai0; ai; ai = ai->ai_next) { |
| 245 | + int sockfd; |
| 246 | + int *newlist; |
| 247 | + |
| 248 | + sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
| 249 | + if (sockfd < 0) |
| 250 | + continue; |
| 251 | + if (sockfd >= FD_SETSIZE) { |
| 252 | + error("too large socket descriptor."); |
| 253 | + close(sockfd); |
| 254 | + continue; |
| 255 | + } |
| 256 | + |
| 257 | +#ifdef IPV6_V6ONLY |
| 258 | + if (ai->ai_family == AF_INET6) { |
| 259 | + int on = 1; |
| 260 | + setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, |
| 261 | + &on, sizeof(on)); |
| 262 | + /* Note: error is not fatal */ |
| 263 | + } |
| 264 | +#endif |
| 265 | + |
| 266 | + if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) { |
| 267 | + close(sockfd); |
| 268 | + continue; /* not fatal */ |
| 269 | + } |
| 270 | + if (listen(sockfd, 5) < 0) { |
| 271 | + close(sockfd); |
| 272 | + continue; /* not fatal */ |
| 273 | + } |
| 274 | + |
| 275 | + newlist = realloc(socklist, sizeof(int) * (socknum + 1)); |
| 276 | + if (!newlist) |
| 277 | + die("memory allocation failed: %s", strerror(errno)); |
| 278 | + |
| 279 | + socklist = newlist; |
| 280 | + socklist[socknum++] = sockfd; |
| 281 | + |
| 282 | + FD_SET(sockfd, &fds_init); |
| 283 | + if (maxfd < sockfd) |
| 284 | + maxfd = sockfd; |
| 285 | + } |
| 286 | + |
| 287 | + freeaddrinfo(ai0); |
| 288 | + |
| 289 | + if (socknum == 0) |
| 290 | + die("unable to allocate any listen sockets on port %u", port); |
236 | 291 |
|
237 | 292 | for (;;) {
|
238 |
| - struct sockaddr_in in; |
239 |
| - socklen_t addrlen = sizeof(in); |
240 |
| - int incoming = accept(sockfd, (void *)&in, &addrlen); |
241 |
| - |
242 |
| - if (incoming < 0) { |
243 |
| - switch (errno) { |
244 |
| - case EAGAIN: |
245 |
| - case EINTR: |
246 |
| - case ECONNABORTED: |
247 |
| - continue; |
248 |
| - default: |
249 |
| - die("accept returned %s", strerror(errno)); |
| 293 | + int i; |
| 294 | + fds = fds_init; |
| 295 | + |
| 296 | + if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 0) { |
| 297 | + error("select failed, resuming: %s", strerror(errno)); |
| 298 | + sleep(1); |
| 299 | + continue; |
| 300 | + } |
| 301 | + |
| 302 | + for (i = 0; i < socknum; i++) { |
| 303 | + int sockfd = socklist[i]; |
| 304 | + |
| 305 | + if (FD_ISSET(sockfd, &fds)) { |
| 306 | + struct sockaddr_storage ss; |
| 307 | + socklen_t sslen = sizeof(ss); |
| 308 | + int incoming = accept(sockfd, (struct sockaddr *)&ss, &sslen); |
| 309 | + if (incoming < 0) { |
| 310 | + switch (errno) { |
| 311 | + case EAGAIN: |
| 312 | + case EINTR: |
| 313 | + case ECONNABORTED: |
| 314 | + continue; |
| 315 | + default: |
| 316 | + die("accept returned %s", strerror(errno)); |
| 317 | + } |
| 318 | + } |
| 319 | + handle(incoming, (struct sockaddr *)&ss, sslen); |
250 | 320 | }
|
251 | 321 | }
|
252 |
| - handle(incoming, &in, addrlen); |
253 | 322 | }
|
254 | 323 | }
|
255 | 324 |
|
|
0 commit comments