From d255b4bec9a1fdf0864640750161ea12999e43a5 Mon Sep 17 00:00:00 2001 From: Marcus Brinkmann Date: Wed, 8 Apr 2009 18:53:57 +0000 Subject: [PATCH] assuan/ 2009-04-08 Marcus Brinkmann * 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 * 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. --- TODO | 7 + assuan/ChangeLog | 13 ++ assuan/assuan-buffer.c | 6 +- assuan/assuan-client.c | 8 +- assuan/assuan-handler.c | 2 - assuan/assuan-inquire.c | 4 +- assuan/assuan-socket.c | 33 +++- assuan/assuan.h | 10 ++ src/ChangeLog | 19 ++ src/engine-assuan.c | 13 +- src/version.c | 12 ++ src/w32-glib-io.c | 375 +++++++++++++++++++++++++++++++++------- src/w32-io.c | 64 ++++++- src/w32-qt-io.cpp | 17 ++ 14 files changed, 504 insertions(+), 79 deletions(-) diff --git a/TODO b/TODO index 6cff25dd..9aeeb26a 100644 --- 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 diff --git a/assuan/ChangeLog b/assuan/ChangeLog index 18e14ed8..8dd2ebbd 100644 --- a/assuan/ChangeLog +++ b/assuan/ChangeLog @@ -1,3 +1,16 @@ +2009-04-08 Marcus Brinkmann + + * 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 * assuan.h: Add prefix macros for _assuan_close and _assuan_usleep. diff --git a/assuan/assuan-buffer.c b/assuan/assuan-buffer.c index b9e35721..e825d9ff 100644 --- a/assuan/assuan-buffer.c +++ b/assuan/assuan-buffer.c @@ -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; diff --git a/assuan/assuan-client.c b/assuan/assuan-client.c index 15f4f1cd..e123e764 100644 --- a/assuan/assuan-client.c +++ b/assuan/assuan-client.c @@ -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 diff --git a/assuan/assuan-handler.c b/assuan/assuan-handler.c index b940bfd4..f504abef 100644 --- a/assuan/assuan-handler.c +++ b/assuan/assuan-handler.c @@ -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) diff --git a/assuan/assuan-inquire.c b/assuan/assuan-inquire.c index 58b9f029..ab710a12 100644 --- a/assuan/assuan-inquire.c +++ b/assuan/assuan-inquire.c @@ -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; diff --git a/assuan/assuan-socket.c b/assuan/assuan-socket.c index 02a62253..74e8eb29 100644 --- a/assuan/assuan-socket.c +++ b/assuan/assuan-socket.c @@ -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 } diff --git a/assuan/assuan.h b/assuan/assuan.h index 4cf6a034..971ff4d9 100644 --- a/assuan/assuan.h +++ b/assuan/assuan.h @@ -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. ******/ diff --git a/src/ChangeLog b/src/ChangeLog index 307543a1..3a570f5a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,22 @@ +2009-04-08 Marcus Brinkmann + + * 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 * gpgme.h.in (GPGME_KEYLIST_MODE_EPHEMERAL): New. diff --git a/src/engine-assuan.c b/src/engine-assuan.c index bfe7a037..12de042f 100644 --- a/src/engine-assuan.c +++ b/src/engine-assuan.c @@ -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)); } diff --git a/src/version.c b/src/version.c index 03d9e9ae..c6fb52b9 100644 --- a/src/version.c +++ b/src/version.c @@ -40,6 +40,10 @@ #include "assuan.h" #endif +#ifdef HAVE_W32_SYSTEM +#include "windows.h" +#endif + /* 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); diff --git a/src/w32-glib-io.c b/src/w32-glib-io.c index c646edcf..5f8c8867 100644 --- a/src/w32-glib-io.c +++ b/src/w32-glib-io.c @@ -80,6 +80,13 @@ 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); } @@ -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); } + + + + + +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 (); +} diff --git a/src/w32-io.c b/src/w32-io.c index 1f62a6f1..1a65e537 100644 --- a/src/w32-io.c +++ b/src/w32-io.c @@ -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; } + + +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 (); +} diff --git a/src/w32-qt-io.cpp b/src/w32-qt-io.cpp index 681493ff..08f780f1 100644 --- a/src/w32-qt-io.cpp +++ b/src/w32-qt-io.cpp @@ -674,3 +674,20 @@ _gpgme_io_dup (int fd) return fd; } + +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; +}