Skip to content

Instantly share code, notes, and snippets.

@Subv
Created December 12, 2014 22:26
Show Gist options
  • Save Subv/1f3ef14e914420be4600 to your computer and use it in GitHub Desktop.
Save Subv/1f3ef14e914420be4600 to your computer and use it in GitHub Desktop.
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