mirror of https://github.com/xqemu/xqemu.git
Merge I/O fixes for win32
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJW4pfoAAoJEL6G67QVEE/f4aIP/11yDBAZxNDglEQofcPltuAP 3jEk4FHTyCWoDroXdrAjK9jqvRHSmmMD5IbpTmdWZqyvhaD/nE8sZjYuDf7NbYow KG5TnC1C6xKj8sYCxUIDiTYSZLFPUXkGDpg8QHeANcGkoWzqF8UTVLxCd1TpeZR3 XKGFb5HTNQlgBWy0sdN5UnqlelmYn3fsL9fcW3Tub8Sl7idaIa6l4IksOIgTfobH jkio5w0nE84VA/kHOGUDhvwQLDKa/ioI74WpvG4cJ5MDC/c9k57Er6ja6iuFdn2u Xtp36m/Nh4gDcn3CEBAwcYvtnfR7F+AVwKu9KUYYgSjcemaXHprPgaYXz8iGHMLY NEl2TNV3aLrd8aisSMgeJl6CYJUxCZBlY7Pbaqk2CTJ+C9Vm1ToQ9rYVXNRF0sTz w5FcVkHEw+zcfRn6uEY8Y+5258Qgj/XuyakNPJQh47ssfEj4FWfWa2aF6QPzc903 hRmdXualRICtXc+yWwkntW25/0fCC+c1kMDf94KFeD6XAXE1rdeBRQqq4Yhhzk31 k2dbOz1lQkE9aZoRZ9iLkROZNQWsnanagVOlpTwJxZqCwt6Km1GqD8F2CzBj80lr p2wVH6wkNnMKRW02lwhrQcik2ICv05Ol1E4OZUPNOfha5tzqGnajEaPvLCRixKAj 97H8w8+PtaIa5l+YhTxl =QBFp -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/berrange/tags/pull-io-win32-2016-03-11-1' into staging Merge I/O fixes for win32 # gpg: Signature made Fri 11 Mar 2016 10:03:20 GMT using RSA key ID 15104FDF # gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" # gpg: aka "Daniel P. Berrange <berrange@redhat.com>" * remotes/berrange/tags/pull-io-win32-2016-03-11-1: osdep: remove use of socket_error() from all code osdep: add wrappers for socket functions char: remove qemu_chr_open_socket_fd method char: remove socket_try_connect method char: remove qemu_chr_finish_socket_connection method io: implement socket watch for win32 using WSAEventSelect+select io: remove checking of EWOULDBLOCK io: use qemu_accept to ensure SOCK_CLOEXEC is set io: introduce qio_channel_create_socket_watch io: pass HANDLE to g_source_add_poll on Win32 io: fix copy+paste mistake in socket error message io: assert errors before asserting content in I/O test io: set correct error object in background reader test thread io: wait for incoming client in socket test io: bind to socket before creating QIOChannelSocket io: initialize sockets in test program io: use bind() to check for IPv4/6 availability osdep: fix socket_error() to work with Mingw64 Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
8326ec2c83
4
Makefile
4
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-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-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): 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
|
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
|
||||||
|
@ -329,7 +329,7 @@ ifneq ($(EXESUF),)
|
||||||
qemu-ga: qemu-ga$(EXESUF) $(QGA_VSS_PROVIDER) $(QEMU_GA_MSI)
|
qemu-ga: qemu-ga$(EXESUF) $(QGA_VSS_PROVIDER) $(QEMU_GA_MSI)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ivshmem-client$(EXESUF): $(ivshmem-client-obj-y)
|
ivshmem-client$(EXESUF): $(ivshmem-client-obj-y) libqemuutil.a libqemustub.a
|
||||||
$(call LINK, $^)
|
$(call LINK, $^)
|
||||||
ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) libqemuutil.a libqemustub.a
|
ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) libqemuutil.a libqemustub.a
|
||||||
$(call LINK, $^)
|
$(call LINK, $^)
|
||||||
|
|
|
@ -615,14 +615,13 @@ static coroutine_fn int send_co_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||||
ret = qemu_co_send(sockfd, hdr, sizeof(*hdr));
|
ret = qemu_co_send(sockfd, hdr, sizeof(*hdr));
|
||||||
if (ret != sizeof(*hdr)) {
|
if (ret != sizeof(*hdr)) {
|
||||||
error_report("failed to send a req, %s", strerror(errno));
|
error_report("failed to send a req, %s", strerror(errno));
|
||||||
ret = -socket_error();
|
return -errno;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qemu_co_send(sockfd, data, *wlen);
|
ret = qemu_co_send(sockfd, data, *wlen);
|
||||||
if (ret != *wlen) {
|
if (ret != *wlen) {
|
||||||
ret = -socket_error();
|
|
||||||
error_report("failed to send a req, %s", strerror(errno));
|
error_report("failed to send a req, %s", strerror(errno));
|
||||||
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
* monitor the file descriptor @fd for the
|
* monitor the file descriptor @fd for the
|
||||||
* I/O conditions in @condition. This is able
|
* I/O conditions in @condition. This is able
|
||||||
* monitor block devices, character devices,
|
* monitor block devices, character devices,
|
||||||
* sockets, pipes but not plain files.
|
* pipes but not plain files or, on Win32, sockets.
|
||||||
*
|
*
|
||||||
* Returns: the new main loop source
|
* Returns: the new main loop source
|
||||||
*/
|
*/
|
||||||
|
@ -47,6 +47,24 @@ GSource *qio_channel_create_fd_watch(QIOChannel *ioc,
|
||||||
int fd,
|
int fd,
|
||||||
GIOCondition condition);
|
GIOCondition condition);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qio_channel_create_socket_watch:
|
||||||
|
* @ioc: the channel object
|
||||||
|
* @fd: the file descriptor
|
||||||
|
* @condition: the I/O condition
|
||||||
|
*
|
||||||
|
* Create a new main loop source that is able to
|
||||||
|
* monitor the file descriptor @fd for the
|
||||||
|
* I/O conditions in @condition. This is equivalent
|
||||||
|
* to qio_channel_create_fd_watch on POSIX systems
|
||||||
|
* but not on Windows.
|
||||||
|
*
|
||||||
|
* Returns: the new main loop source
|
||||||
|
*/
|
||||||
|
GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
|
||||||
|
int fd,
|
||||||
|
GIOCondition condition);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qio_channel_create_fd_pair_watch:
|
* qio_channel_create_fd_pair_watch:
|
||||||
* @ioc: the channel object
|
* @ioc: the channel object
|
||||||
|
|
|
@ -78,6 +78,9 @@ typedef gboolean (*QIOChannelFunc)(QIOChannel *ioc,
|
||||||
struct QIOChannel {
|
struct QIOChannel {
|
||||||
Object parent;
|
Object parent;
|
||||||
unsigned int features; /* bitmask of QIOChannelFeatures */
|
unsigned int features; /* bitmask of QIOChannelFeatures */
|
||||||
|
#ifdef _WIN32
|
||||||
|
HANDLE event; /* For use with GSource on Win32 */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3,26 +3,9 @@
|
||||||
#define QEMU_SOCKET_H
|
#define QEMU_SOCKET_H
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
|
||||||
#include <winsock2.h>
|
|
||||||
#include <ws2tcpip.h>
|
|
||||||
|
|
||||||
#define socket_error() WSAGetLastError()
|
|
||||||
|
|
||||||
int inet_aton(const char *cp, struct in_addr *ia);
|
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 socket_error() errno
|
|
||||||
#define closesocket(s) close(s)
|
|
||||||
|
|
||||||
#endif /* !_WIN32 */
|
#endif /* !_WIN32 */
|
||||||
|
|
||||||
#include "qapi-types.h"
|
#include "qapi-types.h"
|
||||||
|
|
|
@ -26,6 +26,12 @@
|
||||||
#ifndef QEMU_OS_POSIX_H
|
#ifndef QEMU_OS_POSIX_H
|
||||||
#define 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_line_buffering(void);
|
||||||
void os_set_proc_name(const char *s);
|
void os_set_proc_name(const char *s);
|
||||||
|
@ -34,6 +40,9 @@ void os_daemonize(void);
|
||||||
void os_setup_post(void);
|
void os_setup_post(void);
|
||||||
int os_mlock(void);
|
int os_mlock(void);
|
||||||
|
|
||||||
|
#define closesocket(s) close(s)
|
||||||
|
#define ioctlsocket(s, r, v) ioctl(s, r, v)
|
||||||
|
|
||||||
typedef struct timeval qemu_timeval;
|
typedef struct timeval qemu_timeval;
|
||||||
#define qemu_gettimeofday(tp) gettimeofday(tp, NULL)
|
#define qemu_gettimeofday(tp) gettimeofday(tp, NULL)
|
||||||
|
|
||||||
|
|
|
@ -28,32 +28,7 @@
|
||||||
|
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
/* Workaround for older versions of MinGW. */
|
|
||||||
#ifndef ECONNREFUSED
|
|
||||||
# define ECONNREFUSED WSAECONNREFUSED
|
|
||||||
#endif
|
|
||||||
#ifndef EINPROGRESS
|
|
||||||
# define EINPROGRESS WSAEINPROGRESS
|
|
||||||
#endif
|
|
||||||
#ifndef EHOSTUNREACH
|
|
||||||
# define EHOSTUNREACH WSAEHOSTUNREACH
|
|
||||||
#endif
|
|
||||||
#ifndef EINTR
|
|
||||||
# define EINTR WSAEINTR
|
|
||||||
#endif
|
|
||||||
#ifndef EINPROGRESS
|
|
||||||
# define EINPROGRESS WSAEINPROGRESS
|
|
||||||
#endif
|
|
||||||
#ifndef ENETUNREACH
|
|
||||||
# define ENETUNREACH WSAENETUNREACH
|
|
||||||
#endif
|
|
||||||
#ifndef ENOTCONN
|
|
||||||
# define ENOTCONN WSAENOTCONN
|
|
||||||
#endif
|
|
||||||
#ifndef EWOULDBLOCK
|
|
||||||
# define EWOULDBLOCK WSAEWOULDBLOCK
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
/* On w64, setjmp is implemented by _setjmp which needs a second parameter.
|
/* On w64, setjmp is implemented by _setjmp which needs a second parameter.
|
||||||
|
@ -80,7 +55,6 @@ struct tm *gmtime_r(const time_t *timep, struct tm *result);
|
||||||
struct tm *localtime_r(const time_t *timep, struct tm *result);
|
struct tm *localtime_r(const time_t *timep, struct tm *result);
|
||||||
#endif /* CONFIG_LOCALTIME_R */
|
#endif /* CONFIG_LOCALTIME_R */
|
||||||
|
|
||||||
|
|
||||||
static inline void os_setup_signal_handling(void) {}
|
static inline void os_setup_signal_handling(void) {}
|
||||||
static inline void os_daemonize(void) {}
|
static inline void os_daemonize(void) {}
|
||||||
static inline void os_setup_post(void) {}
|
static inline void os_setup_post(void) {}
|
||||||
|
@ -129,4 +103,82 @@ static inline char *realpath(const char *path, char *resolved_path)
|
||||||
return 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
|
#endif
|
||||||
|
|
|
@ -236,8 +236,7 @@ static ssize_t qio_channel_command_readv(QIOChannel *ioc,
|
||||||
retry:
|
retry:
|
||||||
ret = readv(cioc->readfd, iov, niov);
|
ret = readv(cioc->readfd, iov, niov);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (errno == EAGAIN ||
|
if (errno == EAGAIN) {
|
||||||
errno == EWOULDBLOCK) {
|
|
||||||
return QIO_CHANNEL_ERR_BLOCK;
|
return QIO_CHANNEL_ERR_BLOCK;
|
||||||
}
|
}
|
||||||
if (errno == EINTR) {
|
if (errno == EINTR) {
|
||||||
|
@ -265,8 +264,7 @@ static ssize_t qio_channel_command_writev(QIOChannel *ioc,
|
||||||
retry:
|
retry:
|
||||||
ret = writev(cioc->writefd, iov, niov);
|
ret = writev(cioc->writefd, iov, niov);
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
if (errno == EAGAIN ||
|
if (errno == EAGAIN) {
|
||||||
errno == EWOULDBLOCK) {
|
|
||||||
return QIO_CHANNEL_ERR_BLOCK;
|
return QIO_CHANNEL_ERR_BLOCK;
|
||||||
}
|
}
|
||||||
if (errno == EINTR) {
|
if (errno == EINTR) {
|
||||||
|
|
|
@ -96,8 +96,7 @@ static ssize_t qio_channel_file_readv(QIOChannel *ioc,
|
||||||
retry:
|
retry:
|
||||||
ret = readv(fioc->fd, iov, niov);
|
ret = readv(fioc->fd, iov, niov);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (errno == EAGAIN ||
|
if (errno == EAGAIN) {
|
||||||
errno == EWOULDBLOCK) {
|
|
||||||
return QIO_CHANNEL_ERR_BLOCK;
|
return QIO_CHANNEL_ERR_BLOCK;
|
||||||
}
|
}
|
||||||
if (errno == EINTR) {
|
if (errno == EINTR) {
|
||||||
|
@ -125,8 +124,7 @@ static ssize_t qio_channel_file_writev(QIOChannel *ioc,
|
||||||
retry:
|
retry:
|
||||||
ret = writev(fioc->fd, iov, niov);
|
ret = writev(fioc->fd, iov, niov);
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
if (errno == EAGAIN ||
|
if (errno == EAGAIN) {
|
||||||
errno == EWOULDBLOCK) {
|
|
||||||
return QIO_CHANNEL_ERR_BLOCK;
|
return QIO_CHANNEL_ERR_BLOCK;
|
||||||
}
|
}
|
||||||
if (errno == EINTR) {
|
if (errno == EINTR) {
|
||||||
|
|
|
@ -55,6 +55,10 @@ qio_channel_socket_new(void)
|
||||||
ioc = QIO_CHANNEL(sioc);
|
ioc = QIO_CHANNEL(sioc);
|
||||||
ioc->features |= (1 << QIO_CHANNEL_FEATURE_SHUTDOWN);
|
ioc->features |= (1 << QIO_CHANNEL_FEATURE_SHUTDOWN);
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
ioc->event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
trace_qio_channel_socket_new(sioc);
|
trace_qio_channel_socket_new(sioc);
|
||||||
|
|
||||||
return sioc;
|
return sioc;
|
||||||
|
@ -78,11 +82,11 @@ qio_channel_socket_set_fd(QIOChannelSocket *sioc,
|
||||||
|
|
||||||
if (getpeername(fd, (struct sockaddr *)&sioc->remoteAddr,
|
if (getpeername(fd, (struct sockaddr *)&sioc->remoteAddr,
|
||||||
&sioc->remoteAddrLen) < 0) {
|
&sioc->remoteAddrLen) < 0) {
|
||||||
if (socket_error() == ENOTCONN) {
|
if (errno == ENOTCONN) {
|
||||||
memset(&sioc->remoteAddr, 0, sizeof(sioc->remoteAddr));
|
memset(&sioc->remoteAddr, 0, sizeof(sioc->remoteAddr));
|
||||||
sioc->remoteAddrLen = sizeof(sioc->remoteAddr);
|
sioc->remoteAddrLen = sizeof(sioc->remoteAddr);
|
||||||
} else {
|
} else {
|
||||||
error_setg_errno(errp, socket_error(),
|
error_setg_errno(errp, errno,
|
||||||
"Unable to query remote socket address");
|
"Unable to query remote socket address");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -90,7 +94,7 @@ qio_channel_socket_set_fd(QIOChannelSocket *sioc,
|
||||||
|
|
||||||
if (getsockname(fd, (struct sockaddr *)&sioc->localAddr,
|
if (getsockname(fd, (struct sockaddr *)&sioc->localAddr,
|
||||||
&sioc->localAddrLen) < 0) {
|
&sioc->localAddrLen) < 0) {
|
||||||
error_setg_errno(errp, socket_error(),
|
error_setg_errno(errp, errno,
|
||||||
"Unable to query local socket address");
|
"Unable to query local socket address");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -341,13 +345,18 @@ qio_channel_socket_accept(QIOChannelSocket *ioc,
|
||||||
cioc->remoteAddrLen = sizeof(ioc->remoteAddr);
|
cioc->remoteAddrLen = sizeof(ioc->remoteAddr);
|
||||||
cioc->localAddrLen = sizeof(ioc->localAddr);
|
cioc->localAddrLen = sizeof(ioc->localAddr);
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
QIO_CHANNEL(cioc)->event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
trace_qio_channel_socket_accept(ioc);
|
trace_qio_channel_socket_accept(ioc);
|
||||||
cioc->fd = accept(ioc->fd, (struct sockaddr *)&cioc->remoteAddr,
|
cioc->fd = qemu_accept(ioc->fd, (struct sockaddr *)&cioc->remoteAddr,
|
||||||
&cioc->remoteAddrLen);
|
&cioc->remoteAddrLen);
|
||||||
if (cioc->fd < 0) {
|
if (cioc->fd < 0) {
|
||||||
trace_qio_channel_socket_accept_fail(ioc);
|
trace_qio_channel_socket_accept_fail(ioc);
|
||||||
if (socket_error() == EINTR) {
|
if (errno == EINTR) {
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -355,7 +364,7 @@ qio_channel_socket_accept(QIOChannelSocket *ioc,
|
||||||
|
|
||||||
if (getsockname(cioc->fd, (struct sockaddr *)&cioc->localAddr,
|
if (getsockname(cioc->fd, (struct sockaddr *)&cioc->localAddr,
|
||||||
&cioc->localAddrLen) < 0) {
|
&cioc->localAddrLen) < 0) {
|
||||||
error_setg_errno(errp, socket_error(),
|
error_setg_errno(errp, errno,
|
||||||
"Unable to query local socket address");
|
"Unable to query local socket address");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -384,7 +393,10 @@ static void qio_channel_socket_finalize(Object *obj)
|
||||||
{
|
{
|
||||||
QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(obj);
|
QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(obj);
|
||||||
if (ioc->fd != -1) {
|
if (ioc->fd != -1) {
|
||||||
close(ioc->fd);
|
#ifdef WIN32
|
||||||
|
WSAEventSelect(ioc->fd, NULL, 0);
|
||||||
|
#endif
|
||||||
|
closesocket(ioc->fd);
|
||||||
ioc->fd = -1;
|
ioc->fd = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -466,15 +478,14 @@ static ssize_t qio_channel_socket_readv(QIOChannel *ioc,
|
||||||
retry:
|
retry:
|
||||||
ret = recvmsg(sioc->fd, &msg, sflags);
|
ret = recvmsg(sioc->fd, &msg, sflags);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (socket_error() == EAGAIN ||
|
if (errno == EAGAIN) {
|
||||||
socket_error() == EWOULDBLOCK) {
|
|
||||||
return QIO_CHANNEL_ERR_BLOCK;
|
return QIO_CHANNEL_ERR_BLOCK;
|
||||||
}
|
}
|
||||||
if (socket_error() == EINTR) {
|
if (errno == EINTR) {
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_setg_errno(errp, socket_error(),
|
error_setg_errno(errp, errno,
|
||||||
"Unable to read from socket");
|
"Unable to read from socket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -526,14 +537,13 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc,
|
||||||
retry:
|
retry:
|
||||||
ret = sendmsg(sioc->fd, &msg, 0);
|
ret = sendmsg(sioc->fd, &msg, 0);
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
if (socket_error() == EAGAIN ||
|
if (errno == EAGAIN) {
|
||||||
socket_error() == EWOULDBLOCK) {
|
|
||||||
return QIO_CHANNEL_ERR_BLOCK;
|
return QIO_CHANNEL_ERR_BLOCK;
|
||||||
}
|
}
|
||||||
if (socket_error() == EINTR) {
|
if (errno == EINTR) {
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
error_setg_errno(errp, socket_error(),
|
error_setg_errno(errp, errno,
|
||||||
"Unable to write to socket");
|
"Unable to write to socket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -559,17 +569,17 @@ static ssize_t qio_channel_socket_readv(QIOChannel *ioc,
|
||||||
iov[i].iov_len,
|
iov[i].iov_len,
|
||||||
0);
|
0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (socket_error() == EAGAIN) {
|
if (errno == EAGAIN) {
|
||||||
if (done) {
|
if (done) {
|
||||||
return done;
|
return done;
|
||||||
} else {
|
} else {
|
||||||
return QIO_CHANNEL_ERR_BLOCK;
|
return QIO_CHANNEL_ERR_BLOCK;
|
||||||
}
|
}
|
||||||
} else if (socket_error() == EINTR) {
|
} else if (errno == EINTR) {
|
||||||
goto retry;
|
goto retry;
|
||||||
} else {
|
} else {
|
||||||
error_setg_errno(errp, socket_error(),
|
error_setg_errno(errp, errno,
|
||||||
"Unable to write to socket");
|
"Unable to read from socket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -601,16 +611,16 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc,
|
||||||
iov[i].iov_len,
|
iov[i].iov_len,
|
||||||
0);
|
0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (socket_error() == EAGAIN) {
|
if (errno == EAGAIN) {
|
||||||
if (done) {
|
if (done) {
|
||||||
return done;
|
return done;
|
||||||
} else {
|
} else {
|
||||||
return QIO_CHANNEL_ERR_BLOCK;
|
return QIO_CHANNEL_ERR_BLOCK;
|
||||||
}
|
}
|
||||||
} else if (socket_error() == EINTR) {
|
} else if (errno == EINTR) {
|
||||||
goto retry;
|
goto retry;
|
||||||
} else {
|
} else {
|
||||||
error_setg_errno(errp, socket_error(),
|
error_setg_errno(errp, errno,
|
||||||
"Unable to write to socket");
|
"Unable to write to socket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -636,6 +646,11 @@ qio_channel_socket_set_blocking(QIOChannel *ioc,
|
||||||
qemu_set_block(sioc->fd);
|
qemu_set_block(sioc->fd);
|
||||||
} else {
|
} else {
|
||||||
qemu_set_nonblock(sioc->fd);
|
qemu_set_nonblock(sioc->fd);
|
||||||
|
#ifdef WIN32
|
||||||
|
WSAEventSelect(sioc->fd, ioc->event,
|
||||||
|
FD_READ | FD_ACCEPT | FD_CLOSE |
|
||||||
|
FD_CONNECT | FD_WRITE | FD_OOB);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -671,13 +686,18 @@ qio_channel_socket_close(QIOChannel *ioc,
|
||||||
{
|
{
|
||||||
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
|
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
|
||||||
|
|
||||||
if (closesocket(sioc->fd) < 0) {
|
if (sioc->fd != -1) {
|
||||||
|
#ifdef WIN32
|
||||||
|
WSAEventSelect(sioc->fd, NULL, 0);
|
||||||
|
#endif
|
||||||
|
if (closesocket(sioc->fd) < 0) {
|
||||||
|
sioc->fd = -1;
|
||||||
|
error_setg_errno(errp, errno,
|
||||||
|
"Unable to close socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
sioc->fd = -1;
|
sioc->fd = -1;
|
||||||
error_setg_errno(errp, socket_error(),
|
|
||||||
"Unable to close socket");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
sioc->fd = -1;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -703,7 +723,7 @@ qio_channel_socket_shutdown(QIOChannel *ioc,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shutdown(sioc->fd, sockhow) < 0) {
|
if (shutdown(sioc->fd, sockhow) < 0) {
|
||||||
error_setg_errno(errp, socket_error(),
|
error_setg_errno(errp, errno,
|
||||||
"Unable to shutdown socket");
|
"Unable to shutdown socket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -714,9 +734,9 @@ static GSource *qio_channel_socket_create_watch(QIOChannel *ioc,
|
||||||
GIOCondition condition)
|
GIOCondition condition)
|
||||||
{
|
{
|
||||||
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
|
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
|
||||||
return qio_channel_create_fd_watch(ioc,
|
return qio_channel_create_socket_watch(ioc,
|
||||||
sioc->fd,
|
sioc->fd,
|
||||||
condition);
|
condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qio_channel_socket_class_init(ObjectClass *klass,
|
static void qio_channel_socket_class_init(ObjectClass *klass,
|
||||||
|
|
|
@ -30,6 +30,20 @@ struct QIOChannelFDSource {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIN32
|
||||||
|
typedef struct QIOChannelSocketSource QIOChannelSocketSource;
|
||||||
|
struct QIOChannelSocketSource {
|
||||||
|
GSource parent;
|
||||||
|
GPollFD fd;
|
||||||
|
QIOChannel *ioc;
|
||||||
|
SOCKET socket;
|
||||||
|
int revents;
|
||||||
|
GIOCondition condition;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
typedef struct QIOChannelFDPairSource QIOChannelFDPairSource;
|
typedef struct QIOChannelFDPairSource QIOChannelFDPairSource;
|
||||||
struct QIOChannelFDPairSource {
|
struct QIOChannelFDPairSource {
|
||||||
GSource parent;
|
GSource parent;
|
||||||
|
@ -82,6 +96,97 @@ qio_channel_fd_source_finalize(GSource *source)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIN32
|
||||||
|
static gboolean
|
||||||
|
qio_channel_socket_source_prepare(GSource *source G_GNUC_UNUSED,
|
||||||
|
gint *timeout)
|
||||||
|
{
|
||||||
|
*timeout = -1;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NB, this impl only works when the socket is in non-blocking
|
||||||
|
* mode on Win32
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
qio_channel_socket_source_check(GSource *source)
|
||||||
|
{
|
||||||
|
static struct timeval tv0;
|
||||||
|
|
||||||
|
QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
|
||||||
|
WSANETWORKEVENTS ev;
|
||||||
|
fd_set rfds, wfds, xfds;
|
||||||
|
|
||||||
|
if (!ssource->condition) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
WSAEnumNetworkEvents(ssource->socket, ssource->ioc->event, &ev);
|
||||||
|
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_ZERO(&wfds);
|
||||||
|
FD_ZERO(&xfds);
|
||||||
|
if (ssource->condition & G_IO_IN) {
|
||||||
|
FD_SET((SOCKET)ssource->socket, &rfds);
|
||||||
|
}
|
||||||
|
if (ssource->condition & G_IO_OUT) {
|
||||||
|
FD_SET((SOCKET)ssource->socket, &wfds);
|
||||||
|
}
|
||||||
|
if (ssource->condition & G_IO_PRI) {
|
||||||
|
FD_SET((SOCKET)ssource->socket, &xfds);
|
||||||
|
}
|
||||||
|
ssource->revents = 0;
|
||||||
|
if (select(0, &rfds, &wfds, &xfds, &tv0) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FD_ISSET(ssource->socket, &rfds)) {
|
||||||
|
ssource->revents |= G_IO_IN;
|
||||||
|
}
|
||||||
|
if (FD_ISSET(ssource->socket, &wfds)) {
|
||||||
|
ssource->revents |= G_IO_OUT;
|
||||||
|
}
|
||||||
|
if (FD_ISSET(ssource->socket, &xfds)) {
|
||||||
|
ssource->revents |= G_IO_PRI;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ssource->revents;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
qio_channel_socket_source_dispatch(GSource *source,
|
||||||
|
GSourceFunc callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
QIOChannelFunc func = (QIOChannelFunc)callback;
|
||||||
|
QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
|
||||||
|
|
||||||
|
return (*func)(ssource->ioc, ssource->revents, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
qio_channel_socket_source_finalize(GSource *source)
|
||||||
|
{
|
||||||
|
QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
|
||||||
|
|
||||||
|
object_unref(OBJECT(ssource->ioc));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GSourceFuncs qio_channel_socket_source_funcs = {
|
||||||
|
qio_channel_socket_source_prepare,
|
||||||
|
qio_channel_socket_source_check,
|
||||||
|
qio_channel_socket_source_dispatch,
|
||||||
|
qio_channel_socket_source_finalize
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
qio_channel_fd_pair_source_prepare(GSource *source G_GNUC_UNUSED,
|
qio_channel_fd_pair_source_prepare(GSource *source G_GNUC_UNUSED,
|
||||||
gint *timeout)
|
gint *timeout)
|
||||||
|
@ -160,7 +265,11 @@ GSource *qio_channel_create_fd_watch(QIOChannel *ioc,
|
||||||
|
|
||||||
ssource->condition = condition;
|
ssource->condition = condition;
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIN32
|
||||||
|
ssource->fd.fd = (gint64)_get_osfhandle(fd);
|
||||||
|
#else
|
||||||
ssource->fd.fd = fd;
|
ssource->fd.fd = fd;
|
||||||
|
#endif
|
||||||
ssource->fd.events = condition;
|
ssource->fd.events = condition;
|
||||||
|
|
||||||
g_source_add_poll(source, &ssource->fd);
|
g_source_add_poll(source, &ssource->fd);
|
||||||
|
@ -168,6 +277,40 @@ GSource *qio_channel_create_fd_watch(QIOChannel *ioc,
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIN32
|
||||||
|
GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
|
||||||
|
int socket,
|
||||||
|
GIOCondition condition)
|
||||||
|
{
|
||||||
|
GSource *source;
|
||||||
|
QIOChannelSocketSource *ssource;
|
||||||
|
|
||||||
|
source = g_source_new(&qio_channel_socket_source_funcs,
|
||||||
|
sizeof(QIOChannelSocketSource));
|
||||||
|
ssource = (QIOChannelSocketSource *)source;
|
||||||
|
|
||||||
|
ssource->ioc = ioc;
|
||||||
|
object_ref(OBJECT(ioc));
|
||||||
|
|
||||||
|
ssource->condition = condition;
|
||||||
|
ssource->socket = socket;
|
||||||
|
ssource->revents = 0;
|
||||||
|
|
||||||
|
ssource->fd.fd = (gintptr)ioc->event;
|
||||||
|
ssource->fd.events = G_IO_IN;
|
||||||
|
|
||||||
|
g_source_add_poll(source, &ssource->fd);
|
||||||
|
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
|
||||||
|
int socket,
|
||||||
|
GIOCondition condition)
|
||||||
|
{
|
||||||
|
return qio_channel_create_fd_watch(ioc, socket, condition);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
GSource *qio_channel_create_fd_pair_watch(QIOChannel *ioc,
|
GSource *qio_channel_create_fd_pair_watch(QIOChannel *ioc,
|
||||||
int fdread,
|
int fdread,
|
||||||
|
@ -186,10 +329,15 @@ GSource *qio_channel_create_fd_pair_watch(QIOChannel *ioc,
|
||||||
|
|
||||||
ssource->condition = condition;
|
ssource->condition = condition;
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIN32
|
||||||
|
ssource->fdread.fd = (gint64)_get_osfhandle(fdread);
|
||||||
|
ssource->fdwrite.fd = (gint64)_get_osfhandle(fdwrite);
|
||||||
|
#else
|
||||||
ssource->fdread.fd = fdread;
|
ssource->fdread.fd = fdread;
|
||||||
ssource->fdread.events = condition & G_IO_IN;
|
|
||||||
|
|
||||||
ssource->fdwrite.fd = fdwrite;
|
ssource->fdwrite.fd = fdwrite;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ssource->fdread.events = condition & G_IO_IN;
|
||||||
ssource->fdwrite.events = condition & G_IO_OUT;
|
ssource->fdwrite.events = condition & G_IO_OUT;
|
||||||
|
|
||||||
g_source_add_poll(source, &ssource->fdread);
|
g_source_add_poll(source, &ssource->fdread);
|
||||||
|
|
14
io/channel.c
14
io/channel.c
|
@ -274,10 +274,24 @@ void qio_channel_wait(QIOChannel *ioc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static void qio_channel_finalize(Object *obj)
|
||||||
|
{
|
||||||
|
QIOChannel *ioc = QIO_CHANNEL(obj);
|
||||||
|
|
||||||
|
if (ioc->event) {
|
||||||
|
CloseHandle(ioc->event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static const TypeInfo qio_channel_info = {
|
static const TypeInfo qio_channel_info = {
|
||||||
.parent = TYPE_OBJECT,
|
.parent = TYPE_OBJECT,
|
||||||
.name = TYPE_QIO_CHANNEL,
|
.name = TYPE_QIO_CHANNEL,
|
||||||
.instance_size = sizeof(QIOChannel),
|
.instance_size = sizeof(QIOChannel),
|
||||||
|
#ifdef _WIN32
|
||||||
|
.instance_finalize = qio_channel_finalize,
|
||||||
|
#endif
|
||||||
.abstract = true,
|
.abstract = true,
|
||||||
.class_size = sizeof(QIOChannelClass),
|
.class_size = sizeof(QIOChannelClass),
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
|
|
||||||
#include "qemu.h"
|
#include "qemu.h"
|
||||||
#include "flat.h"
|
#include "flat.h"
|
||||||
#define ntohl(x) be32_to_cpu(x)
|
|
||||||
#include <target_flat.h>
|
#include <target_flat.h>
|
||||||
|
|
||||||
//#define DEBUG
|
//#define DEBUG
|
||||||
|
|
|
@ -53,18 +53,16 @@ static ssize_t socket_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
err = socket_error();
|
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||||
|
|
||||||
if (err != EAGAIN && err != EWOULDBLOCK) {
|
|
||||||
error_report("socket_writev_buffer: Got err=%d for (%zu/%zu)",
|
error_report("socket_writev_buffer: Got err=%d for (%zu/%zu)",
|
||||||
err, (size_t)size, (size_t)len);
|
errno, (size_t)size, (size_t)len);
|
||||||
/*
|
/*
|
||||||
* If I've already sent some but only just got the error, I
|
* If I've already sent some but only just got the error, I
|
||||||
* could return the amount validly sent so far and wait for the
|
* could return the amount validly sent so far and wait for the
|
||||||
* next call to report the error, but I'd rather flag the error
|
* next call to report the error, but I'd rather flag the error
|
||||||
* immediately.
|
* immediately.
|
||||||
*/
|
*/
|
||||||
return -err;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Emulate blocking */
|
/* Emulate blocking */
|
||||||
|
@ -99,15 +97,15 @@ static ssize_t socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
|
||||||
if (len != -1) {
|
if (len != -1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (socket_error() == EAGAIN) {
|
if (errno == EAGAIN) {
|
||||||
yield_until_fd_readable(s->fd);
|
yield_until_fd_readable(s->fd);
|
||||||
} else if (socket_error() != EINTR) {
|
} else if (errno != EINTR) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len == -1) {
|
if (len == -1) {
|
||||||
len = -socket_error();
|
len = -errno;
|
||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,12 +59,11 @@ static void tcp_accept_incoming_migration(void *opaque)
|
||||||
socklen_t addrlen = sizeof(addr);
|
socklen_t addrlen = sizeof(addr);
|
||||||
int s = (intptr_t)opaque;
|
int s = (intptr_t)opaque;
|
||||||
QEMUFile *f;
|
QEMUFile *f;
|
||||||
int c, err;
|
int c;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
|
c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
|
||||||
err = socket_error();
|
} while (c < 0 && errno == EINTR);
|
||||||
} while (c < 0 && err == EINTR);
|
|
||||||
qemu_set_fd_handler(s, NULL, NULL, NULL);
|
qemu_set_fd_handler(s, NULL, NULL, NULL);
|
||||||
closesocket(s);
|
closesocket(s);
|
||||||
|
|
||||||
|
@ -72,7 +71,7 @@ static void tcp_accept_incoming_migration(void *opaque)
|
||||||
|
|
||||||
if (c < 0) {
|
if (c < 0) {
|
||||||
error_report("could not accept migration connection (%s)",
|
error_report("could not accept migration connection (%s)",
|
||||||
strerror(err));
|
strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
19
net/socket.c
19
net/socket.c
|
@ -145,15 +145,14 @@ static void net_socket_send_completed(NetClientState *nc, ssize_t len)
|
||||||
static void net_socket_send(void *opaque)
|
static void net_socket_send(void *opaque)
|
||||||
{
|
{
|
||||||
NetSocketState *s = opaque;
|
NetSocketState *s = opaque;
|
||||||
int size, err;
|
int size;
|
||||||
unsigned l;
|
unsigned l;
|
||||||
uint8_t buf1[NET_BUFSIZE];
|
uint8_t buf1[NET_BUFSIZE];
|
||||||
const uint8_t *buf;
|
const uint8_t *buf;
|
||||||
|
|
||||||
size = qemu_recv(s->fd, buf1, sizeof(buf1), 0);
|
size = qemu_recv(s->fd, buf1, sizeof(buf1), 0);
|
||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
err = socket_error();
|
if (errno != EWOULDBLOCK)
|
||||||
if (err != EWOULDBLOCK)
|
|
||||||
goto eoc;
|
goto eoc;
|
||||||
} else if (size == 0) {
|
} else if (size == 0) {
|
||||||
/* end of connection */
|
/* end of connection */
|
||||||
|
@ -566,7 +565,7 @@ static int net_socket_connect_init(NetClientState *peer,
|
||||||
const char *host_str)
|
const char *host_str)
|
||||||
{
|
{
|
||||||
NetSocketState *s;
|
NetSocketState *s;
|
||||||
int fd, connected, ret, err;
|
int fd, connected, ret;
|
||||||
struct sockaddr_in saddr;
|
struct sockaddr_in saddr;
|
||||||
|
|
||||||
if (parse_host_port(&saddr, host_str) < 0)
|
if (parse_host_port(&saddr, host_str) < 0)
|
||||||
|
@ -583,14 +582,12 @@ static int net_socket_connect_init(NetClientState *peer,
|
||||||
for(;;) {
|
for(;;) {
|
||||||
ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
|
ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
err = socket_error();
|
if (errno == EINTR || errno == EWOULDBLOCK) {
|
||||||
if (err == EINTR || err == EWOULDBLOCK) {
|
/* continue */
|
||||||
} else if (err == EINPROGRESS) {
|
} else if (errno == EINPROGRESS ||
|
||||||
|
errno == EALREADY ||
|
||||||
|
errno == EINVAL) {
|
||||||
break;
|
break;
|
||||||
#ifdef _WIN32
|
|
||||||
} else if (err == WSAEALREADY || err == WSAEINVAL) {
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
perror("connect");
|
perror("connect");
|
||||||
closesocket(fd);
|
closesocket(fd);
|
||||||
|
|
96
qemu-char.c
96
qemu-char.c
|
@ -3091,20 +3091,6 @@ static void tcp_chr_close(CharDriverState *chr)
|
||||||
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
|
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qemu_chr_finish_socket_connection(CharDriverState *chr,
|
|
||||||
QIOChannelSocket *sioc)
|
|
||||||
{
|
|
||||||
TCPCharDriver *s = chr->opaque;
|
|
||||||
|
|
||||||
if (s->is_listen) {
|
|
||||||
s->listen_ioc = sioc;
|
|
||||||
s->listen_tag = qio_channel_add_watch(
|
|
||||||
QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL);
|
|
||||||
} else {
|
|
||||||
tcp_chr_new_client(chr, sioc);
|
|
||||||
object_unref(OBJECT(sioc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void qemu_chr_socket_connected(Object *src, Error *err, void *opaque)
|
static void qemu_chr_socket_connected(Object *src, Error *err, void *opaque)
|
||||||
{
|
{
|
||||||
|
@ -3119,37 +3105,11 @@ static void qemu_chr_socket_connected(Object *src, Error *err, void *opaque)
|
||||||
}
|
}
|
||||||
|
|
||||||
s->connect_err_reported = false;
|
s->connect_err_reported = false;
|
||||||
qemu_chr_finish_socket_connection(chr, sioc);
|
tcp_chr_new_client(chr, sioc);
|
||||||
}
|
|
||||||
|
|
||||||
static bool qemu_chr_open_socket_fd(CharDriverState *chr, Error **errp)
|
|
||||||
{
|
|
||||||
TCPCharDriver *s = chr->opaque;
|
|
||||||
QIOChannelSocket *sioc = qio_channel_socket_new();
|
|
||||||
|
|
||||||
if (s->is_listen) {
|
|
||||||
if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
qemu_chr_finish_socket_connection(chr, sioc);
|
|
||||||
} else if (s->reconnect_time) {
|
|
||||||
qio_channel_socket_connect_async(sioc, s->addr,
|
|
||||||
qemu_chr_socket_connected,
|
|
||||||
chr, NULL);
|
|
||||||
} else {
|
|
||||||
if (qio_channel_socket_connect_sync(sioc, s->addr, errp) < 0) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
qemu_chr_finish_socket_connection(chr, sioc);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
object_unref(OBJECT(sioc));
|
object_unref(OBJECT(sioc));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************/
|
/*********************************************************/
|
||||||
/* Ring buffer chardev */
|
/* Ring buffer chardev */
|
||||||
|
|
||||||
|
@ -4258,19 +4218,11 @@ static CharDriverState *qmp_chardev_open_parallel(const char *id,
|
||||||
|
|
||||||
#endif /* WIN32 */
|
#endif /* WIN32 */
|
||||||
|
|
||||||
static void socket_try_connect(CharDriverState *chr)
|
|
||||||
{
|
|
||||||
Error *err = NULL;
|
|
||||||
|
|
||||||
if (!qemu_chr_open_socket_fd(chr, &err)) {
|
|
||||||
check_report_connect_error(chr, err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean socket_reconnect_timeout(gpointer opaque)
|
static gboolean socket_reconnect_timeout(gpointer opaque)
|
||||||
{
|
{
|
||||||
CharDriverState *chr = opaque;
|
CharDriverState *chr = opaque;
|
||||||
TCPCharDriver *s = chr->opaque;
|
TCPCharDriver *s = chr->opaque;
|
||||||
|
QIOChannelSocket *sioc;
|
||||||
|
|
||||||
s->reconnect_timer = 0;
|
s->reconnect_timer = 0;
|
||||||
|
|
||||||
|
@ -4278,7 +4230,10 @@ static gboolean socket_reconnect_timeout(gpointer opaque)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
socket_try_connect(chr);
|
sioc = qio_channel_socket_new();
|
||||||
|
qio_channel_socket_connect_async(sioc, s->addr,
|
||||||
|
qemu_chr_socket_connected,
|
||||||
|
chr, NULL);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -4298,6 +4253,7 @@ static CharDriverState *qmp_chardev_open_socket(const char *id,
|
||||||
bool is_waitconnect = sock->has_wait ? sock->wait : false;
|
bool is_waitconnect = sock->has_wait ? sock->wait : false;
|
||||||
int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0;
|
int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0;
|
||||||
ChardevCommon *common = qapi_ChardevSocket_base(sock);
|
ChardevCommon *common = qapi_ChardevSocket_base(sock);
|
||||||
|
QIOChannelSocket *sioc = NULL;
|
||||||
|
|
||||||
chr = qemu_chr_alloc(common, errp);
|
chr = qemu_chr_alloc(common, errp);
|
||||||
if (!chr) {
|
if (!chr) {
|
||||||
|
@ -4367,22 +4323,40 @@ static CharDriverState *qmp_chardev_open_socket(const char *id,
|
||||||
s->reconnect_time = reconnect;
|
s->reconnect_time = reconnect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sioc = qio_channel_socket_new();
|
||||||
if (s->reconnect_time) {
|
if (s->reconnect_time) {
|
||||||
socket_try_connect(chr);
|
qio_channel_socket_connect_async(sioc, s->addr,
|
||||||
} else if (!qemu_chr_open_socket_fd(chr, errp)) {
|
qemu_chr_socket_connected,
|
||||||
goto error;
|
chr, NULL);
|
||||||
}
|
} else if (s->is_listen) {
|
||||||
|
if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) {
|
||||||
if (is_listen && is_waitconnect) {
|
goto error;
|
||||||
fprintf(stderr, "QEMU waiting for connection on: %s\n",
|
}
|
||||||
chr->filename);
|
s->listen_ioc = sioc;
|
||||||
tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr);
|
if (is_waitconnect) {
|
||||||
|
fprintf(stderr, "QEMU waiting for connection on: %s\n",
|
||||||
|
chr->filename);
|
||||||
|
tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr);
|
||||||
|
}
|
||||||
qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL);
|
qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL);
|
||||||
|
if (!s->ioc) {
|
||||||
|
s->listen_tag = qio_channel_add_watch(
|
||||||
|
QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (qio_channel_socket_connect_sync(sioc, s->addr, errp) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
tcp_chr_new_client(chr, sioc);
|
||||||
|
object_unref(OBJECT(sioc));
|
||||||
}
|
}
|
||||||
|
|
||||||
return chr;
|
return chr;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
if (sioc) {
|
||||||
|
object_unref(OBJECT(sioc));
|
||||||
|
}
|
||||||
if (s->tls_creds) {
|
if (s->tls_creds) {
|
||||||
object_unref(OBJECT(s->tls_creds));
|
object_unref(OBJECT(s->tls_creds));
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,6 @@ typedef char *caddr_t;
|
||||||
# include <iphlpapi.h>
|
# include <iphlpapi.h>
|
||||||
|
|
||||||
#else
|
#else
|
||||||
# define ioctlsocket ioctl
|
|
||||||
# define closesocket(s) close(s)
|
|
||||||
# if !defined(__HAIKU__)
|
# if !defined(__HAIKU__)
|
||||||
# define O_BINARY 0
|
# define O_BINARY 0
|
||||||
# endif
|
# endif
|
||||||
|
|
|
@ -586,11 +586,7 @@ findso:
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((tcp_fconnect(so, so->so_ffamily) == -1) &&
|
if ((tcp_fconnect(so, so->so_ffamily) == -1) &&
|
||||||
#if defined(_WIN32)
|
|
||||||
socket_error() != WSAEWOULDBLOCK
|
|
||||||
#else
|
|
||||||
(errno != EINPROGRESS) && (errno != EWOULDBLOCK)
|
(errno != EINPROGRESS) && (errno != EWOULDBLOCK)
|
||||||
#endif
|
|
||||||
) {
|
) {
|
||||||
u_char code=ICMP_UNREACH_NET;
|
u_char code=ICMP_UNREACH_NET;
|
||||||
DEBUG_MISC((dfd, " tcp fconnect errno = %d-%s\n",
|
DEBUG_MISC((dfd, " tcp fconnect errno = %d-%s\n",
|
||||||
|
|
|
@ -132,7 +132,7 @@ static gpointer test_io_thread_reader(gpointer opaque)
|
||||||
|
|
||||||
if (ret == QIO_CHANNEL_ERR_BLOCK) {
|
if (ret == QIO_CHANNEL_ERR_BLOCK) {
|
||||||
if (data->blocking) {
|
if (data->blocking) {
|
||||||
error_setg(&data->writeerr,
|
error_setg(&data->readerr,
|
||||||
"Unexpected I/O blocking");
|
"Unexpected I/O blocking");
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -233,11 +233,11 @@ void qio_channel_test_run_reader(QIOChannelTest *test,
|
||||||
|
|
||||||
void qio_channel_test_validate(QIOChannelTest *test)
|
void qio_channel_test_validate(QIOChannelTest *test)
|
||||||
{
|
{
|
||||||
|
g_assert(test->readerr == NULL);
|
||||||
|
g_assert(test->writeerr == NULL);
|
||||||
g_assert_cmpint(memcmp(test->input,
|
g_assert_cmpint(memcmp(test->input,
|
||||||
test->output,
|
test->output,
|
||||||
test->len), ==, 0);
|
test->len), ==, 0);
|
||||||
g_assert(test->readerr == NULL);
|
|
||||||
g_assert(test->writeerr == NULL);
|
|
||||||
|
|
||||||
g_free(test->inputv);
|
g_free(test->inputv);
|
||||||
g_free(test->outputv);
|
g_free(test->outputv);
|
||||||
|
|
|
@ -22,66 +22,49 @@
|
||||||
#include "io/channel-socket.h"
|
#include "io/channel-socket.h"
|
||||||
#include "io/channel-util.h"
|
#include "io/channel-util.h"
|
||||||
#include "io-channel-helpers.h"
|
#include "io-channel-helpers.h"
|
||||||
#ifdef HAVE_IFADDRS_H
|
|
||||||
#include <ifaddrs.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int check_protocol_support(bool *has_ipv4, bool *has_ipv6)
|
static int check_bind(struct sockaddr *sa, socklen_t salen, bool *has_proto)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_IFADDRS_H
|
int fd;
|
||||||
struct ifaddrs *ifaddr = NULL, *ifa;
|
|
||||||
struct addrinfo hints = { 0 };
|
|
||||||
struct addrinfo *ai = NULL;
|
|
||||||
int gaierr;
|
|
||||||
|
|
||||||
*has_ipv4 = *has_ipv6 = false;
|
fd = socket(sa->sa_family, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0) {
|
||||||
if (getifaddrs(&ifaddr) < 0) {
|
|
||||||
g_printerr("Failed to lookup interface addresses: %s\n",
|
|
||||||
strerror(errno));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
|
if (bind(fd, sa, salen) < 0) {
|
||||||
if (!ifa->ifa_addr) {
|
close(fd);
|
||||||
continue;
|
if (errno == EADDRNOTAVAIL) {
|
||||||
}
|
*has_proto = false;
|
||||||
|
return 0;
|
||||||
if (ifa->ifa_addr->sa_family == AF_INET) {
|
|
||||||
*has_ipv4 = true;
|
|
||||||
}
|
|
||||||
if (ifa->ifa_addr->sa_family == AF_INET6) {
|
|
||||||
*has_ipv6 = true;
|
|
||||||
}
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeifaddrs(ifaddr);
|
close(fd);
|
||||||
|
*has_proto = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
|
static int check_protocol_support(bool *has_ipv4, bool *has_ipv6)
|
||||||
hints.ai_family = AF_INET6;
|
{
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
struct sockaddr_in sin = {
|
||||||
|
.sin_family = AF_INET,
|
||||||
|
.sin_addr = { .s_addr = htonl(INADDR_LOOPBACK) },
|
||||||
|
};
|
||||||
|
struct sockaddr_in6 sin6 = {
|
||||||
|
.sin6_family = AF_INET6,
|
||||||
|
.sin6_addr = IN6ADDR_LOOPBACK_INIT,
|
||||||
|
};
|
||||||
|
|
||||||
gaierr = getaddrinfo("::1", NULL, &hints, &ai);
|
if (check_bind((struct sockaddr *)&sin, sizeof(sin), has_ipv4) < 0) {
|
||||||
if (gaierr != 0) {
|
return -1;
|
||||||
if (gaierr == EAI_ADDRFAMILY ||
|
}
|
||||||
gaierr == EAI_FAMILY ||
|
if (check_bind((struct sockaddr *)&sin6, sizeof(sin6), has_ipv6) < 0) {
|
||||||
gaierr == EAI_NONAME) {
|
return -1;
|
||||||
*has_ipv6 = false;
|
|
||||||
} else {
|
|
||||||
g_printerr("Failed to resolve ::1 address: %s\n",
|
|
||||||
gai_strerror(gaierr));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
freeaddrinfo(ai);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
|
||||||
*has_ipv4 = *has_ipv6 = false;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -131,6 +114,7 @@ static void test_io_channel_setup_sync(SocketAddress *listen_addr,
|
||||||
QIO_CHANNEL_SOCKET(*src), connect_addr, &error_abort);
|
QIO_CHANNEL_SOCKET(*src), connect_addr, &error_abort);
|
||||||
qio_channel_set_delay(*src, false);
|
qio_channel_set_delay(*src, false);
|
||||||
|
|
||||||
|
qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN);
|
||||||
*dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
|
*dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
|
||||||
g_assert(*dst);
|
g_assert(*dst);
|
||||||
|
|
||||||
|
@ -198,6 +182,7 @@ static void test_io_channel_setup_async(SocketAddress *listen_addr,
|
||||||
|
|
||||||
g_assert(!data.err);
|
g_assert(!data.err);
|
||||||
|
|
||||||
|
qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN);
|
||||||
*dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
|
*dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
|
||||||
g_assert(*dst);
|
g_assert(*dst);
|
||||||
|
|
||||||
|
@ -487,10 +472,20 @@ static void test_io_channel_ipv4_fd(void)
|
||||||
{
|
{
|
||||||
QIOChannel *ioc;
|
QIOChannel *ioc;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
|
struct sockaddr_in sa = {
|
||||||
|
.sin_family = AF_INET,
|
||||||
|
.sin_addr = {
|
||||||
|
.s_addr = htonl(INADDR_LOOPBACK),
|
||||||
|
}
|
||||||
|
/* Leave port unset for auto-assign */
|
||||||
|
};
|
||||||
|
socklen_t salen = sizeof(sa);
|
||||||
|
|
||||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
g_assert_cmpint(fd, >, -1);
|
g_assert_cmpint(fd, >, -1);
|
||||||
|
|
||||||
|
g_assert_cmpint(bind(fd, (struct sockaddr *)&sa, salen), ==, 0);
|
||||||
|
|
||||||
ioc = qio_channel_new_fd(fd, &error_abort);
|
ioc = qio_channel_new_fd(fd, &error_abort);
|
||||||
|
|
||||||
g_assert_cmpstr(object_get_typename(OBJECT(ioc)),
|
g_assert_cmpstr(object_get_typename(OBJECT(ioc)),
|
||||||
|
@ -506,6 +501,7 @@ int main(int argc, char **argv)
|
||||||
bool has_ipv4, has_ipv6;
|
bool has_ipv4, has_ipv6;
|
||||||
|
|
||||||
module_call_init(MODULE_INIT_QOM);
|
module_call_init(MODULE_INIT_QOM);
|
||||||
|
socket_init();
|
||||||
|
|
||||||
g_test_init(&argc, &argv, NULL);
|
g_test_init(&argc, &argv, NULL);
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* os-win32.c
|
* os-win32.c
|
||||||
*
|
*
|
||||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
* Copyright (c) 2010 Red Hat, Inc.
|
* Copyright (c) 2010-2016 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
* QEMU library functions for win32 which are shared between QEMU and
|
* QEMU library functions for win32 which are shared between QEMU and
|
||||||
* the QEMU tools.
|
* the QEMU tools.
|
||||||
|
@ -144,6 +144,83 @@ int socket_set_fast_reuse(int fd)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int socket_error(void)
|
||||||
|
{
|
||||||
|
switch (WSAGetLastError()) {
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
|
case WSAEINTR:
|
||||||
|
return EINTR;
|
||||||
|
case WSAEINVAL:
|
||||||
|
return EINVAL;
|
||||||
|
case WSA_INVALID_HANDLE:
|
||||||
|
return EBADF;
|
||||||
|
case WSA_NOT_ENOUGH_MEMORY:
|
||||||
|
return ENOMEM;
|
||||||
|
case WSA_INVALID_PARAMETER:
|
||||||
|
return EINVAL;
|
||||||
|
case WSAENAMETOOLONG:
|
||||||
|
return ENAMETOOLONG;
|
||||||
|
case WSAENOTEMPTY:
|
||||||
|
return ENOTEMPTY;
|
||||||
|
case WSAEWOULDBLOCK:
|
||||||
|
/* not using EWOULDBLOCK as we don't want code to have
|
||||||
|
* to check both EWOULDBLOCK and EAGAIN */
|
||||||
|
return EAGAIN;
|
||||||
|
case WSAEINPROGRESS:
|
||||||
|
return EINPROGRESS;
|
||||||
|
case WSAEALREADY:
|
||||||
|
return EALREADY;
|
||||||
|
case WSAENOTSOCK:
|
||||||
|
return ENOTSOCK;
|
||||||
|
case WSAEDESTADDRREQ:
|
||||||
|
return EDESTADDRREQ;
|
||||||
|
case WSAEMSGSIZE:
|
||||||
|
return EMSGSIZE;
|
||||||
|
case WSAEPROTOTYPE:
|
||||||
|
return EPROTOTYPE;
|
||||||
|
case WSAENOPROTOOPT:
|
||||||
|
return ENOPROTOOPT;
|
||||||
|
case WSAEPROTONOSUPPORT:
|
||||||
|
return EPROTONOSUPPORT;
|
||||||
|
case WSAEOPNOTSUPP:
|
||||||
|
return EOPNOTSUPP;
|
||||||
|
case WSAEAFNOSUPPORT:
|
||||||
|
return EAFNOSUPPORT;
|
||||||
|
case WSAEADDRINUSE:
|
||||||
|
return EADDRINUSE;
|
||||||
|
case WSAEADDRNOTAVAIL:
|
||||||
|
return EADDRNOTAVAIL;
|
||||||
|
case WSAENETDOWN:
|
||||||
|
return ENETDOWN;
|
||||||
|
case WSAENETUNREACH:
|
||||||
|
return ENETUNREACH;
|
||||||
|
case WSAENETRESET:
|
||||||
|
return ENETRESET;
|
||||||
|
case WSAECONNABORTED:
|
||||||
|
return ECONNABORTED;
|
||||||
|
case WSAECONNRESET:
|
||||||
|
return ECONNRESET;
|
||||||
|
case WSAENOBUFS:
|
||||||
|
return ENOBUFS;
|
||||||
|
case WSAEISCONN:
|
||||||
|
return EISCONN;
|
||||||
|
case WSAENOTCONN:
|
||||||
|
return ENOTCONN;
|
||||||
|
case WSAETIMEDOUT:
|
||||||
|
return ETIMEDOUT;
|
||||||
|
case WSAECONNREFUSED:
|
||||||
|
return ECONNREFUSED;
|
||||||
|
case WSAELOOP:
|
||||||
|
return ELOOP;
|
||||||
|
case WSAEHOSTUNREACH:
|
||||||
|
return EHOSTUNREACH;
|
||||||
|
default:
|
||||||
|
return EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int inet_aton(const char *cp, struct in_addr *ia)
|
int inet_aton(const char *cp, struct in_addr *ia)
|
||||||
{
|
{
|
||||||
uint32_t addr = inet_addr(cp);
|
uint32_t addr = inet_addr(cp);
|
||||||
|
@ -504,3 +581,204 @@ pid_t qemu_fork(Error **errp)
|
||||||
"cannot fork child process");
|
"cannot fork child process");
|
||||||
return -1;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -35,18 +35,16 @@ qemu_co_sendv_recvv(int sockfd, struct iovec *iov, unsigned iov_cnt,
|
||||||
{
|
{
|
||||||
size_t done = 0;
|
size_t done = 0;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
int err;
|
|
||||||
while (done < bytes) {
|
while (done < bytes) {
|
||||||
ret = iov_send_recv(sockfd, iov, iov_cnt,
|
ret = iov_send_recv(sockfd, iov, iov_cnt,
|
||||||
offset + done, bytes - done, do_send);
|
offset + done, bytes - done, do_send);
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
done += ret;
|
done += ret;
|
||||||
} else if (ret < 0) {
|
} else if (ret < 0) {
|
||||||
err = socket_error();
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
if (err == EAGAIN || err == EWOULDBLOCK) {
|
|
||||||
qemu_coroutine_yield();
|
qemu_coroutine_yield();
|
||||||
} else if (done == 0) {
|
} else if (done == 0) {
|
||||||
return -err;
|
return -errno;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -268,7 +268,7 @@ static void wait_for_connect(void *opaque)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
rc = qemu_getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &val, &valsize);
|
rc = qemu_getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &val, &valsize);
|
||||||
} while (rc == -1 && socket_error() == EINTR);
|
} while (rc == -1 && errno == EINTR);
|
||||||
|
|
||||||
/* update rc to contain error */
|
/* update rc to contain error */
|
||||||
if (!rc && val) {
|
if (!rc && val) {
|
||||||
|
@ -330,7 +330,7 @@ static int inet_connect_addr(struct addrinfo *addr, bool *in_progress,
|
||||||
do {
|
do {
|
||||||
rc = 0;
|
rc = 0;
|
||||||
if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) {
|
if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) {
|
||||||
rc = -socket_error();
|
rc = -errno;
|
||||||
}
|
}
|
||||||
} while (rc == -EINTR);
|
} while (rc == -EINTR);
|
||||||
|
|
||||||
|
@ -787,7 +787,7 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp,
|
||||||
do {
|
do {
|
||||||
rc = 0;
|
rc = 0;
|
||||||
if (connect(sock, (struct sockaddr *) &un, sizeof(un)) < 0) {
|
if (connect(sock, (struct sockaddr *) &un, sizeof(un)) < 0) {
|
||||||
rc = -socket_error();
|
rc = -errno;
|
||||||
}
|
}
|
||||||
} while (rc == -EINTR);
|
} while (rc == -EINTR);
|
||||||
|
|
||||||
|
@ -1082,7 +1082,7 @@ SocketAddress *socket_local_address(int fd, Error **errp)
|
||||||
socklen_t sslen = sizeof(ss);
|
socklen_t sslen = sizeof(ss);
|
||||||
|
|
||||||
if (getsockname(fd, (struct sockaddr *)&ss, &sslen) < 0) {
|
if (getsockname(fd, (struct sockaddr *)&ss, &sslen) < 0) {
|
||||||
error_setg_errno(errp, socket_error(), "%s",
|
error_setg_errno(errp, errno, "%s",
|
||||||
"Unable to query local socket address");
|
"Unable to query local socket address");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1097,7 +1097,7 @@ SocketAddress *socket_remote_address(int fd, Error **errp)
|
||||||
socklen_t sslen = sizeof(ss);
|
socklen_t sslen = sizeof(ss);
|
||||||
|
|
||||||
if (getpeername(fd, (struct sockaddr *)&ss, &sslen) < 0) {
|
if (getpeername(fd, (struct sockaddr *)&ss, &sslen) < 0) {
|
||||||
error_setg_errno(errp, socket_error(), "%s",
|
error_setg_errno(errp, errno, "%s",
|
||||||
"Unable to query remote socket address");
|
"Unable to query remote socket address");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue