mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-28 02:03:50 +00:00
Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4188417d6f | |||
| ccbcc9958c | |||
| 8b514d39fe | |||
| a3d1871002 | |||
| 2387863c4a | |||
| 9fc078ac49 | |||
| 5000815f9d | |||
| 1da937c5f1 | |||
| 5f894ea6e5 | |||
| f48e2f9647 | |||
| 1a8c30b332 | |||
| 9ac88a6576 | |||
| 190275fd97 | |||
| f43902a845 | |||
| dc87555982 | |||
| bd4130055d | |||
| faca1b377a | |||
| 56536549cc | |||
| a2b542693b | |||
| e3a6a99cae | |||
| e553e14d53 | |||
| f4cd650f95 | |||
| 38d7021a54 | |||
| b2223ec9db | |||
| 2b1caac3e8 | |||
| 0fc949d29d | |||
| 88d1fb47d4 | |||
| 4f4bf58153 | |||
| 61c0c8bb7c | |||
| a86291a812 | |||
| ea337df5dd | |||
| f0fe092be8 | |||
| 6c1bb8d5c5 | |||
| f2cf3028c5 | |||
| 463f255299 | |||
| aea66ab8e1 | |||
| 084014d942 | |||
| 349b19fc1a | |||
| 896ee3080f | |||
| 63b5e01627 | |||
| 62b0169f05 | |||
| 8d799eaf1c | |||
| 15a1d783cd | |||
| af9f924658 | |||
| cc8ea0f574 | |||
| a020ce62f8 | |||
| bd532f51b4 | |||
| 8694f708eb | |||
| 339694df1b | |||
| 0043edb66f | |||
| 29888a6f35 | |||
| 78aa04ed51 | |||
| fdc8ea262d | |||
| c09c3edd11 | |||
| 910c59ceab | |||
| ee378e1322 | |||
| 5b525e5f35 | |||
| 6b42e8346d | |||
| bba106569a | |||
| 4dea82c984 |
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
WORK_DIR="$PWD"
|
||||
xcrun --sdk iphoneos --show-sdk-path
|
||||
|
||||
# TODO: support iphonesimulator sdk
|
||||
|
||||
cmake -G Xcode -B build/ios \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=16.0 \
|
||||
-DCMAKE_OSX_SYSROOT=iphoneos \
|
||||
-DCMAKE_SYSTEM_NAME=iOS \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DYUZU_USE_EXTERNAL_SDL2=ON \
|
||||
"$@"
|
||||
|
||||
cmake --build build/ios -t eden-ios --config Release
|
||||
@@ -115,7 +115,7 @@ for file in $FILES; do
|
||||
*.cmake|*.sh|*.ps1|*.py|*.rb|*.perl|*.pl|*.nix|*CMakeLists.txt)
|
||||
begin="#"
|
||||
;;
|
||||
*.kt|*.kts|*.cpp|*.h|*.qml|*.c|*.hpp|*.hxx|*.cxx|*.h.in|*.inc)
|
||||
*.kt|*.kts|*.cpp|*.h|*.qml|*.c|*.hpp|*.hxx|*.cxx|*.h.in|*.inc|*.mm)
|
||||
begin="//"
|
||||
;;
|
||||
*)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
diff --git a/libs/process/src/shell.cpp b/libs/process/src/shell.cpp
|
||||
index bf4bbfd8..bc4aae89 100644
|
||||
--- a/libs/process/src/shell.cpp
|
||||
+++ b/libs/process/src/shell.cpp
|
||||
@@ -19,7 +19,7 @@
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
-#elif !defined(__OpenBSD__) && !defined(__ANDROID__)
|
||||
+#elif !defined(__OpenBSD__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IPHONE)
|
||||
#include <wordexp.h>
|
||||
#endif
|
||||
|
||||
@@ -30,7 +30,7 @@ BOOST_PROCESS_V2_DECL const error_category& get_shell_category()
|
||||
{
|
||||
return system_category();
|
||||
}
|
||||
-#elif !defined(__OpenBSD__) && !defined(__ANDROID__)
|
||||
+#elif !defined(__OpenBSD__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IPHONE)
|
||||
|
||||
struct shell_category_t final : public error_category
|
||||
{
|
||||
@@ -99,7 +99,7 @@ auto shell::args() const-> args_type
|
||||
return input_.c_str();
|
||||
}
|
||||
|
||||
-#elif !defined(__OpenBSD__) && !defined(__ANDROID__)
|
||||
+#elif !defined(__OpenBSD__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IPHONE)
|
||||
|
||||
void shell::parse_()
|
||||
{
|
||||
+48
-12
@@ -24,6 +24,29 @@ include(CMakeDependentOption)
|
||||
include(CTest)
|
||||
include(CPMUtil)
|
||||
|
||||
# TODO(crueter): Make this more automatic.
|
||||
if (IOS)
|
||||
list(APPEND CMAKE_FIND_ROOT_PATH "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "")
|
||||
list(APPEND CMAKE_PROGRAM_PATH "/opt/homebrew/bin" CACHE INTERNAL "")
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH CACHE INTERNAL "")
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH CACHE INTERNAL "")
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH CACHE INTERNAL "")
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH CACHE INTERNAL "")
|
||||
|
||||
list(LENGTH CMAKE_OSX_ARCHITECTURES _arch_len)
|
||||
if (NOT _arch_len EQUAL 1)
|
||||
message(FATAL_ERROR "CMAKE_OSX_ARCHITECTURES must contain exactly one architecture.")
|
||||
endif()
|
||||
|
||||
# TODO(crueter): Proper handling for this.
|
||||
if (CMAKE_OSX_ARCHITECTURES STREQUAL arm64)
|
||||
set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
||||
else()
|
||||
set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_OSX_ARCHITECTURES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ARCHITECTURE)
|
||||
message(FATAL_ERROR "Architecture didn't make it out of scope, did you delete DetectArchitecture.cmake?")
|
||||
endif()
|
||||
@@ -45,7 +68,7 @@ if (NETBSD)
|
||||
set(ENV{PKG_CONFIG_PATH} "${PKG_CONFIG_PATH}:${CMAKE_SYSROOT}/usr/pkg/lib/ffmpeg7/pkgconfig")
|
||||
endif()
|
||||
|
||||
cmake_dependent_option(YUZU_STATIC_ROOM "Build a static room executable only (CI only)" OFF "LINUX" OFF)
|
||||
cmake_dependent_option(YUZU_STATIC_ROOM "Build a static room executable only (CI only)" OFF "LINUX OR (APPLE AND NOT IOS)" OFF)
|
||||
if (YUZU_STATIC_ROOM)
|
||||
set(YUZU_ROOM ON)
|
||||
set(YUZU_ROOM_STANDALONE ON)
|
||||
@@ -71,9 +94,15 @@ if (YUZU_STATIC_ROOM)
|
||||
endif()
|
||||
|
||||
# qt stuff
|
||||
option(ENABLE_QT "Enable the Qt frontend" ON)
|
||||
if (IOS OR ANDROID)
|
||||
set(_default_qt OFF)
|
||||
else()
|
||||
set(_default_qt ON)
|
||||
endif()
|
||||
|
||||
option(ENABLE_QT "Enable the Qt frontend" ${_default_qt})
|
||||
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
|
||||
option(ENABLE_UPDATE_CHECKER "Enable update checker (for Qt and Android)" OFF)
|
||||
cmake_dependent_option(ENABLE_UPDATE_CHECKER "Enable update checker (for Qt and Android)" OFF "ENABLE_QT OR ANDROID" OFF)
|
||||
cmake_dependent_option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF "NOT YUZU_USE_BUNDLED_QT" OFF)
|
||||
cmake_dependent_option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF "NOT YUZU_USE_BUNDLED_QT" OFF)
|
||||
set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundled Qt libraries")
|
||||
@@ -220,7 +249,7 @@ endif()
|
||||
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
|
||||
|
||||
set(EXT_DEFAULT OFF)
|
||||
if (MSVC OR ANDROID)
|
||||
if (MSVC OR ANDROID OR IOS)
|
||||
set(EXT_DEFAULT ON)
|
||||
endif()
|
||||
|
||||
@@ -232,14 +261,14 @@ cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from external sour
|
||||
|
||||
# sirit
|
||||
set(BUNDLED_SIRIT_DEFAULT OFF)
|
||||
if (MSVC AND NOT (CMAKE_BUILD_TYPE MATCHES "Deb") OR ANDROID)
|
||||
if ((MSVC AND NOT (CMAKE_BUILD_TYPE MATCHES "Deb")) OR ANDROID OR IOS)
|
||||
set(BUNDLED_SIRIT_DEFAULT ON)
|
||||
endif()
|
||||
|
||||
option(YUZU_USE_BUNDLED_SIRIT "Download bundled sirit" ${BUNDLED_SIRIT_DEFAULT})
|
||||
|
||||
# FreeBSD 15+ has libusb, versions below should disable it
|
||||
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR LINUX OR FREEBSD OR APPLE" OFF)
|
||||
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR LINUX OR FREEBSD OR (APPLE AND NOT IOS)" OFF)
|
||||
|
||||
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT (WIN32 AND ARCHITECTURE_arm64) AND NOT APPLE AND NOT ANDROID" OFF)
|
||||
mark_as_advanced(FORCE ENABLE_OPENGL)
|
||||
@@ -261,10 +290,10 @@ option(YUZU_LEGACY "Apply patches that improve compatibility with older GPUs (e.
|
||||
|
||||
option(NIGHTLY_BUILD "Use Nightly qualifiers in the update checker and build metadata" OFF)
|
||||
|
||||
cmake_dependent_option(YUZU_ROOM "Enable dedicated room functionality" ON "NOT ANDROID" OFF)
|
||||
cmake_dependent_option(YUZU_ROOM "Enable dedicated room functionality" ON "NOT ANDROID AND NOT IOS" OFF)
|
||||
cmake_dependent_option(YUZU_ROOM_STANDALONE "Enable standalone room executable" ON "YUZU_ROOM" OFF)
|
||||
|
||||
cmake_dependent_option(YUZU_CMD "Compile the eden-cli executable" ON "NOT ANDROID" OFF)
|
||||
cmake_dependent_option(YUZU_CMD "Compile the eden-cli executable" ON "NOT ANDROID AND NOT IOS" OFF)
|
||||
|
||||
cmake_dependent_option(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF)
|
||||
|
||||
@@ -308,7 +337,7 @@ if (YUZU_ROOM)
|
||||
add_compile_definitions(YUZU_ROOM)
|
||||
endif()
|
||||
|
||||
if (UNIX AND NOT (LINUX OR WIN32))
|
||||
if ((UNIX OR IOS) AND NOT (LINUX OR WIN32))
|
||||
if(CXX_APPLE OR CXX_CLANG)
|
||||
# libc++ has stop_token and jthread as experimental
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexperimental-library")
|
||||
@@ -381,7 +410,10 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
find_package(RenderDoc MODULE)
|
||||
find_package(RenderDoc MODULE QUIET)
|
||||
if (NOT RenderDoc_FOUND)
|
||||
message(WARNING "RenderDoc not found. Some debugging features may be disabled.")
|
||||
endif()
|
||||
|
||||
# openssl funniness
|
||||
if (YUZU_USE_BUNDLED_OPENSSL)
|
||||
@@ -509,9 +541,13 @@ endfunction()
|
||||
# Platform-specific library requirements
|
||||
# Put these BEFORE EXTERNALS or Boost WILL die
|
||||
# =============================================
|
||||
|
||||
if (APPLE)
|
||||
foreach(fw Carbon Metal Cocoa IOKit CoreVideo CoreMedia Security UniformTypeIdentifiers Foundation)
|
||||
if (IOS)
|
||||
set(_libs Carbon Metal IOKit CoreVideo CoreMedia Security UniformTypeIdentifiers Foundation)
|
||||
else()
|
||||
set(_libs Carbon Metal Cocoa IOKit CoreVideo CoreMedia Security UniformTypeIdentifiers Foundation)
|
||||
endif()
|
||||
foreach(fw ${_libs})
|
||||
find_library(${fw}_LIBRARY ${fw} REQUIRED)
|
||||
list(APPEND PLATFORM_LIBRARIES ${${fw}_LIBRARY})
|
||||
endforeach()
|
||||
|
||||
Vendored
+579
-624
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+503
-548
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+508
-550
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+527
-573
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@
|
||||
- [macOS](#macos)
|
||||
- [OpenIndiana](#openindiana)
|
||||
- [OmniOS](#omnios)
|
||||
- [iOS](#ios)
|
||||
- [HaikuOS](#haikuos)
|
||||
- [OpenBSD](#openbsd)
|
||||
- [FreeBSD](#freebsd)
|
||||
@@ -90,6 +91,16 @@ If it wasn't obvious already, you require a X11 server to properly run the emula
|
||||
|
||||
For Solaris based OSes, `${CMAKE_SYSTEM_NAME}` isn't properly set on CMake (it's set to i686 on AMD64), you may find issues when building OpenSSL from `openssl-cmake`.
|
||||
|
||||
## iOS
|
||||
|
||||
iOS has a dedicated build script, we **highly** recommend using that instead of doing anything else, we don't support any other configuration than the one present in said build script.
|
||||
|
||||
To build, it's simply as easy as doing
|
||||
```sh
|
||||
chmod +x .ci/ios/build.sh
|
||||
.ci/ios/build.sh
|
||||
```
|
||||
|
||||
## HaikuOS
|
||||
|
||||
It's recommended to do a `pkgman full-sync` before installing. See [HaikuOS: Installing applications](https://www.haiku-os.org/guides/daily-tasks/install-applications/). Sometimes the process may be interrupted by an error like "Interrupted syscall". Simply firing the command again fixes the issue. By default `g++` is included on the default installation.
|
||||
|
||||
+21
-33
@@ -1,44 +1,32 @@
|
||||
# User Handbook - Command Line
|
||||
|
||||
There are two main applications, an SDL-based app (`eden-cli`) and a Qt based app (`eden`); both accept the same command line arguments.
|
||||
There are two main applications, an SDL-based app (`eden-cli`) and a Qt based app (`eden`); both accept command line arguments.
|
||||
|
||||
## eden
|
||||
|
||||
- `./eden <path>`: Running with a single argument and nothing else, will make the emulator look for the given file and load it, this behavior is similar to `eden-cli`; allows dragging and dropping games into the application.
|
||||
- `--debug/-d`: Enter debug mode, allow gdb stub at port `1234`
|
||||
- `--config/-c`: Specify alternate configuration file.
|
||||
- `--fullscreen/-f`: Use fullscreen.
|
||||
- `--help/-h`: Display help.
|
||||
- `--game/-g <path>`: Alternate way to specify what to load, overrides. However let it be noted that arguments that use `-` will be treated as options/ignored, if your game, for some reason, starts with `-`, in order to safely handle it you may need to specify it as an argument.
|
||||
- `--multiplayer/-m`: Specify multiplayer options.
|
||||
- `--program/-p`: Specify the program arguments to pass (optional).
|
||||
- `--user/-u <number>`: Specify the user index.
|
||||
- `--version/-v`: Display version and quit.
|
||||
- `--input-profile/-i <name>`: Specifies input profile name to use (for player #0 only).
|
||||
- `--null-render/-n`: Forces the usage of the "Null" render backend irrespective of settings.
|
||||
- `--filter/-x`: Sets the debug log filter irrespective of settings.
|
||||
- `--singlecore/-s`: Forces single-core regardless of settings.
|
||||
|
||||
Only the Qt frontend supports the following arguments:
|
||||
|
||||
- `-g <path>`: Alternate way to specify what to load, overrides. However let it be noted that arguments that use `-` will be treated as options/ignored, if your game, for some reason, starts with `-`, in order to safely handle it you may need to specify it as an argument.
|
||||
- `-f`: Use fullscreen.
|
||||
- `-u <number>`: Select the index of the user to load as.
|
||||
- `-input-profile <name>`: Specifies input profile name to use (for player #0 only).
|
||||
- `-qlaunch`: Launch QLaunch.
|
||||
- `-hlaunch`: Launch homebrew launcher `nx-hbloader`.
|
||||
- Requires a copy of Atmosphere to be extracted onto `sdmc`.
|
||||
- This is a shorthand for `<eden folder>/sdmc/atmosphere/hbl.nsp`.
|
||||
- `-setup`: Launch setup applet.
|
||||
|
||||
`eden` (provided with `--room`), and `eden-room` supports the following options as well:
|
||||
## eden-cli
|
||||
|
||||
- `-n/--room-name`: The name of the room.
|
||||
- `-d/--room-description`: The room description.
|
||||
- `-s/--bind-address`: The bind address for the room.
|
||||
- `-p/--port`: The port used for the room.
|
||||
- `-m/--max-members`: The maximum number of players for this room.
|
||||
- `-w/--password`: The password for the room.
|
||||
- `-g/--preferred-game`: The preferred game for this room.
|
||||
- `-i/--preferred-game-id`: The preferred game-id for this room.
|
||||
- `-u/--username`: The username used for announce.
|
||||
- `-t/--token`: The token used for announce.
|
||||
- `-a/--web-api-url`: yuzu Web API url.
|
||||
- `-b/--ban-list-file`: The file for storing the room ban list.
|
||||
- `-l/--log-file`: The file for storing the room log.
|
||||
- `-h/--help`: Display this help and exit.
|
||||
- `-v/--version`: Output version information and exit.
|
||||
- `--debug/-d`: Enter debug mode, allow gdb stub at port `1234`
|
||||
- `--config/-c`: Specify alternate configuration file.
|
||||
- `--fullscreen/-f`: Set fullscreen.
|
||||
- `--help/-h`: Display help.
|
||||
- `--game/-g`: Specify the game to run.
|
||||
- `--multiplayer/-m`: Specify multiplayer options.
|
||||
- `--program/-p`: Specify the program arguments to pass (optional).
|
||||
- `--user/-u`: Specify the user index.
|
||||
- `--version/-v`: Display version and quit.
|
||||
- `--input-profile/-i`: Specifies input profile name to use (for player #0 only).
|
||||
- `--null-render/-n`: Forces the usage of the "Null" render backend irrespective of settings.
|
||||
- `--filter/-x`: Sets the debug log filter irrespective of settings.
|
||||
- `--singlecore/-s`: Forces single-core regardless of settings.
|
||||
|
||||
Vendored
+6
@@ -272,6 +272,12 @@ if (VulkanMemoryAllocator_ADDED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# httplib
|
||||
if (IOS)
|
||||
set(HTTPLIB_USE_BROTLI_IF_AVAILABLE OFF)
|
||||
endif()
|
||||
AddJsonPackage(httplib)
|
||||
|
||||
# cpp-jwt
|
||||
if (ENABLE_WEB_SERVICE OR ENABLE_UPDATE_CHECKER)
|
||||
AddJsonPackage(cpp-jwt)
|
||||
|
||||
+14
-9
@@ -35,16 +35,21 @@ This file is based off of Yuzu and Dynarmic.
|
||||
# Do note that situations where multiple architectures are defined
|
||||
# should NOT be too dependent on the architecture
|
||||
# otherwise, you may end up with duplicate code
|
||||
if (CMAKE_OSX_ARCHITECTURES)
|
||||
if (DEFINED CMAKE_OSX_ARCHITECTURES)
|
||||
set(MULTIARCH_BUILD 1)
|
||||
set(ARCHITECTURE "${CMAKE_OSX_ARCHITECTURES}")
|
||||
|
||||
# hope and pray the architecture names match
|
||||
foreach(ARCH IN ${CMAKE_OSX_ARCHITECTURES})
|
||||
set(ARCHITECTURE_${ARCH} 1 PARENT_SCOPE)
|
||||
add_definitions(-DARCHITECTURE_${ARCH}=1)
|
||||
endforeach()
|
||||
|
||||
if (IOS)
|
||||
# TODO: Right... the toolchain file won't properly accomodate OSX_ARCHITECTURE
|
||||
# they aren't defining it as a list properly I assume?
|
||||
set(ARCHITECTURE_arm64 1)
|
||||
add_definitions(-DARCHITECTURE_arm64=1)
|
||||
else ()
|
||||
# hope and pray the architecture names match
|
||||
foreach(ARCH ${CMAKE_OSX_ARCHITECTURES})
|
||||
set(ARCHITECTURE_${ARCH} 1)
|
||||
add_definitions(-DARCHITECTURE_${ARCH}=1)
|
||||
endforeach()
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
@@ -218,4 +223,4 @@ if (NOT DEFINED ARCHITECTURE)
|
||||
add_definitions(-DARCHITECTURE_GENERIC=1)
|
||||
endif()
|
||||
|
||||
message(STATUS "[DetectArchitecture] Target architecture: ${ARCHITECTURE}")
|
||||
message(STATUS "[DetectArchitecture] Target architecture: ${ARCHITECTURE}")
|
||||
|
||||
@@ -54,6 +54,12 @@ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
set(CXX_APPLE ON)
|
||||
endif()
|
||||
|
||||
# This fixes some quirks with xcrun or weird iOS toolchain cmake files
|
||||
if (IOS)
|
||||
unset(CXX_CLANG)
|
||||
set(CXX_APPLE ON)
|
||||
endif()
|
||||
|
||||
# https://gitlab.kitware.com/cmake/cmake/-/merge_requests/11112
|
||||
# This works totally fine on MinGW64, but not CLANG{,ARM}64
|
||||
if(MINGW AND CXX_CLANG)
|
||||
|
||||
Vendored
+17
-1
@@ -29,6 +29,22 @@ if (NOT YUZU_USE_BUNDLED_FFMPEG)
|
||||
--extra-ldflags="-nostdlib"
|
||||
)
|
||||
set(FFmpeg_IS_CROSS_COMPILING TRUE)
|
||||
elseif(IOS)
|
||||
execute_process(COMMAND xcrun --sdk iphoneos --show-sdk-path OUTPUT_VARIABLE SYSROOT)
|
||||
# Lovely extra newline apple adds that **we** must remove... thank you apple!
|
||||
string(STRIP "${SYSROOT}" SYSROOT)
|
||||
set(FFmpeg_CC xcrun --sdk iphoneos clang -arch arm64)
|
||||
set(FFmpeg_CXX xcrun --sdk iphoneos clang++ -arch arm64)
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
|
||||
--arch=arm64
|
||||
--enable-cross-compile
|
||||
--sysroot="${SYSROOT}"
|
||||
--extra-ldflags="-miphoneos-version-min=16.0"
|
||||
--install-name-dir='@rpath'
|
||||
--disable-audiotoolbox
|
||||
--disable-videotoolbox
|
||||
)
|
||||
set(FFmpeg_IS_CROSS_COMPILING TRUE)
|
||||
# User attempts to do a FFmpeg cross compilation because...
|
||||
# Here we just quickly test against host/system processors not matching
|
||||
# TODO: Test for versions not matching as well?
|
||||
@@ -62,7 +78,7 @@ elseif (ANDROID)
|
||||
--enable-mediacodec
|
||||
--enable-jni
|
||||
)
|
||||
elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING AND NOT ANDROID)
|
||||
elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING AND NOT ANDROID AND NOT IOS)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBVA libva)
|
||||
pkg_check_modules(CUDA cuda)
|
||||
|
||||
Vendored
+2
-1
@@ -24,7 +24,8 @@ if (MINGW OR LINUX OR APPLE)
|
||||
message(FATAL_ERROR "Required program `autoconf` not found.")
|
||||
endif()
|
||||
|
||||
find_program(LIBTOOLIZE libtoolize)
|
||||
find_program(LIBTOOLIZE
|
||||
NAMES libtoolize glibtoolize)
|
||||
if ("${LIBTOOLIZE}" STREQUAL "LIBTOOLIZE-NOTFOUND")
|
||||
message(FATAL_ERROR "Required program `libtoolize` not found.")
|
||||
endif()
|
||||
|
||||
@@ -177,6 +177,9 @@ else()
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-invalid-offsetof>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-unused-parameter>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-missing-field-initializers>)
|
||||
if (NOT IOS)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-Werror=missing-declarations>)
|
||||
endif()
|
||||
|
||||
if (CXX_CLANG OR CXX_ICC OR CXX_APPLE) # Clang, AppleClang, or Intel C++
|
||||
if (NOT MSVC)
|
||||
@@ -295,4 +298,9 @@ if (ANDROID)
|
||||
target_include_directories(yuzu-android PRIVATE android/app/src/main)
|
||||
endif()
|
||||
|
||||
if (IOS)
|
||||
add_subdirectory(ios)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-Wno-error>)
|
||||
endif()
|
||||
|
||||
include(GenerateDepHashes)
|
||||
|
||||
+1
@@ -30,6 +30,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
||||
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
|
||||
ENABLE_BUFFER_HISTORY("enable_buffer_history"),
|
||||
USE_OPTIMIZED_VERTEX_BUFFERS("use_optimized_vertex_buffers"),
|
||||
ENABLE_GPU_BUFFER_READBACK("enable_gpu_buffer_readback"),
|
||||
SYNC_MEMORY_OPERATIONS("sync_memory_operations"),
|
||||
BUFFER_REORDER_DISABLE("disable_buffer_reorder"),
|
||||
RENDERER_DEBUG("debug"),
|
||||
|
||||
+7
@@ -908,6 +908,13 @@ abstract class SettingsItem(
|
||||
descriptionId = R.string.enable_buffer_history_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.ENABLE_GPU_BUFFER_READBACK,
|
||||
titleId = R.string.enable_gpu_buffer_readback,
|
||||
descriptionId = R.string.enable_gpu_buffer_readback_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.USE_OPTIMIZED_VERTEX_BUFFERS,
|
||||
|
||||
+1
@@ -549,6 +549,7 @@ class SettingsFragmentPresenter(
|
||||
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
|
||||
add(BooleanSetting.RENDERER_REACTIVE_FLUSHING.key)
|
||||
add(BooleanSetting.ENABLE_BUFFER_HISTORY.key)
|
||||
add(BooleanSetting.ENABLE_GPU_BUFFER_READBACK.key)
|
||||
add(BooleanSetting.USE_OPTIMIZED_VERTEX_BUFFERS.key)
|
||||
|
||||
add(HeaderSetting(R.string.hacks))
|
||||
|
||||
@@ -788,7 +788,7 @@ int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject
|
||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj,
|
||||
jstring jprogramId,
|
||||
jstring jupdatePath) {
|
||||
const u64 program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId));
|
||||
u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
|
||||
std::string updatePath = Common::Android::GetJString(env, jupdatePath);
|
||||
std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>(
|
||||
EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
|
||||
@@ -796,7 +796,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* en
|
||||
for (const auto& item : nsp->GetNCAs()) {
|
||||
for (const auto& nca_details : item.second) {
|
||||
if (nca_details.second->GetName().ends_with(".cnmt.nca")) {
|
||||
const auto update_id = FileSys::GetBaseTitleID(nca_details.second->GetTitleId());
|
||||
auto update_id = nca_details.second->GetTitleId() & ~0xFFFULL;
|
||||
if (update_id == program_id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -580,6 +580,8 @@
|
||||
<string name="renderer_reactive_flushing_description">يحسن دقة العرض في بعض الألعاب على حساب الأداء.</string>
|
||||
<string name="enable_buffer_history">تمكين سجل التخزين المؤقت</string>
|
||||
<string name="enable_buffer_history_description">يُتيح هذا الخيار الوصول إلى حالات التخزين المؤقت السابقة. وقد يُحسّن جودة العرض وثبات الأداء في بعض الألعاب.</string>
|
||||
<string name="enable_gpu_buffer_readback">تفعيل قراءة مخزن وحدة معالجة الرسومات</string>
|
||||
<string name="enable_gpu_buffer_readback_description">يحافظ هذا النظام على بيانات المخزن المؤقت المُعدّلة بواسطة وحدة معالجة الرسومات عن طريق قراءتها مرة أخرى قبل التحميل. تتطلب بعض الألعاب ذلك لعرض بعض التأثيرات بشكل صحيح. قد يُسبب ذلك مشاكل إذا لم يتمكن الجهاز من التعامل مع عبء العمل الإضافي.</string>
|
||||
<string name="use_optimized_vertex_buffers">مخازن الرؤوس المُحسّنة</string>
|
||||
<string name="use_optimized_vertex_buffers_description">يُتيح ربطًا مُحسَّنًا لمخازن الرؤوس لتحسين الأداء. يتطلب برامج تشغيل Mesa 26.0+ Turnip/ برامج تشغيل QCOM. قد يتعطل على برامج تشغيل Turnip القديمة (25.3 وما دون).</string>
|
||||
|
||||
@@ -1097,6 +1099,7 @@
|
||||
<string name="gpu_fence_behavior_immediate">فوري</string>
|
||||
<string name="gpu_fence_behavior_balanced">متوازن</string>
|
||||
<string name="gpu_fence_behavior_accurate">دقيق</string>
|
||||
<string name="gpu_fence_behavior_strict">صارم</string>
|
||||
|
||||
<string name="vram_usage_conservative">محافظ</string>
|
||||
<string name="vram_usage_aggressive">عدواني</string>
|
||||
|
||||
@@ -967,6 +967,7 @@ Wirklich fortfahren?</string>
|
||||
<string name="gpu_fence_behavior_immediate">Direkt</string>
|
||||
<string name="gpu_fence_behavior_balanced">Ausgewogen</string>
|
||||
<string name="gpu_fence_behavior_accurate">Genau</string>
|
||||
<string name="gpu_fence_behavior_strict">Strikt</string>
|
||||
|
||||
<string name="vram_usage_conservative">Konservativ</string>
|
||||
<string name="vram_usage_aggressive">Aggressiv</string>
|
||||
|
||||
@@ -289,7 +289,6 @@
|
||||
<string name="gpu_driver_fetcher">Obtenedor de controladores de la GPU</string>
|
||||
<string name="gpu_driver_manager">Gestor de controladores de la GPU</string>
|
||||
<string name="install_gpu_driver_description">Instale los controladores alternativos para obtener un posible mejor rendimiento o precisión</string>
|
||||
<string name="post_processing_add">Añadir efecto</string>
|
||||
<string name="post_processing_open_list">Abrir lista</string>
|
||||
<string name="post_processing_close_list">Cerrar lista</string>
|
||||
<string name="post_processing_reset">Restablecer a predeterminado</string>
|
||||
@@ -524,6 +523,8 @@
|
||||
<string name="renderer_reactive_flushing_description">Mejora la precisión de renderizado en algunos juegos, pero reduce el rendimiento.</string>
|
||||
<string name="enable_buffer_history">Activar el historial del búfer</string>
|
||||
<string name="enable_buffer_history_description">Permite el acceso al estado del búfer anterior. Esta opción puede mejorar la calidad de renderizado y la consistencia en el rendimiento de algunos juegos.</string>
|
||||
<string name="enable_gpu_buffer_readback">Activar la lectura del buffer de la GPU</string>
|
||||
<string name="enable_gpu_buffer_readback_description">Conserva los datos del búfer modificados por la GPU leyéndolos antes de subirlos.\nAlgunos juegos requieren esto para renderizar correctamente ciertos efectos.\nPuede causar problemas si el hardware no puede soportar la carga de trabajo adicional.</string>
|
||||
<string name="use_optimized_vertex_buffers">Búferes de vértices optimizados</string>
|
||||
<string name="use_optimized_vertex_buffers_description">Permite la optimización del enlace del búfer de vértices para un mejor rendimiento. Requiere controladores Mesa 26.0+ Turnip/ controladores QCOM. Fallará con controladores Turnip más antiguos (versión 25.3 o inferior).</string>
|
||||
|
||||
@@ -1036,6 +1037,7 @@
|
||||
<string name="gpu_fence_behavior_immediate">Inmediato</string>
|
||||
<string name="gpu_fence_behavior_balanced">Equilibrado</string>
|
||||
<string name="gpu_fence_behavior_accurate">Preciso</string>
|
||||
<string name="gpu_fence_behavior_strict">Estricto</string>
|
||||
|
||||
<string name="vram_usage_conservative">Conservador</string>
|
||||
<string name="vram_usage_aggressive">Agresivo</string>
|
||||
|
||||
@@ -318,13 +318,6 @@
|
||||
<string name="frame_gen_target_rate">Целевая частота кадров</string>
|
||||
<string name="frame_gen_target_rate_description">Выберите значение под ваш дисплей. Множитель подстроится сам, чтобы его держать, и откатит изменения, если игра начнёт тормозить.</string>
|
||||
<string name="frame_gen_target_rate_off">Использовать фиксированный множитель</string>
|
||||
<string name="frame_gen_on">Вкл.</string>
|
||||
<string name="frame_gen_off">Выкл.</string>
|
||||
<string name="frame_gen_fixed">Фикс.</string>
|
||||
<string name="frame_gen_flow_auto">Авто</string>
|
||||
<string name="frame_gen_quick_description">Включите или выключите генерацию кадров и выберите множитель кадров.</string>
|
||||
<string name="frame_gen_target_rate_quick_description">Генерация кадров с заданной частотой кадров. Множитель регулируется автоматически.</string>
|
||||
<string name="frame_gen_flow_scale_quick_description">Разрешение, используемое для оценки движения между кадрами. Меньшие значения экономят время ГПУ.</string>
|
||||
<string name="frame_gen_queue_target">Целевой размер очереди кадров</string>
|
||||
<string name="frame_gen_queue_target_description">Сколько готовых кадров может ожидать перед выводом на экран. Более длинные очереди сглаживают скачки ГПУ ценой задержки ввода.</string>
|
||||
<string name="frame_gen_queue_target_0">Минимальная задержка (Без буферизации)</string>
|
||||
@@ -335,14 +328,12 @@
|
||||
<string name="frame_gen_flow_scale">Разрешение оценки движения</string>
|
||||
<string name="frame_gen_flow_scale_description">Разрешение прохода оптического потока в долях от выходного разрешения. Его понижение — самый дешёвый способ вернуть производительность.</string>
|
||||
<string name="frame_gen_unsupported">Генерация кадров недоступна</string>
|
||||
<string name="frame_gen_unsupported_description">В этом ГПУ драйвере отсутствует поддержка модели памяти Vulkan или половинной точности (float16), которая требуется шейдерам Lossless Scaling.</string>
|
||||
<string name="lossless_scaling_setup_description">Опционально. Укажите свой Lossless.dll для включения генерации кадров позже.</string>
|
||||
<string name="lossless_scaling_install">Установить Lossless.dll</string>
|
||||
<string name="lossless_scaling_install_description">Для генерации кадров требуется ваша собственная легальная копия Lossless.dll из Lossless Scaling</string>
|
||||
<string name="lossless_scaling_replace_description">Выбрать другой файл Lossless.dll</string>
|
||||
<string name="frame_generation_support">Генерация кадров</string>
|
||||
<string name="frame_generation_supported">Поддерживается</string>
|
||||
<string name="frame_generation_unsupported">Не поддерживается (нет модели памяти Vulkan или float16)</string>
|
||||
<string name="lossless_scaling_description">Предоставьте свою копию Lossless.dll для включения генерации кадров</string>
|
||||
<string name="lossless_scaling_installed">Установлена</string>
|
||||
<string name="lossless_scaling_not_installed">Не установлена</string>
|
||||
@@ -569,6 +560,8 @@
|
||||
<string name="renderer_reactive_flushing_description">Повышение точности рендеринга в некоторых играх за счет снижения производительности.</string>
|
||||
<string name="enable_buffer_history">Включить историю буфера</string>
|
||||
<string name="enable_buffer_history_description">Позволяет обращаться к предыдущим состояниям буфера. Эта опция может повысить качество рендеринга и стабильность производительности в некоторых играх.</string>
|
||||
<string name="enable_gpu_buffer_readback">Включить обратное чтение буфера ГПУ</string>
|
||||
<string name="enable_gpu_buffer_readback_description">Сохраняет измененные ГПУ данные буфера путем чтения их обратно перед выгрузками. Некоторые игры требуют этого, чтобы рендерить определенные эффекты правильно. Может вызывать проблемы если оборудование не может обработать дополнительную рабочую нагрузку.</string>
|
||||
<string name="use_optimized_vertex_buffers">Оптимизированные вершинные буферы</string>
|
||||
<string name="use_optimized_vertex_buffers_description">Включает оптимизированную привязку вершинного буфера для повышения производительности. Требует Mesa Turnip 26.0+ / QCOM. Приводит к вылету на старых версиях драйверов Turnip (25.3 и ниже).</string>
|
||||
|
||||
@@ -1086,6 +1079,7 @@
|
||||
<string name="gpu_fence_behavior_immediate">Мгновенный</string>
|
||||
<string name="gpu_fence_behavior_balanced">Сбалансированный</string>
|
||||
<string name="gpu_fence_behavior_accurate">Точный</string>
|
||||
<string name="gpu_fence_behavior_strict">Строгий</string>
|
||||
|
||||
<string name="vram_usage_conservative">Консервативный</string>
|
||||
<string name="vram_usage_aggressive">Агрессивный</string>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
||||
|
||||
<string name="app_disclaimer">本软件可以运行用于 Nintendo Switch 游戏机的游戏。不包含任何游戏或密钥。<br /><br />在您开始之前, 请定位您设备存储上的 <![CDATA[<b> prod.keys </b>]]> 文件。<br /><br /><![CDATA[<a href=\"https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/QuickStart.md\">了解更多</a>]]></string>
|
||||
<string name="notice_notification_channel_name">错误与注意事项</string>
|
||||
<string name="notice_notification_channel_description">当发生错误时显示通知。</string>
|
||||
<string name="notification_permission_not_granted">未授予通知权限!</string>
|
||||
@@ -291,25 +290,6 @@
|
||||
<string name="gpu_driver_fetcher">GPU驱动获取器</string>
|
||||
<string name="gpu_driver_manager">GPU 驱动管理器</string>
|
||||
<string name="install_gpu_driver_description">安装替代的驱动程序以获得更好的性能和精度</string>
|
||||
<string name="post_processing">后处理效果</string>
|
||||
<string name="post_processing_description">在渲染完成后应用 ReShade FX 效果</string>
|
||||
<string name="post_processing_per_game_description">配置此游戏的效果链</string>
|
||||
<string name="post_processing_add">添加效果</string>
|
||||
<string name="post_processing_remove">移除</string>
|
||||
<string name="post_processing_open_list">打开列表</string>
|
||||
<string name="post_processing_close_list">关闭列表</string>
|
||||
<string name="post_processing_remove_all">移除效果</string>
|
||||
<string name="post_processing_preset_locked">预设已激活。在开始游戏前可以在后处理效果中编辑它。</string>
|
||||
<string name="post_processing_preset_modified">数值已从原始预设被更改。</string>
|
||||
<string name="post_processing_presets">预设</string>
|
||||
<string name="post_processing_preset_new">新建预设</string>
|
||||
<string name="post_processing_preset_new_description">把您加载的效果及当前数值保存为一个预设,以便今后选用。</string>
|
||||
<string name="post_processing_preset_name_invalid">请给预设起一个不含等号的名称。</string>
|
||||
<string name="post_processing_preset_none">无预设</string>
|
||||
<string name="post_processing_preset_delete">删除预设</string>
|
||||
<string name="post_processing_preset_reset">重置预设值</string>
|
||||
<string name="post_processing_reset">重置为默认值</string>
|
||||
<string name="post_processing_empty">找不到效果。请在此文件中放置 .fx 文件:</string>
|
||||
<string name="frame_gen">帧生成</string>
|
||||
<string name="frame_gen_per_game_description">配置针对此游戏的帧生成设定</string>
|
||||
<string name="frame_gen_description">设定要在使用无损缩放渲染的帧之间应用的插帧。启用后强制采用FIFO呈现模式 。</string>
|
||||
@@ -324,13 +304,6 @@
|
||||
<string name="frame_gen_target_rate_60">60 FPS</string>
|
||||
<string name="frame_gen_target_rate_90">90 FPS</string>
|
||||
<string name="frame_gen_target_rate_120">120 FPS</string>
|
||||
<string name="frame_gen_on">开</string>
|
||||
<string name="frame_gen_off">关</string>
|
||||
<string name="frame_gen_fixed">固定</string>
|
||||
<string name="frame_gen_flow_auto">自动</string>
|
||||
<string name="frame_gen_quick_description">打开或关闭帧生成并选择帧生成倍数。</string>
|
||||
<string name="frame_gen_target_rate_quick_description">生成帧到目标帧率。倍率会自动调整。</string>
|
||||
<string name="frame_gen_flow_scale_quick_description">用来估算帧间运动的分辨率。较低的值可以节省 GPU 时间。</string>
|
||||
<string name="frame_gen_queue_target">帧队列目标</string>
|
||||
<string name="frame_gen_queue_target_description">在显示之前有多少已完成渲染的帧正在等待。较大的队列可以缓解 GPU 突发的压力,但会增加输入延迟。</string>
|
||||
<string name="frame_gen_queue_target_0">最低延迟 (无缓冲)</string>
|
||||
@@ -341,14 +314,12 @@
|
||||
<string name="frame_gen_flow_scale">运动预估分辨率</string>
|
||||
<string name="frame_gen_flow_scale_description">光流通道的分辨率,以输出的比例表示。降低它是提升性能最经济的做法。</string>
|
||||
<string name="frame_gen_unsupported">帧生成不可用</string>
|
||||
<string name="frame_gen_unsupported_description">这个 GPU 驱动缺少 Lossless Scaling 着色器所需的 Vulkan 内存模型或半精度 (float16) 支持。</string>
|
||||
<string name="lossless_scaling_setup_description">作为可选项。请提供您自己的 Lossless.dll 以便在之后可以启用帧生成。</string>
|
||||
<string name="lossless_scaling_install">安装 Lossless.dll</string>
|
||||
<string name="lossless_scaling_install_description">帧生成需要您自己从 Lossless Scaling 获得合法的 Lossless.dll 副本</string>
|
||||
<string name="lossless_scaling_replace_description">选择其它 Lossless.dll 副本</string>
|
||||
<string name="frame_generation_support">帧生成</string>
|
||||
<string name="frame_generation_supported">支持</string>
|
||||
<string name="frame_generation_unsupported">不支持 (无 Vulkan 内存模型或 float16)</string>
|
||||
<string name="lossless_scaling">无损缩放</string>
|
||||
<string name="lossless_scaling_description">提供您自己的 Lossless.dll 文件以启用帧生成</string>
|
||||
<string name="lossless_scaling_installed">已安装</string>
|
||||
@@ -570,6 +541,8 @@
|
||||
<string name="renderer_reactive_flushing_description">通过牺牲性能来提升某些游戏的渲染精度。</string>
|
||||
<string name="enable_buffer_history">启用缓冲区历史</string>
|
||||
<string name="enable_buffer_history_description">启用对先前缓冲区状态的访问。此选项可在某些游戏中提升渲染质量并保持性能的一致性。</string>
|
||||
<string name="enable_gpu_buffer_readback">启用 GPU 缓冲区回读</string>
|
||||
<string name="enable_gpu_buffer_readback_description">在上传前回读经由 GPU 修改过的缓冲区数据,以将其保留。一些游戏会用到这项设定以正确渲染某些效果。如果硬件无法处理额外的工作负载,则可能会导致问题。</string>
|
||||
<string name="use_optimized_vertex_buffers">优化顶点缓冲区</string>
|
||||
<string name="use_optimized_vertex_buffers_description">启用经过优化的顶点缓冲区绑定以提升性能。需要 Mesa 26.0 及以上版本的 Turnip 或 QCOM 驱动程序。若使用较旧版本的 Turnip 驱动 (25.3 及以下版本) 则会导致崩溃。</string>
|
||||
|
||||
@@ -638,11 +611,6 @@
|
||||
<string name="log">日志记录</string>
|
||||
<string name="flush_by_line">按行刷新调试日志</string>
|
||||
<string name="flush_by_line_description">在每行写入时刷新调试日志,使在崩溃或冻结时调试更容易。</string>
|
||||
<string name="extended_logging">开启扩展日志</string>
|
||||
<string name="extended_logging_description">将最大日志文件大小从 100 MiB 提升至 1GiB。</string>
|
||||
<string name="log_filter">日志筛选器</string>
|
||||
<string name="log_filter_description">控制 Eden 的日志类别。例如: *:Info Service.LM:Debug</string>
|
||||
|
||||
<!-- GPU Logging strings -->
|
||||
<string name="gpu_logging_header">GPU 日志</string>
|
||||
<string name="gpu_log_level">日志等级</string>
|
||||
@@ -926,8 +894,6 @@
|
||||
<string name="loader_error_file_not_found">ROM 文件不存在</string>
|
||||
|
||||
<string name="loader_requires_firmware">游戏需要固件</string>
|
||||
<string name="loader_requires_firmware_description"><![CDATA[这个游戏可能需要固件才能正常运行,但您还没有安装任何固件。请在启动前安装固件,或者按 “确定” 继续启动。]]></string>
|
||||
|
||||
<!-- Intent Launch strings -->
|
||||
<string name="searching_for_game">正在搜索游戏...</string>
|
||||
<string name="game_not_found_for_title_id">未找到标题ID的游戏: %1$s</string>
|
||||
@@ -1087,6 +1053,7 @@
|
||||
<string name="gpu_fence_behavior_immediate">即时</string>
|
||||
<string name="gpu_fence_behavior_balanced">均衡</string>
|
||||
<string name="gpu_fence_behavior_accurate">精确</string>
|
||||
<string name="gpu_fence_behavior_strict">严格</string>
|
||||
|
||||
<string name="vram_usage_conservative">保守式</string>
|
||||
<string name="vram_usage_aggressive">主动式</string>
|
||||
|
||||
@@ -229,7 +229,7 @@
|
||||
<string name="add_directory_success">遊戲目錄新增成功</string>
|
||||
<string name="enable_update_checks">檢查更新</string>
|
||||
<string name="enable_update_checks_description">在Eden啟動時檢查有無新版本並選擇是否要下載與安裝更新</string>
|
||||
<string name="update_available">發現新版本</string>
|
||||
<string name="update_available">偵測到新版本</string>
|
||||
<string name="update_available_description">有更新可供安裝:%1$s\n\n您要進行更新嗎?</string>
|
||||
<string name="downloading_update">下載更新中</string>
|
||||
<string name="update_download_failed">更新下載失敗</string>
|
||||
@@ -561,6 +561,8 @@
|
||||
<string name="renderer_reactive_flushing_description">犧牲效能,以改善部分遊戲的轉譯準確度</string>
|
||||
<string name="enable_buffer_history">啟用緩衝區歷史</string>
|
||||
<string name="enable_buffer_history_description">允許存取先前的緩衝區狀態。此選項可能會改善部分遊戲的渲染品質與效能穩定性</string>
|
||||
<string name="enable_gpu_buffer_readback">啟用 GPU 緩衝區讀回</string>
|
||||
<string name="enable_gpu_buffer_readback_description">透過在上傳之前先將 GPU 修改過的緩衝區資料讀回來保存資料,部分遊戲需要啟用此功能才能正常渲染遊戲特效。如果硬體無法負荷可能會導致錯誤</string>
|
||||
<string name="use_optimized_vertex_buffers">最佳化頂點緩衝區</string>
|
||||
<string name="use_optimized_vertex_buffers_description">啟用最佳化的頂點緩衝區綁定。需要安裝 Mesa 26.0+ Turnip drivers/Qualcomm drivers。使用舊版 Turnip drivers 會導致當機 (25.3版和更低的版本)</string>
|
||||
|
||||
@@ -1018,40 +1020,9 @@
|
||||
<string name="memory_6gb">6GB (不穩定)</string>
|
||||
<string name="memory_8gb">8GB (不穩定)</string>
|
||||
|
||||
<!-- CPU clock levels -->
|
||||
<string name="clock_normal">正常</string>
|
||||
<string name="clock_boost">加速</string>
|
||||
<string name="clock_fast">超頻</string>
|
||||
|
||||
<!-- GPU clock levels -->
|
||||
<string name="fast_gpu_normal">正常</string>
|
||||
<string name="fast_gpu_medium">加速</string>
|
||||
<string name="fast_gpu_high">超頻</string>
|
||||
|
||||
<!-- GPU swizzle texture size -->
|
||||
<string name="gpu_texturesizeswizzle_verysmall">極小 (16MB)</string>
|
||||
<string name="gpu_texturesizeswizzle_small">小(32MB)</string>
|
||||
<string name="gpu_texturesizeswizzle_normal">正常(128MB)</string>
|
||||
<string name="gpu_texturesizeswizzle_large">大(256MB)</string>
|
||||
<string name="gpu_texturesizeswizzle_verylarge">極大(512MB)</string>
|
||||
|
||||
<!-- GPU swizzle streams -->
|
||||
<string name="gpu_swizzle_verylow">極小(4MB)</string>
|
||||
<string name="gpu_swizzle_low">小(8MB)</string>
|
||||
<string name="gpu_swizzle_normal">正常(16MB)</string>
|
||||
<string name="gpu_swizzle_medium">中(32MB)</string>
|
||||
<string name="gpu_swizzle_high">大(64MB)</string>
|
||||
|
||||
<!-- GPU swizzle chunks -->
|
||||
<string name="gpu_swizzlechunk_verylow">極小(32)</string>
|
||||
<string name="gpu_swizzlechunk_low">小(64)</string>
|
||||
<string name="gpu_swizzlechunk_normal">正常(128)</string>
|
||||
<string name="gpu_swizzlechunk_medium">中(256)</string>
|
||||
<string name="gpu_swizzlechunk_high">大(512)</string>
|
||||
|
||||
<!-- Temperature Units -->
|
||||
<string name="temperature_celsius">攝氏</string>
|
||||
<string name="temperature_fahrenheit">華氏</string>
|
||||
<string name="temperature_celsius">攝氏度</string>
|
||||
<string name="temperature_fahrenheit">華氏度</string>
|
||||
|
||||
<!-- Memory Sizes -->
|
||||
<string name="memory_byte_shorthand">B</string>
|
||||
@@ -1064,8 +1035,6 @@
|
||||
|
||||
<string name="renderer_none">無</string>
|
||||
|
||||
<!-- Renderer Accuracy -->
|
||||
<string name="renderer_accuracy_low">效能</string>
|
||||
<string name="renderer_accuracy_high">準確</string>
|
||||
|
||||
<!-- DMA Accuracy -->
|
||||
|
||||
@@ -558,6 +558,7 @@
|
||||
<item>@string/gpu_fence_behavior_immediate</item>
|
||||
<item>@string/gpu_fence_behavior_balanced</item>
|
||||
<item>@string/gpu_fence_behavior_accurate</item>
|
||||
<item>@string/gpu_fence_behavior_strict</item>
|
||||
</string-array>
|
||||
<integer-array name="gpuFenceBehaviorValues">
|
||||
<item>0</item>
|
||||
|
||||
@@ -586,6 +586,8 @@
|
||||
<string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string>
|
||||
<string name="enable_buffer_history">Enable buffer history</string>
|
||||
<string name="enable_buffer_history_description">Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games.</string>
|
||||
<string name="enable_gpu_buffer_readback">Enable GPU Buffer Readback</string>
|
||||
<string name="enable_gpu_buffer_readback_description">Preserves GPU-modified buffer data by reading it back before uploads. Some games require this to render certain effects properly. May cause issues if the hardware cannot handle the additional workload.</string>
|
||||
<string name="use_optimized_vertex_buffers">Optimized Vertex Buffers</string>
|
||||
<string name="use_optimized_vertex_buffers_description">Enables optimized vertex buffer binding for improved performance. Requires Mesa 26.0+ Turnip drivers/ QCOM drivers. Will crash on older Turnip drivers (25.3 and below).</string>
|
||||
|
||||
@@ -1136,6 +1138,7 @@
|
||||
<string name="gpu_fence_behavior_immediate">Immediate</string>
|
||||
<string name="gpu_fence_behavior_balanced">Balanced</string>
|
||||
<string name="gpu_fence_behavior_accurate">Accurate</string>
|
||||
<string name="gpu_fence_behavior_strict">Strict</string>
|
||||
|
||||
<!-- ASTC Decoding Method Choices -->
|
||||
<string name="accelerate_astc_cpu" translatable="false">CPU</string>
|
||||
|
||||
@@ -76,6 +76,7 @@ add_library(
|
||||
logging.h
|
||||
lz4_compression.cpp
|
||||
lz4_compression.h
|
||||
make_unique_for_overwrite.h
|
||||
math_util.h
|
||||
memory_detect.cpp
|
||||
memory_detect.h
|
||||
@@ -106,6 +107,7 @@ add_library(
|
||||
settings_input.h
|
||||
settings_setting.h
|
||||
slot_vector.h
|
||||
socket_types.h
|
||||
sparse_large_vector.cpp
|
||||
sparse_large_vector.h
|
||||
stb.cpp
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "web_service/web_result.h"
|
||||
|
||||
namespace AnnounceMultiplayerRoom {
|
||||
|
||||
@@ -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
|
||||
|
||||
#include "device_power_state.h"
|
||||
@@ -14,11 +14,14 @@ extern std::atomic<bool> g_has_battery;
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#if TARGET_OS_MAC
|
||||
#if defined(TARGET_OS_MAC) && TARGET_OS_MAC
|
||||
#if TARGET_OS_IPHONE
|
||||
// ios doesnt have this
|
||||
#else
|
||||
#include <IOKit/ps/IOPSKeys.h>
|
||||
#include <IOKit/ps/IOPowerSources.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#elif defined(__linux__)
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
@@ -48,7 +51,9 @@ namespace Common {
|
||||
info.percentage = g_battery_percentage.load(std::memory_order_relaxed);
|
||||
info.charging = g_is_charging.load(std::memory_order_relaxed);
|
||||
info.has_battery = g_has_battery.load(std::memory_order_relaxed);
|
||||
|
||||
#elif defined(__APPLE__) && TARGET_OS_IPHONE
|
||||
// Not implemented
|
||||
info.has_battery = false;
|
||||
#elif defined(__APPLE__) && TARGET_OS_MAC
|
||||
CFTypeRef info_ref = IOPSCopyPowerSourcesInfo();
|
||||
CFArrayRef sources = IOPSCopyPowerSourcesList(info_ref);
|
||||
@@ -96,7 +101,6 @@ namespace Common {
|
||||
#else
|
||||
info.has_battery = false;
|
||||
#endif
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
+20
-18
@@ -17,33 +17,35 @@
|
||||
|
||||
namespace Common {
|
||||
|
||||
// glibc, mlibc, musl, and newlib all define their own variants of strerror_r
|
||||
// We don't need to use the preprocessor, we can just select depending on return type
|
||||
template<typename T> std::string HandleStrerrorR(T r, char *err_str);
|
||||
template<> std::string HandleStrerrorR(char* r, char *) { return std::string{r}; }
|
||||
template<> std::string HandleStrerrorR(const char* r, char *) { return std::string{r}; }
|
||||
template<> std::string HandleStrerrorR(int r, char *err_str) {
|
||||
return std::string{r != 0
|
||||
? "(strerror_r failed to format error)"
|
||||
: err_str};
|
||||
}
|
||||
|
||||
std::string NativeErrorToString(int e) {
|
||||
#ifdef _WIN32
|
||||
LPSTR err_str;
|
||||
|
||||
DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
LPSTR(&err_str), 1, nullptr);
|
||||
if (res) {
|
||||
std::string ret(err_str);
|
||||
LocalFree(err_str);
|
||||
return ret;
|
||||
reinterpret_cast<LPSTR>(&err_str), 1, nullptr);
|
||||
if (!res) {
|
||||
return "(FormatMessageA failed to format error)";
|
||||
}
|
||||
return "(FormatMessageA failed to format error)";
|
||||
std::string ret(err_str);
|
||||
LocalFree(err_str);
|
||||
return ret;
|
||||
#else
|
||||
char err_str[255];
|
||||
return HandleStrerrorR(strerror_r(e, err_str, sizeof(err_str)), err_str);
|
||||
#if defined(__ANDROID__) || \
|
||||
(defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600)))
|
||||
// Thread safe (GNU-specific)
|
||||
const char* str = strerror_r(e, err_str, sizeof(err_str));
|
||||
return std::string(str);
|
||||
#else
|
||||
// Thread safe (XSI-compliant)
|
||||
int second_err = strerror_r(e, err_str, sizeof(err_str));
|
||||
if (second_err != 0) {
|
||||
return "(strerror_r failed to format error)";
|
||||
}
|
||||
return std::string(err_str);
|
||||
#endif // GLIBC etc.
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,11 @@
|
||||
#include <sys/random.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include <sys/types.h>
|
||||
#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
|
||||
// Not available on iOS for some fucking stupid reason...
|
||||
#else
|
||||
#include <sys/random.h>
|
||||
#endif
|
||||
#include <mach/vm_map.h>
|
||||
#include <mach/mach.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Common {
|
||||
|
||||
template <class T>
|
||||
requires(!std::is_array_v<T>)
|
||||
std::unique_ptr<T> make_unique_for_overwrite() {
|
||||
return std::unique_ptr<T>(new T);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
requires std::is_unbounded_array_v<T>
|
||||
std::unique_ptr<T> make_unique_for_overwrite(std::size_t n) {
|
||||
return std::unique_ptr<T>(new std::remove_extent_t<T>[n]);
|
||||
}
|
||||
|
||||
template <class T, class... Args>
|
||||
requires std::is_bounded_array_v<T>
|
||||
void make_unique_for_overwrite(Args&&...) = delete;
|
||||
|
||||
} // namespace Common
|
||||
@@ -8,7 +8,8 @@
|
||||
|
||||
#include <iterator>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include "common/make_unique_for_overwrite.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
@@ -37,9 +38,8 @@ public:
|
||||
ScratchBuffer() = default;
|
||||
|
||||
explicit ScratchBuffer(size_type initial_capacity)
|
||||
: last_requested_size{initial_capacity}
|
||||
, buffer_capacity{initial_capacity}
|
||||
, buffer{std::make_unique_for_overwrite<T[]>(initial_capacity)} {}
|
||||
: last_requested_size{initial_capacity}, buffer_capacity{initial_capacity},
|
||||
buffer{Common::make_unique_for_overwrite<T[]>(initial_capacity)} {}
|
||||
|
||||
~ScratchBuffer() = default;
|
||||
ScratchBuffer(const ScratchBuffer&) = delete;
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
/// The previously held data will remain intact.
|
||||
void resize(size_type size) {
|
||||
if (size > buffer_capacity) {
|
||||
auto new_buffer = std::make_unique_for_overwrite<T[]>(size);
|
||||
auto new_buffer = Common::make_unique_for_overwrite<T[]>(size);
|
||||
std::memcpy(new_buffer.get(), buffer.get(), buffer_capacity * sizeof(T));
|
||||
buffer = std::move(new_buffer);
|
||||
buffer_capacity = size;
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
void resize_destructive(size_type size) {
|
||||
if (size > buffer_capacity) {
|
||||
buffer_capacity = size;
|
||||
buffer = std::make_unique_for_overwrite<T[]>(buffer_capacity);
|
||||
buffer = Common::make_unique_for_overwrite<T[]>(buffer_capacity);
|
||||
}
|
||||
last_requested_size = size;
|
||||
}
|
||||
|
||||
@@ -178,6 +178,10 @@ bool IsGPUFenceBehaviorAccurate() {
|
||||
return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Accurate;
|
||||
}
|
||||
|
||||
bool IsGPUFenceBehaviorStrict() {
|
||||
return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Strict;
|
||||
}
|
||||
|
||||
bool IsFastmemEnabled() {
|
||||
if (values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Debugging)
|
||||
return bool(values.cpuopt_fastmem);
|
||||
|
||||
@@ -525,7 +525,7 @@ struct Values {
|
||||
SwitchableSetting<GpuFenceBehavior, true> gpu_fence_behavior{linkage,
|
||||
GpuFenceBehavior::Default,
|
||||
GpuFenceBehavior::Default,
|
||||
GpuFenceBehavior::Accurate,
|
||||
GpuFenceBehavior::Strict,
|
||||
"gpu_fence_behavior",
|
||||
Category::RendererAdvanced,
|
||||
Specialization::Default,
|
||||
@@ -655,6 +655,13 @@ struct Values {
|
||||
|
||||
SwitchableSetting<bool> rescale_hack{linkage, false, "rescale_hack",
|
||||
Category::RendererHacks};
|
||||
SwitchableSetting<bool> enable_gpu_buffer_readback{linkage,
|
||||
false,
|
||||
"enable_gpu_buffer_readback",
|
||||
Category::RendererAdvanced,
|
||||
Specialization::Default,
|
||||
true,
|
||||
true};
|
||||
|
||||
SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
|
||||
Category::RendererHacks};
|
||||
@@ -972,6 +979,7 @@ bool IsDMALevelSafe();
|
||||
bool IsGPUFenceBehaviorDefault();
|
||||
bool IsGPUFenceBehaviorBalanced();
|
||||
bool IsGPUFenceBehaviorAccurate();
|
||||
bool IsGPUFenceBehaviorStrict();
|
||||
|
||||
bool IsFastmemEnabled();
|
||||
void SetNceEnabled(bool is_64bit);
|
||||
|
||||
@@ -137,7 +137,7 @@ ENUM(VramUsageMode, Conservative, Aggressive);
|
||||
ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV);
|
||||
ENUM(GpuAccuracy, Low, High);
|
||||
ENUM(DmaAccuracy, Default, Unsafe, Safe);
|
||||
ENUM(GpuFenceBehavior, Default, Immediate, Balanced, Accurate);
|
||||
ENUM(GpuFenceBehavior, Default, Immediate, Balanced, Accurate, Strict);
|
||||
ENUM(CpuBackend, Dynarmic, Nce);
|
||||
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid, Debugging);
|
||||
ENUM(CpuClock, Normal, Boost, Overclock)
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Network {
|
||||
|
||||
/// Address families
|
||||
enum class Domain : u8 {
|
||||
Unspecified, ///< Represents 0, used in getaddrinfo hints
|
||||
INET, ///< Address family for IPv4
|
||||
};
|
||||
|
||||
/// Socket types
|
||||
enum class Type {
|
||||
Unspecified, ///< Represents 0, used in getaddrinfo hints
|
||||
STREAM,
|
||||
DGRAM,
|
||||
RAW,
|
||||
SEQPACKET,
|
||||
};
|
||||
|
||||
/// Protocol values for sockets
|
||||
enum class Protocol : u8 {
|
||||
Unspecified, ///< Represents 0, usable in various places
|
||||
IP,
|
||||
ICMP,
|
||||
TCP,
|
||||
UDP,
|
||||
IPV6,
|
||||
RAW,
|
||||
IGMP,
|
||||
GGP,
|
||||
IPV4,
|
||||
ST,
|
||||
EGP,
|
||||
PIGP,
|
||||
RCCMON,
|
||||
NVPII,
|
||||
PUP,
|
||||
ARGUS,
|
||||
EMCON,
|
||||
XNET,
|
||||
CHAOS,
|
||||
MUX,
|
||||
MEAS,
|
||||
HMP,
|
||||
PRM,
|
||||
IDP,
|
||||
TRUNK1,
|
||||
TRUNK2,
|
||||
LEAF1,
|
||||
LEAF2,
|
||||
RDP,
|
||||
IRTP,
|
||||
TP,
|
||||
BLT,
|
||||
NSP,
|
||||
INP,
|
||||
DCCP,
|
||||
//TODO: 3PC,
|
||||
IDPR,
|
||||
XTP,
|
||||
DDP,
|
||||
CMTP,
|
||||
TPXX,
|
||||
IL,
|
||||
SDRP,
|
||||
ROUTING,
|
||||
FRAGMENT,
|
||||
IDRP,
|
||||
RSVP,
|
||||
GRE,
|
||||
MHRP,
|
||||
BHA,
|
||||
ESP,
|
||||
AH,
|
||||
INLSP,
|
||||
SWIPE,
|
||||
NHRP,
|
||||
MOBILE,
|
||||
TLSP,
|
||||
SKIP,
|
||||
ICMPV6,
|
||||
NONE,
|
||||
DSTOPTS,
|
||||
AHIP,
|
||||
CFTP,
|
||||
HELLO,
|
||||
SATEXPAK,
|
||||
KRYPTOLAN,
|
||||
RVD,
|
||||
IPPC,
|
||||
ADFS,
|
||||
SATMON,
|
||||
VISA,
|
||||
IPCV,
|
||||
CPNX,
|
||||
CPHB,
|
||||
WSN,
|
||||
PVP,
|
||||
BRSATMON,
|
||||
ND,
|
||||
WBMON,
|
||||
WBEXPAK,
|
||||
EON,
|
||||
VMTP,
|
||||
SVMTP,
|
||||
VINES,
|
||||
TTP,
|
||||
IGP,
|
||||
DGP,
|
||||
TCF,
|
||||
IGRP,
|
||||
OSPFIGP,
|
||||
SRPC,
|
||||
LARP,
|
||||
MTP,
|
||||
AX25,
|
||||
IPEIP,
|
||||
MICP,
|
||||
SCCSP,
|
||||
ETHERIP,
|
||||
ENCAP,
|
||||
APES,
|
||||
GMTP,
|
||||
IPCOMP,
|
||||
SCTP,
|
||||
MH,
|
||||
UDPLITE,
|
||||
HIP,
|
||||
SHIM6,
|
||||
PIM,
|
||||
CARP,
|
||||
PGM,
|
||||
MPLS,
|
||||
PFSYNC
|
||||
};
|
||||
|
||||
/// Shutdown mode
|
||||
enum class ShutdownHow {
|
||||
RD,
|
||||
WR,
|
||||
RDWR,
|
||||
};
|
||||
|
||||
/// Array of IPv4 address
|
||||
using IPv4Address = std::array<u8, 4>;
|
||||
|
||||
/// Cross-platform sockaddr structure
|
||||
struct SockAddrIn {
|
||||
Domain family;
|
||||
IPv4Address ip;
|
||||
u16 portno;
|
||||
};
|
||||
|
||||
constexpr u32 FLAG_MSG_PEEK = 0x2;
|
||||
constexpr u32 FLAG_MSG_DONTWAIT = 0x80;
|
||||
constexpr u32 FLAG_O_NONBLOCK = 0x800;
|
||||
|
||||
/// Cross-platform addrinfo structure
|
||||
struct AddrInfo {
|
||||
Domain family;
|
||||
Type socket_type;
|
||||
Protocol protocol;
|
||||
SockAddrIn addr;
|
||||
std::optional<std::string> canon_name;
|
||||
};
|
||||
|
||||
} // namespace Network
|
||||
@@ -6,7 +6,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <algorithm>
|
||||
#include <windows.h>
|
||||
#include <mutex>
|
||||
#else
|
||||
@@ -21,36 +20,32 @@ namespace Common {
|
||||
|
||||
#ifdef _WIN32
|
||||
static std::vector<std::pair<u64, u64>> vector_regions {};
|
||||
static std::mutex vector_regions_mutex {};
|
||||
|
||||
// Workaround for handling non-commited memory accessed by Dynarmic; usually result of an error
|
||||
static LONG WINAPI FakePageFaultHandler(PEXCEPTION_POINTERS info) {
|
||||
DWORD code = info->ExceptionRecord->ExceptionCode;
|
||||
u64 exception_addr = reinterpret_cast<u64>(info->ExceptionRecord->ExceptionInformation[1]);
|
||||
u64 exception_addr = reinterpret_cast<u64>(info->ExceptionRecord->ExceptionAddress);
|
||||
|
||||
if (code != EXCEPTION_ACCESS_VIOLATION || info->ExceptionRecord->ExceptionInformation[0] == 1) {
|
||||
if (code != EXCEPTION_ACCESS_VIOLATION) {
|
||||
// Not our problem
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
u64 addr = 0, addr2 = 0;
|
||||
|
||||
{
|
||||
std::lock_guard lock(vector_regions_mutex);
|
||||
for (auto region: vector_regions) {
|
||||
auto addr_shifted = exception_addr >> HostPageBits;
|
||||
if (region.first <= addr_shifted && addr_shifted <= region.second) {
|
||||
addr = addr_shifted;
|
||||
}
|
||||
for (auto region: vector_regions) {
|
||||
auto addr_shifted = exception_addr >> HostPageBits;
|
||||
if (region.first <= addr_shifted && addr_shifted <= region.second) {
|
||||
addr = addr_shifted;
|
||||
}
|
||||
|
||||
// Page-boundary accesses
|
||||
if (auto addr_ = (exception_addr + 0x40) >> HostPageBits; addr_ != addr_shifted && region.first <= addr_ && addr_ <= region.second) {
|
||||
addr2 = addr_;
|
||||
}
|
||||
// Page-boundary accesses
|
||||
if (auto addr_ = (exception_addr + 0x40) >> HostPageBits; addr_ != addr_shifted && region.first <= addr_ && addr_ <= region.second) {
|
||||
addr2 = addr_;
|
||||
}
|
||||
|
||||
if (addr != 0 || addr2 != 0) {
|
||||
break;
|
||||
}
|
||||
if (addr != 0 || addr2 != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,16 +77,8 @@ bool CommitVectorPage(uintptr_t addr, bool write) noexcept {
|
||||
auto res = VirtualQuery(reinterpret_cast<void*>(addr), &info, sizeof(info));
|
||||
if (res == 0) {
|
||||
LOG_CRITICAL(HW_Memory, "Failed to query large buffer region at {:#x} with error {}, will try committing anyway", addr, GetLastError());
|
||||
} else if (info.State == MEM_COMMIT) {
|
||||
DWORD old_protect {};
|
||||
auto perm = write ? PAGE_READWRITE : PAGE_READONLY;
|
||||
if (!VirtualProtect(reinterpret_cast<void*>(addr), HostPageSize, perm, &old_protect)) {
|
||||
LOG_ERROR(HW_Memory, "Failed to change permissions of large buffer region at {:#x}, error {}", addr, GetLastError());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if (info.State != MEM_RESERVE) {
|
||||
LOG_ERROR(HW_Memory, "Tried to commit an unreserved large buffer region at {:#x} that is not mapped (state {:#x})", addr, info.State);
|
||||
LOG_ERROR(HW_Memory, "Tried to commit an unreserved large buffer region at {:#x} that is not mapped or is already committed (state {:#x})", addr, info.State);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -109,21 +96,6 @@ bool CommitVectorPage(uintptr_t addr, bool write) noexcept {
|
||||
#ifndef MAP_NOCORE
|
||||
#define MAP_NOCORE 0
|
||||
#endif
|
||||
#ifndef MADV_FREE
|
||||
#define MADV_FREE MADV_DONTNEED
|
||||
#endif
|
||||
|
||||
void DecommitVectorPage(uintptr_t base) noexcept {
|
||||
#if defined(_WIN32)
|
||||
VirtualFree(reinterpret_cast<LPVOID>(base), HostPageSize, MEM_DECOMMIT);
|
||||
#elif defined(__linux__)
|
||||
// Linux's MADV_DONTNEED zeros out pages for us
|
||||
madvise(reinterpret_cast<void*>(base), HostPageSize, MADV_DONTNEED);
|
||||
#else
|
||||
madvise(reinterpret_cast<void*>(base), HostPageSize, MADV_FREE);
|
||||
std::memset(reinterpret_cast<void*>(base), 0, HostPageSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
void* AllocateMemoryPages(std::size_t size) noexcept {
|
||||
if (auto page = HostPageSize; size % page != 0) {
|
||||
@@ -136,8 +108,7 @@ void* AllocateMemoryPages(std::size_t size) noexcept {
|
||||
void* base = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE);
|
||||
|
||||
if (base != nullptr) {
|
||||
std::lock_guard lock(vector_regions_mutex);
|
||||
vector_regions.emplace_back(reinterpret_cast<u64>(base) >> HostPageBits, (reinterpret_cast<u64>(base) + size) >> HostPageBits);
|
||||
vector_regions.emplace_back(reinterpret_cast<u64>(base), reinterpret_cast<u64>(base) + size);
|
||||
|
||||
static std::once_flag flag;
|
||||
std::call_once(flag, []() { AddVectoredExceptionHandler(1, FakePageFaultHandler); });
|
||||
@@ -163,8 +134,6 @@ void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) noexcept {
|
||||
if (!base)
|
||||
return;
|
||||
#ifdef _WIN32
|
||||
std::lock_guard lock(vector_regions_mutex);
|
||||
std::erase_if(vector_regions, [base](const auto& r) {return r.first == reinterpret_cast<u64>(base); });
|
||||
ASSERT(VirtualFree(base, 0, MEM_RELEASE));
|
||||
#else
|
||||
ASSERT(munmap(base, size) == 0);
|
||||
|
||||
@@ -28,14 +28,13 @@ constexpr u64 HostPageBits = 12;
|
||||
constexpr u64 HostPageMask = ~(HostPageSize - 1);
|
||||
bool CommitVectorPage(uintptr_t addr, bool write) noexcept;
|
||||
#else
|
||||
inline const u64 HostPageSize = sysconf(_SC_PAGESIZE);
|
||||
inline const u64 HostPageBits = std::countr_zero(HostPageSize);
|
||||
inline const u64 HostPageMask = ~(HostPageSize - 1);
|
||||
const u64 HostPageSize = sysconf(_SC_PAGESIZE);
|
||||
const u64 HostPageBits = std::countr_zero(HostPageSize);
|
||||
const u64 HostPageMask = ~(HostPageSize - 1);
|
||||
#endif
|
||||
|
||||
void* AllocateMemoryPages(std::size_t size) noexcept;
|
||||
void FreeMemoryPages(void* base, std::size_t size) noexcept;
|
||||
void DecommitVectorPage(uintptr_t base) noexcept;
|
||||
|
||||
/// A large page-aligned buffer that has optimized memory usage for zero-writes.
|
||||
template <typename T>
|
||||
@@ -81,8 +80,8 @@ public:
|
||||
UNREACHABLE_MSG("Out of bounds RW access on SparseLargeVector @ {}", index);
|
||||
}
|
||||
|
||||
if (!IsCommittedPage(index) && !CommitPage(index)) {
|
||||
UNREACHABLE_MSG("Cannot access SparseLargeVector index {} with RW permission", index);
|
||||
if (!IsCommittedPage(index)) {
|
||||
CommitPage(index);
|
||||
}
|
||||
return base_ptr[index];
|
||||
}
|
||||
@@ -103,8 +102,9 @@ public:
|
||||
LOG_CRITICAL(Common_Memory, "Out of bounds write on SparseLargeVector @ {}", index);
|
||||
return;
|
||||
}
|
||||
if (IsCommittedPage(index) || CommitPage(index))
|
||||
base_ptr[index] = value;
|
||||
if (!IsCommittedPage(index))
|
||||
CommitPage(index);
|
||||
base_ptr[index] = value;
|
||||
}
|
||||
|
||||
void ZeroRegion(std::size_t start, std::size_t end_) noexcept {
|
||||
@@ -114,7 +114,7 @@ public:
|
||||
const u64 end_page = AlignUp(base, HostPageSize);
|
||||
const u64 first_size = (std::min)(end_page, end) - base;
|
||||
|
||||
if (IsCommittedPage(start)) {
|
||||
if (IsCommittedPage(start / sizeof(T))) {
|
||||
std::memset(reinterpret_cast<void*>(base), 0, first_size);
|
||||
}
|
||||
|
||||
@@ -124,16 +124,11 @@ public:
|
||||
base = end_page;
|
||||
|
||||
for (u64 page = base; page < end; page += HostPageSize) {
|
||||
auto index = (page - reinterpret_cast<u64>(base_ptr)) / sizeof(T);
|
||||
if (!IsCommittedPage(index)) {
|
||||
if (!IsCommittedPage((page - reinterpret_cast<u64>(base_ptr)) / sizeof(T))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (end - page >= HostPageSize) {
|
||||
DecommitPage(index);
|
||||
} else {
|
||||
std::memset(reinterpret_cast<void*>(page), 0, end - page);
|
||||
}
|
||||
std::memset(reinterpret_cast<void*>(page), 0, (std::min)( HostPageSize, end - page));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,30 +171,16 @@ private:
|
||||
return (val >> (page & 63)) & 1;
|
||||
}
|
||||
|
||||
constexpr bool CommitPage(std::size_t index) noexcept {
|
||||
constexpr void CommitPage(std::size_t index) noexcept {
|
||||
auto page_index = (index * sizeof(T)) >> HostPageBits;
|
||||
auto page = reinterpret_cast<uintptr_t>(base_ptr + index) & HostPageMask;
|
||||
#if defined(_WIN32)
|
||||
if (!CommitVectorPage(page, true)) {
|
||||
return false;
|
||||
}
|
||||
CommitVectorPage(page, true);
|
||||
#else
|
||||
if (mprotect(reinterpret_cast<void*>(page), HostPageSize, PROT_READ | PROT_WRITE) != 0) {
|
||||
LOG_ERROR(Common_Memory, "Failed to commit large buffer region at index {}, error {}", index, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
mprotect(reinterpret_cast<void*>(page), HostPageSize, PROT_READ | PROT_WRITE);
|
||||
#endif
|
||||
|
||||
committed_pages[page_index >> 6].fetch_or(1ULL << (page_index & 63), std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr void DecommitPage(std::size_t index) noexcept {
|
||||
auto page_index = (index * sizeof(T)) >> HostPageBits;
|
||||
auto page = reinterpret_cast<uintptr_t>(base_ptr + index) & HostPageMask;
|
||||
|
||||
committed_pages[page_index >> 6].fetch_and(~(1ULL << (page_index & 63)), std::memory_order_release);
|
||||
DecommitVectorPage(page);
|
||||
}
|
||||
|
||||
std::size_t alloc_size{};
|
||||
|
||||
+107
-6
@@ -116,18 +116,119 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
|
||||
}
|
||||
|
||||
std::string UTF16ToUTF8(std::u16string_view input) {
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
|
||||
return convert.to_bytes(input.data(), input.data() + input.size());
|
||||
std::string result;
|
||||
result.reserve(input.size());
|
||||
for (size_t i = 0; i < input.size(); ++i) {
|
||||
uint32_t codepoint = input[i];
|
||||
// Handle surrogate pairs
|
||||
if (codepoint >= 0xD800 && codepoint <= 0xDBFF) {
|
||||
if (i + 1 < input.size()) {
|
||||
uint32_t low = input[i + 1];
|
||||
if (low >= 0xDC00 && low <= 0xDFFF) {
|
||||
codepoint = ((codepoint - 0xD800) << 10) + (low - 0xDC00) + 0x10000;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (codepoint <= 0x7F) {
|
||||
result.push_back(static_cast<char>(codepoint));
|
||||
} else if (codepoint <= 0x7FF) {
|
||||
result.push_back(static_cast<char>(0xC0 | (codepoint >> 6)));
|
||||
result.push_back(static_cast<char>(0x80 | (codepoint & 0x3F)));
|
||||
} else if (codepoint <= 0xFFFF) {
|
||||
result.push_back(static_cast<char>(0xE0 | (codepoint >> 12)));
|
||||
result.push_back(static_cast<char>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
result.push_back(static_cast<char>(0x80 | (codepoint & 0x3F)));
|
||||
} else {
|
||||
result.push_back(static_cast<char>(0xF0 | (codepoint >> 18)));
|
||||
result.push_back(static_cast<char>(0x80 | ((codepoint >> 12) & 0x3F)));
|
||||
result.push_back(static_cast<char>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
result.push_back(static_cast<char>(0x80 | (codepoint & 0x3F)));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::u16string UTF8ToUTF16(std::string_view input) {
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
|
||||
return convert.from_bytes(input.data(), input.data() + input.size());
|
||||
std::u16string result;
|
||||
size_t i = 0;
|
||||
while (i < input.size()) {
|
||||
uint32_t codepoint = 0;
|
||||
unsigned char c = input[i];
|
||||
size_t extra = 0;
|
||||
if ((c & 0x80) == 0) {
|
||||
codepoint = c;
|
||||
extra = 0;
|
||||
} else if ((c & 0xE0) == 0xC0) {
|
||||
codepoint = c & 0x1F;
|
||||
extra = 1;
|
||||
} else if ((c & 0xF0) == 0xE0) {
|
||||
codepoint = c & 0x0F;
|
||||
extra = 2;
|
||||
} else if ((c & 0xF8) == 0xF0) {
|
||||
codepoint = c & 0x07;
|
||||
extra = 3;
|
||||
} else {
|
||||
// Invalid UTF-8
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
if (i + extra >= input.size()) break;
|
||||
for (size_t j = 1; j <= extra; ++j) {
|
||||
if ((input[i + j] & 0xC0) != 0x80) {
|
||||
codepoint = 0xFFFD;
|
||||
break;
|
||||
}
|
||||
codepoint = (codepoint << 6) | (input[i + j] & 0x3F);
|
||||
}
|
||||
if (codepoint <= 0xFFFF) {
|
||||
result.push_back(static_cast<char16_t>(codepoint));
|
||||
} else {
|
||||
codepoint -= 0x10000;
|
||||
result.push_back(static_cast<char16_t>(0xD800 + (codepoint >> 10)));
|
||||
result.push_back(static_cast<char16_t>(0xDC00 + (codepoint & 0x3FF)));
|
||||
}
|
||||
i += extra + 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::u32string UTF8ToUTF32(std::string_view input) {
|
||||
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
|
||||
return convert.from_bytes(input.data(), input.data() + input.size());
|
||||
std::u32string result;
|
||||
size_t i = 0;
|
||||
while (i < input.size()) {
|
||||
uint32_t codepoint = 0;
|
||||
unsigned char c = input[i];
|
||||
size_t extra = 0;
|
||||
if ((c & 0x80) == 0) {
|
||||
codepoint = c;
|
||||
extra = 0;
|
||||
} else if ((c & 0xE0) == 0xC0) {
|
||||
codepoint = c & 0x1F;
|
||||
extra = 1;
|
||||
} else if ((c & 0xF0) == 0xE0) {
|
||||
codepoint = c & 0x0F;
|
||||
extra = 2;
|
||||
} else if ((c & 0xF8) == 0xF0) {
|
||||
codepoint = c & 0x07;
|
||||
extra = 3;
|
||||
} else {
|
||||
// Invalid UTF-8
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
if (i + extra >= input.size()) break;
|
||||
for (size_t j = 1; j <= extra; ++j) {
|
||||
if ((input[i + j] & 0xC0) != 0x80) {
|
||||
codepoint = 0xFFFD;
|
||||
break;
|
||||
}
|
||||
codepoint = (codepoint << 6) | (input[i + j] & 0x3F);
|
||||
}
|
||||
result.push_back(codepoint);
|
||||
i += extra + 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
+4
-12
@@ -23,8 +23,6 @@ add_library(core STATIC
|
||||
core_timing.h
|
||||
cpu_manager.cpp
|
||||
cpu_manager.h
|
||||
launch_params.cpp
|
||||
launch_params.h
|
||||
crypto/aes_util.cpp
|
||||
crypto/aes_util.h
|
||||
crypto/ctr_encryption_layer.cpp
|
||||
@@ -1127,7 +1125,6 @@ add_library(core STATIC
|
||||
internal_network/network_interface.h
|
||||
internal_network/socket_proxy.cpp
|
||||
internal_network/socket_proxy.h
|
||||
internal_network/socket_types.h
|
||||
internal_network/sockets.h
|
||||
internal_network/wifi_scanner.h
|
||||
launch_timestamp_cache.cpp
|
||||
@@ -1166,12 +1163,6 @@ add_library(core STATIC
|
||||
tools/renderdoc.cpp
|
||||
tools/renderdoc.h)
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
target_sources(core PRIVATE
|
||||
internal_network/socket_icmp.cpp
|
||||
internal_network/socket_icmp.h)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WIFI_SCAN)
|
||||
target_sources(core PRIVATE internal_network/wifi_scanner.cpp)
|
||||
if (LINUX)
|
||||
@@ -1212,9 +1203,6 @@ endif()
|
||||
|
||||
target_include_directories(core PRIVATE ${OPUS_INCLUDE_DIRS})
|
||||
target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb tz)
|
||||
if (MSVC)
|
||||
target_link_libraries(core PRIVATE getopt)
|
||||
endif()
|
||||
|
||||
if (BOOST_NO_HEADERS)
|
||||
target_link_libraries(core PUBLIC Boost::container Boost::heap Boost::asio Boost::process Boost::crc)
|
||||
@@ -1273,6 +1261,10 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITE
|
||||
hle/service/jit/jit.cpp
|
||||
hle/service/jit/jit.h)
|
||||
target_link_libraries(core PRIVATE dynarmic::dynarmic)
|
||||
# Quick hack for XCode generator...
|
||||
if (IOS)
|
||||
target_include_directories(core PRIVATE "${CMAKE_SOURCE_DIR}/dynarmic/src")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (TARGET OpenSSL::SSL)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <dynarmic/interface/halt_reason.h>
|
||||
#include "dynarmic/src/dynarmic/interface/halt_reason.h"
|
||||
|
||||
#include "core/arm/arm_interface.h"
|
||||
|
||||
|
||||
@@ -22,15 +22,21 @@ DynarmicCallbacks32::DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess
|
||||
, m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()}
|
||||
{}
|
||||
|
||||
u64 DynarmicCallbacks32::MemoryRead(u32 vaddr, size_t size) {
|
||||
CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Read);
|
||||
switch (size) {
|
||||
case sizeof(u64): return m_memory.Read64(vaddr);
|
||||
case sizeof(u32): return m_memory.Read32(vaddr);
|
||||
case sizeof(u16): return m_memory.Read16(vaddr);
|
||||
case sizeof(u8): return m_memory.Read8(vaddr);
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
u8 DynarmicCallbacks32::MemoryRead8(u32 vaddr) {
|
||||
CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
|
||||
return m_memory.Read8(vaddr);
|
||||
}
|
||||
u16 DynarmicCallbacks32::MemoryRead16(u32 vaddr) {
|
||||
CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read);
|
||||
return m_memory.Read16(vaddr);
|
||||
}
|
||||
u32 DynarmicCallbacks32::MemoryRead32(u32 vaddr) {
|
||||
CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read);
|
||||
return m_memory.Read32(vaddr);
|
||||
}
|
||||
u64 DynarmicCallbacks32::MemoryRead64(u32 vaddr) {
|
||||
CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
|
||||
return m_memory.Read64(vaddr);
|
||||
}
|
||||
|
||||
std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
|
||||
@@ -44,17 +50,27 @@ std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
|
||||
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
|
||||
}
|
||||
|
||||
void DynarmicCallbacks32::MemoryWrite(Dynarmic::A32::VAddr vaddr, u64 value, size_t size) {
|
||||
if (CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Write)) {
|
||||
switch (size) {
|
||||
case sizeof(u64): return m_memory.Write64(vaddr, value);
|
||||
case sizeof(u32): return m_memory.Write32(vaddr, u32(value));
|
||||
case sizeof(u16): return m_memory.Write16(vaddr, u16(value));
|
||||
case sizeof(u8): return m_memory.Write8(vaddr, u8(value));
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
void DynarmicCallbacks32::MemoryWrite8(u32 vaddr, u8 value) {
|
||||
if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
|
||||
m_memory.Write8(vaddr, value);
|
||||
}
|
||||
}
|
||||
void DynarmicCallbacks32::MemoryWrite16(u32 vaddr, u16 value) {
|
||||
if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) {
|
||||
m_memory.Write16(vaddr, value);
|
||||
}
|
||||
}
|
||||
void DynarmicCallbacks32::MemoryWrite32(u32 vaddr, u32 value) {
|
||||
if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) {
|
||||
m_memory.Write32(vaddr, value);
|
||||
}
|
||||
}
|
||||
void DynarmicCallbacks32::MemoryWrite64(u32 vaddr, u64 value) {
|
||||
if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) {
|
||||
m_memory.Write64(vaddr, value);
|
||||
}
|
||||
}
|
||||
|
||||
bool DynarmicCallbacks32::MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) {
|
||||
return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) &&
|
||||
m_memory.WriteExclusive8(vaddr, value, expected);
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <dynarmic/interface/A32/a32.h>
|
||||
#include <dynarmic/interface/code_page.h>
|
||||
#include "dynarmic/src/dynarmic/interface/A32/a32.h"
|
||||
#include "dynarmic/src/dynarmic/interface/code_page.h"
|
||||
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
||||
@@ -30,12 +30,18 @@ class System;
|
||||
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
|
||||
public:
|
||||
explicit DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess* process);
|
||||
u64 MemoryRead(u32 vaddr, size_t size) override;
|
||||
u8 MemoryRead8(u32 vaddr) override;
|
||||
u16 MemoryRead16(u32 vaddr) override;
|
||||
u32 MemoryRead32(u32 vaddr) override;
|
||||
u64 MemoryRead64(u32 vaddr) override;
|
||||
std::optional<u32> MemoryReadCode(u32 vaddr) override;
|
||||
void InstructionSynchronizationBarrierRaised() override {
|
||||
last_code_addr = u64(-1); //reset back, force refetch
|
||||
}
|
||||
void MemoryWrite(Dynarmic::A32::VAddr vaddr, u64 value, size_t size) override;
|
||||
void MemoryWrite8(u32 vaddr, u8 value) override;
|
||||
void MemoryWrite16(u32 vaddr, u16 value) override;
|
||||
void MemoryWrite32(u32 vaddr, u32 value) override;
|
||||
void MemoryWrite64(u32 vaddr, u64 value) override;
|
||||
bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override;
|
||||
bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override;
|
||||
bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override;
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "dynarmic/interface/A64/config.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
@@ -22,15 +21,21 @@ DynarmicCallbacks64::DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess
|
||||
, m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()}
|
||||
{}
|
||||
|
||||
u64 DynarmicCallbacks64::MemoryRead(u64 vaddr, size_t size) {
|
||||
CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Read);
|
||||
switch (size) {
|
||||
case sizeof(u64): return m_memory.Read64(vaddr);
|
||||
case sizeof(u32): return m_memory.Read32(vaddr);
|
||||
case sizeof(u16): return m_memory.Read16(vaddr);
|
||||
case sizeof(u8): return m_memory.Read8(vaddr);
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
u8 DynarmicCallbacks64::MemoryRead8(u64 vaddr) {
|
||||
CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
|
||||
return m_memory.Read8(vaddr);
|
||||
}
|
||||
u16 DynarmicCallbacks64::MemoryRead16(u64 vaddr) {
|
||||
CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read);
|
||||
return m_memory.Read16(vaddr);
|
||||
}
|
||||
u32 DynarmicCallbacks64::MemoryRead32(u64 vaddr) {
|
||||
CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read);
|
||||
return m_memory.Read32(vaddr);
|
||||
}
|
||||
u64 DynarmicCallbacks64::MemoryRead64(u64 vaddr) {
|
||||
CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
|
||||
return m_memory.Read64(vaddr);
|
||||
}
|
||||
Dynarmic::A64::Vector DynarmicCallbacks64::MemoryRead128(u64 vaddr) {
|
||||
CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);
|
||||
@@ -48,15 +53,24 @@ std::optional<u32> DynarmicCallbacks64::MemoryReadCode(u64 vaddr) {
|
||||
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
|
||||
}
|
||||
|
||||
void DynarmicCallbacks64::MemoryWrite(Dynarmic::A64::VAddr vaddr, u64 value, std::size_t size) {
|
||||
if (CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Write)) {
|
||||
switch (size) {
|
||||
case sizeof(u64): return m_memory.Write64(vaddr, u64(value));
|
||||
case sizeof(u32): return m_memory.Write32(vaddr, u32(value));
|
||||
case sizeof(u16): return m_memory.Write16(vaddr, u16(value));
|
||||
case sizeof(u8): return m_memory.Write8(vaddr, u8(value));
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
void DynarmicCallbacks64::MemoryWrite8(u64 vaddr, u8 value) {
|
||||
if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
|
||||
m_memory.Write8(vaddr, value);
|
||||
}
|
||||
}
|
||||
void DynarmicCallbacks64::MemoryWrite16(u64 vaddr, u16 value) {
|
||||
if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) {
|
||||
m_memory.Write16(vaddr, value);
|
||||
}
|
||||
}
|
||||
void DynarmicCallbacks64::MemoryWrite32(u64 vaddr, u32 value) {
|
||||
if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) {
|
||||
m_memory.Write32(vaddr, value);
|
||||
}
|
||||
}
|
||||
void DynarmicCallbacks64::MemoryWrite64(u64 vaddr, u64 value) {
|
||||
if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) {
|
||||
m_memory.Write64(vaddr, value);
|
||||
}
|
||||
}
|
||||
void DynarmicCallbacks64::MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) {
|
||||
|
||||
@@ -10,13 +10,12 @@
|
||||
#include <memory>
|
||||
#include "common/container/unordered_map.h"
|
||||
|
||||
#include <dynarmic/interface/A64/a64.h>
|
||||
#include <dynarmic/interface/code_page.h>
|
||||
#include "common/common_types.h"
|
||||
#include "common/hash.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
||||
#include "dynarmic/interface/A64/config.h"
|
||||
#include "../../../dynarmic/src/dynarmic/interface/A64/a64.h"
|
||||
#include "../../../dynarmic/src/dynarmic/interface/code_page.h"
|
||||
#include "../../../common/common_types.h"
|
||||
#include "../../../common/hash.h"
|
||||
#include "../arm_interface.h"
|
||||
#include "dynarmic_exclusive_monitor.h"
|
||||
|
||||
namespace Core::Memory {
|
||||
class Memory;
|
||||
@@ -37,13 +36,19 @@ class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
|
||||
public:
|
||||
explicit DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess* process);
|
||||
|
||||
u64 MemoryRead(u64 vaddr, size_t size) override;
|
||||
u8 MemoryRead8(u64 vaddr) override;
|
||||
u16 MemoryRead16(u64 vaddr) override;
|
||||
u32 MemoryRead32(u64 vaddr) override;
|
||||
u64 MemoryRead64(u64 vaddr) override;
|
||||
Dynarmic::A64::Vector MemoryRead128(u64 vaddr) override;
|
||||
std::optional<u32> MemoryReadCode(u64 vaddr) override;
|
||||
void InstructionSynchronizationBarrierRaised() override {
|
||||
last_code_addr = u64(-1); //reset back, force refetch
|
||||
}
|
||||
void MemoryWrite(Dynarmic::A64::VAddr vaddr, u64 value, std::size_t size) override;
|
||||
void MemoryWrite8(u64 vaddr, u8 value) override;
|
||||
void MemoryWrite16(u64 vaddr, u16 value) override;
|
||||
void MemoryWrite32(u64 vaddr, u32 value) override;
|
||||
void MemoryWrite64(u64 vaddr, u64 value) override;
|
||||
void MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) override;
|
||||
bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override;
|
||||
bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -5,7 +8,7 @@
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <dynarmic/interface/A32/coprocessor.h>
|
||||
#include "dynarmic/interface/A32/coprocessor.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <dynarmic/interface/exclusive_monitor.h>
|
||||
#include "dynarmic/src/dynarmic/interface/exclusive_monitor.h"
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
|
||||
@@ -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 merryhime <https://mary.rs>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
@@ -7,9 +10,9 @@
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wshadow"
|
||||
|
||||
#include <dynarmic/frontend/A64/a64_types.h>
|
||||
#include <dynarmic/frontend/A64/decoder/a64.h>
|
||||
#include <dynarmic/frontend/imm.h>
|
||||
#include "dynarmic/frontend/A64/a64_types.h"
|
||||
#include "dynarmic/frontend/A64/decoder/a64.h"
|
||||
#include "dynarmic/frontend/imm.h"
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
|
||||
@@ -35,20 +35,17 @@ static IPSFileType IdentifyMagic(std::span<const u8> magic) {
|
||||
}
|
||||
|
||||
static bool IsEOF(IPSFileType type, std::span<const u8> magic) {
|
||||
return (type == IPSFileType::IPS && magic.size() >= 3 && std::memcmp(magic.data(), "EOF", 3) == 0)
|
||||
|| (type == IPSFileType::IPS32 && magic.size() >= 4 && std::memcmp(magic.data(), "EEOF", 4) == 0);
|
||||
return (type == IPSFileType::IPS && magic.size() > 3 && std::memcmp(magic.data(), "EOF", 3) == 0)
|
||||
|| (type == IPSFileType::IPS32 && magic.size() > 4 && std::memcmp(magic.data(), "EEOF", 4) == 0);
|
||||
}
|
||||
|
||||
VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) {
|
||||
if (in == nullptr || ips == nullptr)
|
||||
return nullptr;
|
||||
|
||||
const auto type = IdentifyMagic(ips->ReadBytes(0x5));
|
||||
if (type == IPSFileType::Error)
|
||||
return nullptr;
|
||||
|
||||
auto in_data = in->ReadAllBytes();
|
||||
if (in_data.size() == 0)
|
||||
auto const type = IdentifyMagic(in_data);
|
||||
if (type == IPSFileType::Error)
|
||||
return nullptr;
|
||||
|
||||
std::vector<u8> temp(type == IPSFileType::IPS ? 3 : 4);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "common/logging.h"
|
||||
#include "common/uuid.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
|
||||
@@ -61,17 +62,24 @@ SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
|
||||
|
||||
SaveDataFactory::~SaveDataFactory() = default;
|
||||
|
||||
std::string SaveDataFactory::GetSaveDataPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, u128 user_id, u64 save_id) const {
|
||||
if (type == SaveDataType::Account || type == SaveDataType::Device) {
|
||||
const auto requested_id = title_id != 0 ? title_id : program_id;
|
||||
const auto parent_id = system.GetContentProvider().GetParentApplicationId(requested_id);
|
||||
title_id = parent_id.value_or(requested_id);
|
||||
}
|
||||
return GetFullPath(program_id, dir, space, type, title_id, user_id, save_id);
|
||||
}
|
||||
|
||||
VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
||||
const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
|
||||
meta.user_id, meta.system_save_data_id);
|
||||
const auto save_directory = GetSaveDataPath(space, meta.type, meta.program_id, meta.user_id, meta.system_save_data_id);
|
||||
|
||||
return dir->CreateDirectoryRelative(save_directory);
|
||||
}
|
||||
|
||||
VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
||||
|
||||
const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
|
||||
meta.user_id, meta.system_save_data_id);
|
||||
const auto save_directory = GetSaveDataPath(space, meta.type, meta.program_id, meta.user_id, meta.system_save_data_id);
|
||||
|
||||
auto out = dir->GetDirectoryRelative(save_directory);
|
||||
|
||||
@@ -154,8 +162,7 @@ std::string SaveDataFactory::GetUserGameSaveDataRoot(u128 user_id, bool future)
|
||||
|
||||
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
|
||||
u128 user_id) const {
|
||||
const auto path =
|
||||
GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
|
||||
const auto path = GetSaveDataPath(SaveDataSpaceId::User, type, title_id, user_id, 0);
|
||||
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
||||
|
||||
const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName());
|
||||
@@ -173,8 +180,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
|
||||
|
||||
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
|
||||
SaveDataSize new_value) const {
|
||||
const auto path =
|
||||
GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
|
||||
const auto path = GetSaveDataPath(SaveDataSpaceId::User, type, title_id, user_id, 0);
|
||||
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
||||
|
||||
const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName());
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
void SetAutoCreate(bool state);
|
||||
|
||||
private:
|
||||
std::string GetSaveDataPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, u128 user_id, u64 save_id) const;
|
||||
Core::System& system;
|
||||
ProgramId program_id;
|
||||
VirtualDir dir;
|
||||
|
||||
@@ -109,7 +109,8 @@ VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::op
|
||||
auto reference = std::make_unique<FileReference>();
|
||||
this->InsertReferenceIntoListLocked(*reference);
|
||||
|
||||
auto file = std::make_shared<RealVfsFile>(*this, std::move(reference), path, perms, size, std::move(parent_path));
|
||||
auto file = std::shared_ptr<RealVfsFile>(
|
||||
new RealVfsFile(*this, std::move(reference), path, perms, size, std::move(parent_path)));
|
||||
cache[path] = file;
|
||||
|
||||
return file;
|
||||
@@ -176,7 +177,7 @@ bool RealVfsFilesystem::DeleteFile(std::string_view path_) {
|
||||
|
||||
VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, OpenMode perms) {
|
||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||
return std::make_shared<RealVfsDirectory>(*this, path, perms);
|
||||
return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
|
||||
}
|
||||
|
||||
VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, OpenMode perms) {
|
||||
@@ -184,7 +185,7 @@ VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, OpenMode p
|
||||
if (!FS::CreateDirs(path)) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_shared<RealVfsDirectory>(*this, path, perms);
|
||||
return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
|
||||
}
|
||||
|
||||
VirtualDir RealVfsFilesystem::CopyDirectory(std::string_view old_path_,
|
||||
|
||||
@@ -82,9 +82,6 @@ class RealVfsFile : public VfsFile {
|
||||
friend class RealVfsFilesystem;
|
||||
|
||||
public:
|
||||
RealVfsFile(RealVfsFilesystem& base, std::unique_ptr<FileReference> reference,
|
||||
const std::string& path, OpenMode perms = OpenMode::Read,
|
||||
std::optional<u64> size = {}, std::optional<std::string> parent_path = {});
|
||||
~RealVfsFile() override;
|
||||
|
||||
std::string GetName() const override;
|
||||
@@ -98,6 +95,9 @@ public:
|
||||
bool Rename(std::string_view name) override;
|
||||
|
||||
private:
|
||||
RealVfsFile(RealVfsFilesystem& base, std::unique_ptr<FileReference> reference,
|
||||
const std::string& path, OpenMode perms = OpenMode::Read,
|
||||
std::optional<u64> size = {}, std::optional<std::string> parent_path = {});
|
||||
|
||||
RealVfsFilesystem& base;
|
||||
std::unique_ptr<FileReference> reference;
|
||||
@@ -113,8 +113,6 @@ class RealVfsDirectory : public VfsDirectory {
|
||||
friend class RealVfsFilesystem;
|
||||
|
||||
public:
|
||||
RealVfsDirectory(RealVfsFilesystem& base, const std::string& path,
|
||||
OpenMode perms = OpenMode::Read);
|
||||
~RealVfsDirectory() override;
|
||||
|
||||
VirtualFile GetFileRelative(std::string_view relative_path) const override;
|
||||
@@ -140,6 +138,9 @@ public:
|
||||
std::map<std::string, VfsEntryType, std::less<>> GetEntries() const override;
|
||||
|
||||
private:
|
||||
RealVfsDirectory(RealVfsFilesystem& base, const std::string& path,
|
||||
OpenMode perms = OpenMode::Read);
|
||||
|
||||
template <typename T, typename R>
|
||||
std::vector<std::shared_ptr<R>> IterateEntries() const;
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "core/hle/service/am/frontend/applet_web_browser.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
#include "core/hle/service/am/service/storage.h"
|
||||
#include "core/hle/service/am/window_system.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::AM::Frontend {
|
||||
@@ -73,16 +72,10 @@ void FrontendApplet::PushInteractiveOutData(std::shared_ptr<IStorage> storage) {
|
||||
|
||||
void FrontendApplet::Exit() {
|
||||
auto applet_ = applet.lock();
|
||||
{
|
||||
std::scoped_lock lk{applet_->lock};
|
||||
applet_->is_completed = true;
|
||||
applet_->state_changed_event.Signal(system.Kernel());
|
||||
}
|
||||
if (auto caller_applet = applet_->caller_applet.lock()) {
|
||||
std::scoped_lock lk{caller_applet->lock};
|
||||
std::erase(caller_applet->child_applets, applet_);
|
||||
}
|
||||
if (auto* window_system = system.GetAppletManager().GetWindowSystem()) window_system->RequestUpdate();
|
||||
|
||||
std::scoped_lock lk{applet_->lock};
|
||||
applet_->is_completed = true;
|
||||
applet_->state_changed_event.Signal(system.Kernel());
|
||||
}
|
||||
|
||||
FrontendAppletSet::FrontendAppletSet() = default;
|
||||
|
||||
@@ -122,10 +122,7 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
|
||||
auto broker = std::make_shared<AppletDataBroker>(system);
|
||||
applet->caller_applet = caller_applet;
|
||||
applet->caller_applet_broker = broker;
|
||||
{
|
||||
std::scoped_lock lk{caller_applet->lock};
|
||||
caller_applet->child_applets.push_back(applet);
|
||||
}
|
||||
caller_applet->child_applets.push_back(applet);
|
||||
window_system.TrackApplet(applet, false);
|
||||
return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
|
||||
}
|
||||
@@ -151,10 +148,10 @@ std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& syste
|
||||
applet->caller_applet = caller_applet;
|
||||
applet->caller_applet_broker = storage;
|
||||
applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode);
|
||||
{
|
||||
std::scoped_lock lk{caller_applet->lock};
|
||||
caller_applet->child_applets.push_back(applet);
|
||||
}
|
||||
caller_applet->child_applets.push_back(applet);
|
||||
|
||||
window_system.TrackApplet(applet, false);
|
||||
|
||||
return std::make_shared<ILibraryAppletAccessor>(system, storage, applet);
|
||||
}
|
||||
|
||||
|
||||
@@ -517,7 +517,7 @@ void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, b
|
||||
// Layer ordering. Composition sorts back-to-front. Now with enums for calrity.
|
||||
s32 z_index = Background;
|
||||
if (is_overlay) {
|
||||
z_index = this->IsOverlayOpenLocked(*applet) ? Overlay : Background;
|
||||
z_index = Overlay;
|
||||
} else if (inherited_foreground) {
|
||||
z_index = is_obscured ? Foreground : ForegroundVisible;
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ void LoopProcess(Core::System& system) {
|
||||
server_manager->RegisterNamedService("audout:d", std::make_shared<IAudioOutManagerForDebugger>(system), 30);
|
||||
server_manager->RegisterNamedService("audin:d", std::make_shared<IAudioInManagerForDebugger>(system), 30);
|
||||
server_manager->RegisterNamedService("audrec:d", std::make_shared<IFinalOutputRecorderManagerForDebugger>(system), 30);
|
||||
server_manager->RegisterNamedService("audren:d", std::make_shared<IAudioRendererManagerForDebugger>(system), 30);
|
||||
server_manager->RegisterNamedService("audren:d", std::make_shared<IAudioInManager>(system), 30);
|
||||
|
||||
server_manager->RegisterNamedService("audin:u", std::make_shared<IAudioInManager>(system), 30);
|
||||
server_manager->RegisterNamedService("audin:a", std::make_shared<IAudioInManagerForApplet>(system), 30);
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
#include <map>
|
||||
#include <span>
|
||||
#include <boost/icl/interval_set.hpp>
|
||||
#include <dynarmic/interface/A64/a64.h>
|
||||
#include <dynarmic/interface/A64/config.h>
|
||||
#include <dynarmic/interface/code_page.h>
|
||||
#include "dynarmic/interface/A64/a64.h"
|
||||
#include "dynarmic/interface/A64/config.h"
|
||||
#include "dynarmic/interface/code_page.h"
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/common_funcs.h"
|
||||
@@ -71,14 +71,17 @@ public:
|
||||
void InstructionSynchronizationBarrierRaised() override {
|
||||
last_code_addr = u64(-1); //reset back, force refetch
|
||||
}
|
||||
u64 MemoryRead(u64 vaddr, size_t size) override {
|
||||
switch (size) {
|
||||
case sizeof(u64): return ReadMemory<u64>(vaddr);
|
||||
case sizeof(u32): return ReadMemory<u32>(vaddr);
|
||||
case sizeof(u16): return ReadMemory<u16>(vaddr);
|
||||
case sizeof(u8): return ReadMemory<u8>(vaddr);
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
u8 MemoryRead8(u64 vaddr) override {
|
||||
return ReadMemory<u8>(vaddr);
|
||||
}
|
||||
u16 MemoryRead16(u64 vaddr) override {
|
||||
return ReadMemory<u16>(vaddr);
|
||||
}
|
||||
u32 MemoryRead32(u64 vaddr) override {
|
||||
return ReadMemory<u32>(vaddr);
|
||||
}
|
||||
u64 MemoryRead64(u64 vaddr) override {
|
||||
return ReadMemory<u64>(vaddr);
|
||||
}
|
||||
u128 MemoryRead128(u64 vaddr) override {
|
||||
return ReadMemory<u128>(vaddr);
|
||||
@@ -86,19 +89,22 @@ public:
|
||||
std::string MemoryReadCString(u64 vaddr) {
|
||||
std::string result{};
|
||||
u8 next;
|
||||
while ((next = u8(MemoryRead(vaddr++, sizeof(u8)))) != 0)
|
||||
while ((next = MemoryRead8(vaddr++)) != 0)
|
||||
result += char(next);
|
||||
return result;
|
||||
}
|
||||
|
||||
void MemoryWrite(u64 vaddr, u64 value, size_t size) override {
|
||||
switch (size) {
|
||||
case sizeof(u64): WriteMemory<u64>(vaddr, u64(value)); break;
|
||||
case sizeof(u32): WriteMemory<u32>(vaddr, u32(value)); break;
|
||||
case sizeof(u16): WriteMemory<u16>(vaddr, u16(value)); break;
|
||||
case sizeof(u8): WriteMemory<u8>(vaddr, u8(value)); break;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
void MemoryWrite8(u64 vaddr, u8 value) override {
|
||||
WriteMemory<u8>(vaddr, value);
|
||||
}
|
||||
void MemoryWrite16(u64 vaddr, u16 value) override {
|
||||
WriteMemory<u16>(vaddr, value);
|
||||
}
|
||||
void MemoryWrite32(u64 vaddr, u32 value) override {
|
||||
WriteMemory<u32>(vaddr, value);
|
||||
}
|
||||
void MemoryWrite64(u64 vaddr, u64 value) override {
|
||||
WriteMemory<u64>(vaddr, value);
|
||||
}
|
||||
void MemoryWrite128(u64 vaddr, u128 value) override {
|
||||
WriteMemory<u128>(vaddr, value);
|
||||
@@ -187,14 +193,14 @@ public:
|
||||
// The loaded NRO file has ELF relocations that must be processed before it can run.
|
||||
// Normally this would be processed by RTLD, but in HLE context, we don't have
|
||||
// the linker available, so we have to do it ourselves.
|
||||
const VAddr mod_offset{callbacks->MemoryRead(4, sizeof(u32))};
|
||||
if (callbacks->MemoryRead(mod_offset, sizeof(u32)) != Common::MakeMagic('M', 'O', 'D', '0'))
|
||||
const VAddr mod_offset{callbacks->MemoryRead32(4)};
|
||||
if (callbacks->MemoryRead32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0'))
|
||||
return false;
|
||||
|
||||
// For more info about dynamic entries, see the ELF ABI specification:
|
||||
// https://refspecs.linuxbase.org/elf/gabi4+/ch5.dynamic.html
|
||||
// https://refspecs.linuxbase.org/elf/gabi4+/ch4.reloc.html
|
||||
VAddr dynamic_offset{mod_offset + callbacks->MemoryRead(mod_offset + 4, sizeof(u32))};
|
||||
VAddr dynamic_offset{mod_offset + callbacks->MemoryRead32(mod_offset + 4)};
|
||||
VAddr rela_dyn = 0, relr_dyn = 0;
|
||||
size_t num_rela = 0, num_relr = 0;
|
||||
while (true) {
|
||||
@@ -216,8 +222,8 @@ public:
|
||||
for (size_t i = 0; i < num_rela; i++) {
|
||||
const auto rela{callbacks->ReadMemory<Elf64_Rela>(rela_dyn + i * sizeof(Elf64_Rela))};
|
||||
if (Elf64RelType(rela.r_info) == ElfAArch64Relative) {
|
||||
const VAddr contents{callbacks->MemoryRead(rela.r_offset, sizeof(u64))};
|
||||
callbacks->MemoryWrite(rela.r_offset, contents + rela.r_addend, sizeof(u64));
|
||||
const VAddr contents{callbacks->MemoryRead64(rela.r_offset)};
|
||||
callbacks->MemoryWrite64(rela.r_offset, contents + rela.r_addend);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +231,7 @@ public:
|
||||
for (size_t i = 0; i < num_relr; i++) {
|
||||
const auto relr = callbacks->ReadMemory<Elf64_Relr>(relr_dyn + i * sizeof(Elf64_Relr));
|
||||
const auto incr = [&](VAddr where) {
|
||||
callbacks->MemoryWrite(where, callbacks->MemoryRead(where, sizeof(u64)) + relocbase, sizeof(u64));
|
||||
callbacks->MemoryWrite64(where, callbacks->MemoryRead64(where) + relocbase);
|
||||
};
|
||||
if ((relr & 1) == 0) {
|
||||
// where pointer
|
||||
@@ -288,7 +294,7 @@ public:
|
||||
if (argument_stack.size() > 8) {
|
||||
const VAddr new_sp = Common::AlignDown(top_of_stack - (argument_stack.size() - 8) * sizeof(u64), STACK_ALIGN);
|
||||
for (size_t i = 8; i < argument_stack.size(); i++)
|
||||
callbacks->MemoryWrite(new_sp + (i - 8) * sizeof(u64), argument_stack[i], sizeof(u64));
|
||||
callbacks->MemoryWrite64(new_sp + (i - 8) * sizeof(u64), argument_stack[i]);
|
||||
jit->SetSP(new_sp);
|
||||
}
|
||||
// Reset the call state for the next invocation
|
||||
@@ -379,17 +385,17 @@ void DynarmicCallbacks64::CallSVC(u32 swi) {
|
||||
|
||||
if (dest < src) {
|
||||
for (size_t i = 0; i < n; i++)
|
||||
MemoryWrite(dest + i, u8(MemoryRead(src + i, sizeof(u8))), sizeof(u8));
|
||||
MemoryWrite8(dest + i, MemoryRead8(src + i));
|
||||
} else {
|
||||
for (size_t i = n; i > 0; i--)
|
||||
MemoryWrite(dest + i - 1, u8(MemoryRead(src + i - 1, sizeof(u8))), sizeof(u8));
|
||||
MemoryWrite8(dest + i - 1, MemoryRead8(src + i - 1));
|
||||
}
|
||||
} else if (pc == parent.helpers[size_t(HelperFn::Memset)]) {
|
||||
const VAddr dest{parent.jit->GetRegister(0)};
|
||||
const u64 c{parent.jit->GetRegister(1)};
|
||||
const size_t n{parent.jit->GetRegister(2)};
|
||||
for (size_t i = 0; i < n; i++)
|
||||
MemoryWrite(dest + i, u8(c), sizeof(u8));
|
||||
MemoryWrite8(dest + i, u8(c));
|
||||
} else if (pc == parent.helpers[size_t(HelperFn::Resolve)]) {
|
||||
// X0 contains a char* for a symbol to resolve
|
||||
const auto name{MemoryReadCString(parent.jit->GetRegister(0))};
|
||||
@@ -416,7 +422,7 @@ void DynarmicCallbacks64::CallSVC(u32 swi) {
|
||||
}
|
||||
|
||||
void DynarmicCallbacks64::ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) {
|
||||
auto const inst = MemoryRead(pc, sizeof(u32));
|
||||
auto const inst = MemoryRead32(pc);
|
||||
LOG_CRITICAL(Service_JIT, "{} PC @ {:08x}, data = {:08x}", exception, pc, inst);
|
||||
parent.jit->HaltExecution();
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "common/container/unordered_map.h"
|
||||
|
||||
#include "common/logging.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/ldn/ldn_results.h"
|
||||
#include "core/hle/service/ldn/ldn_types.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
@@ -24,7 +24,7 @@ IReceiverService::~IReceiverService() = default;
|
||||
|
||||
Result IReceiverService::OpenReceiver(Out<SharedPointer<IReceiver>> out_receiver) {
|
||||
LOG_DEBUG(Service_PSC, "called");
|
||||
*out_receiver = std::make_shared<IReceiver>(system);
|
||||
*out_receiver = std::shared_ptr<IReceiver>(new IReceiver(system));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
@@ -129,13 +129,6 @@ ServerManager::~ServerManager() {
|
||||
}
|
||||
}
|
||||
|
||||
void ServerManager::StartAdditionalHostThreads(const char* name, size_t num_threads) {
|
||||
for (size_t i = 0; i < num_threads; i++) {
|
||||
auto thread_name = fmt::format("{}:{}", name, i + 1);
|
||||
m_threads.emplace_back(m_system.Kernel().RunOnHostCoreThread(std::move(thread_name), [&] { this->LoopProcessImpl(); }));
|
||||
}
|
||||
}
|
||||
|
||||
void ServerManager::RunServer(std::unique_ptr<ServerManager>&& server_manager) {
|
||||
server_manager->m_system.RunServer(std::move(server_manager));
|
||||
}
|
||||
@@ -252,6 +245,14 @@ Result ServerManager::ManageDeferral(Kernel::KEvent** out_event) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void ServerManager::StartAdditionalHostThreads(const char* name, size_t num_threads) {
|
||||
for (size_t i = 0; i < num_threads; i++) {
|
||||
auto thread_name = fmt::format("{}:{}", name, i + 1);
|
||||
m_threads.emplace_back(m_system.Kernel().RunOnHostCoreThread(
|
||||
std::move(thread_name), [&] { this->LoopProcessImpl(); }));
|
||||
}
|
||||
}
|
||||
|
||||
Result ServerManager::LoopProcess() {
|
||||
SCOPE_EXIT {
|
||||
m_stopped.Set();
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -51,8 +48,8 @@ public:
|
||||
Result ManageDeferral(Kernel::KEvent** out_event);
|
||||
|
||||
Result LoopProcess();
|
||||
|
||||
void StartAdditionalHostThreads(const char* name, size_t num_threads);
|
||||
|
||||
static void RunServer(std::unique_ptr<ServerManager>&& server);
|
||||
|
||||
private:
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
#include "common/logging.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
@@ -20,9 +20,6 @@
|
||||
#include "core/hle/service/sockets/sockets_translate.h"
|
||||
#include "core/internal_network/network.h"
|
||||
#include "core/internal_network/socket_proxy.h"
|
||||
#if defined(__unix__) && !defined(__APPLE__)
|
||||
#include "core/internal_network/socket_icmp.h"
|
||||
#endif
|
||||
#include "core/internal_network/sockets.h"
|
||||
#include "network/network.h"
|
||||
#include <common/settings.h>
|
||||
@@ -31,18 +28,15 @@ namespace Service::Sockets {
|
||||
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] bool IsConnectionBased(Network::Type type) noexcept {
|
||||
bool IsConnectionBased(Type type) {
|
||||
switch (type) {
|
||||
case Network::Type::STREAM:
|
||||
case Network::Type::SEQPACKET:
|
||||
case Type::STREAM:
|
||||
return true;
|
||||
case Network::Type::RAW:
|
||||
case Network::Type::DGRAM:
|
||||
case Network::Type::RDM:
|
||||
case Network::Type::Unspecified:
|
||||
case Type::DGRAM:
|
||||
return false;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
UNIMPLEMENTED_MSG("Unimplemented type={}", type);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +92,7 @@ void BSD_USA::ConnectWork::Execute(BSD_USA* bsd) {
|
||||
void BSD_USA::ConnectWork::Response(HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(bsd_errno == Network::Errno::E_SUCCESS ? 0 : -1);
|
||||
rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
|
||||
rb.PushEnum(bsd_errno);
|
||||
}
|
||||
|
||||
@@ -176,9 +170,10 @@ void BSD_USA::Socket(HLERequestContext& ctx) {
|
||||
const u32 domain = rp.Pop<u32>();
|
||||
const u32 type = rp.Pop<u32>();
|
||||
const u32 protocol = rp.Pop<u32>();
|
||||
|
||||
LOG_DEBUG(Service, "called. domain={} type={} protocol={}", domain, type, protocol);
|
||||
|
||||
const auto [fd, bsd_errno] = SocketImpl(Network::Domain(domain), Network::Type(type), Network::Protocol(protocol));
|
||||
const auto [fd, bsd_errno] = SocketImpl(Domain(domain), Type(type), Protocol(protocol));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
@@ -194,8 +189,8 @@ void BSD_USA::SocketExempt(HLERequestContext& ctx) {
|
||||
|
||||
LOG_DEBUG(Service, "called. domain={} type={} protocol={}", domain, type, protocol);
|
||||
|
||||
auto [fd, bsd_errno] = SocketImpl(Network::Domain(domain), Network::Type(type), Network::Protocol(protocol));
|
||||
if (bsd_errno == Network::Errno::E_SUCCESS) {
|
||||
auto [fd, bsd_errno] = SocketImpl(Domain(domain), Type(type), Protocol(protocol));
|
||||
if (bsd_errno == Errno::SUCCESS) {
|
||||
bsd_errno = ShutdownImpl(fd, 0);
|
||||
}
|
||||
|
||||
@@ -269,13 +264,13 @@ void BSD_USA::GetPeerName(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service, "called. fd={}", fd);
|
||||
|
||||
std::vector<u8> write_buffer(ctx.GetWriteBufferSize());
|
||||
const Network::Errno bsd_errno = GetPeerNameImpl(fd, write_buffer);
|
||||
const Errno bsd_errno = GetPeerNameImpl(fd, write_buffer);
|
||||
|
||||
ctx.WriteBuffer(write_buffer);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(bsd_errno != Network::Errno::E_SUCCESS ? -1 : 0);
|
||||
rb.Push<s32>(bsd_errno != Errno::SUCCESS ? -1 : 0);
|
||||
rb.PushEnum(bsd_errno);
|
||||
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
||||
}
|
||||
@@ -287,13 +282,13 @@ void BSD_USA::GetSockName(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service, "called. fd={}", fd);
|
||||
|
||||
std::vector<u8> write_buffer(ctx.GetWriteBufferSize());
|
||||
const Network::Errno bsd_errno = GetSockNameImpl(fd, write_buffer);
|
||||
const Errno bsd_errno = GetSockNameImpl(fd, write_buffer);
|
||||
|
||||
ctx.WriteBuffer(write_buffer);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(bsd_errno != Network::Errno::E_SUCCESS ? -1 : 0);
|
||||
rb.Push<s32>(bsd_errno != Errno::SUCCESS ? -1 : 0);
|
||||
rb.PushEnum(bsd_errno);
|
||||
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
||||
}
|
||||
@@ -301,19 +296,21 @@ void BSD_USA::GetSockName(HLERequestContext& ctx) {
|
||||
void BSD_USA::GetSockOpt(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const s32 fd = rp.Pop<s32>();
|
||||
const auto level = Network::SocketLevel(rp.Pop<u32>());
|
||||
const auto optname = Network::OptName(rp.Pop<u32>());
|
||||
const u32 level = rp.Pop<u32>();
|
||||
const auto optname = static_cast<OptName>(rp.Pop<u32>());
|
||||
|
||||
std::vector<u8> optval(ctx.GetWriteBufferSize());
|
||||
|
||||
LOG_DEBUG(Service, "called. fd={} level={} optname={:#x} len={:#x}", fd, level, optname, optval.size());
|
||||
const Network::Errno err = GetSockOptImpl(fd, level, optname, optval);
|
||||
LOG_DEBUG(Service, "called. fd={} level={} optname={:#x} len={:#x}", fd, level, optname,
|
||||
optval.size());
|
||||
|
||||
const Errno err = GetSockOptImpl(fd, level, optname, optval);
|
||||
|
||||
ctx.WriteBuffer(optval);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(err == Network::Errno::E_SUCCESS ? 0 : -1);
|
||||
rb.Push<s32>(err == Errno::SUCCESS ? 0 : -1);
|
||||
rb.PushEnum(err);
|
||||
rb.Push<u32>(static_cast<u32>(optval.size()));
|
||||
}
|
||||
@@ -336,7 +333,7 @@ void BSD_USA::Fcntl(HLERequestContext& ctx) {
|
||||
|
||||
LOG_DEBUG(Service, "called. fd={} cmd={} arg={}", fd, cmd, arg);
|
||||
|
||||
const auto [ret, bsd_errno] = FcntlImpl(fd, Network::FcntlCmd(cmd), arg);
|
||||
const auto [ret, bsd_errno] = FcntlImpl(fd, static_cast<FcntlCmd>(cmd), arg);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
@@ -348,11 +345,13 @@ void BSD_USA::SetSockOpt(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const s32 fd = rp.Pop<s32>();
|
||||
const Network::SocketLevel level = Network::SocketLevel(rp.Pop<u32>());
|
||||
const Network::OptName optname = Network::OptName(rp.Pop<u32>());
|
||||
const u32 level = rp.Pop<u32>();
|
||||
const OptName optname = static_cast<OptName>(rp.Pop<u32>());
|
||||
const auto optval = ctx.ReadBuffer();
|
||||
|
||||
LOG_DEBUG(Service, "called. fd={} level={} optname={:#x} optlen={}", fd, level, u32(optname), optval.size());
|
||||
LOG_DEBUG(Service, "called. fd={} level={} optname={:#x} optlen={}", fd, level,
|
||||
static_cast<u32>(optname), optval.size());
|
||||
|
||||
BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval));
|
||||
}
|
||||
|
||||
@@ -474,7 +473,7 @@ void BSD_USA::DuplicateSocket(HLERequestContext& ctx) {
|
||||
|
||||
struct OutputParameters {
|
||||
s32 ret;
|
||||
Network::Errno bsd_errno;
|
||||
Errno bsd_errno;
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 0x8);
|
||||
|
||||
@@ -486,7 +485,7 @@ void BSD_USA::DuplicateSocket(HLERequestContext& ctx) {
|
||||
if (is_user) {
|
||||
rb.PushRaw(OutputParameters{
|
||||
.ret = 0,
|
||||
.bsd_errno = Network::Errno::E_INVAL,
|
||||
.bsd_errno = Errno::INVAL,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -495,10 +494,10 @@ void BSD_USA::DuplicateSocket(HLERequestContext& ctx) {
|
||||
if (auto* res = std::get_if<s32>(&res_v)) {
|
||||
rb.PushRaw(OutputParameters{
|
||||
.ret = *res,
|
||||
.bsd_errno = Network::Errno::E_SUCCESS,
|
||||
.bsd_errno = Errno::SUCCESS,
|
||||
});
|
||||
} else {
|
||||
auto* err = std::get_if<Network::Errno>(&res_v);
|
||||
auto* err = std::get_if<Errno>(&res_v);
|
||||
rb.PushRaw(OutputParameters{
|
||||
.ret = 0,
|
||||
.bsd_errno = *err,
|
||||
@@ -513,7 +512,7 @@ void BSD_USA::EventFd(HLERequestContext& ctx) {
|
||||
|
||||
LOG_WARNING(Service, "(STUBBED) called. initval={}, flags={}", initval, flags);
|
||||
|
||||
BuildErrnoResponse(ctx, Network::Errno::E_SUCCESS);
|
||||
BuildErrnoResponse(ctx, Errno::SUCCESS);
|
||||
}
|
||||
|
||||
template <typename Work>
|
||||
@@ -522,143 +521,132 @@ void BSD_USA::ExecuteWork(HLERequestContext& ctx, Work work) {
|
||||
work.Response(ctx);
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> BSD_USA::SocketImpl(Network::Domain domain, Network::Type type, Network::Protocol protocol) {
|
||||
std::pair<s32, Errno> BSD_USA::SocketImpl(Domain domain, Type type, Protocol protocol) {
|
||||
// user bsd:u has restrictions on SOCK_SEQPACKET and SOCK_RAW
|
||||
LOG_DEBUG(Network, "domain={},type={},protocol={}", u32(domain), u32(type), u32(protocol));
|
||||
if (is_user && (type == Network::Type::SEQPACKET || type == Network::Type::RAW)) {
|
||||
if (type == Network::Type::RAW && domain == Network::Domain::INET && protocol == Network::Protocol::ICMP) {
|
||||
if (is_user && (type == Type::SEQPACKET || type == Type::RAW)) {
|
||||
if (type == Type::RAW && domain == Domain::INET && protocol == Protocol::ICMP) {
|
||||
// fine, can use on bsd:s and bsd:u
|
||||
} else {
|
||||
return {-1, Network::Errno::E_INVAL};
|
||||
return {-1, Errno::INVAL};
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]] const bool unk_flag = (u32(type) & 0x20000000) != 0;
|
||||
[[maybe_unused]] const bool unk_flag = (static_cast<u32>(type) & 0x20000000) != 0;
|
||||
UNIMPLEMENTED_IF_MSG(unk_flag, "Unknown flag in type");
|
||||
type = Network::Type(u32(type) & ~0x20000000);
|
||||
type = static_cast<Type>(static_cast<u32>(type) & ~0x20000000);
|
||||
|
||||
const s32 fd = FindFreeFileDescriptorHandle();
|
||||
if (fd < 0) {
|
||||
LOG_ERROR(Service, "No more file descriptors available");
|
||||
return {-1, Network::Errno::E_MFILE};
|
||||
}
|
||||
|
||||
if (Settings::values.airplane_mode.GetValue() && IsConnectionBased(type)) {
|
||||
LOG_ERROR(Service, "Airplane mode is enabled, cannot create socket");
|
||||
file_descriptors[fd].reset();
|
||||
return {-1, Network::Errno::E_NOTCONN};
|
||||
return {-1, Errno::MFILE};
|
||||
}
|
||||
|
||||
file_descriptors[fd] = FileDescriptor{};
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
|
||||
// ENONMEM might be thrown here
|
||||
LOG_INFO(Service, "New socket fd={},domain={},type={},prot={}", fd, domain, type, protocol);
|
||||
|
||||
// While room is important -- we need to remember ICMP takes priority over **everything else**
|
||||
// TODO: rework this so proxy sockets can be done transparently? -- like what if i need
|
||||
// to browse the internet while playing LDN or something stupid like that?
|
||||
LOG_INFO(Service, "New socket fd={}", fd);
|
||||
|
||||
auto room_member = Network::GetRoomMember().lock();
|
||||
if ((protocol != Network::Protocol::ICMP && protocol != Network::Protocol::ICMPV6)
|
||||
&& (room_member && room_member->IsConnected())) {
|
||||
if (room_member && room_member->IsConnected()) {
|
||||
descriptor.socket = std::make_shared<Network::ProxySocket>();
|
||||
descriptor.socket->fd = fd;
|
||||
} else {
|
||||
descriptor.socket = std::make_shared<Network::Socket>();
|
||||
}
|
||||
auto const bsd_errno = descriptor.socket->Initialize(domain, type, protocol);
|
||||
|
||||
#if defined(__unix__) && !defined(__APPLE__)
|
||||
// ...only unix has this issue it seems, ICMP works otherwise fine on win
|
||||
if ((protocol == Network::Protocol::ICMP || protocol == Network::Protocol::ICMPV6)
|
||||
&& bsd_errno != Network::Errno::E_SUCCESS) {
|
||||
LOG_WARNING(Network, "Using ICMP emulated socket");
|
||||
descriptor.socket = std::make_shared<Network::IcmpSocket>();
|
||||
descriptor.socket->fd = fd;
|
||||
}
|
||||
#endif
|
||||
descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(protocol));
|
||||
descriptor.is_connection_based = IsConnectionBased(type);
|
||||
#ifdef _WIN32
|
||||
if (descriptor.is_connection_based && descriptor.socket->fd == INVALID_SOCKET) {
|
||||
#else
|
||||
if (descriptor.is_connection_based && descriptor.socket->fd == Network::Socket::INVALID_SOCKET) {
|
||||
#endif
|
||||
file_descriptors[fd].reset();
|
||||
return {-1, bsd_errno};
|
||||
|
||||
if (Settings::values.airplane_mode.GetValue() && descriptor.is_connection_based) {
|
||||
LOG_ERROR(Service, "Airplane mode is enabled, cannot create socket");
|
||||
return {-1, Errno::NOTCONN};
|
||||
}
|
||||
return {fd, Network::Errno::E_SUCCESS};
|
||||
|
||||
return {fd, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> BSD_USA::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, s32 nfds, s32 timeout) {
|
||||
LOG_DEBUG(Network, "nfds={},timeout={}", nfds, timeout);
|
||||
std::pair<s32, Errno> BSD_USA::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
|
||||
s32 nfds, s32 timeout) {
|
||||
if (nfds <= 0) {
|
||||
// When no entries are provided, -1 is returned with errno zero
|
||||
return {-1, Network::Errno::E_SUCCESS};
|
||||
return {-1, Errno::SUCCESS};
|
||||
}
|
||||
if (read_buffer.size() < nfds * sizeof(Network::PollFD)) {
|
||||
return {-1, Network::Errno::E_INVAL};
|
||||
if (read_buffer.size() < nfds * sizeof(PollFD)) {
|
||||
return {-1, Errno::INVAL};
|
||||
}
|
||||
if (write_buffer.size() < nfds * sizeof(Network::PollFD)) {
|
||||
return {-1, Network::Errno::E_INVAL};
|
||||
if (write_buffer.size() < nfds * sizeof(PollFD)) {
|
||||
return {-1, Errno::INVAL};
|
||||
}
|
||||
|
||||
std::span<const Network::PollFD> in_fds(reinterpret_cast<const Network::PollFD*>(read_buffer.data()), nfds);
|
||||
std::span<Network::PollFD> out_fds(reinterpret_cast<Network::PollFD*>(write_buffer.data()), nfds);
|
||||
std::copy(in_fds.begin(), in_fds.end(), out_fds.begin());
|
||||
std::vector<PollFD> fds(nfds);
|
||||
std::memcpy(fds.data(), read_buffer.data(), nfds * sizeof(PollFD));
|
||||
|
||||
if (timeout >= 0) {
|
||||
const s64 seconds = timeout / 1000;
|
||||
const u64 nanoseconds = 1'000'000 * (u64(timeout) % 1000);
|
||||
const u64 nanoseconds = 1'000'000 * (static_cast<u64>(timeout) % 1000);
|
||||
|
||||
if (seconds < 0) {
|
||||
return {-1, Network::Errno::E_INVAL};
|
||||
return {-1, Errno::INVAL};
|
||||
}
|
||||
if (nanoseconds > 999'999'999) {
|
||||
return {-1, Network::Errno::E_INVAL};
|
||||
return {-1, Errno::INVAL};
|
||||
}
|
||||
} else if (timeout != -1) {
|
||||
return {-1, Network::Errno::E_INVAL};
|
||||
return {-1, Errno::INVAL};
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < in_fds.size(); ++i) {
|
||||
ASSERT(out_fds[i].fd == in_fds[i].fd && False(in_fds[i].revents));
|
||||
if (!IsFileDescriptorValid(in_fds[i].fd)) {
|
||||
out_fds[i].revents = {};
|
||||
if (!file_descriptors[in_fds[i].fd])
|
||||
out_fds[i].revents = Network::PollEvents::NVAL;
|
||||
return {0, Network::Errno::E_SUCCESS};
|
||||
for (PollFD& pollfd : fds) {
|
||||
ASSERT(False(pollfd.revents));
|
||||
|
||||
if (pollfd.fd > static_cast<s32>(MAX_FD) || pollfd.fd < 0) {
|
||||
LOG_ERROR(Service, "File descriptor handle={} is invalid", pollfd.fd);
|
||||
pollfd.revents = PollEvents{};
|
||||
return {0, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
const std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd];
|
||||
if (!descriptor) {
|
||||
LOG_TRACE(Service, "File descriptor handle={} is not allocated", pollfd.fd);
|
||||
pollfd.revents = PollEvents::Nval;
|
||||
return {0, Errno::SUCCESS};
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Network::HostPollFD> host_pollfds(in_fds.size());
|
||||
std::transform(in_fds.begin(), in_fds.end(), host_pollfds.begin(), [](auto const e) {
|
||||
Network::HostPollFD result{};
|
||||
result.socket = file_descriptors[e.fd]->socket.get();
|
||||
result.events = e.events;
|
||||
result.revents = {};
|
||||
std::vector<Network::PollFD> host_pollfds(fds.size());
|
||||
std::transform(fds.begin(), fds.end(), host_pollfds.begin(), [](PollFD pollfd) {
|
||||
Network::PollFD result;
|
||||
result.socket = file_descriptors[pollfd.fd]->socket.get();
|
||||
result.events = Translate(pollfd.events);
|
||||
result.revents = Network::PollEvents{};
|
||||
return result;
|
||||
});
|
||||
auto const res = Network::Poll(host_pollfds, timeout);
|
||||
for (size_t i = 0; i < in_fds.size(); ++i)
|
||||
out_fds[i].revents = host_pollfds[i].revents;
|
||||
return res;
|
||||
|
||||
const auto result = Network::Poll(host_pollfds, timeout);
|
||||
|
||||
const size_t num = host_pollfds.size();
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
fds[i].revents = Translate(host_pollfds[i].revents);
|
||||
}
|
||||
std::memcpy(write_buffer.data(), fds.data(), nfds * sizeof(PollFD));
|
||||
|
||||
return Translate(result);
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> BSD_USA::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
std::pair<s32, Errno> BSD_USA::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Network::Errno::E_BADF};
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
|
||||
const s32 new_fd = FindFreeFileDescriptorHandle();
|
||||
if (new_fd < 0) {
|
||||
LOG_ERROR(Service, "No more file descriptors available");
|
||||
return {-1, Network::Errno::E_MFILE};
|
||||
return {-1, Errno::MFILE};
|
||||
}
|
||||
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
auto [result, bsd_errno] = descriptor.socket->Accept();
|
||||
if (bsd_errno != Network::Errno::E_SUCCESS) {
|
||||
return {-1, bsd_errno};
|
||||
if (bsd_errno != Network::Errno::SUCCESS) {
|
||||
return {-1, Translate(bsd_errno)};
|
||||
}
|
||||
|
||||
file_descriptors[new_fd] = FileDescriptor{};
|
||||
@@ -666,222 +654,268 @@ std::pair<s32, Network::Errno> BSD_USA::AcceptImpl(s32 fd, std::vector<u8>& writ
|
||||
new_descriptor.socket = std::move(result.socket);
|
||||
new_descriptor.is_connection_based = descriptor.is_connection_based;
|
||||
|
||||
PutValue(write_buffer, result.sockaddr_in);
|
||||
return {new_fd, Network::Errno::E_SUCCESS};
|
||||
const SockAddrIn guest_addr_in = Translate(result.sockaddr_in);
|
||||
PutValue(write_buffer, guest_addr_in);
|
||||
|
||||
return {new_fd, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::BindImpl(s32 fd, std::span<const u8> addr) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
Errno BSD_USA::BindImpl(s32 fd, std::span<const u8> addr) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
ASSERT(addr.size() >= 16);
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
auto addr_in = GetValue<Network::SockAddrIn>(addr);
|
||||
return file_descriptors[fd]->socket->Bind(addr_in);
|
||||
auto addr_in = GetValue<SockAddrIn>(addr);
|
||||
|
||||
return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::ConnectImpl(s32 fd, std::span<const u8> addr) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
Errno BSD_USA::ConnectImpl(s32 fd, std::span<const u8> addr) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
ASSERT(addr.size() >= 16);
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
auto addr_in = GetValue<Network::SockAddrIn>(addr);
|
||||
const Network::Errno result = file_descriptors[fd]->socket->Connect(addr_in);
|
||||
if (result == Network::Errno::E_ISCONN) {
|
||||
auto addr_in = GetValue<SockAddrIn>(addr);
|
||||
|
||||
const Errno result = Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in)));
|
||||
|
||||
if (result == Errno::ISCONN) {
|
||||
LOG_DEBUG(Service, "returned ISCONN - socket already connected");
|
||||
return Network::Errno::E_SUCCESS;
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
Errno BSD_USA::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetPeerName();
|
||||
if (bsd_errno != Network::Errno::E_SUCCESS) {
|
||||
return bsd_errno;
|
||||
if (bsd_errno != Network::Errno::SUCCESS) {
|
||||
return Translate(bsd_errno);
|
||||
}
|
||||
ASSERT(write_buffer.size() >= addr_in.len);
|
||||
write_buffer.resize(addr_in.len);
|
||||
PutValue(write_buffer, addr_in);
|
||||
return bsd_errno;
|
||||
const SockAddrIn guest_addrin = Translate(addr_in);
|
||||
|
||||
ASSERT(write_buffer.size() >= sizeof(guest_addrin));
|
||||
write_buffer.resize(sizeof(guest_addrin));
|
||||
PutValue(write_buffer, guest_addrin);
|
||||
return Translate(bsd_errno);
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
Errno BSD_USA::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetSockName();
|
||||
if (bsd_errno != Network::Errno::E_SUCCESS) {
|
||||
return bsd_errno;
|
||||
if (bsd_errno != Network::Errno::SUCCESS) {
|
||||
return Translate(bsd_errno);
|
||||
}
|
||||
ASSERT(write_buffer.size() >= addr_in.len);
|
||||
write_buffer.resize(addr_in.len);
|
||||
PutValue(write_buffer, addr_in);
|
||||
return bsd_errno;
|
||||
const SockAddrIn guest_addrin = Translate(addr_in);
|
||||
|
||||
ASSERT(write_buffer.size() >= sizeof(guest_addrin));
|
||||
write_buffer.resize(sizeof(guest_addrin));
|
||||
PutValue(write_buffer, guest_addrin);
|
||||
return Translate(bsd_errno);
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::ListenImpl(s32 fd, s32 backlog) {
|
||||
LOG_DEBUG(Network, "fd={},backlog={}", fd, backlog);
|
||||
Errno BSD_USA::ListenImpl(s32 fd, s32 backlog) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
return file_descriptors[fd]->socket->Listen(backlog);
|
||||
return Translate(file_descriptors[fd]->socket->Listen(backlog));
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> BSD_USA::FcntlImpl(s32 fd, Network::FcntlCmd cmd, s32 arg) {
|
||||
LOG_DEBUG(Network, "fd={},cmd={},arg={}", fd, u32(cmd), arg);
|
||||
std::pair<s32, Errno> BSD_USA::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Network::Errno::E_BADF};
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return {-1, Network::Errno::E_BADF};
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
|
||||
switch (cmd) {
|
||||
case Network::FcntlCmd::GETFL:
|
||||
case FcntlCmd::GETFL:
|
||||
ASSERT(arg == 0);
|
||||
return {descriptor.flags, Network::Errno::E_SUCCESS};
|
||||
case Network::FcntlCmd::SETFL: {
|
||||
const bool enable = (arg & u32(Network::FcntlFlags::NONBLOCK_NX)) != 0;
|
||||
const Network::Errno bsd_errno = descriptor.socket->SetNonBlock(enable);
|
||||
if (bsd_errno != Network::Errno::E_SUCCESS) {
|
||||
return {descriptor.flags, Errno::SUCCESS};
|
||||
case FcntlCmd::SETFL: {
|
||||
const bool enable = (arg & Network::FLAG_O_NONBLOCK) != 0;
|
||||
const Errno bsd_errno = Translate(descriptor.socket->SetNonBlock(enable));
|
||||
if (bsd_errno != Errno::SUCCESS) {
|
||||
return {-1, bsd_errno};
|
||||
}
|
||||
descriptor.flags = arg;
|
||||
return {0, Network::Errno::E_SUCCESS};
|
||||
return {0, Errno::SUCCESS};
|
||||
}
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented cmd={}", cmd);
|
||||
return {-1, Network::Errno::E_SUCCESS};
|
||||
return {-1, Errno::SUCCESS};
|
||||
}
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::GetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::vector<u8>& optval) {
|
||||
LOG_DEBUG(Network, "fd={},level={},optname={}", fd, u32(level), u32(optname));
|
||||
Errno BSD_USA::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
if (level != Network::SocketLevel::SOCKET) {
|
||||
LOG_WARNING(Service, "(stubbed) level fd={}, level={}, optname={}", fd, level, optname);
|
||||
if (level != static_cast<u32>(SocketLevel::SOCKET)) {
|
||||
UNIMPLEMENTED_MSG("Unknown getsockopt level");
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
|
||||
|
||||
switch (optname) {
|
||||
case Network::OptName::ERROR_: {
|
||||
case OptName::ERROR_: {
|
||||
auto [pending_err, getsockopt_err] = socket->GetPendingError();
|
||||
if (getsockopt_err == Network::Errno::E_SUCCESS) {
|
||||
if (getsockopt_err == Network::Errno::SUCCESS) {
|
||||
Errno translated_pending_err = Translate(pending_err);
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
optval.size() == sizeof(Network::Errno), { return Network::Errno::E_INVAL; },
|
||||
optval.size() == sizeof(Errno), { return Errno::INVAL; },
|
||||
"Incorrect getsockopt option size");
|
||||
optval.resize(sizeof(Network::Errno));
|
||||
PutValue(optval, pending_err);
|
||||
optval.resize(sizeof(Errno));
|
||||
PutValue(optval, translated_pending_err);
|
||||
}
|
||||
return getsockopt_err;
|
||||
return Translate(getsockopt_err);
|
||||
}
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented optname={}", optname);
|
||||
return Network::Errno::E_SUCCESS;
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::SetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::span<const u8> optval) {
|
||||
LOG_DEBUG(Service, "fd={},level={},optname={}", fd, level, optname);
|
||||
Errno BSD_USA::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
if (level != static_cast<u32>(SocketLevel::SOCKET)) {
|
||||
LOG_WARNING(Service, "(STUBBED) setsockopt with level={}, optname={}", level, optname);
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
|
||||
return socket->SetSockOpt(level, optname, optval);
|
||||
|
||||
if (optname == OptName::LINGER) {
|
||||
ASSERT(optval.size() == sizeof(Linger));
|
||||
auto linger = GetValue<Linger>(optval);
|
||||
ASSERT(linger.onoff == 0 || linger.onoff == 1);
|
||||
|
||||
return Translate(socket->SetLinger(linger.onoff != 0, linger.linger));
|
||||
}
|
||||
|
||||
ASSERT(optval.size() == sizeof(u32));
|
||||
auto value = GetValue<u32>(optval);
|
||||
|
||||
switch (optname) {
|
||||
case OptName::REUSEADDR:
|
||||
ASSERT(value == 0 || value == 1);
|
||||
return Translate(socket->SetReuseAddr(value != 0));
|
||||
case OptName::KEEPALIVE:
|
||||
ASSERT(value == 0 || value == 1);
|
||||
return Translate(socket->SetKeepAlive(value != 0));
|
||||
case OptName::BROADCAST:
|
||||
ASSERT(value == 0 || value == 1);
|
||||
return Translate(socket->SetBroadcast(value != 0));
|
||||
case OptName::SNDBUF:
|
||||
return Translate(socket->SetSndBuf(value));
|
||||
case OptName::RCVBUF:
|
||||
return Translate(socket->SetRcvBuf(value));
|
||||
case OptName::SNDTIMEO:
|
||||
return Translate(socket->SetSndTimeo(value));
|
||||
case OptName::RCVTIMEO:
|
||||
return Translate(socket->SetRcvTimeo(value));
|
||||
case OptName::NOSIGPIPE:
|
||||
LOG_WARNING(Service, "(STUBBED) setting NOSIGPIPE to {}", value);
|
||||
return Errno::SUCCESS;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented optname={}", optname);
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::ShutdownImpl(s32 fd, s32 how) {
|
||||
LOG_DEBUG(Network, "fd={},how={}", fd, how);
|
||||
Errno BSD_USA::ShutdownImpl(s32 fd, s32 how) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
return file_descriptors[fd]->socket->Shutdown(Network::ShutdownHow(how));
|
||||
const Network::ShutdownHow host_how = Translate(static_cast<ShutdownHow>(how));
|
||||
return Translate(file_descriptors[fd]->socket->Shutdown(host_how));
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> BSD_USA::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
|
||||
LOG_DEBUG(Network, "fd={},flags={}", fd, flags);
|
||||
std::pair<s32, Errno> BSD_USA::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Network::Errno::E_BADF};
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
|
||||
// Apply flags
|
||||
if ((flags & u32(Network::MsgOpt::DONTWAIT)) != 0) {
|
||||
flags &= ~u32(Network::MsgOpt::DONTWAIT);
|
||||
if ((descriptor.flags & u32(Network::FcntlFlags::NONBLOCK_NX)) == 0) {
|
||||
using Network::FLAG_MSG_DONTWAIT;
|
||||
using Network::FLAG_O_NONBLOCK;
|
||||
if ((flags & FLAG_MSG_DONTWAIT) != 0) {
|
||||
flags &= ~FLAG_MSG_DONTWAIT;
|
||||
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
|
||||
descriptor.socket->SetNonBlock(true);
|
||||
}
|
||||
}
|
||||
|
||||
const auto [ret, bsd_errno] = descriptor.socket->Recv(flags, message);
|
||||
const auto [ret, bsd_errno] = Translate(descriptor.socket->Recv(flags, message));
|
||||
|
||||
// Restore original state
|
||||
if ((descriptor.flags & u32(Network::FcntlFlags::NONBLOCK_NX)) == 0)
|
||||
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
|
||||
descriptor.socket->SetNonBlock(false);
|
||||
}
|
||||
|
||||
return {ret, bsd_errno};
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> BSD_USA::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message, std::vector<u8>& addr) {
|
||||
LOG_DEBUG(Network, "fd={},flags={}", fd, flags);
|
||||
if (!IsFileDescriptorValid(fd))
|
||||
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};
|
||||
std::pair<s32, Errno> BSD_USA::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
|
||||
std::vector<u8>& addr) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
|
||||
@@ -895,75 +929,79 @@ std::pair<s32, Network::Errno> BSD_USA::RecvFromImpl(s32 fd, u32 flags, std::vec
|
||||
}
|
||||
|
||||
// Apply flags
|
||||
auto const is_nonblock = descriptor.socket->GetNonBlock();
|
||||
auto const f_dontwait = (flags & u32(Network::MsgOpt::DONTWAIT)) != 0;
|
||||
auto const f_waitall = (flags & u32(Network::MsgOpt::WAITALL)) != 0;
|
||||
// DONTWAIT set clears WAITALL, if socket is non-blocking it also clears WAITALL
|
||||
if (f_dontwait || (f_waitall && is_nonblock))
|
||||
flags &= ~u32(Network::MsgOpt::WAITALL);
|
||||
using Network::FLAG_MSG_DONTWAIT;
|
||||
using Network::FLAG_O_NONBLOCK;
|
||||
if ((flags & FLAG_MSG_DONTWAIT) != 0) {
|
||||
flags &= ~FLAG_MSG_DONTWAIT;
|
||||
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
|
||||
descriptor.socket->SetNonBlock(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (f_dontwait) descriptor.socket->SetNonBlock(true); //set non-block
|
||||
const auto [ret, bsd_errno] = descriptor.socket->RecvFrom(flags, message, p_addr_in);
|
||||
if (f_dontwait) descriptor.socket->SetNonBlock(is_nonblock); //restore
|
||||
const auto [ret, bsd_errno] = Translate(descriptor.socket->RecvFrom(flags, message, p_addr_in));
|
||||
|
||||
// Restore original state
|
||||
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
|
||||
descriptor.socket->SetNonBlock(false);
|
||||
}
|
||||
|
||||
if (p_addr_in) {
|
||||
if (ret < 0) {
|
||||
addr.clear();
|
||||
} else {
|
||||
ASSERT(addr.size() >= 16);
|
||||
PutValue(addr, addr_in);
|
||||
const SockAddrIn result = Translate(addr_in);
|
||||
PutValue(addr, result);
|
||||
}
|
||||
}
|
||||
|
||||
return {ret, bsd_errno};
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> BSD_USA::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
|
||||
LOG_DEBUG(Network, "fd={},flags={}", fd, flags);
|
||||
std::pair<s32, Errno> BSD_USA::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Network::Errno::E_BADF};
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return {-1, Network::Errno::E_BADF};
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
return file_descriptors[fd]->socket->Send(message, flags);
|
||||
return Translate(file_descriptors[fd]->socket->Send(message, flags));
|
||||
}
|
||||
|
||||
std::pair<s32, Network::Errno> BSD_USA::SendToImpl(s32 fd, u32 flags, std::span<const u8> message, std::span<const u8> addr) {
|
||||
LOG_DEBUG(Network, "fd={},flags={}", fd, flags);
|
||||
std::pair<s32, Errno> BSD_USA::SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
|
||||
std::span<const u8> addr) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Network::Errno::E_BADF};
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return {-1, Network::Errno::E_BADF};
|
||||
return {-1, Errno::BADF};
|
||||
}
|
||||
|
||||
Network::SockAddrIn addr_in{};
|
||||
Network::SockAddrIn addr_in;
|
||||
Network::SockAddrIn* p_addr_in = nullptr;
|
||||
if (!addr.empty()) {
|
||||
ASSERT(addr.size() >= 16);
|
||||
auto guest_addr_in = GetValue<Network::SockAddrIn>(addr);
|
||||
addr_in = guest_addr_in;
|
||||
auto guest_addr_in = GetValue<SockAddrIn>(addr);
|
||||
addr_in = Translate(guest_addr_in);
|
||||
p_addr_in = &addr_in;
|
||||
}
|
||||
|
||||
return file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in);
|
||||
return Translate(file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in));
|
||||
}
|
||||
|
||||
Network::Errno BSD_USA::CloseImpl(s32 fd) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
Errno BSD_USA::CloseImpl(s32 fd) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
auto const bsd_errno = file_descriptors[fd]->socket->Close();
|
||||
if (bsd_errno != Network::Errno::E_SUCCESS) {
|
||||
const Errno bsd_errno = Translate(file_descriptors[fd]->socket->Close());
|
||||
if (bsd_errno != Errno::SUCCESS) {
|
||||
return bsd_errno;
|
||||
}
|
||||
|
||||
@@ -973,27 +1011,26 @@ Network::Errno BSD_USA::CloseImpl(s32 fd) {
|
||||
return bsd_errno;
|
||||
}
|
||||
|
||||
std::variant<s32, Network::Errno> BSD_USA::DuplicateSocketImpl(s32 fd) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
std::variant<s32, Errno> BSD_USA::DuplicateSocketImpl(s32 fd) {
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Network::Errno::E_BADF;
|
||||
return Errno::BADF;
|
||||
}
|
||||
// Don't use IsFileDescriptorValid as new_fd isn't a proper handle yet
|
||||
if (s32 const new_fd = FindFreeFileDescriptorHandle(); 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 {
|
||||
|
||||
const s32 new_fd = FindFreeFileDescriptorHandle();
|
||||
if (new_fd < 0) {
|
||||
LOG_ERROR(Service, "No more file descriptors available");
|
||||
return Network::Errno::E_MFILE;
|
||||
return Errno::MFILE;
|
||||
}
|
||||
|
||||
file_descriptors[new_fd] = FileDescriptor{
|
||||
.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) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -1005,40 +1042,41 @@ std::optional<std::shared_ptr<Network::SocketBase>> BSD_USA::GetSocket(s32 fd) {
|
||||
}
|
||||
|
||||
s32 BSD_USA::FindFreeFileDescriptorHandle() noexcept {
|
||||
// first three file descriptors are reserved for:
|
||||
// STDOUT_FILENO, STDIN_FILENO and STDERR_FILENO
|
||||
for (s32 fd = 0; fd < s32(file_descriptors.size()); ++fd)
|
||||
if (!file_descriptors[fd])
|
||||
for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) {
|
||||
if (!file_descriptors[fd]) {
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool BSD_USA::IsFileDescriptorValid(s32 fd) const noexcept {
|
||||
if (fd < 0 || fd >= s32(file_descriptors.size())) {
|
||||
LOG_ERROR(Service, "Invalid handle={}", fd);
|
||||
if (fd > static_cast<s32>(MAX_FD) || fd < 0) {
|
||||
LOG_ERROR(Service, "Invalid file descriptor handle={}", fd);
|
||||
return false;
|
||||
}
|
||||
if (!file_descriptors[fd]) {
|
||||
LOG_ERROR(Service, "handle={} is not allocated", fd);
|
||||
LOG_ERROR(Service, "File descriptor handle={} is not allocated", fd);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BSD_USA::BuildErrnoResponse(HLERequestContext& ctx, Network::Errno bsd_errno) const noexcept {
|
||||
void BSD_USA::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept {
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(bsd_errno == Network::Errno::E_SUCCESS ? 0 : -1);
|
||||
rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
|
||||
rb.PushEnum(bsd_errno);
|
||||
}
|
||||
|
||||
void BSD_USA::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
|
||||
for (auto& optional_descriptor : file_descriptors) {
|
||||
if (optional_descriptor.has_value()) {
|
||||
FileDescriptor& descriptor = *optional_descriptor;
|
||||
descriptor.socket.get()->HandleProxyPacket(packet);
|
||||
if (!optional_descriptor.has_value()) {
|
||||
continue;
|
||||
}
|
||||
FileDescriptor& descriptor = *optional_descriptor;
|
||||
descriptor.socket.get()->HandleProxyPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <variant>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sockets/sockets.h"
|
||||
#include "network/network.h"
|
||||
@@ -35,8 +35,8 @@ public:
|
||||
// These methods are called from SSL; the first two are also called from
|
||||
// this class for the corresponding IPC methods.
|
||||
// On the real device, the SSL service makes IPC calls to this service.
|
||||
std::variant<s32, Network::Errno> DuplicateSocketImpl(s32 fd);
|
||||
Network::Errno CloseImpl(s32 fd);
|
||||
std::variant<s32, Errno> DuplicateSocketImpl(s32 fd);
|
||||
Errno CloseImpl(s32 fd);
|
||||
std::optional<std::shared_ptr<Network::SocketBase>> GetSocket(s32 fd);
|
||||
|
||||
private:
|
||||
@@ -58,7 +58,7 @@ private:
|
||||
std::span<const u8> read_buffer;
|
||||
std::vector<u8> write_buffer;
|
||||
s32 ret{};
|
||||
Network::Errno bsd_errno{};
|
||||
Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct AcceptWork {
|
||||
@@ -68,7 +68,7 @@ private:
|
||||
s32 fd;
|
||||
std::vector<u8> write_buffer;
|
||||
s32 ret{};
|
||||
Network::Errno bsd_errno{};
|
||||
Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct ConnectWork {
|
||||
@@ -77,7 +77,7 @@ private:
|
||||
|
||||
s32 fd;
|
||||
std::span<const u8> addr;
|
||||
Network::Errno bsd_errno{};
|
||||
Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct RecvWork {
|
||||
@@ -88,7 +88,7 @@ private:
|
||||
u32 flags;
|
||||
std::vector<u8> message;
|
||||
s32 ret{};
|
||||
Network::Errno bsd_errno{};
|
||||
Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct RecvFromWork {
|
||||
@@ -100,7 +100,7 @@ private:
|
||||
std::vector<u8> message;
|
||||
std::vector<u8> addr;
|
||||
s32 ret{};
|
||||
Network::Errno bsd_errno{};
|
||||
Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct SendWork {
|
||||
@@ -111,7 +111,7 @@ private:
|
||||
u32 flags;
|
||||
std::span<const u8> message;
|
||||
s32 ret{};
|
||||
Network::Errno bsd_errno{};
|
||||
Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct SendToWork {
|
||||
@@ -123,7 +123,7 @@ private:
|
||||
std::span<const u8> message;
|
||||
std::span<const u8> addr;
|
||||
s32 ret{};
|
||||
Network::Errno bsd_errno{};
|
||||
Errno bsd_errno{};
|
||||
};
|
||||
|
||||
void RegisterClient(HLERequestContext& ctx);
|
||||
@@ -155,29 +155,29 @@ private:
|
||||
template <typename Work>
|
||||
void ExecuteWork(HLERequestContext& ctx, Work work);
|
||||
|
||||
std::pair<s32, Network::Errno> SocketImpl(Network::Domain domain, Network::Type type, Network::Protocol protocol);
|
||||
std::pair<s32, Network::Errno> PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, s32 nfds, s32 timeout);
|
||||
std::pair<s32, Network::Errno> AcceptImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Network::Errno BindImpl(s32 fd, std::span<const u8> addr);
|
||||
Network::Errno ConnectImpl(s32 fd, std::span<const u8> addr);
|
||||
Network::Errno GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Network::Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Network::Errno ListenImpl(s32 fd, s32 backlog);
|
||||
std::pair<s32, Network::Errno> FcntlImpl(s32 fd, Network::FcntlCmd cmd, s32 arg);
|
||||
Network::Errno GetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::vector<u8>& optval);
|
||||
Network::Errno SetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::span<const u8> optval);
|
||||
Network::Errno ShutdownImpl(s32 fd, s32 how);
|
||||
std::pair<s32, Network::Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
|
||||
std::pair<s32, Network::Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
|
||||
std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol);
|
||||
std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, s32 nfds, s32 timeout);
|
||||
std::pair<s32, Errno> AcceptImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Errno BindImpl(s32 fd, std::span<const u8> addr);
|
||||
Errno ConnectImpl(s32 fd, std::span<const u8> addr);
|
||||
Errno GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Errno ListenImpl(s32 fd, s32 backlog);
|
||||
std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg);
|
||||
Errno GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval);
|
||||
Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval);
|
||||
Errno ShutdownImpl(s32 fd, s32 how);
|
||||
std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
|
||||
std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
|
||||
std::vector<u8>& addr);
|
||||
std::pair<s32, Network::Errno> SendImpl(s32 fd, u32 flags, std::span<const u8> message);
|
||||
std::pair<s32, Network::Errno> SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
|
||||
std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, std::span<const u8> message);
|
||||
std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
|
||||
std::span<const u8> addr);
|
||||
|
||||
s32 FindFreeFileDescriptorHandle() noexcept;
|
||||
bool IsFileDescriptorValid(s32 fd) const noexcept;
|
||||
|
||||
void BuildErrnoResponse(HLERequestContext& ctx, Network::Errno bsd_errno) const noexcept;
|
||||
void BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept;
|
||||
|
||||
static inline std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors{};
|
||||
|
||||
|
||||
@@ -102,39 +102,39 @@ static bool IsBlockedHost(const std::string& host) {
|
||||
[&host](const std::string& domain) { return host.find(domain) != std::string::npos; });
|
||||
}
|
||||
|
||||
static NetDbError GetAddrInfoErrorToNetDbError(Network::GetAddrInfoError result) {
|
||||
static NetDbError GetAddrInfoErrorToNetDbError(GetAddrInfoError result) {
|
||||
// These combinations have been verified on console (but are not
|
||||
// exhaustive).
|
||||
switch (result) {
|
||||
case Network::GetAddrInfoError::SUCCESS:
|
||||
case GetAddrInfoError::SUCCESS:
|
||||
return NetDbError::Success;
|
||||
case Network::GetAddrInfoError::AGAIN:
|
||||
case GetAddrInfoError::AGAIN:
|
||||
return NetDbError::TryAgain;
|
||||
case Network::GetAddrInfoError::NODATA:
|
||||
case GetAddrInfoError::NODATA:
|
||||
return NetDbError::HostNotFound;
|
||||
case Network::GetAddrInfoError::SERVICE:
|
||||
case GetAddrInfoError::SERVICE:
|
||||
return NetDbError::Success;
|
||||
default:
|
||||
return NetDbError::HostNotFound;
|
||||
}
|
||||
}
|
||||
|
||||
static Network::Errno GetAddrInfoErrorToErrno(Network::GetAddrInfoError result) {
|
||||
static Errno GetAddrInfoErrorToErrno(GetAddrInfoError result) {
|
||||
// These combinations have been verified on console (but are not
|
||||
// exhaustive).
|
||||
switch (result) {
|
||||
case Network::GetAddrInfoError::SUCCESS:
|
||||
case GetAddrInfoError::SUCCESS:
|
||||
// Note: Sometimes a successful lookup sets errno to EADDRNOTAVAIL for
|
||||
// some reason, but that doesn't seem useful to implement.
|
||||
return Network::Errno::E_SUCCESS;
|
||||
case Network::GetAddrInfoError::AGAIN:
|
||||
return Network::Errno::E_SUCCESS;
|
||||
case Network::GetAddrInfoError::NODATA:
|
||||
return Network::Errno::E_SUCCESS;
|
||||
case Network::GetAddrInfoError::SERVICE:
|
||||
return Network::Errno::E_INVAL;
|
||||
return Errno::SUCCESS;
|
||||
case GetAddrInfoError::AGAIN:
|
||||
return Errno::SUCCESS;
|
||||
case GetAddrInfoError::NODATA:
|
||||
return Errno::SUCCESS;
|
||||
case GetAddrInfoError::SERVICE:
|
||||
return Errno::INVAL;
|
||||
default:
|
||||
return Network::Errno::E_SUCCESS;
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +155,9 @@ static void AppendNulTerminated(std::vector<u8>& vec, std::string_view str) {
|
||||
// host's gethostbyname, because it simplifies portability: e.g., getaddrinfo
|
||||
// behaves the same on Unix and Windows, unlike gethostbyname where Windows
|
||||
// doesn't implement h_errno.
|
||||
static std::vector<u8> SerializeAddrInfoAsHostEnt(std::span<const Network::AddrInfo> vec, std::string_view host) {
|
||||
static std::vector<u8> SerializeAddrInfoAsHostEnt(const std::vector<Network::AddrInfo>& vec,
|
||||
std::string_view host) {
|
||||
|
||||
std::vector<u8> data;
|
||||
// h_name: use the input hostname (append nul-terminated)
|
||||
AppendNulTerminated(data, host);
|
||||
@@ -163,12 +165,12 @@ static std::vector<u8> SerializeAddrInfoAsHostEnt(std::span<const Network::AddrI
|
||||
|
||||
Append<u32_be>(data, 0); // count of h_aliases
|
||||
// (If the count were nonzero, the aliases would be appended as nul-terminated here.)
|
||||
Append<u16_be>(data, u16(Network::Domain::INET)); // h_addrtype
|
||||
Append<u16_be>(data, static_cast<u16>(Domain::INET)); // h_addrtype
|
||||
Append<u16_be>(data, sizeof(Network::IPv4Address)); // h_length
|
||||
// h_addr_list:
|
||||
size_t count = vec.size();
|
||||
ASSERT(count <= UINT32_MAX);
|
||||
Append<u32_be>(data, u32(count));
|
||||
Append<u32_be>(data, static_cast<uint32_t>(count));
|
||||
for (const Network::AddrInfo& addrinfo : vec) {
|
||||
// On the Switch, this is passed through htonl despite already being
|
||||
// big-endian, so it ends up as little-endian.
|
||||
@@ -180,7 +182,7 @@ static std::vector<u8> SerializeAddrInfoAsHostEnt(std::span<const Network::AddrI
|
||||
return data;
|
||||
}
|
||||
|
||||
static std::pair<u32, Network::GetAddrInfoError> GetHostByNameRequestImpl(HLERequestContext& ctx) {
|
||||
static std::pair<u32, GetAddrInfoError> GetHostByNameRequestImpl(HLERequestContext& ctx) {
|
||||
struct InputParameters {
|
||||
u8 use_nsd_resolve;
|
||||
u32 cancel_handle;
|
||||
@@ -203,7 +205,7 @@ static std::pair<u32, Network::GetAddrInfoError> GetHostByNameRequestImpl(HLEReq
|
||||
// Prevent resolution of Nintendo servers
|
||||
if (IsBlockedHost(host)) {
|
||||
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
|
||||
return {0, Network::GetAddrInfoError::AGAIN};
|
||||
return {0, GetAddrInfoError::AGAIN};
|
||||
}
|
||||
|
||||
auto res_v = Network::GetAddressInfo(host, /*service*/ std::nullopt);
|
||||
@@ -211,10 +213,10 @@ static std::pair<u32, Network::GetAddrInfoError> GetHostByNameRequestImpl(HLEReq
|
||||
const std::vector<u8> data = SerializeAddrInfoAsHostEnt(*res, host);
|
||||
const u32 data_size = u32(data.size());
|
||||
ctx.WriteBuffer(data, 0);
|
||||
return {data_size, Network::GetAddrInfoError::SUCCESS};
|
||||
return {data_size, GetAddrInfoError::SUCCESS};
|
||||
}
|
||||
auto* err = std::get_if<Network::GetAddrInfoError>(&res_v);
|
||||
return {0, *err};
|
||||
return {0, Translate(*err)};
|
||||
}
|
||||
|
||||
void SFDNSRES::GetHostByNameRequest(HLERequestContext& ctx) {
|
||||
@@ -222,7 +224,7 @@ void SFDNSRES::GetHostByNameRequest(HLERequestContext& ctx) {
|
||||
|
||||
struct OutputParameters {
|
||||
NetDbError netdb_error;
|
||||
Network::Errno bsd_errno;
|
||||
Errno bsd_errno;
|
||||
u32 data_size;
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 0xc);
|
||||
@@ -242,7 +244,7 @@ void SFDNSRES::GetHostByNameRequestWithOptions(HLERequestContext& ctx) {
|
||||
struct OutputParameters {
|
||||
u32 data_size;
|
||||
NetDbError netdb_error;
|
||||
Network::Errno bsd_errno;
|
||||
Errno bsd_errno;
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 0xc);
|
||||
|
||||
@@ -255,23 +257,24 @@ void SFDNSRES::GetHostByNameRequestWithOptions(HLERequestContext& ctx) {
|
||||
});
|
||||
}
|
||||
|
||||
static std::vector<u8> SerializeAddrInfo(std::span<const Network::AddrInfo> vec, std::string_view host) {
|
||||
static std::vector<u8> SerializeAddrInfo(const std::vector<Network::AddrInfo>& vec,
|
||||
std::string_view host) {
|
||||
// Adapted from
|
||||
// https://github.com/switchbrew/libnx/blob/c5a9a909a91657a9818a3b7e18c9b91ff0cbb6e3/nx/source/runtime/resolver.c#L190
|
||||
std::vector<u8> data;
|
||||
|
||||
for (const Network::AddrInfo& addrinfo : vec) {
|
||||
// serialized addrinfo:
|
||||
Append<u32_be>(data, 0xBEEFCAFE); // magic
|
||||
Append<u32_be>(data, 0); // ai_flags
|
||||
Append<u32_be>(data, u32(addrinfo.family)); // ai_family
|
||||
Append<u32_be>(data, u32(addrinfo.socket_type)); // ai_socktype
|
||||
Append<u32_be>(data, u32(addrinfo.protocol)); // ai_protocol
|
||||
Append<u32_be>(data, 0xBEEFCAFE); // magic
|
||||
Append<u32_be>(data, 0); // ai_flags
|
||||
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.family))); // ai_family
|
||||
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.socket_type))); // ai_socktype
|
||||
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.protocol))); // ai_protocol
|
||||
Append<u32_be>(data, 16); // ai_addrlen
|
||||
// ^ *not* sizeof(SerializedSockAddrIn), not that it matters since they're the same size
|
||||
|
||||
// ai_addr:
|
||||
Append<u16_be>(data, u16(addrinfo.addr.family)); // sin_family
|
||||
Append<u16_be>(data, static_cast<u16>(Translate(addrinfo.addr.family))); // sin_family
|
||||
// On the Switch, the following fields are passed through htonl despite
|
||||
// already being big-endian, so they end up as little-endian.
|
||||
Append<u16_le>(data, addrinfo.addr.portno); // sin_port
|
||||
@@ -293,7 +296,7 @@ static std::vector<u8> SerializeAddrInfo(std::span<const Network::AddrInfo> vec,
|
||||
return data;
|
||||
}
|
||||
|
||||
static std::pair<u32, Network::GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext& ctx) {
|
||||
static std::pair<u32, GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext& ctx) {
|
||||
struct InputParameters {
|
||||
u8 use_nsd_resolve;
|
||||
u32 cancel_handle;
|
||||
@@ -318,7 +321,7 @@ static std::pair<u32, Network::GetAddrInfoError> GetAddrInfoRequestImpl(HLEReque
|
||||
// Prevent resolution of Nintendo servers
|
||||
if (IsBlockedHost(host)) {
|
||||
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
|
||||
return {0, Network::GetAddrInfoError::AGAIN};
|
||||
return {0, GetAddrInfoError::AGAIN};
|
||||
}
|
||||
|
||||
std::optional<std::string> service = std::nullopt;
|
||||
@@ -328,23 +331,24 @@ static std::pair<u32, Network::GetAddrInfoError> GetAddrInfoRequestImpl(HLEReque
|
||||
}
|
||||
|
||||
// Serialized hints are also passed in a buffer, but are ignored for now.
|
||||
|
||||
auto res_v = Network::GetAddressInfo(host, service);
|
||||
if (auto* res = std::get_if<std::vector<Network::AddrInfo>>(&res_v)) {
|
||||
const std::vector<u8> data = SerializeAddrInfo(*res, host);
|
||||
const u32 data_size = u32(data.size());
|
||||
ctx.WriteBuffer(data, 0);
|
||||
return {data_size, Network::GetAddrInfoError::SUCCESS};
|
||||
return {data_size, GetAddrInfoError::SUCCESS};
|
||||
}
|
||||
auto* err = std::get_if<Network::GetAddrInfoError>(&res_v);
|
||||
return {0, *err};
|
||||
return {0, Translate(*err)};
|
||||
}
|
||||
|
||||
void SFDNSRES::GetAddrInfoRequest(HLERequestContext& ctx) {
|
||||
auto [data_size, emu_gai_err] = GetAddrInfoRequestImpl(ctx);
|
||||
|
||||
struct OutputParameters {
|
||||
Network::Errno bsd_errno;
|
||||
Network::GetAddrInfoError gai_error;
|
||||
Errno bsd_errno;
|
||||
GetAddrInfoError gai_error;
|
||||
u32 data_size;
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 0xc);
|
||||
@@ -360,7 +364,7 @@ void SFDNSRES::GetAddrInfoRequest(HLERequestContext& ctx) {
|
||||
|
||||
void SFDNSRES::GetGaiStringErrorRequest(HLERequestContext& ctx) {
|
||||
struct InputParameters {
|
||||
Network::GetAddrInfoError gai_errno;
|
||||
GetAddrInfoError gai_errno;
|
||||
};
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto input = rp.PopRaw<InputParameters>();
|
||||
@@ -378,9 +382,9 @@ void SFDNSRES::GetAddrInfoRequestWithOptions(HLERequestContext& ctx) {
|
||||
|
||||
struct OutputParameters {
|
||||
u32 data_size;
|
||||
Network::GetAddrInfoError gai_error;
|
||||
GetAddrInfoError gai_error;
|
||||
NetDbError netdb_error;
|
||||
Network::Errno bsd_errno;
|
||||
Errno bsd_errno;
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 0x10);
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
@@ -16,6 +15,242 @@ class System;
|
||||
|
||||
namespace Service::Sockets {
|
||||
|
||||
enum class Errno : u32 {
|
||||
SUCCESS = 0,
|
||||
BADF = 9,
|
||||
AGAIN = 11,
|
||||
INVAL = 22,
|
||||
MFILE = 24,
|
||||
PIPE = 32,
|
||||
MSGSIZE = 90,
|
||||
CONNABORTED = 103,
|
||||
CONNRESET = 104,
|
||||
NOTCONN = 107,
|
||||
TIMEDOUT = 110,
|
||||
CONNREFUSED = 111,
|
||||
INPROGRESS = 115,
|
||||
ISCONN = 106,
|
||||
};
|
||||
|
||||
enum class GetAddrInfoError : s32 {
|
||||
SUCCESS = 0,
|
||||
ADDRFAMILY = 1,
|
||||
AGAIN = 2,
|
||||
BADFLAGS = 3,
|
||||
FAIL = 4,
|
||||
FAMILY = 5,
|
||||
MEMORY = 6,
|
||||
NODATA = 7,
|
||||
NONAME = 8,
|
||||
SERVICE = 9,
|
||||
SOCKTYPE = 10,
|
||||
SYSTEM = 11,
|
||||
BADHINTS = 12,
|
||||
PROTOCOL = 13,
|
||||
OVERFLOW_ = 14, // avoid name collision with Windows macro
|
||||
OTHER = 15,
|
||||
};
|
||||
|
||||
enum class Domain : u32 {
|
||||
Unspecified = 0,
|
||||
INET = 2,
|
||||
};
|
||||
|
||||
enum class Type : u32 {
|
||||
Unspecified = 0,
|
||||
STREAM = 1,
|
||||
DGRAM = 2,
|
||||
RAW = 3,
|
||||
SEQPACKET = 5,
|
||||
};
|
||||
|
||||
enum class Protocol : u32 {
|
||||
IP = 0,
|
||||
ICMP = 1,
|
||||
TCP = 6,
|
||||
UDP = 17,
|
||||
//
|
||||
IPV6 = 41,
|
||||
RAW = 255,
|
||||
//
|
||||
HOPOPTS = 0,
|
||||
IGMP = 2,
|
||||
GGP = 3,
|
||||
IPV4 = 4,
|
||||
ST = 7,
|
||||
EGP = 8,
|
||||
PIGP = 9,
|
||||
RCCMON = 10,
|
||||
NVPII = 11,
|
||||
PUP = 12,
|
||||
ARGUS = 13,
|
||||
EMCON = 14,
|
||||
XNET = 15,
|
||||
CHAOS = 16,
|
||||
MUX = 18,
|
||||
MEAS = 19,
|
||||
HMP = 20,
|
||||
PRM = 21,
|
||||
IDP = 22,
|
||||
TRUNK1 = 23,
|
||||
TRUNK2 = 24,
|
||||
LEAF1 = 25,
|
||||
LEAF2 = 26,
|
||||
RDP = 27,
|
||||
IRTP = 28,
|
||||
TP = 29,
|
||||
BLT = 30,
|
||||
NSP = 31,
|
||||
INP = 32,
|
||||
DCCP = 33,
|
||||
//3PC = 34,
|
||||
IDPR = 35,
|
||||
XTP = 36,
|
||||
DDP = 37,
|
||||
CMTP = 38,
|
||||
TPXX = 39,
|
||||
IL = 40,
|
||||
SDRP = 42,
|
||||
ROUTING = 43,
|
||||
FRAGMENT = 44,
|
||||
IDRP = 45,
|
||||
RSVP = 46,
|
||||
GRE = 47,
|
||||
MHRP = 48,
|
||||
BHA = 49,
|
||||
ESP = 50,
|
||||
AH = 51,
|
||||
INLSP = 52,
|
||||
SWIPE = 53,
|
||||
NHRP = 54,
|
||||
MOBILE = 55,
|
||||
TLSP = 56,
|
||||
SKIP = 57,
|
||||
ICMPV6 = 58,
|
||||
NONE = 59,
|
||||
DSTOPTS = 60,
|
||||
AHIP = 61,
|
||||
CFTP = 62,
|
||||
HELLO = 63,
|
||||
SATEXPAK = 64,
|
||||
KRYPTOLAN = 65,
|
||||
RVD = 66,
|
||||
IPPC = 67,
|
||||
ADFS = 68,
|
||||
SATMON = 69,
|
||||
VISA = 70,
|
||||
IPCV = 71,
|
||||
CPNX = 72,
|
||||
CPHB = 73,
|
||||
WSN = 74,
|
||||
PVP = 75,
|
||||
BRSATMON = 76,
|
||||
ND = 77,
|
||||
WBMON = 78,
|
||||
WBEXPAK = 79,
|
||||
EON = 80,
|
||||
VMTP = 81,
|
||||
SVMTP = 82,
|
||||
VINES = 83,
|
||||
TTP = 84,
|
||||
IGP = 85,
|
||||
DGP = 86,
|
||||
TCF = 87,
|
||||
IGRP = 88,
|
||||
OSPFIGP = 89,
|
||||
SRPC = 90,
|
||||
LARP = 91,
|
||||
MTP = 92,
|
||||
AX25 = 93,
|
||||
IPEIP = 94,
|
||||
MICP = 95,
|
||||
SCCSP = 96,
|
||||
ETHERIP = 97,
|
||||
ENCAP = 98,
|
||||
APES = 99,
|
||||
GMTP = 100,
|
||||
IPCOMP = 108,
|
||||
SCTP = 132,
|
||||
MH = 135,
|
||||
UDPLITE = 136,
|
||||
HIP = 139,
|
||||
SHIM6 = 140,
|
||||
PIM = 103,
|
||||
CARP = 112,
|
||||
PGM = 113,
|
||||
MPLS = 137,
|
||||
PFSYNC = 240,
|
||||
};
|
||||
|
||||
enum class SocketLevel : u32 {
|
||||
IP = 0,
|
||||
TCP = 6,
|
||||
SOCKET = 0xffff, // i.e. SOL_SOCKET
|
||||
};
|
||||
|
||||
enum class OptName : u32 {
|
||||
REUSEADDR = 0x4,
|
||||
KEEPALIVE = 0x8,
|
||||
BROADCAST = 0x20,
|
||||
LINGER = 0x80,
|
||||
SNDBUF = 0x1001,
|
||||
RCVBUF = 0x1002,
|
||||
SNDTIMEO = 0x1005,
|
||||
RCVTIMEO = 0x1006,
|
||||
ERROR_ = 0x1007, // avoid name collision with Windows macro
|
||||
NOSIGPIPE = 0x800, // at least according to libnx
|
||||
ACCEPTFILTER = 0x1000,
|
||||
BINTIME = 0x2000,
|
||||
NO_OFFLOAD = 0x4000,
|
||||
NO_DDP = 0x8000,
|
||||
};
|
||||
|
||||
enum class ShutdownHow : s32 {
|
||||
RD = 0,
|
||||
WR = 1,
|
||||
RDWR = 2,
|
||||
};
|
||||
|
||||
enum class FcntlCmd : s32 {
|
||||
GETFL = 3,
|
||||
SETFL = 4,
|
||||
};
|
||||
|
||||
struct SockAddrIn {
|
||||
u8 len;
|
||||
u8 family;
|
||||
u16 portno;
|
||||
std::array<u8, 4> ip;
|
||||
std::array<u8, 248> zeroes;
|
||||
};
|
||||
static_assert(sizeof(SockAddrIn) == 0x100);
|
||||
|
||||
enum class PollEvents : u16 {
|
||||
// Using Pascal case because IN is a macro on Windows.
|
||||
In = 1 << 0,
|
||||
Pri = 1 << 1,
|
||||
Out = 1 << 2,
|
||||
Err = 1 << 3,
|
||||
Hup = 1 << 4,
|
||||
Nval = 1 << 5,
|
||||
RdNorm = 1 << 6,
|
||||
RdBand = 1 << 7,
|
||||
WrBand = 1 << 8,
|
||||
};
|
||||
|
||||
DECLARE_ENUM_FLAG_OPERATORS(PollEvents);
|
||||
|
||||
struct PollFD {
|
||||
s32 fd;
|
||||
PollEvents events;
|
||||
PollEvents revents;
|
||||
};
|
||||
|
||||
struct Linger {
|
||||
u32 onoff;
|
||||
u32 linger;
|
||||
};
|
||||
|
||||
void LoopProcess(Core::System& system);
|
||||
|
||||
} // namespace Service::Sockets
|
||||
|
||||
@@ -15,42 +15,388 @@
|
||||
|
||||
namespace Service::Sockets {
|
||||
|
||||
const char* Translate(Network::GetAddrInfoError error) {
|
||||
// https://android.googlesource.com/platform/bionic/+/085543106/libc/dns/net/getaddrinfo.c#254
|
||||
Errno Translate(Network::Errno value) {
|
||||
switch (value) {
|
||||
case Network::Errno::SUCCESS:
|
||||
return Errno::SUCCESS;
|
||||
case Network::Errno::BADF:
|
||||
return Errno::BADF;
|
||||
case Network::Errno::AGAIN:
|
||||
return Errno::AGAIN;
|
||||
case Network::Errno::INVAL:
|
||||
return Errno::INVAL;
|
||||
case Network::Errno::MFILE:
|
||||
return Errno::MFILE;
|
||||
case Network::Errno::PIPE:
|
||||
return Errno::PIPE;
|
||||
case Network::Errno::CONNREFUSED:
|
||||
return Errno::CONNREFUSED;
|
||||
case Network::Errno::NOTCONN:
|
||||
return Errno::NOTCONN;
|
||||
case Network::Errno::TIMEDOUT:
|
||||
return Errno::TIMEDOUT;
|
||||
case Network::Errno::CONNABORTED:
|
||||
return Errno::CONNABORTED;
|
||||
case Network::Errno::CONNRESET:
|
||||
return Errno::CONNRESET;
|
||||
case Network::Errno::INPROGRESS:
|
||||
return Errno::INPROGRESS;
|
||||
case Network::Errno::ISCONN:
|
||||
return Errno::ISCONN;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented errno={}", value);
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value) {
|
||||
return {value.first, Translate(value.second)};
|
||||
}
|
||||
|
||||
GetAddrInfoError Translate(Network::GetAddrInfoError error) {
|
||||
switch (error) {
|
||||
case Network::GetAddrInfoError::SUCCESS:
|
||||
return "Success";
|
||||
return GetAddrInfoError::SUCCESS;
|
||||
case Network::GetAddrInfoError::ADDRFAMILY:
|
||||
return "Address family for hostname not supported";
|
||||
return GetAddrInfoError::ADDRFAMILY;
|
||||
case Network::GetAddrInfoError::AGAIN:
|
||||
return "Temporary failure in name resolution";
|
||||
return GetAddrInfoError::AGAIN;
|
||||
case Network::GetAddrInfoError::BADFLAGS:
|
||||
return "Invalid value for ai_flags";
|
||||
return GetAddrInfoError::BADFLAGS;
|
||||
case Network::GetAddrInfoError::FAIL:
|
||||
return "Non-recoverable failure in name resolution";
|
||||
return GetAddrInfoError::FAIL;
|
||||
case Network::GetAddrInfoError::FAMILY:
|
||||
return "ai_family not supported";
|
||||
return GetAddrInfoError::FAMILY;
|
||||
case Network::GetAddrInfoError::MEMORY:
|
||||
return "Memory allocation failure";
|
||||
return GetAddrInfoError::MEMORY;
|
||||
case Network::GetAddrInfoError::NODATA:
|
||||
return "No address associated with hostname";
|
||||
return GetAddrInfoError::NODATA;
|
||||
case Network::GetAddrInfoError::NONAME:
|
||||
return "hostname nor servname provided, or not known";
|
||||
return GetAddrInfoError::NONAME;
|
||||
case Network::GetAddrInfoError::SERVICE:
|
||||
return "servname not supported for ai_socktype";
|
||||
return GetAddrInfoError::SERVICE;
|
||||
case Network::GetAddrInfoError::SOCKTYPE:
|
||||
return "ai_socktype not supported";
|
||||
return GetAddrInfoError::SOCKTYPE;
|
||||
case Network::GetAddrInfoError::SYSTEM:
|
||||
return "System error returned in errno";
|
||||
return GetAddrInfoError::SYSTEM;
|
||||
case Network::GetAddrInfoError::BADHINTS:
|
||||
return "Invalid value for hints";
|
||||
return GetAddrInfoError::BADHINTS;
|
||||
case Network::GetAddrInfoError::PROTOCOL:
|
||||
return "Resolved protocol is unknown";
|
||||
return GetAddrInfoError::PROTOCOL;
|
||||
case Network::GetAddrInfoError::OVERFLOW_:
|
||||
return GetAddrInfoError::OVERFLOW_;
|
||||
case Network::GetAddrInfoError::OTHER:
|
||||
return GetAddrInfoError::OTHER;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented GetAddrInfoError={}", error);
|
||||
return GetAddrInfoError::OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
const char* Translate(GetAddrInfoError error) {
|
||||
// https://android.googlesource.com/platform/bionic/+/085543106/libc/dns/net/getaddrinfo.c#254
|
||||
switch (error) {
|
||||
case GetAddrInfoError::SUCCESS:
|
||||
return "Success";
|
||||
case GetAddrInfoError::ADDRFAMILY:
|
||||
return "Address family for hostname not supported";
|
||||
case GetAddrInfoError::AGAIN:
|
||||
return "Temporary failure in name resolution";
|
||||
case GetAddrInfoError::BADFLAGS:
|
||||
return "Invalid value for ai_flags";
|
||||
case GetAddrInfoError::FAIL:
|
||||
return "Non-recoverable failure in name resolution";
|
||||
case GetAddrInfoError::FAMILY:
|
||||
return "ai_family not supported";
|
||||
case GetAddrInfoError::MEMORY:
|
||||
return "Memory allocation failure";
|
||||
case GetAddrInfoError::NODATA:
|
||||
return "No address associated with hostname";
|
||||
case GetAddrInfoError::NONAME:
|
||||
return "hostname nor servname provided, or not known";
|
||||
case GetAddrInfoError::SERVICE:
|
||||
return "servname not supported for ai_socktype";
|
||||
case GetAddrInfoError::SOCKTYPE:
|
||||
return "ai_socktype not supported";
|
||||
case GetAddrInfoError::SYSTEM:
|
||||
return "System error returned in errno";
|
||||
case GetAddrInfoError::BADHINTS:
|
||||
return "Invalid value for hints";
|
||||
case GetAddrInfoError::PROTOCOL:
|
||||
return "Resolved protocol is unknown";
|
||||
case GetAddrInfoError::OVERFLOW_:
|
||||
return "Argument buffer overflow";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
Network::Domain Translate(Domain domain) {
|
||||
switch (domain) {
|
||||
case Domain::Unspecified:
|
||||
return Network::Domain::Unspecified;
|
||||
case Domain::INET:
|
||||
return Network::Domain::INET;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented domain={}", domain);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Domain Translate(Network::Domain domain) {
|
||||
switch (domain) {
|
||||
case Network::Domain::Unspecified:
|
||||
return Domain::Unspecified;
|
||||
case Network::Domain::INET:
|
||||
return Domain::INET;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented domain={}", domain);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Network::Type Translate(Type type) {
|
||||
switch (type) {
|
||||
case Type::Unspecified:
|
||||
return Network::Type::Unspecified;
|
||||
case Type::STREAM:
|
||||
return Network::Type::STREAM;
|
||||
case Type::DGRAM:
|
||||
return Network::Type::DGRAM;
|
||||
case Type::RAW:
|
||||
return Network::Type::RAW;
|
||||
case Type::SEQPACKET:
|
||||
return Network::Type::SEQPACKET;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented type={}", type);
|
||||
return Network::Type{};
|
||||
}
|
||||
}
|
||||
|
||||
Type Translate(Network::Type type) {
|
||||
switch (type) {
|
||||
case Network::Type::Unspecified: return Type::Unspecified;
|
||||
case Network::Type::STREAM: return Type::STREAM;
|
||||
case Network::Type::DGRAM: return Type::DGRAM;
|
||||
case Network::Type::RAW: return Type::RAW;
|
||||
case Network::Type::SEQPACKET: return Type::SEQPACKET;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented type={}", type);
|
||||
return Type{};
|
||||
}
|
||||
}
|
||||
|
||||
#define NETWORK_PROTOCOL_TRANSLATE_LIST \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ICMP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TCP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(UDP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPV6) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(RAW) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IGMP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(GGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPV4) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ST) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(EGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PIGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(RCCMON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(NVPII) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PUP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ARGUS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(EMCON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(XNET) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CHAOS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MUX) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MEAS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(HMP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PRM) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IDP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TRUNK1) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TRUNK2) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(LEAF1) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(LEAF2) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(RDP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IRTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(BLT) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(NSP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(INP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(DCCP) \
|
||||
/*NETWORK_PROTOCOL_TRANSLATE_ELEM(3PC)*/ \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IDPR) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(XTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(DDP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CMTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TPXX) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IL) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SDRP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ROUTING) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(FRAGMENT) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IDRP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(RSVP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(GRE) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MHRP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(BHA) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ESP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(AH) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(INLSP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SWIPE) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(NHRP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MOBILE) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TLSP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SKIP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ICMPV6) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(NONE) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(DSTOPTS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(AHIP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CFTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(HELLO) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SATEXPAK) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(KRYPTOLAN) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(RVD) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPPC) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ADFS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SATMON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(VISA) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPCV) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CPNX) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CPHB) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(WSN) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PVP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(BRSATMON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ND) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(WBMON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(WBEXPAK) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(EON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(VMTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SVMTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(VINES) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(DGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TCF) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IGRP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(OSPFIGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SRPC) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(LARP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(AX25) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPEIP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MICP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SCCSP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ETHERIP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ENCAP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(APES) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(GMTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPCOMP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SCTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MH) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(UDPLITE) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(HIP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SHIM6) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PIM) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CARP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PGM) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MPLS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PFSYNC)
|
||||
[[nodiscard]] Network::Protocol Translate(Protocol protocol) {
|
||||
switch (protocol) {
|
||||
#define NETWORK_PROTOCOL_TRANSLATE_ELEM(name) case Protocol::name: return Network::Protocol::name;
|
||||
NETWORK_PROTOCOL_TRANSLATE_LIST
|
||||
#undef NETWORK_PROTOCOL_TRANSLATE_ELEM
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
[[nodiscard]] Protocol Translate(Network::Protocol protocol) {
|
||||
switch (protocol) {
|
||||
#define NETWORK_PROTOCOL_TRANSLATE_ELEM(name) case Network::Protocol::name: return Protocol::name;
|
||||
NETWORK_PROTOCOL_TRANSLATE_LIST
|
||||
#undef NETWORK_PROTOCOL_TRANSLATE_ELEM
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
#undef NETWORK_PROTOCOL_TRANSLATE_LIST
|
||||
|
||||
Network::PollEvents Translate(PollEvents flags) {
|
||||
Network::PollEvents result{};
|
||||
const auto translate = [&result, &flags](PollEvents from, Network::PollEvents to) {
|
||||
if (True(flags & from)) {
|
||||
flags &= ~from;
|
||||
result |= to;
|
||||
}
|
||||
};
|
||||
translate(PollEvents::In, Network::PollEvents::In);
|
||||
translate(PollEvents::Pri, Network::PollEvents::Pri);
|
||||
translate(PollEvents::Out, Network::PollEvents::Out);
|
||||
translate(PollEvents::Err, Network::PollEvents::Err);
|
||||
translate(PollEvents::Hup, Network::PollEvents::Hup);
|
||||
translate(PollEvents::Nval, Network::PollEvents::Nval);
|
||||
translate(PollEvents::RdNorm, Network::PollEvents::RdNorm);
|
||||
translate(PollEvents::RdBand, Network::PollEvents::RdBand);
|
||||
translate(PollEvents::WrBand, Network::PollEvents::WrBand);
|
||||
|
||||
UNIMPLEMENTED_IF_MSG((u16)flags != 0, "Unimplemented flags={}", (u16)flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
PollEvents Translate(Network::PollEvents flags) {
|
||||
PollEvents result{};
|
||||
const auto translate = [&result, &flags](Network::PollEvents from, PollEvents to) {
|
||||
if (True(flags & from)) {
|
||||
flags &= ~from;
|
||||
result |= to;
|
||||
}
|
||||
};
|
||||
|
||||
translate(Network::PollEvents::In, PollEvents::In);
|
||||
translate(Network::PollEvents::Pri, PollEvents::Pri);
|
||||
translate(Network::PollEvents::Out, PollEvents::Out);
|
||||
translate(Network::PollEvents::Err, PollEvents::Err);
|
||||
translate(Network::PollEvents::Hup, PollEvents::Hup);
|
||||
translate(Network::PollEvents::Nval, PollEvents::Nval);
|
||||
translate(Network::PollEvents::RdNorm, PollEvents::RdNorm);
|
||||
translate(Network::PollEvents::RdBand, PollEvents::RdBand);
|
||||
translate(Network::PollEvents::WrBand, PollEvents::WrBand);
|
||||
|
||||
UNIMPLEMENTED_IF_MSG((u16)flags != 0, "Unimplemented flags={}", (u16)flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
Network::SockAddrIn Translate(SockAddrIn value) {
|
||||
// All lengths are valid, from [0 upto 256]
|
||||
return {
|
||||
.family = Translate(Domain(value.family)),
|
||||
.ip = value.ip,
|
||||
.portno = static_cast<u16>(value.portno >> 8 | value.portno << 8),
|
||||
};
|
||||
}
|
||||
|
||||
SockAddrIn Translate(Network::SockAddrIn value) {
|
||||
return {
|
||||
.len = 16,
|
||||
.family = static_cast<u8>(Translate(value.family)),
|
||||
.portno = static_cast<u16>(value.portno >> 8 | value.portno << 8),
|
||||
.ip = value.ip,
|
||||
.zeroes = {},
|
||||
};
|
||||
}
|
||||
|
||||
Network::ShutdownHow Translate(ShutdownHow how) {
|
||||
switch (how) {
|
||||
case ShutdownHow::RD:
|
||||
return Network::ShutdownHow::RD;
|
||||
case ShutdownHow::WR:
|
||||
return Network::ShutdownHow::WR;
|
||||
case ShutdownHow::RDWR:
|
||||
return Network::ShutdownHow::RDWR;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented how={}", how);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::Sockets
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -14,7 +11,49 @@
|
||||
|
||||
namespace Service::Sockets {
|
||||
|
||||
/// Translate abstract errno to guest errno
|
||||
Errno Translate(Network::Errno value);
|
||||
|
||||
/// Translate abstract return value errno pair to guest return value errno pair
|
||||
std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value);
|
||||
|
||||
/// Translate abstract getaddrinfo error to guest getaddrinfo error
|
||||
GetAddrInfoError Translate(Network::GetAddrInfoError value);
|
||||
|
||||
/// Translate guest error to string
|
||||
const char* Translate(Network::GetAddrInfoError value);
|
||||
const char* Translate(GetAddrInfoError value);
|
||||
|
||||
/// Translate guest domain to abstract domain
|
||||
Network::Domain Translate(Domain domain);
|
||||
|
||||
/// Translate abstract domain to guest domain
|
||||
Domain Translate(Network::Domain domain);
|
||||
|
||||
/// Translate guest type to abstract type
|
||||
Network::Type Translate(Type type);
|
||||
|
||||
/// Translate abstract type to guest type
|
||||
Type Translate(Network::Type type);
|
||||
|
||||
/// Translate guest protocol to abstract protocol
|
||||
Network::Protocol Translate(Protocol protocol);
|
||||
|
||||
/// Translate abstract protocol to guest protocol
|
||||
Protocol Translate(Network::Protocol protocol);
|
||||
|
||||
/// Translate guest poll event flags to abstract poll event flags
|
||||
Network::PollEvents Translate(PollEvents flags);
|
||||
|
||||
/// Translate abstract poll event flags to guest poll event flags
|
||||
PollEvents Translate(Network::PollEvents flags);
|
||||
|
||||
/// Translate guest socket address structure to abstract socket address structure
|
||||
Network::SockAddrIn Translate(SockAddrIn value);
|
||||
|
||||
/// Translate abstract socket address structure to guest socket address structure
|
||||
SockAddrIn Translate(Network::SockAddrIn value);
|
||||
|
||||
/// Translate guest shutdown mode to abstract shutdown mode
|
||||
Network::ShutdownHow Translate(ShutdownHow how);
|
||||
|
||||
} // namespace Service::Sockets
|
||||
|
||||
@@ -138,7 +138,7 @@ public:
|
||||
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD_USA>("bsd:u");
|
||||
if (bsd) {
|
||||
auto err = bsd->CloseImpl(fd);
|
||||
if (err != Network::Errno::E_SUCCESS) {
|
||||
if (err != Service::Sockets::Errno::SUCCESS) {
|
||||
LOG_ERROR(Service_SSL, "Failed to close duplicated socket: {}", err);
|
||||
}
|
||||
}
|
||||
@@ -230,7 +230,7 @@ private:
|
||||
R_UNLESS(socket, ResultNoSocket);
|
||||
const bool non_block = mode == IoMode::NonBlocking;
|
||||
const Network::Errno error = socket->SetNonBlock(non_block);
|
||||
if (error != Network::Errno::E_SUCCESS) {
|
||||
if (error != Network::Errno::SUCCESS) {
|
||||
LOG_ERROR(Service_SSL, "Failed to set native socket non-block flag to {}", non_block);
|
||||
}
|
||||
R_SUCCEED();
|
||||
|
||||
@@ -327,10 +327,10 @@ public:
|
||||
BIO_clear_retry_flags(bio);
|
||||
auto [actual, err] = self->socket->Send({reinterpret_cast<const u8*>(buf), len}, 0);
|
||||
switch (err) {
|
||||
case Network::Errno::E_SUCCESS:
|
||||
case Network::Errno::SUCCESS:
|
||||
*actual_p = actual;
|
||||
return 1;
|
||||
case Network::Errno::E_AGAIN:
|
||||
case Network::Errno::AGAIN:
|
||||
BIO_set_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY);
|
||||
return 0;
|
||||
default:
|
||||
@@ -346,13 +346,13 @@ public:
|
||||
BIO_clear_retry_flags(bio);
|
||||
auto [actual, err] = self->socket->Recv(0, {reinterpret_cast<u8*>(buf), len});
|
||||
switch (err) {
|
||||
case Network::Errno::E_SUCCESS:
|
||||
case Network::Errno::SUCCESS:
|
||||
*actual_p = actual;
|
||||
if (actual == 0) {
|
||||
self->got_read_eof = true;
|
||||
}
|
||||
return actual ? 1 : 0;
|
||||
case Network::Errno::E_AGAIN:
|
||||
case Network::Errno::AGAIN:
|
||||
BIO_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY);
|
||||
return 0;
|
||||
default:
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <common/socket_types.h>
|
||||
#include <mutex>
|
||||
#include "core/internal_network/socket_types.h"
|
||||
|
||||
namespace Network {
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "common/socket_types.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
@@ -31,10 +31,68 @@ namespace Network {
|
||||
class SocketBase;
|
||||
class Socket;
|
||||
|
||||
struct HostPollFD {
|
||||
SocketBase* socket = nullptr;
|
||||
Network::PollEvents events = {};
|
||||
Network::PollEvents revents = {};
|
||||
/// Error code for network functions
|
||||
enum class Errno {
|
||||
SUCCESS,
|
||||
BADF,
|
||||
INVAL,
|
||||
MFILE,
|
||||
PIPE,
|
||||
NOTCONN,
|
||||
AGAIN,
|
||||
CONNREFUSED,
|
||||
CONNRESET,
|
||||
CONNABORTED,
|
||||
HOSTUNREACH,
|
||||
NETDOWN,
|
||||
NETUNREACH,
|
||||
TIMEDOUT,
|
||||
MSGSIZE,
|
||||
INPROGRESS,
|
||||
ISCONN,
|
||||
OTHER,
|
||||
};
|
||||
|
||||
enum class GetAddrInfoError {
|
||||
SUCCESS,
|
||||
ADDRFAMILY,
|
||||
AGAIN,
|
||||
BADFLAGS,
|
||||
FAIL,
|
||||
FAMILY,
|
||||
MEMORY,
|
||||
NODATA,
|
||||
NONAME,
|
||||
SERVICE,
|
||||
SOCKTYPE,
|
||||
SYSTEM,
|
||||
BADHINTS,
|
||||
PROTOCOL,
|
||||
OVERFLOW_,
|
||||
OTHER,
|
||||
};
|
||||
|
||||
/// Cross-platform poll fd structure
|
||||
|
||||
enum class PollEvents : u16 {
|
||||
// Using Pascal case because IN is a macro on Windows.
|
||||
In = 1 << 0,
|
||||
Pri = 1 << 1,
|
||||
Out = 1 << 2,
|
||||
Err = 1 << 3,
|
||||
Hup = 1 << 4,
|
||||
Nval = 1 << 5,
|
||||
RdNorm = 1 << 6,
|
||||
RdBand = 1 << 7,
|
||||
WrBand = 1 << 8,
|
||||
};
|
||||
|
||||
DECLARE_ENUM_FLAG_OPERATORS(PollEvents);
|
||||
|
||||
struct PollFD {
|
||||
SocketBase* socket;
|
||||
PollEvents events;
|
||||
PollEvents revents;
|
||||
};
|
||||
|
||||
class NetworkInstance {
|
||||
@@ -43,10 +101,6 @@ public:
|
||||
~NetworkInstance();
|
||||
};
|
||||
|
||||
sockaddr_in TranslateFromSockAddrIn(Network::SockAddrIn input);
|
||||
Network::SockAddrIn TranslateToSockAddrIn(sockaddr_in input);
|
||||
s32 TranslateMsgOptToNative(s32 flags);
|
||||
|
||||
void CancelPendingSocketOperations();
|
||||
void RestartSocketOperations();
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace Network {
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
|
||||
ULONG buf_size = 0;
|
||||
if (GetAdaptersAddresses(
|
||||
@@ -66,7 +66,7 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<NetworkInterface> result;
|
||||
std::vector<Network::NetworkInterface> result;
|
||||
|
||||
for (auto* a = addrs; a; a = a->Next) {
|
||||
|
||||
@@ -89,7 +89,7 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
gw = reinterpret_cast<sockaddr_in*>(a->FirstGatewayAddress->Address.lpSockaddr)
|
||||
->sin_addr;
|
||||
|
||||
result.emplace_back(NetworkInterface{
|
||||
result.emplace_back(Network::NetworkInterface{
|
||||
.name = Common::UTF16ToUTF8(std::wstring{a->FriendlyName}),
|
||||
.ip_address = ip,
|
||||
.subnet_mask = mask,
|
||||
@@ -103,7 +103,7 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
|
||||
#else
|
||||
|
||||
std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
#if defined(__ANDROID__) || defined(__linux__)
|
||||
struct ifaddrs* ifaddr = nullptr;
|
||||
if (getifaddrs(&ifaddr) != 0) {
|
||||
@@ -135,7 +135,7 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
LOG_WARNING(Network, "\"/proc/net/route\" not found - using gateway 0");
|
||||
}
|
||||
#endif
|
||||
std::vector<NetworkInterface> ifaces;
|
||||
std::vector<Network::NetworkInterface> ifaces;
|
||||
for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
|
||||
if (ifa->ifa_addr == nullptr || ifa->ifa_netmask == nullptr /* Have a netmask and address */
|
||||
|| ifa->ifa_addr->sa_family != AF_INET /* Must be of kind AF_INET */
|
||||
@@ -149,7 +149,7 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
});
|
||||
in_addr gw; // Solaris defines s_addr as a macro, can't use special C++ shenanigans here
|
||||
gw.s_addr = it != routes.end() ? it->gateway : 0;
|
||||
ifaces.emplace_back(NetworkInterface{
|
||||
ifaces.emplace_back(Network::NetworkInterface{
|
||||
.name = ifa->ifa_name,
|
||||
.ip_address = std::bit_cast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr,
|
||||
.subnet_mask = std::bit_cast<struct sockaddr_in>(*ifa->ifa_netmask).sin_addr,
|
||||
@@ -159,7 +159,7 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
freeifaddrs(ifaddr);
|
||||
return ifaces;
|
||||
#elif defined(__FreeBSD__)
|
||||
std::vector<NetworkInterface> ifaces;
|
||||
std::vector<Network::NetworkInterface> ifaces;
|
||||
int fd = ::socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
|
||||
if (fd < 0) {
|
||||
LOG_ERROR(Network, "socket: {}", std::strerror(errno));
|
||||
@@ -191,7 +191,7 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
size_t msglen = rtm->rtm_msglen - sizeof(*ifm);
|
||||
char const* p = (char const*)(ifm + 1);
|
||||
|
||||
NetworkInterface iface{};
|
||||
Network::NetworkInterface iface{};
|
||||
for (size_t i = 0; i < RTAX_MAX; i++)
|
||||
if ((ifm->ifm_addrs & (1 << i)) != 0) {
|
||||
struct sockaddr const* sa = reinterpret_cast<struct sockaddr const*>(p);
|
||||
@@ -220,7 +220,7 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
std::optional<NetworkInterface> GetSelectedNetworkInterface() {
|
||||
std::optional<Network::NetworkInterface> GetSelectedNetworkInterface() {
|
||||
auto const& sel_if = Settings::values.network_interface.GetValue();
|
||||
if (auto const ifaces = Network::GetAvailableNetworkInterfaces(); ifaces.size() > 0) {
|
||||
if (sel_if.empty())
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user