assuan/
authorMarcus Brinkmann <mb@g10code.com>
Wed, 8 Apr 2009 18:53:57 +0000 (18:53 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Wed, 8 Apr 2009 18:53:57 +0000 (18:53 +0000)
2009-04-08  Marcus Brinkmann  <marcus@g10code.de>

* assuan.h (_gpgme_io_socket): New prototype.
(_ASSUAN_CUSTOM_IO, _assuan_custom_close, _assuan_custom_read)
(_assuan_custom_write, _assuan_custom_pipe, _assuan_custom_socket)
(_assuan_custom_connect): New macros.
* assuan-socket.c (_assuan_close, _assuan_sock_new)
(_assuan_sock_connect) [_ASSUAN_CUSTOM_IO]: Use custom I/O function.
* assuan-buffer.c (assuan_read_line): Do not handle EAGAIN anymore.
* assuan-client.c (_assuan_read_from_server): Likewise.
* assuan-handler.c (process_next): Likewise
* assuan-inquire.c (assuan_inquire): Likewise.

src/
2009-04-08  Marcus Brinkmann  <marcus@g10code.de>

* w32-glib-io.c (giochannel_table): New members used, fd, socket.
(find_channel): Drop CREATE argument.
(new_dummy_channel_from_fd, new_channel_from_fd)
(new_channel_from_socket): New functions.
(_gpgm_io_fd2str): Implement for sockets.
(_gpgme_io_write, _gpgme_io_read): Translate EAGAIN errors
correctly.
(_gpgme_io_pipe): Fix for new channel bookkeeping.
(_gpgme_io_close, _gpgme_io_dup): Likewise.
(wsa2errno, _gpgme_io_socket, _gpgme_io_connect): New.
* w32-io.c (MAX_READERS, MAX_WRITERS): Bump up to 40.
(wsa2errno, _gpgme_io_socket, _gpgme_io_connect): New.
* w32-qt-io.cpp (_gpgme_io_socket, _gpgme_io_connect): New stubs.
* version.c [HAVE_W32_SYSTEM]: Include "windows.h.
(do_subsystem_inits) [HAVE_W32_SYSTEM]: Call WSAStartup.
* engine-assuan.c (llass_status_handler): Ignore EAGAIN errors.

14 files changed:
TODO
assuan/ChangeLog
assuan/assuan-buffer.c
assuan/assuan-client.c
assuan/assuan-handler.c
assuan/assuan-inquire.c
assuan/assuan-socket.c
assuan/assuan.h
src/ChangeLog
src/engine-assuan.c
src/version.c
src/w32-glib-io.c
src/w32-io.c
src/w32-qt-io.cpp

diff --git a/TODO b/TODO
index 6cff25d..9aeeb26 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,5 +1,12 @@
 Hey Emacs, this is -*- outline -*- mode!
 
+* IMPORTANT
+** When using descriptor passing, we need to set the fd to blocking before
+   issueing simple commands, because we are mixing synchronous
+   commands into potentially asynchronous operations.
+** Might want to implement nonblock for w32 native backend!  Right now,
+   we block reading the next line with assuan.
+
 * Before release:
 ** Figure out if _gpgme_io_pipe should pre-create reader/writer and if we
    then can use !start_it in most invocations.  Note that gpgme_io_dup
index 18e14ed..8dd2ebb 100644 (file)
@@ -1,3 +1,16 @@
+2009-04-08  Marcus Brinkmann  <marcus@g10code.de>
+
+       * assuan.h (_gpgme_io_socket): New prototype.
+       (_ASSUAN_CUSTOM_IO, _assuan_custom_close, _assuan_custom_read)
+       (_assuan_custom_write, _assuan_custom_pipe, _assuan_custom_socket)
+       (_assuan_custom_connect): New macros.
+       * assuan-socket.c (_assuan_close, _assuan_sock_new)
+       (_assuan_sock_connect) [_ASSUAN_CUSTOM_IO]: Use custom I/O function.
+       * assuan-buffer.c (assuan_read_line): Do not handle EAGAIN anymore.
+       * assuan-client.c (_assuan_read_from_server): Likewise.
+       * assuan-handler.c (process_next): Likewise
+       * assuan-inquire.c (assuan_inquire): Likewise.
+
 2009-03-23  Marcus Brinkmann  <marcus@g10code.de>
 
        * assuan.h: Add prefix macros for _assuan_close and _assuan_usleep.
index b9e3572..e825d9f 100644 (file)
@@ -245,11 +245,7 @@ assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen)
   if (!ctx)
     return _assuan_error (ASSUAN_Invalid_Value);
 
