summaryrefslogtreecommitdiff
path: root/src/w32-glib-io.c
diff options
context:
space:
mode:
authorMarcus Brinkmann <mb@g10code.com>2009-04-08 18:53:57 +0000
committerMarcus Brinkmann <mb@g10code.com>2009-04-08 18:53:57 +0000
commitd255b4bec9a1fdf0864640750161ea12999e43a5 (patch)
tree75e870ff7e07cb4f2bf30dc8a136c72eb4bf6bd4 /src/w32-glib-io.c
parent6f8aa0e29d46f3109a5c3f8f9d7a7dc3e7b6abef (diff)
downloadgpgme-d255b4bec9a1fdf0864640750161ea12999e43a5.tar.gz
assuan/
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.
Diffstat (limited to 'src/w32-glib-io.c')
-rw-r--r--src/w32-glib-io.c375
1 files changed, 316 insertions, 59 deletions
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 ();
+}