View Issue Details

IDProjectCategoryView StatusLast Update
0001616GNUnetutil librarypublic2011-09-19 10:45
ReporterLRN Assigned ToLRN  
PrioritylowSeveritymajorReproducibilityN/A
Status closedResolutionfixed 
Summary0001616: IPC for sending SIGTERM on NT OSes
DescriptionFact: GNUnet relies on SIGTERM signal to let a child process clean up and kill itself.
Problem: signals are not supported on NT operating systems. signal() function allows SIGTERM handlers to be installed, but there is no way to send SIGTERM from outside of the process (the process itself is able to call raise() for that purpose).
Solution: use some other form of inter-process communication (IPC) to notify the child process that it should terminate itself (after that the child process can call raise() and proceed normally)
Additional InformationThe IPC method must have the following properties:
1) Must be able to maintain multiple independent parent-child relationships - multiple parents, and each one might have multiple children and be able to send SIGTERM to only one particular child when it wants to.
2) Must have security. Can't allow arbitrary processes to claim to be parents and kill children at will.

According to http://msdn.microsoft.com/en-us/library/aa365574%28VS.85%29.aspx there are 9 IPC methods on operating systems using NT kernel and a win32 subsystem:
1) Clipboard.
  Now, that's ridiculous.
2) COM.
  COM is an object-oriented system that allows processes to transparently call object methods, regardless of object implementation (language, process that runs the code, machine that runs the process). While it might have all necessary properties (or might not, i know only the basics of COM), it's somewhat awkward to implement.
3) Data Copy
  That one is for applications with windows only.
  If we had a window, we would have been able to send messages (we don't need bulk data exchange, just one simple signal) and we would not have had a problem in the first place.
  It is possible to create a hidden window (a window that is never made visible and is only used to receive messages) in each of GNUnet processes. It is also possible to obtain a window handle of any of such windows knowing the PID of the process that owns it (it's a bit awkward, as the mapping goes the other way around - we'll have to enumerate all windows in the system and find the one that was created by the process with a particular PID).
  Windows do not have any security, as far as i know (any process can send any message to any window, and it's up to the owned of the window to check that the message is authentic). If we want one, we'd have to implement it ourselves. Messages leave no traces (AFAIK, it's not possible for a receiver to see which process was the source of a message), so that would be difficult.
4) DDE
  That one is for applications with windows only.
5) File mapping
  Allows multiple processes open the same in-memory file. Requires extra synchronization, and it is unclear how are we to set up that kind of synchronization if we have no working IPC beforehand. Requires for all involved processes to know the "name" of the shared file. Does have OS-level security features, which might allow us to restrict access to the file to particular users (and if GNUnet runs under separate user account, then only GNUnet or GNUnet-derived processes will have access).
6) Mailslots
  Practically the same as named pipes or sockets, but is able to broadcast messages (something we don't need).
7) Pipes
  Anonymous pipes are used for stdtio, we can't use those.
  Named pipes are like sockets - they require the client to know a name of the server pipe to establish communication. Named pipes do have some nice security features:
  a) Named pipes are subject to OS-level security checks (see (5) File mapping for details).
  b) It is possible to restrict a named pipe to only one instance, meaning that the first process that gets to creating a named pipe server with a particular name can (and should) decide to forbid other instances of the same pipe to be created (by other processes or by the same process). If another process tries to create a named pipe with the same name it will fail. Which means that it is possible for a malicious process to create the named pipe server in advance, but that will only prevent GNUnet from using this IPC mechanism (and, effectively, from running at all) and will not allow a malicious process to use it to manage GNUnet child processes.
    It might be difficult to choose names for the named pipe servers. If we use the service/daemon/program-specific (hardcoded) name that is different for each program, we will effectively prevent other instances of this program from running, OS-wide. A possible solution is to use PID as part of the name. A parent process will know the PID of its child process and will know which name to use. The special case of a libtool wrapper (when the child process is a libtool wrapper executable and the actual process we wanted to run is the grandchild) can be handled separately by checking for grandchildren with the same name as the child (especially if the connection is made only when communication is required - it will give the child process enough time to launch a grandchild).
8) RPC
  Looks like COM, and i have no idea how to work with it.
9) Sockets
  Same as named pipes, but without OS-level security and without names (can't have multiple servers running on the same port, and using different ports will make it impossible to guess the right port).
TagsNo tags attached.
Attached Files
handlepasstest_master.c (1,550 bytes)   
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <process.h>


int main (int argc, char **argv)
{
  SECURITY_ATTRIBUTES sa;
  sa.nLength = sizeof (sa);
  sa.lpSecurityDescriptor = NULL;
  sa.bInheritHandle = TRUE;
  HANDLE event0, event1;
  int child_pid;
  char buf[1024];
  DWORD dwresult;

  printf ("MASTER: i am %d\n", getpid());

  if (argc != 2 || (strcmp (argv[1], "child") != 0 && strcmp (argv[1], "grandchild") != 0))
  {
    printf ("argv[1] must be either `child' or `grandchild'\n");
    return 0;
  }

  event0 = CreateEvent (&sa, TRUE, FALSE, NULL);
  event1 = CreateEvent (&sa, TRUE, FALSE, NULL);
  printf ("MASTER: Created events %08X and %08X\n", event0, event1);

  sprintf (buf, "SECRETHANDLEVALUE0=%X", event0);
  printf ("MASTER: calling putenv(%s)\n", buf);
  putenv (buf);
  sprintf (buf, "SECRETHANDLEVALUE1=%X", event1);
  printf ("MASTER: calling putenv(%s)\n", buf);
  putenv (buf);
  SetLastError (0);
  child_pid = _spawnl (_P_NOWAIT, "handlepasstest_slave.exe", "handlepasstest_slave.exe", argv[1], NULL);
  printf ("MASTER: spawned a child (handle=%d), GLE is %d\n", child_pid, GetLastError ());

  SetLastError (0);
  dwresult = WaitForSingleObject (event0, INFINITE);
  printf ("MASTER: Wait for %08X returned %d, GLE is %d\n", event0, dwresult, GetLastError ());

  SetLastError (0);
  BOOL bresult = SetEvent (event1);
  printf ("MASTER: SetEvent for %08X returned %d, GLE is %d\n", event1, bresult, GetLastError ());

  _getch();
  return 0;
}
handlepasstest_master.c (1,550 bytes)   
handlepasstest_slave.c (1,670 bytes)   
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <process.h>


int main (int argc, char **argv)
{
  HANDLE event0, event1;
  int child_pid;
  char *buf0, *buf1, *tmp;
  DWORD dwresult;

  if (argc != 2)
    return 1;

  if (strcmp (argv[1], "child") == 0)
  {
    printf ("SLAVE: i am %d\n", getpid());
    buf0 = getenv ("SECRETHANDLEVALUE0");
    buf1 = getenv ("SECRETHANDLEVALUE1");
    printf ("SLAVE: Got events %s and %s\n", buf0, buf1);
  
    event0 = event1 = NULL;
    if (strlen (buf0) > 0)
      event0 = (HANDLE) strtol (buf0, &tmp, 16);
    if (strlen (buf1) > 0)
      event1 = (HANDLE) strtol (buf1, &tmp, 16);
  
    if (event0 != NULL)
    {
      SetLastError (0);
      BOOL bresult = SetEvent (event0);
      printf ("SLAVE: SetEvent for %08X returned %d, GLE is %d\n", event0, bresult, GetLastError ());
    }
    else
      printf ("SLAVE: event0 is NULL!\n");  
  
    if (event1 != NULL)
    {
      SetLastError (0);
      dwresult = WaitForSingleObject (event1, INFINITE);
      printf ("SLAVE: Wait for %08X returned %d, GLE is %d\n", event1, dwresult, GetLastError ());
    }
    else
      printf ("SLAVE: event1 is NULL!\n");
    _getch();
    return 0;
  }
  else if (strcmp (argv[1], "grandchild") == 0)
  {
    printf ("INTERMEDIATE SLAVE: i am %d\n", getpid());
    SetLastError (0);
    child_pid = _spawnl (_P_NOWAIT, "handlepasstest_slave.exe", "handlepasstest_slave.exe", "child", NULL);
    printf ("INTERMEDIATE SLAVE: spawned a child (handle=%d), GLE is %d\n", child_pid, GetLastError ());
    _getch();
    return 0;
  }
  _getch();
  return 1;
}
handlepasstest_slave.c (1,670 bytes)   
pipes_sockets_and_stuff.diff (46,269 bytes)   
Index: src/arm/gnunet-service-arm_interceptor.c
===================================================================
--- src/arm/gnunet-service-arm_interceptor.c	(revision 13603)
+++ src/arm/gnunet-service-arm_interceptor.c	(working copy)
@@ -187,9 +187,15 @@
    * Have we ever successfully written data to the service?
    */
   int first_write_done;
+
+
+  /**
+   * Service connection attempts
+   */
+  struct ServiceListeningInfo *service_connect_ipv4;
+  struct ServiceListeningInfo *service_connect_ipv6;
 };
 
-
 /**
  * Array with the names of the services started by default.
  */
@@ -694,6 +700,10 @@
 				      &forwardToService, fc);
 }
 
+static void fc_acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc, int is_ipv4, int is_ipv6);
+static void fc_acceptConnection_ipv4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+static void fc_acceptConnection_ipv6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+static int service_try_to_connect (struct sockaddr *addr, socklen_t addrlen, struct ForwardedConnection *fc);
 
 /**
  *
@@ -704,103 +714,252 @@
 {
   struct ForwardedConnection *fc = cls;
   struct GNUNET_TIME_Relative rem;
+  int fail = 0;
+  int failures = 0;
+  int is_zero = 0, is_ipv6 = 0, is_ipv4 = 0;
+  struct sockaddr_in *target_ipv4;
+  struct sockaddr_in6 *target_ipv6;
 
+  int free_ipv4 = 1, free_ipv6 = 1;
+  char listen_address[128];
+  uint16_t listening_port;
+
   fc->start_task = GNUNET_SCHEDULER_NO_TASK;
   if ( (NULL != tc) &&
        (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) )
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-		  _("Unable to forward to service `%s': shutdown\n"),
-		  fc->listen_info->serviceName);
-      closeClientAndServiceSockets (fc, REASON_ERROR);
-      return;
-    }
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+		_("Unable to forward to service `%s': shutdown\n"),
+		fc->listen_info->serviceName);
+    closeClientAndServiceSockets (fc, REASON_ERROR);
+    return;
+  }
   rem = GNUNET_TIME_absolute_get_remaining (fc->timeout);
   if (rem.rel_value == 0)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+		_("Unable to forward to service `%s': timeout before connect\n"),
+		fc->listen_info->serviceName);
+    closeClientAndServiceSockets (fc, REASON_ERROR);
+    return;
+  }
+  target_ipv4 = GNUNET_malloc (sizeof (struct sockaddr_in));
+  target_ipv6 = GNUNET_malloc (sizeof (struct sockaddr_in6));
+
+  switch (fc->listen_info->service_addr->sa_family)
+  {
+  case AF_INET:
+    inet_ntop (fc->listen_info->service_addr->sa_family, (const void *) &((struct sockaddr_in *) fc->listen_info->service_addr)->sin_addr, listen_address, INET_ADDRSTRLEN);
+    if (strncmp (listen_address, "0.0.0.0:", 8) == 0 || strncmp (listen_address, "0.0.0.0", 7) == 0)
+      is_zero = 1;
+    is_ipv4 = 1;
+    listening_port = ((struct sockaddr_in *)fc->listen_info->service_addr)->sin_port;
+    break;
+  case AF_INET6:
+    inet_ntop (fc->listen_info->service_addr->sa_family, (const void *) &((struct sockaddr_in6 *) fc->listen_info->service_addr)->sin6_addr, listen_address, INET6_ADDRSTRLEN);
+    if (strncmp (listen_address, "[::]:", 5) == 0 || strncmp (listen_address, "::", 2) == 0)
+      is_zero = 1;
+    is_ipv6 = 1;
+    listening_port = ((struct sockaddr_in6 *)fc->listen_info->service_addr)->sin6_port;
+    break;
+  default:
+    break;
+  }
+
+  fc->service_connect_ipv4 = NULL;
+  fc->service_connect_ipv6 = NULL;
+  if (is_zero)
+  {
+    /* connect to [::1] and 127.0.0.1 instead of [::] and 0.0.0.0 */
+    inet_pton (AF_INET, "127.0.0.1", &target_ipv4->sin_addr);
+    target_ipv4->sin_family = AF_INET;
+    target_ipv4->sin_port = listening_port;
+    is_ipv4 = 1;
+    free_ipv4 = 0;
+
+    inet_pton (AF_INET6, "0:0:0:0:0:0:0:1", &target_ipv6->sin6_addr);
+    target_ipv6->sin6_family = AF_INET6;
+    target_ipv6->sin6_port = listening_port;
+    is_ipv6 = 1;
+    free_ipv6 = 0;
+  }
+  else
+  {
+    if (is_ipv4)
+      memcpy (target_ipv4, fc->listen_info->service_addr, sizeof (struct sockaddr_in));
+    else if (is_ipv6)
+      memcpy (target_ipv6, fc->listen_info->service_addr, sizeof (struct sockaddr_in6));
+  }
+
+  if (is_ipv4)
+    failures += free_ipv4 = service_try_to_connect ((struct sockaddr *) target_ipv4, sizeof (struct sockaddr_in), fc);
+  if (is_ipv6)
+    failures += free_ipv6 = service_try_to_connect ((struct sockaddr *) target_ipv6, sizeof (struct sockaddr_in6), fc);
+
+  if (is_ipv4 + is_ipv6 <= failures)
+    fail = 1;
+
+  if (free_ipv4)
+    GNUNET_free (target_ipv4);
+  if (free_ipv6)
+    GNUNET_free (target_ipv6);
+
+  if (fail)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _ ("Unable to start service `%s': %s\n"),
+		fc->listen_info->serviceName,
+		STRERROR (errno));
+    closeClientAndServiceSockets (fc, REASON_ERROR);
+    return;
+  }
+}
+
+static void
+fc_acceptConnection_ipv4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  fc_acceptConnection (cls, tc, 1, 0);
+}
+
+static void
+fc_acceptConnection_ipv6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  fc_acceptConnection (cls, tc, 0, 1);
+}
+
+static void
+fc_acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc, int is_ipv4, int is_ipv6)
+{
+  struct ForwardedConnection *fc = cls;
+  struct ServiceListeningInfo *sli;
+
+  if (is_ipv4)
+    sli = fc->service_connect_ipv4;
+  else if (is_ipv6)
+    sli = fc->service_connect_ipv6;
+  else
+    GNUNET_break (0);
+
+  if ((tc->reason & (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT | GNUNET_SCHEDULER_REASON_PREREQ_DONE)) || ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) && fc->armServiceSocket))
+  {
+    GNUNET_NETWORK_socket_close (sli->listeningSocket);
+    if (is_ipv4)
+      fc->service_connect_ipv4 = NULL;
+    else if (is_ipv6)
+      fc->service_connect_ipv6 = NULL;
+  }
+  else if (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)
+  {
+#if DEBUG_SERVICE_MANAGER
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+       "Connected to service, now starting forwarding\n");
+#endif
+    fc->armServiceSocket = sli->listeningSocket;
+    if ((is_ipv4 && fc->service_connect_ipv6 != NULL))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-		  _("Unable to forward to service `%s': timeout before connect\n"),
-		  fc->listen_info->serviceName);
-      closeClientAndServiceSockets (fc, REASON_ERROR);
-      return;
+      GNUNET_SCHEDULER_cancel (fc->service_connect_ipv6->acceptTask);
+      fc->service_connect_ipv6->acceptTask = GNUNET_SCHEDULER_add_now (fc_acceptConnection_ipv6, fc);
     }
-  fc->armServiceSocket =
-    GNUNET_NETWORK_socket_create (fc->listen_info->service_addr->sa_family,
-				  SOCK_STREAM, 0);
-  if (NULL == fc->armServiceSocket)
+    else if (is_ipv6 && fc->service_connect_ipv4 != NULL)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-		  _ ("Unable to start service `%s': %s\n"),
-		  fc->listen_info->serviceName,
-		  STRERROR (errno));
-      closeClientAndServiceSockets (fc, REASON_ERROR);
-      return;
+      GNUNET_SCHEDULER_cancel (fc->service_connect_ipv4->acceptTask);
+      fc->service_connect_ipv4->acceptTask = GNUNET_SCHEDULER_add_now (fc_acceptConnection_ipv4, fc);
     }
-  if ( (GNUNET_SYSERR ==
-	GNUNET_NETWORK_socket_connect (fc->armServiceSocket,
-				       fc->listen_info->service_addr,
-				       fc->listen_info->service_addr_len)) &&
-       (errno != EINPROGRESS) )
+    GNUNET_free (fc->listen_info->service_addr);
+    fc->listen_info->service_addr = sli->service_addr;
+    fc->listen_info->service_addr_len = sli->service_addr_len;
+    /*fc->listen_info->listeningSocket is it closed already?*/
+    if (fc->client_to_service_task == GNUNET_SCHEDULER_NO_TASK)
     {
-      GNUNET_break (GNUNET_OK ==
-		    GNUNET_NETWORK_socket_close (fc->armServiceSocket));
-      fc->armServiceSocket = NULL;
-      fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2);
-  #if DEBUG_SERVICE_MANAGER
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-		  "Failed to connected to service `%s' at `%s', will try again in %llu ms\n",
-		  fc->listen_info->serviceName,
-		  GNUNET_a2s (fc->listen_info->service_addr,
-			      fc->listen_info->service_addr_len),
-		  (unsigned long long) GNUNET_TIME_relative_min (fc->back_off,
-								 rem).rel_value);
-#endif
-      GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
-      fc->start_task
-	= GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_min (fc->back_off,
-								  rem),
-					&start_forwarding,
-					fc);
-      return;
-    }
-#if DEBUG_SERVICE_MANAGER
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-	      "Connected to service, now starting forwarding\n");
-#endif
-  if (fc->client_to_service_task == GNUNET_SCHEDULER_NO_TASK)
-    {
       if (fc->client_to_service_bufferDataLength == 0) 
-	fc->client_to_service_task =
-	  GNUNET_SCHEDULER_add_read_net (
+	  fc->client_to_service_task =
+	    GNUNET_SCHEDULER_add_read_net (
 					 GNUNET_TIME_UNIT_FOREVER_REL,
 					 fc->armClientSocket,
 					 &receiveFromClient, fc);
       else
-	fc->client_to_service_task = 
-	  GNUNET_SCHEDULER_add_write_net (
+	  fc->client_to_service_task = 
+	    GNUNET_SCHEDULER_add_write_net (
 					  GNUNET_TIME_UNIT_FOREVER_REL,
 					  fc->armServiceSocket,
 					  &forwardToService, fc);
     }
-  if (fc->service_to_client_task == GNUNET_SCHEDULER_NO_TASK)
+    if (fc->service_to_client_task == GNUNET_SCHEDULER_NO_TASK)
     {
       if (fc->service_to_client_bufferDataLength == 0) 
-	fc->service_to_client_task =
-	  GNUNET_SCHEDULER_add_read_net (
+	  fc->service_to_client_task =
+	    GNUNET_SCHEDULER_add_read_net (
 					 GNUNET_TIME_UNIT_FOREVER_REL,
 					 fc->armServiceSocket,
 					 &receiveFromService, fc);
       else
-	fc->service_to_client_task = 
-	  GNUNET_SCHEDULER_add_write_net (
+	  fc->service_to_client_task = 
+	    GNUNET_SCHEDULER_add_write_net (
 					  GNUNET_TIME_UNIT_FOREVER_REL,
 					  fc->armClientSocket,
 					  &forwardToClient, fc);
     }
+  }
+  else
+  {
+    GNUNET_break (0);
+  }
+  GNUNET_free (sli);
 }
 
+static int
+service_try_to_connect (struct sockaddr *addr, socklen_t addrlen, struct ForwardedConnection *fc)
+{
+  struct GNUNET_NETWORK_Handle *sock;
+  struct ServiceListeningInfo *serviceListeningInfo;
 
+  sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
+  if (sock == NULL)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to create a socket\n");
+    return 1;
+  }
+  
+  if ( (GNUNET_SYSERR == GNUNET_NETWORK_socket_connect (sock, addr, addrlen)) &&
+       (errno != EINPROGRESS) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect\n");
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
+    return 1;
+  }
 
+  serviceListeningInfo = GNUNET_malloc (sizeof (struct ServiceListeningInfo));
+  serviceListeningInfo->serviceName = NULL;
+  serviceListeningInfo->service_addr = addr;
+  serviceListeningInfo->service_addr_len = addrlen;
+  serviceListeningInfo->listeningSocket = sock;
+
+  switch (addrlen)
+  {
+  case sizeof (struct sockaddr_in):
+    fc->service_connect_ipv4 = serviceListeningInfo;
+    serviceListeningInfo->acceptTask =
+        GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                        serviceListeningInfo->listeningSocket,
+				        &fc_acceptConnection_ipv4, fc);
+    break;
+  case sizeof (struct sockaddr_in6):
+    fc->service_connect_ipv6 = serviceListeningInfo;
+    serviceListeningInfo->acceptTask =
+        GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                        serviceListeningInfo->listeningSocket,
+				        &fc_acceptConnection_ipv6, fc);
+    break;
+  default:
+    GNUNET_break (0);
+    return 1;
+    break;
+  }
+  return 0;
+}
+
+
+
 /**
  *
  */
Index: src/include/gnunet_os_lib.h
===================================================================
--- src/include/gnunet_os_lib.h	(revision 13603)
+++ src/include/gnunet_os_lib.h	(working copy)
@@ -273,6 +273,18 @@
  */
 int GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc);
 
+/**
+ * Read env variable and set up the read end of the control
+ * pipe that parent uses to send signals to this process.
+ *
+ * Only does something on Windows
+ *
+ * @param cls user-specified parameter (NULL)
+ * @param tc task context
+ */
+void GNUNET_OS_install_parent_control_handler (void *cls,
+                                               const struct
+                                               GNUNET_SCHEDULER_TaskContext * tc);
 
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
Index: src/transport/plugin_transport_http.c
===================================================================
--- src/transport/plugin_transport_http.c	(revision 13603)
+++ src/transport/plugin_transport_http.c	(working copy)
@@ -1589,7 +1589,7 @@
   if (delay.rel_value > 0)
   {
 #if DEBUG_HTTP
-	GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: Inbound quota management: delay next read for %llu ms \n", ps, delay.abs_value);
+	GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: Inbound quota management: delay next read for %llu ms \n", ps, delay.rel_value);
 #endif
 	pc->reset_task = GNUNET_SCHEDULER_add_delayed (delay, &reset_inbound_quota_delay, pc);
   }
