[Pkg-gnupg-commit] [libassuan] 305/437: Changed the implementation of CreatePipe under W32CE. Reorganized the source.

Eric Dorland eric at moszumanska.debian.org
Fri May 22 05:33:56 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 f807c38fc5e6b703b85fe86ea8946c9f42bc3e53
Author: Werner Koch <wk at gnupg.org>
Date:   Mon Mar 22 12:16:18 2010 +0000

    Changed the implementation of CreatePipe under W32CE.
    Reorganized the source.
---
 ChangeLog                     |  70 ++-----
 configure.ac                  |  20 +-
 doc/assuan.texi               |  13 +-
 src/ChangeLog                 |  34 ++++
 src/Makefile.am               |  15 +-
 src/assuan-defs.h             |   1 +
 src/assuan-pipe-connect.c     |   8 +-
 src/{assuan.h => assuan.h.in} |  12 +-
 src/gpgcedev.c                | 183 ++++++++++--------
 src/libassuan.def             |   2 +
 src/mkheader.c                | 192 +++++++++++++++++++
 src/system-w32.c              |  27 +++
 src/system-w32ce.c            | 425 ++++++++++++++++++++++++++++--------------
 src/system.c                  |  16 ++
 src/sysutils.c                |  81 +-------
 tests/ChangeLog               |  67 +++++++
 tests/Makefile.am             |   2 +-
 tests/ce-createpipe.c         |   4 +-
 tests/ce-server.c             |   2 +
 tests/pipeconnect.c           | 397 +++++++++++++++++++++++++++++++++++++++
 20 files changed, 1196 insertions(+), 375 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 39a01c5..874dbef 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,13 +1,15 @@
-2010-02-25  Werner Koch  <wk at g10code.com>
+2010-03-22  Werner Koch  <wk at g10code.com>
 
-	* m4/libtool.m4 (_LT_CHECK_MAGIC_METHOD): Fix for non x86 mingw
-	targets.
+	* configure.ac (CC_FOR_BUILD): Add test.
 
-2010-02-24  Werner Koch  <wk at g10code.com>
+2010-03-17  Werner Koch  <wk at g10code.com>
 
-	* tests/ce-server.c: New.
+	* tests/ChangeLog: New.  Move all relevant entries to there.
 
-	* tests/ce-createpipe.c [W32CE]: New.
+2010-02-25  Werner Koch  <wk at g10code.com>
+
+	* m4/libtool.m4 (_LT_CHECK_MAGIC_METHOD): Fix for non x86 mingw
+	targets.
 
 2010-02-11  Werner Koch  <wk at g10code.com>
 
@@ -17,10 +19,6 @@
 
 	* configure.ac (AC_TYPE_UINT16_T): New.
 
-2010-01-27  Werner Koch  <wk at g10code.com>
-
-	* tests/common.h (SOCKET2HANDLE, HANDLE2SOCKET): New.
-
 2010-01-26  Werner Koch  <wk at g10code.com>
 
 	* configure.ac (NETLIBS) [W32CE]: Use -lws2.
@@ -49,16 +47,6 @@
 
 	* configure.ac: Bump version to 2.0.0.
 
-2009-11-05  Marcus Brinkmann  <marcus at g10code.de>
-
-	* tests/fdpassing.c (main): Call assuan_pipe_connect instead
-	of assuan_pipe_connect_ext.
-
-2009-11-04  Werner Koch  <wk at g10code.com>
-
-	* tests/fdpassing.c (register_commands): Add NULL arg to
-	assuan_register_command.
-
 2009-10-16  Marcus Brinkmann  <marcus at g10code.de>
 
 	* autogen.sh: Remove --with-pth-prefix from configure invocation.
@@ -74,7 +62,6 @@
 
 2009-09-19  Marcus Brinkmann  <marcus at g10code.de>
 
-	* tests/fdpassing.c: Update to new API.
 	* configure.ac: Check for stdint.h and inttypes.h.  Invoke
 	AC_TYPE_UINTPTR_T.
 
@@ -101,18 +88,11 @@
 	(AC_CONFIG_FILES): Add src/versioninfo.rc.
 	* ltmain.sh, m4/libtool.m4, m4/ltoptions.m4, m4/ltsugar.m4,
 	m4/ltversion.m4, m4/lt~obsolete.m4: New files from libtool 2.2.6.
-	* tests/Makefile.am (AM_CFLAGS, LDADD): Add gpg-error.
-	* tests/fdpassing.c: Change error values to gpg-error ones.
 
 2009-01-22  Werner Koch  <wk at g10code.com>
 
 	* configure.ac: Check for nanoleep only in libc.
 
-2008-11-03  Marcus Brinkmann  <marcus at g10code.de>
-
-	* tests/fdpassing.c (register_commands): Add missing initializer
-	to silence gcc -W warning.
-
 2008-05-25  Werner Koch  <wk at g10code.com>
 
 	Released 1.0.5.
@@ -130,7 +110,7 @@
 2007-08-24  Werner Koch  <wk at g10code.com>
 
 	Released 1.0.3.
-	
+
 	Switched license of the library code back to LGPLv2.1.  See NEWS.
 
 	* COPYING.LIB: Replaced by LPGLv2.1
@@ -138,7 +118,7 @@
 2007-07-05  Werner Koch  <wk at g10code.com>
 
 	Released 1.0.2.
-	
+
 	Relicensed to LGPLv3.
 
 	* COPYING: Replaced by GPLv3.
@@ -162,13 +142,13 @@
 
 2007-05-30  Werner Koch  <wk at g10code.com>
 
-	* autogen.sh <--build-w32>: Modernize. 
+	* autogen.sh <--build-w32>: Modernize.
 
 2007-05-29  Werner Koch  <wk at g10code.com>
 
 	* configure.ac: Require automake 1.10 and autoconf 2.61.
 	(AM_PROG_CC_C_O): New.  Error out if no C-89 cc is installed.
-	(gl_HEADER_SYS_SOCKET): Explicitly add this for documentation. 
+	(gl_HEADER_SYS_SOCKET): Explicitly add this for documentation.
 
 2007-05-24  Werner Koch  <wk at g10code.com>
 
@@ -202,8 +182,6 @@
 
 	Released 0.9.3.
 
-	* tests/Makefile.am (LDADD): Add NETLIBS.
-
 	* configure.ac: Check for cmsghdr.
 	(USE_DESCRIPTOR_PASSING): Define it then.
 
@@ -214,29 +192,15 @@
 2006-10-04  Werner Koch  <wk at g10code.com>
 
 	Released 0.9.2.
-	
+
 2006-10-04  Werner Koch  <wk at g10code.com>
 
 	Released 0.9.1.
-	
+
 	* configure.ac (AB_INIT): New.
 
 	* m4/autobuild.m4: New.
 
-2006-09-19  Werner Koch  <wk at g10code.com>
-
-	* tests/fdpassing.c: Reverted Marcus changes.
-	(client): New arg FNAME to replace hardwired file name.
-	(main): Pass motd to client.
-	* tests/Makefile.am (AM_CPPFLAGS): Removed.
-	(EXTRA_DIST): Add motd.
-
-2006-09-19  Marcus Brinkmann  <marcus at g10code.de>
-
-	* tests/fdpassing.c (MOTD): New macro.
-	* tests/Makefile.am (AM_CPPFLAGS): New variable.
-	* tests/motd: New file.
-
 2006-09-14  Werner Koch  <wk at g10code.com>
 
 	Released 0.9.0.
@@ -292,7 +256,7 @@
 
 2004-09-27  Werner Koch  <wk at g10code.com>
 
-	* config.sub, config.guess: Updated. 
+	* config.sub, config.guess: Updated.
 
 2004-06-23  Marcus Brinkmann  <marcus at g10code.de>
 
@@ -398,7 +362,7 @@
 	* tests: New directory.
 
 
- Copyright 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ Copyright 2003, 2004, 2005, 2006, 2007, 2010 Free Software Foundation, Inc.
 
  This file is free software; as a special exception the author gives
  unlimited permission to copy and/or distribute it, with or without
@@ -407,5 +371,3 @@
  This file is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-
diff --git a/configure.ac b/configure.ac
index 8c9f3ab..feb918a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -58,7 +58,7 @@ VERSION=$PACKAGE_VERSION
 
 AM_INIT_AUTOMAKE
 AM_MAINTAINER_MODE
-AC_CONFIG_SRCDIR(src/assuan.h)
+AC_CONFIG_SRCDIR(src/assuan.h.in)
 AC_CONFIG_MACRO_DIR(m4)
 AM_CONFIG_HEADER(config.h)
 AC_CANONICAL_HOST
@@ -118,6 +118,22 @@ AC_PROG_LN_S
 AC_PROG_MAKE_SET
 #AC_ARG_PROGRAM
 
+# We need to compile and run a program on the build machine.  A
+# comment in libgpg-error says that the AC_PROG_CC_FOR_BUILD macro in
+# the AC archive is broken for autoconf 2.57.  Given that there is no
+# newer version of that macro, we assume that it is also broken for
+# autoconf 2.61 and thus we use a simple but usually sufficient
+# approach.
+AC_MSG_CHECKING(for cc for build)
+if test "$cross_compiling" = "yes"; then
+  CC_FOR_BUILD="${CC_FOR_BUILD-cc}"
+else
+  CC_FOR_BUILD="${CC_FOR_BUILD-$CC}"
+fi
+AC_MSG_RESULT($CC_FOR_BUILD)
+AC_ARG_VAR(CC_FOR_BUILD,[build system C compiler])
+
+
 if test "$GCC" = yes; then
     CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes"
 
