[Pkg-gnupg-commit] [libassuan] 254/437: 2009-10-16 Marcus Brinkmann <marcus at g10code.de>

Eric Dorland eric at moszumanska.debian.org
Fri May 22 05:33:50 UTC 2015


This is an automated email from the git hooks/post-receive script.

eric pushed a commit to branch master
in repository libassuan.

commit 5e15cf931706f9a6ae00d17569b97d636d6f2945
Author: Marcus Brinkmann <mb at g10code.com>
Date:   Fri Oct 16 18:24:46 2009 +0000

    2009-10-16  Marcus Brinkmann  <marcus at g10code.de>
    
    	* autogen.sh: Remove --with-pth-prefix from configure invocation.
    	* configure.ac (_ASSUAN_IN_LIBASSUAN, PTH_SYSCALL_SOFT): Do not
    	set anymore.
    	(GNUPG_PATH_PTH): Don't invoke.
    	(HAVE_PTH): Remove conditional.
    	(LIBASSUAN_CONFIG_THREAD_MODULES): Removed.
    
    doc/
    2009-10-16  Marcus Brinkmann  <marcus at g10code.com>
    
    	* assuan.texi: Remove documentation for thread support.
    	(assuan_pipe_connect_ext): Update prototype.
    
    src/
    2009-10-16  Marcus Brinkmann  <marcus at g10code.com>
    
    	* conversion.c: Do not include <sys/types.h> and <time.h>.
    	* debug.h (TRACE_BEG6, TRACE4): New macros.
    	(TRACE_SYSERR): Pass _assuan_trace_context to _assuan_debug.
    	* context.c (assuan_set_pointer, assuan_get_pointer,
    	assuan_set_flag, assuan_get_flag, assuan_set_io_monitor,
    	assuan_set_error): Add trace messages.
    
    	* libassuan-config.in, libassuan.m4, Makefile.am: Remove PTH support.
    	* assuan.h (assuan_msghdr_t): New type.
    	(ASSUAN_INVALID_PID): New macro.
    	(ASSUAN_NO_FIXSIGNALS): New flag macro.
    	(ASSUAN_SYSTEM_HOOKS_VERSION): New macro.
    	(struct assuan_system_hooks, assuan_system_hooks_t): New types.
    	(assuan_pipe_connect, assuan_pipe_connect_ext): Don't make ARGV
    	const for name==NULL operation.  Make fd_child_list an array of
    	assuan_fd_t.
    	(assuan_sock_init, assuan_sock_deinit, assuan_set_system_hooks,
    	assuan_ctx_set_system_hooks, __assuan_pipe, __assuan_close,
    	__assuan_spawn, __assuan_socketpair): New function prototypes.
    	(_ASSUAN_SYSTEM_PTH_IMPL, ASSUAN_SYSTEM_PTH_DECL,
    	ASSUAN_SYSTEM_PTH): New macros.
    	(_assuan_system_pth): New declaration.
    	* libassuan.vers, libassuan.defs: Add assuan_sock_init,
    	assuan_sock_deinit, __assuan_pipe, __assuan_close, __assuan_spawn,
    	__assuan_socketpair, assuan_set_system_hooks,
    	assuan_ctx_set_system_hooks.
    
    	* assuan-defs.h (struct assuan_io): Removed, move members to ...
    	(struct assuan_context_s): ... this to ENGINE.  New flag
    	no_fixsignals.  New member SYSTEM.  Remove member IO.
    	(_assuan_pipe, _assuan_read, _assuan_write, _assuan_recvmsg,
    	_assuan_sendmsg, _assuan_spawn, _assuan_socketpair,
    	_assuan_system_hooks, _assuan_system_hooks_copy): New
    	declarations.
    	(_assuan_error_is_eagain, _assuan_waitpid, _assuan_usleep,
    	_assuan_close, _assuan_sock_new, _assuan_sock_connect,
    	_assuan_sock_bind, _assuan_sock_get_nonce,
    	_assuan_sock_check_nonce): Add context argument.
    	(_assuan_io_read, _assuan_io_write, _assuan_simple_sendmsg,
    	_assuan_simple_recvmsg): Removed.
    
    	* context.c (assuan_ctx_set_system_hooks): New function.
    	* assuan.c (assuan_set_system_hooks): New function.
    	(assuan_new_ext): Initialize CTX->system.
    	(assuan_release): Always output trace message.
    
    	* assuan-error.c (_assuan_error_is_eagain): Add ctx argument, pass
    	along to _assuan_usleep.
    	* assuan-inquire.c assuan-listen.c, assuan-socket-server.c,
    	assuan-handler.c, assuan-socket-connect.c, assuan-client.c,
    	assuan-pipe-connect.c, assuan-socket.c: Pass CTX argument to
    	functions that need it
    	(_assuan_sock_new, _assuan_sock_check_none, _assuan_close,
    	_assuan_error_is_eagain and many more).
    	* assuan-socket-server.c (assuan_init_socket_server_ext): Update
    	fields in CTX->engine instead of CTX->io.
    	* assuan-socket-connect (assuan_socket_connect_ext): Likewise.
    	* assuan-uds.c (uds_reader, uds_writer, uds_sendfd): Use
    	_assuan_recvmsg and _assuan_sendmsg instead of
    	_assuan_simple_recvmsg and _assuan_simple_sendmsg respectively.
    	(_assuan_init_uds_io): Update fields in CTX->engine instead of
    	CTX->io.
    	* assuan-buffer.c: Use functions in CTX->engine instead of CTX->io.
    	* assuan-pipe-server.c (assuan_init_pipe_server): Update
    	fields in CTX->engine instead of CTX->io.
    
    	* system.c: Include <sys/types.h>, <time.h>, <fcntl.h>, and
    	<windows.h> resp. <sys/wait.h>.  Define MAX_OPEN_FDS.
    	(_assuan_system_hooks_copy, __assuan_usleep, _assuan_usleep,
    	__assuan_pipe, _assuan_pipe, __assuan_close, _assuan_close,
    	__assuan_read, _assuan_read, __assuan_write, _assuan_write,
    	__assuan_recvmsg, _assuan_recvmsg, __assuan_sendmsg,
    	_assuan_sendmsg, __assuan_spawn, _assuan_spawn, __assuan_waitpid,
    	_assuan_waitpid, __assuan_socketpair, _assuan_socketpair): New
    	functions.
    	(_assuan_system_hooks): New singleton.
    	* assuan-io.c (_assuan_waitpid, do_io_read, _assuan_io_read,
    	do_io_write, _assuan_io_write, _assuan_simple_sendmsg,
    	_assuan_simple_recvmsg, _assuan_usleep): Removed.
    
    	* assuan-pipe-connect (writen, build_w32_commandline,
    	create_inheritable_pipe): Removed (actually moved to system.c).
    	(fix_signals) [_ASSUAN_NO_FIXED_SIGNALS]: Still fix signals.
    	(do_finish): Move waitpid logic to _assuan_waitpid, just call
    	that.
    	(struct at_pipe_fork, struct at_socketpair_fork): New types.
    	(at_pipe_fork_cb, at_socketpair_fork_cb): New callback functions.
    	(pipe_connect_unix, pipe_connect_w32): Replaced by ...
    	(pipe_connect): ... this new function using new system functions.
    	(socketpair_connect): Reimplement to use new system functions.
    	(assuan_pipe_connect, assuan_pipe_connect_ext): Add trace message.
    
    	* assuan-socket.c (_assuan_close): Removed (moved to system.c).
    	(_assuan_sock_new, _assuan_sock_connect, _assuan_sock_bind,
    	_assuan_sock_get_nonce, _assuan_sock_check_nonce): Add context
    	argument.  Use new system interface.
    	(sock_ctx): New singleton.
    	(assuan_sock_init, assuan_sock_deinit): New functions to
    	initialize and deinitialize the singleton.
---
 ChangeLog                   |   9 +
 NEWS                        |  18 +-
 autogen.sh                  |   1 -
 configure.ac                |  23 +-
 doc/ChangeLog               |   5 +
 doc/assuan.texi             |  39 +--
 src/ChangeLog               | 114 +++++++
 src/Makefile.am             |  16 +-
 src/assuan-buffer.c         |  14 +-
 src/assuan-client.c         |   2 +-
 src/assuan-defs.h           |  96 +++---
 src/assuan-error.c          |   6 +-
 src/assuan-handler.c        |   8 +-
 src/assuan-inquire.c        |   2 +-
 src/assuan-io-pth.c         | 170 ----------
 src/assuan-io.c             | 174 +---------
 src/assuan-listen.c         |   4 +-
 src/assuan-pipe-connect.c   | 779 ++++++++++--------------------------------
 src/assuan-pipe-server.c    |   8 +-
 src/assuan-socket-connect.c |  17 +-
 src/assuan-socket-server.c  |  15 +-
 src/assuan-socket.c         | 103 +++---
 src/assuan-uds.c            |  17 +-
 src/assuan.c                |  26 +-
 src/assuan.h                | 207 ++++++++++--
 src/context.c               |  64 +++-
 src/conversion.c            |   5 +-
 src/debug.h                 |  12 +-
 src/libassuan-config.in     |  27 +-
 src/libassuan.def           |   9 +
 src/libassuan.m4            |  42 ---
 src/libassuan.vers          |   8 +
 src/system.c                | 805 ++++++++++++++++++++++++++++++++++++++++++++
 33 files changed, 1599 insertions(+), 1246 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index dbf7b47..7253adc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2009-10-16  Marcus Brinkmann  <marcus at g10code.de>
+
+	* autogen.sh: Remove --with-pth-prefix from configure invocation.
+	* configure.ac (_ASSUAN_IN_LIBASSUAN, PTH_SYSCALL_SOFT): Do not
+	set anymore.
+	(GNUPG_PATH_PTH): Don't invoke.
+	(HAVE_PTH): Remove conditional.
+	(LIBASSUAN_CONFIG_THREAD_MODULES): Removed.
+
 2009-10-08  Marcus Brinkmann  <marcus at g10code.de>
 
 	* configure.ac: AC_REPLACE_FUNCS for vasprintf.
diff --git a/NEWS b/NEWS
index 46042f2..32b79e8 100644
--- a/NEWS
+++ b/NEWS
@@ -13,7 +13,11 @@ Noteworthy changes in version 1.1.0 (unreleased)
    If you use assuan_pipe_connect or assuan_pipe_connect_ext with NAME
    of NULL, you have to provide a non-NULL ARGV argument and check
    that against "server" or "client" to determine which end you got
-   after fork().
+   after fork().  If you use the assuan sock interface, you must call
+   assuan_sock_init after setting global context defaults.
+
+ * Pth support has changed.  This now follows the same style as
+   libgcrypt by setting system hook callbacks.
 
  * Interface changes relative to the 1.0.5 release:
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -51,6 +55,18 @@ assuan_set_io_hooks	       REMOVED: Will come back in expanded form.
 assuan_io_hooks_t  	       REMOVED: Will come back in expanded form.
 assuan_io_monitor_t	       CHANGED: Add a hook data argument.
 assuan_get_command_name        NEW
+assuan_msghdr_t		       NEW
+ASSUAN_INVALID_PID	       NEW
+ASSUAN_NO_FIXSIGNALS           NEW
+ASSUAN_SYSTEM_HOOKS_VERSION    NEW
+assuan_system_hooks_t          NEW
+assuan_set_system_hooks        NEW
+assuan_ctx_set_system_hooks    NEW
+ASSUAN_SYSTEM_PTH_IMPL         NEW
+ASSUAN_SYSTEM_PTH_DECL         NEW
+ASSUAN_SYSTEM_PTH              NEW
+assuan_sock_init               NEW
+assuan_sock_deinit             NEW
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 
diff --git a/autogen.sh b/autogen.sh
index 1b837c6..5300c6f 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -77,7 +77,6 @@ if test "$1" = "--build-w32"; then
 
     ./configure --enable-maintainer-mode  --prefix=${w32root}  \
             --host=${host} --build=${build} \
-            --with-pth-prefix=${w32root} \
             --disable-shared    
 
     exit $?
diff --git a/configure.ac b/configure.ac
index dce02ad..b6353eb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
 # configure.ac - for libassuan
-# Copyright (C) 2001, 2002, 2003, 2006, 2007 Free Software Foundation, Inc.
+# Copyright (C) 2001-2003, 2006, 2007, 2009 Free Software Foundation, Inc.
 # 
 # This file is part of Assuan.
 #
@@ -132,16 +132,6 @@ if test "$GCC" = yes; then
 fi
 
 
-AH_BOTTOM([
-#define _ASSUAN_IN_LIBASSUAN 1
-
-/* We explicitly need to disable PTH's soft mapping as Debian
-   currently enables it by default for no reason. */
-#define PTH_SYSCALL_SOFT 0
-
-])
-
-
 # 
 # Options depending on the host OS.
 # 
@@ -191,12 +181,6 @@ AC_SUBST(BUILD_TIMESTAMP)
 AC_SUBST(BUILD_FILEVERSION)
 AM_CONDITIONAL(HAVE_W32_SYSTEM, test "$have_w32_system" = yes)
 
-#
-# See whether we can build a Pth enabled version
-#
-GNUPG_PATH_PTH
-AM_CONDITIONAL(HAVE_PTH, test "$have_pth" = "yes")
-
 
 # Check for network libraries.  They are needed for tests.
 AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt,
@@ -211,10 +195,6 @@ fi
 # For src/libassuan-config.in
 LIBASSUAN_CONFIG_LIB="-lassuan"
 LIBASSUAN_CONFIG_CFLAGS=""
-LIBASSUAN_CONFIG_THREAD_MODULES=
-if test "$have_pth" = yes; then
-LIBASSUAN_CONFIG_THREAD_MODULES="pth"
-fi
 LIBASSUAN_CONFIG_EXTRA_LIBS=
 if test x"$NETLIBS" != x; then
   LIBASSUAN_CONFIG_EXTRA_LIBS="$LIBASSUAN_CONFIG_EXTRA_LIBS $NETLIBS"
@@ -222,7 +202,6 @@ fi
 AC_SUBST(LIBASSUAN_CONFIG_LIB)
 AC_SUBST(LIBASSUAN_CONFIG_CFLAGS)
 AC_SUBST(LIBASSUAN_CONFIG_API_VERSION)
-AC_SUBST(LIBASSUAN_CONFIG_THREAD_MODULES)
 AC_SUBST(LIBASSUAN_CONFIG_EXTRA_LIBS)
 
 # Checks for header files.
diff --git a/doc/ChangeLog b/doc/ChangeLog
index c567640..6106e35 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,8 @@
+2009-10-16  Marcus Brinkmann  <marcus at g10code.com>
+
+	* assuan.texi: Remove documentation for thread support.
+	(assuan_pipe_connect_ext): Update prototype.
+
 2009-10-14  Werner Koch  <wk at g10code.com>
 
 	* assuan.texi (Utilities): Describe assuan_get_command_name.
diff --git a/doc/assuan.texi b/doc/assuan.texi
index adfc86d..5641aa0 100644
--- a/doc/assuan.texi
+++ b/doc/assuan.texi
@@ -465,10 +465,6 @@ specifying both options to @command{libassuan-config}:
 gcc -o foo foo.c $(libassuan-config --cflags --libs)
 @end example
 
-If your application uses Pth or pthread, you need to pass the option
- at option{--thread=pth} respective @option{--thread=pthread} to the
-invocation of @command{libassuan-config}.
-
 
 @node Automake
 @section Building sources using Automake
@@ -498,36 +494,27 @@ AM_CPPFLAGS = $(LIBASSUAN_CFLAGS)
 LDADD = $(LIBASSUAN_LIBS)
 @end example
 
- at defmac AM_PATH_LIBASSUAN_PTH (@ovar{minimum-version}, @ovar{action-if-found}, @ovar{action-if-not-found})
-Same as @code{AM_PATH_LIBASSUAN} but checks for the GNU Pth enabled
-version of the library and defines @code{LIBASSUAN_PTH_CFLAGS}
- at code{LIBASSUAN_PTH_LIBS} instead.  Use this is you are using GNU Pth.
-Note that you also need to pass the appropriate options for Pth to the
-compiler and linker.
- at end defmac
-
- at defmac AM_PATH_LIBASSUAN_PTHREAD (@ovar{minimum-version}, @ovar{action-if-found}, @ovar{action-if-not-found})
-Same as @code{AM_PATH_LIBASSUAN} but checks for the pthreads enabled
-version of the library and defines @code{LIBASSUAN_PTHREAD_CFLAGS}
- at code{LIBASSUAN_PTHREAD_LIBS} instead.  Use this is you are using GNU Pth.
-Note that you also need to pass the appropriate options for Pth to the
-compiler and linker.
- at end defmac
-
-
 
 @node Multi Threading
 @section Multi Threading
 
-The @code{libassuan} library is thread-safe if you adhere to the following
-requirements:
+The @code{libassuan} library is designed so that it can be used in a
+threaded application, if some rules are followed.
 
 @itemize @bullet
 @item Run the initialization functions before you actually start
-to use threads.
+to use threads.  Specifically, the functions
+ at code{assuan_set_gpg_err_source}, @code{assuan_set_malloc_hooks} and
+ at code{assuan_set_log_cb} should not be called concurrently with
+ at code{assuan_new}.  Use @code{assuan_new_ext} instead or ensure proper
+serialization.
 @item Only one thread at a time may access an @code{libassuan} context.
 @item If you use the default log handler, use
 @code{assuan_set_assuan_log_stream} to setup a default log stream.
+ at item If you have callback functions shared by multiple functions,
+the callback function must be reentrant for that purpose.
+ at code{libassuan} does not serialize invocation of callback functions
+across contexts.
 @end itemize
 
 
@@ -950,12 +937,12 @@ If the peer is not a simple pipe server but one using full-duplex
 sockets, the full-fledged variant of the above function should be
 used:
 
