threads / patch / 22235

v2, 14 partsdaemon-win32

Subject: [PATCH v2 00/14] daemon-win32

## tl;dr

49 messages between Jan 15, 2010 and Jan 19, 2010. Diffs are folded; open one to read it.

replies: 48people: 4as markdown or json

Erik Faye-Lund· Jan 15, 2010, 21:30 UTC · lore

Here's the long overdue v2 of my daemon-win32 attempt. A lot has happened since v1. Most importantly, I abandoned using the async API to replace fork(), and went for explicitly spawning child process that handle the connection.

The patches are on top of the current version of Junio's master-branch.

When talking about patch numbers here, I'm referring to the numbers from the previous round.

Patch 1 has been adjusted to work on top of Martin's ipv6 patches.

Patch 2 has been dropped, because it was made obsolete by the changes to patch 3.

Patch 3 has been simplified as suggested by Hannes. The problem with reporting IPv6 addresses should still be there in theory, but I haven't been able to trigger it. I'm having a feeling that it's better to do a case-by-case patch of the code that reports for this one.

Patch 4 and 5 are unchanged.
Patch 6 and 7 were dropped, in favour of a new approach.
Patch 8 has been updated as suggested.

Patch 9 has been rewritten to spawn a separate child process that serves the client.

Patch 10 is unchanged
Patch 11 has been updated as suggested.

In addition, I've added a patch that add some needed support in our waitpid()-emulation, a (very limited) kill()-emulation, a patch that uses real PIDs on Windows (instead of process-local kernel-handles), a patch that changes the code to use select() instead of poll() to wait for socket-action (due to our limited poll-emulation). And there's a patch that makes sure connections are reported from the root-process.

In addition, I've attached an updated version of the getaddrinfo()-fix that Martin sent me privately. I removed Hannes sign-off (as requested by Martin, due to the update)

The branch can also be found here: http://repo.or.cz/w/git/kusma.git daemon-win32-v2

Puuuh, I hope I didn't miss anything important.
Erik Faye-Lund (10):
  inet_ntop: fix a couple of old-style decls
  mingw: support waitpid with pid > 0 and WNOHANG
  mingw: use real pid
  mingw: add kill emulation
  daemon: use explicit file descriptor
  daemon: use run-command api for async serving
  daemon: use full buffered mode for stderr
  mingw: compile git-daemon
  daemon: use select() instead of poll()
  daemon: report connection from root-process
Martin Storsjö (1):
  Improve the mingw getaddrinfo stub to handle more use cases
Mike Pape (3):
  mingw: add network-wrappers for daemon
  mingw: implement syslog
  compat: add inet_pton and inet_ntop prototypes
 Makefile           |   10 +-
 compat/inet_ntop.c |   22 ++----
 compat/inet_pton.c |    8 +-
 compat/mingw.c     |  141 +++++++++++++++++++++++++++++--
 compat/mingw.h     |   80 +++++++++++++++++-
 daemon.c           |  236 ++++++++++++++++++++++++++++------------------------
 git-compat-util.h  |    9 ++
 7 files changed, 361 insertions(+), 145 deletions(-)
Erik Faye-Lund· Jan 15, 2010, 21:30 UTC · re: Erik Faye-Lund · lore

[PATCH v2 01/14] mingw: add network-wrappers for daemon

From: Mike Pape <dotzenlabs@gmail.com>

git-daemon requires some socket-functionality that is not yet supported in the Windows-port. This patch adds said functionality, and makes sure WSAStartup gets called by socket(), since it is the first network-call in git-daemon. In addition, a check is added to prevent WSAStartup (and WSACleanup, though atexit) from being called more than once, since git-daemon calls both socket() and gethostbyname().

Signed-off-by: Mike Pape <dotzenlabs@gmail.com>
Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>
---
 compat/mingw.c |   43 ++++++++++++++++++++++++++++++++++++++++++-
 compat/mingw.h |   16 ++++++++++++++++
 2 files changed, 58 insertions(+), 1 deletions(-)
Show changes to 2 files +58 −1

compat/mingw.c, compat/mingw.h

diff --git a/compat/mingw.c b/compat/mingw.c
index 0d73f15..42ef9e2 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1095,7 +1095,10 @@ int mingw_getnameinfo(const struct sockaddr *sa, socklen_t salen,
 int mingw_socket(int domain, int type, int protocol)
 {
 	int sockfd;
-	SOCKET s = WSASocket(domain, type, protocol, NULL, 0, 0);
+	SOCKET s;
+
+	ensure_socket_initialization();
+	s = WSASocket(domain, type, protocol, NULL, 0, 0);
 	if (s == INVALID_SOCKET) {
 		/*
 		 * WSAGetLastError() values are regular BSD error codes
@@ -1125,6 +1128,44 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
 	return connect(s, sa, sz);
 }
 
+#undef bind
+int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
+{
+	SOCKET s = (SOCKET)_get_osfhandle(sockfd);
+	return bind(s, sa, sz);
+}
+
+#undef setsockopt
+int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
+{
+	SOCKET s = (SOCKET)_get_osfhandle(sockfd);
+	return setsockopt(s, lvl, optname, (const char*)optval, optlen);
+}
+
+#undef listen
+int mingw_listen(int sockfd, int backlog)
+{
+	SOCKET s = (SOCKET)_get_osfhandle(sockfd);
+	return listen(s, backlog);
+}
+
+#undef accept
+int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
+{
+	int sockfd2;
+
+	SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
+	SOCKET s2 = accept(s1, sa, sz);
+
+	/* convert into a file descriptor */
+	if ((sockfd2 = _open_osfhandle(s2, O_RDWR|O_BINARY)) < 0) {
+		closesocket(s2);
+		return error("unable to make a socket file descriptor: %s",
+			strerror(errno));
+	}
+	return sockfd2;
+}
+
 #undef rename
 int mingw_rename(const char *pold, const char *pnew)
 {
diff --git a/compat/mingw.h b/compat/mingw.h
index b3d299f..07513bb 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -6,6 +6,7 @@
  */
 
 typedef int pid_t;
+typedef int socklen_t;
 #define hstrerror strerror
 
 #define S_IFLNK    0120000 /* Symbolic link */
@@ -34,6 +35,9 @@ typedef int pid_t;
 #define F_SETFD 2
 #define FD_CLOEXEC 0x1
 
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#define ECONNABORTED WSAECONNABORTED
+
 struct passwd {
 	char *pw_name;
 	char *pw_gecos;
@@ -197,6 +201,18 @@ int mingw_socket(int domain, int type, int protocol);
 int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz);
 #define connect mingw_connect
 
+int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz);
+#define bind mingw_bind
+
+int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen);
+#define setsockopt mingw_setsockopt
+
+int mingw_listen(int sockfd, int backlog);
+#define listen mingw_listen
+
+int mingw_accept(int sockfd, struct sockaddr *sa, socklen_t *sz);
+#define accept mingw_accept
+
 int mingw_rename(const char*, const char*);
 #define rename mingw_rename
 
-- 
1.6.6.211.g26720
Erik Faye-Lund· Jan 15, 2010, 21:30 UTC · re: Erik Faye-Lund · lore

[PATCH v2 02/14] mingw: implement syslog

From: Mike Pape <dotzenlabs@gmail.com>

Syslog does not usually exist on Windows, so we implement our own using Window's ReportEvent mechanism.

Signed-off-by: Mike Pape <dotzenlabs@gmail.com>
Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>
---
 compat/mingw.c    |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
 compat/mingw.h    |   15 +++++++++++++++
 daemon.c          |    2 --
 git-compat-util.h |    1 +
 4 files changed, 65 insertions(+), 2 deletions(-)
Show changes to 4 files +65 −2

compat/mingw.c, compat/mingw.h, daemon.c, git-compat-util.h

diff --git a/compat/mingw.c b/compat/mingw.c
index 42ef9e2..54be905 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1351,6 +1351,55 @@ int sigaction(int sig, struct sigaction *in, struct sigaction *out)
 	return 0;
 }
 