@@ -325,8 +341,6 @@ if test $assuan_cv_sys_so_peercred = yes; then
 fi
 
 
-
-
 # Create the config files.
 AC_CONFIG_FILES([Makefile])
 AC_CONFIG_FILES([m4/Makefile])
diff --git a/doc/assuan.texi b/doc/assuan.texi
index be60ecd..9176973 100644
--- a/doc/assuan.texi
+++ b/doc/assuan.texi
@@ -1064,12 +1064,13 @@ 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{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
-closed and some special environment variables are set.  To let the
-caller detect whether the child or the parent continues, the parent
-returns with @code{"client"} returned in @var{argv} and the child
-returns with @code{"server"} in @var{argv}.
+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 closed and
+some special environment variables are set.  To let the caller detect
+whether the child or the parent continues, the parent returns with
+ at code{"client"} returned in @var{argv} and the child returns with
+ at code{"server"} in @var{argv}.  This feature is only available on POSIX
+platforms.
 
 If @var{atfork} is not NULL, this function is called in the child right
 after the fork and the value @var{atforkvalue} is passed as the first
diff --git a/src/ChangeLog b/src/ChangeLog
index 1d5ff2e..6034272 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,5 +1,39 @@
+2010-03-22  Werner Koch  <wk at g10code.com>
+
+	* Makefile.am (mkheader, assuan.h): Build header file.
+	* mkheader.c: New.
+	* assuan.h: Rename to assuan.h.in.
+
+2010-03-18  Werner Koch  <wk at g10code.com>
+
+	* libassuan.def (_assuan_w32ce_prepare_pipe)
+	(_assuan_w32ce_finish_pipe): New
+	* gpgcedev.c (struct opnctx_s): Replace HD by RVID.
+	(GPGCEDEV_IOCTL_SET_HANDLE): Remove.
+	(GPGCEDEV_IOCTL_GET_RVID): New.
+	(create_rendezvous_id): New.
+	(get_new_opnctx): Init the RVID.
+	(set_handle): Remove.
+	(find_and_lock_opnctx, make_pipe, GPG_IOControl): Change to new
+	method.
+	* system-w32ce.c (_assuan_w32ce_prepare_pipe)
+	(_assuan_w32ce_finish_pipe): New.
+	(_assuan_w32ce_create_pipe): Re-implement using the new functions.
+	(__assuan_pipe): Create an inheritable pipe.
+	(build_w32_commandline): New arg FD2_ISNULL.
+	* system.c (_assuan_close_inheritable): New.
+	* assuan-pipe-connect.c (pipe_connect): Use the new function.
+
+	* sysutils.c (_assuan_w32ce_create_pipe): Move to system-w32ce.c.
+
 2010-03-16  Werner Koch  <wk at g10code.com>
 
+	* system-w32ce.c (build_w32_commandline): Add args to pass the
+	special options for the standard descriptors.
+	(utf8_to_wchar, free_wchar): New.
+	(__assuan_spawn): Adjust for changes.  Convert strings for
+	CreateProcess to wchar_t.
+
 	* system.c: For better readability move platform dependend code to ..
 	* system-posix.c, system-w32.c, system-w32ce.c: .. New.
 	* Makefile.am (common_sources): Account for this change.
diff --git a/src/Makefile.am b/src/Makefile.am
index c946f11..6723648 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,5 @@
 # Assuan Makefile
-# Copyright (C) 2001, 2002, 2003, 2009 Free Software Foundation, Inc.
+# Copyright (C) 2001, 2002, 2003, 2009, 2010 Free Software Foundation, Inc.
 #
 # This file is part of Assuan.
 #
@@ -18,7 +18,7 @@
 ## Process this file with automake to produce Makefile.in
 
 EXTRA_DIST = libassuan-config.in libassuan.m4 libassuan.vers \
-             versioninfo.rc.in libassuan.def
+             versioninfo.rc.in libassuan.def mkheader.c
 INCLUDES = -I.. -I$(top_srcdir)/include
 
 bin_SCRIPTS = libassuan-config
@@ -37,8 +37,12 @@ else
 libassuan_version_script_cmd =
 endif
 
+CLEANFILES = mkheader assuan.h
+
+BUILT_SOURCES = assuan.h
 
 common_sources = \
+	assuan.h.in assuan.h w32ce-add.h \
 	assuan-defs.h \
 	assuan.c context.c system.c \
 	debug.c debug.h conversion.c sysutils.c \
@@ -121,3 +125,10 @@ libgpgcedev_la_DEPENDENCIES = gpgcedev.def
 gpgcemgr_SOURCES = gpgcemgr.c
 gpgcemgr_CPPFLAGS = $(AM_CPPFLAGS)
 endif
+
+mkheader: mkheader.c Makefile
+	$(CC_FOR_BUILD) -I. -I$(srcdir) -o $@ $(srcdir)/mkheader.c
+
+assuan.h: assuan.h.in mkheader w32ce-add.h
+	./mkheader $(host_os) $(srcdir)/assuan.h.in >$@
+
diff --git a/src/assuan-defs.h b/src/assuan-defs.h
index dd91f09..63f0d10 100644
--- a/src/assuan-defs.h
+++ b/src/assuan-defs.h
@@ -230,6 +230,7 @@ void _assuan_free (assuan_context_t ctx, void *ptr);
 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);
+int _assuan_close_inheritable (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,
diff --git a/src/assuan-pipe-connect.c b/src/assuan-pipe-connect.c
index dec8ccc..4eccdde 100644
--- a/src/assuan-pipe-connect.c
+++ b/src/assuan-pipe-connect.c
@@ -175,7 +175,7 @@ pipe_connect (assuan_context_t ctx,
   if (_assuan_pipe (ctx, wp, 0) < 0)
     {
       _assuan_close (ctx, rp[0]);
-      _assuan_close (ctx, rp[1]);
+      _assuan_close_inheritable (ctx, rp[1]);
       return _assuan_error (ctx, gpg_err_code_from_syserror ());
     }
   
@@ -197,8 +197,8 @@ pipe_connect (assuan_context_t ctx,
     }
 
   /* Close the stdin/stdout child fds in the parent.  */
-  _assuan_close (ctx, rp[1]);
-  _assuan_close (ctx, wp[0]);
+  _assuan_close_inheritable (ctx, rp[1]);
+  _assuan_close_inheritable (ctx, wp[0]);
 
   ctx->engine.release = _assuan_client_release;
   ctx->engine.readfnc = _assuan_simple_read;
@@ -393,7 +393,7 @@ socketpair_connect (assuan_context_t ctx,
    environment variables are set. To let the caller detect whether the
    child or the parent continues, the child returns "client" or
    "server" in *ARGV (but it is sufficient to check only the first
-   character).  */
+   character).  This feature is only available on POSIX platforms.  */
 gpg_error_t
 assuan_pipe_connect (assuan_context_t ctx,
 		     const char *name, const char *argv[],
diff --git a/src/assuan.h b/src/assuan.h.in
similarity index 98%
rename from src/assuan.h
rename to src/assuan.h.in
index c275287..91b75ab 100644
--- a/src/assuan.h
+++ b/src/assuan.h.in
@@ -1,4 +1,4 @@
-/* assuan.h - Definitions for the Assuan IPC library
+/* assuan.h - Definitions for the Assuan IPC library             -*- c -*-
    Copyright (C) 2001, 2002, 2003, 2005, 2007, 2008, 2009,
                  2010  Free Software Foundation, Inc.
 
@@ -16,6 +16,8 @@
 
    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/>.
+
+   @configure_input@
  */
 
 #ifndef ASSUAN_H
@@ -639,13 +641,7 @@ int __assuan_socketpair (assuan_context_t ctx, int _namespace, int style,
 extern struct assuan_system_hooks _assuan_system_pth;
 #define ASSUAN_SYSTEM_PTH &_assuan_system_pth
 
-#ifdef __MINGW32CE__
-/* FIXME: Include this code only if build for this platform.  */
-DWORD _assuan_w32ce_create_pipe (HANDLE *read_hd, HANDLE *write_hd,
-                                 LPSECURITY_ATTRIBUTES sec_attr, DWORD size);
-#define CreatePipe(a,b,c,d) _assuan_w32ce_create_pipe ((a),(b),(c),(d))
-
-#endif /*__MINGW32CE__*/
+ at include:w32ce-add@
 
 #ifdef __cplusplus
 }
diff --git a/src/gpgcedev.c b/src/gpgcedev.c
index 763ab29..fe9c80a 100644
--- a/src/gpgcedev.c
+++ b/src/gpgcedev.c
@@ -17,6 +17,7 @@
    License along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+
 #include <stdio.h>
 #include <stdarg.h>
 #include <windows.h>
@@ -35,19 +36,21 @@
 #endif /*IOCTL_PSL_NOTIFY*/
 
 
-/* The IOCTL used to tell the device about the handle.
+/* The IOCTL to return the rendezvous id of the handle.
 
-   The required inbuf parameter is the address of a variable holding
-   the handle.  */
-#define GPGCEDEV_IOCTL_SET_HANDLE \
+   The required outbuf parameter is the address of a variable to store
+   the rendezvous ID, which is a LONG value.  */
+#define GPGCEDEV_IOCTL_GET_RVID \
   CTL_CODE (FILE_DEVICE_STREAMS, 2048, METHOD_BUFFERED, FILE_ANY_ACCESS)
 
 /* The IOCTL used to create the pipe. 
 
-   The caller sends this IOCTL to the read handle.  The required inbuf
-   parameter is the address of variable holding the write handle.
-   Note that the SET_HANDLE IOCTLs must have been used prior to this
-   one.  */
+   The caller sends this IOCTL to the read or the write handle.  The
+   required inbuf parameter is address of a variable holding the
+   rendezvous id of the pipe's other end.  There is one possible
+   problem with eocdde: If a pipe is kept in non-rendezvous state
+   until after the rendezvous ids overflow, it is possible that the
+   wrong end will be used.  However this is not a realistic scenario.  */
 #define GPGCEDEV_IOCTL_MAKE_PIPE \
   CTL_CODE (FILE_DEVICE_STREAMS, 2049, METHOD_BUFFERED, FILE_ANY_ACCESS)
 
@@ -62,7 +65,7 @@ struct opnctx_s
                        other context; i.e. a pipe has been
                        established.  */
   int is_write;     /* True if this is the write end of the pipe.  */
-  HANDLE hd;        /* The system's handle object or INVALID_HANDLE_VALUE.  */
+  LONG rvid;        /* The unique rendezvous identifier.  */
   DWORD access_code;/* Value from OpenFile.  */
   DWORD share_mode; /* Value from OpenFile.  */
   CRITICAL_SECTION critsect;  /* Lock for all operations.  */
@@ -118,6 +121,19 @@ log_debug (const char *fmt, ...)
 }
 
 
+/* Return a new rendezvous next command id.  Command Ids are used to group
+   resources of one command.  We will never return an RVID of 0. */
+static LONG
+create_rendezvous_id (void)
+{
+  static LONG rendezvous_id;
+  LONG rvid;
+
+  while (!(rvid = InterlockedIncrement (&rendezvous_id)))
+    ;
+  return rvid;
+}
+
 
 

 /* Return a new opnctx handle and mark it as used.  Returns NULL and
@@ -152,8 +168,7 @@ get_new_opnctx (void)
     }
   opnctx = opnctx_table + idx;
   opnctx->assoc = NULL;
-  opnctx->hd = INVALID_HANDLE_VALUE;
-  opnctx->assoc = 0;
+  opnctx->rvid = create_rendezvous_id ();
   opnctx->buffer_size = 512;
   opnctx->buffer = malloc (opnctx->buffer_size);
   if (!opnctx->buffer)
@@ -173,36 +188,45 @@ get_new_opnctx (void)
   
  leave:
   LeaveCriticalSection (&opnctx_table_cs);
-  log_debug ("get_new_opnctx -> %p\n", opnctx);
+  if (opnctx)
+    log_debug ("get_new_opnctx -> %p (rvid=%ld)\n", opnctx, opnctx->rvid);
+  else
+    log_debug ("get_new_opnctx -> failed\n");
   return opnctx;
 }
 
 
-/* Find the OPNCTX for handle HD.  */
+/* Find the OPNCTX object with the rendezvous id RVID.  */
 static opnctx_t
-find_and_lock_opnctx (HANDLE hd)
+find_and_lock_opnctx (LONG rvid)
 {
   opnctx_t result = NULL;
   int idx;
 
   EnterCriticalSection (&opnctx_table_cs);
   for (idx=0; idx < opnctx_table_size; idx++)
-    if (opnctx_table[idx].inuse && opnctx_table[idx].hd == hd)
+    if (opnctx_table[idx].inuse && opnctx_table[idx].rvid == rvid)
       {
         result = opnctx_table + idx;
         break;
       }
   LeaveCriticalSection (&opnctx_table_cs);
   if (!result)
-    SetLastError (ERROR_INVALID_HANDLE);
+    {
+      SetLastError (ERROR_INVALID_HANDLE);
+      log_debug ("find_opnctx -> invalid rendezvous id\n");
+    }
   else if (TryEnterCriticalSection (&result->critsect))
-    result->locked++;
+    {
+      result->locked++;
+      log_debug ("find_opnctx -> %p (rvid=%ld)\n", result, result->rvid);
+    }
   else
     {
       SetLastError (ERROR_BUSY);
       result = NULL;
+      log_debug ("find_opnctx -> busy\n");
     }
-  log_debug ("find_opnctx -> %p\n", result);
   return result;
 }
 
@@ -353,14 +377,10 @@ GPG_Close (DWORD opnctx_arg)
   for (idx=0; idx < opnctx_table_size; idx++)
     if (opnctx_table[idx].inuse && (opnctx_table + idx) == opnctx)
       {
-        if (opnctx->hd != INVALID_HANDLE_VALUE)
+        if (opnctx->assoc)
           {
-            if (opnctx->assoc)
-              {
-                opnctx->assoc->assoc = NULL;
-                opnctx->assoc = NULL;
-              }
-            opnctx->hd = INVALID_HANDLE_VALUE;
+            opnctx->assoc->assoc = NULL;
+            opnctx->assoc = NULL;
           }
         if (opnctx->locked)
           {
@@ -419,7 +439,7 @@ GPG_Read (DWORD opnctx_arg, void *buffer, DWORD count)
       SetLastError (ERROR_INVALID_ACCESS);
       goto leave;
     }
-  if (rctx->hd == INVALID_HANDLE_VALUE || !rctx->assoc)
+  if (!rctx->assoc)
     {
       SetLastError (ERROR_BROKEN_PIPE);
       goto leave;
@@ -490,7 +510,7 @@ GPG_Write (DWORD opnctx_arg, const void *buffer, DWORD count)
       SetLastError (ERROR_INVALID_ACCESS);
       goto leave;
     }
-  if (wctx->hd == INVALID_HANDLE_VALUE || !wctx->assoc)
+  if (!wctx->assoc)
     {
       SetLastError (ERROR_BROKEN_PIPE);
       goto leave;
@@ -546,79 +566,78 @@ GPG_Seek (DWORD opnctx, long amount, WORD type)
 
 

 static BOOL
-set_handle (opnctx_t opnctx, HANDLE hd)
-{
-  log_debug ("  set_handle(%p, hd=%p)\n", opnctx, hd);
-  if (opnctx->hd != INVALID_HANDLE_VALUE)
-    {
-      SetLastError (ERROR_ALREADY_ASSIGNED);
-      return FALSE;
-    }
-  opnctx->hd = hd;
-  return TRUE;
-}
-
-static BOOL
-make_pipe (opnctx_t rctx, HANDLE hd)
+make_pipe (opnctx_t ctx, LONG rvid)
 {
   BOOL result = FALSE;
-  opnctx_t wctx = NULL;
+  opnctx_t peerctx = NULL;
 
-  log_debug ("  make_pipe(%p, hd=%p)\n", rctx, hd);
-  if (rctx->hd == INVALID_HANDLE_VALUE)
-    {
-      SetLastError (ERROR_NOT_READY);
-      goto leave;
-    }
-  if (rctx->assoc)
+  log_debug ("  make_pipe(%p, rvid=%ld)\n", ctx, rvid);
+  if (ctx->assoc)
     {
       SetLastError (ERROR_ALREADY_ASSIGNED);
       goto leave;
     }
-  if (!(rctx->access_code & GENERIC_READ))
-    {
-      SetLastError (ERROR_INVALID_ACCESS);
-      goto leave;
-    }
 
-  wctx = find_and_lock_opnctx (hd);
-  if (!wctx)
+  peerctx = find_and_lock_opnctx (rvid);
+  if (!peerctx)
     {
       SetLastError (ERROR_NOT_FOUND);
       goto leave;
     }
-  if (wctx == rctx)
+  if (peerctx == ctx)
     {
       SetLastError (ERROR_INVALID_TARGET_HANDLE);
       goto leave;
     }
-  if (wctx->hd == INVALID_HANDLE_VALUE)
+  if (peerctx->assoc)
     {
-      SetLastError (ERROR_NOT_READY);
+      SetLastError (ERROR_ALREADY_ASSIGNED);
       goto leave;
     }
-  if (wctx->assoc)
+
+  if ((ctx->access_code & GENERIC_READ))
     {
-      SetLastError (ERROR_ALREADY_ASSIGNED);
-      goto leave;
+      /* Check that the peer is a write end.  */
+      if (!(peerctx->access_code & GENERIC_WRITE))
+        {
+          SetLastError (ERROR_INVALID_ACCESS);
+          goto leave;
+        }
+      peerctx->space_available = CreateEvent (NULL, FALSE, FALSE, NULL);
+      peerctx->data_available = CreateEvent (NULL, FALSE, FALSE, NULL);
+      
+      ctx->assoc = peerctx;
+      peerctx->assoc = ctx;
+      ctx->is_write = 0;
+      peerctx->is_write = 1;
+      result = TRUE;
+    }
+  else if ((ctx->access_code & GENERIC_WRITE))
+    {
+      /* Check that the peer is a read end.  */
+      if (!(peerctx->access_code & GENERIC_READ))
+        {
+          SetLastError (ERROR_INVALID_ACCESS);
+          goto leave;
+        }
+      ctx->space_available = CreateEvent (NULL, FALSE, FALSE, NULL);
+      ctx->data_available = CreateEvent (NULL, FALSE, FALSE, NULL);
+      
+      ctx->assoc = peerctx;
+      peerctx->assoc = ctx;
+      ctx->is_write = 1;
+      peerctx->is_write = 0;
+      result = TRUE;
     }
-  if (!(wctx->access_code & GENERIC_WRITE))
+  else
     {
       SetLastError (ERROR_INVALID_ACCESS);
       goto leave;
     }
-  wctx->space_available = CreateEvent (NULL, FALSE, FALSE, NULL);
-  wctx->data_available = CreateEvent (NULL, FALSE, FALSE, NULL);
-  
-  rctx->assoc = wctx;
-  wctx->assoc = rctx;
-  rctx->is_write = 0;
-  wctx->is_write = 1;
-  result = TRUE;
 
  leave:
-  if (wctx)
-    unlock_opnctx (wctx);
+  if (peerctx)
+    unlock_opnctx (peerctx);
   return result;
 }
 
@@ -629,6 +648,7 @@ GPG_IOControl (DWORD opnctx_arg, DWORD code, void *inbuf, DWORD inbuflen,
 {
   opnctx_t opnctx = (opnctx_t)opnctx_arg;
   BOOL result = FALSE;
+  LONG rvid;
 
   log_debug ("GPG_IOControl(%p, %d)\n", (void*)opnctx, code);
   if (!validate_and_lock_opnctx (opnctx, LOCK_TRY))
@@ -636,25 +656,28 @@ GPG_IOControl (DWORD opnctx_arg, DWORD code, void *inbuf, DWORD inbuflen,
 
   switch (code)
     {
-    case GPGCEDEV_IOCTL_SET_HANDLE:
-      if (!opnctx || !inbuf || inbuflen < sizeof (HANDLE) 
-          || outbuf || outbuflen || actualoutlen )
+    case GPGCEDEV_IOCTL_GET_RVID:
+      if (!opnctx || inbuf || inbuflen
+          || !outbuf || outbuflen  < sizeof (LONG))
         {
           SetLastError (ERROR_INVALID_PARAMETER);
           goto leave;
         }
-      if (set_handle (opnctx, *(HANDLE*)inbuf))
-        result = TRUE;
+      memcpy (outbuf, &opnctx->rvid, sizeof (LONG));
+      if (actualoutlen)
+        *actualoutlen = sizeof (LONG);
+      result = TRUE;
       break;
 
     case GPGCEDEV_IOCTL_MAKE_PIPE:
-      if (!opnctx || !inbuf || inbuflen < sizeof (HANDLE) 
+      if (!opnctx || !inbuf || inbuflen < sizeof (LONG) 
           || outbuf || outbuflen || actualoutlen )
         {
           SetLastError (ERROR_INVALID_PARAMETER);
           goto leave;
         }
-      if (make_pipe (opnctx, *(HANDLE*)inbuf))
+      memcpy (&rvid, inbuf, sizeof (LONG));
+      if (make_pipe (opnctx, rvid))
         result = TRUE;
       break;
 
diff --git a/src/libassuan.def b/src/libassuan.def
index ba8ed8d..59aba41 100644
--- a/src/libassuan.def
+++ b/src/libassuan.def
@@ -99,6 +99,8 @@ EXPORTS
     assuan_set_sock_nonce               @78
     _assuan_w32ce_create_pipe           @79
     assuan_free                         @80
+    _assuan_w32ce_prepare_pipe          @81
+    _assuan_w32ce_finish_pipe           @82
 
 ; END
 
diff --git a/src/mkheader.c b/src/mkheader.c
new file mode 100644
index 0000000..22cdc94
--- /dev/null
+++ b/src/mkheader.c
@@ -0,0 +1,192 @@
+/* mkheader.c - Create a header file for libassuan.
+ * Copyright (C) 2010 Free Software Foundation, Inc.
+ *
+ * This file is free software; as a special exception the author gives
+ * unlimited permission to copy and/or distribute it, with or without
+ * modifications, as long as this notice is preserved.
+ * 
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define PGM "mkheader"
+
+#define LINESIZE 1024
+
+static const char *host_os;
+static char *srcdir;
+
+
+/* Include the file NAME form the source directory.  The included file
+   is not further expanded.  It may have comments indicated by a
+   double hash masrk at the begin of a line.  */
+static void
+include_file (const char *fname, int lnr, const char *name)
+{
+  FILE *fp;
+  char *incfname;
+  char line[LINESIZE];
+
+  incfname = malloc (strlen (srcdir) + strlen (name) + 1);
+  if (!incfname)
+    {
+      fputs (PGM ": out of core\n", stderr);
+      exit (1);
+    }
+  strcpy (incfname, srcdir);
+  strcat (incfname, name);
+
+  fp = fopen (incfname, "r");
+  if (!fp)
+    {
+      fprintf (stderr, "%s:%d: error including `%s': %s\n", 
+               fname, lnr, incfname, strerror (errno));
+      exit (1);
+    }
+
+  while (fgets (line, LINESIZE, fp))
+    {
+      if (line[0] != '#' && line[1] != '#')
+        fputs (line, stdout);
+    }
+  if (ferror (fp))
+    {
+      fprintf (stderr, "%s:%d: error reading `%s': %s\n", 
+               fname, lnr, incfname, strerror (errno));
+      exit (1);
+    }
+  fclose (fp);
+  free (incfname);
+}
+
+
+static int
+write_special (const char *fname, int lnr, const char *tag)
+{
+  if (!strcmp (tag, "include:w32ce-add"))
+    {
+      if (!strcmp (host_os, "mingw32ce"))
+        include_file (fname, lnr, "w32ce-add.h");
+    }
+  else
+    return 0; /* Unknown tag.  */
+
+  return 1; /* Tag processed.  */
+}
+
+
+int 
+main (int argc, char **argv)
+{
+  FILE *fp;
+  char line[LINESIZE];
+  int lnr = 0;
+  const char *fname, *s;
+  char *p1, *p2;
+
+  if (argc)
+    {
+      argc--; argv++;
+    }
+ 
+  if (argc != 2)
+    {
+      fputs ("usage: " PGM " host_os template.h\n", stderr);
+      return 1;
+    }
+  host_os = argv[0];
+  fname = argv[1];
+
+  srcdir = malloc (strlen (fname) + 2 + 1);
+  if (!srcdir)
+    {
+      fputs (PGM ": out of core\n", stderr);
+      return 1;
+    }
+  strcpy (srcdir, fname);
+  p1 = strrchr (srcdir, '/');
+  if (p1)
+    p1[1] = 0;
+  else
+    strcpy (srcdir, "./");
+
+  fp = fopen (fname, "r");
+  if (!fp)
+    {
+      fprintf (stderr, "%s:%d: can't open file: %s",
+               fname, lnr, strerror (errno));
+      return 1;
+    }
+  
+  while (fgets (line, LINESIZE, fp))
+    {
+      size_t n = strlen (line);
+
+      lnr++;
+      if (!n || line[n-1] != '\n')
+        {
+          fprintf (stderr,
+                   "%s:%d: trailing linefeed missing, line too long or "
+                   "embedded Nul character", fname, lnr);
+          break;
+        }
+      line[--n] = 0;
+      
+      p1 = strchr (line, '@');
+      p2 = p1? strchr (p1+1, '@') : NULL;
+      if (!p1 || !p2 || p2-p1 == 1)
+        {
+          puts (line);
+          continue;
+        }
+      *p1++ = 0;
+      *p2++ = 0;
+      fputs (line, stdout);
+
+      if (!strcmp (p1, "configure_input"))
+        {
+          s = strrchr (fname, '/');
+          printf ("Do not edit.  Generated from %s by %s for %s.", 
+                  s? s+1 : fname, PGM, host_os);
+        }
+      else if (!write_special (fname, lnr, p1))
+        {
+          putchar ('@');
+          fputs (p1, stdout);
+          putchar ('@');
+        }
+      
+      fputs (p2, stdout);
+      putchar ('\n');
+    }
+
+  if (ferror (fp))
+    {
+      fprintf (stderr, "%s:%d: error reading file: %s\n", 
+               fname, lnr, strerror (errno));
+      return 1;
+    }
+
+  fputs ("/*\n"
+         "Local Variables:\n"
+         "buffer-read-only: t\n"
+         "End:\n"
+         "*/\n", stdout);
+
+  if (ferror (stdout))
+    {
+      fprintf (stderr, PGM ": error writing stdout: %s\n", strerror (errno));
+      return 1;
+    }
+  
+  fclose (fp);
+
+  return 0;
+}
diff --git a/src/system-w32.c b/src/system-w32.c
index 31da194..85f0e40 100644
--- a/src/system-w32.c
+++ b/src/system-w32.c
@@ -64,6 +64,33 @@ __assuan_usleep (assuan_context_t ctx, unsigned int usec)
 
 
 

+/* Three simple wrappers, only used because thes function are named in
+   the def file.  */
+HANDLE
+_assuan_w32ce_prepare_pipe (int *r_rvid, int write_end)
+{
+  (void)r_rvid;
+  (void)write_end;
+  return INVALID_HANDLE_VALUE;
+}
+
+HANDLE
+_assuan_w32ce_finish_pipe (int rvid, int write_end)
+{
+  (void)rvid;
+  (void)write_end;
+  return INVALID_HANDLE_VALUE;
+}
+
+DWORD
+_assuan_w32ce_create_pipe (HANDLE *read_hd, HANDLE *write_hd,
+                           LPSECURITY_ATTRIBUTES sec_attr, DWORD size)
+{
+  return CreatePipe (read_hd, write_hd, sec_attr, size);
+}
+
+
+

 /* Create a pipe with one inheritable end.  Default implementation.  */
 int
 __assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
diff --git a/src/system-w32ce.c b/src/system-w32ce.c
index ce0796c..1ecb4d8 100644
--- a/src/system-w32ce.c
+++ b/src/system-w32ce.c
@@ -27,26 +27,72 @@
 #include <time.h>
 #include <fcntl.h>
 #include <windows.h>
+#include <winioctl.h>
+#include <devload.h>
 
 #include "assuan-defs.h"
 #include "debug.h"
 
 
+#define GPGCEDEV_IOCTL_GET_RVID                                         \
+  CTL_CODE (FILE_DEVICE_STREAMS, 2048, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define GPGCEDEV_IOCTL_MAKE_PIPE                                        \
+  CTL_CODE (FILE_DEVICE_STREAMS, 2049, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+
+
 

-assuan_fd_t
-assuan_fdopen (int fd)
+static wchar_t *
+utf8_to_wchar (const char *string)
 {
-  assuan_fd_t ifd = (assuan_fd_t)fd;
-  assuan_fd_t ofd;
+  int n;
+  size_t nbytes;
+  wchar_t *result;
+
+  if (!string)
+    return NULL;
 
-  if (! DuplicateHandle(GetCurrentProcess(), ifd, 
-			GetCurrentProcess(), &ofd, 0,
-			TRUE, DUPLICATE_SAME_ACCESS))
+  n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
+  if (n < 0)
     {
-      gpg_err_set_errno (EIO);
-      return ASSUAN_INVALID_FD;
+      gpg_err_set_errno (EINVAL);
+      return NULL;
+    }
+
+  nbytes = (size_t)(n+1) * sizeof(*result);
+  if (nbytes / sizeof(*result) != (n+1)) 
+    {
+      gpg_err_set_errno (ENOMEM);
+      return NULL;
+    }
+  result = malloc (nbytes);
+  if (!result)
+    return NULL;
+
+  n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
+  if (n < 0)
+    {
+      free (result);
+      gpg_err_set_errno (EINVAL);
+      result = NULL;
     }
-  return ofd;
+  return result;
+}
+
+/* Convenience function.  */
+static void
+free_wchar (wchar_t *string)
+{
+  if (string)
+    free (string);
+}
+
+
+

+assuan_fd_t
+assuan_fdopen (int fd)
+{
+  return (assuan_fd_t)fd;
 }
 
 
@@ -56,60 +102,149 @@ assuan_fdopen (int fd)
 void
 __assuan_usleep (assuan_context_t ctx, unsigned int usec)
 {
-  if (!usec)
-    return;
-
-  Sleep (usec / 1000);
+  if (usec)
+    Sleep (usec / 1000);
 }
 
 
 

-/* Create a pipe with one inheritable end.  Default implementation.  */
-int
-__assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
+/* Prepare a pipe.  Returns a handle which is, depending on WRITE_END,
+   will either act the read or as the write end of the pipe.  The
+   other value returned is a rendezvous id used to complete the pipe
+   creation with _assuan_w32ce_finish_pipe.  The rendezvous id may be
+   passed to another process and that process may finish the pipe
+   creation.  This creates the interprocess pipe.  The rendezvous id
+   is not a handle but a plain number; there is no release function
+   and care should be taken not to pass it to a function expecting a
+   handle.  */
+HANDLE
+_assuan_w32ce_prepare_pipe (int *r_rvid, int write_end)
 {
-  HANDLE rh;
-  HANDLE wh;
-  HANDLE th;
-  SECURITY_ATTRIBUTES sec_attr;
+  HANDLE hd;
+  LONG rvid;
+
+  ActivateDevice (L"Drivers\\GnuPG_Device", 0);
+
+  /* Note: Using "\\$device\\GPG1" should be identical to "GPG1:".
+     However this returns an invalid parameter error without having
+     called GPG_Init in the driver.  The docs mention something about
+     RegisterAFXEx but that API is not documented.  */
+  hd = CreateFile (L"GPG1:", write_end? GENERIC_WRITE : GENERIC_READ,
+                   FILE_SHARE_READ | FILE_SHARE_WRITE,
+                   NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+  if (hd != INVALID_HANDLE_VALUE)
+    {
+      if (!DeviceIoControl (hd, GPGCEDEV_IOCTL_GET_RVID,
+                            NULL, 0, &rvid, sizeof rvid, NULL, NULL))
+        {
+          DWORD lastrc = GetLastError ();
+          CloseHandle (hd);
+          hd = INVALID_HANDLE_VALUE;
+          SetLastError (lastrc);
+        }
+      else
+        *r_rvid = rvid;
+    }
+  
+  return hd;
+}
+
 
-  memset (&sec_attr, 0, sizeof (sec_attr));
-  sec_attr.nLength = sizeof (sec_attr);
-  sec_attr.bInheritHandle = FALSE;
+/* Create a pipe.  WRITE_END shall have the opposite value of the one
+   pssed to _assuan_w32ce_prepare_pipe; see there for more
+   details.  */
+HANDLE
+_assuan_w32ce_finish_pipe (int rvid, int write_end)
+{
+  HANDLE hd;
 
-  if (!CreatePipe (&rh, &wh, &sec_attr, 0))
+  hd = CreateFile (L"GPG1:", write_end? GENERIC_WRITE : GENERIC_READ,
+                   FILE_SHARE_READ | FILE_SHARE_WRITE,
+                   NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);
+  if (hd != INVALID_HANDLE_VALUE)
     {
-      TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_pipe", ctx,
-	      "CreatePipe failed: %s", _assuan_w32_strerror (ctx, -1));
-      gpg_err_set_errno (EIO);
-      return -1;
+      if (!DeviceIoControl (hd, GPGCEDEV_IOCTL_MAKE_PIPE,
+                            &rvid, sizeof rvid, NULL, 0, NULL, NULL))
+        {
+          DWORD lastrc = GetLastError ();
+          CloseHandle (hd);
+          hd = INVALID_HANDLE_VALUE;
+          SetLastError (lastrc);
+        }
+    }
+
+  return hd;
+}
+
+
+/* WindowsCE does not provide a pipe feature.  However we need
+   something like a pipe to convey data between processes and in some
+   cases within a process.  This replacement is not only used by
+   libassuan but exported and thus usable by gnupg and gpgme as well.  */
+DWORD
+_assuan_w32ce_create_pipe (HANDLE *read_hd, HANDLE *write_hd,
+                           LPSECURITY_ATTRIBUTES sec_attr, DWORD size)
+{
+  HANDLE hd[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
+  int rvid;
+  int rc = 0;
+
+  hd[0] = _assuan_w32ce_prepare_pipe (&rvid, 0);
+  if (hd[0] != INVALID_HANDLE_VALUE)
+    {
+      hd[1] = _assuan_w32ce_finish_pipe (rvid, 1);
+      if (hd[1] != INVALID_HANDLE_VALUE)
+        rc = 1;
+      else
+        {
+          DWORD lastrc = GetLastError ();
+          CloseHandle (hd[0]);
+          hd[0] = INVALID_HANDLE_VALUE;
+          SetLastError (lastrc);
+        }
     }
+  
+  *read_hd = hd[0];
+  *write_hd = hd[1];
+  return rc;
+}
+
 
-  if (! DuplicateHandle (GetCurrentProcess(), (inherit_idx == 0) ? rh : wh,
-			 GetCurrentProcess(), &th, 0,
-			 TRUE, DUPLICATE_SAME_ACCESS ))
+/* Create a pipe with one inheritable end.  Default implementation.
+   If INHERIT_IDX is 0, the read end of the pipe is made inheritable;
+   with INHERIT_IDX is 1 the write end will be inheritable.  The
+   question now is how we create an inheritable pipe end under windows
+   CE were handles are process local objects?  The trick we employ is
+   to defer the actual creation to the other end: We create an
+   incomplete pipe and pass a rendezvous id to the other end
+   (process).  The other end now uses the rendezvous id to lookup the
+   pipe in our device driver, creates a new handle and uses that one
+   to finally establish the pipe.  */
+int
+__assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
+{
+  HANDLE hd;
+  int rvid;
+
+  hd = _assuan_w32ce_prepare_pipe (&rvid, !inherit_idx);
+  if (hd == INVALID_HANDLE_VALUE)
     {
       TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_pipe", ctx,
-	      "DuplicateHandle failed: %s", _assuan_w32_strerror (ctx, -1));
-      CloseHandle (rh);
-      CloseHandle (wh);
+	      "CreatePipe failed: %s", _assuan_w32_strerror (ctx, -1));
       gpg_err_set_errno (EIO);
       return -1;
     }
-  if (inherit_idx == 0)
+
+  if (inherit_idx)
     {
-      CloseHandle (rh);
-      rh = th;
+      fd[0] = hd;
+      fd[1] = (void*)rvid;
     }
   else
     {
-      CloseHandle (wh);
-      wh = th;
+      fd[0] = (void*)rvid;
+      fd[1] = hd;
     }
-
-  fd[0] = rh;
-  fd[1] = wh;
-
   return 0;
 }
 
@@ -143,9 +278,13 @@ __assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
      read if recv detects that it is not a network socket.  */
   int res;
 
+  TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "__assuan_read", ctx,
+	      "fd=0x%x, buffer=%p, size=%i", fd, buffer, size);
+
   res = recv (HANDLE2SOCKET (fd), buffer, size, 0);
   if (res == -1)
     {
+      TRACE_LOG1 ("recv failed: rc=%d", (int)WSAGetLastError ());
       switch (WSAGetLastError ())
         {
         case WSAENOTSOCK:
@@ -155,6 +294,7 @@ __assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
             res = ReadFile (fd, buffer, size, &nread, NULL);
             if (! res)
               {
+                TRACE_LOG1 ("ReadFile failed: rc=%d", (int)GetLastError ());
                 switch (GetLastError ())
                   {
                   case ERROR_BROKEN_PIPE:
@@ -184,7 +324,7 @@ __assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
 	  break;
         }
     }
-  return res;
+  return TRACE_SYSRES (res);
 }
 
 
@@ -198,14 +338,19 @@ __assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
      write if send detects that it is not a network socket.  */
   int res;
 
-  res = send (HANDLE2SOCKET (fd), buffer, size, 0);
+  TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "__assuan_write", ctx,
+	      "fd=0x%x, buffer=%p, size=%i", fd, buffer, size);
+
+  res = send ((int)fd, buffer, size, 0);
   if (res == -1 && WSAGetLastError () == WSAENOTSOCK)
     {
       DWORD nwrite;
 
+      TRACE_LOG ("send call failed - trying WriteFile");
       res = WriteFile (fd, buffer, size, &nwrite, NULL);
       if (! res)
         {
+          TRACE_LOG1 ("WriteFile failed: rc=%d", (int)GetLastError ());
           switch (GetLastError ())
             {
             case ERROR_BROKEN_PIPE: 
@@ -222,7 +367,9 @@ __assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
       else
         res = (int) nwrite;
     }
-  return res;
+  else if (res == -1)
+    TRACE_LOG1 ("send call failed: rc=%d", (int)GetLastError ());
+  return TRACE_SYSRES (res);
 }
 
 
@@ -253,17 +400,43 @@ __assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
    CMDLINE gets the address of a newly allocated string.  */
 static int
 build_w32_commandline (assuan_context_t ctx, const char * const *argv,
-		       char **cmdline)
+		       assuan_fd_t fd0, assuan_fd_t fd1, assuan_fd_t fd2,
+                       int fd2_isnull,
+                       char **cmdline)
 {
   int i, n;
   const char *s;
   char *buf, *p;
+  char fdbuf[3*30];
 
+  p = fdbuf;
+  *p = 0;
+  if (fd0 != ASSUAN_INVALID_FD)
+    {
+      snprintf (p, 25, "-&S0=%d ", (int)fd0);
+      p += strlen (p);
+    }
+  if (fd1 != ASSUAN_INVALID_FD)
+    {
+      snprintf (p, 25, "-&S1=%d ", (int)fd1);
+      p += strlen (p);
+    }
+  if (fd2 != ASSUAN_INVALID_FD)
+    {
+      if (fd2_isnull)
+        strcpy (p, "-&S2=null ");
+      else
+        snprintf (p, 25, "-&S2=%d ", (int)fd2);
+      p += strlen (p);
+    }
+  
   *cmdline = NULL;
-  n = 0;
+  n = strlen (fdbuf);
   for (i=0; (s = argv[i]); i++)
     {
-      n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting */
+      if (!i)
+        continue; /* Ignore argv[0].  */
+      n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting) */
       for (; *s; s++)
         if (*s == '\"')
           n++;  /* Need to double inner quotes.  */
@@ -274,10 +447,14 @@ build_w32_commandline (assuan_context_t ctx, const char * const *argv,
   if (! buf)
     return -1;
 
+  p = stpcpy (p, fdbuf);
   for (i = 0; argv[i]; i++) 
     {
-      if (i)
+      if (!i)
+        continue; /* Ignore argv[0].  */
+      if (i > 1)
         p = stpcpy (p, " ");
+
       if (! *argv[i]) /* Empty string. */
         p = stpcpy (p, "\"\"");
       else if (strpbrk (argv[i], " \t\n\v\f\""))
@@ -296,7 +473,7 @@ build_w32_commandline (assuan_context_t ctx, const char * const *argv,
         p = stpcpy (p, argv[i]);
     }
 
-  *cmdline= buf;
+  *cmdline = buf;
   return 0;
 }
 
@@ -309,7 +486,6 @@ __assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
 		void (*atfork) (void *opaque, int reserved),
 		void *atforkvalue, unsigned int flags)
 {
-  SECURITY_ATTRIBUTES sec_attr;
   PROCESS_INFORMATION pi = 
     {
       NULL,      /* Returns process handle.  */
@@ -317,117 +493,95 @@ __assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
       0,         /* Returns pid.  */
       0          /* Returns tid.  */
     };
-  STARTUPINFO si;
   assuan_fd_t fd;
   assuan_fd_t *fdp;
+  assuan_fd_t fd_err;
+  int fd_err_isnull = 0;
   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;
+  /* Dup stderr to /dev/null unless it is in the list of FDs to be
+     passed to the child.  Well we don't actually open nul because
+     that is not available on Windows, but use our hack for it.
+     Because an RVID of 0 is an invalid value and HANDLES will never
+     have this value either, we test for this as well.  */
 
-  /* 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;
+  /* FIXME: CHECKOUT WHAT TO DO WITH STDERR HERE.  WE NEED TO DEFINE
+     WHETHER THE FD_CHILD_LIST HAS HANDLES OR RENDEZVOUS IDS.  */
 
-  /* Dup stderr to /dev/null unless it is in the list of FDs to be
-     passed to the child. */
   fd = assuan_fd_from_posix_fd (fileno (stderr));
   fdp = fd_child_list;
   if (fdp)
     {
-      for (; *fdp != ASSUAN_INVALID_FD && *fdp != fd; fdp++)
+      for (; *fdp != ASSUAN_INVALID_FD && *fdp != 0 && *fdp != fd; fdp++)
         ;
     }
   if (!fdp || *fdp == ASSUAN_INVALID_FD)
+    fd_err_isnull = 1;
+  fd_err = fd;
+
+  if (build_w32_commandline (ctx, argv, fd_in, fd_out, fd_err, fd_err_isnull,
+                             &cmdline))
     {
-      nullfd = CreateFileW (L"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", _assuan_w32_strerror (ctx, -1));
-          _assuan_free (ctx, cmdline);
-          gpg_err_set_errno (EIO);
-          return -1;
-        }
-      si.hStdError = nullfd;
+      return -1;
     }
-  else
-    si.hStdError = 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
-                       | 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));
-      _assuan_free (ctx, cmdline);
-      if (nullfd != INVALID_HANDLE_VALUE)
-        CloseHandle (nullfd);
 
-      gpg_err_set_errno (EIO);
+  TRACE2 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
+          "path=`%s' cmdline=`%s'", name, cmdline);
+
+  {
+    wchar_t *wcmdline, *wname;
+
+    wcmdline = utf8_to_wchar (cmdline);
+    _assuan_free (ctx, cmdline);
+    if (!wcmdline)
       return -1;
-    }
 
-  _assuan_free (ctx, cmdline);
-  if (nullfd != INVALID_HANDLE_VALUE)
-    CloseHandle (nullfd);
+    wname = utf8_to_wchar (name);
+    if (!wname)
+      {
+        free_wchar (wcmdline);
+        return -1;
+      }
+    
+    if (!CreateProcess (wname,                /* Program to start.  */
+                        wcmdline,             /* Command line arguments.  */
+                        NULL,                 /* (not supported)  */
+                        NULL,                 /* (not supported)  */
+                        FALSE,                /* (not supported)  */
+                        (CREATE_SUSPENDED),   /* Creation flags.  */
+                        NULL,                 /* (not supported)  */
+                        NULL,                 /* (not supported)  */
+                        NULL,                 /* (not supported) */
+                        &pi                   /* Returns process information.*/
+                        ))
+      {
+        TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
+                "CreateProcess failed: %s", _assuan_w32_strerror (ctx, -1));
+        free_wchar (wname);
+        free_wchar (wcmdline);
+        gpg_err_set_errno (EIO);
+        return -1;
+      }
+    free_wchar (wname);
+    free_wchar (wcmdline);
+  }
 
   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); */
+  TRACE4 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
+          "CreateProcess ready: hProcess=%p hThread=%p"
+          " dwProcessID=%d dwThreadId=%d\n",
+          pi.hProcess, pi.hThread, (int) pi.dwProcessId, (int) pi.dwThreadId);
 
+  CloseHandle (pi.hThread); 
+  
   *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;
 }
 
 
 
 

-/* 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)
@@ -446,6 +600,7 @@ __assuan_socketpair (assuan_context_t ctx, int namespace, int style,
   return -1;
 }
 
+
 

 /* The default system hooks for assuan contexts.  */
 struct assuan_system_hooks _assuan_system_hooks =
diff --git a/src/system.c b/src/system.c
index 22d7a0b..1f180e9 100644
--- a/src/system.c
+++ b/src/system.c
@@ -170,6 +170,22 @@ _assuan_close (assuan_context_t ctx, assuan_fd_t fd)
 }
 
 
+/* Same as assuan_close but used for the inheritable end of a
+   pipe.  */
+int
+_assuan_close_inheritable (assuan_context_t ctx, assuan_fd_t fd)
+{
+  TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_close", ctx,
+	  "fd=0x%x", fd);
+
+#ifdef HAVE_W32CE_SYSTEM
+  return 0; /* Nothing to do because it is a rendezvous id.  */
+#else
+  return (ctx->system.close) (ctx, fd);
+#endif
+}
+
+
 

 ssize_t
 _assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
diff --git a/src/sysutils.c b/src/sysutils.c
index c7e20a8..1760f44 100644
--- a/src/sysutils.c
+++ b/src/sysutils.c
@@ -34,17 +34,9 @@
 
 #include "assuan-defs.h"
 
-#ifdef HAVE_W32CE_SYSTEM
-#define GPGCEDEV_IOCTL_SET_HANDLE                                      \
-  CTL_CODE (FILE_DEVICE_STREAMS, 2048, METHOD_BUFFERED, FILE_ANY_ACCESS)
-#define GPGCEDEV_IOCTL_MAKE_PIPE                                        \
-  CTL_CODE (FILE_DEVICE_STREAMS, 2049, METHOD_BUFFERED, FILE_ANY_ACCESS)
-#endif /*HAVE_W32CE_SYSTEM*/
-
-
 
 /* This is actually a dummy function to make sure that is module is
-   not empty.  Sokme compilers barf on that.  */
+   not empty.  Some compilers barf on empty modules.  */
 const char *
 _assuan_sysutils_blurb (void)
 {
@@ -141,74 +133,3 @@ _assuan_getenv (const char *name)
 }
 #endif /*HAVE_W32CE_SYSTEM*/
 
-
-#ifdef HAVE_W32_SYSTEM
-/* WindowsCE does not provide a pipe feature.  However we need
-   something like a pipe to convey data between processes and in some
-   cases within a process.  This replacement is not only used by
-   libassuan but exported and thus usable by gnupg and gpgme as well.  */
-DWORD
-_assuan_w32ce_create_pipe (HANDLE *read_hd, HANDLE *write_hd,
-                           LPSECURITY_ATTRIBUTES sec_attr, DWORD size)
-{
-#ifdef HAVE_W32CE_SYSTEM
-  HANDLE hd[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
-
-  *read_hd = *write_hd = INVALID_HANDLE_VALUE;
-
-  ActivateDevice (L"Drivers\\GnuPG_Device", 0);
-
-  /* Note: Using "\\$device\\GPG1" should be identical to "GPG1:".
-     However this returns an invalid parameter error without having
-     called GPG_Init in the driver.  The docs mention something about
-     RegisterAFXEx but that API is not documented.  */
-  hd[0] = CreateFile (L"GPG1:", GENERIC_READ,
-                      FILE_SHARE_READ | FILE_SHARE_WRITE,
-                      NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-  if (hd[0] == INVALID_HANDLE_VALUE)
-    return 0;
-
-  if (!DeviceIoControl (hd[0], GPGCEDEV_IOCTL_SET_HANDLE,
-                        &hd[0], sizeof hd[0], NULL, 0, NULL, NULL))
-    fprintf (stderr, "GPGCEDEV_IOCTL_SET_HANDLE(0) failed: %d\n", 
-             (int)GetLastError ());
-  
-  hd[1] = CreateFile (L"GPG1:", GENERIC_WRITE,
-                      FILE_SHARE_READ | FILE_SHARE_WRITE,
-                      NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);
-  if (hd[1] == INVALID_HANDLE_VALUE)
-    {
-      DWORD lasterr = GetLastError ();
-      CloseHandle (hd[0]);
-      SetLastError (lasterr);
-      return 0;
-    }
-  if (!DeviceIoControl (hd[1], GPGCEDEV_IOCTL_SET_HANDLE,
-                        &hd[1], sizeof hd[1], NULL, 0, NULL, NULL))
-    fprintf (stderr, "GPGCEDEV_IOCTL_SET_HANDLE(1) failed: %d\n", 
-             (int)GetLastError ());
-
-  if (!DeviceIoControl (hd[0], GPGCEDEV_IOCTL_MAKE_PIPE,
-                        &hd[1], sizeof hd[1], NULL, 0, NULL, NULL))
-    {
-      fprintf (stderr, "GPGCEDEV_IOCTL_MAKE_PIPE failed: %d\n", 
-               (int)GetLastError ());
-      if (hd[0] != INVALID_HANDLE_VALUE)
-        CloseHandle (hd[0]);
-      if (hd[1] != INVALID_HANDLE_VALUE)
-        CloseHandle (hd[1]);
-      return 0;
-    }
-  else
-    {
-      *read_hd = hd[0];
-      *write_hd = hd[1];
-      return 1;
-    }
-#else /*!HAVE_W32CE_SYSTEM*/
-  return CreatePipe (read_hd, write_hd, sec_attr, size);
-#endif /*!HAVE_W32CE_SYSTEM*/
-}
-
-#endif /*!HAVE_W32_SYSTEM*/
-
diff --git a/tests/ChangeLog b/tests/ChangeLog
new file mode 100644
index 0000000..c263c65
--- /dev/null
+++ b/tests/ChangeLog
@@ -0,0 +1,67 @@
+2010-03-17  Werner Koch  <wk at g10code.com>
+
+	* pipeconnect.c: New.  Based on fdpassing.c
+
+2010-02-24  Werner Koch  <wk at g10code.com>
+
+	* ce-server.c: New.
+
+	* ce-createpipe.c [W32CE]: New.
+
+2010-01-27  Werner Koch  <wk at g10code.com>
+
+	* common.h (SOCKET2HANDLE, HANDLE2SOCKET): New.
+
+2009-11-05  Marcus Brinkmann  <marcus at g10code.de>
+
+	* fdpassing.c (main): Call assuan_pipe_connect instead
+	of assuan_pipe_connect_ext.
+
+2009-11-04  Werner Koch  <wk at g10code.com>
+
+	* fdpassing.c (register_commands): Add NULL arg to
+	assuan_register_command.
+
+2009-09-19  Marcus Brinkmann  <marcus at g10code.de>
+
+	* fdpassing.c: Update to new API.
+
+2009-08-26  Marcus Brinkmann  <marcus at g10code.de>
+
+	* Makefile.am (AM_CFLAGS, LDADD): Add gpg-error.
+	* fdpassing.c: Change error values to gpg-error ones.
+
+2008-11-03  Marcus Brinkmann  <marcus at g10code.de>
+
+	* fdpassing.c (register_commands): Add missing initializer
+	to silence gcc -W warning.
+
+2006-10-10  Werner Koch  <wk at g10code.com>
+
+	* Makefile.am (LDADD): Add NETLIBS.
+
+2006-09-19  Werner Koch  <wk at g10code.com>
+
+	* fdpassing.c: Reverted Marcus changes.
+	(client): New arg FNAME to replace hardwired file name.
+	(main): Pass motd to client.
+	* Makefile.am (AM_CPPFLAGS): Removed.
+	(EXTRA_DIST): Add motd.
+
+2006-09-19  Marcus Brinkmann  <marcus at g10code.de>
+
+	* fdpassing.c (MOTD): New macro.
+	* Makefile.am (AM_CPPFLAGS): New variable.
+	* motd: New file.
+
+
+ Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+ This file is free software; as a special exception the author gives
+ unlimited permission to copy and/or distribute it, with or without
+ modifications, as long as this notice is preserved.
+
+ This file is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 692748c..ef68924 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -25,7 +25,7 @@ EXTRA_DIST = motd ce-createpipe.c
 BUILT_SOURCES = 
 CLEANFILES = 
 
-TESTS = 
+TESTS = pipeconnect
 
 if HAVE_W32CE_SYSTEM
 w32cetools = ce-createpipe
diff --git a/tests/ce-createpipe.c b/tests/ce-createpipe.c
index 810edbc..b44784c 100644
--- a/tests/ce-createpipe.c
+++ b/tests/ce-createpipe.c
@@ -49,7 +49,7 @@ reader_thread (void *arg)
 	  log_error ("reader: ReadFile failed: rc=%d\n", (int)GetLastError ());
 	  break;
 	}
-      log_info ("reader: red %d bytes\n", (int)nread);
+      log_info ("reader: read %d bytes\n", (int)nread);
       log_printhex ("got: ", buffer, nread);
     }
 
