diff options
Diffstat (limited to '')
| -rw-r--r-- | src/core/hle/service/soc_u.cpp | 100 |
1 files changed, 97 insertions, 3 deletions
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index ff0af8f12..d3e5d4bca 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp | |||
| @@ -151,6 +151,34 @@ static int TranslateError(int error) { | |||
| 151 | return error; | 151 | return error; |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | /// Holds the translation from system network socket options to 3DS network socket options | ||
| 155 | /// Note: -1 = No effect/unavailable | ||
| 156 | static const std::unordered_map<int, int> sockopt_map = { { | ||
| 157 | { 0x0004, SO_REUSEADDR }, | ||
| 158 | { 0x0080, -1 }, | ||
| 159 | { 0x0100, -1 }, | ||
| 160 | { 0x1001, SO_SNDBUF }, | ||
| 161 | { 0x1002, SO_RCVBUF }, | ||
| 162 | { 0x1003, -1 }, | ||
| 163 | #ifdef _WIN32 | ||
| 164 | /// Unsupported in WinSock2 | ||
| 165 | { 0x1004, -1 }, | ||
| 166 | #else | ||
| 167 | { 0x1004, SO_RCVLOWAT }, | ||
| 168 | #endif | ||
| 169 | { 0x1008, SO_TYPE }, | ||
| 170 | { 0x1009, SO_ERROR }, | ||
| 171 | }}; | ||
| 172 | |||
| 173 | /// Converts a socket option from 3ds-specific to platform-specific | ||
| 174 | static int TranslateSockOpt(int console_opt_name) { | ||
| 175 | auto found = sockopt_map.find(console_opt_name); | ||
| 176 | if (found != sockopt_map.end()) { | ||
| 177 | return found->second; | ||
| 178 | } | ||
| 179 | return console_opt_name; | ||
| 180 | } | ||
| 181 | |||
| 154 | /// Holds information about a particular socket | 182 | /// Holds information about a particular socket |
| 155 | struct SocketHolder { | 183 | struct SocketHolder { |
| 156 | u32 socket_fd; ///< The socket descriptor | 184 | u32 socket_fd; ///< The socket descriptor |
| @@ -568,7 +596,7 @@ static void RecvFrom(Service::Interface* self) { | |||
| 568 | socklen_t src_addr_len = sizeof(src_addr); | 596 | socklen_t src_addr_len = sizeof(src_addr); |
| 569 | int ret = ::recvfrom(socket_handle, (char*)output_buff, len, flags, &src_addr, &src_addr_len); | 597 | int ret = ::recvfrom(socket_handle, (char*)output_buff, len, flags, &src_addr, &src_addr_len); |
| 570 | 598 | ||
| 571 | if (buffer_parameters.output_src_address_buffer != 0) { | 599 | if (ret >= 0 && buffer_parameters.output_src_address_buffer != 0 && src_addr_len > 0) { |
| 572 | CTRSockAddr* ctr_src_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(buffer_parameters.output_src_address_buffer)); | 600 | CTRSockAddr* ctr_src_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(buffer_parameters.output_src_address_buffer)); |
| 573 | *ctr_src_addr = CTRSockAddr::FromPlatform(src_addr); | 601 | *ctr_src_addr = CTRSockAddr::FromPlatform(src_addr); |
| 574 | } | 602 | } |
| @@ -724,6 +752,72 @@ static void ShutdownSockets(Service::Interface* self) { | |||
| 724 | cmd_buffer[1] = 0; | 752 | cmd_buffer[1] = 0; |
| 725 | } | 753 | } |
| 726 | 754 | ||
| 755 | static void GetSockOpt(Service::Interface* self) { | ||
| 756 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 757 | u32 socket_handle = cmd_buffer[1]; | ||
| 758 | u32 level = cmd_buffer[2]; | ||
| 759 | int optname = TranslateSockOpt(cmd_buffer[3]); | ||
| 760 | socklen_t optlen = (socklen_t)cmd_buffer[4]; | ||
| 761 | |||
| 762 | int ret = -1; | ||
| 763 | int err = 0; | ||
| 764 | |||
| 765 | if(optname < 0) { | ||
| 766 | #ifdef _WIN32 | ||
| 767 | err = WSAEINVAL; | ||
| 768 | #else | ||
| 769 | err = EINVAL; | ||
| 770 | #endif | ||
| 771 | } else { | ||
| 772 | // 0x100 = static buffer offset (bytes) | ||
| 773 | // + 0x4 = 2nd pointer (u32) position | ||
| 774 | // >> 2 = convert to u32 offset instead of byte offset (cmd_buffer = u32*) | ||
| 775 | char* optval = reinterpret_cast<char *>(Memory::GetPointer(cmd_buffer[0x104 >> 2])); | ||
| 776 | |||
| 777 | ret = ::getsockopt(socket_handle, level, optname, optval, &optlen); | ||
| 778 | err = 0; | ||
| 779 | if (ret == SOCKET_ERROR_VALUE) { | ||
| 780 | err = TranslateError(GET_ERRNO); | ||
| 781 | } | ||
| 782 | } | ||
| 783 | |||
| 784 | cmd_buffer[0] = IPC::MakeHeader(0x11, 4, 2); | ||
| 785 | cmd_buffer[1] = ret; | ||
| 786 | cmd_buffer[2] = err; | ||
| 787 | cmd_buffer[3] = optlen; | ||
| 788 | } | ||
| 789 | |||
| 790 | static void SetSockOpt(Service::Interface* self) { | ||
| 791 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 792 | u32 socket_handle = cmd_buffer[1]; | ||
| 793 | u32 level = cmd_buffer[2]; | ||
| 794 | int optname = TranslateSockOpt(cmd_buffer[3]); | ||
| 795 | |||
| 796 | int ret = -1; | ||
| 797 | int err = 0; | ||
| 798 | |||
| 799 | if(optname < 0) { | ||
| 800 | #ifdef _WIN32 | ||
| 801 | err = WSAEINVAL; | ||
| 802 | #else | ||
| 803 | err = EINVAL; | ||
| 804 | #endif | ||
| 805 | } else { | ||
| 806 | socklen_t optlen = static_cast<socklen_t>(cmd_buffer[4]); | ||
| 807 | const char* optval = reinterpret_cast<const char *>(Memory::GetPointer(cmd_buffer[8])); | ||
| 808 | |||
| 809 | ret = static_cast<u32>(::setsockopt(socket_handle, level, optname, optval, optlen)); | ||
| 810 | err = 0; | ||
| 811 | if (ret == SOCKET_ERROR_VALUE) { | ||
| 812 | err = TranslateError(GET_ERRNO); | ||
| 813 | } | ||
| 814 | } | ||
| 815 | |||
| 816 | cmd_buffer[0] = IPC::MakeHeader(0x12, 4, 4); | ||
| 817 | cmd_buffer[1] = ret; | ||
| 818 | cmd_buffer[2] = err; | ||
| 819 | } | ||
| 820 | |||
| 727 | const Interface::FunctionInfo FunctionTable[] = { | 821 | const Interface::FunctionInfo FunctionTable[] = { |
| 728 | {0x00010044, InitializeSockets, "InitializeSockets"}, | 822 | {0x00010044, InitializeSockets, "InitializeSockets"}, |
| 729 | {0x000200C2, Socket, "Socket"}, | 823 | {0x000200C2, Socket, "Socket"}, |
| @@ -741,8 +835,8 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 741 | {0x000E00C2, nullptr, "GetHostByAddr"}, | 835 | {0x000E00C2, nullptr, "GetHostByAddr"}, |
| 742 | {0x000F0106, nullptr, "GetAddrInfo"}, | 836 | {0x000F0106, nullptr, "GetAddrInfo"}, |
| 743 | {0x00100102, nullptr, "GetNameInfo"}, | 837 | {0x00100102, nullptr, "GetNameInfo"}, |
| 744 | {0x00110102, nullptr, "GetSockOpt"}, | 838 | {0x00110102, GetSockOpt, "GetSockOpt"}, |
| 745 | {0x00120104, nullptr, "SetSockOpt"}, | 839 | {0x00120104, SetSockOpt, "SetSockOpt"}, |
| 746 | {0x001300C2, Fcntl, "Fcntl"}, | 840 | {0x001300C2, Fcntl, "Fcntl"}, |
| 747 | {0x00140084, Poll, "Poll"}, | 841 | {0x00140084, Poll, "Poll"}, |
| 748 | {0x00150042, nullptr, "SockAtMark"}, | 842 | {0x00150042, nullptr, "SockAtMark"}, |