mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-03 19:18:09 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5aa5f2daba |
+2
-2
@@ -22,9 +22,9 @@ Eden is free, open-source, copyleft software, licensed under the terms of the [G
|
||||
|
||||
- No LLM or AI usage, *period*, for patches, pull requests, issues, comments, debugging, brainstorming, etc.
|
||||
- For details on why, see the [detailed AI policy](docs/policies/AI.md).
|
||||
- Usage of any form of profanity or otherwise unsavory language is generally discouraged.
|
||||
- Usage of any form of profanity or otherwise unsavory language is prohibited.
|
||||
- This is primarily because it rarely helps to actually understand what's going on.
|
||||
- Remember that your comments should be focused and actually address what's happening. With very few exceptions, expletives are actively detrimental at best.
|
||||
- Remember that your comments should be focused and actually address what's happening.
|
||||
- New code must follow the same general style as the surrounding codebase. Exceptions may be granted in certain cases.
|
||||
- Maintainers reserve the right to change your patches and pull requests at will. We will try to avoid this.
|
||||
- You should generally respect all decisions made by the [code owners](docs/CODEOWNERS) in your particular subsystem.
|
||||
|
||||
+2
-2
@@ -239,6 +239,6 @@ find ./*/ -name "*.dll" | while read -r dll; do deps "$dll"; done
|
||||
|
||||
## RedoxOS
|
||||
|
||||
The package install may randomly hang at times, in which case it has to be restarted. ALWAYS do a `sudo pkg update` or the chances of it hanging will be close to 90%. If "multiple" installs fail at once, try installing 1 by 1 the packages.
|
||||
Package installs randomly hang at times, you may need to restart it about 3-5 times to complete. Always do `sudo pkg update` or it will hang. Try installing each package individually.
|
||||
|
||||
When CMake invokes certain file syscalls - it may sometimes cause crashes or corruptions on the (kernel?) address space - so reboot the system if there is a "hang" in CMake.
|
||||
When CMake invokes certain file syscalls - most of the time it causes crashes, and corruptions on the address space. Reboot if there's a freeze over 5 minutes.
|
||||
|
||||
+4
-4
@@ -38,7 +38,7 @@ Pull requests are only to be merged by core developers when properly tested and
|
||||
|
||||
- The level of namespacing is generally left to the committer's choice.
|
||||
- However, we never recommend going more than two levels *except* in `hle`, in which case you may go as many as four levels depending on the specificity of your changes.
|
||||
- Ocassionally, up to two additional namespaces may be provided for more clarity.
|
||||
- Occasionally, up to two additional namespaces may be provided for more clarity.
|
||||
- Changes that affect the entire project (sans CMake changes) should be namespaced as `meta`.
|
||||
- Maintainers are permitted to change namespaces at will.
|
||||
- Commits within PRs are not required to be namespaced, but it is highly recommended.
|
||||
@@ -51,8 +51,8 @@ When adding new settings, use `tr("Setting:")` if the setting is meant to be a f
|
||||
- Debug settings must never be turned on by default.
|
||||
- Provide reasonable bounds (for example, a setting controlling the amount of VRAM should never be 0).
|
||||
- The description of the setting must be short and concise, if the setting "does a lot of things" consider splitting the setting into multiple if possible.
|
||||
- Try to avoid excessive/redundant explainations "recommended for most users and games" can just be "(recommended)".
|
||||
- Try to not write "slow/fast" options unless it clearly degrades/increases performance for a given case, as most options may modify behaviour that result in different metrics accross different systems. If for example the option is an "accuracy" option, writing "High" is sufficient to imply "Slow". No need to write "High (Slow)".
|
||||
- Try to avoid excessive/redundant explanations "recommended for most users and games" can just be "(recommended)".
|
||||
- Try to not write "slow/fast" options unless it clearly degrades/increases performance for a given case, as most options may modify behavior that result in different metrics across different systems. If for example the option is an "accuracy" option, writing "High" is sufficient to imply "Slow". No need to write "High (Slow)".
|
||||
|
||||
Some examples:
|
||||
|
||||
@@ -91,7 +91,7 @@ You may additionally need the `Qt Extension Pack` extension if building Qt.
|
||||
|
||||
# Build speedup
|
||||
|
||||
If you have an HDD, use ramdisk (build in RAM), approximately you need 4GB for a full build with debug symbols:
|
||||
If you have an HDD, use ramdisk (build in RAM); you need about 4GB for a `RelWithDebInfo` build:
|
||||
|
||||
```sh
|
||||
mkdir /tmp/ramdisk
|
||||
|
||||
+2
-2
@@ -3,9 +3,9 @@
|
||||
> [!WARNING]
|
||||
> This guide is intended for developers ONLY. If you're looking for configuring the emulator itself, read **[the user handbook](./user/README.md)**.
|
||||
|
||||
Settings on the emulator are very important, toggles and such can be used to guard and/or add branches to paths where some games may crash while others won't, and viceversa.
|
||||
Settings have their own dedicated subsystem. Toggles can be added to gate features and fixes, as not all of them apply to every game.
|
||||
|
||||
However, this process can be tedious for those unfamiliar; this document serves as an outline/documentation for the settings subsystem.
|
||||
However, this process can be tedious for those unfamiliar; this document serves as an outline for the settings subsystem.
|
||||
|
||||
## Index
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ AMD64, aka x86_64, is the most tested and supported architecture for desktop tar
|
||||
|
||||
### Caveats
|
||||
|
||||
AMD64 systems are almost always limited by the CPU. For example, a Zen 5/RX 6600 system will often hit max CPU usage before the GPU ever reaches 70% usage, with minimal exceptions (that tend to pop up only at >200fps). JIT is slow!
|
||||
AMD64 systems are almost always limited by the CPU. For example, a Zen 5/RX 6600 system will often hit max CPU usage before the GPU ever reaches 70% usage, with minimal exceptions (that tend to pop up only at >200fps). JIT is slow.
|
||||
|
||||
Computers on Linux will almost always run Eden strictly better than an equivalent machine on Windows. This is largely due to the way the Linux kernel handles memory management (and the lack of Microsoft spyware).
|
||||
|
||||
@@ -24,7 +24,7 @@ ARM64, aka aarch64, is the only supported architecture for Android, with limited
|
||||
|
||||
### Caveats
|
||||
|
||||
NCE (Native Code Execution) is currently only available on Android and (experimentally) Linux. Support for macOS is in the works, but Windows is extremely unlikely to ever happen (if you want it--submit patches!). Generally, if NCE is available, you should pretty much always use it due to the massive performance hit JIT has.
|
||||
NCE (Native Code Execution) is currently only available on Android and (experimentally) Linux. Support for macOS is in the works, but Windows is extremely unlikely to ever happen (if you want it -- submit patches). Generally, if NCE is available, you should pretty much always use it due to the massive performance hit JIT has.
|
||||
|
||||
When NCE is enabled, do note that the GPU will almost always be the limiting factor. This is especially the case for Android, as well as desktops that lack dedicated GPUs; Adreno, Mali, PowerVR, etc. GPUs are generally significantly weaker relative to their respective CPUs.
|
||||
|
||||
@@ -44,7 +44,7 @@ Only Fedora/riscv64 has been tested, but in theory, every riscv64 distribution t
|
||||
|
||||
## Other
|
||||
|
||||
Other architectures, such as SPARC, MIPS, PowerPC, Loong, and all 32-bit architectures are completely unsupported, as there is no JIT backend or emitter thereof. If you want support for it -- submit patches!
|
||||
Other architectures, such as SPARC, MIPS, PowerPC, Loong, and all 32-bit architectures are completely unsupported, as there is no JIT backend or emitter thereof. If you want support for it -- submit patches.
|
||||
|
||||
IA-64 (Itanium) support is completely unknown. Existing amd64 packages will not run on IA-64 (assuming you can even find a supported Windows/Linux distribution)
|
||||
|
||||
@@ -106,14 +106,14 @@ Qualcomm Snapdragon SoCs are generally the most well supported.
|
||||
* A good base to compare to is the Snapdragon 865--e.g. [Tensor vs SD865](https://archive.is/M1P58)
|
||||
* Some benchmarks may be misleading due to thermal throttling OR RAM requirements.
|
||||
- For example, a Pixel 6a (Tensor G1) performs about 1/3 as well as an 865 due to its lack of RAM and poor thermals.
|
||||
* Remember--always use a cooler if you can, and you MUST have *at least* 8GB of RAM!
|
||||
* Remember--always use a cooler if you can, and you MUST have *at least* 8GB of RAM.
|
||||
- If you're not sure what SoC you have, check [GSMArena](https://www.gsmarena.com) - e.g. [Pixel 9 Pro](https://archive.ph/91VhA)
|
||||
|
||||
Custom ROMs are recommended, *as long as* you know what you're doing.
|
||||
- For most devices, [LineageOS](https://lineageos.org/) is preferred.
|
||||
- [CalyxOS](https://calyxos.org/) is available as well.
|
||||
- For Google Pixel devices ONLY... and [soon another OEM](https://archive.ph/cPpMd)... [GrapheneOS](https://grapheneos.org/) is highly recommended.
|
||||
* As of October 5, 2025, the Pixel 10 line is unsupported, however, [it will be](https://archive.is/viAUl) in the very near future!
|
||||
* As of October 5, 2025, the Pixel 10 line is unsupported, however, [it will be](https://archive.is/viAUl) in the very near future.
|
||||
* Keep checking the [FAQ page](https://grapheneos.org/faq#supported-devices) for news.
|
||||
- Custom ROMs will likely be exclusively recommended in the future due to Google's upcoming [draconian](https://archive.is/hGIjZ), [anti-privacy, anti-user](https://archive.is/mc1CJ) verification requirements.
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@ add_library(
|
||||
settings_input.h
|
||||
settings_setting.h
|
||||
slot_vector.h
|
||||
socket_types.h
|
||||
spin_lock.h
|
||||
stb.cpp
|
||||
stb.h
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "web_service/web_result.h"
|
||||
|
||||
namespace AnnounceMultiplayerRoom {
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Network {
|
||||
|
||||
/// Address families
|
||||
enum class Domain : u8 {
|
||||
Unspecified, ///< Represents 0, used in getaddrinfo hints
|
||||
INET, ///< Address family for IPv4
|
||||
};
|
||||
|
||||
/// Socket types
|
||||
enum class Type {
|
||||
Unspecified, ///< Represents 0, used in getaddrinfo hints
|
||||
STREAM,
|
||||
DGRAM,
|
||||
RAW,
|
||||
SEQPACKET,
|
||||
};
|
||||
|
||||
/// Protocol values for sockets
|
||||
enum class Protocol : u8 {
|
||||
Unspecified, ///< Represents 0, usable in various places
|
||||
IP,
|
||||
ICMP,
|
||||
TCP,
|
||||
UDP,
|
||||
IPV6,
|
||||
RAW,
|
||||
IGMP,
|
||||
GGP,
|
||||
IPV4,
|
||||
ST,
|
||||
EGP,
|
||||
PIGP,
|
||||
RCCMON,
|
||||
NVPII,
|
||||
PUP,
|
||||
ARGUS,
|
||||
EMCON,
|
||||
XNET,
|
||||
CHAOS,
|
||||
MUX,
|
||||
MEAS,
|
||||
HMP,
|
||||
PRM,
|
||||
IDP,
|
||||
TRUNK1,
|
||||
TRUNK2,
|
||||
LEAF1,
|
||||
LEAF2,
|
||||
RDP,
|
||||
IRTP,
|
||||
TP,
|
||||
BLT,
|
||||
NSP,
|
||||
INP,
|
||||
DCCP,
|
||||
//TODO: 3PC,
|
||||
IDPR,
|
||||
XTP,
|
||||
DDP,
|
||||
CMTP,
|
||||
TPXX,
|
||||
IL,
|
||||
SDRP,
|
||||
ROUTING,
|
||||
FRAGMENT,
|
||||
IDRP,
|
||||
RSVP,
|
||||
GRE,
|
||||
MHRP,
|
||||
BHA,
|
||||
ESP,
|
||||
AH,
|
||||
INLSP,
|
||||
SWIPE,
|
||||
NHRP,
|
||||
MOBILE,
|
||||
TLSP,
|
||||
SKIP,
|
||||
ICMPV6,
|
||||
NONE,
|
||||
DSTOPTS,
|
||||
AHIP,
|
||||
CFTP,
|
||||
HELLO,
|
||||
SATEXPAK,
|
||||
KRYPTOLAN,
|
||||
RVD,
|
||||
IPPC,
|
||||
ADFS,
|
||||
SATMON,
|
||||
VISA,
|
||||
IPCV,
|
||||
CPNX,
|
||||
CPHB,
|
||||
WSN,
|
||||
PVP,
|
||||
BRSATMON,
|
||||
ND,
|
||||
WBMON,
|
||||
WBEXPAK,
|
||||
EON,
|
||||
VMTP,
|
||||
SVMTP,
|
||||
VINES,
|
||||
TTP,
|
||||
IGP,
|
||||
DGP,
|
||||
TCF,
|
||||
IGRP,
|
||||
OSPFIGP,
|
||||
SRPC,
|
||||
LARP,
|
||||
MTP,
|
||||
AX25,
|
||||
IPEIP,
|
||||
MICP,
|
||||
SCCSP,
|
||||
ETHERIP,
|
||||
ENCAP,
|
||||
APES,
|
||||
GMTP,
|
||||
IPCOMP,
|
||||
SCTP,
|
||||
MH,
|
||||
UDPLITE,
|
||||
HIP,
|
||||
SHIM6,
|
||||
PIM,
|
||||
CARP,
|
||||
PGM,
|
||||
MPLS,
|
||||
PFSYNC
|
||||
};
|
||||
|
||||
/// Shutdown mode
|
||||
enum class ShutdownHow {
|
||||
RD,
|
||||
WR,
|
||||
RDWR,
|
||||
};
|
||||
|
||||
/// Array of IPv4 address
|
||||
using IPv4Address = std::array<u8, 4>;
|
||||
|
||||
/// Cross-platform sockaddr structure
|
||||
struct SockAddrIn {
|
||||
Domain family;
|
||||
IPv4Address ip;
|
||||
u16 portno;
|
||||
};
|
||||
|
||||
constexpr u32 FLAG_MSG_PEEK = 0x2;
|
||||
constexpr u32 FLAG_MSG_DONTWAIT = 0x80;
|
||||
constexpr u32 FLAG_O_NONBLOCK = 0x800;
|
||||
|
||||
/// Cross-platform addrinfo structure
|
||||
struct AddrInfo {
|
||||
Domain family;
|
||||
Type socket_type;
|
||||
Protocol protocol;
|
||||
SockAddrIn addr;
|
||||
std::optional<std::string> canon_name;
|
||||
};
|
||||
|
||||
} // namespace Network
|
||||
@@ -1129,7 +1129,6 @@ add_library(core STATIC
|
||||
internal_network/network_interface.h
|
||||
internal_network/socket_proxy.cpp
|
||||
internal_network/socket_proxy.h
|
||||
internal_network/socket_types.h
|
||||
internal_network/sockets.h
|
||||
internal_network/wifi_scanner.h
|
||||
launch_timestamp_cache.cpp
|
||||
@@ -1168,12 +1167,6 @@ add_library(core STATIC
|
||||
tools/renderdoc.cpp
|
||||
tools/renderdoc.h)
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
target_sources(core PRIVATE
|
||||
internal_network/socket_icmp.cpp
|
||||
internal_network/socket_icmp.h)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WIFI_SCAN)
|
||||
target_sources(core PRIVATE internal_network/wifi_scanner.cpp)
|
||||
if (LINUX)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "common/container/unordered_map.h"
|
||||
|
||||
#include "common/logging.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/ldn/ldn_results.h"
|
||||
#include "core/hle/service/ldn/ldn_types.h"
|
||||
|
||||
@@ -129,13 +129,6 @@ ServerManager::~ServerManager() {
|
||||
}
|
||||
}
|
||||
|
||||
void ServerManager::StartAdditionalHostThreads(const char* name, size_t num_threads) {
|
||||
for (size_t i = 0; i < num_threads; i++) {
|
||||
auto thread_name = fmt::format("{}:{}", name, i + 1);
|
||||
m_threads.emplace_back(m_system.Kernel().RunOnHostCoreThread(std::move(thread_name), [&] { this->LoopProcessImpl(); }));
|
||||
}
|
||||
}
|
||||
|
||||
void ServerManager::RunServer(std::unique_ptr<ServerManager>&& server_manager) {
|
||||
server_manager->m_system.RunServer(std::move(server_manager));
|
||||
}
|
||||
@@ -252,6 +245,14 @@ Result ServerManager::ManageDeferral(Kernel::KEvent** out_event) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void ServerManager::StartAdditionalHostThreads(const char* name, size_t num_threads) {
|
||||
for (size_t i = 0; i < num_threads; i++) {
|
||||
auto thread_name = fmt::format("{}:{}", name, i + 1);
|
||||
m_threads.emplace_back(m_system.Kernel().RunOnHostCoreThread(
|
||||
std::move(thread_name), [&] { this->LoopProcessImpl(); }));
|
||||
}
|
||||
}
|
||||
|
||||
Result ServerManager::LoopProcess() {
|
||||
SCOPE_EXIT {
|
||||
m_stopped.Set();
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -51,8 +48,8 @@ public:
|
||||
Result ManageDeferral(Kernel::KEvent** out_event);
|
||||
|
||||
Result LoopProcess();
|
||||
|
||||
void StartAdditionalHostThreads(const char* name, size_t num_threads);
|
||||
|
||||
static void RunServer(std::unique_ptr<ServerManager>&& server);
|
||||
|
||||
private:
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
#include "common/logging.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
@@ -20,9 +20,6 @@
|
||||
#include "core/hle/service/sockets/sockets_translate.h"
|
||||
#include "core/internal_network/network.h"
|
||||
#include "core/internal_network/socket_proxy.h"
|
||||
#if defined(__unix__) && !defined(__APPLE__)
|
||||
#include "core/internal_network/socket_icmp.h"
|
||||
#endif
|
||||
#include "core/internal_network/sockets.h"
|
||||
#include "network/network.h"
|
||||
#include <common/settings.h>
|
||||
@@ -31,18 +28,15 @@ namespace Service::Sockets {
|
||||
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] bool IsConnectionBased(Network::Type type) noexcept {
|
||||
bool IsConnectionBased(Type type) {
|
||||
switch (type) {
|
||||
case Network::Type::STREAM:
|
||||
case Network::Type::SEQPACKET:
|
||||
case Type::STREAM:
|
||||
return true;
|
||||
case Network::Type::RAW:
|
||||
case Network::Type::DGRAM:
|
||||
case Network::Type::RDM:
|
||||
case Network::Type::Unspecified:
|
||||
case Type::DGRAM:
|
||||
return false;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
UNIMPLEMENTED_MSG("Unimplemented type={}", type);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +92,7 @@ void BSD_USA::ConnectWork::Execute(BSD_USA* bsd) {
|
||||
void BSD_USA::ConnectWork::Response(HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(bsd_errno == Network::Errno::E_SUCCESS ? 0 : -1);
|
||||
rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
|
||||
rb.PushEnum(bsd_errno);
|
||||
}
|
||||
|
||||
@@ -176,9 +170,10 @@ void BSD_USA::Socket(HLERequestContext& ctx) {
|
||||
const u32 domain = rp.Pop<u32>();
|
||||
const u32 type = rp.Pop<u32>();
|
||||
const u32 protocol = rp.Pop<u32>();
|
||||
|
||||
LOG_DEBUG(Service, "called. domain={} type={} protocol={}", domain, type, protocol);
|
||||
|
||||
const auto [fd, bsd_errno] = SocketImpl(Network::Domain(domain), Network::Type(type), Network::Protocol(protocol));
|
||||
const auto [fd, bsd_errno] = SocketImpl(Domain(domain), Type(type), Protocol(protocol));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
@@ -194,8 +189,8 @@ void BSD_USA::SocketExempt(HLERequestContext& ctx) {
|
||||
|
||||
LOG_DEBUG(Service, "called. domain={} type={} protocol={}", domain, type, protocol);
|
||||
|
||||
auto [fd, bsd_errno] = SocketImpl(Network::Domain(domain), Network::Type(type), Network::Protocol(protocol));
|
||||
if (bsd_errno == Network::Errno::E_SUCCESS) {
|
||||
auto [fd, bsd_errno] = SocketImpl(Domain(domain), Type(type), Protocol(protocol));
|
||||
if (bsd_errno == Errno::SUCCESS) {
|
||||
bsd_errno = ShutdownImpl(fd, 0);
|
||||
}
|
||||
|
||||
@@ -269,13 +264,13 @@ void BSD_USA::GetPeerName(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service, "called. fd={}", fd);
|
||||
|
||||
std::vector<u8> write_buffer(ctx.GetWriteBufferSize());
|
||||
const Network::Errno bsd_errno = GetPeerNameImpl(fd, write_buffer);
|
||||
const Errno bsd_errno = GetPeerNameImpl(fd, write_buffer);
|
||||
|
||||
ctx.WriteBuffer(write_buffer);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(bsd_errno != Network::Errno::E_SUCCESS ? -1 : 0);
|
||||
rb.Push<s32>(bsd_errno != Errno::SUCCESS ? -1 : 0);
|
||||
rb.PushEnum(bsd_errno);
|
||||
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
||||
}
|
||||
@@ -287,13 +282,13 @@ void BSD_USA::GetSockName(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service, "called. fd={}", fd);
|
||||
|
||||
std::vector<u8> write_buffer(ctx.GetWriteBufferSize());
|
||||
const Network::Errno bsd_errno = GetSockNameImpl(fd, write_buffer);
|
||||
const Errno bsd_errno = GetSockNameImpl(fd, write_buffer);
|
||||
|
||||
ctx.WriteBuffer(write_buffer);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(bsd_errno != Network::Errno::E_SUCCESS ? -1 : 0);
|
||||
rb.Push<s32>(bsd_errno != Errno::SUCCESS ? -1 : 0);
|
||||
rb.PushEnum(bsd_errno);
|
||||
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
||||
}
|
||||
@@ -301,19 +296,21 @@ void BSD_USA::GetSockName(HLERequestContext& ctx) {
|
||||
void BSD_USA::GetSockOpt(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const s32 fd = rp.Pop<s32>();
|
||||
const auto level = Network::SocketLevel(rp.Pop<u32>());
|
||||
const auto optname = Network::OptName(rp.Pop<u32>());
|
||||
const u32 level = rp.Pop<u32>();
|
||||
const auto optname = static_cast<OptName>(rp.Pop<u32>());
|
||||
|
||||
std::vector<u8> optval(ctx.GetWriteBufferSize());
|
||||
|
||||
LOG_DEBUG(Service, "called. fd={} level={} optname={:#x} len={:#x}", fd, level, optname, optval.size());
|
||||
const Network::Errno err = GetSockOptImpl(fd, level, optname, optval);
|
||||
LOG_DEBUG(Service, "called. fd={} level={} optname={:#x} len={:#x}", fd, level, optname,
|
||||
optval.size());
|
||||
|
||||
const Errno err = GetSockOptImpl(fd, level, optname, optval);
|
||||
|
||||
ctx.WriteBuffer(optval);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(err == Network::Errno::E_SUCCESS ? 0 : -1);
|
||||
rb.Push<s32>(err == Errno::SUCCESS ? 0 : -1);
|
||||
rb.PushEnum(err);
|
||||
rb.Push<u32>(static_cast<u32>(optval.size()));
|
||||
}
|
||||
@@ -336,7 +333,7 @@ void BSD_USA::Fcntl(HLERequestContext& ctx) {
|
||||
|
||||
LOG_DEBUG(Service, "called. fd={} cmd={} arg={}", fd, cmd, arg);
|
||||
|
||||
const auto [ret, bsd_errno] = FcntlImpl(fd, Network::FcntlCmd(cmd), arg);
|
||||
const auto [ret, bsd_errno] = FcntlImpl(fd, static_cast<FcntlCmd>(cmd), arg);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
@@ -348,11 +345,13 @@ void BSD_USA::SetSockOpt(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const s32 fd = rp.Pop<s32>();
|
||||
const Network::SocketLevel level = Network::SocketLevel(rp.Pop<u32>());
|
||||
const Network::OptName optname = Network::OptName(rp.Pop<u32>());
|
||||
const u32 level = rp.Pop<u32>();
|
||||
const OptName optname = static_cast<OptName>(rp.Pop<u32>());
|
||||
const auto optval = ctx.ReadBuffer();
|
||||
|
||||
LOG_DEBUG(Service, "called. fd={} level={} optname={:#x} optlen={}", fd, level, u32(optname), optval.size());
|
||||
LOG_DEBUG(Service, "called. fd={} level={} optname={:#x} optlen={}", fd, level,
|
||||
static_cast<u32>(optname), optval.size());
|
||||
|
||||
BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval));
|
||||
}
|
||||
|
||||
@@ -474,7 +473,7 @@ void BSD_USA::DuplicateSocket(HLERequestContext& ctx) {
|
||||
|
||||
struct OutputParameters {
|
||||
s32 ret;
|
||||
Network::Errno bsd_errno;
|
||||
Errno bsd_errno;
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 0x8);
|
||||
|
||||
@@ -486,7 +485,7 @@ void BSD_USA::DuplicateSocket(HLERequestContext& ctx) {
|
||||
if (is_user) {
|
||||
rb.PushRaw(OutputParameters{
|
||||
.ret = 0,
|
||||
.bsd_errno = Network::Errno::E_INVAL,
|
||||
.bsd_errno = Errno::INVAL,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -495,10 +494,10 @@ void BSD_USA::DuplicateSocket(HLERequestContext& ctx) {
|
||||
if (auto* res = std::get_if<s32>(&res_v)) {
|
||||
rb.PushRaw(OutputParameters{
|
||||
.ret = *res,
|
||||
.bsd_errno = Network::Errno::E_SUCCESS,
|
||||
.bsd_errno = Errno::SUCCESS,
|
||||
});
|
||||
} else {
|
||||
auto* err = std::get_if<Network::Errno>(&res_v);
|
||||
auto* err = std::get_if<Errno>(&res_v);
|
||||
rb.PushRaw(OutputParameters{
|
||||
.ret = 0,
|
||||
.bsd_errno = *err,
|
||||
@@ -513,7 +512,7 @@ void BSD_USA::EventFd(HLERequestContext& ctx) {
|
||||
|
||||
LOG_WARNING(Service, "(STUBBED) called. initval={}, flags={}", initval, flags);
|
||||
|
||||
BuildErrnoResponse(ctx, Network::Errno::E_SUCCESS);
|
||||
BuildErrnoResponse(ctx, Errno::SUCCESS);
|
||||
}
|
||||
|
||||
template <typename Work>
|
||||
@@ -522,143 +521,132 @@ void BSD_USA::ExecuteWork(HLERequestContext& ctx, Work work) {
|
||||
work.Response(ctx);
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> BSD_USA::SocketImpl(Network::Domain domain, Network::Type type, Network::Protocol protocol) {
|
||||
std::pair<s32, Errno> BSD_USA::SocketImpl(Domain domain, Type type, Protocol protocol) {
|
||||
// user bsd:u has restrictions on SOCK_SEQPACKET and SOCK_RAW
|
||||
LOG_DEBUG(Network, "domain={},type={},protocol={}", u32(domain), u32(type), u32(protocol));
|
||||
if (is_user && (type == Network::Type::SEQPACKET || type == Network::Type::RAW)) {
|
||||
if (type == Network::Type::RAW && domain == Network::Domain::INET && protocol == Network::Protocol::ICMP) {
|
||||
if (is_user && (type == Type::SEQPACKET || type == Type::RAW)) {
|
||||
if (type == Type::RAW && domain == Domain::INET && protocol == Protocol::ICMP) {
|
||||
// fine, can use on bsd:s and bsd:u
|
||||
} else {
|
||||
return {-1, Network::Errno::E_INVAL};
|
||||
return {-1, Errno::INVAL};
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]] const bool unk_flag = (u32(type) & 0x20000000) != 0;
|
||||
[[maybe_unused]] const bool unk_flag = (static_cast<u32>(type) & 0x20000000) != 0;
|
||||
UNIMPLEMENTED_IF_MSG(unk_flag, "Unknown flag in type");
|
||||
type = Network::Type(u32(type) & ~0x20000000);
|
||||
type = static_cast<Type>(static_cast<u32>(type) & ~0x20000000);
|
||||
|
||||
const s32 fd = FindFreeFileDescriptorHandle();
|
||||
if (fd < 0) {
|
||||
LOG_ERROR(Service, "No more file descriptors available");
|
||||
return {-1, Network::Errno::E_MFILE};
|
||||
}
|
||||
|
||||
if (Settings::values.airplane_mode.GetValue() && IsConnectionBased(type)) {
|
||||
LOG_ERROR(Service, "Airplane mode is enabled, cannot create socket");
|
||||
file_descriptors[fd].reset();
|
||||
return {-1, Network::Errno::E_NOTCONN};
|
||||
return {-1, Errno::MFILE};
|
||||
}
|
||||
|
||||
file_descriptors[fd] = FileDescriptor{};
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
|
||||
// ENONMEM might be thrown here
|
||||
LOG_INFO(Service, "New socket fd={},domain={},type={},prot={}", fd, domain, type, protocol);
|
||||
|
||||
// While room is important -- we need to remember ICMP takes priority over **everything else**
|
||||
// TODO: rework this so proxy sockets can be done transparently? -- like what if i need
|
||||
// to browse the internet while playing LDN or something stupid like that?
|
||||
LOG_INFO(Service, "New socket fd={}", fd);
|
||||
|
||||
auto room_member = Network::GetRoomMember().lock();
|
||||
if ((protocol != Network::Protocol::ICMP && protocol != Network::Protocol::ICMPV6)
|
||||
&& (room_member && room_member->IsConnected())) {
|
||||
if (room_member && room_member->IsConnected()) {
|
||||
descriptor.socket = std::make_shared<Network::ProxySocket>();
|
||||
descriptor.socket->fd = fd;
|
||||
} else {
|
||||
descriptor.socket = std::make_shared<Network::Socket>();
|
||||
}
|
||||
auto const bsd_errno = descriptor.socket->Initialize(domain, type, protocol);
|
||||
|
||||
#if defined(__unix__) && !defined(__APPLE__)
|
||||
// ...only unix has this issue it seems, ICMP works otherwise fine on win
|
||||
if ((protocol == Network::Protocol::ICMP || protocol == Network::Protocol::ICMPV6)
|
||||
&& bsd_errno != Network::Errno::E_SUCCESS) {
|
||||
LOG_WARNING(Network, "Using ICMP emulated socket");
|
||||
descriptor.socket = std::make_shared<Network::IcmpSocket>();
|
||||
descriptor.socket->fd = fd;
|
||||
}
|
||||
#endif
|
||||
descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(protocol));
|
||||
descriptor.is_connection_based = IsConnectionBased(type);
|
||||
#ifdef _WIN32
|
||||
if (descriptor.is_connection_based && descriptor.socket->fd == INVALID_SOCKET) {
|
||||
#else
|
||||
if (descriptor.is_connection_based && descriptor.socket->fd == Network::Socket::INVALID_SOCKET) {
|
||||
#endif
|
||||
file_descriptors[fd].reset();
|
||||
return {-1, bsd_errno};
|
||||
|
||||
if (Settings::values.airplane_mode.GetValue() && descriptor.is_connection_based) {
|
||||
LOG_ERROR(Service, "Airplane mode is enabled, cannot create socket");
|
||||
return {-1, Errno::NOTCONN};
|
||||
}
|
||||
return {fd, Network::Errno::E_SUCCESS};
|
||||
|
||||
return {fd, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> BSD_USA::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, s32 nfds, s32 timeout) {
|
||||
LOG_DEBUG(Network, "nfds={},timeout={}", nfds, timeout);
|
||||
std::pair<s32, Errno> BSD_USA::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
|
||||
s32 nfds, s32 timeout) {
|
||||
if (nfds <= 0) {
|
||||
// When no entries are provided, -1 is returned with errno zero
|
||||
return {-1, Network::Errno::E_SUCCESS};
|
||||
return {-1, Errno::SUCCESS};
|
||||
}
|
||||
if (read_buffer.size() < nfds * sizeof(Network::PollFD)) {
|
||||
return {-1, Network::Errno::E_INVAL};
|
||||
if (read_buffer.size() < nfds * sizeof(PollFD)) {
|
||||
return {-1, Errno::INVAL};
|
||||
}
|
||||
if (write_buffer.size() < nfds * sizeof(Network::PollFD)) {
|
||||
return {-1, Network::Errno::E_INVAL};
|
||||
if (write_buffer.size() < nfds * sizeof(PollFD)) {
|
||||
return {-1, Errno::INVAL};
|
||||
}
|
||||
|
||||
std::span<const Network::PollFD> in_fds(reinterpret_cast<const Network::PollFD*>(read_buffer.data()), nfds);
|
||||
std::span<Network::PollFD> out_fds(reinterpret_cast<Network::PollFD*>(write_buffer.data()), nfds);
|
||||
std::copy(in_fds.begin(), in_fds.end(), out_fds.begin());
|
||||
std::vector<PollFD> fds(nfds);
|
||||
std::memcpy(fds.data(), read_buffer.data(), nfds * sizeof(PollFD));
|
||||
|
||||
if (timeout >= 0) {
|
||||
const s64 seconds = timeout / 1000;
|
||||
const u64 nanoseconds = 1'000'000 * (u64(timeout) % 1000);
|
||||
const u64 nanoseconds = 1'000'000 * (static_cast<u64>(timeout) % 1000);
|
||||
|
||||
if (seconds < 0) {
|
||||
return {-1, Network::Errno::E_INVAL};
|
||||
return {-1, Errno::INVAL};
|
||||
}
|
||||
if (nanoseconds > 999'999'999) {
|
||||
return {-1, Network::Errno::E_INVAL};
|
||||
return {-1, Errno::INVAL};
|
||||
}
|
||||
} else if (timeout != -1) {
|
||||
return {-1, Network::Errno::E_INVAL};
|
||||
return {-1, Errno::INVAL};
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < in_fds.size(); ++i) {
|
||||
ASSERT(out_fds[i].fd == in_fds[i].fd && False(in_fds[i].revents));
|
||||
if (!IsFileDescriptorValid(in_fds[i].fd)) {
|
||||
out_fds[i].revents = {};
|
||||
if (!file_descriptors[in_fds[i].fd])
|
||||
out_fds[i].revents = Network::PollEvents::NVAL;
|
||||
return {0, Network::Errno::E_SUCCESS};
|
||||
for (PollFD& pollfd : fds) {
|
||||
ASSERT(False(pollfd.revents));
|
||||
|
||||
if (pollfd.fd > static_cast<s32>(MAX_FD) || pollfd.fd < 0) {
|
||||
LOG_ERROR(Service, "File descriptor handle={} is invalid", pollfd.fd);
|
||||
pollfd.revents = PollEvents{};
|
||||
return {0, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
const std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd];
|
||||
if (!descriptor) {
|
||||
LOG_TRACE(Service, "File descriptor handle={} is not allocated", pollfd.fd);
|
||||
pollfd.revents = PollEvents::Nval;
|
||||
return {0, Errno::SUCCESS};
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Network::HostPollFD> host_pollfds(in_fds.size());
|
||||
std::transform(in_fds.begin(), in_fds.end(), host_pollfds.begin(), [](auto const e) {
|
||||
Network::HostPollFD result{};
|
||||
result.socket = file_descriptors[e.fd]->socket.get();
|
||||
result.events = e.events;
|
||||
result.revents = {};
|
||||
std::vector<Network::PollFD> host_pollfds(fds.size());
|
||||
std::transform(fds.begin(), fds.end(), host_pollfds.begin(), [](PollFD pollfd) {
|
||||
Network::PollFD result;
|
||||
result.socket = file_descriptors[pollfd.fd]->socket.get();
|
||||
result.events = Translate(pollfd.events);
|
||||
result.revents = Network::PollEvents{};
|
||||
return result;
|
||||
});
|
||||
auto const res = Network::Poll(host_pollfds, timeout);
|
||||
for (size_t i = 0; i < in_fds.size(); ++i)
|
||||
out_fds[i].revents = host_pollfds[i].revents;
|
||||
return res;
|
||||
|
||||
const auto result = Network::Poll(host_pollfds, timeout);
|
||||
|
||||
const size_t num = host_pollfds.size();
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
fds[i].revents = Translate(host_pollfds[i].revents);
|
||||
}
|
||||
std::memcpy(write_buffer.data(), fds.data(), nfds * sizeof(PollFD));
|
||||
|
||||
return Translate(result);
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> BSD_USA::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
std::pair<s32, Errno> BSD_USA::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Network::Errno::E_BADF};
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
|
||||
const s32 new_fd = FindFreeFileDescriptorHandle();
|
||||
if (new_fd < 0) {
|
||||
LOG_ERROR(Service, "No more file descriptors available");
|
||||
return {-1, Network::Errno::E_MFILE};
|
||||
return {-1, Errno::MFILE};
|
||||
}
|
||||
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
auto [result, bsd_errno] = descriptor.socket->Accept();
|
||||
if (bsd_errno != Network::Errno::E_SUCCESS) {
|
||||
return {-1, bsd_errno};
|
||||
if (bsd_errno != Network::Errno::SUCCESS) {
|
||||
return {-1, Translate(bsd_errno)};
|
||||
}
|
||||
|
||||
file_descriptors[new_fd] = FileDescriptor{};
|
||||
@@ -666,218 +654,267 @@ std::pair<s32, Network::Errno> BSD_USA::AcceptImpl(s32 fd, std::vector<u8>& writ
|
||||
new_descriptor.socket = std::move(result.socket);
|
||||
new_descriptor.is_connection_based = descriptor.is_connection_based;
|
||||
|
||||
PutValue(write_buffer, result.sockaddr_in);
|
||||
return {new_fd, Network::Errno::E_SUCCESS};
|
||||
const SockAddrIn guest_addr_in = Translate(result.sockaddr_in);
|
||||
PutValue(write_buffer, guest_addr_in);
|
||||
|
||||
return {new_fd, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::BindImpl(s32 fd, std::span<const u8> addr) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
Errno BSD_USA::BindImpl(s32 fd, std::span<const u8> addr) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
ASSERT(addr.size() >= 16);
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
auto addr_in = GetValue<Network::SockAddrIn>(addr);
|
||||
return file_descriptors[fd]->socket->Bind(addr_in);
|
||||
auto addr_in = GetValue<SockAddrIn>(addr);
|
||||
|
||||
return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::ConnectImpl(s32 fd, std::span<const u8> addr) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
Errno BSD_USA::ConnectImpl(s32 fd, std::span<const u8> addr) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
ASSERT(addr.size() >= 16);
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
auto addr_in = GetValue<Network::SockAddrIn>(addr);
|
||||
const Network::Errno result = file_descriptors[fd]->socket->Connect(addr_in);
|
||||
if (result == Network::Errno::E_ISCONN) {
|
||||
auto addr_in = GetValue<SockAddrIn>(addr);
|
||||
|
||||
const Errno result = Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in)));
|
||||
|
||||
if (result == Errno::ISCONN) {
|
||||
LOG_DEBUG(Service, "returned ISCONN - socket already connected");
|
||||
return Network::Errno::E_SUCCESS;
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
Errno BSD_USA::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetPeerName();
|
||||
if (bsd_errno != Network::Errno::E_SUCCESS) {
|
||||
return bsd_errno;
|
||||
if (bsd_errno != Network::Errno::SUCCESS) {
|
||||
return Translate(bsd_errno);
|
||||
}
|
||||
ASSERT(write_buffer.size() >= addr_in.len);
|
||||
write_buffer.resize(addr_in.len);
|
||||
PutValue(write_buffer, addr_in);
|
||||
return bsd_errno;
|
||||
const SockAddrIn guest_addrin = Translate(addr_in);
|
||||
|
||||
ASSERT(write_buffer.size() >= sizeof(guest_addrin));
|
||||
write_buffer.resize(sizeof(guest_addrin));
|
||||
PutValue(write_buffer, guest_addrin);
|
||||
return Translate(bsd_errno);
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
Errno BSD_USA::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetSockName();
|
||||
if (bsd_errno != Network::Errno::E_SUCCESS) {
|
||||
return bsd_errno;
|
||||
if (bsd_errno != Network::Errno::SUCCESS) {
|
||||
return Translate(bsd_errno);
|
||||
}
|
||||
ASSERT(write_buffer.size() >= addr_in.len);
|
||||
write_buffer.resize(addr_in.len);
|
||||
PutValue(write_buffer, addr_in);
|
||||
return bsd_errno;
|
||||
const SockAddrIn guest_addrin = Translate(addr_in);
|
||||
|
||||
ASSERT(write_buffer.size() >= sizeof(guest_addrin));
|
||||
write_buffer.resize(sizeof(guest_addrin));
|
||||
PutValue(write_buffer, guest_addrin);
|
||||
return Translate(bsd_errno);
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::ListenImpl(s32 fd, s32 backlog) {
|
||||
LOG_DEBUG(Network, "fd={},backlog={}", fd, backlog);
|
||||
Errno BSD_USA::ListenImpl(s32 fd, s32 backlog) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
return file_descriptors[fd]->socket->Listen(backlog);
|
||||
return Translate(file_descriptors[fd]->socket->Listen(backlog));
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> BSD_USA::FcntlImpl(s32 fd, Network::FcntlCmd cmd, s32 arg) {
|
||||
LOG_DEBUG(Network, "fd={},cmd={},arg={}", fd, u32(cmd), arg);
|
||||
std::pair<s32, Errno> BSD_USA::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Network::Errno::E_BADF};
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return {-1, Network::Errno::E_BADF};
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
|
||||
switch (cmd) {
|
||||
case Network::FcntlCmd::GETFL:
|
||||
case FcntlCmd::GETFL:
|
||||
ASSERT(arg == 0);
|
||||
return {descriptor.flags, Network::Errno::E_SUCCESS};
|
||||
case Network::FcntlCmd::SETFL: {
|
||||
const bool enable = (arg & u32(Network::FcntlFlags::NONBLOCK_NX)) != 0;
|
||||
const Network::Errno bsd_errno = descriptor.socket->SetNonBlock(enable);
|
||||
if (bsd_errno != Network::Errno::E_SUCCESS) {
|
||||
return {descriptor.flags, Errno::SUCCESS};
|
||||
case FcntlCmd::SETFL: {
|
||||
const bool enable = (arg & Network::FLAG_O_NONBLOCK) != 0;
|
||||
const Errno bsd_errno = Translate(descriptor.socket->SetNonBlock(enable));
|
||||
if (bsd_errno != Errno::SUCCESS) {
|
||||
return {-1, bsd_errno};
|
||||
}
|
||||
descriptor.flags = arg;
|
||||
return {0, Network::Errno::E_SUCCESS};
|
||||
return {0, Errno::SUCCESS};
|
||||
}
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented cmd={}", cmd);
|
||||
return {-1, Network::Errno::E_SUCCESS};
|
||||
return {-1, Errno::SUCCESS};
|
||||
}
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::GetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::vector<u8>& optval) {
|
||||
LOG_DEBUG(Network, "fd={},level={},optname={}", fd, u32(level), u32(optname));
|
||||
Errno BSD_USA::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
if (level != Network::SocketLevel::SOCKET) {
|
||||
LOG_WARNING(Service, "(stubbed) level fd={}, level={}, optname={}", fd, level, optname);
|
||||
if (level != static_cast<u32>(SocketLevel::SOCKET)) {
|
||||
UNIMPLEMENTED_MSG("Unknown getsockopt level");
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
|
||||
|
||||
switch (optname) {
|
||||
case Network::OptName::ERROR_: {
|
||||
case OptName::ERROR_: {
|
||||
auto [pending_err, getsockopt_err] = socket->GetPendingError();
|
||||
if (getsockopt_err == Network::Errno::E_SUCCESS) {
|
||||
if (getsockopt_err == Network::Errno::SUCCESS) {
|
||||
Errno translated_pending_err = Translate(pending_err);
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
optval.size() == sizeof(Network::Errno), { return Network::Errno::E_INVAL; },
|
||||
optval.size() == sizeof(Errno), { return Errno::INVAL; },
|
||||
"Incorrect getsockopt option size");
|
||||
optval.resize(sizeof(Network::Errno));
|
||||
PutValue(optval, pending_err);
|
||||
optval.resize(sizeof(Errno));
|
||||
PutValue(optval, translated_pending_err);
|
||||
}
|
||||
return getsockopt_err;
|
||||
return Translate(getsockopt_err);
|
||||
}
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented optname={}", optname);
|
||||
return Network::Errno::E_SUCCESS;
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::SetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::span<const u8> optval) {
|
||||
LOG_DEBUG(Service, "fd={},level={},optname={}", fd, level, optname);
|
||||
Errno BSD_USA::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
if (level != static_cast<u32>(SocketLevel::SOCKET)) {
|
||||
LOG_WARNING(Service, "(STUBBED) setsockopt with level={}, optname={}", level, optname);
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
|
||||
return socket->SetSockOpt(level, optname, optval);
|
||||
|
||||
if (optname == OptName::LINGER) {
|
||||
ASSERT(optval.size() == sizeof(Linger));
|
||||
auto linger = GetValue<Linger>(optval);
|
||||
ASSERT(linger.onoff == 0 || linger.onoff == 1);
|
||||
|
||||
return Translate(socket->SetLinger(linger.onoff != 0, linger.linger));
|
||||
}
|
||||
|
||||
ASSERT(optval.size() == sizeof(u32));
|
||||
auto value = GetValue<u32>(optval);
|
||||
|
||||
switch (optname) {
|
||||
case OptName::REUSEADDR:
|
||||
ASSERT(value == 0 || value == 1);
|
||||
return Translate(socket->SetReuseAddr(value != 0));
|
||||
case OptName::KEEPALIVE:
|
||||
ASSERT(value == 0 || value == 1);
|
||||
return Translate(socket->SetKeepAlive(value != 0));
|
||||
case OptName::BROADCAST:
|
||||
ASSERT(value == 0 || value == 1);
|
||||
return Translate(socket->SetBroadcast(value != 0));
|
||||
case OptName::SNDBUF:
|
||||
return Translate(socket->SetSndBuf(value));
|
||||
case OptName::RCVBUF:
|
||||
return Translate(socket->SetRcvBuf(value));
|
||||
case OptName::SNDTIMEO:
|
||||
return Translate(socket->SetSndTimeo(value));
|
||||
case OptName::RCVTIMEO:
|
||||
return Translate(socket->SetRcvTimeo(value));
|
||||
case OptName::NOSIGPIPE:
|
||||
LOG_WARNING(Service, "(STUBBED) setting NOSIGPIPE to {}", value);
|
||||
return Errno::SUCCESS;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented optname={}", optname);
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::ShutdownImpl(s32 fd, s32 how) {
|
||||
LOG_DEBUG(Network, "fd={},how={}", fd, how);
|
||||
Errno BSD_USA::ShutdownImpl(s32 fd, s32 how) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
return file_descriptors[fd]->socket->Shutdown(Network::ShutdownHow(how));
|
||||
const Network::ShutdownHow host_how = Translate(static_cast<ShutdownHow>(how));
|
||||
return Translate(file_descriptors[fd]->socket->Shutdown(host_how));
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> BSD_USA::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
|
||||
LOG_DEBUG(Network, "fd={},flags={}", fd, flags);
|
||||
std::pair<s32, Errno> BSD_USA::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Network::Errno::E_BADF};
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
|
||||
// Apply flags
|
||||
if ((flags & u32(Network::MsgOpt::DONTWAIT)) != 0) {
|
||||
flags &= ~u32(Network::MsgOpt::DONTWAIT);
|
||||
if ((descriptor.flags & u32(Network::FcntlFlags::NONBLOCK_NX)) == 0) {
|
||||
using Network::FLAG_MSG_DONTWAIT;
|
||||
using Network::FLAG_O_NONBLOCK;
|
||||
if ((flags & FLAG_MSG_DONTWAIT) != 0) {
|
||||
flags &= ~FLAG_MSG_DONTWAIT;
|
||||
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
|
||||
descriptor.socket->SetNonBlock(true);
|
||||
}
|
||||
}
|
||||
|
||||
const auto [ret, bsd_errno] = descriptor.socket->Recv(flags, message);
|
||||
const auto [ret, bsd_errno] = Translate(descriptor.socket->Recv(flags, message));
|
||||
|
||||
// Restore original state
|
||||
if ((descriptor.flags & u32(Network::FcntlFlags::NONBLOCK_NX)) == 0)
|
||||
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
|
||||
descriptor.socket->SetNonBlock(false);
|
||||
}
|
||||
|
||||
return {ret, bsd_errno};
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> BSD_USA::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message, std::vector<u8>& addr) {
|
||||
LOG_DEBUG(Network, "fd={},flags={}", fd, flags);
|
||||
std::pair<s32, Errno> BSD_USA::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
|
||||
std::vector<u8>& addr) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Network::Errno::E_BADF};
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
@@ -892,17 +929,19 @@ std::pair<s32, Network::Errno> BSD_USA::RecvFromImpl(s32 fd, u32 flags, std::vec
|
||||
}
|
||||
|
||||
// Apply flags
|
||||
if ((flags & u32(Network::MsgOpt::DONTWAIT)) != 0) {
|
||||
flags &= ~u32(Network::MsgOpt::DONTWAIT);
|
||||
if ((descriptor.flags & u32(Network::FcntlFlags::NONBLOCK_NX)) == 0) {
|
||||
using Network::FLAG_MSG_DONTWAIT;
|
||||
using Network::FLAG_O_NONBLOCK;
|
||||
if ((flags & FLAG_MSG_DONTWAIT) != 0) {
|
||||
flags &= ~FLAG_MSG_DONTWAIT;
|
||||
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
|
||||
descriptor.socket->SetNonBlock(true);
|
||||
}
|
||||
}
|
||||
|
||||
const auto [ret, bsd_errno] = descriptor.socket->RecvFrom(flags, message, p_addr_in);
|
||||
const auto [ret, bsd_errno] = Translate(descriptor.socket->RecvFrom(flags, message, p_addr_in));
|
||||
|
||||
// Restore original state
|
||||
if ((descriptor.flags & u32(Network::FcntlFlags::NONBLOCK_NX)) == 0) {
|
||||
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
|
||||
descriptor.socket->SetNonBlock(false);
|
||||
}
|
||||
|
||||
@@ -911,59 +950,58 @@ std::pair<s32, Network::Errno> BSD_USA::RecvFromImpl(s32 fd, u32 flags, std::vec
|
||||
addr.clear();
|
||||
} else {
|
||||
ASSERT(addr.size() >= 16);
|
||||
PutValue(addr, addr_in);
|
||||
const SockAddrIn result = Translate(addr_in);
|
||||
PutValue(addr, result);
|
||||
}
|
||||
}
|
||||
|
||||
return {ret, bsd_errno};
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> BSD_USA::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
|
||||
LOG_DEBUG(Network, "fd={},flags={}", fd, flags);
|
||||
std::pair<s32, Errno> BSD_USA::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Network::Errno::E_BADF};
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return {-1, Network::Errno::E_BADF};
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
return file_descriptors[fd]->socket->Send(message, flags);
|
||||
return Translate(file_descriptors[fd]->socket->Send(message, flags));
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> BSD_USA::SendToImpl(s32 fd, u32 flags, std::span<const u8> message, std::span<const u8> addr) {
|
||||
LOG_DEBUG(Network, "fd={},flags={}", fd, flags);
|
||||
std::pair<s32, Errno> BSD_USA::SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
|
||||
std::span<const u8> addr) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Network::Errno::E_BADF};
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return {-1, Network::Errno::E_BADF};
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
|
||||
Network::SockAddrIn addr_in{};
|
||||
Network::SockAddrIn addr_in;
|
||||
Network::SockAddrIn* p_addr_in = nullptr;
|
||||
if (!addr.empty()) {
|
||||
ASSERT(addr.size() >= 16);
|
||||
auto guest_addr_in = GetValue<Network::SockAddrIn>(addr);
|
||||
addr_in = guest_addr_in;
|
||||
auto guest_addr_in = GetValue<SockAddrIn>(addr);
|
||||
addr_in = Translate(guest_addr_in);
|
||||
p_addr_in = &addr_in;
|
||||
}
|
||||
|
||||
return file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in);
|
||||
return Translate(file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in));
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::CloseImpl(s32 fd) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
Errno BSD_USA::CloseImpl(s32 fd) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
auto const bsd_errno = file_descriptors[fd]->socket->Close();
|
||||
if (bsd_errno != Network::Errno::E_SUCCESS) {
|
||||
const Errno bsd_errno = Translate(file_descriptors[fd]->socket->Close());
|
||||
if (bsd_errno != Errno::SUCCESS) {
|
||||
return bsd_errno;
|
||||
}
|
||||
|
||||
@@ -973,16 +1011,15 @@ Network::Errno BSD_USA::CloseImpl(s32 fd) {
|
||||
return bsd_errno;
|
||||
}
|
||||
|
||||
std::variant<s32, Network::Errno> BSD_USA::DuplicateSocketImpl(s32 fd) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
std::variant<s32, Errno> BSD_USA::DuplicateSocketImpl(s32 fd) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
const s32 new_fd = FindFreeFileDescriptorHandle();
|
||||
if (!IsFileDescriptorValid(new_fd)) {
|
||||
if (new_fd < 0) {
|
||||
LOG_ERROR(Service, "No more file descriptors available");
|
||||
return Network::Errno::E_MFILE;
|
||||
return Errno::MFILE;
|
||||
}
|
||||
|
||||
file_descriptors[new_fd] = FileDescriptor{
|
||||
@@ -994,7 +1031,6 @@ std::variant<s32, Network::Errno> BSD_USA::DuplicateSocketImpl(s32 fd) {
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<Network::SocketBase>> BSD_USA::GetSocket(s32 fd) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -1006,40 +1042,41 @@ std::optional<std::shared_ptr<Network::SocketBase>> BSD_USA::GetSocket(s32 fd) {
|
||||
}
|
||||
|
||||
s32 BSD_USA::FindFreeFileDescriptorHandle() noexcept {
|
||||
// first three file descriptors are reserved for:
|
||||
// STDOUT_FILENO, STDIN_FILENO and STDERR_FILENO
|
||||
for (s32 fd = 0; fd < s32(file_descriptors.size()); ++fd)
|
||||
if (!file_descriptors[fd])
|
||||
for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) {
|
||||
if (!file_descriptors[fd]) {
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool BSD_USA::IsFileDescriptorValid(s32 fd) const noexcept {
|
||||
if (fd < 0 || fd >= s32(file_descriptors.size())) {
|
||||
LOG_ERROR(Service, "Invalid handle={}", fd);
|
||||
if (fd > static_cast<s32>(MAX_FD) || fd < 0) {
|
||||
LOG_ERROR(Service, "Invalid file descriptor handle={}", fd);
|
||||
return false;
|
||||
}
|
||||
if (!file_descriptors[fd]) {
|
||||
LOG_ERROR(Service, "handle={} is not allocated", fd);
|
||||
LOG_ERROR(Service, "File descriptor handle={} is not allocated", fd);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BSD_USA::BuildErrnoResponse(HLERequestContext& ctx, Network::Errno bsd_errno) const noexcept {
|
||||
void BSD_USA::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept {
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(bsd_errno == Network::Errno::E_SUCCESS ? 0 : -1);
|
||||
rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
|
||||
rb.PushEnum(bsd_errno);
|
||||
}
|
||||
|
||||
void BSD_USA::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
|
||||
for (auto& optional_descriptor : file_descriptors) {
|
||||
if (optional_descriptor.has_value()) {
|
||||
FileDescriptor& descriptor = *optional_descriptor;
|
||||
descriptor.socket.get()->HandleProxyPacket(packet);
|
||||
if (!optional_descriptor.has_value()) {
|
||||
continue;
|
||||
}
|
||||
FileDescriptor& descriptor = *optional_descriptor;
|
||||
descriptor.socket.get()->HandleProxyPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <variant>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sockets/sockets.h"
|
||||
#include "network/network.h"
|
||||
@@ -35,8 +35,8 @@ public:
|
||||
// These methods are called from SSL; the first two are also called from
|
||||
// this class for the corresponding IPC methods.
|
||||
// On the real device, the SSL service makes IPC calls to this service.
|
||||
std::variant<s32, Network::Errno> DuplicateSocketImpl(s32 fd);
|
||||
Network::Errno CloseImpl(s32 fd);
|
||||
std::variant<s32, Errno> DuplicateSocketImpl(s32 fd);
|
||||
Errno CloseImpl(s32 fd);
|
||||
std::optional<std::shared_ptr<Network::SocketBase>> GetSocket(s32 fd);
|
||||
|
||||
private:
|
||||
@@ -58,7 +58,7 @@ private:
|
||||
std::span<const u8> read_buffer;
|
||||
std::vector<u8> write_buffer;
|
||||
s32 ret{};
|
||||
Network::Errno bsd_errno{};
|
||||
Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct AcceptWork {
|
||||
@@ -68,7 +68,7 @@ private:
|
||||
s32 fd;
|
||||
std::vector<u8> write_buffer;
|
||||
s32 ret{};
|
||||
Network::Errno bsd_errno{};
|
||||
Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct ConnectWork {
|
||||
@@ -77,7 +77,7 @@ private:
|
||||
|
||||
s32 fd;
|
||||
std::span<const u8> addr;
|
||||
Network::Errno bsd_errno{};
|
||||
Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct RecvWork {
|
||||
@@ -88,7 +88,7 @@ private:
|
||||
u32 flags;
|
||||
std::vector<u8> message;
|
||||
s32 ret{};
|
||||
Network::Errno bsd_errno{};
|
||||
Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct RecvFromWork {
|
||||
@@ -100,7 +100,7 @@ private:
|
||||
std::vector<u8> message;
|
||||
std::vector<u8> addr;
|
||||
s32 ret{};
|
||||
Network::Errno bsd_errno{};
|
||||
Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct SendWork {
|
||||
@@ -111,7 +111,7 @@ private:
|
||||
u32 flags;
|
||||
std::span<const u8> message;
|
||||
s32 ret{};
|
||||
Network::Errno bsd_errno{};
|
||||
Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct SendToWork {
|
||||
@@ -123,7 +123,7 @@ private:
|
||||
std::span<const u8> message;
|
||||
std::span<const u8> addr;
|
||||
s32 ret{};
|
||||
Network::Errno bsd_errno{};
|
||||
Errno bsd_errno{};
|
||||
};
|
||||
|
||||
void RegisterClient(HLERequestContext& ctx);
|
||||
@@ -155,29 +155,29 @@ private:
|
||||
template <typename Work>
|
||||
void ExecuteWork(HLERequestContext& ctx, Work work);
|
||||
|
||||
std::pair<s32, Network::Errno> SocketImpl(Network::Domain domain, Network::Type type, Network::Protocol protocol);
|
||||
std::pair<s32, Network::Errno> PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, s32 nfds, s32 timeout);
|
||||
std::pair<s32, Network::Errno> AcceptImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Network::Errno BindImpl(s32 fd, std::span<const u8> addr);
|
||||
Network::Errno ConnectImpl(s32 fd, std::span<const u8> addr);
|
||||
Network::Errno GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Network::Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Network::Errno ListenImpl(s32 fd, s32 backlog);
|
||||
std::pair<s32, Network::Errno> FcntlImpl(s32 fd, Network::FcntlCmd cmd, s32 arg);
|
||||
Network::Errno GetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::vector<u8>& optval);
|
||||
Network::Errno SetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::span<const u8> optval);
|
||||
Network::Errno ShutdownImpl(s32 fd, s32 how);
|
||||
std::pair<s32, Network::Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
|
||||
std::pair<s32, Network::Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
|
||||
std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol);
|
||||
std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, s32 nfds, s32 timeout);
|
||||
std::pair<s32, Errno> AcceptImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Errno BindImpl(s32 fd, std::span<const u8> addr);
|
||||
Errno ConnectImpl(s32 fd, std::span<const u8> addr);
|
||||
Errno GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Errno ListenImpl(s32 fd, s32 backlog);
|
||||
std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg);
|
||||
Errno GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval);
|
||||
Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval);
|
||||
Errno ShutdownImpl(s32 fd, s32 how);
|
||||
std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
|
||||
std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
|
||||
std::vector<u8>& addr);
|
||||
std::pair<s32, Network::Errno> SendImpl(s32 fd, u32 flags, std::span<const u8> message);
|
||||
std::pair<s32, Network::Errno> SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
|
||||
std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, std::span<const u8> message);
|
||||
std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
|
||||
std::span<const u8> addr);
|
||||
|
||||
s32 FindFreeFileDescriptorHandle() noexcept;
|
||||
bool IsFileDescriptorValid(s32 fd) const noexcept;
|
||||
|
||||
void BuildErrnoResponse(HLERequestContext& ctx, Network::Errno bsd_errno) const noexcept;
|
||||
void BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept;
|
||||
|
||||
static inline std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors{};
|
||||
|
||||
|
||||
@@ -102,39 +102,39 @@ static bool IsBlockedHost(const std::string& host) {
|
||||
[&host](const std::string& domain) { return host.find(domain) != std::string::npos; });
|
||||
}
|
||||
|
||||
static NetDbError GetAddrInfoErrorToNetDbError(Network::GetAddrInfoError result) {
|
||||
static NetDbError GetAddrInfoErrorToNetDbError(GetAddrInfoError result) {
|
||||
// These combinations have been verified on console (but are not
|
||||
// exhaustive).
|
||||
switch (result) {
|
||||
case Network::GetAddrInfoError::SUCCESS:
|
||||
case GetAddrInfoError::SUCCESS:
|
||||
return NetDbError::Success;
|
||||
case Network::GetAddrInfoError::AGAIN:
|
||||
case GetAddrInfoError::AGAIN:
|
||||
return NetDbError::TryAgain;
|
||||
case Network::GetAddrInfoError::NODATA:
|
||||
case GetAddrInfoError::NODATA:
|
||||
return NetDbError::HostNotFound;
|
||||
case Network::GetAddrInfoError::SERVICE:
|
||||
case GetAddrInfoError::SERVICE:
|
||||
return NetDbError::Success;
|
||||
default:
|
||||
return NetDbError::HostNotFound;
|
||||
}
|
||||
}
|
||||
|
||||
static Network::Errno GetAddrInfoErrorToErrno(Network::GetAddrInfoError result) {
|
||||
static Errno GetAddrInfoErrorToErrno(GetAddrInfoError result) {
|
||||
// These combinations have been verified on console (but are not
|
||||
// exhaustive).
|
||||
switch (result) {
|
||||
case Network::GetAddrInfoError::SUCCESS:
|
||||
case GetAddrInfoError::SUCCESS:
|
||||
// Note: Sometimes a successful lookup sets errno to EADDRNOTAVAIL for
|
||||
// some reason, but that doesn't seem useful to implement.
|
||||
return Network::Errno::E_SUCCESS;
|
||||
case Network::GetAddrInfoError::AGAIN:
|
||||
return Network::Errno::E_SUCCESS;
|
||||
case Network::GetAddrInfoError::NODATA:
|
||||
return Network::Errno::E_SUCCESS;
|
||||
case Network::GetAddrInfoError::SERVICE:
|
||||
return Network::Errno::E_INVAL;
|
||||
return Errno::SUCCESS;
|
||||
case GetAddrInfoError::AGAIN:
|
||||
return Errno::SUCCESS;
|
||||
case GetAddrInfoError::NODATA:
|
||||
return Errno::SUCCESS;
|
||||
case GetAddrInfoError::SERVICE:
|
||||
return Errno::INVAL;
|
||||
default:
|
||||
return Network::Errno::E_SUCCESS;
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +155,9 @@ static void AppendNulTerminated(std::vector<u8>& vec, std::string_view str) {
|
||||
// host's gethostbyname, because it simplifies portability: e.g., getaddrinfo
|
||||
// behaves the same on Unix and Windows, unlike gethostbyname where Windows
|
||||
// doesn't implement h_errno.
|
||||
static std::vector<u8> SerializeAddrInfoAsHostEnt(std::span<const Network::AddrInfo> vec, std::string_view host) {
|
||||
static std::vector<u8> SerializeAddrInfoAsHostEnt(const std::vector<Network::AddrInfo>& vec,
|
||||
std::string_view host) {
|
||||
|
||||
std::vector<u8> data;
|
||||
// h_name: use the input hostname (append nul-terminated)
|
||||
AppendNulTerminated(data, host);
|
||||
@@ -163,12 +165,12 @@ static std::vector<u8> SerializeAddrInfoAsHostEnt(std::span<const Network::AddrI
|
||||
|
||||
Append<u32_be>(data, 0); // count of h_aliases
|
||||
// (If the count were nonzero, the aliases would be appended as nul-terminated here.)
|
||||
Append<u16_be>(data, u16(Network::Domain::INET)); // h_addrtype
|
||||
Append<u16_be>(data, static_cast<u16>(Domain::INET)); // h_addrtype
|
||||
Append<u16_be>(data, sizeof(Network::IPv4Address)); // h_length
|
||||
// h_addr_list:
|
||||
size_t count = vec.size();
|
||||
ASSERT(count <= UINT32_MAX);
|
||||
Append<u32_be>(data, u32(count));
|
||||
Append<u32_be>(data, static_cast<uint32_t>(count));
|
||||
for (const Network::AddrInfo& addrinfo : vec) {
|
||||
// On the Switch, this is passed through htonl despite already being
|
||||
// big-endian, so it ends up as little-endian.
|
||||
@@ -180,7 +182,7 @@ static std::vector<u8> SerializeAddrInfoAsHostEnt(std::span<const Network::AddrI
|
||||
return data;
|
||||
}
|
||||
|
||||
static std::pair<u32, Network::GetAddrInfoError> GetHostByNameRequestImpl(HLERequestContext& ctx) {
|
||||
static std::pair<u32, GetAddrInfoError> GetHostByNameRequestImpl(HLERequestContext& ctx) {
|
||||
struct InputParameters {
|
||||
u8 use_nsd_resolve;
|
||||
u32 cancel_handle;
|
||||
@@ -203,7 +205,7 @@ static std::pair<u32, Network::GetAddrInfoError> GetHostByNameRequestImpl(HLEReq
|
||||
// Prevent resolution of Nintendo servers
|
||||
if (IsBlockedHost(host)) {
|
||||
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
|
||||
return {0, Network::GetAddrInfoError::AGAIN};
|
||||
return {0, GetAddrInfoError::AGAIN};
|
||||
}
|
||||
|
||||
auto res_v = Network::GetAddressInfo(host, /*service*/ std::nullopt);
|
||||
@@ -211,10 +213,10 @@ static std::pair<u32, Network::GetAddrInfoError> GetHostByNameRequestImpl(HLEReq
|
||||
const std::vector<u8> data = SerializeAddrInfoAsHostEnt(*res, host);
|
||||
const u32 data_size = u32(data.size());
|
||||
ctx.WriteBuffer(data, 0);
|
||||
return {data_size, Network::GetAddrInfoError::SUCCESS};
|
||||
return {data_size, GetAddrInfoError::SUCCESS};
|
||||
}
|
||||
auto* err = std::get_if<Network::GetAddrInfoError>(&res_v);
|
||||
return {0, *err};
|
||||
return {0, Translate(*err)};
|
||||
}
|
||||
|
||||
void SFDNSRES::GetHostByNameRequest(HLERequestContext& ctx) {
|
||||
@@ -222,7 +224,7 @@ void SFDNSRES::GetHostByNameRequest(HLERequestContext& ctx) {
|
||||
|
||||
struct OutputParameters {
|
||||
NetDbError netdb_error;
|
||||
Network::Errno bsd_errno;
|
||||
Errno bsd_errno;
|
||||
u32 data_size;
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 0xc);
|
||||
@@ -242,7 +244,7 @@ void SFDNSRES::GetHostByNameRequestWithOptions(HLERequestContext& ctx) {
|
||||
struct OutputParameters {
|
||||
u32 data_size;
|
||||
NetDbError netdb_error;
|
||||
Network::Errno bsd_errno;
|
||||
Errno bsd_errno;
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 0xc);
|
||||
|
||||
@@ -255,23 +257,24 @@ void SFDNSRES::GetHostByNameRequestWithOptions(HLERequestContext& ctx) {
|
||||
});
|
||||
}
|
||||
|
||||
static std::vector<u8> SerializeAddrInfo(std::span<const Network::AddrInfo> vec, std::string_view host) {
|
||||
static std::vector<u8> SerializeAddrInfo(const std::vector<Network::AddrInfo>& vec,
|
||||
std::string_view host) {
|
||||
// Adapted from
|
||||
// https://github.com/switchbrew/libnx/blob/c5a9a909a91657a9818a3b7e18c9b91ff0cbb6e3/nx/source/runtime/resolver.c#L190
|
||||
std::vector<u8> data;
|
||||
|
||||
for (const Network::AddrInfo& addrinfo : vec) {
|
||||
// serialized addrinfo:
|
||||
Append<u32_be>(data, 0xBEEFCAFE); // magic
|
||||
Append<u32_be>(data, 0); // ai_flags
|
||||
Append<u32_be>(data, u32(addrinfo.family)); // ai_family
|
||||
Append<u32_be>(data, u32(addrinfo.socket_type)); // ai_socktype
|
||||
Append<u32_be>(data, u32(addrinfo.protocol)); // ai_protocol
|
||||
Append<u32_be>(data, 0xBEEFCAFE); // magic
|
||||
Append<u32_be>(data, 0); // ai_flags
|
||||
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.family))); // ai_family
|
||||
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.socket_type))); // ai_socktype
|
||||
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.protocol))); // ai_protocol
|
||||
Append<u32_be>(data, 16); // ai_addrlen
|
||||
// ^ *not* sizeof(SerializedSockAddrIn), not that it matters since they're the same size
|
||||
|
||||
// ai_addr:
|
||||
Append<u16_be>(data, u16(addrinfo.addr.family)); // sin_family
|
||||
Append<u16_be>(data, static_cast<u16>(Translate(addrinfo.addr.family))); // sin_family
|
||||
// On the Switch, the following fields are passed through htonl despite
|
||||
// already being big-endian, so they end up as little-endian.
|
||||
Append<u16_le>(data, addrinfo.addr.portno); // sin_port
|
||||
@@ -293,7 +296,7 @@ static std::vector<u8> SerializeAddrInfo(std::span<const Network::AddrInfo> vec,
|
||||
return data;
|
||||
}
|
||||
|
||||
static std::pair<u32, Network::GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext& ctx) {
|
||||
static std::pair<u32, GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext& ctx) {
|
||||
struct InputParameters {
|
||||
u8 use_nsd_resolve;
|
||||
u32 cancel_handle;
|
||||
@@ -318,7 +321,7 @@ static std::pair<u32, Network::GetAddrInfoError> GetAddrInfoRequestImpl(HLEReque
|
||||
// Prevent resolution of Nintendo servers
|
||||
if (IsBlockedHost(host)) {
|
||||
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
|
||||
return {0, Network::GetAddrInfoError::AGAIN};
|
||||
return {0, GetAddrInfoError::AGAIN};
|
||||
}
|
||||
|
||||
std::optional<std::string> service = std::nullopt;
|
||||
@@ -328,23 +331,24 @@ static std::pair<u32, Network::GetAddrInfoError> GetAddrInfoRequestImpl(HLEReque
|
||||
}
|
||||
|
||||
// Serialized hints are also passed in a buffer, but are ignored for now.
|
||||
|
||||
auto res_v = Network::GetAddressInfo(host, service);
|
||||
if (auto* res = std::get_if<std::vector<Network::AddrInfo>>(&res_v)) {
|
||||
const std::vector<u8> data = SerializeAddrInfo(*res, host);
|
||||
const u32 data_size = u32(data.size());
|
||||
ctx.WriteBuffer(data, 0);
|
||||
return {data_size, Network::GetAddrInfoError::SUCCESS};
|
||||
return {data_size, GetAddrInfoError::SUCCESS};
|
||||
}
|
||||
auto* err = std::get_if<Network::GetAddrInfoError>(&res_v);
|
||||
return {0, *err};
|
||||
return {0, Translate(*err)};
|
||||
}
|
||||
|
||||
void SFDNSRES::GetAddrInfoRequest(HLERequestContext& ctx) {
|
||||
auto [data_size, emu_gai_err] = GetAddrInfoRequestImpl(ctx);
|
||||
|
||||
struct OutputParameters {
|
||||
Network::Errno bsd_errno;
|
||||
Network::GetAddrInfoError gai_error;
|
||||
Errno bsd_errno;
|
||||
GetAddrInfoError gai_error;
|
||||
u32 data_size;
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 0xc);
|
||||
@@ -360,7 +364,7 @@ void SFDNSRES::GetAddrInfoRequest(HLERequestContext& ctx) {
|
||||
|
||||
void SFDNSRES::GetGaiStringErrorRequest(HLERequestContext& ctx) {
|
||||
struct InputParameters {
|
||||
Network::GetAddrInfoError gai_errno;
|
||||
GetAddrInfoError gai_errno;
|
||||
};
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto input = rp.PopRaw<InputParameters>();
|
||||
@@ -378,9 +382,9 @@ void SFDNSRES::GetAddrInfoRequestWithOptions(HLERequestContext& ctx) {
|
||||
|
||||
struct OutputParameters {
|
||||
u32 data_size;
|
||||
Network::GetAddrInfoError gai_error;
|
||||
GetAddrInfoError gai_error;
|
||||
NetDbError netdb_error;
|
||||
Network::Errno bsd_errno;
|
||||
Errno bsd_errno;
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 0x10);
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
@@ -16,6 +15,242 @@ class System;
|
||||
|
||||
namespace Service::Sockets {
|
||||
|
||||
enum class Errno : u32 {
|
||||
SUCCESS = 0,
|
||||
BADF = 9,
|
||||
AGAIN = 11,
|
||||
INVAL = 22,
|
||||
MFILE = 24,
|
||||
PIPE = 32,
|
||||
MSGSIZE = 90,
|
||||
CONNABORTED = 103,
|
||||
CONNRESET = 104,
|
||||
NOTCONN = 107,
|
||||
TIMEDOUT = 110,
|
||||
CONNREFUSED = 111,
|
||||
INPROGRESS = 115,
|
||||
ISCONN = 106,
|
||||
};
|
||||
|
||||
enum class GetAddrInfoError : s32 {
|
||||
SUCCESS = 0,
|
||||
ADDRFAMILY = 1,
|
||||
AGAIN = 2,
|
||||
BADFLAGS = 3,
|
||||
FAIL = 4,
|
||||
FAMILY = 5,
|
||||
MEMORY = 6,
|
||||
NODATA = 7,
|
||||
NONAME = 8,
|
||||
SERVICE = 9,
|
||||
SOCKTYPE = 10,
|
||||
SYSTEM = 11,
|
||||
BADHINTS = 12,
|
||||
PROTOCOL = 13,
|
||||
OVERFLOW_ = 14, // avoid name collision with Windows macro
|
||||
OTHER = 15,
|
||||
};
|
||||
|
||||
enum class Domain : u32 {
|
||||
Unspecified = 0,
|
||||
INET = 2,
|
||||
};
|
||||
|
||||
enum class Type : u32 {
|
||||
Unspecified = 0,
|
||||
STREAM = 1,
|
||||
DGRAM = 2,
|
||||
RAW = 3,
|
||||
SEQPACKET = 5,
|
||||
};
|
||||
|
||||
enum class Protocol : u32 {
|
||||
IP = 0,
|
||||
ICMP = 1,
|
||||
TCP = 6,
|
||||
UDP = 17,
|
||||
//
|
||||
IPV6 = 41,
|
||||
RAW = 255,
|
||||
//
|
||||
HOPOPTS = 0,
|
||||
IGMP = 2,
|
||||
GGP = 3,
|
||||
IPV4 = 4,
|
||||
ST = 7,
|
||||
EGP = 8,
|
||||
PIGP = 9,
|
||||
RCCMON = 10,
|
||||
NVPII = 11,
|
||||
PUP = 12,
|
||||
ARGUS = 13,
|
||||
EMCON = 14,
|
||||
XNET = 15,
|
||||
CHAOS = 16,
|
||||
MUX = 18,
|
||||
MEAS = 19,
|
||||
HMP = 20,
|
||||
PRM = 21,
|
||||
IDP = 22,
|
||||
TRUNK1 = 23,
|
||||
TRUNK2 = 24,
|
||||
LEAF1 = 25,
|
||||
LEAF2 = 26,
|
||||
RDP = 27,
|
||||
IRTP = 28,
|
||||
TP = 29,
|
||||
BLT = 30,
|
||||
NSP = 31,
|
||||
INP = 32,
|
||||
DCCP = 33,
|
||||
//3PC = 34,
|
||||
IDPR = 35,
|
||||
XTP = 36,
|
||||
DDP = 37,
|
||||
CMTP = 38,
|
||||
TPXX = 39,
|
||||
IL = 40,
|
||||
SDRP = 42,
|
||||
ROUTING = 43,
|
||||
FRAGMENT = 44,
|
||||
IDRP = 45,
|
||||
RSVP = 46,
|
||||
GRE = 47,
|
||||
MHRP = 48,
|
||||
BHA = 49,
|
||||
ESP = 50,
|
||||
AH = 51,
|
||||
INLSP = 52,
|
||||
SWIPE = 53,
|
||||
NHRP = 54,
|
||||
MOBILE = 55,
|
||||
TLSP = 56,
|
||||
SKIP = 57,
|
||||
ICMPV6 = 58,
|
||||
NONE = 59,
|
||||
DSTOPTS = 60,
|
||||
AHIP = 61,
|
||||
CFTP = 62,
|
||||
HELLO = 63,
|
||||
SATEXPAK = 64,
|
||||
KRYPTOLAN = 65,
|
||||
RVD = 66,
|
||||
IPPC = 67,
|
||||
ADFS = 68,
|
||||
SATMON = 69,
|
||||
VISA = 70,
|
||||
IPCV = 71,
|
||||
CPNX = 72,
|
||||
CPHB = 73,
|
||||
WSN = 74,
|
||||
PVP = 75,
|
||||
BRSATMON = 76,
|
||||
ND = 77,
|
||||
WBMON = 78,
|
||||
WBEXPAK = 79,
|
||||
EON = 80,
|
||||
VMTP = 81,
|
||||
SVMTP = 82,
|
||||
VINES = 83,
|
||||
TTP = 84,
|
||||
IGP = 85,
|
||||
DGP = 86,
|
||||
TCF = 87,
|
||||
IGRP = 88,
|
||||
OSPFIGP = 89,
|
||||
SRPC = 90,
|
||||
LARP = 91,
|
||||
MTP = 92,
|
||||
AX25 = 93,
|
||||
IPEIP = 94,
|
||||
MICP = 95,
|
||||
SCCSP = 96,
|
||||
ETHERIP = 97,
|
||||
ENCAP = 98,
|
||||
APES = 99,
|
||||
GMTP = 100,
|
||||
IPCOMP = 108,
|
||||
SCTP = 132,
|
||||
MH = 135,
|
||||
UDPLITE = 136,
|
||||
HIP = 139,
|
||||
SHIM6 = 140,
|
||||
PIM = 103,
|
||||
CARP = 112,
|
||||
PGM = 113,
|
||||
MPLS = 137,
|
||||
PFSYNC = 240,
|
||||
};
|
||||
|
||||
enum class SocketLevel : u32 {
|
||||
IP = 0,
|
||||
TCP = 6,
|
||||
SOCKET = 0xffff, // i.e. SOL_SOCKET
|
||||
};
|
||||
|
||||
enum class OptName : u32 {
|
||||
REUSEADDR = 0x4,
|
||||
KEEPALIVE = 0x8,
|
||||
BROADCAST = 0x20,
|
||||
LINGER = 0x80,
|
||||
SNDBUF = 0x1001,
|
||||
RCVBUF = 0x1002,
|
||||
SNDTIMEO = 0x1005,
|
||||
RCVTIMEO = 0x1006,
|
||||
ERROR_ = 0x1007, // avoid name collision with Windows macro
|
||||
NOSIGPIPE = 0x800, // at least according to libnx
|
||||
ACCEPTFILTER = 0x1000,
|
||||
BINTIME = 0x2000,
|
||||
NO_OFFLOAD = 0x4000,
|
||||
NO_DDP = 0x8000,
|
||||
};
|
||||
|
||||
enum class ShutdownHow : s32 {
|
||||
RD = 0,
|
||||
WR = 1,
|
||||
RDWR = 2,
|
||||
};
|
||||
|
||||
enum class FcntlCmd : s32 {
|
||||
GETFL = 3,
|
||||
SETFL = 4,
|
||||
};
|
||||
|
||||
struct SockAddrIn {
|
||||
u8 len;
|
||||
u8 family;
|
||||
u16 portno;
|
||||
std::array<u8, 4> ip;
|
||||
std::array<u8, 248> zeroes;
|
||||
};
|
||||
static_assert(sizeof(SockAddrIn) == 0x100);
|
||||
|
||||
enum class PollEvents : u16 {
|
||||
// Using Pascal case because IN is a macro on Windows.
|
||||
In = 1 << 0,
|
||||
Pri = 1 << 1,
|
||||
Out = 1 << 2,
|
||||
Err = 1 << 3,
|
||||
Hup = 1 << 4,
|
||||
Nval = 1 << 5,
|
||||
RdNorm = 1 << 6,
|
||||
RdBand = 1 << 7,
|
||||
WrBand = 1 << 8,
|
||||
};
|
||||
|
||||
DECLARE_ENUM_FLAG_OPERATORS(PollEvents);
|
||||
|
||||
struct PollFD {
|
||||
s32 fd;
|
||||
PollEvents events;
|
||||
PollEvents revents;
|
||||
};
|
||||
|
||||
struct Linger {
|
||||
u32 onoff;
|
||||
u32 linger;
|
||||
};
|
||||
|
||||
void LoopProcess(Core::System& system);
|
||||
|
||||
} // namespace Service::Sockets
|
||||
|
||||
@@ -15,42 +15,388 @@
|
||||
|
||||
namespace Service::Sockets {
|
||||
|
||||
const char* Translate(Network::GetAddrInfoError error) {
|
||||
// https://android.googlesource.com/platform/bionic/+/085543106/libc/dns/net/getaddrinfo.c#254
|
||||
Errno Translate(Network::Errno value) {
|
||||
switch (value) {
|
||||
case Network::Errno::SUCCESS:
|
||||
return Errno::SUCCESS;
|
||||
case Network::Errno::BADF:
|
||||
return Errno::BADF;
|
||||
case Network::Errno::AGAIN:
|
||||
return Errno::AGAIN;
|
||||
case Network::Errno::INVAL:
|
||||
return Errno::INVAL;
|
||||
case Network::Errno::MFILE:
|
||||
return Errno::MFILE;
|
||||
case Network::Errno::PIPE:
|
||||
return Errno::PIPE;
|
||||
case Network::Errno::CONNREFUSED:
|
||||
return Errno::CONNREFUSED;
|
||||
case Network::Errno::NOTCONN:
|
||||
return Errno::NOTCONN;
|
||||
case Network::Errno::TIMEDOUT:
|
||||
return Errno::TIMEDOUT;
|
||||
case Network::Errno::CONNABORTED:
|
||||
return Errno::CONNABORTED;
|
||||
case Network::Errno::CONNRESET:
|
||||
return Errno::CONNRESET;
|
||||
case Network::Errno::INPROGRESS:
|
||||
return Errno::INPROGRESS;
|
||||
case Network::Errno::ISCONN:
|
||||
return Errno::ISCONN;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented errno={}", value);
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value) {
|
||||
return {value.first, Translate(value.second)};
|
||||
}
|
||||
|
||||
GetAddrInfoError Translate(Network::GetAddrInfoError error) {
|
||||
switch (error) {
|
||||
case Network::GetAddrInfoError::SUCCESS:
|
||||
return "Success";
|
||||
return GetAddrInfoError::SUCCESS;
|
||||
case Network::GetAddrInfoError::ADDRFAMILY:
|
||||
return "Address family for hostname not supported";
|
||||
return GetAddrInfoError::ADDRFAMILY;
|
||||
case Network::GetAddrInfoError::AGAIN:
|
||||
return "Temporary failure in name resolution";
|
||||
return GetAddrInfoError::AGAIN;
|
||||
case Network::GetAddrInfoError::BADFLAGS:
|
||||
return "Invalid value for ai_flags";
|
||||
return GetAddrInfoError::BADFLAGS;
|
||||
case Network::GetAddrInfoError::FAIL:
|
||||
return "Non-recoverable failure in name resolution";
|
||||
return GetAddrInfoError::FAIL;
|
||||
case Network::GetAddrInfoError::FAMILY:
|
||||
return "ai_family not supported";
|
||||
return GetAddrInfoError::FAMILY;
|
||||
case Network::GetAddrInfoError::MEMORY:
|
||||
return "Memory allocation failure";
|
||||
return GetAddrInfoError::MEMORY;
|
||||
case Network::GetAddrInfoError::NODATA:
|
||||
return "No address associated with hostname";
|
||||
return GetAddrInfoError::NODATA;
|
||||
case Network::GetAddrInfoError::NONAME:
|
||||
return "hostname nor servname provided, or not known";
|
||||
return GetAddrInfoError::NONAME;
|
||||
case Network::GetAddrInfoError::SERVICE:
|
||||
return "servname not supported for ai_socktype";
|
||||
return GetAddrInfoError::SERVICE;
|
||||
case Network::GetAddrInfoError::SOCKTYPE:
|
||||
return "ai_socktype not supported";
|
||||
return GetAddrInfoError::SOCKTYPE;
|
||||
case Network::GetAddrInfoError::SYSTEM:
|
||||
return "System error returned in errno";
|
||||
return GetAddrInfoError::SYSTEM;
|
||||
case Network::GetAddrInfoError::BADHINTS:
|
||||
return "Invalid value for hints";
|
||||
return GetAddrInfoError::BADHINTS;
|
||||
case Network::GetAddrInfoError::PROTOCOL:
|
||||
return "Resolved protocol is unknown";
|
||||
return GetAddrInfoError::PROTOCOL;
|
||||
case Network::GetAddrInfoError::OVERFLOW_:
|
||||
return GetAddrInfoError::OVERFLOW_;
|
||||
case Network::GetAddrInfoError::OTHER:
|
||||
return GetAddrInfoError::OTHER;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented GetAddrInfoError={}", error);
|
||||
return GetAddrInfoError::OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
const char* Translate(GetAddrInfoError error) {
|
||||
// https://android.googlesource.com/platform/bionic/+/085543106/libc/dns/net/getaddrinfo.c#254
|
||||
switch (error) {
|
||||
case GetAddrInfoError::SUCCESS:
|
||||
return "Success";
|
||||
case GetAddrInfoError::ADDRFAMILY:
|
||||
return "Address family for hostname not supported";
|
||||
case GetAddrInfoError::AGAIN:
|
||||
return "Temporary failure in name resolution";
|
||||
case GetAddrInfoError::BADFLAGS:
|
||||
return "Invalid value for ai_flags";
|
||||
case GetAddrInfoError::FAIL:
|
||||
return "Non-recoverable failure in name resolution";
|
||||
case GetAddrInfoError::FAMILY:
|
||||
return "ai_family not supported";
|
||||
case GetAddrInfoError::MEMORY:
|
||||
return "Memory allocation failure";
|
||||
case GetAddrInfoError::NODATA:
|
||||
return "No address associated with hostname";
|
||||
case GetAddrInfoError::NONAME:
|
||||
return "hostname nor servname provided, or not known";
|
||||
case GetAddrInfoError::SERVICE:
|
||||
return "servname not supported for ai_socktype";
|
||||
case GetAddrInfoError::SOCKTYPE:
|
||||
return "ai_socktype not supported";
|
||||
case GetAddrInfoError::SYSTEM:
|
||||
return "System error returned in errno";
|
||||
case GetAddrInfoError::BADHINTS:
|
||||
return "Invalid value for hints";
|
||||
case GetAddrInfoError::PROTOCOL:
|
||||
return "Resolved protocol is unknown";
|
||||
case GetAddrInfoError::OVERFLOW_:
|
||||
return "Argument buffer overflow";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
Network::Domain Translate(Domain domain) {
|
||||
switch (domain) {
|
||||
case Domain::Unspecified:
|
||||
return Network::Domain::Unspecified;
|
||||
case Domain::INET:
|
||||
return Network::Domain::INET;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented domain={}", domain);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Domain Translate(Network::Domain domain) {
|
||||
switch (domain) {
|
||||
case Network::Domain::Unspecified:
|
||||
return Domain::Unspecified;
|
||||
case Network::Domain::INET:
|
||||
return Domain::INET;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented domain={}", domain);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Network::Type Translate(Type type) {
|
||||
switch (type) {
|
||||
case Type::Unspecified:
|
||||
return Network::Type::Unspecified;
|
||||
case Type::STREAM:
|
||||
return Network::Type::STREAM;
|
||||
case Type::DGRAM:
|
||||
return Network::Type::DGRAM;
|
||||
case Type::RAW:
|
||||
return Network::Type::RAW;
|
||||
case Type::SEQPACKET:
|
||||
return Network::Type::SEQPACKET;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented type={}", type);
|
||||
return Network::Type{};
|
||||
}
|
||||
}
|
||||
|
||||
Type Translate(Network::Type type) {
|
||||
switch (type) {
|
||||
case Network::Type::Unspecified: return Type::Unspecified;
|
||||
case Network::Type::STREAM: return Type::STREAM;
|
||||
case Network::Type::DGRAM: return Type::DGRAM;
|
||||
case Network::Type::RAW: return Type::RAW;
|
||||
case Network::Type::SEQPACKET: return Type::SEQPACKET;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented type={}", type);
|
||||
return Type{};
|
||||
}
|
||||
}
|
||||
|
||||
#define NETWORK_PROTOCOL_TRANSLATE_LIST \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ICMP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TCP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(UDP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPV6) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(RAW) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IGMP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(GGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPV4) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ST) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(EGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PIGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(RCCMON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(NVPII) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PUP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ARGUS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(EMCON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(XNET) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CHAOS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MUX) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MEAS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(HMP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PRM) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IDP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TRUNK1) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TRUNK2) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(LEAF1) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(LEAF2) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(RDP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IRTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(BLT) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(NSP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(INP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(DCCP) \
|
||||
/*NETWORK_PROTOCOL_TRANSLATE_ELEM(3PC)*/ \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IDPR) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(XTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(DDP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CMTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TPXX) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IL) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SDRP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ROUTING) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(FRAGMENT) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IDRP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(RSVP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(GRE) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MHRP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(BHA) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ESP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(AH) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(INLSP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SWIPE) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(NHRP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MOBILE) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TLSP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SKIP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ICMPV6) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(NONE) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(DSTOPTS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(AHIP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CFTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(HELLO) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SATEXPAK) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(KRYPTOLAN) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(RVD) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPPC) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ADFS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SATMON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(VISA) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPCV) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CPNX) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CPHB) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(WSN) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PVP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(BRSATMON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ND) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(WBMON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(WBEXPAK) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(EON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(VMTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SVMTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(VINES) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(DGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TCF) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IGRP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(OSPFIGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SRPC) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(LARP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(AX25) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPEIP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MICP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SCCSP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ETHERIP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ENCAP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(APES) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(GMTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPCOMP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SCTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MH) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(UDPLITE) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(HIP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SHIM6) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PIM) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CARP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PGM) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MPLS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PFSYNC)
|
||||
[[nodiscard]] Network::Protocol Translate(Protocol protocol) {
|
||||
switch (protocol) {
|
||||
#define NETWORK_PROTOCOL_TRANSLATE_ELEM(name) case Protocol::name: return Network::Protocol::name;
|
||||
NETWORK_PROTOCOL_TRANSLATE_LIST
|
||||
#undef NETWORK_PROTOCOL_TRANSLATE_ELEM
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
[[nodiscard]] Protocol Translate(Network::Protocol protocol) {
|
||||
switch (protocol) {
|
||||
#define NETWORK_PROTOCOL_TRANSLATE_ELEM(name) case Network::Protocol::name: return Protocol::name;
|
||||
NETWORK_PROTOCOL_TRANSLATE_LIST
|
||||
#undef NETWORK_PROTOCOL_TRANSLATE_ELEM
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
#undef NETWORK_PROTOCOL_TRANSLATE_LIST
|
||||
|
||||
Network::PollEvents Translate(PollEvents flags) {
|
||||
Network::PollEvents result{};
|
||||
const auto translate = [&result, &flags](PollEvents from, Network::PollEvents to) {
|
||||
if (True(flags & from)) {
|
||||
flags &= ~from;
|
||||
result |= to;
|
||||
}
|
||||
};
|
||||
translate(PollEvents::In, Network::PollEvents::In);
|
||||
translate(PollEvents::Pri, Network::PollEvents::Pri);
|
||||
translate(PollEvents::Out, Network::PollEvents::Out);
|
||||
translate(PollEvents::Err, Network::PollEvents::Err);
|
||||
translate(PollEvents::Hup, Network::PollEvents::Hup);
|
||||
translate(PollEvents::Nval, Network::PollEvents::Nval);
|
||||
translate(PollEvents::RdNorm, Network::PollEvents::RdNorm);
|
||||
translate(PollEvents::RdBand, Network::PollEvents::RdBand);
|
||||
translate(PollEvents::WrBand, Network::PollEvents::WrBand);
|
||||
|
||||
UNIMPLEMENTED_IF_MSG((u16)flags != 0, "Unimplemented flags={}", (u16)flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
PollEvents Translate(Network::PollEvents flags) {
|
||||
PollEvents result{};
|
||||
const auto translate = [&result, &flags](Network::PollEvents from, PollEvents to) {
|
||||
if (True(flags & from)) {
|
||||
flags &= ~from;
|
||||
result |= to;
|
||||
}
|
||||
};
|
||||
|
||||
translate(Network::PollEvents::In, PollEvents::In);
|
||||
translate(Network::PollEvents::Pri, PollEvents::Pri);
|
||||
translate(Network::PollEvents::Out, PollEvents::Out);
|
||||
translate(Network::PollEvents::Err, PollEvents::Err);
|
||||
translate(Network::PollEvents::Hup, PollEvents::Hup);
|
||||
translate(Network::PollEvents::Nval, PollEvents::Nval);
|
||||
translate(Network::PollEvents::RdNorm, PollEvents::RdNorm);
|
||||
translate(Network::PollEvents::RdBand, PollEvents::RdBand);
|
||||
translate(Network::PollEvents::WrBand, PollEvents::WrBand);
|
||||
|
||||
UNIMPLEMENTED_IF_MSG((u16)flags != 0, "Unimplemented flags={}", (u16)flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
Network::SockAddrIn Translate(SockAddrIn value) {
|
||||
// All lengths are valid, from [0 upto 256]
|
||||
return {
|
||||
.family = Translate(Domain(value.family)),
|
||||
.ip = value.ip,
|
||||
.portno = static_cast<u16>(value.portno >> 8 | value.portno << 8),
|
||||
};
|
||||
}
|
||||
|
||||
SockAddrIn Translate(Network::SockAddrIn value) {
|
||||
return {
|
||||
.len = 16,
|
||||
.family = static_cast<u8>(Translate(value.family)),
|
||||
.portno = static_cast<u16>(value.portno >> 8 | value.portno << 8),
|
||||
.ip = value.ip,
|
||||
.zeroes = {},
|
||||
};
|
||||
}
|
||||
|
||||
Network::ShutdownHow Translate(ShutdownHow how) {
|
||||
switch (how) {
|
||||
case ShutdownHow::RD:
|
||||
return Network::ShutdownHow::RD;
|
||||
case ShutdownHow::WR:
|
||||
return Network::ShutdownHow::WR;
|
||||
case ShutdownHow::RDWR:
|
||||
return Network::ShutdownHow::RDWR;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented how={}", how);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::Sockets
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -14,7 +11,49 @@
|
||||
|
||||
namespace Service::Sockets {
|
||||
|
||||
/// Translate abstract errno to guest errno
|
||||
Errno Translate(Network::Errno value);
|
||||
|
||||
/// Translate abstract return value errno pair to guest return value errno pair
|
||||
std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value);
|
||||
|
||||
/// Translate abstract getaddrinfo error to guest getaddrinfo error
|
||||
GetAddrInfoError Translate(Network::GetAddrInfoError value);
|
||||
|
||||
/// Translate guest error to string
|
||||
const char* Translate(Network::GetAddrInfoError value);
|
||||
const char* Translate(GetAddrInfoError value);
|
||||
|
||||
/// Translate guest domain to abstract domain
|
||||
Network::Domain Translate(Domain domain);
|
||||
|
||||
/// Translate abstract domain to guest domain
|
||||
Domain Translate(Network::Domain domain);
|
||||
|
||||
/// Translate guest type to abstract type
|
||||
Network::Type Translate(Type type);
|
||||
|
||||
/// Translate abstract type to guest type
|
||||
Type Translate(Network::Type type);
|
||||
|
||||
/// Translate guest protocol to abstract protocol
|
||||
Network::Protocol Translate(Protocol protocol);
|
||||
|
||||
/// Translate abstract protocol to guest protocol
|
||||
Protocol Translate(Network::Protocol protocol);
|
||||
|
||||
/// Translate guest poll event flags to abstract poll event flags
|
||||
Network::PollEvents Translate(PollEvents flags);
|
||||
|
||||
/// Translate abstract poll event flags to guest poll event flags
|
||||
PollEvents Translate(Network::PollEvents flags);
|
||||
|
||||
/// Translate guest socket address structure to abstract socket address structure
|
||||
Network::SockAddrIn Translate(SockAddrIn value);
|
||||
|
||||
/// Translate abstract socket address structure to guest socket address structure
|
||||
SockAddrIn Translate(Network::SockAddrIn value);
|
||||
|
||||
/// Translate guest shutdown mode to abstract shutdown mode
|
||||
Network::ShutdownHow Translate(ShutdownHow how);
|
||||
|
||||
} // namespace Service::Sockets
|
||||
|
||||
@@ -132,7 +132,7 @@ public:
|
||||
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD_USA>("bsd:u");
|
||||
if (bsd) {
|
||||
auto err = bsd->CloseImpl(fd);
|
||||
if (err != Network::Errno::E_SUCCESS) {
|
||||
if (err != Service::Sockets::Errno::SUCCESS) {
|
||||
LOG_ERROR(Service_SSL, "Failed to close duplicated socket: {}", err);
|
||||
}
|
||||
}
|
||||
@@ -203,7 +203,7 @@ private:
|
||||
|
||||
const bool non_block = mode == IoMode::NonBlocking;
|
||||
const Network::Errno error = socket->SetNonBlock(non_block);
|
||||
if (error != Network::Errno::E_SUCCESS) {
|
||||
if (error != Network::Errno::SUCCESS) {
|
||||
LOG_ERROR(Service_SSL, "Failed to set native socket non-block flag to {}", non_block);
|
||||
}
|
||||
return ResultSuccess;
|
||||
|
||||
@@ -290,10 +290,10 @@ public:
|
||||
BIO_clear_retry_flags(bio);
|
||||
auto [actual, err] = self->socket->Send({reinterpret_cast<const u8*>(buf), len}, 0);
|
||||
switch (err) {
|
||||
case Network::Errno::E_SUCCESS:
|
||||
case Network::Errno::SUCCESS:
|
||||
*actual_p = actual;
|
||||
return 1;
|
||||
case Network::Errno::E_AGAIN:
|
||||
case Network::Errno::AGAIN:
|
||||
BIO_set_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY);
|
||||
return 0;
|
||||
default:
|
||||
@@ -309,13 +309,13 @@ public:
|
||||
BIO_clear_retry_flags(bio);
|
||||
auto [actual, err] = self->socket->Recv(0, {reinterpret_cast<u8*>(buf), len});
|
||||
switch (err) {
|
||||
case Network::Errno::E_SUCCESS:
|
||||
case Network::Errno::SUCCESS:
|
||||
*actual_p = actual;
|
||||
if (actual == 0) {
|
||||
self->got_read_eof = true;
|
||||
}
|
||||
return actual ? 1 : 0;
|
||||
case Network::Errno::E_AGAIN:
|
||||
case Network::Errno::AGAIN:
|
||||
BIO_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY);
|
||||
return 0;
|
||||
default:
|
||||
|
||||
@@ -146,11 +146,11 @@ public:
|
||||
const auto read_span = std::span(ciphertext_read_buf).subspan(offset, fill_size);
|
||||
const auto [actual, err] = socket->Recv(0, read_span);
|
||||
switch (err) {
|
||||
case Network::Errno::E_SUCCESS:
|
||||
case Network::Errno::SUCCESS:
|
||||
ASSERT(static_cast<size_t>(actual) <= fill_size);
|
||||
ciphertext_read_buf.resize(offset + actual);
|
||||
return ResultSuccess;
|
||||
case Network::Errno::E_AGAIN:
|
||||
case Network::Errno::AGAIN:
|
||||
ciphertext_read_buf.resize(offset);
|
||||
return ResultWouldBlock;
|
||||
default:
|
||||
@@ -165,12 +165,12 @@ public:
|
||||
while (!ciphertext_write_buf.empty()) {
|
||||
const auto [actual, err] = socket->Send(ciphertext_write_buf, 0);
|
||||
switch (err) {
|
||||
case Network::Errno::E_SUCCESS:
|
||||
case Network::Errno::SUCCESS:
|
||||
ASSERT(static_cast<size_t>(actual) <= ciphertext_write_buf.size());
|
||||
ciphertext_write_buf.erase(ciphertext_write_buf.begin(),
|
||||
ciphertext_write_buf.begin() + actual);
|
||||
break;
|
||||
case Network::Errno::E_AGAIN:
|
||||
case Network::Errno::AGAIN:
|
||||
return ResultWouldBlock;
|
||||
default:
|
||||
LOG_ERROR(Service_SSL, "Socket send returned Network::Errno {}", err);
|
||||
|
||||
@@ -195,7 +195,7 @@ public:
|
||||
LOG_CRITICAL(Service_SSL, "op={}, offset={} actual={}/{} err={}", is_read, offset,
|
||||
actual, cur.size(), static_cast<s32>(err));
|
||||
switch (err) {
|
||||
case Network::Errno::E_SUCCESS:
|
||||
case Network::Errno::SUCCESS:
|
||||
offset += actual;
|
||||
if (actual == 0) {
|
||||
ASSERT(is_read);
|
||||
@@ -203,7 +203,7 @@ public:
|
||||
return errSecEndOfData;
|
||||
}
|
||||
break;
|
||||
case Network::Errno::E_AGAIN:
|
||||
case Network::Errno::AGAIN:
|
||||
*dataLength = offset;
|
||||
return errSSLWouldBlock;
|
||||
default:
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <common/socket_types.h>
|
||||
#include <mutex>
|
||||
#include "core/internal_network/socket_types.h"
|
||||
|
||||
namespace Network {
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "common/socket_types.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
@@ -31,10 +31,68 @@ namespace Network {
|
||||
class SocketBase;
|
||||
class Socket;
|
||||
|
||||
struct HostPollFD {
|
||||
SocketBase* socket = nullptr;
|
||||
Network::PollEvents events = {};
|
||||
Network::PollEvents revents = {};
|
||||
/// Error code for network functions
|
||||
enum class Errno {
|
||||
SUCCESS,
|
||||
BADF,
|
||||
INVAL,
|
||||
MFILE,
|
||||
PIPE,
|
||||
NOTCONN,
|
||||
AGAIN,
|
||||
CONNREFUSED,
|
||||
CONNRESET,
|
||||
CONNABORTED,
|
||||
HOSTUNREACH,
|
||||
NETDOWN,
|
||||
NETUNREACH,
|
||||
TIMEDOUT,
|
||||
MSGSIZE,
|
||||
INPROGRESS,
|
||||
ISCONN,
|
||||
OTHER,
|
||||
};
|
||||
|
||||
enum class GetAddrInfoError {
|
||||
SUCCESS,
|
||||
ADDRFAMILY,
|
||||
AGAIN,
|
||||
BADFLAGS,
|
||||
FAIL,
|
||||
FAMILY,
|
||||
MEMORY,
|
||||
NODATA,
|
||||
NONAME,
|
||||
SERVICE,
|
||||
SOCKTYPE,
|
||||
SYSTEM,
|
||||
BADHINTS,
|
||||
PROTOCOL,
|
||||
OVERFLOW_,
|
||||
OTHER,
|
||||
};
|
||||
|
||||
/// Cross-platform poll fd structure
|
||||
|
||||
enum class PollEvents : u16 {
|
||||
// Using Pascal case because IN is a macro on Windows.
|
||||
In = 1 << 0,
|
||||
Pri = 1 << 1,
|
||||
Out = 1 << 2,
|
||||
Err = 1 << 3,
|
||||
Hup = 1 << 4,
|
||||
Nval = 1 << 5,
|
||||
RdNorm = 1 << 6,
|
||||
RdBand = 1 << 7,
|
||||
WrBand = 1 << 8,
|
||||
};
|
||||
|
||||
DECLARE_ENUM_FLAG_OPERATORS(PollEvents);
|
||||
|
||||
struct PollFD {
|
||||
SocketBase* socket;
|
||||
PollEvents events;
|
||||
PollEvents revents;
|
||||
};
|
||||
|
||||
class NetworkInstance {
|
||||
@@ -43,10 +101,6 @@ public:
|
||||
~NetworkInstance();
|
||||
};
|
||||
|
||||
sockaddr_in TranslateFromSockAddrIn(Network::SockAddrIn input);
|
||||
Network::SockAddrIn TranslateToSockAddrIn(sockaddr_in input);
|
||||
s32 TranslateMsgOptToNative(s32 flags);
|
||||
|
||||
void CancelPendingSocketOperations();
|
||||
void RestartSocketOperations();
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace Network {
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
|
||||
ULONG buf_size = 0;
|
||||
if (GetAdaptersAddresses(
|
||||
@@ -66,7 +66,7 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<NetworkInterface> result;
|
||||
std::vector<Network::NetworkInterface> result;
|
||||
|
||||
for (auto* a = addrs; a; a = a->Next) {
|
||||
|
||||
@@ -89,7 +89,7 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
gw = reinterpret_cast<sockaddr_in*>(a->FirstGatewayAddress->Address.lpSockaddr)
|
||||
->sin_addr;
|
||||
|
||||
result.emplace_back(NetworkInterface{
|
||||
result.emplace_back(Network::NetworkInterface{
|
||||
.name = Common::UTF16ToUTF8(std::wstring{a->FriendlyName}),
|
||||
.ip_address = ip,
|
||||
.subnet_mask = mask,
|
||||
@@ -103,7 +103,7 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
|
||||
#else
|
||||
|
||||
std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
#if defined(__ANDROID__) || defined(__linux__)
|
||||
struct ifaddrs* ifaddr = nullptr;
|
||||
if (getifaddrs(&ifaddr) != 0) {
|
||||
@@ -135,7 +135,7 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
LOG_WARNING(Network, "\"/proc/net/route\" not found - using gateway 0");
|
||||
}
|
||||
#endif
|
||||
std::vector<NetworkInterface> ifaces;
|
||||
std::vector<Network::NetworkInterface> ifaces;
|
||||
for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
|
||||
if (ifa->ifa_addr == nullptr || ifa->ifa_netmask == nullptr /* Have a netmask and address */
|
||||
|| ifa->ifa_addr->sa_family != AF_INET /* Must be of kind AF_INET */
|
||||
@@ -149,7 +149,7 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
});
|
||||
in_addr gw; // Solaris defines s_addr as a macro, can't use special C++ shenanigans here
|
||||
gw.s_addr = it != routes.end() ? it->gateway : 0;
|
||||
ifaces.emplace_back(NetworkInterface{
|
||||
ifaces.emplace_back(Network::NetworkInterface{
|
||||
.name = ifa->ifa_name,
|
||||
.ip_address = std::bit_cast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr,
|
||||
.subnet_mask = std::bit_cast<struct sockaddr_in>(*ifa->ifa_netmask).sin_addr,
|
||||
@@ -159,7 +159,7 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
freeifaddrs(ifaddr);
|
||||
return ifaces;
|
||||
#elif defined(__FreeBSD__)
|
||||
std::vector<NetworkInterface> ifaces;
|
||||
std::vector<Network::NetworkInterface> ifaces;
|
||||
int fd = ::socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
|
||||
if (fd < 0) {
|
||||
LOG_ERROR(Network, "socket: {}", std::strerror(errno));
|
||||
@@ -191,7 +191,7 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
size_t msglen = rtm->rtm_msglen - sizeof(*ifm);
|
||||
char const* p = (char const*)(ifm + 1);
|
||||
|
||||
NetworkInterface iface{};
|
||||
Network::NetworkInterface iface{};
|
||||
for (size_t i = 0; i < RTAX_MAX; i++)
|
||||
if ((ifm->ifm_addrs & (1 << i)) != 0) {
|
||||
struct sockaddr const* sa = reinterpret_cast<struct sockaddr const*>(p);
|
||||
@@ -220,7 +220,7 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
std::optional<NetworkInterface> GetSelectedNetworkInterface() {
|
||||
std::optional<Network::NetworkInterface> GetSelectedNetworkInterface() {
|
||||
auto const& sel_if = Settings::values.network_interface.GetValue();
|
||||
if (auto const ifaces = Network::GetAvailableNetworkInterfaces(); ifaces.size() > 0) {
|
||||
if (sel_if.empty())
|
||||
|
||||
@@ -1,277 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <cerrno>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#ifdef __unix__
|
||||
#include <spawn.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "common/assert.h"
|
||||
#include "common/logging.h"
|
||||
#include "core/internal_network/socket_icmp.h"
|
||||
|
||||
extern "C" {
|
||||
extern char **environ;
|
||||
}
|
||||
|
||||
namespace Network {
|
||||
|
||||
namespace {
|
||||
|
||||
u16 ComputeChecksum(std::span<const u8> data) {
|
||||
u32 sum = 0;
|
||||
for (size_t i = 0; i < data.size(); i += 2) {
|
||||
u32 value = (u32(data[i + 0]) << 8ull) | u32(data[i + 1]); //big endian
|
||||
sum += value;
|
||||
}
|
||||
if (data.size() % 2 != 0){
|
||||
sum += u16(data[data.size() - 1]) << 8;
|
||||
}
|
||||
while ((sum >> 16) != 0)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
return (~sum) & 0xffff;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
IcmpSocket::~IcmpSocket() {
|
||||
if (fd == INVALID_SOCKET) {
|
||||
return;
|
||||
}
|
||||
fd = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
Errno IcmpSocket::SetSockOpt(Network::SocketLevel level, Network::OptName optname, std::span<const u8> optval) {
|
||||
LOG_WARNING(Network, "(stubbed) level={},optname={},optval={}", level, optname, optval.size());
|
||||
if (optname == Network::OptName::RCVTIMEO) {
|
||||
if (optval.size() < sizeof(Network::Timeval))
|
||||
return Errno::E_INVAL;
|
||||
std::memcpy(&rcv_timeo, optval.data(), sizeof(rcv_timeo));
|
||||
}
|
||||
return Errno::E_SUCCESS;
|
||||
}
|
||||
|
||||
Errno IcmpSocket::Initialize(Domain domain, Type type, Protocol socket_protocol) {
|
||||
return Errno::E_SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<IcmpSocket::AcceptResult, Errno> IcmpSocket::Accept() {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return {AcceptResult{}, Errno::E_SUCCESS};
|
||||
}
|
||||
|
||||
Errno IcmpSocket::Connect(Network::SockAddrIn addr_in) {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
connected_addr = addr_in;
|
||||
return Errno::E_SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<Network::SockAddrIn, Errno> IcmpSocket::GetPeerName() {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return {Network::SockAddrIn{}, Errno::E_SUCCESS};
|
||||
}
|
||||
|
||||
std::pair<Network::SockAddrIn, Errno> IcmpSocket::GetSockName() {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return {Network::SockAddrIn{}, Errno::E_SUCCESS};
|
||||
}
|
||||
|
||||
Errno IcmpSocket::Bind(Network::SockAddrIn addr) {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return Errno::E_SUCCESS;
|
||||
}
|
||||
|
||||
Errno IcmpSocket::Listen(s32 backlog) {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return Errno::E_SUCCESS;
|
||||
}
|
||||
|
||||
Errno IcmpSocket::Shutdown(ShutdownHow how) {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return Errno::E_SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> IcmpSocket::Recv(int flags, std::span<u8> message) {
|
||||
LOG_DEBUG(Network, "(stubbed) called");
|
||||
return connected_addr.has_value()
|
||||
? RecvFrom(flags, message, nullptr)
|
||||
: std::make_pair(s32(0), Errno::E_NOTCONN);
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> IcmpSocket::RecvFrom(int flags, std::span<u8> message, Network::SockAddrIn* addr) {
|
||||
LOG_DEBUG(Network, "(stubbed) called");
|
||||
ASSERT(flags == 0);
|
||||
ASSERT(message.size() < std::size_t((std::numeric_limits<int>::max)()));
|
||||
|
||||
#if !defined(__OPENORBIS__) && (defined(__FreeBSD__) || defined(__linux__))
|
||||
const auto rcv_timeout_ms = (s64(rcv_timeo.tv_sec) * 1000) + (s64(rcv_timeo.tv_usec) / 1000);
|
||||
const auto timestamp = std::chrono::steady_clock::now();
|
||||
while (true) {
|
||||
{
|
||||
std::lock_guard guard(pings_mutex);
|
||||
// find ping process that is finished running
|
||||
for (auto it = pings.begin(); it != pings.end();) {
|
||||
pid_t result = waitpid(it->ping_pid, &it->ping_status, WNOHANG);
|
||||
// ping process is still running, go to next
|
||||
if (result != it->ping_pid) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
// ping process is finished, remove and handle it
|
||||
it = pings.erase(it);
|
||||
if (it->ping_status == 0) {
|
||||
if (addr) {
|
||||
addr->family = it->family;
|
||||
addr->ip = it->ip;
|
||||
addr->portno = it->portno;
|
||||
addr->len = 16;
|
||||
addr->zeroes = {};
|
||||
}
|
||||
std::array<u8, 8> data{
|
||||
0,
|
||||
0,
|
||||
0, //checksum
|
||||
0,
|
||||
it->seq_ident[0],
|
||||
it->seq_ident[1],
|
||||
it->seq_ident[2],
|
||||
it->seq_ident[3]
|
||||
};
|
||||
auto const csum = ComputeChecksum(std::span<const u8>{data.begin(), data.end()});
|
||||
data[2] = u8(csum >> 8); //hi
|
||||
data[3] = u8(csum); //lo
|
||||
auto const n = std::min(data.size(), message.size());
|
||||
std::copy(data.begin(), data.begin() + n, message.begin());
|
||||
return {s32(n), Errno::E_SUCCESS};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!blocking)
|
||||
return {-1, Errno::E_AGAIN};
|
||||
|
||||
const auto time_diff = std::chrono::steady_clock::now() - timestamp;
|
||||
const auto time_diff_ms = std::chrono::duration_cast<std::chrono::milliseconds>(time_diff).count();
|
||||
if (time_diff_ms > rcv_timeout_ms)
|
||||
return {-1, Errno::E_TIMEDOUT};
|
||||
|
||||
std::this_thread::yield();
|
||||
}
|
||||
#endif
|
||||
return {-1, Errno::E_INVAL};
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> IcmpSocket::Send(std::span<const u8> message, int flags) {
|
||||
LOG_DEBUG(Network, "(stubbed) called");
|
||||
if (connected_addr.has_value())
|
||||
return SendTo(flags, message, std::addressof(connected_addr.value()));
|
||||
return {s32(0), Errno::E_NOTCONN};
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> IcmpSocket::SendTo(u32 flags, std::span<const u8> message, const Network::SockAddrIn* addr) {
|
||||
LOG_DEBUG(Network, "(stubbed) called");
|
||||
ASSERT(message.size() < size_t((std::numeric_limits<int>::max)()));
|
||||
// 0 -> 8 (IPv4), 128 (IPv6)
|
||||
// 1 -> 0
|
||||
// 2..4 -> checksum
|
||||
// 4..6 -> ident
|
||||
// 6..8 -> seq
|
||||
|
||||
// PLEASE DON'T KILL ME, I SWEAR THIS IS LEGITIMATELY THE BEST WAY TO DO IT
|
||||
// IF YOU OPEN socket() GOOGLE WILL STRAIGHT UP IP BAN YOU AFTER 2 HOURS
|
||||
#if !(defined(__OPENORBIS__) || defined(__ANDROID__)) && (defined(__FreeBSD__) || defined(__linux__))
|
||||
const auto rcv_timeout_ms = (s64(rcv_timeo.tv_sec) * 1000) + (s64(rcv_timeo.tv_usec) / 1000);
|
||||
if (!addr)
|
||||
return {-1, Errno::E_DESTADDRREQ};
|
||||
|
||||
if (message.size() >= 8) {
|
||||
std::string ip_str = fmt::format(
|
||||
"{}.{}.{}.{}",
|
||||
addr->ip[0],
|
||||
addr->ip[1],
|
||||
addr->ip[2],
|
||||
addr->ip[3]
|
||||
);
|
||||
#ifdef __FreeBSD__
|
||||
// ping -W option is a nonfractional int (milliseconds)
|
||||
std::string timeout_str = fmt::format("{}", rcv_timeout_ms);
|
||||
std::vector<char*> argv = {
|
||||
const_cast<char*>("ping"),
|
||||
const_cast<char*>("-c"),
|
||||
const_cast<char*>("1"),
|
||||
const_cast<char*>("-W"),
|
||||
timeout_str.data(),
|
||||
ip_str.data(),
|
||||
nullptr
|
||||
};
|
||||
#elif defined(__linux__)
|
||||
// ping -W option is a fractional float (seconds)
|
||||
auto const rcv_timeout_s = f64(rcv_timeout_ms) / 1000.0;
|
||||
std::string timeout_str = fmt::format("{}", rcv_timeout_s);
|
||||
std::vector<char*> argv = {
|
||||
const_cast<char*>("ping"),
|
||||
const_cast<char*>("-c"),
|
||||
const_cast<char*>("1"),
|
||||
const_cast<char*>("-W"),
|
||||
timeout_str.data(),
|
||||
ip_str.data(),
|
||||
nullptr
|
||||
};
|
||||
#endif
|
||||
pid_t ping_pid;
|
||||
// we should pass in attributes to stop stdout spam, but im too lazy to figure that out
|
||||
if (posix_spawnp(&ping_pid, "ping", nullptr, nullptr, argv.data(), environ) != 0) {
|
||||
LOG_ERROR(Network, "Unable to start ping process for emulated ICMP socket");
|
||||
return {-1, Errno::E_INVAL};
|
||||
}
|
||||
std::lock_guard guard(pings_mutex);
|
||||
if (pings.size() >= pings.max_size())
|
||||
pings.erase(pings.begin());
|
||||
pings.push_back(PingProcessData{
|
||||
.ip = addr->ip,
|
||||
.portno = addr->portno,
|
||||
.ping_pid = ping_pid,
|
||||
.ping_status = 0,
|
||||
.seq_ident = {
|
||||
message[4],
|
||||
message[5],
|
||||
message[6],
|
||||
message[7]
|
||||
},
|
||||
.family = addr->family,
|
||||
});
|
||||
return {s32(message.size()), Errno::E_SUCCESS};
|
||||
}
|
||||
#endif
|
||||
return {-1, Errno::E_INVAL};
|
||||
}
|
||||
|
||||
Errno IcmpSocket::Close() {
|
||||
LOG_DEBUG(Network, "called");
|
||||
fd = INVALID_SOCKET;
|
||||
return Errno::E_SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<Errno, Errno> IcmpSocket::GetPendingError() {
|
||||
LOG_DEBUG(Network, "called");
|
||||
return {Errno::E_SUCCESS, Errno::E_SUCCESS};
|
||||
}
|
||||
|
||||
bool IcmpSocket::IsOpened() const {
|
||||
return fd != INVALID_SOCKET;
|
||||
}
|
||||
|
||||
void IcmpSocket::HandleProxyPacket(const ProxyPacket& packet) {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
}
|
||||
Errno IcmpSocket::SetNonBlock(bool enable) {
|
||||
blocking = !enable;
|
||||
return Errno::E_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace Network
|
||||
@@ -1,56 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <span>
|
||||
#include <utility>
|
||||
#include <sys/types.h>
|
||||
#include <mutex>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "core/internal_network/sockets.h"
|
||||
|
||||
namespace Network {
|
||||
|
||||
struct PingProcessData {
|
||||
IPv4Address ip;
|
||||
u16 portno;
|
||||
pid_t ping_pid;
|
||||
pid_t ping_status;
|
||||
std::array<u8, 4> seq_ident;
|
||||
u8 family;
|
||||
};
|
||||
|
||||
class IcmpSocket : public Network::SocketBase {
|
||||
public:
|
||||
explicit IcmpSocket() noexcept = default;
|
||||
~IcmpSocket() override;
|
||||
Errno Initialize(Domain domain, Type type, Protocol socket_protocol) override;
|
||||
Errno Close() override;
|
||||
std::pair<AcceptResult, Errno> Accept() override;
|
||||
Errno Connect(Network::SockAddrIn addr_in) override;
|
||||
std::pair<Network::SockAddrIn, Errno> GetPeerName() override;
|
||||
std::pair<Network::SockAddrIn, Errno> GetSockName() override;
|
||||
Errno Bind(Network::SockAddrIn addr) override;
|
||||
Errno Listen(s32 backlog) override;
|
||||
Errno Shutdown(ShutdownHow how) override;
|
||||
std::pair<s32, Errno> Recv(int flags, std::span<u8> message) override;
|
||||
std::pair<s32, Errno> RecvFrom(int flags, std::span<u8> message, Network::SockAddrIn* addr) override;
|
||||
std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override;
|
||||
std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message, const Network::SockAddrIn* addr) override;
|
||||
Errno SetSockOpt(Network::SocketLevel level, Network::OptName option, std::span<const u8> value) override;
|
||||
std::pair<Errno, Errno> GetPendingError() override;
|
||||
bool IsOpened() const override;
|
||||
void HandleProxyPacket(const ProxyPacket& packet) override;
|
||||
Errno SetNonBlock(bool enable) override;
|
||||
|
||||
boost::container::static_vector<PingProcessData, 128> pings;
|
||||
std::optional<SockAddrIn> connected_addr;
|
||||
std::mutex pings_mutex;
|
||||
Network::Timeval rcv_timeo;
|
||||
bool blocking = true;
|
||||
};
|
||||
|
||||
} // namespace Network
|
||||
@@ -47,82 +47,71 @@ void ProxySocket::HandleProxyPacket(const ProxyPacket& packet) {
|
||||
received_packets.push(decompressed);
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetNonBlock(bool enable) {
|
||||
blocking = !enable;
|
||||
return Errno::E_SUCCESS;
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetSockOpt(Network::SocketLevel level, Network::OptName optname, std::span<const u8> optval) {
|
||||
LOG_DEBUG(Network, "level={},optname={},optval={}", level, optname, optval.size());
|
||||
// numeric values?
|
||||
if (optval.size() >= sizeof(u32)) {
|
||||
u32 value;
|
||||
std::memcpy(&value, optval.data(), sizeof(value));
|
||||
if (optname == Network::OptName::BROADCAST)
|
||||
broadcast = bool(value);
|
||||
if (optname == Network::OptName::SNDTIMEO)
|
||||
send_timeout = value;
|
||||
if (optname == Network::OptName::RCVTIMEO)
|
||||
receive_timeout = value;
|
||||
}
|
||||
return Errno::E_SUCCESS;
|
||||
template <typename T>
|
||||
Errno ProxySocket::SetSockOpt(SOCKET fd_, int option, T value) {
|
||||
LOG_DEBUG(Network, "(STUBBED) called");
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Errno ProxySocket::Initialize(Domain domain, Type type, Protocol socket_protocol) {
|
||||
protocol = socket_protocol;
|
||||
return Errno::E_SUCCESS;
|
||||
SetSockOpt(fd, SO_TYPE, type);
|
||||
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<ProxySocket::AcceptResult, Errno> ProxySocket::Accept() {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return {AcceptResult{}, Errno::E_SUCCESS};
|
||||
LOG_WARNING(Network, "(STUBBED) called");
|
||||
return {AcceptResult{}, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
Errno ProxySocket::Connect(Network::SockAddrIn addr_in) {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return Errno::E_SUCCESS;
|
||||
Errno ProxySocket::Connect(SockAddrIn addr_in) {
|
||||
LOG_WARNING(Network, "(STUBBED) called");
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<Network::SockAddrIn, Errno> ProxySocket::GetPeerName() {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return {Network::SockAddrIn{}, Errno::E_SUCCESS};
|
||||
std::pair<SockAddrIn, Errno> ProxySocket::GetPeerName() {
|
||||
LOG_WARNING(Network, "(STUBBED) called");
|
||||
return {SockAddrIn{}, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
std::pair<Network::SockAddrIn, Errno> ProxySocket::GetSockName() {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return {Network::SockAddrIn{}, Errno::E_SUCCESS};
|
||||
std::pair<SockAddrIn, Errno> ProxySocket::GetSockName() {
|
||||
LOG_WARNING(Network, "(STUBBED) called");
|
||||
return {SockAddrIn{}, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
Errno ProxySocket::Bind(Network::SockAddrIn addr) {
|
||||
Errno ProxySocket::Bind(SockAddrIn addr) {
|
||||
if (is_bound) {
|
||||
LOG_WARNING(Network, "Rebinding Socket is unimplemented!");
|
||||
return Errno::E_SUCCESS;
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
local_endpoint = addr;
|
||||
is_bound = true;
|
||||
return Errno::E_SUCCESS;
|
||||
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Errno ProxySocket::Listen(s32 backlog) {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return Errno::E_SUCCESS;
|
||||
LOG_WARNING(Network, "(STUBBED) called");
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Errno ProxySocket::Shutdown(ShutdownHow how) {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return Errno::E_SUCCESS;
|
||||
LOG_WARNING(Network, "(STUBBED) called");
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> ProxySocket::Recv(int flags, std::span<u8> message) {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
LOG_WARNING(Network, "(STUBBED) called");
|
||||
ASSERT(flags == 0);
|
||||
ASSERT(message.size() < std::size_t((std::numeric_limits<int>::max)()));
|
||||
return {s32(0), Errno::E_SUCCESS};
|
||||
ASSERT(message.size() < static_cast<size_t>((std::numeric_limits<int>::max)()));
|
||||
|
||||
return {static_cast<s32>(0), Errno::SUCCESS};
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> ProxySocket::RecvFrom(int flags, std::span<u8> message, Network::SockAddrIn* addr) {
|
||||
std::pair<s32, Errno> ProxySocket::RecvFrom(int flags, std::span<u8> message, SockAddrIn* addr) {
|
||||
ASSERT(flags == 0);
|
||||
ASSERT(message.size() < std::size_t((std::numeric_limits<int>::max)()));
|
||||
ASSERT(message.size() < static_cast<size_t>((std::numeric_limits<int>::max)()));
|
||||
|
||||
// TODO (flTobi): Verify the timeout behavior and break when connection is lost
|
||||
const auto timestamp = std::chrono::steady_clock::now();
|
||||
@@ -139,85 +128,88 @@ std::pair<s32, Errno> ProxySocket::RecvFrom(int flags, std::span<u8> message, Ne
|
||||
}
|
||||
|
||||
if (!blocking) {
|
||||
return {-1, Errno::E_AGAIN};
|
||||
return {-1, Errno::AGAIN};
|
||||
}
|
||||
|
||||
std::this_thread::yield();
|
||||
|
||||
const auto time_diff = std::chrono::steady_clock::now() - timestamp;
|
||||
const auto time_diff_ms = std::chrono::duration_cast<std::chrono::milliseconds>(time_diff).count();
|
||||
const auto time_diff_ms =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(time_diff).count();
|
||||
|
||||
if (time_diff_ms > timeout) {
|
||||
return {-1, Errno::E_TIMEDOUT};
|
||||
return {-1, Errno::TIMEDOUT};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::span<u8> message, Network::SockAddrIn* addr, std::size_t max_length) {
|
||||
LOG_DEBUG(Network, "called");
|
||||
std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::span<u8> message, SockAddrIn* addr,
|
||||
std::size_t max_length) {
|
||||
ProxyPacket& packet = received_packets.front();
|
||||
if (addr) {
|
||||
addr->len = 16;
|
||||
addr->family = u8(Network::Domain::INET);
|
||||
addr->family = Domain::INET;
|
||||
addr->ip = packet.local_endpoint.ip; // The senders ip address
|
||||
addr->portno = packet.local_endpoint.portno; // The senders port number
|
||||
addr->zeroes = {};
|
||||
}
|
||||
|
||||
bool peek = (flags & u32(Network::MsgOpt::PEEK)) != 0;
|
||||
bool peek = (flags & FLAG_MSG_PEEK) != 0;
|
||||
std::size_t read_bytes;
|
||||
if (packet.data.size() > max_length) {
|
||||
read_bytes = max_length;
|
||||
std::memcpy(message.data(), packet.data.data(), max_length);
|
||||
memcpy(message.data(), packet.data.data(), max_length);
|
||||
|
||||
if (protocol == Protocol::UDP) {
|
||||
if (!peek) {
|
||||
received_packets.pop();
|
||||
}
|
||||
return {-1, Errno::E_MSGSIZE};
|
||||
return {-1, Errno::MSGSIZE};
|
||||
} else if (protocol == Protocol::TCP) {
|
||||
std::vector<u8> numArray(packet.data.size() - max_length);
|
||||
std::copy(packet.data.begin() + max_length, packet.data.end(), std::back_inserter(numArray));
|
||||
std::copy(packet.data.begin() + max_length, packet.data.end(),
|
||||
std::back_inserter(numArray));
|
||||
packet.data = numArray;
|
||||
}
|
||||
} else {
|
||||
read_bytes = packet.data.size();
|
||||
std::memcpy(message.data(), packet.data.data(), read_bytes);
|
||||
memcpy(message.data(), packet.data.data(), read_bytes);
|
||||
if (!peek) {
|
||||
received_packets.pop();
|
||||
}
|
||||
}
|
||||
|
||||
return {u32(read_bytes), Errno::E_SUCCESS};
|
||||
return {static_cast<u32>(read_bytes), Errno::SUCCESS};
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> ProxySocket::Send(std::span<const u8> message, int flags) {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
ASSERT(message.size() < size_t((std::numeric_limits<int>::max)()));
|
||||
LOG_WARNING(Network, "(STUBBED) called");
|
||||
ASSERT(message.size() < static_cast<size_t>((std::numeric_limits<int>::max)()));
|
||||
ASSERT(flags == 0);
|
||||
return {s32(0), Errno::E_SUCCESS};
|
||||
|
||||
return {static_cast<s32>(0), Errno::SUCCESS};
|
||||
}
|
||||
|
||||
void ProxySocket::SendPacket(ProxyPacket& packet) {
|
||||
if (auto room_member = Network::GetRoomMember().lock()) {
|
||||
if (room_member->IsConnected()) {
|
||||
packet.data = Common::Compression::CompressDataZSTDDefault(packet.data.data(), packet.data.size());
|
||||
packet.data = Common::Compression::CompressDataZSTDDefault(packet.data.data(),
|
||||
packet.data.size());
|
||||
room_member->SendProxyPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, std::span<const u8> message, const Network::SockAddrIn* addr) {
|
||||
LOG_DEBUG(Network, "called");
|
||||
std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, std::span<const u8> message,
|
||||
const SockAddrIn* addr) {
|
||||
ASSERT(flags == 0);
|
||||
|
||||
if (!is_bound) {
|
||||
LOG_ERROR(Network, "ProxySocket is not bound!");
|
||||
return {s32(message.size()), Errno::E_SUCCESS};
|
||||
return {static_cast<s32>(message.size()), Errno::SUCCESS};
|
||||
}
|
||||
|
||||
if (auto room_member = Network::GetRoomMember().lock()) {
|
||||
if (!room_member->IsConnected()) {
|
||||
return {s32(message.size()), Errno::E_SUCCESS};
|
||||
return {static_cast<s32>(message.size()), Errno::SUCCESS};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,20 +234,66 @@ std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, std::span<const u8> message
|
||||
|
||||
SendPacket(packet);
|
||||
|
||||
return {s32(message.size()), Errno::E_SUCCESS};
|
||||
return {static_cast<s32>(message.size()), Errno::SUCCESS};
|
||||
}
|
||||
|
||||
Errno ProxySocket::Close() {
|
||||
LOG_DEBUG(Network, "called");
|
||||
fd = INVALID_SOCKET;
|
||||
closed = true;
|
||||
|
||||
return Errno::E_SUCCESS;
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetLinger(bool enable, u32 linger) {
|
||||
struct Linger {
|
||||
u16 linger_enable;
|
||||
u16 linger_time;
|
||||
} values;
|
||||
values.linger_enable = enable ? 1 : 0;
|
||||
values.linger_time = static_cast<u16>(linger);
|
||||
|
||||
return SetSockOpt(fd, SO_LINGER, values);
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetReuseAddr(bool enable) {
|
||||
return SetSockOpt<u32>(fd, SO_REUSEADDR, enable ? 1 : 0);
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetBroadcast(bool enable) {
|
||||
broadcast = enable;
|
||||
return SetSockOpt<u32>(fd, SO_BROADCAST, enable ? 1 : 0);
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetSndBuf(u32 value) {
|
||||
return SetSockOpt(fd, SO_SNDBUF, value);
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetKeepAlive(bool enable) {
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetRcvBuf(u32 value) {
|
||||
return SetSockOpt(fd, SO_RCVBUF, value);
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetSndTimeo(u32 value) {
|
||||
send_timeout = value;
|
||||
return SetSockOpt(fd, SO_SNDTIMEO, static_cast<int>(value));
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetRcvTimeo(u32 value) {
|
||||
receive_timeout = value;
|
||||
return SetSockOpt(fd, SO_RCVTIMEO, static_cast<int>(value));
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetNonBlock(bool enable) {
|
||||
blocking = !enable;
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<Errno, Errno> ProxySocket::GetPendingError() {
|
||||
LOG_DEBUG(Network, "called");
|
||||
return {Errno::E_SUCCESS, Errno::E_SUCCESS};
|
||||
LOG_DEBUG(Network, "(STUBBED) called");
|
||||
return {Errno::SUCCESS, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
bool ProxySocket::IsOpened() const {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
@@ -29,13 +29,13 @@ public:
|
||||
|
||||
std::pair<AcceptResult, Errno> Accept() override;
|
||||
|
||||
Errno Connect(Network::SockAddrIn addr_in) override;
|
||||
Errno Connect(SockAddrIn addr_in) override;
|
||||
|
||||
std::pair<Network::SockAddrIn, Errno> GetPeerName() override;
|
||||
std::pair<SockAddrIn, Errno> GetPeerName() override;
|
||||
|
||||
std::pair<Network::SockAddrIn, Errno> GetSockName() override;
|
||||
std::pair<SockAddrIn, Errno> GetSockName() override;
|
||||
|
||||
Errno Bind(Network::SockAddrIn addr) override;
|
||||
Errno Bind(SockAddrIn addr) override;
|
||||
|
||||
Errno Listen(s32 backlog) override;
|
||||
|
||||
@@ -43,9 +43,9 @@ public:
|
||||
|
||||
std::pair<s32, Errno> Recv(int flags, std::span<u8> message) override;
|
||||
|
||||
std::pair<s32, Errno> RecvFrom(int flags, std::span<u8> message, Network::SockAddrIn* addr) override;
|
||||
std::pair<s32, Errno> RecvFrom(int flags, std::span<u8> message, SockAddrIn* addr) override;
|
||||
|
||||
std::pair<s32, Errno> ReceivePacket(int flags, std::span<u8> message, Network::SockAddrIn* addr,
|
||||
std::pair<s32, Errno> ReceivePacket(int flags, std::span<u8> message, SockAddrIn* addr,
|
||||
std::size_t max_length);
|
||||
|
||||
std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override;
|
||||
@@ -53,11 +53,28 @@ public:
|
||||
void SendPacket(ProxyPacket& packet);
|
||||
|
||||
std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message,
|
||||
const Network::SockAddrIn* addr) override;
|
||||
const SockAddrIn* addr) override;
|
||||
|
||||
Errno SetLinger(bool enable, u32 linger) override;
|
||||
|
||||
Errno SetReuseAddr(bool enable) override;
|
||||
|
||||
Errno SetBroadcast(bool enable) override;
|
||||
|
||||
Errno SetKeepAlive(bool enable) override;
|
||||
|
||||
Errno SetSndBuf(u32 value) override;
|
||||
|
||||
Errno SetRcvBuf(u32 value) override;
|
||||
|
||||
Errno SetSndTimeo(u32 value) override;
|
||||
|
||||
Errno SetRcvTimeo(u32 value) override;
|
||||
|
||||
Errno SetNonBlock(bool enable) override;
|
||||
|
||||
Errno SetSockOpt(Network::SocketLevel level, Network::OptName option, std::span<const u8> value) override;
|
||||
template <typename T>
|
||||
Errno SetSockOpt(SOCKET fd, int option, T value);
|
||||
|
||||
std::pair<Errno, Errno> GetPendingError() override;
|
||||
|
||||
@@ -69,7 +86,7 @@ private:
|
||||
u32 send_timeout = 0;
|
||||
u32 receive_timeout = 0;
|
||||
bool is_bound = false;
|
||||
Network::SockAddrIn local_endpoint{};
|
||||
SockAddrIn local_endpoint{};
|
||||
bool blocking = true;
|
||||
std::queue<ProxyPacket> received_packets;
|
||||
Protocol protocol;
|
||||
|
||||
@@ -1,470 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/common_funcs.h"
|
||||
|
||||
// Most of these structures are direct mappings of guest's
|
||||
// expectations for these values, in other words, they're the
|
||||
// values that HOS is expected to use AND handle.
|
||||
|
||||
namespace Network {
|
||||
|
||||
enum class Errno : u32 {
|
||||
E_SUCCESS = 0,
|
||||
E_PERM = 1,
|
||||
E_NOENT = 2,
|
||||
E_SRCH = 3,
|
||||
E_INTR = 4,
|
||||
E_IO = 5,
|
||||
E_NXIO = 6,
|
||||
E_2BIG = 7,
|
||||
E_NOEXEC = 8,
|
||||
E_BADF = 9,
|
||||
E_CHILD = 10,
|
||||
E_AGAIN = 11,
|
||||
E_NOMEM = 12,
|
||||
E_ACCES = 13,
|
||||
E_FAULT = 14,
|
||||
E_NOTBLK = 15,
|
||||
E_BUSY = 16,
|
||||
E_EXIST = 17,
|
||||
E_XDEV = 18,
|
||||
E_NODEV = 19,
|
||||
E_NOTDIR = 20,
|
||||
E_ISDIR = 21,
|
||||
E_INVAL = 22,
|
||||
E_NFILE = 23,
|
||||
E_MFILE = 24,
|
||||
E_NOTTY = 25,
|
||||
E_TXTBSY = 26,
|
||||
E_FBIG = 27,
|
||||
E_NOSPC = 28,
|
||||
E_SPIPE = 29,
|
||||
E_ROFS = 30,
|
||||
E_MLINK = 31,
|
||||
E_PIPE = 32,
|
||||
E_DOM = 33,
|
||||
E_RANGE = 34,
|
||||
E_DEADLK = 35,
|
||||
E_NAMETOOLONG = 36,
|
||||
E_NOLCK = 37,
|
||||
E_NOSYS = 38,
|
||||
E_NOTEMPTY = 39,
|
||||
E_LOOP = 40,
|
||||
E_NOMSG = 42,
|
||||
E_IDRM = 43,
|
||||
E_CHRNG = 44,
|
||||
E_L2NSYNC = 45,
|
||||
E_L3HLT = 46,
|
||||
E_L3RST = 47,
|
||||
E_LNRNG = 48,
|
||||
E_UNATCH = 49,
|
||||
E_NOCSI = 50,
|
||||
E_L2HLT = 51,
|
||||
E_BADE = 52,
|
||||
E_BADR = 53,
|
||||
E_XFULL = 54,
|
||||
E_NOANO = 55,
|
||||
E_BADRQC = 56,
|
||||
E_BADSSL = 57,
|
||||
E_BFONT = 59,
|
||||
E_NOSTR = 60,
|
||||
E_NODATA = 61,
|
||||
E_TIME = 62,
|
||||
E_NOSR = 63,
|
||||
E_NONET = 64,
|
||||
E_NOPKG = 65,
|
||||
E_REMOTE = 66,
|
||||
E_NOLINK = 67,
|
||||
E_ADV = 68,
|
||||
E_SRMNT = 69,
|
||||
E_COMM = 70,
|
||||
E_PROTO = 71,
|
||||
E_MULTIHOP = 72,
|
||||
E_DOTDOT = 73,
|
||||
E_BADMSG = 74,
|
||||
E_OVERFLOW = 75,
|
||||
E_NOTUNUQ = 76,
|
||||
E_BADFD = 77,
|
||||
E_REMCHG = 78,
|
||||
E_LIBACC = 79,
|
||||
E_LIBBAD = 80,
|
||||
E_LIBSCN = 81,
|
||||
E_LIBMAX = 82,
|
||||
E_LIBEXEC = 83,
|
||||
E_ILSEQ = 84,
|
||||
E_RESTART = 85,
|
||||
E_STRPIPE = 86,
|
||||
E_USERS = 87,
|
||||
E_NOTSOCK = 88,
|
||||
E_DESTADDRREQ = 89,
|
||||
E_MSGSIZE = 90,
|
||||
E_PROTOTYPE = 91,
|
||||
E_NOPROTOOPT = 92,
|
||||
E_PROTONOSUPPORT = 93,
|
||||
E_SOCKTNOSUPPORT = 94,
|
||||
E_OPNOTSUPP = 95,
|
||||
E_PFNOSUPPORT = 96,
|
||||
E_AFNOSUPPORT = 97,
|
||||
E_ADDRINUSE = 98,
|
||||
E_ADDRNOTAVAIL = 99,
|
||||
E_NETDOWN = 100,
|
||||
E_NETUNREACH = 101,
|
||||
E_NETRESET = 102,
|
||||
E_CONNABORTED = 103,
|
||||
E_CONNRESET = 104,
|
||||
E_NOBUFS = 105,
|
||||
E_ISCONN = 106,
|
||||
E_NOTCONN = 107,
|
||||
E_SHUTDOWN = 108,
|
||||
E_TOOMANYREFS = 109,
|
||||
E_TIMEDOUT = 110,
|
||||
E_CONNREFUSED = 111,
|
||||
E_HOSTDOWN = 112,
|
||||
E_HOSTUNREACH = 113,
|
||||
E_ALREADY = 114,
|
||||
E_INPROGRESS = 115,
|
||||
E_STALE = 116,
|
||||
E_UCLEAN = 117,
|
||||
E_NOTNAM = 118,
|
||||
E_NAVAIL = 119,
|
||||
E_ISNAM = 120,
|
||||
E_REMOTEIO = 121,
|
||||
E_DQUOT = 122,
|
||||
E_NOMEDIUM = 123,
|
||||
E_MEDIUMTYPE = 124,
|
||||
E_CANCELED = 125,
|
||||
E_NOKEY = 126,
|
||||
E_KEYEXPIRED = 127,
|
||||
E_KEYREVOKED = 128,
|
||||
E_KEYREJECTED = 129,
|
||||
E_OWNERDEAD = 130,
|
||||
E_NOTRECOVERABLE = 131,
|
||||
E_RFKILL = 132,
|
||||
E_HWPOISON = 133,
|
||||
E_PROCLIM = 156,
|
||||
};
|
||||
|
||||
enum class GetAddrInfoError : s32 {
|
||||
SUCCESS = 0,
|
||||
ADDRFAMILY = 1,
|
||||
AGAIN = 2,
|
||||
BADFLAGS = 3,
|
||||
FAIL = 4,
|
||||
FAMILY = 5,
|
||||
MEMORY = 6,
|
||||
NODATA = 7,
|
||||
NONAME = 8,
|
||||
SERVICE = 9,
|
||||
SOCKTYPE = 10,
|
||||
SYSTEM = 11,
|
||||
BADHINTS = 12,
|
||||
PROTOCOL = 13,
|
||||
OVERFLOW_ = 14, // avoid name collision with Windows macro
|
||||
OTHER = 15,
|
||||
};
|
||||
|
||||
enum class Domain : u32 {
|
||||
Unspecified = 0,
|
||||
UNIX = 1,
|
||||
INET = 2,
|
||||
IMPLINK = 3,
|
||||
PUP = 4,
|
||||
CHAOS = 5,
|
||||
NETBIOS = 6,
|
||||
ISO = 7,
|
||||
ECMA = 8,
|
||||
DATAKIT = 9,
|
||||
CCITT = 10,
|
||||
SNA = 11,
|
||||
DECnet = 12,
|
||||
DLI = 13,
|
||||
LAT = 14,
|
||||
HYLINK = 15,
|
||||
APPLETALK = 16,
|
||||
ROUTE = 17,
|
||||
LINK = 18,
|
||||
COIP = 20,
|
||||
CNT = 21,
|
||||
IPX = 23,
|
||||
SIP = 24,
|
||||
ISDN = 26,
|
||||
INET6 = 28,
|
||||
NATM = 29,
|
||||
ATM = 30,
|
||||
NETGRAPH = 32,
|
||||
SLOW = 33,
|
||||
SCLUSTER = 34,
|
||||
ARP = 35,
|
||||
BLUETOOTH = 36,
|
||||
IEEE80211 = 37,
|
||||
NETLINK = 38,
|
||||
INET_SDP = 40,
|
||||
INET6_SDP = 42,
|
||||
};
|
||||
|
||||
enum class Type : u32 {
|
||||
Unspecified = 0,
|
||||
STREAM = 1,
|
||||
DGRAM = 2,
|
||||
RAW = 3,
|
||||
RDM = 4,
|
||||
SEQPACKET = 5,
|
||||
};
|
||||
|
||||
enum class Protocol : u32 {
|
||||
IP = 0,
|
||||
ICMP = 1,
|
||||
TCP = 6,
|
||||
UDP = 17,
|
||||
//
|
||||
IPV6 = 41,
|
||||
RAW = 255,
|
||||
//
|
||||
HOPOPTS = 0,
|
||||
IGMP = 2,
|
||||
GGP = 3,
|
||||
IPV4 = 4,
|
||||
ST = 7,
|
||||
EGP = 8,
|
||||
PIGP = 9,
|
||||
RCCMON = 10,
|
||||
NVPII = 11,
|
||||
PUP = 12,
|
||||
ARGUS = 13,
|
||||
EMCON = 14,
|
||||
XNET = 15,
|
||||
CHAOS = 16,
|
||||
MUX = 18,
|
||||
MEAS = 19,
|
||||
HMP = 20,
|
||||
PRM = 21,
|
||||
IDP = 22,
|
||||
TRUNK1 = 23,
|
||||
TRUNK2 = 24,
|
||||
LEAF1 = 25,
|
||||
LEAF2 = 26,
|
||||
RDP = 27,
|
||||
IRTP = 28,
|
||||
TP = 29,
|
||||
BLT = 30,
|
||||
NSP = 31,
|
||||
INP = 32,
|
||||
DCCP = 33,
|
||||
//3PC = 34,
|
||||
IDPR = 35,
|
||||
XTP = 36,
|
||||
DDP = 37,
|
||||
CMTP = 38,
|
||||
TPXX = 39,
|
||||
IL = 40,
|
||||
SDRP = 42,
|
||||
ROUTING = 43,
|
||||
FRAGMENT = 44,
|
||||
IDRP = 45,
|
||||
RSVP = 46,
|
||||
GRE = 47,
|
||||
MHRP = 48,
|
||||
BHA = 49,
|
||||
ESP = 50,
|
||||
AH = 51,
|
||||
INLSP = 52,
|
||||
SWIPE = 53,
|
||||
NHRP = 54,
|
||||
MOBILE = 55,
|
||||
TLSP = 56,
|
||||
SKIP = 57,
|
||||
ICMPV6 = 58,
|
||||
NONE = 59,
|
||||
DSTOPTS = 60,
|
||||
AHIP = 61,
|
||||
CFTP = 62,
|
||||
HELLO = 63,
|
||||
SATEXPAK = 64,
|
||||
KRYPTOLAN = 65,
|
||||
RVD = 66,
|
||||
IPPC = 67,
|
||||
ADFS = 68,
|
||||
SATMON = 69,
|
||||
VISA = 70,
|
||||
IPCV = 71,
|
||||
CPNX = 72,
|
||||
CPHB = 73,
|
||||
WSN = 74,
|
||||
PVP = 75,
|
||||
BRSATMON = 76,
|
||||
ND = 77,
|
||||
WBMON = 78,
|
||||
WBEXPAK = 79,
|
||||
EON = 80,
|
||||
VMTP = 81,
|
||||
SVMTP = 82,
|
||||
VINES = 83,
|
||||
TTP = 84,
|
||||
IGP = 85,
|
||||
DGP = 86,
|
||||
TCF = 87,
|
||||
IGRP = 88,
|
||||
OSPFIGP = 89,
|
||||
SRPC = 90,
|
||||
LARP = 91,
|
||||
MTP = 92,
|
||||
AX25 = 93,
|
||||
IPEIP = 94,
|
||||
MICP = 95,
|
||||
SCCSP = 96,
|
||||
ETHERIP = 97,
|
||||
ENCAP = 98,
|
||||
APES = 99,
|
||||
GMTP = 100,
|
||||
IPCOMP = 108,
|
||||
SCTP = 132,
|
||||
MH = 135,
|
||||
UDPLITE = 136,
|
||||
HIP = 139,
|
||||
SHIM6 = 140,
|
||||
PIM = 103,
|
||||
CARP = 112,
|
||||
PGM = 113,
|
||||
MPLS = 137,
|
||||
PFSYNC = 240,
|
||||
};
|
||||
|
||||
enum class SocketLevel : u32 {
|
||||
IP = 0,
|
||||
ICMP = 1,
|
||||
TCP = 6,
|
||||
UDP = 17,
|
||||
CONFIG = 0xfffe,
|
||||
SOCKET = 0xffff, // i.e. SOL_SOCKET
|
||||
};
|
||||
|
||||
enum class MsgOpt : u32 {
|
||||
OOB = 0x00001,
|
||||
PEEK = 0x00002,
|
||||
DONTROUTE = 0x00004,
|
||||
EOR_ = 0x00008,
|
||||
TRUNC = 0x00010,
|
||||
CTRUNC = 0x00020,
|
||||
WAITALL = 0x00040,
|
||||
DONTWAIT = 0x00080,
|
||||
EOF_ = 0x00100,
|
||||
NOSIGNAL = 0x20000,
|
||||
};
|
||||
|
||||
enum class OptName : u32 {
|
||||
DEBUG = 0x0001,
|
||||
ACCEPTCONN = 0x0002,
|
||||
REUSEADDR = 0x0004,
|
||||
KEEPALIVE = 0x0008,
|
||||
DONTROUTE = 0x0010,
|
||||
BROADCAST = 0x0020,
|
||||
USELOOPBACK = 0x0040,
|
||||
LINGER = 0x0080,
|
||||
OOBINLINE = 0x0100,
|
||||
REUSEPORT = 0x0200,
|
||||
TIMESTAMP = 0x0400,
|
||||
NOSIGPIPE = 0x0800, // at least according to libnx
|
||||
ACCEPTFILER = 0x1000,
|
||||
SNDBUF = 0x1001,
|
||||
RCVBUF = 0x1002,
|
||||
SNDTIMEO = 0x1005,
|
||||
RCVTIMEO = 0x1006,
|
||||
ERROR_ = 0x1007, // avoid name collision with Windows macro
|
||||
ACCEPTFILTER = 0x1000,
|
||||
BINTIME = 0x2000,
|
||||
NO_OFFLOAD = 0x4000,
|
||||
NO_DDP = 0x8000,
|
||||
};
|
||||
enum class TcpOptName : u32 {
|
||||
NODELAY = 0x0001,
|
||||
MAXSEG = 0x0002,
|
||||
NOPUSH = 0x0004,
|
||||
NOOPT = 0x0008,
|
||||
MS5SIG = 0x0010,
|
||||
INFO = 0x0020
|
||||
};
|
||||
|
||||
enum class ShutdownHow : s32 {
|
||||
RD = 0,
|
||||
WR = 1,
|
||||
RDWR = 2,
|
||||
};
|
||||
|
||||
enum class FcntlCmd : s32 {
|
||||
GETFL = 3,
|
||||
SETFL = 4,
|
||||
};
|
||||
|
||||
enum class FcntlFlags : u32 {
|
||||
NONBLOCK = 0x004,
|
||||
NONBLOCK_NX = 0x800,
|
||||
// Provided for convenience
|
||||
NONBLOCK_ANY = u32(NONBLOCK) | u32(NONBLOCK_NX),
|
||||
};
|
||||
|
||||
/// Array of IPv4 address
|
||||
using IPv4Address = std::array<u8, 4>;
|
||||
|
||||
struct SockAddrIn {
|
||||
u8 len;
|
||||
u8 family;
|
||||
u16 portno;
|
||||
IPv4Address ip;
|
||||
std::array<u8, 248> zeroes;
|
||||
};
|
||||
static_assert(sizeof(SockAddrIn) == 0x100);
|
||||
|
||||
enum class PollEvents : u16 {
|
||||
// Using Pascal case because IN is a macro on Windows.
|
||||
IN_ = 0x0001,
|
||||
PRI_ = 0x0002,
|
||||
OUT_ = 0x0004,
|
||||
ERR_ = 0x0008,
|
||||
HUP_ = 0x0010,
|
||||
NVAL = 0x0020,
|
||||
RDNORM = 0x0040,
|
||||
RDBAND = 0x0080,
|
||||
WRBAND = 0x0100,
|
||||
IGNEOF = 0x2000,
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(PollEvents);
|
||||
|
||||
struct PollFD {
|
||||
s32 fd;
|
||||
Network::PollEvents events;
|
||||
Network::PollEvents revents;
|
||||
};
|
||||
static_assert(sizeof(PollFD) == 8);
|
||||
|
||||
struct Linger {
|
||||
s32 onoff;
|
||||
s32 linger;
|
||||
};
|
||||
static_assert(sizeof(Linger) == 8);
|
||||
|
||||
struct Timeval {
|
||||
u64 tv_sec;
|
||||
u64 tv_usec;
|
||||
};
|
||||
static_assert(sizeof(Timeval) == 16);
|
||||
|
||||
/// @brief Cross-platform addrinfo structure (not guest)
|
||||
struct AddrInfo {
|
||||
Domain family;
|
||||
Type socket_type;
|
||||
Protocol protocol;
|
||||
SockAddrIn addr;
|
||||
std::optional<std::string> canon_name;
|
||||
};
|
||||
|
||||
} // namespace Network
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
|
||||
struct AcceptResult {
|
||||
std::unique_ptr<SocketBase> socket;
|
||||
Network::SockAddrIn sockaddr_in;
|
||||
SockAddrIn sockaddr_in;
|
||||
};
|
||||
|
||||
SocketBase() = default;
|
||||
@@ -46,13 +46,13 @@ public:
|
||||
|
||||
virtual std::pair<AcceptResult, Errno> Accept() = 0;
|
||||
|
||||
virtual Errno Connect(Network::SockAddrIn addr_in) = 0;
|
||||
virtual Errno Connect(SockAddrIn addr_in) = 0;
|
||||
|
||||
virtual std::pair<Network::SockAddrIn, Errno> GetPeerName() = 0;
|
||||
virtual std::pair<SockAddrIn, Errno> GetPeerName() = 0;
|
||||
|
||||
virtual std::pair<Network::SockAddrIn, Errno> GetSockName() = 0;
|
||||
virtual std::pair<SockAddrIn, Errno> GetSockName() = 0;
|
||||
|
||||
virtual Errno Bind(Network::SockAddrIn addr) = 0;
|
||||
virtual Errno Bind(SockAddrIn addr) = 0;
|
||||
|
||||
virtual Errno Listen(s32 backlog) = 0;
|
||||
|
||||
@@ -60,16 +60,31 @@ public:
|
||||
|
||||
virtual std::pair<s32, Errno> Recv(int flags, std::span<u8> message) = 0;
|
||||
|
||||
virtual std::pair<s32, Errno> RecvFrom(int flags, std::span<u8> message, Network::SockAddrIn* addr) = 0;
|
||||
virtual std::pair<s32, Errno> RecvFrom(int flags, std::span<u8> message, SockAddrIn* addr) = 0;
|
||||
|
||||
virtual std::pair<s32, Errno> Send(std::span<const u8> message, int flags) = 0;
|
||||
|
||||
virtual std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message, const Network::SockAddrIn* addr) = 0;
|
||||
virtual std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message,
|
||||
const SockAddrIn* addr) = 0;
|
||||
|
||||
virtual Errno SetLinger(bool enable, u32 linger) = 0;
|
||||
|
||||
virtual Errno SetReuseAddr(bool enable) = 0;
|
||||
|
||||
virtual Errno SetKeepAlive(bool enable) = 0;
|
||||
|
||||
virtual Errno SetBroadcast(bool enable) = 0;
|
||||
|
||||
virtual Errno SetSndBuf(u32 value) = 0;
|
||||
|
||||
virtual Errno SetRcvBuf(u32 value) = 0;
|
||||
|
||||
virtual Errno SetSndTimeo(u32 value) = 0;
|
||||
|
||||
virtual Errno SetRcvTimeo(u32 value) = 0;
|
||||
|
||||
virtual Errno SetNonBlock(bool enable) = 0;
|
||||
|
||||
virtual Errno SetSockOpt(Network::SocketLevel level, Network::OptName option, std::span<const u8> value) = 0;
|
||||
|
||||
virtual std::pair<Errno, Errno> GetPendingError() = 0;
|
||||
|
||||
virtual bool IsOpened() const = 0;
|
||||
@@ -80,6 +95,7 @@ public:
|
||||
return fd;
|
||||
}
|
||||
|
||||
protected:
|
||||
SOCKET fd = INVALID_SOCKET;
|
||||
};
|
||||
|
||||
@@ -98,13 +114,13 @@ public:
|
||||
|
||||
std::pair<AcceptResult, Errno> Accept() override;
|
||||
|
||||
Errno Connect(Network::SockAddrIn addr_in) override;
|
||||
Errno Connect(SockAddrIn addr_in) override;
|
||||
|
||||
std::pair<Network::SockAddrIn, Errno> GetPeerName() override;
|
||||
std::pair<SockAddrIn, Errno> GetPeerName() override;
|
||||
|
||||
std::pair<Network::SockAddrIn, Errno> GetSockName() override;
|
||||
std::pair<SockAddrIn, Errno> GetSockName() override;
|
||||
|
||||
Errno Bind(Network::SockAddrIn addr) override;
|
||||
Errno Bind(SockAddrIn addr) override;
|
||||
|
||||
Errno Listen(s32 backlog) override;
|
||||
|
||||
@@ -112,19 +128,38 @@ public:
|
||||
|
||||
std::pair<s32, Errno> Recv(int flags, std::span<u8> message) override;
|
||||
|
||||
std::pair<s32, Errno> RecvFrom(int flags, std::span<u8> message, Network::SockAddrIn* addr) override;
|
||||
std::pair<s32, Errno> RecvFrom(int flags, std::span<u8> message, SockAddrIn* addr) override;
|
||||
|
||||
std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override;
|
||||
|
||||
std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message, const Network::SockAddrIn* addr) override;
|
||||
std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message,
|
||||
const SockAddrIn* addr) override;
|
||||
|
||||
Errno SetLinger(bool enable, u32 linger) override;
|
||||
|
||||
Errno SetReuseAddr(bool enable) override;
|
||||
|
||||
Errno SetKeepAlive(bool enable) override;
|
||||
|
||||
Errno SetBroadcast(bool enable) override;
|
||||
|
||||
Errno SetSndBuf(u32 value) override;
|
||||
|
||||
Errno SetRcvBuf(u32 value) override;
|
||||
|
||||
Errno SetSndTimeo(u32 value) override;
|
||||
|
||||
Errno SetRcvTimeo(u32 value) override;
|
||||
|
||||
Errno SetNonBlock(bool enable) override;
|
||||
|
||||
Errno SetSockOpt(Network::SocketLevel level, Network::OptName option, std::span<const u8> value) override;
|
||||
template <typename T>
|
||||
Errno SetSockOpt(SOCKET fd, int option, T value);
|
||||
|
||||
std::pair<Errno, Errno> GetPendingError() override;
|
||||
|
||||
Errno GetSockOpt(Network::SocketLevel level, Network::OptName optname, std::span<u8> value);
|
||||
template <typename T>
|
||||
std::pair<T, Errno> GetSockOpt(SOCKET fd, int option);
|
||||
|
||||
bool IsOpened() const override;
|
||||
|
||||
@@ -134,6 +169,6 @@ private:
|
||||
bool is_non_blocking = false;
|
||||
};
|
||||
|
||||
std::pair<s32, Errno> Poll(std::span<Network::HostPollFD> poll_fds, s32 timeout);
|
||||
std::pair<s32, Errno> Poll(std::vector<PollFD>& poll_fds, s32 timeout);
|
||||
|
||||
} // namespace Network
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <vector>
|
||||
#include "common/announce_multiplayer_room.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "network/verify_user.h"
|
||||
|
||||
namespace Network {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <thread>
|
||||
#include "common/assert.h"
|
||||
#include "common/polyfill_thread.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "enet/enet.h"
|
||||
#include "network/packet.h"
|
||||
#include "network/room_member.h"
|
||||
@@ -358,23 +358,19 @@ void RoomMember::RoomMemberImpl::HandleProxyPackets(const ENetEvent* event) {
|
||||
// Parse the ProxyPacket from the packet
|
||||
u8 local_family;
|
||||
packet.Read(local_family);
|
||||
proxy_packet.local_endpoint.len = 16;
|
||||
proxy_packet.local_endpoint.family = u8(Network::Domain(local_family));
|
||||
proxy_packet.local_endpoint.family = static_cast<Domain>(local_family);
|
||||
packet.Read(proxy_packet.local_endpoint.ip);
|
||||
packet.Read(proxy_packet.local_endpoint.portno);
|
||||
proxy_packet.local_endpoint.zeroes = {};
|
||||
|
||||
u8 remote_family;
|
||||
packet.Read(remote_family);
|
||||
proxy_packet.remote_endpoint.len = 16;
|
||||
proxy_packet.remote_endpoint.family = u8(Network::Domain(remote_family));
|
||||
proxy_packet.remote_endpoint.family = static_cast<Domain>(remote_family);
|
||||
packet.Read(proxy_packet.remote_endpoint.ip);
|
||||
packet.Read(proxy_packet.remote_endpoint.portno);
|
||||
proxy_packet.local_endpoint.zeroes = {};
|
||||
|
||||
u8 protocol_type;
|
||||
packet.Read(protocol_type);
|
||||
proxy_packet.protocol = Network::Protocol(protocol_type);
|
||||
proxy_packet.protocol = static_cast<Protocol>(protocol_type);
|
||||
|
||||
packet.Read(proxy_packet.broadcast);
|
||||
packet.Read(proxy_packet.data);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <vector>
|
||||
#include "common/announce_multiplayer_room.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "network/room.h"
|
||||
|
||||
namespace Network {
|
||||
@@ -39,8 +39,8 @@ struct LDNPacket {
|
||||
|
||||
/// Information about the received proxy packets.
|
||||
struct ProxyPacket {
|
||||
Network::SockAddrIn local_endpoint;
|
||||
Network::SockAddrIn remote_endpoint;
|
||||
SockAddrIn local_endpoint;
|
||||
SockAddrIn remote_endpoint;
|
||||
Protocol protocol;
|
||||
bool broadcast;
|
||||
std::vector<u8> data;
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -15,18 +12,16 @@ TEST_CASE("Network::Errors", "[core]") {
|
||||
Network::Socket socks[2];
|
||||
for (Network::Socket& sock : socks) {
|
||||
REQUIRE(sock.Initialize(Network::Domain::INET, Network::Type::STREAM,
|
||||
Network::Protocol::TCP) == Network::Errno::E_SUCCESS);
|
||||
Network::Protocol::TCP) == Network::Errno::SUCCESS);
|
||||
}
|
||||
|
||||
Network::SockAddrIn addr{
|
||||
16,
|
||||
u8(Network::Domain::INET),
|
||||
1, // hopefully nobody running this test has something listening on port 1
|
||||
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::E_CONNREFUSED);
|
||||
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::E_NOTCONN);
|
||||
REQUIRE(socks[1].Recv(0, message).second == Network::Errno::NOTCONN);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user