+static HANDLE ms_eventlog;
+
+void openlog(const char *ident, int logopt, int facility)
+{
+	if (ms_eventlog)
+		return;
+	ms_eventlog = RegisterEventSourceA(NULL, ident);
+}
+
+void syslog(int priority, const char *fmt, const char *arg)
+{
+	WORD logtype;
+
+	if (strcmp(fmt, "%s")) {
+		warning("format string of syslog() not implemented");
+		return;
+	}
+
+	switch (priority) {
+		case LOG_EMERG:
+		case LOG_ALERT:
+		case LOG_CRIT:
+		case LOG_ERR:
+			logtype = EVENTLOG_ERROR_TYPE;
+			break;
+
+		case LOG_WARNING:
+			logtype = EVENTLOG_WARNING_TYPE;
+			break;
+
+		case LOG_NOTICE:
+		case LOG_INFO:
+		case LOG_DEBUG:
+		default:
+			logtype = EVENTLOG_INFORMATION_TYPE;
+			break;
+	}
+
+	ReportEventA(ms_eventlog,
+	    logtype,
+	    0,
+	    0,
+	    NULL,
+	    1,
+	    0,
+	    (const char **)&arg,
+	    NULL);
+}
+
 #undef signal
 sig_handler_t mingw_signal(int sig, sig_handler_t handler)
 {
diff --git a/compat/mingw.h b/compat/mingw.h
index 07513bb..d934e56 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -38,6 +38,19 @@ typedef int socklen_t;
 #define EAFNOSUPPORT WSAEAFNOSUPPORT
 #define ECONNABORTED WSAECONNABORTED
 
+#define LOG_PID     0x01
+
+#define LOG_EMERG   0
+#define LOG_ALERT   1
+#define LOG_CRIT    2
+#define LOG_ERR     3
+#define LOG_WARNING 4
+#define LOG_NOTICE  5
+#define LOG_INFO    6
+#define LOG_DEBUG   7
+
+#define LOG_DAEMON  (3<<3)
+
 struct passwd {
 	char *pw_name;
 	char *pw_gecos;
@@ -166,6 +179,8 @@ struct passwd *getpwuid(int uid);
 int setitimer(int type, struct itimerval *in, struct itimerval *out);
 int sigaction(int sig, struct sigaction *in, struct sigaction *out);
 int link(const char *oldpath, const char *newpath);
+void openlog(const char *ident, int logopt, int facility);
+void syslog(int priority, const char *fmt, const char *arg);
 
 /*
  * replacements of existing functions
diff --git a/daemon.c b/daemon.c
index 918e560..79ba1aa 100644
--- a/daemon.c
+++ b/daemon.c
@@ -4,8 +4,6 @@
 #include "run-command.h"
 #include "strbuf.h"
 
-#include <syslog.h>
-
 #ifndef HOST_NAME_MAX
 #define HOST_NAME_MAX 256
 #endif
diff --git a/git-compat-util.h b/git-compat-util.h
index 5c59687..30e6240 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -105,6 +105,7 @@
 #include <netdb.h>
 #include <pwd.h>
 #include <inttypes.h>
+#include <syslog.h>
 #if defined(__CYGWIN__)
 #undef _XOPEN_SOURCE
 #include <grp.h>
-- 
1.6.6.211.g26720
Janos Laube· Jan 15, 2010, 22:57 UTC · re: Erik Faye-Lund · lore

Re: [msysGit] [PATCH v2 02/14] mingw: implement syslog

Show 8 quoted lines
> +static HANDLE ms_eventlog;
> +
> +void openlog(const char *ident, int logopt, int facility)
> +{
> +       if (ms_eventlog)
> +               return;
> +       ms_eventlog = RegisterEventSourceA(NULL, ident);
> +}

maybe make ms_eventlog thread local? for example:

static __thread HANDLE ms_eventlog;
this would break compilation with msvc tho.
janos
Erik Faye-Lund· Jan 15, 2010, 23:01 UTC · re: Janos Laube · lore

Re: [msysGit] [PATCH v2 02/14] mingw: implement syslog

On Fri, Jan 15, 2010 at 11:57 PM, Janos Laube <janos.dev@gmail.com> wrote:
Show 18 quoted lines
>> +static HANDLE ms_eventlog;
>> +
>> +void openlog(const char *ident, int logopt, int facility)
>> +{
>> +       if (ms_eventlog)
>> +               return;
>> +       ms_eventlog = RegisterEventSourceA(NULL, ident);
>> +}
>
> maybe make ms_eventlog thread local?
> for example:
>
> static __thread HANDLE ms_eventlog;
>
> this would break compilation with msvc tho.
>
> janos
>

Since the code that use it isn't multi-threaded, I fail to see the point. In fact even if it were, I'm not sure I see the big point... especially since the "__thread"-keyword isn't used (AFAICT) at all in the git source code so far.

-- 
Erik "kusma" Faye-Lund
Janos Laube· Jan 15, 2010, 23:09 UTC · re: Erik Faye-Lund · lore

Re: [msysGit] [PATCH v2 02/14] mingw: implement syslog

> Since the code that use it isn't multi-threaded, I fail to see the
> point. In fact even if it were, I'm not sure I see the big point...
> especially since the "__thread"-keyword isn't used (AFAICT) at all in
> the git source code so far.

that's why i have put a question mark behind my sentence. it was just an idea :-). it would allow different threads to be an own event source. but yes, i wasn't sure how much git makes use of threads. if it doesn't, it does not make much sense at the moment, indeed.

janos
Erik Faye-Lund· Jan 15, 2010, 21:30 UTC · re: Erik Faye-Lund · lore

[PATCH v2 03/14] compat: add inet_pton and inet_ntop prototypes

From: Mike Pape <dotzenlabs@gmail.com>

Windows doesn't have inet_pton and inet_ntop, so add prototypes in git-compat-util.h for them.

At the same time include git-compat-util.h in the sources for these functions, so they use the network-wrappers from there on Windows.

Signed-off-by: Mike Pape <dotzenlabs@gmail.com>
Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>
---
 Makefile           |    2 ++
 compat/inet_ntop.c |    6 +++---
 compat/inet_pton.c |    8 +++++---
 git-compat-util.h  |    8 ++++++++
 4 files changed, 18 insertions(+), 6 deletions(-)
Show changes to 4 files +18 −6

Makefile, compat/inet_ntop.c, compat/inet_pton.c, git-compat-util.h

diff --git a/Makefile b/Makefile
index ebaa75c..d81b392 100644
--- a/Makefile
+++ b/Makefile
@@ -1289,9 +1289,11 @@ endif
 endif
 ifdef NO_INET_NTOP
 	LIB_OBJS += compat/inet_ntop.o
+	BASIC_CFLAGS += -DNO_INET_NTOP
 endif
 ifdef NO_INET_PTON
 	LIB_OBJS += compat/inet_pton.o
+	BASIC_CFLAGS += -DNO_INET_PTON
 endif
 
 ifdef NO_ICONV
diff --git a/compat/inet_ntop.c b/compat/inet_ntop.c
index f444982..e5b46a0 100644
--- a/compat/inet_ntop.c
+++ b/compat/inet_ntop.c
@@ -17,9 +17,9 @@
 
 #include <errno.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
+
+#include "../git-compat-util.h"
+
 #include <stdio.h>
 #include <string.h>
 
diff --git a/compat/inet_pton.c b/compat/inet_pton.c
index 4078fc0..2ec995e 100644
--- a/compat/inet_pton.c
+++ b/compat/inet_pton.c
@@ -17,9 +17,9 @@
 
 #include <errno.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
+
+#include "../git-compat-util.h"
+
 #include <stdio.h>
 #include <string.h>
 
@@ -41,7 +41,9 @@
  */
 
 static int inet_pton4(const char *src, unsigned char *dst);
+#ifndef NO_IPV6
 static int inet_pton6(const char *src, unsigned char *dst);
+#endif
 
 /* int
  * inet_pton4(src, dst)
diff --git a/git-compat-util.h b/git-compat-util.h
index 30e6240..937fb1b 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -341,6 +341,14 @@ static inline char *gitstrchrnul(const char *s, int c)
 }
 #endif
 
+#ifdef NO_INET_PTON
+int inet_pton(int af, const char *src, void *dst);
+#endif
+
+#ifdef NO_INET_NTOP
+const char *inet_ntop(int af, const void *src, char *dst, size_t size);
+#endif
+
 extern void release_pack_memory(size_t, int);
 
 extern char *xstrdup(const char *str);
-- 
1.6.6.211.g26720
Erik Faye-Lund· Jan 15, 2010, 21:30 UTC · re: Erik Faye-Lund · lore

[PATCH v2 04/14] inet_ntop: fix a couple of old-style decls

Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>
---
 compat/inet_ntop.c |   16 +++-------------
 1 files changed, 3 insertions(+), 13 deletions(-)
Show changes to compat/inet_ntop.c +3 −13
diff --git a/compat/inet_ntop.c b/compat/inet_ntop.c
index e5b46a0..ea249c6 100644
--- a/compat/inet_ntop.c
+++ b/compat/inet_ntop.c
@@ -50,10 +50,7 @@
  *	Paul Vixie, 1996.
  */
 static const char *
-inet_ntop4(src, dst, size)
-	const u_char *src;
-	char *dst;
-	size_t size;
+inet_ntop4(const u_char *src, char *dst, size_t size)
 {
 	static const char fmt[] = "%u.%u.%u.%u";
 	char tmp[sizeof "255.255.255.255"];
@@ -78,10 +75,7 @@ inet_ntop4(src, dst, size)
  *	Paul Vixie, 1996.
  */
 static const char *
-inet_ntop6(src, dst, size)
-	const u_char *src;
-	char *dst;
-	size_t size;
+inet_ntop6(const u_char *src, char *dst, size_t size)
 {
 	/*
 	 * Note that int32_t and int16_t need only be "at least" large enough
@@ -178,11 +172,7 @@ inet_ntop6(src, dst, size)
  *	Paul Vixie, 1996.
  */
 const char *
-inet_ntop(af, src, dst, size)
-	int af;
-	const void *src;
-	char *dst;
-	size_t size;
+inet_ntop(int af, const void *src, char *dst, size_t size)
 {
 	switch (af) {
 	case AF_INET:
-- 
1.6.6.211.g26720
Erik Faye-Lund· Jan 15, 2010, 21:30 UTC · re: Erik Faye-Lund · lore

[PATCH v2 05/14] mingw: support waitpid with pid > 0 and WNOHANG

Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>
---
 compat/mingw.h |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)
Show changes to compat/mingw.h +7 −0
diff --git a/compat/mingw.h b/compat/mingw.h
index d934e56..3005472 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -134,8 +134,15 @@ static inline int mingw_unlink(const char *pathname)
 }
 #define unlink mingw_unlink
 
+#define WNOHANG 1
 static inline int waitpid(pid_t pid, int *status, unsigned options)
 {
+	if (pid > 0 && options & WNOHANG) {
+		if (WAIT_OBJECT_0 != WaitForSingleObject((HANDLE)pid, 0))
+			return 0;
+		options &= ~WNOHANG;
+	}
+
 	if (options == 0)
 		return _cwait(status, pid, 0);
 	errno = EINVAL;
-- 
1.6.6.211.g26720
Johannes Sixt· Jan 15, 2010, 22:28 UTC · re: Erik Faye-Lund · lore

Re: [PATCH v2 05/14] mingw: support waitpid with pid > 0 and WNOHANG

On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
Show 11 quoted lines
>  static inline int waitpid(pid_t pid, int *status, unsigned options)
>  {
> +	if (pid > 0 && options & WNOHANG) {
> +		if (WAIT_OBJECT_0 != WaitForSingleObject((HANDLE)pid, 0))
> +			return 0;
> +		options &= ~WNOHANG;
> +	}
> +
>  	if (options == 0)
>  		return _cwait(status, pid, 0);
>  	errno = EINVAL;

With this change, and in particular the one in the next patch, this function grows too large to be 'static inline'.

-- Hannes
Erik Faye-Lund· Jan 16, 2010, 21:57 UTC · re: Johannes Sixt · lore

Re: [PATCH v2 05/14] mingw: support waitpid with pid > 0 and WNOHANG

On Fri, Jan 15, 2010 at 11:28 PM, Johannes Sixt <j6t@kdbg.org> wrote:
Show 18 quoted lines
> On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
>>  static inline int waitpid(pid_t pid, int *status, unsigned options)
>>  {
>> +     if (pid > 0 && options & WNOHANG) {
>> +             if (WAIT_OBJECT_0 != WaitForSingleObject((HANDLE)pid, 0))
>> +                     return 0;
>> +             options &= ~WNOHANG;
>> +     }
>> +
>>       if (options == 0)
>>               return _cwait(status, pid, 0);
>>       errno = EINVAL;
>
> With this change, and in particular the one in the next patch, this function
> grows too large to be 'static inline'.
>
> -- Hannes
>
Fixed locally.
-- 
Erik "kusma" Faye-Lund
Erik Faye-Lund· Jan 15, 2010, 21:30 UTC · re: Erik Faye-Lund · lore

[PATCH v2 06/14] mingw: use real pid

The Windows port so far used process handles as PID. However, this does not work consistently with getpid.

Change the code to use the real PID, and use OpenProcess to get a process-handle.

Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>
---
 compat/mingw.c |    2 +-
 compat/mingw.h |   35 +++++++++++++++++++++++++++++++----
 2 files changed, 32 insertions(+), 5 deletions(-)
Show changes to 2 files +32 −5

compat/mingw.c, compat/mingw.h

diff --git a/compat/mingw.c b/compat/mingw.c
index 54be905..ce4f829 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -729,7 +729,7 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
 		return -1;
 	}
 	CloseHandle(pi.hThread);
-	return (pid_t)pi.hProcess;
+	return (pid_t)pi.dwProcessId;
 }
 
 pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env)
diff --git a/compat/mingw.h b/compat/mingw.h
index 3005472..ff4a76b 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -137,14 +137,41 @@ static inline int mingw_unlink(const char *pathname)
 #define WNOHANG 1
 static inline int waitpid(pid_t pid, int *status, unsigned options)
 {
-	if (pid > 0 && options & WNOHANG) {
-		if (WAIT_OBJECT_0 != WaitForSingleObject((HANDLE)pid, 0))
+	HANDLE h;
+
+	if (pid <= 0) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid);
+	if (!h) {
+		errno = ECHILD;
+		return -1;
+	}
+
+	if (options & WNOHANG) {
+		if (WaitForSingleObject(h, 0) != WAIT_OBJECT_0) {
+			CloseHandle(h);
 			return 0;
+		}
 		options &= ~WNOHANG;
 	}
 
-	if (options == 0)
-		return _cwait(status, pid, 0);
+	if (options == 0) {
+		if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) {
+			CloseHandle(h);
+			return 0;
+		}
+
+		if (status)
+			GetExitCodeProcess(h, (LPDWORD)status);
+
+		CloseHandle(h);
+		return pid;
+	}
+	CloseHandle(h);
+
 	errno = EINVAL;
 	return -1;
 }
-- 
1.6.6.211.g26720
Johannes Sixt· Jan 15, 2010, 22:30 UTC · re: Erik Faye-Lund · lore

Re: [PATCH v2 06/14] mingw: use real pid

On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
Show 7 quoted lines
> @@ -729,7 +729,7 @@ static pid_t mingw_spawnve(const char *cmd, const char
> **argv, char **env, return -1;
>  	}
>  	CloseHandle(pi.hThread);
> -	return (pid_t)pi.hProcess;
> +	return (pid_t)pi.dwProcessId;
>  }
You are not using the pi.hProcess anymore, so you must close it.
-- Hannes
Erik Faye-Lund· Jan 15, 2010, 22:53 UTC · re: Johannes Sixt · lore

Re: [PATCH v2 06/14] mingw: use real pid

On Fri, Jan 15, 2010 at 11:30 PM, Johannes Sixt <j6t@kdbg.org> wrote:
Show 11 quoted lines
> On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
>> @@ -729,7 +729,7 @@ static pid_t mingw_spawnve(const char *cmd, const char
>> **argv, char **env, return -1;
>>       }
>>       CloseHandle(pi.hThread);
>> -     return (pid_t)pi.hProcess;
>> +     return (pid_t)pi.dwProcessId;
>>  }
>
> You are not using the pi.hProcess anymore, so you must close it.
>

No. If I do, the pid becomes invalid after the process is finished, and waitpid won't work. I couldn't find anywhere were we actually were closing the handle, even after it was finished. So I don't think we leak any more than we already did (for non-daemon purposes).

-- 
Erik "kusma" Faye-Lund
Johannes Sixt· Jan 16, 2010, 08:03 UTC · re: Erik Faye-Lund · lore

Re: [PATCH v2 06/14] mingw: use real pid

On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
Show 16 quoted lines
> On Fri, Jan 15, 2010 at 11:30 PM, Johannes Sixt <j6t@kdbg.org> wrote:
> > On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
> >> @@ -729,7 +729,7 @@ static pid_t mingw_spawnve(const char *cmd, const
> >> char **argv, char **env, return -1;
> >>       }
> >>       CloseHandle(pi.hThread);
> >> -     return (pid_t)pi.hProcess;
> >> +     return (pid_t)pi.dwProcessId;
> >>  }
> >
> > You are not using the pi.hProcess anymore, so you must close it.
>
> No. If I do, the pid becomes invalid after the process is finished,
> and waitpid won't work. I couldn't find anywhere were we actually were
> closing the handle, even after it was finished. So I don't think we
> leak any more than we already did (for non-daemon purposes).

