[svn] assuan - r357 - in trunk: . doc src tests

svn author wk cvs at cvs.gnupg.org
Wed Feb 24 16:50:55 CET 2010


Author: wk
Date: 2010-02-24 16:50:55 +0100 (Wed, 24 Feb 2010)
New Revision: 357

Added:
   trunk/src/gpgcedev.c
   trunk/src/gpgcedev.def
   trunk/src/gpgcemgr.c
   trunk/tests/ce-createpipe.c
Modified:
   trunk/ChangeLog
   trunk/NEWS
   trunk/configure.ac
   trunk/doc/assuan.texi
   trunk/src/ChangeLog
   trunk/src/Makefile.am
   trunk/src/assuan-defs.h
   trunk/src/assuan-handler.c
   trunk/src/assuan-inquire.c
   trunk/src/assuan-pipe-connect.c
   trunk/src/assuan-socket-connect.c
   trunk/src/assuan.h
   trunk/src/libassuan.def
   trunk/src/libassuan.vers
   trunk/src/system.c
   trunk/src/sysutils.c
   trunk/tests/Makefile.am
   trunk/tests/ce-server.c
   trunk/tests/common.h
Log:
A couple of changes to eventually fully support W32ce.


[The diff below has been truncated]

Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2010-02-03 17:00:09 UTC (rev 356)
+++ trunk/ChangeLog	2010-02-24 15:50:55 UTC (rev 357)
@@ -1,3 +1,17 @@
+2010-02-24  Werner Koch  <wk at g10code.com>
+
+	* tests/ce-server.c: New.
+
+	* tests/ce-createpipe.c [W32CE]: New.
+
+2010-02-11  Werner Koch  <wk at g10code.com>
+
+	* configure.ac (inet_pton): Check for it.
+
+2010-02-04  Werner Koch  <wk at g10code.com>
+
+	* configure.ac (AC_TYPE_UINT16_T): New.
+
 2010-01-27  Werner Koch  <wk at g10code.com>
 
 	* tests/common.h (SOCKET2HANDLE, HANDLE2SOCKET): New.

Modified: trunk/src/ChangeLog
===================================================================
--- trunk/src/ChangeLog	2010-02-03 17:00:09 UTC (rev 356)
+++ trunk/src/ChangeLog	2010-02-24 15:50:55 UTC (rev 357)
@@ -1,3 +1,35 @@
+2010-02-24  Werner Koch  <wk at g10code.com>
+
+	* gpgcemgr.c: New.
+	* gpgcedev.c: New.
+	* sysutils.c (_assuan_w32ce_create_pipe): Rewrote to make use of
+	the new driver.
+
+2010-02-16  Werner Koch  <wk at g10code.com>
+
+	* system.c (assuan_free): New.
+	* libassuan.vers (assuan_free): Add it.
+	* libassuan.def (assuan_free): Add it.
+
+2010-02-11  Werner Koch  <wk at g10code.com>
+
+	* assuan-inquire.c (assuan_inquire): Allow case insensitive
+	responses.
+	(_assuan_inquire_ext_cb): Ditto.
+
+2010-02-10  Werner Koch  <wk at g10code.com>
+
+	* assuan-handler.c (std_handler_input, std_handler_output): Make
+	the parsed FD available to the notification functions.  This is
+	the documented behaviour.
+
+2010-02-04  Werner Koch  <wk at g10code.com>
+
+	* assuan-socket-connect.c: Include stdint.h and arpa/inet.h.
+	(parse_portno): New.
+	(assuan_socket_connect): Return a correct error code on failure.
+	Support assuan:// and file:// schemes.
+
 2010-02-03  Marcus Brinkmann  <marcus at g10code.de>
 
 	* libassuan.vers, libassuan.def: Add assuan_set_sock_nonce.
@@ -2,2 +34,9 @@
 
+2010-02-01  Werner Koch  <wk at g10code.com>
+
+	* sysutils.c (_assuan_w32ce_create_pipe): New.
+	* libassuan.def (_assuan_w32ce_create_pipe): New.
+	* assuan-defs.h (CreateFile) [W32CE]: New macro
+	* system.c (__assuan_pipe): Make it work for W32CE.
+
 2010-01-28  Werner Koch  <wk at g10code.com>

Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2010-02-03 17:00:09 UTC (rev 356)
+++ trunk/NEWS	2010-02-24 15:50:55 UTC (rev 357)
@@ -5,7 +5,16 @@
 
  * Support for WindowsCE.
 
+ * Input and output notification handler can now really access the
+   parsed fd as stated in the manual.
 
+ * Interface changes relative to the 2.0.0 release:
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ assuan_free               NEW.
+ _assuan_w32ce_create_pipe NEW.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
 Noteworthy changes in version 2.0.0 (2010-01-08)
 ------------------------------------------------
 

Modified: trunk/configure.ac
===================================================================
--- trunk/configure.ac	2010-02-03 17:00:09 UTC (rev 356)
+++ trunk/configure.ac	2010-02-24 15:50:55 UTC (rev 357)
@@ -224,6 +224,7 @@
 AC_HEADER_STDC
 AC_CHECK_HEADERS([string.h locale.h sys/uio.h stdint.h inttypes.h])
 AC_TYPE_UINTPTR_T
+AC_TYPE_UINT16_T
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
@@ -267,7 +268,7 @@
 #
 # Checks for library functions.
 #
-AC_CHECK_FUNCS([flockfile funlockfile])
+AC_CHECK_FUNCS([flockfile funlockfile inet_pton])
 
 # On some systems (e.g. Solaris) nanosleep requires linking to librl.
 # Given that we use nanosleep only as an optimization over a select

Modified: trunk/doc/assuan.texi
===================================================================
--- trunk/doc/assuan.texi	2010-02-03 17:00:09 UTC (rev 356)
+++ trunk/doc/assuan.texi	2010-02-24 15:50:55 UTC (rev 357)
@@ -216,7 +216,7 @@
 
 On a connect request the server responds either with an okay or an
 error status.  For authentication-check the server may send an Inquiry
-Response prior to the first Okay, and it may also issue Status
+response prior to the first Okay, and it may also issue Status
 messages.  The server must check that the client is allowed to
 connect, this is done by requesting the credentials for the peer and
 comparing them to those of the server.  This avoids attacks based on
@@ -1379,7 +1379,8 @@
 argument passed to that function is the entire line.  Because that line
 has already been parsed when the function gets called, a file descriptor
 set with the @code{INPUT} command may already be used.  That file
