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.
This commit is contained in:
Marcus Brinkmann 2009-04-08 18:53:57 +00:00
parent 6f8aa0e29d
commit d255b4bec9
14 changed files with 504 additions and 79 deletions

7
TODO
View File

@ -1,5 +1,12 @@
Hey Emacs, this is -*- outline -*- mode! 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: * Before release:
** Figure out if _gpgme_io_pipe should pre-create reader/writer and if we ** 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 then can use !start_it in most invocations. Note that gpgme_io_dup

View 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> 2009-03-23 Marcus Brinkmann <marcus@g10code.de>
* assuan.h: Add prefix macros for _assuan_close and _assuan_usleep. * assuan.h: Add prefix macros for _assuan_close and _assuan_usleep.

View File

@ -245,11 +245,7 @@ assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen)
if (!ctx) if (!ctx)
return _assuan_error (ASSUAN_Invalid_Value); return _assuan_error (ASSUAN_Invalid_Value);
do
{
err = _assuan_read_line (ctx); err = _assuan_read_line (ctx);
}
while (_assuan_error_is_eagain (err));
*line = ctx->inbound.line; *line = ctx->inbound.line;
*linelen = ctx->inbound.linelen; *linelen = ctx->inbound.linelen;

View File

@ -40,13 +40,9 @@ _assuan_read_from_server (assuan_context_t ctx, int *okay, int *off)
*okay = 0; *okay = 0;
*off = 0; *off = 0;
do
{
do do
{ {
rc = _assuan_read_line (ctx); rc = _assuan_read_line (ctx);
}
while (_assuan_error_is_eagain (rc));
if (rc) if (rc)
return rc; return rc;
line = ctx->inbound.line; line = ctx->inbound.line;

View File

@ -630,8 +630,6 @@ process_next (assuan_context_t ctx)
required to write full lines without blocking long after starting required to write full lines without blocking long after starting
a partial line. */ a partial line. */
rc = _assuan_read_line (ctx); rc = _assuan_read_line (ctx);
if (_assuan_error_is_eagain (rc))
return 0;
if (rc) if (rc)
return rc; return rc;
if (*ctx->inbound.line == '#' || !ctx->inbound.linelen) if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)

View File

@ -169,9 +169,7 @@ assuan_inquire (assuan_context_t ctx, const char *keyword,
{ {
do do
{ {
do
rc = _assuan_read_line (ctx); rc = _assuan_read_line (ctx);
while (_assuan_error_is_eagain (rc));
if (rc) if (rc)
goto leave; goto leave;
line = (unsigned char *) ctx->inbound.line; line = (unsigned char *) ctx->inbound.line;

View File

@ -145,7 +145,10 @@ read_port_and_nonce (const char *fname, unsigned short *port, char *nonce)
int int
_assuan_close (assuan_fd_t fd) _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)); int rc = closesocket (HANDLE2SOCKET(fd));
if (rc) if (rc)
errno = _assuan_sock_wsa2errno (WSAGetLastError ()); errno = _assuan_sock_wsa2errno (WSAGetLastError ());
@ -160,6 +163,7 @@ _assuan_close (assuan_fd_t fd)
#else #else
return close (fd); return close (fd);
#endif #endif
#endif
} }
@ -173,13 +177,25 @@ _assuan_sock_new (int domain, int type, int proto)
assuan_fd_t res; assuan_fd_t res;
if (domain == AF_UNIX || domain == AF_LOCAL) if (domain == AF_UNIX || domain == AF_LOCAL)
domain = AF_INET; domain = AF_INET;
#ifdef _ASSUAN_CUSTOM_IO
return _assuan_custom_socket (domain, type, proto);
#else
res = SOCKET2HANDLE(socket (domain, type, proto)); res = SOCKET2HANDLE(socket (domain, type, proto));
if (res == ASSUAN_INVALID_FD) if (res == ASSUAN_INVALID_FD)
errno = _assuan_sock_wsa2errno (WSAGetLastError ()); errno = _assuan_sock_wsa2errno (WSAGetLastError ());
return res; return res;
#endif
#else
#ifdef _ASSUAN_CUSTOM_IO
return _gpgme_io_socket (domain, type, proto);
#else #else
return socket (domain, type, proto); return socket (domain, type, proto);
#endif #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_port = myaddr.sin_port;
unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr; 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), ret = connect (HANDLE2SOCKET(sockfd),
(struct sockaddr *)&myaddr, sizeof myaddr); (struct sockaddr *)&myaddr, sizeof myaddr);
#endif
if (!ret) if (!ret)
{ {
/* Send the nonce. */ /* Send the nonce. */
ret = _assuan_io_write (sockfd, nonce, 16); ret = _assuan_io_write (sockfd, nonce, 16);
if (ret >= 0 && ret != 16) if (ret >= 0 && ret != 16)
{ {
@ -220,6 +243,8 @@ _assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
ret = -1; ret = -1;
} }
} }
else
errno = _assuan_sock_wsa2errno (WSAGetLastError ());
return ret; return ret;
} }
else else
@ -231,8 +256,14 @@ _assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
return res; return res;
} }
#else #else
#ifdef _ASSUAN_CUSTOM_IO
return _assuan_custom_connect (sockfd, addr, addrlen);
#else
return connect (sockfd, addr, addrlen); return connect (sockfd, addr, addrlen);
#endif #endif
#endif
} }