- at deftypefun gpg_error_t assuan_pipe_connect_ext (@w{assuan_context_t *@var{ctx}}, at w{const char *@var{name}}, @w{const char *@var{argv}[]}, @w{int *@var{fd_child_list}}, @w{void (*@var{atfork}) (void *, int)}, @w{void *@var{atforkvalue}}, @w{unsigned int @var{flags}})
+ at deftypefun gpg_error_t assuan_pipe_connect_ext (@w{assuan_context_t *@var{ctx}}, at w{const char *@var{name}}, @w{const char *@var{argv}[]}, @w{assuan_fd_t *@var{fd_child_list}}, @w{void (*@var{atfork}) (void *, int)}, @w{void *@var{atforkvalue}}, @w{unsigned int @var{flags}})
 
 A call to this functions forks the current process and executes the
 program @var{name}, passing the arguments given in the NULL-terminated
 list @var{argv}.  A list of file descriptors not to be closed may be
-given using the @code{-1} terminated array @var{fd_child_list}.
+given using the @code{ASSUAN_INVLID_FD} terminated array @var{fd_child_list}.
 
 If @var{name} is a null pointer, only a fork but no exec is done.
 Thus the child continues to run.  However all file descriptors are
diff --git a/src/ChangeLog b/src/ChangeLog
index c9f2172..0d22b02 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,105 @@
+2009-10-16  Marcus Brinkmann  <marcus at g10code.com>
+
+	* conversion.c: Do not include <sys/types.h> and <time.h>.
+	* debug.h (TRACE_BEG6, TRACE4): New macros.
+	(TRACE_SYSERR): Pass _assuan_trace_context to _assuan_debug.
+	* context.c (assuan_set_pointer, assuan_get_pointer,
+	assuan_set_flag, assuan_get_flag, assuan_set_io_monitor,
+	assuan_set_error): Add trace messages.
+
+	* libassuan-config.in, libassuan.m4, Makefile.am: Remove PTH support.
+	* assuan.h (assuan_msghdr_t): New type.
+	(ASSUAN_INVALID_PID): New macro.
+	(ASSUAN_NO_FIXSIGNALS): New flag macro.
+	(ASSUAN_SYSTEM_HOOKS_VERSION): New macro.
+	(struct assuan_system_hooks, assuan_system_hooks_t): New types.
+	(assuan_pipe_connect, assuan_pipe_connect_ext): Don't make ARGV
+	const for name==NULL operation.  Make fd_child_list an array of
+	assuan_fd_t.
+	(assuan_sock_init, assuan_sock_deinit, assuan_set_system_hooks,
+	assuan_ctx_set_system_hooks, __assuan_pipe, __assuan_close,
+	__assuan_spawn, __assuan_socketpair): New function prototypes.
+	(_ASSUAN_SYSTEM_PTH_IMPL, ASSUAN_SYSTEM_PTH_DECL,
+	ASSUAN_SYSTEM_PTH): New macros.
+	(_assuan_system_pth): New declaration.
+	* libassuan.vers, libassuan.defs: Add assuan_sock_init,
+	assuan_sock_deinit, __assuan_pipe, __assuan_close, __assuan_spawn,
+	__assuan_socketpair, assuan_set_system_hooks,
+	assuan_ctx_set_system_hooks.
+
+	* assuan-defs.h (struct assuan_io): Removed, move members to ...
+	(struct assuan_context_s): ... this to ENGINE.  New flag
+	no_fixsignals.  New member SYSTEM.  Remove member IO.
+	(_assuan_pipe, _assuan_read, _assuan_write, _assuan_recvmsg,
+	_assuan_sendmsg, _assuan_spawn, _assuan_socketpair,
+	_assuan_system_hooks, _assuan_system_hooks_copy): New
+	declarations.
+	(_assuan_error_is_eagain, _assuan_waitpid, _assuan_usleep,
+	_assuan_close, _assuan_sock_new, _assuan_sock_connect,
+	_assuan_sock_bind, _assuan_sock_get_nonce,
+	_assuan_sock_check_nonce): Add context argument.
+	(_assuan_io_read, _assuan_io_write, _assuan_simple_sendmsg,
+	_assuan_simple_recvmsg): Removed.
+
+	* context.c (assuan_ctx_set_system_hooks): New function.
+	* assuan.c (assuan_set_system_hooks): New function.
+	(assuan_new_ext): Initialize CTX->system.
+	(assuan_release): Always output trace message.
+	
+	* assuan-error.c (_assuan_error_is_eagain): Add ctx argument, pass
+	along to _assuan_usleep.
+	* assuan-inquire.c assuan-listen.c, assuan-socket-server.c,
+	assuan-handler.c, assuan-socket-connect.c, assuan-client.c,
+	assuan-pipe-connect.c, assuan-socket.c: Pass CTX argument to
+	functions that need it
+	(_assuan_sock_new, _assuan_sock_check_none, _assuan_close,
+	_assuan_error_is_eagain and many more).
+	* assuan-socket-server.c (assuan_init_socket_server_ext): Update
+	fields in CTX->engine instead of CTX->io.
+	* assuan-socket-connect (assuan_socket_connect_ext): Likewise.
+	* assuan-uds.c (uds_reader, uds_writer, uds_sendfd): Use
+	_assuan_recvmsg and _assuan_sendmsg instead of
+	_assuan_simple_recvmsg and _assuan_simple_sendmsg respectively.
+	(_assuan_init_uds_io): Update fields in CTX->engine instead of
+	CTX->io.
+	* assuan-buffer.c: Use functions in CTX->engine instead of CTX->io.
+	* assuan-pipe-server.c (assuan_init_pipe_server): Update
+	fields in CTX->engine instead of CTX->io.
+
+	* system.c: Include <sys/types.h>, <time.h>, <fcntl.h>, and
+	<windows.h> resp. <sys/wait.h>.  Define MAX_OPEN_FDS.
+	(_assuan_system_hooks_copy, __assuan_usleep, _assuan_usleep,
+	__assuan_pipe, _assuan_pipe, __assuan_close, _assuan_close,
+	__assuan_read, _assuan_read, __assuan_write, _assuan_write,
+	__assuan_recvmsg, _assuan_recvmsg, __assuan_sendmsg,
+	_assuan_sendmsg, __assuan_spawn, _assuan_spawn, __assuan_waitpid,
+	_assuan_waitpid, __assuan_socketpair, _assuan_socketpair): New
+	functions.
+	(_assuan_system_hooks): New singleton.
+	* assuan-io.c (_assuan_waitpid, do_io_read, _assuan_io_read,
+	do_io_write, _assuan_io_write, _assuan_simple_sendmsg,
+	_assuan_simple_recvmsg, _assuan_usleep): Removed.
+
+	* assuan-pipe-connect (writen, build_w32_commandline,
+	create_inheritable_pipe): Removed (actually moved to system.c).
+	(fix_signals) [_ASSUAN_NO_FIXED_SIGNALS]: Still fix signals.
+	(do_finish): Move waitpid logic to _assuan_waitpid, just call
+	that.
+	(struct at_pipe_fork, struct at_socketpair_fork): New types.
+	(at_pipe_fork_cb, at_socketpair_fork_cb): New callback functions.
+	(pipe_connect_unix, pipe_connect_w32): Replaced by ...
+	(pipe_connect): ... this new function using new system functions.
+	(socketpair_connect): Reimplement to use new system functions.
+	(assuan_pipe_connect, assuan_pipe_connect_ext): Add trace message.
+
+	* assuan-socket.c (_assuan_close): Removed (moved to system.c).
+	(_assuan_sock_new, _assuan_sock_connect, _assuan_sock_bind,
+	_assuan_sock_get_nonce, _assuan_sock_check_nonce): Add context
+	argument.  Use new system interface.
+	(sock_ctx): New singleton.
+	(assuan_sock_init, assuan_sock_deinit): New functions to
+	initialize and deinitialize the singleton.
+		
 2009-10-14  Werner Koch  <wk at g10code.com>
 
 	* assuan-defs.h (assuan_context_s): Add field CURRENT_CMD_NAME.
@@ -7,6 +109,18 @@
 
 2009-10-08  Marcus Brinkmann  <marcus at g10code.de>
 
+	* Makefile.am (libassuan_pth): Removed.
+	(lib_LTLIBRARIES): Remove $(libassuan_pth).
+	(libassuan_pth_la_SOURCES, libassuan_pth_la_CPPFLAGS)
+	(libassuan_pth_la_CFLAGS, libassuan_pth_la_LIBADD): Removed.
+	* libassuan.m4 (AM_PATH_LIBASSUAN_PTH, AM_PATH_LIBASSUAN_PTHREAD):
+	Removed.
+	* assuan-io-pth.c: Removed.
+	* libassuan-config.in (all_thread_modules): Removed.  Also removed
+	option --thread.
+
+2009-10-08  Marcus Brinkmann  <marcus at g10code.de>
+
 	* assuan.h (assuan_get_assuan_log_stream,
 	assuan_set_assuan_log_stream): Remove prototypes.
 	* libassuan.def: Remove assuan_get_assuan_log_stream,
diff --git a/src/Makefile.am b/src/Makefile.am
index 1e1c46b..bfbcfec 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,16 +21,10 @@ EXTRA_DIST = libassuan-config.in libassuan.m4 libassuan.vers \
              versioninfo.rc.in libassuan.def
 INCLUDES = -I.. -I$(top_srcdir)/include
 
-if HAVE_PTH
-libassuan_pth = libassuan-pth.la
-else
-libassuan_pth = 
-endif
-
 bin_SCRIPTS = libassuan-config
 m4datadir = $(datadir)/aclocal
 m4data_DATA = libassuan.m4
-lib_LTLIBRARIES = libassuan.la $(libassuan_pth)
+lib_LTLIBRARIES = libassuan.la
 include_HEADERS = assuan.h
 
 if HAVE_LD_VERSION_SCRIPT
@@ -107,11 +101,3 @@ libassuan_la_LDFLAGS = $(libassuan_res_ldflag) $(no_undefined) \
 libassuan_la_DEPENDENCIES = @LTLIBOBJS@ \
 	$(srcdir)/libassuan.vers $(libassuan_deps)
 libassuan_la_LIBADD = @LTLIBOBJS@ @NETLIBS@ @GPG_ERROR_LIBS@
-
-if HAVE_PTH
-libassuan_pth_la_SOURCES = $(common_sources) assuan-io-pth.c
-libassuan_pth_la_CPPFLAGS = $(AM_CPPFLAGS) @GPG_ERROR_CFLAGS@ @PTH_CFLAGS@
-libassuan_pth_la_CFLAGS = $(AM_CFLAGS) @GPG_ERROR_CFLAGS@ $(PTH_CFLAGS)
-libassuan_pth_la_LIBADD = @LTLIBOBJS@ @NETLIBS@ @GPG_ERROR_LIBS@ @PTH_LIBS@
-endif
-
diff --git a/src/assuan-buffer.c b/src/assuan-buffer.c
index 583d137..32a9aee 100644
--- a/src/assuan-buffer.c
+++ b/src/assuan-buffer.c
@@ -37,7 +37,7 @@ writen (assuan_context_t ctx, const char *buffer, size_t length)
 {
   while (length)
     {
-      ssize_t nwritten = ctx->io->writefnc (ctx, buffer, length);
+      ssize_t nwritten = ctx->engine.writefnc (ctx, buffer, length);
       
       if (nwritten < 0)
         {
@@ -66,7 +66,7 @@ readline (assuan_context_t ctx, char *buf, size_t buflen,
   *r_nread = 0;
   while (nleft > 0)
     {
-      ssize_t n = ctx->io->readfnc (ctx, buf, nleft);
+      ssize_t n = ctx->engine.readfnc (ctx, buf, nleft);
 
       if (n < 0)
         {
@@ -249,7 +249,7 @@ assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen)
     {
       err = _assuan_read_line (ctx);
     }
-  while (_assuan_error_is_eagain (err));
+  while (_assuan_error_is_eagain (ctx, err));
 
   *line = ctx->inbound.line;
   *linelen = ctx->inbound.linelen;
@@ -551,19 +551,19 @@ assuan_sendfd (assuan_context_t ctx, assuan_fd_t fd)
   return _assuan_error (ctx, GPG_ERR_NOT_IMPLEMENTED);
 #endif
 
-  if (! ctx->io->sendfd)
+  if (! ctx->engine.sendfd)
     return set_error (ctx, GPG_ERR_NOT_IMPLEMENTED,
 		      "server does not support sending and receiving "
 		      "of file descriptors");
-  return ctx->io->sendfd (ctx, fd);
+  return ctx->engine.sendfd (ctx, fd);
 }
 
 gpg_error_t
 assuan_receivefd (assuan_context_t ctx, assuan_fd_t *fd)
 {
-  if (! ctx->io->receivefd)
+  if (! ctx->engine.receivefd)
     return set_error (ctx, GPG_ERR_NOT_IMPLEMENTED,
 		      "server does not support sending and receiving "
 		      "of file descriptors");
-  return ctx->io->receivefd (ctx, fd);
+  return ctx->engine.receivefd (ctx, fd);
 }
diff --git a/src/assuan-client.c b/src/assuan-client.c
index aa74f81..1f860b8 100644
--- a/src/assuan-client.c
+++ b/src/assuan-client.c
@@ -49,7 +49,7 @@ _assuan_read_from_server (assuan_context_t ctx, int *okay, int *off)
 	{
 	  rc = _assuan_read_line (ctx);
 	}
-      while (_assuan_error_is_eagain (rc));
+      while (_assuan_error_is_eagain (ctx, rc));
       if (rc)
         return rc;
       line = ctx->inbound.line;
diff --git a/src/assuan-defs.h b/src/assuan-defs.h
index 95706d6..38f51ed 100644
--- a/src/assuan-defs.h
+++ b/src/assuan-defs.h
@@ -56,19 +56,6 @@ struct cmdtbl_s
 };
 
 
-/* A structure to dispatch I/O functions.  */
-struct assuan_io
-{
-  /* Routine to read from input_fd.  Sets errno on failure.  */
-  ssize_t (*readfnc) (assuan_context_t, void *, size_t);
-  /* Routine to write to output_fd.  Sets errno on failure.  */
-  ssize_t (*writefnc) (assuan_context_t, const void *, size_t);
-  /* Send a file descriptor.  */
-  gpg_error_t (*sendfd) (assuan_context_t, assuan_fd_t);
-  /* Receive a file descriptor.  */
-  gpg_error_t (*receivefd) (assuan_context_t, assuan_fd_t *);
-};
-
 

 /* The context we use with most functions. */
 struct assuan_context_s
@@ -97,17 +84,30 @@ struct assuan_context_s
   {
     unsigned int no_waitpid : 1;
     unsigned int confidential : 1;
+    unsigned int no_fixsignals : 1;
   } flags;
 
   /* If set, this is called right before logging an I/O line.  */
   assuan_io_monitor_t io_monitor;
   void *io_monitor_data;
 
+  /* Callback handlers replacing system I/O functions.  */
+  struct assuan_system_hooks system;
+
   /* Now come the members specific to subsystems or engines.  FIXME:
      This is not developed yet.  See below for the legacy members.  */
   struct
   {
     void (*release) (assuan_context_t ctx);
+
+    /* Routine to read from input_fd.  Sets errno on failure.  */
+    ssize_t (*readfnc) (assuan_context_t, void *, size_t);
+    /* Routine to write to output_fd.  Sets errno on failure.  */
+    ssize_t (*writefnc) (assuan_context_t, const void *, size_t);
+    /* Send a file descriptor.  */
+    gpg_error_t (*sendfd) (assuan_context_t, assuan_fd_t);
+    /* Receive a file descriptor.  */
+    gpg_error_t (*receivefd) (assuan_context_t, assuan_fd_t *);
   } engine;
 
 
@@ -220,11 +220,6 @@ struct assuan_context_s
 
   assuan_fd_t input_fd;   /* Set by the INPUT command.  */
   assuan_fd_t output_fd;  /* Set by the OUTPUT command.  */
-
-  /* io routines.  */
-  struct assuan_io *io;
-
-
 };
 
 

@@ -242,6 +237,38 @@ void *_assuan_realloc (assuan_context_t ctx, void *ptr, size_t cnt);
 void *_assuan_calloc (assuan_context_t ctx, size_t cnt, size_t elsize);
 void _assuan_free (assuan_context_t ctx, void *ptr);
 
+/* System hooks.  */
+void _assuan_usleep (assuan_context_t ctx, unsigned int usec);
+int _assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx);
+int _assuan_close (assuan_context_t ctx, assuan_fd_t fd);
+ssize_t _assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer,
+		      size_t size);
+ssize_t _assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
+		       size_t size);
+int _assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd,
+		     assuan_msghdr_t msg, int flags);
+int _assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd,
+		     assuan_msghdr_t msg, int flags);
+int _assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
+		   const char *argv[],
+		   assuan_fd_t fd_in, assuan_fd_t fd_out,
+		   assuan_fd_t *fd_child_list,
+		   void (*atfork) (void *opaque, int reserved),
+		   void *atforkvalue, unsigned int flags);
+pid_t  _assuan_waitpid (assuan_context_t ctx, pid_t pid, int nowait,
+			int *status, int options);
+int _assuan_socketpair (assuan_context_t ctx, int namespace, int style,
+			int protocol, int filedes[2]);
+
+extern struct assuan_system_hooks _assuan_system_hooks;
+
+/* Copy the system hooks struct, paying attention to version
+   differences.  SRC is usually from the user, DST MUST be from the
+   library.  */
+void
+_assuan_system_hooks_copy (assuan_system_hooks_t dst,
+			   assuan_system_hooks_t src);
+
 

 /*-- assuan-pipe-server.c --*/
 void _assuan_release_context (assuan_context_t ctx);
@@ -273,7 +300,7 @@ gpg_error_t _assuan_inquire_ext_cb (assuan_context_t ctx);
 void _assuan_inquire_release (assuan_context_t ctx);
 
 /* Check if ERR means EAGAIN.  */