Previously, this handle was closed by _cwait() (it was the "pid"), so we didn't leak it.

I somehow thought that you need the process ID instead of the handle for TerminateProcess, but now I see that this is not the case (it takes the handle). So I don't see the point of this change anymore. You say the process handle "does not work consistently with getpid", but I don't know what you mean. Please explain.

-- Hannes
Erik Faye-Lund· Jan 16, 2010, 09:12 UTC · re: Johannes Sixt · lore

Re: [PATCH v2 06/14] mingw: use real pid

On Sat, Jan 16, 2010 at 9:03 AM, Johannes Sixt <j6t@kdbg.org> wrote:
Show 20 quoted lines
> On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
>> On Fri, Jan 15, 2010 at 11:30 PM, Johannes Sixt <j6t@kdbg.org> wrote:
>> > On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
>> >> @@ -729,7 +729,7 @@ static pid_t mingw_spawnve(const char *cmd, const
>> >> char **argv, char **env, return -1;
>> >>       }
>> >>       CloseHandle(pi.hThread);
>> >> -     return (pid_t)pi.hProcess;
>> >> +     return (pid_t)pi.dwProcessId;
>> >>  }
>> >
>> > You are not using the pi.hProcess anymore, so you must close it.
>>
>> No. If I do, the pid becomes invalid after the process is finished,
>> and waitpid won't work. I couldn't find anywhere were we actually were
>> closing the handle, even after it was finished. So I don't think we
>> leak any more than we already did (for non-daemon purposes).
>
> Previously, this handle was closed by _cwait() (it was the "pid"), so we
> didn't leak it.

Oh, I see. My planned route with this (before I looked for where the handle was closed), was to maintain some sort of list of each started PID and their handle, and lookup in that list instead of using OpenProcess. I guess that would solve the problem here, but it feels a bit nasty. Not as nasty as introducing a leak, though.

Show 6 quoted lines
>
> I somehow thought that you need the process ID instead of the handle for
> TerminateProcess, but now I see that this is not the case (it takes the
> handle). So I don't see the point of this change anymore. You say the process
> handle "does not work consistently with getpid", but I don't know what you
> mean. Please explain.

getpid() returns the real PID, and is used for prefixing each logged message by git-daemon. However, the root process reports whenever a new process is started or has terminated using the PID returned by mingw_spawnve(), and this handle does not match up with the PID that getpid() reports. Thus it becomes impossible to tell which reported error belongs to which client.

-- 
Erik "kusma" Faye-Lund
Erik Faye-Lund· Jan 18, 2010, 22:33 UTC · re: Erik Faye-Lund · lore

Re: [PATCH v2 06/14] mingw: use real pid

On Sat, Jan 16, 2010 at 10:12 AM, Erik Faye-Lund <kusmabite@googlemail.com> wrote:

Show 28 quoted lines
> On Sat, Jan 16, 2010 at 9:03 AM, Johannes Sixt <j6t@kdbg.org> wrote:
>> On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
>>> On Fri, Jan 15, 2010 at 11:30 PM, Johannes Sixt <j6t@kdbg.org> wrote:
>>> > On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
>>> >> @@ -729,7 +729,7 @@ static pid_t mingw_spawnve(const char *cmd, const
>>> >> char **argv, char **env, return -1;
>>> >>       }
>>> >>       CloseHandle(pi.hThread);
>>> >> -     return (pid_t)pi.hProcess;
>>> >> +     return (pid_t)pi.dwProcessId;
>>> >>  }
>>> >
>>> > You are not using the pi.hProcess anymore, so you must close it.
>>>
>>> No. If I do, the pid becomes invalid after the process is finished,
>>> and waitpid won't work. I couldn't find anywhere were we actually were
>>> closing the handle, even after it was finished. So I don't think we
>>> leak any more than we already did (for non-daemon purposes).
>>
>> Previously, this handle was closed by _cwait() (it was the "pid"), so we
>> didn't leak it.
>
> Oh, I see. My planned route with this (before I looked for where the
> handle was closed), was to maintain some sort of list of each started
> PID and their handle, and lookup in that list instead of using
> OpenProcess. I guess that would solve the problem here, but it feels a
> bit nasty. Not as nasty as introducing a leak, though.
>
What I had in mind was something along these lines:
Show changes to compat/mingw.c +28 −0
diff --git a/compat/mingw.c b/compat/mingw.c
index e2821b3..71201d0 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -638,6 +638,13 @@ static int env_compare(const void *a, const void *b)
 	return strcasecmp(*ea, *eb);
 }

+struct pid_info {
+	pid_t pid;
+	HANDLE proc;
+};
+static struct pid_info *pinfo;
+static int num_pinfo;
+
 static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
 			   int prepend_cmd)
 {
@@ -729,6 +736,13 @@ static pid_t mingw_spawnve(const char *cmd, const
char **argv, char **env,
 		return -1;
 	}
 	CloseHandle(pi.hThread);
+
+	/* store process handle */
+	num_pinfo++;
+	pinfo = xrealloc(pinfo, sizeof(struct pid_info) * num_pinfo);
+	pinfo[num_pinfo - 1].pid = pi.dwProcessId;
+	pinfo[num_pinfo - 1].proc = pi.hProcess;
+
 	return (pid_t)pi.dwProcessId;
 }

@@ -1536,6 +1550,7 @@ int waitpid(pid_t pid, int *status, unsigned options)
 	}

 	if (options == 0) {
+		int i;
 		if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) {
 			CloseHandle(h);
 			return 0;
@@ -1544,6 +1559,19 @@ int waitpid(pid_t pid, int *status, unsigned options)
 		if (status)
 			GetExitCodeProcess(h, (LPDWORD)status);

+		for (i = 0; i < num_pinfo; ++i)
+			if (pinfo[i].pid == pid)
+				break;
+
+		if (i < num_pinfo) {
+			CloseHandle(pinfo[i].proc);
+			memmove(pinfo + i, pinfo + i + 1,
+			    sizeof(struct pid_info) * (num_pinfo - i - 1));
+			num_pinfo--;
+			pinfo = xrealloc(pinfo,
+			    sizeof(struct pid_info) * num_pinfo);
+		}
+
 		CloseHandle(h);
 		return pid;
 	}
-- 
Erik "kusma" Faye-Lund
Johannes Sixt· Jan 19, 2010, 18:19 UTC · re: Erik Faye-Lund · lore

Re: [PATCH v2 06/14] mingw: use real pid

