{"thread":{"id":"5686","subject":"[PATCH] Cleaned up git-daemon virtual hosting support.","startedAt":"2006-09-25T04:04:28Z","lastAt":"2006-09-26T13:37:36Z","messageCount":5,"participants":["Jon Loeliger","Junio C Hamano","Andreas Ericsson"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"27609","messageId":"E1GRhhk-0004O6-GP@jdl.com","threadId":"5686","inReplyTo":null,"subject":"[PATCH] Cleaned up git-daemon virtual hosting support.","fromName":"Jon Loeliger","fromEmail":"jdl@jdl.com","sentAt":"2006-09-25T04:04:28Z","receivedAt":"2006-09-25T04:04:28Z","isPatch":true,"sender":{"key":"jdl@jdl.com","avatar":"https://gravatar.com/avatar/75ce9a10b151acd2c28ec4ab2136dba7b2ff1634530bd04b155981a749d08a64?d=mp&s=160"},"body":"Standardized on lowercase hostnames from client.\n\nAdded interpolation values for the IP address, Port\nand canoncial hostname of the server as it is contacted\nand named by the client.\n\nAdded --host=host_or_ipaddr option suport.\n\nDocumented mutual exclusivity of --inetd option with\n    --user, --group, --host and --port options.\n\nAdded compat_inet_pton from Paul Vixie as needed.\n\nSmall memory leaks need to be cleaned up still.\n\nSigned-off-by: Jon Loeliger <jdl@jdl.com>\n\n---\n\nJunio,\n\nThis is on top of my previous patch in the next branch.\nThis makes virtual host support way, way less stupid.\nI'll follow up with another patch to clean up the small leaks.\n\nThanks,\njdl\n\n\n Documentation/git-daemon.txt |   45 +++++++--\n Makefile                     |    3 +\n compat/inet_pton.c           |  220 ++++++++++++++++++++++++++++++++++++++++++\n daemon.c                     |  146 ++++++++++++++++++++++++----\n 4 files changed, 387 insertions(+), 27 deletions(-)\n\ndiff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt\nindex 87444b4..422cc37 100644\n--- a/Documentation/git-daemon.txt\n+++ b/Documentation/git-daemon.txt\n@@ -8,14 +8,15 @@ git-daemon - A really simple server for \n SYNOPSIS\n --------\n [verse]\n-'git-daemon' [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n+'git-daemon' [--verbose] [--syslog] [--export-all]\n              [--timeout=n] [--init-timeout=n] [--strict-paths]\n              [--base-path=path] [--user-path | --user-path=path]\n              [--interpolated-path=pathtemplate]\n+             [--reuseaddr] [--detach] [--pid-file=file]\n              [--enable=service] [--disable=service]\n \t     [--allow-override=service] [--forbid-override=service]\n-             [--reuseaddr] [--detach] [--pid-file=file]\n-             [--user=user [--group=group]] [directory...]\n+\t     [--inetd | [--host=host_or_ipaddr] [--port=n] [--user=user [--group=group]]\n+\t     [directory...]\n \n DESCRIPTION\n -----------\n@@ -54,8 +55,12 @@ OPTIONS\n --interpolated-path=pathtemplate::\n \tTo support virtual hosting, an interpolated path template can be\n \tused to dynamically construct alternate paths.  The template\n-\tsupports %H for the target hostname as supplied by the client,\n-\tand %D for the absolute path of the named repository.\t\n+\tsupports %H for the target hostname as supplied by the client but\n+\tconverted to all lowercase, %CH for the canonical hostname,\n+\t%IP for the server's IP address, %P for the port number,\n+\tand %D for the absolute path of the named repository.\n+\tAfter interpolation, the path is validated against the directory\n+\twhitelist.\n \n --export-all::\n \tAllow pulling from all directories that look like GIT repositories\n@@ -64,9 +69,17 @@ OPTIONS\n \n --inetd::\n \tHave the server run as an inetd service. Implies --syslog.\n+\tIncompatible with --port, --host, --user and --group options.\n+\n+--host=host_or_ipaddr::\n+\tListen on an a specific IP address or hostname.  IP addresses can\n+\tbe either an IPv4 address or an IPV6 address if supported.  If IPv6\n+\tis not supported, then --host=hostname is also not supported and\n+\t--host must be given an IPv4 address.\n+\tIncompatible with '--inetd' option.\n \n---port::\n-\tListen on an alternative port.\n+--port=n::\n+\tListen on an alternative port.  Incompatible with '--inetd' option.\n \n --init-timeout::\n \tTimeout between the moment the connection is established and the\n@@ -182,6 +195,24 @@ clients, a symlink from `/software` into\n default repository could be made as well.\n \n \n+git-daemon as regular daemon for virtual hosts::\n+\tTo set up `git-daemon` as a regular, non-inetd service that\n+\thandles repositories for multiple virtual hosts based on\n+\ttheir IP addresses, start the daemon like this:\n++\n+------------------------------------------------\n+\tgit-daemon --verbose --export-all\n+\t\t--interpolated-path=/pub/%IP/%D\n+\t\t/pub/192.168.1.200/software\n+\t\t/pub/10.10.220.23/software\n+------------------------------------------------\n++\n+In this example, the root-level directory `/pub` will contain\n+a subdirectory for each virtual host IP address supported.\n+Repositories can still be accessed by hostname though, assuming\n+they correspond to these IP addresses.\n+\n+\n Author\n ------\n Written by Linus Torvalds <torvalds@osdl.org>, YOSHIFUJI Hideaki\ndiff --git a/Makefile b/Makefile\nindex 673ba2d..bae4822 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -520,6 +520,9 @@ endif\n ifdef NO_INET_NTOP\n \tLIB_OBJS += compat/inet_ntop.o\n endif\n+ifdef NO_INET_PTON\n+\tLIB_OBJS += compat/inet_pton.o\n+endif\n \n ifdef NO_ICONV\n \tALL_CFLAGS += -DNO_ICONV\ndiff --git a/compat/inet_pton.c b/compat/inet_pton.c\nnew file mode 100644\nindex 0000000..5704e0d\n--- /dev/null\n+++ b/compat/inet_pton.c\n@@ -0,0 +1,220 @@\n+/*\n+ * Copyright (C) 1996-2001  Internet Software Consortium.\n+ *\n+ * Permission to use, copy, modify, and distribute this software for any\n+ * purpose with or without fee is hereby granted, provided that the above\n+ * copyright notice and this permission notice appear in all copies.\n+ *\n+ * THE SOFTWARE IS PROVIDED \"AS IS\" AND INTERNET SOFTWARE CONSORTIUM\n+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL\n+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL\n+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,\n+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING\n+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,\n+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION\n+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n+ */\n+\n+#include <errno.h>\n+#include <sys/types.h>\n+#include <sys/socket.h>\n+#include <sys/socket.h>\n+#include <netinet/in.h>\n+#include <arpa/inet.h>\n+#include <stdio.h>\n+#include <string.h>\n+\n+#ifndef NS_INT16SZ\n+#define NS_INT16SZ       2\n+#endif\n+\n+#ifndef NS_INADDRSZ\n+#define NS_INADDRSZ      4\n+#endif\n+\n+#ifndef NS_IN6ADDRSZ\n+#define NS_IN6ADDRSZ    16\n+#endif\n+\n+/*\n+ * WARNING: Don't even consider trying to compile this on a system where\n+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.\n+ */\n+\n+static int inet_pton4(const char *src, unsigned char *dst);\n+static int inet_pton6(const char *src, unsigned char *dst);\n+\n+/* int\n+ * inet_pton4(src, dst)\n+ *      like inet_aton() but without all the hexadecimal and shorthand.\n+ * return:\n+ *      1 if `src' is a valid dotted quad, else 0.\n+ * notice:\n+ *      does not touch `dst' unless it's returning 1.\n+ * author:\n+ *      Paul Vixie, 1996.\n+ */\n+static int\n+inet_pton4(const char *src, unsigned char *dst)\n+{\n+        static const char digits[] = \"0123456789\";\n+        int saw_digit, octets, ch;\n+        unsigned char tmp[NS_INADDRSZ], *tp;\n+\n+        saw_digit = 0;\n+        octets = 0;\n+        *(tp = tmp) = 0;\n+        while ((ch = *src++) != '\\0') {\n+                const char *pch;\n+\n+                if ((pch = strchr(digits, ch)) != NULL) {\n+                        unsigned int new = *tp * 10 + (pch - digits);\n+\n+                        if (new > 255)\n+                                return (0);\n+                        *tp = new;\n+                        if (! saw_digit) {\n+                                if (++octets > 4)\n+                                        return (0);\n+                                saw_digit = 1;\n+                        }\n+                } else if (ch == '.' && saw_digit) {\n+                        if (octets == 4)\n+                                return (0);\n+                        *++tp = 0;\n+                        saw_digit = 0;\n+                } else\n+                        return (0);\n+        }\n+        if (octets < 4)\n+                return (0);\n+        memcpy(dst, tmp, NS_INADDRSZ);\n+        return (1);\n+}\n+\n+/* int\n+ * inet_pton6(src, dst)\n+ *      convert presentation level address to network order binary form.\n+ * return:\n+ *      1 if `src' is a valid [RFC1884 2.2] address, else 0.\n+ * notice:\n+ *      (1) does not touch `dst' unless it's returning 1.\n+ *      (2) :: in a full address is silently ignored.\n+ * credit:\n+ *      inspired by Mark Andrews.\n+ * author:\n+ *      Paul Vixie, 1996.\n+ */\n+\n+#ifndef NO_IPV6\n+static int\n+inet_pton6(const char *src, unsigned char *dst)\n+{\n+        static const char xdigits_l[] = \"0123456789abcdef\",\n+                          xdigits_u[] = \"0123456789ABCDEF\";\n+        unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;\n+        const char *xdigits, *curtok;\n+        int ch, saw_xdigit;\n+        unsigned int val;\n+\n+        memset((tp = tmp), '\\0', NS_IN6ADDRSZ);\n+        endp = tp + NS_IN6ADDRSZ;\n+        colonp = NULL;\n+        /* Leading :: requires some special handling. */\n+        if (*src == ':')\n+                if (*++src != ':')\n+                        return (0);\n+        curtok = src;\n+        saw_xdigit = 0;\n+        val = 0;\n+        while ((ch = *src++) != '\\0') {\n+                const char *pch;\n+\n+                if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)\n+                        pch = strchr((xdigits = xdigits_u), ch);\n+                if (pch != NULL) {\n+                        val <<= 4;\n+                        val |= (pch - xdigits);\n+                        if (val > 0xffff)\n+                                return (0);\n+                        saw_xdigit = 1;\n+                        continue;\n+                }\n+                if (ch == ':') {\n+                        curtok = src;\n+                        if (!saw_xdigit) {\n+                                if (colonp)\n+                                        return (0);\n+                                colonp = tp;\n+                                continue;\n+                        }\n+                        if (tp + NS_INT16SZ > endp)\n+                                return (0);\n+                        *tp++ = (unsigned char) (val >> 8) & 0xff;\n+                        *tp++ = (unsigned char) val & 0xff;\n+                        saw_xdigit = 0;\n+                        val = 0;\n+                        continue;\n+                }\n+                if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&\n+                    inet_pton4(curtok, tp) > 0) {\n+                        tp += NS_INADDRSZ;\n+                        saw_xdigit = 0;\n+                        break;  /* '\\0' was seen by inet_pton4(). */\n+                }\n+                return (0);\n+        }\n+        if (saw_xdigit) {\n+                if (tp + NS_INT16SZ > endp)\n+                        return (0);\n+                *tp++ = (unsigned char) (val >> 8) & 0xff;\n+                *tp++ = (unsigned char) val & 0xff;\n+        }\n+        if (colonp != NULL) {\n+                /*\n+                 * Since some memmove()'s erroneously fail to handle\n+                 * overlapping regions, we'll do the shift by hand.\n+                 */\n+                const int n = tp - colonp;\n+                int i;\n+\n+                for (i = 1; i <= n; i++) {\n+                        endp[- i] = colonp[n - i];\n+                        colonp[n - i] = 0;\n+                }\n+                tp = endp;\n+        }\n+        if (tp != endp)\n+                return (0);\n+        memcpy(dst, tmp, NS_IN6ADDRSZ);\n+        return (1);\n+}\n+#endif\n+\n+/* int\n+ * isc_net_pton(af, src, dst)\n+ *      convert from presentation format (which usually means ASCII printable)\n+ *      to network format (which is usually some kind of binary format).\n+ * return:\n+ *      1 if the address was valid for the specified address family\n+ *      0 if the address wasn't valid (`dst' is untouched in this case)\n+ *      -1 if some other error occurred (`dst' is untouched in this case, too)\n+ * author:\n+ *      Paul Vixie, 1996.\n+ */\n+int\n+inet_pton(int af, const char *src, void *dst)\n+{\n+        switch (af) {\n+        case AF_INET:\n+                return (inet_pton4(src, dst));\n+#ifndef NO_IPV6\n+        case AF_INET6:\n+                return (inet_pton6(src, dst));\n+#endif\n+        default:\n+                errno = EAFNOSUPPORT;\n+                return (-1);\n+        }\n+        /* NOTREACHED */\n+}\ndiff --git a/daemon.c b/daemon.c\nindex ef3a955..5f01184 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -9,6 +9,7 @@ #include <arpa/inet.h>\n #include <syslog.h>\n #include <pwd.h>\n #include <grp.h>\n+#include <limits.h>\n #include \"pkt-line.h\"\n #include \"cache.h\"\n #include \"exec_cmd.h\"\n@@ -19,13 +20,14 @@ static int verbose;\n static int reuseaddr;\n \n static const char daemon_usage[] =\n-\"git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\\n\"\n+\"git-daemon [--verbose] [--syslog] [--export-all]\\n\"\n \"           [--timeout=n] [--init-timeout=n] [--strict-paths]\\n\"\n \"           [--base-path=path] [--user-path | --user-path=path]\\n\"\n \"           [--interpolated-path=path]\\n\"\n \"           [--reuseaddr] [--detach] [--pid-file=file]\\n\"\n \"           [--[enable|disable|allow-override|forbid-override]=service]\\n\"\n-\"           [--user=user [[--group=group]] [directory...]\";\n+\"           [--inetd | [--host=host_or_ipaddr] [--port=n] [--user=user [--group=group]]\\n\"\n+\"           [directory...]\";\n \n /* List of acceptable pathname prefixes */\n static char **ok_paths;\n@@ -56,11 +58,17 @@ static unsigned int init_timeout;\n  * Feel free to make dynamic as needed.\n  */\n #define INTERP_SLOT_HOST\t(0)\n-#define INTERP_SLOT_DIR\t\t(1)\n-#define INTERP_SLOT_PERCENT\t(2)\n+#define INTERP_SLOT_CANON_HOST\t(1)\n+#define INTERP_SLOT_IP\t\t(2)\n+#define INTERP_SLOT_PORT\t(3)\n+#define INTERP_SLOT_DIR\t\t(4)\n+#define INTERP_SLOT_PERCENT\t(5)\n \n static struct interp interp_table[] = {\n \t{ \"%H\", 0},\n+\t{ \"%CH\", 0},\n+\t{ \"%IP\", 0},\n+\t{ \"%P\", 0},\n \t{ \"%D\", 0},\n \t{ \"%%\", \"%\"},\n };\n@@ -401,9 +409,17 @@ static void parse_extra_args(char *extra\n \t\t\tval = extra_args + 5;\n \t\t\tvallen = strlen(val) + 1;\n \t\t\tif (*val) {\n-\t\t\t\tchar *save = xmalloc(vallen);\n+\t\t\t\tchar *port;\n+\t\t\t\tchar *save = xmalloc(vallen);\t/* FIXME: Leak */\n+\n \t\t\t\tinterp_table[INTERP_SLOT_HOST].value = save;\n \t\t\t\tstrlcpy(save, val, vallen);\n+\t\t\t\tport = strrchr(save, ':');\n+\t\t\t\tif (port) {\n+\t\t\t\t\t*port = 0;\n+\t\t\t\t\tport++;\n+\t\t\t\t\tinterp_table[INTERP_SLOT_PORT].value = port;\n+\t\t\t\t}\n \t\t\t}\n \t\t\t/* On to the next one */\n \t\t\textra_args = val + vallen;\n@@ -411,6 +427,73 @@ static void parse_extra_args(char *extra\n \t}\n }\n \n+void fill_in_extra_table_entries(struct interp *itable)\n+{\n+\tchar *hp;\n+\tchar *canon_host = NULL;\n+\tchar *ipaddr = NULL;\n+\n+\t/*\n+\t * Replace literal host with lowercase-ized hostname.\n+\t */\n+\thp = interp_table[INTERP_SLOT_HOST].value;\n+\tfor ( ; *hp; hp++)\n+\t\t*hp = tolower(*hp);\n+\n+\t/*\n+\t * Locate canonical hostname and its IP address.\n+\t */\n+#ifndef NO_IPV6\n+\t{\n+\t\tstruct addrinfo hints;\n+\t\tstruct addrinfo *ai, *ai0;\n+\t\tint gai;\n+\t\tstatic char addrbuf[HOST_NAME_MAX + 1];\n+\n+\t\tmemset(&hints, 0, sizeof(hints));\n+\t\thints.ai_flags = AI_CANONNAME;\n+\n+\t\tgai = getaddrinfo(interp_table[INTERP_SLOT_HOST].value, 0, &hints, &ai0);\n+\t\tif (!gai) {\n+\t\t\tfor (ai = ai0; ai; ai = ai->ai_next) {\n+\t\t\t\tstruct sockaddr_in *sin_addr = (void *)ai->ai_addr;\n+\n+\t\t\t\tcanon_host = xstrdup(ai->ai_canonname);\n+\t\t\t\tinet_ntop(AF_INET, &sin_addr->sin_addr,\n+\t\t\t\t\t  addrbuf, sizeof(addrbuf));\n+\t\t\t\tipaddr = addrbuf;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tfreeaddrinfo(ai0);\n+\t\t}\n+\t}\n+#else\n+\t{\n+\t\tstruct hostent *hent;\n+\t\tstruct sockaddr_in sa;\n+\t\tchar **ap;\n+\t\tstatic char addrbuf[HOST_NAME_MAX + 1];\n+\n+\t\thent = gethostbyname(interp_table[INTERP_SLOT_HOST].value);\n+\t\tcanon_host = xstrdup(hent->h_name);\n+\n+\t\tap = hent->h_addr_list;\n+\t\tmemset(&sa, 0, sizeof sa);\n+\t\tsa.sin_family = hent->h_addrtype;\n+\t\tsa.sin_port = htons(0);\n+\t\tmemcpy(&sa.sin_addr, *ap, hent->h_length);\n+\t\t\t\n+\t\tinet_ntop(hent->h_addrtype, &sa.sin_addr,\n+\t\t\t  addrbuf, sizeof(addrbuf));\n+\t\tipaddr = addrbuf;\n+\t}\n+#endif\n+\n+\tinterp_table[INTERP_SLOT_CANON_HOST].value = canon_host;\t/* FIXME: Leak */\n+\tinterp_table[INTERP_SLOT_IP].value = xstrdup(ipaddr);\t\t/* FIXME: Leak */\n+}\n+\n+\n static int execute(struct sockaddr *addr)\n {\n \tstatic char line[1000];\n@@ -451,8 +534,10 @@ #endif\n \tif (len && line[len-1] == '\\n')\n \t\tline[--len] = 0;\n \n-\tif (len != pktlen)\n+\tif (len != pktlen) {\n \t    parse_extra_args(line + len + 1, pktlen - len - 1);\n+\t    fill_in_extra_table_entries(interp_table);\n+\t}\n \n \tfor (i = 0; i < ARRAY_SIZE(daemon_service); i++) {\n \t\tstruct daemon_service *s = &(daemon_service[i]);\n@@ -656,12 +741,11 @@ static int set_reuse_addr(int sockfd)\n \n #ifndef NO_IPV6\n \n-static int socksetup(int port, int **socklist_p)\n+static int socksetup(char *host, int port, int **socklist_p)\n {\n \tint socknum = 0, *socklist = NULL;\n \tint maxfd = -1;\n \tchar pbuf[NI_MAXSERV];\n-\n \tstruct addrinfo hints, *ai0, *ai;\n \tint gai;\n \n@@ -672,7 +756,7 @@ static int socksetup(int port, int **soc\n \thints.ai_protocol = IPPROTO_TCP;\n \thints.ai_flags = AI_PASSIVE;\n \n-\tgai = getaddrinfo(NULL, pbuf, &hints, &ai0);\n+\tgai = getaddrinfo(host, pbuf, &hints, &ai0);\n \tif (gai)\n \t\tdie(\"getaddrinfo() failed: %s\\n\", gai_strerror(gai));\n \n@@ -726,20 +810,27 @@ #endif\n \n #else /* NO_IPV6 */\n \n-static int socksetup(int port, int **socklist_p)\n+static int socksetup(char *host, int port, int **socklist_p)\n {\n \tstruct sockaddr_in sin;\n \tint sockfd;\n \n-\tsockfd = socket(AF_INET, SOCK_STREAM, 0);\n-\tif (sockfd < 0)\n-\t\treturn 0;\n-\n \tmemset(&sin, 0, sizeof sin);\n \tsin.sin_family = AF_INET;\n-\tsin.sin_addr.s_addr = htonl(INADDR_ANY);\n \tsin.sin_port = htons(port);\n \n+\tif (host) {\n+\t\t/* Well, host better be an IP address here. */\n+\t\tif (inet_pton(AF_INET, host, &sin.sin_addr.s_addr) <= 0)\n+\t\t\treturn 0;\n+\t} else {\n+\t\tsin.sin_addr.s_addr = htonl(INADDR_ANY);\n+\t}\n+\n+\tsockfd = socket(AF_INET, SOCK_STREAM, 0);\n+\tif (sockfd < 0)\n+\t\treturn 0;\n+\n \tif (set_reuse_addr(sockfd)) {\n \t\tclose(sockfd);\n \t\treturn 0;\n@@ -848,13 +939,14 @@ static void store_pid(const char *path)\n \tfclose(f);\n }\n \n-static int serve(int port, struct passwd *pass, gid_t gid)\n+static int serve(char *host, int port, struct passwd *pass, gid_t gid)\n {\n \tint socknum, *socklist;\n \n-\tsocknum = socksetup(port, &socklist);\n+\tsocknum = socksetup(host, port, &socklist);\n \tif (socknum == 0)\n-\t\tdie(\"unable to allocate any listen sockets on port %u\", port);\n+\t\tdie(\"unable to allocate any listen sockets on host %s port %u\",\n+\t\t    host, port);\n \n \tif (pass && gid &&\n \t    (initgroups(pass->pw_name, gid) || setgid (gid) ||\n@@ -866,7 +958,8 @@ static int serve(int port, struct passwd\n \n int main(int argc, char **argv)\n {\n-\tint port = DEFAULT_GIT_PORT;\n+\tint port = 0;\n+\tchar *host = NULL;\n \tint inetd_mode = 0;\n \tconst char *pid_file = NULL, *user_name = NULL, *group_name = NULL;\n \tint detach = 0;\n@@ -883,6 +976,14 @@ int main(int argc, char **argv)\n \tfor (i = 1; i < argc; i++) {\n \t\tchar *arg = argv[i];\n \n+\t\tif (!strncmp(arg, \"--host=\", 7)) {\n+\t\t    char *p = arg + 7;\n+\t\t    char *ph = host = xmalloc(strlen(arg + 7) + 1);\n+\t\t    while (*p)\n+\t\t\t*ph++ = tolower(*p++);\n+\t\t    *ph = 0;\t\t    \n+\t\t    continue;\n+\t\t}\n \t\tif (!strncmp(arg, \"--port=\", 7)) {\n \t\t\tchar *end;\n \t\t\tunsigned long n;\n@@ -988,6 +1089,11 @@ int main(int argc, char **argv)\n \tif (inetd_mode && (group_name || user_name))\n \t\tdie(\"--user and --group are incompatible with --inetd\");\n \n+\tif (inetd_mode && (port || host))\n+\t\tdie(\"--host= and --port= are incompatible with --inetd\");\n+\telse if (port == 0)\n+\t\tport = DEFAULT_GIT_PORT;\n+\n \tif (group_name && !user_name)\n \t\tdie(\"--group supplied without --user\");\n \n@@ -1036,5 +1142,5 @@ int main(int argc, char **argv)\n \tif (pid_file)\n \t\tstore_pid(pid_file);\n \n-\treturn serve(port, pass, gid);\n+\treturn serve(host, port, pass, gid);\n }\n-- \n1.4.2.1.g85d8-dirty\n"},{"id":"27649","messageId":"7vd59jw9lb.fsf@assigned-by-dhcp.cox.net","threadId":"5686","inReplyTo":"E1GRhhk-0004O6-GP@jdl.com","subject":"Re: [PATCH] Cleaned up git-daemon virtual hosting support.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-09-26T04:11:28Z","receivedAt":"2006-09-26T04:11:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"> Added --host=host_or_ipaddr option suport.\n\nI wonder if --listen= might be more appropriate name:\n\n        \"Listen a.b.c.d:port\" (Apache),\n        \"ListenAddress\" (ssh daemon).\n        \"--listen-host=\" (svnserve).\n\nI wanted to find an example or two who uses \"bind\" but I think\nlisten is more popular.\n\n> This is on top of my previous patch in the next branch.\n> This makes virtual host support way, way less stupid.\n> I'll follow up with another patch to clean up the small leaks.\n\nThanks.\n"},{"id":"27665","messageId":"4518DAF7.4050304@op5.se","threadId":"5686","inReplyTo":"7vd59jw9lb.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Cleaned up git-daemon virtual hosting support.","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2006-09-26T07:47:03Z","receivedAt":"2006-09-26T07:47:03Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Junio C Hamano wrote:\n>> Added --host=host_or_ipaddr option suport.\n> \n> I wonder if --listen= might be more appropriate name:\n> \n>         \"Listen a.b.c.d:port\" (Apache),\n>         \"ListenAddress\" (ssh daemon).\n>         \"--listen-host=\" (svnserve).\n> \n> I wanted to find an example or two who uses \"bind\" but I think\n> listen is more popular.\n> \n\nApache has both Bind and Listen (at least 1.3 series). I've never \nunderstood the difference between the two, if there is one.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"27675","messageId":"E1GSCk2-0004b4-4L@jdl.com","threadId":"5686","inReplyTo":"7vd59jw9lb.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Cleaned up git-daemon virtual hosting support.","fromName":"Jon Loeliger","fromEmail":"jdl@jdl.com","sentAt":"2006-09-26T13:12:54Z","receivedAt":"2006-09-26T13:12:54Z","isPatch":true,"sender":{"key":"jdl@jdl.com","avatar":"https://gravatar.com/avatar/75ce9a10b151acd2c28ec4ab2136dba7b2ff1634530bd04b155981a749d08a64?d=mp&s=160"},"body":"So, like, the other day Junio C Hamano mumbled:\n> > Added --host=host_or_ipaddr option suport.\n> \n> I wonder if --listen= might be more appropriate name:\n>         \"Listen a.b.c.d:port\" (Apache),\n\nNo problem.  I'll respin that to use\n\n    --listen=<ip_or_host>\n\nDo you want this?:\n\n    --listen=[<ip_or_host>][:<port>]\n\nAnd if you do, does --port= just go away, fade away, or remain?\n\nWould you prefer patch-on-patch or respin?\n\njdl\n"},{"id":"27676","messageId":"E1GSD7w-0004dP-1g@jdl.com","threadId":"5686","inReplyTo":"7vd59jw9lb.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Cleaned up git-daemon virtual hosting support.","fromName":"Jon Loeliger","fromEmail":"jdl@jdl.com","sentAt":"2006-09-26T13:37:36Z","receivedAt":"2006-09-26T13:37:36Z","isPatch":true,"sender":{"key":"jdl@jdl.com","avatar":"https://gravatar.com/avatar/75ce9a10b151acd2c28ec4ab2136dba7b2ff1634530bd04b155981a749d08a64?d=mp&s=160"},"body":"So, like, the other day Junio C Hamano mumbled:\n> > Added --host=host_or_ipaddr option suport.\n> \n> I wonder if --listen= might be more appropriate name:\n\nHmmm...   I had asked it you wanted to incorporate a \":<port>\"\nnotion into the listen address.  Turns out that is a bad idea\nsince the <host_or_ipaddr> part can also be a IPv6 address\njust riddled with colon characters.\n\nI'll just leave it \"--listen=<host_or_ipaddr>\" and \"--port=<n>\".\n\njdl\n"}]}