diff --git a/src/windows-emulator/devices/afd_endpoint.cpp b/src/windows-emulator/devices/afd_endpoint.cpp index 17210b33..a9b32d42 100644 --- a/src/windows-emulator/devices/afd_endpoint.cpp +++ b/src/windows-emulator/devices/afd_endpoint.cpp @@ -61,6 +61,135 @@ namespace return {std::move(poll_info), std::move(handle_info)}; } + std::optional perform_poll(windows_emulator& win_emu, const io_device_context& c, + const std::span endpoints, + const std::span handles) + { + std::vector poll_data{}; + poll_data.resize(endpoints.size()); + + for (size_t i = 0; i < endpoints.size() && i < handles.size(); ++i) + { + auto& pfd = poll_data.at(i); + auto& handle = handles[i]; + + if (handle.PollEvents & (AFD_POLL_ACCEPT | AFD_POLL_RECEIVE)) + { + pfd.events |= POLLRDNORM; + } + + if (handle.PollEvents & AFD_POLL_RECEIVE_EXPEDITED) + { + pfd.events |= POLLRDNORM; + } + + if (handle.PollEvents & AFD_POLL_RECEIVE_EXPEDITED) + { + pfd.events |= POLLRDBAND; + } + + if (handle.PollEvents & (AFD_POLL_CONNECT_FAIL | AFD_POLL_SEND)) + { + pfd.events |= POLLWRNORM; + } + + /*if ((pfd.events & POLLRDNORM) != 0) + handle.PollEvents |= (AFD_POLL_ACCEPT | AFD_POLL_RECEIVE); + if ((pfd.events & POLLRDBAND) != 0) + handle.PollEvents |= AFD_POLL_RECEIVE_EXPEDITED; + + if ((pfd.events & POLLWRNORM) != 0) + handle.PollEvents |= (AFD_POLL_CONNECT_FAIL | AFD_POLL_SEND); + handle.PollEvents |= (AFD_POLL_DISCONNECT | AFD_POLL_ABORT);*/ + + // ----------------------------- + + pfd.fd = endpoints[i]; + pfd.events = POLLIN; + pfd.revents = pfd.events; + } + + const auto count = poll(poll_data.data(), static_cast(poll_data.size()), 0); + if (count > 0) + { + constexpr auto info_size = offsetof(AFD_POLL_INFO, Handles); + const emulator_object handle_info_obj{win_emu.emu(), c.input_buffer + info_size}; + + size_t current_index = 0; + + for (size_t i = 0; i < endpoints.size(); ++i) + { + const auto& pfd = poll_data.at(i); + if (pfd.revents == 0) + { + continue; + } + + ULONG events = 0; + + if (pfd.revents & POLLRDNORM) + { + events |= (AFD_POLL_ACCEPT | AFD_POLL_RECEIVE); + } + + if (pfd.revents & POLLRDBAND) + { + events |= AFD_POLL_RECEIVE_EXPEDITED; + } + + if (pfd.revents & POLLWRNORM) + { + events |= (AFD_POLL_CONNECT_FAIL | AFD_POLL_SEND); + } + + if ((pfd.revents & (POLLHUP | POLLERR)) == (POLLHUP | POLLERR)) + { + events |= (AFD_POLL_CONNECT_FAIL | AFD_POLL_ABORT); + } + else if (pfd.revents & POLLHUP) + { + events |= AFD_POLL_DISCONNECT; + } + + if (pfd.revents & POLLNVAL) + { + events |= AFD_POLL_LOCAL_CLOSE; + } + + /*if ((handle.PollEvents & (AFD_POLL_ACCEPT | AFD_POLL_RECEIVE)) != 0 && (pfd.events & POLLRDNORM) != 0) + pfd.revents |= POLLRDNORM; + if ((handle.PollEvents & AFD_POLL_RECEIVE_EXPEDITED) != 0 && (pfd.events & POLLRDBAND) != 0) + pfd.revents |= POLLRDBAND; + if ((handle.PollEvents & (AFD_POLL_CONNECT_FAIL | AFD_POLL_SEND)) != 0 && (pfd.events & POLLWRNORM) != 0) + pfd.revents |= POLLWRNORM; + if ((handle.PollEvents & AFD_POLL_DISCONNECT) != 0) + pfd.revents |= POLLHUP; + if ((handle.PollEvents & (AFD_POLL_CONNECT_FAIL | AFD_POLL_ABORT)) != 0) + pfd.revents |= POLLHUP | POLLERR; + if ((handle.PollEvents & AFD_POLL_LOCAL_CLOSE) != 0) + pfd.revents |= POLLNVAL;*/ + + auto entry = handle_info_obj.read(i); + entry.PollEvents = events; + entry.Status = STATUS_SUCCESS; + + handle_info_obj.write(entry, current_index++); + break; + } + + assert(current_index == static_cast(count)); + + emulator_object{win_emu.emu(), c.input_buffer}.access([&](AFD_POLL_INFO& info) + { + info.NumberOfHandles = count; + }); + + return STATUS_SUCCESS; + } + + return {}; + } + struct afd_endpoint : io_device { bool in_poll{}; @@ -187,12 +316,12 @@ namespace return STATUS_SUCCESS; } - static std::vector resolve_endpoints(windows_emulator& win_emu, - const std::span handles) + static std::vector resolve_endpoints(windows_emulator& win_emu, + const std::span handles) { auto& proc = win_emu.process(); - std::vector endpoints{}; + std::vector endpoints{}; endpoints.reserve(handles.size()); for (const auto& handle : handles) @@ -203,13 +332,13 @@ namespace throw std::runtime_error("Bad device!"); } - auto* endpoint = device->get_internal_device(); + const auto* endpoint = device->get_internal_device(); if (!endpoint) { throw std::runtime_error("Device is not an AFD endpoint!"); } - endpoints.push_back(endpoint); + endpoints.push_back(*endpoint->s); } return endpoints; @@ -221,28 +350,10 @@ namespace const auto [info, handles] = get_poll_info(win_emu, c); const auto endpoints = resolve_endpoints(win_emu, handles); - std::vector poll_data{}; - poll_data.resize(endpoints.size()); - - for (size_t i = 0; i < endpoints.size(); ++i) + const auto status = perform_poll(win_emu, c, endpoints, handles); + if (status) { - auto& pfd = poll_data.at(i); - //auto& handle = handles.at(i); - - pfd.fd = *endpoints.at(i)->s; - pfd.events = POLLIN; - pfd.revents = pfd.events; - } - - const auto count = poll(poll_data.data(), static_cast(poll_data.size()), 0); - if (count > 0) - { - emulator_object{win_emu.emu(), c.input_buffer}.access([&](AFD_POLL_INFO& info) - { - info.NumberOfHandles = count; - }); - - t.pending_status = STATUS_SUCCESS; + t.pending_status = *status; return true; } diff --git a/src/windows-emulator/devices/afd_types.hpp b/src/windows-emulator/devices/afd_types.hpp index 30a87df7..944ae5e4 100644 --- a/src/windows-emulator/devices/afd_types.hpp +++ b/src/windows-emulator/devices/afd_types.hpp @@ -85,6 +85,32 @@ typedef struct _AFD_POLL_INFO AFD_POLL_HANDLE_INFO Handles[1]; } AFD_POLL_INFO, *PAFD_POLL_INFO; +#define AFD_POLL_RECEIVE_BIT 0 +#define AFD_POLL_RECEIVE (1 << AFD_POLL_RECEIVE_BIT) +#define AFD_POLL_RECEIVE_EXPEDITED_BIT 1 +#define AFD_POLL_RECEIVE_EXPEDITED (1 << AFD_POLL_RECEIVE_EXPEDITED_BIT) +#define AFD_POLL_SEND_BIT 2 +#define AFD_POLL_SEND (1 << AFD_POLL_SEND_BIT) +#define AFD_POLL_DISCONNECT_BIT 3 +#define AFD_POLL_DISCONNECT (1 << AFD_POLL_DISCONNECT_BIT) +#define AFD_POLL_ABORT_BIT 4 +#define AFD_POLL_ABORT (1 << AFD_POLL_ABORT_BIT) +#define AFD_POLL_LOCAL_CLOSE_BIT 5 +#define AFD_POLL_LOCAL_CLOSE (1 << AFD_POLL_LOCAL_CLOSE_BIT) +#define AFD_POLL_CONNECT_BIT 6 +#define AFD_POLL_CONNECT (1 << AFD_POLL_CONNECT_BIT) +#define AFD_POLL_ACCEPT_BIT 7 +#define AFD_POLL_ACCEPT (1 << AFD_POLL_ACCEPT_BIT) +#define AFD_POLL_CONNECT_FAIL_BIT 8 +#define AFD_POLL_CONNECT_FAIL (1 << AFD_POLL_CONNECT_FAIL_BIT) +#define AFD_POLL_QOS_BIT 9 +#define AFD_POLL_QOS (1 << AFD_POLL_QOS_BIT) +#define AFD_POLL_GROUP_QOS_BIT 10 +#define AFD_POLL_GROUP_QOS (1 << AFD_POLL_GROUP_QOS_BIT) + +#define AFD_NUM_POLL_EVENTS 11 +#define AFD_POLL_ALL ((1 << AFD_NUM_POLL_EVENTS) - 1) + #define _AFD_REQUEST(ioctl) \ ((((ULONG)(ioctl)) >> 2) & 0x03FF) #define _AFD_BASE(ioctl) \