On Montag, 18. Januar 2010, Erik Faye-Lund wrote:
Show 18 quoted lines
> On Sat, Jan 16, 2010 at 10:12 AM, Erik Faye-Lund wrote:
> > On Sat, Jan 16, 2010 at 9:03 AM, Johannes Sixt <j6t@kdbg.org> wrote:
> >> On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
> >>> No. If I do, the pid becomes invalid after the process is finished,
> >>> and waitpid won't work. I couldn't find anywhere were we actually were
> >>> closing the handle, even after it was finished. So I don't think we
> >>> leak any more than we already did (for non-daemon purposes).
> >>
> >> Previously, this handle was closed by _cwait() (it was the "pid"), so we
> >> didn't leak it.
> >
> > Oh, I see. My planned route with this (before I looked for where the
> > handle was closed), was to maintain some sort of list of each started
> > PID and their handle, and lookup in that list instead of using
> > OpenProcess. I guess that would solve the problem here, but it feels a
> > bit nasty. Not as nasty as introducing a leak, though.
>
> What I had in mind was something along these lines:

Given that that the process ID is the user-visible (and system-wide unique) identifier of a process, this looks like the only reasonable way to go. Your implementation looks good as well.

> +	/* store process handle */
	/*
	 * The process ID is the human-readable identifier of the process
	 * that we want to present in log and error messages. The handle
	 * is not useful for this purpose. But we cannot close it, either,
	 * because it is not possible to turn a process ID into a process
	 * handle after the process terminated.
	 * Keep the handle in a list for waitpid.
	 */
Show 6 quoted lines
> +	num_pinfo++;
> +	pinfo = xrealloc(pinfo, sizeof(struct pid_info) * num_pinfo);
> +	pinfo[num_pinfo - 1].pid = pi.dwProcessId;
> +	pinfo[num_pinfo - 1].proc = pi.hProcess;
> +
>  	return (pid_t)pi.dwProcessId;
-- Hannes
Erik Faye-Lund· Jan 19, 2010, 19:23 UTC · re: Johannes Sixt · lore

Re: [PATCH v2 06/14] mingw: use real pid

On Tue, Jan 19, 2010 at 7:19 PM, Johannes Sixt <j6t@kdbg.org> wrote:
Show 35 quoted lines
> On Montag, 18. Januar 2010, Erik Faye-Lund wrote:
>> On Sat, Jan 16, 2010 at 10:12 AM, Erik Faye-Lund wrote:
>> > On Sat, Jan 16, 2010 at 9:03 AM, Johannes Sixt <j6t@kdbg.org> wrote:
>> >> On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
>> >>> No. If I do, the pid becomes invalid after the process is finished,
>> >>> and waitpid won't work. I couldn't find anywhere were we actually were
>> >>> closing the handle, even after it was finished. So I don't think we
>> >>> leak any more than we already did (for non-daemon purposes).
>> >>
>> >> Previously, this handle was closed by _cwait() (it was the "pid"), so we
>> >> didn't leak it.
>> >
>> > Oh, I see. My planned route with this (before I looked for where the
>> > handle was closed), was to maintain some sort of list of each started
>> > PID and their handle, and lookup in that list instead of using
>> > OpenProcess. I guess that would solve the problem here, but it feels a
>> > bit nasty. Not as nasty as introducing a leak, though.
>>
>> What I had in mind was something along these lines:
>
> Given that that the process ID is the user-visible (and system-wide unique)
> identifier of a process, this looks like the only reasonable way to go. Your
> implementation looks good as well.
>
>> +     /* store process handle */
>
>        /*
>         * The process ID is the human-readable identifier of the process
>         * that we want to present in log and error messages. The handle
>         * is not useful for this purpose. But we cannot close it, either,
>         * because it is not possible to turn a process ID into a process
>         * handle after the process terminated.
>         * Keep the handle in a list for waitpid.
>         */
>
Much better, thanks.
-- 
Erik "kusma" Faye-Lund
Erik Faye-Lund· Jan 15, 2010, 21:30 UTC · re: Erik Faye-Lund · lore

[PATCH v2 07/14] mingw: add kill emulation

This is a quite limited kill-emulation; it can only handle SIGTERM on positive pids. However, it's enough for git-daemon.

Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>
---
 compat/mingw.c |   19 +++++++++++++++++++
 compat/mingw.h |    3 +++
 2 files changed, 22 insertions(+), 0 deletions(-)
Show changes to 2 files +22 −0

compat/mingw.c, compat/mingw.h

diff --git a/compat/mingw.c b/compat/mingw.c
index ce4f829..89b9b89 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -829,6 +829,25 @@ void mingw_execvp(const char *cmd, char *const *argv)
 	free_path_split(path);
 }
 
+int mingw_kill(pid_t pid, int sig)
+{
+	if (pid > 0 && sig == SIGTERM) {
+		HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
+
+		if (TerminateProcess(h, -1)) {
+			CloseHandle(h);
+			return 0;
+		}
+
+		CloseHandle(h);
+		errno = err_win_to_posix(GetLastError());
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
 static char **copy_environ(void)
 {
 	char **env;
diff --git a/compat/mingw.h b/compat/mingw.h
index ff4a76b..e72c2ee 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -176,6 +176,9 @@ static inline int waitpid(pid_t pid, int *status, unsigned options)
 	return -1;
 }
 
+#define kill mingw_kill
+int mingw_kill(pid_t pid, int sig);
+
 #ifndef NO_OPENSSL
 #include <openssl/ssl.h>
 static inline int mingw_SSL_set_fd(SSL *ssl, int fd)
-- 
1.6.6.211.g26720
Johannes Sixt· Jan 15, 2010, 22:31 UTC · re: Erik Faye-Lund · lore

Re: [PATCH v2 07/14] mingw: add kill emulation

On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
Show 5 quoted lines
> +int mingw_kill(pid_t pid, int sig)
> +{
> ...
> +		CloseHandle(h);
> +		errno = err_win_to_posix(GetLastError());
Set errno before CloseHandle() to get the correct error.
-- Hannes
Erik Faye-Lund· Jan 16, 2010, 21:56 UTC · re: Johannes Sixt · lore

Re: [PATCH v2 07/14] mingw: add kill emulation

On Fri, Jan 15, 2010 at 11:31 PM, Johannes Sixt <j6t@kdbg.org> wrote:
Show 11 quoted lines
> On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
>> +int mingw_kill(pid_t pid, int sig)
>> +{
>> ...
>> +             CloseHandle(h);
>> +             errno = err_win_to_posix(GetLastError());
>
> Set errno before CloseHandle() to get the correct error.
>
> -- Hannes
>
Thanks for pointing that out. Corrected locally.
-- 
Erik "kusma" Faye-Lund
Erik Faye-Lund· Jan 15, 2010, 21:30 UTC · re: Erik Faye-Lund · lore

[PATCH v2 08/14] daemon: use explicit file descriptor

This patch adds support to specify an explicit file descriotor for communication with the client, instead of using stdin/stdout.

This will be useful for the Windows port, because it will use threads instead of fork() to serve multiple clients, making it impossible to reuse stdin/stdout.

Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>
---
 daemon.c |   43 +++++++++++++++++++++----------------------
 1 files changed, 21 insertions(+), 22 deletions(-)
Show changes to daemon.c +21 −22
diff --git a/daemon.c b/daemon.c
index 79ba1aa..b42792f 100644
--- a/daemon.c
+++ b/daemon.c
@@ -218,7 +218,7 @@ static char *path_ok(char *directory)
 	return NULL;		/* Fallthrough. Deny by default */
 }
 
-typedef int (*daemon_service_fn)(void);
+typedef int (*daemon_service_fn)(int [2]);
 struct daemon_service {
 	const char *name;
 	const char *config_name;
@@ -242,7 +242,7 @@ static int git_daemon_config(const char *var, const char *value, void *cb)
 	return 0;
 }
 
-static int run_service(char *dir, struct daemon_service *service)
+static int run_service(int fd[2], char *dir, struct daemon_service *service)
 {
 	const char *path;
 	int enabled = service->enabled;
@@ -295,7 +295,7 @@ static int run_service(char *dir, struct daemon_service *service)
 	 */
 	signal(SIGTERM, SIG_IGN);
 
-	return service->fn();
+	return service->fn(fd);
 }
 
 static void copy_to_log(int fd)
@@ -319,7 +319,7 @@ static void copy_to_log(int fd)
 	fclose(fp);
 }
 
-static int run_service_command(const char **argv)
+static int run_service_command(int fd[2], const char **argv)
 {
 	struct child_process cld;
 
@@ -327,37 +327,36 @@ static int run_service_command(const char **argv)
 	cld.argv = argv;
 	cld.git_cmd = 1;
 	cld.err = -1;
+	cld.in = fd[0];
+	cld.out = fd[1];
 	if (start_command(&cld))
 		return -1;
 
-	close(0);
-	close(1);
-
 	copy_to_log(cld.err);
 
 	return finish_command(&cld);
 }
 
-static int upload_pack(void)
+static int upload_pack(int fd[2])
 {
 	/* Timeout as string */
 	char timeout_buf[64];
 	const char *argv[] = { "upload-pack", "--strict", timeout_buf, ".", NULL };
 
 	snprintf(timeout_buf, sizeof timeout_buf, "--timeout=%u", timeout);
-	return run_service_command(argv);
+	return run_service_command(fd, argv);
 }
 
-static int upload_archive(void)
+static int upload_archive(int fd[2])
 {
 	static const char *argv[] = { "upload-archive", ".", NULL };
-	return run_service_command(argv);
+	return run_service_command(fd, argv);
 }
 
-static int receive_pack(void)
+static int receive_pack(int fd[2])
 {
 	static const char *argv[] = { "receive-pack", ".", NULL };
-	return run_service_command(argv);
+	return run_service_command(fd, argv);
 }
 
 static struct daemon_service daemon_service[] = {
@@ -487,7 +486,7 @@ static void parse_host_arg(char *extra_args, int buflen)
 }
 
 
-static int execute(struct sockaddr *addr)
+static int execute(int fd[2], struct sockaddr *addr)
 {
 	static char line[1000];
 	int pktlen, len, i;
@@ -520,7 +519,7 @@ static int execute(struct sockaddr *addr)
 	}
 
 	alarm(init_timeout ? init_timeout : timeout);
-	pktlen = packet_read_line(0, line, sizeof(line));
+	pktlen = packet_read_line(fd[0], line, sizeof(line));
 	alarm(0);
 
 	len = strlen(line);
@@ -552,7 +551,7 @@ static int execute(struct sockaddr *addr)
 			 * Note: The directory here is probably context sensitive,
 			 * and might depend on the actual service being performed.
 			 */
-			return run_service(line + namelen + 5, s);
+			return run_service(fd, line + namelen + 5, s);
 		}
 	}
 
