mirror of
				https://git.h3cjp.net/H3cJP/citra.git
				synced 2025-11-04 00:46:37 +00:00 
			
		
		
		
	[network] Error handling reform
`network.cpp` has several error paths which either:
- report "Unhandled host socket error=n" and return `SUCCESS`, or
- switch on a few possible errors, log them, and translate them to
  Errno; the same switch statement is copied and pasted in multiple
  places in the code
Convert these paths to use a helper function `GetAndLogLastError`, which
is roughly the equivalent of one of the switch statements, but:
- handling more cases (both ones that were already in `Errno`, and a few
  more I added), and
- using OS functions to convert the error to a string when logging, so
  it'll describe the error even if it's not one of the ones in the
  switch statement.
  - To handle this, refactor the logic in `GetLastErrorMsg` to expose a
    new function `NativeErrorToString` which takes the error number
    explicitly as an argument.  And improve the Windows version a bit.
Also, add a test which exercises two random error paths.
			
			
This commit is contained in:
		
							parent
							
								
									9e9341f4b4
								
							
						
					
					
						commit
						2910aa77b2
					
				| 
						 | 
				
			
			@ -52,9 +52,13 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
 | 
			
		|||
// Generic function to get last error message.
 | 
			
		||||
// Call directly after the command or use the error num.
 | 
			
		||||
// This function might change the error code.
 | 
			
		||||
// Defined in Misc.cpp.
 | 
			
		||||
// Defined in misc.cpp.
 | 
			
		||||
[[nodiscard]] std::string GetLastErrorMsg();
 | 
			
		||||
 | 
			
		||||
// Like GetLastErrorMsg(), but passing an explicit error code.
 | 
			
		||||
// Defined in misc.cpp.
 | 
			
		||||
[[nodiscard]] std::string NativeErrorToString(int e);
 | 
			
		||||
 | 
			
		||||
