osdep: add wrappers for socket functions

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.

We also bring closesocket & ioctlsocket into this approach. Even
though they are non-standard Win32 names, we can't wrap the normal
close/ioctl methods since there's no reliable way to distinguish
between a file descriptor and HANDLE in Win32.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrange 2016-03-07 20:25:19 +00:00
parent 08b758b482
commit a2d96af4bb
7 changed files with 291 additions and 19 deletions

View File

@ -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, $^)

View File

@ -3,23 +3,9 @@
#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 */
#include "qapi-types.h"

View File

@ -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);
@ -36,6 +42,9 @@ int os_mlock(void);
#define socket_error() errno
#define closesocket(s) close(s)
#define ioctlsocket(s, r, v) ioctl(s, r, v)
typedef struct timeval qemu_timeval;
#define qemu_gettimeofday(tp) gettimeofday(tp, NULL)

View File

@ -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 ioctlsocket
#define ioctlsocket qemu_ioctlsocket_wrap
int qemu_ioctlsocket_wrap(int fd, int req, void *val);
#undef closesocket
#define closesocket qemu_closesocket_wrap
int qemu_closesocket_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

View File

@ -38,7 +38,6 @@
#include "qemu.h"
#include "flat.h"
#define ntohl(x) be32_to_cpu(x)
#include <target_flat.h>
//#define DEBUG

View File

@ -14,8 +14,6 @@ typedef char *caddr_t;
# include <iphlpapi.h>
#else
# define ioctlsocket ioctl
# define closesocket(s) close(s)
# if !defined(__HAIKU__)
# define O_BINARY 0
# endif

View File

@ -581,3 +581,204 @@ 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;
}
#undef ioctlsocket
int qemu_ioctlsocket_wrap(int fd, int req, void *val)
{
int ret;
ret = ioctlsocket(fd, req, val);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#undef closesocket
int qemu_closesocket_wrap(int fd)
{
int ret;
ret = closesocket(fd);
if (ret < 0) {
errno = socket_error();
}
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;
}