gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r18473 - in gnunet/src: arm include util


From: gnunet
Subject: [GNUnet-SVN] r18473 - in gnunet/src: arm include util
Date: Tue, 6 Dec 2011 18:58:40 +0100

Author: grothoff
Date: 2011-12-06 18:58:40 +0100 (Tue, 06 Dec 2011)
New Revision: 18473

Modified:
   gnunet/src/arm/do_start_process.c
   gnunet/src/arm/gnunet-service-arm.c
   gnunet/src/arm/gnunet-service-arm.h
   gnunet/src/arm/gnunet-service-arm_interceptor.c
   gnunet/src/include/gnunet_network_lib.h
   gnunet/src/include/gnunet_os_lib.h
   gnunet/src/include/platform.h
   gnunet/src/util/network.c
   gnunet/src/util/os_priority.c
   gnunet/src/util/service.c
Log:
Implement passing sockets in IPC on W32 (#1975)

Modified: gnunet/src/arm/do_start_process.c
===================================================================
--- gnunet/src/arm/do_start_process.c   2011-12-06 17:29:30 UTC (rev 18472)
+++ gnunet/src/arm/do_start_process.c   2011-12-06 17:58:40 UTC (rev 18473)
@@ -13,7 +13,7 @@
  * @return PID of the started process, -1 on error
  */
 static struct GNUNET_OS_Process *
-do_start_process (const int *lsocks, const char *first_arg, ...)
+do_start_process (const SOCKTYPE *lsocks, const char *first_arg, ...)
 {
   va_list ap;
   char **argv;

Modified: gnunet/src/arm/gnunet-service-arm.c
===================================================================
--- gnunet/src/arm/gnunet-service-arm.c 2011-12-06 17:29:30 UTC (rev 18472)
+++ gnunet/src/arm/gnunet-service-arm.c 2011-12-06 17:58:40 UTC (rev 18473)
@@ -331,7 +331,7 @@
  * @param lsocks -1 terminated list of listen sockets to pass (systemd style), 
or NULL
  */
 static void
-start_process (struct ServiceList *sl, const int *lsocks)
+start_process (struct ServiceList *sl, const SOCKTYPE *lsocks)
 {
   char *loprefix;
   char *options;
@@ -422,7 +422,7 @@
  */
 int
 start_service (struct GNUNET_SERVER_Client *client, const char *servicename,
-               const int *lsocks)
+               const SOCKTYPE *lsocks)
 {
   struct ServiceList *sl;
   char *binary;

Modified: gnunet/src/arm/gnunet-service-arm.h
===================================================================
--- gnunet/src/arm/gnunet-service-arm.h 2011-12-06 17:29:30 UTC (rev 18472)
+++ gnunet/src/arm/gnunet-service-arm.h 2011-12-06 17:58:40 UTC (rev 18473)
@@ -37,7 +37,7 @@
  */
 int
 start_service (struct GNUNET_SERVER_Client *client, const char *servicename,
-               const int *lsocks);
+               const SOCKTYPE *lsocks);
 
 /**
  * Stop listening for connections to a service.

Modified: gnunet/src/arm/gnunet-service-arm_interceptor.c
===================================================================
--- gnunet/src/arm/gnunet-service-arm_interceptor.c     2011-12-06 17:29:30 UTC 
(rev 18472)
+++ gnunet/src/arm/gnunet-service-arm_interceptor.c     2011-12-06 17:58:40 UTC 
(rev 18473)
@@ -980,9 +980,9 @@
   struct ServiceListeningInfo *sli = cls;
   struct ServiceListeningInfo *pos;
   struct ServiceListeningInfo *next;
-  int *lsocks;
+  SOCKTYPE *lsocks;
   unsigned int ls;
-  int use_lsocks;
+  int disable_lsocks;
 
   sli->acceptTask = GNUNET_SCHEDULER_NO_TASK;
   if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
@@ -1025,11 +1025,19 @@
                        GNUNET_NETWORK_get_fd (sli->listeningSocket));
   GNUNET_free (sli->listeningSocket);   /* deliberately no closing! */
   GNUNET_free (sli->service_addr);
+#if WINDOWS
+  GNUNET_array_append (lsocks, ls, INVALID_SOCKET);
+#else
   GNUNET_array_append (lsocks, ls, -1);
+#endif
   start_service (NULL, sli->serviceName, lsocks);
   ls = 0;
   while (lsocks[ls] != -1)
+#if WINDOWS
+    GNUNET_break (0 == closesocket (lsocks[ls++]));
+#else
     GNUNET_break (0 == close (lsocks[ls++]));
+#endif
   GNUNET_array_grow (lsocks, ls, 0);
   GNUNET_free (sli->serviceName);
   GNUNET_free (sli);

Modified: gnunet/src/include/gnunet_network_lib.h
===================================================================
--- gnunet/src/include/gnunet_network_lib.h     2011-12-06 17:29:30 UTC (rev 
18472)
+++ gnunet/src/include/gnunet_network_lib.h     2011-12-06 17:58:40 UTC (rev 
18473)
@@ -96,7 +96,7 @@
  * @return NULL on error (including not supported on target platform)
  */
 struct GNUNET_NETWORK_Handle *
-GNUNET_NETWORK_socket_box_native (int fd);
+GNUNET_NETWORK_socket_box_native (SOCKTYPE fd);
 
 
 /**
@@ -320,8 +320,7 @@
                           const struct GNUNET_NETWORK_Handle *desc);
 
 
-#ifdef __MINGW32__
-/* TODO: maybe #ifdef WINDOWS? -ndurner */
+#if WINDOWS
 /**
  * Add a W32 file handle to the fd set
  * @param fds fd set

Modified: gnunet/src/include/gnunet_os_lib.h
===================================================================
--- gnunet/src/include/gnunet_os_lib.h  2011-12-06 17:29:30 UTC (rev 18472)
+++ gnunet/src/include/gnunet_os_lib.h  2011-12-06 17:58:40 UTC (rev 18473)
@@ -275,7 +275,7 @@
  * @return pointer to process structure of the new process, NULL on error
  */
 struct GNUNET_OS_Process *
-GNUNET_OS_start_process_v (const int *lsocks, const char *filename,
+GNUNET_OS_start_process_v (const SOCKTYPE *lsocks, const char *filename,
                            char *const argv[]);
 
 

Modified: gnunet/src/include/platform.h
===================================================================
--- gnunet/src/include/platform.h       2011-12-06 17:29:30 UTC (rev 18472)
+++ gnunet/src/include/platform.h       2011-12-06 17:58:40 UTC (rev 18473)
@@ -246,4 +246,12 @@
 #define MAKE_UNALIGNED(val) val
 #endif
 
+#if WINDOWS
+#define FDTYPE HANDLE
+#define SOCKTYPE SOCKET
+#else
+#define FDTYPE int
+#define SOCKTYPE int
 #endif
+
+#endif

Modified: gnunet/src/util/network.c
===================================================================
--- gnunet/src/util/network.c   2011-12-06 17:29:30 UTC (rev 18472)
+++ gnunet/src/util/network.c   2011-12-06 17:58:40 UTC (rev 18473)
@@ -377,13 +377,20 @@
  * @return NULL on error (including not supported on target platform)
  */
 struct GNUNET_NETWORK_Handle *
-GNUNET_NETWORK_socket_box_native (int fd)
+GNUNET_NETWORK_socket_box_native (SOCKTYPE fd)
 {
+  struct GNUNET_NETWORK_Handle *ret;
 #if MINGW
-  return NULL;
+  unsigned long i;
+  DWORD d;
+  /* FIXME: Find a better call to check that FD is valid */
+  if (WSAIoctl (fd, FIONBIO, (void *) &i, sizeof (i), NULL, 0, &d, NULL, NULL) 
!= 0)
+    return NULL;                /* invalid FD */
+  ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));
+  ret->fd = fd;
+  ret->af = AF_UNSPEC;
+  return ret;
 #else
-  struct GNUNET_NETWORK_Handle *ret;
-
   if (fcntl (fd, F_GETFD) < 0)
     return NULL;                /* invalid FD */
   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));

