[svn] assuan - r199 - in trunk: . src tests

svn author wk cvs at cvs.gnupg.org
Tue Sep 12 13:07:19 CEST 2006


Author: wk
Date: 2006-09-12 13:07:18 +0200 (Tue, 12 Sep 2006)
New Revision: 199

Added:
   trunk/src/assuan-uds.c
Removed:
   trunk/src/assuan-domain-connect.c
   trunk/src/assuan-domain-server.c
Modified:
   trunk/NEWS
   trunk/TODO
   trunk/src/ChangeLog
   trunk/src/Makefile.am
   trunk/src/assuan-defs.h
   trunk/src/assuan-handler.c
   trunk/src/assuan-io.c
   trunk/src/assuan-pipe-connect.c
   trunk/src/assuan-pipe-server.c
   trunk/src/assuan-socket-server.c
   trunk/src/assuan.h
   trunk/tests/fdpassing.c
Log:
Integrated descriptor passing.


Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/NEWS	2006-09-12 11:07:18 UTC (rev 199)
@@ -17,6 +17,11 @@
    printing of the full data, a new environment variable
    ASSUAN_FULL_LOGGING may be set to any value.
 
+ * Removed the assuan_domain fucntions.  Added new function
+   assuan_pipe_connect_ext to allow connections on a socketpair and to
+   pass descriptors.
+
+
 Noteworthy changes in version 0.6.10 (2005-06-20)
 -------------------------------------------------
 

Modified: trunk/TODO
===================================================================
--- trunk/TODO	2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/TODO	2006-09-12 11:07:18 UTC (rev 199)
@@ -13,3 +13,4 @@
 * Check the system error to assuan error translation
 * Do a configure test for SO_PEERCRED.
   We already use HAVE_SO_PEERCRED buty it never gets defined.
+* Replace assuan_pipe_connect2 by  assuan_pipe_connect.
\ No newline at end of file

Modified: trunk/src/ChangeLog
===================================================================
--- trunk/src/ChangeLog	2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/ChangeLog	2006-09-12 11:07:18 UTC (rev 199)
@@ -1,3 +1,35 @@
+2006-09-12  Werner Koch  <wk at g10code.com>
+
+	* assuan-defs.h (DIM, DIMof): New.
+
+	* assuan-domain-server.c: Removed.
+	* assuan-domain-connect.c: Renamed to ..
+	* assuan-uds.c: this.
+	(domain_reader, domain_writer, domain_sendfd, domain_receivefd) 
+	(assuan_domain_connect, _assuan_domain_init): Removed. 
+	(uds_reader, uds_writer, uds_sendfd, uds_receivefd) 
+	(_assuan_init_uds_io): New.
+	(_assuan_uds_deinit): New.
+
+	* assuan-io.c (_assuan_simple_sendmsg, _assuan_simple_recvmsg): New.
+	(my_pth_fdmode, my_pth_select): New.
+
+2006-09-11  Werner Koch  <wk at g10code.com>
+
+	* assuan-pipe-server.c (assuan_init_pipe_server): Allow for
+	FILEDES to be NULL and try to start as a socketpair server in this
+	case.
+
+	* assuan-pipe-connect.c (assuan_pipe_connect2): Split up into two
+	functions (unix and w32) for clarity.
+	(pipe_connect_unix): This is the new fucntion.  Add USE_CMSG flag.
+	(pipe_connect_w32): Ditto.
+	(initial_handshake): Factored out code.
+	(socketpair_connect): New.
+	(assuan_pipe_connect_ext): New.
+	(do_finish): Handle case if outbound and inbound fd are the same.
+	This is to support socketpairs.
+
 2006-09-10  Werner Koch  <wk at g10code.com>
 
 	* assuan-util.c (_assuan_log_print_buffer)

Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am	2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/Makefile.am	2006-09-12 11:07:18 UTC (rev 199)
@@ -46,9 +46,8 @@
 	assuan-socket-server.c \
 	assuan-pipe-connect.c \
 	assuan-socket-connect.c \
+	assuan-uds.c \
 	assuan-io.c \
-	assuan-domain-connect.c \
-	assuan-domain-server.c \
 	assuan-logging.c \
 	assuan-socket.c
 

Modified: trunk/src/assuan-defs.h
===================================================================
--- trunk/src/assuan-defs.h	2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/assuan-defs.h	2006-09-12 11:07:18 UTC (rev 199)
@@ -106,7 +106,7 @@
   char *hello_line;
   char *okay_line;    /* See assuan_set_okay_line() */
 
-  void *user_pointer;  /* For assuan_get_pointer and assuan-set_pointer (). */
+  void *user_pointer;  /* For assuan_get_pointer and assuan_set_pointer (). */
 
   FILE *log_fp;
 
@@ -116,7 +116,7 @@
     char line[LINELENGTH];
     int linelen;  /* w/o CR, LF - might not be the same as
                      strlen(line) due to embedded nuls. However a nul
-                     is always written at this pos */
+                     is always written at this pos. */
     struct {
       char line[LINELENGTH];
       int linelen ;
@@ -135,7 +135,7 @@
   } outbound;
 
   int pipe_mode;  /* We are in pipe mode, i.e. we can handle just one
-                     connection and must terminate then */
+                     connection and must terminate then. */
   pid_t pid;	  /* The pid of the peer. */
   int listen_fd;  /* The fd we are listening on (used by socket servers) */
   int connected_fd; /* helper */
@@ -144,19 +144,19 @@
   /* Used for Unix domain sockets.  */
   struct sockaddr_un myaddr;
   struct sockaddr_un serveraddr;
-  /* When reading from datagram sockets, we must read an entire
-     message at a time.  This means that we have to do our own
-     buffering to be able to get the semantics of read.  */
-  void *domainbuffer;
-  /* Offset of start of buffer.  */
-  int domainbufferoffset;
-  /* Bytes buffered.  */
-  int domainbuffersize;
-  /* Memory allocated.  */
-  int domainbufferallocated;
 
-  int *pendingfds;
-  int pendingfdscount;
+  /* Structure used for unix domain socket buffering.  FIXME: We don't
+     use datagrams anymore thus we could get away with a simpler
+     buffering approach. */
+  struct {
+    void *buffer;         /* Malloced buffer. */
+    int bufferallocated;  /* Memory allocated.  */
+    int bufferoffset;     /* Offset of start of buffer.  */
+    int buffersize;       /* Bytes buffered.  */
+    
+    int pendingfds[5];    /* Array to save received descriptors.  */
+    int pendingfdscount;  /* Number of received descriptors. */
+  } uds;
 
   void (*deinit_handler)(ASSUAN_CONTEXT);
   int (*accept_handler)(ASSUAN_CONTEXT);
@@ -184,14 +184,11 @@
 int _assuan_new_context (ASSUAN_CONTEXT *r_ctx);
 void _assuan_release_context (ASSUAN_CONTEXT ctx);
 
-/*-- assuan-domain-connect.c --*/
-/* Make a connection to the Unix domain socket NAME and return a new
-   Assuan context in CTX.  SERVER_PID is currently not used but may
-   become handy in the future.  */
-assuan_error_t _assuan_domain_init (ASSUAN_CONTEXT *r_ctx,
-                                    int rendezvousfd,
-                                    pid_t peer);
+/*-- assuan-uds.c --*/
+void _assuan_uds_deinit (assuan_context_t ctx);
+void _assuan_init_uds_io (assuan_context_t ctx);
 