-int _assuan_error_is_eagain (gpg_error_t err);
+int _assuan_error_is_eagain (assuan_context_t ctx, gpg_error_t err);
 
 
 
@@ -290,33 +317,22 @@ void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length);
 
 
 /*-- assuan-io.c --*/
-pid_t _assuan_waitpid (pid_t pid, int *status, int options);
-
 ssize_t _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size);
 ssize_t _assuan_simple_write (assuan_context_t ctx, const void *buffer,
 			      size_t size);
-ssize_t _assuan_io_read (assuan_fd_t fd, void *buffer, size_t size);
-ssize_t _assuan_io_write (assuan_fd_t fd, const void *buffer, size_t size);
-#ifdef HAVE_W32_SYSTEM
-int _assuan_simple_sendmsg (assuan_context_t ctx, void *msg);
-int _assuan_simple_recvmsg (assuan_context_t ctx, void *msg);
-#else
-ssize_t _assuan_simple_sendmsg (assuan_context_t ctx, struct msghdr *msg);
-ssize_t _assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg);
-#endif
-
-void _assuan_usleep (unsigned int usec);
-
 
 /*-- assuan-socket.c --*/
-int _assuan_close (assuan_fd_t fd);
-assuan_fd_t _assuan_sock_new (int domain, int type, int proto);
-int _assuan_sock_connect (assuan_fd_t sockfd,
+
+assuan_fd_t _assuan_sock_new (assuan_context_t ctx, int domain, int type,
+			      int proto);
+int _assuan_sock_connect (assuan_context_t ctx, assuan_fd_t sockfd,
                           struct sockaddr *addr, int addrlen);
-int _assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen);
-int _assuan_sock_get_nonce (struct sockaddr *addr, int addrlen, 
-                            assuan_sock_nonce_t *nonce);
-int _assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce);
+int _assuan_sock_bind (assuan_context_t ctx, assuan_fd_t sockfd,
+		       struct sockaddr *addr, int addrlen);
+int _assuan_sock_get_nonce (assuan_context_t ctx, struct sockaddr *addr,
+			    int addrlen, assuan_sock_nonce_t *nonce);
+int _assuan_sock_check_nonce (assuan_context_t ctx, assuan_fd_t fd,
+			      assuan_sock_nonce_t *nonce);
 #ifdef HAVE_W32_SYSTEM
 int _assuan_sock_wsa2errno (int err);
 #endif
diff --git a/src/assuan-error.c b/src/assuan-error.c
index 60cb0d3..c45ca67 100644
--- a/src/assuan-error.c
+++ b/src/assuan-error.c
@@ -33,13 +33,13 @@
 /* A small helper function to treat EAGAIN transparently to the
    caller.  */
 int
-_assuan_error_is_eagain (gpg_error_t err)
+_assuan_error_is_eagain (assuan_context_t ctx, gpg_error_t err)
 {
   if (gpg_err_code (err) == GPG_ERR_EAGAIN)
     {
       /* Avoid spinning by sleeping for one tenth of a second.  */
-       _assuan_usleep (100000);
-       return 1;
+      _assuan_usleep (ctx, 100000);
+      return 1;
     }
   else
     return 0;
diff --git a/src/assuan-handler.c b/src/assuan-handler.c
index fd41719..7291acd 100644
--- a/src/assuan-handler.c
+++ b/src/assuan-handler.c
@@ -219,6 +219,7 @@ std_handler_input (assuan_context_t ctx, char *line)
   return PROCESS_DONE (ctx, 0);
 }
 
+
 /* Format is OUTPUT FD=<n> */
 static gpg_error_t
 std_handler_output (assuan_context_t ctx, char *line)
@@ -236,9 +237,6 @@ std_handler_output (assuan_context_t ctx, char *line)
 }
 
 
-
-  
-
 /* This is a table with the standard commands and handler for them.
    The table is used to initialize a new context and associate strings
    with default handlers */
@@ -592,7 +590,7 @@ process_next (assuan_context_t ctx)
      required to write full lines without blocking long after starting
      a partial line.  */
   rc = _assuan_read_line (ctx);
-  if (_assuan_error_is_eagain (rc))
+  if (_assuan_error_is_eagain (ctx, rc))
     return 0;
   if (rc)
     return rc;
@@ -670,7 +668,7 @@ process_request (assuan_context_t ctx)
     {
       rc = _assuan_read_line (ctx);
     }
-  while (_assuan_error_is_eagain (rc));
+  while (_assuan_error_is_eagain (ctx, rc));
   if (rc)
     return rc;
   if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
diff --git a/src/assuan-inquire.c b/src/assuan-inquire.c
index dba7cb1..8772a15 100644
--- a/src/assuan-inquire.c
+++ b/src/assuan-inquire.c
@@ -176,7 +176,7 @@ assuan_inquire (assuan_context_t ctx, const char *keyword,
         {
 	  do
 	    rc = _assuan_read_line (ctx);
-	  while (_assuan_error_is_eagain (rc));
+	  while (_assuan_error_is_eagain (ctx, rc));
           if (rc)
             goto leave;
           line = (unsigned char *) ctx->inbound.line;
diff --git a/src/assuan-io-pth.c b/src/assuan-io-pth.c
deleted file mode 100644
index 7e438e9..0000000
--- a/src/assuan-io-pth.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/* assuan-io-pth.c - Pth version of assua-io.c.
-   Copyright (C) 2002, 2004, 2006-2009 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <sys/time.h>
-#include <sys/types.h>
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#if HAVE_SYS_UIO_H
-# include <sys/uio.h>
-#endif
-#include <unistd.h>
-#include <errno.h>
-#ifdef HAVE_W32_SYSTEM
-# include <windows.h>
-#else
-# include <sys/wait.h>
-#endif
-#include <pth.h>
-
-#include "assuan-defs.h"
-
-
-
-#ifndef HAVE_W32_SYSTEM
-pid_t 
-_assuan_waitpid (pid_t pid, int *status, int options)
-{
-  return pth_waitpid (pid, status, options);
-}
-#endif
-
-
-ssize_t
-_assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size)
-{
-  /* Fixme: For W32 we should better not cast the HANDLE type to int.
-     However, this requires changes in w32pth too.  */
-  return _assuan_io_read (ctx->inbound.fd, buffer, size);
-}
-
-ssize_t
-_assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size)
-{
-  return _assuan_io_write (ctx->outbound.fd, buffer, size);
-}
-
-ssize_t
-_assuan_io_read (assuan_fd_t fd, void *buffer, size_t size)
-{
-  return pth_read ((int)fd, buffer, size);
-}
-
-ssize_t
-_assuan_io_write (assuan_fd_t fd, const void *buffer, size_t size)
-{
-  return pth_write ((int)fd, buffer, size);
-}
-
-
-#ifdef HAVE_W32_SYSTEM
-int
-_assuan_simple_sendmsg (assuan_context_t ctx, void *msg)
-#else
-ssize_t
-_assuan_simple_sendmsg (assuan_context_t ctx, struct msghdr *msg)
-#endif
-{
-#if defined(HAVE_W32_SYSTEM)
-  errno = ENOSYS;
-  return -1;
-#else
-  /* Pth does not provide a sendmsg function.  Thus we implement it here.  */
-  int ret;
-  int fd = ctx->outbound.fd;
-  int fdmode;
-
-  fdmode = pth_fdmode (fd, PTH_FDMODE_POLL);
-  if (fdmode == PTH_FDMODE_ERROR)
-    {
-      errno = EBADF;
-      return -1;
-    }
-  if (fdmode == PTH_FDMODE_BLOCK)
-    {
-      fd_set fds;
-
-      FD_ZERO (&fds);
-      FD_SET (fd, &fds);
-      while ( (ret = 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
-}
-
-#ifdef HAVE_W32_SYSTEM
-int
-_assuan_simple_recvmsg (assuan_context_t ctx, void *msg)
-#else
-ssize_t
-_assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg)
-#endif
-{
-#if defined(HAVE_W32_SYSTEM)
-  errno = ENOSYS;
-  return -1;
-#else
-  /* Pth does not provide a recvmsg function.  Thus we implement it here.  */
-  int ret;
-  int fd = ctx->inbound.fd;
-  int fdmode;
-
-  fdmode = pth_fdmode (fd, PTH_FDMODE_POLL);
-  if (fdmode == PTH_FDMODE_ERROR)
-    {
-      errno = EBADF;
-      return -1;
-    }
-  if (fdmode == PTH_FDMODE_BLOCK)
-    {
-      fd_set fds;
-
-      FD_ZERO (&fds);
-      FD_SET (fd, &fds);
-      while ( (ret = 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
-}
-
-
-void
-_assuan_usleep (unsigned int usec)
-{
-  pth_usleep (usec);
-}
diff --git a/src/assuan-io.c b/src/assuan-io.c
index 88accc3..c5bbc99 100644
--- a/src/assuan-io.c
+++ b/src/assuan-io.c
@@ -38,185 +38,15 @@
 #include "assuan-defs.h"
 
 
-#ifndef HAVE_W32_SYSTEM
-pid_t 
-_assuan_waitpid (pid_t pid, int *status, int options)
-{
-  return waitpid (pid, status, options);
-}
-#endif
-
-
-static ssize_t
-do_io_read (assuan_fd_t fd, void *buffer, size_t size)
-{
-#ifdef HAVE_W32_SYSTEM
-  /* Due to the peculiarities of the W32 API we can't use read for a
-     network socket and thus we try to use recv first and fallback to
-     read if recv detects that it is not a network socket.  */
-  int n;
-
-  n = recv (HANDLE2SOCKET(fd), buffer, size, 0);
-  if (n == -1)
-    {
-      switch (WSAGetLastError ())
-        {
-        case WSAENOTSOCK:
-          {
-            DWORD nread = 0;
-            
-            n = ReadFile (fd, buffer, size, &nread, NULL);
-            if (!n)
-              {
-                switch (GetLastError())
-                  {
-                  case ERROR_BROKEN_PIPE: errno = EPIPE; break;
-                  default: errno = EIO; 
-                  }
-                n = -1;
-              }
-            else
-              n = (int)nread;
-          }
-          break;
-          
-        case WSAEWOULDBLOCK: errno = EAGAIN; break;
-        case ERROR_BROKEN_PIPE: errno = EPIPE; break;
-        default: errno = EIO; break;
-        }
-    }
-  return n;
-#else /*!HAVE_W32_SYSTEM*/
-  return read (fd, buffer, size);
-#endif /*!HAVE_W32_SYSTEM*/
-}
-
-
-ssize_t
-_assuan_io_read (assuan_fd_t fd, void *buffer, size_t size)
-{
-  return do_io_read (fd, buffer, size);
-}
-
 ssize_t
 _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size)
 {
-  return do_io_read (ctx->inbound.fd, buffer, size);
+  return _assuan_read (ctx, ctx->inbound.fd, buffer, size);
 }
 
 
-
-static ssize_t
-do_io_write (assuan_fd_t fd, const void *buffer, size_t size)
-{
-#ifdef HAVE_W32_SYSTEM
-  /* Due to the peculiarities of the W32 API we can't use write for a
-     network socket and thus we try to use send first and fallback to
-     write if send detects that it is not a network socket.  */
-  int n;
-
-  n = send (HANDLE2SOCKET(fd), buffer, size, 0);
-  if (n == -1 && WSAGetLastError () == WSAENOTSOCK)
-    {
-      DWORD nwrite;
-
-      n = WriteFile (fd, buffer, size, &nwrite, NULL);
-      if (!n)
-        {
-          switch (GetLastError ())
-            {
-            case ERROR_BROKEN_PIPE: 
-            case ERROR_NO_DATA: errno = EPIPE; break;
-            default:            errno = EIO;   break;
-            }
-          n = -1;
-        }
-      else
-        n = (int)nwrite;
-    }
-  return n;
-#else /*!HAVE_W32_SYSTEM*/
-  return write (fd, buffer, size);
-#endif /*!HAVE_W32_SYSTEM*/
-}
-
-ssize_t
-_assuan_io_write (assuan_fd_t fd, const void *buffer, size_t size)
-{
-  return do_io_write (fd, buffer, size);
-}
-
 ssize_t
 _assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size)
 {
-  return do_io_write (ctx->outbound.fd, buffer, size);
+  return _assuan_write (ctx, ctx->outbound.fd, buffer, size);
 }
-
-
-#ifdef HAVE_W32_SYSTEM
-int
-_assuan_simple_sendmsg (assuan_context_t ctx, void *msg)
-#else
-ssize_t
-_assuan_simple_sendmsg (assuan_context_t ctx, struct msghdr *msg)
-#endif
-{
-#ifdef HAVE_W32_SYSTEM
-  errno = ENOSYS;
-  return -1;
-#else
-  int ret;
-  while ( (ret = sendmsg (ctx->outbound.fd, msg, 0)) == -1 && errno == EINTR)
-    ;
-  return ret;
-#endif
-}
-
-
-#ifdef HAVE_W32_SYSTEM
-int
-_assuan_simple_recvmsg (assuan_context_t ctx, void *msg)
-#else
-ssize_t
-_assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg)
-#endif
-{
-#ifdef HAVE_W32_SYSTEM
-  errno = ENOSYS;
-  return -1;
-#else
-  int ret;
-  while ( (ret = recvmsg (ctx->inbound.fd, msg, 0)) == -1 && errno == EINTR)
-    ;
-  return ret;
-#endif
-}
-
-
-void
-_assuan_usleep (unsigned int usec)
-{
-  if (usec)
-    {
-#ifdef HAVE_NANOSLEEP
-      struct timespec req;
-      struct timespec rem;
-      
-      req.tv_sec = 0;
-      req.tv_nsec = usec * 1000;
-      
-      while (nanosleep (&req, &rem) < 0 && errno == EINTR)
-        req = rem;
-
-#elif defined(HAVE_W32_SYSTEM)
-      Sleep (usec / 1000);
-#else
-      struct timeval tv;
-
-      tv.tv_sec  = usec / 1000000;
-      tv.tv_usec = usec % 1000000;
-      select (0, NULL, NULL, NULL, &tv);
-#endif
-    }
-}
-
diff --git a/src/assuan-listen.c b/src/assuan-listen.c
index 3f57922..2f6c8a3 100644
--- a/src/assuan-listen.c
+++ b/src/assuan-listen.c
@@ -138,7 +138,7 @@ assuan_close_input_fd (assuan_context_t ctx)
 {
   if (!ctx || ctx->input_fd == ASSUAN_INVALID_FD)
     return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
-  _assuan_close (ctx->input_fd);
+  _assuan_close (ctx, ctx->input_fd);
   ctx->input_fd = ASSUAN_INVALID_FD;
   return 0;
 }
@@ -151,7 +151,7 @@ assuan_close_output_fd (assuan_context_t ctx)
   if (!ctx || ctx->output_fd == ASSUAN_INVALID_FD)
     return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
 
-  _assuan_close (ctx->output_fd);
+  _assuan_close (ctx, ctx->output_fd);
   ctx->output_fd = ASSUAN_INVALID_FD;
   return 0;
 }
diff --git a/src/assuan-pipe-connect.c b/src/assuan-pipe-connect.c
index c5e20e7..bdc59a4 100644
--- a/src/assuan-pipe-connect.c
+++ b/src/assuan-pipe-connect.c
@@ -62,7 +62,6 @@
 static void
 fix_signals (void)
 {
-#ifndef _ASSUAN_NO_FIXED_SIGNALS
 #ifndef HAVE_DOSISH_SYSTEM  /* No SIGPIPE for these systems.  */
   static int fixed_signals;
 
@@ -82,58 +81,28 @@ fix_signals (void)
       /* FIXME: This is not MT safe */
     }
 #endif /*HAVE_DOSISH_SYSTEM*/
-#endif /*!_ASSUAN_NO_FIXED_SIGNALS*/
 }
 
 
-#ifndef HAVE_W32_SYSTEM
-static int
-writen (int fd, const char *buffer, size_t length)
-{
-  while (length)
-    {
-      int nwritten = write (fd, buffer, length);
-      
-      if (nwritten < 0)
-        {
-          if (errno == EINTR)
-            continue;
-          return -1; /* write error */
-        }
-      length -= nwritten;
-      buffer += nwritten;
-    }
-  return 0;  /* okay */
-}
-#endif
-
 static void
 do_finish (assuan_context_t ctx)
 {
   if (ctx->inbound.fd != ASSUAN_INVALID_FD)
     {
-      _assuan_close (ctx->inbound.fd);
+      _assuan_close (ctx, ctx->inbound.fd);
       if (ctx->inbound.fd == ctx->outbound.fd)
         ctx->outbound.fd = ASSUAN_INVALID_FD;
       ctx->inbound.fd = ASSUAN_INVALID_FD;
     }
   if (ctx->outbound.fd != ASSUAN_INVALID_FD)
     {
-      _assuan_close (ctx->outbound.fd);
+      _assuan_close (ctx, ctx->outbound.fd);
       ctx->outbound.fd = ASSUAN_INVALID_FD;
     }
-  if (ctx->pid != (pid_t)(-1) && ctx->pid)
+  if (ctx->pid != ASSUAN_INVALID_PID && ctx->pid)
     {
-#ifndef HAVE_W32_SYSTEM
-#ifndef _ASSUAN_USE_DOUBLE_FORK
-      if (!ctx->flags.no_waitpid)
-        _assuan_waitpid (ctx->pid, NULL, 0); 
-      ctx->pid =(pid_t)(-1);
-#endif
-#else /*!HAVE_W32_SYSTEM*/
-      CloseHandle ((HANDLE) ctx->pid);
-      ctx->pid = (pid_t) INVALID_HANDLE_VALUE;
-#endif /*HAVE_W32_SYSTEM*/
+      _assuan_waitpid (ctx, ctx->pid, ctx->flags.no_waitpid, NULL, 0);
+      ctx->pid = ASSUAN_INVALID_PID;
     }
 }
 
