Skip to content

Commit df076bd

Browse files
yoshfujiJunio C Hamano
authored andcommitted
[PATCH] GIT: Listen on IPv6 as well, if available.
Signed-off-by: Hideaki YOSHIFUJI <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 429a935 commit df076bd

File tree

1 file changed

+100
-31
lines changed

1 file changed

+100
-31
lines changed

daemon.c

Lines changed: 100 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
#include <signal.h>
44
#include <sys/wait.h>
55
#include <sys/socket.h>
6+
#include <netdb.h>
67
#include <netinet/in.h>
7-
#include <arpa/inet.h>
88

99
static const char daemon_usage[] = "git-daemon [--inetd | --port=n]";
1010

@@ -79,15 +79,15 @@ static unsigned int children_deleted = 0;
7979

8080
struct child {
8181
pid_t pid;
82-
int addrlen;
83-
struct sockaddr_in address;
82+
socklen_t addrlen;
83+
struct sockaddr_storage address;
8484
} live_child[MAX_CHILDREN];
8585

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)
8787
{
8888
live_child[idx].pid = pid;
8989
live_child[idx].addrlen = addrlen;
90-
live_child[idx].address = *addr;
90+
memcpy(&live_child[idx].address, addr, addrlen);
9191
}
9292

9393
/*
@@ -177,7 +177,7 @@ static void check_max_connections(void)
177177
}
178178
}
179179

180-
static void handle(int incoming, struct sockaddr_in *addr, int addrlen)
180+
static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
181181
{
182182
pid_t pid = fork();
183183

@@ -219,37 +219,106 @@ static void child_handler(int signo)
219219

220220
static int serve(int port)
221221
{
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];
224228

225229
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);
236291

237292
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);
250320
}
251321
}
252-
handle(incoming, &in, addrlen);
253322
}
254323
}
255324

0 commit comments

Comments
 (0)