Index: src/fragmentation/test_frag_ji.c
===================================================================
--- src/fragmentation/test_frag_ji.c	(revision 13603)
+++ src/fragmentation/test_frag_ji.c	(working copy)
@@ -1,60 +1,60 @@
-#include "platform.h"
-#include "gnunet_protocols.h"
-#include "gnunet_fragmentation_lib.h"
-
-struct combine{
-	struct GNUNET_FRAGMENT_Context* ctx;
-	struct GNUNET_PeerIdentity* sender;
-};
-
-void message_proc1(void *cls, const struct GNUNET_MessageHeader * msg){
-	fprintf(stderr, "enter into message_proc1\n");
-
-	struct GNUNET_MessageHeader * originalMsg = (struct GNUNET_MessageHeader *)cls;
-
-	if(ntohs(originalMsg->size) != ntohs(msg->size)){
-			fprintf(stderr, "the received message has the different size with the sent one!\n");
-		}
-	if(ntohs(originalMsg->type) != ntohs(msg->type)){
-			fprintf(stderr, "the received message has the different type with the sent one!\n");
-		}
-	if(memcmp(msg, originalMsg, originalMsg->size)){
-			fprintf(stderr, "the received message is not the sent one!\n");
-	}
-	else{
-		fprintf(stdout, "You got the right message!\n");
-	}
-
-}
-
-void message_proc2(void *cls, const struct GNUNET_MessageHeader * msg){
-	printf("enter into message_proc2\n");
-	struct combine * com2 = (struct combine* )cls;
-	GNUNET_FRAGMENT_process(com2->ctx, com2->sender, msg);
-
-}
-
-int
-main(int argc, char * argv[]){
+#include "platform.h"
+#include "gnunet_protocols.h"
+#include "gnunet_fragmentation_lib.h"
+
+struct combine{
+	struct GNUNET_FRAGMENT_Context* ctx;
+	struct GNUNET_PeerIdentity* sender;
+};
+
+void message_proc1(void *cls, const struct GNUNET_MessageHeader * msg){
+	fprintf(stderr, "enter into message_proc1\n");
+
+	struct GNUNET_MessageHeader * originalMsg = (struct GNUNET_MessageHeader *)cls;
+
+	if(ntohs(originalMsg->size) != ntohs(msg->size)){
+			fprintf(stderr, "the received message has the different size with the sent one!\n");
+		}
+	if(ntohs(originalMsg->type) != ntohs(msg->type)){
+			fprintf(stderr, "the received message has the different type with the sent one!\n");
+		}
+	if(memcmp(msg, originalMsg, originalMsg->size)){
+			fprintf(stderr, "the received message is not the sent one!\n");
+	}
+	else{
+		fprintf(stdout, "You got the right message!\n");
+	}
+
+}
+
+void message_proc2(void *cls, const struct GNUNET_MessageHeader * msg){
+	printf("enter into message_proc2\n");
+	struct combine * com2 = (struct combine* )cls;
+	GNUNET_FRAGMENT_process(com2->ctx, com2->sender, msg);
+
+}
+
+int
+main(int argc, char * argv[]){
 	
-	uint32_t mtu = 512;
-	struct GNUNET_FRAGMENT_Context * ctx;
-	struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *)GNUNET_malloc(sizeof(struct GNUNET_MessageHeader)+2*mtu);
-	ctx = GNUNET_FRAGMENT_context_create(NULL, message_proc1, msg);
-	msg->size = htons(sizeof(struct GNUNET_MessageHeader)+4*mtu);
-	msg->type = htons(GNUNET_MESSAGE_TYPE_HELLO);
-	struct GNUNET_PeerIdentity *sender;
-	sender = (struct GNUNET_PeerIdentity *)GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity));
-
-	memset(sender, 9, sizeof(struct GNUNET_PeerIdentity));
-
-	memset(&msg[1], 5, 2*mtu);
-
-	struct combine *com;
-	com = (struct combine *)GNUNET_malloc(sizeof(struct combine));
-	com->ctx = ctx;
-	com->sender = sender;
-	GNUNET_FRAGMENT_fragment(msg, mtu, message_proc2, com);
-	GNUNET_free(msg);
-	return 0;
-}
+	uint32_t mtu = 512;
+	struct GNUNET_FRAGMENT_Context * ctx;
+	struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *)GNUNET_malloc(sizeof(struct GNUNET_MessageHeader)+2*mtu);
+	ctx = GNUNET_FRAGMENT_context_create(NULL, message_proc1, msg);
+	msg->size = htons(sizeof(struct GNUNET_MessageHeader)+4*mtu);
+	msg->type = htons(GNUNET_MESSAGE_TYPE_HELLO);
+	struct GNUNET_PeerIdentity *sender;
+	sender = (struct GNUNET_PeerIdentity *)GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity));
+
+	memset(sender, 9, sizeof(struct GNUNET_PeerIdentity));
+
+	memset(&msg[1], 5, 2*mtu);
+
+	struct combine *com;
+	com = (struct combine *)GNUNET_malloc(sizeof(struct combine));
+	com->ctx = ctx;
+	com->sender = sender;
+	GNUNET_FRAGMENT_fragment(msg, mtu, message_proc2, com);
+	GNUNET_free(msg);
+	return 0;
+}
Index: src/fragmentation/test_fragmentation_enhanced.c
===================================================================
--- src/fragmentation/test_fragmentation_enhanced.c	(revision 13603)
+++ src/fragmentation/test_fragmentation_enhanced.c	(working copy)
@@ -1,89 +1,89 @@
-/*
-     This file is part of GNUnet.
-     (C) 2009 Christian Grothoff (and other contributing authors)
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file fragmentation/test_fragmentation_enhanced.c
- * @brief testcase for the fragmentation.c
- * @author Ji Lu
- */
-
-#include "platform.h"
-#include "gnunet_protocols.h"
-#include "gnunet_fragmentation_lib.h"
-
-struct combine{
-	struct GNUNET_FRAGMENT_Context* ctx;
-	struct GNUNET_PeerIdentity* sender;
-};
-
-void message_proc1(void *cls, const struct GNUNET_MessageHeader * msg){
-
-	fprintf(stderr, "enter into message_proc1\n");
-
-	struct GNUNET_MessageHeader * originalMsg = (struct GNUNET_MessageHeader *)cls;
-
-	if(ntohs(originalMsg->size) != ntohs(msg->size)){
-			fprintf(stderr, "the received message has the different size with the sent one!\n");
-		}
-	if(ntohs(originalMsg->type) != ntohs(msg->type)){
-			fprintf(stderr, "the received message has the different type with the sent one!\n");
-		}
-	if(memcmp(msg, originalMsg, originalMsg->size)){
-			fprintf(stderr, "the received message is not the sent one!\n");
-	}
-	else{
-			fprintf(stdout, "You got the right message!\n");
-	}
-
-}
-
-void message_proc2(void *cls, const struct GNUNET_MessageHeader * msg){
-
-	printf("enter into message_proc2\n");
-
-	struct combine * com2 = (struct combine* )cls;
-	GNUNET_FRAGMENT_process(com2->ctx, com2->sender, msg);
-
-}
-
-int
-main(int argc, char * argv[]){
+/*
+     This file is part of GNUnet.
+     (C) 2009 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file fragmentation/test_fragmentation_enhanced.c
+ * @brief testcase for the fragmentation.c
+ * @author Ji Lu
+ */
+
+#include "platform.h"
+#include "gnunet_protocols.h"
+#include "gnunet_fragmentation_lib.h"
+
+struct combine{
+	struct GNUNET_FRAGMENT_Context* ctx;
+	struct GNUNET_PeerIdentity* sender;
+};
+
+void message_proc1(void *cls, const struct GNUNET_MessageHeader * msg){
+
+	fprintf(stderr, "enter into message_proc1\n");
+
+	struct GNUNET_MessageHeader * originalMsg = (struct GNUNET_MessageHeader *)cls;
+
+	if(ntohs(originalMsg->size) != ntohs(msg->size)){
+			fprintf(stderr, "the received message has the different size with the sent one!\n");
+		}
+	if(ntohs(originalMsg->type) != ntohs(msg->type)){
+			fprintf(stderr, "the received message has the different type with the sent one!\n");
+		}
+	if(memcmp(msg, originalMsg, originalMsg->size)){
+			fprintf(stderr, "the received message is not the sent one!\n");
+	}
+	else{
+			fprintf(stdout, "You got the right message!\n");
+	}
+
+}
+
+void message_proc2(void *cls, const struct GNUNET_MessageHeader * msg){
+
+	printf("enter into message_proc2\n");
+
+	struct combine * com2 = (struct combine* )cls;
+	GNUNET_FRAGMENT_process(com2->ctx, com2->sender, msg);
+
+}
+
+int
+main(int argc, char * argv[]){
 	
-	uint32_t mtu = 512;
-	struct GNUNET_FRAGMENT_Context * ctx;
-	struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *)GNUNET_malloc(sizeof(struct GNUNET_MessageHeader)+2*mtu);
-	ctx = GNUNET_FRAGMENT_context_create(NULL, message_proc1, msg);
-	msg->size = htons(sizeof(struct GNUNET_MessageHeader)+4*mtu);
-	msg->type = htons(GNUNET_MESSAGE_TYPE_HELLO);
-	struct GNUNET_PeerIdentity *sender;
-	sender = (struct GNUNET_PeerIdentity *)GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity));
-
-	memset(sender, 9, sizeof(struct GNUNET_PeerIdentity));
-
-	memset(&msg[1], 5, 2*mtu);
-
-	struct combine *com;
-	com = (struct combine *)GNUNET_malloc(sizeof(struct combine));
-	com->ctx = ctx;
-	com->sender = sender;
-	GNUNET_FRAGMENT_fragment(msg, mtu, message_proc2, com);
-	GNUNET_free(msg);
-	return 0;
-}
+	uint32_t mtu = 512;
+	struct GNUNET_FRAGMENT_Context * ctx;
+	struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *)GNUNET_malloc(sizeof(struct GNUNET_MessageHeader)+2*mtu);
+	ctx = GNUNET_FRAGMENT_context_create(NULL, message_proc1, msg);
+	msg->size = htons(sizeof(struct GNUNET_MessageHeader)+4*mtu);
+	msg->type = htons(GNUNET_MESSAGE_TYPE_HELLO);
+	struct GNUNET_PeerIdentity *sender;
+	sender = (struct GNUNET_PeerIdentity *)GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity));
+
+	memset(sender, 9, sizeof(struct GNUNET_PeerIdentity));
+
+	memset(&msg[1], 5, 2*mtu);
+
+	struct combine *com;
+	com = (struct combine *)GNUNET_malloc(sizeof(struct combine));
+	com->ctx = ctx;
+	com->sender = sender;
+	GNUNET_FRAGMENT_fragment(msg, mtu, message_proc2, com);
+	GNUNET_free(msg);
+	return 0;
+}
Index: src/hostlist/hostlist-client.c
===================================================================
--- src/hostlist/hostlist-client.c	(revision 13603)
+++ src/hostlist/hostlist-client.c	(working copy)
@@ -1421,6 +1421,7 @@
                   "HOSTLISTFILE", "HOSTLIST");
       return;
     }
+  GNUNET_DISK_directory_create_for_file (filename);
   wh = GNUNET_BIO_write_open (filename);
   if ( NULL == wh)
     {
Index: src/util/scheduler.c
===================================================================
--- src/util/scheduler.c	(revision 13603)
+++ src/util/scheduler.c	(working copy)
@@ -744,6 +744,7 @@
   shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, &sighandler_shutdown);
 #endif
   current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT;
+  GNUNET_SCHEDULER_add_continuation (GNUNET_OS_install_parent_control_handler, NULL, GNUNET_SCHEDULER_REASON_STARTUP);
   GNUNET_SCHEDULER_add_continuation (task,
                                      task_cls,
                                      GNUNET_SCHEDULER_REASON_STARTUP);
@@ -1351,8 +1352,7 @@
   GNUNET_assert (rfd != NULL);
   rs = GNUNET_NETWORK_fdset_create ();
   GNUNET_NETWORK_fdset_handle_set (rs, rfd);
-  ret = GNUNET_SCHEDULER_add_select (sched,
-                                     GNUNET_SCHEDULER_PRIORITY_KEEP,
+  ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_KEEP,
                                      GNUNET_SCHEDULER_NO_TASK, delay,
                                      rs, NULL, task, task_cls);
   GNUNET_NETWORK_fdset_destroy (rs);
@@ -1400,8 +1400,7 @@
   GNUNET_assert (wfd != NULL);
   ws = GNUNET_NETWORK_fdset_create ();
   GNUNET_NETWORK_fdset_handle_set (ws, wfd);
-  ret = GNUNET_SCHEDULER_add_select (sched,
-                                     GNUNET_SCHEDULER_PRIORITY_KEEP,
+  ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_KEEP,
                                      GNUNET_SCHEDULER_NO_TASK,
                                      delay, NULL, ws, task, task_cls);
   GNUNET_NETWORK_fdset_destroy (ws);
Index: src/util/os_priority.c
===================================================================
--- src/util/os_priority.c	(revision 13557)
+++ src/util/os_priority.c	(working copy)
@@ -29,28 +29,95 @@
 #include "gnunet_os_lib.h"
 #include "disk.h"
 
+#define GNUNET_OS_NT_CONTROL_PIPE "GNUNET_OS_NT_CONTROL_PIPE"
+
 struct GNUNET_OS_Process
 {
   pid_t pid;
 #if WINDOWS
   HANDLE handle;
+  struct GNUNET_DISK_PipeHandle *control_pipe;
 #endif
 };
 
 static struct GNUNET_OS_Process current_process;
 
-
 #if WINDOWS
-void
-GNUNET_OS_process_set_handle(struct GNUNET_OS_Process *proc, HANDLE handle)
+void GNUNET_OS_parent_control_handler (void *cls,
+                                       const struct
+                                       GNUNET_SCHEDULER_TaskContext * tc)
 {
-  if (proc->handle != NULL)
-    CloseHandle (proc->handle);
-  proc->handle = handle;
+  struct GNUNET_DISK_PipeHandle *control_pipe = (struct GNUNET_DISK_PipeHandle *) cls;
+  unsigned char code;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_OS_parent_control_handler is invoked because of %d\n", tc->reason);
+
+  if (tc->reason & (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT | GNUNET_SCHEDULER_REASON_PREREQ_DONE))
+  {
+      GNUNET_DISK_pipe_close (control_pipe);
+  }
+  else
+  {
+    if (GNUNET_DISK_file_read (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), &code, sizeof (char)) != sizeof (char))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_DISK_file_read have failed, errno = %d. Closing the control pipe.\n", errno);
+      GNUNET_DISK_pipe_close (control_pipe);
+    }
+    else
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got control code %d\n", code);
+      switch (code)
+      {
+        case 0:
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Raising SIGTERM\n");
+          raise (SIGTERM);
+          break;
+        case 1:
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Raising SIGKILL\n");
+          raise (SIGKILL);
+          break;
+        case 255:
+          /* read more bytes - a possibility for extended signals
+           * in case 254 different valies is not enough
+           */
+          break;
+        default:
+          break;
+      }
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Re-adding parent control handler pipe to the scheduler\n");
+      GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), GNUNET_OS_parent_control_handler, control_pipe);
+    }
+  }
 }
 #endif
 
+void
+GNUNET_OS_install_parent_control_handler (void *cls,
+                                          const struct
+                                          GNUNET_SCHEDULER_TaskContext * tc)
+{
+#ifdef WINDOWS
+  char *env_buf;
+  char *endptr;
+  HANDLE control_pipe_end[2];
+  struct GNUNET_DISK_PipeHandle *control_pipe = NULL;
 
+  env_buf = getenv (GNUNET_OS_NT_CONTROL_PIPE);
+  if (env_buf == NULL || strlen (env_buf) <= 0 || env_buf[0] < '0' || env_buf[0] > '9')
+    return;
+
+  control_pipe_end[0] = (HANDLE) strtol (env_buf, &endptr, 10);
+  control_pipe_end[1] = INVALID_HANDLE_VALUE;
+ 
+  control_pipe = GNUNET_DISK_pipe_from_internal_handles_ (GNUNET_NO, &control_pipe_end[0], &control_pipe_end[1], sizeof (HANDLE));
+  if (control_pipe == NULL)
+    return;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding parent control handler pipe to the scheduler\n");
+  GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), GNUNET_OS_parent_control_handler, control_pipe);
+#endif
+}
+
 /**
  * Get process structure for current process
  *
@@ -66,7 +133,7 @@
   current_process.pid = GetCurrentProcessId ();
   current_process.handle = GetCurrentProcess ();
 #else
-  current_process.pid = 0;
+  current_process.pid = getpid ();
 #endif
   return &current_process;
 }
@@ -75,27 +142,49 @@
 GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
 {
 #if WINDOWS
-  if (sig == SIGKILL || sig == SIGTERM)
+  unsigned char c;
+  DWORD dwresult, error_code = NO_ERROR;
+  BOOL bresult = 1;
+
+  switch (sig)
   {
-    HANDLE h = proc->handle;
-    if (NULL == h)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-		  _("Invalid process information {%d, %08X}\n"),
-		  proc->pid,
-		  h);
+    case SIGKILL:
+      c = 1;
+      break;
+    case SIGTERM:
+      c = 0;
+      break;
+    default:
+      errno = EINVAL;
       return -1;
-    }
-    if (!TerminateProcess (h, 0))
+  }
+
+  if (GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (proc->control_pipe, GNUNET_DISK_PIPE_END_WRITE), &c, sizeof (c)) != sizeof (c))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to write into control pipe, errno is %d\n", errno);
+    bresult = 0;
+  }
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wrote control code into control pipe, now waiting\n");
+    SetLastError (0);
+    dwresult = WaitForSingleObject (proc->handle, 4*1000);
+    error_code = GetLastError ();
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Woke up, returned %d, GLE is %d\n", dwresult, error_code);
+    if (WAIT_OBJECT_0 != dwresult || error_code != NO_ERROR)
     {
-      SetErrnoFromWinError (GetLastError ());
-      return -1;
+      SetLastError (0);
+      bresult = TerminateProcess (proc->handle, 0);
+      error_code = GetLastError ();
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TerminateProcess for the child returned %d, GLE is %d\n", bresult, error_code);
     }
-    else
-      return 0;
   }
-  errno = EINVAL;
-  return -1;
+  if (error_code != NO_ERROR || !bresult)
+  {
+    return -1;
+  }
+  else
+    return 0;
 #else
   return kill (proc->pid, sig);
 #endif
@@ -363,19 +452,32 @@
   STARTUPINFO start;
   PROCESS_INFORMATION proc;
   struct GNUNET_OS_Process *gnunet_proc = NULL;
+  struct GNUNET_DISK_PipeHandle *control_pipe = NULL;
+  char *env_buf;
 
   HANDLE stdin_handle;
   HANDLE stdout_handle;
+  HANDLE control_pipe_read_end, control_pipe_write_end;
 
   char path[MAX_PATH + 1];
 
-  cmdlen = 0;
+  if ((HINSTANCE) 32 >= FindExecutableA (filename, NULL, path)) 
+    {
+      SetErrnoFromWinError (GetLastError ());
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
+      return NULL;
+    }
+
+  cmdlen = strlen (path) + 3;
   va_start (ap, filename);
   while (NULL != (arg = va_arg (ap, char *)))
+  {
       cmdlen = cmdlen + strlen (arg) + 3;
+  }
   va_end (ap);
 
   cmd = idx = GNUNET_malloc (sizeof (char) * (cmdlen + 1));
+  idx += sprintf (idx, "\"%s\" ", path);
   va_start (ap, filename);
   while (NULL != (arg = va_arg (ap, char *)))
       idx += sprintf (idx, "\"%s\" ", arg);
@@ -399,30 +501,42 @@
       start.hStdOutput = stdout_handle;
     }
 
-  if (32 >= FindExecutableA (filename, NULL, path)) 
-    {
-      SetErrnoFromWinError (GetLastError ());
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
-      return NULL;
-    }
+  control_pipe = GNUNET_DISK_pipe (GNUNET_NO, 1, 0);
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), &control_pipe_read_end, sizeof (HANDLE));
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_WRITE), &control_pipe_write_end, sizeof (HANDLE));
 
+  GNUNET_asprintf (&env_buf, "%s=%d", GNUNET_OS_NT_CONTROL_PIPE, control_pipe_read_end);
+  putenv (env_buf);
+  GNUNET_free (env_buf);
+
   if (!CreateProcessA
       (path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &start,
        &proc))
     {
       SetErrnoFromWinError (GetLastError ());
       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", path);
-      return NULL;
+      goto end;
     }
 
   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
   gnunet_proc->pid = proc.dwProcessId;
   gnunet_proc->handle = proc.hProcess;
+  gnunet_proc->control_pipe = control_pipe;
 
   CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
 
   CloseHandle (proc.hThread);
+end:
 
+  GNUNET_asprintf (&env_buf, "%s=", GNUNET_OS_NT_CONTROL_PIPE);
+  putenv (env_buf);
+  GNUNET_free (env_buf);
+
+  if (gnunet_proc == NULL)
+    GNUNET_DISK_pipe_close (control_pipe);
+  else
+    GNUNET_DISK_pipe_close_end (control_pipe, GNUNET_DISK_PIPE_END_READ);
+
   GNUNET_free (cmd);
 
   return gnunet_proc;
@@ -551,12 +665,14 @@
   PROCESS_INFORMATION proc;
   int argcount = 0;
   char non_const_filename[MAX_PATH +1];
-  int filenamelen = 0;
   struct GNUNET_OS_Process *gnunet_proc = NULL;
+  struct GNUNET_DISK_PipeHandle *control_pipe = NULL;
+  char *env_buf;
+  HANDLE control_pipe_read_end, control_pipe_write_end;
 
   GNUNET_assert (lsocks == NULL);
 
-  if (32 >= FindExecutableA (filename, NULL, non_const_filename)) 
+  if ((HINSTANCE) 32 >= FindExecutableA (filename, NULL, non_const_filename)) 
     {
       SetErrnoFromWinError (GetLastError ());
       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
@@ -579,7 +695,12 @@
   arg = (char **) argv;
   while (*arg)
     {
-      non_const_argv[argcount] = GNUNET_strdup (*arg);
+      if (argcount == 0)
+        /* Otherwise we'll get the argv[0] without .exe extension,
+           that will break libtool wrapper */
+        non_const_argv[argcount] = GNUNET_strdup (non_const_filename);
+      else
+        non_const_argv[argcount] = GNUNET_strdup (*arg);
       arg++;
       argcount++;
     }
@@ -606,22 +727,43 @@
   memset (&start, 0, sizeof (start));
   start.cb = sizeof (start);
 
-  if (!CreateProcess
-      (non_const_filename, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
+  control_pipe = GNUNET_DISK_pipe (GNUNET_NO, 1, 0);
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), &control_pipe_read_end, sizeof (HANDLE));
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_WRITE), &control_pipe_write_end, sizeof (HANDLE));
+
+
+  GNUNET_asprintf (&env_buf, "%s=%d", GNUNET_OS_NT_CONTROL_PIPE, control_pipe_read_end);
+  putenv (env_buf);
+  GNUNET_free (env_buf);
+
+  if (!CreateProcessA
+      (non_const_filename, cmd, NULL, NULL, TRUE,
+       DETACHED_PROCESS, NULL, NULL, &start,
        &proc))
     {
       SetErrnoFromWinError (GetLastError ());
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
-      return NULL;
+      goto end;
     }
 
   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
   gnunet_proc->pid = proc.dwProcessId;
   gnunet_proc->handle = proc.hProcess;
+  gnunet_proc->control_pipe = control_pipe;
 
   CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
 
   CloseHandle (proc.hThread);
+end:
+  GNUNET_asprintf (&env_buf, "%s=", GNUNET_OS_NT_CONTROL_PIPE);
+  putenv (env_buf);
+  GNUNET_free (env_buf);
+
+  if (gnunet_proc == NULL)
+    GNUNET_DISK_pipe_close (control_pipe);
+  else
+    GNUNET_DISK_pipe_close_end (control_pipe, GNUNET_DISK_PIPE_END_READ);
+
   GNUNET_free (cmd);
 
   while (argcount > 0)
Index: src/util/network.c
===================================================================
--- src/util/network.c	(revision 13603)
+++ src/util/network.c	(working copy)
@@ -470,8 +470,8 @@
 
 #ifdef MSG_DONTWAIT
   flags |= MSG_DONTWAIT;
+#endif
 
-#endif
   ret = recvfrom (desc->fd, buffer, length, flags, src_addr, addrlen);
 #ifdef MINGW
   if (SOCKET_ERROR == ret)
@@ -1138,9 +1138,19 @@
 
             {
               HANDLE h;
-              DWORD dwBytes;
+              DWORD dwBytes = 0, error_code;
+              BOOL bresult;
               h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);
-              if (!PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))
+              bresult = PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL);
+              error_code = GetLastError ();
+              /* FIXME: This should fail when the pipe is _really_ invalid,
+               * should skip the pipe if the error means that it's
+               * temporarily unavailable, and should succeed if the pipe
+               * is broken (or that the otherwise valid pipe is in a condition
+               * that prevents further reading). 
+               * For now it succeeds only when the pipe is broken or readable.
+               */
+              if (!bresult && error_code != ERROR_BROKEN_PIPE)
                 {
                   retcode = -1;
                   SetErrnoFromWinError (GetLastError ());
@@ -1152,7 +1162,7 @@
 #endif
                   goto select_loop_end;
                 }
-              else if (dwBytes)
+              else if (dwBytes || error_code == ERROR_BROKEN_PIPE)
 
                 {
                   GNUNET_CONTAINER_slist_add (handles_read,
Index: src/util/disk.c
===================================================================
--- src/util/disk.c	(revision 13603)
+++ src/util/disk.c	(working copy)
@@ -1910,4 +1910,95 @@
   return GNUNET_OK;
 }
 
+struct GNUNET_DISK_FileHandle
+GNUNET_DISK_file_from_internal_handle_ (void *src, size_t src_len)
+{
+  struct GNUNET_DISK_FileHandle ret;
+#ifdef MINGW
+  if (src_len == sizeof (HANDLE))
+    ret.h = *(HANDLE *) src;
+  else
+    ret.h = INVALID_HANDLE_VALUE;
+#else
+  if (src_len == sizeof (int))
+    ret.fd = *(int *) src;
+  else
+    ret.fd = -1;
+#endif
+  return ret;
+}
+
+struct GNUNET_DISK_PipeHandle *
+GNUNET_DISK_pipe_from_internal_handles_ (int blocking, void *src0, void *src1, size_t src_len)
+{
+  struct GNUNET_DISK_PipeHandle *p;
+  struct GNUNET_DISK_FileHandle *fds;
+
+  p =
+    GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
+                   2 * sizeof (struct GNUNET_DISK_FileHandle));
+  fds = (struct GNUNET_DISK_FileHandle *) &p[1];
+  p->fd[0] = &fds[0];
+  p->fd[1] = &fds[1];
+  fds[0] = GNUNET_DISK_file_from_internal_handle_ (src0, src_len);
+  fds[1] = GNUNET_DISK_file_from_internal_handle_ (src1, src_len);
+#ifndef MINGW
+  int fd[2];
+  int ret;
+  int flags;
+  int eno;
+
+  fd[0] = fds[0].fd;
+  fd[1] = fds[1].fd;
+  ret = 0;
+  if (fd[0] >= 0)
+  {
+    flags = fcntl (fd[0], F_GETFL);
+    if (!blocking)
+      flags |= O_NONBLOCK;
+    if (0 > fcntl (fd[0], F_SETFL, flags))
+      ret = -1;
+    flags = fcntl (fd[0], F_GETFD);
+    flags |= FD_CLOEXEC;
+    if (0 > fcntl (fd[0], F_SETFD, flags))
+      ret = -1;
+  }
+  if (fd[1] >= 0)
+  {
+    flags = fcntl (fd[1], F_GETFL);
+    if (!blocking)
+      flags |= O_NONBLOCK;
+    if (0 > fcntl (fd[1], F_SETFL, flags))
+      ret = -1;
+    flags = fcntl (fd[1], F_GETFD);
+    flags |= FD_CLOEXEC;
+    if (0 > fcntl (fd[1], F_SETFD, flags))
+      ret = -1;
+  }
+  if (ret == -1)
+    {
+      eno = errno;
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fcntl");
+      GNUNET_free (p);
+      errno = eno;
+      return NULL;    
+    }
+#else
+  /* Empirical fact: DuplicateHandle() on a handle inherited from the parent
+   * dies with ERROR_INVALID_HANDLE, so we won't try to duplicate these to
+   * make them inheritable/uninheritable.
+   */
+  if (!blocking)
+  {
+    DWORD mode;
+
+    mode = PIPE_NOWAIT;
+    SetNamedPipeHandleState (p->fd[0]->h, &mode, NULL, NULL);
+    SetNamedPipeHandleState (p->fd[1]->h, &mode, NULL, NULL);
+    /* this always fails on Windows 95, so we don't care about error handling */
+  }
+#endif
+  return p;
+}
+
 /* end of disk.c */
Index: src/util/connection.c
===================================================================
--- src/util/connection.c	(revision 13603)
+++ src/util/connection.c	(working copy)
@@ -461,7 +461,7 @@
   struct GNUNET_CONNECTION_Handle *sock = cls;
   GNUNET_CONNECTION_TransmitReadyNotify notify;
   struct AddressProbe *pos;
-  
+
   sock->destroy_task = GNUNET_SCHEDULER_NO_TASK;
   GNUNET_assert (sock->dns_active == NULL);
   if (0 != (sock->ccs & COCO_TRANSMIT_READY))
@@ -497,7 +497,11 @@
                   "Shutting down socket (%p)\n", sock);
 #endif
       if (sock->persist != GNUNET_YES)
-        GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR);
+      {
+        if (GNUNET_YES != GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR))
+          GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Socket shutdown didn't go well, errno is %d\n", errno);
+      }
     }
   if (sock->read_task != GNUNET_SCHEDULER_NO_TASK)
     {
@@ -945,6 +949,7 @@
   struct GNUNET_NETWORK_Handle *s;
   struct GNUNET_CONNECTION_Handle *ret;
 
+
   s = GNUNET_NETWORK_socket_create (af_family, SOCK_STREAM, 0);
   if (s == NULL)
     {
Index: src/util/disk.h
===================================================================
--- src/util/disk.h	(revision 13603)
+++ src/util/disk.h	(working copy)
@@ -1,75 +1,71 @@
-/*
-     This file is part of GNUnet.
-     (C) 2009 Christian Grothoff (and other contributing authors)
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
-*/  
-  
-/**
- * @file util/disk.h
- * @brief Internal DISK related helper functions
- * @author Nils Durner
- */ 
-  
-
-#ifndef GNUNET_DISK_H_
-#define GNUNET_DISK_H_
-  
-#include "gnunet_disk_lib.h"
-  
-
-/**
- * Handle used to access files (and pipes).  
- */ 
-struct GNUNET_DISK_FileHandle 
+/*
+     This file is part of GNUnet.
+     (C) 2009 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 2, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/  
+  
+/**
+ * @file util/disk.h
+ * @brief Internal DISK related helper functions
+ * @author Nils Durner
+ */ 
+  
+#ifndef GNUNET_DISK_H_
+#define GNUNET_DISK_H_
+  
+#include "gnunet_disk_lib.h"
+  
+/**
+ * Handle used to access files (and pipes).  
+ */ 
+struct GNUNET_DISK_FileHandle 
 {
-  
-#ifdef MINGW
-  /**
-   * File handle under W32.
-   */ 
+  
+#ifdef MINGW
+  /**
+   * File handle under W32.
+   */ 
   HANDLE h;
-  
+  
 #else                           /* 
  */
-  /**
-   * File handle on other OSes.
-   */ 
+  /**
+   * File handle on other OSes.
+   */ 
   int fd;
-   
+   
 #endif                          /* 
  */
 };
-
-
-
-
-/**
- * Retrieve OS file handle
- *
- * @internal
- * @param fh GNUnet file descriptor
- * @param dst destination buffer
- * @param dst_len length of dst
- * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
- */ 
+
+/**
+ * Retrieve OS file handle
+ *
+ * @internal
+ * @param fh GNUnet file descriptor
+ * @param dst destination buffer
+ * @param dst_len length of dst
+ * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
+ */ 
 int GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle
                                        *fh, 
 void *dst, 
 size_t dst_len);
-
-
-#endif  /* GNUNET_DISK_H_ */
+
+struct GNUNET_DISK_PipeHandle *GNUNET_DISK_pipe_from_internal_handles_ (int blocking, void *src0, void *src1, size_t src_len);
+
+#endif  /* GNUNET_DISK_H_ */
pipes_sockets_and_stuff.diff (46,269 bytes)   
pipes_sockets_and_stuff_2_pipes.diff (18,696 bytes)   
Index: src/include/gnunet_os_lib.h
===================================================================
--- src/include/gnunet_os_lib.h	(revision 13625)
+++ src/include/gnunet_os_lib.h	(working copy)
@@ -273,6 +273,18 @@
  */
 int GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc);
 
+/**
+ * Read env variable and set up the read end of the control
+ * pipe that parent uses to send signals to this process.
+ *
+ * Only does something on Windows
+ *
+ * @param cls user-specified parameter (NULL)
+ * @param tc task context
+ */
+void GNUNET_OS_install_parent_control_handler (void *cls,
+                                               const struct
+                                               GNUNET_SCHEDULER_TaskContext * tc);
 
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
Index: src/util/scheduler.c
===================================================================
--- src/util/scheduler.c	(revision 13625)
+++ src/util/scheduler.c	(working copy)
@@ -744,6 +744,7 @@
   shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, &sighandler_shutdown);
 #endif
   current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT;
+  GNUNET_SCHEDULER_add_continuation (GNUNET_OS_install_parent_control_handler, NULL, GNUNET_SCHEDULER_REASON_STARTUP);
   GNUNET_SCHEDULER_add_continuation (task,
                                      task_cls,
                                      GNUNET_SCHEDULER_REASON_STARTUP);
@@ -1351,8 +1352,7 @@
   GNUNET_assert (rfd != NULL);
   rs = GNUNET_NETWORK_fdset_create ();
   GNUNET_NETWORK_fdset_handle_set (rs, rfd);
-  ret = GNUNET_SCHEDULER_add_select (sched,
-                                     GNUNET_SCHEDULER_PRIORITY_KEEP,
+  ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_KEEP,
                                      GNUNET_SCHEDULER_NO_TASK, delay,
                                      rs, NULL, task, task_cls);
   GNUNET_NETWORK_fdset_destroy (rs);
@@ -1400,8 +1400,7 @@
   GNUNET_assert (wfd != NULL);
   ws = GNUNET_NETWORK_fdset_create ();
   GNUNET_NETWORK_fdset_handle_set (ws, wfd);
-  ret = GNUNET_SCHEDULER_add_select (sched,
-                                     GNUNET_SCHEDULER_PRIORITY_KEEP,
+  ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_KEEP,
                                      GNUNET_SCHEDULER_NO_TASK,
                                      delay, NULL, ws, task, task_cls);
   GNUNET_NETWORK_fdset_destroy (ws);
Index: src/util/os_priority.c
===================================================================
--- src/util/os_priority.c	(revision 13625)
+++ src/util/os_priority.c	(working copy)
@@ -29,28 +29,95 @@
 #include "gnunet_os_lib.h"
 #include "disk.h"
 
+#define GNUNET_OS_NT_CONTROL_PIPE "GNUNET_OS_NT_CONTROL_PIPE"
+
 struct GNUNET_OS_Process
 {
   pid_t pid;
 #if WINDOWS
   HANDLE handle;
+  struct GNUNET_DISK_PipeHandle *control_pipe;
 #endif
 };
 
 static struct GNUNET_OS_Process current_process;
 
-
 #if WINDOWS
-void
-GNUNET_OS_process_set_handle(struct GNUNET_OS_Process *proc, HANDLE handle)
+void GNUNET_OS_parent_control_handler (void *cls,
+                                       const struct
+                                       GNUNET_SCHEDULER_TaskContext * tc)
 {
-  if (proc->handle != NULL)
-    CloseHandle (proc->handle);
-  proc->handle = handle;
+  struct GNUNET_DISK_PipeHandle *control_pipe = (struct GNUNET_DISK_PipeHandle *) cls;
+  unsigned char code;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_OS_parent_control_handler is invoked because of %d\n", tc->reason);
+
+  if (tc->reason & (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT | GNUNET_SCHEDULER_REASON_PREREQ_DONE))
+  {
+      GNUNET_DISK_pipe_close (control_pipe);
+  }
+  else
+  {
+    if (GNUNET_DISK_file_read (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), &code, sizeof (char)) != sizeof (char))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_DISK_file_read have failed, errno = %d. Closing the control pipe.\n", errno);
+      GNUNET_DISK_pipe_close (control_pipe);
+    }
+    else
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got control code %d\n", code);
+      switch (code)
+      {
+        case 0:
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Raising SIGTERM\n");
+          raise (SIGTERM);
+          break;
+        case 1:
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Raising SIGKILL\n");
+          raise (SIGKILL);
+          break;
+        case 255:
+          /* read more bytes - a possibility for extended signals
+           * in case 254 different valies is not enough
+           */
+          break;
+        default:
+          break;
+      }
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Re-adding parent control handler pipe to the scheduler\n");
+      GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), GNUNET_OS_parent_control_handler, control_pipe);
+    }
+  }
 }
 #endif
 
+void
+GNUNET_OS_install_parent_control_handler (void *cls,
+                                          const struct
+                                          GNUNET_SCHEDULER_TaskContext * tc)
+{
+#ifdef WINDOWS
+  char *env_buf;
+  char *endptr;
+  HANDLE control_pipe_end[2];
+  struct GNUNET_DISK_PipeHandle *control_pipe = NULL;
 
+  env_buf = getenv (GNUNET_OS_NT_CONTROL_PIPE);
+  if (env_buf == NULL || strlen (env_buf) <= 0 || env_buf[0] < '0' || env_buf[0] > '9')
+    return;
+
+  control_pipe_end[0] = (HANDLE) strtol (env_buf, &endptr, 10);
+  control_pipe_end[1] = INVALID_HANDLE_VALUE;
+ 
+  control_pipe = GNUNET_DISK_pipe_from_internal_handles_ (GNUNET_NO, &control_pipe_end[0], &control_pipe_end[1], sizeof (HANDLE));
+  if (control_pipe == NULL)
+    return;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding parent control handler pipe to the scheduler\n");
+  GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), GNUNET_OS_parent_control_handler, control_pipe);
+#endif
+}
+
 /**
  * Get process structure for current process
  *
@@ -66,7 +133,7 @@
   current_process.pid = GetCurrentProcessId ();
   current_process.handle = GetCurrentProcess ();
 #else
-  current_process.pid = 0;
+  current_process.pid = getpid ();
 #endif
   return &current_process;
 }
@@ -75,27 +142,49 @@
 GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
 {
 #if WINDOWS
-  if (sig == SIGKILL || sig == SIGTERM)
+  unsigned char c;
+  DWORD dwresult, error_code = NO_ERROR;
+  BOOL bresult = 1;
+
+  switch (sig)
   {
-    HANDLE h = proc->handle;
-    if (NULL == h)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-		  _("Invalid process information {%d, %08X}\n"),
-		  proc->pid,
-		  h);
+    case SIGKILL:
+      c = 1;
+      break;
+    case SIGTERM:
+      c = 0;
+      break;
+    default:
+      errno = EINVAL;
       return -1;
-    }
-    if (!TerminateProcess (h, 0))
+  }
+
+  if (GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (proc->control_pipe, GNUNET_DISK_PIPE_END_WRITE), &c, sizeof (c)) != sizeof (c))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to write into control pipe, errno is %d\n", errno);
+    bresult = 0;
+  }
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wrote control code into control pipe, now waiting\n");
+    SetLastError (0);
+    dwresult = WaitForSingleObject (proc->handle, 4*1000);
+    error_code = GetLastError ();
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Woke up, returned %d, GLE is %d\n", dwresult, error_code);
+    if (WAIT_OBJECT_0 != dwresult || error_code != NO_ERROR)
     {
-      SetErrnoFromWinError (GetLastError ());
-      return -1;
+      SetLastError (0);
+      bresult = TerminateProcess (proc->handle, 0);
+      error_code = GetLastError ();
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TerminateProcess for the child returned %d, GLE is %d\n", bresult, error_code);
     }
-    else
-      return 0;
   }
-  errno = EINVAL;
-  return -1;
+  if (error_code != NO_ERROR || !bresult)
+  {
+    return -1;
+  }
+  else
+    return 0;
 #else
   return kill (proc->pid, sig);
 #endif
@@ -130,15 +219,10 @@
 extern GNUNET_SIGNAL_Handler w32_sigchld_handler;
 
 /**
- * Make seaspider happy.
- */
-#define DWORD_WINAPI DWORD WINAPI
-
-/**
  * @brief Waits for a process to terminate and invokes the SIGCHLD handler
  * @param proc pointer to process structure
  */
-static DWORD_WINAPI
+static DWORD WINAPI
 ChildWaitThread (void *arg)
 {
   struct GNUNET_OS_Process *proc = (struct GNUNET_OS_Process *) arg;
@@ -368,19 +452,32 @@
   STARTUPINFO start;
   PROCESS_INFORMATION proc;
   struct GNUNET_OS_Process *gnunet_proc = NULL;
+  struct GNUNET_DISK_PipeHandle *control_pipe = NULL;
+  char *env_buf;
 
   HANDLE stdin_handle;
   HANDLE stdout_handle;
+  HANDLE control_pipe_read_end, control_pipe_write_end;
 
   char path[MAX_PATH + 1];
 
-  cmdlen = 0;
+  if ((HINSTANCE) 32 >= FindExecutableA (filename, NULL, path)) 
+    {
+      SetErrnoFromWinError (GetLastError ());
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
+      return NULL;
+    }
+
+  cmdlen = strlen (path) + 3;
   va_start (ap, filename);
   while (NULL != (arg = va_arg (ap, char *)))
+  {
       cmdlen = cmdlen + strlen (arg) + 3;
+  }
   va_end (ap);
 
   cmd = idx = GNUNET_malloc (sizeof (char) * (cmdlen + 1));
+  idx += sprintf (idx, "\"%s\" ", path);
   va_start (ap, filename);
   while (NULL != (arg = va_arg (ap, char *)))
       idx += sprintf (idx, "\"%s\" ", arg);
@@ -404,30 +501,42 @@
       start.hStdOutput = stdout_handle;
     }
 
-  if (32 >= (int) FindExecutableA (filename, NULL, path)) 
-    {
-      SetErrnoFromWinError (GetLastError ());
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
-      return NULL;
-    }
+  control_pipe = GNUNET_DISK_pipe (GNUNET_NO, 1, 0);
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), &control_pipe_read_end, sizeof (HANDLE));
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_WRITE), &control_pipe_write_end, sizeof (HANDLE));
 
+  GNUNET_asprintf (&env_buf, "%s=%d", GNUNET_OS_NT_CONTROL_PIPE, control_pipe_read_end);
+  putenv (env_buf);
+  GNUNET_free (env_buf);
+
   if (!CreateProcessA
       (path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &start,
        &proc))
     {
       SetErrnoFromWinError (GetLastError ());
       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", path);
-      return NULL;
+      goto end;
     }
 
   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
   gnunet_proc->pid = proc.dwProcessId;
   gnunet_proc->handle = proc.hProcess;
+  gnunet_proc->control_pipe = control_pipe;
 
   CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
 
   CloseHandle (proc.hThread);
+end:
 
+  GNUNET_asprintf (&env_buf, "%s=", GNUNET_OS_NT_CONTROL_PIPE);
+  putenv (env_buf);
+  GNUNET_free (env_buf);
+
+  if (gnunet_proc == NULL)
+    GNUNET_DISK_pipe_close (control_pipe);
+  else
+    GNUNET_DISK_pipe_close_end (control_pipe, GNUNET_DISK_PIPE_END_READ);
+
   GNUNET_free (cmd);
 
   return gnunet_proc;
@@ -557,10 +666,13 @@
   int argcount = 0;
   char non_const_filename[MAX_PATH +1];
   struct GNUNET_OS_Process *gnunet_proc = NULL;
+  struct GNUNET_DISK_PipeHandle *control_pipe = NULL;
+  char *env_buf;
+  HANDLE control_pipe_read_end, control_pipe_write_end;
 
   GNUNET_assert (lsocks == NULL);
 
-  if (32 >= (int) FindExecutableA (filename, NULL, non_const_filename)) 
+  if ((HINSTANCE) 32 >= FindExecutableA (filename, NULL, non_const_filename)) 
     {
       SetErrnoFromWinError (GetLastError ());
       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
@@ -583,7 +695,12 @@
   arg = (char **) argv;
   while (*arg)
     {
-      non_const_argv[argcount] = GNUNET_strdup (*arg);
+      if (argcount == 0)
+        /* Otherwise we'll get the argv[0] without .exe extension,
+           that will break libtool wrapper */
+        non_const_argv[argcount] = GNUNET_strdup (non_const_filename);
+      else
+        non_const_argv[argcount] = GNUNET_strdup (*arg);
       arg++;
       argcount++;
     }
@@ -610,22 +727,43 @@
   memset (&start, 0, sizeof (start));
   start.cb = sizeof (start);
 
-  if (!CreateProcess
-      (non_const_filename, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
+  control_pipe = GNUNET_DISK_pipe (GNUNET_NO, 1, 0);
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), &control_pipe_read_end, sizeof (HANDLE));
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_WRITE), &control_pipe_write_end, sizeof (HANDLE));
+
+
+  GNUNET_asprintf (&env_buf, "%s=%d", GNUNET_OS_NT_CONTROL_PIPE, control_pipe_read_end);
+  putenv (env_buf);
+  GNUNET_free (env_buf);
+
+  if (!CreateProcessA
+      (non_const_filename, cmd, NULL, NULL, TRUE,
+       DETACHED_PROCESS, NULL, NULL, &start,
        &proc))
     {
       SetErrnoFromWinError (GetLastError ());
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
-      return NULL;
+      goto end;
     }
 
   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
   gnunet_proc->pid = proc.dwProcessId;
   gnunet_proc->handle = proc.hProcess;
+  gnunet_proc->control_pipe = control_pipe;
 
   CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
 
   CloseHandle (proc.hThread);
+end:
+  GNUNET_asprintf (&env_buf, "%s=", GNUNET_OS_NT_CONTROL_PIPE);
+  putenv (env_buf);
+  GNUNET_free (env_buf);
+
+  if (gnunet_proc == NULL)
+    GNUNET_DISK_pipe_close (control_pipe);
+  else
+    GNUNET_DISK_pipe_close_end (control_pipe, GNUNET_DISK_PIPE_END_READ);
+
   GNUNET_free (cmd);
 
   while (argcount > 0)
Index: src/util/network.c
===================================================================
--- src/util/network.c	(revision 13625)
+++ src/util/network.c	(working copy)
@@ -470,8 +470,8 @@
 
 #ifdef MSG_DONTWAIT
   flags |= MSG_DONTWAIT;
+#endif
 
-#endif
   ret = recvfrom (desc->fd, buffer, length, flags, src_addr, addrlen);
 #ifdef MINGW
   if (SOCKET_ERROR == ret)
@@ -1138,9 +1138,19 @@
 
             {
               HANDLE h;
-              DWORD dwBytes;
+              DWORD dwBytes = 0, error_code;
+              BOOL bresult;
               h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);
-              if (!PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))
+              bresult = PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL);
+              error_code = GetLastError ();
+              /* FIXME: This should fail when the pipe is _really_ invalid,
+               * should skip the pipe if the error means that it's
+               * temporarily unavailable, and should succeed if the pipe
+               * is broken (or that the otherwise valid pipe is in a condition
+               * that prevents further reading). 
+               * For now it succeeds only when the pipe is broken or readable.
+               */
+              if (!bresult && error_code != ERROR_BROKEN_PIPE)
                 {
                   retcode = -1;
                   SetErrnoFromWinError (GetLastError ());
@@ -1152,7 +1162,7 @@
 #endif
                   goto select_loop_end;
                 }
-              else if (dwBytes)
+              else if (dwBytes || error_code == ERROR_BROKEN_PIPE)
 
                 {
                   GNUNET_CONTAINER_slist_add (handles_read,
Index: src/util/disk.c
===================================================================
--- src/util/disk.c	(revision 13625)
+++ src/util/disk.c	(working copy)
@@ -1910,4 +1910,95 @@
   return GNUNET_OK;
 }
 
+struct GNUNET_DISK_FileHandle
+GNUNET_DISK_file_from_internal_handle_ (void *src, size_t src_len)
+{
+  struct GNUNET_DISK_FileHandle ret;
+#ifdef MINGW
+  if (src_len == sizeof (HANDLE))
+    ret.h = *(HANDLE *) src;
+  else
+    ret.h = INVALID_HANDLE_VALUE;
+#else
+  if (src_len == sizeof (int))
+    ret.fd = *(int *) src;
+  else
+    ret.fd = -1;
+#endif
+  return ret;
+}
+
+struct GNUNET_DISK_PipeHandle *
+GNUNET_DISK_pipe_from_internal_handles_ (int blocking, void *src0, void *src1, size_t src_len)
+{
+  struct GNUNET_DISK_PipeHandle *p;
+  struct GNUNET_DISK_FileHandle *fds;
+
+  p =
+    GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
+                   2 * sizeof (struct GNUNET_DISK_FileHandle));
+  fds = (struct GNUNET_DISK_FileHandle *) &p[1];
+  p->fd[0] = &fds[0];
+  p->fd[1] = &fds[1];
+  fds[0] = GNUNET_DISK_file_from_internal_handle_ (src0, src_len);
+  fds[1] = GNUNET_DISK_file_from_internal_handle_ (src1, src_len);
+#ifndef MINGW
+  int fd[2];
+  int ret;
+  int flags;
+  int eno;
+
+  fd[0] = fds[0].fd;
+  fd[1] = fds[1].fd;
+  ret = 0;
+  if (fd[0] >= 0)
+  {
+    flags = fcntl (fd[0], F_GETFL);
+    if (!blocking)
+      flags |= O_NONBLOCK;
+    if (0 > fcntl (fd[0], F_SETFL, flags))
+      ret = -1;
+    flags = fcntl (fd[0], F_GETFD);
+    flags |= FD_CLOEXEC;
+    if (0 > fcntl (fd[0], F_SETFD, flags))
+      ret = -1;
+  }
+  if (fd[1] >= 0)
+  {
+    flags = fcntl (fd[1], F_GETFL);
+    if (!blocking)
+      flags |= O_NONBLOCK;
+    if (0 > fcntl (fd[1], F_SETFL, flags))
+      ret = -1;
+    flags = fcntl (fd[1], F_GETFD);
+    flags |= FD_CLOEXEC;
+    if (0 > fcntl (fd[1], F_SETFD, flags))
+      ret = -1;
+  }
+  if (ret == -1)
+    {
+      eno = errno;
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fcntl");
+      GNUNET_free (p);
+      errno = eno;
+      return NULL;    
+    }
+#else
+  /* Empirical fact: DuplicateHandle() on a handle inherited from the parent
+   * dies with ERROR_INVALID_HANDLE, so we won't try to duplicate these to
+   * make them inheritable/uninheritable.
+   */
+  if (!blocking)
+  {
+    DWORD mode;
+
+    mode = PIPE_NOWAIT;
+    SetNamedPipeHandleState (p->fd[0]->h, &mode, NULL, NULL);
+    SetNamedPipeHandleState (p->fd[1]->h, &mode, NULL, NULL);
+    /* this always fails on Windows 95, so we don't care about error handling */
+  }
+#endif
+  return p;
+}
+
 /* end of disk.c */
Index: src/util/disk.h
===================================================================
--- src/util/disk.h	(revision 13625)
+++ src/util/disk.h	(working copy)
@@ -72,4 +72,8 @@
 size_t dst_len);
 
 
+struct GNUNET_DISK_PipeHandle *GNUNET_DISK_pipe_from_internal_handles_ (int blocking, void *src0, void *src1, size_t src_len);
+
+
+
 #endif  /* GNUNET_DISK_H_ */
pipes_sockets_and_stuff_2_sockets.diff (11,878 bytes)   
Index: src/arm/gnunet-service-arm_interceptor.c
===================================================================
--- src/arm/gnunet-service-arm_interceptor.c	(revision 13625)
+++ src/arm/gnunet-service-arm_interceptor.c	(working copy)
@@ -187,9 +187,15 @@
    * Have we ever successfully written data to the service?
    */
   int first_write_done;
+
+
+  /**
+   * Service connection attempts
+   */
+  struct ServiceListeningInfo *service_connect_ipv4;
+  struct ServiceListeningInfo *service_connect_ipv6;
 };
 
-
 /**
  * Array with the names of the services started by default.
  */
@@ -694,6 +700,10 @@
 				      &forwardToService, fc);
 }
 
+static void fc_acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc, int is_ipv4, int is_ipv6);
+static void fc_acceptConnection_ipv4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+static void fc_acceptConnection_ipv6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+static int service_try_to_connect (struct sockaddr *addr, socklen_t addrlen, struct ForwardedConnection *fc);
 
 /**
  *
@@ -704,103 +714,252 @@
 {
   struct ForwardedConnection *fc = cls;
   struct GNUNET_TIME_Relative rem;
+  int fail = 0;
+  int failures = 0;
+  int is_zero = 0, is_ipv6 = 0, is_ipv4 = 0;
+  struct sockaddr_in *target_ipv4;
+  struct sockaddr_in6 *target_ipv6;
 
+  int free_ipv4 = 1, free_ipv6 = 1;
+  char listen_address[128];
+  uint16_t listening_port;
+
   fc->start_task = GNUNET_SCHEDULER_NO_TASK;
   if ( (NULL != tc) &&
        (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) )
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-		  _("Unable to forward to service `%s': shutdown\n"),
-		  fc->listen_info->serviceName);
-      closeClientAndServiceSockets (fc, REASON_ERROR);
-      return;
-    }
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+		_("Unable to forward to service `%s': shutdown\n"),
+		fc->listen_info->serviceName);
+    closeClientAndServiceSockets (fc, REASON_ERROR);
+    return;
+  }
   rem = GNUNET_TIME_absolute_get_remaining (fc->timeout);
   if (rem.rel_value == 0)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+		_("Unable to forward to service `%s': timeout before connect\n"),
+		fc->listen_info->serviceName);
+    closeClientAndServiceSockets (fc, REASON_ERROR);
+    return;
+  }
+  target_ipv4 = GNUNET_malloc (sizeof (struct sockaddr_in));
+  target_ipv6 = GNUNET_malloc (sizeof (struct sockaddr_in6));
+
+  switch (fc->listen_info->service_addr->sa_family)
+  {
+  case AF_INET:
+    inet_ntop (fc->listen_info->service_addr->sa_family, (const void *) &((struct sockaddr_in *) fc->listen_info->service_addr)->sin_addr, listen_address, INET_ADDRSTRLEN);
+    if (strncmp (listen_address, "0.0.0.0:", 8) == 0 || strncmp (listen_address, "0.0.0.0", 7) == 0)
+      is_zero = 1;
+    is_ipv4 = 1;
+    listening_port = ((struct sockaddr_in *)fc->listen_info->service_addr)->sin_port;
+    break;
+  case AF_INET6:
+    inet_ntop (fc->listen_info->service_addr->sa_family, (const void *) &((struct sockaddr_in6 *) fc->listen_info->service_addr)->sin6_addr, listen_address, INET6_ADDRSTRLEN);
+    if (strncmp (listen_address, "[::]:", 5) == 0 || strncmp (listen_address, "::", 2) == 0)
+      is_zero = 1;
+    is_ipv6 = 1;
+    listening_port = ((struct sockaddr_in6 *)fc->listen_info->service_addr)->sin6_port;
+    break;
+  default:
+    break;
+  }
+
+  fc->service_connect_ipv4 = NULL;
+  fc->service_connect_ipv6 = NULL;
+  if (is_zero)
+  {
+    /* connect to [::1] and 127.0.0.1 instead of [::] and 0.0.0.0 */
+    inet_pton (AF_INET, "127.0.0.1", &target_ipv4->sin_addr);
+    target_ipv4->sin_family = AF_INET;
+    target_ipv4->sin_port = listening_port;
+    is_ipv4 = 1;
+    free_ipv4 = 0;
+
+    inet_pton (AF_INET6, "0:0:0:0:0:0:0:1", &target_ipv6->sin6_addr);
+    target_ipv6->sin6_family = AF_INET6;
+    target_ipv6->sin6_port = listening_port;
+    is_ipv6 = 1;
+    free_ipv6 = 0;
+  }
+  else
+  {
+    if (is_ipv4)
+      memcpy (target_ipv4, fc->listen_info->service_addr, sizeof (struct sockaddr_in));
+    else if (is_ipv6)
+      memcpy (target_ipv6, fc->listen_info->service_addr, sizeof (struct sockaddr_in6));
+  }
+
+  if (is_ipv4)
+    failures += free_ipv4 = service_try_to_connect ((struct sockaddr *) target_ipv4, sizeof (struct sockaddr_in), fc);
+  if (is_ipv6)
+    failures += free_ipv6 = service_try_to_connect ((struct sockaddr *) target_ipv6, sizeof (struct sockaddr_in6), fc);
+
+  if (is_ipv4 + is_ipv6 <= failures)
+    fail = 1;
+
+  if (free_ipv4)
+    GNUNET_free (target_ipv4);
+  if (free_ipv6)
+    GNUNET_free (target_ipv6);
+
+  if (fail)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _ ("Unable to start service `%s': %s\n"),
+		fc->listen_info->serviceName,
+		STRERROR (errno));
+    closeClientAndServiceSockets (fc, REASON_ERROR);
+    return;
+  }
+}
+
+static void
+fc_acceptConnection_ipv4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  fc_acceptConnection (cls, tc, 1, 0);
+}
+
+static void
+fc_acceptConnection_ipv6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  fc_acceptConnection (cls, tc, 0, 1);
+}
+
+static void
+fc_acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc, int is_ipv4, int is_ipv6)
+{
+  struct ForwardedConnection *fc = cls;
+  struct ServiceListeningInfo *sli;
+
+  if (is_ipv4)
+    sli = fc->service_connect_ipv4;
+  else if (is_ipv6)
+    sli = fc->service_connect_ipv6;
+  else
+    GNUNET_break (0);
+
+  if ((tc->reason & (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT | GNUNET_SCHEDULER_REASON_PREREQ_DONE)) || ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) && fc->armServiceSocket))
+  {
+    GNUNET_NETWORK_socket_close (sli->listeningSocket);
+    if (is_ipv4)
+      fc->service_connect_ipv4 = NULL;
+    else if (is_ipv6)
+      fc->service_connect_ipv6 = NULL;
+  }
+  else if (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)
+  {
+#if DEBUG_SERVICE_MANAGER
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+       "Connected to service, now starting forwarding\n");
+#endif
+    fc->armServiceSocket = sli->listeningSocket;
+    if ((is_ipv4 && fc->service_connect_ipv6 != NULL))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-		  _("Unable to forward to service `%s': timeout before connect\n"),
-		  fc->listen_info->serviceName);
-      closeClientAndServiceSockets (fc, REASON_ERROR);
-      return;
+      GNUNET_SCHEDULER_cancel (fc->service_connect_ipv6->acceptTask);
+      fc->service_connect_ipv6->acceptTask = GNUNET_SCHEDULER_add_now (fc_acceptConnection_ipv6, fc);
     }
-  fc->armServiceSocket =
-    GNUNET_NETWORK_socket_create (fc->listen_info->service_addr->sa_family,
-				  SOCK_STREAM, 0);
-  if (NULL == fc->armServiceSocket)
+    else if (is_ipv6 && fc->service_connect_ipv4 != NULL)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-		  _ ("Unable to start service `%s': %s\n"),
-		  fc->listen_info->serviceName,
-		  STRERROR (errno));
-      closeClientAndServiceSockets (fc, REASON_ERROR);
-      return;
+      GNUNET_SCHEDULER_cancel (fc->service_connect_ipv4->acceptTask);
+      fc->service_connect_ipv4->acceptTask = GNUNET_SCHEDULER_add_now (fc_acceptConnection_ipv4, fc);
     }
-  if ( (GNUNET_SYSERR ==
-	GNUNET_NETWORK_socket_connect (fc->armServiceSocket,
-				       fc->listen_info->service_addr,
-				       fc->listen_info->service_addr_len)) &&
-       (errno != EINPROGRESS) )
+    GNUNET_free (fc->listen_info->service_addr);
+    fc->listen_info->service_addr = sli->service_addr;
+    fc->listen_info->service_addr_len = sli->service_addr_len;
+    /*fc->listen_info->listeningSocket is it closed already?*/
+    if (fc->client_to_service_task == GNUNET_SCHEDULER_NO_TASK)
     {
-      GNUNET_break (GNUNET_OK ==
-		    GNUNET_NETWORK_socket_close (fc->armServiceSocket));
-      fc->armServiceSocket = NULL;
-      fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2);
-  #if DEBUG_SERVICE_MANAGER
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-		  "Failed to connected to service `%s' at `%s', will try again in %llu ms\n",
-		  fc->listen_info->serviceName,
-		  GNUNET_a2s (fc->listen_info->service_addr,
-			      fc->listen_info->service_addr_len),
-		  (unsigned long long) GNUNET_TIME_relative_min (fc->back_off,
-								 rem).rel_value);
-#endif
-      GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
-      fc->start_task
-	= GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_min (fc->back_off,
-								  rem),
-					&start_forwarding,
-					fc);
-      return;
-    }
-#if DEBUG_SERVICE_MANAGER
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-	      "Connected to service, now starting forwarding\n");
-#endif
-  if (fc->client_to_service_task == GNUNET_SCHEDULER_NO_TASK)
-    {
       if (fc->client_to_service_bufferDataLength == 0) 
-	fc->client_to_service_task =
-	  GNUNET_SCHEDULER_add_read_net (
+	  fc->client_to_service_task =
+	    GNUNET_SCHEDULER_add_read_net (
 					 GNUNET_TIME_UNIT_FOREVER_REL,
 					 fc->armClientSocket,
 					 &receiveFromClient, fc);
       else
-	fc->client_to_service_task = 
-	  GNUNET_SCHEDULER_add_write_net (
+	  fc->client_to_service_task = 
+	    GNUNET_SCHEDULER_add_write_net (
 					  GNUNET_TIME_UNIT_FOREVER_REL,
 					  fc->armServiceSocket,
 					  &forwardToService, fc);
     }
-  if (fc->service_to_client_task == GNUNET_SCHEDULER_NO_TASK)
+    if (fc->service_to_client_task == GNUNET_SCHEDULER_NO_TASK)
     {
       if (fc->service_to_client_bufferDataLength == 0) 
-	fc->service_to_client_task =
-	  GNUNET_SCHEDULER_add_read_net (
+	  fc->service_to_client_task =
+	    GNUNET_SCHEDULER_add_read_net (
 					 GNUNET_TIME_UNIT_FOREVER_REL,
 					 fc->armServiceSocket,
 					 &receiveFromService, fc);
       else
-	fc->service_to_client_task = 
-	  GNUNET_SCHEDULER_add_write_net (
+	  fc->service_to_client_task = 
+	    GNUNET_SCHEDULER_add_write_net (
 					  GNUNET_TIME_UNIT_FOREVER_REL,
 					  fc->armClientSocket,
 					  &forwardToClient, fc);
     }
+  }
+  else
+  {
+    GNUNET_break (0);
+  }
+  GNUNET_free (sli);
 }
 
+static int
+service_try_to_connect (struct sockaddr *addr, socklen_t addrlen, struct ForwardedConnection *fc)
+{
+  struct GNUNET_NETWORK_Handle *sock;
+  struct ServiceListeningInfo *serviceListeningInfo;
 
+  sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
+  if (sock == NULL)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to create a socket\n");
+    return 1;
+  }
+  
+  if ( (GNUNET_SYSERR == GNUNET_NETWORK_socket_connect (sock, addr, addrlen)) &&
+       (errno != EINPROGRESS) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect\n");
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
+    return 1;
+  }
 
+  serviceListeningInfo = GNUNET_malloc (sizeof (struct ServiceListeningInfo));
+  serviceListeningInfo->serviceName = NULL;
+  serviceListeningInfo->service_addr = addr;
+  serviceListeningInfo->service_addr_len = addrlen;
+  serviceListeningInfo->listeningSocket = sock;
+
+  switch (addrlen)
+  {
+  case sizeof (struct sockaddr_in):
+    fc->service_connect_ipv4 = serviceListeningInfo;
+    serviceListeningInfo->acceptTask =
+        GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                        serviceListeningInfo->listeningSocket,
+				        &fc_acceptConnection_ipv4, fc);
+    break;
+  case sizeof (struct sockaddr_in6):
+    fc->service_connect_ipv6 = serviceListeningInfo;
+    serviceListeningInfo->acceptTask =
+        GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                        serviceListeningInfo->listeningSocket,
+				        &fc_acceptConnection_ipv6, fc);
+    break;
+  default:
+    GNUNET_break (0);
+    return 1;
+    break;
+  }
+  return 0;
+}
+
+
+
 /**
  *
  */
0001-W32-Parent-child-control-pipe.patch (21,016 bytes)   
From edbe7000c8c3c77e4e67b2e4b17a71133a579194 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= <lrn1986@gmail.com>
Date: Wed, 10 Nov 2010 12:59:14 +0300
Subject: [PATCH 1/2] [W32] Parent->child control pipe

* GNUNET_OS_start_process* () will create a pipe that is inheritable by the child and place its HANDLE into environment variable table to be passed to the child
* GNUNET_SCHEDULER_run () will call a function that will read this variable and start a thread to handle data coming from the pipe
* GNUNET_OS_process_kill () will write control codes into the pipe, wait for the child to die, and use TerminateProcess() on it in case the wait times out
* Extra functions to create GNUNET_DISK_PIPE from existing native handles
* Extra functions (W32-only) for working with environment tables
---
 src/include/gnunet_os_lib.h |   12 ++
 src/util/disk.c             |   90 +++++++++++++
 src/util/disk.h             |    2 +
 src/util/network.c          |   16 ++-
 src/util/os_priority.c      |  297 +++++++++++++++++++++++++++++++++++++-----
 src/util/scheduler.c        |    2 +
 6 files changed, 380 insertions(+), 39 deletions(-)

diff --git a/src/include/gnunet_os_lib.h b/src/include/gnunet_os_lib.h
index 5ff2b48..6bc6035 100644
--- a/src/include/gnunet_os_lib.h
+++ b/src/include/gnunet_os_lib.h
@@ -273,6 +273,18 @@ int GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
  */
 int GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc);
 
+/**
+ * Read env variable and set up the read end of the control
+ * pipe that parent uses to send signals to this process.
+ *
+ * Only does something on Windows
+ *
+ * @param cls user-specified parameter (NULL)
+ * @param tc task context
+ */
+void GNUNET_OS_install_parent_control_handler (void *cls,
+                                               const struct
+                                               GNUNET_SCHEDULER_TaskContext * tc);
 
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
diff --git a/src/util/disk.c b/src/util/disk.c
index 307c453..1a3b79c 100644
--- a/src/util/disk.c
+++ b/src/util/disk.c
@@ -1910,4 +1910,94 @@ GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
   return GNUNET_OK;
 }
 
+struct GNUNET_DISK_FileHandle
+GNUNET_DISK_file_from_internal_handle_ (void *src, size_t src_len)
+{
+  struct GNUNET_DISK_FileHandle ret;
+#ifdef MINGW
+  if (src_len == sizeof (HANDLE))
+    ret.h = *(HANDLE *) src;
+  else
+    ret.h = INVALID_HANDLE_VALUE;
+#else
+  if (src_len == sizeof (int))
+    ret.fd = *(int *) src;
+  else
+    ret.fd = -1;
+#endif
+  return ret;
+}
+
+struct GNUNET_DISK_PipeHandle *
+GNUNET_DISK_pipe_from_internal_handles_ (int blocking, void *src0, void *src1, size_t src_len)
+{
+  struct GNUNET_DISK_PipeHandle *p;
+  struct GNUNET_DISK_FileHandle *fds;
+
+  p =
+    GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
+                   2 * sizeof (struct GNUNET_DISK_FileHandle));
+  fds = (struct GNUNET_DISK_FileHandle *) &p[1];
+  p->fd[0] = &fds[0];
+  p->fd[1] = &fds[1];
+  fds[0] = GNUNET_DISK_file_from_internal_handle_ (src0, src_len);
+  fds[1] = GNUNET_DISK_file_from_internal_handle_ (src1, src_len);
+#ifndef MINGW
+  int fd[2];
+  int ret;
+  int flags;
+  int eno;
+
+  fd[0] = fds[0].fd;
+  fd[1] = fds[1].fd;
+  ret = 0;
+  if (fd[0] >= 0)
+  {
+    flags = fcntl (fd[0], F_GETFL);
+    if (!blocking)
+      flags |= O_NONBLOCK;
+    if (0 > fcntl (fd[0], F_SETFL, flags))
+      ret = -1;
+    flags = fcntl (fd[0], F_GETFD);
+    flags |= FD_CLOEXEC;
+    if (0 > fcntl (fd[0], F_SETFD, flags))
+      ret = -1;
+  }
+  if (fd[1] >= 0)
+  {
+    flags = fcntl (fd[1], F_GETFL);
+    if (!blocking)
+      flags |= O_NONBLOCK;
+    if (0 > fcntl (fd[1], F_SETFL, flags))
+      ret = -1;
+    flags = fcntl (fd[1], F_GETFD);
+    flags |= FD_CLOEXEC;
+    if (0 > fcntl (fd[1], F_SETFD, flags))
+      ret = -1;
+  }
+  if (ret == -1)
+    {
+      eno = errno;
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fcntl");
+      GNUNET_free (p);
+      errno = eno;
+      return NULL;    
+    }
+#else
+  /* Empirical fact: DuplicateHandle() on a handle inherited from the parent
+   * dies with ERROR_INVALID_HANDLE, so we won't try to duplicate these to
+   * make them inheritable/uninheritable.
+   */
+  if (!blocking)
+  {
+    DWORD mode;
+
+    mode = PIPE_NOWAIT;
+    SetNamedPipeHandleState (p->fd[0]->h, &mode, NULL, NULL);
+    SetNamedPipeHandleState (p->fd[1]->h, &mode, NULL, NULL);
+    /* this always fails on Windows 95, so we don't care about error handling */
+  }
+#endif
+  return p;
+}
 /* end of disk.c */
diff --git a/src/util/disk.h b/src/util/disk.h
index 3d52b9e..5e9647e 100644
--- a/src/util/disk.h
+++ b/src/util/disk.h
@@ -61,5 +61,7 @@ struct GNUNET_DISK_FileHandle
  */ 
 int GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle
                                        *fh, 
void *dst, 
size_t dst_len);
+
+struct GNUNET_DISK_PipeHandle *GNUNET_DISK_pipe_from_internal_handles_ (int blocking, void *src0, void *src1, size_t src_len);
 

 #endif  /* GNUNET_DISK_H_ */
diff --git a/src/util/network.c b/src/util/network.c
index 58d67ed..78ff01e 100644
--- a/src/util/network.c
+++ b/src/util/network.c
@@ -1138,9 +1138,19 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
 
             {
               HANDLE h;
-              DWORD dwBytes;
+              DWORD dwBytes = 0, error_code;
+              BOOL bresult;
               h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);
-              if (!PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))
+              bresult = PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL);
+              error_code = GetLastError ();
+              /* FIXME: This should fail when the pipe is _really_ invalid,
+               * should skip the pipe if the error means that it's
+               * temporarily unavailable, and should succeed if the pipe
+               * is broken (or that the otherwise valid pipe is in a condition
+               * that prevents further reading). 
+               * For now it succeeds only when the pipe is broken or readable.
+               */
+              if (!bresult && error_code != ERROR_BROKEN_PIPE)
                 {
                   retcode = -1;
                   SetErrnoFromWinError (GetLastError ());
@@ -1152,7 +1162,7 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
 #endif
                   goto select_loop_end;
                 }
-              else if (dwBytes)
+              else if (dwBytes || error_code == ERROR_BROKEN_PIPE)
 
                 {
                   GNUNET_CONTAINER_slist_add (handles_read,
diff --git a/src/util/os_priority.c b/src/util/os_priority.c
index fb6c292..10beff4 100644
--- a/src/util/os_priority.c
+++ b/src/util/os_priority.c
@@ -29,11 +29,14 @@
 #include "gnunet_os_lib.h"
 #include "disk.h"
 
+#define GNUNET_OS_NT_CONTROL_PIPE "GNUNET_OS_NT_CONTROL_PIPE"
+
 struct GNUNET_OS_Process
 {
   pid_t pid;
 #if WINDOWS
   HANDLE handle;
+  struct GNUNET_DISK_PipeHandle *control_pipe;
 #endif
 };
 
@@ -42,14 +45,81 @@ static struct GNUNET_OS_Process current_process;
 
 #if WINDOWS
 void
-GNUNET_OS_process_set_handle(struct GNUNET_OS_Process *proc, HANDLE handle)
+GNUNET_OS_parent_control_handler (void *cls,
+                                  const struct
+                                  GNUNET_SCHEDULER_TaskContext * tc)
 {
-  if (proc->handle != NULL)
-    CloseHandle (proc->handle);
-  proc->handle = handle;
+  struct GNUNET_DISK_PipeHandle *control_pipe = (struct GNUNET_DISK_PipeHandle *) cls;
+  unsigned char code;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_OS_parent_control_handler is invoked because of %d\n", tc->reason);
+
+  if (tc->reason & (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT | GNUNET_SCHEDULER_REASON_PREREQ_DONE))
+  {
+      GNUNET_DISK_pipe_close (control_pipe);
+  }
+  else
+  {
+    if (GNUNET_DISK_file_read (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), &code, sizeof (char)) != sizeof (char))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_DISK_file_read have failed, errno = %d. Closing the control pipe.\n", errno);
+      GNUNET_DISK_pipe_close (control_pipe);
+    }
+    else
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got control code %d\n", code);
+      switch (code)
+      {
+        case 0:
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Raising SIGTERM\n");
+          raise (SIGTERM);
+          break;
+        case 1:
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Raising SIGKILL\n");
+          raise (SIGKILL);
+          break;
+        case 255:
+          /* read more bytes - a possibility for extended signals
+           * in case 254 different valies is not enough
+           */
+          break;
+        default:
+          break;
+      }
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Re-adding parent control handler pipe to the scheduler\n");
+      GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), GNUNET_OS_parent_control_handler, control_pipe);
+    }
+  }
 }
 #endif
 
+void
+GNUNET_OS_install_parent_control_handler (void *cls,
+                                          const struct
+                                          GNUNET_SCHEDULER_TaskContext * tc)
+{
+#ifdef WINDOWS
+  char *env_buf;
+  char *endptr;
+  HANDLE control_pipe_end[2];
+  struct GNUNET_DISK_PipeHandle *control_pipe = NULL;
+
+  env_buf = getenv (GNUNET_OS_NT_CONTROL_PIPE);
+  if (env_buf == NULL || strlen (env_buf) <= 0 || env_buf[0] < '0' || env_buf[0] > '9')
+    return;
+
+  control_pipe_end[0] = (HANDLE) strtol (env_buf, &endptr, 10);
+  control_pipe_end[1] = INVALID_HANDLE_VALUE;
+ 
+  control_pipe = GNUNET_DISK_pipe_from_internal_handles_ (GNUNET_NO, &control_pipe_end[0], &control_pipe_end[1], sizeof (HANDLE));
+  if (control_pipe == NULL)
+    return;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding parent control handler pipe to the scheduler\n");
+  GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), GNUNET_OS_parent_control_handler, control_pipe);
+#endif
+}
+
 
 /**
  * Get process structure for current process
@@ -66,7 +136,7 @@ GNUNET_OS_process_current ()
   current_process.pid = GetCurrentProcessId ();
   current_process.handle = GetCurrentProcess ();
 #else
-  current_process.pid = 0;
+  current_process.pid = getpid ();
 #endif
   return &current_process;
 }
@@ -75,27 +145,56 @@ int
 GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
 {
 #if WINDOWS
-  if (sig == SIGKILL || sig == SIGTERM)
+  unsigned char c;
+  DWORD dwresult, error_code = NO_ERROR;
+  BOOL bresult = 1;
+
+  switch (sig)
   {
-    HANDLE h = proc->handle;
-    if (NULL == h)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-		  _("Invalid process information {%d, %08X}\n"),
-		  proc->pid,
-		  h);
-      return -1;
-    }
-    if (!TerminateProcess (h, 0))
-    {
-      SetErrnoFromWinError (GetLastError ());
-      return -1;
+  case SIGKILL:
+    c = 1;
+    break;
+  case SIGTERM:
+    c = 0;
+    break;
+  default:
+    errno = EINVAL;
+    return -1;
+  }
+
+  if (GNUNET_DISK_file_write (
+      GNUNET_DISK_pipe_handle (proc->control_pipe, GNUNET_DISK_PIPE_END_WRITE),
+      &c, sizeof (c)) != sizeof (c))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        "Failed to write into control pipe, errno is %d\n", errno);
+    bresult = 0;
+  }
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        "Wrote control code into control pipe, now waiting\n");
+    SetLastError (0);
+    dwresult = WaitForSingleObject (proc->handle, 4*1000);
+    error_code = GetLastError ();
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        "Woke up, returned %d, GLE is %d\n", dwresult, error_code);
+    if (WAIT_OBJECT_0 != dwresult || error_code != NO_ERROR)
+    {
+      SetLastError (0);
+      bresult = TerminateProcess (proc->handle, 0);
+      error_code = GetLastError ();
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+          "TerminateProcess for the child returned %d, GLE is %d\n", bresult,
+          error_code);
     }
-    else
-      return 0;
   }
-  errno = EINVAL;
-  return -1;
+  if (error_code != NO_ERROR || !bresult)
+  {
+    return -1;
+  }
+  else
+    return 0;
 #else
   return kill (proc->pid, sig);
 #endif
@@ -258,6 +357,80 @@ GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
   return GNUNET_OK;
 }
 
+#if WINDOWS
+/**
+ * Look through the @env_table and find its size (in bytes, excluding
+ * all NULL-terminators) and item count.
+ *
+ * Use count + size + 1 to calculate the size of the envtable in memory
+ *
+ * @param env_table environment table, as returned by GetEnvironmentStrings()
+ * @param count returned number of elements
+ * @param size returned total length of the items
+ * @return GNUNET_SYSERR on error, GNUNET_OK on success
+ */
+int
+GetEnvTableSizeA (const char *env_table, size_t *count, size_t *size)
+{
+  size_t tablesize = 0;
+  size_t items_count = 0;
+  const char *ptr;
+  if (!env_table)
+    return GNUNET_SYSERR;
+  for (items_count = 0, ptr = win32_env_table; ptr[0] != 0; items_count++)
+  {
+    size_t len = strlen (ptr);
+    tablesize += len;
+    ptr += len + 1;
+  }
+  if (count)
+    *count = items_count;
+  if (size)
+    *size = tablesize;
+  return GNUNET_OK;
+}
+
+char *
+CreateEnvTableA ()
+{
+  char *result = NULL;
+  size_t count, size;
+  const char *win32_env_table;
+  win32_env_table = GetEnvironmentStrings ();
+  if (win32_env_table == NULL || GNUNET_OK != GetEnvTableSizeA (win32_env_table, &count, &size))
+    return NULL;
+  result = GNUNET_malloc (count + size + 1);
+  if (result)
+    memcpy (result, win32_env_table, count + size + 1);
+  if (win32_env_table)
+    FreeEnvironmentStrings (win32_env_table);
+  return result;
+}
+
+char *
+AddToEnvTableA (char *env_table, const char *newvar)
+{
+  char *result = NULL, *ptr;
+  size_t count, size, new_var_size;
+  new_var_size = strlen (newvar);
+  if (env_table == NULL || GNUNET_OK != GetEnvTableSizeA ((const char *) env_table, &count, &size))
+  {
+    GNUNET_free (env_table);
+    return NULL;
+  }
+  result = GNUNET_malloc (count + 1 + size + new_var_size + 1);
+  if (result)
+  {
+    memcpy (result, win32_env_table, count + size);
+    ptr = result + count + size;
+    memcpy (ptr, newvar, new_var_size + 1);
+    ptr[new_var_size + 1] = 0;
+  }
+  GNUNET_free (env_table);
+  return result;
+}
+#endif
+
 /**
  * Start a process.
  *
@@ -368,19 +541,31 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   STARTUPINFO start;
   PROCESS_INFORMATION proc;
   struct GNUNET_OS_Process *gnunet_proc = NULL;
+  struct GNUNET_DISK_PipeHandle *control_pipe = NULL;
+  char *env_buf;
+  char *env_block = NULL;
 
   HANDLE stdin_handle;
   HANDLE stdout_handle;
+  HANDLE control_pipe_read_end, control_pipe_write_end;
 
   char path[MAX_PATH + 1];
 
-  cmdlen = 0;
+  if ((HINSTANCE) 32 >= FindExecutableA (filename, NULL, path)) 
+    {
+      SetErrnoFromWinError (GetLastError ());
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
+      return NULL;
+    }
+
+  cmdlen = strlen (path) + 3;
   va_start (ap, filename);
   while (NULL != (arg = va_arg (ap, char *)))
       cmdlen = cmdlen + strlen (arg) + 3;
   va_end (ap);
 
   cmd = idx = GNUNET_malloc (sizeof (char) * (cmdlen + 1));
+  idx += sprintf (idx, "\"%s\" ", path);
   va_start (ap, filename);
   while (NULL != (arg = va_arg (ap, char *)))
       idx += sprintf (idx, "\"%s\" ", arg);
@@ -404,35 +589,47 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
       start.hStdOutput = stdout_handle;
     }
 
-  if (32 >= (int) FindExecutableA (filename, NULL, path)) 
-    {
-      SetErrnoFromWinError (GetLastError ());
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
-      return NULL;
-    }
+  control_pipe = GNUNET_DISK_pipe (GNUNET_NO, 1, 0);
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), &control_pipe_read_end, sizeof (HANDLE));
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_WRITE), &control_pipe_write_end, sizeof (HANDLE));
+
+  env_block = CreateEnvTableA (env_block);
+  GNUNET_asprintf (&env_buf, "%s=%d", GNUNET_OS_NT_CONTROL_PIPE, control_pipe_read_end);
+  env_block = AddToEnvTableA (env_block, (const char *) env_buf);
+  GNUNET_free (env_buf);
 
   if (!CreateProcessA
-      (path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &start,
+      (path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS, env_block, NULL, &start,
        &proc))
     {
       SetErrnoFromWinError (GetLastError ());
       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", path);
-      return NULL;
+      goto end;
     }
 
   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
   gnunet_proc->pid = proc.dwProcessId;
   gnunet_proc->handle = proc.hProcess;
+  gnunet_proc->control_pipe = control_pipe;
 
   CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
 
   CloseHandle (proc.hThread);
+end:
+
+  if (env_block)
+    GNUNET_free (env_block); 
+
+  if (gnunet_proc == NULL)
+    GNUNET_DISK_pipe_close (control_pipe);
+  else
+    GNUNET_DISK_pipe_close_end (control_pipe, GNUNET_DISK_PIPE_END_READ);
+
 
   GNUNET_free (cmd);
 
   return gnunet_proc;
 #endif
-
 }
 
 
@@ -557,6 +754,9 @@ GNUNET_OS_start_process_v (const int *lsocks,
   int argcount = 0;
   char non_const_filename[MAX_PATH +1];
   struct GNUNET_OS_Process *gnunet_proc = NULL;
+  struct GNUNET_DISK_PipeHandle *control_pipe = NULL;
+  char *env_buf = NULL, *env_block = NULL;
+  HANDLE control_pipe_read_end, control_pipe_write_end;
 
   GNUNET_assert (lsocks == NULL);
 
@@ -583,7 +783,12 @@ GNUNET_OS_start_process_v (const int *lsocks,
   arg = (char **) argv;
   while (*arg)
     {
-      non_const_argv[argcount] = GNUNET_strdup (*arg);
+      if (argcount == 0)
+        /* Otherwise we'll get the argv[0] without .exe extension,
+           that will break libtool wrapper */
+        non_const_argv[argcount] = GNUNET_strdup (non_const_filename);
+      else
+        non_const_argv[argcount] = GNUNET_strdup (*arg);
       arg++;
       argcount++;
     }