-  do
-    {
-      err = _assuan_read_line (ctx);
-    }
-  while (_assuan_error_is_eagain (err));
+  err = _assuan_read_line (ctx);
 
   *line = ctx->inbound.line;
   *linelen = ctx->inbound.linelen;
index 15f4f1c..e123e76 100644 (file)
@@ -42,16 +42,12 @@ _assuan_read_from_server (assuan_context_t ctx, int *okay, int *off)
   *off = 0;
   do 
     {
-      do
-       {
-         rc = _assuan_read_line (ctx);
-       }
-      while (_assuan_error_is_eagain (rc));
+      rc = _assuan_read_line (ctx);
       if (rc)
         return rc;
       line = ctx->inbound.line;
       linelen = ctx->inbound.linelen;
-    }    
+    }
   while (*line == '#' || !linelen);
 
   if (linelen >= 1
index b940bfd..f504abe 100644 (file)
@@ -630,8 +630,6 @@ process_next (assuan_context_t ctx)
      required to write full lines without blocking long after starting
      a partial line.  */
   rc = _assuan_read_line (ctx);
-  if (_assuan_error_is_eagain (rc))
-    return 0;
   if (rc)
     return rc;
   if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
index 58b9f02..ab710a1 100644 (file)
@@ -169,9 +169,7 @@ assuan_inquire (assuan_context_t ctx, const char *keyword,
     {
       do 
         {
-         do
-           rc = _assuan_read_line (ctx);
-         while (_assuan_error_is_eagain (rc));
+         rc = _assuan_read_line (ctx);
           if (rc)
             goto leave;
           line = (unsigned char *) ctx->inbound.line;
index 02a6225..74e8eb2 100644 (file)
@@ -145,7 +145,10 @@ read_port_and_nonce (const char *fname, unsigned short *port, char *nonce)
 int
 _assuan_close (assuan_fd_t fd)
 {
-#if defined (HAVE_W32_SYSTEM) && !defined(_ASSUAN_IN_GPGME_BUILD_ASSUAN)
+#ifdef _ASSUAN_CUSTOM_IO
+  return _assuan_custom_close (fd);
+#else
+#ifdef (HAVE_W32_SYSTEM)
   int rc = closesocket (HANDLE2SOCKET(fd));
   if (rc)
     errno = _assuan_sock_wsa2errno (WSAGetLastError ());
@@ -160,6 +163,7 @@ _assuan_close (assuan_fd_t fd)
 #else
   return close (fd);
 #endif
+#endif
 }
 
 
@@ -173,13 +177,25 @@ _assuan_sock_new (int domain, int type, int proto)
   assuan_fd_t res;
   if (domain == AF_UNIX || domain == AF_LOCAL)
     domain = AF_INET;
+
+#ifdef _ASSUAN_CUSTOM_IO
+  return _assuan_custom_socket (domain, type, proto);
+#else
   res = SOCKET2HANDLE(socket (domain, type, proto));
   if (res == ASSUAN_INVALID_FD)
     errno = _assuan_sock_wsa2errno (WSAGetLastError ());
   return res;
+#endif
+
+#else
+
+#ifdef _ASSUAN_CUSTOM_IO
+  return _gpgme_io_socket (domain, type, proto);
 #else
   return socket (domain, type, proto);
 #endif
+
+#endif
 }
 
 
@@ -208,11 +224,18 @@ _assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
       unaddr->sun_port = myaddr.sin_port;
       unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr;
   
+#ifdef _ASSUAN_CUSTOM_IO
+      ret = _assuan_custom_connect (sockfd,
+                                   (struct sockaddr *)&myaddr, sizeof myaddr);
+#else
       ret = connect (HANDLE2SOCKET(sockfd), 
                      (struct sockaddr *)&myaddr, sizeof myaddr);
+#endif
+
       if (!ret)
         {
           /* Send the nonce. */
+
           ret = _assuan_io_write (sockfd, nonce, 16);
           if (ret >= 0 && ret != 16)
             {
@@ -220,6 +243,8 @@ _assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
               ret = -1;
             }
         }
+      else
+        errno = _assuan_sock_wsa2errno (WSAGetLastError ());
       return ret;
     }
   else
@@ -231,8 +256,14 @@ _assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
       return res;
     }      
 #else
+
+#ifdef _ASSUAN_CUSTOM_IO
+  return _assuan_custom_connect (sockfd, addr, addrlen);
+#else
   return connect (sockfd, addr, addrlen);
 #endif
+
+#endif
 }
 
 
