2010-06-10 Marcus Brinkmann <marcus@g10code.de>

* debug.h (TRACE_SUC6): New macro.
	* w32-io.c (MAX_SLAFD): New macro.
	(fd_table): New static variable.
	(new_fd, release_fd): New functions.
	(fd_to_handle, handle_to_fd, handle_to_socket): Remove macros.
	(MAX_READERS, MAX_WRITERS): Increase to 64.
	(notify_table): Increase to MAX_SLAFD.
	(struct reader_context_s, struct writer_context_s): Add member
	file_sock.
	(reader, writer): Use file_hd vs file_sock to decide if socket
	operations to use.  Remove auto-detect mode.
	(create_reader, create_writer): Set file_sock.  Unblock pending
	thread only if this is a pipe fd.
	(_gpgme_io_pipe): Allocate fds from table and return slot indices
	instead of windows handles.  This allows to properly handle RVIDs.
	(_gpgme_io_close): Handle dup'ed file descriptors.
	(build_commandline) [HAVE_W32_SYSTEM]: Use RVID from fd table now.
	(_gpgme_io_spawn): Use fd table now.
	(_gpgme_io_fd2str): Use RVID from fd table now.
	(_gpgme_io_dup): Implement using fd table.
	(_gpgme_io_socket): Allocate fds from table.
	(_gpgme_io_connect): Use fd from table.
This commit is contained in:
Marcus Brinkmann 2010-06-10 13:49:19 +00:00
parent b243c4263e
commit dbb1112da1
3 changed files with 293 additions and 130 deletions

View File

@ -1,3 +1,30 @@
2010-06-10 Marcus Brinkmann <marcus@g10code.de>
* debug.h (TRACE_SUC6): New macro.
* w32-io.c (MAX_SLAFD): New macro.
(fd_table): New static variable.
(new_fd, release_fd): New functions.
(fd_to_handle, handle_to_fd, handle_to_socket): Remove macros.
(MAX_READERS, MAX_WRITERS): Increase to 64.
(notify_table): Increase to MAX_SLAFD.
(struct reader_context_s, struct writer_context_s): Add member
file_sock.
(reader, writer): Use file_hd vs file_sock to decide if socket
operations to use. Remove auto-detect mode.
(create_reader, create_writer): Set file_sock. Unblock pending
thread only if this is a pipe fd.
(_gpgme_io_pipe): Allocate fds from table and return slot indices
instead of windows handles. This allows to properly handle RVIDs.
(_gpgme_io_close): Handle dup'ed file descriptors.
(build_commandline) [HAVE_W32_SYSTEM]: Use RVID from fd table now.
(_gpgme_io_spawn): Use fd table now.
(_gpgme_io_fd2str): Use RVID from fd table now.
(_gpgme_io_dup): Implement using fd table.
(_gpgme_io_socket): Allocate fds from table.
(_gpgme_io_connect): Use fd from table.
* w32-glib-io.c (find_channel): Check that the slot is used.
2010-06-09 Marcus Brinkmann <marcus@g10code.de> 2010-06-09 Marcus Brinkmann <marcus@g10code.de>
* w32-io.c [HAVE_W32CE_SYSTEM]: Include assuan.h and winioctl.h. * w32-io.c [HAVE_W32CE_SYSTEM]: Include assuan.h and winioctl.h.

View File

@ -204,6 +204,10 @@ void _gpgme_debug_frame_end (void);
_gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \
_gpgme_trace_func, arg1, arg2, arg3, arg4, arg5), \ _gpgme_trace_func, arg1, arg2, arg3, arg4, arg5), \
_gpgme_debug_frame_end (), 0 _gpgme_debug_frame_end (), 0
#define TRACE_SUC6(fmt, arg1, arg2, arg3, arg4, arg5, arg6) \
_gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \
_gpgme_trace_func, arg1, arg2, arg3, arg4, arg5, arg6), \
_gpgme_debug_frame_end (), 0
#define TRACE_LOG(fmt) \ #define TRACE_LOG(fmt) \
_gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \

View File