@@ -117,7 +117,7 @@ run_test (void)
   switch (WaitForMultipleObjects (2, threads, FALSE, INFINITE))
     {
     case WAIT_OBJECT_0:
-      log_info ("reader thread finished firstt\n");
+      log_info ("reader thread finished first\n");
       break;
     case WAIT_OBJECT_0 + 1:
       log_info ("writer thread finished first\n");
diff --git a/tests/ce-server.c b/tests/ce-server.c
index 6ff3cae..9975e53 100644
--- a/tests/ce-server.c
+++ b/tests/ce-server.c
@@ -898,6 +898,8 @@ cmd_run (assuan_context_t ctx, char *line)
 #endif /*HAVE_W32CE_SYSTEM*/
 
 
+
+
 

 static const char hlp_newdataport[] = 
   "NEWDATAPORT\n"
diff --git a/tests/pipeconnect.c b/tests/pipeconnect.c
new file mode 100644
index 0000000..ddb4a06
--- /dev/null
+++ b/tests/pipeconnect.c
@@ -0,0 +1,397 @@
+/* pipeconnect.c  - Check the assuan_pipe_connect call.
+   Copyright (C) 2006, 2009, 2010 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 3 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/>.
+ */
+
+/* 
+   This tests creates a program which starts an assuan server and runs
+   some simple tests on it.  The other program is actually the same
+   program but called with the option --server.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "../src/assuan.h"
+#include "common.h"
+
+static assuan_fd_t my_stdin = ASSUAN_INVALID_FD;
+static assuan_fd_t my_stdout = ASSUAN_INVALID_FD;
+static assuan_fd_t my_stderr = ASSUAN_INVALID_FD;
+
+
+static gpg_error_t
+cmd_echo (assuan_context_t ctx, char *line)
+{
+  log_info ("got ECHO command (%s)\n", line);
+
+  assuan_send_data (ctx, line, strlen (line));
+
+  return 0;
+}
+
+
+static gpg_error_t
+cmd_cat (assuan_context_t ctx, char *line)
+{
+  assuan_fd_t fd, fdout;
+  int c;
+  FILE *fp, *fpout;
+  int nbytes;
+
+  log_info ("got CAT command (%s)\n", line);
+
+  fd = assuan_get_input_fd (ctx);
+  if (fd == ASSUAN_INVALID_FD)
+    return gpg_error (GPG_ERR_ASS_NO_INPUT);
+  fdout = assuan_get_output_fd (ctx);
+  if (fdout == ASSUAN_INVALID_FD)
+    return gpg_error (GPG_ERR_ASS_NO_OUTPUT);
+  fp = fdopen (fd, "r");
+  if (!fp)
+    {
+      log_error ("fdopen failed on input fd: %s\n", strerror (errno));
+      return gpg_error (GPG_ERR_ASS_GENERAL);
+    }
+
+  fpout = fdopen (fdout, "w");
+  if (!fpout)
+    {
+      log_error ("fdopen failed on output fd: %s\n", strerror (errno));
+      fclose (fp);
+      return gpg_error (GPG_ERR_ASS_GENERAL);
+    }
+
+  nbytes = 0;
+  while ( (c=getc (fp)) != -1)
+    {
+      putc (c, fpout); 
+      nbytes++;
+    }
+  log_info ("done printing %d bytes to output fd\n", nbytes);
+
+  /* Fixme:  This also closes the original fd. */
+  fclose (fp);
+  fclose (fpout);
+  return 0;
+}
+
+
+static gpg_error_t
+server_register_commands (assuan_context_t ctx)
+{
+  static struct
+  {
+    const char *name;
+    gpg_error_t (*handler) (assuan_context_t, char *line);
+  } table[] =
+      {
+	{ "ECHO", cmd_echo },
+	{ "CAT", cmd_cat },
+	{ "INPUT", NULL },
+	{ "OUTPUT", NULL },
+	{ NULL, NULL }
+      };
+  int i;
+  gpg_error_t rc;
+
+  for (i=0; table[i].name; i++)
+    {
+      rc = assuan_register_command (ctx, table[i].name, table[i].handler, NULL);
+      if (rc)
+        return rc;
+    }
+  return 0;
+}
+
+
+static void
+run_server (int enable_debug)
+{
+  int rc;
+  assuan_context_t ctx;
+  assuan_fd_t filedes[2];
+
+  filedes[0] = my_stdin;
+  filedes[1] = my_stdout;
+
+  rc = assuan_new (&ctx);
+  if (rc)
+    log_fatal ("assuan_new failed: %s\n", gpg_strerror (rc));
+
+  rc = assuan_init_pipe_server (ctx, filedes);
+  if (rc)
+    log_fatal ("assuan_init_pipe_server failed: %s\n", 
+               gpg_strerror (rc));
+
+  rc = server_register_commands (ctx);
+  if (rc)
+    log_fatal ("register_commands failed: %s\n", gpg_strerror(rc));
+
+  if (enable_debug)
+    assuan_set_log_stream (ctx, stderr);
+
+  for (;;) 
+    {
+      rc = assuan_accept (ctx);
+      if (rc)
+        {
+          if (rc != -1)
+            log_error ("assuan_accept failed: %s\n", gpg_strerror (rc));
+          break;
+        }
+      
+      log_info ("client connected.  Client's pid is %ld\n",
+                (long)assuan_get_pid (ctx));
+
+      rc = assuan_process (ctx);
+      if (rc)
+        log_error ("assuan_process failed: %s\n", gpg_strerror (rc));
+    }
+  
+  assuan_release (ctx);
+}
+
+
+
+
+
+
+