index 4cf6a03..971ff4d 100644 (file)
@@ -77,6 +77,7 @@ int _gpgme_io_read (int fd, void *buffer, size_t count);
 int _gpgme_io_write (int fd, const void *buffer, size_t count);
 int _gpgme_io_sendmsg (int sock, const struct msghdr *msg, int flags);
 int _gpgme_io_recvmsg (int sock, struct msghdr *msg, int flags);
+int _gpgme_io_socket (int domain, int type, int proto);
 
 #define _assuan_funopen _gpgme_funopen
 
@@ -90,6 +91,15 @@ int _gpgme_io_recvmsg (int sock, struct msghdr *msg, int flags);
 #define sendmsg              _gpgme_io_sendmsg
 #define recvmsg       _gpgme_io_recvmsg
 #endif /*_ASSUAN_IN_GPGME_BUILD_ASSUAN*/
+
+#define _ASSUAN_CUSTOM_IO 1
+#define _assuan_custom_close _gpgme_io_close
+#define _assuan_custom_read _gpgme_io_read
+#define _assuan_custom_write _gpgme_io_write
+#define _assuan_custom_pipe _gpgme_io_pipe
+#define _assuan_custom_socket _gpgme_io_socket
+#define _assuan_custom_connect _gpgme_io_connect
+
 /**** End GPGME specific modifications. ******/
 
 
index 307543a..3a570f5 100644 (file)
@@ -1,3 +1,22 @@
+2009-04-08  Marcus Brinkmann  <marcus@g10code.de>
+
+       * w32-glib-io.c (giochannel_table): New members used, fd, socket.
+       (find_channel): Drop CREATE argument.
+       (new_dummy_channel_from_fd, new_channel_from_fd)
+       (new_channel_from_socket): New functions.
+       (_gpgm_io_fd2str): Implement for sockets.
+       (_gpgme_io_write, _gpgme_io_read): Translate EAGAIN errors
+       correctly.
+       (_gpgme_io_pipe): Fix for new channel bookkeeping.
+       (_gpgme_io_close, _gpgme_io_dup): Likewise.
+       (wsa2errno, _gpgme_io_socket, _gpgme_io_connect): New.
+       * w32-io.c (MAX_READERS, MAX_WRITERS): Bump up to 40.
+       (wsa2errno, _gpgme_io_socket, _gpgme_io_connect): New.
+       * w32-qt-io.cpp (_gpgme_io_socket, _gpgme_io_connect): New stubs.
+       * version.c [HAVE_W32_SYSTEM]: Include "windows.h.
+       (do_subsystem_inits) [HAVE_W32_SYSTEM]: Call WSAStartup.
+       * engine-assuan.c (llass_status_handler): Ignore EAGAIN errors.
+
 2009-03-18  Werner Koch  <wk@g10code.com>
 
        * gpgme.h.in (GPGME_KEYLIST_MODE_EPHEMERAL): New.
index bfe7a03..12de042 100644 (file)
@@ -415,7 +415,18 @@ llass_status_handler (void *opaque, int fd)
       err = assuan_read_line (llass->assuan_ctx, &line, &linelen);
       if (err)
        {
-          TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
+         /* Reading a full line may not be possible when
+            communicating over a socket in nonblocking mode.  In this
+            case, we are done for now.  */
+         if (gpg_err_code (err) == GPG_ERR_EAGAIN)
+           {
+             TRACE1 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
+                     "fd 0x%x: EAGAIN reading assuan line (ignored)", fd);
+             err = 0;
+             continue;
+           }
+         
+         TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
                  "fd 0x%x: error reading assuan line: %s",
                   fd, gpg_strerror (err));
        }