@@ -610,22 +815,42 @@ GNUNET_OS_start_process_v (const int *lsocks,
   memset (&start, 0, sizeof (start));
   start.cb = sizeof (start);
 
-  if (!CreateProcess
-      (non_const_filename, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
+  control_pipe = GNUNET_DISK_pipe (GNUNET_NO, 1, 0);
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), &control_pipe_read_end, sizeof (HANDLE));
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_WRITE), &control_pipe_write_end, sizeof (HANDLE));
+
+  env_block = CreateEnvTableA (env_block);
+  GNUNET_asprintf (&env_buf, "%s=%d", GNUNET_OS_NT_CONTROL_PIPE, control_pipe_read_end);
+  env_block = AddToEnvTableA (env_block, (const char *) env_buf);
+  GNUNET_free (env_buf);
+
+  if (!CreateProcessA
+      (non_const_filename, cmd, NULL, NULL, TRUE,
+       DETACHED_PROCESS, env_block, NULL, &start,
        &proc))
     {
       SetErrnoFromWinError (GetLastError ());
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
-      return NULL;
+      goto end;
     }
 
   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
   gnunet_proc->pid = proc.dwProcessId;
   gnunet_proc->handle = proc.hProcess;
+  gnunet_proc->control_pipe = control_pipe;
 
   CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
 
   CloseHandle (proc.hThread);
+end:
+  if (env_block)
+    GNUNET_free (env_block); 
+
+  if (gnunet_proc == NULL)
+    GNUNET_DISK_pipe_close (control_pipe);
+  else
+    GNUNET_DISK_pipe_close_end (control_pipe, GNUNET_DISK_PIPE_END_READ);
+
   GNUNET_free (cmd);
 
   while (argcount > 0)
diff --git a/src/util/scheduler.c b/src/util/scheduler.c
index 0a4798b..88275e9 100644
--- a/src/util/scheduler.c
+++ b/src/util/scheduler.c
@@ -744,6 +744,8 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
   shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, &sighandler_shutdown);
 #endif
   current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT;
+  GNUNET_SCHEDULER_add_continuation (GNUNET_OS_install_parent_control_handler,
+				     NULL, GNUNET_SCHEDULER_REASON_STARTUP);
   GNUNET_SCHEDULER_add_continuation (task,
                                      task_cls,
                                      GNUNET_SCHEDULER_REASON_STARTUP);
-- 
1.7.3.1.msysgit.0

0002-Fix-environment-table-generation-for-child-processes.patch (8,940 bytes)   
From 251ec6e3e4c8552595c1e0ef735ca76573237565 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= <lrn1986@gmail.com>
Date: Wed, 10 Nov 2010 17:42:04 +0300
Subject: [PATCH 2/2] Fix environment table generation for child processes

---
 src/util/os_priority.c |  172 +++++++++++++++++++++++++++++-------------------
 1 files changed, 103 insertions(+), 69 deletions(-)

diff --git a/src/util/os_priority.c b/src/util/os_priority.c
index 10beff4..45ad63d 100644
--- a/src/util/os_priority.c
+++ b/src/util/os_priority.c
@@ -115,7 +115,7 @@ GNUNET_OS_install_parent_control_handler (void *cls,
   if (control_pipe == NULL)
     return;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding parent control handler pipe to the scheduler\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding parent control handler pipe %d to the scheduler\n", control_pipe_end[0]);
   GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), GNUNET_OS_parent_control_handler, control_pipe);
 #endif
 }
@@ -358,75 +358,100 @@ GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
 }
 
 #if WINDOWS
-/**
- * Look through the @env_table and find its size (in bytes, excluding
- * all NULL-terminators) and item count.
- *
- * Use count + size + 1 to calculate the size of the envtable in memory
- *
- * @param env_table environment table, as returned by GetEnvironmentStrings()
- * @param count returned number of elements
- * @param size returned total length of the items
- * @return GNUNET_SYSERR on error, GNUNET_OK on success
- */
-int
-GetEnvTableSizeA (const char *env_table, size_t *count, size_t *size)
+char *
+CreateCustomEnvTable (char **vars)
 {
+  char *win32_env_table, *ptr, **var_ptr, *result, *result_ptr;
   size_t tablesize = 0;
   size_t items_count = 0;
-  const char *ptr;
-  if (!env_table)
-    return GNUNET_SYSERR;
+  size_t n_found = 0, n_var;
+  char *index = NULL;
+  size_t c;
+  size_t var_len;
+  char *var;
+  char *val;
+  win32_env_table = GetEnvironmentStringsA ();
+  if (win32_env_table == NULL)
+    return NULL;
+  for (c = 0, var_ptr = vars; *var_ptr; var_ptr += 2, c++);
+  n_var = c;
+  index = GNUNET_malloc (n_var);
+  for (c = 0; c < n_var; c++)
+    index[c] = 0;
   for (items_count = 0, ptr = win32_env_table; ptr[0] != 0; items_count++)
   {
     size_t len = strlen (ptr);
-    tablesize += len;
-    ptr += len + 1;
+    int found = 0;
+    for (var_ptr = vars; *var_ptr; var_ptr++)
+    {
+      var = *var_ptr++;
+      val = *var_ptr;
+      var_len = strlen (var);
+      if (strncmp (var, ptr, var_len) == 0)
+      {
+        found = 1;
+        index[c] = 1;
+        tablesize += var_len + strlen (val) + 1;
+        break;
+      }
+    }
+    if (!found)
+      tablesize += len + 1;
+    ptr += len + 1; 
   }
-  if (count)
-    *count = items_count;
-  if (size)
-    *size = tablesize;
-  return GNUNET_OK;
-}
-
-char *
-CreateEnvTableA ()
-{
-  char *result = NULL;
-  size_t count, size;
-  const char *win32_env_table;
-  win32_env_table = GetEnvironmentStrings ();
-  if (win32_env_table == NULL || GNUNET_OK != GetEnvTableSizeA (win32_env_table, &count, &size))
-    return NULL;
-  result = GNUNET_malloc (count + size + 1);
-  if (result)
-    memcpy (result, win32_env_table, count + size + 1);
-  if (win32_env_table)
-    FreeEnvironmentStrings (win32_env_table);
-  return result;
-}
-
-char *
-AddToEnvTableA (char *env_table, const char *newvar)
-{
-  char *result = NULL, *ptr;
-  size_t count, size, new_var_size;
-  new_var_size = strlen (newvar);
-  if (env_table == NULL || GNUNET_OK != GetEnvTableSizeA ((const char *) env_table, &count, &size))
+  for (n_found = 0, c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
   {
-    GNUNET_free (env_table);
-    return NULL;
+    var = *var_ptr++;
+    val = *var_ptr;
+    if (index[c] != 1)
+      n_found += strlen (var) + strlen (val) + 1;
+  }
+  result = GNUNET_malloc (tablesize + n_found + 1);
+  for (result_ptr = result, ptr = win32_env_table; ptr[0] != 0;)
+  {
+    size_t len = strlen (ptr);
+    int found = 0;
+    for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
+    {
+      var = *var_ptr++;
+      val = *var_ptr;
+      var_len = strlen (var);
+      if (strncmp (var, ptr, var_len) == 0)
+      {
+        found = 1;
+        break;
+      }
+    }
+    if (!found)
+    {
+      strcpy (result_ptr, ptr);
+      result_ptr += len + 1;
+    }
+    else
+    {
+      strcpy (result_ptr, var);
+      result_ptr += var_len;
+      strcpy (result_ptr, val);
+      result_ptr += strlen (val) + 1;
+    }
+    ptr += len + 1;
   }
-  result = GNUNET_malloc (count + 1 + size + new_var_size + 1);
-  if (result)
+  for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
   {
-    memcpy (result, win32_env_table, count + size);
-    ptr = result + count + size;
-    memcpy (ptr, newvar, new_var_size + 1);
-    ptr[new_var_size + 1] = 0;
+    var = *var_ptr++;
+    val = *var_ptr;
+    var_len = strlen (var);
+    if (index[c] != 1)
+    {
+      strcpy (result_ptr, var);
+      result_ptr += var_len;
+      strcpy (result_ptr, val);
+      result_ptr += strlen (val) + 1;
+    }
   }
-  GNUNET_free (env_table);
+  FreeEnvironmentStrings (win32_env_table);
+  GNUNET_free (index);
+  *result_ptr = 0;
   return result;
 }
 #endif
@@ -542,8 +567,8 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   PROCESS_INFORMATION proc;
   struct GNUNET_OS_Process *gnunet_proc = NULL;
   struct GNUNET_DISK_PipeHandle *control_pipe = NULL;
-  char *env_buf;
   char *env_block = NULL;
+  char *our_env[3] = { NULL, NULL, NULL };
 
   HANDLE stdin_handle;
   HANDLE stdout_handle;
@@ -593,10 +618,12 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), &control_pipe_read_end, sizeof (HANDLE));
   GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_WRITE), &control_pipe_write_end, sizeof (HANDLE));
 
-  env_block = CreateEnvTableA (env_block);
-  GNUNET_asprintf (&env_buf, "%s=%d", GNUNET_OS_NT_CONTROL_PIPE, control_pipe_read_end);
-  env_block = AddToEnvTableA (env_block, (const char *) env_buf);
-  GNUNET_free (env_buf);
+  GNUNET_asprintf (&our_env[0], "%s=", GNUNET_OS_NT_CONTROL_PIPE);
+  GNUNET_asprintf (&our_env[1], "%d", control_pipe_read_end);
+  our_env[2] = NULL;
+  env_block = CreateCustomEnvTable (our_env);
+  GNUNET_free (our_env[0]);
+  GNUNET_free (our_env[1]);
 
   if (!CreateProcessA
       (path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS, env_block, NULL, &start,
@@ -612,6 +639,8 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   gnunet_proc->handle = proc.hProcess;
   gnunet_proc->control_pipe = control_pipe;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started a child process, control pipe %d->%d\n", control_pipe_write_end, control_pipe_read_end);
+
   CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
 
   CloseHandle (proc.hThread);
@@ -755,7 +784,8 @@ GNUNET_OS_start_process_v (const int *lsocks,
   char non_const_filename[MAX_PATH +1];
   struct GNUNET_OS_Process *gnunet_proc = NULL;
   struct GNUNET_DISK_PipeHandle *control_pipe = NULL;
-  char *env_buf = NULL, *env_block = NULL;
+  char *env_block = NULL;
+  char *our_env[3] = { NULL, NULL, NULL };
   HANDLE control_pipe_read_end, control_pipe_write_end;
 
   GNUNET_assert (lsocks == NULL);
@@ -819,10 +849,12 @@ GNUNET_OS_start_process_v (const int *lsocks,
   GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), &control_pipe_read_end, sizeof (HANDLE));
   GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_WRITE), &control_pipe_write_end, sizeof (HANDLE));
 
-  env_block = CreateEnvTableA (env_block);
-  GNUNET_asprintf (&env_buf, "%s=%d", GNUNET_OS_NT_CONTROL_PIPE, control_pipe_read_end);
-  env_block = AddToEnvTableA (env_block, (const char *) env_buf);
-  GNUNET_free (env_buf);
+  GNUNET_asprintf (&our_env[0], "%s=", GNUNET_OS_NT_CONTROL_PIPE);
+  GNUNET_asprintf (&our_env[1], "%d", control_pipe_read_end);
+  our_env[2] = NULL;
+  env_block = CreateCustomEnvTable (our_env);
+  GNUNET_free (our_env[0]);
+  GNUNET_free (our_env[1]);
 
   if (!CreateProcessA
       (non_const_filename, cmd, NULL, NULL, TRUE,
@@ -834,6 +866,8 @@ GNUNET_OS_start_process_v (const int *lsocks,
       goto end;
     }
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started a child process, control pipe %d->%d\n", control_pipe_write_end, control_pipe_read_end);
+
   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
   gnunet_proc->pid = proc.dwProcessId;
   gnunet_proc->handle = proc.hProcess;
-- 
1.7.3.1.msysgit.0

0001-Parent-child-control-pipes-ndurner-s-IO-based.patch (62,938 bytes)   
From 1b84258d3a3c9cb12ecb32cae26d64432aee8dff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= <lrn1986@gmail.com>
Date: Sun, 5 Dec 2010 05:38:20 +0300
Subject: [PATCH] Parent-child control pipes (ndurner's IO-based)

---
 src/arm/gnunet-service-arm.c                       |    6 +-
 src/core/test_core_api.c                           |    2 +-
 src/core/test_core_api_reliability.c               |    2 +-
 src/core/test_core_api_start_only.c                |    2 +-
 src/core/test_core_quota_compliance.c              |    2 +-
 src/datastore/perf_datastore_api.c                 |    2 +-
 src/datastore/test_datastore_api.c                 |    2 +-
 src/datastore/test_datastore_api_management.c      |    2 +-
 src/dht/test_dht_api.c                             |    2 +-
 src/fs/test_fs_download.c                          |    2 +-
 src/fs/test_fs_download_indexed.c                  |    2 +-
 src/fs/test_fs_download_persistence.c              |    2 +-
 src/fs/test_fs_list_indexed.c                      |    2 +-
 src/fs/test_fs_namespace.c                         |    2 +-
 src/fs/test_fs_namespace_list_updateable.c         |    2 +-
 src/fs/test_fs_publish.c                           |    2 +-
 src/fs/test_fs_publish_persistence.c               |    2 +-
 src/fs/test_fs_search.c                            |    2 +-
 src/fs/test_fs_search_persistence.c                |    2 +-
 src/fs/test_fs_start_stop.c                        |    2 +-
 src/fs/test_fs_unindex.c                           |    2 +-
 src/fs/test_fs_unindex_persistence.c               |    2 +-
 src/hostlist/test_gnunet_daemon_hostlist.c         |    2 +-
 .../test_gnunet_daemon_hostlist_learning.c         |    4 +-
 src/include/gnunet_disk_lib.h                      |   17 +-
 src/include/gnunet_os_lib.h                        |   14 +-
 src/peerinfo/perf_peerinfo_api.c                   |    2 +-
 src/peerinfo/test_peerinfo_api.c                   |    2 +-
 src/statistics/test_statistics_api.c               |    4 +-
 src/statistics/test_statistics_api_loop.c          |    2 +-
 src/testing/testing.c                              |    4 +-
 src/transport/plugin_transport_tcp.c               |    2 +-
 src/transport/plugin_transport_udp.c               |    2 +-
 src/transport/test_quota_compliance.c              |    2 +-
 src/transport/test_transport_api.c                 |    2 +-
 src/transport/test_transport_api_reliability.c     |    2 +-
 src/util/crypto_random.c                           |    6 +-
 src/util/disk.c                                    |   99 +++-
 src/util/network.c                                 |   21 +-
 src/util/os_priority.c                             |  607 ++++++++++++++++++--
 src/util/scheduler.c                               |    3 +
 src/util/test_os_start_process.c                   |    2 +-
 src/util/test_resolver_api.c                       |    2 +-
 src/vpn/gnunet-daemon-vpn.c                        |    4 +-
 44 files changed, 730 insertions(+), 123 deletions(-)

diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c
index c967c64..e1f4dcb 100644
--- a/src/arm/gnunet-service-arm.c
+++ b/src/arm/gnunet-service-arm.c
@@ -198,7 +198,7 @@ config_change_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 	{
 	  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
 		      _("Restarting service `%s' due to configuration file change.\n"));
-	  if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM))
+	  if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM, GNUNET_YES))
 	    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
 	  else
 	    pos->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
@@ -579,7 +579,7 @@ stop_service (struct GNUNET_SERVER_Client *client,
 	      "Sending kill signal to service `%s', waiting for process to die.\n",
 	      servicename);
 #endif
-  if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM, GNUNET_YES))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   pos->next = running;
   running = pos;
@@ -730,7 +730,7 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 	  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
 		      "Stopping service `%s'\n",
 		      pos->name);
-	  if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM))
+	  if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM, GNUNET_YES))
 	    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
 	}
       pos = pos->next;
diff --git a/src/core/test_core_api.c b/src/core/test_core_api.c
index 814ebe8..286497a 100644
--- a/src/core/test_core_api.c
+++ b/src/core/test_core_api.c
@@ -322,7 +322,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/core/test_core_api_reliability.c b/src/core/test_core_api_reliability.c
index 9192c95..480ca75 100644
--- a/src/core/test_core_api_reliability.c
+++ b/src/core/test_core_api_reliability.c
@@ -477,7 +477,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/core/test_core_api_start_only.c b/src/core/test_core_api_start_only.c
index dc5e35b..f361528 100644
--- a/src/core/test_core_api_start_only.c
+++ b/src/core/test_core_api_start_only.c
@@ -215,7 +215,7 @@ stop_arm (struct PeerContext *p)
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
 	      "Stopping peer\n");
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/core/test_core_quota_compliance.c b/src/core/test_core_quota_compliance.c
index 6c5a528..243e8df 100644
--- a/src/core/test_core_quota_compliance.c
+++ b/src/core/test_core_quota_compliance.c
@@ -665,7 +665,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/datastore/perf_datastore_api.c b/src/datastore/perf_datastore_api.c
index 1f7c828..aa0c932 100644
--- a/src/datastore/perf_datastore_api.c
+++ b/src/datastore/perf_datastore_api.c
@@ -391,7 +391,7 @@ check ()
   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
                       argv, "perf-datastore-api", "nohelp",
                       options, &run, NULL);
-  if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (proc, SIGTERM, GNUNET_NO))
     {
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
       ok = 1;
diff --git a/src/datastore/test_datastore_api.c b/src/datastore/test_datastore_api.c
index 06abc0c..de04655 100644
--- a/src/datastore/test_datastore_api.c
+++ b/src/datastore/test_datastore_api.c
@@ -660,7 +660,7 @@ check ()
                       argv, "test-datastore-api", "nohelp",
                       options, &run, NULL);
 #if START_DATASTORE
-  if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (proc, SIGTERM, GNUNET_NO))
     {
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
       ok = 1;
diff --git a/src/datastore/test_datastore_api_management.c b/src/datastore/test_datastore_api_management.c
index d17d8fb..03e14d6 100644
--- a/src/datastore/test_datastore_api_management.c
+++ b/src/datastore/test_datastore_api_management.c
@@ -370,7 +370,7 @@ check ()
   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
                       argv, "test-datastore-api", "nohelp",
                       options, &run, NULL);
-  if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (proc, SIGTERM, GNUNET_NO))
     {
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
       ok = 1;
diff --git a/src/dht/test_dht_api.c b/src/dht/test_dht_api.c
index b82d8cd..ab1e65f 100644
--- a/src/dht/test_dht_api.c
+++ b/src/dht/test_dht_api.c
@@ -120,7 +120,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   GNUNET_OS_process_wait (p->arm_proc);
   GNUNET_OS_process_close (p->arm_proc);
diff --git a/src/fs/test_fs_download.c b/src/fs/test_fs_download.c
index 549a2ee..0ea3e28 100644
--- a/src/fs/test_fs_download.c
+++ b/src/fs/test_fs_download.c
@@ -257,7 +257,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/fs/test_fs_download_indexed.c b/src/fs/test_fs_download_indexed.c
index 6e59f97..f35c4c7 100644
--- a/src/fs/test_fs_download_indexed.c
+++ b/src/fs/test_fs_download_indexed.c
@@ -259,7 +259,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/fs/test_fs_download_persistence.c b/src/fs/test_fs_download_persistence.c
index 66d1199..1bb0107 100644
--- a/src/fs/test_fs_download_persistence.c
+++ b/src/fs/test_fs_download_persistence.c
@@ -317,7 +317,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/fs/test_fs_list_indexed.c b/src/fs/test_fs_list_indexed.c
index 206e58b..2ced9ff 100644
--- a/src/fs/test_fs_list_indexed.c
+++ b/src/fs/test_fs_list_indexed.c
@@ -209,7 +209,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/fs/test_fs_namespace.c b/src/fs/test_fs_namespace.c
index 0d37aff..230e4d0 100644
--- a/src/fs/test_fs_namespace.c
+++ b/src/fs/test_fs_namespace.c
@@ -82,7 +82,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/fs/test_fs_namespace_list_updateable.c b/src/fs/test_fs_namespace_list_updateable.c
index 359800f..bd41595 100644
--- a/src/fs/test_fs_namespace_list_updateable.c
+++ b/src/fs/test_fs_namespace_list_updateable.c
@@ -86,7 +86,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/fs/test_fs_publish.c b/src/fs/test_fs_publish.c
index 327fa5a..2eb639c 100644
--- a/src/fs/test_fs_publish.c
+++ b/src/fs/test_fs_publish.c
@@ -195,7 +195,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/fs/test_fs_publish_persistence.c b/src/fs/test_fs_publish_persistence.c
index 52b2b27..c6283b2 100644
--- a/src/fs/test_fs_publish_persistence.c
+++ b/src/fs/test_fs_publish_persistence.c
@@ -252,7 +252,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/fs/test_fs_search.c b/src/fs/test_fs_search.c
index b003b75..6a49d63 100644
--- a/src/fs/test_fs_search.c
+++ b/src/fs/test_fs_search.c
@@ -200,7 +200,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/fs/test_fs_search_persistence.c b/src/fs/test_fs_search_persistence.c
index 4def3fe..4e90f15 100644
--- a/src/fs/test_fs_search_persistence.c
+++ b/src/fs/test_fs_search_persistence.c
@@ -269,7 +269,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/fs/test_fs_start_stop.c b/src/fs/test_fs_start_stop.c
index 71043bf..126a4cc 100644
--- a/src/fs/test_fs_start_stop.c
+++ b/src/fs/test_fs_start_stop.c
@@ -72,7 +72,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/fs/test_fs_unindex.c b/src/fs/test_fs_unindex.c
index e2c0e86..899bed9 100644
--- a/src/fs/test_fs_unindex.c
+++ b/src/fs/test_fs_unindex.c
@@ -205,7 +205,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/fs/test_fs_unindex_persistence.c b/src/fs/test_fs_unindex_persistence.c
index eec1815..fa7c503 100644
--- a/src/fs/test_fs_unindex_persistence.c
+++ b/src/fs/test_fs_unindex_persistence.c
@@ -273,7 +273,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/hostlist/test_gnunet_daemon_hostlist.c b/src/hostlist/test_gnunet_daemon_hostlist.c
index b3859f6..7b8009d 100644
--- a/src/hostlist/test_gnunet_daemon_hostlist.c
+++ b/src/hostlist/test_gnunet_daemon_hostlist.c
@@ -154,7 +154,7 @@ waitpid_task (void *cls,
 #if START_ARM 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
 	      "Killing ARM process.\n");
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/hostlist/test_gnunet_daemon_hostlist_learning.c b/src/hostlist/test_gnunet_daemon_hostlist_learning.c
index 6f66b9c..5438a3c 100644
--- a/src/hostlist/test_gnunet_daemon_hostlist_learning.c
+++ b/src/hostlist/test_gnunet_daemon_hostlist_learning.c
@@ -133,7 +133,7 @@ static void shutdown_testcase()
 #if START_ARM
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Killing hostlist server ARM process.\n");
-  if (0 != GNUNET_OS_process_kill (adv_peer.arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (adv_peer.arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(adv_peer.arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
@@ -147,7 +147,7 @@ static void shutdown_testcase()
 #if START_ARM
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Killing hostlist client ARM process.\n");
-  if (0 != GNUNET_OS_process_kill (learn_peer.arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (learn_peer.arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   if (GNUNET_OS_process_wait(learn_peer.arm_proc) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
diff --git a/src/include/gnunet_disk_lib.h b/src/include/gnunet_disk_lib.h
index a59d10e..744eb05 100644
--- a/src/include/gnunet_disk_lib.h
+++ b/src/include/gnunet_disk_lib.h
@@ -643,13 +643,24 @@ int GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h);
 int GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h);
 
 /**
- * Creates a named pipe/FIFO
- * @param fn name of the named pipe
+ * Creates a named pipe/FIFO and opens it
+ * @param fn pointer to the name of the named pipe or to NULL
  * @param flags open flags
  * @param perm access permissions
  * @return pipe handle on success, NULL on error
  */
-struct GNUNET_DISK_FileHandle *GNUNET_DISK_npipe_open (const char *fn,
+struct GNUNET_DISK_FileHandle *GNUNET_DISK_npipe_open (char **fn,
+    enum GNUNET_DISK_OpenFlags flags, enum GNUNET_DISK_AccessPermissions perm);
+
+/**
+ * Opens already existing named pipe/FIFO
+ *
+ * @param fn name of an existing named pipe
+ * @param flags open flags
+ * @param perm access permissions
+ * @return pipe handle on success, NULL on error
+ */
+struct GNUNET_DISK_FileHandle *GNUNET_DISK_npipe_open_existing (const char *fn,
     enum GNUNET_DISK_OpenFlags flags, enum GNUNET_DISK_AccessPermissions perm);
 
 /**
diff --git a/src/include/gnunet_os_lib.h b/src/include/gnunet_os_lib.h
index 5ff2b48..8d18c6e 100644
--- a/src/include/gnunet_os_lib.h
+++ b/src/include/gnunet_os_lib.h
@@ -192,9 +192,13 @@ struct GNUNET_OS_Process *GNUNET_OS_process_current (void);
  *
  * @param proc pointer to process structure
  * @param sig signal
+ * @param time_out GNUNET_YES to add a scheduler task that will kill() the
+ *        process directly if signaling via control pipe times out, GNUNET_NO
+ *        otherwise. Use GNUNET_NO when running outside of a scheduler, or
+ *        when you are going to use GNUNET_OS_process_wait() right away.
  * @return 0 on success, -1 on error
  */
-int GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig);
+int GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig, int time_out);
 
 
 /**
@@ -274,6 +278,14 @@ int GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
 int GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc);
 
 
+/**
+ * Connects this process to its parent via pipe
+ */
+void
+GNUNET_OS_install_parent_control_handler (void *cls,
+                                          const struct
+                                          GNUNET_SCHEDULER_TaskContext * tc);
+
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
 #endif
diff --git a/src/peerinfo/perf_peerinfo_api.c b/src/peerinfo/perf_peerinfo_api.c
index fe1851a..c503e83 100755
--- a/src/peerinfo/perf_peerinfo_api.c
+++ b/src/peerinfo/perf_peerinfo_api.c
@@ -185,7 +185,7 @@ check ()
 	   numpeers,
 	   NUM_REQUESTS * NUM_REQUESTS / 2);
 #if START_SERVICE
-  if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (proc, SIGTERM, GNUNET_NO))
     {
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
       ok = 1;
diff --git a/src/peerinfo/test_peerinfo_api.c b/src/peerinfo/test_peerinfo_api.c
index fdd0dc4..2bcc982 100644
--- a/src/peerinfo/test_peerinfo_api.c
+++ b/src/peerinfo/test_peerinfo_api.c
@@ -182,7 +182,7 @@ check ()
   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
                       argv, "test-peerinfo-api", "nohelp",
                       options, &run, &ok);
-  if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (proc, SIGTERM, GNUNET_NO))
     {
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
       ok = 1;
diff --git a/src/statistics/test_statistics_api.c b/src/statistics/test_statistics_api.c
index 9e43663..42a511c 100644
--- a/src/statistics/test_statistics_api.c
+++ b/src/statistics/test_statistics_api.c
@@ -166,7 +166,7 @@ check ()
   GNUNET_PROGRAM_run (5, argv, "test-statistics-api", "nohelp",
                       options, &run, &ok);
 #if START_SERVICE
-  if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (proc, SIGTERM, GNUNET_NO))
     {
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
       ok = 1;
@@ -190,7 +190,7 @@ check ()
   GNUNET_PROGRAM_run (5, argv, "test-statistics-api", "nohelp",
                       options, &run_more, &ok);
 #if START_SERVICE
-  if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (proc, SIGTERM, GNUNET_NO))
     {
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
       ok = 1;
diff --git a/src/statistics/test_statistics_api_loop.c b/src/statistics/test_statistics_api_loop.c
index 02f4aca..f03a869 100644
--- a/src/statistics/test_statistics_api_loop.c
+++ b/src/statistics/test_statistics_api_loop.c
@@ -106,7 +106,7 @@ check ()
   GNUNET_PROGRAM_run (3, argv, "test-statistics-api", "nohelp",
                       options, &run, &ok);
 #if START_SERVICE
-  if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (proc, SIGTERM, GNUNET_NO))
     {
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
       ok = 1;
diff --git a/src/testing/testing.c b/src/testing/testing.c
index 0204f31..f0f3402 100644
--- a/src/testing/testing.c
+++ b/src/testing/testing.c
@@ -401,7 +401,7 @@ start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
           d->cb = NULL;
           GNUNET_DISK_pipe_close (d->pipe_stdout);
           d->pipe_stdout = NULL;
-          (void) GNUNET_OS_process_kill (d->proc, SIGKILL);
+          (void) GNUNET_OS_process_kill (d->proc, SIGKILL, GNUNET_NO);
           GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (d->proc));
           GNUNET_OS_process_close (d->proc);
           d->proc = NULL;
@@ -411,7 +411,7 @@ start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
         }
       GNUNET_DISK_pipe_close (d->pipe_stdout);
       d->pipe_stdout = NULL;
-      (void) GNUNET_OS_process_kill (d->proc, SIGKILL);
+      (void) GNUNET_OS_process_kill (d->proc, SIGKILL, GNUNET_NO);
       GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (d->proc));
       GNUNET_OS_process_close (d->proc);
       d->proc = NULL;
diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c
index 627cb6b..6dcb21f 100644
--- a/src/transport/plugin_transport_tcp.c
+++ b/src/transport/plugin_transport_tcp.c
@@ -3012,7 +3012,7 @@ libgnunet_plugin_transport_tcp_done (void *cls)
 
   if (plugin->behind_nat == GNUNET_YES)
     {
-      if (0 != GNUNET_OS_process_kill (plugin->server_proc, SIGTERM))
+      if (0 != GNUNET_OS_process_kill (plugin->server_proc, SIGTERM, GNUNET_NO))
         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
       GNUNET_OS_process_wait (plugin->server_proc);
       GNUNET_OS_process_close (plugin->server_proc);
diff --git a/src/transport/plugin_transport_udp.c b/src/transport/plugin_transport_udp.c
index 4bf66f2..3595028 100644
--- a/src/transport/plugin_transport_udp.c
+++ b/src/transport/plugin_transport_udp.c
@@ -522,7 +522,7 @@ udp_transport_server_stop (void *cls)
     }
   if (plugin->behind_nat == GNUNET_YES)
     {
-      if (0 != GNUNET_OS_process_kill (plugin->server_proc, SIGTERM))
+      if (0 != GNUNET_OS_process_kill (plugin->server_proc, SIGTERM, GNUNET_NO))
 	GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
       GNUNET_OS_process_wait (plugin->server_proc);
       GNUNET_OS_process_close (plugin->server_proc);
diff --git a/src/transport/test_quota_compliance.c b/src/transport/test_quota_compliance.c
index e4b7280..db92140 100644
--- a/src/transport/test_quota_compliance.c
+++ b/src/transport/test_quota_compliance.c
@@ -196,7 +196,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   GNUNET_OS_process_wait (p->arm_proc);
   GNUNET_OS_process_close (p->arm_proc);
diff --git a/src/transport/test_transport_api.c b/src/transport/test_transport_api.c
index 5bf57b8..0d8adf7 100644
--- a/src/transport/test_transport_api.c
+++ b/src/transport/test_transport_api.c
@@ -118,7 +118,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   GNUNET_OS_process_wait (p->arm_proc);
   GNUNET_OS_process_close (p->arm_proc);
diff --git a/src/transport/test_transport_api_reliability.c b/src/transport/test_transport_api_reliability.c
index 31c5970..d7bfa6e 100644
--- a/src/transport/test_transport_api_reliability.c
+++ b/src/transport/test_transport_api_reliability.c
@@ -139,7 +139,7 @@ static void
 stop_arm (struct PeerContext *p)
 {
 #if START_ARM
-  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM, GNUNET_NO))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   GNUNET_OS_process_wait (p->arm_proc);
   GNUNET_OS_process_close (p->arm_proc);
diff --git a/src/util/crypto_random.c b/src/util/crypto_random.c
index 6228174..8d8179d 100644
--- a/src/util/crypto_random.c
+++ b/src/util/crypto_random.c
@@ -208,7 +208,7 @@ entropy_generator (void *cls,
     {
       if (genproc != NULL)
         {
-          if (0 != GNUNET_OS_process_kill (genproc, SIGTERM))
+          if (0 != GNUNET_OS_process_kill (genproc, SIGTERM, GNUNET_NO))
             GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "kill");
           GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc));
           GNUNET_OS_process_close (genproc);
@@ -226,7 +226,7 @@ entropy_generator (void *cls,
           GNUNET_break (0);
           return;
         }
-      if (0 != GNUNET_OS_process_kill (genproc, SIGTERM))
+      if (0 != GNUNET_OS_process_kill (genproc, SIGTERM, GNUNET_NO))
         GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "kill");
       GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc));
       GNUNET_OS_process_close (genproc);
