aboutsummaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/hle/service/nifm/nifm.cpp41
-rw-r--r--src/core/internal_network/socket_proxy.cpp62
2 files changed, 65 insertions, 38 deletions
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 153b0f2193..e0a23f7a63 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -73,17 +73,17 @@ static u128 MakeUuidFromName(std::string_view name) {
// A joined room is the emulated network, even in airplane mode. Its sockets only reach room
// members, and LAN games (e.g. Mario Kart World LAN Play) need their connection request accepted.
static bool IsNetworkAvailable() {
- if (const auto room_member = Network::GetRoomMember().lock();
- room_member && room_member->GetState() == Network::RoomMember::State::Joined) {
- return true;
+ if (const auto room_member = Network::GetRoomMember().lock()) {
+ // The room host and moderators are in the Moderator state instead of Joined
+ const auto state = room_member->GetState();
+ if (state == Network::RoomMember::State::Joined ||
+ state == Network::RoomMember::State::Moderator) {
+ return true;
+ }
}
return Network::GetHostIPv4Address().has_value() && !Settings::values.airplane_mode.GetValue();
}
-// Room fake IPs are spread over 192.168.0.0/16, and some room servers give members different /24s.
-// A host /24 mask would then put room members on different subnets, so LAN games ignore each other.
-constexpr Network::IPv4Address RoomSubnetMask{255, 255, 0, 0};
-
// This is nn::nifm::RequestState
enum class RequestState : u32 {
NotSubmitted = 1,
@@ -124,6 +124,17 @@ struct IpAddressSetting {
};
static_assert(sizeof(IpAddressSetting) == 0xD, "IpAddressSetting has incorrect size.");
+// Room fake IPs are spread over 192.168.0.0/16, and some room servers give members different /24s.
+// A host /24 mask would then put room members on different subnets, so LAN games ignore each other.
+constexpr Network::IPv4Address RoomSubnetMask{255, 255, 0, 0};
+
+static void ApplyRoomAddress(const Network::RoomMember& room_member, IpAddressSetting& setting) {
+ if (room_member.IsConnected()) {
+ setting.ip_address = room_member.GetFakeIpAddress();
+ setting.subnet_mask = RoomSubnetMask;
+ }
+}
+
// This is nn::nifm::DnsSetting
struct DnsSetting {
bool is_automatic{};
@@ -585,11 +596,7 @@ void IGeneralService::GetCurrentNetworkProfile(HLERequestContext& ctx) {
std::strncpy(profile.network_name.data(), st.ssid, sizeof(profile.network_name) - 1);
if (auto room_member = Network::GetRoomMember().lock()) {
- if (room_member->IsConnected()) {
- profile.ip_setting_data.ip_address_setting.ip_address =
- room_member->GetFakeIpAddress();
- profile.ip_setting_data.ip_address_setting.subnet_mask = RoomSubnetMask;
- }
+ ApplyRoomAddress(*room_member, profile.ip_setting_data.ip_address_setting);
profile.ip_setting_data.dns_setting.secondary_dns = {8, 8, 8, 8};
}
@@ -726,10 +733,7 @@ void IGeneralService::GetNetworkProfile(HLERequestContext& ctx) {
}();
if (auto room_member = Network::GetRoomMember().lock()) {
- if (room_member->IsConnected()) {
- profile.ip_setting_data.ip_address_setting.ip_address = room_member->GetFakeIpAddress();
- profile.ip_setting_data.ip_address_setting.subnet_mask = RoomSubnetMask;
- }
+ ApplyRoomAddress(*room_member, profile.ip_setting_data.ip_address_setting);
}
ctx.WriteBuffer(profile);
@@ -917,10 +921,7 @@ void IGeneralService::GetCurrentIpConfigInfo(HLERequestContext& ctx) {
}
if (auto room_member = Network::GetRoomMember().lock()) {
- if (room_member->IsConnected()) {
- info.ip.ip_address = room_member->GetFakeIpAddress();
- info.ip.subnet_mask = RoomSubnetMask;
- }
+ ApplyRoomAddress(*room_member, info.ip);
info.dns.is_automatic = true;
info.dns.primary_dns = {1, 1, 1, 1};
info.dns.secondary_dns = {8, 8, 8, 8};
diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp
index f42ed61e21..83eb2ce9d0 100644
--- a/src/core/internal_network/socket_proxy.cpp
+++ b/src/core/internal_network/socket_proxy.cpp
@@ -31,21 +31,21 @@ ProxySocket::~ProxySocket() {
}
void ProxySocket::HandleProxyPacket(const ProxyPacket& packet) {
- if (protocol != packet.protocol || local_endpoint.portno != packet.remote_endpoint.portno ||
- closed) {
- return;
- }
-
- if (!broadcast && packet.broadcast) {
- LOG_INFO(Network, "Received broadcast packet, but not configured for broadcast mode");
- return;
- }
-
- auto decompressed = packet;
- decompressed.data = Common::Compression::DecompressDataZSTD(packet.data);
-
{
+ // Runs on the room thread, while the game thread may bind, close or reconfigure the socket
std::lock_guard guard(packets_mutex);
+ if (protocol != packet.protocol || local_endpoint.portno != packet.remote_endpoint.portno ||
+ closed) {
+ return;
+ }
+
+ if (!broadcast && packet.broadcast) {
+ LOG_INFO(Network, "Received broadcast packet, but not configured for broadcast mode");
+ return;
+ }
+
+ auto decompressed = packet;
+ decompressed.data = Common::Compression::DecompressDataZSTD(packet.data);
received_packets.push(std::move(decompressed));
}
packets_cv.notify_one();
@@ -58,7 +58,10 @@ Errno ProxySocket::SetSockOpt(SOCKET fd_, int option, T value) {
}
Errno ProxySocket::Initialize(Domain domain, Type type, Protocol socket_protocol) {
- protocol = socket_protocol;
+ {
+ std::lock_guard guard(packets_mutex);
+ protocol = socket_protocol;
+ }
SetSockOpt(fd, SO_TYPE, type);
return Errno::SUCCESS;
@@ -85,6 +88,7 @@ std::pair<SockAddrIn, Errno> ProxySocket::GetSockName() {
}
Errno ProxySocket::Bind(SockAddrIn addr) {
+ std::lock_guard guard(packets_mutex);
if (is_bound) {
LOG_WARNING(Network, "Rebinding Socket is unimplemented!");
return Errno::SUCCESS;
@@ -106,6 +110,14 @@ Errno ProxySocket::Shutdown(ShutdownHow how) {
}
std::pair<s32, Errno> ProxySocket::Recv(int flags, std::span<u8> message) {
+ if (protocol == Protocol::TCP) {
+ // Room TCP sockets have no peer (Connect and Send are stubs). Report an empty queue as the
+ // end of the stream, as before, instead of blocking the bsd service until the timeout.
+ std::lock_guard guard(packets_mutex);
+ if (received_packets.empty()) {
+ return {0, Errno::SUCCESS};
+ }
+ }
return RecvFrom(flags, message, nullptr);
}
@@ -114,6 +126,9 @@ std::pair<s32, Errno> ProxySocket::RecvFrom(int flags, std::span<u8> message, So
ASSERT(message.size() < static_cast<size_t>((std::numeric_limits<int>::max)()));
std::unique_lock lock(packets_mutex);
+ if (closed) {
+ return {-1, Errno::BADF};
+ }
if (received_packets.empty()) {
if (!blocking) {
return {-1, Errno::AGAIN};
@@ -124,9 +139,12 @@ std::pair<s32, Errno> ProxySocket::RecvFrom(int flags, std::span<u8> message, So
// the timeout to 5s instead. An expired wait is reported like an SO_RCVTIMEO timeout.
const u32 timeout = receive_timeout == 0 ? 5000 : receive_timeout;
if (!packets_cv.wait_for(lock, std::chrono::milliseconds{timeout},
- [this] { return !received_packets.empty(); })) {
+ [this] { return closed || !received_packets.empty(); })) {
return {-1, Errno::AGAIN};
}
+ if (closed) {
+ return {-1, Errno::BADF};
+ }
}
return ReceivePacket(flags, message, addr, message.size());
@@ -217,8 +235,13 @@ std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, std::span<const u8> message
}
Errno ProxySocket::Close() {
- fd = INVALID_SOCKET;
- closed = true;
+ {
+ std::lock_guard guard(packets_mutex);
+ fd = INVALID_SOCKET;
+ closed = true;
+ received_packets = {};
+ }
+ packets_cv.notify_all();
return Errno::SUCCESS;
}
@@ -239,7 +262,10 @@ Errno ProxySocket::SetReuseAddr(bool enable) {
}
Errno ProxySocket::SetBroadcast(bool enable) {
- broadcast = enable;
+ {
+ std::lock_guard guard(packets_mutex);
+ broadcast = enable;
+ }
return SetSockOpt<u32>(fd, SO_BROADCAST, enable ? 1 : 0);
}