@@ -652,6 +651,7 @@ static void check_dead_children(void)
 
 static void handle(int incoming, struct sockaddr *addr, int addrlen)
 {
+	int fd[2];
 	pid_t pid;
 
 	if (max_connections && live_children >= max_connections) {
@@ -676,11 +676,9 @@ static void handle(int incoming, struct sockaddr *addr, int addrlen)
 		return;
 	}
 
-	dup2(incoming, 0);
-	dup2(incoming, 1);
-	close(incoming);
-
-	exit(execute(addr));
+	fd[0] = incoming;
+	fd[1] = dup(incoming);
+	exit(execute(fd, addr));
 }
 
 static void child_handler(int signo)
@@ -1107,6 +1105,7 @@ int main(int argc, char **argv)
 		    base_path);
 
 	if (inetd_mode) {
+		int fd[2] = { 0, 1 };
 		struct sockaddr_storage ss;
 		struct sockaddr *peer = (struct sockaddr *)&ss;
 		socklen_t slen = sizeof(ss);
@@ -1117,7 +1116,7 @@ int main(int argc, char **argv)
 		if (getpeername(0, peer, &slen))
 			peer = NULL;
 
-		return execute(peer);
+		return execute(fd, peer);
 	}
 
 	if (detach) {
-- 
1.6.6.211.g26720
Johannes Sixt· Jan 15, 2010, 22:36 UTC · re: Erik Faye-Lund · lore

Re: [PATCH v2 08/14] daemon: use explicit file descriptor

On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
Show 7 quoted lines
> This patch adds support to specify an explicit file
> descriotor for communication with the client, instead
> of using stdin/stdout.
>
> This will be useful for the Windows port, because it
> will use threads instead of fork() to serve multiple
> clients, making it impossible to reuse stdin/stdout.
This statement is a bit outdated.
-- Hannes
Erik Faye-Lund· Jan 16, 2010, 21:52 UTC · re: Johannes Sixt · lore

Re: [PATCH v2 08/14] daemon: use explicit file descriptor

On Fri, Jan 15, 2010 at 11:36 PM, Johannes Sixt <j6t@kdbg.org> wrote:
Show 13 quoted lines
> On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
>> This patch adds support to specify an explicit file
>> descriotor for communication with the client, instead
>> of using stdin/stdout.
>>
>> This will be useful for the Windows port, because it
>> will use threads instead of fork() to serve multiple
>> clients, making it impossible to reuse stdin/stdout.
>
> This statement is a bit outdated.
>
> -- Hannes
>
Heh, yeah. I apparently missed that this patch isn't needed at all any more.
Thanks for noticing something was off :)
-- 
Erik "kusma" Faye-Lund
Erik Faye-Lund· Jan 15, 2010, 21:30 UTC · re: Erik Faye-Lund · lore

[PATCH v2 09/14] 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. Conveniently enough, we have an API for async operation already.

Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>
---
 daemon.c |   87 +++++++++++++++++++++++++++++++------------------------------
 1 files changed, 44 insertions(+), 43 deletions(-)
Show changes to daemon.c +44 −43
diff --git a/daemon.c b/daemon.c
index b42792f..2d63cbc 100644
--- a/daemon.c
+++ b/daemon.c
@@ -583,17 +583,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))
@@ -602,19 +602,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".
@@ -623,14 +610,14 @@ static void remove_child(pid_t pid)
  */
 static void kill_some_child(void)
 {
-	const struct child *blanket, *next;
+	struct child *blanket, *next;
 
 	if (!(blanket = firstborn))
 		return;
 
 	for (; (next = blanket->next); blanket = next)
 		if (!addrcmp(&blanket->address, &next->address)) {
-			kill(blanket->pid, SIGTERM);
+			kill(blanket->cld.pid, SIGTERM);
 			break;
 		}
 }
@@ -640,19 +627,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;
 }
 
+char **cld_argv;
 static void handle(int incoming, struct sockaddr *addr, int addrlen)
 {
-	int fd[2];
-	pid_t pid;
+	struct child_process cld = { 0 };
 
 	if (max_connections && live_children >= max_connections) {
 		kill_some_child();
@@ -665,20 +659,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);
 
-	fd[0] = incoming;
-	fd[1] = dup(incoming);
-	exit(execute(fd, addr));
+	if (start_command(&cld))
+		logerror("unable to fork");
+	else
+		add_child(&cld, addr, addrlen);
+	close(incoming);
 }
 
 static void child_handler(int signo)
@@ -934,7 +923,7 @@ int main(int argc, char **argv)
 {
 	int listen_port = 0;
 	char *listen_addr = NULL;
-	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;
@@ -960,7 +949,12 @@ int main(int argc, char **argv)
 				continue;
 			}
 		}
+		if (!strcmp(arg, "--serve")) {
+			serve_mode = 1;
+			continue;
+		}
 		if (!strcmp(arg, "--inetd")) {
+			serve_mode = 1;
 			inetd_mode = 1;
 			log_syslog = 1;
 			continue;
@@ -1104,13 +1098,13 @@ int main(int argc, char **argv)
 		die("base-path '%s' does not exist or is not a directory",
 		    base_path);
 
-	if (inetd_mode) {
+	if (serve_mode) {
 		int fd[2] = { 0, 1 };
 		struct sockaddr_storage ss;
 		struct sockaddr *peer = (struct sockaddr *)&ss;
 		socklen_t slen = sizeof(ss);
 
-		if (!freopen("/dev/null", "w", stderr))
+		if (inetd_mode && !freopen("/dev/null", "w", stderr))
 			die_errno("failed to redirect stderr to /dev/null");
 
 		if (getpeername(0, peer, &slen))
@@ -1129,5 +1123,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);
 }
-- 
1.6.6.211.g26720
Johannes Sixt· Jan 15, 2010, 22:42 UTC · re: Erik Faye-Lund · lore

Re: [PATCH v2 09/14] daemon: use run-command api for async serving

On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
> fork() is only available on POSIX, so to support git-daemon
> on Windows we have to use something else. Conveniently
> enough, we have an API for async operation already.

I had a huh?-moment when I read this statement. This patch does not use what we call 'async', but start_command().

-- Hannes
Erik Faye-Lund· Jan 15, 2010, 21:30 UTC · re: Erik Faye-Lund · lore

[PATCH v2 10/14] daemon: use full buffered mode for stderr

Windows doesn't support line buffered mode for file streams, so let's just use full buffered mode with a big buffer ("4096 should be enough for everyone") and add explicit flushing.

Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>
---
 daemon.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
Show changes to daemon.c +4 −2
diff --git a/daemon.c b/daemon.c
index 2d63cbc..fc2c150 100644
--- a/daemon.c
+++ b/daemon.c
@@ -66,12 +66,14 @@ static void logreport(int priority, const char *err, va_list params)
 		syslog(priority, "%s", buf);
 	} else {
 		/*
-		 * Since stderr is set to linebuffered mode, the
+		 * Since stderr is set to buffered mode, the
 		 * logging of different processes will not overlap
+		 * unless they overflow the (rather big) buffers.
 		 */
 		fprintf(stderr, "[%"PRIuMAX"] ", (uintmax_t)getpid());
 		vfprintf(stderr, err, params);
 		fputc('\n', stderr);
+		fflush(stderr);
 	}
 }
 
@@ -1062,7 +1064,7 @@ int main(int argc, char **argv)
 		set_die_routine(daemon_die);
 	} else
 		/* avoid splitting a message in the middle */
-		setvbuf(stderr, NULL, _IOLBF, 0);
+		setvbuf(stderr, NULL, _IOFBF, 4096);
 
 	if (inetd_mode && (group_name || user_name))
 		die("--user and --group are incompatible with --inetd");
-- 
1.6.6.211.g26720
Erik Faye-Lund· Jan 15, 2010, 21:30 UTC · re: Erik Faye-Lund · lore

[PATCH v2 11/14] mingw: compile git-daemon

--user and --detach are disabled on Windows due to lack of fork(), setuid(), setgid(), setsid() and initgroups().

Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>
---
 Makefile       |    8 +++-----
 compat/mingw.h |    1 +
 daemon.c       |   19 ++++++++++++++-----
 3 files changed, 18 insertions(+), 10 deletions(-)
Show changes to 3 files +18 −10

Makefile, compat/mingw.h, daemon.c

diff --git a/Makefile b/Makefile
index d81b392..cb6c36d 100644
--- a/Makefile
+++ b/Makefile
@@ -390,6 +390,7 @@ EXTRA_PROGRAMS =
 
 # ... and all the rest that could be moved out of bindir to gitexecdir
 PROGRAMS += $(EXTRA_PROGRAMS)
+PROGRAMS += git-daemon$X
 PROGRAMS += git-fast-import$X
 PROGRAMS += git-hash-object$X
 PROGRAMS += git-imap-send$X
@@ -986,7 +987,6 @@ ifeq ($(uname_S),Windows)
 	NO_SVN_TESTS = YesPlease
 	NO_PERL_MAKEMAKER = YesPlease
 	RUNTIME_PREFIX = YesPlease
-	NO_POSIX_ONLY_PROGRAMS = YesPlease
 	NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
 	NO_NSEC = YesPlease
 	USE_WIN32_MMAP = YesPlease
@@ -1037,7 +1037,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_SVN_TESTS = YesPlease
 	NO_PERL_MAKEMAKER = YesPlease
 	RUNTIME_PREFIX = YesPlease
-	NO_POSIX_ONLY_PROGRAMS = YesPlease
 	NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
 	NO_NSEC = YesPlease
 	USE_WIN32_MMAP = YesPlease
@@ -1047,6 +1046,8 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_REGEX = YesPlease
 	BLK_SHA1 = YesPlease
 	NO_PYTHON = YesPlease
+	NO_INET_PTON = YesPlease
+	NO_INET_NTOP = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o
@@ -1141,9 +1142,6 @@ ifdef ZLIB_PATH
 endif
 EXTLIBS += -lz
 
-ifndef NO_POSIX_ONLY_PROGRAMS
-	PROGRAMS += git-daemon$X
-endif
 ifndef NO_OPENSSL
 	OPENSSL_LIBSSL = -lssl
 	ifdef OPENSSLDIR
diff --git a/compat/mingw.h b/compat/mingw.h
index e72c2ee..173bec5 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -7,6 +7,7 @@
 
 typedef int pid_t;
 typedef int socklen_t;
+typedef unsigned int gid_t;
 #define hstrerror strerror
 
 #define S_IFLNK    0120000 /* Symbolic link */
diff --git a/daemon.c b/daemon.c
index fc2c150..cdf5c72 100644
--- a/daemon.c
+++ b/daemon.c
@@ -589,7 +589,7 @@ static struct child {
 	struct sockaddr_storage address;
 } *firstborn;
 