@@ -247,7 +247,7 @@ killfind ()
 {
   if (genproc != NULL)
     {
-      GNUNET_OS_process_kill (genproc, SIGKILL);
+      GNUNET_OS_process_kill (genproc, SIGKILL, GNUNET_NO);
       GNUNET_OS_process_close (genproc);
       genproc = NULL;
     }
diff --git a/src/util/disk.c b/src/util/disk.c
index 0b37da8..5d35fa0 100644
--- a/src/util/disk.c
+++ b/src/util/disk.c
@@ -31,6 +31,7 @@
 #include "gnunet_disk_lib.h"
 #include "gnunet_scheduler_lib.h"
 #include "gnunet_strings_lib.h"
+#include "gnunet_crypto_lib.h"
 #include "disk.h"
 
 
@@ -1877,20 +1878,20 @@ GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
 
 
 /**
- * Creates a named pipe/FIFO
- * @param fn name of the named pipe
+ * Creates a named pipe/FIFO and opens it
+ * @param fn pointer to the name of the named pipe or to NULL
  * @param flags open flags
  * @param perm access permissions
  * @return pipe handle on success, NULL on error
  */
 struct GNUNET_DISK_FileHandle *
-GNUNET_DISK_npipe_open (const char *fn,
+GNUNET_DISK_npipe_open (char **fn,
                        enum GNUNET_DISK_OpenFlags flags,
                        enum GNUNET_DISK_AccessPermissions perm)
 {
-#ifdef MINGW
+#if WINDOWS && !defined(__CYGWIN__)
   struct GNUNET_DISK_FileHandle *ret;
-  HANDLE h;
+  HANDLE h = NULL;
   DWORD openMode;
   char *name;
 
@@ -1905,21 +1906,50 @@ GNUNET_DISK_npipe_open (const char *fn,
   if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
     openMode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
 
-  GNUNET_asprintf(&name, "\\\\.\\pipe\\pipename\\%s", fn);
-  h = CreateNamedPipe (fn, openMode | FILE_FLAG_OVERLAPPED,
-      PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0, NULL);
-  GNUNET_free(name);
-  if (h == NULL)
+  while (h == NULL)
     {
-      SetErrnoFromWinError(GetLastError());
-      return NULL;
+      name = NULL;
+      if (*fn != NULL)
+        {
+          GNUNET_asprintf(&name, "\\\\.\\pipe\\%.246s", fn);
+          h = CreateNamedPipe (name, openMode | FILE_FLAG_OVERLAPPED,
+              PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0, NULL);
+        }
+      else
+        {
+          GNUNET_asprintf(fn, "\\\\.\\pipe\\gnunet-%llu",
+              GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX));
+          h = CreateNamedPipe (*fn, openMode | FILE_FLAG_OVERLAPPED,
+              PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0, NULL);
+        }
+      if (name)
+          GNUNET_free(name);
+      /* don't re-set name to NULL yet */
+      if (h == INVALID_HANDLE_VALUE)
+        {
+          SetErrnoFromWinError(GetLastError());
+          if (name == NULL)
+            {
+              GNUNET_free (*fn);
+              *fn = NULL;
+              if (errno != EEXIST)
+                  return NULL;
+            }
+          else
+              return NULL;
+        }
     }
+  errno = 0;
 
   ret = GNUNET_malloc(sizeof(*ret));
   ret->h = h;
+  ret->type = GNUNET_PIPE;
 
   return ret;
 #else
+  /* FIXME: if fn is NULL generate a fn (something in /usr/share/gnunet/,
+   * with a random number attached
+   */  
   if (mkfifo(fn, translate_unix_perms(perm)) == -1)
     {
       if ( (errno != EEXIST) ||
@@ -1933,6 +1963,51 @@ GNUNET_DISK_npipe_open (const char *fn,
 }
 
 /**
+ * Opens already existing named pipe/FIFO
+ *
+ * @param fn name of an existing named pipe
+ * @param flags open flags
+ * @param perm access permissions
+ * @return pipe handle on success, NULL on error
+ */
+struct GNUNET_DISK_FileHandle *
+GNUNET_DISK_npipe_open_existing (const char *fn,
+                                 enum GNUNET_DISK_OpenFlags flags,
+                                 enum GNUNET_DISK_AccessPermissions perm)
+{
+#if WINDOWS && !defined(__CYGWIN__)
+  struct GNUNET_DISK_FileHandle *ret;
+  HANDLE h;
+  DWORD openMode;
+
+  openMode = 0;
+  if (flags & GNUNET_DISK_OPEN_READWRITE)
+    openMode = GENERIC_WRITE | GENERIC_READ;
+  else if (flags & GNUNET_DISK_OPEN_READ)
+    openMode = GENERIC_READ;
+  else if (flags & GNUNET_DISK_OPEN_WRITE)
+    openMode = GENERIC_WRITE;
+
+  h = CreateFile (fn, openMode, 0, NULL, OPEN_EXISTING,
+      FILE_FLAG_OVERLAPPED | FILE_READ_ATTRIBUTES, NULL);
+  if (h == INVALID_HANDLE_VALUE)
+    {
+      SetErrnoFromWinError(GetLastError());
+      return NULL;
+    }
+
+  ret = GNUNET_malloc(sizeof(*ret));
+  ret->h = h;
+  ret->type = GNUNET_PIPE;
+
+  return ret;
+#else
+  flags = flags & (~GNUNET_DISK_OPEN_FAILIFEXISTS);
+  return GNUNET_DISK_file_open(fn, flags, perm);
+#endif
+}
+
+/**
  * Closes a named pipe/FIFO
  * @param pipe named pipe
  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
diff --git a/src/util/network.c b/src/util/network.c
index 3b76a35..c2929ac 100644
--- a/src/util/network.c
+++ b/src/util/network.c
@@ -1125,15 +1125,26 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
                 {
                   if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
                     {
-                      retcode = -1;
-                      SetErrnoFromWinError (GetLastError ());
+                      DWORD error_code = GetLastError ();
+                      switch (error_code)
+                      {
+                      case ERROR_BROKEN_PIPE:
+                        GNUNET_CONTAINER_slist_add (handles_read,
+                                                  GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
+                                                  fh, sizeof (struct GNUNET_DISK_FileHandle));
+                        retcode++;
+                        break;
+                      default:
+                        retcode = -1;
+                        SetErrnoFromWinError (error_code);
 
     #if DEBUG_NETWORK
-                      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
-                                           "PeekNamedPipe");
+                        GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+                                             "PeekNamedPipe");
 
     #endif
-                      goto select_loop_end;
+                        goto select_loop_end;
+                      }
                     }
                   else if (dwBytes)
 
diff --git a/src/util/os_priority.c b/src/util/os_priority.c
index fb6c292..7a6fc4a 100644
--- a/src/util/os_priority.c
+++ b/src/util/os_priority.c
@@ -27,29 +27,106 @@
 #include "platform.h"
 #include "gnunet_common.h"
 #include "gnunet_os_lib.h"
+#include "gnunet_scheduler_lib.h"
 #include "disk.h"
 
+#define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE"
+
 struct GNUNET_OS_Process
 {
   pid_t pid;
 #if WINDOWS
   HANDLE handle;
 #endif
+  int sig;
+  struct GNUNET_DISK_FileHandle *control_pipe;
+  GNUNET_SCHEDULER_TaskIdentifier kill_timeout_task;
 };
 
 static struct GNUNET_OS_Process current_process;
 
 
-#if WINDOWS
+/**
+ * This handler is called when there are control data to be read on the pipe
+ */
 void
-GNUNET_OS_process_set_handle(struct GNUNET_OS_Process *proc, HANDLE handle)
+GNUNET_OS_parent_control_handler (void *cls,
+                                  const struct
+                                  GNUNET_SCHEDULER_TaskContext * tc)
 {
-  if (proc->handle != NULL)
-    CloseHandle (proc->handle);
-  proc->handle = handle;
+  struct GNUNET_DISK_FileHandle *control_pipe = (struct GNUNET_DISK_FileHandle *) cls;
+  unsigned char code;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_OS_parent_control_handler is invoked because of %d\n", tc->reason);
+
+  if (tc->reason & (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT | GNUNET_SCHEDULER_REASON_PREREQ_DONE))
+  {
+    GNUNET_DISK_npipe_close (control_pipe);
+  }
+  else
+  {
+    if (GNUNET_DISK_file_read (control_pipe, &code, sizeof (char)) != sizeof (char))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read have failed, errno = %d. Closing the control pipe.\n", errno);
+      GNUNET_DISK_npipe_close (control_pipe);
+    }
+    else
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got control code %d\n", code);
+      switch (code)
+      {
+        case 0:
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Raising SIGTERM\n");
+          raise (SIGTERM);
+          break;
+        case 1:
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Raising SIGKILL\n");
+          raise (SIGKILL);
+          break;
+        case 255:
+          /* read more bytes - a possibility for extended signals
+           * in case 254 different valies is not enough
+           */
+          break;
+        default:
+          break;
+      }
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Re-scheduling the parent control handler pipe\n");
+      GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, control_pipe, GNUNET_OS_parent_control_handler, control_pipe);
+    }
+  }
 }
-#endif
 
+/**
+ * Connects this process to its parent via pipe
+ */
+void
+GNUNET_OS_install_parent_control_handler (void *cls,
+                                          const struct
+                                          GNUNET_SCHEDULER_TaskContext * tc)
+{
+  char *env_buf;
+  struct GNUNET_DISK_FileHandle *control_pipe = NULL;
+
+  env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
+  if (env_buf == NULL || strlen (env_buf) <= 0)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not installing a handler because %s=%s\n", GNUNET_OS_CONTROL_PIPE, env_buf);
+    return;
+  }
+
+  control_pipe = GNUNET_DISK_npipe_open_existing (env_buf,
+      GNUNET_DISK_OPEN_READ,
+      GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
+  if (control_pipe == NULL)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to open the pipe `%s'\n", env_buf);
+    return;
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding parent control handler pipe `%s' to the scheduler\n", env_buf);
+  GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, control_pipe, GNUNET_OS_parent_control_handler, control_pipe);
+}
 
 /**
  * Get process structure for current process
@@ -71,34 +148,129 @@ GNUNET_OS_process_current ()
   return &current_process;
 }
 
-int
-GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
+struct GNUNET_OS_process_kill_timeout_cls
 {
-#if WINDOWS
-  if (sig == SIGKILL || sig == SIGTERM)
+  struct GNUNET_OS_Process *proc;
+  int sig;
+};
+
+void
+GNUNET_OS_process_kill_timeout (void *cls,
+    const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct GNUNET_OS_Process *proc = (struct GNUNET_OS_Process *) cls;
+  enum GNUNET_OS_ProcessStatusType type;
+  unsigned long code;
+  unsigned char c;
+  size_t s;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_OS_process_kill_timeout() is called because of %d\n", tc->reason);
+
+  if (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT && GNUNET_OS_process_status (proc, &type, &code) == GNUNET_NO)
   {
-    HANDLE h = proc->handle;
-    if (NULL == h)
+    switch (proc->sig)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-		  _("Invalid process information {%d, %08X}\n"),
-		  proc->pid,
-		  h);
-      return -1;
+    case SIGTERM:
+      c = 0;
+      break;
+    case SIGKILL:
+      c = 1;
+      break;
     }
-    if (!TerminateProcess (h, 0))
+
+    s = sizeof (c);
+    if (GNUNET_DISK_file_write (proc->control_pipe, &c, s) != s)
     {
-      SetErrnoFromWinError (GetLastError ());
-      return -1;
+#if !WINDOWS || defined(__CYGWIN__)
+      kill (proc->pid, proc->sig);
+#else
+      DWORD dwresult, error_code;
+      BOOL bresult;
+      SetLastError (0);
+      dwresult = WaitForSingleObject (proc->handle, 0);
+      error_code = GetLastError ();
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+          "Woke up, returned %d, GLE is %d\n", dwresult, error_code);
+      if (WAIT_OBJECT_0 != dwresult || error_code != NO_ERROR)
+      {
+        SetLastError (0);
+        bresult = TerminateProcess (proc->handle, 0);
+        error_code = GetLastError ();
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+            "TerminateProcess for the child returned %d, GLE is %d\n", bresult,
+            error_code);
+      }
+#endif
+    }
+  }
+  proc->kill_timeout_task = 0;
+}
+
+int
+GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig, int time_out)
+{
+  unsigned char c;
+  size_t s;
+  int res = 0;
+  int ret = 0;
+
+  if (proc->kill_timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (proc->kill_timeout_task);
+    proc->kill_timeout_task = 0;
+  }
+
+  switch (sig)
+  {
+  case SIGTERM:
+    c = 0;
+    break;
+  case SIGKILL:
+    c = 1;
+    break;
+  default:
+    errno = EINVAL;
+    return -1;
+  }
+
+  s = sizeof (c);
+  ret = GNUNET_DISK_file_write (proc->control_pipe, &c, s);
+  if (ret != s)
+  {
+    if (errno == ECOMM)
+    {
+      /* Child process is not controllable via pipe */
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+          "Child process is not controllable, will kill it directly\n");
+      if (time_out == GNUNET_YES)
+      {
+        proc->sig = sig;
+        proc->kill_timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+            (GNUNET_TIME_UNIT_SECONDS, 0), GNUNET_OS_process_kill_timeout, proc);
+      }
+      else
+      {
+        struct GNUNET_SCHEDULER_TaskContext tc;
+        tc.reason = GNUNET_SCHEDULER_REASON_TIMEOUT;
+        GNUNET_OS_process_kill_timeout (proc, &tc);
+      }
     }
     else
-      return 0;
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+          "Failed to write into control pipe , errno is %d\n", errno);
+      res = -1;
+    }
   }
-  errno = EINVAL;
-  return -1;
-#else
-  return kill (proc->pid, sig);
-#endif
+  else if (time_out == GNUNET_YES)
+  {
+    proc->sig = sig;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        "Wrote control code into control pipe, now waiting\n");
+    proc->kill_timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+        (GNUNET_TIME_UNIT_SECONDS, 3), GNUNET_OS_process_kill_timeout, proc);
+  }
+  return res;
 }
 
 /**
@@ -117,14 +289,18 @@ GNUNET_OS_process_get_pid (struct GNUNET_OS_Process *proc)
 void
 GNUNET_OS_process_close (struct GNUNET_OS_Process *proc)
 {
-#if WINDOWS
+  if (proc->kill_timeout_task)
+    GNUNET_SCHEDULER_cancel (proc->kill_timeout_task);
+  if (proc->control_pipe)
+    GNUNET_DISK_npipe_close (proc->control_pipe);
+#if WINDOWS && !defined(__CYGWIN__)
   if (proc->handle != NULL)
     CloseHandle (proc->handle);
 #endif  
   GNUNET_free (proc);
 }
 
-#if WINDOWS
+#if WINDOWS && !defined(__CYGWIN__)
 #include "gnunet_signal_lib.h"
 
 extern GNUNET_SIGNAL_Handler w32_sigchld_handler;
@@ -258,6 +434,105 @@ GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
   return GNUNET_OK;
 }
 
+#if WINDOWS && !defined(__CYGWIN__)
+char *
+CreateCustomEnvTable (char **vars)
+{
+  char *win32_env_table, *ptr, **var_ptr, *result, *result_ptr;
+  size_t tablesize = 0;
+  size_t items_count = 0;
+  size_t n_found = 0, n_var;
+  char *index = NULL;
+  size_t c;
+  size_t var_len;
+  char *var;
+  char *val;
+  win32_env_table = GetEnvironmentStringsA ();
+  if (win32_env_table == NULL)
+    return NULL;
+  for (c = 0, var_ptr = vars; *var_ptr; var_ptr += 2, c++);
+  n_var = c;
+  index = GNUNET_malloc (n_var);
+  for (c = 0; c < n_var; c++)
+    index[c] = 0;
+  for (items_count = 0, ptr = win32_env_table; ptr[0] != 0; items_count++)
+  {
+    size_t len = strlen (ptr);
+    int found = 0;
+    for (var_ptr = vars; *var_ptr; var_ptr++)
+    {
+      var = *var_ptr++;
+      val = *var_ptr;
+      var_len = strlen (var);
+      if (strncmp (var, ptr, var_len) == 0)
+      {
+        found = 1;
+        index[c] = 1;
+        tablesize += var_len + strlen (val) + 1;
+        break;
+      }
+    }
+    if (!found)
+      tablesize += len + 1;
+    ptr += len + 1; 
+  }
+  for (n_found = 0, c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
+  {
+    var = *var_ptr++;
+    val = *var_ptr;
+    if (index[c] != 1)
+      n_found += strlen (var) + strlen (val) + 1;
+  }
+  result = GNUNET_malloc (tablesize + n_found + 1);
+  for (result_ptr = result, ptr = win32_env_table; ptr[0] != 0;)
+  {
+    size_t len = strlen (ptr);
+    int found = 0;
+    for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
+    {
+      var = *var_ptr++;
+      val = *var_ptr;
+      var_len = strlen (var);
+      if (strncmp (var, ptr, var_len) == 0)
+      {
+        found = 1;
+        break;
+      }
+    }
+    if (!found)
+    {
+      strcpy (result_ptr, ptr);
+      result_ptr += len + 1;
+    }
+    else
+    {
+      strcpy (result_ptr, var);
+      result_ptr += var_len;
+      strcpy (result_ptr, val);
+      result_ptr += strlen (val) + 1;
+    }
+    ptr += len + 1;
+  }
+  for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
+  {
+    var = *var_ptr++;
+    val = *var_ptr;
+    var_len = strlen (var);
+    if (index[c] != 1)
+    {
+      strcpy (result_ptr, var);
+      result_ptr += var_len;
+      strcpy (result_ptr, val);
+      result_ptr += strlen (val) + 1;
+    }
+  }
+  FreeEnvironmentStrings (win32_env_table);
+  GNUNET_free (index);
+  *result_ptr = 0;
+  return result;
+}
+#endif
+
 /**
  * Start a process.
  *
@@ -273,10 +548,12 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
 			 const char *filename, ...)
 {
   va_list ap;
+  char *childpipename = NULL;
+  struct GNUNET_DISK_FileHandle *control_pipe = NULL;
+  struct GNUNET_OS_Process *gnunet_proc = NULL;
 
 #ifndef MINGW
   pid_t ret;
-  struct GNUNET_OS_Process *gnunet_proc = NULL;
   char **argv;
   int argc;
   int fd_stdout_write;
@@ -284,6 +561,12 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   int fd_stdin_read;
   int fd_stdin_write;
 
+  control_pipe = GNUNET_DISK_npipe_open (&childpipename,
+      GNUNET_DISK_OPEN_WRITE, GNUNET_DISK_PERM_USER_READ |
+      GNUNET_DISK_PERM_USER_WRITE);
+  if (control_pipe == NULL)
+    return NULL;
+
   argc = 0;
   va_start (ap, filename);
   while (NULL != va_arg (ap, char *))
@@ -316,6 +599,7 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
       if (ret == -1)
         {
           GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
+          GNUNET_DISK_npipe_close (control_pipe);
         }
       else
         {
@@ -337,11 +621,16 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
 #endif
           gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
           gnunet_proc->pid = ret;
+          gnunet_proc->control_pipe = control_pipe;
         }
       GNUNET_free (argv);
+      GNUNET_free (childpipename);
       return gnunet_proc;
     }
 
+  setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1);
+  GNUNET_free (childpipename);
+
   if (pipe_stdout != NULL)
     {
       GNUNET_break (0 == close (fd_stdout_read));
@@ -367,23 +656,89 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   char *cmd, *idx;
   STARTUPINFO start;
   PROCESS_INFORMATION proc;
-  struct GNUNET_OS_Process *gnunet_proc = NULL;
 
   HANDLE stdin_handle;
   HANDLE stdout_handle;
 
   char path[MAX_PATH + 1];
 
+  char *our_env[3] = { NULL, NULL, NULL };
+  char *env_block = NULL;
+  char *pathbuf;
+  DWORD pathbuf_len, alloc_len;
+  char *self_prefix;
+  char *bindir;
+  char *libdir;
+  char *ptr;
+  char *non_const_filename;
+
+  /* Search in prefix dir (hopefully - the directory from which
+   * the current module was loaded), bindir and libdir, then in PATH
+   */
+  self_prefix = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX);
+  bindir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR);
+  libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
+
+  pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0);
+
+  alloc_len = pathbuf_len + 1 + strlen (self_prefix) + 1 + strlen (bindir) + 1 + strlen (libdir);
+
+  pathbuf = GNUNET_malloc (alloc_len * sizeof (char));
+
+  ptr = pathbuf;
+  ptr += sprintf (pathbuf, "%s;%s;%s;", self_prefix, bindir, libdir);
+  GNUNET_free (self_prefix);
+  GNUNET_free (bindir);
+  GNUNET_free (libdir);
+
+  alloc_len = GetEnvironmentVariableA ("PATH", ptr, pathbuf_len);
+  if (alloc_len != pathbuf_len - 1)
+  {
+    GNUNET_free (pathbuf);
+    errno = ENOSYS; /* PATH changed on the fly. What kind of error is that? */
+    return NULL;
+  }
+
+  cmdlen = strlen (filename);
+  if (cmdlen < 5 || strcmp (&filename[cmdlen - 4], ".exe") != 0)
+    GNUNET_asprintf (&non_const_filename, "%s.exe", filename);
+  else
+    GNUNET_asprintf (&non_const_filename, "%s", filename);
+
+  /* Check that this is the full path. If it isn't, search. */
+  if (non_const_filename[1] == ':')
+    snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename);
+  else if (!SearchPathA (pathbuf, non_const_filename, NULL, sizeof (path) / sizeof (char), path, NULL))
+    {
+      SetErrnoFromWinError (GetLastError ());
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "SearchPath", non_const_filename);
+      GNUNET_free (non_const_filename);
+      GNUNET_free (pathbuf);
+      return NULL;
+    }
+  GNUNET_free (pathbuf);
+  GNUNET_free (non_const_filename);
+ 
   cmdlen = 0;
   va_start (ap, filename);
   while (NULL != (arg = va_arg (ap, char *)))