index 03d9e9a..c6fb52b 100644 (file)
 #include "assuan.h"
 #endif
 
+#ifdef HAVE_W32_SYSTEM
+#include "windows.h"
+#endif
+
 \f
 /* Bootstrap the subsystems needed for concurrent operation.  This
    must be done once at startup.  We can not guarantee this using a
@@ -54,6 +58,14 @@ do_subsystem_inits (void)
   if (done)
     return;
 
+#ifdef HAVE_W32_SYSTEM
+      {
+        WSADATA wsadat;
+        
+        WSAStartup (0x202, &wsadat);
+      }
+#endif
+
   _gpgme_sema_subsystem_init ();
 #ifdef HAVE_ASSUAN_H
   assuan_set_assuan_err_source (GPG_ERR_SOURCE_GPGME);
index c646edc..5f8c886 100644 (file)
 
 static struct 
 {
+  int used;
+
+  /* If this is not -1, then it's a libc file descriptor.  */
+  int fd;
+  /* If fd is -1, this is the Windows socket handle.  */
+  int socket;
+
   GIOChannel *chan;
   /* The boolean PRIMARY is true if this file descriptor caused the
      allocation of CHAN.  Only then should CHAN be destroyed when this
@@ -102,20 +109,96 @@ static struct
 
 
 static GIOChannel *
-find_channel (int fd, int create)
+find_channel (int fd)
 {
   if (fd < 0 || fd >= MAX_SLAFD)
     return NULL;
 
-  if (create && !giochannel_table[fd].chan)
+  return giochannel_table[fd].chan;
+}
+
+
+/* Returns the FD or -1 on resource limit.  */
+int
+new_dummy_channel_from_fd (int cfd)
+{
+  int idx;
+
+  for (idx = 0; idx < MAX_SLAFD; idx++)
+    if (! giochannel_table[idx].used)
+      break;
+
+  if (idx == MAX_SLAFD)
     {
-      giochannel_table[fd].chan = g_io_channel_win32_new_fd (fd);
-      giochannel_table[fd].primary = 1;
-      g_io_channel_set_encoding (giochannel_table[fd].chan, NULL, NULL);
-      g_io_channel_set_buffered (giochannel_table[fd].chan, FALSE);
+      errno = EIO;
+      return -1;
     }
 
-  return giochannel_table[fd].chan;
+  giochannel_table[idx].used = 1;
+  giochannel_table[idx].chan = NULL;
+  giochannel_table[idx].fd = cfd;
+  giochannel_table[idx].socket = INVALID_SOCKET;
+  giochannel_table[idx].primary = 1;
+
+  return idx;
+}
+
+
+/* Returns the FD or -1 on resource limit.  */
+int
+new_channel_from_fd (int cfd)
+{
+  int idx;
+
+  for (idx = 0; idx < MAX_SLAFD; idx++)
+    if (! giochannel_table[idx].used)
+      break;
+
+  if (idx == MAX_SLAFD)
+    {
+      errno = EIO;
+      return -1;
+    }
+
+  giochannel_table[idx].used = 1;
+  giochannel_table[idx].chan = g_io_channel_win32_new_fd (cfd);
+  giochannel_table[idx].fd = cfd;
+  giochannel_table[idx].socket = INVALID_SOCKET;
+  giochannel_table[idx].primary = 1;
+
+  g_io_channel_set_encoding (giochannel_table[idx].chan, NULL, NULL);
+  g_io_channel_set_buffered (giochannel_table[idx].chan, FALSE);
+
+  return idx;
+}
+
+
+/* Returns the FD or -1 on resource limit.  */
+int
+new_channel_from_socket (int sock)
+{
+  int idx;
+
+  for (idx = 0; idx < MAX_SLAFD; idx++)
+    if (! giochannel_table[idx].used)
+      break;
+
+  if (idx == MAX_SLAFD)
+    {
+      errno = EIO;
+      return -1;
+    }
+
+  giochannel_table[idx].used = 1;
+  giochannel_table[idx].chan = g_io_channel_win32_new_socket (sock);
+  giochannel_table[idx].fd = -1;
+  giochannel_table[idx].socket = sock;
+  giochannel_table[idx].primary = 1;
+
+  g_io_channel_set_encoding (giochannel_table[idx].chan, NULL, NULL);
+  g_io_channel_set_buffered (giochannel_table[idx].chan, FALSE);
+
+  return idx;
 }
 
 
