daemon: use run-command api for async serving
authorErik Faye-Lund <kusmabite@gmail.com>
Thu, 4 Nov 2010 01:35:16 +0000 (02:35 +0100)
committerJunio C Hamano <gitster@pobox.com>
Thu, 4 Nov 2010 23:53:50 +0000 (16:53 -0700)
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>
daemon.c

index 535ae88018f54ea57a304848c24dff4955a55909..40595933bea6ddc516a49f7bd5de29b3bb91db16 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -614,17 +614,17 @@ static unsigned int live_children;
 
 static struct child {
        struct child *next;
-       pid_t pid;
+       struct child_process cld;
        struct sockaddr_storage address;
 } *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;
 
        newborn = xcalloc(1, sizeof(*newborn));
        live_children++;
-       newborn->pid = pid;
+       memcpy(&newborn->cld, cld, sizeof(*cld));
        memcpy(&newborn->address, addr, addrlen);
        for (cradle = &firstborn; *cradle; cradle = &(*cradle)->next)
                if (!addrcmp(&(*cradle)->address, &newborn->address))
@@ -633,19 +633,6 @@ static void add_child(pid_t pid, struct sockaddr *addr, int addrlen)
        *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
  * past "max_connections".
@@ -661,7 +648,7 @@ static void kill_some_child(void)
 
        for (; (next = blanket->next); blanket = next)
                if (!addrcmp(&blanket->address, &next->address)) {
-                       kill(blanket->pid, SIGTERM);
+                       kill(blanket->cld.pid, SIGTERM);
                        break;
                }
 }
@@ -671,18 +658,26 @@ static void check_dead_children(void)
        int status;
        pid_t pid;
 
-       while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
-               const char *dead = "";
-               remove_child(pid);
-               if (!WIFEXITED(status) || (WEXITSTATUS(status) > 0))
-                       dead = " (with error)";
-               loginfo("[%"PRIuMAX"] Disconnected%s", (uintmax_t)pid, dead);
-       }
+       struct child **cradle, *blanket;
+       for (cradle = &firstborn; (blanket = *cradle);)
+               if ((pid = waitpid(blanket->cld.pid, &status, WNOHANG)) > 1) {
+                       const char *dead = "";
+                       if (status)
+                               dead = " (with error)";
+                       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)
 {
-       pid_t pid;
+       struct child_process cld = { 0 };
 
        if (max_connections && live_children >= max_connections) {
                kill_some_child();
@@ -695,22 +690,15 @@ static void handle(int incoming, struct sockaddr *addr, int addrlen)
                }
        }
 
-       if ((pid = fork())) {
-               close(incoming);
-               if (pid < 0) {
-                       logerror("Couldn't fork %s", strerror(errno));
-                       return;
-               }
-
-               add_child(pid, addr, addrlen);
-               return;
-       }
+       cld.argv = (const char **)cld_argv;
+       cld.in = incoming;
+       cld.out = dup(incoming);
 
-       dup2(incoming, 0);
-       dup2(incoming, 1);
+       if (start_command(&cld))
+               logerror("unable to fork");
+       else
+               add_child(&cld, addr, addrlen);
        close(incoming);
-
-       exit(execute(addr));
 }
 
 static void child_handler(int signo)
@@ -991,7 +979,7 @@ int main(int argc, char **argv)
 {
        int listen_port = 0;
        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;
        int detach = 0;
        struct passwd *pass = NULL;
@@ -1017,6 +1005,10 @@ int main(int argc, char **argv)
                                continue;
                        }
                }
+               if (!strcmp(arg, "--serve")) {
+                       serve_mode = 1;
+                       continue;
+               }
                if (!strcmp(arg, "--inetd")) {
                        inetd_mode = 1;
                        log_syslog = 1;
@@ -1162,17 +1154,19 @@ int main(int argc, char **argv)
                    base_path);
 
        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 *peer = (struct sockaddr *)&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))
-                       peer = NULL;
-
-               return execute(peer);
+                       return execute(NULL);
+               else
+                       return execute(peer);
        }
 
        if (detach) {
@@ -1185,5 +1179,12 @@ int main(int argc, char **argv)
        if (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);
 }