Better (and portable) fd_set handling for NetDll_select, and properly tracks guest handles as well.

This commit is contained in:
gibbed 2017-01-09 08:00:42 -06:00
parent d43af82889
commit 5cbb542fa3

View file

@ -727,38 +727,47 @@ dword_result_t NetDll_accept(dword_t caller, dword_t socket_handle,
DECLARE_XAM_EXPORT(NetDll_accept, DECLARE_XAM_EXPORT(NetDll_accept,
ExportTag::kImplemented | ExportTag::kNetworking); ExportTag::kImplemented | ExportTag::kNetworking);
void LoadFdset(const uint8_t* src, fd_set* dest) { typedef struct x_fd_set {
dest->fd_count = xe::load_and_swap<uint32_t>(src); xe::be<uint32_t> fd_count;
for (u_int i = 0; i < 64; ++i) { xe::be<uint32_t> fd_array[64];
SOCKET native_handle = INVALID_SOCKET; } x_fd_set;
if (i < dest->fd_count) {
auto socket_handle = struct host_set {
static_cast<X_HANDLE>(xe::load_and_swap<uint32_t>(src + 4 + i * 4)); uint32_t fd_count;
if (socket_handle) { object_ref<XSocket> sockets[64];
// Convert from Xenia -> native };
auto socket = kernel_state()->object_table()->LookupObject<XSocket>(
socket_handle); void LoadFdset(const x_fd_set* guest_set, host_set* host_set) {
assert_not_null(socket); assert_true(guest_set->fd_count < 64);
native_handle = socket->native_handle(); host_set->fd_count = guest_set->fd_count;
} for (uint32_t i = 0; i < host_set->fd_count; ++i) {
auto socket_handle = static_cast<X_HANDLE>(guest_set->fd_array[i]);
if (socket_handle == -1) {
host_set->fd_count = i;
break;
} }
dest->fd_array[i] = native_handle; // Convert from Xenia -> native
auto socket =
kernel_state()->object_table()->LookupObject<XSocket>(socket_handle);
assert_not_null(socket);
host_set->sockets[i] = socket;
} }
} }
void StoreFdset(const fd_set& src, uint8_t* dest) { void ImportFdset(host_set* host_set, fd_set* native_set) {
xe::store_and_swap<uint32_t>(dest, src.fd_count); FD_ZERO(native_set);
for (u_int i = 0; i < src.fd_count; ++i) { for (uint32_t i = 0; i < host_set->fd_count; ++i) {
SOCKET socket_handle = src.fd_array[i]; FD_SET(host_set->sockets[i]->native_handle(), native_set);
}
}
// TODO: Native -> Xenia void StoreFdset(fd_set* native_set, host_set* host_set, x_fd_set* guest_set) {
guest_set->fd_count = 0;
if (socket_handle != INVALID_SOCKET) { for (uint32_t i = 0; i < host_set->fd_count; ++i) {
assert_true(socket_handle >> 32 == 0); auto socket = host_set->sockets[i];
xe::store_and_swap<uint32_t>(dest + 4 + i * 4, auto native_handle = socket->native_handle();
static_cast<uint32_t>(socket_handle)); if (FD_ISSET(native_handle, native_set)) {
} else { guest_set->fd_array[guest_set->fd_count++] = socket->handle();
xe::store_and_swap<uint32_t>(dest + 4 + i * 4, -1);
} }
} }
} }
@ -775,17 +784,23 @@ SHIM_CALL NetDll_select_shim(PPCContext* ppc_context,
XELOGD("NetDll_select(%d, %d, %.8X, %.8X, %.8X, %.8X)", caller, nfds, XELOGD("NetDll_select(%d, %d, %.8X, %.8X, %.8X, %.8X)", caller, nfds,
readfds_ptr, writefds_ptr, exceptfds_ptr, timeout_ptr); readfds_ptr, writefds_ptr, exceptfds_ptr, timeout_ptr);
host_set hostreadfds = {0};
fd_set readfds = {0}; fd_set readfds = {0};
if (readfds_ptr) { if (readfds_ptr) {
LoadFdset(SHIM_MEM_ADDR(readfds_ptr), &readfds); LoadFdset((x_fd_set*)SHIM_MEM_ADDR(readfds_ptr), &hostreadfds);
ImportFdset(&hostreadfds, &readfds);
} }
host_set hostwritefds = {0};
fd_set writefds = {0}; fd_set writefds = {0};
if (writefds_ptr) { if (writefds_ptr) {
LoadFdset(SHIM_MEM_ADDR(writefds_ptr), &writefds); LoadFdset((x_fd_set*)SHIM_MEM_ADDR(writefds_ptr), &hostwritefds);
ImportFdset(&hostwritefds, &writefds);
} }
host_set hostexceptfds = {0};
fd_set exceptfds = {0}; fd_set exceptfds = {0};
if (exceptfds_ptr) { if (exceptfds_ptr) {
LoadFdset(SHIM_MEM_ADDR(exceptfds_ptr), &exceptfds); LoadFdset((x_fd_set*)SHIM_MEM_ADDR(exceptfds_ptr), &hostexceptfds);
ImportFdset(&hostexceptfds, &exceptfds);
} }
timeval* timeout_in = nullptr; timeval* timeout_in = nullptr;
timeval timeout; timeval timeout;
@ -801,15 +816,18 @@ SHIM_CALL NetDll_select_shim(PPCContext* ppc_context,
writefds_ptr ? &writefds : nullptr, writefds_ptr ? &writefds : nullptr,
exceptfds_ptr ? &exceptfds : nullptr, timeout_in); exceptfds_ptr ? &exceptfds : nullptr, timeout_in);
if (readfds_ptr) { if (readfds_ptr) {
StoreFdset(readfds, SHIM_MEM_ADDR(readfds_ptr)); StoreFdset(&readfds, &hostreadfds, (x_fd_set*)SHIM_MEM_ADDR(readfds_ptr));
} }
if (writefds_ptr) { if (writefds_ptr) {
StoreFdset(writefds, SHIM_MEM_ADDR(writefds_ptr)); StoreFdset(&writefds, &hostwritefds,
(x_fd_set*)SHIM_MEM_ADDR(writefds_ptr));
} }
if (exceptfds_ptr) { if (exceptfds_ptr) {
StoreFdset(exceptfds, SHIM_MEM_ADDR(exceptfds_ptr)); StoreFdset(&exceptfds, &hostexceptfds,
(x_fd_set*)SHIM_MEM_ADDR(exceptfds_ptr));
} }
// TODO(gibbed): modify ret to be what's actually copied to the guest fd_sets?
SHIM_SET_RETURN_32(ret); SHIM_SET_RETURN_32(ret);
} }