QMP command to import win32 sockets

-----BEGIN PGP SIGNATURE-----
 
 iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmQPDQ0cHG1hcmNhbmRy
 ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5eTUD/41+bodkctP9wtNQT5g
 4P2XQysa9dhxIaQuPT48J5bN0velOAv+p+e9jNMojVPHogACRGkjJUGrh2AhaWJO
 bpqB5teNz3pbTLAHNrqiJdUrJDI0WSqBN2q7WgfbzvHMugBqul13n6UG/cVWH8D3
 pDX3miBl9Cv3zUDFzPjHH3eR/MHz+6wXmuzUGQdWqyGBoLwqgWA3Bqh39BDVOeJf
 03Kq3TbJSP096EjGGrq1pTYDIIv9AKzUWgn8tT8S73sD3J0BN28Gl5HirXDx8e/4
 2WtW/XLYKjqoUl7RmXOjfOarCV+kxzdoYCAUYfyH6DLWrkXc41L5ugFdyxxQ66Sh
 +on7hKCBzPEOPEXmlm6HlMj3bK4C/GI6mIoaZgCrsvj9xlehhQNtwpndAwAR8esH
 perQ6q+jPdoQnBvOBgC3amckS1kYdbQivTILkoopumw/q4waG5reyA4rshbhm/bs
 U33ZRzob0XyRWqvWAcq9hnWB5gvQCcppeJlu60gocnX5wdZOjbnsBXw3l+r2osIh
 izJbxwM6xmz9oHh50nhDCn42JrNdSnZJdJ/XA/lrOkTHQ6kbZO7v86Y/mKQz+Vyx
 Uyhb8/y8gKrUkZlGCEMvQVcyvOA8vneX8WhfZUm6w5MWWCNKfCrEl6UGmFkPAL0m
 +sUYIhN5PSxWSQU5MWogXtQEPA==
 =/Y/7
 -----END PGP SIGNATURE-----

Merge tag 'win-socket-pull-request' of https://gitlab.com/marcandre.lureau/qemu into staging

QMP command to import win32 sockets

# -----BEGIN PGP SIGNATURE-----
#
# iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmQPDQ0cHG1hcmNhbmRy
# ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5eTUD/41+bodkctP9wtNQT5g
# 4P2XQysa9dhxIaQuPT48J5bN0velOAv+p+e9jNMojVPHogACRGkjJUGrh2AhaWJO
# bpqB5teNz3pbTLAHNrqiJdUrJDI0WSqBN2q7WgfbzvHMugBqul13n6UG/cVWH8D3
# pDX3miBl9Cv3zUDFzPjHH3eR/MHz+6wXmuzUGQdWqyGBoLwqgWA3Bqh39BDVOeJf
# 03Kq3TbJSP096EjGGrq1pTYDIIv9AKzUWgn8tT8S73sD3J0BN28Gl5HirXDx8e/4
# 2WtW/XLYKjqoUl7RmXOjfOarCV+kxzdoYCAUYfyH6DLWrkXc41L5ugFdyxxQ66Sh
# +on7hKCBzPEOPEXmlm6HlMj3bK4C/GI6mIoaZgCrsvj9xlehhQNtwpndAwAR8esH
# perQ6q+jPdoQnBvOBgC3amckS1kYdbQivTILkoopumw/q4waG5reyA4rshbhm/bs
# U33ZRzob0XyRWqvWAcq9hnWB5gvQCcppeJlu60gocnX5wdZOjbnsBXw3l+r2osIh
# izJbxwM6xmz9oHh50nhDCn42JrNdSnZJdJ/XA/lrOkTHQ6kbZO7v86Y/mKQz+Vyx
# Uyhb8/y8gKrUkZlGCEMvQVcyvOA8vneX8WhfZUm6w5MWWCNKfCrEl6UGmFkPAL0m
# +sUYIhN5PSxWSQU5MWogXtQEPA==
# =/Y/7
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 13 Mar 2023 11:46:21 GMT
# gpg:                using RSA key 87A9BD933F87C606D276F62DDAE8E10975969CE5
# gpg:                issuer "marcandre.lureau@redhat.com"
# gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>" [full]
# gpg:                 aka "Marc-André Lureau <marcandre.lureau@gmail.com>" [full]
# Primary key fingerprint: 87A9 BD93 3F87 C606 D276  F62D DAE8 E109 7596 9CE5

* tag 'win-socket-pull-request' of https://gitlab.com/marcandre.lureau/qemu: (25 commits)
  monitor: restrict command getfd to POSIX hosts
  qtest: enable vnc-display test on win32
  libqtest: make qtest_qmp_add_client work on win32
  qmp: add 'get-win32-socket'
  monitor: release the lock before calling close()
  qmp: 'add_client' actually expects sockets
  osdep: implement qemu_socketpair() for win32
  tests/docker: fix a win32 error due to portability
  char: do not double-close fd when failing to add client
  tests: fix path separator, use g_build_filename()
  win32: replace closesocket() with close() wrapper
  os-posix: remove useless ioctlsocket() define
  win32: avoid mixing SOCKET and file descriptor space
  slirp: open-code qemu_socket_(un)select()
  slirp: unregister the win32 SOCKET
  main-loop: remove qemu_fd_register(), win32/slirp/socket specific
  aio/win32: aio_set_fd_handler() only supports SOCKET
  aio: make aio_set_fd_poll() static to aio-posix.c
  win32/socket: introduce qemu_socket_unselect() helper
  win32/socket: introduce qemu_socket_select() helper
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2023-03-13 13:44:17 +00:00
commit 284c52eec2
38 changed files with 715 additions and 272 deletions

View File

@ -573,13 +573,13 @@ static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_emu)
goto err_exit;
}
closesocket(fds[1]);
close(fds[1]);
return 0;
err_exit:
closesocket(fds[0]);
closesocket(fds[1]);
close(fds[0]);
close(fds[1]);
return -1;
}

View File

