From b36a2d66865ae8205b6a7589b8566f27746002f4 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 16 Sep 2020 11:45:00 -0400 Subject: Kernel+LibC+UserspaceEmulator: Mostly add recvmsg(), sendmsg() The implementation only supports a single iovec for now. Some might say having more than one iovec is the main point of recvmsg() and sendmsg(), but I'm interested in the control message bits. --- DevTools/UserspaceEmulator/Emulator.cpp | 80 ++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 31 deletions(-) (limited to 'DevTools/UserspaceEmulator/Emulator.cpp') diff --git a/DevTools/UserspaceEmulator/Emulator.cpp b/DevTools/UserspaceEmulator/Emulator.cpp index 657a8fa390..f523758f7c 100644 --- a/DevTools/UserspaceEmulator/Emulator.cpp +++ b/DevTools/UserspaceEmulator/Emulator.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -354,10 +355,10 @@ u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3) return virt$listen(arg1, arg2); case SC_select: return virt$select(arg1); - case SC_sendto: - return virt$sendto(arg1); - case SC_recvfrom: - return virt$recvfrom(arg1); + case SC_recvmsg: + return virt$recvmsg(arg1, arg2, arg3); + case SC_sendmsg: + return virt$sendmsg(arg1, arg2, arg3); case SC_kill: return virt$kill(arg1, arg2); case SC_set_mmap_name: @@ -593,49 +594,66 @@ int Emulator::virt$socket(int domain, int type, int protocol) return syscall(SC_socket, domain, type, protocol); } -int Emulator::virt$recvfrom(FlatPtr params_addr) +int Emulator::virt$recvmsg(int sockfd, FlatPtr msg_addr, int flags) { - Syscall::SC_recvfrom_params params; - mmu().copy_from_vm(¶ms, params_addr, sizeof(params)); - auto buffer = ByteBuffer::create_uninitialized(params.buffer.size); + msghdr mmu_msg; + mmu().copy_from_vm(&mmu_msg, msg_addr, sizeof(mmu_msg)); - if (!params.addr_length && params.addr) - return -EINVAL; + if (mmu_msg.msg_iovlen != 1) + return -ENOTSUP; // FIXME: Support this :) + iovec mmu_iov; + mmu().copy_from_vm(&mmu_iov, (FlatPtr)mmu_msg.msg_iov, sizeof(mmu_iov)); + auto buffer = ByteBuffer::create_uninitialized(mmu_iov.iov_len); - socklen_t address_length = 0; - if (params.addr_length) - mmu().copy_from_vm(&address_length, (FlatPtr)params.addr_length, sizeof(address_length)); - - sockaddr_storage address; - if (params.addr) - mmu().copy_from_vm(&address, (FlatPtr)params.addr, min(sizeof(address), (size_t)address_length)); + ByteBuffer control_buffer; + if (mmu_msg.msg_control) + control_buffer = ByteBuffer::create_uninitialized(mmu_msg.msg_controllen); - int rc = recvfrom(params.sockfd, buffer.data(), buffer.size(), params.flags, params.addr ? (struct sockaddr*)&address : nullptr, params.addr_length ? &address_length : nullptr); + sockaddr_storage addr; + iovec iov = { buffer.data(), buffer.size() }; + msghdr msg = { &addr, sizeof(addr), &iov, 1, mmu_msg.msg_control ? control_buffer.data() : nullptr, mmu_msg.msg_controllen, mmu_msg.msg_flags }; + int rc = recvmsg(sockfd, &msg, flags); if (rc < 0) return -errno; - mmu().copy_to_vm((FlatPtr)params.buffer.data, buffer.data(), buffer.size()); - - if (params.addr) - mmu().copy_to_vm((FlatPtr)params.addr, &address, address_length); - if (params.addr_length) - mmu().copy_to_vm((FlatPtr)params.addr_length, &address_length, sizeof(address_length)); + mmu().copy_to_vm((FlatPtr)mmu_iov.iov_base, buffer.data(), mmu_iov.iov_len); + if (mmu_msg.msg_name) + mmu().copy_to_vm((FlatPtr)mmu_msg.msg_name, &addr, min(sizeof(addr), (size_t)mmu_msg.msg_namelen)); + if (mmu_msg.msg_control) + mmu().copy_to_vm((FlatPtr)mmu_msg.msg_control, control_buffer.data(), min(mmu_msg.msg_controllen, msg.msg_controllen)); + mmu_msg.msg_namelen = msg.msg_namelen; + mmu_msg.msg_controllen = msg.msg_controllen; + mmu_msg.msg_flags = msg.msg_flags; + mmu().copy_to_vm(msg_addr, &mmu_msg, sizeof(mmu_msg)); return rc; } -int Emulator::virt$sendto(FlatPtr params_addr) +int Emulator::virt$sendmsg(int sockfd, FlatPtr msg_addr, int flags) { - Syscall::SC_sendto_params params; - mmu().copy_from_vm(¶ms, params_addr, sizeof(params)); + msghdr mmu_msg; + mmu().copy_from_vm(&mmu_msg, msg_addr, sizeof(mmu_msg)); + + if (mmu_msg.msg_iovlen != 1) + return -ENOTSUP; // FIXME: Support this :) + iovec mmu_iov; + mmu().copy_from_vm(&mmu_iov, (FlatPtr)mmu_msg.msg_iov, sizeof(mmu_iov)); + auto buffer = mmu().copy_buffer_from_vm((FlatPtr)mmu_iov.iov_base, mmu_iov.iov_len); - auto buffer = mmu().copy_buffer_from_vm((FlatPtr)params.data.data, params.data.size); + ByteBuffer control_buffer; + if (mmu_msg.msg_control) + control_buffer = ByteBuffer::create_uninitialized(mmu_msg.msg_controllen); sockaddr_storage address; - if (params.addr) - mmu().copy_from_vm(&address, (FlatPtr)params.addr, min(sizeof(address), (size_t)params.addr_length)); + socklen_t address_length = 0; + if (mmu_msg.msg_name) { + address_length = min(sizeof(address), (size_t)mmu_msg.msg_namelen); + mmu().copy_from_vm(&address, (FlatPtr)mmu_msg.msg_name, address_length); + } - return sendto(params.sockfd, buffer.data(), buffer.size(), params.flags, params.addr ? (struct sockaddr*)&address : nullptr, params.addr_length); + iovec iov = { buffer.data(), buffer.size() }; + msghdr msg = { mmu_msg.msg_name ? &address : nullptr, address_length, &iov, 1, mmu_msg.msg_control ? control_buffer.data() : nullptr, mmu_msg.msg_controllen, mmu_msg.msg_flags }; + return sendmsg(sockfd, &msg, flags); } int Emulator::virt$select(FlatPtr params_addr) -- cgit v1.2.3