aboutsummaryrefslogtreecommitdiffstats
path: root/src/estream.c
diff options
context:
space:
mode:
authorNIIBE Yutaka <[email protected]>2022-04-04 04:54:49 +0000
committerNIIBE Yutaka <[email protected]>2022-04-04 04:54:49 +0000
commit018ea46a30cf4eda70070ba42c4fee642fb2fd8a (patch)
treebfc099c365b8e39d202a9c77bf3308a97c9547b1 /src/estream.c
parentw32: Fix handle_to_pid for MinGW-w64. (diff)
downloadlibgpg-error-018ea46a30cf4eda70070ba42c4fee642fb2fd8a.tar.gz
libgpg-error-018ea46a30cf4eda70070ba42c4fee642fb2fd8a.zip
w32: Add ES_SYSHD_SOCK support for gpgrt_sysopen.
* src/mkheader.c (write_special): Support @SOCKET_t@ substitution. * src/gpgrt-int.h (gpgrt_stream_backend_kind_t): Add BACKEND_SOCK. * src/gpg-error.h.in (struct _gpgrt_syshd): Use @SOCKET_t@. * src/estream.c [HAVE_W32_SYSTEM] (estream_cookie_sock_t): New. [HAVE_W32_SYSTEM] (func_sock_create, func_sock_read): New. [HAVE_W32_SYSTEM] (func_sock_write, func_sock_seek): New. [HAVE_W32_SYSTEM] (func_sock_destroy, func_sock_ioctl): New. [HAVE_W32_SYSTEM] (estream_functions_sock, do_sockopen): New. [HAVE_W32_SYSTEM] (do_sysopen): Call do_sockopen. -- Signed-off-by: NIIBE Yutaka <[email protected]>
Diffstat (limited to 'src/estream.c')
-rw-r--r--src/estream.c256
1 files changed, 255 insertions, 1 deletions
diff --git a/src/estream.c b/src/estream.c
index 0542f59..32f8f48 100644
--- a/src/estream.c
+++ b/src/estream.c
@@ -1197,12 +1197,214 @@ static struct cookie_io_functions_s estream_functions_fd =
};
+
+#ifdef HAVE_W32_SYSTEM
+/*
+ * Implementation of SOCKET based I/O.
+ */
+
+/* Cookie for SOCKET objects. */
+typedef struct estream_cookie_sock
+{
+ SOCKET sock; /* The SOCKET we are using for actual output. */
+ int no_close; /* If set we won't close the file descriptor. */
+ int nonblock; /* Non-blocking mode is enabled. */
+} *estream_cookie_sock_t;
+
+
+/*
+ * Create function for objects indentified by a libc file descriptor.
+ */
+static int
+func_sock_create (void **cookie, SOCKET sock,
+ unsigned int modeflags, int no_close)
+{
+ estream_cookie_sock_t sock_cookie;
+ int err;
+
+ trace (("enter: sock=%d mf=%x nc=%d", (int)sock, modeflags, no_close));
+
+ sock_cookie = mem_alloc (sizeof (*sock_cookie));
+ if (! sock_cookie)
+ err = -1;
+ else
+ {
+ sock_cookie->sock = sock;
+ sock_cookie->no_close = no_close;
+ sock_cookie->nonblock = !!(modeflags & O_NONBLOCK);
+ *cookie = sock_cookie;
+ err = 0;
+ }
+
+ trace_errno (err, ("leave: cookie=%p err=%d", *cookie, err));
+ return err;
+}
+
+
+/*
+ * Read function for SOCKET objects.
+ */
+static gpgrt_ssize_t
+func_sock_read (void *cookie, void *buffer, size_t size)
+
+{
+ estream_cookie_sock_t file_cookie = cookie;
+ gpgrt_ssize_t bytes_read;
+
+ trace (("enter: cookie=%p buffer=%p size=%d", cookie, buffer, (int)size));
+
+ if (!size)
+ bytes_read = -1; /* We don't know whether anything is pending. */
+ else if (IS_INVALID_FD (file_cookie->sock))
+ {
+ _gpgrt_yield ();
+ bytes_read = 0;
+ }
+ else
+ {
+ _gpgrt_pre_syscall ();
+ do
+ {
+ bytes_read = recv (file_cookie->sock, buffer, size, 0);
+ }
+ while (bytes_read == -1 && errno == EINTR);
+ _gpgrt_post_syscall ();
+ }
+ trace_errno (bytes_read == -1, ("leave: bytes_read=%d", (int)bytes_read));
+ return bytes_read;
+}
+
+
+/*
+ * Write function for SOCKET objects.
+ */
+static gpgrt_ssize_t
+func_sock_write (void *cookie, const void *buffer, size_t size)
+{
+ estream_cookie_sock_t file_cookie = cookie;
+ gpgrt_ssize_t bytes_written;
+
+ trace (("enter: cookie=%p buffer=%p size=%d", cookie, buffer, (int)size));
+
+ if (IS_INVALID_FD (file_cookie->sock))
+ {
+ _gpgrt_yield ();
+ bytes_written = size; /* Yeah: Success writing to the bit bucket. */
+ }
+ else if (buffer)
+ {
+ _gpgrt_pre_syscall ();
+ do
+ {
+ bytes_written = send (file_cookie->sock, buffer, size, 0);
+ }
+ while (bytes_written == -1 && errno == EINTR);
+ _gpgrt_post_syscall ();
+ }
+ else
+ bytes_written = size; /* Note that for a flush SIZE should be 0. */
+
+ trace_errno (bytes_written == -1,
+ ("leave: bytes_written=%d", (int)bytes_written));
+ return bytes_written;
+}
+
+
+/*
+ * Seek function for SOCKET objects.
+ */
+static int
+func_sock_seek (void *cookie, gpgrt_off_t *offset, int whence)
+{
+ (void)cookie;
+ (void)offset;
+ (void)whence;
+ _set_errno (ESPIPE);
+ return -1;
+}
+
+
+/*
+ * The IOCTL function for SOCKET objects.
+ */
+static int
+func_sock_ioctl (void *cookie, int cmd, void *ptr, size_t *len)
+{
+ estream_cookie_sock_t sock_cookie = cookie;
+ int ret;
+
+ if (cmd == COOKIE_IOCTL_NONBLOCK && !len)
+ {
+ sock_cookie->nonblock = !!ptr;
+ if (IS_INVALID_FD (sock_cookie->sock))
+ {
+ _set_errno (EINVAL);
+ ret = -1;
+ }
+ else
+ {
+ u_long mode = 0;
+
+ if (sock_cookie->nonblock)
+ mode = 1;
+
+ ret = ioctlsocket (sock_cookie->sock, FIONBIO, &mode);
+ }
+ }
+ else
+ {
+ _set_errno (EINVAL);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+/*
+ * The destroy function for SOCKET objects.
+ */
+static int
+func_sock_destroy (void *cookie)
+{
+ estream_cookie_sock_t sock_cookie = cookie;
+ int err;
+
+ trace (("enter: cookie=%p", cookie));
+
+ if (sock_cookie)
+ {
+ if (IS_INVALID_FD (sock_cookie->sock))
+ err = 0;
+ else
+ err = sock_cookie->no_close? 0 : closesocket (sock_cookie->sock);
+ mem_free (sock_cookie);
+ }
+ else
+ err = 0;
+
+ trace_errno (err,("leave: err=%d", err));
+ return err;
+}
+
+
+/*
+ * Access object for the fd functions.
+ */
+static struct cookie_io_functions_s estream_functions_sock =
+ {
+ {
+ func_sock_read,
+ func_sock_write,
+ func_sock_seek,
+ func_sock_destroy,
+ },
+ func_sock_ioctl,
+ };
/*
* Implementation of W32 handle based I/O.
*/
-#ifdef HAVE_W32_SYSTEM
/* Cookie for fd objects. */
typedef struct estream_cookie_w32
@@ -3645,6 +3847,53 @@ _gpgrt_fpopen_nc (FILE *fp, const char *mode)
#ifdef HAVE_W32_SYSTEM
+static estream_t
+do_sockopen (SOCKET sock, const char *mode, int no_close, int with_locked_list)
+{
+ int create_called = 0;
+ estream_t stream = NULL;
+ void *cookie = NULL;
+ unsigned int modeflags, xmode;
+ int err;
+ es_syshd_t syshd;
+
+ err = parse_mode (mode, &modeflags, &xmode, NULL);
+ if (err)
+ goto out;
+ if ((xmode & X_SYSOPEN))
+ {
+ /* Not allowed for sockopen. */
+ _set_errno (EINVAL);
+ err = -1;
+ goto out;
+ }
+
+ err = func_sock_create (&cookie, sock, modeflags, no_close);
+ if (err)
+ goto out;
+
+ syshd.type = ES_SYSHD_SOCK;
+ syshd.u.sock = sock;
+ create_called = 1;
+ err = create_stream (&stream, cookie, &syshd,
+ BACKEND_SOCK, estream_functions_sock,
+ modeflags, xmode, with_locked_list);
+
+ if (!err && stream)
+ {
+ if ((modeflags & O_NONBLOCK))
+ err = stream->intern->func_ioctl (cookie, COOKIE_IOCTL_NONBLOCK,
+ "", NULL);
+ }
+
+ out:
+ if (err && create_called)
+ (*estream_functions_sock.public.func_close) (cookie);
+
+ return stream;
+}
+
+
estream_t
do_w32open (HANDLE hd, const char *mode,
int no_close, int with_locked_list)
@@ -3692,11 +3941,16 @@ do_sysopen (es_syshd_t *syshd, const char *mode, int no_close)
switch (syshd->type)
{
case ES_SYSHD_FD:
+#ifndef HAVE_W32_SYSTEM
case ES_SYSHD_SOCK:
+#endif
stream = do_fdopen (syshd->u.fd, mode, no_close, 0);
break;
#ifdef HAVE_W32_SYSTEM
+ case ES_SYSHD_SOCK:
+ stream = do_sockopen (syshd->u.sock, mode, no_close, 0);
+ break;
case ES_SYSHD_HANDLE:
stream = do_w32open (syshd->u.handle, mode, no_close, 0);
break;