@@ -166,178 +135,96 @@ initial_handshake (assuan_context_t ctx)
   return err;
 }
 
+

+struct at_pipe_fork
+{
+  void (*user_atfork) (void *opaque, int reserved);
+  void *user_atforkvalue;
+};
+
+
+static void
+at_pipe_fork_cb (void *opaque, int reserved)
+{
+  struct at_pipe_fork *atp = opaque;
+          
+  if (atp->user_atfork)
+    atp->user_atfork (atp->user_atforkvalue, reserved);
 
 #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. */
+  {
+    char mypidstr[50];
+    
+    /* 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. */
+    sprintf (mypidstr, "%lu", (unsigned long) getpid ());
+    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");
+  }
+#endif
+}
+
+
 static gpg_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, unsigned int flags)
+pipe_connect (assuan_context_t ctx,
+	      const char *name, const char **argv,
+	      int *fd_child_list,
+	      void (*atfork) (void *opaque, int reserved),
+	      void *atforkvalue, unsigned int flags)
 {
-  int rp[2];
-  int wp[2];
-  pid_t pid;
-  char mypidstr[50];
   gpg_error_t rc;
-  static struct assuan_io io = { _assuan_simple_read, _assuan_simple_write,
-				 0, 0 };
+  assuan_fd_t rp[2];
+  assuan_fd_t wp[2];
+  pid_t pid;
+  int res;
+  struct at_pipe_fork atp;
 
-  (void)flags;
+  atp.user_atfork = atfork;
+  atp.user_atforkvalue = atforkvalue;
 
   if (!ctx || !name || !argv || !argv[0])
     return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
 
-  fix_signals ();
+  if (! ctx->flags.no_fixsignals)
+    fix_signals ();
 
-  sprintf (mypidstr, "%lu", (unsigned long)getpid ());
-
-  if (pipe (rp) < 0)
-    return _assuan_error (ctx, GPG_ERR_ASS_GENERAL);
+  if (_assuan_pipe (ctx, rp, 1) < 0)
+    return _assuan_error (ctx, gpg_err_code_from_syserror ());
   
-  if (pipe (wp) < 0)
+  if (_assuan_pipe (ctx, wp, 0) < 0)
     {
-      close (rp[0]);
-      close (rp[1]);
-      return _assuan_error (ctx, GPG_ERR_ASS_GENERAL);
+      _assuan_close (ctx, rp[0]);
+      _assuan_close (ctx, rp[1]);
+      return _assuan_error (ctx, gpg_err_code_from_syserror ());
     }
 
-  /* FIXME: For GPGME we should better use _gpgme_io_spawn.  The PID
-     stored here is actually soon useless.  */
-  pid = fork ();
-  if (pid < 0)
+  /* FIXME: Use atfork handler that closes child fds on Unix.  */
+  res = _assuan_spawn (ctx, &pid, name, argv, wp[0], rp[1],
+		       fd_child_list, at_pipe_fork_cb, &atp, flags);
+  if (res < 0)
     {
-      close (rp[0]);
-      close (rp[1]);
-      close (wp[0]);
-      close (wp[1]);
-      return _assuan_error (ctx, GPG_ERR_ASS_GENERAL);
+      rc = gpg_err_code_from_syserror ();
+      _assuan_close (ctx, rp[0]);
+      _assuan_close (ctx, rp[1]);
+      _assuan_close (ctx, wp[0]);
+      _assuan_close (ctx, wp[1]);
+      return _assuan_error (ctx, rc);
     }
 
-  if (pid == 0)
-    {
-#ifdef _ASSUAN_USE_DOUBLE_FORK      
-      pid_t pid2;
-
-      if ((pid2 = 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)
-                {
-		  TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx,
-			  "dup2 failed in child: %s", strerror (errno));
-                  _exit (4);
-                }
-            }
-          if (wp[0] != STDIN_FILENO)
-            {
-              if (dup2 (wp[0], STDIN_FILENO) == -1)
-                {
-		  TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx,
-			  "dup2 failed in child: %s", 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)
-                {
-		  TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx,
-			  "can't open `/dev/null': %s", strerror (errno));
-                  _exit (4);
-                }
-              if (dup2 (fd, STDERR_FILENO) == -1)
-                {
-		  TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx,
-			  "dup2(dev/null, 2) failed: %s", 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 (ctx, GPG_ERR_ASS_SERVER_START),
-                    name, strerror (errno));
-          errbuf[sizeof(errbuf)-1] = 0;
-          writen (1, errbuf, strlen (errbuf));
-          _exit (4);
-        }
-#ifdef _ASSUAN_USE_DOUBLE_FORK
-      if (pid2 == -1)
-	_exit (1);
-      else
-	_exit (0);
-#endif
-    }
-
-#ifdef _ASSUAN_USE_DOUBLE_FORK
-  _assuan_waitpid (pid, NULL, 0);
-  pid = -1;
-#endif
-
-  close (rp[1]);
-  close (wp[0]);
+  /* Close the stdin/stdout child fds in the parent.  */
+  _assuan_close (ctx, rp[1]);
+  _assuan_close (ctx, wp[0]);
 
-  ctx->io = &io;
+  ctx->engine.release = _assuan_disconnect;
+  ctx->engine.readfnc = _assuan_simple_read;
+  ctx->engine.writefnc = _assuan_simple_write;
+  ctx->engine.sendfd = NULL;
+  ctx->engine.receivefd = NULL;
   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. */
@@ -350,176 +237,133 @@ pipe_connect_unix (assuan_context_t ctx,
     _assuan_reset (ctx);
   return rc;
 }
-#endif /*!HAVE_W32_SYSTEM*/
 
 
+/* FIXME: For socketpair_connect, use spawn function and add atfork
+   handler to do the right thing.  Instead of stdin and stdout, we
+   extend the fd_child_list by fds[1].  */
+
+#ifndef HAVE_W32_SYSTEM
+struct at_socketpair_fork
+{
+  assuan_fd_t peer_fd;
+  void (*user_atfork) (void *opaque, int reserved);
+  void *user_atforkvalue;
+};
+
+
+static void
+at_socketpair_fork_cb (void *opaque, int reserved)
+{
+  struct at_socketpair_fork *atp = opaque;
+          
+  if (atp->user_atfork)
+    atp->user_atfork (atp->user_atforkvalue, reserved);
+
 #ifndef HAVE_W32_SYSTEM
+  {
+    char mypidstr[50];
+    
+    /* 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. */
+    sprintf (mypidstr, "%lu", (unsigned long) getpid ());
+    setenv ("_assuan_pipe_connect_pid", mypidstr, 1);
+
+    /* Now set the environment variable used to convey the
+       connection's file descriptor.  */
+    sprintf (mypidstr, "%d", atp->peer_fd);
+    if (setenv ("_assuan_connection_fd", mypidstr, 1))
+      _exit (4);
+  }
+#endif
+}
+
+
 /* This function is similar to pipe_connect but uses a socketpair and
    sets the I/O up to use sendmsg/recvmsg. */
 static gpg_error_t
 socketpair_connect (assuan_context_t ctx,
-                    const char *name, const char *argv[],
+                    const char *name, const char **argv,
                     int *fd_child_list,
                     void (*atfork) (void *opaque, int reserved),
                     void *atforkvalue)
 {
   gpg_error_t err;
+  int idx;
   int fds[2];
   char mypidstr[50];
   pid_t pid;
+  int *child_fds = NULL;
+  int child_fds_cnt = 0;
+  struct at_socketpair_fork atp;
+  int rc;
+
+  TRACE_BEG3 (ctx, ASSUAN_LOG_CTX, "socketpair_connect", ctx,
+	      "name=%s,atfork=%p,atforkvalue=%p", name ? name : "(null)",
+	      atfork, atforkvalue);
+
+  atp.user_atfork = atfork;
+  atp.user_atforkvalue = atforkvalue;
 
   if (!ctx
       || (name && (!argv || !argv[0]))
       || (!name && !argv))
     return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
 
-  fix_signals ();
+  if (! ctx->flags.no_fixsignals)
+    fix_signals ();
 
   sprintf (mypidstr, "%lu", (unsigned long)getpid ());
 
-  if ( socketpair (AF_LOCAL, SOCK_STREAM, 0, fds) )
+  while (fd_child_list[child_fds_cnt] != ASSUAN_INVALID_FD)
+    child_fds_cnt++;
+  child_fds = _assuan_malloc (ctx, (child_fds_cnt + 2) * sizeof (int));
+  if (! child_fds)
+    return TRACE_ERR (gpg_err_code_from_syserror ());
+  memcpy (&child_fds[1], fd_child_list, (child_fds_cnt + 1) * sizeof (int));
+  
+  if (_assuan_socketpair (ctx, AF_LOCAL, SOCK_STREAM, 0, fds))
     {
-      TRACE1 (ctx, ASSUAN_LOG_SYSIO, "socketpair_connect", ctx,
-	      "socketpair failed: %s", strerror (errno));
-      return _assuan_error (ctx, GPG_ERR_ASS_GENERAL);
+      TRACE_LOG1 ("socketpair failed: %s", strerror (errno));
+      _assuan_free (ctx, child_fds);
+      return TRACE_ERR (GPG_ERR_ASS_GENERAL);
     }
+  atp.peer_fd = fds[1];
+  child_fds[0] = fds[1];
 
-  pid = fork ();
-  if (pid < 0)
+
+  rc = _assuan_spawn (ctx, &pid, name, argv, ASSUAN_INVALID_FD,
+		      ASSUAN_INVALID_FD, child_fds, at_socketpair_fork_cb,
+		      &atp, 0);
+  if (rc < 0)
     {
-      close (fds[0]);
-      close (fds[1]);
-      /* FIXME: cleanup ctx */
-      return _assuan_error (ctx, GPG_ERR_ASS_GENERAL);
+      err = gpg_err_code_from_syserror ();
+      _assuan_close (ctx, fds[0]);
+      _assuan_close (ctx, fds[1]);
+      _assuan_free (ctx, child_fds);
+      return TRACE_ERR (err);
     }
 
-  if (pid == 0)
+  /* For W32, the user needs to know the server-local names of the
+     inherited handles.  Return them here.  Note that the translation
+     of the peer socketpair fd (fd_child_list[0]) must be done by the
+     wrapper program based on the environment variable
+     _assuan_connection_fd.  */
+  for (idx = 0; fd_child_list[idx] != -1; idx++)
+    /* We add 1 to skip over the socketpair end.  */
+    fd_child_list[idx] = child_fds[idx + 1];
+
+  /* If this is the server child process, exit early.  */
+  if (! name && (*argv)[0] == 's')
     {
-#ifdef _ASSUAN_USE_DOUBLE_FORK      
-      pid_t pid2;
-
-      if ((pid2 = 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)
-            {
-	      TRACE1 (ctx, ASSUAN_LOG_SYSIO, "socketpair_connect", ctx,
-		      "dup2(dev/null) failed: %s", strerror (errno));
-              _exit (4);
-            }
-          fd = open ("/dev/null", O_WRONLY);
-          if (fd == -1 || dup2 (fd, STDOUT_FILENO) == -1)
-            {
-	      TRACE1 (ctx, ASSUAN_LOG_SYSIO, "socketpair_connect", ctx,
-		      "dup2(dev/null) failed: %s", 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)
-                {
-		  TRACE1 (ctx, ASSUAN_LOG_SYSIO, "socketpair_connect", ctx,
-			  "dup2(dev/null) failed: %s", 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))
-            {
-	      TRACE1 (ctx, ASSUAN_LOG_SYSIO, "socketpair_connect", ctx,
-		      "setenv failed: %s", strerror (errno));
-              _exit (4);
-            }
-
-          if (!name)
-            {
-              /* No name and no args given, thus we don't do an exec
-                 but continue the forked process.  */
-	      *argv = "server";
-
- 	      /* FIXME: Cleanup.  */
-               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 (ctx, GPG_ERR_ASS_SERVER_START),
-                    name, strerror (errno));
-          errbuf[sizeof(errbuf)-1] = 0;
-          writen (fds[1], errbuf, strlen (errbuf));
-          _exit (4);
-        }
-#ifdef _ASSUAN_USE_DOUBLE_FORK
-      if (pid2 == -1)
-	_exit (1);
-      else
-	_exit (0);
-#endif
+      _assuan_free (ctx, child_fds);
+      _assuan_close (ctx, fds[0]);
+      return 0;
     }
 
-  if (! name)
-    *argv = "client";
-
-#ifdef _ASSUAN_USE_DOUBLE_FORK
-  _assuan_waitpid (pid, NULL, 0);
-  pid = -1;
-#endif
-
-  close (fds[1]);
+  _assuan_close (ctx, fds[1]);
 
   ctx->pipe_mode = 1;
   ctx->inbound.fd  = fds[0]; 
@@ -535,282 +379,6 @@ socketpair_connect (assuan_context_t 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.  */
-static int
-build_w32_commandline (assuan_context_t ctx, const char * const *argv, char **cmdline)
-{
-  int i, n;
-  const char *s;
-  char *buf, *p;
-
-  *cmdline = NULL;
-  n = 0;
-  for (i=0; (s=argv[i]); i++)
-    {
-      n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting */
-      for (; *s; s++)
-        if (*s == '\"')
-          n++;  /* Need to double inner quotes.  */
-    }
-  n++;
-
-  buf = p = _assuan_malloc (ctx, n);
-  if (!buf)
-    return -1;
-
-  for (i=0; argv[i]; i++) 
-    {
-      if (i)
-        p = stpcpy (p, " ");
-      if (!*argv[i]) /* Empty string. */
-        p = stpcpy (p, "\"\"");
-      else if (strpbrk (argv[i], " \t\n\v\f\""))
-        {
-          p = stpcpy (p, "\"");
-          for (s=argv[i]; *s; s++)
-            {
-              *p++ = *s;
-              if (*s == '\"')
-                *p++ = *s;
-            }
-          *p++ = '\"';
-          *p = 0;
-        }
-      else
-        p = stpcpy (p, argv[i]);
-    }
-
-  *cmdline= buf;
-  return 0;
-}
-#endif /*HAVE_W32_SYSTEM*/
-
-
-#ifdef HAVE_W32_SYSTEM
-/* Create pipe where one end end is inheritable.  */
-static int
-create_inheritable_pipe (assuan_context_t ctx,
-			 assuan_fd_t filedes[2], int for_write)
-{
-  HANDLE r, w, h;
-  SECURITY_ATTRIBUTES sec_attr;
-
-  memset (&sec_attr, 0, sizeof sec_attr );
-  sec_attr.nLength = sizeof sec_attr;
-  sec_attr.bInheritHandle = FALSE;
-    
-  if (!CreatePipe (&r, &w, &sec_attr, 0))
-    {
-      TRACE1 (ctx, ASSUAN_LOG_SYSIO, "create_inheritable_pipe", ctx,
-	      "CreatePipe failed: %s", _assuan_w32_strerror (ctx, -1));
-      return -1;
-    }
-
-  if (!DuplicateHandle (GetCurrentProcess(), for_write? r : w,
-                        GetCurrentProcess(), &h, 0,
-                        TRUE, DUPLICATE_SAME_ACCESS ))
-    {
-      TRACE1 (ctx, ASSUAN_LOG_SYSIO, "create_inheritable_pipe", ctx,
-	      "DuplicateHandle failed: %s", _assuan_w32_strerror (ctx, -1));
-      CloseHandle (r);
-      CloseHandle (w);
-      return -1;
-    }
-  if (for_write)
-    {
-      CloseHandle (r);
-      r = h;
-    }
-  else
-    {
-      CloseHandle (w);
-      w = h;
-    }
-
-  filedes[0] = r;
-  filedes[1] = w;
-  return 0;
-}
-#endif /*HAVE_W32_SYSTEM*/
-
-
-#ifdef HAVE_W32_SYSTEM
-#define pipe_connect pipe_connect_w32
-/* W32 version of the pipe connection code. */
-static gpg_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, unsigned int flags)
-{
-  gpg_error_t err;
-  assuan_fd_t rp[2];
-  assuan_fd_t wp[2];
-  char mypidstr[50];
-  char *cmdline;
-  SECURITY_ATTRIBUTES sec_attr;
-  PROCESS_INFORMATION pi = 
-    {
-      NULL,      /* Returns process handle.  */
-      0,         /* Returns primary thread handle.  */
-      0,         /* Returns pid.  */
-      0          /* Returns tid.  */
-    };
-  STARTUPINFO si;
-  int fd, *fdp;
-  HANDLE nullfd = INVALID_HANDLE_VALUE;
-  static struct assuan_io io = { _assuan_simple_read, _assuan_simple_write,
-				 0, 0 };
-
-  if (!ctx || !name || !argv || !argv[0])
-    return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
-
-  fix_signals ();
-
-  sprintf (mypidstr, "%lu", (unsigned long)getpid ());
-
-  /* Build the command line.  */
-  if (build_w32_commandline (ctx, argv, &cmdline))
-    return _assuan_error (ctx, gpg_err_code_from_syserror ());
-
-  /* Create thew two pipes. */
-  if (create_inheritable_pipe (ctx, rp, 0))
-    {
-      _assuan_free (ctx, cmdline);
-      return _assuan_error (ctx, GPG_ERR_ASS_GENERAL);
-    }
-  
-  if (create_inheritable_pipe (ctx, wp, 1))
-    {
-      CloseHandle (rp[0]);
-      CloseHandle (rp[1]);
-      _assuan_free (ctx, cmdline);
-      return _assuan_error (ctx, GPG_ERR_ASS_GENERAL);
-    }
-
-
-  /* fixme: Actually we should set the "_assuan_pipe_connect_pid" env
-     variable.  However this requires us to write a full environment
-     handler, because the strings are expected in sorted order.  The
-     suggestion given in the MS Reference Library, to save the old
-     value, changeit, create proces and restore it, is not thread
-     safe.  */
-
-  /* Start the process.  */
-  memset (&sec_attr, 0, sizeof sec_attr );
-  sec_attr.nLength = sizeof sec_attr;
-  sec_attr.bInheritHandle = FALSE;
-  
-  memset (&si, 0, sizeof si);
-  si.cb = sizeof (si);
-  si.dwFlags = STARTF_USESTDHANDLES;
-  si.hStdInput  = wp[0];
-  si.hStdOutput = rp[1];
-
-  /* Dup stderr to /dev/null unless it is in the list of FDs to be
-     passed to the child. */
-  fd = fileno (stderr);
-  fdp = fd_child_list;
-  if (fdp)
-    {
-      for (; *fdp != -1 && *fdp != fd; fdp++)
-        ;
-    }
-  if (!fdp || *fdp == -1)
-    {
-      nullfd = CreateFile ("nul", GENERIC_WRITE,
-                           FILE_SHARE_READ | FILE_SHARE_WRITE,
-                           NULL, OPEN_EXISTING, 0, NULL);
-      if (nullfd == INVALID_HANDLE_VALUE)
-        {
-	  TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_w32", ctx,
-		  "can't open `nul': %s", _assuan_w32_strerror (ctx, -1));
-          CloseHandle (rp[0]);
-          CloseHandle (rp[1]);
-          CloseHandle (wp[0]);
-          CloseHandle (wp[1]);
-          _assuan_free (ctx, cmdline);
-	  /* FIXME: Cleanup?  */
-          return -1;
-        }
-      si.hStdError = nullfd;
-    }
-  else
-    si.hStdError = (void*)_get_osfhandle (fd);
-
-
-  /* Note: We inherit all handles flagged as inheritable.  This seems
-     to be a security flaw but there seems to be no way of selecting
-     handles to inherit. */
-  /*   _assuan_log_printf ("CreateProcess, path=`%s' cmdline=`%s'\n", */
-  /*                       name, cmdline); */
-  if (!CreateProcess (name,                 /* Program to start.  */
-                      cmdline,              /* Command line arguments.  */
-                      &sec_attr,            /* Process security attributes.  */
-                      &sec_attr,            /* Thread security attributes.  */
-                      TRUE,                 /* Inherit handles.  */
-                      (CREATE_DEFAULT_ERROR_MODE
-                       | ((flags & 128)? DETACHED_PROCESS : 0)
-                       | GetPriorityClass (GetCurrentProcess ())
-                       | CREATE_SUSPENDED), /* Creation flags.  */
-                      NULL,                 /* Environment.  */
-                      NULL,                 /* Use current drive/directory.  */
-                      &si,                  /* Startup information. */
-                      &pi                   /* Returns process information.  */
-                      ))
-    {
-      TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_w32", ctx,
-	      "CreateProcess failed: %s", _assuan_w32_strerror (ctx, -1));
-      CloseHandle (rp[0]);
-      CloseHandle (rp[1]);
-      CloseHandle (wp[0]);
-      CloseHandle (wp[1]);
-      if (nullfd != INVALID_HANDLE_VALUE)
-        CloseHandle (nullfd);
-      _assuan_free (ctx, cmdline);
-      /* FIXME: Cleanup?  */
-      return _assuan_error (ctx, GPG_ERR_ASS_GENERAL);
-    }
-  _assuan_free (ctx, cmdline);
-  cmdline = NULL;
-  if (nullfd != INVALID_HANDLE_VALUE)
-    {
-      CloseHandle (nullfd);
-      nullfd = INVALID_HANDLE_VALUE;
-    }
-
-  CloseHandle (rp[1]);
-  CloseHandle (wp[0]);
-
-  /*   _assuan_log_printf ("CreateProcess ready: hProcess=%p hThread=%p" */
-  /*                       " dwProcessID=%d dwThreadId=%d\n", */
-  /*                       pi.hProcess, pi.hThread, */
-  /*                       (int) pi.dwProcessId, (int) pi.dwThreadId); */
-
-  ResumeThread (pi.hThread);
-  CloseHandle (pi.hThread); 
-
-  ctx->io = &io;
-  ctx->engine.release = _assuan_disconnect;
-  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;
-  ctx->pid = (pid_t) pi.hProcess;
-
-  err = initial_handshake (ctx);
-  if (err)
-    _assuan_reset (ctx);
-  return err;
-}
-#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
@@ -820,6 +388,9 @@ gpg_error_t
 assuan_pipe_connect (assuan_context_t ctx, const char *name,
 		     const char *argv[], int *fd_child_list)
 {
+  TRACE1 (ctx, ASSUAN_LOG_CTX, "assuan_pipe_connect", ctx,
+	  "name=%s", name ? name : "(null)");
+
   return pipe_connect (ctx, name, argv, fd_child_list, NULL, NULL, 0);
 }
 
