daemon: use run-command api for async serving

fork() is only available on POSIX, so to support git-daemon
on Windows we have to use something else.

Instead we invent the flag --serve, which is a stripped down
version of --inetd-mode. We use start_command() to call
git-daemon with this flag appended to serve clients.

Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Erik Faye-Lund 2010-11-04 02:35:16 +01:00 коммит произвёл Junio C Hamano
Родитель 82fc07b7ba
Коммит 30e1560230
1 изменённых файлов: 47 добавлений и 46 удалений

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

@ -614,17 +614,17 @@ static unsigned int live_children;
static struct child { static struct child {
struct child *next; struct child *next;
pid_t pid; struct child_process cld;
struct sockaddr_storage address; struct sockaddr_storage address;
} *firstborn; } *firstborn;
static void add_child(pid_t pid, struct sockaddr *addr, int addrlen) static void add_child(struct child_process *cld, struct sockaddr *addr, int addrlen)
{ {
struct child *newborn, **cradle; struct child *newborn, **cradle;
newborn = xcalloc(1, sizeof(*newborn)); newborn = xcalloc(1, sizeof(*newborn));
live_children++; live_children++;
newborn->pid = pid; memcpy(&newborn->cld, cld, sizeof(*cld));
memcpy(&newborn->address, addr, addrlen); memcpy(&newborn->address, addr, addrlen);
for (cradle = &firstborn; *cradle; cradle = &(*cradle)->next) for (cradle = &firstborn; *cradle; cradle = &(*cradle)->next)
if (!addrcmp(&(*cradle)->address, &newborn->address)) if (!addrcmp(&(*cradle)->address, &newborn->address))
@ -633,19 +633,6 @@ static void add_child(pid_t pid, struct sockaddr *addr, int addrlen)
*cradle = newborn; *cradle = newborn;
} }
static void remove_child(pid_t pid)
{
struct child **cradle, *blanket;
for (cradle = &firstborn; (blanket = *cradle); cradle = &blanket->next)
if (blanket->pid == pid) {
*cradle = blanket->next;
live_children--;
free(blanket);
break;
}
}
/* /*
* This gets called if the number of connections grows * This gets called if the number of connections grows
* past "max_connections". * past "max_connections".
@ -661,7 +648,7 @@ static void kill_some_child(void)
for (; (next = blanket->next); blanket = next) for (; (next = blanket->next); blanket = next)
if (!addrcmp(&blanket->address, &next->address)) { if (!addrcmp(&blanket->address, &next->address)) {
kill(blanket->pid, SIGTERM); kill(blanket->cld.pid, SIGTERM);
break; break;
} }
} }
@ -671,18 +658,26 @@ static void check_dead_children(void)
int status; int status;
pid_t pid; pid_t pid;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { struct child **cradle, *blanket;
for (cradle = &firstborn; (blanket = *cradle);)
if ((pid = waitpid(blanket->cld.pid, &status, WNOHANG)) > 1) {
const char *dead = ""; const char *dead = "";
remove_child(pid); if (status)
if (!WIFEXITED(status) || (WEXITSTATUS(status) > 0))
dead = " (with error)"; dead = " (with error)";
loginfo("[%"PRIuMAX"] Disconnected%s", (uintmax_t)pid, dead); loginfo("[%"PRIuMAX"] Disconnected%s", (uintmax_t)pid, dead);
}
/* remove the child */
*cradle = blanket->next;
live_children--;
free(blanket);
} else
cradle = &blanket->next;
} }
static char **cld_argv;
static void handle(int incoming, struct sockaddr *addr, int addrlen) static void handle(int incoming, struct sockaddr *addr, int addrlen)
{ {
pid_t pid; struct child_process cld = { 0 };
if (max_connections && live_children >= max_connections) { if (max_connections && live_children >= max_connections) {
kill_some_child(); kill_some_child();
@ -695,22 +690,15 @@ static void handle(int incoming, struct sockaddr *addr, int addrlen)
} }
} }
if ((pid = fork())) { cld.argv = (const char **)cld_argv;
cld.in = incoming;
cld.out = dup(incoming);
if (start_command(&cld))
logerror("unable to fork");
else
add_child(&cld, addr, addrlen);
close(incoming); close(incoming);
if (pid < 0) {
logerror("Couldn't fork %s", strerror(errno));
return;
}
add_child(pid, addr, addrlen);
return;
}
dup2(incoming, 0);
dup2(incoming, 1);
close(incoming);
exit(execute(addr));
} }
static void child_handler(int signo) static void child_handler(int signo)
@ -991,7 +979,7 @@ int main(int argc, char **argv)
{ {
int listen_port = 0; int listen_port = 0;
struct string_list listen_addr = STRING_LIST_INIT_NODUP; struct string_list listen_addr = STRING_LIST_INIT_NODUP;
int inetd_mode = 0; int serve_mode = 0, 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;
struct passwd *pass = NULL; struct passwd *pass = NULL;
@ -1017,6 +1005,10 @@ int main(int argc, char **argv)
continue; continue;
} }
} }
if (!strcmp(arg, "--serve")) {
serve_mode = 1;
continue;
}
if (!strcmp(arg, "--inetd")) { if (!strcmp(arg, "--inetd")) {
inetd_mode = 1; inetd_mode = 1;
log_syslog = 1; log_syslog = 1;
@ -1162,16 +1154,18 @@ int main(int argc, char **argv)
base_path); base_path);
if (inetd_mode) { if (inetd_mode) {
if (!freopen("/dev/null", "w", stderr))
die_errno("failed to redirect stderr to /dev/null");
}
if (inetd_mode || serve_mode) {
struct sockaddr_storage ss; struct sockaddr_storage ss;
struct sockaddr *peer = (struct sockaddr *)&ss; struct sockaddr *peer = (struct sockaddr *)&ss;
socklen_t slen = sizeof(ss); socklen_t slen = sizeof(ss);
if (!freopen("/dev/null", "w", stderr))
die_errno("failed to redirect stderr to /dev/null");
if (getpeername(0, peer, &slen)) if (getpeername(0, peer, &slen))
peer = NULL; return execute(NULL);
else
return execute(peer); return execute(peer);
} }
@ -1185,5 +1179,12 @@ int main(int argc, char **argv)
if (pid_file) if (pid_file)
store_pid(pid_file); store_pid(pid_file);
/* prepare argv for serving-processes */
cld_argv = xmalloc(sizeof (char *) * (argc + 2));
for (i = 0; i < argc; ++i)
cld_argv[i] = argv[i];
cld_argv[argc] = "--serve";
cld_argv[argc+1] = NULL;
return serve(&listen_addr, listen_port, pass, gid); return serve(&listen_addr, listen_port, pass, gid);
} }