qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Daniel P. Berrange" <berrange@redhat.com>
To: qemu-devel@nongnu.org
Cc: Paolo Bonzini <pbonzini@redhat.com>,
	Andrew Baumann <Andrew.Baumann@microsoft.com>,
	Stefan Weil <sw@weilnetz.de>
Subject: [Qemu-devel] [PATCH v1 17/21] osdep: add wrappers for socket functions
Date: Wed,  9 Mar 2016 17:28:20 +0000	[thread overview]
Message-ID: <1457544504-8548-18-git-send-email-berrange@redhat.com> (raw)
In-Reply-To: <1457544504-8548-1-git-send-email-berrange@redhat.com>

The windows socket functions look identical to the normal POSIX
sockets functions, but instead of setting errno, the caller needs
to call WSAGetLastError(). QEMU has tried to deal with this
incompatibility by defining a socket_error() method that callers
must use that abstracts the difference between WSAGetLastError()
and errno.

This approach is somewhat error prone though - many callers of
the sockets functions are just using errno directly because it
is easy to forget the need use a QEMU specific wrapper. It is
not always immediately obvious that a particular function will
in fact call into Windows sockets functions, so the dev may not
even realize they need to use socket_error().

This introduces an alternative approach to portability inspired
by the way GNULIB fixes portability problems. We use a macro to
redefine the original socket function names to refer to a QEMU
wrapper function. The wrapper function calls the original Win32
sockets method and then sets errno from the WSAGetLastError()
value.

Thus all code can simply call the normal POSIX sockets APIs are
have standard errno reporting on error, even on Windows. This
makes the socket_error() method obsolete.

The only two methods which are non-trivial to handle are close()
and ioctl() since both of these logically apply both sockets and
regular file handles. The wrappers use a no-op getsockopt() call
to determine if the file handle is a socket or not, and thus
decide which underlying Win32 method to call.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 Makefile                  |   4 +-
 include/qemu/sockets.h    |  10 ---
 include/sysemu/os-posix.h |   6 ++
 include/sysemu/os-win32.h |  79 +++++++++++++++++
 util/oslib-win32.c        | 219 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 306 insertions(+), 12 deletions(-)

diff --git a/Makefile b/Makefile
index 70e3ebc..1d076a9 100644
--- a/Makefile
+++ b/Makefile
@@ -238,7 +238,7 @@ qemu-img$(EXESUF): qemu-img.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-o
 qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
 qemu-io$(EXESUF): qemu-io.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
 
-qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
+qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o libqemuutil.a libqemustub.a
 
 fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o libqemuutil.a libqemustub.a
 fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
@@ -329,7 +329,7 @@ ifneq ($(EXESUF),)
 qemu-ga: qemu-ga$(EXESUF) $(QGA_VSS_PROVIDER) $(QEMU_GA_MSI)
 endif
 
-ivshmem-client$(EXESUF): $(ivshmem-client-obj-y)
+ivshmem-client$(EXESUF): $(ivshmem-client-obj-y) libqemuutil.a libqemustub.a
 	$(call LINK, $^)
 ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) libqemuutil.a libqemustub.a
 	$(call LINK, $^)
diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
index 49499f2..fec2254 100644
--- a/include/qemu/sockets.h
+++ b/include/qemu/sockets.h
@@ -3,21 +3,11 @@
 #define QEMU_SOCKET_H
 
 #ifdef _WIN32
-#include <windows.h>
-#include <winsock2.h>
-#include <ws2tcpip.h>
 
 int inet_aton(const char *cp, struct in_addr *ia);
 
 #else
 
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/un.h>
-
 #define closesocket(s) close(s)
 
 #endif /* !_WIN32 */
diff --git a/include/sysemu/os-posix.h b/include/sysemu/os-posix.h
index e9fec2e..718f35e 100644
--- a/include/sysemu/os-posix.h
+++ b/include/sysemu/os-posix.h
@@ -26,6 +26,12 @@
 #ifndef QEMU_OS_POSIX_H
 #define QEMU_OS_POSIX_H
 
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/un.h>
 
 void os_set_line_buffering(void);
 void os_set_proc_name(const char *s);
diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h
index 239771d..97503ce 100644
--- a/include/sysemu/os-win32.h
+++ b/include/sysemu/os-win32.h
@@ -28,6 +28,7 @@
 
 #include <winsock2.h>
 #include <windows.h>
+#include <ws2tcpip.h>
 
 #if defined(_WIN64)
 /* On w64, setjmp is implemented by _setjmp which needs a second parameter.
@@ -104,4 +105,82 @@ static inline char *realpath(const char *path, char *resolved_path)
     return resolved_path;
 }
 
+
+/* We wrap all the sockets functions so that we can
+ * set errno based on WSAGetLastError()
+ */
+
+#undef connect
+#define connect qemu_connect_wrap
+int qemu_connect_wrap(int sockfd, const struct sockaddr *addr,
+                      socklen_t addrlen);
+
+#undef listen
+#define listen qemu_listen_wrap
+int qemu_listen_wrap(int sockfd, int backlog);
+
+#undef bind
+#define bind qemu_bind_wrap
+int qemu_bind_wrap(int sockfd, const struct sockaddr *addr,
+                   socklen_t addrlen);
+
+#undef socket
+#define socket qemu_socket_wrap
+int qemu_socket_wrap(int domain, int type, int protocol);
+
+#undef accept
+#define accept qemu_accept_wrap
+int qemu_accept_wrap(int sockfd, struct sockaddr *addr,
+                     socklen_t *addrlen);
+
+#undef shutdown
+#define shutdown qemu_shutdown_wrap
+int qemu_shutdown_wrap(int sockfd, int how);
+
+#undef ioctl
+#define ioctl qemu_ioctl_wrap
+int qemu_ioctl_wrap(int fd, int req, void *val);
+
+#undef close
+#define close qemu_close_wrap
+int qemu_close_wrap(int fd);
+
+#undef getsockopt
+#define getsockopt qemu_getsockopt_wrap
+int qemu_getsockopt_wrap(int sockfd, int level, int optname,
+                         void *optval, socklen_t *optlen);
+
+#undef setsockopt
+#define setsockopt qemu_setsockopt_wrap
+int qemu_setsockopt_wrap(int sockfd, int level, int optname,
+                         const void *optval, socklen_t optlen);
+
+#undef getpeername
+#define getpeername qemu_getpeername_wrap
+int qemu_getpeername_wrap(int sockfd, struct sockaddr *addr,
+                          socklen_t *addrlen);
+
+#undef getsockname
+#define getsockname qemu_getsockname_wrap
+int qemu_getsockname_wrap(int sockfd, struct sockaddr *addr,
+                          socklen_t *addrlen);
+
+#undef send
+#define send qemu_send_wrap
+ssize_t qemu_send_wrap(int sockfd, const void *buf, size_t len, int flags);
+
+#undef sendto
+#define sendto qemu_sendto_wrap
+ssize_t qemu_sendto_wrap(int sockfd, const void *buf, size_t len, int flags,
+                         const struct sockaddr *addr, socklen_t addrlen);
+
+#undef recv
+#define recv qemu_recv_wrap
+ssize_t qemu_recv_wrap(int sockfd, void *buf, size_t len, int flags);
+
+#undef recvfrom
+#define recvfrom qemu_recvfrom_wrap
+ssize_t qemu_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags,
+                           struct sockaddr *addr, socklen_t *addrlen);
+
 #endif
diff --git a/util/oslib-win32.c b/util/oslib-win32.c
index 37b143b..b8c9cbe 100644
--- a/util/oslib-win32.c
+++ b/util/oslib-win32.c
@@ -579,3 +579,222 @@ pid_t qemu_fork(Error **errp)
                      "cannot fork child process");
     return -1;
 }