-descriptor is available by calling @code{assuan_get_input_fd}.
+descriptor is available by calling @code{assuan_get_input_fd}.  If the
+notification function returns an error, the input fd does not change.
 @end deftypefun
 
 @deftypefun gpg_error_t assuan_register_output_notify (@w{assuan_context_t @var{ctx}}, @w{assuan_handler_t @var{handler}})
@@ -1390,7 +1391,8 @@
 argument passed to that function is the entire line.  Because that line
 has already been parsed when the function gets called, a file descriptor
 set with the @code{OUTPUT} command may already be used.  That file
-descriptor is available by calling @code{assuan_get_output_fd}.
+descriptor is available by calling @code{assuan_get_output_fd}. If the
+notification function returns an error, the output fd does not change.
 @end deftypefun
 
 @deftypefun gpg_error_t assuan_set_hello_line (@w{assuan_context_t @var{ctx}}, @w{const char *@var{line}})

Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am	2010-02-03 17:00:09 UTC (rev 356)
+++ trunk/src/Makefile.am	2010-02-24 15:50:55 UTC (rev 357)
@@ -25,6 +25,10 @@
 m4datadir = $(datadir)/aclocal
 m4data_DATA = libassuan.m4
 lib_LTLIBRARIES = libassuan.la
+if HAVE_W32CE_SYSTEM
+lib_LTLIBRARIES += libgpgcedev.la
+bin_PROGRAMS = gpgcemgr
+endif
 include_HEADERS = assuan.h
 
 if HAVE_LD_VERSION_SCRIPT
@@ -97,3 +101,12 @@
 libassuan_la_DEPENDENCIES = @LTLIBOBJS@ \
 	$(srcdir)/libassuan.vers $(libassuan_deps)
 libassuan_la_LIBADD = @LTLIBOBJS@ @NETLIBS@ @GPG_ERROR_LIBS@
+
+if HAVE_W32CE_SYSTEM
+libgpgcedev_la_SOURCES = gpgcedev.c
+libgpgcedev_la_CPPFLAGS = $(AM_CPPFLAGS)
+libgpgcedev_la_LDFLAGS = $(no_undefined) -export-symbols $(srcdir)/gpgcedev.def
+libgpgcedev_la_DEPENDENCIES = gpgcedev.def
+gpgcemgr_SOURCES = gpgcemgr.c
+gpgcemgr_CPPFLAGS = $(AM_CPPFLAGS)
+endif

Modified: trunk/src/assuan-defs.h
===================================================================
--- trunk/src/assuan-defs.h	2010-02-03 17:00:09 UTC (rev 356)
+++ trunk/src/assuan-defs.h	2010-02-24 15:50:55 UTC (rev 357)
@@ -1,5 +1,6 @@
 /* assuan-defs.h - Internal definitions to Assuan
-   Copyright (C) 2001, 2002, 2004, 2005, 2007-2009 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2002, 2004, 2005, 2007, 2008,
+                 2009, 2010 Free Software Foundation, Inc.
 
    This file is part of Assuan.
 
@@ -339,12 +340,14 @@
 const char *_assuan_sysutils_blurb (void);
 
 #ifdef HAVE_W32CE_SYSTEM
+
 #define getpid() GetCurrentProcessId ()
 char *_assuan_getenv (const char *name);
 #define getenv(a) _assuan_getenv ((a))
-#endif
 
+#endif /*HAVE_W32CE_SYSTEM*/
 
+
 /* Prototypes for replacement functions.  */
 #ifndef HAVE_MEMRCHR
 void *memrchr (const void *block, int c, size_t size);

Modified: trunk/src/assuan-handler.c
===================================================================
--- trunk/src/assuan-handler.c	2010-02-03 17:00:09 UTC (rev 356)
+++ trunk/src/assuan-handler.c	2010-02-24 15:50:55 UTC (rev 357)
@@ -234,7 +234,7 @@
 	return set_error (ctx, GPG_ERR_ASS_SYNTAX, "number required");
 #ifdef HAVE_W32_SYSTEM
       /* Fixme: For a W32/64bit system we will need to change the cast
-         and the conversion fucntion.  */
+         and the conversion function.  */
       *rfd = (void*)strtoul (line, &endp, 10);
 #else
       *rfd = strtoul (line, &endp, 10);
@@ -259,14 +259,20 @@
 std_handler_input (assuan_context_t ctx, char *line)
 {
   gpg_error_t rc;
-  assuan_fd_t fd;
+  assuan_fd_t fd, oldfd;
 
   rc = assuan_command_parse_fd (ctx, line, &fd);
   if (rc)
     return PROCESS_DONE (ctx, rc);
   if (ctx->input_notify_fnc)
-    rc = ctx->input_notify_fnc (ctx, line);
-  if (! rc)
+    {
+      oldfd = ctx->input_fd;
+      ctx->input_fd = fd;
+      rc = ctx->input_notify_fnc (ctx, line);
+      if (rc)
+        ctx->input_fd = oldfd;
+    }
+  else if (!rc)
     ctx->input_fd = fd;
   return PROCESS_DONE (ctx, rc);
 }
@@ -277,14 +283,20 @@
 std_handler_output (assuan_context_t ctx, char *line)
 {
   gpg_error_t rc;
-  assuan_fd_t fd;
+  assuan_fd_t fd, oldfd;
 
   rc = assuan_command_parse_fd (ctx, line, &fd);
   if (rc)
     return PROCESS_DONE (ctx, rc);
   if (ctx->output_notify_fnc)
-    rc = ctx->output_notify_fnc (ctx, line);
-  if (!rc)
+    {
+      oldfd = ctx->output_fd;
+      ctx->output_fd = fd;
+      rc = ctx->output_notify_fnc (ctx, line);
+      if (rc)
+        ctx->output_fd = oldfd;
+    }
+  else if (!rc)
     ctx->output_fd = fd;
   return PROCESS_DONE (ctx, rc);
 }

Modified: trunk/src/assuan-inquire.c
===================================================================
--- trunk/src/assuan-inquire.c	2010-02-03 17:00:09 UTC (rev 356)
+++ trunk/src/assuan-inquire.c	2010-02-24 15:50:55 UTC (rev 357)
@@ -183,15 +183,23 @@
           linelen = ctx->inbound.linelen;
         }    
       while (*line == '#' || !linelen);
-      if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
+
+      /* Note: As a convenience for manual testing we allow case
+         insensitive keywords.  */
+      if ((line[0] == 'E'||line[0] == 'e')
+          && (line[1] == 'N' || line[1] == 'n')
+          && (line[2] == 'D' || line[2] == 'd')
           && (!line[3] || line[3] == ' '))
         break; /* END command received*/
