Skip to content

Commit

Permalink
win32: avoid mixing SOCKET and file descriptor space
Browse files Browse the repository at this point in the history
Until now, a win32 SOCKET handle is often cast to an int file
descriptor, as this is what other OS use for sockets. When necessary,
QEMU eventually queries whether it's a socket with the help of
fd_is_socket(). However, there is no guarantee of conflict between the
fd and SOCKET space. Such conflict would have surprising consequences,
we shouldn't mix them.

Also, it is often forgotten that SOCKET must be closed with
closesocket(), and not close().

Instead, let's make the win32 socket wrapper functions return and take a
file descriptor, and let util/ wrappers do the fd/SOCKET conversion as
necessary. A bit of adaptation is necessary in io/ as well.

Unfortunately, we can't drop closesocket() usage, despite
_open_osfhandle() documentation claiming transfer of ownership, testing
shows bad behaviour if you forget to call closesocket().

Signed-off-by: Marc-André Lureau <[email protected]>
Reviewed-by: Stefan Berger <[email protected]>
Message-Id: <[email protected]>
  • Loading branch information
elmarco committed Mar 13, 2023
1 parent fd3c333 commit abe3428
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 41 deletions.
4 changes: 2 additions & 2 deletions include/sysemu/os-win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@ static inline void qemu_funlockfile(FILE *f)
}

/* Helper for WSAEventSelect, to report errors */
bool qemu_socket_select(SOCKET s, WSAEVENT hEventObject,
bool qemu_socket_select(int sockfd, WSAEVENT hEventObject,
long lNetworkEvents, Error **errp);

bool qemu_socket_unselect(SOCKET s, 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()
Expand Down
6 changes: 3 additions & 3 deletions io/channel-watch.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,13 +275,13 @@ 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;

qemu_socket_select(socket, ioc->event,
qemu_socket_select(sockfd, ioc->event,
FD_READ | FD_ACCEPT | FD_CLOSE |
FD_CONNECT | FD_WRITE | FD_OOB, NULL);

Expand All @@ -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;
Expand Down
9 changes: 6 additions & 3 deletions util/aio-win32.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,18 @@ void aio_set_fd_handler(AioContext *ctx,
{
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;
}
}
Expand All @@ -92,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) {
Expand Down Expand Up @@ -120,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);
qemu_socket_select(node->pfd.fd, event, bitmask, NULL);
qemu_socket_select(fd, event, bitmask, NULL);
}
if (old_node) {
aio_remove_fd_handler(ctx, old_node);
Expand Down
Loading

0 comments on commit abe3428

Please sign in to comment.