diff options
Diffstat (limited to '')
-rw-r--r-- | src/VBox/NetworkServices/NAT/RTWinPoll.cpp | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/src/VBox/NetworkServices/NAT/RTWinPoll.cpp b/src/VBox/NetworkServices/NAT/RTWinPoll.cpp new file mode 100644 index 00000000..5e6f5789 --- /dev/null +++ b/src/VBox/NetworkServices/NAT/RTWinPoll.cpp @@ -0,0 +1,154 @@ +/* $Id: RTWinPoll.cpp $ */ +/** @file + * NAT Network - poll(2) implementation for winsock. + */ + +/* + * Copyright (C) 2013-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ +#define LOG_GROUP LOG_GROUP_NAT_SERVICE + +#include <iprt/asm.h> +#include <iprt/assert.h> +#include <iprt/cdefs.h> +#include <iprt/errcore.h> +#include <iprt/string.h> + +#include <iprt/errcore.h> +#include <VBox/log.h> + +#include <iprt/win/winsock2.h> +#include <iprt/win/windows.h> +#include "winpoll.h" + +static HANDLE g_hNetworkEvent; + +int +RTWinPoll(struct pollfd *pFds, unsigned int nfds, int timeout, int *pNready) +{ + AssertPtrReturn(pFds, VERR_INVALID_PARAMETER); + + if (g_hNetworkEvent == WSA_INVALID_EVENT) + { + g_hNetworkEvent = WSACreateEvent(); + AssertReturn(g_hNetworkEvent != WSA_INVALID_EVENT, VERR_INTERNAL_ERROR); + } + + for (unsigned int i = 0; i < nfds; ++i) + { + long eventMask = 0; + short pollEvents = pFds[i].events; + + /* clean revents */ + pFds[i].revents = 0; + + /* ignore invalid sockets */ + if (pFds[i].fd == INVALID_SOCKET) + continue; + + /* + * POLLIN Data other than high priority data may be read without blocking. + * This is equivalent to ( POLLRDNORM | POLLRDBAND ). + * POLLRDBAND Priority data may be read without blocking. + * POLLRDNORM Normal data may be read without blocking. + */ + if (pollEvents & POLLIN) + eventMask |= FD_READ | FD_ACCEPT; + + /* + * POLLOUT Normal data may be written without blocking. This is equivalent + * to POLLWRNORM. + * POLLWRNORM Normal data may be written without blocking. + */ + if (pollEvents & POLLOUT) + eventMask |= FD_WRITE | FD_CONNECT; + + /* + * This is "moral" equivalent to POLLHUP. + */ + eventMask |= FD_CLOSE; + WSAEventSelect(pFds[i].fd, g_hNetworkEvent, eventMask); + } + + DWORD index = WSAWaitForMultipleEvents(1, + &g_hNetworkEvent, + FALSE, + timeout == RT_INDEFINITE_WAIT ? WSA_INFINITE : timeout, + FALSE); + if (index != WSA_WAIT_EVENT_0) + { + if (index == WSA_WAIT_TIMEOUT) + return VERR_TIMEOUT; + } + + int nready = 0; + for (unsigned int i = 0; i < nfds; ++i) + { + short revents = 0; + WSANETWORKEVENTS NetworkEvents; + int err; + + if (pFds[i].fd == INVALID_SOCKET) + continue; + + RT_ZERO(NetworkEvents); + + err = WSAEnumNetworkEvents(pFds[i].fd, + g_hNetworkEvent, + &NetworkEvents); + + if (err == SOCKET_ERROR) + { + if (WSAGetLastError() == WSAENOTSOCK) + { + pFds[i].revents = POLLNVAL; + ++nready; + } + continue; + } + + /* deassociate socket with event */ + WSAEventSelect(pFds[i].fd, g_hNetworkEvent, 0); + +#define WSA_TO_POLL(_wsaev, _pollev) \ + do { \ + if (NetworkEvents.lNetworkEvents & (_wsaev)) { \ + revents |= (_pollev); \ + if (NetworkEvents.iErrorCode[_wsaev##_BIT] != 0) { \ + Log2(("sock %d: %s: %R[sockerr]\n", \ + pFds[i].fd, #_wsaev, \ + NetworkEvents.iErrorCode[_wsaev##_BIT])); \ + revents |= POLLERR; \ + } \ + } \ + } while (0) + + WSA_TO_POLL(FD_READ, POLLIN); + WSA_TO_POLL(FD_ACCEPT, POLLIN); + WSA_TO_POLL(FD_WRITE, POLLOUT); + WSA_TO_POLL(FD_CONNECT, POLLOUT); + WSA_TO_POLL(FD_CLOSE, POLLHUP | (pFds[i].events & POLLIN)); + + Assert((revents & ~(pFds[i].events | POLLHUP | POLLERR)) == 0); + + if (revents != 0) + { + pFds[i].revents = revents; + ++nready; + } + } + WSAResetEvent(g_hNetworkEvent); + + if (pNready) + *pNready = nready; + + return VINF_SUCCESS; +} |