@@ -860,6 +431,9 @@ assuan_pipe_connect_ext (assuan_context_t ctx,
                          void (*atfork) (void *opaque, int reserved),
                          void *atforkvalue, unsigned int flags)
 {
+  TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_pipe_connect_ext", ctx,
+	  "name=%s,flags=0x%x", name ? name : "(null)", flags);
+
   if ((flags & 1))
     {
 #ifdef HAVE_W32_SYSTEM
@@ -873,3 +447,4 @@ assuan_pipe_connect_ext (assuan_context_t ctx,
     return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue,
                          flags);
 }
+
diff --git a/src/assuan-pipe-server.c b/src/assuan-pipe-server.c
index 3c30d48..7849fa5 100644
--- a/src/assuan-pipe-server.c
+++ b/src/assuan-pipe-server.c
@@ -77,8 +77,6 @@ assuan_init_pipe_server (assuan_context_t ctx, int filedes[2])
   assuan_fd_t infd = ASSUAN_INVALID_FD;
   assuan_fd_t outfd = ASSUAN_INVALID_FD;
   int is_usd = 0;
-  static struct assuan_io io = { _assuan_simple_read, _assuan_simple_write,
-				 0, 0 };
 
   rc = _assuan_register_std_commands (ctx);
   if (rc)
@@ -117,6 +115,10 @@ assuan_init_pipe_server (assuan_context_t ctx, int filedes[2])
 
   ctx->is_server = 1;
   ctx->engine.release = deinit_pipe_server;
+  ctx->engine.readfnc = _assuan_simple_read;
+  ctx->engine.writefnc = _assuan_simple_write;
+  ctx->engine.sendfd = NULL;
+  ctx->engine.receivefd = NULL;
   ctx->pipe_mode = 1;
 
   s = getenv ("_assuan_pipe_connect_pid");
@@ -135,8 +137,6 @@ assuan_init_pipe_server (assuan_context_t ctx, int filedes[2])
       _assuan_init_uds_io (ctx);
       ctx->deinit_handler = _assuan_uds_deinit;
     }
-  else
-    ctx->io = &io;
 
   return 0;
 }
diff --git a/src/assuan-socket-connect.c b/src/assuan-socket-connect.c
index ac2df5b..21997f0 100644
--- a/src/assuan-socket-connect.c
+++ b/src/assuan-socket-connect.c
@@ -58,12 +58,12 @@ do_finish (assuan_context_t ctx)
 {
   if (ctx->inbound.fd != ASSUAN_INVALID_FD)
     {
-      _assuan_close (ctx->inbound.fd);
+      _assuan_close (ctx, ctx->inbound.fd);
       ctx->inbound.fd = ASSUAN_INVALID_FD;
     }
   if (ctx->outbound.fd != ASSUAN_INVALID_FD)
     {
-      _assuan_close (ctx->outbound.fd);
+      _assuan_close (ctx, ctx->outbound.fd);
       ctx->outbound.fd = ASSUAN_INVALID_FD;
     }
 }