View 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_write (int fd, const void *buffer, size_t count);
int _gpgme_io_sendmsg (int sock, const struct msghdr *msg, int flags); 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_recvmsg (int sock, struct msghdr *msg, int flags);
int _gpgme_io_socket (int domain, int type, int proto);
#define _assuan_funopen _gpgme_funopen #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 sendmsg _gpgme_io_sendmsg
#define recvmsg _gpgme_io_recvmsg #define recvmsg _gpgme_io_recvmsg
#endif /*_ASSUAN_IN_GPGME_BUILD_ASSUAN*/ #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. ******/ /**** End GPGME specific modifications. ******/

View 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> 2009-03-18 Werner Koch <wk@g10code.com>
* gpgme.h.in (GPGME_KEYLIST_MODE_EPHEMERAL): New. * gpgme.h.in (GPGME_KEYLIST_MODE_EPHEMERAL): New.

View File

@ -415,6 +415,17 @@ llass_status_handler (void *opaque, int fd)
err = assuan_read_line (llass->assuan_ctx, &line, &linelen); err = assuan_read_line (llass->assuan_ctx, &line, &linelen);
if (err) if (err)
{ {
/* 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, TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
"fd 0x%x: error reading assuan line: %s", "fd 0x%x: error reading assuan line: %s",
fd, gpg_strerror (err)); fd, gpg_strerror (err));

View File

@ -40,6 +40,10 @@
#include "assuan.h" #include "assuan.h"
#endif #endif
#ifdef HAVE_W32_SYSTEM
#include "windows.h"
#endif
/* Bootstrap the subsystems needed for concurrent operation. This /* Bootstrap the subsystems needed for concurrent operation. This
must be done once at startup. We can not guarantee this using a must be done once at startup. We can not guarantee this using a
@ -54,6 +58,14 @@ do_subsystem_inits (void)
if (done) if (done)
return; return;
#ifdef HAVE_W32_SYSTEM
{
WSADATA wsadat;
WSAStartup (0x202, &wsadat);
}
#endif
_gpgme_sema_subsystem_init (); _gpgme_sema_subsystem_init ();
#ifdef HAVE_ASSUAN_H #ifdef HAVE_ASSUAN_H
assuan_set_assuan_err_source (GPG_ERR_SOURCE_GPGME); assuan_set_assuan_err_source (GPG_ERR_SOURCE_GPGME);

View File

@ -80,6 +80,13 @@
static struct 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; GIOChannel *chan;
/* The boolean PRIMARY is true if this file descriptor caused the /* The boolean PRIMARY is true if this file descriptor caused the
allocation of CHAN. Only then should CHAN be destroyed when this allocation of CHAN. Only then should CHAN be destroyed when this
@ -102,20 +109,96 @@ static struct
static GIOChannel * static GIOChannel *
find_channel (int fd, int create) find_channel (int fd)
{ {
if (fd < 0 || fd >= MAX_SLAFD) if (fd < 0 || fd >= MAX_SLAFD)
return NULL; 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); errno = EIO;
giochannel_table[fd].primary = 1; return -1;
g_io_channel_set_encoding (giochannel_table[fd].chan, NULL, NULL);
g_io_channel_set_buffered (giochannel_table[fd].chan, FALSE);
} }
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 * void *
gpgme_get_giochannel (int fd) gpgme_get_giochannel (int fd)
{ {
return find_channel (fd, 0); return find_channel (fd);
} }
@ -131,7 +214,7 @@ gpgme_get_giochannel (int fd)
void * void *
gpgme_get_fdptr (int fd) gpgme_get_fdptr (int fd)
{ {
return find_channel (fd, 0); return find_channel (fd);
} }
@ -141,9 +224,17 @@ gpgme_get_fdptr (int fd)
int int
_gpgme_io_fd2str (char *buf, int buflen, int fd) _gpgme_io_fd2str (char *buf, int buflen, int fd)
{ {
HANDLE hndl;
TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_fd2str", fd, "fd=%d", fd); TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_fd2str", fd, "fd=%d", fd);
TRACE_SUC1 ("syshd=%p", _get_osfhandle (fd)); if (giochannel_table[fd].fd != -1)
return snprintf (buf, buflen, "%d", (int) _get_osfhandle (fd)); 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, TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
"buffer=%p, count=%u", buffer, count); "buffer=%p, count=%u", buffer, count);
chan = find_channel (fd, 0); chan = find_channel (fd);
if (!chan) if (!chan)
{ {
TRACE_LOG ("no channel registered"); TRACE_LOG ("no channel registered");
@ -192,6 +283,11 @@ _gpgme_io_read (int fd, void *buffer, size_t count)
if (status == G_IO_STATUS_EOF) if (status == G_IO_STATUS_EOF)
nread = 0; nread = 0;
else if (status == G_IO_STATUS_AGAIN)
{
nread = -1;
saved_errno = EAGAIN;
}
else if (status != G_IO_STATUS_NORMAL) else if (status != G_IO_STATUS_NORMAL)
{ {
TRACE_LOG1 ("status %d", status); TRACE_LOG1 ("status %d", status);
@ -199,6 +295,7 @@ _gpgme_io_read (int fd, void *buffer, size_t count)
saved_errno = EIO; saved_errno = EIO;
} }
if (nread != 0 && nread != -1)
TRACE_LOGBUF (buffer, nread); TRACE_LOGBUF (buffer, nread);
errno = saved_errno; errno = saved_errno;
@ -213,11 +310,13 @@ _gpgme_io_write (int fd, const void *buffer, size_t count)
gsize nwritten; gsize nwritten;
GIOChannel *chan; GIOChannel *chan;
GIOStatus status; GIOStatus status;
GError *err = NULL;
TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd, TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
"buffer=%p, count=%u", buffer, count); "buffer=%p, count=%u", buffer, count);
TRACE_LOGBUF (buffer, count); TRACE_LOGBUF (buffer, count);
chan = find_channel (fd, 0); chan = find_channel (fd);
if (!chan) if (!chan)
{ {
TRACE_LOG ("fd %d: no channel registered"); 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, status = g_io_channel_write_chars (chan, (gchar *) buffer, count,
&nwritten, NULL); &nwritten, &err);
if (status != G_IO_STATUS_NORMAL) 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; nwritten = -1;
saved_errno = EIO; saved_errno = EIO;
@ -241,13 +351,14 @@ _gpgme_io_write (int fd, const void *buffer, size_t count)
int int
_gpgme_io_pipe (int filedes[2], int inherit_idx) _gpgme_io_pipe (int filedes[2], int inherit_idx)
{ {
GIOChannel *chan; int fds[2];
TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes, TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
"inherit_idx=%i (GPGME uses it for %s)", "inherit_idx=%i (GPGME uses it for %s)",
inherit_idx, inherit_idx ? "reading" : "writing"); inherit_idx, inherit_idx ? "reading" : "writing");
#define PIPEBUF_SIZE 4096 #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); return TRACE_SYSRES (-1);
/* Make one end inheritable. */ /* Make one end inheritable. */
@ -255,13 +366,13 @@ _gpgme_io_pipe (int filedes[2], int inherit_idx)
{ {
int new_read; int new_read;
new_read = _dup (filedes[0]); new_read = _dup (fds[0]);
_close (filedes[0]); _close (fds[0]);
filedes[0] = new_read; fds[0] = new_read;
if (new_read < 0) if (new_read < 0)
{ {
_close (filedes[1]); _close (fds[1]);
return TRACE_SYSRES (-1); return TRACE_SYSRES (-1);
} }
} }
@ -269,33 +380,48 @@ _gpgme_io_pipe (int filedes[2], int inherit_idx)
{ {
int new_write; int new_write;
new_write = _dup (filedes[1]); new_write = _dup (fds[1]);
_close (filedes[1]); _close (fds[1]);
filedes[1] = new_write; fds[1] = new_write;
if (new_write < 0) if (new_write < 0)
{ {
_close (filedes[0]); _close (fds[0]);
return TRACE_SYSRES (-1); return TRACE_SYSRES (-1);
} }
} }
/* Now we have a pipe with the right end inheritable. The other end /* For _gpgme_io_close. */
should have a giochannel. */ filedes[inherit_idx] = new_dummy_channel_from_fd (fds[inherit_idx]);
chan = find_channel (filedes[1 - inherit_idx], 1); if (filedes[inherit_idx] < 0)
if (!chan)
{ {
int saved_errno = errno; 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; errno = saved_errno;
return TRACE_SYSRES (-1); return TRACE_SYSRES (-1);
} }
return TRACE_SUC5 ("read=0x%x/%p, write=0x%x/%p, channel=%p", return TRACE_SUC5 ("read=0x%x/%p, write=0x%x/%p, channel=%p",
filedes[0], (HANDLE) _get_osfhandle (filedes[0]), filedes[0],
filedes[1], (HANDLE) _get_osfhandle (filedes[1]), (HANDLE) _get_osfhandle (giochannel_table[filedes[0]].fd),
chan); 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); return TRACE_SYSRES (-1);
} }
assert (giochannel_table[fd].used);
/* First call the notify handler. */ /* First call the notify handler. */
if (notify_table[fd].handler) if (notify_table[fd].handler)
{ {
@ -323,14 +451,21 @@ _gpgme_io_close (int fd)
{ {
if (giochannel_table[fd].primary) if (giochannel_table[fd].primary)
g_io_channel_shutdown (giochannel_table[fd].chan, 1, NULL); g_io_channel_shutdown (giochannel_table[fd].chan, 1, NULL);
else
_close (fd);
g_io_channel_unref (giochannel_table[fd].chan); g_io_channel_unref (giochannel_table[fd].chan);
giochannel_table[fd].chan = NULL;
} }
else 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 (); TRACE_SUC ();
return 0; return 0;
@ -365,7 +500,7 @@ _gpgme_io_set_nonblocking (int fd)
TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd); TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
chan = find_channel (fd, 0); chan = find_channel (fd);
if (!chan) if (!chan)
{ {
errno = EIO; errno = EIO;
@ -375,6 +510,7 @@ _gpgme_io_set_nonblocking (int fd)
status = g_io_channel_set_flags (chan, status = g_io_channel_set_flags (chan,
g_io_channel_get_flags (chan) | g_io_channel_get_flags (chan) |
G_IO_FLAG_NONBLOCK, NULL); G_IO_FLAG_NONBLOCK, NULL);
if (status != G_IO_STATUS_NORMAL) if (status != G_IO_STATUS_NORMAL)
{ {
#if 0 #if 0
@ -549,7 +685,8 @@ _gpgme_io_spawn (const char *path, char * const argv[],
HANDLE hd; HANDLE hd;
/* Make it inheritable for the wrapper process. */ /* 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)) pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
{ {
TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ()); 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; continue;
if ((fds[i].for_read || fds[i].for_write) 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_ADD1 (dbg_help, "[BAD0x%x ", fds[i].fd);
TRACE_END (dbg_help, "]"); TRACE_END (dbg_help, "]");
@ -787,26 +924,146 @@ _gpgme_io_dup (int fd)
int newfd; int newfd;
GIOChannel *chan; GIOChannel *chan;
TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_dup", fd, "dup (%d)", fd); TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd);
newfd = _dup (fd); if (fd < 0 || fd >= MAX_SLAFD || !giochannel_table[fd].used)
if (newfd == -1) {
return TRACE_SYSRES (-1); errno = EINVAL;
if (newfd < 0 || newfd >= MAX_SLAFD) return TRACE_SYSRES (-1);
}
for (newfd = 0; newfd < MAX_SLAFD; newfd++)
if (! giochannel_table[newfd].used)
break;
if (newfd == MAX_SLAFD)
{ {
/* New FD won't fit into our table. */
_close (newfd);
errno = EIO; errno = EIO;
return TRACE_SYSRES (-1); return TRACE_SYSRES (-1);
} }
assert (giochannel_table[newfd].chan == NULL);
chan = find_channel (fd, 0);
assert (chan);
chan = giochannel_table[fd].chan;
g_io_channel_ref (chan); g_io_channel_ref (chan);
giochannel_table[newfd].used = 1;
giochannel_table[newfd].chan = chan; giochannel_table[newfd].chan = chan;
giochannel_table[newfd].fd = -1;
giochannel_table[newfd].socket = INVALID_SOCKET;
giochannel_table[newfd].primary = 0; giochannel_table[newfd].primary = 0;
return TRACE_SYSRES (newfd); 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 ();
}

View File

@ -53,8 +53,8 @@
#define READBUF_SIZE 4096 #define READBUF_SIZE 4096
#define WRITEBUF_SIZE 4096 #define WRITEBUF_SIZE 4096
#define PIPEBUF_SIZE 4096 #define PIPEBUF_SIZE 4096
#define MAX_READERS 20 #define MAX_READERS 40
#define MAX_WRITERS 20 #define MAX_WRITERS 40
static struct static struct
{ {
@ -1469,3 +1469,63 @@ gpgme_get_fdptr (int fd)
{ {
return NULL; 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 ();
}

View File

@ -674,3 +674,20 @@ _gpgme_io_dup (int fd)
return 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;
}