-static void add_child(struct child_process *cld, struct sockaddr *addr, int addrlen)
+static void add_child(struct child_process *cld, struct sockaddr *addr, socklen_t addrlen)
 {
 	struct child *newborn, **cradle;
 
@@ -646,7 +646,7 @@ static void check_dead_children(void)
 }
 
 char **cld_argv;
-static void handle(int incoming, struct sockaddr *addr, int addrlen)
+static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
 {
 	struct child_process cld = { 0 };
 
@@ -847,7 +847,7 @@ static int service_loop(int socknum, int *socklist)
 		for (i = 0; i < socknum; i++) {
 			if (pfd[i].revents & POLLIN) {
 				struct sockaddr_storage ss;
-				unsigned int sslen = sizeof(ss);
+				socklen_t sslen = sizeof(ss);
 				int incoming = accept(pfd[i].fd, (struct sockaddr *)&ss, &sslen);
 				if (incoming < 0) {
 					switch (errno) {
@@ -879,6 +879,7 @@ static void sanitize_stdfds(void)
 
 static void daemonize(void)
 {
+#ifndef WIN32
 	switch (fork()) {
 		case 0:
 			break;
@@ -893,6 +894,9 @@ static void daemonize(void)
 	close(1);
 	close(2);
 	sanitize_stdfds();
+#else
+	die("--detach is not supported on Windows");
+#endif
 }
 
 static void store_pid(const char *path)
@@ -913,10 +917,12 @@ static int serve(char *listen_addr, int listen_port, struct passwd *pass, gid_t
 		die("unable to allocate any listen sockets on host %s port %u",
 		    listen_addr, listen_port);
 
+#ifndef WIN32
 	if (pass && gid &&
 	    (initgroups(pass->pw_name, gid) || setgid (gid) ||
 	     setuid(pass->pw_uid)))
 		die("cannot drop privileges");
+#endif
 
 	return service_loop(socknum, socklist);
 }
@@ -929,7 +935,6 @@ int main(int argc, char **argv)
 	const char *pid_file = NULL, *user_name = NULL, *group_name = NULL;
 	int detach = 0;
 	struct passwd *pass = NULL;
-	struct group *group;
 	gid_t gid = 0;
 	int i;
 
@@ -1078,6 +1083,7 @@ int main(int argc, char **argv)
 		die("--group supplied without --user");
 
 	if (user_name) {
+#ifndef WIN32
 		pass = getpwnam(user_name);
 		if (!pass)
 			die("user not found - %s", user_name);
@@ -1085,12 +1091,15 @@ int main(int argc, char **argv)
 		if (!group_name)
 			gid = pass->pw_gid;
 		else {
-			group = getgrnam(group_name);
+			struct group *group = getgrnam(group_name);
 			if (!group)
 				die("group not found - %s", group_name);
 
 			gid = group->gr_gid;
 		}
+#else
+		die("--user is not supported on Windows");
+#endif
 	}
 
 	if (strict_paths && (!ok_paths || !*ok_paths))
-- 
1.6.6.211.g26720
Erik Faye-Lund· Jan 15, 2010, 21:30 UTC · re: Erik Faye-Lund · lore

[PATCH v2 12/14] Improve the mingw getaddrinfo stub to handle more use cases

From: Martin Storsjö <martin@martin.st>

Allow the node parameter to be null, which is used for getting the default bind address.

Also allow the hints parameter to be null, to improve standard conformance of the stub implementation a little.

Signed-off-by: Martin Storsjo <martin@martin.st>
---
 compat/mingw.c |   28 +++++++++++++++++++++-------
 1 files changed, 21 insertions(+), 7 deletions(-)
Show changes to compat/mingw.c +21 −7
diff --git a/compat/mingw.c b/compat/mingw.c
index 89b9b89..02d411a 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -932,19 +932,22 @@ static int WSAAPI getaddrinfo_stub(const char *node, const char *service,
 				   const struct addrinfo *hints,
 				   struct addrinfo **res)
 {
-	struct hostent *h = gethostbyname(node);
+	struct hostent *h = NULL;
 	struct addrinfo *ai;
 	struct sockaddr_in *sin;
 
-	if (!h)
-		return WSAGetLastError();
+	if (node) {
+		h = gethostbyname(node);
+		if (!h)
+			return WSAGetLastError();
+	}
 
 	ai = xmalloc(sizeof(struct addrinfo));
 	*res = ai;
 	ai->ai_flags = 0;
 	ai->ai_family = AF_INET;
-	ai->ai_socktype = hints->ai_socktype;
-	switch (hints->ai_socktype) {
+	ai->ai_socktype = hints ? hints->ai_socktype : 0;
+	switch (ai->ai_socktype) {
 	case SOCK_STREAM:
 		ai->ai_protocol = IPPROTO_TCP;
 		break;
@@ -956,14 +959,25 @@ static int WSAAPI getaddrinfo_stub(const char *node, const char *service,
 		break;
 	}
 	ai->ai_addrlen = sizeof(struct sockaddr_in);
-	ai->ai_canonname = strdup(h->h_name);
+	if (hints && (hints->ai_flags & AI_CANONNAME))
+		ai->ai_canonname = h ? strdup(h->h_name) : NULL;
+	else
+		ai->ai_canonname = NULL;
 
 	sin = xmalloc(ai->ai_addrlen);
 	memset(sin, 0, ai->ai_addrlen);
 	sin->sin_family = AF_INET;
+	/* Note: getaddrinfo is supposed to allow service to be a string,
+	 * which should be looked up using getservbyname. This is
+	 * currently not implemented */
 	if (service)
 		sin->sin_port = htons(atoi(service));
-	sin->sin_addr = *(struct in_addr *)h->h_addr;
+	if (h)
+		sin->sin_addr = *(struct in_addr *)h->h_addr;
+	else if (hints && (hints->ai_flags & AI_PASSIVE))
+		sin->sin_addr.s_addr = INADDR_ANY;
+	else
+		sin->sin_addr.s_addr = INADDR_LOOPBACK;
 	ai->ai_addr = (struct sockaddr *)sin;
 	ai->ai_next = 0;
 	return 0;
-- 
1.6.6.211.g26720
Erik Faye-Lund· Jan 15, 2010, 21:30 UTC · re: Erik Faye-Lund · lore

[PATCH v2 13/14] daemon: use select() instead of poll()

Windows doesn't have poll(), and the poll-emulation in compat/mingw.c doesn't support checking multiple sockets.

Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>
---
 compat/mingw.h |    7 +++++++
 daemon.c       |   27 ++++++++++++---------------
 2 files changed, 19 insertions(+), 15 deletions(-)
Show changes to 2 files +19 −15

compat/mingw.h, daemon.c

diff --git a/compat/mingw.h b/compat/mingw.h
index 173bec5..e515726 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -269,6 +269,13 @@ int mingw_accept(int sockfd, struct sockaddr *sa, socklen_t *sz);
 int mingw_rename(const char*, const char*);
 #define rename mingw_rename
 
+#undef FD_SET
+#define FD_SET(fd, set) do { \
+	((fd_set*)(set))->fd_array[((fd_set *)(set))->fd_count++] = _get_osfhandle(fd); \
+	} while(0)
+#undef FD_ISSET
+#define FD_ISSET(fd, set) __WSAFDIsSet(_get_osfhandle(fd), (fd_set *)(set))
+
 #if defined(USE_WIN32_MMAP) || defined(_MSC_VER)
 int mingw_getpagesize(void);
 #define getpagesize mingw_getpagesize
diff --git a/daemon.c b/daemon.c
index cdf5c72..95cf299 100644
--- a/daemon.c
+++ b/daemon.c
@@ -818,26 +818,23 @@ static int socksetup(char *listen_addr, int listen_port, int **socklist_p)
 
 static int service_loop(int socknum, int *socklist)
 {
-	struct pollfd *pfd;
-	int i;
-
-	pfd = xcalloc(socknum, sizeof(struct pollfd));
-
-	for (i = 0; i < socknum; i++) {
-		pfd[i].fd = socklist[i];
-		pfd[i].events = POLLIN;
-	}
-
 	signal(SIGCHLD, child_handler);
 
 	for (;;) {
-		int i;
+		int i, maxfd = 0;
+		fd_set fds;
 
 		check_dead_children();
 
-		if (poll(pfd, socknum, -1) < 0) {
+		FD_ZERO(&fds);
+		for (i = 0; i < socknum; i++) {
+			FD_SET(socklist[i], &fds);
+			maxfd = socklist[i] > maxfd ? socklist[i] : maxfd;
+		}
+
+		if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 0) {
 			if (errno != EINTR) {
-				logerror("Poll failed, resuming: %s",
+				logerror("select() failed, resuming: %s",
 				      strerror(errno));
 				sleep(1);
 			}
@@ -845,10 +842,10 @@ static int service_loop(int socknum, int *socklist)
 		}
 
 		for (i = 0; i < socknum; i++) {
-			if (pfd[i].revents & POLLIN) {
+			if (FD_ISSET(socklist[i], &fds)) {
 				struct sockaddr_storage ss;
 				socklen_t sslen = sizeof(ss);
-				int incoming = accept(pfd[i].fd, (struct sockaddr *)&ss, &sslen);
+				int incoming = accept(socklist[i], (struct sockaddr *)&ss, &sslen);
 				if (incoming < 0) {
 					switch (errno) {
 					case EAGAIN:
-- 
1.6.6.211.g26720
Johannes Sixt· Jan 15, 2010, 22:49 UTC · re: Erik Faye-Lund · lore

Re: [PATCH v2 13/14] daemon: use select() instead of poll()

On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
Show 7 quoted lines
> +#undef FD_SET
> +#define FD_SET(fd, set) do { \
> +	((fd_set*)(set))->fd_array[((fd_set *)(set))->fd_count++] =
> _get_osfhandle(fd); \ +	} while(0)
> +#undef FD_ISSET
> +#define FD_ISSET(fd, set) __WSAFDIsSet(_get_osfhandle(fd), (fd_set
> *)(set)) +

I'm worried about the internals that you have to use here. Isn't it possible save the original macro text and use it in the new definition, like (this is for exposition only):

#define ORIG_FD_SET(fd, set) FD_SET(fd, set) #undef FD_SET #define FD_SET(fd, set) ORIG_FD_SET(_get_osfhandle(fd), set)

Another approach would be to extend the poll emulation such that it uses select if all FDs to wait for are sockets, and I think this would be the case in this application.

-- Hannes
Erik Faye-Lund· Jan 15, 2010, 23:08 UTC · re: Johannes Sixt · lore

Re: [PATCH v2 13/14] daemon: use select() instead of poll()

On Fri, Jan 15, 2010 at 11:49 PM, Johannes Sixt <j6t@kdbg.org> wrote:
Show 17 quoted lines
> On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
>> +#undef FD_SET
>> +#define FD_SET(fd, set) do { \
>> +     ((fd_set*)(set))->fd_array[((fd_set *)(set))->fd_count++] =
>> _get_osfhandle(fd); \ +       } while(0)
>> +#undef FD_ISSET
>> +#define FD_ISSET(fd, set) __WSAFDIsSet(_get_osfhandle(fd), (fd_set
>> *)(set)) +
>
> I'm worried about the internals that you have to use here. Isn't it possible
> save the original macro text and use it in the new definition, like (this is
> for exposition only):
>
> #define ORIG_FD_SET(fd, set) FD_SET(fd, set)
> #undef FD_SET
> #define FD_SET(fd, set) ORIG_FD_SET(_get_osfhandle(fd), set)
>

Redefining it is indeed fishy - I guess I should also have noted that I even stripped the code down slightly (compared to the original).

I'm no preprocessor wizard, but I'll give it a stab.
> Another approach would be to extend the poll emulation such that it uses
> select if all FDs to wait for are sockets, and I think this would be the case
> in this application.
>

The problem with that is differentiating between pipes and sockets. GetFileType() returns FILE_TYPE_PIPE for sockets (ugh). I did find some code in gnulib that used WSAEnumNetworkEvents() to differentiate between them, but I find this quite hacky.

-- 
Erik "kusma" Faye-Lund
Erik Faye-Lund· Jan 15, 2010, 23:23 UTC · re: Erik Faye-Lund · lore

Re: [PATCH v2 13/14] daemon: use select() instead of poll()

On Sat, Jan 16, 2010 at 12:08 AM, Erik Faye-Lund <kusmabite@googlemail.com> wrote:

Show 24 quoted lines
> On Fri, Jan 15, 2010 at 11:49 PM, Johannes Sixt <j6t@kdbg.org> wrote:
>> On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
>>> +#undef FD_SET
>>> +#define FD_SET(fd, set) do { \
>>> +     ((fd_set*)(set))->fd_array[((fd_set *)(set))->fd_count++] =
>>> _get_osfhandle(fd); \ +       } while(0)
>>> +#undef FD_ISSET
>>> +#define FD_ISSET(fd, set) __WSAFDIsSet(_get_osfhandle(fd), (fd_set
>>> *)(set)) +
>>
>> I'm worried about the internals that you have to use here. Isn't it possible
>> save the original macro text and use it in the new definition, like (this is
>> for exposition only):
>>
>> #define ORIG_FD_SET(fd, set) FD_SET(fd, set)
>> #undef FD_SET
>> #define FD_SET(fd, set) ORIG_FD_SET(_get_osfhandle(fd), set)
>>
>
> Redefining it is indeed fishy - I guess I should also have noted that
> I even stripped the code down slightly (compared to the original).
>
> I'm no preprocessor wizard, but I'll give it a stab.
>
The following worked for me:
Show changes to compat/mingw.h +6 −3
diff --git a/compat/mingw.h b/compat/mingw.h
index e515726..ea15967 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -269,10 +269,13 @@ int mingw_accept(int sockfd, struct sockaddr
*sa, socklen_t *sz);
 int mingw_rename(const char*, const char*);
 #define rename mingw_rename

+static inline void mingw_fd_set(int fd, fd_set *set)
+{
+	FD_SET(_get_osfhandle(fd), set);
+}
 #undef FD_SET
-#define FD_SET(fd, set) do { \
-	((fd_set*)(set))->fd_array[((fd_set *)(set))->fd_count++] =
_get_osfhandle(fd); \
-	} while(0)
+#define FD_SET(a,b) mingw_fd_set(a,b)
+
 #undef FD_ISSET
 #define FD_ISSET(fd, set) __WSAFDIsSet(_get_osfhandle(fd), (fd_set *)(set))
-- 
Erik "kusma" Faye-Lund
Johannes Sixt· Jan 16, 2010, 08:06 UTC · re: Erik Faye-Lund · lore

Re: [PATCH v2 13/14] daemon: use select() instead of poll()

On Samstag, 16. Januar 2010, Erik Faye-Lund wrote:
Show 10 quoted lines
> +static inline void mingw_fd_set(int fd, fd_set *set)
> +{
> +	FD_SET(_get_osfhandle(fd), set);
> +}
>  #undef FD_SET
> +#define FD_SET(a,b) mingw_fd_set(a,b)
> +
>  #undef FD_ISSET
>  #define FD_ISSET(fd, set) __WSAFDIsSet(_get_osfhandle(fd), (fd_set
> *)(set))

Ah, yes, how obvious ;) You are going to do the same with FD_ISSET as well, aren't you?

-- Hannes
Erik Faye-Lund· Jan 16, 2010, 09:26 UTC · re: Johannes Sixt · lore

Re: [PATCH v2 13/14] daemon: use select() instead of poll()

On Sat, Jan 16, 2010 at 9:06 AM, Johannes Sixt <j6t@kdbg.org> wrote:
Show 17 quoted lines
> On Samstag, 16. Januar 2010, Erik Faye-Lund wrote:
>> +static inline void mingw_fd_set(int fd, fd_set *set)
>> +{
>> +     FD_SET(_get_osfhandle(fd), set);
>> +}
>>  #undef FD_SET
>> +#define FD_SET(a,b) mingw_fd_set(a,b)
>> +
>>  #undef FD_ISSET
>>  #define FD_ISSET(fd, set) __WSAFDIsSet(_get_osfhandle(fd), (fd_set
>> *)(set))
>
> Ah, yes, how obvious ;) You are going to do the same with FD_ISSET as well,
> aren't you?
>
> -- Hannes
>