-      if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N')
+      if ((line[0] == 'C' || line[0] == 'c')
+          && (line[1] == 'A' || line[1] == 'a')
+          && (line[2] == 'N' || line[2] == 'n'))
         {
           rc = _assuan_error (ctx, GPG_ERR_ASS_CANCELED);
           goto leave;
         }
-      if (line[0] != 'D' || line[1] != ' ' || nodataexpected)
+      if ((line[0] != 'D' && line[0] != 'd') 
+          || line[1] != ' ' || nodataexpected)
         {
           rc = _assuan_error (ctx, GPG_ERR_ASS_UNEXPECTED_CMD);
           goto leave;
@@ -268,19 +276,23 @@
   linelen = ctx->inbound.linelen;
   mb = ctx->inquire_membuf;
 
-  if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N')
+  if ((line[0] == 'C' || line[0] == 'c')
+      && (line[1] == 'A' || line[1] == 'a')
+      && (line[2] == 'N' || line[2] == 'n'))
     {
       rc = _assuan_error (ctx, GPG_ERR_ASS_CANCELED);
       goto leave;
     }
-  if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
+  if ((line[0] == 'E'||line[0] == 'e')
+      && (line[1] == 'N' || line[1] == 'n')
+      && (line[2] == 'D' || line[2] == 'd')
       && (!line[3] || line[3] == ' '))
     {
       rc = 0;
       goto leave;
     }
 
-  if (line[0] != 'D' || line[1] != ' ' || mb == NULL)
+  if ((line[0] != 'D' && line[0] != 'd') || line[1] != ' ' || mb == NULL)
     {
       rc = _assuan_error (ctx, GPG_ERR_ASS_UNEXPECTED_CMD);
       goto leave;
@@ -344,8 +356,8 @@
  * @cb: A callback handler which is invoked after the operation completed.
  * @cb_data: A user-provided value passed to the callback handler.
  * 
- * A Server may use this to Send an inquire.  r_buffer, r_length and
- * maxlen may all be NULL/0 to indicate that no real data is expected.
+ * A server may use this to send an inquire.  R_BUFFER, R_LENGTH and
+ * MAXLEN may all be NULL/0 to indicate that no real data is expected.
  * When this function returns, 
  *
  * Return value: 0 on success or an ASSUAN error code

Modified: trunk/src/assuan-pipe-connect.c
===================================================================
--- trunk/src/assuan-pipe-connect.c	2010-02-03 17:00:09 UTC (rev 356)
+++ trunk/src/assuan-pipe-connect.c	2010-02-24 15:50:55 UTC (rev 357)
@@ -382,7 +382,7 @@
           pipes are usually created using the `socketpair' function.
           It also enables features only available with such servers.
 
-   Bit 7: If set and there is a need to start ther server it will be
+   Bit 7: If set and there is a need to start the server it will be
           started as a background process.  This flag is useful under
           W32 systems, so that no new console is created and pops up a
           console window when starting the server

Modified: trunk/src/assuan-socket-connect.c
===================================================================
--- trunk/src/assuan-socket-connect.c	2010-02-03 17:00:09 UTC (rev 356)
+++ trunk/src/assuan-socket-connect.c	2010-02-24 15:50:55 UTC (rev 357)
@@ -23,13 +23,18 @@
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
 #include <unistd.h>
 #include <sys/types.h>
-#ifndef HAVE_W32_SYSTEM
-#include <sys/socket.h>
-#include <sys/un.h>
+#ifdef HAVE_W32_SYSTEM
+# include <windows.h>
 #else
-#include <windows.h>
+# include <sys/socket.h>
+# include <sys/un.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
 #endif
 
 #include "assuan-defs.h"
@@ -53,19 +58,74 @@
 #endif
 
 
+#undef WITH_IPV6
+#if defined (AF_INET6) && defined(PF_INET) \
+    && defined (INET6_ADDRSTRLEN) && defined(HAVE_INET_PTON)
+# define WITH_IPV6 1
+#endif
+
+
+
+/* Returns true if STR represents a valid port number in decimal
+   notation and no garbage is following.  */
+static int 
+parse_portno (const char *str, uint16_t *r_port)
+{
+  unsigned int value;
+
+  for (value=0; *str && (*str >= '0' && *str <= '9'); str++)
+    {
+      value = value * 10 + (*str - '0');
+      if (value > 65535)
+        return 0;
+    }
+  if (*str || !value)
+    return 0;
+
+  *r_port = value;
+  return 1;
+}
+
+
+
 /* Make a connection to the Unix domain socket NAME and return a new
    Assuan context in CTX.  SERVER_PID is currently not used but may
-   become handy in the future.  With flags set to 1 sendmsg and
-   recvmsg are used. */
+   become handy in the future.  Defined flag bits are:
+
+     ASSUAN_SOCKET_CONNECT_FDPASSING
+        sendmsg and recvmsg are used.
+
+   NAME must either start with a slash and optional with a drive
+   prefix ("c:") or use one of these URL schemata:
+
+      file://<fname>
+
+        This is the same as the defualt just with an explicit schemata.
+
+      assuan://<ipaddr>:<port>
+      assuan://[<ip6addr>]:<port>
+         
+        Connect using TCP to PORT of the server with the numerical
+        IPADDR.  Not that the '[' and ']' are literal characters.
+
+  */
 gpg_error_t
 assuan_socket_connect (assuan_context_t ctx, const char *name,
 		       pid_t server_pid, unsigned int flags)
 {
-  gpg_error_t err;
+  gpg_error_t err = 0;
   assuan_fd_t fd;
-  struct sockaddr_un srvr_addr;
-  size_t len;
+#ifdef WITH_IPV6
+  struct sockaddr_in6 srvr_addr_in6;
+#endif
+  struct sockaddr_un srvr_addr_un;
+  struct sockaddr_in srvr_addr_in;
+  struct sockaddr *srvr_addr = NULL;
+  uint16_t port = 0;
+  size_t len = 0;
   const char *s;
+  int af = AF_LOCAL;
+  int pf = PF_LOCAL;
 
   TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_socket_connect", ctx,
 	  "name=%s, flags=0x%x", name ? name : "(null)", flags);
@@ -73,38 +133,127 @@
   if (!ctx || !name)
     return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
 
-  /* We require that the name starts with a slash, so that we
-     eventually can reuse this function for other socket types.  To
-     make things easier we allow an optional driver prefix.  */
-  s = name;
-  if (*s && s[1] == ':')
-    s += 2;
-  if (*s != DIRSEP_C && *s != '/')
-    return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
+  if (!strncmp (name, "file://", 7) && name[7])
+    name += 7;
+  else if (!strncmp (name, "assuan://", 9) && name[9])
+    {
+      name += 9;
+      af = AF_INET;
+      pf = PF_INET;
+    }
+  else /* Default.  */
+    {
+      /* We require that the name starts with a slash if no URL
+         schemata is used.  To make things easier we allow an optional
+         driver prefix.  */
+      s = name;
+      if (*s && s[1] == ':')
+        s += 2;
+      if (*s != DIRSEP_C && *s != '/')
+        return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
+    }
 
-  if (strlen (name)+1 >= sizeof srvr_addr.sun_path)
-    return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
+  if (af == AF_LOCAL)
+    {
+      if (strlen (name)+1 >= sizeof srvr_addr_un.sun_path)
+        return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
 
-  fd = _assuan_sock_new (ctx, PF_LOCAL, SOCK_STREAM, 0);
+      memset (&srvr_addr_un, 0, sizeof srvr_addr_un);
+      srvr_addr_un.sun_family = AF_LOCAL;
+      strncpy (srvr_addr_un.sun_path, name, sizeof (srvr_addr_un.sun_path) - 1);
+      srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path) - 1] = 0;
+      len = SUN_LEN (&srvr_addr_un);
+
+      srvr_addr = (struct sockaddr *)&srvr_addr_un;
+    }
+  else
+    {
+      char *addrstr, *p;
+      void *addrbuf = NULL;
+
+      addrstr = _assuan_malloc (ctx, strlen (name) + 1);
+      if (!addrstr)
+        return _assuan_error (ctx, gpg_err_code_from_syserror ());
+
+      if (*addrstr == '[')
+        {
+          strcpy (addrstr, name+1);
+          p = strchr (addrstr, ']');
+          if (!p || p[1] != ':' || !parse_portno (p+2, &port))
+            err = _assuan_error (ctx, GPG_ERR_BAD_URI);
+          else 
+            {
+              *p = 0;
+#ifdef WITH_IPV6
+              af = AF_INET6;
+              pf = PF_INET6;
+              memset (&srvr_addr_in6, 0, sizeof srvr_addr_in6);
+              srvr_addr_in6.sin6_family = af;
+              srvr_addr_in6.sin6_port = htons (port);
+              addrbuf = &srvr_addr_in6.sin6_addr;
+              srvr_addr = (struct sockaddr *)&srvr_addr_in6;
+              len = sizeof srvr_addr_in6;
+#else
+              err =  _assuan_error (ctx, GPG_ERR_EAFNOSUPPORT);
+#endif
+            }
+        }
+      else
+        {
+          strcpy (addrstr, name);
+          p = strchr (addrstr, ':');
+          if (!p || !parse_portno (p+1, &port))
+            err = _assuan_error (ctx, GPG_ERR_BAD_URI);
+          else
+            {
+              *p = 0;
+              memset (&srvr_addr_in, 0, sizeof srvr_addr_in);
+              srvr_addr_in.sin_family = af;
+              srvr_addr_in.sin_port = htons (port);
+              addrbuf = &srvr_addr_in.sin_addr;
+              srvr_addr = (struct sockaddr *)&srvr_addr_in;
+              len = sizeof srvr_addr_in;
+            }
+        }
+
+      if (!err)
+        {
+#ifdef HAVE_INET_PTON
+          switch (inet_pton (af, addrstr, addrbuf))
+            {
+            case 1:  break;
+            case 0:  err = _assuan_error (ctx, GPG_ERR_BAD_URI); break;
+            default: err = _assuan_error (ctx, gpg_err_code_from_syserror ());
+            }
+#else /*!HAVE_INET_PTON*/
+          /* We need to use the old function.  If we are here v6
+             support isn't enabled anyway and thus we can do fine
+             without.  Note that Windows as a compatible inet_pton
+             function named inetPton, but only since Vista.  */
+          srvr_addr_in.sin_addr.s_addr = inet_addr (addrstr);
+          if (srvr_addr_in.sin_addr.s_addr == INADDR_NONE)
+            err = _assuan_error (ctx, GPG_ERR_BAD_URI);
+#endif /*!HAVE_INET_PTON*/
+        }
+      
+      _assuan_free (ctx, addrstr);
+      if (err)
+        return err;
+    }
+  
+  fd = _assuan_sock_new (ctx, pf, SOCK_STREAM, 0);
   if (fd == ASSUAN_INVALID_FD)
     {
-      TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect_ext", ctx,
-	      "can't create socket: %s", strerror (errno));
-      /* FIXME: Cleanup  */
-      return _assuan_error (ctx, GPG_ERR_ASS_GENERAL);
+      err = _assuan_error (ctx, gpg_err_code_from_syserror ());
+      TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect", ctx,
+              "can't create socket: %s", strerror (errno));
+      return err;
     }
 
-  memset (&srvr_addr, 0, sizeof srvr_addr);
-  srvr_addr.sun_family = AF_LOCAL;
-  strncpy (srvr_addr.sun_path, name, sizeof (srvr_addr.sun_path) - 1);
-  srvr_addr.sun_path[sizeof (srvr_addr.sun_path) - 1] = 0;
-  len = SUN_LEN (&srvr_addr);
-
-  if (_assuan_sock_connect (ctx, fd, (struct sockaddr *) &srvr_addr, len) == -1)
+  if (_assuan_sock_connect (ctx, fd, srvr_addr, len) == -1)
     {
-      TRACE2 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect_ext", ctx,
+      TRACE2 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect", ctx,
 	      "can't connect to `%s': %s\n", name, strerror (errno));
-      /* FIXME: Cleanup */
       _assuan_close (ctx, fd);
       return _assuan_error (ctx, GPG_ERR_ASS_CONNECT_FAILED);
     }
@@ -129,14 +278,14 @@
 
     err = _assuan_read_from_server (ctx, &response, &off);
     if (err)
-      TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect_ext", ctx,
+      TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect", ctx,
 	      "can't connect to server: %s\n", gpg_strerror (err));
     else if (response != ASSUAN_RESPONSE_OK)
       {
 	char *sname = _assuan_encode_c_string (ctx, ctx->inbound.line);
 	if (sname)
 	  {
-	    TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect_ext", ctx,
+	    TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect", ctx,
 		    "can't connect to server: %s", sname);
 	    _assuan_free (ctx, sname);
 	  }

