summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/announce_multiplayer_session.cpp6
-rw-r--r--src/core/hle/service/nifm/nifm.cpp342
-rw-r--r--src/core/hle/service/nifm/nifm.h27
-rw-r--r--src/core/hle/service/sockets/bsd.cpp40
-rw-r--r--src/core/hle/service/sockets/bsd.h13
-rw-r--r--src/core/hle/service/sockets/sockets.h6
-rw-r--r--src/core/hle/service/sockets/sockets_translate.cpp2
-rw-r--r--src/core/internal_network/network.cpp62
-rw-r--r--src/core/internal_network/network.h43
-rw-r--r--src/core/internal_network/socket_proxy.cpp284
-rw-r--r--src/core/internal_network/socket_proxy.h97
-rw-r--r--src/core/internal_network/sockets.h132
13 files changed, 781 insertions, 275 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 4e39649a8..3230d7199 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -724,6 +724,8 @@ add_library(core STATIC
724 internal_network/network_interface.cpp 724 internal_network/network_interface.cpp
725 internal_network/network_interface.h 725 internal_network/network_interface.h
726 internal_network/sockets.h 726 internal_network/sockets.h
727 internal_network/socket_proxy.cpp
728 internal_network/socket_proxy.h
727 loader/deconstructed_rom_directory.cpp 729 loader/deconstructed_rom_directory.cpp
728 loader/deconstructed_rom_directory.h 730 loader/deconstructed_rom_directory.h
729 loader/kip.cpp 731 loader/kip.cpp
diff --git a/src/core/announce_multiplayer_session.cpp b/src/core/announce_multiplayer_session.cpp
index d73a488cf..6737ce85a 100644
--- a/src/core/announce_multiplayer_session.cpp
+++ b/src/core/announce_multiplayer_session.cpp
@@ -31,7 +31,7 @@ AnnounceMultiplayerSession::AnnounceMultiplayerSession(Network::RoomNetwork& roo
31} 31}
32 32
33WebService::WebResult AnnounceMultiplayerSession::Register() { 33WebService::WebResult AnnounceMultiplayerSession::Register() {
34 std::shared_ptr<Network::Room> room = room_network.GetRoom().lock(); 34 auto room = room_network.GetRoom().lock();
35 if (!room) { 35 if (!room) {
36 return WebService::WebResult{WebService::WebResult::Code::LibError, 36 return WebService::WebResult{WebService::WebResult::Code::LibError,
37 "Network is not initialized", ""}; 37 "Network is not initialized", ""};
@@ -102,7 +102,7 @@ void AnnounceMultiplayerSession::UpdateBackendData(std::shared_ptr<Network::Room
102void AnnounceMultiplayerSession::AnnounceMultiplayerLoop() { 102void AnnounceMultiplayerSession::AnnounceMultiplayerLoop() {
103 // Invokes all current bound error callbacks. 103 // Invokes all current bound error callbacks.
104 const auto ErrorCallback = [this](WebService::WebResult result) { 104 const auto ErrorCallback = [this](WebService::WebResult result) {
105 std::lock_guard<std::mutex> lock(callback_mutex); 105 std::lock_guard lock(callback_mutex);
106 for (auto callback : error_callbacks) { 106 for (auto callback : error_callbacks) {
107 (*callback)(result); 107 (*callback)(result);
108 } 108 }
@@ -120,7 +120,7 @@ void AnnounceMultiplayerSession::AnnounceMultiplayerLoop() {
120 std::future<WebService::WebResult> future; 120 std::future<WebService::WebResult> future;
121 while (!shutdown_event.WaitUntil(update_time)) { 121 while (!shutdown_event.WaitUntil(update_time)) {
122 update_time += announce_time_interval; 122 update_time += announce_time_interval;
123 std::shared_ptr<Network::Room> room = room_network.GetRoom().lock(); 123 auto room = room_network.GetRoom().lock();
124 if (!room) { 124 if (!room) {
125 break; 125 break;
126 } 126 }
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 2889973e4..e3ef06481 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -6,7 +6,6 @@
6#include "core/hle/kernel/k_event.h" 6#include "core/hle/kernel/k_event.h"
7#include "core/hle/service/kernel_helpers.h" 7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/nifm/nifm.h" 8#include "core/hle/service/nifm/nifm.h"
9#include "core/hle/service/service.h"
10 9
11namespace { 10namespace {
12 11
@@ -271,213 +270,228 @@ public:
271 } 270 }
272}; 271};
273 272
274class IGeneralService final : public ServiceFramework<IGeneralService> { 273void IGeneralService::GetClientId(Kernel::HLERequestContext& ctx) {
275public: 274 static constexpr u32 client_id = 1;
276 explicit IGeneralService(Core::System& system_); 275 LOG_WARNING(Service_NIFM, "(STUBBED) called");
277 276
278private: 277 IPC::ResponseBuilder rb{ctx, 4};
279 void GetClientId(Kernel::HLERequestContext& ctx) { 278 rb.Push(ResultSuccess);
280 static constexpr u32 client_id = 1; 279 rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
281 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 280}
282 281
283 IPC::ResponseBuilder rb{ctx, 4}; 282void IGeneralService::CreateScanRequest(Kernel::HLERequestContext& ctx) {
284 rb.Push(ResultSuccess); 283 LOG_DEBUG(Service_NIFM, "called");
285 rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
286 }
287 284
288 void CreateScanRequest(Kernel::HLERequestContext& ctx) { 285 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
289 LOG_DEBUG(Service_NIFM, "called");
290 286
291 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 287 rb.Push(ResultSuccess);
288 rb.PushIpcInterface<IScanRequest>(system);
289}
292 290
293 rb.Push(ResultSuccess); 291void IGeneralService::CreateRequest(Kernel::HLERequestContext& ctx) {
294 rb.PushIpcInterface<IScanRequest>(system); 292 LOG_DEBUG(Service_NIFM, "called");
295 }
296 293
297 void CreateRequest(Kernel::HLERequestContext& ctx) { 294 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
298 LOG_DEBUG(Service_NIFM, "called");
299 295
300 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 296 rb.Push(ResultSuccess);
297 rb.PushIpcInterface<IRequest>(system);
298}
301 299
302 rb.Push(ResultSuccess); 300void IGeneralService::GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
303 rb.PushIpcInterface<IRequest>(system); 301 LOG_WARNING(Service_NIFM, "(STUBBED) called");
304 }
305 302
306 void GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) { 303 const auto net_iface = Network::GetSelectedNetworkInterface();
307 LOG_WARNING(Service_NIFM, "(STUBBED) called");
308 304
309 const auto net_iface = Network::GetSelectedNetworkInterface(); 305 SfNetworkProfileData network_profile_data = [&net_iface] {
310 306 if (!net_iface) {
311 const SfNetworkProfileData network_profile_data = [&net_iface] { 307 return SfNetworkProfileData{};
312 if (!net_iface) { 308 }
313 return SfNetworkProfileData{}; 309
314 } 310 return SfNetworkProfileData{
315 311 .ip_setting_data{
316 return SfNetworkProfileData{ 312 .ip_address_setting{
317 .ip_setting_data{ 313 .is_automatic{true},
318 .ip_address_setting{ 314 .current_address{Network::TranslateIPv4(net_iface->ip_address)},
319 .is_automatic{true}, 315 .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
320 .current_address{Network::TranslateIPv4(net_iface->ip_address)}, 316 .gateway{Network::TranslateIPv4(net_iface->gateway)},
321 .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
322 .gateway{Network::TranslateIPv4(net_iface->gateway)},
323 },
324 .dns_setting{
325 .is_automatic{true},
326 .primary_dns{1, 1, 1, 1},
327 .secondary_dns{1, 0, 0, 1},
328 },
329 .proxy_setting{
330 .enabled{false},
331 .port{},
332 .proxy_server{},
333 .automatic_auth_enabled{},
334 .user{},
335 .password{},
336 },
337 .mtu{1500},
338 }, 317 },
339 .uuid{0xdeadbeef, 0xdeadbeef}, 318 .dns_setting{
340 .network_name{"yuzu Network"}, 319 .is_automatic{true},
341 .wireless_setting_data{ 320 .primary_dns{1, 1, 1, 1},
342 .ssid_length{12}, 321 .secondary_dns{1, 0, 0, 1},
343 .ssid{"yuzu Network"},
344 .passphrase{"yuzupassword"},
345 }, 322 },
346 }; 323 .proxy_setting{
347 }(); 324 .enabled{false},
348 325 .port{},
349 ctx.WriteBuffer(network_profile_data); 326 .proxy_server{},
327 .automatic_auth_enabled{},
328 .user{},
329 .password{},
330 },
331 .mtu{1500},
332 },
333 .uuid{0xdeadbeef, 0xdeadbeef},
334 .network_name{"yuzu Network"},
335 .wireless_setting_data{
336 .ssid_length{12},
337 .ssid{"yuzu Network"},
338 .passphrase{"yuzupassword"},
339 },
340 };
341 }();
350 342
351 IPC::ResponseBuilder rb{ctx, 2}; 343 // When we're connected to a room, spoof the hosts IP address
352 rb.Push(ResultSuccess); 344 if (auto room_member = network.GetRoomMember().lock()) {
345 if (room_member->IsConnected()) {
346 network_profile_data.ip_setting_data.ip_address_setting.current_address =
347 room_member->GetFakeIpAddress();
348 }
353 } 349 }
354 350
355 void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { 351 ctx.WriteBuffer(network_profile_data);
356 LOG_WARNING(Service_NIFM, "(STUBBED) called");
357 352
358 IPC::ResponseBuilder rb{ctx, 2}; 353 IPC::ResponseBuilder rb{ctx, 2};
359 rb.Push(ResultSuccess); 354 rb.Push(ResultSuccess);
360 } 355}
361 356
362 void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) { 357void IGeneralService::RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
363 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 358 LOG_WARNING(Service_NIFM, "(STUBBED) called");
364 359
365 auto ipv4 = Network::GetHostIPv4Address(); 360 IPC::ResponseBuilder rb{ctx, 2};
366 if (!ipv4) { 361 rb.Push(ResultSuccess);
367 LOG_ERROR(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0"); 362}
368 ipv4.emplace(Network::IPv4Address{0, 0, 0, 0});
369 }
370 363
371 IPC::ResponseBuilder rb{ctx, 3}; 364void IGeneralService::GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
372 rb.Push(ResultSuccess); 365 LOG_WARNING(Service_NIFM, "(STUBBED) called");
373 rb.PushRaw(*ipv4); 366
367 auto ipv4 = Network::GetHostIPv4Address();
368 if (!ipv4) {
369 LOG_ERROR(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0");
370 ipv4.emplace(Network::IPv4Address{0, 0, 0, 0});
374 } 371 }
375 372
376 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { 373 // When we're connected to a room, spoof the hosts IP address
377 LOG_DEBUG(Service_NIFM, "called"); 374 if (auto room_member = network.GetRoomMember().lock()) {
375 if (room_member->IsConnected()) {
376 ipv4 = room_member->GetFakeIpAddress();
377 }
378 }
378 379
379 ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, 380 IPC::ResponseBuilder rb{ctx, 3};
380 "SfNetworkProfileData is not the correct size"); 381 rb.Push(ResultSuccess);
381 u128 uuid{}; 382 rb.PushRaw(*ipv4);
382 auto buffer = ctx.ReadBuffer(); 383}
383 std::memcpy(&uuid, buffer.data() + 8, sizeof(u128));
384 384
385 IPC::ResponseBuilder rb{ctx, 6, 0, 1}; 385void IGeneralService::CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
386 LOG_DEBUG(Service_NIFM, "called");
386 387
387 rb.Push(ResultSuccess); 388 ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "SfNetworkProfileData is not the correct size");
388 rb.PushIpcInterface<INetworkProfile>(system); 389 u128 uuid{};
389 rb.PushRaw<u128>(uuid); 390 auto buffer = ctx.ReadBuffer();
390 } 391 std::memcpy(&uuid, buffer.data() + 8, sizeof(u128));
391 392
392 void GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) { 393 IPC::ResponseBuilder rb{ctx, 6, 0, 1};
393 LOG_WARNING(Service_NIFM, "(STUBBED) called");
394 394
395 struct IpConfigInfo { 395 rb.Push(ResultSuccess);
396 IpAddressSetting ip_address_setting{}; 396 rb.PushIpcInterface<INetworkProfile>(system);
397 DnsSetting dns_setting{}; 397 rb.PushRaw<u128>(uuid);
398 }; 398}
399 static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting),
400 "IpConfigInfo has incorrect size.");
401 399
402 const auto net_iface = Network::GetSelectedNetworkInterface(); 400void IGeneralService::GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) {
401 LOG_WARNING(Service_NIFM, "(STUBBED) called");
403 402
404 const IpConfigInfo ip_config_info = [&net_iface] { 403 struct IpConfigInfo {
405 if (!net_iface) { 404 IpAddressSetting ip_address_setting{};
406 return IpConfigInfo{}; 405 DnsSetting dns_setting{};
407 } 406 };
407 static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting),
408 "IpConfigInfo has incorrect size.");
408 409
409 return IpConfigInfo{ 410 const auto net_iface = Network::GetSelectedNetworkInterface();
410 .ip_address_setting{
411 .is_automatic{true},
412 .current_address{Network::TranslateIPv4(net_iface->ip_address)},
413 .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
414 .gateway{Network::TranslateIPv4(net_iface->gateway)},
415 },
416 .dns_setting{
417 .is_automatic{true},
418 .primary_dns{1, 1, 1, 1},
419 .secondary_dns{1, 0, 0, 1},
420 },
421 };
422 }();
423 411
424 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)}; 412 IpConfigInfo ip_config_info = [&net_iface] {
425 rb.Push(ResultSuccess); 413 if (!net_iface) {
426 rb.PushRaw<IpConfigInfo>(ip_config_info); 414 return IpConfigInfo{};
427 } 415 }
428 416
429 void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) { 417 return IpConfigInfo{
430 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 418 .ip_address_setting{
419 .is_automatic{true},
420 .current_address{Network::TranslateIPv4(net_iface->ip_address)},
421 .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
422 .gateway{Network::TranslateIPv4(net_iface->gateway)},
423 },
424 .dns_setting{
425 .is_automatic{true},
426 .primary_dns{1, 1, 1, 1},
427 .secondary_dns{1, 0, 0, 1},
428 },
429 };
430 }();
431 431
432 IPC::ResponseBuilder rb{ctx, 3}; 432 // When we're connected to a room, spoof the hosts IP address
433 rb.Push(ResultSuccess); 433 if (auto room_member = network.GetRoomMember().lock()) {
434 rb.Push<u8>(0); 434 if (room_member->IsConnected()) {
435 ip_config_info.ip_address_setting.current_address = room_member->GetFakeIpAddress();
436 }
435 } 437 }
436 438
437 void GetInternetConnectionStatus(Kernel::HLERequestContext& ctx) { 439 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)};
438 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 440 rb.Push(ResultSuccess);
441 rb.PushRaw<IpConfigInfo>(ip_config_info);
442}
439 443
440 struct Output { 444void IGeneralService::IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) {
441 InternetConnectionType type{InternetConnectionType::WiFi}; 445 LOG_WARNING(Service_NIFM, "(STUBBED) called");
442 u8 wifi_strength{3};
443 InternetConnectionStatus state{InternetConnectionStatus::Connected};
444 };
445 static_assert(sizeof(Output) == 0x3, "Output has incorrect size.");
446 446
447 constexpr Output out{}; 447 IPC::ResponseBuilder rb{ctx, 3};
448 rb.Push(ResultSuccess);
449 rb.Push<u8>(1);
450}
448 451
449 IPC::ResponseBuilder rb{ctx, 3}; 452void IGeneralService::GetInternetConnectionStatus(Kernel::HLERequestContext& ctx) {
450 rb.Push(ResultSuccess); 453 LOG_WARNING(Service_NIFM, "(STUBBED) called");
451 rb.PushRaw(out);
452 }
453 454
454 void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) { 455 struct Output {
455 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 456 InternetConnectionType type{InternetConnectionType::WiFi};
457 u8 wifi_strength{3};
458 InternetConnectionStatus state{InternetConnectionStatus::Connected};
459 };
460 static_assert(sizeof(Output) == 0x3, "Output has incorrect size.");
456 461
457 IPC::ResponseBuilder rb{ctx, 3}; 462 constexpr Output out{};
458 rb.Push(ResultSuccess); 463
459 if (Network::GetHostIPv4Address().has_value()) { 464 IPC::ResponseBuilder rb{ctx, 3};
460 rb.Push<u8>(1); 465 rb.Push(ResultSuccess);
461 } else { 466 rb.PushRaw(out);
462 rb.Push<u8>(0); 467}
463 } 468
469void IGeneralService::IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) {
470 LOG_WARNING(Service_NIFM, "(STUBBED) called");
471
472 IPC::ResponseBuilder rb{ctx, 3};
473 rb.Push(ResultSuccess);
474 if (Network::GetHostIPv4Address().has_value()) {
475 rb.Push<u8>(1);
476 } else {
477 rb.Push<u8>(0);
464 } 478 }
479}
465 480
466 void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) { 481void IGeneralService::IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
467 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 482 LOG_ERROR(Service_NIFM, "(STUBBED) called");
468 483
469 IPC::ResponseBuilder rb{ctx, 3}; 484 IPC::ResponseBuilder rb{ctx, 3};
470 rb.Push(ResultSuccess); 485 rb.Push(ResultSuccess);
471 if (Network::GetHostIPv4Address().has_value()) { 486 if (Network::GetHostIPv4Address().has_value()) {
472 rb.Push<u8>(1); 487 rb.Push<u8>(1);
473 } else { 488 } else {
474 rb.Push<u8>(0); 489 rb.Push<u8>(0);
475 }
476 } 490 }
477}; 491}
478 492
479IGeneralService::IGeneralService(Core::System& system_) 493IGeneralService::IGeneralService(Core::System& system_)
480 : ServiceFramework{system_, "IGeneralService"} { 494 : ServiceFramework{system_, "IGeneralService"}, network{system_.GetRoomNetwork()} {
481 // clang-format off 495 // clang-format off
482 static const FunctionInfo functions[] = { 496 static const FunctionInfo functions[] = {
483 {1, &IGeneralService::GetClientId, "GetClientId"}, 497 {1, &IGeneralService::GetClientId, "GetClientId"},
@@ -528,6 +542,8 @@ IGeneralService::IGeneralService(Core::System& system_)
528 RegisterHandlers(functions); 542 RegisterHandlers(functions);
529} 543}
530 544
545IGeneralService::~IGeneralService() = default;
546
531class NetworkInterface final : public ServiceFramework<NetworkInterface> { 547class NetworkInterface final : public ServiceFramework<NetworkInterface> {
532public: 548public:
533 explicit NetworkInterface(const char* name, Core::System& system_) 549 explicit NetworkInterface(const char* name, Core::System& system_)
diff --git a/src/core/hle/service/nifm/nifm.h b/src/core/hle/service/nifm/nifm.h
index 5f62d0014..48161be28 100644
--- a/src/core/hle/service/nifm/nifm.h
+++ b/src/core/hle/service/nifm/nifm.h
@@ -3,6 +3,11 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/service.h"
7#include "network/network.h"
8#include "network/room.h"
9#include "network/room_member.h"
10
6namespace Core { 11namespace Core {
7class System; 12class System;
8} 13}
@@ -16,4 +21,26 @@ namespace Service::NIFM {
16/// Registers all NIFM services with the specified service manager. 21/// Registers all NIFM services with the specified service manager.
17void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); 22void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
18 23
24class IGeneralService final : public ServiceFramework<IGeneralService> {
25public:
26 explicit IGeneralService(Core::System& system_);
27 ~IGeneralService() override;
28
29private:
30 void GetClientId(Kernel::HLERequestContext& ctx);
31 void CreateScanRequest(Kernel::HLERequestContext& ctx);
32 void CreateRequest(Kernel::HLERequestContext& ctx);
33 void GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx);
34 void RemoveNetworkProfile(Kernel::HLERequestContext& ctx);
35 void GetCurrentIpAddress(Kernel::HLERequestContext& ctx);
36 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx);
37 void GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx);
38 void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx);
39 void GetInternetConnectionStatus(Kernel::HLERequestContext& ctx);
40 void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx);
41 void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx);
42
43 Network::RoomNetwork& network;
44};
45
19} // namespace Service::NIFM 46} // namespace Service::NIFM
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index c7194731e..e08c3cb67 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -9,12 +9,16 @@
9#include <fmt/format.h> 9#include <fmt/format.h>
10 10
11#include "common/microprofile.h" 11#include "common/microprofile.h"
12#include "common/socket_types.h"
13#include "core/core.h"
12#include "core/hle/ipc_helpers.h" 14#include "core/hle/ipc_helpers.h"
13#include "core/hle/kernel/k_thread.h" 15#include "core/hle/kernel/k_thread.h"
14#include "core/hle/service/sockets/bsd.h" 16#include "core/hle/service/sockets/bsd.h"
15#include "core/hle/service/sockets/sockets_translate.h" 17#include "core/hle/service/sockets/sockets_translate.h"
16#include "core/internal_network/network.h" 18#include "core/internal_network/network.h"
19#include "core/internal_network/socket_proxy.h"
17#include "core/internal_network/sockets.h" 20#include "core/internal_network/sockets.h"
21#include "network/network.h"
18 22
19namespace Service::Sockets { 23namespace Service::Sockets {
20 24
@@ -472,7 +476,13 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
472 476
473 LOG_INFO(Service, "New socket fd={}", fd); 477 LOG_INFO(Service, "New socket fd={}", fd);
474 478
475 descriptor.socket = std::make_unique<Network::Socket>(); 479 auto room_member = room_network.GetRoomMember().lock();
480 if (room_member && room_member->IsConnected()) {
481 descriptor.socket = std::make_unique<Network::ProxySocket>(room_network);
482 } else {
483 descriptor.socket = std::make_unique<Network::Socket>();
484 }
485
476 descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(type, protocol)); 486 descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(type, protocol));
477 descriptor.is_connection_based = IsConnectionBased(type); 487 descriptor.is_connection_based = IsConnectionBased(type);
478 488
@@ -648,7 +658,7 @@ std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
648 ASSERT(arg == 0); 658 ASSERT(arg == 0);
649 return {descriptor.flags, Errno::SUCCESS}; 659 return {descriptor.flags, Errno::SUCCESS};
650 case FcntlCmd::SETFL: { 660 case FcntlCmd::SETFL: {
651 const bool enable = (arg & FLAG_O_NONBLOCK) != 0; 661 const bool enable = (arg & Network::FLAG_O_NONBLOCK) != 0;
652 const Errno bsd_errno = Translate(descriptor.socket->SetNonBlock(enable)); 662 const Errno bsd_errno = Translate(descriptor.socket->SetNonBlock(enable));
653 if (bsd_errno != Errno::SUCCESS) { 663 if (bsd_errno != Errno::SUCCESS) {
654 return {-1, bsd_errno}; 664 return {-1, bsd_errno};
@@ -669,7 +679,7 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, con
669 return Errno::BADF; 679 return Errno::BADF;
670 } 680 }
671 681
672 Network::Socket* const socket = file_descriptors[fd]->socket.get(); 682 Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
673 683
674 if (optname == OptName::LINGER) { 684 if (optname == OptName::LINGER) {
675 ASSERT(optlen == sizeof(Linger)); 685 ASSERT(optlen == sizeof(Linger));
@@ -724,6 +734,8 @@ std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message)
724 FileDescriptor& descriptor = *file_descriptors[fd]; 734 FileDescriptor& descriptor = *file_descriptors[fd];
725 735
726 // Apply flags 736 // Apply flags
737 using Network::FLAG_MSG_DONTWAIT;
738 using Network::FLAG_O_NONBLOCK;
727 if ((flags & FLAG_MSG_DONTWAIT) != 0) { 739 if ((flags & FLAG_MSG_DONTWAIT) != 0) {
728 flags &= ~FLAG_MSG_DONTWAIT; 740 flags &= ~FLAG_MSG_DONTWAIT;
729 if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) { 741 if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
@@ -759,6 +771,8 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess
759 } 771 }
760 772
761 // Apply flags 773 // Apply flags
774 using Network::FLAG_MSG_DONTWAIT;
775 using Network::FLAG_O_NONBLOCK;
762 if ((flags & FLAG_MSG_DONTWAIT) != 0) { 776 if ((flags & FLAG_MSG_DONTWAIT) != 0) {
763 flags &= ~FLAG_MSG_DONTWAIT; 777 flags &= ~FLAG_MSG_DONTWAIT;
764 if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) { 778 if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
@@ -857,8 +871,19 @@ void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) co
857 rb.PushEnum(bsd_errno); 871 rb.PushEnum(bsd_errno);
858} 872}
859 873
874void BSD::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
875 for (auto& optional_descriptor : file_descriptors) {
876 if (!optional_descriptor.has_value()) {
877 continue;
878 }
879 FileDescriptor& descriptor = *optional_descriptor;
880 descriptor.socket.get()->HandleProxyPacket(packet);
881 }
882}
883
860BSD::BSD(Core::System& system_, const char* name) 884BSD::BSD(Core::System& system_, const char* name)
861 : ServiceFramework{system_, name, ServiceThreadType::CreateNew} { 885 : ServiceFramework{system_, name, ServiceThreadType::CreateNew}, room_network{
886 system_.GetRoomNetwork()} {
862 // clang-format off 887 // clang-format off
863 static const FunctionInfo functions[] = { 888 static const FunctionInfo functions[] = {
864 {0, &BSD::RegisterClient, "RegisterClient"}, 889 {0, &BSD::RegisterClient, "RegisterClient"},
@@ -899,6 +924,13 @@ BSD::BSD(Core::System& system_, const char* name)
899 // clang-format on 924 // clang-format on
900 925
901 RegisterHandlers(functions); 926 RegisterHandlers(functions);
927
928 if (auto room_member = room_network.GetRoomMember().lock()) {
929 proxy_packet_received = room_member->BindOnProxyPacketReceived(
930 [this](const Network::ProxyPacket& packet) { OnProxyPacketReceived(packet); });
931 } else {
932 LOG_ERROR(Service, "Network isn't initalized");
933 }
902} 934}
903 935
904BSD::~BSD() = default; 936BSD::~BSD() = default;
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index 9ea36428d..81e855e0f 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -7,14 +7,17 @@
7#include <vector> 7#include <vector>
8 8
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/socket_types.h"
10#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
11#include "core/hle/service/sockets/sockets.h" 12#include "core/hle/service/sockets/sockets.h"
13#include "network/network.h"
12 14
13namespace Core { 15namespace Core {
14class System; 16class System;
15} 17}
16 18
17namespace Network { 19namespace Network {
20class SocketBase;
18class Socket; 21class Socket;
19} // namespace Network 22} // namespace Network
20 23
@@ -30,7 +33,7 @@ private:
30 static constexpr size_t MAX_FD = 128; 33 static constexpr size_t MAX_FD = 128;
31 34
32 struct FileDescriptor { 35 struct FileDescriptor {
33 std::unique_ptr<Network::Socket> socket; 36 std::unique_ptr<Network::SocketBase> socket;
34 s32 flags = 0; 37 s32 flags = 0;
35 bool is_connection_based = false; 38 bool is_connection_based = false;
36 }; 39 };
@@ -165,6 +168,14 @@ private:
165 void BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept; 168 void BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept;
166 169
167 std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors; 170 std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors;
171
172 Network::RoomNetwork& room_network;
173
174 /// Callback to parse and handle a received wifi packet.
175 void OnProxyPacketReceived(const Network::ProxyPacket& packet);
176
177 // Callback identifier for the OnProxyPacketReceived event.
178 Network::RoomMember::CallbackHandle<Network::ProxyPacket> proxy_packet_received;
168}; 179};
169 180
170class BSDCFG final : public ServiceFramework<BSDCFG> { 181class BSDCFG final : public ServiceFramework<BSDCFG> {
diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h
index b735b00fc..31b7dad33 100644
--- a/src/core/hle/service/sockets/sockets.h
+++ b/src/core/hle/service/sockets/sockets.h
@@ -22,7 +22,9 @@ enum class Errno : u32 {
22 AGAIN = 11, 22 AGAIN = 11,
23 INVAL = 22, 23 INVAL = 22,
24 MFILE = 24, 24 MFILE = 24,
25 MSGSIZE = 90,
25 NOTCONN = 107, 26 NOTCONN = 107,
27 TIMEDOUT = 110,
26}; 28};
27 29
28enum class Domain : u32 { 30enum class Domain : u32 {
@@ -96,10 +98,6 @@ struct Linger {
96 u32 linger; 98 u32 linger;
97}; 99};
98 100
99constexpr u32 FLAG_MSG_DONTWAIT = 0x80;
100
101constexpr u32 FLAG_O_NONBLOCK = 0x800;
102
103/// Registers all Sockets services with the specified service manager. 101/// Registers all Sockets services with the specified service manager.
104void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); 102void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
105 103
diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp
index 2db10ec81..023aa0486 100644
--- a/src/core/hle/service/sockets/sockets_translate.cpp
+++ b/src/core/hle/service/sockets/sockets_translate.cpp
@@ -25,6 +25,8 @@ Errno Translate(Network::Errno value) {
25 return Errno::MFILE; 25 return Errno::MFILE;
26 case Network::Errno::NOTCONN: 26 case Network::Errno::NOTCONN:
27 return Errno::NOTCONN; 27 return Errno::NOTCONN;
28 case Network::Errno::TIMEDOUT:
29 return Errno::TIMEDOUT;
28 default: 30 default:
29 UNIMPLEMENTED_MSG("Unimplemented errno={}", value); 31 UNIMPLEMENTED_MSG("Unimplemented errno={}", value);
30 return Errno::SUCCESS; 32 return Errno::SUCCESS;
diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp
index 36c43cc8f..cdf38a2a4 100644
--- a/src/core/internal_network/network.cpp
+++ b/src/core/internal_network/network.cpp
@@ -32,6 +32,7 @@
32#include "core/internal_network/network.h" 32#include "core/internal_network/network.h"
33#include "core/internal_network/network_interface.h" 33#include "core/internal_network/network_interface.h"
34#include "core/internal_network/sockets.h" 34#include "core/internal_network/sockets.h"
35#include "network/network.h"
35 36
36namespace Network { 37namespace Network {
37 38
@@ -114,7 +115,10 @@ Errno TranslateNativeError(int e) {
114 return Errno::NETDOWN; 115 return Errno::NETDOWN;
115 case WSAENETUNREACH: 116 case WSAENETUNREACH:
116 return Errno::NETUNREACH; 117 return Errno::NETUNREACH;
118 case WSAEMSGSIZE:
119 return Errno::MSGSIZE;
117 default: 120 default:
121 UNIMPLEMENTED_MSG("Unimplemented errno={}", e);
118 return Errno::OTHER; 122 return Errno::OTHER;
119 } 123 }
120} 124}
@@ -125,7 +129,6 @@ using SOCKET = int;
125using WSAPOLLFD = pollfd; 129using WSAPOLLFD = pollfd;
126using ULONG = u64; 130using ULONG = u64;
127 131
128constexpr SOCKET INVALID_SOCKET = -1;
129constexpr SOCKET SOCKET_ERROR = -1; 132constexpr SOCKET SOCKET_ERROR = -1;
130 133
131constexpr int SD_RECEIVE = SHUT_RD; 134constexpr int SD_RECEIVE = SHUT_RD;
@@ -206,7 +209,10 @@ Errno TranslateNativeError(int e) {
206 return Errno::NETDOWN; 209 return Errno::NETDOWN;
207 case ENETUNREACH: 210 case ENETUNREACH:
208 return Errno::NETUNREACH; 211 return Errno::NETUNREACH;
212 case EMSGSIZE:
213 return Errno::MSGSIZE;
209 default: 214 default:
215 UNIMPLEMENTED_MSG("Unimplemented errno={}", e);
210 return Errno::OTHER; 216 return Errno::OTHER;
211 } 217 }
212} 218}
@@ -329,16 +335,6 @@ PollEvents TranslatePollRevents(short revents) {
329 return result; 335 return result;
330} 336}
331 337
332template <typename T>
333Errno SetSockOpt(SOCKET fd, int option, T value) {
334 const int result =
335 setsockopt(fd, SOL_SOCKET, option, reinterpret_cast<const char*>(&value), sizeof(value));
336 if (result != SOCKET_ERROR) {
337 return Errno::SUCCESS;
338 }
339 return GetAndLogLastError();
340}
341
342} // Anonymous namespace 338} // Anonymous namespace
343 339
344NetworkInstance::NetworkInstance() { 340NetworkInstance::NetworkInstance() {
@@ -350,26 +346,16 @@ NetworkInstance::~NetworkInstance() {
350} 346}
351 347
352std::optional<IPv4Address> GetHostIPv4Address() { 348std::optional<IPv4Address> GetHostIPv4Address() {
353 const std::string& selected_network_interface = Settings::values.network_interface.GetValue(); 349 const auto network_interface = Network::GetSelectedNetworkInterface();
354 const auto network_interfaces = Network::GetAvailableNetworkInterfaces(); 350 if (!network_interface.has_value()) {
355 if (network_interfaces.size() == 0) { 351 LOG_ERROR(Network, "GetSelectedNetworkInterface returned no interface");
356 LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces");
357 return {}; 352 return {};
358 } 353 }
359 354
360 const auto res = 355 std::array<char, 16> ip_addr = {};
361 std::ranges::find_if(network_interfaces, [&selected_network_interface](const auto& iface) { 356 ASSERT(inet_ntop(AF_INET, &network_interface->ip_address, ip_addr.data(), sizeof(ip_addr)) !=
362 return iface.name == selected_network_interface; 357 nullptr);
363 }); 358 return TranslateIPv4(network_interface->ip_address);
364
365 if (res != network_interfaces.end()) {
366 char ip_addr[16] = {};
367 ASSERT(inet_ntop(AF_INET, &res->ip_address, ip_addr, sizeof(ip_addr)) != nullptr);
368 return TranslateIPv4(res->ip_address);
369 } else {
370 LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
371 return {};
372 }
373} 359}
374 360
375std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) { 361std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) {
@@ -412,7 +398,19 @@ Socket::~Socket() {
412 fd = INVALID_SOCKET; 398 fd = INVALID_SOCKET;
413} 399}
414 400
415Socket::Socket(Socket&& rhs) noexcept : fd{std::exchange(rhs.fd, INVALID_SOCKET)} {} 401Socket::Socket(Socket&& rhs) noexcept {
402 fd = std::exchange(rhs.fd, INVALID_SOCKET);
403}
404
405template <typename T>
406Errno Socket::SetSockOpt(SOCKET fd_, int option, T value) {
407 const int result =
408 setsockopt(fd_, SOL_SOCKET, option, reinterpret_cast<const char*>(&value), sizeof(value));
409 if (result != SOCKET_ERROR) {
410 return Errno::SUCCESS;
411 }
412 return GetAndLogLastError();
413}
416 414
417Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) { 415Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) {
418 fd = socket(TranslateDomain(domain), TranslateType(type), TranslateProtocol(protocol)); 416 fd = socket(TranslateDomain(domain), TranslateType(type), TranslateProtocol(protocol));
@@ -423,7 +421,7 @@ Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) {
423 return GetAndLogLastError(); 421 return GetAndLogLastError();
424} 422}
425 423
426std::pair<Socket::AcceptResult, Errno> Socket::Accept() { 424std::pair<SocketBase::AcceptResult, Errno> Socket::Accept() {
427 sockaddr addr; 425 sockaddr addr;
428 socklen_t addrlen = sizeof(addr); 426 socklen_t addrlen = sizeof(addr);
429 const SOCKET new_socket = accept(fd, &addr, &addrlen); 427 const SOCKET new_socket = accept(fd, &addr, &addrlen);
@@ -634,4 +632,8 @@ bool Socket::IsOpened() const {
634 return fd != INVALID_SOCKET; 632 return fd != INVALID_SOCKET;
635} 633}
636 634
635void Socket::HandleProxyPacket(const ProxyPacket& packet) {
636 LOG_WARNING(Network, "ProxyPacket received, but not in Proxy mode!");
637}
638
637} // namespace Network 639} // namespace Network
diff --git a/src/core/internal_network/network.h b/src/core/internal_network/network.h
index 10e5ef10d..36994c22e 100644
--- a/src/core/internal_network/network.h
+++ b/src/core/internal_network/network.h
@@ -8,6 +8,7 @@
8 8
9#include "common/common_funcs.h" 9#include "common/common_funcs.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/socket_types.h"
11 12
12#ifdef _WIN32 13#ifdef _WIN32
13#include <winsock2.h> 14#include <winsock2.h>
@@ -17,6 +18,7 @@
17 18
18namespace Network { 19namespace Network {
19 20
21class SocketBase;
20class Socket; 22class Socket;
21 23
22/// Error code for network functions 24/// Error code for network functions
@@ -31,46 +33,11 @@ enum class Errno {
31 HOSTUNREACH, 33 HOSTUNREACH,
32 NETDOWN, 34 NETDOWN,
33 NETUNREACH, 35 NETUNREACH,
36 TIMEDOUT,
37 MSGSIZE,
34 OTHER, 38 OTHER,
35}; 39};
36 40
37/// Address families
38enum class Domain {
39 INET, ///< Address family for IPv4
40};
41
42/// Socket types
43enum class Type {
44 STREAM,
45 DGRAM,
46 RAW,
47 SEQPACKET,
48};
49
50/// Protocol values for sockets
51enum class Protocol {
52 ICMP,
53 TCP,
54 UDP,
55};
56
57/// Shutdown mode
58enum class ShutdownHow {
59 RD,
60 WR,
61 RDWR,
62};
63
64/// Array of IPv4 address
65using IPv4Address = std::array<u8, 4>;
66
67/// Cross-platform sockaddr structure
68struct SockAddrIn {
69 Domain family;
70 IPv4Address ip;
71 u16 portno;
72};
73
74/// Cross-platform poll fd structure 41/// Cross-platform poll fd structure
75 42
76enum class PollEvents : u16 { 43enum class PollEvents : u16 {
@@ -86,7 +53,7 @@ enum class PollEvents : u16 {
86DECLARE_ENUM_FLAG_OPERATORS(PollEvents); 53DECLARE_ENUM_FLAG_OPERATORS(PollEvents);
87 54
88struct PollFD { 55struct PollFD {
89 Socket* socket; 56 SocketBase* socket;
90 PollEvents events; 57 PollEvents events;
91 PollEvents revents; 58 PollEvents revents;
92}; 59};
diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp
new file mode 100644
index 000000000..49d067f4c
--- /dev/null
+++ b/src/core/internal_network/socket_proxy.cpp
@@ -0,0 +1,284 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <chrono>
5#include <thread>
6
7#include "common/assert.h"
8#include "common/logging/log.h"
9#include "core/internal_network/network.h"
10#include "core/internal_network/network_interface.h"
11#include "core/internal_network/socket_proxy.h"
12
13namespace Network {
14
15ProxySocket::ProxySocket(RoomNetwork& room_network_) noexcept : room_network{room_network_} {}
16
17ProxySocket::~ProxySocket() {
18 if (fd == INVALID_SOCKET) {
19 return;
20 }
21 fd = INVALID_SOCKET;
22}
23
24void ProxySocket::HandleProxyPacket(const ProxyPacket& packet) {
25 if (protocol != packet.protocol || local_endpoint.portno != packet.remote_endpoint.portno ||
26 closed) {
27 return;
28 }
29 std::lock_guard guard(packets_mutex);
30 received_packets.push(packet);
31}
32
33template <typename T>
34Errno ProxySocket::SetSockOpt(SOCKET fd_, int option, T value) {
35 LOG_DEBUG(Network, "(STUBBED) called");
36 return Errno::SUCCESS;
37}
38
39Errno ProxySocket::Initialize(Domain domain, Type type, Protocol socket_protocol) {
40 protocol = socket_protocol;
41 SetSockOpt(fd, SO_TYPE, type);
42
43 return Errno::SUCCESS;
44}
45
46std::pair<ProxySocket::AcceptResult, Errno> ProxySocket::Accept() {
47 LOG_WARNING(Network, "(STUBBED) called");
48 return {AcceptResult{}, Errno::SUCCESS};
49}
50
51Errno ProxySocket::Connect(SockAddrIn addr_in) {
52 LOG_WARNING(Network, "(STUBBED) called");
53 return Errno::SUCCESS;
54}
55
56std::pair<SockAddrIn, Errno> ProxySocket::GetPeerName() {
57 LOG_WARNING(Network, "(STUBBED) called");
58 return {SockAddrIn{}, Errno::SUCCESS};
59}
60
61std::pair<SockAddrIn, Errno> ProxySocket::GetSockName() {
62 LOG_WARNING(Network, "(STUBBED) called");
63 return {SockAddrIn{}, Errno::SUCCESS};
64}
65
66Errno ProxySocket::Bind(SockAddrIn addr) {
67 if (is_bound) {
68 LOG_WARNING(Network, "Rebinding Socket is unimplemented!");
69 return Errno::SUCCESS;
70 }
71 local_endpoint = addr;
72 is_bound = true;
73
74 return Errno::SUCCESS;
75}
76
77Errno ProxySocket::Listen(s32 backlog) {
78 LOG_WARNING(Network, "(STUBBED) called");
79 return Errno::SUCCESS;
80}
81
82Errno ProxySocket::Shutdown(ShutdownHow how) {
83 LOG_WARNING(Network, "(STUBBED) called");
84 return Errno::SUCCESS;
85}
86
87std::pair<s32, Errno> ProxySocket::Recv(int flags, std::vector<u8>& message) {
88 LOG_WARNING(Network, "(STUBBED) called");
89 ASSERT(flags == 0);
90 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
91
92 return {static_cast<s32>(0), Errno::SUCCESS};
93}
94
95std::pair<s32, Errno> ProxySocket::RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) {
96 ASSERT(flags == 0);
97 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
98
99 // TODO (flTobi): Verify the timeout behavior and break when connection is lost
100 const auto timestamp = std::chrono::steady_clock::now();
101 // When receive_timeout is set to zero, the socket is supposed to wait indefinitely until a
102 // packet arrives. In order to prevent lost packets from hanging the emulation thread, we set
103 // the timeout to 5s instead
104 const auto timeout = receive_timeout == 0 ? 5000 : receive_timeout;
105 while (true) {
106 {
107 std::lock_guard guard(packets_mutex);
108 if (received_packets.size() > 0) {
109 return ReceivePacket(flags, message, addr, message.size());
110 }
111 }
112
113 if (!blocking) {
114 return {-1, Errno::AGAIN};
115 }
116
117 std::this_thread::yield();
118
119 const auto time_diff = std::chrono::steady_clock::now() - timestamp;
120 const auto time_diff_ms =
121 std::chrono::duration_cast<std::chrono::milliseconds>(time_diff).count();
122
123 if (time_diff_ms > timeout) {
124 return {-1, Errno::TIMEDOUT};
125 }
126 }
127}
128
129std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::vector<u8>& message,
130 SockAddrIn* addr, std::size_t max_length) {
131 ProxyPacket& packet = received_packets.front();
132 if (addr) {
133 addr->family = Domain::INET;
134 addr->ip = packet.local_endpoint.ip; // The senders ip address
135 addr->portno = packet.local_endpoint.portno; // The senders port number
136 }
137
138 bool peek = (flags & FLAG_MSG_PEEK) != 0;
139 std::size_t read_bytes;
140 if (packet.data.size() > max_length) {
141 read_bytes = max_length;
142 message.clear();
143 std::copy(packet.data.begin(), packet.data.begin() + read_bytes,
144 std::back_inserter(message));
145 message.resize(max_length);
146
147 if (protocol == Protocol::UDP) {
148 if (!peek) {
149 received_packets.pop();
150 }
151 return {-1, Errno::MSGSIZE};
152 } else if (protocol == Protocol::TCP) {
153 std::vector<u8> numArray(packet.data.size() - max_length);
154 std::copy(packet.data.begin() + max_length, packet.data.end(),
155 std::back_inserter(numArray));
156 packet.data = numArray;
157 }
158 } else {
159 read_bytes = packet.data.size();
160 message.clear();
161 std::copy(packet.data.begin(), packet.data.end(), std::back_inserter(message));
162 message.resize(max_length);
163 if (!peek) {
164 received_packets.pop();
165 }
166 }
167
168 return {static_cast<u32>(read_bytes), Errno::SUCCESS};
169}
170
171std::pair<s32, Errno> ProxySocket::Send(const std::vector<u8>& message, int flags) {
172 LOG_WARNING(Network, "(STUBBED) called");
173 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
174 ASSERT(flags == 0);
175
176 return {static_cast<s32>(0), Errno::SUCCESS};
177}
178
179void ProxySocket::SendPacket(ProxyPacket& packet) {
180 if (auto room_member = room_network.GetRoomMember().lock()) {
181 if (room_member->IsConnected()) {
182 room_member->SendProxyPacket(packet);
183 }
184 }
185}
186
187std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, const std::vector<u8>& message,
188 const SockAddrIn* addr) {
189 ASSERT(flags == 0);
190
191 if (!is_bound) {
192 LOG_ERROR(Network, "ProxySocket is not bound!");
193 return {static_cast<s32>(message.size()), Errno::SUCCESS};
194 }
195
196 if (auto room_member = room_network.GetRoomMember().lock()) {
197 if (!room_member->IsConnected()) {
198 return {static_cast<s32>(message.size()), Errno::SUCCESS};
199 }
200 }
201
202 ProxyPacket packet;
203 packet.local_endpoint = local_endpoint;
204 packet.remote_endpoint = *addr;
205 packet.protocol = protocol;
206 packet.broadcast = broadcast;
207
208 auto& ip = local_endpoint.ip;
209 auto ipv4 = Network::GetHostIPv4Address();
210 // If the ip is all zeroes (INADDR_ANY) or if it matches the hosts ip address,
211 // replace it with a "fake" routing address
212 if (std::all_of(ip.begin(), ip.end(), [](u8 i) { return i == 0; }) || (ipv4 && ipv4 == ip)) {
213 if (auto room_member = room_network.GetRoomMember().lock()) {
214 packet.local_endpoint.ip = room_member->GetFakeIpAddress();
215 }
216 }
217
218 packet.data.clear();
219 std::copy(message.begin(), message.end(), std::back_inserter(packet.data));
220
221 SendPacket(packet);
222
223 return {static_cast<s32>(message.size()), Errno::SUCCESS};
224}
225
226Errno ProxySocket::Close() {
227 fd = INVALID_SOCKET;
228 closed = true;
229
230 return Errno::SUCCESS;
231}
232
233Errno ProxySocket::SetLinger(bool enable, u32 linger) {
234 struct Linger {
235 u16 linger_enable;
236 u16 linger_time;
237 } values;
238 values.linger_enable = enable ? 1 : 0;
239 values.linger_time = static_cast<u16>(linger);
240
241 return SetSockOpt(fd, SO_LINGER, values);
242}
243
244Errno ProxySocket::SetReuseAddr(bool enable) {
245 return SetSockOpt<u32>(fd, SO_REUSEADDR, enable ? 1 : 0);
246}
247
248Errno ProxySocket::SetBroadcast(bool enable) {
249 broadcast = enable;
250 return SetSockOpt<u32>(fd, SO_BROADCAST, enable ? 1 : 0);
251}
252
253Errno ProxySocket::SetSndBuf(u32 value) {
254 return SetSockOpt(fd, SO_SNDBUF, value);
255}
256
257Errno ProxySocket::SetKeepAlive(bool enable) {
258 return Errno::SUCCESS;
259}
260
261Errno ProxySocket::SetRcvBuf(u32 value) {
262 return SetSockOpt(fd, SO_RCVBUF, value);
263}
264
265Errno ProxySocket::SetSndTimeo(u32 value) {
266 send_timeout = value;
267 return SetSockOpt(fd, SO_SNDTIMEO, static_cast<int>(value));
268}
269
270Errno ProxySocket::SetRcvTimeo(u32 value) {
271 receive_timeout = value;
272 return SetSockOpt(fd, SO_RCVTIMEO, static_cast<int>(value));
273}
274
275Errno ProxySocket::SetNonBlock(bool enable) {
276 blocking = !enable;
277 return Errno::SUCCESS;
278}
279
280bool ProxySocket::IsOpened() const {
281 return fd != INVALID_SOCKET;
282}
283
284} // namespace Network
diff --git a/src/core/internal_network/socket_proxy.h b/src/core/internal_network/socket_proxy.h
new file mode 100644
index 000000000..f12b5f567
--- /dev/null
+++ b/src/core/internal_network/socket_proxy.h
@@ -0,0 +1,97 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <mutex>
7#include <vector>
8#include <queue>
9
10#include "common/common_funcs.h"
11#include "core/internal_network/sockets.h"
12#include "network/network.h"
13
14namespace Network {
15
16class ProxySocket : public SocketBase {
17public:
18 YUZU_NON_COPYABLE(ProxySocket);
19 YUZU_NON_MOVEABLE(ProxySocket);
20
21 explicit ProxySocket(RoomNetwork& room_network_) noexcept;
22 ~ProxySocket() override;
23
24 void HandleProxyPacket(const ProxyPacket& packet) override;
25
26 Errno Initialize(Domain domain, Type type, Protocol socket_protocol) override;
27
28 Errno Close() override;
29
30 std::pair<AcceptResult, Errno> Accept() override;
31
32 Errno Connect(SockAddrIn addr_in) override;
33
34 std::pair<SockAddrIn, Errno> GetPeerName() override;
35
36 std::pair<SockAddrIn, Errno> GetSockName() override;
37
38 Errno Bind(SockAddrIn addr) override;
39
40 Errno Listen(s32 backlog) override;
41
42 Errno Shutdown(ShutdownHow how) override;
43
44 std::pair<s32, Errno> Recv(int flags, std::vector<u8>& message) override;
45
46 std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) override;
47
48 std::pair<s32, Errno> ReceivePacket(int flags, std::vector<u8>& message, SockAddrIn* addr,
49 std::size_t max_length);
50
51 std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) override;
52
53 void SendPacket(ProxyPacket& packet);
54
55 std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message,
56 const SockAddrIn* addr) override;
57
58 Errno SetLinger(bool enable, u32 linger) override;
59
60 Errno SetReuseAddr(bool enable) override;
61
62 Errno SetBroadcast(bool enable) override;
63
64 Errno SetKeepAlive(bool enable) override;
65
66 Errno SetSndBuf(u32 value) override;
67
68 Errno SetRcvBuf(u32 value) override;
69
70 Errno SetSndTimeo(u32 value) override;
71
72 Errno SetRcvTimeo(u32 value) override;
73
74 Errno SetNonBlock(bool enable) override;
75
76 template <typename T>
77 Errno SetSockOpt(SOCKET fd, int option, T value);
78
79 bool IsOpened() const override;
80
81private:
82 bool broadcast = false;
83 bool closed = false;
84 u32 send_timeout = 0;
85 u32 receive_timeout = 0;
86 bool is_bound = false;
87 SockAddrIn local_endpoint{};
88 bool blocking = true;
89 std::queue<ProxyPacket> received_packets;
90 Protocol protocol;
91
92 std::mutex packets_mutex;
93
94 RoomNetwork& room_network;
95};
96
97} // namespace Network
diff --git a/src/core/internal_network/sockets.h b/src/core/internal_network/sockets.h
index 77e27e928..a70429b19 100644
--- a/src/core/internal_network/sockets.h
+++ b/src/core/internal_network/sockets.h
@@ -14,20 +14,88 @@
14 14
15#include "common/common_types.h" 15#include "common/common_types.h"
16#include "core/internal_network/network.h" 16#include "core/internal_network/network.h"
17#include "network/network.h"
17 18
18// TODO: C++20 Replace std::vector usages with std::span 19// TODO: C++20 Replace std::vector usages with std::span
19 20
20namespace Network { 21namespace Network {
21 22
22class Socket { 23class SocketBase {
23public: 24public:
25#ifdef YUZU_UNIX
26 using SOCKET = int;
27 static constexpr SOCKET INVALID_SOCKET = -1;
28 static constexpr SOCKET SOCKET_ERROR = -1;
29#endif
30
24 struct AcceptResult { 31 struct AcceptResult {
25 std::unique_ptr<Socket> socket; 32 std::unique_ptr<SocketBase> socket;
26 SockAddrIn sockaddr_in; 33 SockAddrIn sockaddr_in;
27 }; 34 };
35 virtual ~SocketBase() = default;
36
37 virtual SocketBase& operator=(const SocketBase&) = delete;
38
39 // Avoid closing sockets implicitly
40 virtual SocketBase& operator=(SocketBase&&) noexcept = delete;
41
42 virtual Errno Initialize(Domain domain, Type type, Protocol protocol) = 0;
43
44 virtual Errno Close() = 0;
45
46 virtual std::pair<AcceptResult, Errno> Accept() = 0;
47
48 virtual Errno Connect(SockAddrIn addr_in) = 0;
49
50 virtual std::pair<SockAddrIn, Errno> GetPeerName() = 0;
51
52 virtual std::pair<SockAddrIn, Errno> GetSockName() = 0;
53
54 virtual Errno Bind(SockAddrIn addr) = 0;
55
56 virtual Errno Listen(s32 backlog) = 0;
57
58 virtual Errno Shutdown(ShutdownHow how) = 0;
59
60 virtual std::pair<s32, Errno> Recv(int flags, std::vector<u8>& message) = 0;
61
62 virtual std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message,
63 SockAddrIn* addr) = 0;
64
65 virtual std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) = 0;
66
67 virtual std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message,
68 const SockAddrIn* addr) = 0;
69
70 virtual Errno SetLinger(bool enable, u32 linger) = 0;
28 71
29 explicit Socket() = default; 72 virtual Errno SetReuseAddr(bool enable) = 0;
30 ~Socket(); 73
74 virtual Errno SetKeepAlive(bool enable) = 0;
75
76 virtual Errno SetBroadcast(bool enable) = 0;
77
78 virtual Errno SetSndBuf(u32 value) = 0;
79
80 virtual Errno SetRcvBuf(u32 value) = 0;
81
82 virtual Errno SetSndTimeo(u32 value) = 0;
83
84 virtual Errno SetRcvTimeo(u32 value) = 0;
85
86 virtual Errno SetNonBlock(bool enable) = 0;
87
88 virtual bool IsOpened() const = 0;
89
90 virtual void HandleProxyPacket(const ProxyPacket& packet) = 0;
91
92 SOCKET fd = INVALID_SOCKET;
93};
94
95class Socket : public SocketBase {
96public:
97 Socket() = default;
98 ~Socket() override;
31 99
32 Socket(const Socket&) = delete; 100 Socket(const Socket&) = delete;
33 Socket& operator=(const Socket&) = delete; 101 Socket& operator=(const Socket&) = delete;
@@ -37,57 +105,57 @@ public:
37 // Avoid closing sockets implicitly 105 // Avoid closing sockets implicitly
38 Socket& operator=(Socket&&) noexcept = delete; 106 Socket& operator=(Socket&&) noexcept = delete;
39 107
40 Errno Initialize(Domain domain, Type type, Protocol protocol); 108 Errno Initialize(Domain domain, Type type, Protocol protocol) override;
41 109
42 Errno Close(); 110 Errno Close() override;
43 111
44 std::pair<AcceptResult, Errno> Accept(); 112 std::pair<AcceptResult, Errno> Accept() override;
45 113
46 Errno Connect(SockAddrIn addr_in); 114 Errno Connect(SockAddrIn addr_in) override;
47 115
48 std::pair<SockAddrIn, Errno> GetPeerName(); 116 std::pair<SockAddrIn, Errno> GetPeerName() override;
49 117
50 std::pair<SockAddrIn, Errno> GetSockName(); 118 std::pair<SockAddrIn, Errno> GetSockName() override;
51 119
52 Errno Bind(SockAddrIn addr); 120 Errno Bind(SockAddrIn addr) override;
53 121
54 Errno Listen(s32 backlog); 122 Errno Listen(s32 backlog) override;
55 123
56 Errno Shutdown(ShutdownHow how); 124 Errno Shutdown(ShutdownHow how) override;
57 125
58 std::pair<s32, Errno> Recv(int flags, std::vector<u8>& message); 126 std::pair<s32, Errno> Recv(int flags, std::vector<u8>& message) override;
59 127
60 std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr); 128 std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) override;
61 129
62 std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags); 130 std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) override;
63 131
64 std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message, const SockAddrIn* addr); 132 std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message,
133 const SockAddrIn* addr) override;
65 134
66 Errno SetLinger(bool enable, u32 linger); 135 Errno SetLinger(bool enable, u32 linger) override;
67 136
68 Errno SetReuseAddr(bool enable); 137 Errno SetReuseAddr(bool enable) override;
69 138
70 Errno SetKeepAlive(bool enable); 139 Errno SetKeepAlive(bool enable) override;
71 140
72 Errno SetBroadcast(bool enable); 141 Errno SetBroadcast(bool enable) override;
73 142
74 Errno SetSndBuf(u32 value); 143 Errno SetSndBuf(u32 value) override;
75 144
76 Errno SetRcvBuf(u32 value); 145 Errno SetRcvBuf(u32 value) override;
77 146
78 Errno SetSndTimeo(u32 value); 147 Errno SetSndTimeo(u32 value) override;
79 148
80 Errno SetRcvTimeo(u32 value); 149 Errno SetRcvTimeo(u32 value) override;
81 150
82 Errno SetNonBlock(bool enable); 151 Errno SetNonBlock(bool enable) override;
83 152
84 bool IsOpened() const; 153 template <typename T>
154 Errno SetSockOpt(SOCKET fd, int option, T value);
85 155
86#if defined(_WIN32) 156 bool IsOpened() const override;
87 SOCKET fd = INVALID_SOCKET; 157
88#elif YUZU_UNIX 158 void HandleProxyPacket(const ProxyPacket& packet) override;
89 int fd = -1;
90#endif
91}; 159};
92 160
93std::pair<s32, Errno> Poll(std::vector<PollFD>& poll_fds, s32 timeout); 161std::pair<s32, Errno> Poll(std::vector<PollFD>& poll_fds, s32 timeout);