diff options
author | Marcus Brinkmann <[email protected]> | 2009-04-08 18:53:57 +0000 |
---|---|---|
committer | Marcus Brinkmann <[email protected]> | 2009-04-08 18:53:57 +0000 |
commit | d255b4bec9a1fdf0864640750161ea12999e43a5 (patch) | |
tree | 75e870ff7e07cb4f2bf30dc8a136c72eb4bf6bd4 /src/w32-glib-io.c | |
parent | 2009-03-23 Marcus Brinkmann <[email protected]> (diff) | |
download | gpgme-d255b4bec9a1fdf0864640750161ea12999e43a5.tar.gz gpgme-d255b4bec9a1fdf0864640750161ea12999e43a5.zip |
assuan/
2009-04-08 Marcus Brinkmann <[email protected]>
* 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 <[email protected]>
* 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.c | 375 |
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 (); +} |