-      cmdlen = cmdlen + strlen (arg) + 3;
+  {
+      if (cmdlen == 0)
+        cmdlen = cmdlen + strlen (path) + 3;
+      else
+        cmdlen = cmdlen + strlen (arg) + 3;
+  }
   va_end (ap);
 
   cmd = idx = GNUNET_malloc (sizeof (char) * (cmdlen + 1));
   va_start (ap, filename);
   while (NULL != (arg = va_arg (ap, char *)))
-      idx += sprintf (idx, "\"%s\" ", arg);
+  {
+      if (idx == cmd)
+        idx += sprintf (idx, "\"%s\" ", path);
+      else
+        idx += sprintf (idx, "\"%s\" ", arg);
+  }
   va_end (ap);
 
   memset (&start, 0, sizeof (start));
@@ -404,28 +759,46 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
       start.hStdOutput = stdout_handle;
     }
 
-  if (32 >= (int) FindExecutableA (filename, NULL, path)) 
-    {
-      SetErrnoFromWinError (GetLastError ());
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
-      return NULL;
-    }
+  control_pipe = GNUNET_DISK_npipe_open (&childpipename,
+      GNUNET_DISK_OPEN_WRITE, GNUNET_DISK_PERM_USER_READ |
+      GNUNET_DISK_PERM_USER_WRITE);
+  if (control_pipe == NULL)
+  {
+    GNUNET_free (cmd);
+    GNUNET_free (path);
+    return NULL;
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n", childpipename);
+
+  GNUNET_asprintf (&our_env[0], "%s=", GNUNET_OS_CONTROL_PIPE);
+  GNUNET_asprintf (&our_env[1], "%s", childpipename);
+  our_env[2] = NULL;
+  env_block = CreateCustomEnvTable (our_env);
+  GNUNET_free (our_env[0]);
+  GNUNET_free (our_env[1]);
 
   if (!CreateProcessA
-      (path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &start,
-       &proc))
+      (path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED,
+       env_block, NULL, &start, &proc))
     {
       SetErrnoFromWinError (GetLastError ());
       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", path);
+      GNUNET_free (env_block);
+      GNUNET_free (cmd);
       return NULL;
     }
 
+  GNUNET_free (env_block);
+
   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
   gnunet_proc->pid = proc.dwProcessId;
   gnunet_proc->handle = proc.hProcess;
+  gnunet_proc->control_pipe = control_pipe;
 
   CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
 
+  ResumeThread (proc.hThread);
   CloseHandle (proc.hThread);
 
   GNUNET_free (cmd);
@@ -450,6 +823,9 @@ struct GNUNET_OS_Process *
 GNUNET_OS_start_process_v (const int *lsocks,
 			   const char *filename, char *const argv[])
 {
+  struct GNUNET_DISK_FileHandle *control_pipe = NULL;
+  char *childpipename = NULL;
+
 #ifndef MINGW
   pid_t ret;
   char lpid[16];
@@ -463,6 +839,12 @@ GNUNET_OS_start_process_v (const int *lsocks,
   int *lscp;
   unsigned int ls;    
 
+  control_pipe = GNUNET_DISK_npipe_open (&childpipename,
+      GNUNET_DISK_OPEN_WRITE, GNUNET_DISK_PERM_USER_READ |
+      GNUNET_DISK_PERM_USER_WRITE);
+  if (control_pipe == NULL)
+    return NULL;
+
   lscp = NULL;
   ls = 0;
   if (lsocks != NULL)
@@ -482,6 +864,7 @@ GNUNET_OS_start_process_v (const int *lsocks,
       if (ret == -1)
         {
           GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
+          GNUNET_DISK_npipe_close (control_pipe);
         }
       else
         {
@@ -498,10 +881,16 @@ GNUNET_OS_start_process_v (const int *lsocks,
 #endif
           gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
           gnunet_proc->pid = ret;
+          gnunet_proc->control_pipe = control_pipe;
         }
       GNUNET_array_grow (lscp, ls, 0);
+      GNUNET_free (childpipename);
       return gnunet_proc;
     }
+
+  setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1);
+  GNUNET_free (childpipename);
+
   if (lscp != NULL)
     {
       /* read systemd documentation... */
@@ -555,17 +944,68 @@ GNUNET_OS_start_process_v (const int *lsocks,
   STARTUPINFO start;
   PROCESS_INFORMATION proc;
   int argcount = 0;
-  char non_const_filename[MAX_PATH +1];
   struct GNUNET_OS_Process *gnunet_proc = NULL;
 
+  char path[MAX_PATH + 1];
+
+  char *our_env[3] = { NULL, NULL, NULL };
+  char *env_block = NULL;
+  char *pathbuf;
+  DWORD pathbuf_len, alloc_len;
+  char *self_prefix;
+  char *bindir;
+  char *libdir;
+  char *ptr;
+  char *non_const_filename;
+
   GNUNET_assert (lsocks == NULL);
 
-  if (32 >= (int) FindExecutableA (filename, NULL, non_const_filename)) 
+  /* Search in prefix dir (hopefully - the directory from which
+   * the current module was loaded), bindir and libdir, then in PATH
+   */
+  self_prefix = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX);
+  bindir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR);
+  libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
+
+  pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0);
+
+  alloc_len = pathbuf_len + 1 + strlen (self_prefix) + 1 + strlen (bindir) + 1 + strlen (libdir);
+
+  pathbuf = GNUNET_malloc (alloc_len * sizeof (char));
+
+  ptr = pathbuf;
+  ptr += sprintf (pathbuf, "%s;%s;%s;", self_prefix, bindir, libdir);
+  GNUNET_free (self_prefix);
+  GNUNET_free (bindir);
+  GNUNET_free (libdir);
+
+  alloc_len = GetEnvironmentVariableA ("PATH", ptr, pathbuf_len);
+  if (alloc_len != pathbuf_len - 1)
+  {
+    GNUNET_free (pathbuf);
+    errno = ENOSYS; /* PATH changed on the fly. What kind of error is that? */
+    return NULL;
+  }
+
+  cmdlen = strlen (filename);
+  if (cmdlen < 5 || strcmp (&filename[cmdlen - 4], ".exe") != 0)
+    GNUNET_asprintf (&non_const_filename, "%s.exe", filename);
+  else
+    GNUNET_asprintf (&non_const_filename, "%s", filename);
+
+  /* Check that this is the full path. If it isn't, search. */
+  if (non_const_filename[1] == ':')
+    snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename);
+  else if (!SearchPathA (pathbuf, non_const_filename, NULL, sizeof (path) / sizeof (char), path, NULL))
     {
       SetErrnoFromWinError (GetLastError ());
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "SearchPath", non_const_filename);
+      GNUNET_free (non_const_filename);
+      GNUNET_free (pathbuf);
       return NULL;
     }
+  GNUNET_free (pathbuf);
+  GNUNET_free (non_const_filename);
 
   /* Count the number of arguments */
   arg = (char **) argv;
@@ -583,7 +1023,10 @@ GNUNET_OS_start_process_v (const int *lsocks,
   arg = (char **) argv;
   while (*arg)
     {
-      non_const_argv[argcount] = GNUNET_strdup (*arg);
+      if (arg == argv)
+        non_const_argv[argcount] = GNUNET_strdup (path);
+      else
+        non_const_argv[argcount] = GNUNET_strdup (*arg);
       arg++;
       argcount++;
     }
@@ -607,31 +1050,56 @@ GNUNET_OS_start_process_v (const int *lsocks,
       arg++;
     }
 
+  while (argcount > 0)
+    GNUNET_free (non_const_argv[--argcount]);
+  GNUNET_free (non_const_argv);
+
   memset (&start, 0, sizeof (start));
   start.cb = sizeof (start);
 
+  control_pipe = GNUNET_DISK_npipe_open (&childpipename,
+      GNUNET_DISK_OPEN_WRITE, GNUNET_DISK_PERM_USER_READ |
+      GNUNET_DISK_PERM_USER_WRITE);
+  if (control_pipe == NULL)
+  {
+    GNUNET_free (cmd);
+    GNUNET_free (path);
+    return NULL;
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n", childpipename);
+
+  GNUNET_asprintf (&our_env[0], "%s=", GNUNET_OS_CONTROL_PIPE);
+  GNUNET_asprintf (&our_env[1], "%s", childpipename);
+  our_env[2] = NULL;
+  env_block = CreateCustomEnvTable (our_env);
+  GNUNET_free (our_env[0]);
+  GNUNET_free (our_env[1]);
+
   if (!CreateProcess
-      (non_const_filename, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
-       &proc))
+      (path, cmd, NULL, NULL, FALSE, DETACHED_PROCESS | CREATE_SUSPENDED,
+       env_block, NULL, &start, &proc))
     {
       SetErrnoFromWinError (GetLastError ());
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
+      GNUNET_free (env_block);
+      GNUNET_free (cmd);
       return NULL;
     }
 
+  GNUNET_free (env_block);
+
   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
   gnunet_proc->pid = proc.dwProcessId;
   gnunet_proc->handle = proc.hProcess;
+  gnunet_proc->control_pipe = control_pipe;
 
   CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
 
+  ResumeThread (proc.hThread);
   CloseHandle (proc.hThread);
   GNUNET_free (cmd);
 
-  while (argcount > 0)
-    GNUNET_free (non_const_argv[--argcount]);
-  GNUNET_free (non_const_argv);
-
   return gnunet_proc;
 #endif
 }
@@ -741,8 +1209,13 @@ GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
 int
 GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
 {
-
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
+  if (proc->kill_timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (proc->kill_timeout_task);
+    proc->kill_timeout_task = 0;
+    kill (proc->pid, proc->sig);
+  }
   pid_t pid = proc->pid;
   if (pid != waitpid (pid, NULL, 0))
     return GNUNET_SYSERR;
@@ -763,13 +1236,35 @@ GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
   if (h == NULL)
     h = GetCurrentProcess ();
 
-  if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
+  if (proc->kill_timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (proc->kill_timeout_task);
+    proc->kill_timeout_task = 0;
+    if (WAIT_OBJECT_0 != WaitForSingleObject (h, 4000))
     {
-      SetErrnoFromWinError (GetLastError ());
-      ret = GNUNET_SYSERR;
+      struct GNUNET_SCHEDULER_TaskContext tc;
+      tc.reason = GNUNET_SCHEDULER_REASON_TIMEOUT;
+      GNUNET_OS_process_kill_timeout (proc, &tc);
+      if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
+      {
+        ret = GNUNET_SYSERR;
+        SetErrnoFromWinError (GetLastError ());
+      }
+      else
+        ret = GNUNET_OK;
     }
-  else
     ret = GNUNET_OK;
+  }
+  else
+  {
+    if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
+      {
+        SetErrnoFromWinError (GetLastError ());
+        ret = GNUNET_SYSERR;
+      }
+    else
+      ret = GNUNET_OK;
+  }
 
   return ret;
 #endif
diff --git a/src/util/scheduler.c b/src/util/scheduler.c
index 13b3f85..353c7ea 100644
--- a/src/util/scheduler.c
+++ b/src/util/scheduler.c
@@ -741,6 +741,9 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
   GNUNET_SCHEDULER_add_continuation (task,
                                      task_cls,
                                      GNUNET_SCHEDULER_REASON_STARTUP);
+  GNUNET_SCHEDULER_add_continuation (GNUNET_OS_install_parent_control_handler,
+                                     NULL, GNUNET_SCHEDULER_REASON_STARTUP);
+
   last_tr = 0;
   busy_wait_warning = 0;
   while ((pending != NULL) ||
diff --git a/src/util/test_os_start_process.c b/src/util/test_os_start_process.c
index f82860e..d648a04 100644
--- a/src/util/test_os_start_process.c
+++ b/src/util/test_os_start_process.c
@@ -50,7 +50,7 @@ static void
 end_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
 
-  if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (proc, SIGTERM, GNUNET_NO))
     {
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
     }
diff --git a/src/util/test_resolver_api.c b/src/util/test_resolver_api.c
index 3d1d544..8da5ae0 100644
--- a/src/util/test_resolver_api.c
+++ b/src/util/test_resolver_api.c
@@ -378,7 +378,7 @@ check()
   GNUNET_free(fn);
   GNUNET_assert(GNUNET_OK == GNUNET_PROGRAM_run((sizeof(argv) / sizeof(char *))
       - 1, argv, "test-resolver-api", "nohelp", options, &run, &ok));
-  if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (proc, SIGTERM, GNUNET_NO))
     {
       GNUNET_log_strerror(GNUNET_ERROR_TYPE_WARNING, "kill");
       ok = 1;
diff --git a/src/vpn/gnunet-daemon-vpn.c b/src/vpn/gnunet-daemon-vpn.c
index 3b3dbfa..bb41e0c 100644
--- a/src/vpn/gnunet-daemon-vpn.c
+++ b/src/vpn/gnunet-daemon-vpn.c
@@ -195,7 +195,7 @@ cleanup(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tskctx) {
     /* stop the helper */
     if (helper_proc != NULL)
       {
-	GNUNET_OS_process_kill (helper_proc, SIGTERM);
+	GNUNET_OS_process_kill (helper_proc, SIGTERM, GNUNET_NO);
 	GNUNET_OS_process_wait (helper_proc);
 	GNUNET_OS_process_close (helper_proc);
 	helper_proc = NULL;
@@ -250,7 +250,7 @@ start_helper_and_schedule(void *cls,
 static void
 restart_helper(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tskctx) {
     // Kill the helper
-    GNUNET_OS_process_kill (helper_proc, SIGKILL);
+    GNUNET_OS_process_kill (helper_proc, SIGKILL, GNUNET_NO);
     GNUNET_OS_process_wait (helper_proc);
     GNUNET_OS_process_close (helper_proc);
     helper_proc = NULL;
-- 
1.7.3.1.msysgit.0

0001-Fix-unique-named-pipe-generation.patch (2,856 bytes)   
From cfd2f3e50e7077e83d9b7e06d48f12253d188b3b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= <lrn1986@gmail.com>
Date: Mon, 6 Dec 2010 19:55:01 +0300
Subject: [PATCH] Fix unique named pipe generation

---
 src/util/disk.c |   27 ++++++++++++++++++++++++---
 1 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/src/util/disk.c b/src/util/disk.c
index b8bc946..b0a86a9 100644
--- a/src/util/disk.c
+++ b/src/util/disk.c
@@ -34,6 +34,7 @@
 #include "gnunet_crypto_lib.h"
 #include "disk.h"
 
+#define DEBUG_NPIPE GNUNET_YES
 
 /**
  * Block size for IO for copying files.
@@ -1912,10 +1913,14 @@ GNUNET_DISK_npipe_open (char **fn,
 
   while (h == NULL)
     {
+      DWORD error_code;
       name = NULL;
       if (*fn != NULL)
         {
           GNUNET_asprintf(&name, "\\\\.\\pipe\\%.246s", fn);
+#if DEBUG_NPIPE
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to create an instance of named pipe `%s'\n", name);
+#endif
           h = CreateNamedPipe (name, openMode | FILE_FLAG_OVERLAPPED,
               PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0, NULL);
         }
@@ -1923,21 +1928,37 @@ GNUNET_DISK_npipe_open (char **fn,
         {
           GNUNET_asprintf(fn, "\\\\.\\pipe\\gnunet-%llu",
               GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX));
-          h = CreateNamedPipe (*fn, openMode | FILE_FLAG_OVERLAPPED,
+#if DEBUG_NPIPE
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to create unique named pipe `%s'\n", *fn);
+#endif
+          h = CreateNamedPipe (*fn, openMode | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
               PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0, NULL);
         }
+      error_code = GetLastError ();
       if (name)
           GNUNET_free(name);
       /* don't re-set name to NULL yet */
       if (h == INVALID_HANDLE_VALUE)
         {
-          SetErrnoFromWinError(GetLastError());
+          SetErrnoFromWinError(error_code);
+#if DEBUG_NPIPE
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Pipe creation have failed because of %d, errno is %d\n", error_code, errno);
+#endif
           if (name == NULL)
             {
+#if DEBUG_NPIPE
+              GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Pipe was to be unique, considering re-creation\n");
+#endif
               GNUNET_free (*fn);
               *fn = NULL;
-              if (errno != EEXIST)
+              if (error_code != ERROR_ACCESS_DENIED && error_code != ERROR_PIPE_BUSY)
+                {
                   return NULL;
+                }
+#if DEBUG_NPIPE
+              GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Pipe name was not unique, trying again\n");
+#endif
+              h = NULL;
             }
           else
               return NULL;
-- 
1.7.3.1.msysgit.0

0001-Temporary-fix-for-process_kill.patch (2,437 bytes)   
From 200f94a42cd862321db5832744f237c250fbce38 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1=D1?=
 =?UTF-8?q?=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= <lrn1986@gmail.com>
Date: Tue, 28 Dec 2010 02:00:59 +0300
Subject: [PATCH] Temporary fix for process_kill()

---
 src/util/os_priority.c |   52 ++++++++++++++---------------------------------
 1 files changed, 16 insertions(+), 36 deletions(-)

diff --git a/src/util/os_priority.c b/src/util/os_priority.c
index 4d2f98b..acb1219 100644
--- a/src/util/os_priority.c
+++ b/src/util/os_priority.c
@@ -146,46 +146,26 @@ GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
     else
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
           "Failed to write into control pipe , errno is %d\n", errno);
+#if WINDOWS
+    res = 0;
+    TerminateProcess (proc->handle, 0);
+#else
     res = PLIBC_KILL (proc->pid, sig);
+#endif
   }
   else
   {
-  	struct GNUNET_NETWORK_FDSet *rfds;
-    struct GNUNET_NETWORK_FDSet *efds;
-
-    rfds = GNUNET_NETWORK_fdset_create ();
-    efds = GNUNET_NETWORK_fdset_create ();
-
-    GNUNET_NETWORK_fdset_handle_set (rfds, proc->control_pipe);
-    GNUNET_NETWORK_fdset_handle_set (efds, proc->control_pipe);
-
- read_next:
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-            "Wrote control code into control pipe, now waiting\n");
-
-        ret = GNUNET_NETWORK_socket_select (rfds, NULL, efds,
-            GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_unit (),
-                5000));
-
-        if (ret < 1 || GNUNET_NETWORK_fdset_handle_isset (efds,
-            proc->control_pipe))
-          {
-            /* Just to be sure */
-            PLIBC_KILL (proc->pid, sig);
-            res = 0;
-          }
-        else
-          {
-            if (GNUNET_DISK_file_read (proc->control_pipe, &ret,
-                sizeof(ret)) != GNUNET_OK)
-              res = PLIBC_KILL (proc->pid, sig);
-
-            /* Child signaled shutdown is in progress */
-            goto read_next;
-          }
-      }
-
-    return res;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        "Wrote control code into control pipe, now waiting\n");
+    WaitForSingleObject (proc->handle, 5000);
+#if WINDOWS
+    TerminateProcess (proc->handle, 0);
+#else
+    PLIBC_KILL (proc->pid, sig);
+#endif
+    res = 0;
+  }
+  return res;
 #else
   return kill (proc->pid, sig);
 #endif
-- 
1.7.4

0001-More-permanent-fix-for-os_process_kill.patch (3,106 bytes)   
From 9eff5a988c4c11894d59353d9461b080d623ed4e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1=D1?=
 =?UTF-8?q?=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= <lrn1986@gmail.com>
Date: Wed, 13 Jul 2011 05:01:11 +0400
Subject: [PATCH] More permanent fix for os_process_kill

---
 src/util/os_priority.c |   57 ++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 50 insertions(+), 7 deletions(-)

diff --git a/src/util/os_priority.c b/src/util/os_priority.c
index acb1219..2f1b96d 100644
--- a/src/util/os_priority.c
+++ b/src/util/os_priority.c
@@ -146,25 +146,68 @@ GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
     else
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
           "Failed to write into control pipe , errno is %d\n", errno);
-#if WINDOWS
-    res = 0;
+#if WINDOWS && !defined(__CYGWIN__)
     TerminateProcess (proc->handle, 0);
 #else
-    res = PLIBC_KILL (proc->pid, sig);
+    PLIBC_KILL (proc->pid, sig);
 #endif
   }
   else
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
         "Wrote control code into control pipe, now waiting\n");
-    WaitForSingleObject (proc->handle, 5000);
+
 #if WINDOWS
-    TerminateProcess (proc->handle, 0);
+    /* Give it 3 seconds to die, then kill it in a nice Windows-specific way */
+    if (WaitForSingleObject (proc->handle, 3000) != WAIT_OBJECT_0)
+      TerminateProcess (proc->handle, 0);
+    res = 0;
 #else
-    PLIBC_KILL (proc->pid, sig);
+    struct GNUNET_NETWORK_FDSet *rfds;
+    struct GNUNET_NETWORK_FDSet *efds;
+
+    rfds = GNUNET_NETWORK_fdset_create ();
+    efds = GNUNET_NETWORK_fdset_create ();
+
+    GNUNET_NETWORK_fdset_handle_set (rfds, proc->control_pipe);
+    GNUNET_NETWORK_fdset_handle_set (efds, proc->control_pipe);
+
+    /* Ndurner thought this up, and i have no idea what it does.
+     * There's have never been any code to answer the shutdown call
+     * (write a single int into the pipe, so that this function can read it).
+     * On *nix select() will probably tell that pipe is ready
+     * for reading, once the other process shuts down,
+     * but the read () call will fail, triggering a kill ()
+     * on the pid that is already dead. This will probably result in non-0
+     * return from kill(), and therefore from this function.
+     */
+    while (1)
+    {
+      ret = GNUNET_NETWORK_socket_select (rfds, NULL, efds,
+          GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_unit (),
+              5000));
+
+      if (ret < 1 || GNUNET_NETWORK_fdset_handle_isset (efds,
+          proc->control_pipe))
+        {
+          /* Just to be sure */
+          PLIBC_KILL (proc->pid, sig);
+          res = 0;
+          break;
+        }
+      else
+        {
+          if (GNUNET_DISK_file_read (proc->control_pipe, &ret,
+              sizeof(ret)) != GNUNET_OK)
+            res = PLIBC_KILL (proc->pid, sig);
+
+          /* Child signaled shutdown is in progress */
+          continue;
+        }
+     }
 #endif
-    res = 0;
   }
+
   return res;
 #else
   return kill (proc->pid, sig);
-- 
1.7.4

Relationships

related to 0001626 closedLRN Use IPK_SELF_PREFIX to form a path to peerinfo service 

Activities

LRN

2010-11-05 16:35

developer   ~0004142

So far named pipes seem to be the most adequate choice.

Christian Grothoff

2010-11-05 18:11

manager   ~0004143

http://en.wikipedia.org/wiki/Interix

LRN

2010-11-05 18:50

developer   ~0004144

Oh, come on, just say it outright - http://en.wikipedia.org/wiki/Cygwin

It's not really a solution.

NDurner

2010-11-05 21:18

developer   ~0004145

Other possible solutions:
- have a special signal handler function and call that with CreateRemoteThread fromt the parent.
- inherit anonymous pipe, pass handle value via command line
- don't remember if stdio/stderr handles are used for something useful, could be used for IPC

I suspect problems with #3 and #4 in sessions without desktop interaction (most importantly Windows services).

LRN

2010-11-05 22:02

developer   ~0004146

CreateRemoteThread() sounds good. MSDN says: "Terminal Services isolates each terminal session by design. Therefore, CreateRemoteThread fails if the target process is in a different session than the calling process.", but i guess this is OK for us, since all GNUnet processes that ought to be controllable this way would be in the same session. Also, this method is available to any process in the same session with sufficient privileges. Which might be good or bad depending on your viewpoint. I'm especially concerned about UAC in NT 6.x (although GNUnet already does a number of things that require special privileges, so CreateRemoteThread() is unlikely to add anything new here).

By the way, what's the security situation with kill() on Linux? AFAIK kill(pid, SIGTERM) requires that the target process is either owned by the same user (through uid inheritance or suid) or the user does have special privileges for messing with processes that are not his own. Is that the kind of security that should be had on NT, or more lax/more strict security will do (although it's not like it's possible to prevent a root/Administrator from killing something...)?

Passing anonymous pipe via commandline - too ugly, and if you're thinking of C FDs, it won't work when two processes have different C runtimes (point's kinda mood, since the processes we speak of are built together).
Stdio/stderr may be used (and daemonization would and should cut these off).

Here's another solution that i've remembered: make processes into Windwos services. It won't be easy (services require quite a bit of special code), but services can be shut down nicely. Downsides: a) Will be awkward to create so many services, and do that semi-dynamically too (as services/daemons are added to GNUnet configuration), and b) Will be awkward to run multiple instances of the same service (would we want that at all?)

Another option is to use SetConsoleCtrlHandler() in the child process to set up extra handler for CTRL+BREAK, and then use GenerateConsoleCtrlEvent() to send CTRL+BREAK event to the whole process group (processes will have to be created with CREATE_NEW_PROCESS_GROUP flag, and default CTRL+C handling will be disabled).

So, named pipes still hold, and CreateRemoteThread() seems a viable option.

P.S. None of this will work with non-GNUnet processes, since it requires special code in each controllable process. Are there cases when such processes have to be launched and terminated?

Christian Grothoff

2010-11-05 22:32

manager   ~0004147

ARM on UNIX is quite general, but on W32 we can probably say that all children will be GNUnet processes.

As for running multiple instances of the same service: we do that for testing, but we could live without it. What's awkward about having many services? (and how does starting/stopping services then work?) I mean, just looking at the name, services might be the right thing.

CreateRemoteThread -- do I understand correctly that this would create a thread in the child process and then you'd raise a signal there? Sounds viable but possibly very ugly. I agree that CTRL+BREAK and named pipes are also possible.

Given that we will have issues with intermediate child processes (be it libtool wrappers, gnunet-monkey or whatever), I think these approaches are problematic:

1) named pipes -- hard to pick unique names and communicate them and to kill transitively

2) CreateRemoteThread -- note that we need to actually control the circumstances under which the sub-sub-process is killed; i.e. the gnunet-nat-server should not be killed by ARM but by its direct parent; in the case of VPN and WLAN, this issue becomes really important (clean shutdown!)

Approaches I like best so far:

1) Windows services (but I don't know enough about this, you only said it would work but it is ugly to have many -- care to elaborate?)

2) CRTL+BREAK (since this is really not a big abuse since it is about the shutdown of the service; and it supports sending it to the group)

LRN

2010-11-05 23:12

developer   ~0004148

About many services - normally there's one service that does one thing. Also, normally services are created by software when it is installed. But if we restrict that to GNUnet-only processes, that would be about 10 services, which isn't many. Although it's still more than i've ever seen being used by one piece of software. Also, Microsoft-originated services often share the same process, running in separate threads within it, so gnunet would be unusual for both having many services and having many processes.