Do I really need to? There's already a single function for that, with no "ugly hidden internals" there; __WSAFDIsSet() is documented in MSDN. I mean, Sure... I could... I just don't see the point.

-- 
Erik "kusma" Faye-Lund
Johannes Sixt· Jan 16, 2010, 10:38 UTC · re: Erik Faye-Lund · lore

Re: [PATCH v2 13/14] daemon: use select() instead of poll()

On Samstag, 16. Januar 2010, Erik Faye-Lund wrote:
Show 19 quoted lines
> On Sat, Jan 16, 2010 at 9:06 AM, Johannes Sixt <j6t@kdbg.org> wrote:
> > On Samstag, 16. Januar 2010, Erik Faye-Lund wrote:
> >> +static inline void mingw_fd_set(int fd, fd_set *set)
> >> +{
> >> +     FD_SET(_get_osfhandle(fd), set);
> >> +}
> >>  #undef FD_SET
> >> +#define FD_SET(a,b) mingw_fd_set(a,b)
> >> +
> >>  #undef FD_ISSET
> >>  #define FD_ISSET(fd, set) __WSAFDIsSet(_get_osfhandle(fd), (fd_set
> >> *)(set))
> >
> > Ah, yes, how obvious ;) You are going to do the same with FD_ISSET as
> > well, aren't you?
>
> Do I really need to? There's already a single function for that, with
> no "ugly hidden internals" there; __WSAFDIsSet() is documented in
> MSDN. I mean, Sure... I could... I just don't see the point.

__WSAFDIsSet is "ugly hidden internals" and we should not rely on it when we can use the official FD_ISSET for our own FD_ISSET.

-- Hannes
Erik Faye-Lund· Jan 16, 2010, 11:05 UTC · re: Johannes Sixt · lore

Re: [PATCH v2 13/14] daemon: use select() instead of poll()

On Sat, Jan 16, 2010 at 11:38 AM, Johannes Sixt <j6t@kdbg.org> wrote:
Show 26 quoted lines
> On Samstag, 16. Januar 2010, Erik Faye-Lund wrote:
>> On Sat, Jan 16, 2010 at 9:06 AM, Johannes Sixt <j6t@kdbg.org> wrote:
>> > On Samstag, 16. Januar 2010, Erik Faye-Lund wrote:
>> >> +static inline void mingw_fd_set(int fd, fd_set *set)
>> >> +{
>> >> +     FD_SET(_get_osfhandle(fd), set);
>> >> +}
>> >>  #undef FD_SET
>> >> +#define FD_SET(a,b) mingw_fd_set(a,b)
>> >> +
>> >>  #undef FD_ISSET
>> >>  #define FD_ISSET(fd, set) __WSAFDIsSet(_get_osfhandle(fd), (fd_set
>> >> *)(set))
>> >
>> > Ah, yes, how obvious ;) You are going to do the same with FD_ISSET as
>> > well, aren't you?
>>
>> Do I really need to? There's already a single function for that, with
>> no "ugly hidden internals" there; __WSAFDIsSet() is documented in
>> MSDN. I mean, Sure... I could... I just don't see the point.
>
> __WSAFDIsSet is "ugly hidden internals" and we should not rely on it when we
> can use the official FD_ISSET for our own FD_ISSET.
>
> -- Hannes
>

...but __WSAFDIsSet() seems to be every bit as official on Windows as FD_ISSET() (documented in msdn, without any notes not to use it), so I still don't really see the point.

However, I don't personally care one way or the other, so just doing it is probably less work than convincing you that I don't have to ;)

-- 
Erik "kusma" Faye-Lund
Andreas Schwab· Jan 16, 2010, 11:27 UTC · re: Erik Faye-Lund · lore

Re: [PATCH v2 13/14] daemon: use select() instead of poll()

Erik Faye-Lund <kusmabite@googlemail.com> writes:
> ...but __WSAFDIsSet() seems to be every bit as official on Windows as
> FD_ISSET() (documented in msdn, without any notes not to use it), so I
> still don't really see the point.

The fact that it starts with two underscores suggests that it is kinda internal.

Andreas.
-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."
Erik Faye-Lund· Jan 16, 2010, 11:43 UTC · re: Andreas Schwab · lore

Re: [PATCH v2 13/14] daemon: use select() instead of poll()