@@ -123,7 +206,7 @@ find_channel (int fd, int create)
 void *
 gpgme_get_giochannel (int fd)
 {
-  return find_channel (fd, 0);
+  return find_channel (fd);
 }
 
 
@@ -131,7 +214,7 @@ gpgme_get_giochannel (int fd)
 void *
 gpgme_get_fdptr (int fd)
 {
-  return find_channel (fd, 0);
+  return find_channel (fd);
 }
 
 
@@ -141,9 +224,17 @@ gpgme_get_fdptr (int fd)
 int
 _gpgme_io_fd2str (char *buf, int buflen, int fd)
 {
+  HANDLE hndl;
+    
   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_fd2str", fd, "fd=%d", fd);
-  TRACE_SUC1 ("syshd=%p", _get_osfhandle (fd));
-  return snprintf (buf, buflen, "%d", (int) _get_osfhandle (fd));
+  if (giochannel_table[fd].fd != -1)
+    hndl = (HANDLE) _get_osfhandle (giochannel_table[fd].fd);
+  else
+    hndl = (HANDLE) giochannel_table[fd].socket;
+
+  TRACE_SUC1 ("syshd=%p", hndl);
+  
+  return snprintf (buf, buflen, "%d", (int) hndl);
 }
 
 \f
@@ -170,7 +261,7 @@ _gpgme_io_read (int fd, void *buffer, size_t count)
   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
              "buffer=%p, count=%u", buffer, count);
 
-  chan = find_channel (fd, 0);
+  chan = find_channel (fd);
   if (!chan)
     {
       TRACE_LOG ("no channel registered");
@@ -192,14 +283,20 @@ _gpgme_io_read (int fd, void *buffer, size_t count)
 
   if (status == G_IO_STATUS_EOF)
     nread = 0;
+  else if (status == G_IO_STATUS_AGAIN)
+    {
+      nread = -1;
+      saved_errno = EAGAIN;
+    }
   else if (status != G_IO_STATUS_NORMAL)
     {
       TRACE_LOG1 ("status %d", status);
       nread = -1;
       saved_errno = EIO;
     }
-
-  TRACE_LOGBUF (buffer, nread);
+  
+  if (nread != 0 && nread != -1)
+    TRACE_LOGBUF (buffer, nread);
 
   errno = saved_errno;
   return TRACE_SYSRES (nread);
@@ -213,11 +310,13 @@ _gpgme_io_write (int fd, const void *buffer, size_t count)
   gsize nwritten;
   GIOChannel *chan;
   GIOStatus status;
+  GError *err = NULL;
+
   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
              "buffer=%p, count=%u", buffer, count);
   TRACE_LOGBUF (buffer, count);
 