@@ -96,8 +96,6 @@ assuan_socket_connect_ext (assuan_context_t ctx,
                            const char *name, pid_t server_pid,
                            unsigned int flags)
 {
-  static struct assuan_io io = { _assuan_simple_read, _assuan_simple_write,
-				 NULL, NULL };
   gpg_error_t err;
   assuan_fd_t fd;
   struct sockaddr_un srvr_addr;
@@ -120,7 +118,7 @@ assuan_socket_connect_ext (assuan_context_t ctx,
   if (strlen (name)+1 >= sizeof srvr_addr.sun_path)
     return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
 
-  fd = _assuan_sock_new (PF_LOCAL, SOCK_STREAM, 0);
+  fd = _assuan_sock_new (ctx, PF_LOCAL, SOCK_STREAM, 0);
   if (fd == ASSUAN_INVALID_FD)
     {
       TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect_ext", ctx,
@@ -135,17 +133,20 @@ assuan_socket_connect_ext (assuan_context_t ctx,
   srvr_addr.sun_path[sizeof (srvr_addr.sun_path) - 1] = 0;
   len = SUN_LEN (&srvr_addr);
 
-  if ( _assuan_sock_connect (fd, (struct sockaddr *) &srvr_addr, len) == -1 )
+  if (_assuan_sock_connect (ctx, fd, (struct sockaddr *) &srvr_addr, len) == -1)
     {
       TRACE2 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect_ext", ctx,
 	      "can't connect to `%s': %s\n", name, strerror (errno));
       /* FIXME: Cleanup */
-      _assuan_close (fd);
+      _assuan_close (ctx, fd);
       return _assuan_error (ctx, GPG_ERR_ASS_CONNECT_FAILED);
     }
  
-  ctx->io = &io;
   ctx->engine.release = _assuan_disconnect;
+  ctx->engine.readfnc = _assuan_simple_read;
+  ctx->engine.writefnc = _assuan_simple_write;
+  ctx->engine.sendfd = NULL;
+  ctx->engine.receivefd = NULL;
   ctx->deinit_handler = ((flags&1))? _assuan_uds_deinit :  do_deinit;
   ctx->finish_handler = do_finish;
   ctx->inbound.fd = fd;
diff --git a/src/assuan-socket-server.c b/src/assuan-socket-server.c
index b46a4e7..3487b19 100644
--- a/src/assuan-socket-server.c
+++ b/src/assuan-socket-server.c
@@ -96,9 +96,9 @@ accept_connection (assuan_context_t ctx)
     {
       return _assuan_error (ctx, gpg_err_code_from_syserror ());
     }
-  if (_assuan_sock_check_nonce (fd, &ctx->listen_nonce))
+  if (_assuan_sock_check_nonce (ctx, fd, &ctx->listen_nonce))
     {
-      _assuan_close (fd);
+      _assuan_close (ctx, fd);
       return _assuan_error (ctx, GPG_ERR_ASS_ACCEPT_FAILED);
     }
 
@@ -112,12 +112,12 @@ finish_connection (assuan_context_t ctx)
 {
   if (ctx->inbound.fd != ASSUAN_INVALID_FD)
     {
-      _assuan_close (ctx->inbound.fd);
+      _assuan_close (ctx, ctx->inbound.fd);
       ctx->inbound.fd = ASSUAN_INVALID_FD;
     }
   if (ctx->outbound.fd != ASSUAN_INVALID_FD)
     {
-      _assuan_close (ctx->outbound.fd);
+      _assuan_close (ctx, ctx->outbound.fd);
       ctx->outbound.fd = ASSUAN_INVALID_FD;
     }
 }
@@ -155,15 +155,16 @@ assuan_init_socket_server_ext (assuan_context_t ctx, assuan_fd_t fd,
                                unsigned int flags)
 {
   gpg_error_t rc;
-  static struct assuan_io io = { _assuan_simple_read, _assuan_simple_write,
-				 0, 0 };
 
   rc = _assuan_register_std_commands (ctx);
   if (rc)
     return rc;
 
-  ctx->io = &io;
   ctx->engine.release = deinit_socket_server;
+  ctx->engine.readfnc = _assuan_simple_read;
+  ctx->engine.writefnc = _assuan_simple_write;
+  ctx->engine.sendfd = NULL;
+  ctx->engine.receivefd = NULL;
   ctx->is_server = 1;
   if (flags & 2)
     ctx->pipe_mode = 1; /* We want a second accept to indicate EOF. */
diff --git a/src/assuan-socket.c b/src/assuan-socket.c
index e638503..a6ee7a4 100644
--- a/src/assuan-socket.c
+++ b/src/assuan-socket.c
@@ -144,33 +144,11 @@ read_port_and_nonce (const char *fname, unsigned short *port, char *nonce)
 #endif /*HAVE_W32_SYSTEM*/
 
 
-
-int
-_assuan_close (assuan_fd_t fd)
-{
-#ifdef HAVE_W32_SYSTEM
-  int rc = closesocket (HANDLE2SOCKET(fd));
-  if (rc)
-    errno = _assuan_sock_wsa2errno (WSAGetLastError ());
-  if (rc && WSAGetLastError () == WSAENOTSOCK)
-    {
-      rc = CloseHandle (fd);
-      if (rc)
-	/* FIXME. */
-	errno = EIO;
-    }
-  return rc;
-#else
-  return close (fd);
-#endif
-}
-
-
 /* Return a new socket.  Note that under W32 we consider a socket the
    same as an System Handle; all functions using such a handle know
    about this dual use and act accordingly. */ 
 assuan_fd_t
-_assuan_sock_new (int domain, int type, int proto)
+_assuan_sock_new (assuan_context_t ctx, int domain, int type, int proto)
 {
 #ifdef HAVE_W32_SYSTEM
   assuan_fd_t res;
@@ -187,7 +165,8 @@ _assuan_sock_new (int domain, int type, int proto)
 
 
 int
-_assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
+_assuan_sock_connect (assuan_context_t ctx, assuan_fd_t sockfd,
+		      struct sockaddr *addr, int addrlen)
 {
 #ifdef HAVE_W32_SYSTEM
   if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
@@ -199,7 +178,7 @@ _assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
       int ret;
       
       unaddr = (struct sockaddr_un *)addr;
-      if (read_port_and_nonce (unaddr->sun_path, &port, nonce))
+      if (read_port_and_nonce (ctx, unaddr->sun_path, &port, nonce))
         return -1;
       
       myaddr.sin_family = AF_INET;
@@ -216,7 +195,7 @@ _assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
       if (!ret)
         {
           /* Send the nonce. */
-          ret = _assuan_io_write (sockfd, nonce, 16);
+          ret = _assuan_write (ctx, sockfd, nonce, 16);
           if (ret >= 0 && ret != 16)
             {
               errno = EIO;
@@ -240,7 +219,8 @@ _assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
 
 
 int
-_assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
+_assuan_sock_bind (assuan_context_t ctx, assuan_fd_t sockfd,
+		   struct sockaddr *addr, int addrlen)
 {
 #ifdef HAVE_W32_SYSTEM
   if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
@@ -312,8 +292,8 @@ _assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
 
 
 int
-_assuan_sock_get_nonce (struct sockaddr *addr, int addrlen, 
-                        assuan_sock_nonce_t *nonce)
+_assuan_sock_get_nonce (assuan_context_t ctx, struct sockaddr *addr,
+			int addrlen, assuan_sock_nonce_t *nonce)
 {
 #ifdef HAVE_W32_SYSTEM
   if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
@@ -328,7 +308,7 @@ _assuan_sock_get_nonce (struct sockaddr *addr, int addrlen,
         }
       nonce->length = 16;
       unaddr = (struct sockaddr_un *)addr;
-      if (read_port_and_nonce (unaddr->sun_path, &port, nonce->nonce))
+      if (read_port_and_nonce (ctx, unaddr->sun_path, &port, nonce->nonce))
         return -1;
     }
   else
@@ -346,7 +326,8 @@ _assuan_sock_get_nonce (struct sockaddr *addr, int addrlen,
  
  
 int
-_assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
+_assuan_sock_check_nonce (assuan_context_t ctx, assuan_fd_t fd,
+			  assuan_sock_nonce_t *nonce)
 {
 #ifdef HAVE_W32_SYSTEM
   char buffer[16], *p;
@@ -367,12 +348,12 @@ _assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
       errno = EINVAL;
       return -1;
     }
-      
+
   p = buffer;
   nleft = 16;
   while (nleft)
     {
-      n = _assuan_io_read (SOCKET2HANDLE(fd), p, nleft);
+      n = _assuan_read (ctx, SOCKET2HANDLE(fd), p, nleft);
       if (n < 0 && errno == EINTR)
         ;
       else if (n < 0 && errno == EAGAIN)
@@ -404,39 +385,83 @@ _assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
 
 
 /* Public API.  */
+
+/* In the future, we can allow access to sock_ctx, if that context's
+   hook functions need to be overridden.  There can only be one global
+   assuan_sock_* user (one library or one application) with this
+   convenience interface, if non-standard hook functions are
+   needed.  */
+static assuan_context_t sock_ctx;
+
+gpg_error_t
+assuan_sock_init ()
+{
+  gpg_error_t err;
+#ifdef HAVE_W32_SYSTEM
+  WSADATA wsadat;
+#endif
+
+  if (sock_ctx != NULL)
+    return 0;
+
+  err = assuan_new (&sock_ctx);
+	
+#ifdef HAVE_W32_SYSTEM
+  if (! err)
+    WSAStartup (0x202, &wsadat);
+#endif
+
+  return err;
+}
+
+
+void
+assuan_sock_deinit ()
+{
+  if (sock_ctx == NULL)
+    return;
+
+#ifdef HAVE_W32_SYSTEM
+  WSACleanup ();
+#endif
+
+  assuan_release (sock_ctx);
+}
+  
+
 int
 assuan_sock_close (assuan_fd_t fd)
 {
-  return _assuan_close (fd);
+  return _assuan_close (sock_ctx, fd);
 }
 
 assuan_fd_t 
 assuan_sock_new (int domain, int type, int proto)
 {
-  return _assuan_sock_new (domain, type, proto);
+  return _assuan_sock_new (sock_ctx, domain, type, proto);
 }
 
 int
 assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
 {
-  return _assuan_sock_connect (sockfd, addr, addrlen);
+  return _assuan_sock_connect (sock_ctx, sockfd, addr, addrlen);
 }
 
 int
 assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
 {
-  return _assuan_sock_bind (sockfd, addr, addrlen);
+  return _assuan_sock_bind (sock_ctx, sockfd, addr, addrlen);
 }
 
 int
 assuan_sock_get_nonce (struct sockaddr *addr, int addrlen, 
                        assuan_sock_nonce_t *nonce)
 {     
-  return _assuan_sock_get_nonce (addr, addrlen, nonce);
+  return _assuan_sock_get_nonce (sock_ctx, addr, addrlen, nonce);
 }
 
 int
 assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
 {
-  return _assuan_sock_check_nonce (fd, nonce);
+  return _assuan_sock_check_nonce (sock_ctx, fd, nonce);
 }
diff --git a/src/assuan-uds.c b/src/assuan-uds.c
index 1c2d106..2bec03d 100644
--- a/src/assuan-uds.c
+++ b/src/assuan-uds.c
@@ -107,7 +107,7 @@ uds_reader (assuan_context_t ctx, void *buf, size_t buflen)
       msg.msg_controllen = sizeof (control_u.control);
 #endif
 
-      len = _assuan_simple_recvmsg (ctx, &msg);
+      len = _assuan_recvmsg (ctx, ctx->inbound.fd, &msg, 0);
       if (len < 0)
         return -1;
       if (len == 0)
@@ -133,7 +133,7 @@ uds_reader (assuan_context_t ctx, void *buf, size_t buflen)
 		  TRACE1 (ctx, ASSUAN_LOG_SYSIO, "uds_reader", ctx,
 			  "too many descriptors pending - "
 			  "closing received descriptor %d", fd);
-                  _assuan_close (fd);
+                  _assuan_close (ctx, fd);
                 }
               else
                 ctx->uds.pendingfds[ctx->uds.pendingfdscount++] = fd;
@@ -181,7 +181,7 @@ uds_writer (assuan_context_t ctx, const void *buf, size_t buflen)
   iovec.iov_base = (void*)buf;
   iovec.iov_len = buflen;
 
-  len = _assuan_simple_sendmsg (ctx, &msg);
+  len = _assuan_sendmsg (ctx, ctx->outbound.fd, &msg, 0);
 
   return len;
 #else /*HAVE_W32_SYSTEM*/
@@ -231,7 +231,7 @@ uds_sendfd (assuan_context_t ctx, assuan_fd_t fd)
   cmptr->cmsg_type = SCM_RIGHTS;
   *((int*)CMSG_DATA (cmptr)) = fd;
 
-  len = _assuan_simple_sendmsg (ctx, &msg);
+  len = _assuan_sendmsg (ctx, ctx->outbound.fd, &msg, 0);
   if (len < 0)
     {
       int saved_errno = errno;
@@ -281,7 +281,7 @@ _assuan_uds_close_fds (assuan_context_t ctx)
   int i;
 
   for (i = 0; i < ctx->uds.pendingfdscount; i++)
-    _assuan_close (ctx->uds.pendingfds[i]);
+    _assuan_close (ctx, ctx->uds.pendingfds[i]);
   ctx->uds.pendingfdscount = 0;
 }
 
@@ -307,10 +307,11 @@ _assuan_uds_deinit (assuan_context_t ctx)
 void
 _assuan_init_uds_io (assuan_context_t ctx)
 {
-  static struct assuan_io io = { uds_reader, uds_writer,
-				 uds_sendfd, uds_receivefd };
+  ctx->engine.readfnc = uds_reader;
+  ctx->engine.writefnc = uds_writer;
+  ctx->engine.sendfd = uds_sendfd;
+  ctx->engine.receivefd = uds_receivefd;
 
-  ctx->io = &io;
   ctx->uds.buffer = 0;
   ctx->uds.bufferoffset = 0;
   ctx->uds.buffersize = 0;
diff --git a/src/assuan.c b/src/assuan.c
index 4848ec4..31263d4 100644
--- a/src/assuan.c
+++ b/src/assuan.c
@@ -92,6 +92,13 @@ assuan_get_log_cb (assuan_log_cb_t *log_cb, void **log_cb_data)
 }
 
 

+void
+assuan_set_system_hooks (assuan_system_hooks_t system_hooks)
+{
+  _assuan_system_hooks_copy (&_assuan_system_hooks, system_hooks);
+}
+
+

 /* Create a new Assuan context.  The initial parameters are all needed
    in the creation of the context.  */
 gpg_error_t
@@ -123,6 +130,7 @@ assuan_new_ext (assuan_context_t *r_ctx, gpg_err_source_t err_source,
       return TRACE_ERR (gpg_err_code_from_syserror ());
 
     memcpy (ctx, &wctx, sizeof (*ctx));
+    ctx->system = _assuan_system_hooks;
 
     /* FIXME: Delegate to subsystems/engines, as the FDs are not our
        responsibility (we don't deallocate them, for example).  */
@@ -168,13 +176,13 @@ _assuan_reset (assuan_context_t ctx)
 void
 assuan_release (assuan_context_t ctx)
 {
-  if (ctx)
-    {
-      TRACE (ctx, ASSUAN_LOG_CTX, "assuan_release", ctx);
-      
-      _assuan_reset (ctx);
-      /* None of the members that are our responsibility requires
-         deallocation.  */
-      _assuan_free (ctx, ctx);
-    }
+  TRACE (ctx, ASSUAN_LOG_CTX, "assuan_release", ctx);
+
+  if (! ctx)
+    return;
+
+  _assuan_reset (ctx);
+  /* None of the members that are our responsibility requires
+     deallocation.  */
+  _assuan_free (ctx, ctx);
 }
diff --git a/src/assuan.h b/src/assuan.h
index c0b1fea..c63e396 100644
--- a/src/assuan.h
+++ b/src/assuan.h
@@ -33,30 +33,19 @@
 #endif
 #endif /*!_ASSUAN_NO_SOCKET_WRAPPER*/
 
+#ifdef _WIN32
+typedef void *assuan_msghdr_t;
+#else
+typedef struct msghdr *assuan_msghdr_t;
+#endif
+
 #include <gpg-error.h>
 
 /* Compile time configuration:
 
    #define _ASSUAN_NO_SOCKET_WRAPPER
 
-       Do not include the definitions for the socket wrapper feature.
-
-   The follwing macros are used internally in the implementation of
-   libassuan:
-
-     #define _ASSUAN_NO_PTH 
-
-       This avoids inclusion of special GNU Pth hacks.
-
-     #define _ASSUAN_NO_FIXED_SIGNALS 
-
-       This disables changing of certain signal handler; i.e. SIGPIPE.
-
-     #define _ASSUAN_USE_DOUBLE_FORK
-
-       Use a double fork approach when connecting to a server through
-       a pipe.
- */
+   Do not include the definitions for the socket wrapper feature.  */
 
 
 #ifdef __cplusplus
@@ -95,9 +84,11 @@ typedef struct assuan_context_s *assuan_context_t;
 #ifdef _WIN32
 typedef void *assuan_fd_t;
 #define ASSUAN_INVALID_FD ((void*)(-1))
+#define ASSUAN_INVALID_PID ((pid_t) -1)
 #else
 typedef int assuan_fd_t;
 #define ASSUAN_INVALID_FD (-1)
+#define ASSUAN_INVALID_PID ((pid_t) -1)
 #endif
 
 
@@ -208,6 +199,8 @@ typedef unsigned int assuan_flag_t;
 /* This flag indicates whether Assuan logging is in confidential mode.
    You can use assuan_{begin,end}_condidential to change the mode.  */
 #define ASSUAN_CONFIDENTIAL 2
+/* This flag suppresses fix up of signal handlers for pipes.  */
+#define ASSUAN_NO_FIXSIGNALS 3
 
 /* For context CTX, set the flag FLAG to VALUE.  Values for flags
    are usually 1 or 0 but certain flags might allow for other values;
@@ -243,6 +236,52 @@ typedef unsigned int (*assuan_io_monitor_t) (assuan_context_t ctx, void *hook,
 void assuan_set_io_monitor (assuan_context_t ctx,
 			    assuan_io_monitor_t io_monitor, void *hook_data);
 
+
+#define ASSUAN_SYSTEM_HOOKS_VERSION 1
+struct assuan_system_hooks
+{
+  /* Always set to ASSUAN_SYTEM_HOOKS_VERSION.  */
+  int version;
+
+  /* Sleep for the given number of microseconds.  */
+  void (*usleep) (assuan_context_t ctx, unsigned int usec);
+
+  /* Create a pipe with an inheritable end.  */
+  int (*pipe) (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx);
+
+ /* Close the given file descriptor, created with _assuan_pipe or one
+   of the socket functions.  */
+  int (*close) (assuan_context_t ctx, assuan_fd_t fd);
+
+
+  ssize_t (*read) (assuan_context_t ctx, assuan_fd_t fd, void *buffer,
+		   size_t size);
+  ssize_t (*write) (assuan_context_t ctx, assuan_fd_t fd,
+		    const void *buffer, size_t size);
+
+  int (*recvmsg) (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
+		  int flags);
+  int (*sendmsg) (assuan_context_t ctx, assuan_fd_t fd,
+		  const assuan_msghdr_t msg, int flags);
+
+  /* If NAME is NULL, don't exec, just fork.  FD_CHILD_LIST is
+     modified to reflect the value of the FD in the peer process (on
+     Windows).  */
+  int (*spawn) (assuan_context_t ctx, pid_t *r_pid, const char *name,
+		const char **argv,
+		assuan_fd_t fd_in, assuan_fd_t fd_out,
+		assuan_fd_t *fd_child_list,
+		void (*atfork) (void *opaque, int reserved),
+		void *atforkvalue, unsigned int flags);
+
+  /* If action is 0, like waitpid.  If action is 1, just release the PID?  */
+  pid_t (*waitpid) (assuan_context_t ctx, pid_t pid,
+		    int action, int *status, int options);
+  int (*socketpair) (assuan_context_t ctx, int namespace, int style,
+		     int protocol, assuan_fd_t filedes[2]);
+};
+typedef struct assuan_system_hooks *assuan_system_hooks_t;
+
 

 /* Configuration of the default log handler.  */
 
@@ -328,11 +367,11 @@ void assuan_set_sock_nonce (assuan_context_t ctx, assuan_sock_nonce_t *nonce);
 gpg_error_t assuan_pipe_connect (assuan_context_t ctx,
 				 const char *name,
 				 const char *argv[],
-				 int *fd_child_list);
+				 assuan_fd_t *fd_child_list);
 gpg_error_t assuan_pipe_connect_ext (assuan_context_t ctx,
 				     const char *name,
 				     const char *argv[],
-				     int *fd_child_list,
+				     assuan_fd_t *fd_child_list,
 				     void (*atfork) (void *, int),
 				     void *atforkvalue,
 				     unsigned int flags);
@@ -401,6 +440,8 @@ gpg_error_t assuan_set_error (assuan_context_t ctx, gpg_error_t err, const char
 
 /* These are socket wrapper functions to support an emulation of Unix
    domain sockets on Windows W32.  */
+gpg_error_t assuan_sock_init (void);
+void assuan_sock_deinit (void);
 int assuan_sock_close (assuan_fd_t fd);
 assuan_fd_t assuan_sock_new (int domain, int type, int proto);
 int assuan_sock_connect (assuan_fd_t sockfd, 
@@ -410,6 +451,132 @@ int assuan_sock_get_nonce (struct sockaddr *addr, int addrlen,
                            assuan_sock_nonce_t *nonce);
 int assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce);
 
+

+/* Set the default or per context system callbacks.  This is
+   irreversible.  */
+void assuan_set_system_hooks (assuan_system_hooks_t system_hooks);
+
+void assuan_ctx_set_system_hooks (assuan_context_t ctx,
+				  assuan_system_hooks_t system_hooks);
+
+int __assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx);
+int __assuan_close (assuan_context_t ctx, assuan_fd_t fd);
+int __assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
+		    const char **argv, assuan_fd_t fd_in, assuan_fd_t fd_out,
+		    assuan_fd_t *fd_child_list,
+		    void (*atfork) (void *opaque, int reserved),
+		    void *atforkvalue, unsigned int flags);
+int __assuan_socketpair (assuan_context_t ctx, int namespace, int style,
+			 int protocol, assuan_fd_t filedes[2]);
+
+#ifdef _WIN32
+#define _ASSUAN_SYSTEM_PTH_IMPL						\
+  static int _assuan_pth_recvmsg (assuan_context_t ctx, assuan_fd_t fd, \
+				  assuan_msghdr_t msg, int flags)	\
+  {									\
+    (void) ctx;								\
+    errno = ENOSYS;							\
+    return -1;								\
+  }									\
+  static int _assuan_pth_sendmsg (assuan_context_t ctx, assuan_fd_t fd, \
+				  const assuan_msghdr_t msg, int flags) \
+  {									\
+    (void) ctx;								\
+    errno = ENOSYS;							\
+    return -1;								\
+  }
+#else
+#define _ASSUAN_SYSTEM_PTH_IMPL						\
+  static int _assuan_pth_recvmsg (assuan_context_t ctx, assuan_fd_t fd, \
+				  assuan_msghdr_t msg, int flags)	\
+  {									\
+    /* Pth does not provide a recvmsg function.  We implement it.  */	\
+    int ret;								\
+    int fdmode;								\
+									\
+    (void) ctx;								\
+    fdmode = pth_fdmode (fd, PTH_FDMODE_POLL);				\
+    if (fdmode == PTH_FDMODE_ERROR)					\
+      {									\
+        errno = EBADF;							\
+        return -1;							\
+      }									\
+    if (fdmode == PTH_FDMODE_BLOCK)					\
+      {									\
+        fd_set fds;							\
+									\
+	FD_ZERO (&fds);							\
+	FD_SET (fd, &fds);						\
+	while ((ret = pth_select (fd + 1, &fds, NULL, NULL, NULL)) < 0	\
+	       && errno == EINTR)					\
+	  ;								\
+	if (ret < 0)							\
+	  return -1;							\
+      }									\
+    									\
+    while ((ret = recvmsg (fd, msg, flags)) == -1 && errno == EINTR)	\
+      ;									\
+    return ret;								\
+  }									\
+  static int _assuan_pth_sendmsg (assuan_context_t ctx, assuan_fd_t fd, \
+				  const assuan_msghdr_t msg, int flags) \
+  {									\
+    /* Pth does not provide a sendmsg function.  We implement it.  */	\
+    int ret;								\
+    int fdmode;								\
+									\
+    (void) ctx;								\
+    fdmode = pth_fdmode (fd, PTH_FDMODE_POLL);				\
+    if (fdmode == PTH_FDMODE_ERROR)					\
+      {									\
+        errno = EBADF;							\
+	return -1;							\
+      }									\
+    if (fdmode == PTH_FDMODE_BLOCK)					\
+      {									\
+        fd_set fds;							\
+									\
+	FD_ZERO (&fds);							\
+	FD_SET (fd, &fds);						\
+	while ((ret = pth_select (fd + 1, NULL, &fds, NULL, NULL)) < 0	\
+	       && errno == EINTR)					\
+	  ;								\
+	if (ret < 0)							\
+	  return -1;							\
+	}								\
+									\
+    while ((ret = sendmsg (fd, msg, flags)) == -1 && errno == EINTR)	\
+      ;									\
+    return ret;								\
+  }
+#endif
+
+
+#define ASSUAN_SYSTEM_PTH_IMPL						\
+  static void _assuan_pth_usleep (assuan_context_t ctx, unsigned int usec) \
+  { (void) ctx; pth_usleep (usec); }					\
+  static ssize_t _assuan_pth_read (assuan_context_t ctx, assuan_fd_t fd, \
+				void *buffer, size_t size)		\
+  { (void) ctx; return pth_read (fd, buffer, size); }			\
+  static ssize_t _assuan_pth_write (assuan_context_t ctx, assuan_fd_t fd, \
+				 const void *buffer, size_t size)	\
+  { (void) ctx; return pth_write (fd, buffer, size); }			\
+  _ASSUAN_SYSTEM_PTH_IMPL						\
+  static pid_t _assuan_pth_waitpid (assuan_context_t ctx, pid_t pid,     \
+				   int nowait, int *status, int options) \
+  { (void) ctx;                                                         \
+     if (!nowait) return pth_waitpid (pid, status, options);            \
+      else return 0; }							\
+									\
+  struct assuan_system_hooks _assuan_system_pth =			\
+    { ASSUAN_SYSTEM_HOOKS_VERSION, _assuan_pth_usleep, __assuan_pipe,	\
+      __assuan_close, _assuan_pth_read, _assuan_pth_write,		\
+      _assuan_pth_recvmsg, _assuan_pth_sendmsg,				\
+      __assuan_spawn, _assuan_pth_waitpid, __assuan_socketpair }
+
+extern struct assuan_system_hooks _assuan_system_pth;
+#define ASSUAN_SYSTEM_PTH &_assuan_system_pth
+
 
 #ifdef __cplusplus
 }
diff --git a/src/context.c b/src/context.c
index d87672b..3e707ca 100644
--- a/src/context.c
+++ b/src/context.c
@@ -28,10 +28,13 @@
 

 /* Set user-data in a context.  */
 void
-assuan_set_pointer (assuan_context_t ctx, void *pointer)
+assuan_set_pointer (assuan_context_t ctx, void *user_pointer)
 {
+  TRACE1 (ctx, ASSUAN_LOG_CTX, "assuan_set_pointer", ctx,
+	  "user_pointer=%p", user_pointer);
+
   if (ctx)
-    ctx->user_pointer = pointer;
+    ctx->user_pointer = user_pointer;
 }
 
 
@@ -39,6 +42,9 @@ assuan_set_pointer (assuan_context_t ctx, void *pointer)
 void *
 assuan_get_pointer (assuan_context_t ctx)
 {
+  TRACE1 (ctx, ASSUAN_LOG_CTX, "assuan_get_pointer", ctx,
+	  "ctx->user_pointer=%p", ctx ? ctx->user_pointer : NULL);
+
   if (! ctx)
     return NULL;
 
@@ -52,6 +58,9 @@ assuan_get_pointer (assuan_context_t ctx)
 void
 assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value)
 {
+  TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_set_flag", ctx,
+	  "flag=%i,value=%i", flag, value);
+
   if (!ctx)
     return;
 
@@ -64,6 +73,10 @@ assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value)
     case ASSUAN_CONFIDENTIAL:
       ctx->flags.confidential = value;
       break;
+
+    case ASSUAN_NO_FIXSIGNALS:
+      ctx->flags.no_fixsignals = value;
+      break;
     }
 }
 
@@ -72,18 +85,29 @@ assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value)
 int
 assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag)
 {
+  int res = 0;
+  TRACE_BEG1 (ctx, ASSUAN_LOG_CTX, "assuan_get_flag", ctx,
+	      "flag=%i", flag);
+
   if (! ctx)
     return 0;
 
   switch (flag)
     {
     case ASSUAN_NO_WAITPID:
-      return ctx->flags.no_waitpid;
+      res = ctx->flags.no_waitpid;
+      break;
+
     case ASSUAN_CONFIDENTIAL:
-      return ctx->flags.confidential;
+      res = ctx->flags.confidential;
+      break;
+
+    case ASSUAN_NO_FIXSIGNALS:
+      res = ctx->flags.no_fixsignals;
+      break;
     }
 
-  return 0;
+  return TRACE_SUC1 ("flag_value=%i", res);
 }
 
 
@@ -103,15 +127,31 @@ assuan_end_confidential (assuan_context_t ctx)
 }
 
 

+/* Set the system callbacks.  */
+void
+assuan_ctx_set_system_hooks (assuan_context_t ctx,
+			     assuan_system_hooks_t system_hooks)
+{
+  TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_set_system_hooks", ctx,
+	  "system_hooks=%p (version %i)", system_hooks,
+	  system_hooks->version);
+
+  _assuan_system_hooks_copy (&ctx->system, system_hooks);
+}
+
+

 /* Set the IO monitor function.  */
 void assuan_set_io_monitor (assuan_context_t ctx,
 			    assuan_io_monitor_t io_monitor, void *hook_data)
 {
-  if (ctx)
-    {
-      ctx->io_monitor = io_monitor;
-      ctx->io_monitor_data = hook_data;
-    }
+  TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_set_io_monitor", ctx,
+	  "io_monitor=%p,hook_data=%p", io_monitor, hook_data);
+
+  if (! ctx)
+    return;
+
+  ctx->io_monitor = io_monitor;
+  ctx->io_monitor_data = hook_data;
 }
 
 