Modified: trunk/src/assuan.h
===================================================================
--- trunk/src/assuan.h	2010-02-03 17:00:09 UTC (rev 356)
+++ trunk/src/assuan.h	2010-02-24 15:50:55 UTC (rev 357)
@@ -199,6 +199,10 @@
 /* Release all resources associated with the given context.  */
 void assuan_release (assuan_context_t ctx);
 
+/* Release the memory at PTR using the allocation handler of the
+   context CTX.  This is a convenience function.  */
+void assuan_free (assuan_context_t ctx, void *ptr);
+
 
 /* Set user-data in a context.  */
 void assuan_set_pointer (assuan_context_t ctx, void *pointer);
@@ -634,7 +638,14 @@
 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__*/
+
 #ifdef __cplusplus
 }
 #endif

Added: trunk/src/gpgcedev.c
===================================================================
--- trunk/src/gpgcedev.c	                        (rev 0)
+++ trunk/src/gpgcedev.c	2010-02-24 15:50:55 UTC (rev 357)
@@ -0,0 +1,720 @@
+/* gpgcedrv.c - WindowsCE device driver to implement a pipe.
+   Copyright (C) 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/>.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <windows.h>
+#include <devload.h>
+#include <winioctl.h>
+
+#define ENABLE_DEBUG
+#warning Cancel and caller process termination not handled.
+
+
+/* Missing IOCTLs in the current mingw32ce.  */
+#ifndef IOCTL_PSL_NOTIFY
+# define FILE_DEVICE_PSL 259
+# define IOCTL_PSL_NOTIFY                               \
+  CTL_CODE (259, 255, METHOD_NEITHER, FILE_ANY_ACCESS)
+#endif /*IOCTL_PSL_NOTIFY*/
+
+
+/* The IOCTL used to tell the device about the handle.
+
+   The required inbuf parameter is the address of a variable holding
+   the handle.  */
+#define GPGCEDEV_IOCTL_SET_HANDLE \
+  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.  */
+#define GPGCEDEV_IOCTL_MAKE_PIPE \
+  CTL_CODE (FILE_DEVICE_STREAMS, 2049, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+
+/* An object to store information pertaining to an open-context.  */
+struct opnctx_s;
+typedef struct opnctx_s *opnctx_t;
+struct opnctx_s
+{
+  int inuse;        /* True if this object has valid data.  */
+  opnctx_t assoc;   /* This context has been associated with this
+                       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.  */
+  DWORD access_code;/* Value from OpenFile.  */
+  DWORD share_mode; /* Value from OpenFile.  */
+  CRITICAL_SECTION critsect;  /* Lock for all operations.  */
+  int locked;       /* True if we are in a critical section.  */
+
+  /* The malloced buffer and its size.  We use a buffer for each
+     handle which allows us eventually implement a system to
+     distribute data to several handles.  Not sure whether this is
+     really needed but as a side effect it makes the code easier. */
+  char *buffer;       
+  size_t buffer_size;
+  size_t buffer_len;  /* The valid length of the bufer.  */
+  size_t buffer_pos;  /* The actual read or write position.  */
+
+  HANDLE space_available; /* Set if space is available.  */
+  HANDLE data_available;  /* Set if data is available.  */
+};
+
+/* A malloced table of open-context and the number of allocated slots.  */
+static opnctx_t opnctx_table;
+static size_t   opnctx_table_size;
+
+/* A criticial section object used to protect the OPNCTX_TABLE.  */
+static CRITICAL_SECTION opnctx_table_cs;
+
+/* We don't need a device context thus we use the adress of the
+   critical section object for it.  */
+#define DEVCTX_VALUE ((DWORD)(&opnctx_table_cs))
+
+/* Constants used for our lock functions.  */
+#define LOCK_TRY  0
+#define LOCK_WAIT 1
+
+
+
+static void
+log_debug (const char *fmt, ...)
+{
+#ifndef ENABLE_DEBUG
+  (void)fmt;
+#else
+  va_list arg_ptr;
+  FILE *fp;
+
+  fp = fopen ("\\gpgcedev.log", "a+");
+  if (!fp)
+    return;
+  va_start (arg_ptr, fmt);
+  vfprintf (fp, fmt, arg_ptr);
+  va_end (arg_ptr);
+  fclose (fp);
+#endif
+}
+
+
+
+
+/* Return a new opnctx handle and mark it as used.  Returns NULL and
+   sets LastError on memory failure etc.  On success the context is
+   locked.  */
+static opnctx_t
+get_new_opnctx (void)
+{
+  opnctx_t opnctx = NULL;
+  int idx;
+
+  EnterCriticalSection (&opnctx_table_cs);
+  for (idx=0; idx < opnctx_table_size; idx++)
+    if (!opnctx_table[idx].inuse)
+      break;
+  if (idx == opnctx_table_size)
+    {
+      /* We need to increase the size of the table.  The approach we
+         take is straightforward to minimize the risk of bugs.  */
+      opnctx_t newtbl;
+      size_t newsize = opnctx_table_size + 64;
+
+      newtbl = calloc (newsize, sizeof *newtbl);
+      if (!newtbl)
+        goto leave;
+      for (idx=0; idx < opnctx_table_size; idx++)
+        newtbl[idx] = opnctx_table[idx];
+      free (opnctx_table);
+      opnctx_table = newtbl;
+      idx = opnctx_table_size;
+      opnctx_table_size = newsize;
+    }
+  opnctx = opnctx_table + idx;
+  opnctx->assoc = NULL;
+  opnctx->hd = INVALID_HANDLE_VALUE;
+  opnctx->assoc = 0;
+  opnctx->buffer_size = 512;
+  opnctx->buffer = malloc (opnctx->buffer_size);
+  if (!opnctx->buffer)
+    {
+      opnctx = NULL;
+      goto leave;
+    }
+  opnctx->buffer_len = 0;
+  opnctx->buffer_pos = 0;
+  opnctx->data_available = INVALID_HANDLE_VALUE;
+  opnctx->space_available = INVALID_HANDLE_VALUE;
+
+  opnctx->inuse = 1;
+  InitializeCriticalSection (&opnctx->critsect);
+  EnterCriticalSection (&opnctx->critsect);
+  opnctx->locked = 1;
+  
+ leave:
+  LeaveCriticalSection (&opnctx_table_cs);
+  log_debug ("get_new_opnctx -> %p\n", opnctx);
+  return opnctx;
+}
+
+
+/* Find the OPNCTX for handle HD.  */
+static opnctx_t
+find_and_lock_opnctx (HANDLE hd)
+{
+  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)
+      {
+        result = opnctx_table + idx;
+        break;
+      }
+  LeaveCriticalSection (&opnctx_table_cs);
+  if (!result)
+    SetLastError (ERROR_INVALID_HANDLE);
+  else if (TryEnterCriticalSection (&result->critsect))
+    result->locked++;
+  else
+    {
+      SetLastError (ERROR_BUSY);
+      result = NULL;
+    }
+  log_debug ("find_opnctx -> %p\n", result);
+  return result;
+}
+
+
+/* Check that OPNCTX is valid.  Returns TRUE if it is valid or FALSE
+   if it is a bad or closed contect.  In the latter case SetLastError
+   is called.  In the former case a lock is taken and unlock_opnctx
+   needs to be called.  If WAIT is false the fucntion only tries to
+   acquire a lock. */
+static BOOL
+validate_and_lock_opnctx (opnctx_t opnctx, int wait)
+{
+  BOOL result = FALSE;
+  int idx;
+
+  EnterCriticalSection (&opnctx_table_cs);
+  for (idx=0; idx < opnctx_table_size; idx++)
+    if (opnctx_table[idx].inuse && (opnctx_table + idx) == opnctx)
+      {
+        result = TRUE;
+        break;
+      }
+  LeaveCriticalSection (&opnctx_table_cs);
+
+  if (!result)
+    SetLastError (ERROR_INVALID_HANDLE);
+  else if (wait)
+    {
+      EnterCriticalSection (&opnctx->critsect);
+      opnctx->locked++;
+    }
+  else if (TryEnterCriticalSection (&opnctx->critsect))
+    opnctx->locked++;
+  else
+    {
+      SetLastError (ERROR_BUSY);
+      result = FALSE;
+    }
+  return result;
+}
+
+
+static void
+unlock_opnctx (opnctx_t opnctx)
+{
+  opnctx->locked--;
+  LeaveCriticalSection (&opnctx->critsect);
+}
+
+
+
+
+static char *
+wchar_to_utf8 (const wchar_t *string)
+{
+  int n;
+  size_t length = wcslen (string);
+  char *result;
+
+  n = WideCharToMultiByte (CP_UTF8, 0, string, length, NULL, 0, NULL, NULL);
+  if (n < 0 || (n+1) <= 0)
+    abort ();
+
+  result = malloc (n+1);
+  if (!result)
+    abort ();
+  n = WideCharToMultiByte (CP_ACP, 0, string, length, result, n, NULL, NULL);
+  if (n < 0)
+    abort ();
+  
+  result[n] = 0;
+  return result;
+}
+
+
+/* Initialize the device and return a device specific context.  */
+DWORD
+GPG_Init (LPCTSTR active_key, DWORD bus_context)
+{
+  char *tmpbuf;
+  (void)bus_context;
+  
+  tmpbuf = wchar_to_utf8 (active_key);
+  log_debug ("GPG_Init (%s)\n", tmpbuf);
+  free (tmpbuf);
+
+  /* We don't need any global data.  However, we need to return
+     something.  */
+  return DEVCTX_VALUE;
+}
+
+
+
+/* Deinitialize this device driver.  */
+BOOL
+GPG_Deinit (DWORD devctx)
+{
+  log_debug ("GPG_Deinit (%p)\n", (void*)devctx);
+  if (devctx != DEVCTX_VALUE)
+    {
+      SetLastError (ERROR_INVALID_PARAMETER);
+      return FALSE; /* Error.  */
+    }
+  
+  /* FIXME: Release resources.  */
+
+  return TRUE; /* Success.  */
+}
+
+
+
+/* Create a new open context.  This fucntion is called due to a
+   CreateFile from the application.  */
+DWORD
+GPG_Open (DWORD devctx, DWORD access_code, DWORD share_mode)
+{
+  opnctx_t opnctx;
+
+  log_debug ("GPG_Open(devctx=%p)\n", (void*)devctx);
+  if (devctx != DEVCTX_VALUE)
+    {
+      SetLastError (ERROR_INVALID_PARAMETER);
+      return 0; /* Error.  */
+    }
+
+  opnctx = get_new_opnctx ();
+  if (!opnctx)
+    return 0;
+  opnctx->access_code = access_code;
+  opnctx->share_mode = share_mode;
+
+  unlock_opnctx (opnctx);
+  return (DWORD)opnctx;
+}
+
+
+
+BOOL
+GPG_Close (DWORD opnctx_arg)
+{
+  opnctx_t opnctx = (opnctx_t)opnctx_arg;
+  BOOL result = FALSE;
+  int idx;
+
+  log_debug ("GPG_Close(%p)\n", (void*)opnctx);
+
+  EnterCriticalSection (&opnctx_table_cs);
+  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)
+              {
+                opnctx->assoc->assoc = NULL;
+                opnctx->assoc = NULL;
+              }
+            opnctx->hd = INVALID_HANDLE_VALUE;
+          }
+        if (opnctx->locked)
+          {
+            /* FIXME: Check earlier or use close only in locked state
+               or use PReClose.  */
+            log_debug ("GPG_Close while still locked\n");
+          }
+        DeleteCriticalSection (&opnctx->critsect);
+        if (opnctx->buffer)
+          {
+            free (opnctx->buffer);
+            opnctx->buffer = NULL;
+            opnctx->buffer_size = 0;
+          }
+        if (opnctx->space_available != INVALID_HANDLE_VALUE)
+          {
+            CloseHandle (opnctx->space_available);
+            opnctx->space_available = INVALID_HANDLE_VALUE;
+          }
+        if (opnctx->data_available != INVALID_HANDLE_VALUE)
+          {
+            CloseHandle (opnctx->data_available);
+            opnctx->data_available = INVALID_HANDLE_VALUE;
+          }
+        opnctx->inuse = 0;
+        result = TRUE;
+        break;
+      }
+  LeaveCriticalSection (&opnctx_table_cs);
+
+  if (!result)
+    SetLastError (ERROR_INVALID_HANDLE);
+  return result;
+}
+
+
+
+DWORD
+GPG_Read (DWORD opnctx_arg, void *buffer, DWORD count)
+{
+  opnctx_t rctx = (opnctx_t)opnctx_arg;
+  opnctx_t wctx;
+  int result = -1;
+  const char *src;
+  char *dst;
+
+  log_debug ("GPG_Read(%p, count=%d)\n", (void*)rctx, count);
+
+  /* We use the write end's buffer, thus there is no need to wait for
+     our (read end) lock.  */
+  if (!validate_and_lock_opnctx (rctx, LOCK_TRY))
+    return -1; /* Error.  */
+
+  if (rctx->is_write)
+    {
+      SetLastError (ERROR_INVALID_ACCESS);
+      goto leave;
+    }
+  if (rctx->hd == INVALID_HANDLE_VALUE || !rctx->assoc)
+    {
+      SetLastError (ERROR_BROKEN_PIPE);
+      goto leave;
+    }
+
+  /* Read from the corresponding write buffer.  */
+ retry:
+  wctx = rctx->assoc;
+  if (!validate_and_lock_opnctx (wctx, LOCK_WAIT))
+    goto leave;
+
+  if (wctx->buffer_pos == wctx->buffer_len)
+    {
+      unlock_opnctx (wctx);
+      log_debug ("%s:%d: WFSO(data_available)\n",  __func__, __LINE__);
+      WaitForSingleObject (wctx->data_available, INFINITE);
+      log_debug ("%s:%d: WFSO ... woke up\n",  __func__, __LINE__);
+      goto retry;
+    }
+  
+  dst = buffer;
+  src = wctx->buffer + wctx->buffer_pos;
+  while (count > 0 && wctx->buffer_pos < wctx->buffer_len)
+    {
+      *dst++ = *src++;
+      count--;
+      wctx->buffer_pos++;
+    }
+  result = (dst - (char*)buffer);
+  if (wctx->buffer_pos == wctx->buffer_len)
+    wctx->buffer_pos = wctx->buffer_len = 0;
+  
+  /* Now there should be some space available.  Signal the write end.
+     Even if COUNT was passed as NULL and no space is available,
+     signaling must be done.  */
+  if (!SetEvent (wctx->space_available))
+    {
+      log_debug ("%s:%d: SetEvent(space_available) failed: rc=%d\n",
+                 __func__, __LINE__, (int)GetLastError ());
+      unlock_opnctx (wctx);
+      goto leave;
+    }
+  unlock_opnctx (wctx);
+
+ leave:
+  unlock_opnctx (rctx);
+  return result;
+}
+
+
+
+DWORD
+GPG_Write (DWORD opnctx_arg, const void *buffer, DWORD count)
+{
+  opnctx_t wctx = (opnctx_t)opnctx_arg;
+  int result = -1;
+  const char *src;
+  char *dst;
+  size_t nwritten = 0;
+
+  log_debug ("GPG_Write(%p, count=%d)\n", (void*)wctx, count);
+ retry:
+  if (!validate_and_lock_opnctx (wctx, LOCK_WAIT))
+    return -1; /* Error.  */
+
+  if (!wctx->is_write)
+    {
+      SetLastError (ERROR_INVALID_ACCESS);
+      goto leave;
+    }
+  if (wctx->hd == INVALID_HANDLE_VALUE || !wctx->assoc)
+    {
+      SetLastError (ERROR_BROKEN_PIPE);
+      goto leave;
+    }
+  if (!count)
+    {
+      result = 0;
+      goto leave;
+    }
+
+  /* Write to our buffer.  */
+  if (wctx->buffer_len == wctx->buffer_size)
+    {
+      /* Buffer is full.  */
+      unlock_opnctx (wctx);
+      log_debug ("%s:%d: WFSO(space_available)\n",  __func__, __LINE__);
+      WaitForSingleObject (wctx->space_available, INFINITE);
+      log_debug ("%s:%d: WFSO ... woke up\n",  __func__, __LINE__);
+      goto retry;
+    }
+
+  src = buffer;
+  dst = wctx->buffer + wctx->buffer_len;
+  while (count > 0 && wctx->buffer_len < wctx->buffer_size)
+    {
+      *dst++ = *src++;
+      count--;
+      wctx->buffer_len++;
+      nwritten++;
+    }
+  if (!SetEvent (wctx->data_available))
+    {
+      log_debug ("%s:%d: SetEvent(data_available) failed: rc=%d\n",
+                 __func__, __LINE__, (int)GetLastError ());
+      goto leave;
+    }
+  result = nwritten;
+
+ leave:
+  unlock_opnctx (wctx);
+  return result;
+}
+
+
+
+DWORD
+GPG_Seek (DWORD opnctx, long amount, WORD type)
+{
+  SetLastError (ERROR_SEEK_ON_DEVICE);
+  return -1; /* Error.  */
+}
+
+
+
+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)
+{
+  BOOL result = FALSE;
+  opnctx_t wctx = 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)
+    {
+      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)
+    {
+      SetLastError (ERROR_NOT_FOUND);
+      goto leave;
+    }
+  if (wctx == rctx)
+    {
+      SetLastError (ERROR_INVALID_TARGET_HANDLE);
+      goto leave;
+    }
+  if (wctx->hd == INVALID_HANDLE_VALUE)
+    {
+      SetLastError (ERROR_NOT_READY);
+      goto leave;
+    }
+  if (wctx->assoc)
+    {
+      SetLastError (ERROR_ALREADY_ASSIGNED);
+      goto leave;
+    }
+  if (!(wctx->access_code & GENERIC_WRITE))
+    {
+      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);
+  return result;
+}
+
+
+BOOL
+GPG_IOControl (DWORD opnctx_arg, DWORD code, void *inbuf, DWORD inbuflen,
+               void *outbuf, DWORD outbuflen, DWORD *actualoutlen)
+{
+  opnctx_t opnctx = (opnctx_t)opnctx_arg;
+  BOOL result = FALSE;
+
+  log_debug ("GPG_IOControl(%p, %d)\n", (void*)opnctx, code);
+  if (!validate_and_lock_opnctx (opnctx, LOCK_TRY))
+    return FALSE;
+
+  switch (code)
+    {
+    case GPGCEDEV_IOCTL_SET_HANDLE:
+      if (!opnctx || !inbuf || inbuflen < sizeof (HANDLE) 
+          || outbuf || outbuflen || actualoutlen )
+        {
+          SetLastError (ERROR_INVALID_PARAMETER);
+          goto leave;
+        }
+      if (set_handle (opnctx, *(HANDLE*)inbuf))
+        result = TRUE;
+      break;
+
+    case GPGCEDEV_IOCTL_MAKE_PIPE:
+      if (!opnctx || !inbuf || inbuflen < sizeof (HANDLE) 
+          || outbuf || outbuflen || actualoutlen )
+        {
+          SetLastError (ERROR_INVALID_PARAMETER);
+          goto leave;
+        }
+      if (make_pipe (opnctx, *(HANDLE*)inbuf))
+        result = TRUE;
+      break;
+
+    case IOCTL_PSL_NOTIFY:
+      /* Unexpected process termination.  */
+      break;
+
+    default:
+      SetLastError (ERROR_INVALID_PARAMETER);
+      break;
+    }
+
+ leave:
+  unlock_opnctx (opnctx);
+  return result;
+}
+
+
+
+void
+GPG_PowerUp (DWORD devctx)
+{
+}
+
+
+
+void
+GPG_PowerDown (DWORD devctx)
+{
+}
+
+
+
+
+/* Entry point called by the DLL loader.  */
+int WINAPI
+DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
+{
+  (void)reserved;
+
+  switch (reason)
+    {
+    case DLL_PROCESS_ATTACH:
+      InitializeCriticalSection (&opnctx_table_cs);
+      break;
+
+    case DLL_THREAD_ATTACH:
+      break;
+
+    case DLL_THREAD_DETACH:
+      break;
+
+    case DLL_PROCESS_DETACH:
+      DeleteCriticalSection (&opnctx_table_cs);
+      break;
+
+    default:
+      break;
+    }
+  
+  return TRUE;
+}
+

Added: trunk/src/gpgcedev.def
===================================================================
--- trunk/src/gpgcedev.def	                        (rev 0)
+++ trunk/src/gpgcedev.def	2010-02-24 15:50:55 UTC (rev 357)
@@ -0,0 +1,33 @@
+; gpgcedev.def - List of symbols to export for gpgcedev.
+; Copyright (C) 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/>.
+
+
+EXPORTS
+    GPG_Init
+    GPG_Deinit
+    GPG_Open
+    GPG_Close
+    GPG_Read
+    GPG_Write
+    GPG_Seek
+    GPG_IOControl
+    GPG_PowerUp
+    GPG_PowerDown
+
+; END
+

Added: trunk/src/gpgcemgr.c
===================================================================
--- trunk/src/gpgcemgr.c	                        (rev 0)
+++ trunk/src/gpgcemgr.c	2010-02-24 15:50:55 UTC (rev 357)
@@ -0,0 +1,72 @@
+/* gpgcempg.c - Manager fopr GPG CE devices
+   Copyright (C) 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/>.
+ */
+
+#define _WIN32_WCE 0x0500
+
+#include <stdio.h>
+#include <windows.h>
+
+#define PGM "gpgcemgr"
+
+#warning Fixme: Add support to create the device.
+
+int
+main (int argc, char **argv)
+{
+  int result = 0;
+  HANDLE shd;
+  DEVMGR_DEVICE_INFORMATION dinfo;
+
+  memset (&dinfo, 0, sizeof dinfo);
+  dinfo.dwSize = sizeof dinfo;
+  shd = FindFirstDevice (DeviceSearchByLegacyName, L"GPG1:", &dinfo);
+  if (shd == INVALID_HANDLE_VALUE)
+    {
+      if (GetLastError () == 18)
+        fprintf (stderr, PGM": device not found\n");
+      else
+        {
+          fprintf (stderr, PGM": FindFirstDevice failed: rc=%d\n", 
+                   (int)GetLastError ());
+          result = 1;
+        }
+    }
+  else
+    {
+      fprintf (stderr, PGM": ActivateDevice handle is %p\n", dinfo.hDevice);
+      if (dinfo.hDevice && dinfo.hDevice != INVALID_HANDLE_VALUE)
+        {
+          if (!DeactivateDevice (dinfo.hDevice))
+            {
+              fprintf (stderr, PGM": DeactivateDevice failed: rc=%d\n",
+                       (int)GetLastError ());
+              result = 1;
+            }
+          else
+            fprintf (stderr, PGM": DeactivateDevice succeeded\n");
+        }
+      FindClose (shd);
+    }
+  fflush (stdout);
+  fflush (stderr);
+  Sleep (1000);
+  return result;
+}
+
+