@ -1175,12 +1175,10 @@ bool qmp_add_client_char(int fd, bool has_skipauth, bool skipauth,
if (!s) {
error_setg(errp, "protocol '%s' is invalid", protocol);
close(fd);
return false;
}
if (qemu_chr_add_client(s, fd) < 0) {
error_setg(errp, "failed to add client");
close(fd);
return false;
}
return true;

View File

@ -59,7 +59,7 @@ qcrypto_afalg_socket_bind(const char *type, const char *name,
if (bind(sbind, (const struct sockaddr *)&salg, sizeof(salg)) != 0) {
error_setg_errno(errp, errno, "Failed to bind socket");
closesocket(sbind);
close(sbind);
return -1;
}
@ -105,11 +105,11 @@ void qcrypto_afalg_comm_free(QCryptoAFAlg *afalg)
}
if (afalg->tfmfd != -1) {
closesocket(afalg->tfmfd);
close(afalg->tfmfd);
}
if (afalg->opfd != -1) {
closesocket(afalg->opfd);
close(afalg->opfd);
}
g_free(afalg);

View File

@ -1486,6 +1486,7 @@ SRST
Inject an MCE on the given CPU (x86 only).
ERST
#ifdef CONFIG_POSIX
{
.name = "getfd",
.args_type = "fdname:s",
@ -1501,6 +1502,7 @@ SRST
mechanism on unix sockets, it is stored using the name *fdname* for
later use by other monitor commands.
ERST
#endif
{
.name = "closefd",

View File

@ -340,7 +340,7 @@ static void hv_syndbg_realize(DeviceState *dev, Error **errp)
syndbg->servaddr.sin_family = AF_INET;
if (connect(syndbg->socket, (struct sockaddr *)&syndbg->servaddr,
sizeof(syndbg->servaddr)) < 0) {
closesocket(syndbg->socket);
close(syndbg->socket);
error_setg(errp, "%s failed to connect to socket", TYPE_HV_SYNDBG);
return;
}
@ -357,7 +357,7 @@ static void hv_syndbg_unrealize(DeviceState *dev)
if (syndbg->socket > 0) {
qemu_set_fd_handler(syndbg->socket, NULL, NULL, NULL);
closesocket(syndbg->socket);
close(syndbg->socket);
}
}

View File

@ -482,14 +482,6 @@ void aio_set_fd_handler(AioContext *ctx,
IOHandler *io_poll_ready,
void *opaque);
/* Set polling begin/end callbacks for a file descriptor that has already been
* registered with aio_set_fd_handler. Do nothing if the file descriptor is
* not registered.
*/
void aio_set_fd_poll(AioContext *ctx, int fd,
IOHandler *io_poll_begin,
IOHandler *io_poll_end);
/* Register an event notifier and associated callbacks. Behaves very similarly
* to event_notifier_set_handler. Unlike event_notifier_set_handler, these callbacks
* will be invoked when using aio_poll().

View File

@ -519,6 +519,12 @@ static inline void error_propagator_cleanup(ErrorPropagator *prop)
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(ErrorPropagator, error_propagator_cleanup);
/*
* Special error destination to warn on error.
* See error_setg() and error_propagate() for details.
*/
extern Error *error_warn;
/*
* Special error destination to abort on error.
* See error_setg() and error_propagate() for details.

View File

@ -387,8 +387,6 @@ void qemu_cond_timedwait_iothread(QemuCond *cond, int ms);
/* internal interfaces */
void qemu_fd_register(int fd);
#define qemu_bh_new(cb, opaque) \
qemu_bh_new_full((cb), (opaque), (stringify(cb)))
QEMUBH *qemu_bh_new_full(QEMUBHFunc *cb, void *opaque, const char *name);

View File

@ -665,20 +665,6 @@ void qemu_prealloc_mem(int fd, char *area, size_t sz, int max_threads,
*/
char *qemu_get_pid_name(pid_t pid);
/**
* qemu_fork:
*
* A version of fork that avoids signal handler race
* conditions that can lead to child process getting
* signals that are otherwise only expected by the
* parent. It also resets all signal handlers to the
* default settings.
*
* Returns 0 to child process, pid number to parent
* or -1 on failure.
*/
pid_t qemu_fork(Error **errp);
/* Using intptr_t ensures that qemu_*_page_mask is sign-extended even
* when intptr_t is 32-bit and we are aligning a long long.
*/

View File

@ -15,7 +15,6 @@ int inet_aton(const char *cp, struct in_addr *ia);
bool fd_is_socket(int fd);
int qemu_socket(int domain, int type, int protocol);
#ifndef WIN32
/**
* qemu_socketpair:
* @domain: specifies a communication domain, such as PF_UNIX
@ -30,7 +29,6 @@ int qemu_socket(int domain, int type, int protocol);
* Return 0 on success.
*/
int qemu_socketpair(int domain, int type, int protocol, int sv[2]);
#endif
int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
/*

View File

@ -51,9 +51,6 @@ void os_daemonize(void);
void os_setup_post(void);
int os_mlock(void);
#define closesocket(s) close(s)
#define ioctlsocket(s, r, v) ioctl(s, r, v)
int os_set_daemonize(bool d);
bool is_daemonized(void);

View File

@ -29,6 +29,7 @@
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include "qemu/typedefs.h"
#ifdef HAVE_AFUNIX_H
#include <afunix.h>
@ -164,10 +165,20 @@ static inline void qemu_funlockfile(FILE *f)
#endif
}
/* Helper for WSAEventSelect, to report errors */
bool qemu_socket_select(int sockfd, WSAEVENT hEventObject,
long lNetworkEvents, Error **errp);
bool qemu_socket_unselect(int sockfd, Error **errp);
/* We wrap all the sockets functions so that we can
* set errno based on WSAGetLastError()
*/
#undef close
#define close qemu_close_wrap
int qemu_close_wrap(int fd);
#undef connect
#define connect qemu_connect_wrap
int qemu_connect_wrap(int sockfd, const struct sockaddr *addr,
@ -199,10 +210,6 @@ int qemu_shutdown_wrap(int sockfd, int how);
#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,

View File

@ -442,9 +442,9 @@ static void qio_channel_socket_finalize(Object *obj)
}
}
#ifdef WIN32
WSAEventSelect(ioc->fd, NULL, 0);
qemu_socket_unselect(ioc->fd, NULL);
#endif
closesocket(ioc->fd);
close(ioc->fd);
ioc->fd = -1;
}
}
@ -846,13 +846,13 @@ qio_channel_socket_close(QIOChannel *ioc,
if (sioc->fd != -1) {
#ifdef WIN32
WSAEventSelect(sioc->fd, NULL, 0);
qemu_socket_unselect(sioc->fd, NULL);
#endif
if (qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_LISTEN)) {
socket_listen_cleanup(sioc->fd, errp);
}
if (closesocket(sioc->fd) < 0) {
if (close(sioc->fd) < 0) {
sioc->fd = -1;
error_setg_errno(&err, errno, "Unable to close socket");
error_propagate(errp, err);

View File

@ -275,15 +275,15 @@ GSource *qio_channel_create_fd_watch(QIOChannel *ioc,
#ifdef CONFIG_WIN32
GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
int socket,
int sockfd,
GIOCondition condition)
{
GSource *source;
QIOChannelSocketSource *ssource;
WSAEventSelect(socket, ioc->event,
FD_READ | FD_ACCEPT | FD_CLOSE |
FD_CONNECT | FD_WRITE | FD_OOB);
qemu_socket_select(sockfd, ioc->event,
FD_READ | FD_ACCEPT | FD_CLOSE |
FD_CONNECT | FD_WRITE | FD_OOB, NULL);
source = g_source_new(&qio_channel_socket_source_funcs,
sizeof(QIOChannelSocketSource));
@ -293,7 +293,7 @@ GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
object_ref(OBJECT(ioc));
ssource->condition = condition;
ssource->socket = socket;
ssource->socket = _get_osfhandle(sockfd);
ssource->revents = 0;
ssource->fd.fd = (gintptr)ioc->event;

View File

@ -61,11 +61,48 @@ struct MonFdset {
static QemuMutex mon_fdsets_lock;
static QLIST_HEAD(, MonFdset) mon_fdsets;
static bool monitor_add_fd(Monitor *mon, int fd, const char *fdname, Error **errp)
{
mon_fd_t *monfd;
if (qemu_isdigit(fdname[0])) {
close(fd);
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdname",
"a name not starting with a digit");
return false;
}
/* See close() call below. */
qemu_mutex_lock(&mon->mon_lock);
QLIST_FOREACH(monfd, &mon->fds, next) {
int tmp_fd;
if (strcmp(monfd->name, fdname) != 0) {
continue;
}
tmp_fd = monfd->fd;
monfd->fd = fd;
qemu_mutex_unlock(&mon->mon_lock);
/* Make sure close() is outside critical section */
close(tmp_fd);
return true;
}
monfd = g_new0(mon_fd_t, 1);
monfd->name = g_strdup(fdname);
monfd->fd = fd;
QLIST_INSERT_HEAD(&mon->fds, monfd, next);
qemu_mutex_unlock(&mon->mon_lock);
return true;
}
#ifdef CONFIG_POSIX
void qmp_getfd(const char *fdname, Error **errp)
{
Monitor *cur_mon = monitor_cur();
mon_fd_t *monfd;
int fd, tmp_fd;
int fd;
fd = qemu_chr_fe_get_msgfd(&cur_mon->chr);
if (fd == -1) {
@ -73,32 +110,9 @@ void qmp_getfd(const char *fdname, Error **errp)
return;
}
if (qemu_isdigit(fdname[0])) {
close(fd);
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdname",
"a name not starting with a digit");
return;
}
QEMU_LOCK_GUARD(&cur_mon->mon_lock);
QLIST_FOREACH(monfd, &cur_mon->fds, next) {
if (strcmp(monfd->name, fdname) != 0) {
continue;
}
tmp_fd = monfd->fd;
monfd->fd = fd;
/* Make sure close() is outside critical section */
close(tmp_fd);
return;
}
monfd = g_new0(mon_fd_t, 1);
monfd->name = g_strdup(fdname);
monfd->fd = fd;
QLIST_INSERT_HEAD(&cur_mon->fds, monfd, next);
monitor_add_fd(cur_mon, fd, fdname, errp);
}
#endif
void qmp_closefd(const char *fdname, Error **errp)
{
@ -211,6 +225,41 @@ error:
return NULL;
}
#ifdef WIN32
void qmp_get_win32_socket(const char *infos, const char *fdname, Error **errp)
{
g_autofree WSAPROTOCOL_INFOW *info = NULL;
gsize len;
SOCKET sk;
int fd;
info = (void *)g_base64_decode(infos, &len);
if (len != sizeof(*info)) {
error_setg(errp, "Invalid WSAPROTOCOL_INFOW value");
return;
}
sk = WSASocketW(FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
info, 0, 0);
if (sk == INVALID_SOCKET) {
error_setg_win32(errp, WSAGetLastError(), "Couldn't import socket");
return;
}
fd = _open_osfhandle(sk, _O_BINARY);
if (fd < 0) {
error_setg_errno(errp, errno, "Failed to associate a FD with the SOCKET");
closesocket(sk);
return;
}
monitor_add_fd(monitor_cur(), fd, fdname, errp);
}
#endif
void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp)
{
MonFdset *mon_fdset;

View File

@ -192,6 +192,7 @@ void hmp_change(Monitor *mon, const QDict *qdict)
hmp_handle_error(mon, err);
}
#ifdef CONFIG_POSIX
void hmp_getfd(Monitor *mon, const QDict *qdict)
{
const char *fdname = qdict_get_str(qdict, "fdname");
@ -200,6 +201,7 @@ void hmp_getfd(Monitor *mon, const QDict *qdict)
qmp_getfd(fdname, &err);
hmp_handle_error(mon, err);
}
#endif
void hmp_closefd(Monitor *mon, const QDict *qdict)
{

View File

@ -14,6 +14,7 @@
*/
#include "qemu/osdep.h"
#include "qemu/sockets.h"
#include "monitor-internal.h"
#include "monitor/qdev.h"
#include "monitor/qmp-helpers.h"
@ -139,6 +140,12 @@ void qmp_add_client(const char *protocol, const char *fdname,
return;
}
if (!fd_is_socket(fd)) {
error_setg(errp, "parameter @fdname must name a socket");
close(fd);
return;
}
for (i = 0; i < ARRAY_SIZE(protocol_table); i++) {
if (!strcmp(protocol, protocol_table[i].name)) {
if (!protocol_table[i].add_client(fd, has_skipauth, skipauth,

View File

@ -230,7 +230,7 @@ static int net_dgram_mcast_create(struct sockaddr_in *mcastaddr,
return fd;
fail:
if (fd >= 0) {
closesocket(fd);
close(fd);
}
return -1;
}
@ -352,7 +352,7 @@ static int net_dgram_mcast_init(NetClientState *peer,
if (convert_host_port(saddr, local->u.inet.host, local->u.inet.port,
errp) < 0) {
g_free(saddr);
closesocket(fd);
close(fd);
return -1;
}
@ -360,14 +360,14 @@ static int net_dgram_mcast_init(NetClientState *peer,
if (saddr->sin_addr.s_addr == 0) {
error_setg(errp, "can't setup multicast destination address");
g_free(saddr);
closesocket(fd);
close(fd);
return -1;
}
/* clone dgram socket */
newfd = net_dgram_mcast_create(saddr, NULL, errp);
if (newfd < 0) {
g_free(saddr);
closesocket(fd);
close(fd);
return -1;
}
/* clone newfd to fd, close newfd */
@ -494,14 +494,14 @@ int net_init_dgram(const Netdev *netdev, const char *name,
if (ret < 0) {
error_setg_errno(errp, errno,
"can't set socket option SO_REUSEADDR");
closesocket(fd);
close(fd);
return -1;
}
ret = bind(fd, (struct sockaddr *)&laddr_in, sizeof(laddr_in));
if (ret < 0) {
error_setg_errno(errp, errno, "can't bind ip=%s to socket",
inet_ntoa(laddr_in.sin_addr));
closesocket(fd);
close(fd);
return -1;
}
qemu_socket_set_nonblock(fd);
@ -548,7 +548,7 @@ int net_init_dgram(const Netdev *netdev, const char *name,
if (ret < 0) {
error_setg_errno(errp, errno, "can't bind unix=%s to socket",
laddr_un.sun_path);
closesocket(fd);
close(fd);
return -1;
}
qemu_socket_set_nonblock(fd);

View File

@ -248,12 +248,24 @@ static void net_slirp_timer_mod(void *timer, int64_t expire_timer,
static void net_slirp_register_poll_fd(int fd, void *opaque)
{
qemu_fd_register(fd);
#ifdef WIN32
AioContext *ctxt = qemu_get_aio_context();
if (WSAEventSelect(fd, event_notifier_get_handle(&ctxt->notifier),
FD_READ | FD_ACCEPT | FD_CLOSE |
FD_CONNECT | FD_WRITE | FD_OOB) != 0) {
error_setg_win32(&error_warn, WSAGetLastError(), "failed to WSAEventSelect()");
}
#endif
}
static void net_slirp_unregister_poll_fd(int fd, void *opaque)
{
/* no qemu_fd_unregister */
#ifdef WIN32
if (WSAEventSelect(fd, NULL, 0) != 0) {
error_setg_win32(&error_warn, WSAGetLastError(), "failed to WSAEventSelect()");
}
#endif
}
static void net_slirp_notify(void *opaque)

View File

@ -172,7 +172,7 @@ static void net_socket_send(void *opaque)
if (s->listen_fd != -1) {
qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
}
closesocket(s->fd);
close(s->fd);
s->fd = -1;
net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
@ -299,7 +299,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr,
return fd;
fail:
if (fd >= 0)
closesocket(fd);
close(fd);
return -1;
}
@ -314,7 +314,7 @@ static void net_socket_cleanup(NetClientState *nc)
}
if (s->listen_fd != -1) {
qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
closesocket(s->listen_fd);
close(s->listen_fd);
s->listen_fd = -1;
}
}
@ -399,7 +399,7 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
return s;
err:
closesocket(fd);
close(fd);
return NULL;
}
@ -456,7 +456,7 @@ static NetSocketState *net_socket_fd_init(NetClientState *peer,
if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,
(socklen_t *)&optlen)< 0) {
error_setg(errp, "can't get socket option SO_TYPE");
closesocket(fd);
close(fd);
return NULL;
}
switch(so_type) {
@ -468,7 +468,7 @@ static NetSocketState *net_socket_fd_init(NetClientState *peer,
default:
error_setg(errp, "socket type=%d for fd=%d must be either"
" SOCK_DGRAM or SOCK_STREAM", so_type, fd);
closesocket(fd);
close(fd);
}
return NULL;
}
@ -526,13 +526,13 @@ static int net_socket_listen_init(NetClientState *peer,
if (ret < 0) {
error_setg_errno(errp, errno, "can't bind ip=%s to socket",
inet_ntoa(saddr.sin_addr));
closesocket(fd);
close(fd);
return -1;
}
ret = listen(fd, 0);
if (ret < 0) {
error_setg_errno(errp, errno, "can't listen on socket");
closesocket(fd);
close(fd);
return -1;
}
@ -579,7 +579,7 @@ static int net_socket_connect_init(NetClientState *peer,
break;
} else {
error_setg_errno(errp, errno, "can't connect socket");
closesocket(fd);
close(fd);
return -1;
}
} else {
@ -671,14 +671,14 @@ static int net_socket_udp_init(NetClientState *peer,
if (ret < 0) {
error_setg_errno(errp, errno,
"can't set socket option SO_REUSEADDR");
closesocket(fd);
close(fd);
return -1;
}
ret = bind(fd, (struct sockaddr *)&laddr, sizeof(laddr));
if (ret < 0) {
error_setg_errno(errp, errno, "can't bind ip=%s to socket",
inet_ntoa(laddr.sin_addr));
closesocket(fd);
close(fd);
return -1;
}
qemu_socket_set_nonblock(fd);

View File

@ -14,6 +14,9 @@
# Allow client connections for VNC, Spice and socket based
# character devices to be passed in to QEMU via SCM_RIGHTS.
#
# If the FD associated with @fdname is not a socket, the command will fail and
# the FD will be closed.
#
# @protocol: protocol name. Valid names are "vnc", "spice", "@dbus-display" or
# the name of a character device (eg. from -chardev id=XXXX)
#
@ -270,7 +273,38 @@
# <- { "return": {} }
#
##
{ 'command': 'getfd', 'data': {'fdname': 'str'} }
{ 'command': 'getfd', 'data': {'fdname': 'str'}, 'if': 'CONFIG_POSIX' }
##
# @get-win32-socket:
#
# Add a socket that was duplicated to QEMU process with
# WSADuplicateSocketW() via WSASocket() & WSAPROTOCOL_INFOW structure
# and assign it a name (the SOCKET is associated with a CRT file
# descriptor)
#
# @info: the WSAPROTOCOL_INFOW structure (encoded in base64)
#
# @fdname: file descriptor name
#
# Returns: Nothing on success
#
# Since: 8.0
#
# Notes: If @fdname already exists, the file descriptor assigned to
# it will be closed and replaced by the received file
# descriptor.
#
# The 'closefd' command can be used to explicitly close the
# file descriptor when it is no longer needed.
#
# Example:
#
# -> { "execute": "get-win32-socket", "arguments": { "info": "abcd123..", fdname": "skclient" } }
# <- { "return": {} }
#
##
{ 'command': 'get-win32-socket', 'data': {'info': 'str', 'fdname': 'str'}, 'if': 'CONFIG_WIN32' }
##
# @closefd:

View File

@ -23,10 +23,10 @@ import enum
import tempfile
import re
import signal
import getpass
from tarfile import TarFile, TarInfo
from io import StringIO, BytesIO
from shutil import copy, rmtree
from pwd import getpwuid
from datetime import datetime, timedelta
@ -316,7 +316,7 @@ class Docker(object):
if user:
uid = os.getuid()
uname = getpwuid(uid).pw_name
uname = getpass.getuser()
tmp_df.write("\n")
tmp_df.write("RUN id %s 2>/dev/null || useradd -u %d -U %s" %
(uname, uid, uname))
@ -570,7 +570,7 @@ class UpdateCommand(SubCommand):
if args.user:
uid = os.getuid()
uname = getpwuid(uid).pw_name
uname = getpass.getuser()
df.write("\n")
df.write("RUN id %s 2>/dev/null || useradd -u %d -U %s" %
(uname, uid, uname))

View File

@ -124,7 +124,7 @@ static int socket_accept(int sock)
(void *)&timeout, sizeof(timeout))) {
fprintf(stderr, "%s failed to set SO_RCVTIMEO: %s\n",
__func__, strerror(errno));
closesocket(sock);
close(sock);
return -1;
}
@ -135,7 +135,7 @@ static int socket_accept(int sock)
if (ret == -1) {
fprintf(stderr, "%s failed: %s\n", __func__, strerror(errno));
}
closesocket(sock);
close(sock);
return ret;
}
@ -564,8 +564,8 @@ void qtest_quit(QTestState *s)
qtest_remove_abrt_handler(s);
qtest_kill_qemu(s);
closesocket(s->fd);
closesocket(s->qmp_fd);
close(s->fd);
close(s->qmp_fd);
g_string_free(s->rx, true);
for (GList *it = s->pending_events; it != NULL; it = it->next) {
@ -1478,13 +1478,28 @@ void qtest_qmp_device_add(QTestState *qts, const char *driver, const char *id,
qobject_unref(args);
}
#ifndef _WIN32
void qtest_qmp_add_client(QTestState *qts, const char *protocol, int fd)
{
QDict *resp;
#ifdef WIN32
WSAPROTOCOL_INFOW info;
g_autofree char *info64 = NULL;
SOCKET s;
assert(fd_is_socket(fd));
s = _get_osfhandle(fd);
if (WSADuplicateSocketW(s, GetProcessId((HANDLE)qts->qemu_pid), &info) == SOCKET_ERROR) {
g_autofree char *emsg = g_win32_error_message(WSAGetLastError());
g_error("WSADuplicateSocketW failed: %s", emsg);
}
info64 = g_base64_encode((guchar *)&info, sizeof(info));
resp = qtest_qmp(qts, "{'execute': 'get-win32-socket',"
"'arguments': {'fdname': 'fdname', 'info': %s}}", info64);
#else
resp = qtest_qmp_fds(qts, &fd, 1, "{'execute': 'getfd',"
"'arguments': {'fdname': 'fdname'}}");
#endif
g_assert(resp);
g_assert(!qdict_haskey(resp, "event")); /* We don't expect any events */
g_assert(!qdict_haskey(resp, "error"));
@ -1498,7 +1513,6 @@ void qtest_qmp_add_client(QTestState *qts, const char *protocol, int fd)
g_assert(!qdict_haskey(resp, "error"));
qobject_unref(resp);
}
#endif
/*
* Generic hot-unplugging test via the device_del QMP command.

View File

@ -758,17 +758,16 @@ void qtest_qmp_device_add_qdict(QTestState *qts, const char *drv,
void qtest_qmp_device_add(QTestState *qts, const char *driver, const char *id,
const char *fmt, ...) G_GNUC_PRINTF(4, 5);
#ifndef _WIN32
/**
* qtest_qmp_add_client:
* @qts: QTestState instance to operate on
* @protocol: the protocol to add to
* @fd: the client file-descriptor
*
* Call QMP ``getfd`` followed by ``add_client`` with the given @fd.
* Call QMP ``getfd`` (on Windows ``get-win32-socket``) followed by
* ``add_client`` with the given @fd.
*/
void qtest_qmp_add_client(QTestState *qts, const char *protocol, int fd);
#endif /* _WIN32 */
/**
* qtest_qmp_device_del_send:

View File

@ -107,7 +107,7 @@ static void test_nrf51_uart(void)
g_assert_true(recv(sock_fd, s, 10, 0) == 5);
g_assert_true(memcmp(s, "world", 5) == 0);
closesocket(sock_fd);
close(sock_fd);
qtest_quit(qts);
}

View File

@ -99,7 +99,7 @@ static int inet_get_free_port_multiple(int nb, int *port, bool ipv6)
nb = i;
for (i = 0; i < nb; i++) {
closesocket(sock[i]);
close(sock[i]);
}
return nb;
@ -361,8 +361,8 @@ static void test_stream_fd(void)
qtest_quit(qts1);
qtest_quit(qts0);
closesocket(sock[0]);
closesocket(sock[1]);
close(sock[0]);
close(sock[1]);
}
#endif
@ -487,8 +487,8 @@ static void test_dgram_fd(void)
qtest_quit(qts1);
qtest_quit(qts0);
closesocket(sv[0]);
closesocket(sv[1]);
close(sv[0]);
close(sv[1]);
}
#endif

View File

@ -19,7 +19,7 @@ typedef struct Test {
GMainLoop *loop;
} Test;
#if !defined(WIN32) && !defined(CONFIG_DARWIN)
#if !defined(CONFIG_DARWIN)
static void on_vnc_error(VncConnection* self,
const char* msg)
@ -38,10 +38,7 @@ static void on_vnc_auth_failure(VncConnection *self,
static bool
test_setup(Test *test)
{
#ifdef WIN32
g_test_skip("Not supported on Windows yet");
return false;
#elif defined(CONFIG_DARWIN)
#if defined(CONFIG_DARWIN)
g_test_skip("Broken on Darwin");
return false;
#else
@ -59,7 +56,12 @@ test_setup(Test *test)
g_signal_connect(test->conn, "vnc-auth-failure",
G_CALLBACK(on_vnc_auth_failure), NULL);
vnc_connection_set_auth_type(test->conn, VNC_CONNECTION_AUTH_NONE);
#ifdef WIN32
vnc_connection_open_fd(test->conn, _get_osfhandle(pair[0]));
#else
vnc_connection_open_fd(test->conn, pair[0]);
#endif
test->loop = g_main_loop_new(NULL, FALSE);
return true;

View File

@ -11,6 +11,7 @@ tests = {
'check-qobject': [],
'check-qjson': [],
'check-qlit': [],
'test-error-report': [],
'test-qobject-output-visitor': [testqapi],
'test-clone-visitor': [testqapi],
'test-qobject-input-visitor': [testqapi],

View File

@ -160,7 +160,7 @@ void socket_check_afunix_support(bool *has_afunix)
int fd;
fd = socket(PF_UNIX, SOCK_STREAM, 0);
closesocket(fd);
close(fd);
#ifdef _WIN32
*has_afunix = (fd != (int)INVALID_SOCKET);

View File

@ -0,0 +1,139 @@
/*
* Error reporting test
*
* Copyright (C) 2022 Red Hat Inc.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "glib-compat.h"
#include <locale.h>
#include "qemu/error-report.h"
#include "qapi/error.h"
static void
test_error_report_simple(void)
{
if (g_test_subprocess()) {
error_report("%s", "test error");
warn_report("%s", "test warn");
info_report("%s", "test info");
return;
}
g_test_trap_subprocess(NULL, 0, 0);
g_test_trap_assert_passed();
g_test_trap_assert_stderr("\
test-error-report: test error*\
test-error-report: warning: test warn*\
test-error-report: info: test info*\
");
}
static void
test_error_report_loc(void)
{
if (g_test_subprocess()) {
loc_set_file("some-file.c", 7717);
error_report("%s", "test error1");
loc_set_none();
error_report("%s", "test error2");
return;
}
g_test_trap_subprocess(NULL, 0, 0);
g_test_trap_assert_passed();
g_test_trap_assert_stderr("\
test-error-report:some-file.c:7717: test error1*\
test-error-report: test error2*\
");
}
static void
test_error_report_glog(void)
{
if (g_test_subprocess()) {
g_message("gmessage");
return;
}
g_test_trap_subprocess(NULL, 0, 0);
g_test_trap_assert_passed();
g_test_trap_assert_stderr("test-error-report: info: gmessage*");
}
static void
test_error_report_once(void)
{
int i;
if (g_test_subprocess()) {
for (i = 0; i < 3; i++) {
warn_report_once("warn");
error_report_once("err");
}
return;
}
g_test_trap_subprocess(NULL, 0, 0);
g_test_trap_assert_passed();
g_test_trap_assert_stderr("\
test-error-report: warning: warn*\
test-error-report: err*\
");
}
static void
test_error_report_timestamp(void)
{
if (g_test_subprocess()) {
message_with_timestamp = true;
warn_report("warn");
error_report("err");
return;
}
g_test_trap_subprocess(NULL, 0, 0);
g_test_trap_assert_passed();
g_test_trap_assert_stderr("\
*-*-*:*:* test-error-report: warning: warn*\
*-*-*:*:* test-error-report: err*\
");
}
static void
test_error_warn(void)
{
if (g_test_subprocess()) {
error_setg(&error_warn, "Testing &error_warn");
return;
}
g_test_trap_subprocess(NULL, 0, 0);
g_test_trap_assert_passed();
g_test_trap_assert_stderr("\
test-error-report: warning: Testing &error_warn*\
");
}
int
main(int argc, char *argv[])
{
setlocale(LC_ALL, "");
g_test_init(&argc, &argv, NULL);
error_init("test-error-report");
g_test_add_func("/error-report/simple", test_error_report_simple);
g_test_add_func("/error-report/loc", test_error_report_loc);
g_test_add_func("/error-report/glog", test_error_report_glog);
g_test_add_func("/error-report/once", test_error_report_once);
g_test_add_func("/error-report/timestamp", test_error_report_timestamp);
g_test_add_func("/error-report/warn", test_error_warn);
return g_test_run();
}

View File

@ -35,7 +35,7 @@ static char *socat = NULL;
static void test_io_channel_command_fifo(bool async)
{
g_autofree gchar *tmpdir = g_dir_make_tmp("qemu-test-io-channel.XXXXXX", NULL);
g_autofree gchar *fifo = g_strdup_printf("%s/%s", tmpdir, TEST_FIFO);
g_autofree gchar *fifo = g_build_filename(tmpdir, TEST_FIFO, NULL);
g_autofree gchar *srcargs = g_strdup_printf("%s - PIPE:%s,wronly", socat, fifo);
g_autofree gchar *dstargs = g_strdup_printf("%s PIPE:%s,rdonly -", socat, fifo);
g_auto(GStrv) srcargv = g_strsplit(srcargs, " ", -1);

View File

@ -180,9 +180,9 @@ void aio_set_fd_handler(AioContext *ctx,
}
}
void aio_set_fd_poll(AioContext *ctx, int fd,
IOHandler *io_poll_begin,
IOHandler *io_poll_end)
static void aio_set_fd_poll(AioContext *ctx, int fd,
IOHandler *io_poll_begin,
IOHandler *io_poll_end)
{
AioHandler *node = find_aio_handler(ctx, fd);

View File

@ -22,6 +22,7 @@
#include "qemu/sockets.h"
#include "qapi/error.h"
#include "qemu/rcu_queue.h"
#include "qemu/error-report.h"
struct AioHandler {
EventNotifier *e;
@ -70,13 +71,20 @@ void aio_set_fd_handler(AioContext *ctx,
IOHandler *io_poll_ready,
void *opaque)
{
/* fd is a SOCKET in our case */
AioHandler *old_node;
AioHandler *node = NULL;
SOCKET s;
if (!fd_is_socket(fd)) {
error_report("fd=%d is not a socket, AIO implementation is missing", fd);
return;
}
s = _get_osfhandle(fd);
qemu_lockcnt_lock(&ctx->list_lock);
QLIST_FOREACH(old_node, &ctx->aio_handlers, node) {
if (old_node->pfd.fd == fd && !old_node->deleted) {
if (old_node->pfd.fd == s && !old_node->deleted) {
break;
}
}
@ -87,7 +95,7 @@ void aio_set_fd_handler(AioContext *ctx,
/* Alloc and insert if it's not already there */
node = g_new0(AioHandler, 1);
node->pfd.fd = fd;
node->pfd.fd = s;
node->pfd.events = 0;
if (node->io_read) {
@ -115,7 +123,7 @@ void aio_set_fd_handler(AioContext *ctx,
QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, node, node);
event = event_notifier_get_handle(&ctx->notifier);
WSAEventSelect(node->pfd.fd, event, bitmask);
qemu_socket_select(fd, event, bitmask, NULL);
}
if (old_node) {
aio_remove_fd_handler(ctx, old_node);
@ -125,13 +133,6 @@ void aio_set_fd_handler(AioContext *ctx,
aio_notify(ctx);
}
void aio_set_fd_poll(AioContext *ctx, int fd,
IOHandler *io_poll_begin,
IOHandler *io_poll_end)
{
/* Not implemented */
}
void aio_set_event_notifier(AioContext *ctx,
EventNotifier *e,
bool is_external,

View File

@ -27,8 +27,9 @@ struct Error
Error *error_abort;
Error *error_fatal;
Error *error_warn;
static void error_handle_fatal(Error **errp, Error *err)
static void error_handle(Error **errp, Error *err)
{
if (errp == &error_abort) {
fprintf(stderr, "Unexpected error in %s() at %s:%d:\n",
@ -43,6 +44,9 @@ static void error_handle_fatal(Error **errp, Error *err)
error_report_err(err);
exit(1);
}
if (errp == &error_warn) {
warn_report_err(err);
}
}
G_GNUC_PRINTF(6, 0)
@ -71,7 +75,7 @@ static void error_setv(Error **errp,
err->line = line;
err->func = func;
error_handle_fatal(errp, err);
error_handle(errp, err);
*errp = err;
errno = saved_errno;
@ -284,7 +288,7 @@ void error_propagate(Error **dst_errp, Error *local_err)
if (!local_err) {
return;
}
error_handle_fatal(dst_errp, local_err);
error_handle(dst_errp, local_err);
if (dst_errp && !*dst_errp) {
*dst_errp = local_err;
} else {

View File

@ -252,10 +252,6 @@ static int max_priority;
static int glib_pollfds_idx;
static int glib_n_poll_fds;
void qemu_fd_register(int fd)
{
}
static void glib_pollfds_fill(int64_t *cur_timeout)
{
GMainContext *context = g_main_context_default();
@ -414,13 +410,6 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
}
}
void qemu_fd_register(int fd)
{
WSAEventSelect(fd, event_notifier_get_handle(&qemu_aio_context->notifier),
FD_READ | FD_ACCEPT | FD_CLOSE |
FD_CONNECT | FD_WRITE | FD_OOB);
}
static int pollfds_fill(GArray *pollfds, fd_set *rfds, fd_set *wfds,
fd_set *xfds)
{

View File

@ -583,76 +583,6 @@ char *qemu_get_pid_name(pid_t pid)
}
pid_t qemu_fork(Error **errp)
{
sigset_t oldmask, newmask;
struct sigaction sig_action;
int saved_errno;
pid_t pid;
/*
* Need to block signals now, so that child process can safely
* kill off caller's signal handlers without a race.
*/
sigfillset(&newmask);
if (pthread_sigmask(SIG_SETMASK, &newmask, &oldmask) != 0) {
error_setg_errno(errp, errno,
"cannot block signals");
return -1;
}
pid = fork();
saved_errno = errno;
if (pid < 0) {
/* attempt to restore signal mask, but ignore failure, to
* avoid obscuring the fork failure */
(void)pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
error_setg_errno(errp, saved_errno,
"cannot fork child process");
errno = saved_errno;
return -1;
} else if (pid) {
/* parent process */
/* Restore our original signal mask now that the child is
* safely running. Only documented failures are EFAULT (not
* possible, since we are using just-grabbed mask) or EINVAL
* (not possible, since we are using correct arguments). */
(void)pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
} else {
/* child process */
size_t i;
/* Clear out all signal handlers from parent so nothing
* unexpected can happen in our child once we unblock
* signals */
sig_action.sa_handler = SIG_DFL;
sig_action.sa_flags = 0;
sigemptyset(&sig_action.sa_mask);
for (i = 1; i < NSIG; i++) {
/* Only possible errors are EFAULT or EINVAL The former
* won't happen, the latter we expect, so no need to check
* return value */
(void)sigaction(i, &sig_action, NULL);
}
/* Unmask all signals in child, since we've no idea what the
* caller's done with their signal mask and don't want to
* propagate that to children */
sigemptyset(&newmask);
if (pthread_sigmask(SIG_SETMASK, &newmask, NULL) != 0) {
Error *local_err = NULL;
error_setg_errno(&local_err, errno,
"cannot unblock signals");
error_report_err(local_err);
_exit(1);
}
}
return pid;
}
void *qemu_alloc_stack(size_t *sz)
{
void *ptr, *guardpage;

View File

@ -180,7 +180,7 @@ static int socket_error(void)
void qemu_socket_set_block(int fd)
{
unsigned long opt = 0;
WSAEventSelect(fd, NULL, 0);
qemu_socket_unselect(fd, NULL);
ioctlsocket(fd, FIONBIO, &opt);
}
@ -283,21 +283,155 @@ char *qemu_get_pid_name(pid_t pid)
}
pid_t qemu_fork(Error **errp)
bool qemu_socket_select(int sockfd, WSAEVENT hEventObject,
long lNetworkEvents, Error **errp)
{
errno = ENOSYS;
error_setg_errno(errp, errno,
"cannot fork child process");
return -1;
SOCKET s = _get_osfhandle(sockfd);
if (errp == NULL) {
errp = &error_warn;
}
if (s == INVALID_SOCKET) {
error_setg(errp, "invalid socket fd=%d", sockfd);
return false;
}
if (WSAEventSelect(s, hEventObject, lNetworkEvents) != 0) {
error_setg_win32(errp, WSAGetLastError(), "failed to WSAEventSelect()");
return false;
}
return true;
}
bool qemu_socket_unselect(int sockfd, Error **errp)
{
return qemu_socket_select(sockfd, NULL, 0, errp);
}
int qemu_socketpair(int domain, int type, int protocol, int sv[2])
{
struct sockaddr_un addr = {
0,
};
socklen_t socklen;
int listener = -1;
int client = -1;
int server = -1;
g_autofree char *path = NULL;
int tmpfd;
u_long arg;
int ret = -1;
g_return_val_if_fail(sv != NULL, -1);
addr.sun_family = AF_UNIX;
socklen = sizeof(addr);
tmpfd = g_file_open_tmp(NULL, &path, NULL);
if (tmpfd == -1 || !path) {
errno = EACCES;
goto out;
}
close(tmpfd);
if (strlen(path) >= sizeof(addr.sun_path)) {
errno = EINVAL;
goto out;
}
strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
listener = socket(domain, type, protocol);
if (listener == -1) {
goto out;
}
if (DeleteFile(path) == 0 && GetLastError() != ERROR_FILE_NOT_FOUND) {
errno = EACCES;
goto out;
}
g_clear_pointer(&path, g_free);
if (bind(listener, (struct sockaddr *)&addr, socklen) == -1) {
goto out;
}
if (listen(listener, 1) == -1) {
goto out;
}
client = socket(domain, type, protocol);
if (client == -1) {
goto out;
}
arg = 1;
if (ioctlsocket(client, FIONBIO, &arg) != NO_ERROR) {
goto out;
}
if (connect(client, (struct sockaddr *)&addr, socklen) == -1 &&
WSAGetLastError() != WSAEWOULDBLOCK) {
goto out;
}
server = accept(listener, NULL, NULL);
if (server == -1) {
goto out;
}
arg = 0;
if (ioctlsocket(client, FIONBIO, &arg) != NO_ERROR) {
goto out;
}
arg = 0;
if (ioctlsocket(client, SIO_AF_UNIX_GETPEERPID, &arg) != NO_ERROR) {
goto out;
}
if (arg != GetCurrentProcessId()) {
errno = EPERM;
goto out;
}
sv[0] = server;
server = -1;
sv[1] = client;
client = -1;
ret = 0;
out:
if (listener != -1) {
close(listener);
}
if (client != -1) {
close(client);
}
if (server != -1) {
close(server);
}
if (path) {
DeleteFile(path);
}
return ret;
}
#undef connect
int qemu_connect_wrap(int sockfd, const struct sockaddr *addr,
socklen_t addrlen)
{
int ret;
ret = connect(sockfd, addr, addrlen);
SOCKET s = _get_osfhandle(sockfd);
if (s == INVALID_SOCKET) {
return -1;
}
ret = connect(s, addr, addrlen);
if (ret < 0) {
if (WSAGetLastError() == WSAEWOULDBLOCK) {
errno = EINPROGRESS;
@ -313,7 +447,13 @@ int qemu_connect_wrap(int sockfd, const struct sockaddr *addr,
int qemu_listen_wrap(int sockfd, int backlog)
{
int ret;
ret = listen(sockfd, backlog);
SOCKET s = _get_osfhandle(sockfd);
if (s == INVALID_SOCKET) {
return -1;
}
ret = listen(s, backlog);
if (ret < 0) {
errno = socket_error();
}
@ -326,7 +466,13 @@ int qemu_bind_wrap(int sockfd, const struct sockaddr *addr,
socklen_t addrlen)
{
int ret;
ret = bind(sockfd, addr, addrlen);
SOCKET s = _get_osfhandle(sockfd);
if (s == INVALID_SOCKET) {
return -1;
}
ret = bind(s, addr, addrlen);
if (ret < 0) {
errno = socket_error();
}
@ -334,15 +480,82 @@ int qemu_bind_wrap(int sockfd, const struct sockaddr *addr,
}
#undef close
int qemu_close_wrap(int fd)
{
int ret;
DWORD flags = 0;
SOCKET s = INVALID_SOCKET;
if (fd_is_socket(fd)) {
s = _get_osfhandle(fd);
/*
* If we were to just call _close on the descriptor, it would close the
* HANDLE, but it wouldn't free any of the resources associated to the
* SOCKET, and we can't call _close after calling closesocket, because
* closesocket has already closed the HANDLE, and _close would attempt to
* close the HANDLE again, resulting in a double free. We can however
* protect the HANDLE from actually being closed long enough to close the
* file descriptor, then close the socket itself.
*/
if (!GetHandleInformation((HANDLE)s, &flags)) {
errno = EACCES;
return -1;
}
if (!SetHandleInformation((HANDLE)s, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE)) {
errno = EACCES;
return -1;
}
}
ret = close(fd);
if (s != INVALID_SOCKET && !SetHandleInformation((HANDLE)s, flags, flags)) {
errno = EACCES;
return -1;
}
/*
* close() returns EBADF since we PROTECT_FROM_CLOSE the underlying handle,
* but the FD is actually freed
*/
if (ret < 0 && (s == INVALID_SOCKET || errno != EBADF)) {
return ret;
}
if (s != INVALID_SOCKET) {
ret = closesocket(s);
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) {
SOCKET s;
int fd;
s = socket(domain, type, protocol);
if (s == -1) {
errno = socket_error();
return -1;
}
return ret;
fd = _open_osfhandle(s, _O_BINARY);
if (fd < 0) {
closesocket(s);
/* _open_osfhandle may not set errno, and closesocket() may override it */
errno = ENOMEM;
}
return fd;
}
@ -350,12 +563,27 @@ int qemu_socket_wrap(int domain, int type, int protocol)
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();
int fd;
SOCKET s = _get_osfhandle(sockfd);
if (s == INVALID_SOCKET) {
return -1;
}
return ret;
s = accept(s, addr, addrlen);
if (s == -1) {
errno = socket_error();
return -1;
}
fd = _open_osfhandle(s, _O_BINARY);
if (fd < 0) {
closesocket(s);
/* _open_osfhandle may not set errno, and closesocket() may override it */
errno = ENOMEM;
}
return fd;
}
@ -363,7 +591,13 @@ int qemu_accept_wrap(int sockfd, struct sockaddr *addr,
int qemu_shutdown_wrap(int sockfd, int how)
{
int ret;
ret = shutdown(sockfd, how);
SOCKET s = _get_osfhandle(sockfd);
if (s == INVALID_SOCKET) {
return -1;
}
ret = shutdown(s, how);
if (ret < 0) {
errno = socket_error();
}
@ -375,19 +609,13 @@ int qemu_shutdown_wrap(int sockfd, int how)
int qemu_ioctlsocket_wrap(int fd, int req, void *val)
{
int ret;
ret = ioctlsocket(fd, req, val);
if (ret < 0) {
errno = socket_error();
SOCKET s = _get_osfhandle(fd);
if (s == INVALID_SOCKET) {
return -1;
}
return ret;
}
#undef closesocket
int qemu_closesocket_wrap(int fd)
{
int ret;
ret = closesocket(fd);
ret = ioctlsocket(s, req, val);
if (ret < 0) {
errno = socket_error();
}
@ -400,7 +628,13 @@ int qemu_getsockopt_wrap(int sockfd, int level, int optname,
void *optval, socklen_t *optlen)
{
int ret;
ret = getsockopt(sockfd, level, optname, optval, optlen);
SOCKET s = _get_osfhandle(sockfd);
if (s == INVALID_SOCKET) {
return -1;
}
ret = getsockopt(s, level, optname, optval, optlen);
if (ret < 0) {
errno = socket_error();
}
@ -413,7 +647,13 @@ 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);
SOCKET s = _get_osfhandle(sockfd);
if (s == INVALID_SOCKET) {
return -1;
}
ret = setsockopt(s, level, optname, optval, optlen);
if (ret < 0) {
errno = socket_error();
}
@ -426,7 +666,13 @@ int qemu_getpeername_wrap(int sockfd, struct sockaddr *addr,
socklen_t *addrlen)
{
int ret;
ret = getpeername(sockfd, addr, addrlen);
SOCKET s = _get_osfhandle(sockfd);
if (s == INVALID_SOCKET) {
return -1;
}
ret = getpeername(s, addr, addrlen);
if (ret < 0) {
errno = socket_error();
}
@ -439,7 +685,13 @@ int qemu_getsockname_wrap(int sockfd, struct sockaddr *addr,
socklen_t *addrlen)
{
int ret;
ret = getsockname(sockfd, addr, addrlen);
SOCKET s = _get_osfhandle(sockfd);
if (s == INVALID_SOCKET) {
return -1;
}
ret = getsockname(s, addr, addrlen);
if (ret < 0) {
errno = socket_error();
}
@ -451,7 +703,13 @@ int qemu_getsockname_wrap(int sockfd, struct sockaddr *addr,
ssize_t qemu_send_wrap(int sockfd, const void *buf, size_t len, int flags)
{
int ret;
ret = send(sockfd, buf, len, flags);
SOCKET s = _get_osfhandle(sockfd);
if (s == INVALID_SOCKET) {
return -1;
}
ret = send(s, buf, len, flags);
if (ret < 0) {
errno = socket_error();
}
@ -464,7 +722,13 @@ 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);
SOCKET s = _get_osfhandle(sockfd);
if (s == INVALID_SOCKET) {
return -1;
}
ret = sendto(s, buf, len, flags, addr, addrlen);
if (ret < 0) {
errno = socket_error();
}
@ -476,7 +740,13 @@ ssize_t qemu_sendto_wrap(int sockfd, const void *buf, size_t len, int flags,
ssize_t qemu_recv_wrap(int sockfd, void *buf, size_t len, int flags)
{
int ret;
ret = recv(sockfd, buf, len, flags);
SOCKET s = _get_osfhandle(sockfd);
if (s == INVALID_SOCKET) {
return -1;
}
ret = recv(s, buf, len, flags);
if (ret < 0) {
errno = socket_error();
}
@ -489,7 +759,13 @@ 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);
SOCKET s = _get_osfhandle(sockfd);
if (s == INVALID_SOCKET) {
return -1;
}
ret = recvfrom(s, buf, len, flags, addr, addrlen);
if (ret < 0) {
errno = socket_error();
}

View File

@ -326,7 +326,7 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
* recover from this situation, so we need to recreate the
* socket to allow bind attempts for subsequent ports:
*/
closesocket(slisten);
close(slisten);
slisten = -1;
}
}
@ -337,7 +337,7 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
listen_failed:
saved_errno = errno;
if (slisten >= 0) {
closesocket(slisten);
close(slisten);
}
freeaddrinfo(res);
errno = saved_errno;
@ -380,7 +380,7 @@ static int inet_connect_addr(const InetSocketAddress *saddr,
if (rc < 0) {
error_setg_errno(errp, errno, "Failed to connect to '%s:%s'",
saddr->host, saddr->port);
closesocket(sock);
close(sock);
return -1;
}
@ -483,7 +483,7 @@ int inet_connect_saddr(InetSocketAddress *saddr, Error **errp)
if (ret < 0) {
error_setg_errno(errp, errno, "Unable to set KEEPALIVE");
closesocket(sock);
close(sock);
return -1;
}
}
@ -580,7 +580,7 @@ static int inet_dgram_saddr(InetSocketAddress *sraddr,
err:
if (sock != -1) {
closesocket(sock);
close(sock);
}
if (local) {
freeaddrinfo(local);
@ -777,7 +777,7 @@ static int vsock_connect_addr(const VsockSocketAddress *vaddr,
if (rc < 0) {
error_setg_errno(errp, errno, "Failed to connect to '%s:%s'",
vaddr->cid, vaddr->port);
closesocket(sock);
close(sock);
return -1;
}
@ -814,13 +814,13 @@ static int vsock_listen_saddr(VsockSocketAddress *vaddr,
if (bind(slisten, (const struct sockaddr *)&svm, sizeof(svm)) != 0) {
error_setg_errno(errp, errno, "Failed to bind socket");
closesocket(slisten);
close(slisten);
return -1;
}
if (listen(slisten, num) != 0) {
error_setg_errno(errp, errno, "Failed to listen on socket");
closesocket(slisten);
close(slisten);
return -1;
}
return slisten;
@ -978,7 +978,7 @@ static int unix_listen_saddr(UnixSocketAddress *saddr,
err:
g_free(pathbuf);
closesocket(sock);
close(sock);
return -1;
}
@ -1041,7 +1041,7 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp)
return sock;
err:
closesocket(sock);
close(sock);
return -1;
}
@ -1238,7 +1238,7 @@ int socket_listen(SocketAddress *addr, int num, Error **errp)
*/
if (listen(fd, num) != 0) {
error_setg_errno(errp, errno, "Failed to listen on fd socket");
closesocket(fd);
close(fd);
return -1;
}
break;