Each service has a path to the binary and command line arguments as properties, as well as login and password for the account it runs under (unless it's one of the system accounts, in which case only login is needed).
Registering services requires administrative privileges.
I've seen cases when it was impossible to unregister a service without rebooting the machine (i still don't know exactly what kind of resource lock causes such things). Registering a service should not require a reboot, as far as i remember.

Services are controlled by the service manager, which can is accessible by programs (including special utilities shipped with the OS).

I'll be able to give you more info after i re-read the documentation (it's been a while since i've created a service).

And i'll see how Ctrl+Break would work in GNUnet (since it doesn't require that much new code). Although this approach might not work when one of the child processes calls CreateProcess with CREATE_NEW_CONSOLE (libtool wrapper doesn't do that, don't know about gnunet-monkey).

LRN

2010-11-06 04:47

developer   ~0004149

Ctrl+Break & GenerateConsoleCtrlEvent() didn't work out. The function call fails with error code 6, and when i googled, i've found this - http://www.microsoft.com/msj/0698/win320698.aspx . It reinforces the same thing that MSDN says - the process that calls GenerateConsoleCtrlEvent() MUST share the same console as the process group it sends the signal to. Which is not the case, as we call CreateProcess() with DETACHED_PROCESS flag, preventing child processes from inheriting our console. The article proposes to insert a helper process into a new group first and then use IPC to order it to call GenerateConsoleCtrlEvent(), so now we're back where we started - in a need for IPC.

LRN

2010-11-06 06:31

developer   ~0004150

About named pipes: picking unique names isn't as difficult, as i've explained before. Let's supposed we have gnunet-service-arm.exe (PID=1234) that spawns a child - gnunet-service-statistics.exe, which is a libtool wrapper for .libs/gnunet-service-statistics.exe. When gnunet-service-arm.exe was launched, it created the first (and the only one) instance of the pipe "\\.\pipe\1234gnunet-service-arm.exe" (if the instance with that name is taken, gnunet-service-arm dies). It runs gnunet-service-statistics.exe (PID=2345), the libtool wrapper, which in turn runs .libs/gnunet-service-statistics.exe (PID=3456) - the real statistics service. The statistics service then walks the process tree upward from itself; first it finds its parent, gnunet-service-statistics.exe (PID=2345). It ignores the parent, since its name is the same - a special case to handle libtool wrapper. Then it finds its grandparent - gnunet-service-arm.exe (PID=1234) and tries to connect to "\\.\pipe\1234gnunet-service-arm.exe" - and, against all odds, succeeds. Now gnunet-service-arm can control it. If the connection attempt fails, statistics service just continues on, and will have to be killed in a disruptive way later.
You might ask "what about gnunet-monkey?" - well, gnunet-monkey (and any other process that spawns children) will have a named pipe, since it does have to have control over children just as the ARM does.

Now that i'm thinking of it, there might be a way to work around intermediate processes not having a named pipe for children to connect to. When the parent process launches the child, it can wait a set amount of time and then try to create the named pipe that the child should have created (exe name is known, as well as the pid, so figuring out the name is not a problem). If the attempt succeeds, it means that the child didn't create it by itself, and the parent will use it to control its grandchildren. The downside is that child processes which DO create named pipes must be quick enough about it, otherwise their parents will beat them to it and the childs will have to die (well, unless they know in advance that they don't need to control their own children, in which case they might just let their parents get the pipes).

LRN

2010-11-06 10:12

developer   ~0004151

Service implementation details:

At some point (usually during software installation or when user runs one of GNUnet programs with special argument(s)) call OpenSCManager() with SC_MANAGER_CREATE_SERVICE access right to get Service Control Manager handle (requires administrative privileges), then use its handle to call CreateService(), specifying:
  service name (up to 256 chars),
  display name (up to 256 chars),
  service type (SERVICE_WIN32_OWN_PROCESS in our case),
  autostart type (auto-start on system startup - for ARM, on-demand - for everything else),
  startup failure severity (SERVICE_ERROR_NORMAL, we're not critical to the system),
  path to the binary (with command line arguments, if any; MSDN says this argument is entirely optional, see below),
  account under which the service will run - either existing user account or one of 3 special accounts - LocalService (user-level privileges, authenticates as Anonymous over network), NetworkService (user-level privileges, authenticates using this PC's account over network) or LocalSystem (admin-level privileges, authenticates using this PC's account over network),
  password for the account (NULL if a special account is used),
  and some other (relatively unimportant) stuff.
This adds the service to the service database. Its handle (returned by CreateService) can be closed afterwards.

Then at some point service binary is run. That happens either because:
 a) someone called OpenSCManager() (without admin privileges this time), then called OpenService() with SERVICE_START access right (default service security descriptor grants SERVICE_START only to LocalSystem account and to administrators, we'd need to create a custom SD and set it with SetServiceObjectSecurity (), so that simple users are allowed to at least start GNUnet ARM, which will work under LocalSystem account itself and will have no problems starting other services), and then called StartService(), specifying an array of command line arguments (0th argument is the service binary; if argument array is NULL, the arguments/binary specified at CreateService will be used), or
 b) someone have used SCM control utility (usually the services.msc snap-in) to start the service (not sure which privileges are required), in which case the arguments/binary specified at CreateService are used.

Service doesn't get any environment variables from Service Control Manager (it does get normal set of system-wide env vars).

Service starts in its main() function. At this point it's a normal process and depending on argv contents it might decide to not to become a service process. If it does decide, it calls StartServiceCtrlDispatcher() passing service dispatch table (that contains a list of service names and pointers to their SvcMain functions; remember, a single process can host multiple services) - and that's it. Service control dispatcher takes over the thread, connects to SCM, creates a new thread and calls SvcMain of a particular service within that new thread. SvcMain gets argv (not sure if it's the same argv that main() gets; probably the same if this is a single-service-per-process case; in case of multiple-services-per-process, when a process is already running a service dispatcher, SCM probably calls SvcMain directly, avoiding main())

MSDN claims that the application's main thread (the one that starts at main()) is the one that should call StartServiceCtrlDispatcher().

SvcMain of the service calls RegisterServiceCtrlHandlerEx() to specify a callback that will be used by SCM to control the service, then the service calls SetServiceStatus() with SERVICE_RUNNING to tell SCM that it runs (service must not use system API until after it reported itself as running - system API might invoke services, and if they are not running, they should be started, and SCM is restricted to starting one service at a time). Once running, the service can initialize and do useful work.

SCM will call the handler registered by RegisterServiceCtrlHandlerEx() (the handler will be executed in the service dispatcher thread's context!) to signal that the service should start/stop/report its status/whatever). It's up to the handler implementation to communicate with the thread running SvcMain and tell it to wrap up.

SvcMain MUST return (to let SCM clean up after it) when it is closing down (abort(), ExitProcess() and GNUNET_assert() are not recommended).

Once SCM finished cleaning up (once all services running within this process have returned from SvcMain), the StartServiceCtrlDispatcher() call will return back to main(), and main() is free to do anything at that point (AFAIK), mostly it just returns.

Now i need to figure out how that applies to GNUnet. Namely, GNUnet programs tend to have minimalistic main() function, which will set up logging (at most) and call GNUNET_program_run() or GNUNET_service_run() depending on the program type. This doesn't mean anything - gnunet-daemon-* processes will use GNUNET_program_run(), not GNUNET_service_run() as might be expected from daemons.

Anyway, either of these functions will do quite a bit of initialization, set up a scheduler and add at least one function to its queue, then run that scheduler.

So, if a GNUnet process is to be servicized, it has to follow the procedure described above, and run GNUNET_program/service_run() only when SvcMain() have registered a control handler and reported the service as running.

A service is able specify whether or not it accepts control signals at the moment, preventing SCM from sending those (useful when a work, such as initialization, has to be done without interruptions).

NDurner

2010-11-06 12:05

developer   ~0004152

Services:
---------

GNUnet 0.8 used one service for gnunetd. However:
- services are registered and managed in one place (in one big Services UI list). That'd look very unesthetic.

- services are identified by name AFAIK

- services always have a fixed path. I'd like the GNUnet child processes be relocatable for debugging purposes (by not depending on the SCM infrastructure)

To make a long story short: services are convenience for end-users from my point of view and nothing an application should use internally.


Ctrl Handler
------------

Doesn't work if you don't have a console window open (most of the time for GNUnet users).

NDurner

2010-11-06 12:18

developer   ~0004153

Yet another possibility: dbus
Don't know about the quality of their Windows port.

LRN

2010-11-06 12:27

developer   ~0004154

LRN: ndurner, you should read a bit more carefully what i wrote in the bug discussion
    ndurner: too much :-)
    LRN: ctrl handler didn't work (i've tested it) because it doesn't share a console with the child process
    ndurner: yeah, I know that
    LRN: About services:
    LRN: services are registered and managed by special API. The fact that users can use services.msc to do some basic service management (if they have administrative privileges) should not concern us
    ndurner: I know that too
    LRN: Also, complex applications (MS Exchange comes to ming) would register 5-7 different services for their operations, so it's not like we're writing a new chapter in polluting the service list with junk
    LRN: s/ming/mind/
    LRN: services are indeed identified by name. Why should that be a problem? It's not like there are going to be two gnunet-service-arm running simultaneously (unless you think of test cases, but even test cases shouldn't do that)
    LRN: Services have fixed path, but StartService() is (should be?) capable of specifying different path
    LRN: The real bitch about services is about all the code that i'll have to write, not to mention extra threads. Pipes should be easier, IMHO.

-------------

dbus: the only thing i remember about dbus is that i've failed to build it when i've tried 0000003:0000002 years ago.
It does appear to be working (i think Mumble uses it).

Christian Grothoff

2010-11-06 12:52

manager   ~0004155

So my reading of this is:

1) service would be the right thing to do for ARM itself (as part of an installer, if run as admin)

2) services would in general be a bit involved to implement, and for debugging and ease-of-use named pipes seem easier

My issue with named-pipes with parent-traversal (as described above) is that the parent will have several children to control, so using a single pipe named after the parent's PID won't work. However, how about this:

a) create a uniquely named control pipe (either by using a mkstemp equivalent, or by using some larger random string in the name that is collision-resistant)

b) store the NAME of that pipe in an environment variable (!) to pass it on to the child process (this should achieve the desired transitivity, and wrappers like monkey can choose to mess with it or not).

amatus

2010-11-06 19:46

reporter   ~0004156

I think it would be possible to use an anonymous pipe and pass its HANDLE value in an environment variable. We would need to test to see if that HANDLE will make it all the way to a grandchild when the child (the wrapper script) calls _spawn.

FYI: the reason they switched from exec to spawn is because the return code of the execd program doesn't make it back to the parent of the execing program for some reason.

LRN

2010-11-07 00:58

reporter   ~0004157

I've uploaded two source files - one for a master and one for a slave - of a testcase.

Here's the output i've got (MinGW-GCC 4.5.0, testcase is compiled as 32-bit, NT 6.2 x64):

>handlepasstest_master.exe child
MASTER: i am 5756
MASTER: Created events 0000002C and 00000030
MASTER: calling putenv(SECRETHANDLEVALUE0=2C)
MASTER: calling putenv(SECRETHANDLEVALUE1=30)
MASTER: spawned a child (handle=56), GLE is 1812
SLAVE: i am 7412
SLAVE: Got events 2C and 30
SLAVE: SetEvent for 0000002C returned 1, GLE is 0
MASTER: Wait for 0000002C returned 0, GLE is 0
MASTER: SetEvent for 00000030 returned 1, GLE is 0
SLAVE: Wait for 00000030 returned 0, GLE is 0

>handlepasstest_master.exe grandchild
MASTER: i am 9284
MASTER: Created events 0000002C and 00000030
MASTER: calling putenv(SECRETHANDLEVALUE0=2C)
MASTER: calling putenv(SECRETHANDLEVALUE1=30)
MASTER: spawned a child (handle=56), GLE is 1812
INTERMEDIATE SLAVE: i am 4216
INTERMEDIATE SLAVE: spawned a child (handle=56), GLE is 1812
SLAVE: i am 9096
SLAVE: Got events 2C and 30
SLAVE: SetEvent for 0000002C returned 1, GLE is 0
MASTER: Wait for 0000002C returned 0, GLE is 0
MASTER: SetEvent for 00000030 returned 1, GLE is 0
SLAVE: Wait for 00000030 returned 0, GLE is 0

LRN

2010-11-07 01:11

reporter   ~0004158

The output for the same binaries, running under NT 5.1.2600:

>handlepasstest_master.exe child
MASTER: i am 1924
MASTER: Created events 000007E8 and 000007F4
MASTER: calling putenv(SECRETHANDLEVALUE0=7E8)
MASTER: calling putenv(SECRETHANDLEVALUE1=7F4)
MASTER: spawned a child (handle=1992), GLE is 0
SLAVE: i am 1768
SLAVE: Got events 7E8 and 7F4
MASTER: Wait for 000007E8 returned 0, GLE is 0
MASTER: SetEvent for 000007F4 returned 1, GLE is 0
SLAVE: SetEvent for 000007E8 returned 1, GLE is 0
SLAVE: Wait for 000007F4 returned 0, GLE is 0

>handlepasstest_master.exe grandchild
MASTER: i am 1552
MASTER: Created events 000007E8 and 000007F4
MASTER: calling putenv(SECRETHANDLEVALUE0=7E8)
MASTER: calling putenv(SECRETHANDLEVALUE1=7F4)
MASTER: spawned a child (handle=1992), GLE is 0
INTERMEDIATE SLAVE: i am 1360
INTERMEDIATE SLAVE: spawned a child (handle=1992), GLE is 0
SLAVE: i am 1604
SLAVE: Got events 7E8 and 7F4
SLAVE: SetEvent for 000007E8 returned 1, GLE is 0
MASTER: Wait for 000007E8 returned 0, GLE is 0
MASTER: SetEvent for 000007F4 returned 1, GLE is 0
SLAVE: Wait for 000007F4 returned 0, GLE is 0

It also worked under the same NT 6.2 x64 as above, but using a non-privileged standard user account.

LRN

2010-11-09 10:10

reporter   ~0004159

Uploaded pipes_sockets_and_stuff.diff , which contains all changes i've made:
* parent->child control via anonymous pipe passed through env variable
* small fixes here and there
* fix for service manager to use right ip-address when connecting to service instead of 0.0.0.0 or ::

diffs for disk.h, test_fragmentation_enhanced.c and test_frag_ji.c are broken due to line-endings, but only disk.h really contains new code

Christian Grothoff

2010-11-09 14:57

manager   ~0004160

You're passing pointers (to handles) as environment variables
and using 32-bit values for what might be a 64-bit HANDLE.

My suggestion with using ENV was to use *named* pipes and pass the *name* of the named pipe, not the handle (so you'd pass a 'char *' in the environment)
I'm not sure how this can even work (W32 HANDLEs are numbers that can be exchanged like that between processes => that'd sound like a crazy security issue). But even if it works, I don't think passing pointers via env is something I should condone ;-). Also, even if some code always fails on W95, it would make sense to check for errors (i.e. to report problems on W95).

Also, there were a ton of merge errors when I tried to apply the patch. Given that especially the W32-code is not even compiled on my system, I could not apply this patch as-is if I wanted to (without most likely breaking a ton of stuff).

I have committed those changes that were unrelated (hostlist mkdir, for example) and that did not give me grief when patching.

So please:

0) try to keep your diff closer against HEAD
1) don't pass pointers through the environment; use named pipes; the disk.h ugliness should also be avoided this way
2) Maybe break the whole patch down into some smaller ones that are more easily checkable?

LRN

2010-11-09 17:39

reporter   ~0004161

I'm passing handles, not pointers to them
(as for using 32-bit values - you're welcome to fix that; when i've tried to use strtoll, it gave a size mismatch warning)

handles can be *inherited*, just like FDs can. The only problem is to pass the *value* of the inherited handle to the child, so that it can use it. For standard streams this is done automatically. For everything else - commandline arguments, env variables, etc

0) Normally i do, but today i wanted to wrap up as fast as i can
1) See above
2) Might be difficult with svn (i will have to edit the output of svn diff by hand - more than i usually do)

LRN

2010-11-09 18:00

reporter   ~0004162

Uploaded pipes_sockets_and_stuff_2_pipes.diff and pipes_sockets_and_stuff_2_sockets.diff
It's the same as before (no changes), just against current SVN HEAD, and is split in to (really, socket changes are restricted to one file; everything else is about parent->child control).

NDurner

2010-11-09 22:06

reporter   ~0004163

Also, please use the lpEnvironment argument of CreateProcess() instead of putenv().

For patch management, Bzr branches (maybe on launchpad.net) would work for me.

Christian Grothoff

2010-11-10 10:03

manager   ~0004165

pipes_sockets_and_stuff_2_sockets.diff has been merged with SVN HEAD -- plus some style fixes.

Christian Grothoff

2010-11-10 12:48

manager   ~0004166

13635 now makes the code also work for PF_UNIX, does some more cleanup and PREVENTS trying both IPv4 and IPv6-connections since this can never really be useful: if we got an incoming v4 to forward, forwarding to v4 should work, and ditto for v6. So we don't ever really need to try multiple families.

LRN

2010-11-10 15:49

reporter   ~0004169

Uploaded 0001-W32-Parent-child-control-pipe.patch and 0002-Fix-environment-table-generation-for-child-processes.patch (should be applied one on top of the other)
This fixes the way environment variables are passed to child processes, as NDurner requested.
Otherwise it's basically the same as before.

NDurner

2010-11-10 20:02

reporter   ~0004170

Some notes:

[this was written before looking at the 2nd patch, please excuse if parts are not applicable anymore]

- internal helper functions like GetEnvTableSizeA() should be static

- GetEnvTableSizeA() can just look for the "\0\0" pattern

- don't split the env. setup in 3 steps (CreateEnvTableA, GNUNET_asprintf, AddToEnvTableA) that all allocate temporary buffers, but do that work in one big step: query current environment, get the size of the current environment, add the required space for the new variable, allocate that much memory, copy current environment over and finally add the new variable.

- I now agree that named pipes are better (because the abstraction from native handles helps with interoperability to some degree. Furthermore, I really dislike GNUNET_DISK_file_from_internal_handle(s)).

- We should not only wait 4 seconds for the child to actually terminate, but a signal from the child that it is going to terminate would also suffice at that point. Force-killing sometime later should still be included, but ideally via a continuation. Also, possibly stalling the current thread for 4 seconds should be avoided.

[/]

- I believe the ChildWaitThread can be done with a continuation now

LRN

2010-12-05 21:30

reporter   ~0004199

Uploaded 0001-Parent-child-control-pipes-ndurner-s-IO-based.patch

This is a parent-child control pipe implementation on top of ndurner-style I/O (i.e. it does not need W32IO from 0001620), with some fixes.

First, since there is a delay in killing process, which is handled by scheduling a timeout, i had to add extra argument that controls the timeout scheduling - because scheduling something while NOT running under a scheduler makes GNUnet crash. This is where the majority of the micro-two-lines-per-file changes came from.

Now, the real changes:

gnunet_disk_lib.h:
Added prototypes for new function, fixed documentation

gnunet_os_lib.h:
Fixed prototype and documentation for _kill
Added a prototype for new parent control handle fuction

disk.c:
Changed GNUNET_DISK_npipe_open() to generate unique pipe name (FIXME: POSIX implementation required!). This is done to make sure that all platform-dependent code related to name generation is kept inside disk.c and doesn't spill out to the caller of GNUNET_DISK_npipe_open().
Fixed GNUNET_DISK_npipe_open() to restrict the length of the pipe to 256 characters.
Fixed GNUNET_DISK_npipe_open() to fail on INVALID_HANDLE_VALUE instead of NULL return value
Fixed GNUNET_DISK_npipe_open() to set the type to GNUNET_PIPE
Added GNUNET_DISK_npipe_open_existing(), which opens the client end of the pipe (on POSIX it's just open(), on W32 it's CreateFile())

network.c:
Fixed GNUNET_NETWORK_socket_select() to handle broken pipes correctly

os_priority.c:
Use SearchPath with custom-made PATH instead of FindExecutable, to search in executable load dir, bindir, libdir and the PATH
Added control-pipe-related code. The code is built for both platforms and is used on both platforms (in favor of kill() on POSIX; although it will fall back to kill()/TerminateProcess() in case of failure).
Copied CreateCustomEnvTable() from previous patch (used in conjuction with CreateProcess())
Added control-pipe creation to both _start_process() functions (POSIX and W32; POSIX one requires testing).
Added .exe extension fix to _start_process()

scheduler.c:
Added a continuation that registers the parent-child handler

LRN

2010-12-06 17:56

reporter   ~0004203

Uploaded 0001-Fix-unique-named-pipe-generation.patch

Apply it on top of 0001-Parent-child-control-pipes-ndurner-s-IO-based.patch to fix unique pipe generation.

NDurner

2010-12-15 21:13

reporter   ~0004206

Last edited: 2010-12-15 21:20

Applied the last two patches to https://gnunet.org/svn/branches/gnunet/mantis_0001616 , will make changes before merging to trunk there

NDurner

2010-12-27 13:52

reporter   ~0004220

merged branch to trunk, please check

NDurner

2010-12-27 21:04

reporter   ~0004221

From IRC:
(21:00:37) LRN: 1616 requires feedback (i just gave it to you - it works).

LRN

2011-07-13 03:03

reporter   ~0004499

Reopening this to add a couple of patches.

LRN

2011-07-13 03:08

reporter   ~0004500

Added 0001-Temporary-fix-for-process_kill.patch and 0001-More-permanent-fix-for-os_process_kill.patch

First patch is what i had in my private patch queue all these...months?...since this issue was closed at the end of 2010. It's a bit shaggy and not cross-platform.

Second patch is a fix on top of that. Brings back ndurner's code (with some creative rewriting to get rid of goto) for non-Windows (when workarounds are enabled), and continues to use WinAPI on Windows.

Patches should be applied one on top of the other (just to clarify; i know that not all people are used to gittish patches, and these two aren't even typical).

It might be (and was) debatable whether it is a good idea at all to wait for a process death within *_kill(), but so far it works well enough for me.

Christian Grothoff

2011-07-14 19:14

manager   ~0004505

Applied the last two patches as SVN 15964/15965. This bug is getting too messy. If possible, I'd appreciate it if instead of re-opening this one, we create a new description of what is (still) wrong -- if any -- and possibly link to this bug if needed next time ;-).

Issue History

Date Modified Username Field Change
2010-11-05 16:34 LRN New Issue
2010-11-05 16:35 LRN Note Added: 0004142
2010-11-05 18:11 Christian Grothoff Note Added: 0004143
2010-11-05 18:50 LRN Note Added: 0004144
2010-11-05 21:18 NDurner Note Added: 0004145
2010-11-05 22:02 LRN Note Added: 0004146
2010-11-05 22:32 Christian Grothoff Note Added: 0004147
2010-11-05 23:12 LRN Note Added: 0004148
2010-11-06 04:47 LRN Note Added: 0004149
2010-11-06 06:31 LRN Note Added: 0004150
2010-11-06 10:12 LRN Note Added: 0004151
2010-11-06 12:05 NDurner Note Added: 0004152
2010-11-06 12:18 NDurner Note Added: 0004153
2010-11-06 12:27 LRN Note Added: 0004154
2010-11-06 12:52 Christian Grothoff Note Added: 0004155
2010-11-06 19:46 amatus Note Added: 0004156
2010-11-07 00:50 LRN File Added: handlepasstest_master.c
2010-11-07 00:50 LRN File Added: handlepasstest_slave.c
2010-11-07 00:52 LRN File Deleted: handlepasstest_master.c
2010-11-07 00:52 LRN File Deleted: handlepasstest_slave.c
2010-11-07 00:56 LRN File Added: handlepasstest_master.c
2010-11-07 00:56 LRN File Added: handlepasstest_slave.c
2010-11-07 00:58 LRN Note Added: 0004157
2010-11-07 01:11 LRN Note Added: 0004158
2010-11-09 10:06 LRN File Added: pipes_sockets_and_stuff.diff
2010-11-09 10:10 LRN Note Added: 0004159
2010-11-09 14:57 Christian Grothoff Note Added: 0004160
2010-11-09 17:39 LRN Note Added: 0004161
2010-11-09 17:58 LRN File Added: pipes_sockets_and_stuff_2_pipes.diff
2010-11-09 17:59 LRN File Added: pipes_sockets_and_stuff_2_sockets.diff
2010-11-09 18:00 LRN Note Added: 0004162
2010-11-09 22:06 NDurner Note Added: 0004163
2010-11-10 10:03 Christian Grothoff Note Added: 0004165
2010-11-10 12:48 Christian Grothoff Note Added: 0004166
2010-11-10 15:47 LRN File Added: 0001-W32-Parent-child-control-pipe.patch
2010-11-10 15:47 LRN File Added: 0002-Fix-environment-table-generation-for-child-processes.patch
2010-11-10 15:49 LRN Note Added: 0004169
2010-11-10 20:02 NDurner Note Added: 0004170
2010-11-30 12:25 Christian Grothoff Status new => assigned
2010-11-30 12:25 Christian Grothoff Assigned To => NDurner
2010-12-05 21:30 LRN File Added: 0001-Parent-child-control-pipes-ndurner-s-IO-based.patch
2010-12-05 21:30 LRN Note Added: 0004199
2010-12-06 17:55 LRN File Added: 0001-Fix-unique-named-pipe-generation.patch
2010-12-06 17:56 LRN Note Added: 0004203
2010-12-15 21:13 NDurner Note Added: 0004206
2010-12-15 21:20 NDurner Note Edited: 0004206
2010-12-27 00:40 NDurner Relationship added related to 0001626
2010-12-27 13:52 NDurner Assigned To NDurner => LRN
2010-12-27 13:52 NDurner Note Added: 0004220
2010-12-27 13:52 NDurner Status assigned => feedback
2010-12-27 21:04 NDurner Note Added: 0004221
2010-12-27 21:04 NDurner Status feedback => resolved
2010-12-27 21:04 NDurner Fixed in Version => Git master
2010-12-27 21:04 NDurner Resolution open => fixed
2011-04-27 16:18 Christian Grothoff Status resolved => closed
2011-07-13 03:03 LRN Note Added: 0004499
2011-07-13 03:03 LRN Status closed => feedback
2011-07-13 03:03 LRN Resolution fixed => reopened
2011-07-13 03:03 LRN File Added: 0001-Temporary-fix-for-process_kill.patch
2011-07-13 03:04 LRN File Added: 0001-More-permanent-fix-for-os_process_kill.patch
2011-07-13 03:08 LRN Note Added: 0004500
2011-07-14 19:14 Christian Grothoff Note Added: 0004505
2011-07-14 19:14 Christian Grothoff Status feedback => resolved
2011-07-14 19:14 Christian Grothoff Resolution reopened => fixed
2011-07-18 13:34 Christian Grothoff Status resolved => closed
2011-09-19 10:45 Christian Grothoff Fixed in Version Git master => 0.9.0pre3
2011-09-19 10:45 Christian Grothoff Target Version Git master => 0.9.0pre3