+
 /*-- assuan-handler.c --*/
 int _assuan_register_std_commands (ASSUAN_CONTEXT ctx);
 
@@ -259,6 +256,8 @@
 ssize_t _assuan_simple_read (ASSUAN_CONTEXT ctx, void *buffer, size_t size);
 ssize_t _assuan_simple_write (ASSUAN_CONTEXT ctx, const void *buffer,
 			      size_t size);
+ssize_t _assuan_simple_sendmsg (assuan_context_t ctx, struct msghdr *msg);
+ssize_t _assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg);
 
 /*-- assuan-socket.c --*/
 int _assuan_close (int fd);
@@ -290,4 +289,9 @@
 int setenv (const char *name, const char *value, int replace);
 #endif
 
+
+#define DIM(v)		     (sizeof(v)/sizeof((v)[0]))
+#define DIMof(type,member)   DIM(((type *)0)->member)
+
+
 #endif /*ASSUAN_DEFS_H*/

Deleted: trunk/src/assuan-domain-connect.c

Deleted: trunk/src/assuan-domain-server.c

Modified: trunk/src/assuan-handler.c
===================================================================
--- trunk/src/assuan-handler.c	2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/assuan-handler.c	2006-09-12 11:07:18 UTC (rev 199)
@@ -479,7 +479,7 @@
       rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK");
     }
   else if (err_is_eof (rc))
-    { /* No error checking because the peer may have already disconnect */ 
+    { /* No error checking because the peer may have already disconnect. */ 
       assuan_write_line (ctx, "OK closing connection");
       ctx->finish_handler (ctx);
     }

Modified: trunk/src/assuan-io.c
===================================================================
--- trunk/src/assuan-io.c	2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/assuan-io.c	2006-09-12 11:07:18 UTC (rev 199)
@@ -1,5 +1,5 @@
 /* assuan-io.c - Wraps the read and write functions.
- *	Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ *	Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc.
  *
  * This file is part of Assuan.
  *
@@ -23,23 +23,69 @@
 #include <config.h>
 #endif
 
-#include "assuan-defs.h"
 #include <sys/types.h>
+#include <sys/socket.h>
+#if HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
 #include <unistd.h>
+#include <errno.h>
 #ifdef HAVE_W32_SYSTEM
 #include <windows.h>
 #endif
 
+#include "assuan-defs.h"
+
+/* We can't include pth.h and we are not sure whether other headers
+   already included it.  This we define macros with the same
+   values. */
+#define MY_PTH_FDMODE_ERROR    (-1)
+#define MY_PTH_FDMODE_POLL     0
+#define MY_PTH_FDMODE_BLOCK    1
+#define MY_PTH_FDMODE_NONBLOCK 2
+
+
 #ifndef _ASSUAN_NO_PTH
 extern ssize_t pth_read (int fd, void *buffer, size_t size);
 extern ssize_t pth_write (int fd, const void *buffer, size_t size);
+extern int     pth_fdmode (int, int);
+extern int     pth_select(int, fd_set*, fd_set*, fd_set*, struct timeval*);
 
 #ifndef HAVE_W32_SYSTEM
 #pragma weak pth_read
 #pragma weak pth_write
+#pragma weak pth_fdmode
+#pragma weak pth_select
 #endif
 #endif /*!_ASSUAN_NO_PTH*/
 
+#ifndef _ASSUAN_NO_PTH
+/* Wrapper around pth_fdmode. */
+static int
+my_pth_fdmode (int fd, int mode)
+{
+  if (pth_fdmode)
+    return pth_fdmode (fd, mode);
+  else
+    return MY_PTH_FDMODE_NONBLOCK; /* This is okay, given the way we use it. */
+}
+#endif /*_ASSUAN_NO_PTH*/
+
+#ifndef _ASSUAN_NO_PTH
+/* Wrapper around pth_select. */
+static int 
+my_pth_select (int nfd, fd_set *rfds, fd_set *wfds, fd_set *efds,
+               struct timeval *timeout)
+{
+  if (pth_select)
+    return pth_select (nfd, rfds, wfds, efds, timeout);
+  else
+    return 1; /* Fake one fd ready; this is okay, given the way we use it. */
+}
+#endif /*_ASSUAN_NO_PTH*/
+
+
+
 ssize_t
 _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size)
 {
@@ -69,3 +115,87 @@
 # endif
 #endif
 }
+
+
+ssize_t
+_assuan_simple_sendmsg (assuan_context_t ctx, struct msghdr *msg)
+{
+#if defined(HAVE_W32_SYSTEM)
+  return _assuan_error (ASSUAN_Not_Implemented);
+#elif defined(_ASSUAN_NO_PTH)
+  int ret;
+  while ( (ret = sendmsg (ctx->outbound.fd, msg, 0)) == -1 && errno == EINTR)
+    ;
+  return ret;
+#else
+  /* Pth does not provide a sendmsg function.  Thus we implement it here.  */
+  int ret;
+  int fd = ctx->outbound.fd;
+  int fdmode;
+
+  fdmode = my_pth_fdmode (fd, MY_PTH_FDMODE_POLL);
+  if (fdmode == MY_PTH_FDMODE_ERROR)
+    {
+      errno = EBADF;
+      return -1;
+    }
+  if (fdmode == MY_PTH_FDMODE_BLOCK)
+    {
+      fd_set fds;
+
+      FD_ZERO (&fds);
+      FD_SET (fd, &fds);
+      while ( (ret = my_pth_select (fd+1, NULL, &fds, NULL, NULL)) < 0
+              && errno == EINTR)
+        ;
+      if (ret < 0)
+        return -1;
+    }
+
+  while ((ret = sendmsg (fd, msg, 0)) == -1 && errno == EINTR)
+    ;
+  return ret;
+#endif
+}
+
+
+ssize_t
+_assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg)
+{
+#if defined(HAVE_W32_SYSTEM)
+  return _assuan_error (ASSUAN_Not_Implemented);
+#elif defined(_ASSUAN_NO_PTH)
+  int ret;
+  while ( (ret = recvmsg (ctx->inbound.fd, msg, 0)) == -1 && errno == EINTR)
+    ;
+  return ret;
+#else
+  /* Pth does not provide a recvmsg function.  Thus we implement it here.  */
+  int ret;
+  int fd = ctx->inbound.fd;
+  int fdmode;
+
+  fdmode = my_pth_fdmode (fd, MY_PTH_FDMODE_POLL);
+  if (fdmode == MY_PTH_FDMODE_ERROR)
+    {
+      errno = EBADF;
+      return -1;
+    }
+  if (fdmode == MY_PTH_FDMODE_BLOCK)
+    {
+      fd_set fds;
+
+      FD_ZERO (&fds);
+      FD_SET (fd, &fds);
+      while ( (ret = my_pth_select (fd+1, &fds, NULL, NULL, NULL)) < 0
+              && errno == EINTR)
+        ;
+      if (ret < 0)
+        return -1;
+    }
+
+  while ((ret = recvmsg (fd, msg, 0)) == -1 && errno == EINTR)
+    ;
+  return ret;
+#endif
+}

Modified: trunk/src/assuan-pipe-connect.c
===================================================================
--- trunk/src/assuan-pipe-connect.c	2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/assuan-pipe-connect.c	2006-09-12 11:07:18 UTC (rev 199)
@@ -1,5 +1,5 @@
 /* assuan-pipe-connect.c - Establish a pipe connection (client) 
- *	Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
  *
  * This file is part of Assuan.
  *
@@ -112,6 +112,8 @@
   if (ctx->inbound.fd != -1)
     {
       _assuan_close (ctx->inbound.fd);
+      if (ctx->inbound.fd == ctx->outbound.fd)
+        ctx->outbound.fd = -1;
       ctx->inbound.fd = -1;
     }
   if (ctx->outbound.fd != -1)
@@ -139,6 +141,402 @@
 }
 
 
+/* Helper for pipe_connect. */
+static assuan_error_t
+initial_handshake (assuan_context_t *ctx)
+{
+  int okay, off;
+  assuan_error_t err;
+  
+  err = _assuan_read_from_server (*ctx, &okay, &off);
+  if (err)
+    _assuan_log_printf ("can't connect server: %s\n",
+                        assuan_strerror (err));
+  else if (okay != 1)
+    {
+      _assuan_log_printf ("can't connect server: `%s'\n",
+                          (*ctx)->inbound.line);
+      err = _assuan_error (ASSUAN_Connect_Failed);
+    }
+
+  if (err)
+    {
+      assuan_disconnect (*ctx);
+      *ctx = NULL;
+    }
+  return err;
+}
+
+
+#ifndef HAVE_W32_SYSTEM
+#define pipe_connect pipe_connect_unix
+/* Unix version of the pipe connection code.  We use an extra macro to
+   make ChangeLog entries easier. */
+static assuan_error_t
+pipe_connect_unix (assuan_context_t *ctx,
+                   const char *name, const char *const argv[],
+                   int *fd_child_list,
+                   void (*atfork) (void *opaque, int reserved),
+                   void *atforkvalue)
+{
+  assuan_error_t err;
+  int rp[2];
+  int wp[2];
+  char mypidstr[50];
+
+  if (!ctx || !name || !argv || !argv[0])
+    return _assuan_error (ASSUAN_Invalid_Value);
+
+  fix_signals ();
+
+  sprintf (mypidstr, "%lu", (unsigned long)getpid ());
+
+  if (pipe (rp) < 0)
+    return _assuan_error (ASSUAN_General_Error);
+  
+  if (pipe (wp) < 0)
+    {
+      close (rp[0]);
+      close (rp[1]);
+      return _assuan_error (ASSUAN_General_Error);
+    }
+
+  err = _assuan_new_context (ctx);
+  if (err)
+    {
+      close (rp[0]);
+      close (rp[1]);
+      close (wp[0]);
+      close (wp[1]);
+      return err;
+    }
+  (*ctx)->pipe_mode = 1;
+  (*ctx)->inbound.fd  = rp[0];  /* Our inbound is read end of read pipe. */
+  (*ctx)->outbound.fd = wp[1];  /* Our outbound is write end of write pipe. */
+  (*ctx)->deinit_handler = do_deinit;
+  (*ctx)->finish_handler = do_finish;
+
+  /* FIXME: For GPGME we should better use _gpgme_io_spawn.  The PID
+     stored here is actually soon useless.  */
+  (*ctx)->pid = fork ();
+  if ((*ctx)->pid < 0)
+    {
+      close (rp[0]);
+      close (rp[1]);
+      close (wp[0]);
+      close (wp[1]);
+      _assuan_release_context (*ctx); 
+      return _assuan_error (ASSUAN_General_Error);
+    }
+
+  if ((*ctx)->pid == 0)
+    {
+#ifdef _ASSUAN_USE_DOUBLE_FORK      
+      pid_t pid;
+
+      if ((pid = fork ()) == 0)
+#endif
+	{
+          int i, n;
+          char errbuf[512];
+          int *fdp;
+          
+          if (atfork)
+            atfork (atforkvalue, 0);
+
+          /* Dup handles to stdin/stdout. */
+          if (rp[1] != STDOUT_FILENO)
+            {
+              if (dup2 (rp[1], STDOUT_FILENO) == -1)
+                {
+                  _assuan_log_printf ("dup2 failed in child: %s\n",
+                                      strerror (errno));
+                  _exit (4);
+                }
+            }
+          if (wp[0] != STDIN_FILENO)
+            {
+              if (dup2 (wp[0], STDIN_FILENO) == -1)
+                {
+                  _assuan_log_printf ("dup2 failed in child: %s\n",
+                                      strerror (errno));
+                  _exit (4);
+                }
+            }
+
+          /* Dup stderr to /dev/null unless it is in the list of FDs to be
+             passed to the child. */
+          fdp = fd_child_list;
+          if (fdp)
+            {
+              for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
+                ;
+            }
+          if (!fdp || *fdp == -1)
+            {
+              int fd = open ("/dev/null", O_WRONLY);
+              if (fd == -1)
+                {
+                  _assuan_log_printf ("can't open `/dev/null': %s\n",
+                                      strerror (errno));
+                  _exit (4);
+                }
+              if (dup2 (fd, STDERR_FILENO) == -1)
+                {
+                  _assuan_log_printf ("dup2(dev/null, 2) failed: %s\n",
+                                      strerror (errno));
+                  _exit (4);
+                }
+            }
+
+
+          /* Close all files which will not be duped and are not in the
+             fd_child_list. */
+          n = sysconf (_SC_OPEN_MAX);
+          if (n < 0)
+            n = MAX_OPEN_FDS;
+          for (i=0; i < n; i++)
+            {
+              if ( i == STDIN_FILENO || i == STDOUT_FILENO
+                   || i == STDERR_FILENO)
+                continue;
+              fdp = fd_child_list;
+              if (fdp)
+                {
+                  while (*fdp != -1 && *fdp != i)
+                    fdp++;
+                }
+
+              if (!(fdp && *fdp != -1))
+                close(i);
+            }
+          errno = 0;
+
+          /* We store our parents pid in the environment so that the
+             execed assuan server is able to read the actual pid of the
+             client.  The server can't use getppid because it might have
+             been double forked before the assuan server has been
+             initialized. */
+          setenv ("_assuan_pipe_connect_pid", mypidstr, 1);
+
+          /* Make sure that we never pass a connection fd variable
+             when using a simple pipe. */
+          unsetenv ("_assuan_connection_fd");
+
+          execv (name, (char *const *) argv); 
+          /* oops - use the pipe to tell the parent about it */
+          snprintf (errbuf, sizeof(errbuf)-1,
+                    "ERR %d can't exec `%s': %.50s\n",
+                    _assuan_error (ASSUAN_Problem_Starting_Server),
+                    name, strerror (errno));
+          errbuf[sizeof(errbuf)-1] = 0;
+          writen (1, errbuf, strlen (errbuf));
+          _exit (4);
+        }
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+      if (pid == -1)
+	_exit (1);
+      else
+	_exit (0);
+#endif
+    }
+
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+  waitpid ((*ctx)->pid, NULL, 0);
+  (*ctx)->pid = -1;
+#endif
+
+  close (rp[1]);
+  close (wp[0]);
+
+  return initial_handshake (ctx);
+}
+#endif /*!HAVE_W32_SYSTEM*/
+
+
+#ifndef HAVE_W32_SYSTEM
+/* This function is similar to pipe_connect but uses a socketpair and
+   sets the I/O up to use sendmsg/recvmsg. */
+static assuan_error_t
+socketpair_connect (assuan_context_t *ctx,
+                    const char *name, const char *const argv[],
+                    int *fd_child_list,
+                    void (*atfork) (void *opaque, int reserved),
+                    void *atforkvalue)
+{
+  assuan_error_t err;
+  int fds[2];
+  char mypidstr[50];
+
+  if (!ctx
+      || (name && (!argv || !argv[0]))
+      || (!name && argv))
+    return _assuan_error (ASSUAN_Invalid_Value);
+
+  fix_signals ();
+
+  sprintf (mypidstr, "%lu", (unsigned long)getpid ());
+
+  if ( socketpair (AF_LOCAL, SOCK_STREAM, 0, fds) )
+    {
+      _assuan_log_printf ("socketpair failed: %s\n", strerror (errno));
+      return _assuan_error (ASSUAN_General_Error);
+    }
+  
+  err = _assuan_new_context (ctx);
+  if (err)
+    {
+      close (fds[0]);
+      close (fds[1]);
+      return err;
+    }
+  (*ctx)->pipe_mode = 1;
+  (*ctx)->inbound.fd  = fds[0]; 
+  (*ctx)->outbound.fd = fds[0]; 
+  _assuan_init_uds_io (*ctx);
+  (*ctx)->deinit_handler = _assuan_uds_deinit;
+  (*ctx)->finish_handler = do_finish;
+
+  (*ctx)->pid = fork ();
+  if ((*ctx)->pid < 0)
+    {
+      close (fds[0]);
+      close (fds[1]);
+      _assuan_release_context (*ctx); 
+      *ctx = NULL;
+      return _assuan_error (ASSUAN_General_Error);
+    }
+
+  if ((*ctx)->pid == 0)
+    {
+#ifdef _ASSUAN_USE_DOUBLE_FORK      
+      pid_t pid;
+
+      if ((pid = fork ()) == 0)
+#endif
+	{
+          int fd, i, n;
+          char errbuf[512];
+          int *fdp;
+          
+          if (atfork)
+            atfork (atforkvalue, 0);
+
+          /* Connect stdin and stdout to /dev/null. */
+          fd = open ("/dev/null", O_RDONLY);
+          if (fd == -1 || dup2 (fd, STDIN_FILENO) == -1)
+            {
+              _assuan_log_printf ("dup2(dev/null) failed: %s\n",
+                                  strerror (errno));
+              _exit (4);
+            }
+          fd = open ("/dev/null", O_WRONLY);
+          if (fd == -1 || dup2 (fd, STDOUT_FILENO) == -1)
+            {
+              _assuan_log_printf ("dup2(dev/null) failed: %s\n",
+                                  strerror (errno));
+              _exit (4);
+            }
+
+          /* Dup stderr to /dev/null unless it is in the list of FDs to be
+             passed to the child. */
+          fdp = fd_child_list;
+          if (fdp)
+            {
+              for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
+                ;
+            }
+          if (!fdp || *fdp == -1)
+            {
+              fd = open ("/dev/null", O_WRONLY);
+              if (fd == -1 || dup2 (fd, STDERR_FILENO) == -1)
+                {
+                  _assuan_log_printf ("dup2(dev/null) failed: %s\n",
+                                      strerror (errno));
+                  _exit (4);
+                }
+            }
+
+
+          /* Close all files which will not be duped, are not in the
+             fd_child_list and are not the connection fd. */
+          n = sysconf (_SC_OPEN_MAX);
+          if (n < 0)
+            n = MAX_OPEN_FDS;
+          for (i=0; i < n; i++)
+            {
+              if ( i == STDIN_FILENO || i == STDOUT_FILENO
+                   || i == STDERR_FILENO || i == fds[1])
+                continue;
+              fdp = fd_child_list;
+              if (fdp)
+                {
+                  while (*fdp != -1 && *fdp != i)
+                    fdp++;
+                }
+
+              if (!(fdp && *fdp != -1))
+                close(i);
+            }
+          errno = 0;
+
+          /* We store our parents pid in the environment so that the
+             execed assuan server is able to read the actual pid of the
+             client.  The server can't use getppid becuase it might have
+             been double forked before the assuan server has been
+             initialized. */
+          setenv ("_assuan_pipe_connect_pid", mypidstr, 1);
+
+          /* Now set the environment variable used to convey the
+             connection's file descriptor. */
+          sprintf (mypidstr, "%d", fds[1]);
+          if (setenv ("_assuan_connection_fd", mypidstr, 1))
+            {
+              _assuan_log_printf ("setenv failed: %s\n", strerror (errno));
+              _exit (4);
+            }
+
+          if (!name && !argv)
+            {
+              /* No name and no args given, thus we don't do an exec
+                 but continue the forked process.  */
+              _assuan_release_context (*ctx);
+              *ctx = NULL;
+              return 0;
+            }
+
+          execv (name, (char *const *) argv); 
+          /* oops - use the pipe to tell the parent about it */
+          snprintf (errbuf, sizeof(errbuf)-1,
+                    "ERR %d can't exec `%s': %.50s\n",
+                    _assuan_error (ASSUAN_Problem_Starting_Server),
+                    name, strerror (errno));
+          errbuf[sizeof(errbuf)-1] = 0;
+          writen (1, errbuf, strlen (errbuf));
+          _exit (4);
+        }
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+      if (pid == -1)
+	_exit (1);
+      else
+	_exit (0);
+#endif
+    }
+
+
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+  waitpid ((*ctx)->pid, NULL, 0);
+  (*ctx)->pid = -1;
+#endif
+
+  close (fds[1]);
+  
+  return initial_handshake (ctx);
+}
+#endif /*!HAVE_W32_SYSTEM*/
+
+
+
 #ifdef HAVE_W32_SYSTEM
 /* Build a command line for use with W32's CreateProcess.  On success
    CMDLINE gets the address of a newly allocated string.  */
