mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-27 19:26:52 +00:00
Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2014a57782 | |||
| 6e9f0f22cc | |||
| ec33801c2b | |||
| e9eae6465f | |||
| f85477be83 | |||
| e986b9cfc3 | |||
| 07b1d3dc18 | |||
| 8225eab163 | |||
| 7ad5f0151d | |||
| 67bfb51e70 | |||
| 8fa8d07790 | |||
| e75202a142 | |||
| c64cfab8c4 | |||
| 4d4e72266f | |||
| 8d162b1396 | |||
| 8b12773efa | |||
| 2af067f2dd | |||
| aaa0597eea | |||
| 39fd76edd7 | |||
| bb8efd44ed | |||
| f9209bade4 | |||
| 33656ac087 | |||
| 2c540edb20 | |||
| 7718a3077c | |||
| 5a11bf8d7e | |||
| a076805ca4 | |||
| a418632d4a | |||
| d595a02b56 | |||
| 48cc80d276 | |||
| 1c3657fd9c | |||
| 80a6af639b | |||
| dc88d95e8d | |||
| c0cfd02731 | |||
| c8d514da84 | |||
| 767a0f7ccd | |||
| 538452bb0c | |||
| 487a07ac78 | |||
| 85d7e44712 | |||
| 69685a86bd | |||
| 4c9cfbbd7d | |||
| d82f7e4291 | |||
| d9fd21ab5c | |||
| 1e2fe06834 | |||
| f8e0a62a6c | |||
| 4711730ced | |||
| 7966ec8809 | |||
| 25f56fdf69 | |||
| 8f0cc0922c | |||
| 744668e405 | |||
| 1914cdf463 | |||
| 0d6334af1c | |||
| b87d4537e1 | |||
| 5aaff108f6 | |||
| a4c469c984 | |||
| 58d6833b8e | |||
| 4141b4148a | |||
| f52339bcbb | |||
| f82682b1a6 | |||
| 2a3823b4ae | |||
| 02c7b30cc1 | |||
| 9a08b5ca7d | |||
| 8bec8954c5 | |||
| 967b27b9c5 |
@@ -333,11 +333,6 @@
|
|||||||
"repo": "herumi/xbyak",
|
"repo": "herumi/xbyak",
|
||||||
"version": "v7.40.1"
|
"version": "v7.40.1"
|
||||||
},
|
},
|
||||||
"zbic": {
|
|
||||||
"hash": "fbe2f37986377d7f0d96ae3224c80b5971df6e8b6961f68061f1975ebb2e8cb78f07b90f014b007be4023dbf5513581504e7f7d61a5237cb2a8a7a61ae11e482",
|
|
||||||
"repo": "kinnay/zbic",
|
|
||||||
"version": "11b08f2712264bbed731545085cbd9702096ceb7"
|
|
||||||
},
|
|
||||||
"zlib": {
|
"zlib": {
|
||||||
"hash": "16fea4df307a68cf0035858abe2fd550250618a97590e202037acd18a666f57afc10f8836cbbd472d54a0e76539d0e558cb26f059d53de52ff90634bbf4f47d4",
|
"hash": "16fea4df307a68cf0035858abe2fd550250618a97590e202037acd18a666f57afc10f8836cbbd472d54a0e76539d0e558cb26f059d53de52ff90634bbf4f47d4",
|
||||||
"min_version": "1.2",
|
"min_version": "1.2",
|
||||||
|
|||||||
Vendored
-5
@@ -48,11 +48,6 @@ if (NOT TARGET stb::headers)
|
|||||||
add_library(stb::headers ALIAS stb)
|
add_library(stb::headers ALIAS stb)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
AddJsonPackage(NAME zbic DOWNLOAD_ONLY)
|
|
||||||
set(ZBIC_INCLUDE_DIR
|
|
||||||
"${zbic_SOURCE_DIR}/src"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
|
|
||||||
# ItaniumDemangle (Windows only)
|
# ItaniumDemangle (Windows only)
|
||||||
if (WIN32 AND NOT TARGET LLVM::Demangle)
|
if (WIN32 AND NOT TARGET LLVM::Demangle)
|
||||||
add_library(demangle demangle/ItaniumDemangle.cpp)
|
add_library(demangle demangle/ItaniumDemangle.cpp)
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ add_library(
|
|||||||
fs/fs_util.h
|
fs/fs_util.h
|
||||||
fs/path_util.cpp
|
fs/path_util.cpp
|
||||||
fs/path_util.h
|
fs/path_util.h
|
||||||
|
hash.h
|
||||||
heap_tracker.cpp
|
heap_tracker.cpp
|
||||||
heap_tracker.h
|
heap_tracker.h
|
||||||
hex_util.cpp
|
hex_util.cpp
|
||||||
@@ -105,7 +106,6 @@ add_library(
|
|||||||
settings_input.h
|
settings_input.h
|
||||||
settings_setting.h
|
settings_setting.h
|
||||||
slot_vector.h
|
slot_vector.h
|
||||||
socket_types.h
|
|
||||||
sparse_large_vector.cpp
|
sparse_large_vector.cpp
|
||||||
sparse_large_vector.h
|
sparse_large_vector.h
|
||||||
stb.cpp
|
stb.cpp
|
||||||
@@ -136,8 +136,6 @@ add_library(
|
|||||||
uuid.cpp
|
uuid.cpp
|
||||||
uuid.h
|
uuid.h
|
||||||
vector_math.h
|
vector_math.h
|
||||||
zbic_compression.cpp
|
|
||||||
zbic_compression.h
|
|
||||||
zstd_compression.cpp
|
zstd_compression.cpp
|
||||||
zstd_compression.h
|
zstd_compression.h
|
||||||
fs/ryujinx_compat.h fs/ryujinx_compat.cpp
|
fs/ryujinx_compat.h fs/ryujinx_compat.cpp
|
||||||
@@ -148,10 +146,6 @@ add_library(
|
|||||||
net/net.h net/net.cpp
|
net/net.h net/net.cpp
|
||||||
container/unordered_map.h container/unordered_set.h)
|
container/unordered_map.h container/unordered_set.h)
|
||||||
|
|
||||||
set_source_files_properties(zbic_compression.cpp PROPERTIES
|
|
||||||
INCLUDE_DIRECTORIES "${ZBIC_INCLUDE_DIR}"
|
|
||||||
COMPILE_OPTIONS "$<$<CXX_COMPILER_ID:Clang,GNU>:-Wno-unused-function;-Wno-missing-declarations;-Wno-shadow>")
|
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_sources(common PRIVATE windows/timer_resolution.cpp
|
target_sources(common PRIVATE windows/timer_resolution.cpp
|
||||||
windows/timer_resolution.h)
|
windows/timer_resolution.h)
|
||||||
|
|||||||
+251
-252
@@ -12,94 +12,93 @@
|
|||||||
#include "common/android/multiplayer/multiplayer.h"
|
#include "common/android/multiplayer/multiplayer.h"
|
||||||
#include <network/network.h>
|
#include <network/network.h>
|
||||||
|
|
||||||
static struct {
|
|
||||||
JavaVM *java_vm;
|
|
||||||
jclass native_library_class;
|
|
||||||
jclass disk_cache_progress_class;
|
|
||||||
jclass load_callback_stage_class;
|
|
||||||
jclass game_dir_class;
|
|
||||||
jmethodID game_dir_constructor;
|
|
||||||
jmethodID exit_emulation_activity;
|
|
||||||
jmethodID disk_cache_load_progress;
|
|
||||||
jmethodID on_emulation_started;
|
|
||||||
jmethodID on_emulation_stopped;
|
|
||||||
jmethodID on_program_changed;
|
|
||||||
jmethodID copy_to_storage;
|
|
||||||
jmethodID file_exists;
|
|
||||||
jmethodID file_extension;
|
|
||||||
|
|
||||||
jclass game_class;
|
static JavaVM *s_java_vm;
|
||||||
jmethodID game_constructor;
|
static jclass s_native_library_class;
|
||||||
jfieldID game_title_field;
|
static jclass s_disk_cache_progress_class;
|
||||||
jfieldID game_path_field;
|
static jclass s_load_callback_stage_class;
|
||||||
jfieldID game_program_id_field;
|
static jclass s_game_dir_class;
|
||||||
jfieldID game_developer_field;
|
static jmethodID s_game_dir_constructor;
|
||||||
jfieldID game_version_field;
|
static jmethodID s_exit_emulation_activity;
|
||||||
jfieldID game_is_homebrew_field;
|
static jmethodID s_disk_cache_load_progress;
|
||||||
|
static jmethodID s_on_emulation_started;
|
||||||
|
static jmethodID s_on_emulation_stopped;
|
||||||
|
static jmethodID s_on_program_changed;
|
||||||
|
static jmethodID s_copy_to_storage;
|
||||||
|
static jmethodID s_file_exists;
|
||||||
|
static jmethodID s_file_extension;
|
||||||
|
|
||||||
jclass string_class;
|
static jclass s_game_class;
|
||||||
jclass pair_class;
|
static jmethodID s_game_constructor;
|
||||||
jmethodID pair_constructor;
|
static jfieldID s_game_title_field;
|
||||||
jfieldID pair_first_field;
|
static jfieldID s_game_path_field;
|
||||||
jfieldID pair_second_field;
|
static jfieldID s_game_program_id_field;
|
||||||
|
static jfieldID s_game_developer_field;
|
||||||
|
static jfieldID s_game_version_field;
|
||||||
|
static jfieldID s_game_is_homebrew_field;
|
||||||
|
|
||||||
jclass overlay_control_data_class;
|
static jclass s_string_class;
|
||||||
jmethodID overlay_control_data_constructor;
|
static jclass s_pair_class;
|
||||||
jfieldID overlay_control_data_id_field;
|
static jmethodID s_pair_constructor;
|
||||||
jfieldID overlay_control_data_enabled_field;
|
static jfieldID s_pair_first_field;
|
||||||
jfieldID overlay_control_data_individual_scale_field;
|
static jfieldID s_pair_second_field;
|
||||||
jfieldID overlay_control_data_landscape_position_field;
|
|
||||||
jfieldID overlay_control_data_portrait_position_field;
|
|
||||||
jfieldID overlay_control_data_foldable_position_field;
|
|
||||||
|
|
||||||
jclass patch_class;
|
static jclass s_overlay_control_data_class;
|
||||||
jmethodID patch_constructor;
|
static jmethodID s_overlay_control_data_constructor;
|
||||||
jfieldID patch_enabled_field;
|
static jfieldID s_overlay_control_data_id_field;
|
||||||
jfieldID patch_name_field;
|
static jfieldID s_overlay_control_data_enabled_field;
|
||||||
jfieldID patch_version_field;
|
static jfieldID s_overlay_control_data_individual_scale_field;
|
||||||
jfieldID patch_type_field;
|
static jfieldID s_overlay_control_data_landscape_position_field;
|
||||||
jfieldID patch_program_id_field;
|
static jfieldID s_overlay_control_data_portrait_position_field;
|
||||||
jfieldID patch_title_id_field;
|
static jfieldID s_overlay_control_data_foldable_position_field;
|
||||||
|
|
||||||
jclass double_class;
|
static jclass s_patch_class;
|
||||||
jmethodID double_constructor;
|
static jmethodID s_patch_constructor;
|
||||||
jmethodID double_value_method;
|
static jfieldID s_patch_enabled_field;
|
||||||
|
static jfieldID s_patch_name_field;
|
||||||
|
static jfieldID s_patch_version_field;
|
||||||
|
static jfieldID s_patch_type_field;
|
||||||
|
static jfieldID s_patch_program_id_field;
|
||||||
|
static jfieldID s_patch_title_id_field;
|
||||||
|
|
||||||
jclass integer_class;
|
static jclass s_double_class;
|
||||||
jmethodID integer_constructor;
|
static jmethodID s_double_constructor;
|
||||||
jmethodID integer_value_method;
|
static jmethodID s_double_value_method;
|
||||||
|
|
||||||
jclass boolean_class;
|
static jclass s_integer_class;
|
||||||
jmethodID boolean_constructor;
|
static jmethodID s_integer_constructor;
|
||||||
jmethodID boolean_value_method;
|
static jmethodID s_integer_value_method;
|
||||||
|
|
||||||
jclass player_input_class;
|
static jclass s_boolean_class;
|
||||||
jmethodID player_input_constructor;
|
static jmethodID s_boolean_constructor;
|
||||||
jfieldID player_input_connected_field;
|
static jmethodID s_boolean_value_method;
|
||||||
jfieldID player_input_buttons_field;
|
|
||||||
jfieldID player_input_analogs_field;
|
|
||||||
jfieldID player_input_motions_field;
|
|
||||||
jfieldID player_input_vibration_enabled_field;
|
|
||||||
jfieldID player_input_vibration_strength_field;
|
|
||||||
jfieldID player_input_body_color_left_field;
|
|
||||||
jfieldID player_input_body_color_right_field;
|
|
||||||
jfieldID player_input_button_color_left_field;
|
|
||||||
jfieldID player_input_button_color_right_field;
|
|
||||||
jfieldID player_input_profile_name_field;
|
|
||||||
jfieldID player_input_use_system_vibrator_field;
|
|
||||||
|
|
||||||
jclass yuzu_input_device_interface;
|
static jclass s_player_input_class;
|
||||||
jmethodID yuzu_input_device_get_name;
|
static jmethodID s_player_input_constructor;
|
||||||
jmethodID yuzu_input_device_get_guid;
|
static jfieldID s_player_input_connected_field;
|
||||||
jmethodID yuzu_input_device_get_port;
|
static jfieldID s_player_input_buttons_field;
|
||||||
jmethodID yuzu_input_device_get_supports_vibration;
|
static jfieldID s_player_input_analogs_field;
|
||||||
jmethodID yuzu_input_device_vibrate;
|
static jfieldID s_player_input_motions_field;
|
||||||
jmethodID yuzu_input_device_get_axes;
|
static jfieldID s_player_input_vibration_enabled_field;
|
||||||
jmethodID yuzu_input_device_has_keys;
|
static jfieldID s_player_input_vibration_strength_field;
|
||||||
|
static jfieldID s_player_input_body_color_left_field;
|
||||||
|
static jfieldID s_player_input_body_color_right_field;
|
||||||
|
static jfieldID s_player_input_button_color_left_field;
|
||||||
|
static jfieldID s_player_input_button_color_right_field;
|
||||||
|
static jfieldID s_player_input_profile_name_field;
|
||||||
|
static jfieldID s_player_input_use_system_vibrator_field;
|
||||||
|
|
||||||
jmethodID add_netplay_message;
|
static jclass s_yuzu_input_device_interface;
|
||||||
jmethodID clear_chat;
|
static jmethodID s_yuzu_input_device_get_name;
|
||||||
} state;
|
static jmethodID s_yuzu_input_device_get_guid;
|
||||||
|
static jmethodID s_yuzu_input_device_get_port;
|
||||||
|
static jmethodID s_yuzu_input_device_get_supports_vibration;
|
||||||
|
static jmethodID s_yuzu_input_device_vibrate;
|
||||||
|
static jmethodID s_yuzu_input_device_get_axes;
|
||||||
|
static jmethodID s_yuzu_input_device_has_keys;
|
||||||
|
|
||||||
|
static jmethodID s_add_netplay_message;
|
||||||
|
static jmethodID s_clear_chat;
|
||||||
|
|
||||||
static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
|
static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
|
||||||
|
|
||||||
@@ -107,14 +106,14 @@ namespace Common::Android {
|
|||||||
JNIEnv *GetEnvForThread() {
|
JNIEnv *GetEnvForThread() {
|
||||||
thread_local static struct OwnedEnv {
|
thread_local static struct OwnedEnv {
|
||||||
OwnedEnv() {
|
OwnedEnv() {
|
||||||
status = state.java_vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
|
status = s_java_vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
|
||||||
if (status == JNI_EDETACHED)
|
if (status == JNI_EDETACHED)
|
||||||
state.java_vm->AttachCurrentThread(&env, nullptr);
|
s_java_vm->AttachCurrentThread(&env, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
~OwnedEnv() {
|
~OwnedEnv() {
|
||||||
if (status == JNI_EDETACHED)
|
if (status == JNI_EDETACHED)
|
||||||
state.java_vm->DetachCurrentThread();
|
s_java_vm->DetachCurrentThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
int status;
|
int status;
|
||||||
@@ -124,303 +123,303 @@ namespace Common::Android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
jclass GetNativeLibraryClass() {
|
jclass GetNativeLibraryClass() {
|
||||||
return state.native_library_class;
|
return s_native_library_class;
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass GetDiskCacheProgressClass() {
|
jclass GetDiskCacheProgressClass() {
|
||||||
return state.disk_cache_progress_class;
|
return s_disk_cache_progress_class;
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass GetDiskCacheLoadCallbackStageClass() {
|
jclass GetDiskCacheLoadCallbackStageClass() {
|
||||||
return state.load_callback_stage_class;
|
return s_load_callback_stage_class;
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass GetGameDirClass() {
|
jclass GetGameDirClass() {
|
||||||
return state.game_dir_class;
|
return s_game_dir_class;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetGameDirConstructor() {
|
jmethodID GetGameDirConstructor() {
|
||||||
return state.game_dir_constructor;
|
return s_game_dir_constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetExitEmulationActivity() {
|
jmethodID GetExitEmulationActivity() {
|
||||||
return state.exit_emulation_activity;
|
return s_exit_emulation_activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetDiskCacheLoadProgress() {
|
jmethodID GetDiskCacheLoadProgress() {
|
||||||
return state.disk_cache_load_progress;
|
return s_disk_cache_load_progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetCopyToStorage() {
|
jmethodID GetCopyToStorage() {
|
||||||
return state.copy_to_storage;
|
return s_copy_to_storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetFileExists() {
|
jmethodID GetFileExists() {
|
||||||
return state.file_exists;
|
return s_file_exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetFileExtension() {
|
jmethodID GetFileExtension() {
|
||||||
return state.file_extension;
|
return s_file_extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetOnEmulationStarted() {
|
jmethodID GetOnEmulationStarted() {
|
||||||
return state.on_emulation_started;
|
return s_on_emulation_started;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetOnEmulationStopped() {
|
jmethodID GetOnEmulationStopped() {
|
||||||
return state.on_emulation_stopped;
|
return s_on_emulation_stopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetOnProgramChanged() {
|
jmethodID GetOnProgramChanged() {
|
||||||
return state.on_program_changed;
|
return s_on_program_changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass GetGameClass() {
|
jclass GetGameClass() {
|
||||||
return state.game_class;
|
return s_game_class;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetGameConstructor() {
|
jmethodID GetGameConstructor() {
|
||||||
return state.game_constructor;
|
return s_game_constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetGameTitleField() {
|
jfieldID GetGameTitleField() {
|
||||||
return state.game_title_field;
|
return s_game_title_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetGamePathField() {
|
jfieldID GetGamePathField() {
|
||||||
return state.game_path_field;
|
return s_game_path_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetGameProgramIdField() {
|
jfieldID GetGameProgramIdField() {
|
||||||
return state.game_program_id_field;
|
return s_game_program_id_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetGameDeveloperField() {
|
jfieldID GetGameDeveloperField() {
|
||||||
return state.game_developer_field;
|
return s_game_developer_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetGameVersionField() {
|
jfieldID GetGameVersionField() {
|
||||||
return state.game_version_field;
|
return s_game_version_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetGameIsHomebrewField() {
|
jfieldID GetGameIsHomebrewField() {
|
||||||
return state.game_is_homebrew_field;
|
return s_game_is_homebrew_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass GetStringClass() {
|
jclass GetStringClass() {
|
||||||
return state.string_class;
|
return s_string_class;
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass GetPairClass() {
|
jclass GetPairClass() {
|
||||||
return state.pair_class;
|
return s_pair_class;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetPairConstructor() {
|
jmethodID GetPairConstructor() {
|
||||||
return state.pair_constructor;
|
return s_pair_constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPairFirstField() {
|
jfieldID GetPairFirstField() {
|
||||||
return state.pair_first_field;
|
return s_pair_first_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPairSecondField() {
|
jfieldID GetPairSecondField() {
|
||||||
return state.pair_second_field;
|
return s_pair_second_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass GetOverlayControlDataClass() {
|
jclass GetOverlayControlDataClass() {
|
||||||
return state.overlay_control_data_class;
|
return s_overlay_control_data_class;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetOverlayControlDataConstructor() {
|
jmethodID GetOverlayControlDataConstructor() {
|
||||||
return state.overlay_control_data_constructor;
|
return s_overlay_control_data_constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetOverlayControlDataIdField() {
|
jfieldID GetOverlayControlDataIdField() {
|
||||||
return state.overlay_control_data_id_field;
|
return s_overlay_control_data_id_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetOverlayControlDataEnabledField() {
|
jfieldID GetOverlayControlDataEnabledField() {
|
||||||
return state.overlay_control_data_enabled_field;
|
return s_overlay_control_data_enabled_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetOverlayControlDataIndividualScaleField() {
|
jfieldID GetOverlayControlDataIndividualScaleField() {
|
||||||
return state.overlay_control_data_individual_scale_field;
|
return s_overlay_control_data_individual_scale_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetOverlayControlDataLandscapePositionField() {
|
jfieldID GetOverlayControlDataLandscapePositionField() {
|
||||||
return state.overlay_control_data_landscape_position_field;
|
return s_overlay_control_data_landscape_position_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetOverlayControlDataPortraitPositionField() {
|
jfieldID GetOverlayControlDataPortraitPositionField() {
|
||||||
return state.overlay_control_data_portrait_position_field;
|
return s_overlay_control_data_portrait_position_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetOverlayControlDataFoldablePositionField() {
|
jfieldID GetOverlayControlDataFoldablePositionField() {
|
||||||
return state.overlay_control_data_foldable_position_field;
|
return s_overlay_control_data_foldable_position_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass GetPatchClass() {
|
jclass GetPatchClass() {
|
||||||
return state.patch_class;
|
return s_patch_class;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetPatchConstructor() {
|
jmethodID GetPatchConstructor() {
|
||||||
return state.patch_constructor;
|
return s_patch_constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPatchEnabledField() {
|
jfieldID GetPatchEnabledField() {
|
||||||
return state.patch_enabled_field;
|
return s_patch_enabled_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPatchNameField() {
|
jfieldID GetPatchNameField() {
|
||||||
return state.patch_name_field;
|
return s_patch_name_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPatchVersionField() {
|
jfieldID GetPatchVersionField() {
|
||||||
return state.patch_version_field;
|
return s_patch_version_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPatchTypeField() {
|
jfieldID GetPatchTypeField() {
|
||||||
return state.patch_type_field;
|
return s_patch_type_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPatchProgramIdField() {
|
jfieldID GetPatchProgramIdField() {
|
||||||
return state.patch_program_id_field;
|
return s_patch_program_id_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPatchTitleIdField() {
|
jfieldID GetPatchTitleIdField() {
|
||||||
return state.patch_title_id_field;
|
return s_patch_title_id_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass GetDoubleClass() {
|
jclass GetDoubleClass() {
|
||||||
return state.double_class;
|
return s_double_class;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetDoubleConstructor() {
|
jmethodID GetDoubleConstructor() {
|
||||||
return state.double_constructor;
|
return s_double_constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetDoubleValueMethod() {
|
jmethodID GetDoubleValueMethod() {
|
||||||
return state.double_value_method;
|
return s_double_value_method;
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass GetIntegerClass() {
|
jclass GetIntegerClass() {
|
||||||
return state.integer_class;
|
return s_integer_class;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetIntegerConstructor() {
|
jmethodID GetIntegerConstructor() {
|
||||||
return state.integer_constructor;
|
return s_integer_constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetIntegerValueMethod() {
|
jmethodID GetIntegerValueMethod() {
|
||||||
return state.integer_value_method;
|
return s_integer_value_method;
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass GetBooleanClass() {
|
jclass GetBooleanClass() {
|
||||||
return state.boolean_class;
|
return s_boolean_class;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetBooleanConstructor() {
|
jmethodID GetBooleanConstructor() {
|
||||||
return state.boolean_constructor;
|
return s_boolean_constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetBooleanValueMethod() {
|
jmethodID GetBooleanValueMethod() {
|
||||||
return state.boolean_value_method;
|
return s_boolean_value_method;
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass GetPlayerInputClass() {
|
jclass GetPlayerInputClass() {
|
||||||
return state.player_input_class;
|
return s_player_input_class;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetPlayerInputConstructor() {
|
jmethodID GetPlayerInputConstructor() {
|
||||||
return state.player_input_constructor;
|
return s_player_input_constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPlayerInputConnectedField() {
|
jfieldID GetPlayerInputConnectedField() {
|
||||||
return state.player_input_connected_field;
|
return s_player_input_connected_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPlayerInputButtonsField() {
|
jfieldID GetPlayerInputButtonsField() {
|
||||||
return state.player_input_buttons_field;
|
return s_player_input_buttons_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPlayerInputAnalogsField() {
|
jfieldID GetPlayerInputAnalogsField() {
|
||||||
return state.player_input_analogs_field;
|
return s_player_input_analogs_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPlayerInputMotionsField() {
|
jfieldID GetPlayerInputMotionsField() {
|
||||||
return state.player_input_motions_field;
|
return s_player_input_motions_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPlayerInputVibrationEnabledField() {
|
jfieldID GetPlayerInputVibrationEnabledField() {
|
||||||
return state.player_input_vibration_enabled_field;
|
return s_player_input_vibration_enabled_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPlayerInputVibrationStrengthField() {
|
jfieldID GetPlayerInputVibrationStrengthField() {
|
||||||
return state.player_input_vibration_strength_field;
|
return s_player_input_vibration_strength_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPlayerInputBodyColorLeftField() {
|
jfieldID GetPlayerInputBodyColorLeftField() {
|
||||||
return state.player_input_body_color_left_field;
|
return s_player_input_body_color_left_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPlayerInputBodyColorRightField() {
|
jfieldID GetPlayerInputBodyColorRightField() {
|
||||||
return state.player_input_body_color_right_field;
|
return s_player_input_body_color_right_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPlayerInputButtonColorLeftField() {
|
jfieldID GetPlayerInputButtonColorLeftField() {
|
||||||
return state.player_input_button_color_left_field;
|
return s_player_input_button_color_left_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPlayerInputButtonColorRightField() {
|
jfieldID GetPlayerInputButtonColorRightField() {
|
||||||
return state.player_input_button_color_right_field;
|
return s_player_input_button_color_right_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPlayerInputProfileNameField() {
|
jfieldID GetPlayerInputProfileNameField() {
|
||||||
return state.player_input_profile_name_field;
|
return s_player_input_profile_name_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetPlayerInputUseSystemVibratorField() {
|
jfieldID GetPlayerInputUseSystemVibratorField() {
|
||||||
return state.player_input_use_system_vibrator_field;
|
return s_player_input_use_system_vibrator_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass GetYuzuInputDeviceInterface() {
|
jclass GetYuzuInputDeviceInterface() {
|
||||||
return state.yuzu_input_device_interface;
|
return s_yuzu_input_device_interface;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetYuzuDeviceGetName() {
|
jmethodID GetYuzuDeviceGetName() {
|
||||||
return state.yuzu_input_device_get_name;
|
return s_yuzu_input_device_get_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetYuzuDeviceGetGUID() {
|
jmethodID GetYuzuDeviceGetGUID() {
|
||||||
return state.yuzu_input_device_get_guid;
|
return s_yuzu_input_device_get_guid;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetYuzuDeviceGetPort() {
|
jmethodID GetYuzuDeviceGetPort() {
|
||||||
return state.yuzu_input_device_get_port;
|
return s_yuzu_input_device_get_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetYuzuDeviceGetSupportsVibration() {
|
jmethodID GetYuzuDeviceGetSupportsVibration() {
|
||||||
return state.yuzu_input_device_get_supports_vibration;
|
return s_yuzu_input_device_get_supports_vibration;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetYuzuDeviceVibrate() {
|
jmethodID GetYuzuDeviceVibrate() {
|
||||||
return state.yuzu_input_device_vibrate;
|
return s_yuzu_input_device_vibrate;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetYuzuDeviceGetAxes() {
|
jmethodID GetYuzuDeviceGetAxes() {
|
||||||
return state.yuzu_input_device_get_axes;
|
return s_yuzu_input_device_get_axes;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetYuzuDeviceHasKeys() {
|
jmethodID GetYuzuDeviceHasKeys() {
|
||||||
return state.yuzu_input_device_has_keys;
|
return s_yuzu_input_device_has_keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetAddNetPlayMessage() {
|
jmethodID GetAddNetPlayMessage() {
|
||||||
return state.add_netplay_message;
|
return s_add_netplay_message;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID ClearChat() {
|
jmethodID ClearChat() {
|
||||||
return state.clear_chat;
|
return s_clear_chat;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@@ -437,20 +436,20 @@ namespace Common::Android {
|
|||||||
|
|
||||||
// UnInitialize Android Storage
|
// UnInitialize Android Storage
|
||||||
Common::FS::Android::UnRegisterCallbacks();
|
Common::FS::Android::UnRegisterCallbacks();
|
||||||
env->DeleteGlobalRef(state.native_library_class);
|
env->DeleteGlobalRef(s_native_library_class);
|
||||||
env->DeleteGlobalRef(state.disk_cache_progress_class);
|
env->DeleteGlobalRef(s_disk_cache_progress_class);
|
||||||
env->DeleteGlobalRef(state.load_callback_stage_class);
|
env->DeleteGlobalRef(s_load_callback_stage_class);
|
||||||
env->DeleteGlobalRef(state.game_dir_class);
|
env->DeleteGlobalRef(s_game_dir_class);
|
||||||
env->DeleteGlobalRef(state.game_class);
|
env->DeleteGlobalRef(s_game_class);
|
||||||
env->DeleteGlobalRef(state.string_class);
|
env->DeleteGlobalRef(s_string_class);
|
||||||
env->DeleteGlobalRef(state.pair_class);
|
env->DeleteGlobalRef(s_pair_class);
|
||||||
env->DeleteGlobalRef(state.overlay_control_data_class);
|
env->DeleteGlobalRef(s_overlay_control_data_class);
|
||||||
env->DeleteGlobalRef(state.patch_class);
|
env->DeleteGlobalRef(s_patch_class);
|
||||||
env->DeleteGlobalRef(state.double_class);
|
env->DeleteGlobalRef(s_double_class);
|
||||||
env->DeleteGlobalRef(state.integer_class);
|
env->DeleteGlobalRef(s_integer_class);
|
||||||
env->DeleteGlobalRef(state.boolean_class);
|
env->DeleteGlobalRef(s_boolean_class);
|
||||||
env->DeleteGlobalRef(state.player_input_class);
|
env->DeleteGlobalRef(s_player_input_class);
|
||||||
env->DeleteGlobalRef(state.yuzu_input_device_interface);
|
env->DeleteGlobalRef(s_yuzu_input_device_interface);
|
||||||
|
|
||||||
// UnInitialize applets
|
// UnInitialize applets
|
||||||
SoftwareKeyboard::CleanupJNI(env);
|
SoftwareKeyboard::CleanupJNI(env);
|
||||||
@@ -464,7 +463,7 @@ namespace Common::Android {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void Initialize(JavaVM* vm, JNIEnv *env) {
|
void Initialize(JavaVM* vm, JNIEnv *env) {
|
||||||
state.java_vm = vm;
|
s_java_vm = vm;
|
||||||
InitFFmpegOnLoad(vm);
|
InitFFmpegOnLoad(vm);
|
||||||
|
|
||||||
if (env->ExceptionCheck()) {
|
if (env->ExceptionCheck()) {
|
||||||
@@ -473,169 +472,169 @@ void Initialize(JavaVM* vm, JNIEnv *env) {
|
|||||||
|
|
||||||
// Initialize Java classes
|
// Initialize Java classes
|
||||||
const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary");
|
const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary");
|
||||||
state.native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class));
|
s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class));
|
||||||
state.disk_cache_progress_class = reinterpret_cast<jclass>(env->NewGlobalRef(
|
s_disk_cache_progress_class = reinterpret_cast<jclass>(env->NewGlobalRef(
|
||||||
env->FindClass("org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress")));
|
env->FindClass("org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress")));
|
||||||
state.load_callback_stage_class = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass(
|
s_load_callback_stage_class = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass(
|
||||||
"org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage")));
|
"org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage")));
|
||||||
|
|
||||||
const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir");
|
const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir");
|
||||||
state.game_dir_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_dir_class));
|
s_game_dir_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_dir_class));
|
||||||
state.game_dir_constructor = env->GetMethodID(game_dir_class, "<init>",
|
s_game_dir_constructor = env->GetMethodID(game_dir_class, "<init>",
|
||||||
"(Ljava/lang/String;Z)V");
|
"(Ljava/lang/String;Z)V");
|
||||||
env->DeleteLocalRef(game_dir_class);
|
env->DeleteLocalRef(game_dir_class);
|
||||||
|
|
||||||
// Initialize methods
|
// Initialize methods
|
||||||
state.exit_emulation_activity =
|
s_exit_emulation_activity =
|
||||||
env->GetStaticMethodID(state.native_library_class, "exitEmulationActivity", "(I)V");
|
env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V");
|
||||||
state.disk_cache_load_progress =
|
s_disk_cache_load_progress =
|
||||||
env->GetStaticMethodID(state.disk_cache_progress_class, "loadProgress", "(III)V");
|
env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V");
|
||||||
state.copy_to_storage = env->GetStaticMethodID(state.native_library_class, "copyFileToStorage",
|
s_copy_to_storage = env->GetStaticMethodID(s_native_library_class, "copyFileToStorage",
|
||||||
"(Ljava/lang/String;Ljava/lang/String;)Z");
|
"(Ljava/lang/String;Ljava/lang/String;)Z");
|
||||||
state.file_exists = env->GetStaticMethodID(state.native_library_class, "exists",
|
s_file_exists = env->GetStaticMethodID(s_native_library_class, "exists",
|
||||||
"(Ljava/lang/String;)Z");
|
"(Ljava/lang/String;)Z");
|
||||||
state.file_extension = env->GetStaticMethodID(state.native_library_class, "getFileExtension",
|
s_file_extension = env->GetStaticMethodID(s_native_library_class, "getFileExtension",
|
||||||
"(Ljava/lang/String;)Ljava/lang/String;");
|
"(Ljava/lang/String;)Ljava/lang/String;");
|
||||||
state.on_emulation_started =
|
s_on_emulation_started =
|
||||||
env->GetStaticMethodID(state.native_library_class, "onEmulationStarted", "()V");
|
env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V");
|
||||||
state.on_emulation_stopped =
|
s_on_emulation_stopped =
|
||||||
env->GetStaticMethodID(state.native_library_class, "onEmulationStopped", "(I)V");
|
env->GetStaticMethodID(s_native_library_class, "onEmulationStopped", "(I)V");
|
||||||
state.on_program_changed =
|
s_on_program_changed =
|
||||||
env->GetStaticMethodID(state.native_library_class, "onProgramChanged", "(I)V");
|
env->GetStaticMethodID(s_native_library_class, "onProgramChanged", "(I)V");
|
||||||
|
|
||||||
const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game");
|
const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game");
|
||||||
state.game_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_class));
|
s_game_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_class));
|
||||||
state.game_constructor = env->GetMethodID(game_class, "<init>",
|
s_game_constructor = env->GetMethodID(game_class, "<init>",
|
||||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
|
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
|
||||||
"String;Ljava/lang/String;Ljava/lang/String;Z)V");
|
"String;Ljava/lang/String;Ljava/lang/String;Z)V");
|
||||||
state.game_title_field = env->GetFieldID(game_class, "title", "Ljava/lang/String;");
|
s_game_title_field = env->GetFieldID(game_class, "title", "Ljava/lang/String;");
|
||||||
state.game_path_field = env->GetFieldID(game_class, "path", "Ljava/lang/String;");
|
s_game_path_field = env->GetFieldID(game_class, "path", "Ljava/lang/String;");
|
||||||
state.game_program_id_field = env->GetFieldID(game_class, "programId", "Ljava/lang/String;");
|
s_game_program_id_field = env->GetFieldID(game_class, "programId", "Ljava/lang/String;");
|
||||||
state.game_developer_field = env->GetFieldID(game_class, "developer", "Ljava/lang/String;");
|
s_game_developer_field = env->GetFieldID(game_class, "developer", "Ljava/lang/String;");
|
||||||
state.game_version_field = env->GetFieldID(game_class, "version", "Ljava/lang/String;");
|
s_game_version_field = env->GetFieldID(game_class, "version", "Ljava/lang/String;");
|
||||||
state.game_is_homebrew_field = env->GetFieldID(game_class, "isHomebrew", "Z");
|
s_game_is_homebrew_field = env->GetFieldID(game_class, "isHomebrew", "Z");
|
||||||
env->DeleteLocalRef(game_class);
|
env->DeleteLocalRef(game_class);
|
||||||
|
|
||||||
const jclass string_class = env->FindClass("java/lang/String");
|
const jclass string_class = env->FindClass("java/lang/String");
|
||||||
state.string_class = reinterpret_cast<jclass>(env->NewGlobalRef(string_class));
|
s_string_class = reinterpret_cast<jclass>(env->NewGlobalRef(string_class));
|
||||||
env->DeleteLocalRef(string_class);
|
env->DeleteLocalRef(string_class);
|
||||||
|
|
||||||
const jclass pair_class = env->FindClass("kotlin/Pair");
|
const jclass pair_class = env->FindClass("kotlin/Pair");
|
||||||
state.pair_class = reinterpret_cast<jclass>(env->NewGlobalRef(pair_class));
|
s_pair_class = reinterpret_cast<jclass>(env->NewGlobalRef(pair_class));
|
||||||
state.pair_constructor =
|
s_pair_constructor =
|
||||||
env->GetMethodID(pair_class, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");
|
env->GetMethodID(pair_class, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");
|
||||||
state.pair_first_field = env->GetFieldID(pair_class, "first", "Ljava/lang/Object;");
|
s_pair_first_field = env->GetFieldID(pair_class, "first", "Ljava/lang/Object;");
|
||||||
state.pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;");
|
s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;");
|
||||||
env->DeleteLocalRef(pair_class);
|
env->DeleteLocalRef(pair_class);
|
||||||
|
|
||||||
const jclass overlay_control_data_class =
|
const jclass overlay_control_data_class =
|
||||||
env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData");
|
env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData");
|
||||||
state.overlay_control_data_class =
|
s_overlay_control_data_class =
|
||||||
reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class));
|
reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class));
|
||||||
state.overlay_control_data_constructor =
|
s_overlay_control_data_constructor =
|
||||||
env->GetMethodID(overlay_control_data_class, "<init>",
|
env->GetMethodID(overlay_control_data_class, "<init>",
|
||||||
"(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;F)V");
|
"(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;F)V");
|
||||||
state.overlay_control_data_id_field =
|
s_overlay_control_data_id_field =
|
||||||
env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;");
|
env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;");
|
||||||
state.overlay_control_data_enabled_field =
|
s_overlay_control_data_enabled_field =
|
||||||
env->GetFieldID(overlay_control_data_class, "enabled", "Z");
|
env->GetFieldID(overlay_control_data_class, "enabled", "Z");
|
||||||
state.overlay_control_data_landscape_position_field =
|
s_overlay_control_data_landscape_position_field =
|
||||||
env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;");
|
env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;");
|
||||||
state.overlay_control_data_portrait_position_field =
|
s_overlay_control_data_portrait_position_field =
|
||||||
env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;");
|
env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;");
|
||||||
state.overlay_control_data_foldable_position_field =
|
s_overlay_control_data_foldable_position_field =
|
||||||
env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;");
|
env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;");
|
||||||
state.overlay_control_data_individual_scale_field =
|
s_overlay_control_data_individual_scale_field =
|
||||||
env->GetFieldID(overlay_control_data_class, "individualScale", "F");
|
env->GetFieldID(overlay_control_data_class, "individualScale", "F");
|
||||||
env->DeleteLocalRef(overlay_control_data_class);
|
env->DeleteLocalRef(overlay_control_data_class);
|
||||||
|
|
||||||
const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch");
|
const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch");
|
||||||
state.patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class));
|
s_patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class));
|
||||||
state.patch_constructor = env->GetMethodID(
|
s_patch_constructor = env->GetMethodID(
|
||||||
patch_class, "<init>",
|
patch_class, "<init>",
|
||||||
"(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JI)V");
|
"(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JI)V");
|
||||||
state.patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z");
|
s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z");
|
||||||
state.patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;");
|
s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;");
|
||||||
state.patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;");
|
s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;");
|
||||||
state.patch_type_field = env->GetFieldID(patch_class, "type", "I");
|
s_patch_type_field = env->GetFieldID(patch_class, "type", "I");
|
||||||
state.patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;");
|
s_patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;");
|
||||||
state.patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;");
|
s_patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;");
|
||||||
env->DeleteLocalRef(patch_class);
|
env->DeleteLocalRef(patch_class);
|
||||||
|
|
||||||
const jclass double_class = env->FindClass("java/lang/Double");
|
const jclass double_class = env->FindClass("java/lang/Double");
|
||||||
state.double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class));
|
s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class));
|
||||||
state.double_constructor = env->GetMethodID(double_class, "<init>", "(D)V");
|
s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V");
|
||||||
state.double_value_method = env->GetMethodID(double_class, "doubleValue", "()D");
|
s_double_value_method = env->GetMethodID(double_class, "doubleValue", "()D");
|
||||||
env->DeleteLocalRef(double_class);
|
env->DeleteLocalRef(double_class);
|
||||||
|
|
||||||
const jclass int_class = env->FindClass("java/lang/Integer");
|
const jclass int_class = env->FindClass("java/lang/Integer");
|
||||||
state.integer_class = reinterpret_cast<jclass>(env->NewGlobalRef(int_class));
|
s_integer_class = reinterpret_cast<jclass>(env->NewGlobalRef(int_class));
|
||||||
state.integer_constructor = env->GetMethodID(int_class, "<init>", "(I)V");
|
s_integer_constructor = env->GetMethodID(int_class, "<init>", "(I)V");
|
||||||
state.integer_value_method = env->GetMethodID(int_class, "intValue", "()I");
|
s_integer_value_method = env->GetMethodID(int_class, "intValue", "()I");
|
||||||
env->DeleteLocalRef(int_class);
|
env->DeleteLocalRef(int_class);
|
||||||
|
|
||||||
const jclass boolean_class = env->FindClass("java/lang/Boolean");
|
const jclass boolean_class = env->FindClass("java/lang/Boolean");
|
||||||
state.boolean_class = reinterpret_cast<jclass>(env->NewGlobalRef(boolean_class));
|
s_boolean_class = reinterpret_cast<jclass>(env->NewGlobalRef(boolean_class));
|
||||||
state.boolean_constructor = env->GetMethodID(boolean_class, "<init>", "(Z)V");
|
s_boolean_constructor = env->GetMethodID(boolean_class, "<init>", "(Z)V");
|
||||||
state.boolean_value_method = env->GetMethodID(boolean_class, "booleanValue", "()Z");
|
s_boolean_value_method = env->GetMethodID(boolean_class, "booleanValue", "()Z");
|
||||||
env->DeleteLocalRef(boolean_class);
|
env->DeleteLocalRef(boolean_class);
|
||||||
|
|
||||||
const jclass player_input_class =
|
const jclass player_input_class =
|
||||||
env->FindClass("org/yuzu/yuzu_emu/features/input/model/PlayerInput");
|
env->FindClass("org/yuzu/yuzu_emu/features/input/model/PlayerInput");
|
||||||
state.player_input_class = reinterpret_cast<jclass>(env->NewGlobalRef(player_input_class));
|
s_player_input_class = reinterpret_cast<jclass>(env->NewGlobalRef(player_input_class));
|
||||||
state.player_input_constructor = env->GetMethodID(
|
s_player_input_constructor = env->GetMethodID(
|
||||||
player_input_class, "<init>",
|
player_input_class, "<init>",
|
||||||
"(Z[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZIJJJJLjava/lang/String;Z)V");
|
"(Z[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZIJJJJLjava/lang/String;Z)V");
|
||||||
state.player_input_connected_field = env->GetFieldID(player_input_class, "connected", "Z");
|
s_player_input_connected_field = env->GetFieldID(player_input_class, "connected", "Z");
|
||||||
state.player_input_buttons_field =
|
s_player_input_buttons_field =
|
||||||
env->GetFieldID(player_input_class, "buttons", "[Ljava/lang/String;");
|
env->GetFieldID(player_input_class, "buttons", "[Ljava/lang/String;");
|
||||||
state.player_input_analogs_field =
|
s_player_input_analogs_field =
|
||||||
env->GetFieldID(player_input_class, "analogs", "[Ljava/lang/String;");
|
env->GetFieldID(player_input_class, "analogs", "[Ljava/lang/String;");
|
||||||
state.player_input_motions_field =
|
s_player_input_motions_field =
|
||||||
env->GetFieldID(player_input_class, "motions", "[Ljava/lang/String;");
|
env->GetFieldID(player_input_class, "motions", "[Ljava/lang/String;");
|
||||||
state.player_input_vibration_enabled_field =
|
s_player_input_vibration_enabled_field =
|
||||||
env->GetFieldID(player_input_class, "vibrationEnabled", "Z");
|
env->GetFieldID(player_input_class, "vibrationEnabled", "Z");
|
||||||
state.player_input_vibration_strength_field =
|
s_player_input_vibration_strength_field =
|
||||||
env->GetFieldID(player_input_class, "vibrationStrength", "I");
|
env->GetFieldID(player_input_class, "vibrationStrength", "I");
|
||||||
state.player_input_body_color_left_field =
|
s_player_input_body_color_left_field =
|
||||||
env->GetFieldID(player_input_class, "bodyColorLeft", "J");
|
env->GetFieldID(player_input_class, "bodyColorLeft", "J");
|
||||||
state.player_input_body_color_right_field =
|
s_player_input_body_color_right_field =
|
||||||
env->GetFieldID(player_input_class, "bodyColorRight", "J");
|
env->GetFieldID(player_input_class, "bodyColorRight", "J");
|
||||||
state.player_input_button_color_left_field =
|
s_player_input_button_color_left_field =
|
||||||
env->GetFieldID(player_input_class, "buttonColorLeft", "J");
|
env->GetFieldID(player_input_class, "buttonColorLeft", "J");
|
||||||
state.player_input_button_color_right_field =
|
s_player_input_button_color_right_field =
|
||||||
env->GetFieldID(player_input_class, "buttonColorRight", "J");
|
env->GetFieldID(player_input_class, "buttonColorRight", "J");
|
||||||
state.player_input_profile_name_field =
|
s_player_input_profile_name_field =
|
||||||
env->GetFieldID(player_input_class, "profileName", "Ljava/lang/String;");
|
env->GetFieldID(player_input_class, "profileName", "Ljava/lang/String;");
|
||||||
state.player_input_use_system_vibrator_field =
|
s_player_input_use_system_vibrator_field =
|
||||||
env->GetFieldID(player_input_class, "useSystemVibrator", "Z");
|
env->GetFieldID(player_input_class, "useSystemVibrator", "Z");
|
||||||
env->DeleteLocalRef(player_input_class);
|
env->DeleteLocalRef(player_input_class);
|
||||||
|
|
||||||
const jclass yuzu_input_device_interface =
|
const jclass yuzu_input_device_interface =
|
||||||
env->FindClass("org/yuzu/yuzu_emu/features/input/YuzuInputDevice");
|
env->FindClass("org/yuzu/yuzu_emu/features/input/YuzuInputDevice");
|
||||||
state.yuzu_input_device_interface =
|
s_yuzu_input_device_interface =
|
||||||
reinterpret_cast<jclass>(env->NewGlobalRef(yuzu_input_device_interface));
|
reinterpret_cast<jclass>(env->NewGlobalRef(yuzu_input_device_interface));
|
||||||
state.yuzu_input_device_get_name =
|
s_yuzu_input_device_get_name =
|
||||||
env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;");
|
env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;");
|
||||||
state.yuzu_input_device_get_guid =
|
s_yuzu_input_device_get_guid =
|
||||||
env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;");
|
env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;");
|
||||||
state.yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort",
|
s_yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort",
|
||||||
"()I");
|
"()I");
|
||||||
state.yuzu_input_device_get_supports_vibration =
|
s_yuzu_input_device_get_supports_vibration =
|
||||||
env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z");
|
env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z");
|
||||||
state.yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate",
|
s_yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate",
|
||||||
"(F)V");
|
"(F)V");
|
||||||
state.yuzu_input_device_get_axes =
|
s_yuzu_input_device_get_axes =
|
||||||
env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;");
|
env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;");
|
||||||
state.yuzu_input_device_has_keys =
|
s_yuzu_input_device_has_keys =
|
||||||
env->GetMethodID(yuzu_input_device_interface, "hasKeys", "([I)[Z");
|
env->GetMethodID(yuzu_input_device_interface, "hasKeys", "([I)[Z");
|
||||||
env->DeleteLocalRef(yuzu_input_device_interface);
|
env->DeleteLocalRef(yuzu_input_device_interface);
|
||||||
state.add_netplay_message = env->GetStaticMethodID(state.native_library_class, "addNetPlayMessage",
|
s_add_netplay_message = env->GetStaticMethodID(s_native_library_class, "addNetPlayMessage",
|
||||||
"(ILjava/lang/String;)V");
|
"(ILjava/lang/String;)V");
|
||||||
state.clear_chat = env->GetStaticMethodID(state.native_library_class, "clearChat", "()V");
|
s_clear_chat = env->GetStaticMethodID(s_native_library_class, "clearChat", "()V");
|
||||||
|
|
||||||
// Initialize Android Storage
|
// Initialize Android Storage
|
||||||
Common::FS::Android::RegisterCallbacks(env, state.native_library_class);
|
Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
|
||||||
|
|
||||||
// Initialize applets
|
// Initialize applets
|
||||||
Common::Android::SoftwareKeyboard::InitJNI(env);
|
Common::Android::SoftwareKeyboard::InitJNI(env);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/socket_types.h"
|
#include "core/internal_network/socket_types.h"
|
||||||
#include "web_service/web_result.h"
|
#include "web_service/web_result.h"
|
||||||
|
|
||||||
namespace AnnounceMultiplayerRoom {
|
namespace AnnounceMultiplayerRoom {
|
||||||
|
|||||||
+18
-4
@@ -22,22 +22,36 @@ template <typename T>
|
|||||||
return std::size_t(sizeof(T) * CHAR_BIT);
|
return std::size_t(sizeof(T) * CHAR_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
requires std::is_integral_v<T>
|
||||||
|
[[nodiscard]] constexpr u32 MostSignificantBit(const T value) {
|
||||||
|
return u32(sizeof(T) * CHAR_BIT - 1 - std::countl_zero(value));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
requires std::is_integral_v<T>
|
requires std::is_integral_v<T>
|
||||||
[[nodiscard]] constexpr T Log2Floor(const T value) {
|
[[nodiscard]] constexpr T Log2Floor(const T value) {
|
||||||
return std::bit_width(value) - 1;
|
return T(MostSignificantBit<T>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
requires std::is_integral_v<T>
|
requires std::is_integral_v<T>
|
||||||
[[nodiscard]] constexpr T Log2Ceil(const T value) {
|
[[nodiscard]] constexpr T Log2Ceil(const T value) {
|
||||||
return std::bit_width(value - 1);
|
const T log2_f = Log2Floor<T>(value);
|
||||||
|
return T(log2_f + T((value ^ (T(1ULL) << log2_f)) != T(0ULL)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires std::is_integral_v<T>
|
||||||
|
[[nodiscard]] T NextPow2(T value) {
|
||||||
|
return T(1ULL << (sizeof(T) * CHAR_BIT - std::countl_zero(value - 1U)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t bit_index, typename T>
|
template <size_t bit_index, typename T>
|
||||||
requires (std::is_integral_v<T> && bit_index < BitSize<T>())
|
requires std::is_integral_v<T>
|
||||||
[[nodiscard]] constexpr bool Bit(const T value) {
|
[[nodiscard]] constexpr bool Bit(const T value) {
|
||||||
return (T(value >> bit_index) & T(1)) == T(1);
|
static_assert(bit_index < BitSize<T>(), "bit_index must be smaller than size of T");
|
||||||
|
return ((value >> bit_index) & T(1)) == T(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Common
|
} // namespace Common
|
||||||
|
|||||||
@@ -25,18 +25,26 @@ template <typename T>
|
|||||||
requires std::is_unsigned_v<T>
|
requires std::is_unsigned_v<T>
|
||||||
inline std::size_t HashValue(T val) {
|
inline std::size_t HashValue(T val) {
|
||||||
const unsigned int size_t_bits = std::numeric_limits<std::size_t>::digits;
|
const unsigned int size_t_bits = std::numeric_limits<std::size_t>::digits;
|
||||||
const unsigned int length = (std::numeric_limits<T>::digits - 1) / static_cast<unsigned int>(size_t_bits);
|
const unsigned int length =
|
||||||
|
(std::numeric_limits<T>::digits - 1) / static_cast<unsigned int>(size_t_bits);
|
||||||
|
|
||||||
std::size_t seed = 0;
|
std::size_t seed = 0;
|
||||||
for (unsigned int i = length * size_t_bits; i > 0; i -= size_t_bits)
|
|
||||||
seed ^= std::size_t(val >> i) + (seed << 6) + (seed >> 2);
|
for (unsigned int i = length * size_t_bits; i > 0; i -= size_t_bits) {
|
||||||
return seed ^= std::size_t(val) + (seed << 6) + (seed >> 2);
|
seed ^= static_cast<size_t>(val >> i) + (seed << 6) + (seed >> 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
seed ^= static_cast<size_t>(val) + (seed << 6) + (seed >> 2);
|
||||||
|
|
||||||
|
return seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t Bits>
|
template <size_t Bits>
|
||||||
struct HashCombineImpl {
|
struct HashCombineImpl {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static inline T fn(T seed, T value) {
|
static inline T fn(T seed, T value) {
|
||||||
return seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||||
|
return seed;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -15,14 +12,14 @@ namespace Common {
|
|||||||
template <typename N, typename D>
|
template <typename N, typename D>
|
||||||
requires std::is_integral_v<N> && std::is_unsigned_v<D>
|
requires std::is_integral_v<N> && std::is_unsigned_v<D>
|
||||||
[[nodiscard]] constexpr N DivCeil(N number, D divisor) {
|
[[nodiscard]] constexpr N DivCeil(N number, D divisor) {
|
||||||
return N((D(number) + divisor - 1) / divisor);
|
return static_cast<N>((static_cast<D>(number) + divisor - 1) / divisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ceiled integer division with logarithmic divisor in base 2
|
/// Ceiled integer division with logarithmic divisor in base 2
|
||||||
template <typename N, typename D>
|
template <typename N, typename D>
|
||||||
requires std::is_integral_v<N> && std::is_unsigned_v<D>
|
requires std::is_integral_v<N> && std::is_unsigned_v<D>
|
||||||
[[nodiscard]] constexpr N DivCeilLog2(N value, D alignment_log2) {
|
[[nodiscard]] constexpr N DivCeilLog2(N value, D alignment_log2) {
|
||||||
return N((D(value) + (D(1) << alignment_log2) - 1) >> alignment_log2);
|
return static_cast<N>((static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Common
|
} // namespace Common
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <utility>
|
||||||
|
#include <boost/functional/hash.hpp>
|
||||||
|
|
||||||
|
namespace Common {
|
||||||
|
|
||||||
|
struct PairHash {
|
||||||
|
template <class T1, class T2>
|
||||||
|
std::size_t operator()(const std::pair<T1, T2>& pair) const noexcept {
|
||||||
|
std::size_t seed = std::hash<T1>()(pair.first);
|
||||||
|
boost::hash_combine(seed, std::hash<T2>()(pair.second));
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct IdentityHash {
|
||||||
|
[[nodiscard]] size_t operator()(T value) const noexcept {
|
||||||
|
return static_cast<size_t>(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Common
|
||||||
+16
-10
@@ -1,6 +1,3 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
|
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
|
||||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
@@ -19,12 +16,14 @@ namespace Common {
|
|||||||
|
|
||||||
[[nodiscard]] constexpr u8 ToHexNibble(char c) {
|
[[nodiscard]] constexpr u8 ToHexNibble(char c) {
|
||||||
if (c >= 65 && c <= 70) {
|
if (c >= 65 && c <= 70) {
|
||||||
return u8(c - 55);
|
return static_cast<u8>(c - 55);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c >= 97 && c <= 102) {
|
if (c >= 97 && c <= 102) {
|
||||||
return u8(c - 87);
|
return static_cast<u8>(c - 87);
|
||||||
}
|
}
|
||||||
return u8(c - 48);
|
|
||||||
|
return static_cast<u8>(c - 48);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
|
[[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
|
||||||
@@ -32,28 +31,35 @@ namespace Common {
|
|||||||
template <std::size_t Size, bool le = false>
|
template <std::size_t Size, bool le = false>
|
||||||
[[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
|
[[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
|
||||||
ASSERT_MSG(Size * 2 <= str.size(), "Invalid string size");
|
ASSERT_MSG(Size * 2 <= str.size(), "Invalid string size");
|
||||||
|
|
||||||
std::array<u8, Size> out{};
|
std::array<u8, Size> out{};
|
||||||
if constexpr (le) {
|
if constexpr (le) {
|
||||||
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {
|
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {
|
||||||
out[i / 2] = u8((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));
|
out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (std::size_t i = 0; i < 2 * Size; i += 2) {
|
for (std::size_t i = 0; i < 2 * Size; i += 2) {
|
||||||
out[i / 2] = u8((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));
|
out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ContiguousContainer>
|
template <typename ContiguousContainer>
|
||||||
requires std::is_same_v<typename ContiguousContainer::value_type, u8>
|
|
||||||
[[nodiscard]] std::string HexToString(const ContiguousContainer& data, bool upper = true) {
|
[[nodiscard]] std::string HexToString(const ContiguousContainer& data, bool upper = true) {
|
||||||
|
static_assert(std::is_same_v<typename ContiguousContainer::value_type, u8>,
|
||||||
|
"Underlying type within the contiguous container must be u8.");
|
||||||
|
|
||||||
constexpr std::size_t pad_width = 2;
|
constexpr std::size_t pad_width = 2;
|
||||||
|
|
||||||
std::string out;
|
std::string out;
|
||||||
out.reserve(std::size(data) * pad_width);
|
out.reserve(std::size(data) * pad_width);
|
||||||
|
|
||||||
const auto format_str = fmt::runtime(upper ? "{:02X}" : "{:02x}");
|
const auto format_str = fmt::runtime(upper ? "{:02X}" : "{:02x}");
|
||||||
for (const u8 c : data)
|
for (const u8 c : data) {
|
||||||
out += fmt::format(format_str, c);
|
out += fmt::format(format_str, c);
|
||||||
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-10
@@ -10,7 +10,6 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
@@ -96,10 +95,9 @@ std::string FormatLogMessage(const Entry& entry) noexcept {
|
|||||||
|
|
||||||
template <typename It>
|
template <typename It>
|
||||||
Level GetLevelByName(const It begin, const It end) {
|
Level GetLevelByName(const It begin, const It end) {
|
||||||
std::string_view const sv{begin, end};
|
|
||||||
for (u32 i = 0; i < u32(Level::Count); ++i) {
|
for (u32 i = 0; i < u32(Level::Count); ++i) {
|
||||||
auto const level_name = GetLevelName(Level(i));
|
const char* level_name = GetLevelName(Level(i));
|
||||||
if (boost::iequals(sv, level_name))
|
if (Common::ComparePartialString(begin, end, level_name))
|
||||||
return Level(i);
|
return Level(i);
|
||||||
}
|
}
|
||||||
return Level::Count;
|
return Level::Count;
|
||||||
@@ -107,10 +105,9 @@ Level GetLevelByName(const It begin, const It end) {
|
|||||||
|
|
||||||
template <typename It>
|
template <typename It>
|
||||||
Class GetClassByName(const It begin, const It end) {
|
Class GetClassByName(const It begin, const It end) {
|
||||||
std::string_view const sv{begin, end};
|
|
||||||
for (u32 i = 0; i < u32(Class::Count); ++i) {
|
for (u32 i = 0; i < u32(Class::Count); ++i) {
|
||||||
auto const level_name = GetLogClassName(Class(i));
|
const char* level_name = GetLogClassName(Class(i));
|
||||||
if (boost::iequals(sv, level_name))
|
if (Common::ComparePartialString(begin, end, level_name))
|
||||||
return Class(i);
|
return Class(i);
|
||||||
}
|
}
|
||||||
return Class::Count;
|
return Class::Count;
|
||||||
@@ -123,13 +120,12 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
|||||||
LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: {}", std::string(begin, end));
|
LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: {}", std::string(begin, end));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto const sv = std::string_view{begin, level_separator};
|
const Level level = GetLevelByName(level_separator + 1, end);
|
||||||
auto const level = GetLevelByName(level_separator + 1, end);
|
|
||||||
if (level == Level::Count) {
|
if (level == Level::Count) {
|
||||||
LOG_ERROR(Log, "Unknown log level in filter: {}", std::string(begin, end));
|
LOG_ERROR(Log, "Unknown log level in filter: {}", std::string(begin, end));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (boost::iequals(sv, "*")) {
|
if (Common::ComparePartialString(begin, level_separator, "*")) {
|
||||||
instance.class_levels.fill(level);
|
instance.class_levels.fill(level);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,6 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <boost/algorithm/string/classification.hpp>
|
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
|
||||||
#include <boost/algorithm/string/split.hpp>
|
|
||||||
|
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/param_package.h"
|
#include "common/param_package.h"
|
||||||
@@ -18,16 +15,17 @@
|
|||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
constexpr auto KEY_VALUE_SEPARATOR = ":";
|
constexpr char KEY_VALUE_SEPARATOR = ':';
|
||||||
constexpr auto PARAM_SEPARATOR = ",";
|
constexpr char PARAM_SEPARATOR = ',';
|
||||||
constexpr auto ESCAPE_CHARACTER = "$";
|
|
||||||
constexpr auto KEY_VALUE_SEPARATOR_ESCAPE = "$0";
|
constexpr char ESCAPE_CHARACTER = '$';
|
||||||
constexpr auto PARAM_SEPARATOR_ESCAPE = "$1";
|
constexpr char KEY_VALUE_SEPARATOR_ESCAPE[] = "$0";
|
||||||
constexpr auto ESCAPE_CHARACTER_ESCAPE = "$2";
|
constexpr char PARAM_SEPARATOR_ESCAPE[] = "$1";
|
||||||
|
constexpr char ESCAPE_CHARACTER_ESCAPE[] = "$2";
|
||||||
|
|
||||||
/// A placeholder for empty param packages to avoid empty strings
|
/// A placeholder for empty param packages to avoid empty strings
|
||||||
/// (they may be recognized as "not set" by some frontend libraries like qt)
|
/// (they may be recognized as "not set" by some frontend libraries like qt)
|
||||||
constexpr auto EMPTY_PLACEHOLDER = "[empty]";
|
constexpr char EMPTY_PLACEHOLDER[] = "[empty]";
|
||||||
|
|
||||||
ParamPackage::ParamPackage(const std::string& serialized) {
|
ParamPackage::ParamPackage(const std::string& serialized) {
|
||||||
if (serialized == EMPTY_PLACEHOLDER) {
|
if (serialized == EMPTY_PLACEHOLDER) {
|
||||||
@@ -35,20 +33,20 @@ ParamPackage::ParamPackage(const std::string& serialized) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> pairs;
|
std::vector<std::string> pairs;
|
||||||
boost::split(pairs, serialized, boost::is_any_of(PARAM_SEPARATOR));
|
Common::SplitString(serialized, PARAM_SEPARATOR, pairs);
|
||||||
|
|
||||||
for (const std::string& pair : pairs) {
|
for (const std::string& pair : pairs) {
|
||||||
std::vector<std::string> key_value;
|
std::vector<std::string> key_value;
|
||||||
boost::split(key_value, pair, boost::is_any_of(KEY_VALUE_SEPARATOR));
|
Common::SplitString(pair, KEY_VALUE_SEPARATOR, key_value);
|
||||||
if (key_value.size() != 2) {
|
if (key_value.size() != 2) {
|
||||||
LOG_ERROR(Common, "invalid key pair {}", pair);
|
LOG_ERROR(Common, "invalid key pair {}", pair);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& part : key_value) {
|
for (std::string& part : key_value) {
|
||||||
boost::replace_all(part, KEY_VALUE_SEPARATOR_ESCAPE, KEY_VALUE_SEPARATOR);
|
part = Common::ReplaceAll(part, KEY_VALUE_SEPARATOR_ESCAPE, {KEY_VALUE_SEPARATOR});
|
||||||
boost::replace_all(part, PARAM_SEPARATOR_ESCAPE, PARAM_SEPARATOR);
|
part = Common::ReplaceAll(part, PARAM_SEPARATOR_ESCAPE, {PARAM_SEPARATOR});
|
||||||
boost::replace_all(part, ESCAPE_CHARACTER_ESCAPE, ESCAPE_CHARACTER);
|
part = Common::ReplaceAll(part, ESCAPE_CHARACTER_ESCAPE, {ESCAPE_CHARACTER});
|
||||||
}
|
}
|
||||||
|
|
||||||
Set(key_value[0], std::move(key_value[1]));
|
Set(key_value[0], std::move(key_value[1]));
|
||||||
@@ -65,10 +63,10 @@ std::string ParamPackage::Serialize() const {
|
|||||||
|
|
||||||
for (const auto& pair : data) {
|
for (const auto& pair : data) {
|
||||||
std::array<std::string, 2> key_value{{pair.first, pair.second}};
|
std::array<std::string, 2> key_value{{pair.first, pair.second}};
|
||||||
for (auto& part : key_value) {
|
for (std::string& part : key_value) {
|
||||||
boost::replace_all(part, ESCAPE_CHARACTER, ESCAPE_CHARACTER_ESCAPE);
|
part = Common::ReplaceAll(part, {ESCAPE_CHARACTER}, ESCAPE_CHARACTER_ESCAPE);
|
||||||
boost::replace_all(part, PARAM_SEPARATOR, PARAM_SEPARATOR_ESCAPE);
|
part = Common::ReplaceAll(part, {PARAM_SEPARATOR}, PARAM_SEPARATOR_ESCAPE);
|
||||||
boost::replace_all(part, KEY_VALUE_SEPARATOR, KEY_VALUE_SEPARATOR_ESCAPE);
|
part = Common::ReplaceAll(part, {KEY_VALUE_SEPARATOR}, KEY_VALUE_SEPARATOR_ESCAPE);
|
||||||
}
|
}
|
||||||
result += key_value[0] + KEY_VALUE_SEPARATOR + key_value[1] + PARAM_SEPARATOR;
|
result += key_value[0] + KEY_VALUE_SEPARATOR + key_value[1] + PARAM_SEPARATOR;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,178 +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"
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -24,6 +24,22 @@
|
|||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
|
/// Make a string lowercase
|
||||||
|
std::string ToLower(const std::string_view sv) {
|
||||||
|
std::string str{sv};
|
||||||
|
std::transform(str.begin(), str.end(), str.begin(),
|
||||||
|
[](auto const c) { return char(std::tolower(c)); });
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make a string uppercase
|
||||||
|
std::string ToUpper(const std::string_view sv) {
|
||||||
|
std::string str{sv};
|
||||||
|
std::transform(str.begin(), str.end(), str.begin(),
|
||||||
|
[](auto const c) { return char(std::toupper(c)); });
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename,
|
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename,
|
||||||
std::string* _pExtension) {
|
std::string* _pExtension) {
|
||||||
if (full_path.empty())
|
if (full_path.empty())
|
||||||
@@ -64,6 +80,41 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SplitString(const std::string& str, const char delim, std::vector<std::string>& output) {
|
||||||
|
std::istringstream iss(str);
|
||||||
|
output.resize(1);
|
||||||
|
|
||||||
|
while (std::getline(iss, *output.rbegin(), delim)) {
|
||||||
|
output.emplace_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
output.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TabsToSpaces(int tab_size, std::string in) {
|
||||||
|
std::size_t i = 0;
|
||||||
|
|
||||||
|
while ((i = in.find('\t')) != std::string::npos) {
|
||||||
|
in.replace(i, 1, tab_size, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) {
|
||||||
|
std::size_t pos = 0;
|
||||||
|
|
||||||
|
if (src == dest)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
while ((pos = result.find(src, pos)) != std::string::npos) {
|
||||||
|
result.replace(pos, src.size(), dest);
|
||||||
|
pos += dest.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::string UTF16ToUTF8(std::u16string_view input) {
|
std::string UTF16ToUTF8(std::u16string_view input) {
|
||||||
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
|
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
|
||||||
return convert.to_bytes(input.data(), input.data() + input.size());
|
return convert.to_bytes(input.data(), input.data() + input.size());
|
||||||
|
|||||||
@@ -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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
|
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
|
||||||
@@ -16,6 +16,12 @@
|
|||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
|
/// Make a string lowercase
|
||||||
|
[[nodiscard]] std::string ToLower(const std::string_view sv);
|
||||||
|
|
||||||
|
/// Make a string uppercase
|
||||||
|
[[nodiscard]] std::string ToUpper(const std::string_view sv);
|
||||||
|
|
||||||
[[nodiscard]] inline std::string StringFromBuffer(std::span<const u8> data) noexcept {
|
[[nodiscard]] inline std::string StringFromBuffer(std::span<const u8> data) noexcept {
|
||||||
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
|
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
|
||||||
}
|
}
|
||||||
@@ -23,8 +29,37 @@ namespace Common {
|
|||||||
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
|
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Turns " hej " into "hej". Also handles tabs.
|
||||||
|
[[nodiscard]] inline std::string StripSpaces(const std::string_view str) noexcept {
|
||||||
|
const std::size_t s = str.find_first_not_of(" \t\r\n");
|
||||||
|
if (str.npos != s)
|
||||||
|
return std::string{str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1)};
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// "\"hello\"" is turned to "hello"
|
||||||
|
/// This one assumes that the string has already been space stripped in both
|
||||||
|
/// ends, as done by StripSpaces above, for example.
|
||||||
|
[[nodiscard]] inline std::string StripQuotes(const std::string_view s) noexcept {
|
||||||
|
if (s.size() && '\"' == s[0] && '\"' == *s.rbegin())
|
||||||
|
return std::string{s.substr(1, s.size() - 2)};
|
||||||
|
return std::string{s};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline std::string StringFromBool(bool value) noexcept {
|
||||||
|
return value ? "True" : "False";
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::string TabsToSpaces(int tab_size, std::string in);
|
||||||
|
|
||||||
|
void SplitString(const std::string& str, char delim, std::vector<std::string>& output);
|
||||||
|
|
||||||
// "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe"
|
// "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe"
|
||||||
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension);
|
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename,
|
||||||
|
std::string* _pExtension);
|
||||||
|
|
||||||
|
[[nodiscard]] std::string ReplaceAll(std::string result, const std::string& src,
|
||||||
|
const std::string& dest);
|
||||||
|
|
||||||
[[nodiscard]] std::string UTF16ToUTF8(std::u16string_view input);
|
[[nodiscard]] std::string UTF16ToUTF8(std::u16string_view input);
|
||||||
[[nodiscard]] std::u16string UTF8ToUTF16(std::string_view input);
|
[[nodiscard]] std::u16string UTF8ToUTF16(std::string_view input);
|
||||||
@@ -38,13 +73,30 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
|
|||||||
|
|
||||||
[[nodiscard]] std::u16string U16StringFromBuffer(const u16* input, std::size_t length);
|
[[nodiscard]] std::u16string U16StringFromBuffer(const u16* input, std::size_t length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares the string defined by the range [`begin`, `end`) to the null-terminated C-string
|
||||||
|
* `other` for equality.
|
||||||
|
*/
|
||||||
|
template <typename InIt>
|
||||||
|
[[nodiscard]] inline bool ComparePartialString(InIt begin, InIt end, const char* other) noexcept {
|
||||||
|
for (; begin != end && *other != '\0'; ++begin, ++other) {
|
||||||
|
if (*begin != *other) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Only return true if both strings finished at the same point
|
||||||
|
return (begin == end) == (*other == '\0');
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't
|
/// Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't
|
||||||
/// NUL-terminated then the string ends at max_len characters.
|
/// NUL-terminated then the string ends at max_len characters.
|
||||||
[[nodiscard]] std::string StringFromFixedZeroTerminatedBuffer(std::string_view buffer, std::size_t max_len);
|
[[nodiscard]] std::string StringFromFixedZeroTerminatedBuffer(std::string_view buffer,
|
||||||
|
std::size_t max_len);
|
||||||
|
|
||||||
/// Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't
|
/// Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't
|
||||||
/// null-terminated, then the string ends at the greatest multiple of two less then or equal to
|
/// null-terminated, then the string ends at the greatest multiple of two less then or equal to
|
||||||
/// max_len_bytes.
|
/// max_len_bytes.
|
||||||
[[nodiscard]] std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer, std::size_t max_len);
|
[[nodiscard]] std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
|
||||||
|
std::size_t max_len);
|
||||||
|
|
||||||
} // namespace Common
|
} // namespace Common
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#include "common/zbic_compression.h"
|
|
||||||
|
|
||||||
#define ZSTD_ZBIC_SUPPORT 1
|
|
||||||
#define ZSTDLIB_VISIBLE static
|
|
||||||
#define ZSTDLIB_HIDDEN static
|
|
||||||
#define ZSTDERRORLIB_VISIBLE static
|
|
||||||
#define ZSTDERRORLIB_HIDDEN static
|
|
||||||
#undef ZSTD_MULTITHREAD
|
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
#undef _GNU_SOURCE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "zstd.h"
|
|
||||||
#define g_ZSTD_threading_useless_symbol g_ZSTD_zbic_threading_useless_symbol
|
|
||||||
#include "zstd.c"
|
|
||||||
#undef g_ZSTD_threading_useless_symbol
|
|
||||||
|
|
||||||
namespace Common::Compression {
|
|
||||||
|
|
||||||
bool IsZBIC(std::span<const u8> src) {
|
|
||||||
if (src.size() < sizeof(u32)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
u32 magic = 0;
|
|
||||||
std::memcpy(&magic, src.data(), sizeof(u32));
|
|
||||||
return magic == ZSTD_MAGICNUMBER; // 0x4349425A ("ZBIC")
|
|
||||||
}
|
|
||||||
|
|
||||||
int DecompressDataZBIC(std::span<u8> dst, std::span<const u8> src) {
|
|
||||||
if (dst.empty() || src.empty()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
const size_t res = ZSTD_decompress(dst.data(), dst.size(), src.data(), src.size());
|
|
||||||
if (ZSTD_isError(res)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return static_cast<int>(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Common::Compression
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <span>
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace Common::Compression {
|
|
||||||
|
|
||||||
[[nodiscard]] bool IsZBIC(std::span<const u8> src);
|
|
||||||
|
|
||||||
[[nodiscard]] int DecompressDataZBIC(std::span<u8> dst, std::span<const u8> src);
|
|
||||||
|
|
||||||
} // namespace Common::Compression
|
|
||||||
@@ -1127,6 +1127,7 @@ add_library(core STATIC
|
|||||||
internal_network/network_interface.h
|
internal_network/network_interface.h
|
||||||
internal_network/socket_proxy.cpp
|
internal_network/socket_proxy.cpp
|
||||||
internal_network/socket_proxy.h
|
internal_network/socket_proxy.h
|
||||||
|
internal_network/socket_types.h
|
||||||
internal_network/sockets.h
|
internal_network/sockets.h
|
||||||
internal_network/wifi_scanner.h
|
internal_network/wifi_scanner.h
|
||||||
launch_timestamp_cache.cpp
|
launch_timestamp_cache.cpp
|
||||||
@@ -1165,6 +1166,12 @@ add_library(core STATIC
|
|||||||
tools/renderdoc.cpp
|
tools/renderdoc.cpp
|
||||||
tools/renderdoc.h)
|
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)
|
if (ENABLE_WIFI_SCAN)
|
||||||
target_sources(core PRIVATE internal_network/wifi_scanner.cpp)
|
target_sources(core PRIVATE internal_network/wifi_scanner.cpp)
|
||||||
if (LINUX)
|
if (LINUX)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <dynarmic/interface/A64/a64.h>
|
#include <dynarmic/interface/A64/a64.h>
|
||||||
#include <dynarmic/interface/code_page.h>
|
#include <dynarmic/interface/code_page.h>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/hash.h"
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
||||||
#include "dynarmic/interface/A64/config.h"
|
#include "dynarmic/interface/A64/config.h"
|
||||||
|
|||||||
+19
-12
@@ -168,7 +168,7 @@ void CpuManager::ShutdownThread(Kernel::KernelCore& kernel) {
|
|||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) {
|
void CpuManager::RunThread(std::stop_token token, std::size_t core) {
|
||||||
/// Initialization
|
/// Initialization
|
||||||
system.RegisterCoreThread(core);
|
system.RegisterCoreThread(core);
|
||||||
std::string name = is_multicore ? ("CPUCore_" + std::to_string(core)) : std::string{"CPUThread"};
|
std::string name = is_multicore ? ("CPUCore_" + std::to_string(core)) : std::string{"CPUThread"};
|
||||||
@@ -178,19 +178,26 @@ void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) {
|
|||||||
auto& data = core_data[core];
|
auto& data = core_data[core];
|
||||||
data.host_context = Common::Fiber::ThreadToFiber();
|
data.host_context = Common::Fiber::ThreadToFiber();
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
SCOPE_EXIT {
|
||||||
|
data.host_context->Exit();
|
||||||
|
};
|
||||||
|
|
||||||
// Running
|
// Running
|
||||||
gpu_barrier->arrive_and_wait();
|
if (!gpu_barrier->Sync(token)) {
|
||||||
if (!stop_token.stop_requested()) {
|
return;
|
||||||
if (!is_async_gpu && !is_multicore) {
|
|
||||||
system.GPU().ObtainContext();
|
|
||||||
}
|
|
||||||
auto& kernel = system.Kernel();
|
|
||||||
auto& scheduler = *kernel.CurrentScheduler();
|
|
||||||
auto* thread = scheduler.GetSchedulerCurrentThread();
|
|
||||||
Kernel::SetCurrentThread(kernel, thread);
|
|
||||||
Common::Fiber::YieldTo(data.host_context, *thread->GetHostContext());
|
|
||||||
}
|
}
|
||||||
data.host_context->Exit();
|
|
||||||
|
if (!is_async_gpu && !is_multicore) {
|
||||||
|
system.GPU().ObtainContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& kernel = system.Kernel();
|
||||||
|
auto& scheduler = *kernel.CurrentScheduler();
|
||||||
|
auto* thread = scheduler.GetSchedulerCurrentThread();
|
||||||
|
Kernel::SetCurrentThread(kernel, thread);
|
||||||
|
|
||||||
|
Common::Fiber::YieldTo(data.host_context, *thread->GetHostContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <barrier>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@@ -53,7 +52,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OnGpuReady() {
|
void OnGpuReady() {
|
||||||
gpu_barrier->arrive_and_wait();
|
gpu_barrier->Sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Initialize();
|
void Initialize();
|
||||||
@@ -96,7 +95,7 @@ private:
|
|||||||
|
|
||||||
static constexpr std::size_t max_cycle_runs = 5;
|
static constexpr std::size_t max_cycle_runs = 5;
|
||||||
|
|
||||||
std::optional<std::barrier<>> gpu_barrier{};
|
std::optional<Common::Barrier> gpu_barrier{};
|
||||||
struct CoreData {
|
struct CoreData {
|
||||||
std::shared_ptr<Common::Fiber> host_context;
|
std::shared_ptr<Common::Fiber> host_context;
|
||||||
std::jthread host_thread;
|
std::jthread host_thread;
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
|
|
||||||
#include "common/fs/file.h"
|
#include "common/fs/file.h"
|
||||||
@@ -623,7 +622,7 @@ void KeyManager::LoadFromFile(const std::filesystem::path& file_path, bool is_ti
|
|||||||
Key128 key = Common::HexStringToArray<16>(out[1]);
|
Key128 key = Common::HexStringToArray<16>(out[1]);
|
||||||
s128_keys[{S128KeyType::Titlekey, rights_id[1], rights_id[0]}] = key;
|
s128_keys[{S128KeyType::Titlekey, rights_id[1], rights_id[0]}] = key;
|
||||||
} else {
|
} else {
|
||||||
boost::algorithm::to_lower(out[0]);
|
out[0] = Common::ToLower(out[0]);
|
||||||
if (const auto iter128 = Find128ByName(out[0]); iter128 != s128_file_id.end()) {
|
if (const auto iter128 = Find128ByName(out[0]); iter128 != s128_file_id.end()) {
|
||||||
const auto& index = iter128->second;
|
const auto& index = iter128->second;
|
||||||
const Key128 key = Common::HexStringToArray<16>(out[1]);
|
const Key128 key = Common::HexStringToArray<16>(out[1]);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/hex_util.h"
|
#include "common/hex_util.h"
|
||||||
@@ -42,13 +41,16 @@ static_assert(sizeof(Package2Header) == 0x200, "Package2Header has incorrect siz
|
|||||||
|
|
||||||
const u8 PartitionDataManager::MAX_KEYBLOB_SOURCE_HASH = 32;
|
const u8 PartitionDataManager::MAX_KEYBLOB_SOURCE_HASH = 32;
|
||||||
|
|
||||||
static FileSys::VirtualFile FindFileInDirWithNames(const FileSys::VirtualDir& dir, const std::string& name) {
|
static FileSys::VirtualFile FindFileInDirWithNames(const FileSys::VirtualDir& dir,
|
||||||
const auto upper = boost::algorithm::to_upper_copy(name);
|
const std::string& name) {
|
||||||
|
const auto upper = Common::ToUpper(name);
|
||||||
|
|
||||||
for (const auto& fname : {name, name + ".bin", upper, upper + ".BIN"}) {
|
for (const auto& fname : {name, name + ".bin", upper, upper + ".BIN"}) {
|
||||||
if (dir->GetFile(fname) != nullptr) {
|
if (dir->GetFile(fname) != nullptr) {
|
||||||
return dir->GetFile(fname);
|
return dir->GetFile(fname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/hex_util.h"
|
#include "common/hex_util.h"
|
||||||
@@ -74,10 +73,12 @@ VirtualDir FindSubdirectoryCaseless(const VirtualDir dir, std::string_view name)
|
|||||||
#else
|
#else
|
||||||
const auto subdirs = dir->GetSubdirectories();
|
const auto subdirs = dir->GetSubdirectories();
|
||||||
for (const auto& subdir : subdirs) {
|
for (const auto& subdir : subdirs) {
|
||||||
if (name == boost::algorithm::to_lower_copy(subdir->GetName())) {
|
std::string dir_name = Common::ToLower(subdir->GetName());
|
||||||
|
if (dir_name == name) {
|
||||||
return subdir;
|
return subdir;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/fs/path_util.h"
|
#include "common/fs/path_util.h"
|
||||||
@@ -1415,10 +1414,11 @@ void ExternalContentProvider::ScanDirectory(const VirtualDir& dir) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto ext = boost::to_lower_copy(filename.substr(dot_pos + 1));
|
const auto extension = Common::ToLower(filename.substr(dot_pos + 1));
|
||||||
if (ext == "nsp") {
|
|
||||||
|
if (extension == "nsp") {
|
||||||
ProcessNSP(file);
|
ProcessNSP(file);
|
||||||
} else if (ext == "xci") {
|
} else if (extension == "xci") {
|
||||||
ProcessXCI(file);
|
ProcessXCI(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
#include <regex>
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
|
|
||||||
@@ -64,8 +63,8 @@ NAX::NAX(VirtualFile file_)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string two_dir = boost::algorithm::to_upper_copy(std::string{match[1]});
|
const std::string two_dir = Common::ToUpper(std::string{match[1]});
|
||||||
const std::string nca_id = boost::algorithm::to_lower_copy(std::string{match[2]});
|
const std::string nca_id = Common::ToLower(std::string{match[2]});
|
||||||
status = Parse(fmt::format("/registered/{}/{}.nca", two_dir, nca_id));
|
status = Parse(fmt::format("/registered/{}/{}.nca", two_dir, nca_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -22,14 +19,8 @@ constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores - sync wit
|
|||||||
|
|
||||||
// Virtual to Physical core map.
|
// Virtual to Physical core map.
|
||||||
constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{
|
constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{
|
||||||
0, 1, 2, 3, 0, 0, 0, 0,
|
0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 3,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr inline size_t NumVirtualCores = Common::BitSize<u64>();
|
static constexpr inline size_t NumVirtualCores = Common::BitSize<u64>();
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
#include "common/container/unordered_map.h"
|
#include "common/container/unordered_map.h"
|
||||||
|
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/socket_types.h"
|
#include "core/internal_network/socket_types.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
#include "core/hle/service/ldn/ldn_results.h"
|
#include "core/hle/service/ldn/ldn_results.h"
|
||||||
#include "core/hle/service/ldn/ldn_types.h"
|
#include "core/hle/service/ldn/ldn_types.h"
|
||||||
|
|||||||
@@ -129,6 +129,13 @@ 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) {
|
void ServerManager::RunServer(std::unique_ptr<ServerManager>&& server_manager) {
|
||||||
server_manager->m_system.RunServer(std::move(server_manager));
|
server_manager->m_system.RunServer(std::move(server_manager));
|
||||||
}
|
}
|
||||||
@@ -245,14 +252,6 @@ Result ServerManager::ManageDeferral(Kernel::KEvent** out_event) {
|
|||||||
R_SUCCEED();
|
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() {
|
Result ServerManager::LoopProcess() {
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT {
|
||||||
m_stopped.Set();
|
m_stopped.Set();
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -48,8 +51,8 @@ public:
|
|||||||
Result ManageDeferral(Kernel::KEvent** out_event);
|
Result ManageDeferral(Kernel::KEvent** out_event);
|
||||||
|
|
||||||
Result LoopProcess();
|
Result LoopProcess();
|
||||||
void StartAdditionalHostThreads(const char* name, size_t num_threads);
|
|
||||||
|
|
||||||
|
void StartAdditionalHostThreads(const char* name, size_t num_threads);
|
||||||
static void RunServer(std::unique_ptr<ServerManager>&& server);
|
static void RunServer(std::unique_ptr<ServerManager>&& server);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#include <fmt/ranges.h>
|
#include <fmt/ranges.h>
|
||||||
|
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/socket_types.h"
|
#include "core/internal_network/socket_types.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
@@ -20,6 +20,9 @@
|
|||||||
#include "core/hle/service/sockets/sockets_translate.h"
|
#include "core/hle/service/sockets/sockets_translate.h"
|
||||||
#include "core/internal_network/network.h"
|
#include "core/internal_network/network.h"
|
||||||
#include "core/internal_network/socket_proxy.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 "core/internal_network/sockets.h"
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
#include <common/settings.h>
|
#include <common/settings.h>
|
||||||
@@ -28,15 +31,18 @@ namespace Service::Sockets {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool IsConnectionBased(Type type) {
|
[[nodiscard]] bool IsConnectionBased(Network::Type type) noexcept {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Type::STREAM:
|
case Network::Type::STREAM:
|
||||||
|
case Network::Type::SEQPACKET:
|
||||||
return true;
|
return true;
|
||||||
case Type::DGRAM:
|
case Network::Type::RAW:
|
||||||
|
case Network::Type::DGRAM:
|
||||||
|
case Network::Type::RDM:
|
||||||
|
case Network::Type::Unspecified:
|
||||||
return false;
|
return false;
|
||||||
default:
|
default:
|
||||||
UNIMPLEMENTED_MSG("Unimplemented type={}", type);
|
UNREACHABLE();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +98,7 @@ void BSD_USA::ConnectWork::Execute(BSD_USA* bsd) {
|
|||||||
void BSD_USA::ConnectWork::Response(HLERequestContext& ctx) {
|
void BSD_USA::ConnectWork::Response(HLERequestContext& ctx) {
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
|
rb.Push<s32>(bsd_errno == Network::Errno::E_SUCCESS ? 0 : -1);
|
||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,10 +176,9 @@ void BSD_USA::Socket(HLERequestContext& ctx) {
|
|||||||
const u32 domain = rp.Pop<u32>();
|
const u32 domain = rp.Pop<u32>();
|
||||||
const u32 type = rp.Pop<u32>();
|
const u32 type = rp.Pop<u32>();
|
||||||
const u32 protocol = rp.Pop<u32>();
|
const u32 protocol = rp.Pop<u32>();
|
||||||
|
|
||||||
LOG_DEBUG(Service, "called. domain={} type={} protocol={}", domain, type, protocol);
|
LOG_DEBUG(Service, "called. domain={} type={} protocol={}", domain, type, protocol);
|
||||||
|
|
||||||
const auto [fd, bsd_errno] = SocketImpl(Domain(domain), Type(type), Protocol(protocol));
|
const auto [fd, bsd_errno] = SocketImpl(Network::Domain(domain), Network::Type(type), Network::Protocol(protocol));
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
@@ -189,8 +194,8 @@ void BSD_USA::SocketExempt(HLERequestContext& ctx) {
|
|||||||
|
|
||||||
LOG_DEBUG(Service, "called. domain={} type={} protocol={}", domain, type, protocol);
|
LOG_DEBUG(Service, "called. domain={} type={} protocol={}", domain, type, protocol);
|
||||||
|
|
||||||
auto [fd, bsd_errno] = SocketImpl(Domain(domain), Type(type), Protocol(protocol));
|
auto [fd, bsd_errno] = SocketImpl(Network::Domain(domain), Network::Type(type), Network::Protocol(protocol));
|
||||||
if (bsd_errno == Errno::SUCCESS) {
|
if (bsd_errno == Network::Errno::E_SUCCESS) {
|
||||||
bsd_errno = ShutdownImpl(fd, 0);
|
bsd_errno = ShutdownImpl(fd, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,13 +269,13 @@ void BSD_USA::GetPeerName(HLERequestContext& ctx) {
|
|||||||
LOG_DEBUG(Service, "called. fd={}", fd);
|
LOG_DEBUG(Service, "called. fd={}", fd);
|
||||||
|
|
||||||
std::vector<u8> write_buffer(ctx.GetWriteBufferSize());
|
std::vector<u8> write_buffer(ctx.GetWriteBufferSize());
|
||||||
const Errno bsd_errno = GetPeerNameImpl(fd, write_buffer);
|
const Network::Errno bsd_errno = GetPeerNameImpl(fd, write_buffer);
|
||||||
|
|
||||||
ctx.WriteBuffer(write_buffer);
|
ctx.WriteBuffer(write_buffer);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 5};
|
IPC::ResponseBuilder rb{ctx, 5};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push<s32>(bsd_errno != Errno::SUCCESS ? -1 : 0);
|
rb.Push<s32>(bsd_errno != Network::Errno::E_SUCCESS ? -1 : 0);
|
||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
||||||
}
|
}
|
||||||
@@ -282,13 +287,13 @@ void BSD_USA::GetSockName(HLERequestContext& ctx) {
|
|||||||
LOG_DEBUG(Service, "called. fd={}", fd);
|
LOG_DEBUG(Service, "called. fd={}", fd);
|
||||||
|
|
||||||
std::vector<u8> write_buffer(ctx.GetWriteBufferSize());
|
std::vector<u8> write_buffer(ctx.GetWriteBufferSize());
|
||||||
const Errno bsd_errno = GetSockNameImpl(fd, write_buffer);
|
const Network::Errno bsd_errno = GetSockNameImpl(fd, write_buffer);
|
||||||
|
|
||||||
ctx.WriteBuffer(write_buffer);
|
ctx.WriteBuffer(write_buffer);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 5};
|
IPC::ResponseBuilder rb{ctx, 5};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push<s32>(bsd_errno != Errno::SUCCESS ? -1 : 0);
|
rb.Push<s32>(bsd_errno != Network::Errno::E_SUCCESS ? -1 : 0);
|
||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
||||||
}
|
}
|
||||||
@@ -296,21 +301,19 @@ void BSD_USA::GetSockName(HLERequestContext& ctx) {
|
|||||||
void BSD_USA::GetSockOpt(HLERequestContext& ctx) {
|
void BSD_USA::GetSockOpt(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
const u32 level = rp.Pop<u32>();
|
const auto level = Network::SocketLevel(rp.Pop<u32>());
|
||||||
const auto optname = static_cast<OptName>(rp.Pop<u32>());
|
const auto optname = Network::OptName(rp.Pop<u32>());
|
||||||
|
|
||||||
std::vector<u8> optval(ctx.GetWriteBufferSize());
|
std::vector<u8> optval(ctx.GetWriteBufferSize());
|
||||||
|
|
||||||
LOG_DEBUG(Service, "called. fd={} level={} optname={:#x} len={:#x}", fd, level, optname,
|
LOG_DEBUG(Service, "called. fd={} level={} optname={:#x} len={:#x}", fd, level, optname, optval.size());
|
||||||
optval.size());
|
const Network::Errno err = GetSockOptImpl(fd, level, optname, optval);
|
||||||
|
|
||||||
const Errno err = GetSockOptImpl(fd, level, optname, optval);
|
|
||||||
|
|
||||||
ctx.WriteBuffer(optval);
|
ctx.WriteBuffer(optval);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 5};
|
IPC::ResponseBuilder rb{ctx, 5};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push<s32>(err == Errno::SUCCESS ? 0 : -1);
|
rb.Push<s32>(err == Network::Errno::E_SUCCESS ? 0 : -1);
|
||||||
rb.PushEnum(err);
|
rb.PushEnum(err);
|
||||||
rb.Push<u32>(static_cast<u32>(optval.size()));
|
rb.Push<u32>(static_cast<u32>(optval.size()));
|
||||||
}
|
}
|
||||||
@@ -333,7 +336,7 @@ void BSD_USA::Fcntl(HLERequestContext& ctx) {
|
|||||||
|
|
||||||
LOG_DEBUG(Service, "called. fd={} cmd={} arg={}", fd, cmd, arg);
|
LOG_DEBUG(Service, "called. fd={} cmd={} arg={}", fd, cmd, arg);
|
||||||
|
|
||||||
const auto [ret, bsd_errno] = FcntlImpl(fd, static_cast<FcntlCmd>(cmd), arg);
|
const auto [ret, bsd_errno] = FcntlImpl(fd, Network::FcntlCmd(cmd), arg);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
@@ -345,13 +348,11 @@ void BSD_USA::SetSockOpt(HLERequestContext& ctx) {
|
|||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
const u32 level = rp.Pop<u32>();
|
const Network::SocketLevel level = Network::SocketLevel(rp.Pop<u32>());
|
||||||
const OptName optname = static_cast<OptName>(rp.Pop<u32>());
|
const Network::OptName optname = Network::OptName(rp.Pop<u32>());
|
||||||
const auto optval = ctx.ReadBuffer();
|
const auto optval = ctx.ReadBuffer();
|
||||||
|
|
||||||
LOG_DEBUG(Service, "called. fd={} level={} optname={:#x} optlen={}", fd, level,
|
LOG_DEBUG(Service, "called. fd={} level={} optname={:#x} optlen={}", fd, level, u32(optname), optval.size());
|
||||||
static_cast<u32>(optname), optval.size());
|
|
||||||
|
|
||||||
BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval));
|
BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,7 +474,7 @@ void BSD_USA::DuplicateSocket(HLERequestContext& ctx) {
|
|||||||
|
|
||||||
struct OutputParameters {
|
struct OutputParameters {
|
||||||
s32 ret;
|
s32 ret;
|
||||||
Errno bsd_errno;
|
Network::Errno bsd_errno;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(OutputParameters) == 0x8);
|
static_assert(sizeof(OutputParameters) == 0x8);
|
||||||
|
|
||||||
@@ -485,7 +486,7 @@ void BSD_USA::DuplicateSocket(HLERequestContext& ctx) {
|
|||||||
if (is_user) {
|
if (is_user) {
|
||||||
rb.PushRaw(OutputParameters{
|
rb.PushRaw(OutputParameters{
|
||||||
.ret = 0,
|
.ret = 0,
|
||||||
.bsd_errno = Errno::INVAL,
|
.bsd_errno = Network::Errno::E_INVAL,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -494,10 +495,10 @@ void BSD_USA::DuplicateSocket(HLERequestContext& ctx) {
|
|||||||
if (auto* res = std::get_if<s32>(&res_v)) {
|
if (auto* res = std::get_if<s32>(&res_v)) {
|
||||||
rb.PushRaw(OutputParameters{
|
rb.PushRaw(OutputParameters{
|
||||||
.ret = *res,
|
.ret = *res,
|
||||||
.bsd_errno = Errno::SUCCESS,
|
.bsd_errno = Network::Errno::E_SUCCESS,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
auto* err = std::get_if<Errno>(&res_v);
|
auto* err = std::get_if<Network::Errno>(&res_v);
|
||||||
rb.PushRaw(OutputParameters{
|
rb.PushRaw(OutputParameters{
|
||||||
.ret = 0,
|
.ret = 0,
|
||||||
.bsd_errno = *err,
|
.bsd_errno = *err,
|
||||||
@@ -512,7 +513,7 @@ void BSD_USA::EventFd(HLERequestContext& ctx) {
|
|||||||
|
|
||||||
LOG_WARNING(Service, "(STUBBED) called. initval={}, flags={}", initval, flags);
|
LOG_WARNING(Service, "(STUBBED) called. initval={}, flags={}", initval, flags);
|
||||||
|
|
||||||
BuildErrnoResponse(ctx, Errno::SUCCESS);
|
BuildErrnoResponse(ctx, Network::Errno::E_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Work>
|
template <typename Work>
|
||||||
@@ -521,132 +522,143 @@ void BSD_USA::ExecuteWork(HLERequestContext& ctx, Work work) {
|
|||||||
work.Response(ctx);
|
work.Response(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD_USA::SocketImpl(Domain domain, Type type, Protocol protocol) {
|
std::pair<s32, Network::Errno> BSD_USA::SocketImpl(Network::Domain domain, Network::Type type, Network::Protocol protocol) {
|
||||||
// user bsd:u has restrictions on SOCK_SEQPACKET and SOCK_RAW
|
// user bsd:u has restrictions on SOCK_SEQPACKET and SOCK_RAW
|
||||||
if (is_user && (type == Type::SEQPACKET || type == Type::RAW)) {
|
LOG_DEBUG(Network, "domain={},type={},protocol={}", u32(domain), u32(type), u32(protocol));
|
||||||
if (type == Type::RAW && domain == Domain::INET && protocol == Protocol::ICMP) {
|
if (is_user && (type == Network::Type::SEQPACKET || type == Network::Type::RAW)) {
|
||||||
|
if (type == Network::Type::RAW && domain == Network::Domain::INET && protocol == Network::Protocol::ICMP) {
|
||||||
// fine, can use on bsd:s and bsd:u
|
// fine, can use on bsd:s and bsd:u
|
||||||
} else {
|
} else {
|
||||||
return {-1, Errno::INVAL};
|
return {-1, Network::Errno::E_INVAL};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[maybe_unused]] const bool unk_flag = (static_cast<u32>(type) & 0x20000000) != 0;
|
[[maybe_unused]] const bool unk_flag = (u32(type) & 0x20000000) != 0;
|
||||||
UNIMPLEMENTED_IF_MSG(unk_flag, "Unknown flag in type");
|
UNIMPLEMENTED_IF_MSG(unk_flag, "Unknown flag in type");
|
||||||
type = static_cast<Type>(static_cast<u32>(type) & ~0x20000000);
|
type = Network::Type(u32(type) & ~0x20000000);
|
||||||
|
|
||||||
const s32 fd = FindFreeFileDescriptorHandle();
|
const s32 fd = FindFreeFileDescriptorHandle();
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
LOG_ERROR(Service, "No more file descriptors available");
|
LOG_ERROR(Service, "No more file descriptors available");
|
||||||
return {-1, Errno::MFILE};
|
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};
|
||||||
}
|
}
|
||||||
|
|
||||||
file_descriptors[fd] = FileDescriptor{};
|
file_descriptors[fd] = FileDescriptor{};
|
||||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||||
|
|
||||||
// ENONMEM might be thrown here
|
// ENONMEM might be thrown here
|
||||||
|
LOG_INFO(Service, "New socket fd={},domain={},type={},prot={}", fd, domain, type, protocol);
|
||||||
|
|
||||||
LOG_INFO(Service, "New socket fd={}", fd);
|
// 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?
|
||||||
auto room_member = Network::GetRoomMember().lock();
|
auto room_member = Network::GetRoomMember().lock();
|
||||||
if (room_member && room_member->IsConnected()) {
|
if ((protocol != Network::Protocol::ICMP && protocol != Network::Protocol::ICMPV6)
|
||||||
|
&& (room_member && room_member->IsConnected())) {
|
||||||
descriptor.socket = std::make_shared<Network::ProxySocket>();
|
descriptor.socket = std::make_shared<Network::ProxySocket>();
|
||||||
|
descriptor.socket->fd = fd;
|
||||||
} else {
|
} else {
|
||||||
descriptor.socket = std::make_shared<Network::Socket>();
|
descriptor.socket = std::make_shared<Network::Socket>();
|
||||||
}
|
}
|
||||||
|
auto const bsd_errno = descriptor.socket->Initialize(domain, type, protocol);
|
||||||
|
|
||||||
descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(protocol));
|
#if defined(__unix__) && !defined(__APPLE__)
|
||||||
descriptor.is_connection_based = IsConnectionBased(type);
|
// ...only unix has this issue it seems, ICMP works otherwise fine on win
|
||||||
|
if ((protocol == Network::Protocol::ICMP || protocol == Network::Protocol::ICMPV6)
|
||||||
if (Settings::values.airplane_mode.GetValue() && descriptor.is_connection_based) {
|
&& bsd_errno != Network::Errno::E_SUCCESS) {
|
||||||
LOG_ERROR(Service, "Airplane mode is enabled, cannot create socket");
|
LOG_WARNING(Network, "Using ICMP emulated socket");
|
||||||
return {-1, Errno::NOTCONN};
|
descriptor.socket = std::make_shared<Network::IcmpSocket>();
|
||||||
|
descriptor.socket->fd = fd;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return {fd, Errno::SUCCESS};
|
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};
|
||||||
|
}
|
||||||
|
return {fd, Network::Errno::E_SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD_USA::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
|
std::pair<s32, Network::Errno> BSD_USA::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, s32 nfds, s32 timeout) {
|
||||||
s32 nfds, s32 timeout) {
|
LOG_DEBUG(Network, "nfds={},timeout={}", nfds, timeout);
|
||||||
if (nfds <= 0) {
|
if (nfds <= 0) {
|
||||||
// When no entries are provided, -1 is returned with errno zero
|
// When no entries are provided, -1 is returned with errno zero
|
||||||
return {-1, Errno::SUCCESS};
|
return {-1, Network::Errno::E_SUCCESS};
|
||||||
}
|
}
|
||||||
if (read_buffer.size() < nfds * sizeof(PollFD)) {
|
if (read_buffer.size() < nfds * sizeof(Network::PollFD)) {
|
||||||
return {-1, Errno::INVAL};
|
return {-1, Network::Errno::E_INVAL};
|
||||||
}
|
}
|
||||||
if (write_buffer.size() < nfds * sizeof(PollFD)) {
|
if (write_buffer.size() < nfds * sizeof(Network::PollFD)) {
|
||||||
return {-1, Errno::INVAL};
|
return {-1, Network::Errno::E_INVAL};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<PollFD> fds(nfds);
|
std::span<const Network::PollFD> in_fds(reinterpret_cast<const Network::PollFD*>(read_buffer.data()), nfds);
|
||||||
std::memcpy(fds.data(), read_buffer.data(), nfds * sizeof(PollFD));
|
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());
|
||||||
|
|
||||||
if (timeout >= 0) {
|
if (timeout >= 0) {
|
||||||
const s64 seconds = timeout / 1000;
|
const s64 seconds = timeout / 1000;
|
||||||
const u64 nanoseconds = 1'000'000 * (static_cast<u64>(timeout) % 1000);
|
const u64 nanoseconds = 1'000'000 * (u64(timeout) % 1000);
|
||||||
|
|
||||||
if (seconds < 0) {
|
if (seconds < 0) {
|
||||||
return {-1, Errno::INVAL};
|
return {-1, Network::Errno::E_INVAL};
|
||||||
}
|
}
|
||||||
if (nanoseconds > 999'999'999) {
|
if (nanoseconds > 999'999'999) {
|
||||||
return {-1, Errno::INVAL};
|
return {-1, Network::Errno::E_INVAL};
|
||||||
}
|
}
|
||||||
} else if (timeout != -1) {
|
} else if (timeout != -1) {
|
||||||
return {-1, Errno::INVAL};
|
return {-1, Network::Errno::E_INVAL};
|
||||||
}
|
}
|
||||||
|
|
||||||
for (PollFD& pollfd : fds) {
|
for (size_t i = 0; i < in_fds.size(); ++i) {
|
||||||
ASSERT(False(pollfd.revents));
|
ASSERT(out_fds[i].fd == in_fds[i].fd && False(in_fds[i].revents));
|
||||||
|
if (!IsFileDescriptorValid(in_fds[i].fd)) {
|
||||||
if (pollfd.fd > static_cast<s32>(MAX_FD) || pollfd.fd < 0) {
|
out_fds[i].revents = {};
|
||||||
LOG_ERROR(Service, "File descriptor handle={} is invalid", pollfd.fd);
|
if (!file_descriptors[in_fds[i].fd])
|
||||||
pollfd.revents = PollEvents{};
|
out_fds[i].revents = Network::PollEvents::NVAL;
|
||||||
return {0, Errno::SUCCESS};
|
return {0, Network::Errno::E_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::PollFD> host_pollfds(fds.size());
|
std::vector<Network::HostPollFD> host_pollfds(in_fds.size());
|
||||||
std::transform(fds.begin(), fds.end(), host_pollfds.begin(), [](PollFD pollfd) {
|
std::transform(in_fds.begin(), in_fds.end(), host_pollfds.begin(), [](auto const e) {
|
||||||
Network::PollFD result;
|
Network::HostPollFD result{};
|
||||||
result.socket = file_descriptors[pollfd.fd]->socket.get();
|
result.socket = file_descriptors[e.fd]->socket.get();
|
||||||
result.events = Translate(pollfd.events);
|
result.events = e.events;
|
||||||
result.revents = Network::PollEvents{};
|
result.revents = {};
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
auto const res = Network::Poll(host_pollfds, timeout);
|
||||||
const auto result = Network::Poll(host_pollfds, timeout);
|
for (size_t i = 0; i < in_fds.size(); ++i)
|
||||||
|
out_fds[i].revents = host_pollfds[i].revents;
|
||||||
const size_t num = host_pollfds.size();
|
return res;
|
||||||
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, Errno> BSD_USA::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
|
std::pair<s32, Network::Errno> BSD_USA::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||||
|
LOG_DEBUG(Network, "fd={}", fd);
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return {-1, Errno::BADF};
|
return {-1, Network::Errno::E_BADF};
|
||||||
}
|
}
|
||||||
|
|
||||||
const s32 new_fd = FindFreeFileDescriptorHandle();
|
const s32 new_fd = FindFreeFileDescriptorHandle();
|
||||||
if (new_fd < 0) {
|
if (new_fd < 0) {
|
||||||
LOG_ERROR(Service, "No more file descriptors available");
|
LOG_ERROR(Service, "No more file descriptors available");
|
||||||
return {-1, Errno::MFILE};
|
return {-1, Network::Errno::E_MFILE};
|
||||||
}
|
}
|
||||||
|
|
||||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||||
auto [result, bsd_errno] = descriptor.socket->Accept();
|
auto [result, bsd_errno] = descriptor.socket->Accept();
|
||||||
if (bsd_errno != Network::Errno::SUCCESS) {
|
if (bsd_errno != Network::Errno::E_SUCCESS) {
|
||||||
return {-1, Translate(bsd_errno)};
|
return {-1, bsd_errno};
|
||||||
}
|
}
|
||||||
|
|
||||||
file_descriptors[new_fd] = FileDescriptor{};
|
file_descriptors[new_fd] = FileDescriptor{};
|
||||||
@@ -654,268 +666,222 @@ std::pair<s32, Errno> BSD_USA::AcceptImpl(s32 fd, std::vector<u8>& write_buffer)
|
|||||||
new_descriptor.socket = std::move(result.socket);
|
new_descriptor.socket = std::move(result.socket);
|
||||||
new_descriptor.is_connection_based = descriptor.is_connection_based;
|
new_descriptor.is_connection_based = descriptor.is_connection_based;
|
||||||
|
|
||||||
const SockAddrIn guest_addr_in = Translate(result.sockaddr_in);
|
PutValue(write_buffer, result.sockaddr_in);
|
||||||
PutValue(write_buffer, guest_addr_in);
|
return {new_fd, Network::Errno::E_SUCCESS};
|
||||||
|
|
||||||
return {new_fd, Errno::SUCCESS};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD_USA::BindImpl(s32 fd, std::span<const u8> addr) {
|
Network::Errno BSD_USA::BindImpl(s32 fd, std::span<const u8> addr) {
|
||||||
|
LOG_DEBUG(Network, "fd={}", fd);
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
ASSERT(addr.size() >= 16);
|
ASSERT(addr.size() >= 16);
|
||||||
if (!file_descriptors[fd]->socket) {
|
if (!file_descriptors[fd]->socket) {
|
||||||
LOG_WARNING(Service, "Uninitialized socket");
|
LOG_WARNING(Service, "Uninitialized socket");
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto addr_in = GetValue<SockAddrIn>(addr);
|
auto addr_in = GetValue<Network::SockAddrIn>(addr);
|
||||||
|
return file_descriptors[fd]->socket->Bind(addr_in);
|
||||||
return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD_USA::ConnectImpl(s32 fd, std::span<const u8> addr) {
|
Network::Errno BSD_USA::ConnectImpl(s32 fd, std::span<const u8> addr) {
|
||||||
|
LOG_DEBUG(Network, "fd={}", fd);
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(addr.size() >= 16);
|
ASSERT(addr.size() >= 16);
|
||||||
if (!file_descriptors[fd]->socket) {
|
if (!file_descriptors[fd]->socket) {
|
||||||
LOG_WARNING(Service, "Uninitialized socket");
|
LOG_WARNING(Service, "Uninitialized socket");
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto addr_in = GetValue<SockAddrIn>(addr);
|
auto addr_in = GetValue<Network::SockAddrIn>(addr);
|
||||||
|
const Network::Errno result = file_descriptors[fd]->socket->Connect(addr_in);
|
||||||
const Errno result = Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in)));
|
if (result == Network::Errno::E_ISCONN) {
|
||||||
|
|
||||||
if (result == Errno::ISCONN) {
|
|
||||||
LOG_DEBUG(Service, "returned ISCONN - socket already connected");
|
LOG_DEBUG(Service, "returned ISCONN - socket already connected");
|
||||||
return Errno::SUCCESS;
|
return Network::Errno::E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD_USA::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
Network::Errno BSD_USA::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||||
|
LOG_DEBUG(Network, "fd={}", fd);
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file_descriptors[fd]->socket) {
|
if (!file_descriptors[fd]->socket) {
|
||||||
LOG_WARNING(Service, "Uninitialized socket");
|
LOG_WARNING(Service, "Uninitialized socket");
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetPeerName();
|
const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetPeerName();
|
||||||
if (bsd_errno != Network::Errno::SUCCESS) {
|
if (bsd_errno != Network::Errno::E_SUCCESS) {
|
||||||
return Translate(bsd_errno);
|
return bsd_errno;
|
||||||
}
|
}
|
||||||
const SockAddrIn guest_addrin = Translate(addr_in);
|
ASSERT(write_buffer.size() >= addr_in.len);
|
||||||
|
write_buffer.resize(addr_in.len);
|
||||||
ASSERT(write_buffer.size() >= sizeof(guest_addrin));
|
PutValue(write_buffer, addr_in);
|
||||||
write_buffer.resize(sizeof(guest_addrin));
|
return bsd_errno;
|
||||||
PutValue(write_buffer, guest_addrin);
|
|
||||||
return Translate(bsd_errno);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD_USA::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
Network::Errno BSD_USA::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||||
|
LOG_DEBUG(Network, "fd={}", fd);
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file_descriptors[fd]->socket) {
|
if (!file_descriptors[fd]->socket) {
|
||||||
LOG_WARNING(Service, "Uninitialized socket");
|
LOG_WARNING(Service, "Uninitialized socket");
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetSockName();
|
const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetSockName();
|
||||||
if (bsd_errno != Network::Errno::SUCCESS) {
|
if (bsd_errno != Network::Errno::E_SUCCESS) {
|
||||||
return Translate(bsd_errno);
|
return bsd_errno;
|
||||||
}
|
}
|
||||||
const SockAddrIn guest_addrin = Translate(addr_in);
|
ASSERT(write_buffer.size() >= addr_in.len);
|
||||||
|
write_buffer.resize(addr_in.len);
|
||||||
ASSERT(write_buffer.size() >= sizeof(guest_addrin));
|
PutValue(write_buffer, addr_in);
|
||||||
write_buffer.resize(sizeof(guest_addrin));
|
return bsd_errno;
|
||||||
PutValue(write_buffer, guest_addrin);
|
|
||||||
return Translate(bsd_errno);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD_USA::ListenImpl(s32 fd, s32 backlog) {
|
Network::Errno BSD_USA::ListenImpl(s32 fd, s32 backlog) {
|
||||||
|
LOG_DEBUG(Network, "fd={},backlog={}", fd, backlog);
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
if (!file_descriptors[fd]->socket) {
|
if (!file_descriptors[fd]->socket) {
|
||||||
LOG_WARNING(Service, "Uninitialized socket");
|
LOG_WARNING(Service, "Uninitialized socket");
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
return Translate(file_descriptors[fd]->socket->Listen(backlog));
|
return file_descriptors[fd]->socket->Listen(backlog);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD_USA::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
|
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);
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return {-1, Errno::BADF};
|
return {-1, Network::Errno::E_BADF};
|
||||||
}
|
}
|
||||||
if (!file_descriptors[fd]->socket) {
|
if (!file_descriptors[fd]->socket) {
|
||||||
LOG_WARNING(Service, "Uninitialized socket");
|
LOG_WARNING(Service, "Uninitialized socket");
|
||||||
return {-1, Errno::BADF};
|
return {-1, Network::Errno::E_BADF};
|
||||||
}
|
}
|
||||||
|
|
||||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case FcntlCmd::GETFL:
|
case Network::FcntlCmd::GETFL:
|
||||||
ASSERT(arg == 0);
|
ASSERT(arg == 0);
|
||||||
return {descriptor.flags, Errno::SUCCESS};
|
return {descriptor.flags, Network::Errno::E_SUCCESS};
|
||||||
case FcntlCmd::SETFL: {
|
case Network::FcntlCmd::SETFL: {
|
||||||
const bool enable = (arg & Network::FLAG_O_NONBLOCK) != 0;
|
const bool enable = (arg & u32(Network::FcntlFlags::NONBLOCK_NX)) != 0;
|
||||||
const Errno bsd_errno = Translate(descriptor.socket->SetNonBlock(enable));
|
const Network::Errno bsd_errno = descriptor.socket->SetNonBlock(enable);
|
||||||
if (bsd_errno != Errno::SUCCESS) {
|
if (bsd_errno != Network::Errno::E_SUCCESS) {
|
||||||
return {-1, bsd_errno};
|
return {-1, bsd_errno};
|
||||||
}
|
}
|
||||||
descriptor.flags = arg;
|
descriptor.flags = arg;
|
||||||
return {0, Errno::SUCCESS};
|
return {0, Network::Errno::E_SUCCESS};
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
UNIMPLEMENTED_MSG("Unimplemented cmd={}", cmd);
|
UNIMPLEMENTED_MSG("Unimplemented cmd={}", cmd);
|
||||||
return {-1, Errno::SUCCESS};
|
return {-1, Network::Errno::E_SUCCESS};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD_USA::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval) {
|
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));
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
if (!file_descriptors[fd]->socket) {
|
if (!file_descriptors[fd]->socket) {
|
||||||
LOG_WARNING(Service, "Uninitialized socket");
|
LOG_WARNING(Service, "Uninitialized socket");
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (level != static_cast<u32>(SocketLevel::SOCKET)) {
|
if (level != Network::SocketLevel::SOCKET) {
|
||||||
UNIMPLEMENTED_MSG("Unknown getsockopt level");
|
LOG_WARNING(Service, "(stubbed) level fd={}, level={}, optname={}", fd, level, optname);
|
||||||
return Errno::SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
|
Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
|
||||||
|
|
||||||
switch (optname) {
|
switch (optname) {
|
||||||
case OptName::ERROR_: {
|
case Network::OptName::ERROR_: {
|
||||||
auto [pending_err, getsockopt_err] = socket->GetPendingError();
|
auto [pending_err, getsockopt_err] = socket->GetPendingError();
|
||||||
if (getsockopt_err == Network::Errno::SUCCESS) {
|
if (getsockopt_err == Network::Errno::E_SUCCESS) {
|
||||||
Errno translated_pending_err = Translate(pending_err);
|
|
||||||
ASSERT_OR_EXECUTE_MSG(
|
ASSERT_OR_EXECUTE_MSG(
|
||||||
optval.size() == sizeof(Errno), { return Errno::INVAL; },
|
optval.size() == sizeof(Network::Errno), { return Network::Errno::E_INVAL; },
|
||||||
"Incorrect getsockopt option size");
|
"Incorrect getsockopt option size");
|
||||||
optval.resize(sizeof(Errno));
|
optval.resize(sizeof(Network::Errno));
|
||||||
PutValue(optval, translated_pending_err);
|
PutValue(optval, pending_err);
|
||||||
}
|
}
|
||||||
return Translate(getsockopt_err);
|
return getsockopt_err;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
UNIMPLEMENTED_MSG("Unimplemented optname={}", optname);
|
UNIMPLEMENTED_MSG("Unimplemented optname={}", optname);
|
||||||
return Errno::SUCCESS;
|
return Network::Errno::E_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD_USA::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval) {
|
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);
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
if (!file_descriptors[fd]->socket) {
|
if (!file_descriptors[fd]->socket) {
|
||||||
LOG_WARNING(Service, "Uninitialized socket");
|
LOG_WARNING(Service, "Uninitialized socket");
|
||||||
return Errno::BADF;
|
return Network::Errno::E_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();
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD_USA::ShutdownImpl(s32 fd, s32 how) {
|
Network::Errno BSD_USA::ShutdownImpl(s32 fd, s32 how) {
|
||||||
|
LOG_DEBUG(Network, "fd={},how={}", fd, how);
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
if (!file_descriptors[fd]->socket) {
|
if (!file_descriptors[fd]->socket) {
|
||||||
LOG_WARNING(Service, "Uninitialized socket");
|
LOG_WARNING(Service, "Uninitialized socket");
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
const Network::ShutdownHow host_how = Translate(static_cast<ShutdownHow>(how));
|
return file_descriptors[fd]->socket->Shutdown(Network::ShutdownHow(how));
|
||||||
return Translate(file_descriptors[fd]->socket->Shutdown(host_how));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD_USA::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
|
std::pair<s32, Network::Errno> BSD_USA::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
|
||||||
|
LOG_DEBUG(Network, "fd={},flags={}", fd, flags);
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return {-1, Errno::BADF};
|
return {-1, Network::Errno::E_BADF};
|
||||||
}
|
}
|
||||||
|
|
||||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||||
|
|
||||||
// Apply flags
|
// Apply flags
|
||||||
using Network::FLAG_MSG_DONTWAIT;
|
if ((flags & u32(Network::MsgOpt::DONTWAIT)) != 0) {
|
||||||
using Network::FLAG_O_NONBLOCK;
|
flags &= ~u32(Network::MsgOpt::DONTWAIT);
|
||||||
if ((flags & FLAG_MSG_DONTWAIT) != 0) {
|
if ((descriptor.flags & u32(Network::FcntlFlags::NONBLOCK_NX)) == 0) {
|
||||||
flags &= ~FLAG_MSG_DONTWAIT;
|
|
||||||
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
|
|
||||||
descriptor.socket->SetNonBlock(true);
|
descriptor.socket->SetNonBlock(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto [ret, bsd_errno] = Translate(descriptor.socket->Recv(flags, message));
|
const auto [ret, bsd_errno] = descriptor.socket->Recv(flags, message);
|
||||||
|
|
||||||
// Restore original state
|
// Restore original state
|
||||||
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
|
if ((descriptor.flags & u32(Network::FcntlFlags::NONBLOCK_NX)) == 0)
|
||||||
descriptor.socket->SetNonBlock(false);
|
descriptor.socket->SetNonBlock(false);
|
||||||
}
|
|
||||||
|
|
||||||
return {ret, bsd_errno};
|
return {ret, bsd_errno};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD_USA::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
|
std::pair<s32, Network::Errno> BSD_USA::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message, std::vector<u8>& addr) {
|
||||||
std::vector<u8>& addr) {
|
LOG_DEBUG(Network, "fd={},flags={}", fd, flags);
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd))
|
||||||
return {-1, Errno::BADF};
|
return {-1, Network::Errno::E_BADF};
|
||||||
}
|
if (message.size() == 0)
|
||||||
|
return {0, Network::Errno::E_SUCCESS};
|
||||||
|
if (!std::in_range<u32>(message.size()))
|
||||||
|
return {-1, Network::Errno::E_FAULT};
|
||||||
|
|
||||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||||
|
|
||||||
@@ -929,79 +895,75 @@ std::pair<s32, Errno> BSD_USA::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>&
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply flags
|
// Apply flags
|
||||||
using Network::FLAG_MSG_DONTWAIT;
|
auto const is_nonblock = descriptor.socket->GetNonBlock();
|
||||||
using Network::FLAG_O_NONBLOCK;
|
auto const f_dontwait = (flags & u32(Network::MsgOpt::DONTWAIT)) != 0;
|
||||||
if ((flags & FLAG_MSG_DONTWAIT) != 0) {
|
auto const f_waitall = (flags & u32(Network::MsgOpt::WAITALL)) != 0;
|
||||||
flags &= ~FLAG_MSG_DONTWAIT;
|
// DONTWAIT set clears WAITALL, if socket is non-blocking it also clears WAITALL
|
||||||
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
|
if (f_dontwait || (f_waitall && is_nonblock))
|
||||||
descriptor.socket->SetNonBlock(true);
|
flags &= ~u32(Network::MsgOpt::WAITALL);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto [ret, bsd_errno] = Translate(descriptor.socket->RecvFrom(flags, message, p_addr_in));
|
if (f_dontwait) descriptor.socket->SetNonBlock(true); //set non-block
|
||||||
|
const auto [ret, bsd_errno] = descriptor.socket->RecvFrom(flags, message, p_addr_in);
|
||||||
// Restore original state
|
if (f_dontwait) descriptor.socket->SetNonBlock(is_nonblock); //restore
|
||||||
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
|
|
||||||
descriptor.socket->SetNonBlock(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p_addr_in) {
|
if (p_addr_in) {
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
addr.clear();
|
addr.clear();
|
||||||
} else {
|
} else {
|
||||||
ASSERT(addr.size() >= 16);
|
ASSERT(addr.size() >= 16);
|
||||||
const SockAddrIn result = Translate(addr_in);
|
PutValue(addr, addr_in);
|
||||||
PutValue(addr, result);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {ret, bsd_errno};
|
return {ret, bsd_errno};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD_USA::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
|
std::pair<s32, Network::Errno> BSD_USA::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
|
||||||
|
LOG_DEBUG(Network, "fd={},flags={}", fd, flags);
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return {-1, Errno::BADF};
|
return {-1, Network::Errno::E_BADF};
|
||||||
}
|
}
|
||||||
if (!file_descriptors[fd]->socket) {
|
if (!file_descriptors[fd]->socket) {
|
||||||
LOG_WARNING(Service, "Uninitialized socket");
|
LOG_WARNING(Service, "Uninitialized socket");
|
||||||
return {-1, Errno::BADF};
|
return {-1, Network::Errno::E_BADF};
|
||||||
}
|
}
|
||||||
return Translate(file_descriptors[fd]->socket->Send(message, flags));
|
return file_descriptors[fd]->socket->Send(message, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD_USA::SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
|
std::pair<s32, Network::Errno> BSD_USA::SendToImpl(s32 fd, u32 flags, std::span<const u8> message, std::span<const u8> addr) {
|
||||||
std::span<const u8> addr) {
|
LOG_DEBUG(Network, "fd={},flags={}", fd, flags);
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return {-1, Errno::BADF};
|
return {-1, Network::Errno::E_BADF};
|
||||||
}
|
}
|
||||||
if (!file_descriptors[fd]->socket) {
|
if (!file_descriptors[fd]->socket) {
|
||||||
LOG_WARNING(Service, "Uninitialized socket");
|
LOG_WARNING(Service, "Uninitialized socket");
|
||||||
return {-1, Errno::BADF};
|
return {-1, Network::Errno::E_BADF};
|
||||||
}
|
}
|
||||||
|
|
||||||
Network::SockAddrIn addr_in;
|
Network::SockAddrIn addr_in{};
|
||||||
Network::SockAddrIn* p_addr_in = nullptr;
|
Network::SockAddrIn* p_addr_in = nullptr;
|
||||||
if (!addr.empty()) {
|
if (!addr.empty()) {
|
||||||
ASSERT(addr.size() >= 16);
|
ASSERT(addr.size() >= 16);
|
||||||
auto guest_addr_in = GetValue<SockAddrIn>(addr);
|
auto guest_addr_in = GetValue<Network::SockAddrIn>(addr);
|
||||||
addr_in = Translate(guest_addr_in);
|
addr_in = guest_addr_in;
|
||||||
p_addr_in = &addr_in;
|
p_addr_in = &addr_in;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Translate(file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in));
|
return file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD_USA::CloseImpl(s32 fd) {
|
Network::Errno BSD_USA::CloseImpl(s32 fd) {
|
||||||
|
LOG_DEBUG(Network, "fd={}", fd);
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
if (!file_descriptors[fd]->socket) {
|
if (!file_descriptors[fd]->socket) {
|
||||||
LOG_WARNING(Service, "Uninitialized socket");
|
LOG_WARNING(Service, "Uninitialized socket");
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Errno bsd_errno = Translate(file_descriptors[fd]->socket->Close());
|
auto const bsd_errno = file_descriptors[fd]->socket->Close();
|
||||||
if (bsd_errno != Errno::SUCCESS) {
|
if (bsd_errno != Network::Errno::E_SUCCESS) {
|
||||||
return bsd_errno;
|
return bsd_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1011,26 +973,27 @@ Errno BSD_USA::CloseImpl(s32 fd) {
|
|||||||
return bsd_errno;
|
return bsd_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::variant<s32, Errno> BSD_USA::DuplicateSocketImpl(s32 fd) {
|
std::variant<s32, Network::Errno> BSD_USA::DuplicateSocketImpl(s32 fd) {
|
||||||
|
LOG_DEBUG(Network, "fd={}", fd);
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Network::Errno::E_BADF;
|
||||||
}
|
}
|
||||||
|
// Don't use IsFileDescriptorValid as new_fd isn't a proper handle yet
|
||||||
const s32 new_fd = FindFreeFileDescriptorHandle();
|
if (s32 const new_fd = FindFreeFileDescriptorHandle(); new_fd >= 0) {
|
||||||
if (new_fd < 0) {
|
file_descriptors[new_fd] = FileDescriptor{
|
||||||
|
.socket = file_descriptors[fd]->socket,
|
||||||
|
.flags = file_descriptors[fd]->flags,
|
||||||
|
.is_connection_based = file_descriptors[fd]->is_connection_based,
|
||||||
|
};
|
||||||
|
return new_fd;
|
||||||
|
} else {
|
||||||
LOG_ERROR(Service, "No more file descriptors available");
|
LOG_ERROR(Service, "No more file descriptors available");
|
||||||
return Errno::MFILE;
|
return Network::Errno::E_MFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_descriptors[new_fd] = FileDescriptor{
|
|
||||||
.socket = file_descriptors[fd]->socket,
|
|
||||||
.flags = file_descriptors[fd]->flags,
|
|
||||||
.is_connection_based = file_descriptors[fd]->is_connection_based,
|
|
||||||
};
|
|
||||||
return new_fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::shared_ptr<Network::SocketBase>> BSD_USA::GetSocket(s32 fd) {
|
std::optional<std::shared_ptr<Network::SocketBase>> BSD_USA::GetSocket(s32 fd) {
|
||||||
|
LOG_DEBUG(Network, "fd={}", fd);
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@@ -1042,41 +1005,40 @@ std::optional<std::shared_ptr<Network::SocketBase>> BSD_USA::GetSocket(s32 fd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s32 BSD_USA::FindFreeFileDescriptorHandle() noexcept {
|
s32 BSD_USA::FindFreeFileDescriptorHandle() noexcept {
|
||||||
for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) {
|
// first three file descriptors are reserved for:
|
||||||
if (!file_descriptors[fd]) {
|
// STDOUT_FILENO, STDIN_FILENO and STDERR_FILENO
|
||||||
|
for (s32 fd = 0; fd < s32(file_descriptors.size()); ++fd)
|
||||||
|
if (!file_descriptors[fd])
|
||||||
return fd;
|
return fd;
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BSD_USA::IsFileDescriptorValid(s32 fd) const noexcept {
|
bool BSD_USA::IsFileDescriptorValid(s32 fd) const noexcept {
|
||||||
if (fd > static_cast<s32>(MAX_FD) || fd < 0) {
|
if (fd < 0 || fd >= s32(file_descriptors.size())) {
|
||||||
LOG_ERROR(Service, "Invalid file descriptor handle={}", fd);
|
LOG_ERROR(Service, "Invalid handle={}", fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!file_descriptors[fd]) {
|
if (!file_descriptors[fd]) {
|
||||||
LOG_ERROR(Service, "File descriptor handle={} is not allocated", fd);
|
LOG_ERROR(Service, "handle={} is not allocated", fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD_USA::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept {
|
void BSD_USA::BuildErrnoResponse(HLERequestContext& ctx, Network::Errno bsd_errno) const noexcept {
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
|
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
|
rb.Push<s32>(bsd_errno == Network::Errno::E_SUCCESS ? 0 : -1);
|
||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD_USA::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
|
void BSD_USA::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
|
||||||
for (auto& optional_descriptor : file_descriptors) {
|
for (auto& optional_descriptor : file_descriptors) {
|
||||||
if (!optional_descriptor.has_value()) {
|
if (optional_descriptor.has_value()) {
|
||||||
continue;
|
FileDescriptor& descriptor = *optional_descriptor;
|
||||||
|
descriptor.socket.get()->HandleProxyPacket(packet);
|
||||||
}
|
}
|
||||||
FileDescriptor& descriptor = *optional_descriptor;
|
|
||||||
descriptor.socket.get()->HandleProxyPacket(packet);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/socket_types.h"
|
#include "core/internal_network/socket_types.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
#include "core/hle/service/sockets/sockets.h"
|
#include "core/hle/service/sockets/sockets.h"
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
@@ -35,8 +35,8 @@ public:
|
|||||||
// These methods are called from SSL; the first two are also called from
|
// These methods are called from SSL; the first two are also called from
|
||||||
// this class for the corresponding IPC methods.
|
// this class for the corresponding IPC methods.
|
||||||
// On the real device, the SSL service makes IPC calls to this service.
|
// On the real device, the SSL service makes IPC calls to this service.
|
||||||
std::variant<s32, Errno> DuplicateSocketImpl(s32 fd);
|
std::variant<s32, Network::Errno> DuplicateSocketImpl(s32 fd);
|
||||||
Errno CloseImpl(s32 fd);
|
Network::Errno CloseImpl(s32 fd);
|
||||||
std::optional<std::shared_ptr<Network::SocketBase>> GetSocket(s32 fd);
|
std::optional<std::shared_ptr<Network::SocketBase>> GetSocket(s32 fd);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -58,7 +58,7 @@ private:
|
|||||||
std::span<const u8> read_buffer;
|
std::span<const u8> read_buffer;
|
||||||
std::vector<u8> write_buffer;
|
std::vector<u8> write_buffer;
|
||||||
s32 ret{};
|
s32 ret{};
|
||||||
Errno bsd_errno{};
|
Network::Errno bsd_errno{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AcceptWork {
|
struct AcceptWork {
|
||||||
@@ -68,7 +68,7 @@ private:
|
|||||||
s32 fd;
|
s32 fd;
|
||||||
std::vector<u8> write_buffer;
|
std::vector<u8> write_buffer;
|
||||||
s32 ret{};
|
s32 ret{};
|
||||||
Errno bsd_errno{};
|
Network::Errno bsd_errno{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ConnectWork {
|
struct ConnectWork {
|
||||||
@@ -77,7 +77,7 @@ private:
|
|||||||
|
|
||||||
s32 fd;
|
s32 fd;
|
||||||
std::span<const u8> addr;
|
std::span<const u8> addr;
|
||||||
Errno bsd_errno{};
|
Network::Errno bsd_errno{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RecvWork {
|
struct RecvWork {
|
||||||
@@ -88,7 +88,7 @@ private:
|
|||||||
u32 flags;
|
u32 flags;
|
||||||
std::vector<u8> message;
|
std::vector<u8> message;
|
||||||
s32 ret{};
|
s32 ret{};
|
||||||
Errno bsd_errno{};
|
Network::Errno bsd_errno{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RecvFromWork {
|
struct RecvFromWork {
|
||||||
@@ -100,7 +100,7 @@ private:
|
|||||||
std::vector<u8> message;
|
std::vector<u8> message;
|
||||||
std::vector<u8> addr;
|
std::vector<u8> addr;
|
||||||
s32 ret{};
|
s32 ret{};
|
||||||
Errno bsd_errno{};
|
Network::Errno bsd_errno{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SendWork {
|
struct SendWork {
|
||||||
@@ -111,7 +111,7 @@ private:
|
|||||||
u32 flags;
|
u32 flags;
|
||||||
std::span<const u8> message;
|
std::span<const u8> message;
|
||||||
s32 ret{};
|
s32 ret{};
|
||||||
Errno bsd_errno{};
|
Network::Errno bsd_errno{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SendToWork {
|
struct SendToWork {
|
||||||
@@ -123,7 +123,7 @@ private:
|
|||||||
std::span<const u8> message;
|
std::span<const u8> message;
|
||||||
std::span<const u8> addr;
|
std::span<const u8> addr;
|
||||||
s32 ret{};
|
s32 ret{};
|
||||||
Errno bsd_errno{};
|
Network::Errno bsd_errno{};
|
||||||
};
|
};
|
||||||
|
|
||||||
void RegisterClient(HLERequestContext& ctx);
|
void RegisterClient(HLERequestContext& ctx);
|
||||||
@@ -155,29 +155,29 @@ private:
|
|||||||
template <typename Work>
|
template <typename Work>
|
||||||
void ExecuteWork(HLERequestContext& ctx, Work work);
|
void ExecuteWork(HLERequestContext& ctx, Work work);
|
||||||
|
|
||||||
std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol);
|
std::pair<s32, Network::Errno> SocketImpl(Network::Domain domain, Network::Type type, Network::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, Network::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);
|
std::pair<s32, Network::Errno> AcceptImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||||
Errno BindImpl(s32 fd, std::span<const u8> addr);
|
Network::Errno BindImpl(s32 fd, std::span<const u8> addr);
|
||||||
Errno ConnectImpl(s32 fd, std::span<const u8> addr);
|
Network::Errno ConnectImpl(s32 fd, std::span<const u8> addr);
|
||||||
Errno GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer);
|
Network::Errno GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||||
Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer);
|
Network::Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||||
Errno ListenImpl(s32 fd, s32 backlog);
|
Network::Errno ListenImpl(s32 fd, s32 backlog);
|
||||||
std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg);
|
std::pair<s32, Network::Errno> FcntlImpl(s32 fd, Network::FcntlCmd cmd, s32 arg);
|
||||||
Errno GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval);
|
Network::Errno GetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::vector<u8>& optval);
|
||||||
Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval);
|
Network::Errno SetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::span<const u8> optval);
|
||||||
Errno ShutdownImpl(s32 fd, s32 how);
|
Network::Errno ShutdownImpl(s32 fd, s32 how);
|
||||||
std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
|
std::pair<s32, Network::Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
|
||||||
std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
|
std::pair<s32, Network::Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
|
||||||
std::vector<u8>& addr);
|
std::vector<u8>& addr);
|
||||||
std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, std::span<const u8> message);
|
std::pair<s32, Network::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::pair<s32, Network::Errno> SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
|
||||||
std::span<const u8> addr);
|
std::span<const u8> addr);
|
||||||
|
|
||||||
s32 FindFreeFileDescriptorHandle() noexcept;
|
s32 FindFreeFileDescriptorHandle() noexcept;
|
||||||
bool IsFileDescriptorValid(s32 fd) const noexcept;
|
bool IsFileDescriptorValid(s32 fd) const noexcept;
|
||||||
|
|
||||||
void BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept;
|
void BuildErrnoResponse(HLERequestContext& ctx, Network::Errno bsd_errno) const noexcept;
|
||||||
|
|
||||||
static inline std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors{};
|
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; });
|
[&host](const std::string& domain) { return host.find(domain) != std::string::npos; });
|
||||||
}
|
}
|
||||||
|
|
||||||
static NetDbError GetAddrInfoErrorToNetDbError(GetAddrInfoError result) {
|
static NetDbError GetAddrInfoErrorToNetDbError(Network::GetAddrInfoError result) {
|
||||||
// These combinations have been verified on console (but are not
|
// These combinations have been verified on console (but are not
|
||||||
// exhaustive).
|
// exhaustive).
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case GetAddrInfoError::SUCCESS:
|
case Network::GetAddrInfoError::SUCCESS:
|
||||||
return NetDbError::Success;
|
return NetDbError::Success;
|
||||||
case GetAddrInfoError::AGAIN:
|
case Network::GetAddrInfoError::AGAIN:
|
||||||
return NetDbError::TryAgain;
|
return NetDbError::TryAgain;
|
||||||
case GetAddrInfoError::NODATA:
|
case Network::GetAddrInfoError::NODATA:
|
||||||
return NetDbError::HostNotFound;
|
return NetDbError::HostNotFound;
|
||||||
case GetAddrInfoError::SERVICE:
|
case Network::GetAddrInfoError::SERVICE:
|
||||||
return NetDbError::Success;
|
return NetDbError::Success;
|
||||||
default:
|
default:
|
||||||
return NetDbError::HostNotFound;
|
return NetDbError::HostNotFound;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Errno GetAddrInfoErrorToErrno(GetAddrInfoError result) {
|
static Network::Errno GetAddrInfoErrorToErrno(Network::GetAddrInfoError result) {
|
||||||
// These combinations have been verified on console (but are not
|
// These combinations have been verified on console (but are not
|
||||||
// exhaustive).
|
// exhaustive).
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case GetAddrInfoError::SUCCESS:
|
case Network::GetAddrInfoError::SUCCESS:
|
||||||
// Note: Sometimes a successful lookup sets errno to EADDRNOTAVAIL for
|
// Note: Sometimes a successful lookup sets errno to EADDRNOTAVAIL for
|
||||||
// some reason, but that doesn't seem useful to implement.
|
// some reason, but that doesn't seem useful to implement.
|
||||||
return Errno::SUCCESS;
|
return Network::Errno::E_SUCCESS;
|
||||||
case GetAddrInfoError::AGAIN:
|
case Network::GetAddrInfoError::AGAIN:
|
||||||
return Errno::SUCCESS;
|
return Network::Errno::E_SUCCESS;
|
||||||
case GetAddrInfoError::NODATA:
|
case Network::GetAddrInfoError::NODATA:
|
||||||
return Errno::SUCCESS;
|
return Network::Errno::E_SUCCESS;
|
||||||
case GetAddrInfoError::SERVICE:
|
case Network::GetAddrInfoError::SERVICE:
|
||||||
return Errno::INVAL;
|
return Network::Errno::E_INVAL;
|
||||||
default:
|
default:
|
||||||
return Errno::SUCCESS;
|
return Network::Errno::E_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,9 +155,7 @@ static void AppendNulTerminated(std::vector<u8>& vec, std::string_view str) {
|
|||||||
// host's gethostbyname, because it simplifies portability: e.g., getaddrinfo
|
// host's gethostbyname, because it simplifies portability: e.g., getaddrinfo
|
||||||
// behaves the same on Unix and Windows, unlike gethostbyname where Windows
|
// behaves the same on Unix and Windows, unlike gethostbyname where Windows
|
||||||
// doesn't implement h_errno.
|
// doesn't implement h_errno.
|
||||||
static std::vector<u8> SerializeAddrInfoAsHostEnt(const std::vector<Network::AddrInfo>& vec,
|
static std::vector<u8> SerializeAddrInfoAsHostEnt(std::span<const Network::AddrInfo> vec, std::string_view host) {
|
||||||
std::string_view host) {
|
|
||||||
|
|
||||||
std::vector<u8> data;
|
std::vector<u8> data;
|
||||||
// h_name: use the input hostname (append nul-terminated)
|
// h_name: use the input hostname (append nul-terminated)
|
||||||
AppendNulTerminated(data, host);
|
AppendNulTerminated(data, host);
|
||||||
@@ -165,12 +163,12 @@ static std::vector<u8> SerializeAddrInfoAsHostEnt(const std::vector<Network::Add
|
|||||||
|
|
||||||
Append<u32_be>(data, 0); // count of h_aliases
|
Append<u32_be>(data, 0); // count of h_aliases
|
||||||
// (If the count were nonzero, the aliases would be appended as nul-terminated here.)
|
// (If the count were nonzero, the aliases would be appended as nul-terminated here.)
|
||||||
Append<u16_be>(data, static_cast<u16>(Domain::INET)); // h_addrtype
|
Append<u16_be>(data, u16(Network::Domain::INET)); // h_addrtype
|
||||||
Append<u16_be>(data, sizeof(Network::IPv4Address)); // h_length
|
Append<u16_be>(data, sizeof(Network::IPv4Address)); // h_length
|
||||||
// h_addr_list:
|
// h_addr_list:
|
||||||
size_t count = vec.size();
|
size_t count = vec.size();
|
||||||
ASSERT(count <= UINT32_MAX);
|
ASSERT(count <= UINT32_MAX);
|
||||||
Append<u32_be>(data, static_cast<uint32_t>(count));
|
Append<u32_be>(data, u32(count));
|
||||||
for (const Network::AddrInfo& addrinfo : vec) {
|
for (const Network::AddrInfo& addrinfo : vec) {
|
||||||
// On the Switch, this is passed through htonl despite already being
|
// On the Switch, this is passed through htonl despite already being
|
||||||
// big-endian, so it ends up as little-endian.
|
// big-endian, so it ends up as little-endian.
|
||||||
@@ -182,7 +180,7 @@ static std::vector<u8> SerializeAddrInfoAsHostEnt(const std::vector<Network::Add
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::pair<u32, GetAddrInfoError> GetHostByNameRequestImpl(HLERequestContext& ctx) {
|
static std::pair<u32, Network::GetAddrInfoError> GetHostByNameRequestImpl(HLERequestContext& ctx) {
|
||||||
struct InputParameters {
|
struct InputParameters {
|
||||||
u8 use_nsd_resolve;
|
u8 use_nsd_resolve;
|
||||||
u32 cancel_handle;
|
u32 cancel_handle;
|
||||||
@@ -205,7 +203,7 @@ static std::pair<u32, GetAddrInfoError> GetHostByNameRequestImpl(HLERequestConte
|
|||||||
// Prevent resolution of Nintendo servers
|
// Prevent resolution of Nintendo servers
|
||||||
if (IsBlockedHost(host)) {
|
if (IsBlockedHost(host)) {
|
||||||
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
|
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
|
||||||
return {0, GetAddrInfoError::AGAIN};
|
return {0, Network::GetAddrInfoError::AGAIN};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto res_v = Network::GetAddressInfo(host, /*service*/ std::nullopt);
|
auto res_v = Network::GetAddressInfo(host, /*service*/ std::nullopt);
|
||||||
@@ -213,10 +211,10 @@ static std::pair<u32, GetAddrInfoError> GetHostByNameRequestImpl(HLERequestConte
|
|||||||
const std::vector<u8> data = SerializeAddrInfoAsHostEnt(*res, host);
|
const std::vector<u8> data = SerializeAddrInfoAsHostEnt(*res, host);
|
||||||
const u32 data_size = u32(data.size());
|
const u32 data_size = u32(data.size());
|
||||||
ctx.WriteBuffer(data, 0);
|
ctx.WriteBuffer(data, 0);
|
||||||
return {data_size, GetAddrInfoError::SUCCESS};
|
return {data_size, Network::GetAddrInfoError::SUCCESS};
|
||||||
}
|
}
|
||||||
auto* err = std::get_if<Network::GetAddrInfoError>(&res_v);
|
auto* err = std::get_if<Network::GetAddrInfoError>(&res_v);
|
||||||
return {0, Translate(*err)};
|
return {0, *err};
|
||||||
}
|
}
|
||||||
|
|
||||||
void SFDNSRES::GetHostByNameRequest(HLERequestContext& ctx) {
|
void SFDNSRES::GetHostByNameRequest(HLERequestContext& ctx) {
|
||||||
@@ -224,7 +222,7 @@ void SFDNSRES::GetHostByNameRequest(HLERequestContext& ctx) {
|
|||||||
|
|
||||||
struct OutputParameters {
|
struct OutputParameters {
|
||||||
NetDbError netdb_error;
|
NetDbError netdb_error;
|
||||||
Errno bsd_errno;
|
Network::Errno bsd_errno;
|
||||||
u32 data_size;
|
u32 data_size;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(OutputParameters) == 0xc);
|
static_assert(sizeof(OutputParameters) == 0xc);
|
||||||
@@ -244,7 +242,7 @@ void SFDNSRES::GetHostByNameRequestWithOptions(HLERequestContext& ctx) {
|
|||||||
struct OutputParameters {
|
struct OutputParameters {
|
||||||
u32 data_size;
|
u32 data_size;
|
||||||
NetDbError netdb_error;
|
NetDbError netdb_error;
|
||||||
Errno bsd_errno;
|
Network::Errno bsd_errno;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(OutputParameters) == 0xc);
|
static_assert(sizeof(OutputParameters) == 0xc);
|
||||||
|
|
||||||
@@ -257,24 +255,23 @@ void SFDNSRES::GetHostByNameRequestWithOptions(HLERequestContext& ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<u8> SerializeAddrInfo(const std::vector<Network::AddrInfo>& vec,
|
static std::vector<u8> SerializeAddrInfo(std::span<const Network::AddrInfo> vec, std::string_view host) {
|
||||||
std::string_view host) {
|
|
||||||
// Adapted from
|
// Adapted from
|
||||||
// https://github.com/switchbrew/libnx/blob/c5a9a909a91657a9818a3b7e18c9b91ff0cbb6e3/nx/source/runtime/resolver.c#L190
|
// https://github.com/switchbrew/libnx/blob/c5a9a909a91657a9818a3b7e18c9b91ff0cbb6e3/nx/source/runtime/resolver.c#L190
|
||||||
std::vector<u8> data;
|
std::vector<u8> data;
|
||||||
|
|
||||||
for (const Network::AddrInfo& addrinfo : vec) {
|
for (const Network::AddrInfo& addrinfo : vec) {
|
||||||
// serialized addrinfo:
|
// serialized addrinfo:
|
||||||
Append<u32_be>(data, 0xBEEFCAFE); // magic
|
Append<u32_be>(data, 0xBEEFCAFE); // magic
|
||||||
Append<u32_be>(data, 0); // ai_flags
|
Append<u32_be>(data, 0); // ai_flags
|
||||||
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.family))); // ai_family
|
Append<u32_be>(data, u32(addrinfo.family)); // ai_family
|
||||||
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.socket_type))); // ai_socktype
|
Append<u32_be>(data, u32(addrinfo.socket_type)); // ai_socktype
|
||||||
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.protocol))); // ai_protocol
|
Append<u32_be>(data, u32(addrinfo.protocol)); // ai_protocol
|
||||||
Append<u32_be>(data, 16); // ai_addrlen
|
Append<u32_be>(data, 16); // ai_addrlen
|
||||||
// ^ *not* sizeof(SerializedSockAddrIn), not that it matters since they're the same size
|
// ^ *not* sizeof(SerializedSockAddrIn), not that it matters since they're the same size
|
||||||
|
|
||||||
// ai_addr:
|
// ai_addr:
|
||||||
Append<u16_be>(data, static_cast<u16>(Translate(addrinfo.addr.family))); // sin_family
|
Append<u16_be>(data, u16(addrinfo.addr.family)); // sin_family
|
||||||
// On the Switch, the following fields are passed through htonl despite
|
// On the Switch, the following fields are passed through htonl despite
|
||||||
// already being big-endian, so they end up as little-endian.
|
// already being big-endian, so they end up as little-endian.
|
||||||
Append<u16_le>(data, addrinfo.addr.portno); // sin_port
|
Append<u16_le>(data, addrinfo.addr.portno); // sin_port
|
||||||
@@ -296,7 +293,7 @@ static std::vector<u8> SerializeAddrInfo(const std::vector<Network::AddrInfo>& v
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::pair<u32, GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext& ctx) {
|
static std::pair<u32, Network::GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext& ctx) {
|
||||||
struct InputParameters {
|
struct InputParameters {
|
||||||
u8 use_nsd_resolve;
|
u8 use_nsd_resolve;
|
||||||
u32 cancel_handle;
|
u32 cancel_handle;
|
||||||
@@ -321,7 +318,7 @@ static std::pair<u32, GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext
|
|||||||
// Prevent resolution of Nintendo servers
|
// Prevent resolution of Nintendo servers
|
||||||
if (IsBlockedHost(host)) {
|
if (IsBlockedHost(host)) {
|
||||||
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
|
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
|
||||||
return {0, GetAddrInfoError::AGAIN};
|
return {0, Network::GetAddrInfoError::AGAIN};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> service = std::nullopt;
|
std::optional<std::string> service = std::nullopt;
|
||||||
@@ -331,24 +328,23 @@ static std::pair<u32, GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Serialized hints are also passed in a buffer, but are ignored for now.
|
// Serialized hints are also passed in a buffer, but are ignored for now.
|
||||||
|
|
||||||
auto res_v = Network::GetAddressInfo(host, service);
|
auto res_v = Network::GetAddressInfo(host, service);
|
||||||
if (auto* res = std::get_if<std::vector<Network::AddrInfo>>(&res_v)) {
|
if (auto* res = std::get_if<std::vector<Network::AddrInfo>>(&res_v)) {
|
||||||
const std::vector<u8> data = SerializeAddrInfo(*res, host);
|
const std::vector<u8> data = SerializeAddrInfo(*res, host);
|
||||||
const u32 data_size = u32(data.size());
|
const u32 data_size = u32(data.size());
|
||||||
ctx.WriteBuffer(data, 0);
|
ctx.WriteBuffer(data, 0);
|
||||||
return {data_size, GetAddrInfoError::SUCCESS};
|
return {data_size, Network::GetAddrInfoError::SUCCESS};
|
||||||
}
|
}
|
||||||
auto* err = std::get_if<Network::GetAddrInfoError>(&res_v);
|
auto* err = std::get_if<Network::GetAddrInfoError>(&res_v);
|
||||||
return {0, Translate(*err)};
|
return {0, *err};
|
||||||
}
|
}
|
||||||
|
|
||||||
void SFDNSRES::GetAddrInfoRequest(HLERequestContext& ctx) {
|
void SFDNSRES::GetAddrInfoRequest(HLERequestContext& ctx) {
|
||||||
auto [data_size, emu_gai_err] = GetAddrInfoRequestImpl(ctx);
|
auto [data_size, emu_gai_err] = GetAddrInfoRequestImpl(ctx);
|
||||||
|
|
||||||
struct OutputParameters {
|
struct OutputParameters {
|
||||||
Errno bsd_errno;
|
Network::Errno bsd_errno;
|
||||||
GetAddrInfoError gai_error;
|
Network::GetAddrInfoError gai_error;
|
||||||
u32 data_size;
|
u32 data_size;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(OutputParameters) == 0xc);
|
static_assert(sizeof(OutputParameters) == 0xc);
|
||||||
@@ -364,7 +360,7 @@ void SFDNSRES::GetAddrInfoRequest(HLERequestContext& ctx) {
|
|||||||
|
|
||||||
void SFDNSRES::GetGaiStringErrorRequest(HLERequestContext& ctx) {
|
void SFDNSRES::GetGaiStringErrorRequest(HLERequestContext& ctx) {
|
||||||
struct InputParameters {
|
struct InputParameters {
|
||||||
GetAddrInfoError gai_errno;
|
Network::GetAddrInfoError gai_errno;
|
||||||
};
|
};
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
auto input = rp.PopRaw<InputParameters>();
|
auto input = rp.PopRaw<InputParameters>();
|
||||||
@@ -382,9 +378,9 @@ void SFDNSRES::GetAddrInfoRequestWithOptions(HLERequestContext& ctx) {
|
|||||||
|
|
||||||
struct OutputParameters {
|
struct OutputParameters {
|
||||||
u32 data_size;
|
u32 data_size;
|
||||||
GetAddrInfoError gai_error;
|
Network::GetAddrInfoError gai_error;
|
||||||
NetDbError netdb_error;
|
NetDbError netdb_error;
|
||||||
Errno bsd_errno;
|
Network::Errno bsd_errno;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(OutputParameters) == 0x10);
|
static_assert(sizeof(OutputParameters) == 0x10);
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/internal_network/socket_types.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
@@ -15,242 +16,6 @@ class System;
|
|||||||
|
|
||||||
namespace Service::Sockets {
|
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);
|
void LoopProcess(Core::System& system);
|
||||||
|
|
||||||
} // namespace Service::Sockets
|
} // namespace Service::Sockets
|
||||||
|
|||||||
@@ -15,388 +15,42 @@
|
|||||||
|
|
||||||
namespace Service::Sockets {
|
namespace Service::Sockets {
|
||||||
|
|
||||||
Errno Translate(Network::Errno value) {
|
const char* Translate(Network::GetAddrInfoError error) {
|
||||||
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 GetAddrInfoError::SUCCESS;
|
|
||||||
case Network::GetAddrInfoError::ADDRFAMILY:
|
|
||||||
return GetAddrInfoError::ADDRFAMILY;
|
|
||||||
case Network::GetAddrInfoError::AGAIN:
|
|
||||||
return GetAddrInfoError::AGAIN;
|
|
||||||
case Network::GetAddrInfoError::BADFLAGS:
|
|
||||||
return GetAddrInfoError::BADFLAGS;
|
|
||||||
case Network::GetAddrInfoError::FAIL:
|
|
||||||
return GetAddrInfoError::FAIL;
|
|
||||||
case Network::GetAddrInfoError::FAMILY:
|
|
||||||
return GetAddrInfoError::FAMILY;
|
|
||||||
case Network::GetAddrInfoError::MEMORY:
|
|
||||||
return GetAddrInfoError::MEMORY;
|
|
||||||
case Network::GetAddrInfoError::NODATA:
|
|
||||||
return GetAddrInfoError::NODATA;
|
|
||||||
case Network::GetAddrInfoError::NONAME:
|
|
||||||
return GetAddrInfoError::NONAME;
|
|
||||||
case Network::GetAddrInfoError::SERVICE:
|
|
||||||
return GetAddrInfoError::SERVICE;
|
|
||||||
case Network::GetAddrInfoError::SOCKTYPE:
|
|
||||||
return GetAddrInfoError::SOCKTYPE;
|
|
||||||
case Network::GetAddrInfoError::SYSTEM:
|
|
||||||
return GetAddrInfoError::SYSTEM;
|
|
||||||
case Network::GetAddrInfoError::BADHINTS:
|
|
||||||
return GetAddrInfoError::BADHINTS;
|
|
||||||
case Network::GetAddrInfoError::PROTOCOL:
|
|
||||||
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
|
// https://android.googlesource.com/platform/bionic/+/085543106/libc/dns/net/getaddrinfo.c#254
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case GetAddrInfoError::SUCCESS:
|
case Network::GetAddrInfoError::SUCCESS:
|
||||||
return "Success";
|
return "Success";
|
||||||
case GetAddrInfoError::ADDRFAMILY:
|
case Network::GetAddrInfoError::ADDRFAMILY:
|
||||||
return "Address family for hostname not supported";
|
return "Address family for hostname not supported";
|
||||||
case GetAddrInfoError::AGAIN:
|
case Network::GetAddrInfoError::AGAIN:
|
||||||
return "Temporary failure in name resolution";
|
return "Temporary failure in name resolution";
|
||||||
case GetAddrInfoError::BADFLAGS:
|
case Network::GetAddrInfoError::BADFLAGS:
|
||||||
return "Invalid value for ai_flags";
|
return "Invalid value for ai_flags";
|
||||||
case GetAddrInfoError::FAIL:
|
case Network::GetAddrInfoError::FAIL:
|
||||||
return "Non-recoverable failure in name resolution";
|
return "Non-recoverable failure in name resolution";
|
||||||
case GetAddrInfoError::FAMILY:
|
case Network::GetAddrInfoError::FAMILY:
|
||||||
return "ai_family not supported";
|
return "ai_family not supported";
|
||||||
case GetAddrInfoError::MEMORY:
|
case Network::GetAddrInfoError::MEMORY:
|
||||||
return "Memory allocation failure";
|
return "Memory allocation failure";
|
||||||
case GetAddrInfoError::NODATA:
|
case Network::GetAddrInfoError::NODATA:
|
||||||
return "No address associated with hostname";
|
return "No address associated with hostname";
|
||||||
case GetAddrInfoError::NONAME:
|
case Network::GetAddrInfoError::NONAME:
|
||||||
return "hostname nor servname provided, or not known";
|
return "hostname nor servname provided, or not known";
|
||||||
case GetAddrInfoError::SERVICE:
|
case Network::GetAddrInfoError::SERVICE:
|
||||||
return "servname not supported for ai_socktype";
|
return "servname not supported for ai_socktype";
|
||||||
case GetAddrInfoError::SOCKTYPE:
|
case Network::GetAddrInfoError::SOCKTYPE:
|
||||||
return "ai_socktype not supported";
|
return "ai_socktype not supported";
|
||||||
case GetAddrInfoError::SYSTEM:
|
case Network::GetAddrInfoError::SYSTEM:
|
||||||
return "System error returned in errno";
|
return "System error returned in errno";
|
||||||
case GetAddrInfoError::BADHINTS:
|
case Network::GetAddrInfoError::BADHINTS:
|
||||||
return "Invalid value for hints";
|
return "Invalid value for hints";
|
||||||
case GetAddrInfoError::PROTOCOL:
|
case Network::GetAddrInfoError::PROTOCOL:
|
||||||
return "Resolved protocol is unknown";
|
return "Resolved protocol is unknown";
|
||||||
case GetAddrInfoError::OVERFLOW_:
|
case Network::GetAddrInfoError::OVERFLOW_:
|
||||||
return "Argument buffer overflow";
|
return "Argument buffer overflow";
|
||||||
default:
|
default:
|
||||||
return "Unknown error";
|
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
|
} // namespace Service::Sockets
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -11,49 +14,7 @@
|
|||||||
|
|
||||||
namespace Service::Sockets {
|
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
|
/// Translate guest error to string
|
||||||
const char* Translate(GetAddrInfoError value);
|
const char* Translate(Network::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
|
} // namespace Service::Sockets
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ public:
|
|||||||
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD_USA>("bsd:u");
|
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD_USA>("bsd:u");
|
||||||
if (bsd) {
|
if (bsd) {
|
||||||
auto err = bsd->CloseImpl(fd);
|
auto err = bsd->CloseImpl(fd);
|
||||||
if (err != Service::Sockets::Errno::SUCCESS) {
|
if (err != Network::Errno::E_SUCCESS) {
|
||||||
LOG_ERROR(Service_SSL, "Failed to close duplicated socket: {}", err);
|
LOG_ERROR(Service_SSL, "Failed to close duplicated socket: {}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -230,7 +230,7 @@ private:
|
|||||||
R_UNLESS(socket, ResultNoSocket);
|
R_UNLESS(socket, ResultNoSocket);
|
||||||
const bool non_block = mode == IoMode::NonBlocking;
|
const bool non_block = mode == IoMode::NonBlocking;
|
||||||
const Network::Errno error = socket->SetNonBlock(non_block);
|
const Network::Errno error = socket->SetNonBlock(non_block);
|
||||||
if (error != Network::Errno::SUCCESS) {
|
if (error != Network::Errno::E_SUCCESS) {
|
||||||
LOG_ERROR(Service_SSL, "Failed to set native socket non-block flag to {}", non_block);
|
LOG_ERROR(Service_SSL, "Failed to set native socket non-block flag to {}", non_block);
|
||||||
}
|
}
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
|
|||||||
@@ -327,10 +327,10 @@ public:
|
|||||||
BIO_clear_retry_flags(bio);
|
BIO_clear_retry_flags(bio);
|
||||||
auto [actual, err] = self->socket->Send({reinterpret_cast<const u8*>(buf), len}, 0);
|
auto [actual, err] = self->socket->Send({reinterpret_cast<const u8*>(buf), len}, 0);
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case Network::Errno::SUCCESS:
|
case Network::Errno::E_SUCCESS:
|
||||||
*actual_p = actual;
|
*actual_p = actual;
|
||||||
return 1;
|
return 1;
|
||||||
case Network::Errno::AGAIN:
|
case Network::Errno::E_AGAIN:
|
||||||
BIO_set_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY);
|
BIO_set_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY);
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
@@ -346,13 +346,13 @@ public:
|
|||||||
BIO_clear_retry_flags(bio);
|
BIO_clear_retry_flags(bio);
|
||||||
auto [actual, err] = self->socket->Recv(0, {reinterpret_cast<u8*>(buf), len});
|
auto [actual, err] = self->socket->Recv(0, {reinterpret_cast<u8*>(buf), len});
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case Network::Errno::SUCCESS:
|
case Network::Errno::E_SUCCESS:
|
||||||
*actual_p = actual;
|
*actual_p = actual;
|
||||||
if (actual == 0) {
|
if (actual == 0) {
|
||||||
self->got_read_eof = true;
|
self->got_read_eof = true;
|
||||||
}
|
}
|
||||||
return actual ? 1 : 0;
|
return actual ? 1 : 0;
|
||||||
case Network::Errno::AGAIN:
|
case Network::Errno::E_AGAIN:
|
||||||
BIO_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY);
|
BIO_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY);
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <common/socket_types.h>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include "core/internal_network/socket_types.h"
|
||||||
|
|
||||||
namespace Network {
|
namespace Network {
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/socket_types.h"
|
#include "core/internal_network/socket_types.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
@@ -31,68 +31,10 @@ namespace Network {
|
|||||||
class SocketBase;
|
class SocketBase;
|
||||||
class Socket;
|
class Socket;
|
||||||
|
|
||||||
/// Error code for network functions
|
struct HostPollFD {
|
||||||
enum class Errno {
|
SocketBase* socket = nullptr;
|
||||||
SUCCESS,
|
Network::PollEvents events = {};
|
||||||
BADF,
|
Network::PollEvents revents = {};
|
||||||
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 {
|
class NetworkInstance {
|
||||||
@@ -101,6 +43,10 @@ public:
|
|||||||
~NetworkInstance();
|
~NetworkInstance();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sockaddr_in TranslateFromSockAddrIn(Network::SockAddrIn input);
|
||||||
|
Network::SockAddrIn TranslateToSockAddrIn(sockaddr_in input);
|
||||||
|
s32 TranslateMsgOptToNative(s32 flags);
|
||||||
|
|
||||||
void CancelPendingSocketOperations();
|
void CancelPendingSocketOperations();
|
||||||
void RestartSocketOperations();
|
void RestartSocketOperations();
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ namespace Network {
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||||
|
|
||||||
ULONG buf_size = 0;
|
ULONG buf_size = 0;
|
||||||
if (GetAdaptersAddresses(
|
if (GetAdaptersAddresses(
|
||||||
@@ -66,7 +66,7 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Network::NetworkInterface> result;
|
std::vector<NetworkInterface> result;
|
||||||
|
|
||||||
for (auto* a = addrs; a; a = a->Next) {
|
for (auto* a = addrs; a; a = a->Next) {
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
|||||||
gw = reinterpret_cast<sockaddr_in*>(a->FirstGatewayAddress->Address.lpSockaddr)
|
gw = reinterpret_cast<sockaddr_in*>(a->FirstGatewayAddress->Address.lpSockaddr)
|
||||||
->sin_addr;
|
->sin_addr;
|
||||||
|
|
||||||
result.emplace_back(Network::NetworkInterface{
|
result.emplace_back(NetworkInterface{
|
||||||
.name = Common::UTF16ToUTF8(std::wstring{a->FriendlyName}),
|
.name = Common::UTF16ToUTF8(std::wstring{a->FriendlyName}),
|
||||||
.ip_address = ip,
|
.ip_address = ip,
|
||||||
.subnet_mask = mask,
|
.subnet_mask = mask,
|
||||||
@@ -103,7 +103,7 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||||
#if defined(__ANDROID__) || defined(__linux__)
|
#if defined(__ANDROID__) || defined(__linux__)
|
||||||
struct ifaddrs* ifaddr = nullptr;
|
struct ifaddrs* ifaddr = nullptr;
|
||||||
if (getifaddrs(&ifaddr) != 0) {
|
if (getifaddrs(&ifaddr) != 0) {
|
||||||
@@ -135,7 +135,7 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
|||||||
LOG_WARNING(Network, "\"/proc/net/route\" not found - using gateway 0");
|
LOG_WARNING(Network, "\"/proc/net/route\" not found - using gateway 0");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
std::vector<Network::NetworkInterface> ifaces;
|
std::vector<NetworkInterface> ifaces;
|
||||||
for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
|
for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
|
||||||
if (ifa->ifa_addr == nullptr || ifa->ifa_netmask == nullptr /* Have a netmask and address */
|
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 */
|
|| ifa->ifa_addr->sa_family != AF_INET /* Must be of kind AF_INET */
|
||||||
@@ -149,7 +149,7 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
|||||||
});
|
});
|
||||||
in_addr gw; // Solaris defines s_addr as a macro, can't use special C++ shenanigans here
|
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;
|
gw.s_addr = it != routes.end() ? it->gateway : 0;
|
||||||
ifaces.emplace_back(Network::NetworkInterface{
|
ifaces.emplace_back(NetworkInterface{
|
||||||
.name = ifa->ifa_name,
|
.name = ifa->ifa_name,
|
||||||
.ip_address = std::bit_cast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr,
|
.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,
|
.subnet_mask = std::bit_cast<struct sockaddr_in>(*ifa->ifa_netmask).sin_addr,
|
||||||
@@ -159,7 +159,7 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
|||||||
freeifaddrs(ifaddr);
|
freeifaddrs(ifaddr);
|
||||||
return ifaces;
|
return ifaces;
|
||||||
#elif defined(__FreeBSD__)
|
#elif defined(__FreeBSD__)
|
||||||
std::vector<Network::NetworkInterface> ifaces;
|
std::vector<NetworkInterface> ifaces;
|
||||||
int fd = ::socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
|
int fd = ::socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
LOG_ERROR(Network, "socket: {}", std::strerror(errno));
|
LOG_ERROR(Network, "socket: {}", std::strerror(errno));
|
||||||
@@ -191,7 +191,7 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
|||||||
size_t msglen = rtm->rtm_msglen - sizeof(*ifm);
|
size_t msglen = rtm->rtm_msglen - sizeof(*ifm);
|
||||||
char const* p = (char const*)(ifm + 1);
|
char const* p = (char const*)(ifm + 1);
|
||||||
|
|
||||||
Network::NetworkInterface iface{};
|
NetworkInterface iface{};
|
||||||
for (size_t i = 0; i < RTAX_MAX; i++)
|
for (size_t i = 0; i < RTAX_MAX; i++)
|
||||||
if ((ifm->ifm_addrs & (1 << i)) != 0) {
|
if ((ifm->ifm_addrs & (1 << i)) != 0) {
|
||||||
struct sockaddr const* sa = reinterpret_cast<struct sockaddr const*>(p);
|
struct sockaddr const* sa = reinterpret_cast<struct sockaddr const*>(p);
|
||||||
@@ -220,7 +220,7 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
|||||||
|
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
std::optional<Network::NetworkInterface> GetSelectedNetworkInterface() {
|
std::optional<NetworkInterface> GetSelectedNetworkInterface() {
|
||||||
auto const& sel_if = Settings::values.network_interface.GetValue();
|
auto const& sel_if = Settings::values.network_interface.GetValue();
|
||||||
if (auto const ifaces = Network::GetAvailableNetworkInterfaces(); ifaces.size() > 0) {
|
if (auto const ifaces = Network::GetAvailableNetworkInterfaces(); ifaces.size() > 0) {
|
||||||
if (sel_if.empty())
|
if (sel_if.empty())
|
||||||
|
|||||||
@@ -0,0 +1,281 @@
|
|||||||
|
// 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IcmpSocket::GetNonBlock() {
|
||||||
|
return !blocking;
|
||||||
|
}
|
||||||
|
Errno IcmpSocket::SetNonBlock(bool enable) {
|
||||||
|
blocking = !enable;
|
||||||
|
return Errno::E_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Network
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
// 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;
|
||||||
|
bool GetNonBlock() 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,169 +47,147 @@ void ProxySocket::HandleProxyPacket(const ProxyPacket& packet) {
|
|||||||
received_packets.push(decompressed);
|
received_packets.push(decompressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
bool ProxySocket::GetNonBlock() {
|
||||||
Errno ProxySocket::SetSockOpt(SOCKET fd_, int option, T value) {
|
return blocking;
|
||||||
LOG_DEBUG(Network, "(STUBBED) called");
|
}
|
||||||
return Errno::SUCCESS;
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno ProxySocket::Initialize(Domain domain, Type type, Protocol socket_protocol) {
|
Errno ProxySocket::Initialize(Domain domain, Type type, Protocol socket_protocol) {
|
||||||
protocol = socket_protocol;
|
protocol = socket_protocol;
|
||||||
SetSockOpt(fd, SO_TYPE, type);
|
return Errno::E_SUCCESS;
|
||||||
|
|
||||||
return Errno::SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<ProxySocket::AcceptResult, Errno> ProxySocket::Accept() {
|
std::pair<ProxySocket::AcceptResult, Errno> ProxySocket::Accept() {
|
||||||
LOG_WARNING(Network, "(STUBBED) called");
|
LOG_WARNING(Network, "(stubbed) called");
|
||||||
return {AcceptResult{}, Errno::SUCCESS};
|
return {AcceptResult{}, Errno::E_SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno ProxySocket::Connect(SockAddrIn addr_in) {
|
Errno ProxySocket::Connect(Network::SockAddrIn addr_in) {
|
||||||
LOG_WARNING(Network, "(STUBBED) called");
|
LOG_WARNING(Network, "(stubbed) called");
|
||||||
return Errno::SUCCESS;
|
return Errno::E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<SockAddrIn, Errno> ProxySocket::GetPeerName() {
|
std::pair<Network::SockAddrIn, Errno> ProxySocket::GetPeerName() {
|
||||||
LOG_WARNING(Network, "(STUBBED) called");
|
LOG_WARNING(Network, "(stubbed) called");
|
||||||
return {SockAddrIn{}, Errno::SUCCESS};
|
return {Network::SockAddrIn{}, Errno::E_SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<SockAddrIn, Errno> ProxySocket::GetSockName() {
|
std::pair<Network::SockAddrIn, Errno> ProxySocket::GetSockName() {
|
||||||
LOG_WARNING(Network, "(STUBBED) called");
|
LOG_WARNING(Network, "(stubbed) called");
|
||||||
return {SockAddrIn{}, Errno::SUCCESS};
|
return {Network::SockAddrIn{}, Errno::E_SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno ProxySocket::Bind(SockAddrIn addr) {
|
Errno ProxySocket::Bind(Network::SockAddrIn addr) {
|
||||||
if (is_bound) {
|
if (is_bound) {
|
||||||
LOG_WARNING(Network, "Rebinding Socket is unimplemented!");
|
LOG_WARNING(Network, "Rebinding Socket is unimplemented!");
|
||||||
return Errno::SUCCESS;
|
return Errno::E_SUCCESS;
|
||||||
}
|
}
|
||||||
local_endpoint = addr;
|
local_endpoint = addr;
|
||||||
is_bound = true;
|
is_bound = true;
|
||||||
|
return Errno::E_SUCCESS;
|
||||||
return Errno::SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno ProxySocket::Listen(s32 backlog) {
|
Errno ProxySocket::Listen(s32 backlog) {
|
||||||
LOG_WARNING(Network, "(STUBBED) called");
|
LOG_WARNING(Network, "(stubbed) called");
|
||||||
return Errno::SUCCESS;
|
return Errno::E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno ProxySocket::Shutdown(ShutdownHow how) {
|
Errno ProxySocket::Shutdown(ShutdownHow how) {
|
||||||
LOG_WARNING(Network, "(STUBBED) called");
|
LOG_WARNING(Network, "(stubbed) called");
|
||||||
return Errno::SUCCESS;
|
return Errno::E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> ProxySocket::Recv(int flags, std::span<u8> message) {
|
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(flags == 0 && message.size() < std::size_t((std::numeric_limits<int>::max)()));
|
||||||
ASSERT(message.size() < static_cast<size_t>((std::numeric_limits<int>::max)()));
|
return {s32(0), Errno::E_SUCCESS};
|
||||||
|
|
||||||
return {static_cast<s32>(0), Errno::SUCCESS};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> ProxySocket::RecvFrom(int flags, std::span<u8> message, SockAddrIn* addr) {
|
std::pair<s32, Errno> ProxySocket::RecvFrom(int flags, std::span<u8> message, Network::SockAddrIn* addr) {
|
||||||
ASSERT(flags == 0);
|
LOG_DEBUG(Network, "called");
|
||||||
ASSERT(message.size() < static_cast<size_t>((std::numeric_limits<int>::max)()));
|
ASSERT(flags == 0 && message.size() < std::size_t((std::numeric_limits<int>::max)()));
|
||||||
|
do {
|
||||||
// TODO (flTobi): Verify the timeout behavior and break when connection is lost
|
std::unique_lock lk{packets_mutex};
|
||||||
const auto timestamp = std::chrono::steady_clock::now();
|
if (received_packets.size() > 0)
|
||||||
// When receive_timeout is set to zero, the socket is supposed to wait indefinitely until a
|
return ReceivePacket(flags, message, addr, message.size());
|
||||||
// packet arrives. In order to prevent lost packets from hanging the emulation thread, we set
|
} while (blocking);
|
||||||
// the timeout to 5s instead
|
return {-1, Errno::E_AGAIN};
|
||||||
const auto timeout = receive_timeout == 0 ? 5000 : receive_timeout;
|
|
||||||
while (true) {
|
|
||||||
{
|
|
||||||
std::lock_guard guard(packets_mutex);
|
|
||||||
if (received_packets.size() > 0) {
|
|
||||||
return ReceivePacket(flags, message, addr, message.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!blocking) {
|
|
||||||
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();
|
|
||||||
|
|
||||||
if (time_diff_ms > timeout) {
|
|
||||||
return {-1, Errno::TIMEDOUT};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::span<u8> message, SockAddrIn* addr,
|
std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::span<u8> message, Network::SockAddrIn* addr, std::size_t max_length) {
|
||||||
std::size_t max_length) {
|
LOG_DEBUG(Network, "called");
|
||||||
ProxyPacket& packet = received_packets.front();
|
ProxyPacket& packet = received_packets.front();
|
||||||
if (addr) {
|
if (addr) {
|
||||||
addr->family = Domain::INET;
|
addr->len = 16;
|
||||||
|
addr->family = u8(Network::Domain::INET);
|
||||||
addr->ip = packet.local_endpoint.ip; // The senders ip address
|
addr->ip = packet.local_endpoint.ip; // The senders ip address
|
||||||
addr->portno = packet.local_endpoint.portno; // The senders port number
|
addr->portno = packet.local_endpoint.portno; // The senders port number
|
||||||
|
addr->zeroes = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool peek = (flags & FLAG_MSG_PEEK) != 0;
|
bool peek = (flags & u32(Network::MsgOpt::PEEK)) != 0;
|
||||||
std::size_t read_bytes;
|
std::size_t read_bytes = (std::min)(max_length, packet.data.size());
|
||||||
if (packet.data.size() > max_length) {
|
std::memcpy(message.data(), packet.data.data(), read_bytes);
|
||||||
read_bytes = max_length;
|
if (!peek) {
|
||||||
memcpy(message.data(), packet.data.data(), max_length);
|
packet.data.erase(packet.data.begin(), packet.data.begin() + read_bytes);
|
||||||
|
if (packet.data.empty())
|
||||||
if (protocol == Protocol::UDP) {
|
|
||||||
if (!peek) {
|
|
||||||
received_packets.pop();
|
|
||||||
}
|
|
||||||
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));
|
|
||||||
packet.data = numArray;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
read_bytes = packet.data.size();
|
|
||||||
memcpy(message.data(), packet.data.data(), read_bytes);
|
|
||||||
if (!peek) {
|
|
||||||
received_packets.pop();
|
received_packets.pop();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (packet.data.size() > max_length && protocol == Protocol::UDP) {
|
||||||
return {static_cast<u32>(read_bytes), Errno::SUCCESS};
|
LOG_ERROR(Network, "Packet size");
|
||||||
|
return {-1, Errno::E_MSGSIZE};
|
||||||
|
}
|
||||||
|
return {u32(read_bytes), Errno::E_SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> ProxySocket::Send(std::span<const u8> message, int flags) {
|
std::pair<s32, Errno> ProxySocket::Send(std::span<const u8> message, int flags) {
|
||||||
LOG_WARNING(Network, "(STUBBED) called");
|
LOG_WARNING(Network, "(stubbed) called");
|
||||||
ASSERT(message.size() < static_cast<size_t>((std::numeric_limits<int>::max)()));
|
ASSERT(message.size() < size_t((std::numeric_limits<int>::max)()));
|
||||||
ASSERT(flags == 0);
|
ASSERT(flags == 0);
|
||||||
|
return {s32(0), Errno::E_SUCCESS};
|
||||||
return {static_cast<s32>(0), Errno::SUCCESS};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProxySocket::SendPacket(ProxyPacket& packet) {
|
void ProxySocket::SendPacket(ProxyPacket& packet) {
|
||||||
if (auto room_member = Network::GetRoomMember().lock()) {
|
if (auto room_member = Network::GetRoomMember().lock()) {
|
||||||
if (room_member->IsConnected()) {
|
if (room_member->IsConnected()) {
|
||||||
packet.data = Common::Compression::CompressDataZSTDDefault(packet.data.data(),
|
packet.data = Common::Compression::CompressDataZSTDDefault(packet.data.data(), packet.data.size());
|
||||||
packet.data.size());
|
|
||||||
room_member->SendProxyPacket(packet);
|
room_member->SendProxyPacket(packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, std::span<const u8> message,
|
std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, std::span<const u8> message, const Network::SockAddrIn* addr) {
|
||||||
const SockAddrIn* addr) {
|
LOG_DEBUG(Network, "called");
|
||||||
ASSERT(flags == 0);
|
ASSERT(flags == 0);
|
||||||
|
|
||||||
if (!is_bound) {
|
if (!is_bound) {
|
||||||
LOG_ERROR(Network, "ProxySocket is not bound!");
|
LOG_ERROR(Network, "ProxySocket is not bound!");
|
||||||
return {static_cast<s32>(message.size()), Errno::SUCCESS};
|
return {s32(message.size()), Errno::E_SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto room_member = Network::GetRoomMember().lock()) {
|
if (auto room_member = Network::GetRoomMember().lock()) {
|
||||||
if (!room_member->IsConnected()) {
|
if (!room_member->IsConnected()) {
|
||||||
return {static_cast<s32>(message.size()), Errno::SUCCESS};
|
return {s32(message.size()), Errno::E_SUCCESS};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,66 +212,20 @@ std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, std::span<const u8> message
|
|||||||
|
|
||||||
SendPacket(packet);
|
SendPacket(packet);
|
||||||
|
|
||||||
return {static_cast<s32>(message.size()), Errno::SUCCESS};
|
return {s32(message.size()), Errno::E_SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno ProxySocket::Close() {
|
Errno ProxySocket::Close() {
|
||||||
|
LOG_DEBUG(Network, "called");
|
||||||
fd = INVALID_SOCKET;
|
fd = INVALID_SOCKET;
|
||||||
closed = true;
|
closed = true;
|
||||||
|
|
||||||
return Errno::SUCCESS;
|
return Errno::E_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() {
|
std::pair<Errno, Errno> ProxySocket::GetPendingError() {
|
||||||
LOG_DEBUG(Network, "(STUBBED) called");
|
LOG_DEBUG(Network, "called");
|
||||||
return {Errno::SUCCESS, Errno::SUCCESS};
|
return {Errno::E_SUCCESS, Errno::E_SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProxySocket::IsOpened() const {
|
bool ProxySocket::IsOpened() const {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
@@ -22,62 +22,25 @@ public:
|
|||||||
~ProxySocket() override;
|
~ProxySocket() override;
|
||||||
|
|
||||||
void HandleProxyPacket(const ProxyPacket& packet) override;
|
void HandleProxyPacket(const ProxyPacket& packet) override;
|
||||||
|
|
||||||
Errno Initialize(Domain domain, Type type, Protocol socket_protocol) override;
|
Errno Initialize(Domain domain, Type type, Protocol socket_protocol) override;
|
||||||
|
|
||||||
Errno Close() override;
|
Errno Close() override;
|
||||||
|
|
||||||
std::pair<AcceptResult, Errno> Accept() override;
|
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<Network::SockAddrIn, Errno> GetSockName() override;
|
||||||
std::pair<SockAddrIn, Errno> GetPeerName() override;
|
Errno Bind(Network::SockAddrIn addr) override;
|
||||||
|
|
||||||
std::pair<SockAddrIn, Errno> GetSockName() override;
|
|
||||||
|
|
||||||
Errno Bind(SockAddrIn addr) override;
|
|
||||||
|
|
||||||
Errno Listen(s32 backlog) override;
|
Errno Listen(s32 backlog) override;
|
||||||
|
|
||||||
Errno Shutdown(ShutdownHow how) override;
|
Errno Shutdown(ShutdownHow how) override;
|
||||||
|
|
||||||
std::pair<s32, Errno> Recv(int flags, std::span<u8> message) 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> 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::size_t max_length);
|
||||||
|
|
||||||
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;
|
std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override;
|
||||||
|
|
||||||
void SendPacket(ProxyPacket& packet);
|
void SendPacket(ProxyPacket& packet);
|
||||||
|
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,
|
bool GetNonBlock() 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 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;
|
std::pair<Errno, Errno> GetPendingError() override;
|
||||||
|
|
||||||
bool IsOpened() const override;
|
bool IsOpened() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -86,7 +49,7 @@ private:
|
|||||||
u32 send_timeout = 0;
|
u32 send_timeout = 0;
|
||||||
u32 receive_timeout = 0;
|
u32 receive_timeout = 0;
|
||||||
bool is_bound = false;
|
bool is_bound = false;
|
||||||
SockAddrIn local_endpoint{};
|
Network::SockAddrIn local_endpoint{};
|
||||||
bool blocking = true;
|
bool blocking = true;
|
||||||
std::queue<ProxyPacket> received_packets;
|
std::queue<ProxyPacket> received_packets;
|
||||||
Protocol protocol;
|
Protocol protocol;
|
||||||
|
|||||||
@@ -0,0 +1,470 @@
|
|||||||
|
// 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 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
@@ -30,7 +30,7 @@ public:
|
|||||||
|
|
||||||
struct AcceptResult {
|
struct AcceptResult {
|
||||||
std::unique_ptr<SocketBase> socket;
|
std::unique_ptr<SocketBase> socket;
|
||||||
SockAddrIn sockaddr_in;
|
Network::SockAddrIn sockaddr_in;
|
||||||
};
|
};
|
||||||
|
|
||||||
SocketBase() = default;
|
SocketBase() = default;
|
||||||
@@ -41,61 +41,29 @@ public:
|
|||||||
YUZU_NON_MOVEABLE(SocketBase);
|
YUZU_NON_MOVEABLE(SocketBase);
|
||||||
|
|
||||||
virtual Errno Initialize(Domain domain, Type type, Protocol protocol) = 0;
|
virtual Errno Initialize(Domain domain, Type type, Protocol protocol) = 0;
|
||||||
|
|
||||||
virtual Errno Close() = 0;
|
virtual Errno Close() = 0;
|
||||||
|
|
||||||
virtual std::pair<AcceptResult, Errno> Accept() = 0;
|
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<Network::SockAddrIn, Errno> GetSockName() = 0;
|
||||||
virtual std::pair<SockAddrIn, Errno> GetPeerName() = 0;
|
virtual Errno Bind(Network::SockAddrIn addr) = 0;
|
||||||
|
|
||||||
virtual std::pair<SockAddrIn, Errno> GetSockName() = 0;
|
|
||||||
|
|
||||||
virtual Errno Bind(SockAddrIn addr) = 0;
|
|
||||||
|
|
||||||
virtual Errno Listen(s32 backlog) = 0;
|
virtual Errno Listen(s32 backlog) = 0;
|
||||||
|
|
||||||
virtual Errno Shutdown(ShutdownHow how) = 0;
|
virtual Errno Shutdown(ShutdownHow how) = 0;
|
||||||
|
|
||||||
virtual std::pair<s32, Errno> Recv(int flags, std::span<u8> message) = 0;
|
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> 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,
|
virtual bool GetNonBlock() = 0;
|
||||||
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 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 std::pair<Errno, Errno> GetPendingError() = 0;
|
||||||
|
|
||||||
virtual bool IsOpened() const = 0;
|
virtual bool IsOpened() const = 0;
|
||||||
|
|
||||||
virtual void HandleProxyPacket(const ProxyPacket& packet) = 0;
|
virtual void HandleProxyPacket(const ProxyPacket& packet) = 0;
|
||||||
|
|
||||||
[[nodiscard]] SOCKET GetFD() const {
|
[[nodiscard]] SOCKET GetFD() const {
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
|
||||||
SOCKET fd = INVALID_SOCKET;
|
SOCKET fd = INVALID_SOCKET;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -109,66 +77,30 @@ public:
|
|||||||
Socket(Socket&& rhs) noexcept;
|
Socket(Socket&& rhs) noexcept;
|
||||||
|
|
||||||
Errno Initialize(Domain domain, Type type, Protocol protocol) override;
|
Errno Initialize(Domain domain, Type type, Protocol protocol) override;
|
||||||
|
|
||||||
Errno Close() override;
|
Errno Close() override;
|
||||||
|
|
||||||
std::pair<AcceptResult, Errno> Accept() override;
|
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<Network::SockAddrIn, Errno> GetSockName() override;
|
||||||
std::pair<SockAddrIn, Errno> GetPeerName() override;
|
Errno Bind(Network::SockAddrIn addr) override;
|
||||||
|
|
||||||
std::pair<SockAddrIn, Errno> GetSockName() override;
|
|
||||||
|
|
||||||
Errno Bind(SockAddrIn addr) override;
|
|
||||||
|
|
||||||
Errno Listen(s32 backlog) override;
|
Errno Listen(s32 backlog) override;
|
||||||
|
|
||||||
Errno Shutdown(ShutdownHow how) override;
|
Errno Shutdown(ShutdownHow how) override;
|
||||||
|
|
||||||
std::pair<s32, Errno> Recv(int flags, std::span<u8> message) 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> 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> 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,
|
bool GetNonBlock() override;
|
||||||
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 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;
|
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;
|
bool IsOpened() const override;
|
||||||
|
|
||||||
void HandleProxyPacket(const ProxyPacket& packet) override;
|
void HandleProxyPacket(const ProxyPacket& packet) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool is_non_blocking = false;
|
bool is_non_blocking = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::pair<s32, Errno> Poll(std::vector<PollFD>& poll_fds, s32 timeout);
|
std::pair<s32, Errno> Poll(std::span<Network::HostPollFD> poll_fds, s32 timeout);
|
||||||
|
|
||||||
} // namespace Network
|
} // namespace Network
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <concepts>
|
#include <concepts>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
|
||||||
#include "common/concepts.h"
|
#include "common/concepts.h"
|
||||||
#include "common/fs/path_util.h"
|
#include "common/fs/path_util.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
@@ -171,7 +170,8 @@ FileType GuessFromFilename(const std::string& name) {
|
|||||||
else if (name == "00")
|
else if (name == "00")
|
||||||
return FileType::NCA;
|
return FileType::NCA;
|
||||||
|
|
||||||
auto const extension = boost::algorithm::to_lower_copy(std::string(Common::FS::GetExtensionFromFilename(name)));
|
auto const extension =
|
||||||
|
Common::ToLower(std::string(Common::FS::GetExtensionFromFilename(name)));
|
||||||
if (extension == "nro")
|
if (extension == "nro")
|
||||||
return FileType::NRO;
|
return FileType::NRO;
|
||||||
else if (extension == "nso")
|
else if (extension == "nso")
|
||||||
|
|||||||
+4
-31
@@ -7,14 +7,12 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <span>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/hex_util.h"
|
#include "common/hex_util.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/lz4_compression.h"
|
#include "common/lz4_compression.h"
|
||||||
#include "common/zbic_compression.h"
|
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
@@ -106,36 +104,11 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
|
|||||||
for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
|
for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
|
||||||
nso_file.Read(compressed_data.data(), nso_header.segments_compressed_size[i], nso_header.segments[i].offset);
|
nso_file.Read(compressed_data.data(), nso_header.segments_compressed_size[i], nso_header.segments[i].offset);
|
||||||
if (nso_header.IsSegmentCompressed(i)) {
|
if (nso_header.IsSegmentCompressed(i)) {
|
||||||
if (nso_header.IsZBICCompressed()) {
|
int r = Common::Compression::DecompressDataLZ4(decompressed_size.data(), nso_header.segments[i].size, compressed_data.data(), nso_header.segments_compressed_size[i]);
|
||||||
// ZBIC compression
|
ASSERT(r == int(nso_header.segments[i].size));
|
||||||
const int r = Common::Compression::DecompressDataZBIC(
|
std::memcpy(codeset.memory.data() + module_start + nso_header.segments[i].location, decompressed_size.data(), nso_header.segments[i].size);
|
||||||
std::span<u8>{decompressed_size}.first(nso_header.segments[i].size),
|
|
||||||
std::span<const u8>{compressed_data}.first(nso_header.segments_compressed_size[i])
|
|
||||||
);
|
|
||||||
ASSERT(r > 0);
|
|
||||||
} else {
|
|
||||||
// LZ4 compression
|
|
||||||
int r = Common::Compression::DecompressDataLZ4(
|
|
||||||
decompressed_size.data(),
|
|
||||||
nso_header.segments[i].size,
|
|
||||||
compressed_data.data(),
|
|
||||||
nso_header.segments_compressed_size[i]
|
|
||||||
);
|
|
||||||
ASSERT(r == int(nso_header.segments[i].size));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memcpy(
|
|
||||||
codeset.memory.data() + module_start + nso_header.segments[i].location,
|
|
||||||
decompressed_size.data(),
|
|
||||||
nso_header.segments[i].size
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// Not compressed
|
std::memcpy(codeset.memory.data() + module_start + nso_header.segments[i].location, compressed_data.data(), nso_header.segments[i].size);
|
||||||
std::memcpy(
|
|
||||||
codeset.memory.data() + module_start + nso_header.segments[i].location,
|
|
||||||
compressed_data.data(),
|
|
||||||
nso_header.segments[i].size
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
codeset.segments[i].addr = module_start + nso_header.segments[i].location;
|
codeset.segments[i].addr = module_start + nso_header.segments[i].location;
|
||||||
codeset.segments[i].offset = module_start + nso_header.segments[i].location;
|
codeset.segments[i].offset = module_start + nso_header.segments[i].location;
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -61,9 +58,6 @@ struct NSOHeader {
|
|||||||
std::array<SHA256Hash, 3> segment_hashes;
|
std::array<SHA256Hash, 3> segment_hashes;
|
||||||
|
|
||||||
bool IsSegmentCompressed(size_t segment_num) const;
|
bool IsSegmentCompressed(size_t segment_num) const;
|
||||||
bool IsZBICCompressed() const {
|
|
||||||
return ((flags >> 7) & 1) != 0;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size.");
|
static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size.");
|
||||||
static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable.");
|
static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable.");
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#include <regex>
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <boost/algorithm/string/trim.hpp>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// windows.h needs to be included before shellapi.h
|
// windows.h needs to be included before shellapi.h
|
||||||
@@ -133,7 +132,7 @@ static Network::Room::BanList LoadBanList(const std::string& path) {
|
|||||||
std::string line;
|
std::string line;
|
||||||
std::getline(file, line);
|
std::getline(file, line);
|
||||||
line.erase(std::remove(line.begin(), line.end(), '\0'), line.end());
|
line.erase(std::remove(line.begin(), line.end(), '\0'), line.end());
|
||||||
boost::trim(line);
|
line = Common::StripSpaces(line);
|
||||||
if (line.empty()) {
|
if (line.empty()) {
|
||||||
// An empty line marks start of the IP ban list
|
// An empty line marks start of the IP ban list
|
||||||
ban_list_type = true;
|
ban_list_type = true;
|
||||||
|
|||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/announce_multiplayer_room.h"
|
#include "common/announce_multiplayer_room.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/socket_types.h"
|
#include "core/internal_network/socket_types.h"
|
||||||
#include "network/verify_user.h"
|
#include "network/verify_user.h"
|
||||||
|
|
||||||
namespace Network {
|
namespace Network {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/polyfill_thread.h"
|
#include "common/polyfill_thread.h"
|
||||||
#include "common/socket_types.h"
|
#include "core/internal_network/socket_types.h"
|
||||||
#include "enet/enet.h"
|
#include "enet/enet.h"
|
||||||
#include "network/packet.h"
|
#include "network/packet.h"
|
||||||
#include "network/room_member.h"
|
#include "network/room_member.h"
|
||||||
@@ -358,19 +358,23 @@ void RoomMember::RoomMemberImpl::HandleProxyPackets(const ENetEvent* event) {
|
|||||||
// Parse the ProxyPacket from the packet
|
// Parse the ProxyPacket from the packet
|
||||||
u8 local_family;
|
u8 local_family;
|
||||||
packet.Read(local_family);
|
packet.Read(local_family);
|
||||||
proxy_packet.local_endpoint.family = static_cast<Domain>(local_family);
|
proxy_packet.local_endpoint.len = 16;
|
||||||
|
proxy_packet.local_endpoint.family = u8(Network::Domain(local_family));
|
||||||
packet.Read(proxy_packet.local_endpoint.ip);
|
packet.Read(proxy_packet.local_endpoint.ip);
|
||||||
packet.Read(proxy_packet.local_endpoint.portno);
|
packet.Read(proxy_packet.local_endpoint.portno);
|
||||||
|
proxy_packet.local_endpoint.zeroes = {};
|
||||||
|
|
||||||
u8 remote_family;
|
u8 remote_family;
|
||||||
packet.Read(remote_family);
|
packet.Read(remote_family);
|
||||||
proxy_packet.remote_endpoint.family = static_cast<Domain>(remote_family);
|
proxy_packet.remote_endpoint.len = 16;
|
||||||
|
proxy_packet.remote_endpoint.family = u8(Network::Domain(remote_family));
|
||||||
packet.Read(proxy_packet.remote_endpoint.ip);
|
packet.Read(proxy_packet.remote_endpoint.ip);
|
||||||
packet.Read(proxy_packet.remote_endpoint.portno);
|
packet.Read(proxy_packet.remote_endpoint.portno);
|
||||||
|
proxy_packet.local_endpoint.zeroes = {};
|
||||||
|
|
||||||
u8 protocol_type;
|
u8 protocol_type;
|
||||||
packet.Read(protocol_type);
|
packet.Read(protocol_type);
|
||||||
proxy_packet.protocol = static_cast<Protocol>(protocol_type);
|
proxy_packet.protocol = Network::Protocol(protocol_type);
|
||||||
|
|
||||||
packet.Read(proxy_packet.broadcast);
|
packet.Read(proxy_packet.broadcast);
|
||||||
packet.Read(proxy_packet.data);
|
packet.Read(proxy_packet.data);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/announce_multiplayer_room.h"
|
#include "common/announce_multiplayer_room.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/socket_types.h"
|
#include "core/internal_network/socket_types.h"
|
||||||
#include "network/room.h"
|
#include "network/room.h"
|
||||||
|
|
||||||
namespace Network {
|
namespace Network {
|
||||||
@@ -39,8 +39,8 @@ struct LDNPacket {
|
|||||||
|
|
||||||
/// Information about the received proxy packets.
|
/// Information about the received proxy packets.
|
||||||
struct ProxyPacket {
|
struct ProxyPacket {
|
||||||
SockAddrIn local_endpoint;
|
Network::SockAddrIn local_endpoint;
|
||||||
SockAddrIn remote_endpoint;
|
Network::SockAddrIn remote_endpoint;
|
||||||
Protocol protocol;
|
Protocol protocol;
|
||||||
bool broadcast;
|
bool broadcast;
|
||||||
std::vector<u8> data;
|
std::vector<u8> data;
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <QEventLoop>
|
#include <QEventLoop>
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
#include "common/httplib.h"
|
#include "common/httplib.h"
|
||||||
|
|
||||||
@@ -46,7 +45,7 @@ void DiscordImpl::Pause() {
|
|||||||
|
|
||||||
std::string DiscordImpl::GetGameString(const std::string& title) {
|
std::string DiscordImpl::GetGameString(const std::string& title) {
|
||||||
// Convert to lowercase
|
// Convert to lowercase
|
||||||
std::string icon_name = boost::algorithm::to_lower_copy(title);
|
std::string icon_name = Common::ToLower(title);
|
||||||
|
|
||||||
// Replace spaces with dashes
|
// Replace spaces with dashes
|
||||||
std::replace(icon_name.begin(), icon_name.end(), ' ', '-');
|
std::replace(icon_name.begin(), icon_name.end(), ' ', '-');
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -12,16 +15,18 @@ TEST_CASE("Network::Errors", "[core]") {
|
|||||||
Network::Socket socks[2];
|
Network::Socket socks[2];
|
||||||
for (Network::Socket& sock : socks) {
|
for (Network::Socket& sock : socks) {
|
||||||
REQUIRE(sock.Initialize(Network::Domain::INET, Network::Type::STREAM,
|
REQUIRE(sock.Initialize(Network::Domain::INET, Network::Type::STREAM,
|
||||||
Network::Protocol::TCP) == Network::Errno::SUCCESS);
|
Network::Protocol::TCP) == Network::Errno::E_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
Network::SockAddrIn addr{
|
Network::SockAddrIn addr{
|
||||||
Network::Domain::INET,
|
16,
|
||||||
{127, 0, 0, 1},
|
u8(Network::Domain::INET),
|
||||||
1, // hopefully nobody running this test has something listening on port 1
|
1, // hopefully nobody running this test has something listening on port 1
|
||||||
|
{127, 0, 0, 1},
|
||||||
|
{},
|
||||||
};
|
};
|
||||||
REQUIRE(socks[0].Connect(addr) == Network::Errno::CONNREFUSED);
|
REQUIRE(socks[0].Connect(addr) == Network::Errno::E_CONNREFUSED);
|
||||||
|
|
||||||
std::vector<u8> message{1, 2, 3, 4};
|
std::vector<u8> message{1, 2, 3, 4};
|
||||||
REQUIRE(socks[1].Recv(0, message).second == Network::Errno::NOTCONN);
|
REQUIRE(socks[1].Recv(0, message).second == Network::Errno::E_NOTCONN);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -55,7 +55,7 @@ size_t StagingBuffers::RequestBuffer(size_t requested_size) {
|
|||||||
}
|
}
|
||||||
StagingBufferAlloc alloc;
|
StagingBufferAlloc alloc;
|
||||||
alloc.buffer.Create();
|
alloc.buffer.Create();
|
||||||
const auto next_pow2_size = std::bit_ceil(requested_size);
|
const auto next_pow2_size = Common::NextPow2(requested_size);
|
||||||
glNamedBufferStorage(alloc.buffer.handle, next_pow2_size, nullptr,
|
glNamedBufferStorage(alloc.buffer.handle, next_pow2_size, nullptr,
|
||||||
storage_flags | GL_MAP_PERSISTENT_BIT);
|
storage_flags | GL_MAP_PERSISTENT_BIT);
|
||||||
alloc.map = static_cast<u8*>(glMapNamedBufferRange(alloc.buffer.handle, 0, next_pow2_size,
|
alloc.map = static_cast<u8*>(glMapNamedBufferRange(alloc.buffer.handle, 0, next_pow2_size,
|
||||||
|
|||||||
@@ -1404,7 +1404,7 @@ void FormatConversionPass::ConvertImage(Image& dst_image, Image& src_image,
|
|||||||
const u32 copy_size = region.width * region.height * region.depth * img_bpp;
|
const u32 copy_size = region.width * region.height * region.depth * img_bpp;
|
||||||
if (pbo_size < copy_size) {
|
if (pbo_size < copy_size) {
|
||||||
intermediate_pbo.Create();
|
intermediate_pbo.Create();
|
||||||
pbo_size = std::bit_ceil(copy_size);
|
pbo_size = Common::NextPow2(copy_size);
|
||||||
glNamedBufferData(intermediate_pbo.handle, pbo_size, nullptr, GL_STREAM_COPY);
|
glNamedBufferData(intermediate_pbo.handle, pbo_size, nullptr, GL_STREAM_COPY);
|
||||||
}
|
}
|
||||||
// Copy from source to PBO
|
// Copy from source to PBO
|
||||||
|
|||||||
@@ -1011,7 +1011,7 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
|
|||||||
if (buffers[level]) {
|
if (buffers[level]) {
|
||||||
return *buffers[level];
|
return *buffers[level];
|
||||||
}
|
}
|
||||||
const auto new_size = std::bit_ceil(needed_size);
|
const auto new_size = Common::NextPow2(needed_size);
|
||||||
static constexpr VkBufferUsageFlags flags =
|
static constexpr VkBufferUsageFlags flags =
|
||||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
||||||
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
|
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
|
||||||
|
|||||||
@@ -2190,7 +2190,7 @@ void TextureCache<P>::UnregisterImage(ImageId image_id) {
|
|||||||
image.flags &= ~ImageFlagBits::BadOverlap;
|
image.flags &= ~ImageFlagBits::BadOverlap;
|
||||||
lru_cache.Free(image.lru_index);
|
lru_cache.Free(image.lru_index);
|
||||||
const auto& clear_page_table =
|
const auto& clear_page_table =
|
||||||
[image_id](u64 page, ::Common::unordered_map<u64, std::vector<ImageId>>& selected_page_table) {
|
[image_id](u64 page, ::Common::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>>& selected_page_table) {
|
||||||
const auto page_it = selected_page_table.find(page);
|
const auto page_it = selected_page_table.find(page);
|
||||||
if (page_it == selected_page_table.end()) {
|
if (page_it == selected_page_table.end()) {
|
||||||
ASSERT_MSG(false, "Unregistering unregistered page={:#x}", page << YUZU_PAGEBITS);
|
ASSERT_MSG(false, "Unregistering unregistered page={:#x}", page << YUZU_PAGEBITS);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/hash.h"
|
||||||
#include "common/literals.h"
|
#include "common/literals.h"
|
||||||
#include "common/lru_cache.h"
|
#include "common/lru_cache.h"
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
@@ -68,7 +69,7 @@ struct AsyncDecodeContext {
|
|||||||
std::atomic_bool complete;
|
std::atomic_bool complete;
|
||||||
};
|
};
|
||||||
|
|
||||||
using TextureCacheGPUMap = ::Common::unordered_map<u64, std::vector<ImageId>>;
|
using TextureCacheGPUMap = ::Common::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>>;
|
||||||
|
|
||||||
class TextureCacheChannelInfo : public ChannelInfo {
|
class TextureCacheChannelInfo : public ChannelInfo {
|
||||||
public:
|
public:
|
||||||
@@ -442,7 +443,7 @@ private:
|
|||||||
u64 last_framebuffer_serial = 0;
|
u64 last_framebuffer_serial = 0;
|
||||||
|
|
||||||
::Common::unordered_map<RenderTargets, FramebufferId> framebuffers;
|
::Common::unordered_map<RenderTargets, FramebufferId> framebuffers;
|
||||||
::Common::unordered_map<u64, std::vector<ImageMapId>> page_table;
|
::Common::unordered_map<u64, std::vector<ImageMapId>, Common::IdentityHash<u64>> page_table;
|
||||||
::Common::unordered_map<ImageId, boost::container::small_vector<ImageViewId, 16>> sparse_views;
|
::Common::unordered_map<ImageId, boost::container::small_vector<ImageViewId, 16>> sparse_views;
|
||||||
|
|
||||||
DAddr virtual_invalid_space{};
|
DAddr virtual_invalid_space{};
|
||||||
|
|||||||
Reference in New Issue
Block a user