@@ -121,6 +161,10 @@ void assuan_set_io_monitor (assuan_context_t ctx,
 gpg_error_t
 assuan_set_error (assuan_context_t ctx, gpg_error_t err, const char *text)
 {
+  TRACE4 (ctx, ASSUAN_LOG_CTX, "assuan_set_error", ctx,
+	  "err=%i (%s,%s),text=%s", err, gpg_strsource (err),
+	  gpg_strerror (err), text);
+  
   ctx->err_no = err;
   ctx->err_str = text;
   return err;
diff --git a/src/conversion.c b/src/conversion.c
index af5026e..88a7fd0 100644
--- a/src/conversion.c
+++ b/src/conversion.c
@@ -1,6 +1,6 @@
 /* conversion.c - String conversion helper functions.
    Copyright (C) 2000 Werner Koch (dd9jn)
-   Copyright (C) 2001, 2002, 2003, 2004, 2007 g10 Code GmbH
+   Copyright (C) 2001, 2002, 2003, 2004, 2007, 2009 g10 Code GmbH
  
    This file is part of Assuan.
 
@@ -25,9 +25,6 @@
 
 #include <stdlib.h>
 #include <string.h>
-/* Solaris 8 needs sys/types.h before time.h.  */
-#include <sys/types.h>
-#include <time.h>
 #include <errno.h>
 #include <ctype.h>
 
diff --git a/src/debug.h b/src/debug.h
index 13e5419..4b4a41d 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -123,6 +123,12 @@ void _assuan_debug_buffer (assuan_context_t ctx, unsigned int cat,
 		 "%s (%s=%p): enter: " fmt "\n",			\
 		 _assuan_trace_func, _assuan_trace_tagname,		\
 		 _assuan_trace_tag, arg1, arg2, arg3, arg4), 0
+#define TRACE_BEG6(ctx, lvl, name, tag, fmt, arg1, arg2, arg3, arg4,arg5,arg6) \
+  _TRACE (ctx, lvl, name, tag);						\
+  _assuan_debug (_assuan_trace_context, _assuan_trace_level,		\
+		 "%s (%s=%p): enter: " fmt "\n",			\
+		 _assuan_trace_func, _assuan_trace_tagname,		\
+		 _assuan_trace_tag, arg1, arg2, arg3, arg4, arg5, arg6), 0
 
 #define TRACE_BEG8(ctx, lvl, name, tag, fmt, arg1, arg2, arg3, arg4,	\
 		   arg5, arg6, arg7, arg8)				\
@@ -149,6 +155,10 @@ void _assuan_debug_buffer (assuan_context_t ctx, unsigned int cat,
   _assuan_debug (ctx, lvl, "%s (%s=%p): call: " fmt "\n",		\
 		 name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \
 		 arg2, arg3), 0
+#define TRACE4(ctx, lvl, name, tag, fmt, arg1, arg2, arg3, arg4)	\
+  _assuan_debug (ctx, lvl, "%s (%s=%p): call: " fmt "\n",		\
+		 name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \
+		 arg2, arg3, arg4), 0
 #define TRACE6(ctx, lvl, name, tag, fmt, arg1, arg2, arg3, arg4, arg5, arg6) \
   _assuan_debug (ctx, lvl, "%s (%s=%p): call: " fmt "\n",		\
 		 name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1,	\
@@ -171,7 +181,7 @@ void _assuan_debug_buffer (assuan_context_t ctx, unsigned int cat,
 		   _assuan_trace_tag, strerror (errno)), (res))
 #define TRACE_SYSERR(res)						\
   res == 0 ? ((void) (TRACE_SUC1 ("result=%i", res)), (res)) :		\
-    (_assuan_debug (_assuan_trace_level, "%s (%s=%p): error: %s\n",	\
+    (_assuan_debug (_assuan_trace_context, _assuan_trace_level, "%s (%s=%p): error: %s\n", \
 		    _assuan_trace_func, _assuan_trace_tagname,		\
 		    _assuan_trace_tag, strerror (res)), (res))
 
diff --git a/src/libassuan-config.in b/src/libassuan-config.in
index 50c9805..561ff96 100644
--- a/src/libassuan-config.in
+++ b/src/libassuan-config.in
@@ -18,8 +18,6 @@ lib="@LIBASSUAN_CONFIG_LIB@"
 extralibs="@LIBASSUAN_CONFIG_EXTRA_LIBS@ $gpg_error_libs"
 cflags="@LIBASSUAN_CONFIG_CFLAGS@ $gpg_error_cflags"
 api_version="@LIBASSUAN_CONFIG_API_VERSION@"
-all_thread_modules="@LIBASSUAN_CONFIG_THREAD_MODULES@"
-thread_module=
 prefix=@prefix@
 exec_prefix=@exec_prefix@
 includes=""
@@ -31,18 +29,11 @@ echo_prefix=no
 echo_exec_prefix=no
 
 
-if test x"$all_thread_modules" = x; then
-  all_thread_modules="none pthread"
-else
-  all_thread_modules="none pthread $all_thread_modules"
-fi
-
 usage()
 {
 	cat <<EOF
 Usage: $PGM [OPTIONS]
 Options:
-	[--thread={`echo "${all_thread_modules}" | sed 's/ /|/g'`}]
 	[--prefix[=DIR]]
 	[--exec-prefix[=DIR]]
 	[--version]
@@ -82,22 +73,6 @@ while test $# -gt 0; do
     --api-version)
       echo_api_version=yes
       ;;
-    --thread=*)
-      for mod in $all_thread_modules; do
-	if test "$mod" = "$optarg"; then
-           thread_module="-$mod"
-	fi
-      done
-      if test "x$thread_module" = "x"; then
-	usage 1 1>&2
-      fi
-      if test "$thread_module" = "-none"; then
-        thread_module=""
-      fi
-      if test "$thread_module" = "-pthread"; then
-        thread_module=""
-      fi
-      ;;
     --cflags)
       echo_cflags=yes
       ;;
@@ -145,5 +120,5 @@ if test "$echo_libs" = "yes"; then
 	fi
       done
     fi
-    echo $libdirs $lib${thread_module} $extralibs
+    echo $libdirs $lib $extralibs
 fi
diff --git a/src/libassuan.def b/src/libassuan.def
index b2450d8..9750748 100644
--- a/src/libassuan.def
+++ b/src/libassuan.def
@@ -84,7 +84,16 @@ EXPORTS
     assuan_transact			@63
     assuan_write_line			@64
     assuan_write_status			@65
+    assuan_sock_init
+    assuan_sock_deinit
     assuan_get_command_name             @66
 
+    __assuan_pipe
+    __assuan_close
+    __assuan_spawn
+    __assuan_socketpair
+    assuan_set_system_hooks
+    assuan_ctx_set_system_hooks
+
 ; END
 
diff --git a/src/libassuan.m4 b/src/libassuan.m4
index 004eee3..bac1be8 100644
--- a/src/libassuan.m4
+++ b/src/libassuan.m4
@@ -131,45 +131,3 @@ AC_DEFUN([AM_PATH_LIBASSUAN],
   AC_SUBST(LIBASSUAN_CFLAGS)
   AC_SUBST(LIBASSUAN_LIBS)
 ])
-
-
-dnl AM_PATH_LIBASSUAN_PTH([MINIMUM-VERSION,
-dnl                      [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
-dnl Test for libassuan and define LIBASSUAN_PTH_CFLAGS and LIBASSUAN_PTH_LIBS
-dnl
-AC_DEFUN([AM_PATH_LIBASSUAN_PTH],
-[ _AM_PATH_LIBASSUAN_COMMON($1,pth)
-  if test $ok = yes; then
-    LIBASSUAN_PTH_CFLAGS=`$LIBASSUAN_CONFIG $libassuan_config_args --thread=pth --cflags`
-    LIBASSUAN_PTH_LIBS=`$LIBASSUAN_CONFIG $libassuan_config_args --thread=pth --libs`
-    ifelse([$2], , :, [$2])
-  else
-    LIBASSUAN_PTH_CFLAGS=""
-    LIBASSUAN_PTH_LIBS=""
-    ifelse([$3], , :, [$3])
-  fi
-  AC_SUBST(LIBASSUAN_PTH_CFLAGS)
-  AC_SUBST(LIBASSUAN_PTH_LIBS)
-])
-
-
-dnl AM_PATH_LIBASSUAN_PTHREAD([MINIMUM-VERSION,
-dnl                           [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
-dnl Test for libassuan and define LIBASSUAN_PTHREAD_CFLAGS 
-dnl                           and LIBASSUAN_PTHREAD_LIBS
-dnl
-AC_DEFUN([AM_PATH_LIBASSUAN_PTHREAD],
-[ _AM_PATH_LIBASSUAN_COMMON($1,pthread)
-  if test $ok = yes; then
-    LIBASSUAN_PTHREAD_CFLAGS=`$LIBASSUAN_CONFIG $libassuan_config_args --thread=pthread --cflags`
-    LIBASSUAN_PTHREAD_LIBS=`$LIBASSUAN_CONFIG $libassuan_config_args --thread=pthread --libs`
-    ifelse([$2], , :, [$2])
-  else
-    LIBASSUAN_PTHREAD_CFLAGS=""
-    LIBASSUAN_PTHREAD_LIBS=""
-    ifelse([$3], , :, [$3])
-  fi
-  AC_SUBST(LIBASSUAN_PTHREAD_CFLAGS)
-  AC_SUBST(LIBASSUAN_PTHREAD_LIBS)
-])
-
diff --git a/src/libassuan.vers b/src/libassuan.vers
index e4f6a7a..9b5b5e0 100644
--- a/src/libassuan.vers
+++ b/src/libassuan.vers
@@ -91,6 +91,14 @@ LIBASSUAN_1.0 {
     assuan_new_ext;
     assuan_new;
     assuan_release;
+    assuan_sock_init;
+    assuan_sock_deinit;
+    __assuan_pipe;
+    __assuan_close;
+    __assuan_spawn;
+    __assuan_socketpair;
+    assuan_set_system_hooks;
+    assuan_ctx_set_system_hooks;
 
   local:
     *;
diff --git a/src/system.c b/src/system.c
index dd0c079..91a5a10 100644
--- a/src/system.c
+++ b/src/system.c
@@ -24,10 +24,25 @@
 
 #include <stdlib.h>
 #include <errno.h>
+/* Solaris 8 needs sys/types.h before time.h.  */
+#include <sys/types.h>
+#include <time.h>
+#include <fcntl.h>
+#ifdef HAVE_W32_SYSTEM
+# include <windows.h>
+#else
+# include <sys/wait.h>
+#endif
 
 #include "assuan-defs.h"
 #include "debug.h"
 
+#ifdef _POSIX_OPEN_MAX
+#define MAX_OPEN_FDS _POSIX_OPEN_MAX
+#else
+#define MAX_OPEN_FDS 20
+#endif
+
 

 /* Manage memory specific to a context.  */
 
@@ -70,3 +85,793 @@ _assuan_free (assuan_context_t ctx, void *ptr)
   if (ptr)
     ctx->malloc_hooks.free (ptr);
 }
+
+

+/* Copy the system hooks struct, paying attention to version
+   differences.  SRC is usually from the user, DST MUST be from the
+   library.  */
+void
+_assuan_system_hooks_copy (assuan_system_hooks_t dst,
+			   assuan_system_hooks_t src)
+
+{
+  memset (dst, '\0', sizeof (*dst));
+
+  dst->version = ASSUAN_SYSTEM_HOOKS_VERSION;
+  if (src->version >= 1)
+    {
+      dst->usleep = src->usleep;
+      dst->pipe = src->pipe;
+      dst->close = src->close;
+      dst->read = src->read;
+      dst->write = src->write;
+      dst->sendmsg = src->sendmsg;
+      dst->recvmsg = src->recvmsg;
+      dst->spawn = src->spawn;
+      dst->waitpid = src->waitpid;
+      dst->socketpair = src->socketpair;
+    }
+  if (src->version > 1)
+    /* FIXME.  Application uses newer version of the library.  What to
+       do?  */
+    ;
+}
+
+

+/* Sleep for the given number of microseconds.  Default
+   implementation.  */
+static void
+__assuan_usleep (assuan_context_t ctx, unsigned int usec)
+{
+  if (! usec)
+    return;
+
+#ifdef HAVE_NANOSLEEP
+  {
+    struct timespec req;
+    struct timespec rem;
+      
+    req.tv_sec = 0;
+    req.tv_nsec = usec * 1000;
+  
+    while (nanosleep (&req, &rem) < 0 && errno == EINTR)
+      req = rem;
+  }
+#elif defined(HAVE_W32_SYSTEM)
+  Sleep (usec / 1000);
+#else
+  {
+    struct timeval tv;
+  
+    tv.tv_sec  = usec / 1000000;
+    tv.tv_usec = usec % 1000000;
+    select (0, NULL, NULL, NULL, &tv);
+  }
+#endif
+}
+
+
+/* Sleep for the given number of microseconds.  */
+void
+_assuan_usleep (assuan_context_t ctx, unsigned int usec)
+{
+  TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_usleep", ctx,
+	  "usec=%u", usec);
+
+  return (ctx->system.usleep) (ctx, usec);
+}
+
+

+/* Create a pipe with one inheritable end.  Default implementation.  */
+int
+__assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
+{
+#ifdef HAVE_W32_SYSTEM
+  HANDLE rh;
+  HANDLE wh;
+  HANDLE th;
+  SECURITY_ATTRIBUTES sec_attr;
+  TRACE_BEG2 (ctx, ASSUAN_LOG_SYSIO, "__assuan_pipe", ctx,
+	      "inherit_idx=%i (Assuan uses it for %s)",
+	      inherit_idx, inherit_idx ? "reading" : "writing");
+
+  memset (&sec_attr, 0, sizeof (sec_attr));
+  sec_attr.nLength = sizeof (sec_attr);
+  sec_attr.bInheritHandle = FALSE;
+
+  if (! CreatePipe (&rh, &wh, &sec_attr, 0))
+    {
+      TRACE_LOG1 ("CreatePipe failed: %s", _assuan_w32_strerror (ctx, -1));
+      errno = EIO;
+      return TRACE_SYSRES (-1);
+    }
+
+  if (! DuplicateHandle (GetCurrentProcess(), (inherit_idx == 0) ? rh : wh,
+			 GetCurrentProcess(), &th, 0,
+			 TRUE, DUPLICATE_SAME_ACCESS ))
+    {
+      TRACE_LOG1 ("DuplicateHandle failed: %s", _assuan_w32_strerror (ctx, -1));
+      CloseHandle (rh);
+      CloseHandle (wh);
+      errno = EIO;
+      return TRACE_SYSRES (-1);
+    }
+  if (inherit_idx == 0)
+    {
+      CloseHandle (rh);
+      rh = th;
+    }
+  else
+    {
+      CloseHandle (wh);
+      wh = th;
+    }
+
+  fd[0] = rh;
+  fd[1] = wh;
+
+  return TRACE_SUC ();
+#else
+  return pipe (fd);
+#endif
+}
+
+
+/* Create a pipe with one inheritable end.  */
+int
+_assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
+{
+  return (ctx->system.pipe) (ctx, fd, inherit_idx);
+}
+
+

+/* Close the given file descriptor, created with _assuan_pipe or one
+   of the socket functions.  Default implementation.  */
+int
+__assuan_close (assuan_context_t ctx, assuan_fd_t fd)
+{
+#ifdef HAVE_W32_SYSTEM
+  int rc = closesocket (HANDLE2SOCKET(fd));
+  if (rc)
+    errno = _assuan_sock_wsa2errno (WSAGetLastError ());
+  if (rc && WSAGetLastError () == WSAENOTSOCK)
+    {
+      rc = CloseHandle (fd);
+      if (rc)
+        /* FIXME. */
+        errno = EIO;
+    }
+  return rc;
+#else
+  return close (fd);
+#endif
+}
+
+
+/* Close the given file descriptor, created with _assuan_pipe or one
+   of the socket functions.  */
+int
+_assuan_close (assuan_context_t ctx, assuan_fd_t fd)
+{
+  TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_close", ctx,
+	  "fd=0x%x", fd);
+
+  return (ctx->system.close) (ctx, fd);
+}
+
+

+static ssize_t
+__assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
+{
+#ifdef HAVE_W32_SYSTEM
+  /* Due to the peculiarities of the W32 API we can't use read for a
+     network socket and thus we try to use recv first and fallback to
+     read if recv detects that it is not a network socket.  */
+  int res;
+
+  res = recv (HANDLE2SOCKET (fd), buffer, size, 0);
+  if (res == -1)
+    {
+      switch (WSAGetLastError ())
+        {
+        case WSAENOTSOCK:
+          {
+            DWORD nread = 0;
+            
+            res = ReadFile (fd, buffer, size, &nread, NULL);
+            if (! res)
+              {
+                switch (GetLastError ())
+                  {
+                  case ERROR_BROKEN_PIPE:
+		    errno = EPIPE;
+		    break;
+
+                  default:
+		    errno = EIO; 
+                  }
+                res = -1;
+              }
+            else
+              res = (int) nread;
+          }
+          break;
+          
+        case WSAEWOULDBLOCK:
+	  errno = EAGAIN;
+	  break;
+
+        case ERROR_BROKEN_PIPE:
+	  errno = EPIPE;
+	  break;
+
+        default:
+	  errno = EIO;
+	  break;
+        }
+    }
+  return res;
+#else	/*!HAVE_W32_SYSTEM*/
+  return read (fd, buffer, size);
+#endif	/*!HAVE_W32_SYSTEM*/
+}
+
+
+ssize_t
+_assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
+{
+  return (ctx->system.read) (ctx, fd, buffer, size);
+}
+
+

+static ssize_t
+__assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
+		size_t size)
+{
+#ifdef HAVE_W32_SYSTEM
+  /* Due to the peculiarities of the W32 API we can't use write for a
+     network socket and thus we try to use send first and fallback to
+     write if send detects that it is not a network socket.  */
+  int res;
+
+  res = send (HANDLE2SOCKET (fd), buffer, size, 0);
+  if (res == -1 && WSAGetLastError () == WSAENOTSOCK)
+    {
+      DWORD nwrite;
+
+      res = WriteFile (fd, buffer, size, &nwrite, NULL);
+      if (! res)
+        {
+          switch (GetLastError ())
+            {
+            case ERROR_BROKEN_PIPE: 
+            case ERROR_NO_DATA:
+	      errno = EPIPE;
+	      break;
+	      
+            default:
+	      errno = EIO;
+	      break;
+            }
+          res = -1;
+        }
+      else
+        res = (int) nwrite;
+    }
+  return res;
+#else	/*!HAVE_W32_SYSTEM*/
+  return write (fd, buffer, size);
+#endif	/*!HAVE_W32_SYSTEM*/
+}
+
+
+ssize_t
+_assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
+	       size_t size)
+{
+  return (ctx->system.write) (ctx, fd, buffer, size);
+}
+
+

+static int
+__assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
+		  int flags)
+{
+#ifdef HAVE_W32_SYSTEM
+  errno = ENOSYS;
+  return -1;
+#else
+  int ret;
+  do
+    ret = recvmsg (fd, msg, flags);
+  while (ret == -1 && errno == EINTR);
+
+  return ret;
+#endif
+}
+
+
+int
+_assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
+		 int flags)
+{
+  return (ctx->system.recvmsg) (ctx, fd, msg, flags);
+}
+
+

+static int
+__assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
+		  int flags)
+{
+#ifdef HAVE_W32_SYSTEM
+  errno = ENOSYS;
+  return -1;
+#else
+  int ret;
+  do
+    ret = sendmsg (fd, msg, flags);
+  while (ret == -1 && errno == EINTR);
+
+  return ret;
+#endif
+}
+
+
+int
+_assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
+		 int flags)
+{
+  return (ctx->system.sendmsg) (ctx, fd, msg, flags);
+}
+
+