@@ -237,21 +635,16 @@
 #endif /*HAVE_W32_SYSTEM*/
 
 
-/* Connect to a server over a pipe, creating the assuan context and
-   returning it in CTX.  The server filename is NAME, the argument
-   vector in ARGV.  FD_CHILD_LIST is a -1 terminated list of file
-   descriptors not to close in the child.  ATFORK is called in the
-   child right after the fork; ATFORKVALUE is passed as the first
-   argument and 0 is passed as the second argument. The ATFORK
-   function should only act if the second value is 0. */
-assuan_error_t
-assuan_pipe_connect2 (assuan_context_t *ctx,
-                      const char *name, const char *const argv[],
-                      int *fd_child_list,
-                      void (*atfork) (void *opaque, int reserved),
-                      void *atforkvalue)
+#ifdef HAVE_W32_SYSTEM
+#define pipe_connect pipe_connect_w32
+/* W32 version of the pipe connection code. */
+static assuan_error_t
+pipe_connect_w32 (assuan_context_t *ctx,
+                  const char *name, const char *const argv[],
+                  int *fd_child_list,
+                  void (*atfork) (void *opaque, int reserved),
+                  void *atforkvalue)
 {
-#ifdef HAVE_W32_SYSTEM
   assuan_error_t err;
   int rp[2];
   int wp[2];
@@ -414,201 +807,11 @@
   (*ctx)->pid = 0;  /* We don't use the PID. */
   CloseHandle (pi.hProcess); /* We don't need to wait for the process. */
 
-#else /*!HAVE_W32_SYSTEM*/
-  assuan_error_t err;
-  int rp[2];
-  int wp[2];
-  char mypidstr[50];
-
-  if (!ctx || !name || !argv || !argv[0])
-    return _assuan_error (ASSUAN_Invalid_Value);
-
-  fix_signals ();
-
-  sprintf (mypidstr, "%lu", (unsigned long)getpid ());
-
-  if (pipe (rp) < 0)
-    return _assuan_error (ASSUAN_General_Error);
-
-  if (pipe (wp) < 0)
-    {
-      close (rp[0]);
-      close (rp[1]);
-      return _assuan_error (ASSUAN_General_Error);
-    }
-  
-  err = _assuan_new_context (ctx);
-  if (err)
-    {
-      close (rp[0]);
-      close (rp[1]);
-      close (wp[0]);
-      close (wp[1]);
-      return err;
-    }
-  (*ctx)->pipe_mode = 1;
-  (*ctx)->inbound.fd  = rp[0];  /* Our inbound is read end of read pipe. */
-  (*ctx)->outbound.fd = wp[1];  /* Our outbound is write end of write pipe. */
-  (*ctx)->deinit_handler = do_deinit;
-  (*ctx)->finish_handler = do_finish;
-
-  /* FIXME: For GPGME we should better use _gpgme_io_spawn.  The PID
-     stored here is actually soon useless.  */
-  (*ctx)->pid = fork ();
-  if ((*ctx)->pid < 0)
-    {
-      close (rp[0]);
-      close (rp[1]);
-      close (wp[0]);
-      close (wp[1]);
-      _assuan_release_context (*ctx); 
-      return _assuan_error (ASSUAN_General_Error);
-    }
-
-  if ((*ctx)->pid == 0)
-    {
-#ifdef _ASSUAN_USE_DOUBLE_FORK      
-      pid_t pid;
-
-      if ((pid = fork ()) == 0)
-#endif
-	{
-          int i, n;
-          char errbuf[512];
-          int *fdp;
-          
-          if (atfork)
-            atfork (atforkvalue, 0);
-
-          /* Dup handles to stdin/stdout. */
-          if (rp[1] != STDOUT_FILENO)
-            {
-              if (dup2 (rp[1], STDOUT_FILENO) == -1)
-                {
-                  _assuan_log_printf ("dup2 failed in child: %s\n",
-                                      strerror (errno));
-                  _exit (4);
-                }
-            }
-          if (wp[0] != STDIN_FILENO)
-            {
-              if (dup2 (wp[0], STDIN_FILENO) == -1)
-                {
-                  _assuan_log_printf ("dup2 failed in child: %s\n",
-                                      strerror (errno));
-                  _exit (4);
-                }
-            }
-
-          /* Dup stderr to /dev/null unless it is in the list of FDs to be
-             passed to the child. */
-          fdp = fd_child_list;
-          if (fdp)
-            {
-              for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
-                ;
-            }
-          if (!fdp || *fdp == -1)
-            {
-              int fd = open ("/dev/null", O_WRONLY);
-              if (fd == -1)
-                {
-                  _assuan_log_printf ("can't open `/dev/null': %s\n",
-                                      strerror (errno));
-                  _exit (4);
-                }
-              if (dup2 (fd, STDERR_FILENO) == -1)
-                {
-                  _assuan_log_printf ("dup2(dev/null, 2) failed: %s\n",
-                                      strerror (errno));
-                  _exit (4);
-                }
-            }
-
-
-          /* Close all files which will not be duped and are not in the
-             fd_child_list. */
-          n = sysconf (_SC_OPEN_MAX);
-          if (n < 0)
-            n = MAX_OPEN_FDS;
-          for (i=0; i < n; i++)
-            {
-              if ( i == STDIN_FILENO || i == STDOUT_FILENO
-                   || i == STDERR_FILENO)
-                continue;
-              fdp = fd_child_list;
-              if (fdp)
-                {
-                  while (*fdp != -1 && *fdp != i)
-                    fdp++;
-                }
-
-              if (!(fdp && *fdp != -1))
-                close(i);
-            }
-          errno = 0;
-
-          /* We store our parents pid in the environment so that the
-             execed assuan server is able to read the actual pid of the
-             client.  The server can't use getppid becuase it might have
-             been double forked before the assuan server has been
-             initialized. */
-          setenv ("_assuan_pipe_connect_pid", mypidstr, 1);
-
-          execv (name, (char *const *) argv); 
-          /* oops - use the pipe to tell the parent about it */
-          snprintf (errbuf, sizeof(errbuf)-1,
-                    "ERR %d can't exec `%s': %.50s\n",
-                    _assuan_error (ASSUAN_Problem_Starting_Server),
-                    name, strerror (errno));
-          errbuf[sizeof(errbuf)-1] = 0;
-          writen (1, errbuf, strlen (errbuf));
-          _exit (4);
-        }
-#ifdef _ASSUAN_USE_DOUBLE_FORK
-      if (pid == -1)
-	_exit (1);
-      else
-	_exit (0);
-#endif
-    }
-
-#ifdef _ASSUAN_USE_DOUBLE_FORK
-  waitpid ((*ctx)->pid, NULL, 0);
-  (*ctx)->pid = -1;
-#endif
-
-  close (rp[1]);
-  close (wp[0]);
-
-#endif /*!HAVE_W32_SYSTEM*/
-
-  /* initial handshake */
-  {
-    int okay, off;
-
-    err = _assuan_read_from_server (*ctx, &okay, &off);
-    if (err)
-      _assuan_log_printf ("can't connect server: %s\n",
-                          assuan_strerror (err));
-    else if (okay != 1)
-      {
-	_assuan_log_printf ("can't connect server: `%s'\n",
-                            (*ctx)->inbound.line);
-	err = _assuan_error (ASSUAN_Connect_Failed);
-      }
-  }
-
-  if (err)
-    {
-      assuan_disconnect (*ctx);
-      *ctx = NULL;
-    }
-
-  return err;
+  return initial_handshake (ctx);
 }