#define DECLARE_ENUM_FLAG_OPERATORS(type)                                                          \
 | 
			
		||||
    [[nodiscard]] constexpr type operator|(type a, type b) noexcept {                              \
 | 
			
		||||
        using T = std::underlying_type_t<type>;                                                    \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,27 +12,41 @@
 | 
			
		|||
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
 | 
			
		||||
// Generic function to get last error message.
 | 
			
		||||
// Call directly after the command or use the error num.
 | 
			
		||||
// This function might change the error code.
 | 
			
		||||
std::string GetLastErrorMsg() {
 | 
			
		||||
    static constexpr std::size_t buff_size = 255;
 | 
			
		||||
    char err_str[buff_size];
 | 
			
		||||
 | 
			
		||||
std::string NativeErrorToString(int e) {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(),
 | 
			
		||||
                   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr);
 | 
			
		||||
    return std::string(err_str, buff_size);
 | 
			
		||||
#elif defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600))
 | 
			
		||||
    LPSTR err_str;
 | 
			
		||||
 | 
			
		||||
    DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
 | 
			
		||||
                                   FORMAT_MESSAGE_IGNORE_INSERTS,
 | 
			
		||||
                               nullptr, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
 | 
			
		||||
                               reinterpret_cast<LPSTR>(&err_str), 1, nullptr);
 | 
			
		||||
    if (!res) {
 | 
			
		||||
        return "(FormatMessageA failed to format error)";
 | 
			
		||||
    }
 | 
			
		||||
    std::string ret(err_str);
 | 
			
		||||
    LocalFree(err_str);
 | 
			
		||||
    return ret;
 | 
			
		||||
#else
 | 
			
		||||
    char err_str[255];
 | 
			
		||||
#if defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600))
 | 
			
		||||
    // Thread safe (GNU-specific)
 | 
			
		||||
    const char* str = strerror_r(errno, err_str, buff_size);
 | 
			
		||||
    const char* str = strerror_r(e, err_str, sizeof(err_str));
 | 
			
		||||
    return std::string(str);
 | 
			
		||||
#else
 | 
			
		||||
    // Thread safe (XSI-compliant)
 | 
			
		||||
    const int success = strerror_r(errno, err_str, buff_size);
 | 
			
		||||
    if (success != 0) {
 | 
			
		||||
        return {};
 | 
			
		||||
    int second_err = strerror_r(e, err_str, sizeof(err_str));
 | 
			
		||||
    if (second_err != 0) {
 | 
			
		||||
        return "(strerror_r failed to format error)";
 | 
			
		||||
    }
 | 
			
		||||
    return std::string(err_str);
 | 
			
		||||
#endif // GLIBC etc.
 | 
			
		||||
#endif // _WIN32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string GetLastErrorMsg() {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    return NativeErrorToString(GetLastError());
 | 
			
		||||
#else
 | 
			
		||||
    return NativeErrorToString(errno);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@
 | 
			
		|||
#include <limits>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname
 | 
			
		||||
| 
						 | 
				
			
			@ -90,15 +91,36 @@ LINGER MakeLinger(bool enable, u32 linger_value) {
 | 
			
		|||
    return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int LastError() {
 | 
			
		||||
    return WSAGetLastError();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool EnableNonBlock(SOCKET fd, bool enable) {
 | 
			
		||||
    u_long value = enable ? 1 : 0;
 | 
			
		||||
    return ioctlsocket(fd, FIONBIO, &value) != SOCKET_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Errno TranslateNativeError(int e) {
 | 
			
		||||
    switch (e) {
 | 
			
		||||
    case WSAEBADF:
 | 
			
		||||
        return Errno::BADF;
 | 
			
		||||
    case WSAEINVAL:
 | 
			
		||||
        return Errno::INVAL;
 | 
			
		||||
    case WSAEMFILE:
 | 
			
		||||
        return Errno::MFILE;
 | 
			
		||||
    case WSAENOTCONN:
 | 
			
		||||
        return Errno::NOTCONN;
 | 
			
		||||
    case WSAEWOULDBLOCK:
 | 
			
		||||
        return Errno::AGAIN;
 | 
			
		||||
    case WSAECONNREFUSED:
 | 
			
		||||
        return Errno::CONNREFUSED;
 | 
			
		||||
    case WSAEHOSTUNREACH:
 | 
			
		||||
        return Errno::HOSTUNREACH;
 | 
			
		||||
    case WSAENETDOWN:
 | 
			
		||||
        return Errno::NETDOWN;
 | 
			
		||||
    case WSAENETUNREACH:
 | 
			
		||||
        return Errno::NETUNREACH;
 | 
			
		||||
    default:
 | 
			
		||||
        return Errno::OTHER;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#elif YUZU_UNIX // ^ _WIN32 v YUZU_UNIX
 | 
			
		||||
 | 
			
		||||
using SOCKET = int;
 | 
			
		||||
| 
						 | 
				
			
			@ -108,9 +130,6 @@ using ULONG = u64;
 | 
			
		|||
constexpr SOCKET INVALID_SOCKET = -1;
 | 
			
		||||
constexpr SOCKET SOCKET_ERROR = -1;
 | 
			
		||||
 | 
			
		||||
constexpr int WSAEWOULDBLOCK = EAGAIN;
 | 
			
		||||
constexpr int WSAENOTCONN = ENOTCONN;
 | 
			
		||||
 | 
			
		||||
constexpr int SD_RECEIVE = SHUT_RD;
 | 
			
		||||
constexpr int SD_SEND = SHUT_WR;
 | 
			
		||||
constexpr int SD_BOTH = SHUT_RDWR;
 | 
			
		||||
| 
						 | 
				
			
			@ -162,10 +181,6 @@ linger MakeLinger(bool enable, u32 linger_value) {
 | 
			
		|||
    return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int LastError() {
 | 
			
		||||
    return errno;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool EnableNonBlock(int fd, bool enable) {
 | 
			
		||||
    int flags = fcntl(fd, F_GETFD);
 | 
			
		||||
    if (flags == -1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -179,8 +194,43 @@ bool EnableNonBlock(int fd, bool enable) {
 | 
			
		|||
    return fcntl(fd, F_SETFD, flags) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Errno TranslateNativeError(int e) {
 | 
			
		||||
    switch (e) {
 | 
			
		||||
    case EBADF:
 | 
			
		||||
        return Errno::BADF;
 | 
			
		||||
    case EINVAL:
 | 
			
		||||
        return Errno::INVAL;
 | 
			
		||||
    case EMFILE:
 | 
			
		||||
        return Errno::MFILE;
 | 
			
		||||
    case ENOTCONN:
 | 
			
		||||
        return Errno::NOTCONN;
 | 
			
		||||
    case EAGAIN:
 | 
			
		||||
        return Errno::AGAIN;
 | 
			
		||||
    case ECONNREFUSED:
 | 
			
		||||
        return Errno::CONNREFUSED;
 | 
			
		||||
    case EHOSTUNREACH:
 | 
			
		||||
        return Errno::HOSTUNREACH;
 | 
			
		||||
    case ENETDOWN:
 | 
			
		||||
        return Errno::NETDOWN;
 | 
			
		||||
    case ENETUNREACH:
 | 
			
		||||
        return Errno::NETUNREACH;
 | 
			
		||||
    default:
 | 
			
		||||
        return Errno::OTHER;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
Errno GetAndLogLastError() {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    int e = WSAGetLastError();
 | 
			
		||||
#else
 | 
			
		||||
    int e = errno;
 | 
			
		||||
#endif
 | 
			
		||||
    LOG_ERROR(Network, "Socket operation error: {}", NativeErrorToString(e));
 | 
			
		||||
    return TranslateNativeError(e);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int TranslateDomain(Domain domain) {
 | 
			
		||||
    switch (domain) {
 | 
			
		||||
    case Domain::INET:
 | 
			
		||||
| 
						 | 
				
			
			@ -290,9 +340,7 @@ Errno SetSockOpt(SOCKET fd, int option, T value) {
 | 
			
		|||
    if (result != SOCKET_ERROR) {
 | 
			
		||||
        return Errno::SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
    const int ec = LastError();
 | 
			
		||||
    UNREACHABLE_MSG("Unhandled host socket error={}", ec);
 | 
			
		||||
    return Errno::SUCCESS;
 | 
			
		||||
    return GetAndLogLastError();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // Anonymous namespace
 | 
			
		||||
| 
						 | 
				
			
			@ -308,14 +356,12 @@ NetworkInstance::~NetworkInstance() {
 | 
			
		|||
std::pair<IPv4Address, Errno> GetHostIPv4Address() {
 | 
			
		||||
    std::array<char, 256> name{};
 | 
			
		||||
    if (gethostname(name.data(), static_cast<int>(name.size()) - 1) == SOCKET_ERROR) {
 | 
			
		||||
        UNIMPLEMENTED_MSG("Unhandled gethostname error");
 | 
			
		||||
        return {IPv4Address{}, Errno::SUCCESS};
 | 
			
		||||
        return {IPv4Address{}, GetAndLogLastError()};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hostent* const ent = gethostbyname(name.data());
 | 
			
		||||
    if (!ent) {
 | 
			
		||||
        UNIMPLEMENTED_MSG("Unhandled gethostbyname error");
 | 
			
		||||
        return {IPv4Address{}, Errno::SUCCESS};
 | 
			
		||||
        return {IPv4Address{}, GetAndLogLastError()};
 | 
			
		||||
    }
 | 
			
		||||
    if (ent->h_addr_list == nullptr) {
 | 
			
		||||
        UNIMPLEMENTED_MSG("No addr provided in hostent->h_addr_list");
 | 
			
		||||
| 
						 | 
				
			
			@ -359,9 +405,7 @@ std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) {
 | 
			
		|||
 | 
			
		||||
    ASSERT(result == SOCKET_ERROR);
 | 
			
		||||
 | 
			
		||||
    const int ec = LastError();
 | 
			
		||||
    UNREACHABLE_MSG("Unhandled host socket error={}", ec);
 | 
			
		||||
    return {-1, Errno::SUCCESS};
 | 
			
		||||
    return {-1, GetAndLogLastError()};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Socket::~Socket() {
 | 
			
		||||
| 
						 | 
				
			
			@ -380,9 +424,7 @@ Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) {
 | 
			
		|||
        return Errno::SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const int ec = LastError();
 | 
			
		||||
    UNREACHABLE_MSG("Unhandled host socket error={}", ec);
 | 
			
		||||
    return Errno::SUCCESS;
 | 
			
		||||
    return GetAndLogLastError();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::pair<Socket::AcceptResult, Errno> Socket::Accept() {
 | 
			
		||||
| 
						 | 
				
			
			@ -391,9 +433,7 @@ std::pair<Socket::AcceptResult, Errno> Socket::Accept() {
 | 
			
		|||
    const SOCKET new_socket = accept(fd, &addr, &addrlen);
 | 
			
		||||
 | 
			
		||||
    if (new_socket == INVALID_SOCKET) {
 | 
			
		||||
        const int ec = LastError();
 | 
			
		||||
        UNREACHABLE_MSG("Unhandled host socket error={}", ec);
 | 
			
		||||
        return {AcceptResult{}, Errno::SUCCESS};
 | 
			
		||||
        return {AcceptResult{}, GetAndLogLastError()};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    AcceptResult result;
 | 
			
		||||
| 
						 | 
				
			
			@ -412,23 +452,14 @@ Errno Socket::Connect(SockAddrIn addr_in) {
 | 
			
		|||
        return Errno::SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (const int ec = LastError()) {
 | 
			
		||||
    case WSAEWOULDBLOCK:
 | 
			
		||||
        LOG_DEBUG(Service, "EAGAIN generated");
 | 
			
		||||
        return Errno::AGAIN;
 | 
			
		||||
    default:
 | 
			
		||||
        UNREACHABLE_MSG("Unhandled host socket error={}", ec);
 | 
			
		||||
        return Errno::SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
    return GetAndLogLastError();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::pair<SockAddrIn, Errno> Socket::GetPeerName() {
 | 
			
		||||
    sockaddr addr;
 | 
			
		||||
    socklen_t addrlen = sizeof(addr);
 | 
			
		||||
    if (getpeername(fd, &addr, &addrlen) == SOCKET_ERROR) {
 | 
			
		||||
        const int ec = LastError();
 | 
			
		||||
        UNREACHABLE_MSG("Unhandled host socket error={}", ec);
 | 
			
		||||
        return {SockAddrIn{}, Errno::SUCCESS};
 | 
			
		||||
        return {SockAddrIn{}, GetAndLogLastError()};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ASSERT(addrlen == sizeof(sockaddr_in));
 | 
			
		||||
| 
						 | 
				
			
			@ -439,9 +470,7 @@ std::pair<SockAddrIn, Errno> Socket::GetSockName() {
 | 
			
		|||
    sockaddr addr;
 | 
			
		||||
    socklen_t addrlen = sizeof(addr);
 | 
			
		||||
    if (getsockname(fd, &addr, &addrlen) == SOCKET_ERROR) {
 | 
			
		||||
        const int ec = LastError();
 | 
			
		||||
        UNREACHABLE_MSG("Unhandled host socket error={}", ec);
 | 
			
		||||
        return {SockAddrIn{}, Errno::SUCCESS};
 | 
			
		||||
        return {SockAddrIn{}, GetAndLogLastError()};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ASSERT(addrlen == sizeof(sockaddr_in));
 | 
			
		||||
| 
						 | 
				
			
			@ -454,9 +483,7 @@ Errno Socket::Bind(SockAddrIn addr) {
 | 
			
		|||
        return Errno::SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const int ec = LastError();
 | 
			
		||||
    UNREACHABLE_MSG("Unhandled host socket error={}", ec);
 | 
			
		||||
    return Errno::SUCCESS;
 | 
			
		||||
    return GetAndLogLastError();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Errno Socket::Listen(s32 backlog) {
 | 
			
		||||
| 
						 | 
				
			
			@ -464,9 +491,7 @@ Errno Socket::Listen(s32 backlog) {
 | 
			
		|||
        return Errno::SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const int ec = LastError();
 | 
			
		||||
    UNREACHABLE_MSG("Unhandled host socket error={}", ec);
 | 
			
		||||
    return Errno::SUCCESS;
 | 
			
		||||
    return GetAndLogLastError();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Errno Socket::Shutdown(ShutdownHow how) {
 | 
			
		||||
| 
						 | 
				
			
			@ -489,14 +514,7 @@ Errno Socket::Shutdown(ShutdownHow how) {
 | 
			
		|||
        return Errno::SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (const int ec = LastError()) {
 | 
			
		||||
    case WSAENOTCONN:
 | 
			
		||||
        LOG_ERROR(Service, "ENOTCONN generated");
 | 
			
		||||
        return Errno::NOTCONN;
 | 
			
		||||
    default:
 | 
			
		||||
        UNREACHABLE_MSG("Unhandled host socket error={}", ec);
 | 
			
		||||
        return Errno::SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
    return GetAndLogLastError();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) {
 | 
			
		||||
| 
						 | 
				
			
			@ -509,17 +527,7 @@ std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) {
 | 
			
		|||
        return {static_cast<s32>(result), Errno::SUCCESS};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (const int ec = LastError()) {
 | 
			
		||||
    case WSAEWOULDBLOCK:
 | 
			
		||||
        LOG_DEBUG(Service, "EAGAIN generated");
 | 
			
		||||
        return {-1, Errno::AGAIN};
 | 
			
		||||
    case WSAENOTCONN:
 | 
			
		||||
        LOG_ERROR(Service, "ENOTCONN generated");
 | 
			
		||||
        return {-1, Errno::NOTCONN};
 | 
			
		||||
    default:
 | 
			
		||||
        UNREACHABLE_MSG("Unhandled host socket error={}", ec);
 | 
			
		||||
        return {0, Errno::SUCCESS};
 | 
			
		||||
    }
 | 
			
		||||
    return {-1, GetAndLogLastError()};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) {
 | 
			
		||||
| 
						 | 
				
			
			@ -541,17 +549,7 @@ std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, Sock
 | 
			
		|||
        return {static_cast<s32>(result), Errno::SUCCESS};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (const int ec = LastError()) {
 | 
			
		||||
    case WSAEWOULDBLOCK:
 | 
			
		||||
        LOG_DEBUG(Service, "EAGAIN generated");
 | 
			
		||||
        return {-1, Errno::AGAIN};
 | 
			
		||||
    case WSAENOTCONN:
 | 
			
		||||
        LOG_ERROR(Service, "ENOTCONN generated");
 | 
			
		||||
        return {-1, Errno::NOTCONN};
 | 
			
		||||
    default:
 | 
			
		||||
        UNREACHABLE_MSG("Unhandled host socket error={}", ec);
 | 
			
		||||
        return {-1, Errno::SUCCESS};
 | 
			
		||||
    }
 | 
			
		||||
    return {-1, GetAndLogLastError()};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) {
 | 
			
		||||
| 
						 | 
				
			
			@ -564,18 +562,7 @@ std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) {
 | 
			
		|||
        return {static_cast<s32>(result), Errno::SUCCESS};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const int ec = LastError();
 | 
			
		||||
    switch (ec) {
 | 
			
		||||
    case WSAEWOULDBLOCK:
 | 
			
		||||
        LOG_DEBUG(Service, "EAGAIN generated");
 | 
			
		||||
        return {-1, Errno::AGAIN};
 | 
			
		||||
    case WSAENOTCONN:
 | 
			
		||||
        LOG_ERROR(Service, "ENOTCONN generated");
 | 
			
		||||
        return {-1, Errno::NOTCONN};
 | 
			
		||||
    default:
 | 
			
		||||
        UNREACHABLE_MSG("Unhandled host socket error={}", ec);
 | 
			
		||||
        return {-1, Errno::SUCCESS};
 | 
			
		||||
    }
 | 
			
		||||
    return {-1, GetAndLogLastError()};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message,
 | 
			
		||||
| 
						 | 
				
			
			@ -597,9 +584,7 @@ std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message,
 | 
			
		|||
        return {static_cast<s32>(result), Errno::SUCCESS};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const int ec = LastError();
 | 
			
		||||
    UNREACHABLE_MSG("Unhandled host socket error={}", ec);
 | 
			
		||||
    return {-1, Errno::SUCCESS};
 | 
			
		||||
    return {-1, GetAndLogLastError()};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Errno Socket::Close() {
 | 
			
		||||
| 
						 | 
				
			
			@ -642,9 +627,7 @@ Errno Socket::SetNonBlock(bool enable) {
 | 
			
		|||
    if (EnableNonBlock(fd, enable)) {
 | 
			
		||||
        return Errno::SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
    const int ec = LastError();
 | 
			
		||||
    UNREACHABLE_MSG("Unhandled host socket error={}", ec);
 | 
			
		||||
    return Errno::SUCCESS;
 | 
			
		||||
    return GetAndLogLastError();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Socket::IsOpened() const {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@
 | 
			
		|||
#include <array>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
 | 
			
		||||
namespace Network {
 | 
			
		||||
| 
						 | 
				
			
			@ -21,6 +22,11 @@ enum class Errno {
 | 
			
		|||
    MFILE,
 | 
			
		||||
    NOTCONN,
 | 
			
		||||
    AGAIN,
 | 
			
		||||
    CONNREFUSED,
 | 
			
		||||
    HOSTUNREACH,
 | 
			
		||||
    NETDOWN,
 | 
			
		||||
    NETUNREACH,
 | 
			
		||||
    OTHER,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Address families
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@ add_executable(tests
 | 
			
		|||
    common/param_package.cpp
 | 
			
		||||
    common/ring_buffer.cpp
 | 
			
		||||
    core/core_timing.cpp
 | 
			
		||||
    core/network/network.cpp
 | 
			
		||||
    tests.cpp
 | 
			
		||||
    video_core/buffer_base.cpp
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										28
									
								
								src/tests/core/network/network.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/tests/core/network/network.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
// Copyright 2021 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <catch2/catch.hpp>
 | 
			
		||||
 | 
			
		||||
#include "core/network/network.h"
 | 
			
		||||
#include "core/network/sockets.h"
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Network::Errors", "[core]") {
 | 
			
		||||
    Network::NetworkInstance network_instance; // initialize network
 | 
			
		||||
 | 
			
		||||
    Network::Socket socks[2];
 | 
			
		||||
    for (Network::Socket& sock : socks) {
 | 
			
		||||
        REQUIRE(sock.Initialize(Network::Domain::INET, Network::Type::STREAM,
 | 
			
		||||
                                Network::Protocol::TCP) == Network::Errno::SUCCESS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Network::SockAddrIn addr{
 | 
			
		||||
        Network::Domain::INET,
 | 
			
		||||
        {127, 0, 0, 1},
 | 
			
		||||
        1, // hopefully nobody running this test has something listening on port 1
 | 
			
		||||
    };
 | 
			
		||||
    REQUIRE(socks[0].Connect(addr) == Network::Errno::CONNREFUSED);
 | 
			
		||||
 | 
			
		||||
    std::vector<u8> message{1, 2, 3, 4};
 | 
			
		||||
    REQUIRE(socks[1].Recv(0, message).second == Network::Errno::NOTCONN);
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in a new issue