+#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.  */
+static int
+build_w32_commandline (assuan_context_t ctx, const char * const *argv,
+		       char **cmdline)
+{
+  int i, n;
+  const char *s;
+  char *buf, *p;
+
+  *cmdline = NULL;
+  n = 0;
+  for (i=0; (s = argv[i]); i++)
+    {
+      n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting */
+      for (; *s; s++)
+        if (*s == '\"')
+          n++;  /* Need to double inner quotes.  */
+    }
+  n++;
+
+  buf = p = _assuan_malloc (ctx, n);
+  if (! buf)
+    return -1;
+
+  for (i = 0; argv[i]; i++) 
+    {
+      if (i)
+        p = stpcpy (p, " ");
+      if (! *argv[i]) /* Empty string. */
+        p = stpcpy (p, "\"\"");
+      else if (strpbrk (argv[i], " \t\n\v\f\""))
+        {
+          p = stpcpy (p, "\"");
+          for (s = argv[i]; *s; s++)
+            {
+              *p++ = *s;
+              if (*s == '\"')
+                *p++ = *s;
+            }
+          *p++ = '\"';
+          *p = 0;
+        }
+      else
+        p = stpcpy (p, argv[i]);
+    }
+
+  *cmdline= buf;
+  return 0;
+}
+
+
+int
+__assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
+		const char **argv,
+		assuan_fd_t fd_in, assuan_fd_t fd_out,
+		assuan_fd_t *fd_child_list,
+		void (*atfork) (void *opaque, int reserved),
+		void *atforkvalue, unsigned int flags)
+{
+  SECURITY_ATTRIBUTES sec_attr;
+  PROCESS_INFORMATION pi = 
+    {
+      NULL,      /* Returns process handle.  */
+      0,         /* Returns primary thread handle.  */
+      0,         /* Returns pid.  */
+      0          /* Returns tid.  */
+    };
+  STARTUPINFO si;
+  int fd;
+  int *fdp;
+  char *cmdline;
+  HANDLE nullfd = INVALID_HANDLE_VALUE;
+
+  /* fixme: Actually we should set the "_assuan_pipe_connect_pid" env
+     variable.  However this requires us to write a full environment
+     handler, because the strings are expected in sorted order.  The
+     suggestion given in the MS Reference Library, to save the old
+     value, changeit, create proces and restore it, is not thread
+     safe.  */
+
+  /* Build the command line.  */
+  if (build_w32_commandline (ctx, argv, &cmdline))
+    return -1;
+
+  /* Start the process.  */
+  memset (&sec_attr, 0, sizeof sec_attr);
+  sec_attr.nLength = sizeof sec_attr;
+  sec_attr.bInheritHandle = FALSE;
+  
+  memset (&si, 0, sizeof si);
+  si.cb = sizeof (si);
+  si.dwFlags = STARTF_USESTDHANDLES;
+  /* FIXME: Dup to nul if ASSUAN_INVALID_FD.  */
+  si.hStdInput  = fd_in;
+  si.hStdOutput = fd_out;
+
+  /* Dup stderr to /dev/null unless it is in the list of FDs to be
+     passed to the child. */
+  fd = fileno (stderr);
+  fdp = fd_child_list;
+  if (fdp)
+    {
+      for (; *fdp != -1 && *fdp != fd; fdp++)
+        ;
+    }
+  if (!fdp || *fdp == -1)
+    {
+      nullfd = CreateFile ("nul", GENERIC_WRITE,
+                           FILE_SHARE_READ | FILE_SHARE_WRITE,
+                           NULL, OPEN_EXISTING, 0, NULL);
+      if (nullfd == INVALID_HANDLE_VALUE)
+        {
+	  TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
+		  "can't open `nul': %s", w32_strerror (ctx, -1));
+          _assuan_free (cmdline);
+          return -1;
+        }
+      si.hStdError = nullfd;
+    }
+  else
+    si.hStdError = (void*)_get_osfhandle (fd);
+
+
+  /* Note: We inherit all handles flagged as inheritable.  This seems
+     to be a security flaw but there seems to be no way of selecting
+     handles to inherit. */
+  /*   _assuan_log_printf ("CreateProcess, path=`%s' cmdline=`%s'\n", */
+  /*                       name, cmdline); */
+  if (!CreateProcess (name,                 /* Program to start.  */
+                      cmdline,              /* Command line arguments.  */
+                      &sec_attr,            /* Process security attributes.  */
+                      &sec_attr,            /* Thread security attributes.  */
+                      TRUE,                 /* Inherit handles.  */
+                      (CREATE_DEFAULT_ERROR_MODE
+                       | ((flags & 128)? DETACHED_PROCESS : 0)
+                       | GetPriorityClass (GetCurrentProcess ())
+                       | CREATE_SUSPENDED), /* Creation flags.  */
+                      NULL,                 /* Environment.  */
+                      NULL,                 /* Use current drive/directory.  */
+                      &si,                  /* Startup information. */
+                      &pi                   /* Returns process information.  */
+                      ))
+    {
+      TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_w32", ctx,
+	      "CreateProcess failed: %s", w32_strerror (ctx, -1));
+      _assuan_free (cmdline);
+      if (nullfd != INVALID_HANDLE_VALUE)
+        CloseHandle (nullfd);
+
+      errno = EIO;
+      return -1;
+    }
+
+  _assuan_free (cmdline);
+  if (nullfd != INVALID_HANDLE_VALUE)
+    CloseHandle (nullfd);
+
+  ResumeThread (pi.hThread);
+  CloseHandle (pi.hThread); 
+
+  /*   _assuan_log_printf ("CreateProcess ready: hProcess=%p hThread=%p" */
+  /*                       " dwProcessID=%d dwThreadId=%d\n", */
+  /*                       pi.hProcess, pi.hThread, */
+  /*                       (int) pi.dwProcessId, (int) pi.dwThreadId); */
+
+  *r_pid = (pid_t) pi.hProcess;
+
+  /* No need to modify peer process, as we don't change the handle
+     names.  However this also means we are not safe, as we inherit
+     too many handles.  Should use approach similar to gpgme and glib
+     using a helper process.  */
+
+  return 0;
+}
+
+#else
+
+static int
+writen (int fd, const char *buffer, size_t length)
+{
+  while (length)
+    {
+      int nwritten = write (fd, buffer, length);
+      
+      if (nwritten < 0)
+        {
+          if (errno == EINTR)
+            continue;
+          return -1; /* write error */
+        }
+      length -= nwritten;
+      buffer += nwritten;
+    }
+  return 0;  /* okay */
+}
+
+
+int
+__assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
+		const char **argv,
+		assuan_fd_t fd_in, assuan_fd_t fd_out,
+		assuan_fd_t *fd_child_list,
+		void (*atfork) (void *opaque, int reserved),
+		void *atforkvalue, unsigned int flags)
+{
+  int pid;
+
+  pid = fork ();
+  if (pid < 0)
+    return -1;
+
+  if (pid == 0)
+    {
+      /* Child process (server side).  */
+      int i;
+      int n;
+      char errbuf[512];
+      int *fdp;
+      int fdnul;
+
+      if (atfork)
+	atfork (atforkvalue, 0);
+
+      fdnul = open ("/dev/null", O_WRONLY);
+      if (fdnul == -1)
+	{
+	  TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
+		  "can't open `/dev/null': %s", strerror (errno));
+	  _exit (4);
+	}
+      
+      /* Dup handles to stdin/stdout. */
+      if (fd_out != STDOUT_FILENO)
+	{
+	  if (dup2 (fd_out == ASSUAN_INVALID_FD ? fdnul : fd_out,
+		    STDOUT_FILENO) == -1)
+	    {
+	      TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
+		      "dup2 failed in child: %s", strerror (errno));
+	      _exit (4);
+	    }
+	}
+      
+      if (fd_in != STDIN_FILENO)
+	{
+	  if (dup2 (fd_in == ASSUAN_INVALID_FD ? fdnul : fd_in,
+		    STDIN_FILENO) == -1)
+	    {
+	      TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
+		      "dup2 failed in child: %s", 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)
+	{
+	  if (dup2 (fdnul, STDERR_FILENO) == -1)
+	    {
+	      TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx,
+		      "dup2(dev/null, 2) failed: %s", strerror (errno));
+	      _exit (4);
+	    }
+	}
+      close (fdnul);
+      
+      /* 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;
+      
+      if (! name)
+	{
+	  /* No name and no args given, thus we don't do an exec
+	     but continue the forked process.  */
+	  *argv = "server";
+	  
+	  /* FIXME: Cleanup.  */
+	  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 (ctx, GPG_ERR_ASS_SERVER_START),
+		name, strerror (errno));
+      errbuf[sizeof(errbuf)-1] = 0;
+      writen (1, errbuf, strlen (errbuf));
+      _exit (4);
+    }
+
+  if (! name)
+    *argv = "client";
+  
+  *r_pid = pid;
+
+  return 0;
+}
+#endif	/* ! HAVE_W32_SYSTEM */
+
+
+/* Create a new process from NAME and ARGV.  Provide FD_IN and FD_OUT
+   as stdin and stdout.  Inherit the ASSUAN_INVALID_FD-terminated
+   FD_CHILD_LIST as given (no remapping), which must be inheritable.
+   On Unix, call ATFORK with ATFORKVALUE after fork and before exec.  */
+int
+_assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
+	       const char **argv,
+	       assuan_fd_t fd_in, assuan_fd_t fd_out,
+	       assuan_fd_t *fd_child_list,
+	       void (*atfork) (void *opaque, int reserved),
+	       void *atforkvalue, unsigned int flags)
+{
+  int res;
+  int i;
+  TRACE_BEG6 (ctx, ASSUAN_LOG_CTX, "_assuan_spawn", ctx,
+	      "name=%s,fd_in=0x%x,fd_out=0x%x,"
+	      "atfork=%p,atforkvalue=%p,flags=%i",
+	      name ? name : "(null)", fd_in, fd_out,
+	      atfork, atforkvalue, flags);
+
+  if (name)
+    {
+      i = 0;
+      while (argv[i])
+	{
+	  TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
+	  i++;
+	}
+    }
+  i = 0;
+  while (fd_child_list[i] != ASSUAN_INVALID_FD)
+    {
+      TRACE_LOG2 ("fd_child_list[%2i] = 0x%x", i, fd_child_list[i]);
+      i++;
+    }
+
+  res = (ctx->system.spawn) (ctx, r_pid, name, argv, fd_in, fd_out,
+			      fd_child_list, atfork, atforkvalue, flags);
+
+  if (name)
+    {
+      TRACE_LOG1 ("pid = 0x%x", *r_pid);
+    }
+  else
+    {
+      TRACE_LOG2 ("pid = 0x%x (%s)", *r_pid, *argv);
+    }
+
+  return TRACE_SYSERR (res);
+}
+
+

+/* FIXME: Add some sort of waitpid function that covers GPGME and
+   gpg-agent's use of assuan.  */
+static pid_t 
+__assuan_waitpid (assuan_context_t ctx, pid_t pid, int nowait,
+		  int *status, int options)
+{
+#ifndef HAVE_W32_SYSTEM
+  /* We can't just release the PID, a waitpid is mandatory.  But
+     NOWAIT in POSIX systems just means the caller already did the
+     waitpid for this child.  */
+  if (! nowait)
+    return waitpid (pid, NULL, 0); 
+#else	/* ! HAVE_W32_SYSTEM */
+  CloseHandle ((HANDLE) pid);
+#endif	/* HAVE_W32_SYSTEM */
+}
+
+
+pid_t 
+_assuan_waitpid (assuan_context_t ctx, pid_t pid, int action,
+		 int *status, int options)
+{
+  return (ctx->system.waitpid) (ctx, pid, action, status, options);
+}
+
+

+int
+__assuan_socketpair (assuan_context_t ctx, int namespace, int style,
+		     int protocol, int filedes[2])
+{
+#if HAVE_W32_SYSTEM
+  errno = ENOSYS;
+  return -1;
+#else
+  return socketpair (namespace, style, protocol, filedes);
+#endif
+}
+
+int
+_assuan_socketpair (assuan_context_t ctx, int namespace, int style,
+		    int protocol, assuan_fd_t filedes[2])
+{
+  int res;
+  TRACE_BEG4 (ctx, ASSUAN_LOG_SYSIO, "_assuan_socketpair", ctx,
+	      "namespace=%i,style=%i,protocol=%i,filedes=%p",
+	      namespace, style, protocol, filedes);
+  
+  res = (ctx->system.socketpair) (ctx, namespace, style, protocol, filedes);
+  if (res == 0)
+    TRACE_LOG2 ("filedes = { 0x%x, 0x%x }", filedes[0], filedes[1]);
+
+  return TRACE_SYSERR (res);
+}
+
+

+/* The default system hooks for assuan contexts.  */
+struct assuan_system_hooks _assuan_system_hooks =
+  {
+    ASSUAN_SYSTEM_HOOKS_VERSION,
+    __assuan_usleep,
+    __assuan_pipe,
+    __assuan_close,
+    __assuan_read,
+    __assuan_write,
+    __assuan_recvmsg,
+    __assuan_sendmsg,
+    __assuan_spawn,
+    __assuan_waitpid,
+    __assuan_socketpair    
+  };

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-gnupg/libassuan.git



More information about the Pkg-gnupg-commit mailing list