+#endif /*HAVE_W32_SYSTEM*/
 
-
+
 /* Connect to a server over a pipe, creating the assuan context and
    returning it in CTX.  The server filename is NAME, the argument
    vector in ARGV.  FD_CHILD_LIST is a -1 terminated list of file
@@ -617,5 +820,53 @@
 assuan_pipe_connect (assuan_context_t *ctx, const char *name,
 		     const char *const argv[], int *fd_child_list)
 {
-  return assuan_pipe_connect2 (ctx, name, argv, fd_child_list, NULL, NULL);
+  return pipe_connect (ctx, name, argv, fd_child_list, NULL, NULL);
 }
+
+
+/* Connect to a server over a pipe, creating the assuan context and
+   returning it in CTX.  The server filename is NAME, the argument
+   vector in ARGV.  FD_CHILD_LIST is a -1 terminated list of file
+   descriptors not to close in the child.  ATFORK is called in the
+   child right after the fork; ATFORKVALUE is passed as the first
+   argument and 0 is passed as the second argument. The ATFORK
+   function should only act if the second value is 0. */
+assuan_error_t
+assuan_pipe_connect2 (assuan_context_t *ctx,
+                      const char *name, const char *const argv[],
+                      int *fd_child_list,
+                      void (*atfork) (void *opaque, int reserved),
+                      void *atforkvalue)
+{
+  return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue);
+}
+
+
+/* Connect to a server over a socketpair, creating the assuan context
+   and returning it in CTX.  The server filename is NAME, the argument
+   vector in ARGV.  FD_CHILD_LIST is a -1 terminated list of file
+   descriptors not to close in the child.  ATFORK is called in the
+   child right after the fork; ATFORKVALUE is passed as the first
+   argument and 0 is passed as the second argument. The ATFORK
+   function should only act if the second value is 0.  
+
+   If NAME as well as ARGV are NULL, no exec is done but the same
+   process is continued.  However all file descriptors are closed and
+   some specila environment variables are set. To let the caller
+   detect whether the cild or the parent continues, the child returns
+   a CTX of NULL. */
+assuan_error_t
+assuan_pipe_connect_ext (assuan_context_t *ctx,
+                         const char *name, const char *const argv[],
+                         int *fd_child_list,
+                         void (*atfork) (void *opaque, int reserved),
+                         void *atforkvalue)
+{
+#ifdef HAVE_W32_SYSTEM
+  return _assuan_error (ASSUAN_Not_Implemented);
+#else
+  return socketpair_connect (ctx, name, argv, fd_child_list,
+                             atfork, atforkvalue);
+#endif
+}
+