+
+
+#undef connect
+int qemu_connect_wrap(int sockfd, const struct sockaddr *addr,
+                      socklen_t addrlen)
+{
+    int ret;
+    ret = connect(sockfd, addr, addrlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+
+#undef listen
+int qemu_listen_wrap(int sockfd, int backlog)
+{
+    int ret;
+    ret = listen(sockfd, backlog);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+
+#undef bind
+int qemu_bind_wrap(int sockfd, const struct sockaddr *addr,
+                   socklen_t addrlen)
+{
+    int ret;
+    ret = bind(sockfd, addr, addrlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+
+#undef socket
+int qemu_socket_wrap(int domain, int type, int protocol)
+{
+    int ret;
+    ret = socket(domain, type, protocol);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+
+#undef accept
+int qemu_accept_wrap(int sockfd, struct sockaddr *addr,
+                     socklen_t *addrlen)
+{
+    int ret;
+    ret = accept(sockfd, addr, addrlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+
+#undef shutdown
+int qemu_shutdown_wrap(int sockfd, int how)
+{
+    int ret;
+    ret = shutdown(sockfd, how);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+
+static bool qemu_is_socket(int fd)
+{
+    int optval = 0;
+    socklen_t optlen;
+    optlen = sizeof(optval);
+    return getsockopt(fd, SOL_SOCKET, SO_TYPE,
+                      (char *)&optval, &optlen) == 0;
+}
+
+#undef ioctl
+int qemu_ioctl_wrap(int fd, int req, void *val)
+{
+    int ret;
+    if (qemu_is_socket(fd)) {
+        ret = ioctlsocket(fd, req, val);
+        if (ret < 0) {
+            errno = socket_error();
+        }
+    } else {
+        errno = EINVAL;
+        ret = -1;
+    }
+    return ret;
+}
+
+
+#undef close
+int qemu_close_wrap(int fd)
+{
+    int ret;
+    if (qemu_is_socket(fd)) {
+        ret = closesocket(fd);
+        if (ret < 0) {
+            errno = socket_error();
+        }
+    } else {
+        ret = close(fd);
+    }
+    return ret;
+}
+
+
+#undef getsockopt
+int qemu_getsockopt_wrap(int sockfd, int level, int optname,
+                         void *optval, socklen_t *optlen)
+{
+    int ret;
+    ret = getsockopt(sockfd, level, optname, optval, optlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+
+#undef setsockopt
+int qemu_setsockopt_wrap(int sockfd, int level, int optname,
+                         const void *optval, socklen_t optlen)
+{
+    int ret;
+    ret = setsockopt(sockfd, level, optname, optval, optlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+
+#undef getpeername
+int qemu_getpeername_wrap(int sockfd, struct sockaddr *addr,
+                          socklen_t *addrlen)
+{
+    int ret;
+    ret = getpeername(sockfd, addr, addrlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+
+#undef getsockname
+int qemu_getsockname_wrap(int sockfd, struct sockaddr *addr,
+                          socklen_t *addrlen)
+{
+    int ret;
+    ret = getsockname(sockfd, addr, addrlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+
+#undef send
+ssize_t qemu_send_wrap(int sockfd, const void *buf, size_t len, int flags)
+{
+    int ret;
+    ret = send(sockfd, buf, len, flags);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+
+#undef sendto
+ssize_t qemu_sendto_wrap(int sockfd, const void *buf, size_t len, int flags,
+                         const struct sockaddr *addr, socklen_t addrlen)
+{
+    int ret;
+    ret = sendto(sockfd, buf, len, flags, addr, addrlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+
+#undef recv
+ssize_t qemu_recv_wrap(int sockfd, void *buf, size_t len, int flags)
+{
+    int ret;
+    ret = recv(sockfd, buf, len, flags);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+
+#undef recvfrom
+ssize_t qemu_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags,
+                           struct sockaddr *addr, socklen_t *addrlen)
+{
+    int ret;
+    ret = recvfrom(sockfd, buf, len, flags, addr, addrlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
-- 
2.5.0

  parent reply	other threads:[~2016-03-09 17:29 UTC|newest]

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-03-09 17:28 [Qemu-devel] [PATCH v1 00/21] Multiple fixes & improves to QIOChannel & Win32 Daniel P. Berrange
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 01/21] osdep: fix socket_error() to work with Mingw64 Daniel P. Berrange
2016-03-10 16:12   ` Paolo Bonzini
2016-03-10 16:13     ` Daniel P. Berrange
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 02/21] io: use bind() to check for IPv4/6 availability Daniel P. Berrange
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 03/21] io: initialize sockets in test program Daniel P. Berrange
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 04/21] io: bind to socket before creating QIOChannelSocket Daniel P. Berrange
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 05/21] io: wait for incoming client in socket test Daniel P. Berrange
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 06/21] io: set correct error object in background reader test thread Daniel P. Berrange
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 07/21] io: assert errors before asserting content in I/O test Daniel P. Berrange
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 08/21] io: fix copy+paste mistake in socket error message Daniel P. Berrange
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 09/21] io: add missing EWOULDBLOCK checks in Win32 I/O code paths Daniel P. Berrange
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 10/21] io: pass HANDLE to g_source_add_poll on Win32 Daniel P. Berrange
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 11/21] io: introduce qio_channel_create_socket_watch Daniel P. Berrange
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 12/21] io: implement socket watch for win32 using WSAEventSelect+select Daniel P. Berrange
2016-03-09 17:47   ` Paolo Bonzini
2016-03-09 19:59     ` Eric Blake
2016-03-09 21:24       ` Paolo Bonzini
2016-03-10  9:41         ` Daniel P. Berrange
2016-03-10  9:54           ` Paolo Bonzini
2016-03-10 16:30             ` Eric Blake
2016-03-10 14:50     ` Daniel P. Berrange
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 13/21] char: ensure listener socket is in blocking mode when waiting Daniel P. Berrange
2016-03-09 17:48   ` Paolo Bonzini
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 14/21] char: remove qemu_chr_finish_socket_connection method Daniel P. Berrange
2016-03-09 17:49   ` Paolo Bonzini
2016-03-10 14:50     ` Daniel P. Berrange
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 15/21] char: remove socket_try_connect method Daniel P. Berrange
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 16/21] char: remove qemu_chr_open_socket_fd method Daniel P. Berrange
2016-03-09 17:53   ` Paolo Bonzini
2016-03-10 14:51     ` Daniel P. Berrange
2016-03-09 17:28 ` Daniel P. Berrange [this message]
2016-03-09 18:04   ` [Qemu-devel] [PATCH v1 17/21] osdep: add wrappers for socket functions Paolo Bonzini
2016-03-10 14:52     ` Daniel P. Berrange
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 18/21] osdep: remove use of Win32 specific closesocket/ioctlsocket Daniel P. Berrange
2016-03-10 14:53   ` Daniel P. Berrange
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 19/21] osdep: remove use of socket_error() from all code Daniel P. Berrange
2016-03-09 17:59   ` Paolo Bonzini
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 20/21] osdep: remove direct use of qemu_socket & qemu_accept Daniel P. Berrange
2016-03-09 18:00   ` Paolo Bonzini
2016-03-09 17:28 ` [Qemu-devel] [PATCH v1 21/21] error: ensure errno detail is printed with error_abort Daniel P. Berrange
2016-03-09 18:01   ` Paolo Bonzini
2016-03-10  8:55   ` Markus Armbruster
2016-03-10  9:40     ` Daniel P. Berrange
2016-03-10 20:36       ` Markus Armbruster
2016-03-09 18:06 ` [Qemu-devel] [PATCH v1 00/21] Multiple fixes & improves to QIOChannel & Win32 Paolo Bonzini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1457544504-8548-18-git-send-email-berrange@redhat.com \
    --to=berrange@redhat.com \
    --cc=Andrew.Baumann@microsoft.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=sw@weilnetz.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).