Modified: gnunet/src/util/os_priority.c
===================================================================
--- gnunet/src/util/os_priority.c       2011-12-06 17:29:30 UTC (rev 18472)
+++ gnunet/src/util/os_priority.c       2011-12-06 17:58:40 UTC (rev 18473)
@@ -852,7 +852,8 @@
  * @return process ID of the new process, -1 on error
  */
 struct GNUNET_OS_Process *
-GNUNET_OS_start_process_v (const int *lsocks, const char *filename,
+GNUNET_OS_start_process_v (const SOCKTYPE *lsocks,
+                           const char *filename,
                            char *const argv[])
 {
 #if ENABLE_WINDOWS_WORKAROUNDS
@@ -979,7 +980,7 @@
 
   char path[MAX_PATH + 1];
 
-  char *our_env[3] = { NULL, NULL, NULL };
+  char *our_env[5] = { NULL, NULL, NULL, NULL, NULL };
   char *env_block = NULL;
   char *pathbuf;
   DWORD pathbuf_len, alloc_len;
@@ -988,8 +989,12 @@
   char *libdir;
   char *ptr;
   char *non_const_filename;
+  struct GNUNET_DISK_PipeHandle *lsocks_pipe;
+  const struct GNUNET_DISK_FileHandle *lsocks_write_fd;
+  HANDLE lsocks_read;
+  HANDLE lsocks_write;
 
-  GNUNET_assert (lsocks == NULL);
+  int fail;
 
   /* Search in prefix dir (hopefully - the directory from which
    * the current module was loaded), bindir and libdir, then in PATH
@@ -1103,7 +1108,26 @@
     GNUNET_free (path);
     return NULL;
   }
+  if (lsocks != NULL)
+  {
+    lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO);
 
+    if (lsocks_pipe == NULL)
+    {
+      GNUNET_free (cmd);
+      GNUNET_free (path);
+      GNUNET_DISK_pipe_close (lsocks_pipe);
+      return NULL;
+    }
+    lsocks_write_fd = GNUNET_DISK_pipe_handle (lsocks_pipe,
+        GNUNET_DISK_PIPE_END_WRITE);
+    GNUNET_DISK_internal_file_handle_ (lsocks_write_fd,
+                                       &lsocks_write, sizeof (HANDLE));
+    GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
+                                       (lsocks_pipe, 
GNUNET_DISK_PIPE_END_READ),
+                                       &lsocks_read, sizeof (HANDLE));
+  }
+
 #if DEBUG_OS
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n",
        childpipename);
@@ -1111,17 +1135,31 @@
 
   GNUNET_asprintf (&our_env[0], "%s=", GNUNET_OS_CONTROL_PIPE);
   GNUNET_asprintf (&our_env[1], "%s", childpipename);
-  our_env[2] = NULL;
+  GNUNET_free (childpipename);
+  if (lsocks == NULL)
+    our_env[2] = NULL;
+  else
+  {
+    /*This will tell the child that we're going to send lsocks over the pipe*/
+    GNUNET_asprintf (&our_env[2], "%s=", "GNUNET_OS_READ_LSOCKS");
+    GNUNET_asprintf (&our_env[3], "%lu", lsocks_read);
+    our_env[4] = NULL;
+  }
   env_block = CreateCustomEnvTable (our_env);
-  GNUNET_free (our_env[0]);
-  GNUNET_free (our_env[1]);
+  GNUNET_free_non_null (our_env[0]);
+  GNUNET_free_non_null (our_env[1]);
+  GNUNET_free_non_null (our_env[2]);
+  GNUNET_free_non_null (our_env[3]);
 
-  if (!CreateProcess
-      (path, cmd, NULL, NULL, FALSE, DETACHED_PROCESS | CREATE_SUSPENDED,
+  if (!CreateProcessA
+      (path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED,
        env_block, NULL, &start, &proc))
   {
     SetErrnoFromWinError (GetLastError ());
     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
+    GNUNET_DISK_npipe_close (control_pipe);
+    if (lsocks != NULL)
+      GNUNET_DISK_pipe_close (lsocks_pipe);
     GNUNET_free (env_block);
     GNUNET_free (cmd);
     return NULL;
@@ -1140,6 +1178,85 @@
   CloseHandle (proc.hThread);
   GNUNET_free (cmd);
 
+  if (lsocks == NULL)
+    return gnunet_proc;
+
+  GNUNET_DISK_pipe_close_end (lsocks_pipe, GNUNET_DISK_PIPE_END_READ);
+
+  /* This is a replacement for "goto error" that doesn't use goto */
+  fail = 1;
+  do
+  {
+    int wrote;
+    uint64_t size, count, i;
+
+    /* Tell the number of sockets */
+    for (count = 0; lsocks && lsocks[count] != INVALID_SOCKET; count++);
+
+    wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
+    if (wrote != sizeof (count))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u count bytes to 
the child: %u\n", sizeof (count), GetLastError ());
+      break;
+    }
+    for (i = 0; lsocks && lsocks[i] != INVALID_SOCKET; i++)
+    {
+      WSAPROTOCOL_INFOA pi;
+      /* Get a socket duplication info */
+      if (SOCKET_ERROR == WSADuplicateSocketA (lsocks[i], gnunet_proc->pid, 
&pi))
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to duplicate an 
socket[%llu]: %u\n", i, GetLastError ());
+        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
+        break;
+      }
+      /* Synchronous I/O is not nice, but we can't schedule this:
+       * lsocks will be closed/freed by the caller soon, and until
+       * the child creates a duplicate, closing a socket here will
+       * close it for good.
+       */
+      /* Send the size of the structure
+       * (the child might be built with different headers...)
+       */
+      size = sizeof (pi);
+      wrote = GNUNET_DISK_file_write (lsocks_write_fd, &size, sizeof (size));
+      if (wrote != sizeof (size))
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u size[%llu] 
bytes to the child: %u\n", sizeof (size), i, GetLastError ());
+        break;
+      }
+      /* Finally! Send the data */
+      wrote = GNUNET_DISK_file_write (lsocks_write_fd, &pi, sizeof (pi));
+      if (wrote != sizeof (pi))
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u socket[%llu] 
bytes to the child: %u\n", sizeof (pi), i, GetLastError ());
+        break;
+      }
+    }
+    /* This will block us until the child makes a final read or closes
+     * the pipe (hence no 'wrote' check), since we have to wait for it
+     * to duplicate the last socket, before we return and start closing
+     * our own copies)
+     */
+    wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
+    fail = 0;
+  }
+  while (fail);
+
+  GNUNET_DISK_file_sync (lsocks_write_fd);
+  GNUNET_DISK_pipe_close (lsocks_pipe);
+
+  if (fail)
+  {
+    /* If we can't pass on the socket(s), the child will block forever,
+     * better put it out of its misery.
+     */
+    TerminateProcess (gnunet_proc->handle, 0);
+    CloseHandle (gnunet_proc->handle);
+    GNUNET_DISK_npipe_close (gnunet_proc->control_pipe);
+    GNUNET_free (gnunet_proc);
+    return NULL;
+  }
+
   return gnunet_proc;
 #endif
 }