Modified: trunk/src/assuan-pipe-server.c
===================================================================
--- trunk/src/assuan-pipe-server.c	2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/assuan-pipe-server.c	2006-09-12 11:07:18 UTC (rev 199)
@@ -111,8 +111,28 @@
       ctx->inbound.fd  = _get_osfhandle (filedes[0]);
       ctx->outbound.fd = _get_osfhandle (filedes[1]);
 #else
-      ctx->inbound.fd  = filedes[0];
-      ctx->outbound.fd = filedes[1];
+      s = getenv ("_assuan_connection_fd");
+      if (!filedes && s && *s && atoi (s) >= 0 )
+        {
+          /* Well, we are called with an bi-directional file
+             descriptor.  Prepare for using sendmsg/recvmsg.  In this
+             case we ignore the passed file descriptors. */
+          ctx->inbound.fd  = ctx->outbound.fd = atoi (s);
+          _assuan_init_uds_io (ctx);
+          ctx->deinit_handler = _assuan_uds_deinit;
+        }
+      else if (filedes)
+        {
+          /* Standard pipe server. */
+          ctx->inbound.fd  = filedes[0];
+          ctx->outbound.fd = filedes[1];
+        }
+      else
+        {
+          _assuan_release_context (*r_ctx);
+          *r_ctx = NULL;
+          return ASSUAN_Problem_Starting_Server;
+        }
 #endif
       ctx->pipe_mode = 1;
 

Modified: trunk/src/assuan-socket-server.c
===================================================================
--- trunk/src/assuan-socket-server.c	2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/assuan-socket-server.c	2006-09-12 11:07:18 UTC (rev 199)
@@ -34,6 +34,10 @@
 
 #include "assuan-defs.h"
 
+static struct assuan_io io = { _assuan_simple_read,
+			       _assuan_simple_write };
+
+
 static int
 accept_connection_bottom (assuan_context_t ctx)
 {
@@ -105,9 +109,6 @@
   finish_connection (ctx);
 }
 
-static struct assuan_io io = { _assuan_simple_read,
-			       _assuan_simple_write };
-
 /* Initialize a server for the socket LISTEN_FD which has already be
    put into listen mode */
 int

Copied: trunk/src/assuan-uds.c (from rev 196, trunk/src/assuan-domain-connect.c)
===================================================================
--- trunk/src/assuan-domain-connect.c	2006-09-06 16:36:45 UTC (rev 196)
+++ trunk/src/assuan-uds.c	2006-09-12 11:07:18 UTC (rev 199)
@@ -0,0 +1,273 @@
+/* assuan-uds.c - Assuan unix domain socket utilities
+ * Copyright (C) 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of Assuan.
+ *
+ * Assuan is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Assuan 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA. 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#ifndef HAVE_W32_SYSTEM
+#include <sys/socket.h>
+#include <sys/un.h>
+#else
+#include <windows.h>
+#endif
+#if HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <assert.h>
+
+#include "assuan-defs.h"
+
+
+/* Read from a unix domain socket using sendmsg.  */
+static ssize_t
+uds_reader (assuan_context_t ctx, void *buf, size_t buflen)
+{
+  int len = ctx->uds.buffersize;
+
+#ifndef HAVE_W32_SYSTEM
+
+  if (!ctx->uds.bufferallocated)
+    {
+      ctx->uds.buffer = xtrymalloc (2048);
+      if (!ctx->uds.buffer)
+        return _assuan_error (ASSUAN_Out_Of_Core);
+      ctx->uds.bufferallocated = 2048;
+    }
+
+  while (!len)  /* No data is buffered.  */
+    {
+      struct msghdr msg;
+      struct iovec iovec;
+      union {
+        struct cmsghdr cm;
+        char control[CMSG_SPACE(sizeof (int))];
+      } control_u;
+      struct cmsghdr *cmptr;
+
+      memset (&msg, 0, sizeof (msg));
+
+      msg.msg_name = NULL;
+      msg.msg_namelen = 0;
+      msg.msg_iov = &iovec;
+      msg.msg_iovlen = 1;
+      iovec.iov_base = ctx->uds.buffer;
+      iovec.iov_len = ctx->uds.bufferallocated;
+      msg.msg_control = control_u.control;
+      msg.msg_controllen = sizeof (control_u.control);
+
+      len = _assuan_simple_recvmsg (ctx, &msg);
+      if (len < 0)
+        return -1;
+
+      ctx->uds.buffersize = len;
+      ctx->uds.bufferoffset = 0;
+
+      cmptr = CMSG_FIRSTHDR (&msg);
+      if (cmptr && cmptr->cmsg_len == CMSG_LEN (sizeof(int)))
+        {
+          if (cmptr->cmsg_level != SOL_SOCKET
+              || cmptr->cmsg_type != SCM_RIGHTS)
+            _assuan_log_printf ("unexpected ancillary data received\n");
+          else
+            {
+              int fd = *((int*)CMSG_DATA (cmptr));
+
+              if (ctx->uds.pendingfdscount >= DIM (ctx->uds.pendingfds))
+                {
+                  _assuan_log_printf ("too many descriptors pending - "
+                                      "closing received descriptor %d\n", fd);
+                  _assuan_close (fd);
+                }
+              else
+                ctx->uds.pendingfds[ctx->uds.pendingfdscount++] = fd;
+            }
+	}
+    }
+#else /*HAVE_W32_SYSTEM*/
+  len = recvfrom (ctx->inbound.fd, buf, buflen, 0, NULL, NULL);
+#endif /*HAVE_W32_SYSTEM*/
+
+  /* Return some data to the user.  */
+
+  if (len > buflen) /* We have more than the user requested.  */
+    len = buflen;
+
+  memcpy (buf, ctx->uds.buffer + ctx->uds.bufferoffset, len);
+  ctx->uds.buffersize -= len;
+  assert (ctx->uds.buffersize >= 0);
+  ctx->uds.bufferoffset += len;
+  assert (ctx->uds.bufferoffset <= ctx->uds.bufferallocated);
+
+  return len;
+}
+
+
+/* Write to the domain server.  */
+static ssize_t
+uds_writer (assuan_context_t ctx, const void *buf, size_t buflen)
+{
+#ifndef HAVE_W32_SYSTEM
+  struct msghdr msg;
+  struct iovec iovec;
+  ssize_t len;
+
+  memset (&msg, 0, sizeof (msg));
+
+  msg.msg_name = NULL;
+  msg.msg_namelen = 0;
+  msg.msg_iovlen = 1;
+  msg.msg_iov = &iovec;
+  iovec.iov_base = (void*)buf;
+  iovec.iov_len = buflen;
+  msg.msg_control = 0;
+  msg.msg_controllen = 0;
+
+  len = _assuan_simple_sendmsg (ctx, &msg);
+#else /*HAVE_W32_SYSTEM*/
+  int len;
+  
+  len = sendto (ctx->outbound.fd, buf, buflen, 0,
+                (struct sockaddr *)&ctx->serveraddr,
+                sizeof (struct sockaddr_in));
+#endif /*HAVE_W32_SYSTEM*/
+  return len;
+}
+
+
+static assuan_error_t
+uds_sendfd (assuan_context_t ctx, int fd)
+{
+#ifndef HAVE_W32_SYSTEM
+  struct msghdr msg;
+  struct iovec iovec;
+  union {
+    struct cmsghdr cm;
+    char control[CMSG_SPACE(sizeof (int))];
+  } control_u;
+  struct cmsghdr *cmptr;
+  int len;
+  char buffer[80];
+
+  /* We need to send some real data so that a read won't return 0
+     which will be taken as an EOF.  It also helps with debugging. */ 
+  snprintf (buffer, sizeof(buffer)-1, "# descriptor %d is in flight\n", fd);
+  buffer[sizeof(buffer)-1] = 0;
+
+  memset (&msg, 0, sizeof (msg));
+
+  msg.msg_name = NULL;
+  msg.msg_namelen = 0;
+  msg.msg_iovlen = 1;
+  msg.msg_iov = &iovec;
+  iovec.iov_base = buffer;
+  iovec.iov_len = strlen (buffer);
+
+  msg.msg_control = control_u.control;
+  msg.msg_controllen = sizeof (control_u.control);
+  cmptr = CMSG_FIRSTHDR (&msg);
+  cmptr->cmsg_len = CMSG_LEN(sizeof(int));
+  cmptr->cmsg_level = SOL_SOCKET;
+  cmptr->cmsg_type = SCM_RIGHTS;
+  *((int*)CMSG_DATA (cmptr)) = fd;
+
+  len = _assuan_simple_sendmsg (ctx, &msg);
+  if (len < 0)
+    {
+      _assuan_log_printf ("uds_sendfd: %s\n", strerror (errno));
+      return _assuan_error (ASSUAN_Write_Error);
+    }
+  else
+    return 0;
+#else
+  return _assuan_error (ASSUAN_Not_Implemented);
+#endif
+}
+
+
+static assuan_error_t
+uds_receivefd (assuan_context_t ctx, int *fd)
+{
+#ifndef HAVE_W32_SYSTEM
+  if (!ctx->uds.pendingfds)
+    {
+      _assuan_log_printf ("no pending file descriptors!\n");
+      return _assuan_error (ASSUAN_General_Error);
+    }
+
+  *fd = ctx->uds.pendingfds[0];
+  if (--ctx->uds.pendingfdscount)
+    memmove (ctx->uds.pendingfds, ctx->uds.pendingfds + 1,
+             ctx->uds.pendingfdscount * sizeof (int));
+
+  return 0;
+#else
+  return _assuan_error (ASSUAN_Not_Implemented);
+#endif
+}
+
+
+/* Deinitialize the unix domain socket I/O functions.  */
+void
+_assuan_uds_deinit (assuan_context_t ctx)
+{
+  int i;
+
+  /* First call the finish_handler which should close descriptors etc. */
+  ctx->finish_handler (ctx);
+
+  if (ctx->uds.buffer)
+    {
+      assert (ctx->uds.bufferallocated);
+      ctx->uds.bufferallocated = 0;
+      xfree (ctx->uds.buffer);
+    }
+
+  for (i = 0; i < ctx->uds.pendingfdscount; i++)
+    _assuan_close (ctx->uds.pendingfds[i]);
+  ctx->uds.pendingfdscount = 0;
+}
+
+
+
+/* Helper function to initialize a context for domain I/O. */
+void
+_assuan_init_uds_io (assuan_context_t ctx)
+{
+  static struct assuan_io io = { uds_reader, uds_writer,
+				 uds_sendfd, uds_receivefd };
+
+  ctx->io = &io;
+  ctx->uds.buffer = 0;
+  ctx->uds.bufferoffset = 0;
+  ctx->uds.buffersize = 0;
+  ctx->uds.bufferallocated = 0;
+  ctx->uds.pendingfdscount = 0;
+}
+