-  chan = find_channel (fd, 0);
+  chan = find_channel (fd);
   if (!chan)
     {
       TRACE_LOG ("fd %d: no channel registered");
@@ -226,8 +325,19 @@ _gpgme_io_write (int fd, const void *buffer, size_t count)
     }
 
   status = g_io_channel_write_chars (chan, (gchar *) buffer, count,
-                                    &nwritten, NULL);
-  if (status != G_IO_STATUS_NORMAL)
+                                    &nwritten, &err);
+  if (err)
+    {
+      TRACE_LOG1 ("write error: %s", err->message);
+      g_error_free (err);
+    }
+
+  if (status == G_IO_STATUS_AGAIN)
+    {
+      nwritten = -1;
+      saved_errno = EAGAIN;
+    }
+  else if (status != G_IO_STATUS_NORMAL)
     {
       nwritten = -1;
       saved_errno = EIO;
@@ -241,13 +351,14 @@ _gpgme_io_write (int fd, const void *buffer, size_t count)
 int
 _gpgme_io_pipe (int filedes[2], int inherit_idx)
 {
-  GIOChannel *chan;
+  int fds[2];
+
   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
              "inherit_idx=%i (GPGME uses it for %s)",
              inherit_idx, inherit_idx ? "reading" : "writing");
 
 #define PIPEBUF_SIZE  4096
-  if (_pipe (filedes, PIPEBUF_SIZE, O_NOINHERIT | O_BINARY) == -1)
+  if (_pipe (fds, PIPEBUF_SIZE, O_NOINHERIT | O_BINARY) == -1)
     return TRACE_SYSRES (-1);
 
   /* Make one end inheritable. */
@@ -255,13 +366,13 @@ _gpgme_io_pipe (int filedes[2], int inherit_idx)
     {
       int new_read;
 
-      new_read = _dup (filedes[0]);
-      _close (filedes[0]);
-      filedes[0] = new_read;
+      new_read = _dup (fds[0]);
+      _close (fds[0]);
+      fds[0] = new_read;
 
       if (new_read < 0)
        {
-         _close (filedes[1]);
+         _close (fds[1]);
          return TRACE_SYSRES (-1);
        }
     }
@@ -269,33 +380,48 @@ _gpgme_io_pipe (int filedes[2], int inherit_idx)
     {
       int new_write;
 
-      new_write = _dup (filedes[1]);
-      _close (filedes[1]);
-      filedes[1] = new_write;
+      new_write = _dup (fds[1]);
+      _close (fds[1]);
+      fds[1] = new_write;
 
       if (new_write < 0)
        {
-         _close (filedes[0]);
+         _close (fds[0]);
          return TRACE_SYSRES (-1);
        }
     }
 
-  /* Now we have a pipe with the right end inheritable.  The other end
-     should have a giochannel.  */
-  chan = find_channel (filedes[1 - inherit_idx], 1);
-  if (!chan)
+  /* For _gpgme_io_close.  */
+  filedes[inherit_idx] = new_dummy_channel_from_fd (fds[inherit_idx]);
+  if (filedes[inherit_idx] < 0)
     {
       int saved_errno = errno;
-      _close (filedes[0]);
-      _close (filedes[1]);
+      
+      _close (fds[0]);
+      _close (fds[1]);
       errno = saved_errno;
       return TRACE_SYSRES (-1);
     }
 
+  /* Now we have a pipe with the correct end inheritable.  The other end
+     should have a giochannel.  */
+  filedes[1 - inherit_idx] = new_channel_from_fd (fds[1 - inherit_idx]);
+  if (filedes[1 - inherit_idx] < 0)
+    {
+      int saved_errno = errno;
+      
+      _gpgme_io_close (fds[inherit_idx]);
+      _close (fds[1 - inherit_idx]);
+      errno = saved_errno;
+      return TRACE_SYSRES (-1);
+    }
+  
   return TRACE_SUC5 ("read=0x%x/%p, write=0x%x/%p, channel=%p",
-         filedes[0], (HANDLE) _get_osfhandle (filedes[0]),
-         filedes[1], (HANDLE) _get_osfhandle (filedes[1]),
-         chan);
+                    filedes[0],
+                    (HANDLE) _get_osfhandle (giochannel_table[filedes[0]].fd),
+                    filedes[1],
+                    (HANDLE) _get_osfhandle (giochannel_table[filedes[1]].fd),
+                    giochannel_table[1 - inherit_idx].chan);
 }
 
 
@@ -310,6 +436,8 @@ _gpgme_io_close (int fd)
       return TRACE_SYSRES (-1);
     }
 
+  assert (giochannel_table[fd].used);
+
   /* First call the notify handler.  */
   if (notify_table[fd].handler)
     {
@@ -318,19 +446,26 @@ _gpgme_io_close (int fd)
       notify_table[fd].value = NULL;
     }
 
-  /* Then do the close.  */    
+  /* Then do the close.  */
   if (giochannel_table[fd].chan)
     {
       if (giochannel_table[fd].primary)
        g_io_channel_shutdown (giochannel_table[fd].chan, 1, NULL);
-      else
-       _close (fd);
-
+      
       g_io_channel_unref (giochannel_table[fd].chan);
-      giochannel_table[fd].chan = NULL;
     }
   else
-    _close (fd);
+    {
+      /* Dummy entry, just close.  */
+      assert (giochannel_table[fd].fd != -1);
+      _close (giochannel_table[fd].fd);
+    }
+       
+  giochannel_table[fd].used = 0;
+  giochannel_table[fd].fd = -1;
+  giochannel_table[fd].socket = INVALID_SOCKET;
+  giochannel_table[fd].chan = NULL;
+  giochannel_table[fd].primary = 0;
 
   TRACE_SUC ();
   return 0;
