{"thread":{"id":"24696","subject":"[PATCH/RFC] added possibility to supply more than one --listen argument to git-daemon","startedAt":"2010-08-10T18:56:01Z","lastAt":"2010-08-10T18:56:02Z","messageCount":2,"participants":["Alexander Sulfrian"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"147669","messageId":"1281466562-28105-1-git-send-email-alexander@sulfrian.net","threadId":"24696","inReplyTo":null,"subject":"[PATCH/RFC] added possibility to supply more than one --listen argument to git-daemon","fromName":"Alexander Sulfrian","fromEmail":"alexander@sulfrian.net","sentAt":"2010-08-10T18:56:01Z","receivedAt":"2010-08-10T18:56:01Z","isPatch":true,"sender":{"key":"alexander@sulfrian.net","avatar":"https://avatars.githubusercontent.com/u/149450?v=4"},"body":"Hi list,\n\nI have written a patch to allow more than one --listen argument to the\ngit daemon. The current situation is, that the daemon silently ignores\nall --listen arguments beside the last one. So there is no possibility\nto let on server listen on many addresses without let it bind to all.\n\nEven if that is currently not a problem with ipv4 addresses, in the\nfuture that problem gets even worse. I wanted git-daemon to listen on\nan ipv4 address and an ipv6 address. That is currently not possible\nwithout running two instances. So I created that patch.\n\nWhat do you think?\n\nThanks,\nAlex\n\n\nPS: This is my first patch for git.git, so please point out if I done\n    something technically wrong.\n"},{"id":"147668","messageId":"1281466562-28105-2-git-send-email-alexander@sulfrian.net","threadId":"24696","inReplyTo":"1281466562-28105-1-git-send-email-alexander@sulfrian.net","subject":"[PATCH/RFC] added possibility to supply more than one --listen argument to git-daemon","fromName":"Alexander Sulfrian","fromEmail":"alexander@sulfrian.net","sentAt":"2010-08-10T18:56:02Z","receivedAt":"2010-08-10T18:56:02Z","isPatch":true,"sender":{"key":"alexander@sulfrian.net","avatar":"https://avatars.githubusercontent.com/u/149450?v=4"},"body":"--listen arguments are gathered in a string_list\nserve and socksetup get listen_addr as string_list\nsocketsetup creates a listen socket for each host in that string_list\n\nSigned-off-by: Alexander Sulfrian <alexander@sulfrian.net>\n---\n daemon.c |  183 ++++++++++++++++++++++++++++++++++++--------------------------\n 1 files changed, 107 insertions(+), 76 deletions(-)\n\ndiff --git a/daemon.c b/daemon.c\nindex e22a2b7..f4492fe 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -3,6 +3,7 @@\n #include \"exec_cmd.h\"\n #include \"run-command.h\"\n #include \"strbuf.h\"\n+#include \"string-list.h\"\n \n #include <syslog.h>\n \n@@ -736,7 +737,7 @@ static int set_reuse_addr(int sockfd)\n \n #ifndef NO_IPV6\n \n-static int socksetup(char *listen_addr, int listen_port, int **socklist_p)\n+static int socksetup(struct string_list *listen_addr, int listen_port, int **socklist_p)\n {\n \tint socknum = 0, *socklist = NULL;\n \tint maxfd = -1;\n@@ -744,6 +745,7 @@ static int socksetup(char *listen_addr, int listen_port, int **socklist_p)\n \tstruct addrinfo hints, *ai0, *ai;\n \tint gai;\n \tlong flags;\n+\tint i;\n \n \tsprintf(pbuf, \"%d\", listen_port);\n \tmemset(&hints, 0, sizeof(hints));\n@@ -752,57 +754,69 @@ static int socksetup(char *listen_addr, int listen_port, int **socklist_p)\n \thints.ai_protocol = IPPROTO_TCP;\n \thints.ai_flags = AI_PASSIVE;\n \n-\tgai = getaddrinfo(listen_addr, pbuf, &hints, &ai0);\n-\tif (gai)\n-\t\tdie(\"getaddrinfo() failed: %s\", gai_strerror(gai));\n+\ti = 0;\n+\tdo {\n+\t\tif (listen_addr->nr > 0) {\n+\t\t\tgai = getaddrinfo(listen_addr->items[i].string, pbuf,\n+\t\t\t\t\t  &hints, &ai0);\n+\t\t}\n+\t\telse {\n+\t\t\tgai = getaddrinfo(NULL, pbuf, &hints, &ai0);\n+\t\t}\n \n-\tfor (ai = ai0; ai; ai = ai->ai_next) {\n-\t\tint sockfd;\n+\t\tif (gai)\n+\t\t\tdie(\"getaddrinfo() failed: %s\", gai_strerror(gai));\n \n-\t\tsockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);\n-\t\tif (sockfd < 0)\n-\t\t\tcontinue;\n-\t\tif (sockfd >= FD_SETSIZE) {\n-\t\t\tlogerror(\"Socket descriptor too large\");\n-\t\t\tclose(sockfd);\n-\t\t\tcontinue;\n-\t\t}\n+\t\tfor (ai = ai0; ai; ai = ai->ai_next) {\n+\t\t\tint sockfd;\n+\n+\t\t\tsockfd = socket(ai->ai_family, ai->ai_socktype,\n+\t\t\t\t\tai->ai_protocol);\n+\t\t\tif (sockfd < 0)\n+\t\t\t\tcontinue;\n+\t\t\tif (sockfd >= FD_SETSIZE) {\n+\t\t\t\tlogerror(\"Socket descriptor too large\");\n+\t\t\t\tclose(sockfd);\n+\t\t\t\tcontinue;\n+\t\t\t}\n \n #ifdef IPV6_V6ONLY\n-\t\tif (ai->ai_family == AF_INET6) {\n-\t\t\tint on = 1;\n-\t\t\tsetsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,\n-\t\t\t\t   &on, sizeof(on));\n-\t\t\t/* Note: error is not fatal */\n-\t\t}\n+\t\t\tif (ai->ai_family == AF_INET6) {\n+\t\t\t\tint on = 1;\n+\t\t\t\tsetsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,\n+\t\t\t\t\t   &on, sizeof(on));\n+\t\t\t\t/* Note: error is not fatal */\n+\t\t\t}\n #endif\n \n-\t\tif (set_reuse_addr(sockfd)) {\n-\t\t\tclose(sockfd);\n-\t\t\tcontinue;\n-\t\t}\n+\t\t\tif (set_reuse_addr(sockfd)) {\n+\t\t\t\tclose(sockfd);\n+\t\t\t\tcontinue;\n+\t\t\t}\n \n-\t\tif (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {\n-\t\t\tclose(sockfd);\n-\t\t\tcontinue;\t/* not fatal */\n-\t\t}\n-\t\tif (listen(sockfd, 5) < 0) {\n-\t\t\tclose(sockfd);\n-\t\t\tcontinue;\t/* not fatal */\n-\t\t}\n+\t\t\tif (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {\n+\t\t\t\tclose(sockfd);\n+\t\t\t\tcontinue;\t/* not fatal */\n+\t\t\t}\n+\t\t\tif (listen(sockfd, 5) < 0) {\n+\t\t\t\tclose(sockfd);\n+\t\t\t\tcontinue;\t/* not fatal */\n+\t\t\t}\n \n-\t\tflags = fcntl(sockfd, F_GETFD, 0);\n-\t\tif (flags >= 0)\n-\t\t\tfcntl(sockfd, F_SETFD, flags | FD_CLOEXEC);\n+\t\t\tflags = fcntl(sockfd, F_GETFD, 0);\n+\t\t\tif (flags >= 0)\n+\t\t\t\tfcntl(sockfd, F_SETFD, flags | FD_CLOEXEC);\n \n-\t\tsocklist = xrealloc(socklist, sizeof(int) * (socknum + 1));\n-\t\tsocklist[socknum++] = sockfd;\n+\t\t\tsocklist = xrealloc(socklist,\n+\t\t\t\t\t    sizeof(int) * (socknum + 1));\n+\t\t\tsocklist[socknum++] = sockfd;\n \n-\t\tif (maxfd < sockfd)\n-\t\t\tmaxfd = sockfd;\n-\t}\n+\t\t\tif (maxfd < sockfd)\n+\t\t\t\tmaxfd = sockfd;\n+\t\t}\n \n-\tfreeaddrinfo(ai0);\n+\t\tfreeaddrinfo(ai0);\n+\t} while  (++i < listen_addr->nr);\n \n \t*socklist_p = socklist;\n \treturn socknum;\n@@ -810,50 +824,60 @@ static int socksetup(char *listen_addr, int listen_port, int **socklist_p)\n \n #else /* NO_IPV6 */\n \n-static int socksetup(char *listen_addr, int listen_port, int **socklist_p)\n+static int socksetup(struct string_list *listen_addr, int listen_port, int **socklist_p)\n {\n+\tint socknum = 0, *socklist = NULL;\n \tstruct sockaddr_in sin;\n \tint sockfd;\n \tlong flags;\n+\tint i;\n \n \tmemset(&sin, 0, sizeof sin);\n \tsin.sin_family = AF_INET;\n \tsin.sin_port = htons(listen_port);\n \n-\tif (listen_addr) {\n-\t\t/* Well, host better be an IP address here. */\n-\t\tif (inet_pton(AF_INET, listen_addr, &sin.sin_addr.s_addr) <= 0)\n+\ti = 0;\n+\tdo {\n+\t\tif (listen_addr->nr > 0) {\n+\t\t\t/* Well, host better be an IP address here. */\n+\t\t\tif (inet_pton(AF_INET, listen_addr->items[i].string,\n+\t\t\t\t      &sin.sin_addr.s_addr) <= 0)\n+\t\t\t\treturn 0;\n+\t\t}\n+\t\telse {\n+\t\t\tsin.sin_addr.s_addr = htonl(INADDR_ANY);\n+\t\t}\n+\n+\t\tsockfd = socket(AF_INET, SOCK_STREAM, 0);\n+\t\tif (sockfd < 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+\t\tif (set_reuse_addr(sockfd)) {\n+\t\t\tclose(sockfd);\n+\t\t\treturn 0;\n+\t\t}\n \n-\tif (set_reuse_addr(sockfd)) {\n-\t\tclose(sockfd);\n-\t\treturn 0;\n-\t}\n+\t\tif ( bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0 ) {\n+\t\t\tclose(sockfd);\n+\t\t\treturn 0;\n+\t\t}\n \n-\tif ( bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0 ) {\n-\t\tclose(sockfd);\n-\t\treturn 0;\n-\t}\n+\t\tif (listen(sockfd, 5) < 0) {\n+\t\t\tclose(sockfd);\n+\t\t\treturn 0;\n+\t\t}\n \n-\tif (listen(sockfd, 5) < 0) {\n-\t\tclose(sockfd);\n-\t\treturn 0;\n-\t}\n+\t\tflags = fcntl(sockfd, F_GETFD, 0);\n+\t\tif (flags >= 0)\n+\t\t\tfcntl(sockfd, F_SETFD, flags | FD_CLOEXEC);\n \n-\tflags = fcntl(sockfd, F_GETFD, 0);\n-\tif (flags >= 0)\n-\t\tfcntl(sockfd, F_SETFD, flags | FD_CLOEXEC);\n+\t\tsocklist = xrealloc(socklist, sizeof(int) * (socknum + 1));\n+\t\tsocklist[socknum++] = sockfd;\n \n-\t*socklist_p = xmalloc(sizeof(int));\n-\t**socklist_p = sockfd;\n-\treturn 1;\n+\t} while (++i < listen_addr->nr);\n+\n+\t*socklist_p = socklist;\n+\treturn socknum;\n }\n \n #endif\n@@ -946,14 +970,14 @@ static void store_pid(const char *path)\n \t\tdie_errno(\"failed to write pid file '%s'\", path);\n }\n \n-static int serve(char *listen_addr, int listen_port, struct passwd *pass, gid_t gid)\n+static int serve(struct string_list *listen_addr, int listen_port, struct passwd *pass, gid_t gid)\n {\n \tint socknum, *socklist;\n \n \tsocknum = socksetup(listen_addr, listen_port, &socklist);\n \tif (socknum == 0)\n-\t\tdie(\"unable to allocate any listen sockets on host %s port %u\",\n-\t\t    listen_addr, listen_port);\n+\t\tdie(\"unable to allocate any listen sockets on port %u\",\n+\t\t    listen_port);\n \n \tif (pass && gid &&\n \t    (initgroups(pass->pw_name, gid) || setgid (gid) ||\n@@ -966,14 +990,17 @@ static int serve(char *listen_addr, int listen_port, struct passwd *pass, gid_t\n int main(int argc, char **argv)\n {\n \tint listen_port = 0;\n-\tchar *listen_addr = NULL;\n \tint inetd_mode = 0;\n+\tstruct string_list listen_addr;\n \tconst char *pid_file = NULL, *user_name = NULL, *group_name = NULL;\n \tint detach = 0;\n \tstruct passwd *pass = NULL;\n \tstruct group *group;\n \tgid_t gid = 0;\n \tint i;\n+\tint return_value;\n+\n+\tmemset(&listen_addr, 0, sizeof(struct string_list));\n \n \tgit_extract_argv0_path(argv[0]);\n \n@@ -981,7 +1008,7 @@ int main(int argc, char **argv)\n \t\tchar *arg = argv[i];\n \n \t\tif (!prefixcmp(arg, \"--listen=\")) {\n-\t\t\tlisten_addr = xstrdup_tolower(arg + 9);\n+\t\t\tstring_list_append(&listen_addr, xstrdup_tolower(arg + 9));\n \t\t\tcontinue;\n \t\t}\n \t\tif (!prefixcmp(arg, \"--port=\")) {\n@@ -1106,7 +1133,7 @@ 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 && (listen_port || listen_addr))\n+\tif (inetd_mode && (listen_port || (listen_addr.nr > 0)))\n \t\tdie(\"--listen= and --port= are incompatible with --inetd\");\n \telse if (listen_port == 0)\n \t\tlisten_port = DEFAULT_GIT_PORT;\n@@ -1161,5 +1188,9 @@ int main(int argc, char **argv)\n \tif (pid_file)\n \t\tstore_pid(pid_file);\n \n-\treturn serve(listen_addr, listen_port, pass, gid);\n+\treturn_value = serve(&listen_addr, listen_port, pass, gid);\n+\n+\tstring_list_clear(&listen_addr, 0);\n+\n+\treturn return_value;\n }\n-- \n1.7.1\n"}]}