diff options
| -rw-r--r-- | src/core/hle/service/soc_u.cpp | 73 |
1 files changed, 58 insertions, 15 deletions
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index 9d836349a..1c3ea03a2 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp | |||
| @@ -295,6 +295,26 @@ union CTRSockAddr { | |||
| 295 | } | 295 | } |
| 296 | }; | 296 | }; |
| 297 | 297 | ||
| 298 | /// Filters valid sockopt names and converts from platform-specific name if necessary | ||
| 299 | static int GetSockOptName(u32 name) { | ||
| 300 | switch(name) { | ||
| 301 | case SO_RCVLOWAT: | ||
| 302 | #ifdef _WIN32 | ||
| 303 | // LOWAT not supported by WinSock | ||
| 304 | return -1; | ||
| 305 | #endif | ||
| 306 | case SO_REUSEADDR: | ||
| 307 | case SO_SNDBUF: | ||
| 308 | case SO_RCVBUF: | ||
| 309 | case SO_TYPE: | ||
| 310 | case SO_ERROR: | ||
| 311 | return name; | ||
| 312 | default: | ||
| 313 | // all other options are either ineffectual or unsupported | ||
| 314 | return -1; | ||
| 315 | } | ||
| 316 | } | ||
| 317 | |||
| 298 | /// Holds info about the currently open sockets | 318 | /// Holds info about the currently open sockets |
| 299 | static std::unordered_map<u32, SocketHolder> open_sockets; | 319 | static std::unordered_map<u32, SocketHolder> open_sockets; |
| 300 | 320 | ||
| @@ -728,18 +748,29 @@ static void GetSockOpt(Service::Interface* self) { | |||
| 728 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | 748 | u32* cmd_buffer = Kernel::GetCommandBuffer(); |
| 729 | u32 socket_handle = cmd_buffer[1]; | 749 | u32 socket_handle = cmd_buffer[1]; |
| 730 | u32 level = cmd_buffer[2]; | 750 | u32 level = cmd_buffer[2]; |
| 731 | u32 optname = cmd_buffer[3]; | 751 | int optname = GetSockOptName(cmd_buffer[3]); |
| 732 | socklen_t optlen = (socklen_t)cmd_buffer[4]; | 752 | socklen_t optlen = (socklen_t)cmd_buffer[4]; |
| 733 | 753 | ||
| 734 | // 0x100 = static buffer offset (bytes) | 754 | int ret = -1; |
| 735 | // + 0x4 = 2nd pointer (u32) position | ||
| 736 | // >> 2 = convert to u32 offset instead of byte offset (cmd_buffer = u32*) | ||
| 737 | char* optval = reinterpret_cast<char*>(Memory::GetPointer(cmd_buffer[0x104 >> 2])); | ||
| 738 | |||
| 739 | int ret = ::getsockopt(socket_handle, level, optname, optval, &optlen); | ||
| 740 | int err = 0; | 755 | int err = 0; |
| 741 | if (ret == SOCKET_ERROR_VALUE) { | 756 | |
| 742 | err = TranslateError(GET_ERRNO); | 757 | if(optname < 0) { |
| 758 | #ifdef _WIN32 | ||
| 759 | err = WSAEINVAL; | ||
| 760 | #else | ||
| 761 | err = EINVAL; | ||
| 762 | #endif | ||
| 763 | } else { | ||
| 764 | // 0x100 = static buffer offset (bytes) | ||
| 765 | // + 0x4 = 2nd pointer (u32) position | ||
| 766 | // >> 2 = convert to u32 offset instead of byte offset (cmd_buffer = u32*) | ||
| 767 | char *optval = reinterpret_cast<char *>(Memory::GetPointer(cmd_buffer[0x104 >> 2])); | ||
| 768 | |||
| 769 | ret = ::getsockopt(socket_handle, level, optname, optval, &optlen); | ||
| 770 | err = 0; | ||
| 771 | if (ret == SOCKET_ERROR_VALUE) { | ||
| 772 | err = TranslateError(GET_ERRNO); | ||
| 773 | } | ||
| 743 | } | 774 | } |
| 744 | 775 | ||
| 745 | cmd_buffer[0] = IPC::MakeHeader(0x11, 4, 2); | 776 | cmd_buffer[0] = IPC::MakeHeader(0x11, 4, 2); |
| @@ -752,14 +783,26 @@ static void SetSockOpt(Service::Interface* self) { | |||
| 752 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | 783 | u32* cmd_buffer = Kernel::GetCommandBuffer(); |
| 753 | u32 socket_handle = cmd_buffer[1]; | 784 | u32 socket_handle = cmd_buffer[1]; |
| 754 | u32 level = cmd_buffer[2]; | 785 | u32 level = cmd_buffer[2]; |
| 755 | u32 optname = cmd_buffer[3]; | 786 | int optname = GetSockOptName(cmd_buffer[3]); |
| 756 | socklen_t optlen = static_cast<socklen_t>(cmd_buffer[4]); | ||
| 757 | const char *optval = reinterpret_cast<const char*>(Memory::GetPointer(cmd_buffer[8])); | ||
| 758 | 787 | ||
| 759 | int ret = static_cast<u32>(::setsockopt(socket_handle, level, optname, optval, optlen)); | 788 | int ret = -1; |
| 760 | int err = 0; | 789 | int err = 0; |
| 761 | if (ret == SOCKET_ERROR_VALUE) { | 790 | |
| 762 | err = TranslateError(GET_ERRNO); | 791 | if(optname < 0) { |
| 792 | #ifdef _WIN32 | ||
| 793 | err = WSAEINVAL; | ||
| 794 | #else | ||
| 795 | err = EINVAL; | ||
| 796 | #endif | ||
| 797 | } else { | ||
| 798 | socklen_t optlen = static_cast<socklen_t>(cmd_buffer[4]); | ||
| 799 | const char *optval = reinterpret_cast<const char *>(Memory::GetPointer(cmd_buffer[8])); | ||
| 800 | |||
| 801 | ret = static_cast<u32>(::setsockopt(socket_handle, level, optname, optval, optlen)); | ||
| 802 | err = 0; | ||
| 803 | if (ret == SOCKET_ERROR_VALUE) { | ||
| 804 | err = TranslateError(GET_ERRNO); | ||
| 805 | } | ||
| 763 | } | 806 | } |
| 764 | 807 | ||
| 765 | cmd_buffer[0] = IPC::MakeHeader(0x12, 4, 4); | 808 | cmd_buffer[0] = IPC::MakeHeader(0x12, 4, 4); |