(Note: I'll argue only for the sake for the argument here, I've already pretty much decided to follow Hannes' suggestion)

On Sat, Jan 16, 2010 at 12:27 PM, Andreas Schwab <schwab@linux-m68k.org> wrote:
> The fact that it starts with two underscores suggests that it is kinda
> internal.
>

But the fact that it is documented more than suggests that it isn't. Not any more, anyhow. This is pretty much how winapi works. Internal stuff isn't documented, once it's documented it isn't internal anymore. In fact, winapi doesn't really deal with "internal" and "external" functions, it deals with documented and undocumented. Some documented functions/features have documented compatibility issues.

-- 
Erik "kusma" Faye-Lund
Johannes Sixt· Jan 16, 2010, 12:36 UTC · re: Erik Faye-Lund · lore

Re: [PATCH v2 13/14] daemon: use select() instead of poll()

On Samstag, 16. Januar 2010, Erik Faye-Lund wrote:
> ...but __WSAFDIsSet() seems to be every bit as official on Windows as
> FD_ISSET() (documented in msdn, without any notes not to use it), so I
> still don't really see the point.

I didn't know nor check whether it is documented, but assumed from the '__' that it must be internal. Being documented makes a big difference. I'm fine with either solution.

-- Hannes
Erik Faye-Lund· Jan 16, 2010, 21:31 UTC · re: Johannes Sixt · lore

Re: [PATCH v2 13/14] daemon: use select() instead of poll()

On Sat, Jan 16, 2010 at 1:36 PM, Johannes Sixt <j6t@kdbg.org> wrote:
Show 9 quoted lines
> On Samstag, 16. Januar 2010, Erik Faye-Lund wrote:
>> ...but __WSAFDIsSet() seems to be every bit as official on Windows as
>> FD_ISSET() (documented in msdn, without any notes not to use it), so I
>> still don't really see the point.
>
> I didn't know nor check whether it is documented, but assumed from the '__'
> that it must be internal. Being documented makes a big difference. I'm fine
> with either solution.
>

OK, in that case, I'll leave it as it is. The current code is slightly more tested (I've been using it for some weeks), and I'm slightly lazy ;)

But I'll update FD_SET...
-- 
Erik "kusma" Faye-Lund
Johannes Sixt· Jan 16, 2010, 08:08 UTC · re: Erik Faye-Lund · lore

Re: [PATCH v2 13/14] daemon: use select() instead of poll()

On Samstag, 16. Januar 2010, Erik Faye-Lund wrote:
> The problem with that is differentiating between pipes and sockets.
> GetFileType() returns FILE_TYPE_PIPE for sockets (ugh). I did find
> some code in gnulib that used WSAEnumNetworkEvents() to differentiate
> between them, but I find this quite hacky.

Wouldn't it be possible to call getsockopt(), and if it returns ENOTSOCK (WSAENOTSOCK), then it is a pipe?

-- Hannes
Erik Faye-Lund· Jan 16, 2010, 09:14 UTC · re: Johannes Sixt · lore

Re: [PATCH v2 13/14] daemon: use select() instead of poll()

On Sat, Jan 16, 2010 at 9:08 AM, Johannes Sixt <j6t@kdbg.org> wrote:
Show 11 quoted lines
> On Samstag, 16. Januar 2010, Erik Faye-Lund wrote:
>> The problem with that is differentiating between pipes and sockets.
>> GetFileType() returns FILE_TYPE_PIPE for sockets (ugh). I did find
>> some code in gnulib that used WSAEnumNetworkEvents() to differentiate
>> between them, but I find this quite hacky.
>
> Wouldn't it be possible to call getsockopt(), and if it returns ENOTSOCK
> (WSAENOTSOCK), then it is a pipe?
>
> -- Hannes
>

I read reports that this didn't work in Wine. Not that I care that much about Wine.

-- 
Erik "kusma" Faye-Lund
Johannes Sixt· Jan 16, 2010, 10:44 UTC · re: Erik Faye-Lund · lore

Re: [PATCH v2 13/14] daemon: use select() instead of poll()

On Samstag, 16. Januar 2010, Erik Faye-Lund wrote:
Show 6 quoted lines
> On Sat, Jan 16, 2010 at 9:08 AM, Johannes Sixt <j6t@kdbg.org> wrote:
> > Wouldn't it be possible to call getsockopt(), and if it returns ENOTSOCK
> > (WSAENOTSOCK), then it is a pipe?
>
> I read reports that this didn't work in Wine. Not that I care that
> much about Wine.

What does it mean that "it does not work"? Is it that it does not return ENOTSOCK, so that we mistake pipes as sockets?

-- Hannes
Erik Faye-Lund· Jan 16, 2010, 10:59 UTC · re: Johannes Sixt · lore

Re: [PATCH v2 13/14] daemon: use select() instead of poll()

On Sat, Jan 16, 2010 at 11:44 AM, Johannes Sixt <j6t@kdbg.org> wrote:
Show 13 quoted lines
> On Samstag, 16. Januar 2010, Erik Faye-Lund wrote:
>> On Sat, Jan 16, 2010 at 9:08 AM, Johannes Sixt <j6t@kdbg.org> wrote:
>> > Wouldn't it be possible to call getsockopt(), and if it returns ENOTSOCK
>> > (WSAENOTSOCK), then it is a pipe?
>>
>> I read reports that this didn't work in Wine. Not that I care that
>> much about Wine.
>
> What does it mean that "it does not work"? Is it that it does not return
> ENOTSOCK, so that we mistake pipes as sockets?
>
> -- Hannes
>
Yes, according to the gnulib sources[1], getsockopt returns 0 for pipes.
[1]: http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob;f=lib/poll.c;h=90d99d92dca5d7ce2f31097e4b8fc06a83aae245;hb=HEAD#l80
-- 
Erik "kusma" Faye-Lund
Erik Faye-Lund· Jan 15, 2010, 21:30 UTC · re: Erik Faye-Lund · lore

[PATCH v2 14/14] daemon: report connection from root-process

Report incoming connections from the process that accept() the connection instead of the handling process.

This enables "Connection from"-reporting on Windows, where getpeername(0, ...) consistently fails.

Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>
---
 daemon.c |   70 +++++++++++++++++++++++++++++++++++--------------------------
 1 files changed, 40 insertions(+), 30 deletions(-)
Show changes to daemon.c +40 −30
diff --git a/daemon.c b/daemon.c
index 95cf299..3423ffa 100644
--- a/daemon.c
+++ b/daemon.c
@@ -493,33 +493,6 @@ static int execute(int fd[2], struct sockaddr *addr)
 	static char line[1000];
 	int pktlen, len, i;
 
-	if (addr) {
-		char addrbuf[256] = "";
-		int port = -1;
-
-		if (addr->sa_family == AF_INET) {
-			struct sockaddr_in *sin_addr = (void *) addr;
-			inet_ntop(addr->sa_family, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf));
-			port = ntohs(sin_addr->sin_port);
-#ifndef NO_IPV6
-		} else if (addr && addr->sa_family == AF_INET6) {
-			struct sockaddr_in6 *sin6_addr = (void *) addr;
-
-			char *buf = addrbuf;
-			*buf++ = '['; *buf = '\0'; /* stpcpy() is cool */
-			inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1);
-			strcat(buf, "]");
-
-			port = ntohs(sin6_addr->sin6_port);
-#endif
-		}
-		loginfo("Connection from %s:%d", addrbuf, port);
-		setenv("REMOTE_ADDR", addrbuf, 1);
-	}
-	else {
-		unsetenv("REMOTE_ADDR");
-	}
-
 	alarm(init_timeout ? init_timeout : timeout);
 	pktlen = packet_read_line(fd[0], line, sizeof(line));
 	alarm(0);
@@ -645,10 +618,35 @@ static void check_dead_children(void)
 			cradle = &blanket->next;
 }
 
+static char *get_addrstr(int *port, struct sockaddr *addr)
+{
+	static char addrbuf[256] = "";
+	if (addr->sa_family == AF_INET) {
+		struct sockaddr_in *sin_addr = (void *) addr;
+		inet_ntop(addr->sa_family, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf));
+		*port = ntohs(sin_addr->sin_port);
+#ifndef NO_IPV6
+	} else if (addr && addr->sa_family == AF_INET6) {
+		struct sockaddr_in6 *sin6_addr = (void *) addr;
+
+		char *buf = addrbuf;
+		*buf++ = '['; *buf = '\0'; /* stpcpy() is cool */
+		inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1);
+		strcat(buf, "]");
+
+		*port = ntohs(sin6_addr->sin6_port);
+#endif
+	}
+	return addrbuf;
+}
+
 char **cld_argv;
 static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
 {
 	struct child_process cld = { 0 };
+	char *addrstr, envbuf[300] = "REMOTE_ADDR=";
+	char *env[] = { envbuf, NULL };
+	int port = -1;
 
 	if (max_connections && live_children >= max_connections) {
 		kill_some_child();
@@ -661,14 +659,21 @@ static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
 		}
 	}
 
+	addrstr = get_addrstr(&port, addr);
+	strcat(envbuf, addrstr);
+
+	cld.env = (const char **)env;
 	cld.argv = (const char **)cld_argv;
 	cld.in = incoming;
 	cld.out = dup(incoming);
 
 	if (start_command(&cld))
 		logerror("unable to fork");
-	else
+	else {
+		loginfo("[%"PRIuMAX"] Connection from %s:%d",
+		    (uintmax_t)cld.pid, addrstr, port);
 		add_child(&cld, addr, addrlen);
+	}
 	close(incoming);
 }
 
@@ -1115,8 +1120,13 @@ int main(int argc, char **argv)
 		if (inetd_mode && !freopen("/dev/null", "w", stderr))
 			die_errno("failed to redirect stderr to /dev/null");
 
-		if (getpeername(0, peer, &slen))
-			peer = NULL;
+		if (!getpeername(0, peer, &slen)) {
+			int port = -1;
+			char *addrstr = get_addrstr(&port, peer);
+			setenv("REMOTE_ADDR", addrstr, 1);
+			loginfo("[%"PRIuMAX"] Connection from %s:%d",
+			    (uintmax_t)getpid(), addrstr, port);
+		}
 
 		return execute(fd, peer);
 	}
-- 
1.6.6.211.g26720
Johannes Sixt· Jan 15, 2010, 22:27 UTC · re: Erik Faye-Lund · lore

Re: [PATCH v2 00/14] daemon-win32

A very nicely done series. Thank you very much!
On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
> Here's the long overdue v2 of my daemon-win32 attempt. A lot
> has happened since v1. Most importantly, I abandoned using
> the async API to replace fork(), and went for explicitly
> spawning child process that handle the connection.

IOW, you run git-daemon recursively in inetd mode (almost). Let's see what people say about this approach.

-- Hannes
Erik Faye-Lund· Jan 15, 2010, 22:51 UTC · re: Johannes Sixt · lore

Re: [PATCH v2 00/14] daemon-win32

On Fri, Jan 15, 2010 at 11:27 PM, Johannes Sixt <j6t@kdbg.org> wrote:
Show 13 quoted lines
> A very nicely done series. Thank you very much!
>
> On Freitag, 15. Januar 2010, Erik Faye-Lund wrote:
>> Here's the long overdue v2 of my daemon-win32 attempt. A lot
>> has happened since v1. Most importantly, I abandoned using
>> the async API to replace fork(), and went for explicitly
>> spawning child process that handle the connection.
>
> IOW, you run git-daemon recursively in inetd mode (almost). Let's see what
> people say about this approach.
>
> -- Hannes
>
Yes. Or, a subset of the inetd-mode.
-- 
Erik "kusma" Faye-Lund

← back to recent threads