Created
December 12, 2014 22:26
-
-
Save Subv/1f3ef14e914420be4600 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp | |
index 4a96f71..18696be 100644 | |
--- a/src/core/hle/service/soc_u.cpp | |
+++ b/src/core/hle/service/soc_u.cpp | |
@@ -8,10 +8,6 @@ | |
#include <winsock2.h> | |
#include <ws2tcpip.h> | |
#include <unordered_map> | |
- | |
-#define WSAEAGAIN WSAEWOULDBLOCK | |
-#define ERRNO(x) WSA##x | |
-#define GET_ERRNO WSAGetLastError() | |
#else | |
#include <sys/socket.h> | |
#include <netinet/in.h> | |
@@ -19,34 +15,36 @@ | |
#include <arpa/inet.h> | |
#include <fcntl.h> | |
#include <poll.h> | |
- | |
-#define ERRNO(x) x | |
-#define GET_ERRNO errno | |
#endif | |
-#define SOCKET_ERROR_VALUE (-1) | |
- | |
#include "common/log.h" | |
#include "core/hle/hle.h" | |
#include "core/hle/service/soc_u.h" | |
+#define SOCKET_ERROR_VALUE (-1) | |
+ | |
+#if EMU_PLATFORM == PLATFORM_WINDOWS | |
+#define WSAEAGAIN WSAEWOULDBLOCK | |
+#define ERRNO(x) WSA##x | |
+#define GET_ERRNO WSAGetLastError() | |
+else | |
+#define ERRNO(x) x | |
+#define GET_ERRNO errno | |
+#endif | |
+ | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// Namespace SOC_U | |
namespace SOC_U { | |
-struct ErrorMap { | |
- int from; | |
- int to; | |
-}; | |
- | |
#if EMU_PLATFORM != PLATFORM_WINDOWS | |
static const u32 error_map_size = 77; | |
#else | |
static const u32 error_map_size = 76; | |
#endif | |
-static const std::array<ErrorMap, error_map_size> error_map = { { | |
+/// Holds the translation from system network errors to 3DS network errors | |
+static const std::array<std::pair<int, int>, error_map_size> error_map = { { | |
{ E2BIG, 1 }, | |
{ ERRNO(EACCES), 2 }, | |
{ ERRNO(EADDRINUSE), 3 }, | |
@@ -129,23 +127,49 @@ static const std::array<ErrorMap, error_map_size> error_map = { { | |
/// Converts a network error from platform-specific to 3ds-specific | |
static int TranslateError(int error) { | |
- auto found = std::find_if(error_map.begin(), error_map.end(), [error](ErrorMap const& eqivalence) { | |
- return eqivalence.from == error; | |
+ auto found = std::find_if(error_map.begin(), error_map.end(), [error](std::pair<int, int> const& eqivalence) { | |
+ return eqivalence.first == error; | |
}); | |
if (found != error_map.end()) | |
- return -found->to; | |
+ return -found->second; | |
return error; | |
} | |
/// Structure to represent the 3ds' pollfd structure, which is different than most implementations | |
-struct hw_pollfd { | |
+struct CTRPollFD { | |
u32 fd; ///< Socket handle | |
u32 events; ///< Events to poll for (input) | |
u32 revents; ///< Events received (output) | |
}; | |
+/// Structure to represent the 3ds' sockaddr structure | |
+struct CTRSockAddr { | |
+ u8 len; ///< The length of the entire structure, only the set fields count | |
+ u8 sa_family; ///< The address family of the sockaddr | |
+ u8 sa_data[0x1A]; ///< The extra data, this varies, depending on the address family | |
+ | |
+ /// Convert a 3DS CTRSockAddr to a platform-specific sockaddr | |
+ static sockaddr ToPlatform(CTRSockAddr const& ctr_addr) { | |
+ sockaddr result; | |
+ result.sa_family = ctr_addr.sa_family; | |
+ memset(result.sa_data, 0, sizeof(result.sa_data)); | |
+ memcpy(result.sa_data, ctr_addr.sa_data, ctr_addr.len - 2); | |
+ return result; | |
+ } | |
+ | |
+ /// Convert a platform-specific sockaddr to a 3DS CTRSockAddr | |
+ static CTRSockAddr FromPlatform(sockaddr const& addr) { | |
+ CTRSockAddr result; | |
+ result.sa_family = addr.sa_family; | |
+ result.len = sizeof(addr); | |
+ memset(result.sa_data, 0, sizeof(result.sa_data)); | |
+ memcpy(result.sa_data, addr.sa_data, sizeof(addr) - 2); | |
+ return result; | |
+ } | |
+}; | |
+ | |
#if EMU_PLATFORM == PLATFORM_WINDOWS | |
/// Holds info about whether a specific socket is blocking or not | |
/// This only exists on Windows because it has no way of querying if a socket is blocking or not | |
@@ -191,13 +215,16 @@ static void Bind(Service::Interface* self) { | |
u32* cmd_buffer = Service::GetCommandBuffer(); | |
u32 socket_handle = cmd_buffer[1]; | |
u32 len = cmd_buffer[2]; | |
- sockaddr* sock_addr = reinterpret_cast<sockaddr*>(Memory::GetPointer(cmd_buffer[6])); | |
-#if EMU_PLATFORM != PLATFORM_MACOSX | |
- // OS X uses the first byte for the struct length, Windows doesn't | |
- if (sock_addr != nullptr) | |
- sock_addr->sa_family >>= 8; | |
-#endif | |
- int res = ::bind(socket_handle, sock_addr, len == 8 ? sizeof(sockaddr_in) : sizeof(sockaddr_in6)); | |
+ CTRSockAddr* ctr_sock_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[6])); | |
+ | |
+ if (ctr_sock_addr == nullptr) { | |
+ cmd_buffer[1] = -1; // TODO(Subv): Correct code | |
+ return; | |
+ } | |
+ | |
+ sockaddr sock_addr = CTRSockAddr::ToPlatform(*ctr_sock_addr); | |
+ | |
+ int res = ::bind(socket_handle, &sock_addr, sizeof(sock_addr)); | |
if (res != 0) | |
res = TranslateError(GET_ERRNO); | |
@@ -399,8 +426,8 @@ static void Poll(Service::Interface* self) { | |
u32* cmd_buffer = Service::GetCommandBuffer(); | |
u32 nfds = cmd_buffer[1]; | |
int timeout = cmd_buffer[2]; | |
- hw_pollfd* input_fds = reinterpret_cast<hw_pollfd*>(Memory::GetPointer(cmd_buffer[6])); | |
- hw_pollfd* output_fds = reinterpret_cast<hw_pollfd*>(Memory::GetPointer(cmd_buffer[0x104 >> 2])); | |
+ CTRPollFD* input_fds = reinterpret_cast<CTRPollFD*>(Memory::GetPointer(cmd_buffer[6])); | |
+ CTRPollFD* output_fds = reinterpret_cast<CTRPollFD*>(Memory::GetPointer(cmd_buffer[0x104 >> 2])); | |
// The 3ds_pollfd and the pollfd structures may be different (Windows/Linux have different sizes) | |
// so we have to copy the data |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment