Merge branch 'as/daemon-multi-listen'

* as/daemon-multi-listen:
  daemon: allow more than one host address given via --listen
  daemon: add helper function named_sock_setup
This commit is contained in:
Junio C Hamano 2010-10-26 21:50:03 -07:00
Родитель 0141215c9b 3a3a29c1da
Коммит e6202dfe00
2 изменённых файлов: 54 добавлений и 27 удалений

Просмотреть файл

@ -85,6 +85,7 @@ OPTIONS
be either an IPv4 address or an IPv6 address if supported. If IPv6 be either an IPv4 address or an IPv6 address if supported. If IPv6
is not supported, then --listen=hostname is also not supported and is not supported, then --listen=hostname is also not supported and
--listen must be given an IPv4 address. --listen must be given an IPv4 address.
Can be given more than once.
Incompatible with '--inetd' option. Incompatible with '--inetd' option.
--port=<n>:: --port=<n>::

Просмотреть файл

@ -3,6 +3,7 @@
#include "exec_cmd.h" #include "exec_cmd.h"
#include "run-command.h" #include "run-command.h"
#include "strbuf.h" #include "strbuf.h"
#include "string-list.h"
#include <syslog.h> #include <syslog.h>
@ -734,11 +735,17 @@ static int set_reuse_addr(int sockfd)
&on, sizeof(on)); &on, sizeof(on));
} }
struct socketlist {
int *list;
size_t nr;
size_t alloc;
};
#ifndef NO_IPV6 #ifndef NO_IPV6
static int socksetup(char *listen_addr, int listen_port, int **socklist_p) static int setup_named_sock(char *listen_addr, int listen_port, struct socketlist *socklist)
{ {
int socknum = 0, *socklist = NULL; int socknum = 0;
int maxfd = -1; int maxfd = -1;
char pbuf[NI_MAXSERV]; char pbuf[NI_MAXSERV];
struct addrinfo hints, *ai0, *ai; struct addrinfo hints, *ai0, *ai;
@ -753,8 +760,10 @@ static int socksetup(char *listen_addr, int listen_port, int **socklist_p)
hints.ai_flags = AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
gai = getaddrinfo(listen_addr, pbuf, &hints, &ai0); gai = getaddrinfo(listen_addr, pbuf, &hints, &ai0);
if (gai) if (gai) {
die("getaddrinfo() failed: %s", gai_strerror(gai)); logerror("getaddrinfo() for %s failed: %s", listen_addr, gai_strerror(gai));
return 0;
}
for (ai = ai0; ai; ai = ai->ai_next) { for (ai = ai0; ai; ai = ai->ai_next) {
int sockfd; int sockfd;
@ -795,8 +804,9 @@ static int socksetup(char *listen_addr, int listen_port, int **socklist_p)
if (flags >= 0) if (flags >= 0)
fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC); fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC);
socklist = xrealloc(socklist, sizeof(int) * (socknum + 1)); ALLOC_GROW(socklist->list, socklist->nr + 1, socklist->alloc);
socklist[socknum++] = sockfd; socklist->list[socklist->nr++] = sockfd;
socknum++;
if (maxfd < sockfd) if (maxfd < sockfd)
maxfd = sockfd; maxfd = sockfd;
@ -804,13 +814,12 @@ static int socksetup(char *listen_addr, int listen_port, int **socklist_p)
freeaddrinfo(ai0); freeaddrinfo(ai0);
*socklist_p = socklist;
return socknum; return socknum;
} }
#else /* NO_IPV6 */ #else /* NO_IPV6 */
static int socksetup(char *listen_addr, int listen_port, int **socklist_p) static int setup_named_sock(char *listen_addr, int listen_port, struct socketlist *socklist)
{ {
struct sockaddr_in sin; struct sockaddr_in sin;
int sockfd; int sockfd;
@ -851,22 +860,39 @@ static int socksetup(char *listen_addr, int listen_port, int **socklist_p)
if (flags >= 0) if (flags >= 0)
fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC); fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC);
*socklist_p = xmalloc(sizeof(int)); ALLOC_GROW(socklist->list, socklist->nr + 1, socklist->alloc);
**socklist_p = sockfd; socklist->list[socklist->nr++] = sockfd;
return 1; return 1;
} }
#endif #endif
static int service_loop(int socknum, int *socklist) static void socksetup(struct string_list *listen_addr, int listen_port, struct socketlist *socklist)
{
if (!listen_addr->nr)
setup_named_sock(NULL, listen_port, socklist);
else {
int i, socknum;
for (i = 0; i < listen_addr->nr; i++) {
socknum = setup_named_sock(listen_addr->items[i].string,
listen_port, socklist);
if (socknum == 0)
logerror("unable to allocate any listen sockets for host %s on port %u",
listen_addr->items[i].string, listen_port);
}
}
}
static int service_loop(struct socketlist *socklist)
{ {
struct pollfd *pfd; struct pollfd *pfd;
int i; int i;
pfd = xcalloc(socknum, sizeof(struct pollfd)); pfd = xcalloc(socklist->nr, sizeof(struct pollfd));
for (i = 0; i < socknum; i++) { for (i = 0; i < socklist->nr; i++) {
pfd[i].fd = socklist[i]; pfd[i].fd = socklist->list[i];
pfd[i].events = POLLIN; pfd[i].events = POLLIN;
} }
@ -877,7 +903,7 @@ static int service_loop(int socknum, int *socklist)
check_dead_children(); check_dead_children();
if (poll(pfd, socknum, -1) < 0) { if (poll(pfd, socklist->nr, -1) < 0) {
if (errno != EINTR) { if (errno != EINTR) {
logerror("Poll failed, resuming: %s", logerror("Poll failed, resuming: %s",
strerror(errno)); strerror(errno));
@ -886,7 +912,7 @@ static int service_loop(int socknum, int *socklist)
continue; continue;
} }
for (i = 0; i < socknum; i++) { for (i = 0; i < socklist->nr; i++) {
if (pfd[i].revents & POLLIN) { if (pfd[i].revents & POLLIN) {
struct sockaddr_storage ss; struct sockaddr_storage ss;
unsigned int sslen = sizeof(ss); unsigned int sslen = sizeof(ss);
@ -946,27 +972,27 @@ static void store_pid(const char *path)
die_errno("failed to write pid file '%s'", path); die_errno("failed to write pid file '%s'", path);
} }
static int serve(char *listen_addr, int listen_port, struct passwd *pass, gid_t gid) static int serve(struct string_list *listen_addr, int listen_port, struct passwd *pass, gid_t gid)
{ {
int socknum, *socklist; struct socketlist socklist = { NULL, 0, 0 };
socknum = socksetup(listen_addr, listen_port, &socklist); socksetup(listen_addr, listen_port, &socklist);
if (socknum == 0) if (socklist.nr == 0)
die("unable to allocate any listen sockets on host %s port %u", die("unable to allocate any listen sockets on port %u",
listen_addr, listen_port); listen_port);
if (pass && gid && if (pass && gid &&
(initgroups(pass->pw_name, gid) || setgid (gid) || (initgroups(pass->pw_name, gid) || setgid (gid) ||
setuid(pass->pw_uid))) setuid(pass->pw_uid)))
die("cannot drop privileges"); die("cannot drop privileges");
return service_loop(socknum, socklist); return service_loop(&socklist);
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int listen_port = 0; int listen_port = 0;
char *listen_addr = NULL; struct string_list listen_addr = STRING_LIST_INIT_NODUP;
int inetd_mode = 0; int inetd_mode = 0;
const char *pid_file = NULL, *user_name = NULL, *group_name = NULL; const char *pid_file = NULL, *user_name = NULL, *group_name = NULL;
int detach = 0; int detach = 0;
@ -981,7 +1007,7 @@ int main(int argc, char **argv)
char *arg = argv[i]; char *arg = argv[i];
if (!prefixcmp(arg, "--listen=")) { if (!prefixcmp(arg, "--listen=")) {
listen_addr = xstrdup_tolower(arg + 9); string_list_append(&listen_addr, xstrdup_tolower(arg + 9));
continue; continue;
} }
if (!prefixcmp(arg, "--port=")) { if (!prefixcmp(arg, "--port=")) {
@ -1106,7 +1132,7 @@ int main(int argc, char **argv)
if (inetd_mode && (group_name || user_name)) if (inetd_mode && (group_name || user_name))
die("--user and --group are incompatible with --inetd"); die("--user and --group are incompatible with --inetd");
if (inetd_mode && (listen_port || listen_addr)) if (inetd_mode && (listen_port || (listen_addr.nr > 0)))
die("--listen= and --port= are incompatible with --inetd"); die("--listen= and --port= are incompatible with --inetd");
else if (listen_port == 0) else if (listen_port == 0)
listen_port = DEFAULT_GIT_PORT; listen_port = DEFAULT_GIT_PORT;
@ -1161,5 +1187,5 @@ int main(int argc, char **argv)
if (pid_file) if (pid_file)
store_pid(pid_file); store_pid(pid_file);
return serve(listen_addr, listen_port, pass, gid); return serve(&listen_addr, listen_port, pass, gid);
} }