Modified: gnunet/src/util/service.c
===================================================================
--- gnunet/src/util/service.c   2011-12-06 17:29:30 UTC (rev 18472)
+++ gnunet/src/util/service.c   2011-12-06 17:58:40 UTC (rev 18473)
@@ -1079,7 +1079,90 @@
 }
 
 
+#ifdef MINGW
 /**
+ * @return GNUNET_YES if ok, GNUNET_NO if not ok (must bind yourself),
+ * and GNUNET_SYSERR on error.
+ */
+static int
+receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
+{
+  const char *env_buf;
+  int fail;
+  uint64_t count, i;
+  HANDLE lsocks_pipe;
+
+  env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
+  if ((env_buf == NULL) || (strlen (env_buf) <= 0))
+  {
+    return GNUNET_NO;
+  }
+  /* Using W32 API directly here, because this pipe will
+   * never be used outside of this function, and it's just too much of a bother
+   * to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
+   */
+  lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10);
+  if (lsocks_pipe == 0 || lsocks_pipe == INVALID_HANDLE_VALUE)
+    return GNUNET_NO;
+
+  fail = 1;
+  do
+  {
+    int ret;
+    int fail2;
+    DWORD rd;
+
+    ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL);
+    if (ret == 0 || rd != sizeof (count) || count == 0)
+      break;
+    sctx->lsocks =
+        GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1));
+
+    fail2 = 1;
+    for (i = 0; i < count; i++)
+    {
+      WSAPROTOCOL_INFOA pi;
+      uint64_t size;
+      SOCKET s;
+      ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL);
+      if (ret == 0 || rd != sizeof (size) || size != sizeof (pi))
+        break;
+      ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL);
+      if (ret == 0 || rd != sizeof (pi))
+        break;
+      s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, 
WSA_FLAG_OVERLAPPED);
+      sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
+      if (sctx->lsocks[i] == NULL)
+        break;
+      else if (i == count - 1)
+        fail2 = 0;
+    }
+    if (fail2)
+      break;
+    sctx->lsocks[count] = NULL;
+    fail = 0;
+  }
+  while (fail);
+
+  CloseHandle (lsocks_pipe);
+
+  if (fail)
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _("Could not access a pre-bound socket, will try to bind myself\n"));
+    for (i = 0; sctx->lsocks[i] != NULL && i < count; i++)
+      GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i]));
+    GNUNET_free (sctx->lsocks);
+    sctx->lsocks = NULL;
+    return GNUNET_NO;
+  }
+
+  return GNUNET_YES;
+}
+#endif
+
+
+/**
  * Setup addr, addrlen, idle_timeout
  * based on configuration!
  *
@@ -1175,6 +1258,12 @@
     unsetenv ("LISTEN_PID");
     unsetenv ("LISTEN_FDS");
   }
+#else
+  if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL)
+  {
+    receive_sockets_from_parent (sctx);
+    putenv ("GNUNET_OS_READ_LSOCKS=");
+  }
 #endif
 
   if ((sctx->lsocks == NULL) &&




reply via email to

[Prev in Thread] Current Thread [Next in Thread]