@ -46,22 +46,87 @@
#include "debug.h" #include "debug.h"
/* We assume that a HANDLE can be represented by an int which should /* FIXME: Optimize. */
be true for all i386 systems (HANDLE is defined as void *) and #define MAX_SLAFD 512
these are the only systems for which Windows is available. Further
we assume that -1 denotes an invalid handle. */ static struct
{
int used;
/* If this is not INVALID_HANDLE_VALUE, then it's a handle. */
HANDLE handle;
/* If this is not INVALID_SOCKET, then it's a Windows socket. */
int socket;
/* If this is not 0, then it's a rendezvous ID for the pipe server. */
int rvid;
/* DUP_FROM is -1 if this file descriptor was allocated by pipe or
socket functions. Only then should the handle or socket be
destroyed when this FD is closed. This, together with the fact
that dup'ed file descriptors are closed before the file
descriptors from which they are dup'ed are closed, ensures that
the handle or socket is always valid, and shared among all file
descriptors refering to the same underlying object.
The logic behind this is that there is only one reason for us to
dup file descriptors anyway: to allow simpler book-keeping of
file descriptors shared between GPGME and libassuan, which both
want to close something. Using the same handle for these
duplicates works just fine. */
int dup_from;
} fd_table[MAX_SLAFD];
/* Returns the FD or -1 on resource limit. */
int
new_fd (void)
{
int idx;
for (idx = 0; idx < MAX_SLAFD; idx++)
if (! fd_table[idx].used)
break;
if (idx == MAX_SLAFD)
{
gpg_err_set_errno (EIO);
return -1;
}
fd_table[idx].used = 1;
fd_table[idx].handle = INVALID_HANDLE_VALUE;
fd_table[idx].socket = INVALID_SOCKET;
fd_table[idx].rvid = 0;
fd_table[idx].dup_from = -1;
return idx;
}
void
release_fd (int fd)
{
if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
return;
fd_table[fd].used = 0;
fd_table[fd].handle = INVALID_HANDLE_VALUE;
fd_table[fd].socket = INVALID_SOCKET;
fd_table[fd].rvid = 0;
fd_table[fd].dup_from = -1;
}
#define fd_to_handle(a) ((HANDLE)(a))
#define handle_to_fd(a) ((int)(a))
#define pid_to_handle(a) ((HANDLE)(a)) #define pid_to_handle(a) ((HANDLE)(a))
#define handle_to_pid(a) ((int)(a)) #define handle_to_pid(a) ((int)(a))
#define handle_to_socket(a) ((unsigned int)(a))
#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 40 #define MAX_READERS 64
#define MAX_WRITERS 40 #define MAX_WRITERS 64
static struct static struct
{ {
@ -69,13 +134,14 @@ static struct
int fd; int fd;
_gpgme_close_notify_handler_t handler; _gpgme_close_notify_handler_t handler;
void *value; void *value;
} notify_table[256]; } notify_table[MAX_SLAFD];
DEFINE_STATIC_LOCK (notify_table_lock); DEFINE_STATIC_LOCK (notify_table_lock);
struct reader_context_s struct reader_context_s
{ {
HANDLE file_hd; HANDLE file_hd;
int file_sock;
HANDLE thread_hd; HANDLE thread_hd;
int refcount; int refcount;
@ -110,6 +176,7 @@ DEFINE_STATIC_LOCK (reader_table_lock);
struct writer_context_s struct writer_context_s
{ {
HANDLE file_hd; HANDLE file_hd;
int file_sock;
HANDLE thread_hd; HANDLE thread_hd;
int refcount; int refcount;
@ -229,7 +296,10 @@ reader (void *arg)
TRACE_BEG1 (DEBUG_SYSIO, "gpgme:reader", ctx->file_hd, TRACE_BEG1 (DEBUG_SYSIO, "gpgme:reader", ctx->file_hd,
"thread=%p", ctx->thread_hd); "thread=%p", ctx->thread_hd);
sock = is_socket (ctx->file_hd); if (ctx->file_hd != INVALID_HANDLE_VALUE)
sock = 0;
else
sock = 1;
for (;;) for (;;)
{ {
@ -260,25 +330,13 @@ reader (void *arg)
TRACE_LOG2 ("%s %d bytes", sock? "receiving":"reading", nbytes); TRACE_LOG2 ("%s %d bytes", sock? "receiving":"reading", nbytes);
if (sock == -1 || sock == 1) if (sock)
{ {
int n; int n;
n = recv (handle_to_socket (ctx->file_hd), n = recv (ctx->file_sock, ctx->buffer + ctx->writepos, nbytes, 0);
ctx->buffer + ctx->writepos, nbytes, 0);
if (n < 0) if (n < 0)
{ {
if (sock == -1)
{
if (WSAGetLastError () == WSAENOTSOCK)
{
sock = 0;
goto try_readfile;
}
else
sock = 1;
}
ctx->error_code = (int) WSAGetLastError (); ctx->error_code = (int) WSAGetLastError ();
if (ctx->error_code == ERROR_BROKEN_PIPE) if (ctx->error_code == ERROR_BROKEN_PIPE)
{ {
@ -296,7 +354,6 @@ reader (void *arg)
} }
else else
{ {
try_readfile:
if (!ReadFile (ctx->file_hd, if (!ReadFile (ctx->file_hd,
ctx->buffer + ctx->writepos, nbytes, &nread, NULL)) ctx->buffer + ctx->writepos, nbytes, &nread, NULL))
{ {
@ -348,7 +405,7 @@ reader (void *arg)
static struct reader_context_s * static struct reader_context_s *
create_reader (HANDLE fd) create_reader (int fd)
{ {
struct reader_context_s *ctx; struct reader_context_s *ctx;
SECURITY_ATTRIBUTES sec_attr; SECURITY_ATTRIBUTES sec_attr;
@ -367,7 +424,14 @@ create_reader (HANDLE fd)
return NULL; return NULL;
} }
ctx->file_hd = fd; if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
{
TRACE_SYSERR (EIO);
return NULL;
}
ctx->file_hd = fd_table[fd].handle;
ctx->file_sock = fd_table[fd].socket;
ctx->refcount = 1; ctx->refcount = 1;
ctx->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL); ctx->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
if (ctx->have_data_ev) if (ctx->have_data_ev)
@ -440,11 +504,14 @@ destroy_reader (struct reader_context_s *ctx)
reading. Then we need to unblock the reader in the pipe driver reading. Then we need to unblock the reader in the pipe driver
to make our reader thread notice that we want it to go away. */ to make our reader thread notice that we want it to go away. */
if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK, if (ctx->file_hd != INVALID_HANDLE_VALUE)
NULL, 0, NULL, 0, NULL, NULL))
{ {
TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd, if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK,
"unblock control call failed for thread %p", ctx->thread_hd); NULL, 0, NULL, 0, NULL, NULL))
{
TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd,
"unblock control call failed for thread %p", ctx->thread_hd);
}
} }
#endif #endif
@ -491,7 +558,7 @@ find_reader (int fd, int start_it)
if (i != reader_table_size) if (i != reader_table_size)
{ {
rd = create_reader (fd_to_handle (fd)); rd = create_reader (fd);
if (rd) if (rd)
{ {
reader_table[i].fd = fd; reader_table[i].fd = fd;
@ -614,7 +681,10 @@ writer (void *arg)
TRACE_BEG1 (DEBUG_SYSIO, "gpgme:writer", ctx->file_hd, TRACE_BEG1 (DEBUG_SYSIO, "gpgme:writer", ctx->file_hd,
"thread=%p", ctx->thread_hd); "thread=%p", ctx->thread_hd);
sock = is_socket (ctx->file_hd); if (ctx->file_hd != INVALID_HANDLE_VALUE)
sock = 0;
else
sock = 1;
for (;;) for (;;)
{ {
@ -648,27 +718,15 @@ writer (void *arg)
/* Note that CTX->nbytes is not zero at this point, because /* Note that CTX->nbytes is not zero at this point, because
_gpgme_io_write always writes at least 1 byte before waking _gpgme_io_write always writes at least 1 byte before waking
us up, unless CTX->stop_me is true, which we catch above. */ us up, unless CTX->stop_me is true, which we catch above. */
if (sock == -1 || sock == 1) if (sock)
{ {
/* We need to try send first because a socket handle can't /* We need to try send first because a socket handle can't
be used with WriteFile. */ be used with WriteFile. */
int n; int n;
n = send (handle_to_socket (ctx->file_hd), n = send (ctx->file_sock, ctx->buffer, ctx->nbytes, 0);
ctx->buffer, ctx->nbytes, 0);
if (n < 0) if (n < 0)
{ {
if (sock == -1)
{
if (WSAGetLastError () == WSAENOTSOCK)
{
sock = 0;
goto try_writefile;
}
else
sock = 1;
}
ctx->error_code = (int) WSAGetLastError (); ctx->error_code = (int) WSAGetLastError ();
ctx->error = 1; ctx->error = 1;
TRACE_LOG1 ("send error: ec=%d", ctx->error_code); TRACE_LOG1 ("send error: ec=%d", ctx->error_code);
@ -678,7 +736,6 @@ writer (void *arg)
} }
else else
{ {
try_writefile:
if (!WriteFile (ctx->file_hd, ctx->buffer, if (!WriteFile (ctx->file_hd, ctx->buffer,
ctx->nbytes, &nwritten, NULL)) ctx->nbytes, &nwritten, NULL))
{ {
@ -711,7 +768,7 @@ writer (void *arg)
static struct writer_context_s * static struct writer_context_s *
create_writer (HANDLE fd) create_writer (int fd)
{ {
struct writer_context_s *ctx; struct writer_context_s *ctx;
SECURITY_ATTRIBUTES sec_attr; SECURITY_ATTRIBUTES sec_attr;
@ -730,7 +787,14 @@ create_writer (HANDLE fd)
return NULL; return NULL;
} }
ctx->file_hd = fd; if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
{
TRACE_SYSERR (EIO);
return NULL;
}
ctx->file_hd = fd_table[fd].handle;
ctx->file_sock = fd_table[fd].socket;
ctx->refcount = 1; ctx->refcount = 1;
ctx->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL); ctx->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
if (ctx->have_data) if (ctx->have_data)
@ -853,7 +917,7 @@ find_writer (int fd, int start_it)
if (i != writer_table_size) if (i != writer_table_size)
{ {
wt = create_writer (fd_to_handle (fd)); wt = create_writer (fd);
if (wt) if (wt)
{ {
writer_table[i].fd = fd; writer_table[i].fd = fd;
@ -969,22 +1033,39 @@ _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)
{ {
HANDLE rh; int rfd;
HANDLE wh; int wfd;
#ifdef HAVE_W32CE_SYSTEM #ifdef HAVE_W32CE_SYSTEM
HANDLE hd; HANDLE hd;
int rvid; int rvid;
#else
HANDLE rh;
HANDLE wh;
SECURITY_ATTRIBUTES sec_attr;
#endif
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");
rfd = new_fd ();
if (rfd == -1)
return TRACE_SYSRES (-1);
wfd = new_fd ();
if (wfd == -1)
{
release_fd (rfd);
return TRACE_SYSRES (-1);
}
#ifdef HAVE_W32CE_SYSTEM
hd = _assuan_w32ce_prepare_pipe (&rvid, !inherit_idx); hd = _assuan_w32ce_prepare_pipe (&rvid, !inherit_idx);
if (hd == INVALID_HANDLE_VALUE) if (hd == INVALID_HANDLE_VALUE)
{ {
TRACE_LOG1 ("_assuan_w32ce_prepare_pipe failed: ec=%d", TRACE_LOG1 ("_assuan_w32ce_prepare_pipe failed: ec=%d",
(int) GetLastError ()); (int) GetLastError ());
release_fd (rfd);
release_fd (wfd);
/* FIXME: Should translate the error code. */ /* FIXME: Should translate the error code. */
gpg_err_set_errno (EIO); gpg_err_set_errno (EIO);
return TRACE_SYSRES (-1); return TRACE_SYSRES (-1);
@ -992,18 +1073,16 @@ _gpgme_io_pipe (int filedes[2], int inherit_idx)
if (inherit_idx == 0) if (inherit_idx == 0)
{ {
/* FIXME: For now. We need to detect them at close. */ fd_table[rfd].rvid = rvid;
rh = (void*) ((rvid << 1) | 1); fd_table[wfd].handle = hd;
wh = hd;
} }
else else
{ {
rh = hd; fd_table[rfd].handle = hd;
/* FIXME: For now. We need to detect them at close. */ fd_table[wfd].rvid = rvid;
wh = (void*) ((rvid << 1) | 1);
} }
#else #else
SECURITY_ATTRIBUTES sec_attr;
memset (&sec_attr, 0, sizeof (sec_attr)); memset (&sec_attr, 0, sizeof (sec_attr));
sec_attr.nLength = sizeof (sec_attr); sec_attr.nLength = sizeof (sec_attr);
@ -1012,6 +1091,8 @@ _gpgme_io_pipe (int filedes[2], int inherit_idx)
if (!CreatePipe (&rh, &wh, &sec_attr, PIPEBUF_SIZE)) if (!CreatePipe (&rh, &wh, &sec_attr, PIPEBUF_SIZE))
{ {
TRACE_LOG1 ("CreatePipe failed: ec=%d", (int) GetLastError ()); TRACE_LOG1 ("CreatePipe failed: ec=%d", (int) GetLastError ());
release_fd (rfd);
release_fd (wfd);
/* FIXME: Should translate the error code. */ /* FIXME: Should translate the error code. */
gpg_err_set_errno (EIO); gpg_err_set_errno (EIO);
return TRACE_SYSRES (-1); return TRACE_SYSRES (-1);
@ -1027,6 +1108,8 @@ _gpgme_io_pipe (int filedes[2], int inherit_idx)
{ {
TRACE_LOG1 ("DuplicateHandle failed: ec=%d", TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
(int) GetLastError ()); (int) GetLastError ());
release_fd (rfd);
release_fd (wfd);
CloseHandle (rh); CloseHandle (rh);
CloseHandle (wh); CloseHandle (wh);
/* FIXME: Should translate the error code. */ /* FIXME: Should translate the error code. */
@ -1045,6 +1128,8 @@ _gpgme_io_pipe (int filedes[2], int inherit_idx)
{ {
TRACE_LOG1 ("DuplicateHandle failed: ec=%d", TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
(int) GetLastError ()); (int) GetLastError ());
release_fd (rfd);
release_fd (wfd);
CloseHandle (rh); CloseHandle (rh);
CloseHandle (wh); CloseHandle (wh);
/* FIXME: Should translate the error code. */ /* FIXME: Should translate the error code. */
@ -1054,20 +1139,25 @@ _gpgme_io_pipe (int filedes[2], int inherit_idx)
CloseHandle (wh); CloseHandle (wh);
wh = hd; wh = hd;
} }
fd_table[rfd].handle = rh;
fd_table[wfd].handle = wh;
#endif #endif
if (inherit_idx == 0) if (inherit_idx == 0)
{ {
struct writer_context_s *ctx; struct writer_context_s *ctx;
ctx = find_writer (handle_to_fd (wh), 0); ctx = find_writer (wfd, 0);
assert (ctx == NULL); assert (ctx == NULL);
ctx = find_writer (handle_to_fd (wh), 1); ctx = find_writer (wfd, 1);
if (!ctx) if (!ctx)
{ {
#ifndef HAVE_W32CE_SYSTEM /* No way/need to close RVIDs on Windows CE. */
CloseHandle (rh); if (fd_table[rfd].handle)
#endif CloseHandle (fd_table[rfd].handle);
CloseHandle (wh); if (fd_table[wfd].handle)
CloseHandle (fd_table[wfd].handle);
release_fd (rfd);
release_fd (wfd);
/* FIXME: Should translate the error code. */ /* FIXME: Should translate the error code. */
gpg_err_set_errno (EIO); gpg_err_set_errno (EIO);
return TRACE_SYSRES (-1); return TRACE_SYSRES (-1);
@ -1076,24 +1166,29 @@ _gpgme_io_pipe (int filedes[2], int inherit_idx)
else if (inherit_idx == 1) else if (inherit_idx == 1)
{ {
struct reader_context_s *ctx; struct reader_context_s *ctx;
ctx = find_reader (handle_to_fd (rh), 0); ctx = find_reader (rfd, 0);
assert (ctx == NULL); assert (ctx == NULL);
ctx = find_reader (handle_to_fd (rh), 1); ctx = find_reader (rfd, 1);
if (!ctx) if (!ctx)
{ {
CloseHandle (rh); if (fd_table[rfd].handle)
#ifndef HAVE_W32CE_SYSTEM CloseHandle (fd_table[rfd].handle);
CloseHandle (wh); /* No way/need to close RVIDs on Windows CE. */
#endif if (fd_table[wfd].handle)
CloseHandle (fd_table[wfd].handle);
release_fd (rfd);
release_fd (wfd);
/* FIXME: Should translate the error code. */ /* FIXME: Should translate the error code. */
gpg_err_set_errno (EIO); gpg_err_set_errno (EIO);
return TRACE_SYSRES (-1); return TRACE_SYSRES (-1);
} }
} }
filedes[0] = handle_to_fd (rh); filedes[0] = rfd;
filedes[1] = handle_to_fd (wh); filedes[1] = wfd;
return TRACE_SUC2 ("read=%p, write=%p", rh, wh); return TRACE_SUC6 ("read=0x%x (%p/0x%x), write=0x%x (%p/0x%x)",
rfd, fd_table[rfd].handle, fd_table[rfd].rvid,
wfd, fd_table[wfd].handle, fd_table[wfd].rvid);
} }
@ -1103,6 +1198,7 @@ _gpgme_io_close (int fd)
int i; int i;
_gpgme_close_notify_handler_t handler = NULL; _gpgme_close_notify_handler_t handler = NULL;
void *value = NULL; void *value = NULL;
TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd); TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
if (fd == -1) if (fd == -1)
@ -1110,12 +1206,11 @@ _gpgme_io_close (int fd)
gpg_err_set_errno (EBADF); gpg_err_set_errno (EBADF);
return TRACE_SYSRES (-1); return TRACE_SYSRES (-1);
} }
if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
#ifdef HAVE_W32CE_SYSTEM {
/* FIXME: For now: This is a rendezvous id. */ gpg_err_set_errno (EBADF);
if (fd & 1) return TRACE_SYSRES (-1);
return TRACE_SYSRES (0); }
#endif
kill_reader (fd); kill_reader (fd);
kill_writer (fd); kill_writer (fd);
@ -1136,14 +1231,33 @@ _gpgme_io_close (int fd)
if (handler) if (handler)
handler (fd, value); handler (fd, value);
if (!CloseHandle (fd_to_handle (fd))) if (fd_table[fd].dup_from == -1)
{ {
TRACE_LOG1 ("CloseHandle failed: ec=%d", (int) GetLastError ()); if (fd_table[fd].handle != INVALID_HANDLE_VALUE)
/* FIXME: Should translate the error code. */ {
gpg_err_set_errno (EIO); if (!CloseHandle (fd_table[fd].handle))
return TRACE_SYSRES (-1); {
TRACE_LOG1 ("CloseHandle failed: ec=%d", (int) GetLastError ());
/* FIXME: Should translate the error code. */
gpg_err_set_errno (EIO);
return TRACE_SYSRES (-1);
}
}
else if (fd_table[fd].socket != INVALID_SOCKET)
{
if (closesocket (fd_table[fd].socket))
{
TRACE_LOG1 ("closesocket failed: ec=%d", (int) WSAGetLastError ());
/* FIXME: Should translate the error code. */
gpg_err_set_errno (EIO);
return TRACE_SYSRES (-1);
}
}
/* Nothing to do for RVIDs. */
} }
release_fd (fd);
return TRACE_SYSRES (0); return TRACE_SYSRES (0);
} }
@ -1188,6 +1302,7 @@ _gpgme_io_set_nonblocking (int fd)
return 0; return 0;
} }
#ifdef HAVE_W32CE_SYSTEM #ifdef HAVE_W32CE_SYSTEM
static char * static char *
build_commandline (char **argv, int fd0, int fd0_isnull, build_commandline (char **argv, int fd0, int fd0_isnull,
@ -1202,42 +1317,28 @@ build_commandline (char **argv, int fd0, int fd0_isnull,
p = fdbuf; p = fdbuf;
*p = 0; *p = 0;
strcpy (p, "-&S0=null ");
p += strlen (p);
if (fd0 != -1) if (fd0 != -1)
{ {
/* FIXME */
if (fd0 & 1)
fd0 = fd0 >> 1;
if (fd0_isnull) if (fd0_isnull)
strcpy (p, "-&S0=null "); strcpy (p, "-&S0=null ");
else else
snprintf (p, 25, "-&S0=%d ", (int)fd0); snprintf (p, 25, "-&S0=%d ", fd_table[fd0].rvid);
p += strlen (p); p += strlen (p);
} }
if (fd1 != -1) if (fd1 != -1)
{ {
/* FIXME */
if (fd1 & 1)
fd1 = fd1 >> 1;
if (fd1_isnull) if (fd1_isnull)
strcpy (p, "-&S1=null "); strcpy (p, "-&S1=null ");
else else
snprintf (p, 25, "-&S1=%d ", (int)fd1); snprintf (p, 25, "-&S1=%d ", fd_table[fd1].rvid);
p += strlen (p); p += strlen (p);
} }
if (fd2 != -1) if (fd2 != -1)
{ {
/* FIXME */
if (fd2 & 1)
fd2 = fd2 >> 1;
if (fd2_isnull) if (fd2_isnull)
strcpy (p, "-&S2=null "); strcpy (p, "-&S2=null ");
else else
snprintf (p, 25, "-&S2=%d ", (int)fd2); snprintf (p, 25, "-&S2=%d ", fd_table[fd2].rvid);
p += strlen (p); p += strlen (p);
} }
strcpy (p, "-&S2=null "); strcpy (p, "-&S2=null ");
@ -1378,7 +1479,22 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
for (i = 0; fd_list[i].fd != -1; i++) for (i = 0; fd_list[i].fd != -1; i++)
{ {
TRACE_LOG3 ("fd_list[%2i] = fd %i, dup_to %i", i, fd_list[i].fd, fd_list[i].dup_to); int fd = fd_list[i].fd;
TRACE_LOG3 ("fd_list[%2i] = fd %i, dup_to %i", i, fd, fd_list[i].dup_to);
if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
{
TRACE_LOG1 ("invalid fd 0x%x", fd);
gpg_err_set_errno (EBADF);
return TRACE_SYSRES (-1);
}
if (fd_table[fd].rvid == 0)
{
TRACE_LOG1 ("fd 0x%x not inheritable (not an RVID)", fd);
gpg_err_set_errno (EBADF);
return TRACE_SYSRES (-1);
}
if (fd_list[i].dup_to == 0) if (fd_list[i].dup_to == 0)
{ {
fd_in = fd_list[i].fd; fd_in = fd_list[i].fd;
@ -1428,7 +1544,7 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
for (i = 0; fd_list[i].fd != -1; i++) for (i = 0; fd_list[i].fd != -1; i++)
{ {
/* Return the child name of this handle. */ /* Return the child name of this handle. */
fd_list[i].peer_name = fd_list[i].fd; fd_list[i].peer_name = fd_table[fd_list[i].fd].rvid;
} }
#else #else
@ -1749,6 +1865,7 @@ _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
else if (code == WAIT_FAILED) else if (code == WAIT_FAILED)
{ {
int le = (int) GetLastError (); int le = (int) GetLastError ();
#if 0
if (le == ERROR_INVALID_HANDLE) if (le == ERROR_INVALID_HANDLE)
{ {
int k; int k;
@ -1765,6 +1882,7 @@ _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
} }
TRACE_LOG (" oops, or not???"); TRACE_LOG (" oops, or not???");
} }
#endif
TRACE_LOG1 ("WFMO failed: %d", le); TRACE_LOG1 ("WFMO failed: %d", le);
count = -1; count = -1;
} }
@ -1813,9 +1931,11 @@ _gpgme_io_fd2str (char *buf, int buflen, int fd)
{ {
#ifdef HAVE_W32CE_SYSTEM #ifdef HAVE_W32CE_SYSTEM
/* FIXME: For now. See above. */ /* FIXME: For now. See above. */
if (fd & 1) if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used
fd = fd >> 1; || fd_table[fd].rvid == 0)
/* FIXME: The real problems start if fd is not of this type! */ fd = -1;
else
fd = fd_table[fd].rvid;
#endif #endif
return snprintf (buf, buflen, "%d", fd); return snprintf (buf, buflen, "%d", fd);
@ -1825,28 +1945,28 @@ _gpgme_io_fd2str (char *buf, int buflen, int fd)
int int
_gpgme_io_dup (int fd) _gpgme_io_dup (int fd)
{ {
#ifdef HAVE_W32CE_SYSTEM int newfd;
gpg_err_set_errno (EIO);
return -1;
#else
HANDLE handle = fd_to_handle (fd);
HANDLE new_handle = fd_to_handle (fd);
int i;
struct reader_context_s *rd_ctx; struct reader_context_s *rd_ctx;
struct writer_context_s *wt_ctx; struct writer_context_s *wt_ctx;
int i;
TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd); TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd);
if (!DuplicateHandle (GetCurrentProcess(), handle, if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
GetCurrentProcess(), &new_handle,
0, FALSE, DUPLICATE_SAME_ACCESS))
{ {
TRACE_LOG1 ("DuplicateHandle failed: ec=%d\n", (int) GetLastError ()); gpg_err_set_errno (EINVAL);
/* FIXME: Translate error code. */
gpg_err_set_errno (EIO);
return TRACE_SYSRES (-1); return TRACE_SYSRES (-1);
} }
newfd = new_fd();
if (newfd == -1)
return TRACE_SYSRES (-1);
fd_table[newfd].handle = fd_table[fd].handle;
fd_table[newfd].socket = fd_table[fd].socket;
fd_table[newfd].rvid = fd_table[fd].rvid;
fd_table[newfd].dup_from = fd;
rd_ctx = find_reader (fd, 0); rd_ctx = find_reader (fd, 0);
if (rd_ctx) if (rd_ctx)
{ {
@ -1860,7 +1980,7 @@ _gpgme_io_dup (int fd)
break; break;
/* FIXME. */ /* FIXME. */
assert (i != reader_table_size); assert (i != reader_table_size);
reader_table[i].fd = handle_to_fd (new_handle); reader_table[i].fd = newfd;
reader_table[i].context = rd_ctx; reader_table[i].context = rd_ctx;
reader_table[i].used = 1; reader_table[i].used = 1;
UNLOCK (reader_table_lock); UNLOCK (reader_table_lock);
@ -1879,14 +1999,13 @@ _gpgme_io_dup (int fd)
break; break;
/* FIXME. */ /* FIXME. */
assert (i != writer_table_size); assert (i != writer_table_size);
writer_table[i].fd = handle_to_fd (new_handle); writer_table[i].fd = newfd;
writer_table[i].context = wt_ctx; writer_table[i].context = wt_ctx;
writer_table[i].used = 1; writer_table[i].used = 1;
UNLOCK (writer_table_lock); UNLOCK (writer_table_lock);
} }
return TRACE_SYSRES (handle_to_fd (new_handle)); return TRACE_SYSRES (newfd);
#endif
} }
@ -1931,18 +2050,25 @@ int
_gpgme_io_socket (int domain, int type, int proto) _gpgme_io_socket (int domain, int type, int proto)
{ {
int res; int res;
int fd;
TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain, TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
"type=%i, protp=%i", type, proto); "type=%i, protp=%i", type, proto);
fd = new_fd();
if (fd == -1)
return TRACE_SYSRES (-1);
res = socket (domain, type, proto); res = socket (domain, type, proto);
if (res == INVALID_SOCKET) if (res == INVALID_SOCKET)
{ {
release_fd (fd);
gpg_err_set_errno (wsa2errno (WSAGetLastError ())); gpg_err_set_errno (wsa2errno (WSAGetLastError ()));
return TRACE_SYSRES (-1); return TRACE_SYSRES (-1);
} }
fd_table[fd].socket = res;
TRACE_SUC1 ("socket=0x%x", res); TRACE_SUC2 ("socket=0x%x (0x%x)", fd, fd_table[fd].socket);
return res; return res;
} }
@ -1956,7 +2082,13 @@ _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd, TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
"addr=%p, addrlen=%i", addr, addrlen); "addr=%p, addrlen=%i", addr, addrlen);
res = connect (fd, addr, addrlen); if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
{
gpg_err_set_errno (EBADF);
return TRACE_SYSRES (-1);
}
res = connect (fd_table[fd].socket, addr, addrlen);
if (res) if (res)
{ {
gpg_err_set_errno (wsa2errno (WSAGetLastError ())); gpg_err_set_errno (wsa2errno (WSAGetLastError ()));