+static gpg_error_t
+data_cb (void *opaque, const void *buffer, size_t length)
+{
+  (void)opaque;
+
+  if (buffer)
+    printf ("Received data `%.*s'\n", (int)length, (char*)buffer);
+  return 0;
+}
+  
+
+static void
+run_client (const char *servername)
+{
+  gpg_error_t err;
+  assuan_context_t ctx;
+  assuan_fd_t no_close_fds[2];
+  const char *arglist[5];
+
+  no_close_fds[0] = fileno (stderr);
+  no_close_fds[1] = ASSUAN_INVALID_FD;
+
+  arglist[0] = servername;
+  arglist[1] = "--server";
+  arglist[2] = debug? "--debug" : verbose? "--verbose":NULL;
+  arglist[3] = NULL;
+
+  err = assuan_new (&ctx);
+  if (err)
+    log_fatal ("assuan_new failed: %s\n", gpg_strerror (err));
+
+  err = assuan_pipe_connect (ctx, servername, arglist, no_close_fds,
+                             NULL, NULL, 0);
+  if (err)
+    {
+      log_error ("assuan_pipe_connect failed: %s\n",
+                 gpg_strerror (err));
+      assuan_release (ctx);
+      return;
+    }
+      
+  log_info ("server started; pid is %ld\n",
+            (long)assuan_get_pid (ctx));
+  
+  err = assuan_transact (ctx, "ECHO Your lucky number is 3552664958674928.  "
+                         "Watch for it everywhere.",
+                         data_cb, NULL, NULL, NULL, NULL, NULL);
+  if (err)
+    {
+      log_error ("sending ECHO failed: %s\n", gpg_strerror (err));
+      return;
+    }
+
+  err = assuan_transact (ctx, "BYE", NULL, NULL, NULL, NULL, NULL, NULL);
+  if (err)
+    {
+      log_error ("sending BYE failed: %s\n", gpg_strerror (err));
+      return;
+    }
+
+  assuan_release (ctx);
+  return;
+}
+
+
+static void
+parse_std_file_handles (int *argcp, char ***argvp)
+{
+#ifdef HAVE_W32CE_SYSTEM
+  int argc = *argcp;
+  char **argv = *argvp;
+  const char *s;
+  assuan_fd_t fd;
+  int i;
+  int fixup = 0;
+
+  if (!argc)
+    return;
+
+  for (argc--, argv++; argc; argc--, argv++)
+    {
+      s = *argv;
+      if (*s == '-' && s[1] == '&' && s[2] == 'S'
+          && (s[3] == '0' || s[3] == '1' || s[3] == '2')
+          && s[4] == '=' 
+          && (strchr ("-01234567890", s[5]) || !strcmp (s+5, "null")))
+        {
+          if (s[5] == 'n')
+            fd = ASSUAN_INVALID_FD;
+          else
+            fd = _assuan_w32ce_finish_pipe (atoi (s+5), s[3] != '0');
+          switch (s[3] - '0')
+            {
+            case 0: my_stdin = fd; break;
+            case 1: my_stdout = fd; break;
+            case 2: my_stderr = fd; break;
+            }
+
+          fixup++;
+        }
+      else
+        break;
+    }
+
+  if (fixup)
+    {
+      argc = *argcp;
+      argc -= fixup;
+      *argcp = argc;
+
+      argv = *argvp;
+      for (i=1; i < argc; i++)
+        argv[i] = argv[i + fixup];
+      for (; i < argc + fixup; i++)
+        argv[i] = NULL;
+    }
+#else
+  (void)argcp;
+  (void)argvp;
+  my_stdin = 0;
+  my_stdout = 1;
+  my_stderr = 2;
+#endif
+}
+
+
+/* 
+     M A I N
+ */
+int 
+main (int argc, char **argv)
+{
+  gpg_error_t err;
+  const char *myname = "no-pgm";
+  int last_argc = -1;
+  int server = 0;
+  int silent_client = 0;
+  int silent_server = 0;
+
+  parse_std_file_handles (&argc, &argv);
+  if (argc)
+    {
+      myname = *argv;
+      log_set_prefix (*argv);
+      argc--; argv++;
+    }
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--help"))
+        {
+          printf ("usage: %s [options]\n"
+                  "\n"
+                  "Options:\n"
+                  "  --verbose      Show what is going on\n"
+                  "  --server       Run in server mode\n",
+                  log_get_prefix ());
+          exit (0);
+        }
+      if (!strcmp (*argv, "--verbose"))
+        {
+          verbose = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--debug"))
+        {
+          verbose = debug = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--server"))
+        {
+          server = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--silent-server"))
+        {
+          silent_server = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--silent-client"))
+        {
+          silent_client = 1;
+          argc--; argv++;
+        }
+      else
+        log_fatal ("invalid option `%s' (try --help)\n", *argv);
+    }
+
+  log_set_prefix (xstrconcat (log_get_prefix (), 
+                              server? ".server":".client", NULL));
+  assuan_set_assuan_log_prefix (log_get_prefix ());
+
+  err = assuan_sock_init ();
+  if (err)
+    log_fatal ("socket init failed: %s\n", gpg_strerror (err));
+
+  if (server)
+    {
+      log_info ("server started\n");
+      if (debug && !silent_server)
+        assuan_set_assuan_log_stream (stderr);
+      run_server (debug && !silent_server);
+      log_info ("server finished\n");
+    }
+  else
+    {
+      log_info ("client started\n");
+      if (debug && !silent_client)
+        assuan_set_assuan_log_stream (stderr);
+      run_client (myname);
+      log_info ("client finished\n");
+    }
+
+  return errorcount ? 1 : 0;
+}
+

-- 
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