aboutsummaryrefslogtreecommitdiffstats
path: root/src/system-w32.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/system-w32.c')
-rw-r--r--src/system-w32.c76
1 files changed, 74 insertions, 2 deletions
diff --git a/src/system-w32.c b/src/system-w32.c
index 76ff2a0..1392a1e 100644
--- a/src/system-w32.c
+++ b/src/system-w32.c
@@ -167,6 +167,10 @@ __assuan_close (assuan_context_t ctx, assuan_fd_t fd)
+/* To encode/decode file HANDLE, we use FDPASS_FORMAT */
+#define FDPASS_FORMAT "%p"
+#define FDPASS_MSG_SIZE (sizeof (uintptr_t)*2 + 1)
+
/* Get a file HANDLE to send, from POSIX fd. */
static gpg_error_t
get_file_handle (int fd, int server_pid, HANDLE *r_handle)
@@ -220,6 +224,30 @@ w32_fdpass_send (assuan_context_t ctx, assuan_fd_t fd)
return err;
}
+static int
+process_fdpass_msg (const char *fdpass_msg, size_t msglen, int *r_fd)
+{
+ void *file_handle;
+ int res;
+ int fd;
+
+ *r_fd = -1;
+
+ res = sscanf (fdpass_msg, FDPASS_FORMAT, &file_handle);
+ if (res != 1)
+ return -1;
+
+ fd = _open_osfhandle ((intptr_t)file_handle, _O_RDWR);
+ if (fd < 0)
+ {
+ CloseHandle (file_handle);
+ return -1;
+ }
+
+ *r_fd = fd;
+ return 0;
+}
+
/* Receive a HANDLE from the peer and turn it into a FD (POSIX fd). */
gpg_error_t
@@ -252,7 +280,53 @@ __assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
if (ctx->flags.is_socket)
{
+ fd_set fds;
int tries = 3;
+ fd_set efds;
+
+ FD_ZERO (&fds);
+ FD_SET (HANDLE2SOCKET (fd), &fds);
+ FD_ZERO (&efds);
+ FD_SET (HANDLE2SOCKET (fd), &efds);
+ res = select (0, &fds, NULL, &efds, NULL);
+ if (res < 0)
+ {
+ gpg_err_set_errno (EIO);
+ return -1;
+ }
+ else if (FD_ISSET (HANDLE2SOCKET (fd), &efds))
+ {
+ int fd_recv;
+ char fdpass_msg[FDPASS_MSG_SIZE];
+
+ /* the message of ! */
+ res = recv (HANDLE2SOCKET (fd), fdpass_msg, sizeof (fdpass_msg), MSG_OOB);
+ if (res < 0)
+ {
+ gpg_err_set_errno (EIO);
+ return -1;
+ }
+
+ /* the body of message */
+ res = recv (HANDLE2SOCKET (fd), fdpass_msg, sizeof (fdpass_msg), 0);
+ if (res < 0)
+ {
+ gpg_err_set_errno (EIO);
+ return -1;
+ }
+
+ res = process_fdpass_msg (fdpass_msg, res, &fd_recv);
+ if (res < 0)
+ {
+ gpg_err_set_errno (EIO);
+ return -1;
+ }
+
+ ctx->uds.pendingfds[ctx->uds.pendingfdscount++] = (assuan_fd_t)fd_recv;
+ TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_read", ctx,
+ "received fd: %d", fd_recv);
+ /* Fall through */
+ }
again:
ec = 0;
@@ -266,8 +340,6 @@ __assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
layer then needs to take care of EAGAIN. No need to
specify a timeout - the socket is not expected to be in
blocking mode. */
- fd_set fds;
-
FD_ZERO (&fds);
FD_SET (HANDLE2SOCKET (fd), &fds);
select (0, &fds, NULL, NULL, NULL);