Modified: trunk/src/libassuan.def
===================================================================
--- trunk/src/libassuan.def	2010-02-03 17:00:09 UTC (rev 356)
+++ trunk/src/libassuan.def	2010-02-24 15:50:55 UTC (rev 357)
@@ -97,5 +97,8 @@
     assuan_client_read_response		@76
     assuan_client_parse_response	@77
     assuan_set_sock_nonce               @78
+    _assuan_w32ce_create_pipe           @79
+    assuan_free                         @80
+
 ; END
 

Modified: trunk/src/libassuan.vers
===================================================================
--- trunk/src/libassuan.vers	2010-02-03 17:00:09 UTC (rev 356)
+++ trunk/src/libassuan.vers	2010-02-24 15:50:55 UTC (rev 357)
@@ -97,6 +97,7 @@
     assuan_transact;
     assuan_write_line;
     assuan_write_status;
+    assuan_free;
 
     __assuan_close;
     __assuan_pipe;

Modified: trunk/src/system.c
===================================================================
--- trunk/src/system.c	2010-02-03 17:00:09 UTC (rev 356)
+++ trunk/src/system.c	2010-02-24 15:50:55 UTC (rev 357)
@@ -113,6 +113,16 @@
     ctx->malloc_hooks.free (ptr);
 }
 
+
+/* Release the memory at PTR using the allocation handler of the
+   context CTX.  This is a convenience function.  */
+void
+assuan_free (assuan_context_t ctx, void *ptr)
+{
+  _assuan_free (ctx, ptr);
+}
+
+
 
 /* Copy the system hooks struct, paying attention to version
    differences.  SRC is usually from the user, DST MUST be from the
@@ -203,19 +213,13 @@
   sec_attr.nLength = sizeof (sec_attr);
   sec_attr.bInheritHandle = FALSE;
 
-#ifdef HAVE_W32CE_SYSTEM
-# warning Implement a CreatePipe Replacement.  
-      gpg_err_set_errno (EIO);
-      return -1;
-#else
-  if (! CreatePipe (&rh, &wh, &sec_attr, 0))
+  if (!CreatePipe (&rh, &wh, &sec_attr, 0))
     {
       TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_pipe", ctx,
 	      "CreatePipe failed: %s", _assuan_w32_strerror (ctx, -1));
       gpg_err_set_errno (EIO);
       return -1;
     }
-#endif
 




More information about the Gnupg-commits mailing list