diff --git a/core/libs/CMakeLists.txt b/core/libs/CMakeLists.txt index 686be48ce..51aa2d888 100644 --- a/core/libs/CMakeLists.txt +++ b/core/libs/CMakeLists.txt @@ -104,6 +104,15 @@ endforeach() add_custom_target(libs DEPENDS ${PATCHED_OUTPUTS}) if(BUILD_TESTING) + add_executable(guest_address_tests tests/GuestAddressConversion.cpp) + target_include_directories(guest_address_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + target_link_libraries(guest_address_tests PRIVATE libkernel libc) + configure_windows_unwind(guest_address_tests) + add_test(NAME guest_addresses COMMAND guest_address_tests) + if(WIN32) + set_tests_properties(guest_addresses PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() add_executable(guest_error_tests tests/GuestErrors.cpp) target_include_directories(guest_error_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(guest_error_tests PRIVATE libc) diff --git a/core/libs/prx/libkernel/CMakeLists.txt b/core/libs/prx/libkernel/CMakeLists.txt index 598cca734..6467aebce 100644 --- a/core/libs/prx/libkernel/CMakeLists.txt +++ b/core/libs/prx/libkernel/CMakeLists.txt @@ -25,6 +25,7 @@ add_library(libkernel SHARED EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/Pthread/Posix/Tsd.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Pthread/Posix/Sem.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Socket/src/Socket.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Socket/src/AddressConversion.cpp ${CMAKE_CURRENT_SOURCE_DIR}/EventFlag/src/EventFlag.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Module/src/Module.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Aio/src/Aio.cpp @@ -41,6 +42,7 @@ add_library(libkernel SHARED EXCLUDE_FROM_ALL target_include_directories(libkernel PRIVATE ${LIBS_INCLUDE_DIR}) target_link_libraries(libkernel PRIVATE libc) if(WIN32) + target_link_libraries(libkernel PRIVATE ws2_32) target_compile_definitions(libkernel PRIVATE _WIN32_WINNT=0x0602) endif() configure_windows_unwind(libkernel) diff --git a/core/libs/prx/libkernel/Socket/src/AddressConversion.cpp b/core/libs/prx/libkernel/Socket/src/AddressConversion.cpp new file mode 100644 index 000000000..b10fb9633 --- /dev/null +++ b/core/libs/prx/libkernel/Socket/src/AddressConversion.cpp @@ -0,0 +1,47 @@ +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#else +#include +#endif +#include "prx/libc/include/general/VabiMacros.hpp" +#include +#include + +extern "C" int* APS5_VABI __error_nid_postfix(); + +extern "C" { +int APS5_VABI __inet_pton_nid_postfix(int family, const char* text, void* destination) { + if (family != 2 && family != 28) { *__error_nid_postfix() = 47; return -1; } + if (!text || !destination) { *__error_nid_postfix() = 14; return -1; } + unsigned char address[16]{}; + const int nativeFamily = family == 2 ? AF_INET : AF_INET6; +#ifdef _WIN32 + const int result = InetPtonA(nativeFamily, text, address); +#else + const int result = ::inet_pton(nativeFamily, text, address); +#endif + if (result == 1) std::memcpy(destination, address, family == 2 ? 4 : 16); + else if (result == -1) *__error_nid_postfix() = 22; + return result; +} + +const char* APS5_VABI __inet_ntop_nid_postfix(int family, const void* source, + char* destination, std::uint32_t capacity) { + if (family != 2 && family != 28) { *__error_nid_postfix() = 47; return nullptr; } + if (!source || !destination) { *__error_nid_postfix() = 14; return nullptr; } + char text[INET6_ADDRSTRLEN]{}; + const int nativeFamily = family == 2 ? AF_INET : AF_INET6; +#ifdef _WIN32 + const auto* result = InetNtopA(nativeFamily, const_cast(source), text, sizeof(text)); +#else + const auto* result = ::inet_ntop(nativeFamily, source, text, sizeof(text)); +#endif + if (!result) { *__error_nid_postfix() = 22; return nullptr; } + const auto size = std::strlen(text) + 1; + if (size > capacity) { *__error_nid_postfix() = 28; return nullptr; } + std::memcpy(destination, text, size); + return destination; +} +} diff --git a/core/libs/tests/GuestAddressConversion.cpp b/core/libs/tests/GuestAddressConversion.cpp new file mode 100644 index 000000000..458ec1b13 --- /dev/null +++ b/core/libs/tests/GuestAddressConversion.cpp @@ -0,0 +1,34 @@ +#include "prx/libc/include/general/VabiMacros.hpp" +#include +#include +#include +#include + +extern "C" { +int APS5_VABI __inet_pton_nid_postfix(int, const char*, void*); +const char* APS5_VABI __inet_ntop_nid_postfix(int, const void*, char*, std::uint32_t); +int* APS5_VABI __error_nid_postfix(); +} +static void Require(bool value) { if (!value) std::abort(); } +int main() { + for (int family : {2, 28}) { + const char* input = family == 2 ? "192.0.2.17" : "2001:db8::17"; + std::array address{}; + Require(__inet_pton_nid_postfix(family, input, address.data()) == 1); + char output[64]{}; + Require(__inet_ntop_nid_postfix(family, address.data(), output, sizeof(output)) == output); + Require(std::strcmp(input, output) == 0); + output[0] = 'x'; + Require(__inet_ntop_nid_postfix(family, address.data(), output, 1) == nullptr); + Require(*__error_nid_postfix() == 28 && output[0] == 'x'); + const auto original = address; + Require(__inet_pton_nid_postfix(family, "not-an-address", address.data()) == 0); + Require(address == original); + } + std::array address{}; + Require(__inet_pton_nid_postfix(10, "::1", address.data()) == -1); + Require(*__error_nid_postfix() == 47); // Linux AF_INET6 is not PS5 AF_INET6 + Require(__inet_pton_nid_postfix(2, "256.1.2.3", address.data()) == 0); + Require(__inet_pton_nid_postfix(28, "::ffff:192.0.2.17", address.data()) == 1); + Require(address[10] == 255 && address[11] == 255 && address[12] == 192 && address[15] == 17); +}