Modified: trunk/src/assuan.h
===================================================================
--- trunk/src/assuan.h	2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/src/assuan.h	2006-09-12 11:07:18 UTC (rev 199)
@@ -347,7 +347,7 @@
    file descriptor via CTX and stores it in *RDF (the CTX must be
    capable of passing file descriptors).  */
 assuan_error_t assuan_command_parse_fd (assuan_context_t ctx, char *line,
-				     int *rfd);
+                                        int *rfd);
 
 /*-- assuan-listen.c --*/
 assuan_error_t assuan_set_hello_line (assuan_context_t ctx, const char *line);
@@ -368,38 +368,29 @@
 
 
 /*-- assuan-pipe-connect.c --*/
-assuan_error_t assuan_pipe_connect (assuan_context_t *ctx, const char *name,
+assuan_error_t assuan_pipe_connect (assuan_context_t *ctx,
+                                    const char *name,
 				    const char *const argv[],
 				    int *fd_child_list);
-assuan_error_t assuan_pipe_connect2 (assuan_context_t *ctx, const char *name,
+assuan_error_t assuan_pipe_connect2 (assuan_context_t *ctx,
+                                     const char *name,
                                      const char *const argv[],
 				     int *fd_child_list,
                                      void (*atfork) (void*, int),
                                      void *atforkvalue);
+assuan_error_t assuan_pipe_connect_ext (assuan_context_t *ctx, 
+                                        const char *name,
+                                        const char *const argv[],
+                                        int *fd_child_list,
+                                        void (*atfork) (void *, int),
+                                        void *atforkvalue);
+
 /*-- assuan-socket-connect.c --*/
 assuan_error_t assuan_socket_connect (assuan_context_t *ctx, const char *name,
                                       pid_t server_pid);
 
-/*-- assuan-domain-connect.c --*/
 
-/* Connect to a Unix domain socket server.  RENDEZVOUSFD is
-   bidirectional file descriptor (normally returned via socketpair)
-   which the client can use to rendezvous with the server.  SERVER s
-   the server's pid.  */
-assuan_error_t assuan_domain_connect (assuan_context_t *r_ctx,
-                                      int rendezvousfd,
-                                      pid_t server);
 
-/*-- assuan-domain-server.c --*/
-
-/* RENDEZVOUSFD is a bidirectional file descriptor (normally returned
-   via socketpair) that the domain server can use to rendezvous with
-   the client.  CLIENT is the client's pid.  */
-assuan_error_t assuan_init_domain_server (assuan_context_t *r_ctx,
-                                          int rendezvousfd,
-                                          pid_t client);
-
-
 /*-- assuan-connect.c --*/
 void assuan_disconnect (assuan_context_t ctx);
 pid_t assuan_get_pid (assuan_context_t ctx);

Modified: trunk/tests/fdpassing.c
===================================================================
--- trunk/tests/fdpassing.c	2006-09-11 13:15:48 UTC (rev 198)
+++ trunk/tests/fdpassing.c	2006-09-12 11:07:18 UTC (rev 199)
@@ -45,23 +45,28 @@
   int fd;
   int c;
   FILE *fp;
+  int nbytes;
 
   log_info ("got ECHO command (%s)\n", line);
 
   fd = assuan_get_input_fd (ctx);
   if (fd == -1)
     return ASSUAN_No_Input;
-  fp = fdopen (dup (fd), "r");
+  fp = fdopen (fd, "r");
   if (!fp)
     {
       log_error ("fdopen failed on input fd: %s\n", strerror (errno));
       return ASSUAN_General_Error;
     }
   log_info ("printing input to stdout:\n");
+  nbytes = 0;
   while ( (c=getc (fp)) != -1)
-    putc (c, stdout); 
+    {
+      putc (c, stdout); 
+      nbytes++;
+    }
   fflush (stdout); 
-  log_info ("done printing input to stdout\n");
+  log_info ("done printing %d bytes to stdout\n", nbytes);
 
   fclose (fp);
   return 0;
@@ -93,22 +98,21 @@
 
 
 static void
-server (int fd)
+server (void)
 {
   int rc;
   assuan_context_t ctx;
 
-  log_info ("server started on fd %d\n", fd);
+  log_info ("server started\n");
 
-  rc = assuan_init_domain_server (&ctx, fd, (pid_t)(-1));
+  rc = assuan_init_pipe_server (&ctx, NULL);
   if (rc)
-    log_fatal ("assuan_init_domain_server failed: %s\n", assuan_strerror (rc));
+    log_fatal ("assuan_init_pipe_server failed: %s\n", assuan_strerror (rc));
 
   rc = register_commands (ctx);
   if (rc)
     log_fatal ("register_commands failed: %s\n", assuan_strerror(rc));
 
-  assuan_set_assuan_log_prefix (log_prefix);
   assuan_set_log_stream (ctx, stderr);
 
   for (;;) 
@@ -116,7 +120,8 @@
       rc = assuan_accept (ctx);
       if (rc)
         {
-          log_error ("assuan_accept failed: %s\n", assuan_strerror (rc));
+          if (rc != -1)
+            log_error ("assuan_accept failed: %s\n", assuan_strerror (rc));
           break;
         }
 
@@ -140,53 +145,51 @@
 
 /* Client main.  If true is returned, a disconnect has not been done. */
 static int
-client (int fd)
+client (assuan_context_t ctx)
 {
   int rc;
-  assuan_context_t ctx;
   FILE *fp;
   int i;
 
-  log_info ("client started on fd %d\n", fd);
+  log_info ("client started\n");
 
-  rc = assuan_domain_connect (&ctx, fd, (pid_t)(-1));
-  if (rc)
+  for (i=0; i < 8; i++)
     {
-      log_error ("assuan_domain_connect failed: %s\n", assuan_strerror (rc));
-      return -1;
-    }
+      fp = fopen ("/etc/motd", "r");
+      if (!fp)
+        {
+          log_error ("failed to open `%s': %s\n", "/etc/motd",
+                     strerror (errno));
+          return -1;
+        }
+      
+      rc = assuan_sendfd (ctx, fileno (fp));
+      if (rc)
+        {
+          log_error ("assuan_sendfd failed: %s\n", assuan_strerror (rc));
+          return -1;
+        }
+      fclose (fp);
 
-  fp = fopen ("/etc/motd", "r");
-  if (!fp)
-    {
-      log_error ("failed to open `%s': %s\n", "/etc/motd", strerror (errno));
-      return -1;
-    }
+      rc = assuan_transact (ctx, "INPUT FD", NULL, NULL, NULL, NULL,
+                            NULL, NULL);
+      if (rc)
+        {
+          log_error ("sending INPUT FD failed: %s\n", assuan_strerror (rc));
+          return -1;
+        }
 
-  rc = assuan_sendfd (ctx, fileno (fp));
-  if (rc)
-    {
-      log_error ("assuan_sendfd failed: %s\n", assuan_strerror (rc));
-      return -1;
+      rc = assuan_transact (ctx, "ECHO", NULL, NULL, NULL, NULL, NULL, NULL);
+      if (rc)
+        {
+          log_error ("sending ECHO failed: %s\n", assuan_strerror (rc));
+          return -1;
+        }
     }
-  
-  rc = assuan_transact (ctx, "INPUT FD", NULL, NULL, NULL, NULL, NULL, NULL);
-  if (rc)
-    {
-      log_error ("sending INPUT FD failed: %s\n", assuan_strerror (rc));
-      return -1;
-    }
 
+  /* Give us some time to check with lsof that all descriptors are closed. */
+/*   sleep (10); */
 
-  rc = assuan_transact (ctx, "ECHO", NULL, NULL, NULL, NULL, NULL, NULL);
-  if (rc)
-    {
-      log_error ("sending ECHO failed: %s\n", assuan_strerror (rc));
-      return -1;
-    }
-
-  sleep (100);
-
   assuan_disconnect (ctx);
   return 0;
 }
@@ -204,8 +207,12 @@
 {
   int last_argc = -1;
   const char *srcdir = getenv ("srcdir");
-  int fds[2];
-  pid_t pid;
+  assuan_context_t ctx;
+  int err;
+  int no_close_fds[2];
+  const char *arglist[10];
+  int is_server = 0;
+  int with_exec = 0;
   
   if (!srcdir)
     srcdir = ".";
@@ -223,7 +230,10 @@
           puts (
 "usage: ./fdpassing [options]\n"
 "\n"
-"       Options are --verbose and --debug");
+"Options:\n"
+"  --verbose      Show what is going on\n"
+"  --with-exec    Exec the child.  Default is just a fork\n"
+);
           exit (0);
         }
       if (!strcmp (*argv, "--verbose"))
@@ -236,29 +246,60 @@
           verbose = debug = 1;
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--server"))
+        {
+          is_server = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--with-exec"))
+        {
+          with_exec = 1;
+          argc--; argv++;
+        }
     }
 
-  /* Create a socketpair.  */
-  if ( socketpair (AF_LOCAL, SOCK_STREAM, 0, fds) )
-    log_fatal ("socketpair failed: %s\n", strerror (errno));
+  assuan_set_assuan_log_prefix (log_prefix);
+  assuan_set_assuan_log_stream (stderr);
 
-  /* Fork and run server and client.  */
-  pid = fork ();
-  if (pid == (pid_t)(-1))
-    log_fatal ("fork failed: %s\n", strerror (errno));
-  if (!pid)
+  if (is_server)
     {
-      server (fds[0]); /* The child is our server. */
+      server ();
       log_info ("server finished\n");
     }
   else
     {
-      if (client (fds[1])) /* The parent is the client.  */
+      no_close_fds[0] = 2;
+      no_close_fds[1] = -1;
+      if (with_exec)
         {
-          log_info ("waiting for server to terminate...\n");
-          waitpid (pid, NULL, 0); 
+          arglist[0] = "fdpassing";
+          arglist[1] = "--server";
+          arglist[2] = verbose? "--verbose":NULL;
+          arglist[3] = NULL;
         }
-      log_info ("client finished\n");
+      err = assuan_pipe_connect_ext (&ctx, with_exec? "./fdpassing":NULL,
+                                     with_exec? arglist :NULL,
+                                     no_close_fds, NULL, NULL);
+      if (err)
+        {
+          log_error ("assuan_pipe_connect failed: %s\n",assuan_strerror (err));
+          return 1;
+        }
+      
+      if (!ctx)
+        {
+          server ();
+          log_info ("server finished\n");
+        }
+      else
+        {
+          if (client (ctx)) 
+            {
+              log_info ("waiting for server to terminate...\n");
+              assuan_disconnect (ctx);
+            }
+          log_info ("client finished\n");
+        }
     }
 
   return errorcount? 1:0;




More information about the Gnupg-commits mailing list