@@ -365,16 +500,17 @@ _gpgme_io_set_nonblocking (int fd)
  
   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
 
-  chan = find_channel (fd, 0);
+  chan = find_channel (fd);
   if (!chan)
     {
       errno = EIO;
       return TRACE_SYSRES (-1);
     }
 
-   status = g_io_channel_set_flags (chan,
+  status = g_io_channel_set_flags (chan,
                                   g_io_channel_get_flags (chan) |
                                   G_IO_FLAG_NONBLOCK, NULL);
+
   if (status != G_IO_STATUS_NORMAL)
     {
 #if 0
@@ -549,7 +685,8 @@ _gpgme_io_spawn (const char *path, char * const argv[],
       HANDLE hd;
 
       /* Make it inheritable for the wrapper process.  */
-      if (!DuplicateHandle (GetCurrentProcess(), _get_osfhandle (fd_list[i].fd),
+      if (!DuplicateHandle (GetCurrentProcess(),
+                           _get_osfhandle (giochannel_table[fd_list[i].fd].fd),
                            pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
        {
          TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
@@ -694,7 +831,7 @@ _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
        continue;
 
       if ((fds[i].for_read || fds[i].for_write)
-          && !(chan = find_channel (fds[i].fd, 0)))
+          && !(chan = find_channel (fds[i].fd)))
         {
           TRACE_ADD1 (dbg_help, "[BAD0x%x ", fds[i].fd);
           TRACE_END (dbg_help, "]"); 
@@ -786,27 +923,147 @@ _gpgme_io_dup (int fd)
 {
   int newfd;
   GIOChannel *chan;
-  
-  TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_dup", fd, "dup (%d)", fd);
 
-  newfd = _dup (fd);
-  if (newfd == -1)
-    return TRACE_SYSRES (-1);
-  if (newfd < 0 || newfd >= MAX_SLAFD)
+  TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd);
+
+  if (fd < 0 || fd >= MAX_SLAFD || !giochannel_table[fd].used)
     {
-      /* New FD won't fit into our table.  */
-      _close (newfd);
-      errno = EIO; 
+      errno = EINVAL;
       return TRACE_SYSRES (-1);
     }
-  assert (giochannel_table[newfd].chan == NULL);
-
-  chan = find_channel (fd, 0);
-  assert (chan);
 
+  for (newfd = 0; newfd < MAX_SLAFD; newfd++)
+    if (! giochannel_table[newfd].used)
+      break;
+  if (newfd == MAX_SLAFD)
+    {
+      errno = EIO;
+      return TRACE_SYSRES (-1);
+    }
+  
+  chan = giochannel_table[fd].chan;
   g_io_channel_ref (chan);
+  giochannel_table[newfd].used = 1;
   giochannel_table[newfd].chan = chan;
+  giochannel_table[newfd].fd = -1;
+  giochannel_table[newfd].socket = INVALID_SOCKET;
   giochannel_table[newfd].primary = 0;
 
   return TRACE_SYSRES (newfd);
 }
+
+\f
+
+
+\f
+static int
+wsa2errno (int err)
+{
+  switch (err)
+    {
+    case WSAENOTSOCK:
+      return EINVAL;
+    case WSAEWOULDBLOCK:
+      return EAGAIN;
+    case ERROR_BROKEN_PIPE:
+      return EPIPE;
+    case WSANOTINITIALISED:
+      return ENOSYS;
+    default:
+      return EIO;
+    }
+}
+
+
+int
+_gpgme_io_socket (int domain, int type, int proto)
+{
+  int res;
+  int fd;
+
+  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
+             "type=%i, protp=%i", type, proto);
+
+  res = socket (domain, type, proto);
+  if (res == INVALID_SOCKET)
+    {
+      errno = wsa2errno (WSAGetLastError ());
+      return TRACE_SYSRES (-1);
+    }
+
+  fd = new_channel_from_socket (res);
+  if (fd < 0)
+    {
+      int saved_errno = errno;
+      closesocket (res);
+      errno = saved_errno;
+      return TRACE_SYSRES (-1);
+    }
+
+  TRACE_SUC2 ("fd=%i, socket=0x%x", fd, res);
+  
+  return fd;
+}
+
+
+int
+_gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
+{
+  GIOChannel *chan; 
+  int sockfd;
+  int res;
+  GIOFlags flags;
+  GIOStatus status;
+  GError *err = NULL;
+
+  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
+             "addr=%p, addrlen=%i", addr, addrlen);
+
+  chan = find_channel (fd);
+  if (! chan)
+    {
+      errno = EINVAL;
+      return TRACE_SYSRES (-1);
+    }
+
+  flags = g_io_channel_get_flags (chan);
+  if (flags & G_IO_FLAG_NONBLOCK)
+    {
+      status = g_io_channel_set_flags (chan, flags & ~G_IO_FLAG_NONBLOCK, &err);
+      if (err)
+       {
+         TRACE_LOG1 ("setting flags error: %s", err->message);
+         g_error_free (err);
+         err = NULL;
+       }
+      if (status != G_IO_STATUS_NORMAL)
+       {
+         errno = EIO;
+         return TRACE_SYSRES (-1);
+       }
+    }
+
+  sockfd = giochannel_table[fd].socket;
+  if (sockfd == INVALID_SOCKET)
+    {
+      errno = EINVAL;
+      return TRACE_SYSRES (-1);
+    }
+
+  TRACE_LOG1 ("connect sockfd=0x%x", sockfd);
+  res = connect (sockfd, addr, addrlen);
+
+  /* FIXME: Error ignored here.  */
+  if (! (flags & G_IO_FLAG_NONBLOCK))
+    g_io_channel_set_flags (chan, flags, NULL);
+
+  if (res)
+    {
+      TRACE_LOG2 ("connect failed: %i %i", res, WSAGetLastError ());
+
+      errno = wsa2errno (WSAGetLastError ());
+      return TRACE_SYSRES (-1);
+    }
+
+  return TRACE_SUC ();
+}
index 1f62a6f..1a65e53 100644 (file)
@@ -53,8 +53,8 @@
 #define READBUF_SIZE 4096
 #define WRITEBUF_SIZE 4096
 #define PIPEBUF_SIZE  4096
-#define MAX_READERS 20
-#define MAX_WRITERS 20
+#define MAX_READERS 40
+#define MAX_WRITERS 40
 
 static struct
 {
@@ -1469,3 +1469,63 @@ gpgme_get_fdptr (int fd)
 {
   return NULL;
 }
+
+\f
+static int
+wsa2errno (int err)
+{
+  switch (err)
+    {
+    case WSAENOTSOCK:
+      return EINVAL;
+    case WSAEWOULDBLOCK:
+      return EAGAIN;
+    case ERROR_BROKEN_PIPE:
+      return EPIPE;
+    case WSANOTINITIALISED:
+      return ENOSYS;
+    default:
+      return EIO;
+    }
+}
+
+
+int
+_gpgme_io_socket (int domain, int type, int proto)
+{
+  int res;
+
+  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
+             "type=%i, protp=%i", type, proto);
+
+  res = socket (domain, type, proto);
+  if (res == INVALID_SOCKET)
+    {
+      errno = wsa2errno (WSAGetLastError ());
+      return TRACE_SYSRES (-1);
+    }
+
+  TRACE_SUC1 ("socket=0x%x", res);
+  
+  return res;
+}
+
+
+int
+_gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
+{
+  int sockfd;
+  int res;
+
+  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
+             "addr=%p, addrlen=%i", addr, addrlen);
+
+  res = connect (sockfd, addr, addrlen);
+  if (!res)
+    {
+      errno = wsa2errno (WSAGetLastError ());
+      return TRACE_SYSRES (-1);
+    }
+
+  return TRACE_SUC ();
+}
index 681493f..08f780f 100644 (file)
@@ -674,3 +674,20 @@ _gpgme_io_dup (int fd)
     return fd;
 }
 
+\f
+extern "C"
+int
+_gpgme_io_socket (int domain, int type, int proto)
+{
+  errno = EIO;
+  return -1;
+}
+
+
+extern "C"
+int
+_gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
+{
+  errno = EIO;
+  return -1;
+}