1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-25 04:02:42 +01:00

rpcn: signaling handler improvements & upnp

Simplify signaling by making Matching2 a layer over normal signaling.
Implements UPNP port forwarding
Implement sceNpMatching2AbortRequest
Fix reported bw in sceNpUtil
Hack for Fat Princess binding udp on 3658
Reenable CB for sceNpBasicAddPlayersHistoryAsync
Misc fixes
This commit is contained in:
RipleyTom 2023-01-12 04:05:05 +01:00 committed by Megamouse
parent 364c33060b
commit 6186ac0245
45 changed files with 1290 additions and 747 deletions

3
.gitignore vendored
View File

@ -122,6 +122,9 @@ yaml-cpp.pc
/3rdparty/libusb_cmake/config.h /3rdparty/libusb_cmake/config.h
/3rdparty/libusb_cmake/libusb-1.0.pc /3rdparty/libusb_cmake/libusb-1.0.pc
# miniupnp
/3rdparty/miniupnp/x64/*
# ssl certificate # ssl certificate
cacert.pem cacert.pem

3
.gitmodules vendored
View File

@ -80,3 +80,6 @@
path = 3rdparty/libsdl-org/SDL path = 3rdparty/libsdl-org/SDL
url = https://github.com/libsdl-org/SDL.git url = https://github.com/libsdl-org/SDL.git
ignore = dirty ignore = dirty
[submodule "3rdparty/miniupnp/miniupnp"]
path = 3rdparty/miniupnp/miniupnp
url = https://github.com/miniupnp/miniupnp.git

View File

@ -358,6 +358,9 @@ if(USE_SDL)
endif() endif()
endif() endif()
# MINIUPNP
add_subdirectory(miniupnp EXCLUDE_FROM_ALL)
# add nice ALIAS targets for ease of use # add nice ALIAS targets for ease of use
if(USE_SYSTEM_LIBUSB) if(USE_SYSTEM_LIBUSB)
add_library(3rdparty::libusb ALIAS usb-1.0-shared) add_library(3rdparty::libusb ALIAS usb-1.0-shared)
@ -385,3 +388,4 @@ add_library(3rdparty::wolfssl ALIAS wolfssl)
add_library(3rdparty::libcurl ALIAS libcurl) add_library(3rdparty::libcurl ALIAS libcurl)
add_library(3rdparty::soundtouch ALIAS soundtouch) add_library(3rdparty::soundtouch ALIAS soundtouch)
add_library(3rdparty::sdl2 ALIAS ${SDL2_TARGET}) add_library(3rdparty::sdl2 ALIAS ${SDL2_TARGET})
add_library(3rdparty::miniupnpc ALIAS libminiupnpc-static)

8
3rdparty/miniupnp/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,8 @@
option (UPNPC_BUILD_STATIC "Build static library" TRUE)
option (UPNPC_BUILD_SHARED "Build shared library" FALSE)
option (UPNPC_BUILD_TESTS "Build test executables" FALSE)
option (UPNPC_BUILD_SAMPLE "Build sample executables" FALSE)
option (NO_GETADDRINFO "Define NO_GETADDRINFO" FALSE)
option (UPNPC_NO_INSTALL "Disable installation" TRUE)
add_subdirectory(miniupnp/miniupnpc EXCLUDE_FROM_ALL)

1
3rdparty/miniupnp/miniupnp vendored Submodule

@ -0,0 +1 @@
Subproject commit f4a739d73083bee207af30b8aa3e668383ee070e

View File

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{5228f863-e0dd-4de7-aa7b-5c52b14cd4d0}</ProjectGuid>
<RootNamespace>miniupnpcstatic</RootNamespace>
</PropertyGroup>
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default_macros.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_WINSOCK_DEPRECATED_NO_WARNINGS; _CRT_SECURE_NO_WARNINGS;MINIUPNP_STATICLIB;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>generated;miniupnp\miniupnpc;miniupnp\miniupnpc\include</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
</Link>
<PreBuildEvent>
<Command>cd $(ProjectDir)miniupnp\miniupnpc\msvc
cscript genminiupnpcstrings.vbs</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_WINSOCK_DEPRECATED_NO_WARNINGS; _CRT_SECURE_NO_WARNINGS;MINIUPNP_STATICLIB;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>generated;miniupnp\miniupnpc;miniupnp\miniupnpc\include</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>
</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PreBuildEvent>
<Command>cd $(ProjectDir)miniupnp\miniupnpc\msvc
cscript genminiupnpcstrings.vbs</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="miniupnp\miniupnpc\src\addr_is_reserved.c" />
<ClCompile Include="miniupnp\miniupnpc\src\connecthostport.c" />
<ClCompile Include="miniupnp\miniupnpc\src\igd_desc_parse.c" />
<ClCompile Include="miniupnp\miniupnpc\src\minisoap.c" />
<ClCompile Include="miniupnp\miniupnpc\src\minissdpc.c" />
<ClCompile Include="miniupnp\miniupnpc\src\miniupnpc.c" />
<ClCompile Include="miniupnp\miniupnpc\src\miniwget.c" />
<ClCompile Include="miniupnp\miniupnpc\src\minixml.c" />
<ClCompile Include="miniupnp\miniupnpc\src\portlistingparse.c" />
<ClCompile Include="miniupnp\miniupnpc\src\receivedata.c" />
<ClCompile Include="miniupnp\miniupnpc\src\upnpcommands.c" />
<ClCompile Include="miniupnp\miniupnpc\src\upnpdev.c" />
<ClCompile Include="miniupnp\miniupnpc\src\upnperrors.c" />
<ClCompile Include="miniupnp\miniupnpc\src\upnpreplyparse.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="miniupnp\miniupnpc\src\addr_is_reserved.h" />
<ClInclude Include="miniupnp\miniupnpc\src\connecthostport.h" />
<ClInclude Include="miniupnp\miniupnpc\include\igd_desc_parse.h" />
<ClInclude Include="miniupnp\miniupnpc\src\minisoap.h" />
<ClInclude Include="miniupnp\miniupnpc\src\minissdpc.h" />
<ClInclude Include="miniupnp\miniupnpc\include\miniupnpc.h" />
<ClInclude Include="miniupnp\miniupnpc\miniupnpcstrings.h" />
<ClInclude Include="miniupnp\miniupnpc\include\miniupnpctypes.h" />
<ClInclude Include="miniupnp\miniupnpc\include\miniupnpc_declspec.h" />
<ClInclude Include="miniupnp\miniupnpc\include\miniwget.h" />
<ClInclude Include="miniupnp\miniupnpc\src\miniwget_private.h" />
<ClInclude Include="miniupnp\miniupnpc\src\minixml.h" />
<ClInclude Include="miniupnp\miniupnpc\include\portlistingparse.h" />
<ClInclude Include="miniupnp\miniupnpc\src\receivedata.h" />
<ClInclude Include="miniupnp\miniupnpc\include\upnpcommands.h" />
<ClInclude Include="miniupnp\miniupnpc\include\upnpdev.h" />
<ClInclude Include="miniupnp\miniupnpc\include\upnperrors.h" />
<ClInclude Include="miniupnp\miniupnpc\include\upnpreplyparse.h" />
<ClInclude Include="miniupnp\miniupnpc\src\win32_snprintf.h" />
<ClInclude Include="miniupnp\miniupnpc\rc_version.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -74,7 +74,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcurl", "3rdparty\curl\li
{73973223-5EE8-41CA-8E88-1D60E89A237B} = {73973223-5EE8-41CA-8E88-1D60E89A237B} {73973223-5EE8-41CA-8E88-1D60E89A237B} = {73973223-5EE8-41CA-8E88-1D60E89A237B}
EndProjectSection EndProjectSection
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPIRV", "3rdparty\SPIRV\spirv.vcxproj", "{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spirv", "3rdparty\SPIRV\spirv.vcxproj", "{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rdParty", "3rdParty", "{6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rdParty", "3rdParty", "{6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}"
EndProject EndProject
@ -93,6 +93,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "pine", "pine", "{A55DA1B5-C
3rdparty\pine\pine_server.h = 3rdparty\pine\pine_server.h 3rdparty\pine\pine_server.h = 3rdparty\pine\pine_server.h
EndProjectSection EndProjectSection
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniupnpc_static", "3rdparty\miniupnp\miniupnpc_static.vcxproj", "{5228F863-E0DD-4DE7-AA7B-5C52B14CD4D0}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64 Debug|x64 = Debug|x64
@ -187,6 +189,10 @@ Global
{8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}.Debug|x64.Build.0 = Debug|x64 {8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}.Debug|x64.Build.0 = Debug|x64
{8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}.Release|x64.ActiveCfg = Release|x64 {8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}.Release|x64.ActiveCfg = Release|x64
{8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}.Release|x64.Build.0 = Release|x64 {8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}.Release|x64.Build.0 = Release|x64
{5228F863-E0DD-4DE7-AA7B-5C52B14CD4D0}.Debug|x64.ActiveCfg = Debug|x64
{5228F863-E0DD-4DE7-AA7B-5C52B14CD4D0}.Debug|x64.Build.0 = Debug|x64
{5228F863-E0DD-4DE7-AA7B-5C52B14CD4D0}.Release|x64.ActiveCfg = Release|x64
{5228F863-E0DD-4DE7-AA7B-5C52B14CD4D0}.Release|x64.Build.0 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -216,6 +222,7 @@ Global
{508C291A-3D18-49F5-B25D-F7C8DB92CB21} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8} {508C291A-3D18-49F5-B25D-F7C8DB92CB21} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
{8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8} {8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
{A55DA1B5-CC17-4525-BE7F-1659CE17BB56} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8} {A55DA1B5-CC17-4525-BE7F-1659CE17BB56} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
{5228F863-E0DD-4DE7-AA7B-5C52B14CD4D0} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {06CC7920-E085-4B81-9582-8DE8AAD42510} SolutionGuid = {06CC7920-E085-4B81-9582-8DE8AAD42510}

View File

@ -159,6 +159,10 @@ target_link_libraries(rpcs3_emu
PUBLIC PUBLIC
3rdparty::soundtouch) 3rdparty::soundtouch)
target_link_libraries(rpcs3_emu
PUBLIC
3rdparty::miniupnpc)
# Cell # Cell
target_sources(rpcs3_emu PRIVATE target_sources(rpcs3_emu PRIVATE
Cell/MFC.cpp Cell/MFC.cpp
@ -411,6 +415,8 @@ target_sources(rpcs3_emu PRIVATE
NP/np_structs_extra.cpp NP/np_structs_extra.cpp
NP/rpcn_client.cpp NP/rpcn_client.cpp
NP/rpcn_config.cpp NP/rpcn_config.cpp
NP/upnp_config.cpp
NP/upnp_handler.cpp
) )
# Memory # Memory

View File

@ -221,16 +221,15 @@ error_code cellNetCtlGetInfo(s32 code, vm::ptr<CellNetCtlInfo> info)
switch (code) switch (code)
{ {
case CELL_NET_CTL_INFO_DEVICE: info->device = CELL_NET_CTL_DEVICE_WIRED; break; case CELL_NET_CTL_INFO_DEVICE: info->device = CELL_NET_CTL_DEVICE_WIRED; break;
// case CELL_NET_CTL_INFO_ETHER_ADDR: std::memset(info->ether_addr.data, 0xFF, sizeof(info->ether_addr.data)); break;
case CELL_NET_CTL_INFO_MTU: info->mtu = 1500; break; case CELL_NET_CTL_INFO_MTU: info->mtu = 1500; break;
case CELL_NET_CTL_INFO_LINK: info->link = CELL_NET_CTL_LINK_CONNECTED; break; case CELL_NET_CTL_INFO_LINK: info->link = CELL_NET_CTL_LINK_CONNECTED; break;
case CELL_NET_CTL_INFO_LINK_TYPE: info->link_type = CELL_NET_CTL_LINK_TYPE_10BASE_FULL; break; case CELL_NET_CTL_INFO_LINK_TYPE: info->link_type = CELL_NET_CTL_LINK_TYPE_100BASE_FULL; break;
case CELL_NET_CTL_INFO_IP_CONFIG: info->ip_config = CELL_NET_CTL_IP_STATIC; break; case CELL_NET_CTL_INFO_IP_CONFIG: info->ip_config = CELL_NET_CTL_IP_STATIC; break;
case CELL_NET_CTL_INFO_DEFAULT_ROUTE: strcpy_trunc(info->default_route, "192.168.1.1"); break; case CELL_NET_CTL_INFO_DEFAULT_ROUTE: strcpy_trunc(info->default_route, "192.168.1.1"); break;
case CELL_NET_CTL_INFO_PRIMARY_DNS: strcpy_trunc(info->primary_dns, np::ip_to_string(nph.get_dns_ip())); break; case CELL_NET_CTL_INFO_PRIMARY_DNS: strcpy_trunc(info->primary_dns, np::ip_to_string(nph.get_dns_ip())); break;
case CELL_NET_CTL_INFO_SECONDARY_DNS: strcpy_trunc(info->secondary_dns, np::ip_to_string(nph.get_dns_ip())); break; case CELL_NET_CTL_INFO_SECONDARY_DNS: strcpy_trunc(info->secondary_dns, np::ip_to_string(nph.get_dns_ip())); break;
case CELL_NET_CTL_INFO_IP_ADDRESS: strcpy_trunc(info->ip_address, np::ip_to_string(nph.get_public_ip_addr())); break; case CELL_NET_CTL_INFO_IP_ADDRESS: strcpy_trunc(info->ip_address, np::ip_to_string(nph.get_local_ip_addr())); break; // verified on HW
case CELL_NET_CTL_INFO_NETMASK: strcpy_trunc(info->netmask, "255.255.255.255"); break; case CELL_NET_CTL_INFO_NETMASK: strcpy_trunc(info->netmask, "255.255.255.0"); break;
case CELL_NET_CTL_INFO_HTTP_PROXY_CONFIG: info->http_proxy_config = 0; break; case CELL_NET_CTL_INFO_HTTP_PROXY_CONFIG: info->http_proxy_config = 0; break;
case CELL_NET_CTL_INFO_DHCP_HOSTNAME: strcpy_trunc(info->dhcp_hostname, nph.get_hostname()); break; case CELL_NET_CTL_INFO_DHCP_HOSTNAME: strcpy_trunc(info->dhcp_hostname, nph.get_hostname()); break;
default: cellNetCtl.error("Unsupported request: %s", InfoCodeToName(code)); break; default: cellNetCtl.error("Unsupported request: %s", InfoCodeToName(code)); break;
@ -348,7 +347,7 @@ error_code cellNetCtlGetNatInfo(vm::ptr<CellNetCtlNatInfo> natInfo)
natInfo->nat_type = CELL_NET_CTL_NATINFO_NAT_TYPE_2; natInfo->nat_type = CELL_NET_CTL_NATINFO_NAT_TYPE_2;
natInfo->stun_status = CELL_NET_CTL_NATINFO_STUN_OK; natInfo->stun_status = CELL_NET_CTL_NATINFO_STUN_OK;
natInfo->upnp_status = CELL_NET_CTL_NATINFO_UPNP_NO; natInfo->upnp_status = nph.get_upnp_status();
return CELL_OK; return CELL_OK;
} }

View File

@ -18,6 +18,7 @@
#include "Emu/Cell/lv2/sys_fs.h" #include "Emu/Cell/lv2/sys_fs.h"
#include "Emu/NP/np_handler.h" #include "Emu/NP/np_handler.h"
#include "Emu/NP/np_contexts.h" #include "Emu/NP/np_contexts.h"
#include "Emu/NP/np_helpers.h"
#include "Emu/system_config.h" #include "Emu/system_config.h"
LOG_CHANNEL(sceNp); LOG_CHANNEL(sceNp);
@ -5237,11 +5238,11 @@ error_code sceNpSignalingActivateConnection(u32 ctx_id, vm::ptr<SceNpId> npId, v
return SCE_NP_SIGNALING_ERROR_INVALID_ARGUMENT; return SCE_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
} }
if (strncmp(nph.get_npid().handle.data, npId->handle.data, 16) == 0) if (np::is_same_npid(nph.get_npid(), *npId))
return SCE_NP_SIGNALING_ERROR_OWN_NP_ID; return SCE_NP_SIGNALING_ERROR_OWN_NP_ID;
auto& sigh = g_fxo->get<named_thread<signaling_handler>>(); auto& sigh = g_fxo->get<named_thread<signaling_handler>>();
*conn_id = sigh.init_sig_infos(npId.get_ptr()); *conn_id = sigh.init_sig1(*npId);
return CELL_OK; return CELL_OK;
} }
@ -5298,19 +5299,15 @@ error_code sceNpSignalingGetConnectionStatus(u32 ctx_id, u32 conn_id, vm::ptr<s3
const auto si = sigh.get_sig_infos(conn_id); const auto si = sigh.get_sig_infos(conn_id);
if (si.connStatus == SCE_NP_SIGNALING_CONN_STATUS_ACTIVE && si.ext_status == ext_sign_peer) if (!si)
{ return SCE_NP_SIGNALING_ERROR_CONN_NOT_FOUND;
*conn_status = SCE_NP_SIGNALING_CONN_STATUS_INACTIVE;
} *conn_status = si->conn_status;
else
{
*conn_status = si.connStatus;
}
if (peer_addr) if (peer_addr)
(*peer_addr).np_s_addr = si.addr; // infos.addr is already BE (*peer_addr).np_s_addr = si->addr; // infos.addr is already BE
if (peer_port) if (peer_port)
*peer_port = si.port; *peer_port = si->port;
return CELL_OK; return CELL_OK;
} }
@ -5334,33 +5331,36 @@ error_code sceNpSignalingGetConnectionInfo(u32 ctx_id, u32 conn_id, s32 code, vm
auto& sigh = g_fxo->get<named_thread<signaling_handler>>(); auto& sigh = g_fxo->get<named_thread<signaling_handler>>();
const auto si = sigh.get_sig_infos(conn_id); const auto si = sigh.get_sig_infos(conn_id);
if (!si)
return SCE_NP_SIGNALING_ERROR_CONN_NOT_FOUND;
switch (code) switch (code)
{ {
case SCE_NP_SIGNALING_CONN_INFO_RTT: case SCE_NP_SIGNALING_CONN_INFO_RTT:
{ {
info->rtt = si.rtt; info->rtt = si->rtt;
break; break;
} }
case SCE_NP_SIGNALING_CONN_INFO_BANDWIDTH: case SCE_NP_SIGNALING_CONN_INFO_BANDWIDTH:
{ {
info->bandwidth = 10'000'000; // 10 MBPS HACK info->bandwidth = 100'000'000; // 100 MBPS HACK
break; break;
} }
case SCE_NP_SIGNALING_CONN_INFO_PEER_NPID: case SCE_NP_SIGNALING_CONN_INFO_PEER_NPID:
{ {
info->npId = si.npid; info->npId = si->npid;
break; break;
} }
case SCE_NP_SIGNALING_CONN_INFO_PEER_ADDRESS: case SCE_NP_SIGNALING_CONN_INFO_PEER_ADDRESS:
{ {
info->address.port = std::bit_cast<u16, be_t<u16>>(si.port); info->address.port = std::bit_cast<u16, be_t<u16>>(si->port);
info->address.addr.np_s_addr = si.addr; info->address.addr.np_s_addr = si->addr;
break; break;
} }
case SCE_NP_SIGNALING_CONN_INFO_MAPPED_ADDRESS: case SCE_NP_SIGNALING_CONN_INFO_MAPPED_ADDRESS:
{ {
info->address.port = std::bit_cast<u16, be_t<u16>>(si.mapped_port); info->address.port = std::bit_cast<u16, be_t<u16>>(si->mapped_port);
info->address.addr.np_s_addr = si.mapped_addr; info->address.addr.np_s_addr = si->mapped_addr;
break; break;
} }
case SCE_NP_SIGNALING_CONN_INFO_PACKET_LOSS: case SCE_NP_SIGNALING_CONN_INFO_PACKET_LOSS:
@ -5393,8 +5393,13 @@ error_code sceNpSignalingGetConnectionFromNpId(u32 ctx_id, vm::ptr<SceNpId> npId
return SCE_NP_SIGNALING_ERROR_INVALID_ARGUMENT; return SCE_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
} }
if (np::is_same_npid(*npId, nph.get_npid()))
{
return SCE_NP_SIGNALING_ERROR_OWN_NP_ID;
}
auto& sigh = g_fxo->get<named_thread<signaling_handler>>(); auto& sigh = g_fxo->get<named_thread<signaling_handler>>();
const auto found_conn_id = sigh.get_conn_id_from_npid(npId.get_ptr()); const auto found_conn_id = sigh.get_conn_id_from_npid(*npId);
if (!found_conn_id) if (!found_conn_id)
{ {
@ -5455,9 +5460,9 @@ error_code sceNpSignalingGetLocalNetInfo(u32 ctx_id, vm::ptr<SceNpSignalingNetIn
info->mapped_addr = nph.get_public_ip_addr(); info->mapped_addr = nph.get_public_ip_addr();
// Pure speculation below // Pure speculation below
info->nat_status = 0; info->nat_status = SCE_NP_SIGNALING_NETINFO_NAT_STATUS_TYPE2;
info->upnp_status = 0; info->upnp_status = nph.get_upnp_status();
info->npport_status = 0; info->npport_status = SCE_NP_SIGNALING_NETINFO_NPPORT_STATUS_OPEN;
info->npport = SCE_NP_PORT; info->npport = SCE_NP_PORT;
return CELL_OK; return CELL_OK;
@ -5537,25 +5542,8 @@ error_code sceNpUtilCmpNpId(vm::ptr<SceNpId> id1, vm::ptr<SceNpId> id2)
return SCE_NP_UTIL_ERROR_INVALID_ARGUMENT; return SCE_NP_UTIL_ERROR_INVALID_ARGUMENT;
} }
// Unknown what this constant means if (!np::is_same_npid(*id1, *id2))
// if (id1->reserved[0] != 1 || id2->reserved[0] != 1)
// {
// return SCE_NP_UTIL_ERROR_INVALID_NP_ID;
// }
if (strncmp(id1->handle.data, id2->handle.data, 16))// || id1->unk1[0] != id2->unk1[0])
{
return not_an_error(SCE_NP_UTIL_ERROR_NOT_MATCH); return not_an_error(SCE_NP_UTIL_ERROR_NOT_MATCH);
}
// if (id1->unk1[1] != id2->unk1[1])
// {
// // If either is zero they match
// if (id1->opt[4] && id2->opt[4])
// {
// return SCE_NP_UTIL_ERROR_NOT_MATCH;
// }
// }
return CELL_OK; return CELL_OK;
} }

View File

@ -6,6 +6,7 @@
#include "sceNp2.h" #include "sceNp2.h"
#include "Emu/NP/np_handler.h" #include "Emu/NP/np_handler.h"
#include "Emu/NP/np_contexts.h" #include "Emu/NP/np_contexts.h"
#include "Emu/NP/np_helpers.h"
#include "cellSysutil.h" #include "cellSysutil.h"
LOG_CHANNEL(sceNp2); LOG_CHANNEL(sceNp2);
@ -444,20 +445,35 @@ error_code sceNpMatching2SignalingGetConnectionStatus(
return SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT; return SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT;
} }
auto [res, npid] = nph.local_get_npid(roomId, memberId);
if (res)
return res;
if (np::is_same_npid(nph.get_npid(), *npid))
return SCE_NP_SIGNALING_ERROR_OWN_NP_ID;
auto& sigh = g_fxo->get<named_thread<signaling_handler>>(); auto& sigh = g_fxo->get<named_thread<signaling_handler>>();
const auto si = sigh.get_sig2_infos(roomId, memberId); auto conn_id = sigh.get_conn_id_from_npid(*npid);
if (!conn_id)
return SCE_NP_SIGNALING_ERROR_CONN_NOT_FOUND;
*connStatus = si.connStatus; const auto si = sigh.get_sig_infos(*conn_id);
if (!si)
return SCE_NP_SIGNALING_ERROR_CONN_NOT_FOUND;
*connStatus = si->conn_status;
if (peerAddr) if (peerAddr)
{ {
(*peerAddr).np_s_addr = si.addr; // infos.addr is already BE (*peerAddr).np_s_addr = si->addr; // infos.addr is already BE
} }
if (peerPort) if (peerPort)
{ {
*peerPort = si.port; *peerPort = si->port;
} }
return CELL_OK; return CELL_OK;
@ -616,42 +632,58 @@ error_code sceNpMatching2SignalingGetConnectionInfo(
return SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT; return SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT;
} }
auto [res, npid] = nph.local_get_npid(roomId, memberId);
if (res)
return res;
if (np::is_same_npid(nph.get_npid(), *npid))
return SCE_NP_SIGNALING_ERROR_OWN_NP_ID;
auto& sigh = g_fxo->get<named_thread<signaling_handler>>(); auto& sigh = g_fxo->get<named_thread<signaling_handler>>();
const auto si = sigh.get_sig2_infos(roomId, memberId);
auto conn_id = sigh.get_conn_id_from_npid(*npid);
if (!conn_id)
return SCE_NP_SIGNALING_ERROR_CONN_NOT_FOUND;
const auto si = sigh.get_sig_infos(*conn_id);
if (!si)
return SCE_NP_SIGNALING_ERROR_CONN_NOT_FOUND;
switch (code) switch (code)
{ {
case SCE_NP_SIGNALING_CONN_INFO_RTT: case SCE_NP_SIGNALING_CONN_INFO_RTT:
{ {
connInfo->rtt = si.rtt; connInfo->rtt = si->rtt;
sceNp2.warning("Returning a RTT of %d microseconds", connInfo->rtt); sceNp2.warning("Returning a RTT of %d microseconds", connInfo->rtt);
break; break;
} }
case SCE_NP_SIGNALING_CONN_INFO_BANDWIDTH: case SCE_NP_SIGNALING_CONN_INFO_BANDWIDTH:
{ {
connInfo->bandwidth = 10'000'000; // 10 MBPS HACK connInfo->bandwidth = 100'000'000; // 100 MBPS HACK
break; break;
} }
case SCE_NP_SIGNALING_CONN_INFO_PEER_NPID: case SCE_NP_SIGNALING_CONN_INFO_PEER_NPID:
{ {
connInfo->npId = si.npid; connInfo->npId = si->npid;
break; break;
} }
case SCE_NP_SIGNALING_CONN_INFO_PEER_ADDRESS: case SCE_NP_SIGNALING_CONN_INFO_PEER_ADDRESS:
{ {
connInfo->address.port = std::bit_cast<u16, be_t<u16>>(si.port); connInfo->address.port = std::bit_cast<u16, be_t<u16>>(si->port);
connInfo->address.addr.np_s_addr = si.addr; connInfo->address.addr.np_s_addr = si->addr;
break; break;
} }
case SCE_NP_SIGNALING_CONN_INFO_MAPPED_ADDRESS: case SCE_NP_SIGNALING_CONN_INFO_MAPPED_ADDRESS:
{ {
connInfo->address.port = std::bit_cast<u16, be_t<u16>>(si.mapped_port); connInfo->address.port = std::bit_cast<u16, be_t<u16>>(si->mapped_port);
connInfo->address.addr.np_s_addr = si.mapped_addr; connInfo->address.addr.np_s_addr = si->mapped_addr;
break; break;
} }
case SCE_NP_SIGNALING_CONN_INFO_PACKET_LOSS: case SCE_NP_SIGNALING_CONN_INFO_PACKET_LOSS:
{ {
connInfo->packet_loss = 1; // HACK connInfo->packet_loss = 0; // HACK
break; break;
} }
default: default:
@ -709,7 +741,7 @@ error_code sceNpMatching2GetRoomMemberDataExternalList(SceNpMatching2ContextId c
error_code sceNpMatching2AbortRequest(SceNpMatching2ContextId ctxId, SceNpMatching2RequestId reqId) error_code sceNpMatching2AbortRequest(SceNpMatching2ContextId ctxId, SceNpMatching2RequestId reqId)
{ {
sceNp2.todo("sceNpMatching2AbortRequest(ctxId=%d, reqId=%d)", ctxId, reqId); sceNp2.warning("sceNpMatching2AbortRequest(ctxId=%d, reqId=%d)", ctxId, reqId);
auto& nph = g_fxo->get<named_thread<np::np_handler>>(); auto& nph = g_fxo->get<named_thread<np::np_handler>>();
@ -728,6 +760,9 @@ error_code sceNpMatching2AbortRequest(SceNpMatching2ContextId ctxId, SceNpMatchi
return SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND; return SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND;
} }
if (!nph.abort_request(reqId))
return SCE_NP_MATCHING2_ERROR_REQUEST_NOT_FOUND;
return CELL_OK; return CELL_OK;
} }
@ -1591,7 +1626,7 @@ error_code sceNpMatching2SignalingCancelPeerNetInfo(SceNpMatching2ContextId ctxI
error_code sceNpMatching2SignalingGetLocalNetInfo(vm::ptr<SceNpMatching2SignalingNetInfo> netinfo) error_code sceNpMatching2SignalingGetLocalNetInfo(vm::ptr<SceNpMatching2SignalingNetInfo> netinfo)
{ {
sceNp2.todo("sceNpMatching2SignalingGetLocalNetInfo(netinfo=*0x%x)", netinfo); sceNp2.warning("sceNpMatching2SignalingGetLocalNetInfo(netinfo=*0x%x)", netinfo);
auto& nph = g_fxo->get<named_thread<np::np_handler>>(); auto& nph = g_fxo->get<named_thread<np::np_handler>>();
@ -1600,12 +1635,17 @@ error_code sceNpMatching2SignalingGetLocalNetInfo(vm::ptr<SceNpMatching2Signalin
return SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED; return SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED;
} }
if (!netinfo) if (!netinfo || netinfo->size != sizeof(SceNpMatching2SignalingNetInfo))
{ {
// TODO: check netinfo->size
return SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT; return SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT;
} }
netinfo->localAddr = nph.get_local_ip_addr();
netinfo->mappedAddr = nph.get_public_ip_addr();
// Pure speculation below
netinfo->natStatus = SCE_NP_SIGNALING_NETINFO_NAT_STATUS_TYPE2;
return CELL_OK; return CELL_OK;
} }
@ -1639,9 +1679,8 @@ error_code sceNpMatching2SignalingGetPeerNetInfoResult(SceNpMatching2ContextId c
return SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED; return SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED;
} }
if (!netinfo) if (!netinfo || netinfo->size != sizeof(SceNpMatching2SignalingNetInfo))
{ {
// TODO: check netinfo->size
return SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT; return SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT;
} }

View File

@ -1555,9 +1555,9 @@ struct SceNpMatching2CbQueueInfo
u8 reserved[12]; u8 reserved[12];
}; };
union SceNpMatching2SignalingNetInfo // TODO check values struct SceNpMatching2SignalingNetInfo
{ {
be_t<u64> size; be_t<u32> size;
be_t<u32> localAddr; be_t<u32> localAddr;
be_t<u32> mappedAddr; be_t<u32> mappedAddr;
be_t<u32> natStatus; be_t<u32> natStatus;

View File

@ -39,8 +39,8 @@ struct bandwidth_test
} }
} }
test_result.upload_bps = 16000.0; test_result.upload_bps = 100'000'000.0;
test_result.download_bps = 16000.0; test_result.download_bps = 100'000'000.0;
test_result.result = CELL_OK; test_result.result = CELL_OK;
status = SCE_NP_UTIL_BANDWIDTH_TEST_STATUS_FINISHED; status = SCE_NP_UTIL_BANDWIDTH_TEST_STATUS_FINISHED;
finished = true; finished = true;

View File

@ -1769,7 +1769,7 @@ error_code sys_net_abort(ppu_thread& ppu, s32 type, u64 arg, s32 flags)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
sys_net.todo("sys_net_abort(type=%d, arg=0x%x, flags=0x%x)", type, arg, flags); sys_net.warning("sys_net_abort(type=%d, arg=0x%x, flags=0x%x)", type, arg, flags);
enum abort_type : s32 enum abort_type : s32
{ {

View File

@ -50,6 +50,13 @@ lv2_socket_native::~lv2_socket_native()
::close(socket); ::close(socket);
#endif #endif
} }
if (bound_port)
{
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
nph.upnp_remove_port_mapping(bound_port, type == SYS_NET_SOCK_STREAM ? "TCP" : "UDP");
bound_port = 0;
}
} }
s32 lv2_socket_native::create_socket() s32 lv2_socket_native::create_socket()
@ -143,10 +150,36 @@ s32 lv2_socket_native::bind(const sys_net_sockaddr& addr)
native_addr.sin_addr.s_addr = saddr; native_addr.sin_addr.s_addr = saddr;
::socklen_t native_addr_len = sizeof(native_addr); ::socklen_t native_addr_len = sizeof(native_addr);
// Note that this is a hack(TODO)
// ATM we don't support binding 3658 udp because we use it for the p2ps main socket
// Only Fat Princess is known to do this to my knowledge
if (psa_in->sin_port == 3658 && type == SYS_NET_SOCK_DGRAM)
{
native_addr.sin_port = std::bit_cast<u16, be_t<u16>>(3659);
}
sys_net.warning("[Native] Trying to bind %s:%d", native_addr.sin_addr, std::bit_cast<be_t<u16>, u16>(native_addr.sin_port)); sys_net.warning("[Native] Trying to bind %s:%d", native_addr.sin_addr, std::bit_cast<be_t<u16>, u16>(native_addr.sin_port));
if (::bind(socket, reinterpret_cast<struct sockaddr*>(&native_addr), native_addr_len) == 0) if (::bind(socket, reinterpret_cast<struct sockaddr*>(&native_addr), native_addr_len) == 0)
{ {
// Only UPNP port forward binds to 0.0.0.0
if (saddr == 0)
{
if (native_addr.sin_port == 0)
{
sockaddr_in client_addr;
socklen_t client_addr_size = sizeof(client_addr);
ensure(::getsockname(socket, reinterpret_cast<struct sockaddr*>(&client_addr), &client_addr_size) == 0);
bound_port = std::bit_cast<u16, be_t<u16>>(client_addr.sin_port);
}
else
{
bound_port = std::bit_cast<u16, be_t<u16>>(native_addr.sin_port);
}
nph.upnp_add_port_mapping(bound_port, type == SYS_NET_SOCK_STREAM ? "TCP" : "UDP");
}
last_bound_addr = addr; last_bound_addr = addr;
return CELL_OK; return CELL_OK;
} }
@ -1011,6 +1044,13 @@ void lv2_socket_native::close()
auto& dnshook = g_fxo->get<np::dnshook>(); auto& dnshook = g_fxo->get<np::dnshook>();
dnshook.remove_dns_spy(lv2_id); dnshook.remove_dns_spy(lv2_id);
if (bound_port)
{
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
nph.upnp_remove_port_mapping(bound_port, type == SYS_NET_SOCK_STREAM ? "TCP" : "UDP");
bound_port = 0;
}
} }
s32 lv2_socket_native::shutdown(s32 how) s32 lv2_socket_native::shutdown(s32 how)

View File

@ -68,4 +68,5 @@ private:
s32 so_reuseaddr = 0; s32 so_reuseaddr = 0;
s32 so_reuseport = 0; s32 so_reuseport = 0;
#endif #endif
u16 bound_port = 0;
}; };

View File

@ -83,16 +83,12 @@ void need_network()
initialize_tcp_timeout_monitor(); initialize_tcp_timeout_monitor();
} }
network_thread::network_thread() noexcept void network_thread::bind_sce_np_port()
{ {
if (g_cfg.net.psn_status == np_psn_status::psn_rpcn) std::lock_guard list_lock(list_p2p_ports_mutex);
list_p2p_ports.emplace(std::piecewise_construct, std::forward_as_tuple(SCE_NP_PORT), std::forward_as_tuple(SCE_NP_PORT)); list_p2p_ports.emplace(std::piecewise_construct, std::forward_as_tuple(SCE_NP_PORT), std::forward_as_tuple(SCE_NP_PORT));
} }
network_thread::~network_thread()
{
}
void network_thread::operator()() void network_thread::operator()()
{ {
std::vector<std::shared_ptr<lv2_socket>> socklist; std::vector<std::shared_ptr<lv2_socket>> socklist;

View File

@ -17,10 +17,7 @@ struct network_thread
static constexpr auto thread_name = "Network Thread"; static constexpr auto thread_name = "Network Thread";
network_thread() noexcept; void bind_sce_np_port();
~network_thread();
void operator()(); void operator()();
}; };

View File

@ -10,6 +10,7 @@
#include "Emu/NP/signaling_handler.h" #include "Emu/NP/signaling_handler.h"
#include "sys_net_helpers.h" #include "sys_net_helpers.h"
#include "Emu/NP/vport0.h" #include "Emu/NP/vport0.h"
#include "Emu/NP/np_handler.h"
LOG_CHANNEL(sys_net); LOG_CHANNEL(sys_net);
@ -69,6 +70,9 @@ nt_p2p_port::nt_p2p_port(u16 port)
if (ret_bind == -1) if (ret_bind == -1)
fmt::throw_exception("Failed to bind DGRAM socket to %d for P2P: %s!", port, get_last_error(true)); fmt::throw_exception("Failed to bind DGRAM socket to %d for P2P: %s!", port, get_last_error(true));
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
nph.upnp_add_port_mapping(port, "UDP");
sys_net.notice("P2P port %d was bound!", port); sys_net.notice("P2P port %d was bound!", port);
} }
@ -82,6 +86,9 @@ nt_p2p_port::~nt_p2p_port()
::close(p2p_socket); ::close(p2p_socket);
#endif #endif
} }
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
nph.upnp_remove_port_mapping(port, "UDP");
} }
void nt_p2p_port::dump_packet(p2ps_encapsulated_tcp* tcph) void nt_p2p_port::dump_packet(p2ps_encapsulated_tcp* tcph)

View File

@ -3,6 +3,9 @@
#include "Emu/NP/np_allocator.h" #include "Emu/NP/np_allocator.h"
#include "Emu/NP/np_cache.h" #include "Emu/NP/np_cache.h"
#include "Emu/NP/np_helpers.h"
LOG_CHANNEL(np_cache);
namespace np namespace np
{ {
@ -80,20 +83,32 @@ namespace np
rooms[sce_roomdata->roomId].update(sce_roomdata); rooms[sce_roomdata->roomId].update(sce_roomdata);
} }
void cache_manager::add_member(SceNpMatching2RoomId room_id, const SceNpMatching2RoomMemberDataInternal* sce_roommemberdata) bool cache_manager::add_member(SceNpMatching2RoomId room_id, const SceNpMatching2RoomMemberDataInternal* sce_roommemberdata)
{ {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
ensure(rooms.contains(room_id), "cache_manager::add_member: Room not cached!"); if (!rooms.contains(room_id))
rooms[room_id].members.insert_or_assign(sce_roommemberdata->memberId, member_cache(sce_roommemberdata)); {
np_cache.error("np_cache::add_member cache miss: room_id(%d)", room_id);
return false;
} }
void cache_manager::del_member(SceNpMatching2RoomId room_id, SceNpMatching2RoomMemberId member_id) rooms[room_id].members.insert_or_assign(sce_roommemberdata->memberId, member_cache(sce_roommemberdata));
return true;
}
bool cache_manager::del_member(SceNpMatching2RoomId room_id, SceNpMatching2RoomMemberId member_id)
{ {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
ensure(rooms.contains(room_id), "cache_manager::del_member: Room not cached!"); if (!rooms.contains(room_id))
{
np_cache.error("np_cache::del_member cache miss: room_id(%d)/member_id(%d)", room_id, member_id);
return false;
}
rooms.erase(member_id); rooms.erase(member_id);
return true;
} }
void cache_manager::update_password(SceNpMatching2RoomId room_id, const std::optional<SceNpMatching2SessionPassword>& password) void cache_manager::update_password(SceNpMatching2RoomId room_id, const std::optional<SceNpMatching2SessionPassword>& password)
@ -121,7 +136,7 @@ namespace np
SceNpMatching2RoomJoinedSlotMask join_mask = 0; SceNpMatching2RoomJoinedSlotMask join_mask = 0;
for (const auto& member : room.members) for (const auto& member : room.members)
{ {
join_mask |= (1 << (member.first - 1)); join_mask |= (1 << ((member.first >> 4) - 1));
} }
slots.joinedSlotMask = join_mask; slots.joinedSlotMask = join_mask;
slots.passwordSlotMask = room.mask_password; slots.passwordSlotMask = room.mask_password;
@ -307,14 +322,45 @@ namespace np
return needed_data_size; return needed_data_size;
} }
SceNpId cache_manager::get_npid(u64 room_id, u16 member_id) std::pair<error_code, std::optional<SceNpId>> cache_manager::get_npid(u64 room_id, u16 member_id)
{ {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
ensure(rooms.contains(room_id), "cache_manager::get_npid: Room not cached!"); if (!rooms.contains(room_id))
ensure(::at32(rooms, room_id).members.contains(member_id), "cache_manager::get_npid: Member not cached!"); {
np_cache.error("np_cache::get_npid cache miss room_id: room_id(%d)/member_id(%d)", room_id, member_id);
return {SCE_NP_MATCHING2_ERROR_INVALID_ROOM_ID, std::nullopt};
}
return ::at32(::at32(rooms, room_id).members, member_id).userInfo.npId; if (!::at32(rooms, room_id).members.contains(member_id))
{
np_cache.error("np_cache::get_npid cache miss member_id: room_id(%d)/member_id(%d)", room_id, member_id);
return {SCE_NP_MATCHING2_ERROR_INVALID_MEMBER_ID, std::nullopt};
}
return {CELL_OK, ::at32(::at32(rooms, room_id).members, member_id).userInfo.npId};
}
std::optional<u16> cache_manager::get_memberid(u64 room_id, const SceNpId& npid)
{
std::lock_guard lock(mutex);
if (!rooms.contains(room_id))
{
np_cache.error("np_cache::get_memberid cache miss room_id: room_id(%d)/npid(%s)", room_id, static_cast<const char*>(npid.handle.data));
return std::nullopt;
}
const auto& members = ::at32(rooms, room_id).members;
for (const auto& [id, member_cache] : members)
{
if (np::is_same_npid(member_cache.userInfo.npId, npid))
return id;
}
np_cache.error("np_cache::get_memberid cache miss member_id: room_id(%d)/npid(%s)", room_id, static_cast<const char*>(npid.handle.data));
return std::nullopt;
} }
} // namespace np } // namespace np

View File

@ -67,15 +67,16 @@ namespace np
cache_manager() = default; cache_manager() = default;
void insert_room(const SceNpMatching2RoomDataInternal* sce_roomdata); void insert_room(const SceNpMatching2RoomDataInternal* sce_roomdata);
void add_member(SceNpMatching2RoomId room_id, const SceNpMatching2RoomMemberDataInternal* sce_roommemberdata); bool add_member(SceNpMatching2RoomId room_id, const SceNpMatching2RoomMemberDataInternal* sce_roommemberdata);
void del_member(SceNpMatching2RoomId room_id, SceNpMatching2RoomMemberId member_id); bool del_member(SceNpMatching2RoomId room_id, SceNpMatching2RoomMemberId member_id);
void update_password(SceNpMatching2RoomId room_id, const std::optional<SceNpMatching2SessionPassword>& password); void update_password(SceNpMatching2RoomId room_id, const std::optional<SceNpMatching2SessionPassword>& password);
std::pair<error_code, std::optional<SceNpMatching2RoomSlotInfo>> get_slots(SceNpMatching2RoomId room_id); std::pair<error_code, std::optional<SceNpMatching2RoomSlotInfo>> get_slots(SceNpMatching2RoomId room_id);
std::pair<error_code, std::vector<SceNpMatching2RoomMemberId>> get_memberids(u64 room_id, s32 sort_method); std::pair<error_code, std::vector<SceNpMatching2RoomMemberId>> get_memberids(u64 room_id, s32 sort_method);
std::pair<error_code, std::optional<SceNpMatching2SessionPassword>> get_password(SceNpMatching2RoomId room_id); std::pair<error_code, std::optional<SceNpMatching2SessionPassword>> get_password(SceNpMatching2RoomId room_id);
error_code get_member_and_attrs(SceNpMatching2RoomId room_id, SceNpMatching2RoomMemberId member_id, const std::vector<SceNpMatching2AttributeId>& binattrs_list, SceNpMatching2RoomMemberDataInternal* ptr_member, u32 addr_data, u32 size_data); error_code get_member_and_attrs(SceNpMatching2RoomId room_id, SceNpMatching2RoomMemberId member_id, const std::vector<SceNpMatching2AttributeId>& binattrs_list, SceNpMatching2RoomMemberDataInternal* ptr_member, u32 addr_data, u32 size_data);
SceNpId get_npid(u64 room_id, u16 member_id); std::pair<error_code, std::optional<SceNpId>> get_npid(u64 room_id, u16 member_id);
std::optional<u16> get_memberid(u64 room_id, const SceNpId& npid);
private: private:
shared_mutex mutex; shared_mutex mutex;

View File

@ -6,7 +6,6 @@
#include "Emu/Cell/Modules/sceNp2.h" #include "Emu/Cell/Modules/sceNp2.h"
#include "Emu/Cell/Modules/cellNetCtl.h" #include "Emu/Cell/Modules/cellNetCtl.h"
#include "Utilities/StrUtil.h" #include "Utilities/StrUtil.h"
#include "Emu/Cell/Modules/cellSysutil.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/NP/np_structs_extra.h" #include "Emu/NP/np_structs_extra.h"
#include "Emu/System.h" #include "Emu/System.h"
@ -14,6 +13,8 @@
#include "Emu/NP/np_contexts.h" #include "Emu/NP/np_contexts.h"
#include "Emu/NP/np_helpers.h" #include "Emu/NP/np_helpers.h"
#include "Emu/RSX/Overlays/overlay_message.h" #include "Emu/RSX/Overlays/overlay_message.h"
#include "Emu/Cell/lv2/sys_net/network_context.h"
#include "Emu/Cell/lv2/sys_net/sys_net_helpers.h"
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
@ -342,21 +343,18 @@ namespace np
{ {
g_fxo->need<named_thread<signaling_handler>>(); g_fxo->need<named_thread<signaling_handler>>();
std::lock_guard lock(mutex_rpcn);
rpcn = rpcn::rpcn_client::get_instance();
is_connected = (g_cfg.net.net_active == np_internet_status::enabled); is_connected = (g_cfg.net.net_active == np_internet_status::enabled);
is_psn_active = (g_cfg.net.psn_status >= np_psn_status::psn_fake); is_psn_active = (g_cfg.net.psn_status >= np_psn_status::psn_fake) && is_connected;
if (get_net_status() == CELL_NET_CTL_STATE_IPObtained) if (get_net_status() == CELL_NET_CTL_STATE_IPObtained)
{ {
discover_ip_address();
if (!discover_ether_address()) if (!discover_ether_address() || !discover_ip_address())
{ {
nph_log.error("Failed to discover ethernet address!"); nph_log.error("Failed to discover ethernet or ip address!");
is_connected = false; is_connected = false;
is_psn_active = false; is_psn_active = false;
return;
} }
// Convert dns address // Convert dns address
@ -383,6 +381,19 @@ namespace np
{ {
bind_ip = conv.s_addr; bind_ip = conv.s_addr;
} }
if (g_cfg.net.upnp_enabled)
upnp.upnp_enable();
}
if (is_psn_active && g_cfg.net.psn_status == np_psn_status::psn_rpcn)
{
g_fxo->need<network_context>();
auto& nc = g_fxo->get<network_context>();
nc.bind_sce_np_port();
std::lock_guard lock(mutex_rpcn);
rpcn = rpcn::rpcn_client::get_instance();
} }
} }
@ -449,46 +460,45 @@ namespace np
ar(m_pool, m_size, m_allocs, m_avail); ar(m_pool, m_size, m_allocs, m_avail);
} }
void np_handler::discover_ip_address() bool np_handler::discover_ip_address()
{ {
hostname.clear(); auto sockfd = socket(AF_INET, SOCK_DGRAM, 0);
hostname.resize(1024);
const auto use_default_ip_addr = [this](const std::string_view error_msg) auto close_socket = [&]()
{ {
nph_log.error("discover_ip_address: %s", error_msg); #ifdef _WIN32
nph_log.error("discover_ip_address: Defaulting to 127.0.0.1!"); closesocket(sockfd);
local_ip_addr = 0x0100007f; #else
public_ip_addr = local_ip_addr; close(sockfd);
#endif
}; };
if (gethostname(hostname.data(), hostname.size()) == -1) ::sockaddr_in addr;
std::memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = 53;
addr.sin_addr.s_addr = 0x08080808;
if (connect(sockfd, reinterpret_cast<const sockaddr *>(&addr), sizeof(addr)) != 0)
{ {
use_default_ip_addr("gethostname failed!"); // If connect fails a route to the internet is not available
return; nph_log.error("connect to discover local ip failed: %d", get_native_error());
close_socket();
return false; // offline
} }
// nph_log.notice("discover_ip_address: Hostname was determined to be %s", hostname.c_str()); sockaddr_in client_addr;
socklen_t client_addr_size = sizeof(client_addr);
hostent* host = gethostbyname(hostname.data()); if (getsockname(sockfd, reinterpret_cast<struct sockaddr*>(&client_addr), &client_addr_size) != 0)
if (!host)
{ {
use_default_ip_addr("gethostbyname failed!"); rpcn_log.error("getsockname to discover local ip failed: %d", get_native_error());
return; close_socket();
return true; // still assume online
} }
if (host->h_addrtype != AF_INET) local_ip_addr = client_addr.sin_addr.s_addr;
{ nph_log.trace("discover_ip_address: IP was determined to be %s", ip_to_string(local_ip_addr));
use_default_ip_addr("Could only find IPv6 addresses for current host!"); close_socket();
return; return true;
}
local_ip_addr = read_from_ptr<u32>(host->h_addr_list[0]);
// Set public address to local discovered address for now, may be updated later from RPCN socket
public_ip_addr = local_ip_addr;
// nph_log.notice("discover_ip_address: IP was determined to be %s", ip_to_string(local_ip_addr));
} }
bool np_handler::discover_ether_address() bool np_handler::discover_ether_address()
@ -612,6 +622,14 @@ namespace np
return is_psn_active ? SCE_NP_MANAGER_STATUS_ONLINE : SCE_NP_MANAGER_STATUS_OFFLINE; return is_psn_active ? SCE_NP_MANAGER_STATUS_ONLINE : SCE_NP_MANAGER_STATUS_OFFLINE;
} }
s32 np_handler::get_upnp_status() const
{
if (upnp.is_active())
return SCE_NP_SIGNALING_NETINFO_UPNP_STATUS_VALID;
return SCE_NP_SIGNALING_NETINFO_UPNP_STATUS_INVALID;
}
const SceNpId& np_handler::get_npid() const const SceNpId& np_handler::get_npid() const
{ {
return npid; return npid;
@ -649,7 +667,7 @@ namespace np
std::string s_npid = g_cfg_rpcn.get_npid(); std::string s_npid = g_cfg_rpcn.get_npid();
ensure(!s_npid.empty()); // It should have been generated before this ensure(!s_npid.empty()); // It should have been generated before this
string_to_npid(s_npid, &npid); string_to_npid(s_npid, npid);
auto& sigh = g_fxo->get<named_thread<signaling_handler>>(); auto& sigh = g_fxo->get<named_thread<signaling_handler>>();
sigh.set_self_sig_info(npid); sigh.set_self_sig_info(npid);
} }
@ -660,8 +678,8 @@ namespace np
break; break;
case np_psn_status::psn_fake: case np_psn_status::psn_fake:
{ {
string_to_online_name("RPCS3's user", &online_name); string_to_online_name("RPCS3's user", online_name);
string_to_avatar_url("https://rpcs3.net/cdn/netplay/DefaultAvatar.png", &avatar_url); string_to_avatar_url("https://rpcs3.net/cdn/netplay/DefaultAvatar.png", avatar_url);
break; break;
} }
case np_psn_status::psn_rpcn: case np_psn_status::psn_rpcn:
@ -692,8 +710,8 @@ namespace np
rsx::overlays::queue_message(localized_string_id::RPCN_SUCCESS_LOGGED_ON); rsx::overlays::queue_message(localized_string_id::RPCN_SUCCESS_LOGGED_ON);
string_to_online_name(rpcn->get_online_name(), &online_name); string_to_online_name(rpcn->get_online_name(), online_name);
string_to_avatar_url(rpcn->get_avatar_url(), &avatar_url); string_to_avatar_url(rpcn->get_avatar_url(), avatar_url);
public_ip_addr = rpcn->get_addr_sig(); public_ip_addr = rpcn->get_addr_sig();
local_ip_addr = std::bit_cast<u32, be_t<u32>>(rpcn->get_addr_local()); local_ip_addr = std::bit_cast<u32, be_t<u32>>(rpcn->get_addr_local());
@ -930,7 +948,7 @@ namespace np
return false; return false;
} }
u32 np_handler::generate_callback_info(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam) u32 np_handler::generate_callback_info(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, SceNpMatching2Event event_type)
{ {
callback_info ret; callback_info ret;
@ -942,6 +960,7 @@ namespace np
ret.ctx_id = ctx_id; ret.ctx_id = ctx_id;
ret.cb_arg = (optParam && optParam->cbFuncArg) ? optParam->cbFuncArg : ctx->default_match2_optparam.cbFuncArg; ret.cb_arg = (optParam && optParam->cbFuncArg) ? optParam->cbFuncArg : ctx->default_match2_optparam.cbFuncArg;
ret.cb = (optParam && optParam->cbFunc) ? optParam->cbFunc : ctx->default_match2_optparam.cbFunc; ret.cb = (optParam && optParam->cbFunc) ? optParam->cbFunc : ctx->default_match2_optparam.cbFunc;
ret.event_type = event_type;
nph_log.warning("Callback used is 0x%x", ret.cb); nph_log.warning("Callback used is 0x%x", ret.cb);
@ -953,16 +972,31 @@ namespace np
return req_id; return req_id;
} }
np_handler::callback_info np_handler::take_pending_request(u32 req_id) std::optional<np_handler::callback_info> np_handler::take_pending_request(u32 req_id)
{ {
std::lock_guard lock(mutex_pending_requests); std::lock_guard lock(mutex_pending_requests);
if (!pending_requests.contains(req_id))
return std::nullopt;
const auto cb_info = std::move(::at32(pending_requests, req_id)); const auto cb_info = std::move(::at32(pending_requests, req_id));
pending_requests.erase(req_id); pending_requests.erase(req_id);
return cb_info; return cb_info;
} }
bool np_handler::abort_request(u32 req_id)
{
auto cb_info_opt = take_pending_request(req_id);
if (!cb_info_opt)
return false;
cb_info_opt->queue_callback(req_id, 0, SCE_NP_MATCHING2_ERROR_ABORTED, 0);
return true;
}
event_data& np_handler::allocate_req_result(u32 event_key, u32 max_size, u32 initial_size) event_data& np_handler::allocate_req_result(u32 event_key, u32 max_size, u32 initial_size)
{ {
std::lock_guard lock(mutex_match2_req_results); std::lock_guard lock(mutex_match2_req_results);
@ -974,14 +1008,14 @@ namespace np
{ {
const u32 req_id = get_req_id(0); const u32 req_id = get_req_id(0);
// if (basic_handler) if (basic_handler.handler_func)
// { {
// sysutil_register_cb([basic_handler = this->basic_handler, req_id, basic_handler_arg = this->basic_handler_arg](ppu_thread& cb_ppu) -> s32 sysutil_register_cb([req_id, cb = basic_handler.handler_func, cb_arg = basic_handler.handler_arg](ppu_thread& cb_ppu) -> s32
// { {
// basic_handler(cb_ppu, SCE_NP_BASIC_EVENT_ADD_PLAYERS_HISTORY_RESULT, 0, req_id, basic_handler_arg); cb(cb_ppu, SCE_NP_BASIC_EVENT_ADD_PLAYERS_HISTORY_RESULT, 0, req_id, cb_arg);
// return 0; return 0;
// }); });
// } }
return req_id; return req_id;
} }
@ -1006,11 +1040,16 @@ namespace np
} }
SceNpId npid_friend; SceNpId npid_friend;
string_to_npid(str_friend.value(), &npid_friend); string_to_npid(str_friend.value(), npid_friend);
return {CELL_OK, npid_friend}; return {CELL_OK, npid_friend};
} }
std::pair<error_code, std::optional<SceNpId>> np_handler::local_get_npid(u64 room_id, u16 member_id)
{
return np_cache.get_npid(room_id, member_id);
}
std::pair<error_code, std::optional<SceNpMatching2SessionPassword>> np_handler::local_get_room_password(SceNpMatching2RoomId room_id) std::pair<error_code, std::optional<SceNpMatching2SessionPassword>> np_handler::local_get_room_password(SceNpMatching2RoomId room_id)
{ {
return np_cache.get_password(room_id); return np_cache.get_password(room_id);
@ -1030,4 +1069,14 @@ namespace np
{ {
return np_cache.get_member_and_attrs(room_id, member_id, binattrs_list, ptr_member, addr_data, size_data); return np_cache.get_member_and_attrs(room_id, member_id, binattrs_list, ptr_member, addr_data, size_data);
} }
void np_handler::upnp_add_port_mapping(u16 internal_port, std::string_view protocol)
{
upnp.add_port_redir(np::ip_to_string(get_local_ip_addr()), internal_port, protocol);
}
void np_handler::upnp_remove_port_mapping(u16 internal_port, std::string_view protocol)
{
upnp.remove_port_redir(internal_port, protocol);
}
} // namespace np } // namespace np

View File

@ -7,6 +7,7 @@
#include "Emu/Memory/vm_ptr.h" #include "Emu/Memory/vm_ptr.h"
#include "Emu/Cell/Modules/sceNp.h" #include "Emu/Cell/Modules/sceNp.h"
#include "Emu/Cell/Modules/sceNp2.h" #include "Emu/Cell/Modules/sceNp2.h"
#include "Emu/Cell/Modules/cellSysutil.h"
#include "Emu/NP/rpcn_client.h" #include "Emu/NP/rpcn_client.h"
#include "Emu/NP/generated/np2_structs_generated.h" #include "Emu/NP/generated/np2_structs_generated.h"
@ -15,6 +16,7 @@
#include "Emu/NP/np_cache.h" #include "Emu/NP/np_cache.h"
#include "Emu/NP/np_event_data.h" #include "Emu/NP/np_event_data.h"
#include "Emu/NP/np_contexts.h" #include "Emu/NP/np_contexts.h"
#include "Emu/NP/upnp_handler.h"
namespace np namespace np
{ {
@ -83,6 +85,7 @@ namespace np
s32 get_psn_status() const; s32 get_psn_status() const;
s32 get_net_status() const; s32 get_net_status() const;
s32 get_upnp_status() const;
const SceNpId& get_npid() const; const SceNpId& get_npid() const;
const SceNpOnlineId& get_online_id() const; const SceNpOnlineId& get_online_id() const;
@ -165,6 +168,7 @@ namespace np
void get_score_friend(std::shared_ptr<score_transaction_ctx>& trans_ctx, SceNpScoreBoardId boardId, bool include_self, vm::ptr<SceNpScoreRankData> rankArray, u32 rankArraySize, vm::ptr<SceNpScoreComment> commentArray, u32 commentArraySize, vm::ptr<void> infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr<CellRtcTick> lastSortDate, vm::ptr<SceNpScoreRankNumber> totalRecord, bool async); void get_score_friend(std::shared_ptr<score_transaction_ctx>& trans_ctx, SceNpScoreBoardId boardId, bool include_self, vm::ptr<SceNpScoreRankData> rankArray, u32 rankArraySize, vm::ptr<SceNpScoreComment> commentArray, u32 commentArraySize, vm::ptr<void> infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr<CellRtcTick> lastSortDate, vm::ptr<SceNpScoreRankNumber> totalRecord, bool async);
// Local functions // Local functions
std::pair<error_code, std::optional<SceNpId>> local_get_npid(u64 room_id, u16 member_id);
std::pair<error_code, std::optional<SceNpMatching2RoomSlotInfo>> local_get_room_slots(SceNpMatching2RoomId room_id); std::pair<error_code, std::optional<SceNpMatching2RoomSlotInfo>> local_get_room_slots(SceNpMatching2RoomId room_id);
std::pair<error_code, std::optional<SceNpMatching2SessionPassword>> local_get_room_password(SceNpMatching2RoomId room_id); std::pair<error_code, std::optional<SceNpMatching2SessionPassword>> local_get_room_password(SceNpMatching2RoomId room_id);
std::pair<error_code, std::vector<SceNpMatching2RoomMemberId>> local_get_room_memberids(SceNpMatching2RoomId room_id, s32 sort_method); std::pair<error_code, std::vector<SceNpMatching2RoomMemberId>> local_get_room_memberids(SceNpMatching2RoomId room_id, s32 sort_method);
@ -179,10 +183,15 @@ namespace np
void req_ticket(u32 version, const SceNpId* npid, const char* service_id, const u8* cookie, u32 cookie_size, const char* entitlement_id, u32 consumed_count); void req_ticket(u32 version, const SceNpId* npid, const char* service_id, const u8* cookie, u32 cookie_size, const char* entitlement_id, u32 consumed_count);
const ticket& get_ticket() const; const ticket& get_ticket() const;
u32 add_players_to_history(vm::cptr<SceNpId> npids, u32 count); u32 add_players_to_history(vm::cptr<SceNpId> npids, u32 count);
bool abort_request(u32 req_id);
// For signaling // For signaling
void req_sign_infos(const std::string& npid, u32 conn_id); void req_sign_infos(const std::string& npid, u32 conn_id);
// For UPNP
void upnp_add_port_mapping(u16 internal_port, std::string_view protocol);
void upnp_remove_port_mapping(u16 internal_port, std::string_view protocol);
// For custom menu // For custom menu
struct custom_menu_action struct custom_menu_action
{ {
@ -205,7 +214,7 @@ namespace np
private: private:
// Various generic helpers // Various generic helpers
void discover_ip_address(); bool discover_ip_address();
bool discover_ether_address(); bool discover_ether_address();
bool error_and_disconnect(const std::string& error_msg); bool error_and_disconnect(const std::string& error_msg);
@ -267,9 +276,23 @@ namespace np
SceNpMatching2ContextId ctx_id; SceNpMatching2ContextId ctx_id;
vm::ptr<SceNpMatching2RequestCallback> cb; vm::ptr<SceNpMatching2RequestCallback> cb;
vm::ptr<void> cb_arg; vm::ptr<void> cb_arg;
SceNpMatching2Event event_type;
void queue_callback(u32 req_id, u32 event_key, s32 error_code, u32 data_size) const
{
if (cb)
{
sysutil_register_cb([=, *this](ppu_thread& cb_ppu) -> s32
{
cb(cb_ppu, ctx_id, req_id, event_type, event_key, error_code, data_size, cb_arg);
return 0;
});
}
}
}; };
u32 generate_callback_info(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam);
callback_info take_pending_request(u32 req_id); u32 generate_callback_info(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, SceNpMatching2Event event_type);
std::optional<callback_info> take_pending_request(u32 req_id);
shared_mutex mutex_pending_requests; shared_mutex mutex_pending_requests;
std::unordered_map<u32, callback_info> pending_requests; std::unordered_map<u32, callback_info> pending_requests;
@ -327,5 +350,8 @@ namespace np
// RPCN // RPCN
shared_mutex mutex_rpcn; shared_mutex mutex_rpcn;
std::shared_ptr<rpcn::rpcn_client> rpcn; std::shared_ptr<rpcn::rpcn_client> rpcn;
// UPNP
upnp_handler upnp;
}; };
} // namespace np } // namespace np

View File

@ -22,25 +22,65 @@ namespace np
return fmt::format("%02X:%02X:%02X:%02X:%02X:%02X", ether[0], ether[1], ether[2], ether[3], ether[4], ether[5]); return fmt::format("%02X:%02X:%02X:%02X:%02X:%02X", ether[0], ether[1], ether[2], ether[3], ether[4], ether[5]);
} }
void string_to_npid(std::string_view str, SceNpId* npid) void string_to_npid(std::string_view str, SceNpId& npid)
{ {
memset(npid, 0, sizeof(SceNpId)); memset(&npid, 0, sizeof(npid));
strcpy_trunc(npid->handle.data, str); strcpy_trunc(npid.handle.data, str);
// npid->reserved[0] = 1; // npid->reserved[0] = 1;
} }
void string_to_online_name(std::string_view str, SceNpOnlineName* online_name) void string_to_online_name(std::string_view str, SceNpOnlineName& online_name)
{ {
strcpy_trunc(online_name->data, str); memset(&online_name, 0, sizeof(online_name));
strcpy_trunc(online_name.data, str);
} }
void string_to_avatar_url(std::string_view str, SceNpAvatarUrl* avatar_url) void string_to_avatar_url(std::string_view str, SceNpAvatarUrl& avatar_url)
{ {
strcpy_trunc(avatar_url->data, str); memset(&avatar_url, 0, sizeof(avatar_url));
strcpy_trunc(avatar_url.data, str);
} }
void string_to_communication_id(std::string_view str, SceNpCommunicationId* comm_id) void string_to_communication_id(std::string_view str, SceNpCommunicationId& comm_id)
{ {
strcpy_trunc(comm_id->data, str); memset(&comm_id, 0, sizeof(comm_id));
strcpy_trunc(comm_id.data, str);
}
bool is_valid_npid(const SceNpId& npid)
{
if (!std::all_of(npid.handle.data, npid.handle.data + 16, [](char c) { return std::isalnum(c) || c == '-' || c == '_' || c == 0; } )
|| npid.handle.data[16] != 0
|| !std::all_of(npid.handle.dummy, npid.handle.dummy + 3, [](char val) { return val == 0; }) )
{
return false;
}
return true;
}
bool is_same_npid(const SceNpId& npid_1, const SceNpId& npid_2)
{
// Unknown what this constant means
// if (id1->reserved[0] != 1 || id2->reserved[0] != 1)
// {
// return SCE_NP_UTIL_ERROR_INVALID_NP_ID;
// }
if (strncmp(npid_1.handle.data, npid_2.handle.data, 16) == 0) // || id1->unk1[0] != id2->unk1[0])
{
return true;
}
// if (id1->unk1[1] != id2->unk1[1])
// {
// // If either is zero they match
// if (id1->opt[4] && id2->opt[4])
// {
// return SCE_NP_UTIL_ERROR_NOT_MATCH;
// }
// }
return false;
} }
} }

View File

@ -1,3 +1,5 @@
#pragma once
#include "util/types.hpp" #include "util/types.hpp"
#include "Emu/Cell/Modules/sceNp.h" #include "Emu/Cell/Modules/sceNp.h"
#include "Emu/Cell/Modules/sceNp2.h" #include "Emu/Cell/Modules/sceNp2.h"
@ -7,8 +9,11 @@ namespace np
std::string ip_to_string(u32 addr); std::string ip_to_string(u32 addr);
std::string ether_to_string(std::array<u8, 6>& ether); std::string ether_to_string(std::array<u8, 6>& ether);
void string_to_npid(std::string_view str, SceNpId* npid); void string_to_npid(std::string_view str, SceNpId& npid);
void string_to_online_name(std::string_view str, SceNpOnlineName* online_name); void string_to_online_name(std::string_view str, SceNpOnlineName& online_name);
void string_to_avatar_url(std::string_view str, SceNpAvatarUrl* avatar_url); void string_to_avatar_url(std::string_view str, SceNpAvatarUrl& avatar_url);
void string_to_communication_id(std::string_view str, SceNpCommunicationId* comm_id); void string_to_communication_id(std::string_view str, SceNpCommunicationId& comm_id);
bool is_valid_npid(const SceNpId& npid);
bool is_same_npid(const SceNpId& npid_1, const SceNpId& npid_2);
} }

View File

@ -29,7 +29,8 @@ namespace np
RoomMemberUpdateInfo_to_SceNpMatching2RoomMemberUpdateInfo(edata, update_info, notif_data); RoomMemberUpdateInfo_to_SceNpMatching2RoomMemberUpdateInfo(edata, update_info, notif_data);
np_memory.shrink_allocation(edata.addr(), edata.size()); np_memory.shrink_allocation(edata.addr(), edata.size());
np_cache.add_member(room_id, notif_data->roomMemberDataInternal.get_ptr()); if (!np_cache.add_member(room_id, notif_data->roomMemberDataInternal.get_ptr()))
return;
rpcn_log.notice("Received notification that user %s(%d) joined the room(%d)", notif_data->roomMemberDataInternal->userInfo.npId.handle.data, notif_data->roomMemberDataInternal->memberId, room_id); rpcn_log.notice("Received notification that user %s(%d) joined the room(%d)", notif_data->roomMemberDataInternal->userInfo.npId.handle.data, notif_data->roomMemberDataInternal->memberId, room_id);
extra_nps::print_room_member_data_internal(notif_data->roomMemberDataInternal.get_ptr()); extra_nps::print_room_member_data_internal(notif_data->roomMemberDataInternal.get_ptr());
@ -60,7 +61,8 @@ namespace np
RoomMemberUpdateInfo_to_SceNpMatching2RoomMemberUpdateInfo(edata, update_info, notif_data); RoomMemberUpdateInfo_to_SceNpMatching2RoomMemberUpdateInfo(edata, update_info, notif_data);
np_memory.shrink_allocation(edata.addr(), edata.size()); np_memory.shrink_allocation(edata.addr(), edata.size());
np_cache.del_member(room_id, notif_data->roomMemberDataInternal->memberId); if (!np_cache.del_member(room_id, notif_data->roomMemberDataInternal->memberId))
return;
rpcn_log.notice("Received notification that user %s(%d) left the room(%d)", notif_data->roomMemberDataInternal->userInfo.npId.handle.data, notif_data->roomMemberDataInternal->memberId, room_id); rpcn_log.notice("Received notification that user %s(%d) left the room(%d)", notif_data->roomMemberDataInternal->userInfo.npId.handle.data, notif_data->roomMemberDataInternal->memberId, room_id);
extra_nps::print_room_member_data_internal(notif_data->roomMemberDataInternal.get_ptr()); extra_nps::print_room_member_data_internal(notif_data->roomMemberDataInternal.get_ptr());
@ -154,7 +156,8 @@ namespace np
RoomMemberDataInternalUpdateInfo_to_SceNpMatching2RoomMemberDataInternalUpdateInfo(edata, update_info, notif_data); RoomMemberDataInternalUpdateInfo_to_SceNpMatching2RoomMemberDataInternalUpdateInfo(edata, update_info, notif_data);
np_memory.shrink_allocation(edata.addr(), edata.size()); np_memory.shrink_allocation(edata.addr(), edata.size());
np_cache.add_member(room_id, notif_data->newRoomMemberDataInternal.get_ptr()); if (!np_cache.add_member(room_id, notif_data->newRoomMemberDataInternal.get_ptr()))
return;
rpcn_log.notice("Received notification that user's %s(%d) room (%d) data was updated", notif_data->newRoomMemberDataInternal->userInfo.npId.handle.data, notif_data->newRoomMemberDataInternal->memberId, room_id); rpcn_log.notice("Received notification that user's %s(%d) room (%d) data was updated", notif_data->newRoomMemberDataInternal->userInfo.npId.handle.data, notif_data->newRoomMemberDataInternal->memberId, room_id);
extra_nps::print_room_member_data_internal(notif_data->newRoomMemberDataInternal.get_ptr()); extra_nps::print_room_member_data_internal(notif_data->newRoomMemberDataInternal.get_ptr());
@ -200,22 +203,27 @@ namespace np
void np_handler::notif_p2p_connect(std::vector<u8>& data) void np_handler::notif_p2p_connect(std::vector<u8>& data)
{ {
if (data.size() != 16) vec_stream noti(data);
const u64 room_id = noti.get<u64>();
const u16 member_id = noti.get<u16>();
const u16 port_p2p = noti.get<u16>();
const u32 addr_p2p = noti.get<u32>();
if (noti.is_error())
{ {
rpcn_log.error("Notification data for SignalP2PConnect != 14"); rpcn_log.error("Received faulty SignalP2PConnect notification");
return; return;
} }
const u64 room_id = read_from_ptr<le_t<u64>>(data); auto [res, npid] = np_cache.get_npid(room_id, member_id);
const u16 member_id = read_from_ptr<le_t<u16>>(data, 8); if (!npid)
const u16 port_p2p = read_from_ptr<be_t<u16>>(data, 10); return;
const u32 addr_p2p = read_from_ptr<le_t<u32>>(data, 12);
rpcn_log.notice("Received notification to connect to member(%d) of room(%d): %s:%d", member_id, room_id, ip_to_string(addr_p2p), port_p2p); rpcn_log.notice("Received notification to connect to member(%d=%s) of room(%d): %s:%d", member_id, reinterpret_cast<const char*>((*npid).handle.data), room_id, ip_to_string(addr_p2p), port_p2p);
// Attempt Signaling // Attempt Signaling
auto& sigh = g_fxo->get<named_thread<signaling_handler>>(); auto& sigh = g_fxo->get<named_thread<signaling_handler>>();
sigh.set_sig2_infos(room_id, member_id, SCE_NP_SIGNALING_CONN_STATUS_PENDING, addr_p2p, port_p2p, np_cache.get_npid(room_id, member_id)); const u32 conn_id = sigh.init_sig2(*npid, room_id, member_id);
sigh.start_sig2(room_id, member_id); sigh.start_sig(conn_id, addr_p2p, port_p2p);
} }
} // namespace np } // namespace np

View File

@ -35,7 +35,7 @@ namespace np
u32 np_handler::get_server_status(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, u16 server_id) u32 np_handler::get_server_status(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, u16 server_id)
{ {
// TODO: actually implement interaction with server for this? // TODO: actually implement interaction with server for this?
u32 req_id = generate_callback_info(ctx_id, optParam); u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_GetServerInfo);
u32 event_key = get_event_key(); u32 event_key = get_event_key();
auto& edata = allocate_req_result(event_key, SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_GetServerInfo, sizeof(SceNpMatching2GetServerInfoResponse)); auto& edata = allocate_req_result(event_key, SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_GetServerInfo, sizeof(SceNpMatching2GetServerInfoResponse));
@ -44,61 +44,38 @@ namespace np
serv_info->server.status = SCE_NP_MATCHING2_SERVER_STATUS_AVAILABLE; serv_info->server.status = SCE_NP_MATCHING2_SERVER_STATUS_AVAILABLE;
np_memory.shrink_allocation(edata.addr(), edata.size()); np_memory.shrink_allocation(edata.addr(), edata.size());
const auto cb_info = take_pending_request(req_id); const auto cb_info_opt = take_pending_request(req_id);
ensure(cb_info_opt);
if (cb_info.cb) cb_info_opt->queue_callback(req_id, event_key, 0, edata.size());
{
sysutil_register_cb([=, size = edata.size()](ppu_thread& cb_ppu) -> s32
{
cb_info.cb(cb_ppu, cb_info.ctx_id, req_id, SCE_NP_MATCHING2_REQUEST_EVENT_GetServerInfo, event_key, 0, size, cb_info.cb_arg);
return 0;
});
}
return req_id; return req_id;
} }
u32 np_handler::create_server_context(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, u16 /*server_id*/) u32 np_handler::create_server_context(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, u16 /*server_id*/)
{ {
u32 req_id = generate_callback_info(ctx_id, optParam); u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_CreateServerContext);
u32 event_key = get_event_key();
const auto cb_info = take_pending_request(req_id); const auto cb_info_opt = take_pending_request(req_id);
ensure(cb_info_opt);
if (cb_info.cb) cb_info_opt->queue_callback(req_id, 0, 0, 0);
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
{
cb_info.cb(cb_ppu, cb_info.ctx_id, req_id, SCE_NP_MATCHING2_REQUEST_EVENT_CreateServerContext, event_key, 0, 0, cb_info.cb_arg);
return 0;
});
}
return req_id; return req_id;
} }
u32 np_handler::delete_server_context(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, u16 /*server_id*/) u32 np_handler::delete_server_context(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, u16 /*server_id*/)
{ {
u32 req_id = generate_callback_info(ctx_id, optParam); u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_DeleteServerContext);
u32 event_key = get_event_key();
const auto cb_info = take_pending_request(req_id); const auto cb_info_opt = take_pending_request(req_id);
ensure(cb_info_opt);
if (cb_info.cb) cb_info_opt->queue_callback(req_id, 0, 0, 0);
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
{
cb_info.cb(cb_ppu, cb_info.ctx_id, req_id, SCE_NP_MATCHING2_REQUEST_EVENT_DeleteServerContext, event_key, 0, 0, cb_info.cb_arg);
return 0;
});
}
return req_id; return req_id;
} }
u32 np_handler::get_world_list(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, u16 server_id) u32 np_handler::get_world_list(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, u16 server_id)
{ {
u32 req_id = generate_callback_info(ctx_id, optParam); u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_GetWorldInfoList);
if (!rpcn->get_world_list(req_id, get_match2_context(ctx_id)->communicationId, server_id)) if (!rpcn->get_world_list(req_id, get_match2_context(ctx_id)->communicationId, server_id))
{ {
@ -111,7 +88,10 @@ namespace np
bool np_handler::reply_get_world_list(u32 req_id, std::vector<u8>& reply_data) bool np_handler::reply_get_world_list(u32 req_id, std::vector<u8>& reply_data)
{ {
const auto cb_info = take_pending_request(req_id); auto cb_info_opt = take_pending_request(req_id);
if (!cb_info_opt)
return true;
vec_stream reply(reply_data, 1); vec_stream reply(reply_data, 1);
@ -139,31 +119,18 @@ namespace np
for (usz i = 0; i < world_list.size(); i++) for (usz i = 0; i < world_list.size(); i++)
{ {
worlds[i].worldId = world_list[i]; worlds[i].worldId = world_list[i];
worlds[i].numOfLobby = 1; // TODO
worlds[i].maxNumOfTotalLobbyMember = 10000;
worlds[i].curNumOfTotalLobbyMember = 1;
worlds[i].curNumOfRoom = 1;
worlds[i].curNumOfTotalRoomMember = 1;
} }
} }
np_memory.shrink_allocation(edata.addr(), edata.size()); np_memory.shrink_allocation(edata.addr(), edata.size());
cb_info_opt->queue_callback(req_id, event_key, 0, edata.size());
if (cb_info.cb)
{
sysutil_register_cb([=, size = edata.size()](ppu_thread& cb_ppu) -> s32
{
cb_info.cb(cb_ppu, cb_info.ctx_id, req_id, SCE_NP_MATCHING2_REQUEST_EVENT_GetWorldInfoList, event_key, 0, size, cb_info.cb_arg);
return 0;
});
}
return true; return true;
} }
u32 np_handler::create_join_room(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2CreateJoinRoomRequest* req) u32 np_handler::create_join_room(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2CreateJoinRoomRequest* req)
{ {
u32 req_id = generate_callback_info(ctx_id, optParam); u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_CreateJoinRoom);
extra_nps::print_createjoinroom(req); extra_nps::print_createjoinroom(req);
@ -181,7 +148,10 @@ namespace np
bool np_handler::reply_create_join_room(u32 req_id, std::vector<u8>& reply_data) bool np_handler::reply_create_join_room(u32 req_id, std::vector<u8>& reply_data)
{ {
const auto cb_info = take_pending_request(req_id); auto cb_info_opt = take_pending_request(req_id);
if (!cb_info_opt)
return true;
vec_stream reply(reply_data, 1); vec_stream reply(reply_data, 1);
auto* resp = reply.get_flatbuffer<RoomDataInternal>(); auto* resp = reply.get_flatbuffer<RoomDataInternal>();
@ -200,29 +170,16 @@ namespace np
np_cache.insert_room(room_info); np_cache.insert_room(room_info);
np_cache.update_password(room_resp->roomDataInternal->roomId, cached_cj_password); np_cache.update_password(room_resp->roomDataInternal->roomId, cached_cj_password);
// Establish Matching2 self signaling info
auto& sigh = g_fxo->get<named_thread<signaling_handler>>();
sigh.set_self_sig2_info(room_info->roomId, 1);
sigh.set_sig2_infos(room_info->roomId, 1, SCE_NP_SIGNALING_CONN_STATUS_ACTIVE, rpcn->get_addr_sig(), rpcn->get_port_sig(), get_npid(), true);
// TODO? Should this send a message to Signaling CB? Is this even necessary?
extra_nps::print_create_room_resp(room_resp); extra_nps::print_create_room_resp(room_resp);
if (cb_info.cb) cb_info_opt->queue_callback(req_id, event_key, 0, edata.size());
{
sysutil_register_cb([=, size = edata.size()](ppu_thread& cb_ppu) -> s32
{
cb_info.cb(cb_ppu, cb_info.ctx_id, req_id, SCE_NP_MATCHING2_REQUEST_EVENT_CreateJoinRoom, event_key, 0, size, cb_info.cb_arg);
return 0;
});
}
return true; return true;
} }
u32 np_handler::join_room(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2JoinRoomRequest* req) u32 np_handler::join_room(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2JoinRoomRequest* req)
{ {
u32 req_id = generate_callback_info(ctx_id, optParam); u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_JoinRoom);
extra_nps::print_joinroom(req); extra_nps::print_joinroom(req);
@ -237,6 +194,11 @@ namespace np
bool np_handler::reply_join_room(u32 req_id, std::vector<u8>& reply_data) bool np_handler::reply_join_room(u32 req_id, std::vector<u8>& reply_data)
{ {
auto cb_info_opt = take_pending_request(req_id);
if (!cb_info_opt)
return true;
s32 error_code = 0; s32 error_code = 0;
if (rpcn::is_error(static_cast<rpcn::ErrorType>(reply_data[0]))) if (rpcn::is_error(static_cast<rpcn::ErrorType>(reply_data[0])))
@ -250,19 +212,9 @@ namespace np
} }
} }
const auto cb_info = take_pending_request(req_id);
if (error_code != 0) if (error_code != 0)
{ {
if (cb_info.cb) cb_info_opt->queue_callback(req_id, 0, error_code, 0);
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
{
cb_info.cb(cb_ppu, cb_info.ctx_id, req_id, SCE_NP_MATCHING2_REQUEST_EVENT_JoinRoom, 0, error_code, 0, cb_info.cb_arg);
return 0;
});
}
return true; return true;
} }
@ -278,34 +230,21 @@ namespace np
auto& edata = allocate_req_result(event_key, SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_JoinRoom, sizeof(SceNpMatching2JoinRoomResponse)); auto& edata = allocate_req_result(event_key, SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_JoinRoom, sizeof(SceNpMatching2JoinRoomResponse));
auto* room_resp = reinterpret_cast<SceNpMatching2JoinRoomResponse*>(edata.data()); auto* room_resp = reinterpret_cast<SceNpMatching2JoinRoomResponse*>(edata.data());
auto* room_info = edata.allocate<SceNpMatching2RoomDataInternal>(sizeof(SceNpMatching2RoomDataInternal), room_resp->roomDataInternal); auto* room_info = edata.allocate<SceNpMatching2RoomDataInternal>(sizeof(SceNpMatching2RoomDataInternal), room_resp->roomDataInternal);
u16 member_id = RoomDataInternal_to_SceNpMatching2RoomDataInternal(edata, resp, room_info, npid); RoomDataInternal_to_SceNpMatching2RoomDataInternal(edata, resp, room_info, npid);
np_memory.shrink_allocation(edata.addr(), edata.size()); np_memory.shrink_allocation(edata.addr(), edata.size());
np_cache.insert_room(room_info); np_cache.insert_room(room_info);
extra_nps::print_room_data_internal(room_info); extra_nps::print_room_data_internal(room_info);
// Establish Matching2 self signaling info cb_info_opt->queue_callback(req_id, event_key, 0, edata.size());
auto& sigh = g_fxo->get<named_thread<signaling_handler>>();
sigh.set_self_sig2_info(room_info->roomId, member_id);
sigh.set_sig2_infos(room_info->roomId, member_id, SCE_NP_SIGNALING_CONN_STATUS_ACTIVE, rpcn->get_addr_sig(), rpcn->get_port_sig(), get_npid(), true);
// TODO? Should this send a message to Signaling CB? Is this even necessary?
if (cb_info.cb)
{
sysutil_register_cb([=, size = edata.size()](ppu_thread& cb_ppu) -> s32
{
cb_info.cb(cb_ppu, cb_info.ctx_id, req_id, SCE_NP_MATCHING2_REQUEST_EVENT_JoinRoom, event_key, 0, size, cb_info.cb_arg);
return 0;
});
}
return true; return true;
} }
u32 np_handler::leave_room(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2LeaveRoomRequest* req) u32 np_handler::leave_room(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2LeaveRoomRequest* req)
{ {
u32 req_id = generate_callback_info(ctx_id, optParam); u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_LeaveRoom);
if (!rpcn->leave_room(req_id, get_match2_context(ctx_id)->communicationId, req)) if (!rpcn->leave_room(req_id, get_match2_context(ctx_id)->communicationId, req))
{ {
@ -318,34 +257,27 @@ namespace np
bool np_handler::reply_leave_room(u32 req_id, std::vector<u8>& reply_data) bool np_handler::reply_leave_room(u32 req_id, std::vector<u8>& reply_data)
{ {
const auto cb_info = take_pending_request(req_id); auto cb_info_opt = take_pending_request(req_id);
if (!cb_info_opt)
return true;
vec_stream reply(reply_data, 1); vec_stream reply(reply_data, 1);
u64 room_id = reply.get<u64>(); u64 room_id = reply.get<u64>();
if (reply.is_error()) if (reply.is_error())
return error_and_disconnect("Malformed reply to LeaveRoom command"); return error_and_disconnect("Malformed reply to LeaveRoom command");
u32 event_key = get_event_key(); // Unsure if necessary if there is no data
// Disconnect all users from that room // Disconnect all users from that room
auto& sigh = g_fxo->get<named_thread<signaling_handler>>(); auto& sigh = g_fxo->get<named_thread<signaling_handler>>();
sigh.disconnect_sig2_users(room_id); sigh.disconnect_sig2_users(room_id);
cb_info_opt->queue_callback(req_id, 0, 0, 0);
if (cb_info.cb)
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
{
cb_info.cb(cb_ppu, cb_info.ctx_id, req_id, SCE_NP_MATCHING2_REQUEST_EVENT_LeaveRoom, event_key, 0, 0, cb_info.cb_arg);
return 0;
});
}
return true; return true;
} }
u32 np_handler::search_room(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SearchRoomRequest* req) u32 np_handler::search_room(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SearchRoomRequest* req)
{ {
u32 req_id = generate_callback_info(ctx_id, optParam); u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SearchRoom);
extra_nps::print_search_room(req); extra_nps::print_search_room(req);
@ -360,7 +292,10 @@ namespace np
bool np_handler::reply_search_room(u32 req_id, std::vector<u8>& reply_data) bool np_handler::reply_search_room(u32 req_id, std::vector<u8>& reply_data)
{ {
const auto cb_info = take_pending_request(req_id); auto cb_info_opt = take_pending_request(req_id);
if (!cb_info_opt)
return true;
vec_stream reply(reply_data, 1); vec_stream reply(reply_data, 1);
auto* resp = reply.get_flatbuffer<SearchRoomResponse>(); auto* resp = reply.get_flatbuffer<SearchRoomResponse>();
@ -376,22 +311,14 @@ namespace np
np_memory.shrink_allocation(edata.addr(), edata.size()); np_memory.shrink_allocation(edata.addr(), edata.size());
extra_nps::print_search_room_resp(search_resp); extra_nps::print_search_room_resp(search_resp);
cb_info_opt->queue_callback(req_id, event_key, 0, edata.size());
if (cb_info.cb)
{
sysutil_register_cb([=, size = edata.size()](ppu_thread& cb_ppu) -> s32
{
cb_info.cb(cb_ppu, cb_info.ctx_id, req_id, SCE_NP_MATCHING2_REQUEST_EVENT_SearchRoom, event_key, 0, size, cb_info.cb_arg);
return 0;
});
}
return true; return true;
} }
u32 np_handler::get_roomdata_external_list(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2GetRoomDataExternalListRequest* req) u32 np_handler::get_roomdata_external_list(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2GetRoomDataExternalListRequest* req)
{ {
u32 req_id = generate_callback_info(ctx_id, optParam); u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomDataExternalList);
extra_nps::print_get_roomdata_external_list_req(req); extra_nps::print_get_roomdata_external_list_req(req);
@ -406,7 +333,10 @@ namespace np
bool np_handler::reply_get_roomdata_external_list(u32 req_id, std::vector<u8>& reply_data) bool np_handler::reply_get_roomdata_external_list(u32 req_id, std::vector<u8>& reply_data)
{ {
const auto cb_info = take_pending_request(req_id); auto cb_info_opt = take_pending_request(req_id);
if (!cb_info_opt)
return true;
vec_stream reply(reply_data, 1); vec_stream reply(reply_data, 1);
auto* resp = reply.get_flatbuffer<GetRoomDataExternalListResponse>(); auto* resp = reply.get_flatbuffer<GetRoomDataExternalListResponse>();
@ -423,21 +353,14 @@ namespace np
extra_nps::print_get_roomdata_external_list_resp(sce_get_room_ext_resp); extra_nps::print_get_roomdata_external_list_resp(sce_get_room_ext_resp);
if (cb_info.cb) cb_info_opt->queue_callback(req_id, event_key, 0, edata.size());
{
sysutil_register_cb([=, size = edata.size()](ppu_thread& cb_ppu) -> s32
{
cb_info.cb(cb_ppu, cb_info.ctx_id, req_id, SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomDataExternalList, event_key, 0, size, cb_info.cb_arg);
return 0;
});
}
return true; return true;
} }
u32 np_handler::set_roomdata_external(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SetRoomDataExternalRequest* req) u32 np_handler::set_roomdata_external(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SetRoomDataExternalRequest* req)
{ {
u32 req_id = generate_callback_info(ctx_id, optParam); u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomDataExternal);
extra_nps::print_set_roomdata_ext_req(req); extra_nps::print_set_roomdata_ext_req(req);
@ -452,25 +375,19 @@ namespace np
bool np_handler::reply_set_roomdata_external(u32 req_id, std::vector<u8>& /*reply_data*/) bool np_handler::reply_set_roomdata_external(u32 req_id, std::vector<u8>& /*reply_data*/)
{ {
const auto cb_info = take_pending_request(req_id); auto cb_info_opt = take_pending_request(req_id);
u32 event_key = get_event_key(); // Unsure if necessary if there is no data if (!cb_info_opt)
return true;
if (cb_info.cb) cb_info_opt->queue_callback(req_id, 0, 0, 0);
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
{
cb_info.cb(cb_ppu, cb_info.ctx_id, req_id, SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomDataExternal, event_key, 0, 0, cb_info.cb_arg);
return 0;
});
}
return true; return true;
} }
u32 np_handler::get_roomdata_internal(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2GetRoomDataInternalRequest* req) u32 np_handler::get_roomdata_internal(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2GetRoomDataInternalRequest* req)
{ {
u32 req_id = generate_callback_info(ctx_id, optParam); u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomDataInternal);
if (!rpcn->get_roomdata_internal(req_id, get_match2_context(ctx_id)->communicationId, req)) if (!rpcn->get_roomdata_internal(req_id, get_match2_context(ctx_id)->communicationId, req))
{ {
@ -483,7 +400,10 @@ namespace np
bool np_handler::reply_get_roomdata_internal(u32 req_id, std::vector<u8>& reply_data) bool np_handler::reply_get_roomdata_internal(u32 req_id, std::vector<u8>& reply_data)
{ {
const auto cb_info = take_pending_request(req_id); auto cb_info_opt = take_pending_request(req_id);
if (!cb_info_opt)
return true;
vec_stream reply(reply_data, 1); vec_stream reply(reply_data, 1);
@ -504,21 +424,14 @@ namespace np
extra_nps::print_room_data_internal(room_info); extra_nps::print_room_data_internal(room_info);
if (cb_info.cb) cb_info_opt->queue_callback(req_id, event_key, 0, edata.size());
{
sysutil_register_cb([=, size = edata.size()](ppu_thread& cb_ppu) -> s32
{
cb_info.cb(cb_ppu, cb_info.ctx_id, req_id, SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomDataInternal, event_key, 0, size, cb_info.cb_arg);
return 0;
});
}
return true; return true;
} }
u32 np_handler::set_roomdata_internal(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SetRoomDataInternalRequest* req) u32 np_handler::set_roomdata_internal(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SetRoomDataInternalRequest* req)
{ {
u32 req_id = generate_callback_info(ctx_id, optParam); u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomDataInternal);
// TODO: extra_nps::print_set_roomdata_req(req); // TODO: extra_nps::print_set_roomdata_req(req);
@ -535,25 +448,19 @@ namespace np
bool np_handler::reply_set_roomdata_internal(u32 req_id, std::vector<u8>& /*reply_data*/) bool np_handler::reply_set_roomdata_internal(u32 req_id, std::vector<u8>& /*reply_data*/)
{ {
const auto cb_info = take_pending_request(req_id); auto cb_info_opt = take_pending_request(req_id);
u32 event_key = get_event_key(); // Unsure if necessary if there is no data if (!cb_info_opt)
return true;
if (cb_info.cb) cb_info_opt->queue_callback(req_id, 0, 0, 0);
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
{
cb_info.cb(cb_ppu, cb_info.ctx_id, req_id, SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomDataInternal, event_key, 0, 0, cb_info.cb_arg);
return 0;
});
}
return true; return true;
} }
u32 np_handler::set_roommemberdata_internal(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SetRoomMemberDataInternalRequest* req) u32 np_handler::set_roommemberdata_internal(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SetRoomMemberDataInternalRequest* req)
{ {
u32 req_id = generate_callback_info(ctx_id, optParam); u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomMemberDataInternal);
extra_nps::print_set_roommemberdata_int_req(req); extra_nps::print_set_roommemberdata_int_req(req);
@ -568,25 +475,19 @@ namespace np
bool np_handler::reply_set_roommemberdata_internal(u32 req_id, std::vector<u8>& /*reply_data*/) bool np_handler::reply_set_roommemberdata_internal(u32 req_id, std::vector<u8>& /*reply_data*/)
{ {
const auto cb_info = take_pending_request(req_id); auto cb_info_opt = take_pending_request(req_id);
u32 event_key = get_event_key(); // Unsure if necessary if there is no data if (!cb_info_opt)
return true;
if (cb_info.cb) cb_info_opt->queue_callback(req_id, 0, 0, 0);
{
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
{
cb_info.cb(cb_ppu, cb_info.ctx_id, req_id, SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomMemberDataInternal, event_key, 0, 0, cb_info.cb_arg);
return 0;
});
}
return true; return true;
} }
u32 np_handler::get_ping_info(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SignalingGetPingInfoRequest* req) u32 np_handler::get_ping_info(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SignalingGetPingInfoRequest* req)
{ {
u32 req_id = generate_callback_info(ctx_id, optParam); u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SignalingGetPingInfo);
if (!rpcn->ping_room_owner(req_id, get_match2_context(ctx_id)->communicationId, req->roomId)) if (!rpcn->ping_room_owner(req_id, get_match2_context(ctx_id)->communicationId, req->roomId))
{ {
@ -599,7 +500,10 @@ namespace np
bool np_handler::reply_get_ping_info(u32 req_id, std::vector<u8>& reply_data) bool np_handler::reply_get_ping_info(u32 req_id, std::vector<u8>& reply_data)
{ {
const auto cb_info = take_pending_request(req_id); auto cb_info_opt = take_pending_request(req_id);
if (!cb_info_opt)
return true;
vec_stream reply(reply_data, 1); vec_stream reply(reply_data, 1);
@ -614,22 +518,14 @@ namespace np
auto* final_ping_resp = reinterpret_cast<SceNpMatching2SignalingGetPingInfoResponse*>(edata.data()); auto* final_ping_resp = reinterpret_cast<SceNpMatching2SignalingGetPingInfoResponse*>(edata.data());
GetPingInfoResponse_to_SceNpMatching2SignalingGetPingInfoResponse(resp, final_ping_resp); GetPingInfoResponse_to_SceNpMatching2SignalingGetPingInfoResponse(resp, final_ping_resp);
np_memory.shrink_allocation(edata.addr(), edata.size()); np_memory.shrink_allocation(edata.addr(), edata.size());
cb_info_opt->queue_callback(req_id, event_key, 0, edata.size());
if (cb_info.cb)
{
sysutil_register_cb([=, size = edata.size()](ppu_thread& cb_ppu) -> s32
{
cb_info.cb(cb_ppu, cb_info.ctx_id, req_id, SCE_NP_MATCHING2_REQUEST_EVENT_SignalingGetPingInfo, event_key, 0, size, cb_info.cb_arg);
return 0;
});
}
return true; return true;
} }
u32 np_handler::send_room_message(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SendRoomMessageRequest* req) u32 np_handler::send_room_message(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2SendRoomMessageRequest* req)
{ {
u32 req_id = generate_callback_info(ctx_id, optParam); u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_SendRoomMessage);
if (!rpcn->send_room_message(req_id, get_match2_context(ctx_id)->communicationId, req)) if (!rpcn->send_room_message(req_id, get_match2_context(ctx_id)->communicationId, req))
{ {
@ -642,16 +538,12 @@ namespace np
bool np_handler::reply_send_room_message(u32 req_id, std::vector<u8>& /*reply_data*/) bool np_handler::reply_send_room_message(u32 req_id, std::vector<u8>& /*reply_data*/)
{ {
const auto cb_info = take_pending_request(req_id); auto cb_info_opt = take_pending_request(req_id);
if (cb_info.cb) if (!cb_info_opt)
{ return true;
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
{ cb_info_opt->queue_callback(req_id, 0, 0, 0);
cb_info.cb(cb_ppu, cb_info.ctx_id, req_id, SCE_NP_MATCHING2_REQUEST_EVENT_SendRoomMessage, 0, 0, 0, cb_info.cb_arg);
return 0;
});
}
return true; return true;
} }
@ -1112,8 +1004,8 @@ namespace np
cur_rank = &rankPlayerArray[i].rankData; cur_rank = &rankPlayerArray[i].rankData;
} }
string_to_npid(fb_rankdata->npId()->string_view(), &cur_rank->npId); string_to_npid(fb_rankdata->npId()->string_view(), cur_rank->npId);
string_to_online_name(fb_rankdata->onlineName()->string_view(), &cur_rank->onlineName); string_to_online_name(fb_rankdata->onlineName()->string_view(), cur_rank->onlineName);
cur_rank->pcId = fb_rankdata->pcId(); cur_rank->pcId = fb_rankdata->pcId();
cur_rank->serialRank = fb_rankdata->rank(); cur_rank->serialRank = fb_rankdata->rank();

View File

@ -18,6 +18,7 @@ namespace extra_nps
void print_sigoptparam(const SceNpMatching2SignalingOptParam* opt) void print_sigoptparam(const SceNpMatching2SignalingOptParam* opt)
{ {
sceNp2.warning("SceNpMatching2SignalingOptParam:");
sceNp2.warning("type: %d", opt->type); sceNp2.warning("type: %d", opt->type);
sceNp2.warning("flag: %d", opt->flag); sceNp2.warning("flag: %d", opt->flag);
sceNp2.warning("hubMemberId: %d", opt->hubMemberId); sceNp2.warning("hubMemberId: %d", opt->hubMemberId);
@ -227,7 +228,10 @@ namespace extra_nps
sceNp2.warning("curMemberNum: %d", room->curMemberNum); sceNp2.warning("curMemberNum: %d", room->curMemberNum);
sceNp2.warning("SceNpMatching2RoomPasswordSlotMask: 0x%x", room->passwordSlotMask); sceNp2.warning("SceNpMatching2RoomPasswordSlotMask: 0x%x", room->passwordSlotMask);
sceNp2.warning("owner: *0x%x", room->owner); sceNp2.warning("owner: *0x%x", room->owner);
if (room->owner)
print_userinfo2(room->owner.get_ptr()); print_userinfo2(room->owner.get_ptr());
sceNp2.warning("roomGroup: *0x%x", room->roomGroup); sceNp2.warning("roomGroup: *0x%x", room->roomGroup);
// TODO: print roomGroup // TODO: print roomGroup
sceNp2.warning("roomGroupNum: %d", room->roomGroupNum); sceNp2.warning("roomGroupNum: %d", room->roomGroupNum);

View File

@ -71,7 +71,7 @@ namespace rpcn
return get_localized_string(rpcn_state_to_localized_string_id(state)); return get_localized_string(rpcn_state_to_localized_string_id(state));
} }
constexpr u32 RPCN_PROTOCOL_VERSION = 18; constexpr u32 RPCN_PROTOCOL_VERSION = 19;
constexpr usz RPCN_HEADER_SIZE = 15; constexpr usz RPCN_HEADER_SIZE = 15;
constexpr usz COMMUNICATION_ID_SIZE = 9; constexpr usz COMMUNICATION_ID_SIZE = 9;

View File

@ -1,6 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "rpcn_config.h" #include "rpcn_config.h"
#include "Emu/System.h" #include "Utilities/File.h"
cfg_rpcn g_cfg_rpcn; cfg_rpcn g_cfg_rpcn;

View File

@ -5,6 +5,7 @@
#include "Emu/Cell/Modules/cellSysutil.h" #include "Emu/Cell/Modules/cellSysutil.h"
#include "np_handler.h" #include "np_handler.h"
#include "Emu/NP/vport0.h" #include "Emu/NP/vport0.h"
#include "Emu/NP/np_helpers.h"
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
@ -102,17 +103,15 @@ void signaling_handler::signal_ext_sig_callback(u32 conn_id, int event) const
void signaling_handler::signal_sig2_callback(u64 room_id, u16 member_id, SceNpMatching2Event event) const void signaling_handler::signal_sig2_callback(u64 room_id, u16 member_id, SceNpMatching2Event event) const
{ {
// Signal the callback if (room_id && sig2_cb)
if (sig2_cb)
{ {
sysutil_register_cb([sig2_cb = this->sig2_cb, sig2_cb_ctx = this->sig2_cb_ctx, room_id, member_id, event, sig2_cb_arg = this->sig2_cb_arg](ppu_thread& cb_ppu) -> s32 sysutil_register_cb([sig2_cb = this->sig2_cb, sig2_cb_ctx = this->sig2_cb_ctx, room_id, member_id, event, sig2_cb_arg = this->sig2_cb_arg](ppu_thread& cb_ppu) -> s32
{ {
sig2_cb(cb_ppu, sig2_cb_ctx, room_id, member_id, event, 0, sig2_cb_arg); sig2_cb(cb_ppu, sig2_cb_ctx, room_id, member_id, event, 0, sig2_cb_arg);
return 0; return 0;
}); });
}
sign_log.notice("Called sig2 CB: 0x%x (room_id: %d, member_id: %d)", event, room_id, member_id); sign_log.notice("Called sig2 CB: 0x%x (room_id: %d, member_id: %d)", event, room_id, member_id);
}
} }
/////////////////////////////////// ///////////////////////////////////
@ -164,9 +163,21 @@ bool signaling_handler::validate_signaling_packet(const signaling_packet* sp)
return false; return false;
} }
if (sp->version != 1u && sp->version != 2u) if (sp->version != SIGNALING_VERSION)
{ {
sign_log.error("Invalid version in signaling packet"); sign_log.error("Invalid version in signaling packet: %d, expected: %d", sp->version, SIGNALING_VERSION);
if (sp->version > SIGNALING_VERSION)
sign_log.error("You are most likely using an outdated version of RPCS3");
else
sign_log.error("The other user is most likely using an outdated version of RPCS3");
return false;
}
if (!np::is_valid_npid(sp->npid))
{
sign_log.error("Invalid npid in signaling packet");
return false; return false;
} }
@ -187,57 +198,36 @@ void signaling_handler::process_incoming_messages()
auto op_addr = msg.src_addr; auto op_addr = msg.src_addr;
auto op_port = msg.src_port; auto op_port = msg.src_port;
auto* sp = reinterpret_cast<const signaling_packet*>(msg.data.data()); const auto* sp = reinterpret_cast<const signaling_packet*>(msg.data.data());
if (!validate_signaling_packet(sp)) if (!validate_signaling_packet(sp))
continue; continue;
if (sign_log.trace) if (sign_log.trace)
{ {
in_addr addr; in_addr addr{};
addr.s_addr = op_addr; addr.s_addr = op_addr;
if (sp->version == 1u)
{
char npid_buf[17]{};
memcpy(npid_buf, sp->V1.npid.handle.data, 16);
std::string npid(npid_buf);
char ip_str[16]; char ip_str[16];
inet_ntop(AF_INET, &addr, ip_str, sizeof(ip_str)); inet_ntop(AF_INET, &addr, ip_str, sizeof(ip_str));
std::string_view npid(sp->npid.handle.data);
sign_log.trace("sig1 %s from %s:%d(%s)", sp->command, ip_str, op_port, npid); sign_log.trace("SP %s from %s:%d(npid: %s)", sp->command, ip_str, op_port, npid);
}
else
{
char inet_addr[16];
const char* inet_addr_string = inet_ntop(AF_INET, &addr, inet_addr, sizeof(inet_addr));
sign_log.trace("sig2 %s from %s:%d(%d:%d)", sp->command, inet_addr_string, op_port, sp->V2.room_id, sp->V2.member_id);
}
} }
bool reply = false, schedule_repeat = false; bool reply = false, schedule_repeat = false;
auto& sent_packet = sp->version == 1u ? sig1_packet : sig2_packet; auto& sent_packet = sig_packet;
// Get signaling info for user to know if we should even bother looking further // Get signaling info for user to know if we should even bother looking further
auto si = get_signaling_ptr(sp); auto si = get_signaling_ptr(sp);
if (!si && sp->version == 1u && sp->command == signal_connect) if (!si && sp->command == signal_connect)
{ {
// Connection can be remotely established and not mutual // Connection can be remotely established and not mutual
const u32 conn_id = create_sig_infos(&sp->V1.npid); const u32 conn_id = get_always_conn_id(sp->npid);
si = ::at32(sig1_peers, conn_id); si = ::at32(sig_peers, conn_id);
// Activate the connection without triggering the main CB
si->connStatus = SCE_NP_SIGNALING_CONN_STATUS_ACTIVE;
si->addr = op_addr;
si->port = op_port;
si->ext_status = ext_sign_peer;
// Notify extended callback that peer activated
signal_ext_sig_callback(conn_id, SCE_NP_SIGNALING_EVENT_EXT_PEER_ACTIVATED);
} }
if (!si || (si->connStatus == SCE_NP_SIGNALING_CONN_STATUS_INACTIVE && sp->command != signal_finished)) if (!si && sp->command != signal_finished)
{ {
// User is unknown to us or the connection is inactive // User is unknown to us or the connection is inactive
// Ignore packet unless it's a finished packet in case the finished_ack wasn't received by opponent // Ignore packet unless it's a finished packet in case the finished_ack wasn't received by opponent
@ -300,7 +290,7 @@ void signaling_handler::process_incoming_messages()
sent_packet.command = signal_connect_ack; sent_packet.command = signal_connect_ack;
sent_packet.timestamp_sender = sp->timestamp_sender; sent_packet.timestamp_sender = sp->timestamp_sender;
sent_packet.timestamp_receiver = now.time_since_epoch().count(); sent_packet.timestamp_receiver = now.time_since_epoch().count();
// connection is established update_si_addr(si, op_addr, op_port);
break; break;
case signal_connect_ack: case signal_connect_ack:
update_rtt(sp->timestamp_sender); update_rtt(sp->timestamp_sender);
@ -310,7 +300,6 @@ void signaling_handler::process_incoming_messages()
sent_packet.command = signal_confirm; sent_packet.command = signal_confirm;
sent_packet.timestamp_receiver = now.time_since_epoch().count(); sent_packet.timestamp_receiver = now.time_since_epoch().count();
retire_packet(si, signal_connect); retire_packet(si, signal_connect);
// connection is active
update_si_addr(si, op_addr, op_port); update_si_addr(si, op_addr, op_port);
update_si_mapped_addr(si, sp->sent_addr, sp->sent_port); update_si_mapped_addr(si, sp->sent_addr, sp->sent_port);
update_si_status(si, SCE_NP_SIGNALING_CONN_STATUS_ACTIVE); update_si_status(si, SCE_NP_SIGNALING_CONN_STATUS_ACTIVE);
@ -321,21 +310,20 @@ void signaling_handler::process_incoming_messages()
schedule_repeat = false; schedule_repeat = false;
setup_ping(); setup_ping();
retire_packet(si, signal_connect_ack); retire_packet(si, signal_connect_ack);
// connection is active
update_si_addr(si, op_addr, op_port); update_si_addr(si, op_addr, op_port);
update_si_mapped_addr(si, sp->sent_addr, sp->sent_port); update_si_mapped_addr(si, sp->sent_addr, sp->sent_port);
update_si_status(si, SCE_NP_SIGNALING_CONN_STATUS_ACTIVE, true); update_ext_si_status(si, true);
break; break;
case signal_finished: case signal_finished:
reply = true; reply = true;
schedule_repeat = false; schedule_repeat = false;
sent_packet.command = signal_finished_ack; sent_packet.command = signal_finished_ack;
// terminate connection update_ext_si_status(si, false);
update_si_status(si, SCE_NP_SIGNALING_CONN_STATUS_INACTIVE);
break; break;
case signal_finished_ack: case signal_finished_ack:
reply = false; reply = false;
schedule_repeat = false; schedule_repeat = false;
update_si_status(si, SCE_NP_SIGNALING_CONN_STATUS_INACTIVE);
retire_packet(si, signal_finished); retire_packet(si, signal_finished);
break; break;
default: sign_log.error("Invalid signaling command received"); continue; default: sign_log.error("Invalid signaling command received"); continue;
@ -369,37 +357,39 @@ void signaling_handler::operator()()
for (auto it = qpackets.begin(); it != qpackets.end();) for (auto it = qpackets.begin(); it != qpackets.end();)
{ {
if (it->first > now) auto& [timestamp, sig] = *it;
if (timestamp > now)
break; break;
if (it->second.sig_info->time_last_msg_recvd < now - 60s) if (sig.sig_info->time_last_msg_recvd < now - 60s)
{ {
// We had no connection to opponent for 60 seconds, consider the connection dead // We had no connection to opponent for 60 seconds, consider the connection dead
sign_log.trace("Timeout disconnection"); sign_log.notice("Timeout disconnection");
update_si_status(it->second.sig_info, SCE_NP_SIGNALING_CONN_STATUS_INACTIVE); update_si_status(sig.sig_info, SCE_NP_SIGNALING_CONN_STATUS_INACTIVE);
break; // qpackets will be emptied of all packets from this user so we're requeuing break; // qpackets will be emptied of all packets for this user so we're requeuing
} }
// Update the timestamp if necessary // Update the timestamp if necessary
switch (it->second.packet.command) switch (sig.packet.command)
{ {
case signal_connect: case signal_connect:
case signal_ping: case signal_ping:
it->second.packet.timestamp_sender = now.time_since_epoch().count(); sig.packet.timestamp_sender = now.time_since_epoch().count();
break; break;
case signal_connect_ack: case signal_connect_ack:
it->second.packet.timestamp_receiver = now.time_since_epoch().count(); sig.packet.timestamp_receiver = now.time_since_epoch().count();
break; break;
default: default:
break; break;
} }
// Resend the packet // Resend the packet
send_signaling_packet(it->second.packet, it->second.sig_info->addr, it->second.sig_info->port); send_signaling_packet(sig.packet, sig.sig_info->addr, sig.sig_info->port);
// Reschedule another packet // Reschedule another packet
SignalingCommand cmd = it->second.packet.command; SignalingCommand cmd = sig.packet.command;
auto& si = it->second.sig_info; auto& si = sig.sig_info;
std::chrono::milliseconds delay(500); std::chrono::milliseconds delay(500);
switch (cmd) switch (cmd)
@ -441,6 +431,8 @@ void signaling_handler::update_si_addr(std::shared_ptr<signaling_info>& si, u32
ensure(si); ensure(si);
if (si->addr != new_addr || si->port != new_port) if (si->addr != new_addr || si->port != new_port)
{
if (sign_log.trace)
{ {
in_addr addr_old, addr_new; in_addr addr_old, addr_new;
addr_old.s_addr = si->addr; addr_old.s_addr = si->addr;
@ -452,6 +444,8 @@ void signaling_handler::update_si_addr(std::shared_ptr<signaling_info>& si, u32
inet_ntop(AF_INET, &addr_new, ip_str_new, sizeof(ip_str_new)); inet_ntop(AF_INET, &addr_new, ip_str_new, sizeof(ip_str_new));
sign_log.trace("Updated Address from %s:%d to %s:%d", ip_str_old, si->port, ip_str_new, new_port); sign_log.trace("Updated Address from %s:%d to %s:%d", ip_str_old, si->port, ip_str_new, new_port);
}
si->addr = new_addr; si->addr = new_addr;
si->port = new_port; si->port = new_port;
} }
@ -461,7 +455,9 @@ void signaling_handler::update_si_mapped_addr(std::shared_ptr<signaling_info>& s
{ {
ensure(si); ensure(si);
if (si->addr != new_addr || si->port != new_port) if (si->mapped_addr != new_addr || si->mapped_port != new_port)
{
if (sign_log.trace)
{ {
in_addr addr_old, addr_new; in_addr addr_old, addr_new;
addr_old.s_addr = si->mapped_addr; addr_old.s_addr = si->mapped_addr;
@ -473,59 +469,60 @@ void signaling_handler::update_si_mapped_addr(std::shared_ptr<signaling_info>& s
inet_ntop(AF_INET, &addr_new, ip_str_new, sizeof(ip_str_new)); inet_ntop(AF_INET, &addr_new, ip_str_new, sizeof(ip_str_new));
sign_log.trace("Updated Mapped Address from %s:%d to %s:%d", ip_str_old, si->mapped_port, ip_str_new, new_port); sign_log.trace("Updated Mapped Address from %s:%d to %s:%d", ip_str_old, si->mapped_port, ip_str_new, new_port);
}
si->mapped_addr = new_addr; si->mapped_addr = new_addr;
si->mapped_port = new_port; si->mapped_port = new_port;
} }
} }
void signaling_handler::update_si_status(std::shared_ptr<signaling_info>& si, s32 new_status, bool confirm_packet) void signaling_handler::update_si_status(std::shared_ptr<signaling_info>& si, s32 new_status)
{ {
if (!si) if (!si)
return; return;
if (si->connStatus == SCE_NP_SIGNALING_CONN_STATUS_PENDING && new_status == SCE_NP_SIGNALING_CONN_STATUS_ACTIVE) if (si->conn_status == SCE_NP_SIGNALING_CONN_STATUS_PENDING && new_status == SCE_NP_SIGNALING_CONN_STATUS_ACTIVE)
{ {
si->connStatus = SCE_NP_SIGNALING_CONN_STATUS_ACTIVE; si->conn_status = SCE_NP_SIGNALING_CONN_STATUS_ACTIVE;
ensure(si->version == 1u || si->version == 2u);
if (si->version == 1u)
signal_sig_callback(si->conn_id, SCE_NP_SIGNALING_EVENT_ESTABLISHED); signal_sig_callback(si->conn_id, SCE_NP_SIGNALING_EVENT_ESTABLISHED);
else
signal_sig2_callback(si->room_id, si->member_id, SCE_NP_MATCHING2_SIGNALING_EVENT_Established); signal_sig2_callback(si->room_id, si->member_id, SCE_NP_MATCHING2_SIGNALING_EVENT_Established);
return; if (si->op_activated)
}
if ((si->connStatus == SCE_NP_SIGNALING_CONN_STATUS_PENDING || si->connStatus == SCE_NP_SIGNALING_CONN_STATUS_ACTIVE) && new_status == SCE_NP_SIGNALING_CONN_STATUS_INACTIVE)
{
si->connStatus = SCE_NP_SIGNALING_CONN_STATUS_INACTIVE;
ensure(si->version == 1u || si->version == 2u);
if (si->version == 1u)
signal_sig_callback(si->conn_id, SCE_NP_SIGNALING_EVENT_DEAD);
else
signal_sig2_callback(si->room_id, si->member_id, SCE_NP_MATCHING2_SIGNALING_EVENT_Dead);
retire_all_packets(si);
return;
}
if (confirm_packet && si->version == 1u && si->ext_status == ext_sign_none)
{
si->ext_status = ext_sign_mutual;
signal_ext_sig_callback(si->conn_id, SCE_NP_SIGNALING_EVENT_EXT_MUTUAL_ACTIVATED); signal_ext_sig_callback(si->conn_id, SCE_NP_SIGNALING_EVENT_EXT_MUTUAL_ACTIVATED);
} }
else if ((si->conn_status == SCE_NP_SIGNALING_CONN_STATUS_PENDING || si->conn_status == SCE_NP_SIGNALING_CONN_STATUS_ACTIVE) && new_status == SCE_NP_SIGNALING_CONN_STATUS_INACTIVE)
{
si->conn_status = SCE_NP_SIGNALING_CONN_STATUS_INACTIVE;
signal_sig_callback(si->conn_id, SCE_NP_SIGNALING_EVENT_DEAD);
signal_sig2_callback(si->room_id, si->member_id, SCE_NP_MATCHING2_SIGNALING_EVENT_Dead);
retire_all_packets(si);
}
}
void signaling_handler::update_ext_si_status(std::shared_ptr<signaling_info>& si, bool op_activated)
{
if (op_activated && !si->op_activated)
{
si->op_activated = true;
if (si->conn_status != SCE_NP_SIGNALING_CONN_STATUS_ACTIVE)
signal_ext_sig_callback(si->conn_id, SCE_NP_SIGNALING_EVENT_EXT_PEER_ACTIVATED);
else
signal_ext_sig_callback(si->conn_id, SCE_NP_SIGNALING_EVENT_EXT_MUTUAL_ACTIVATED);
}
else if (!op_activated && si->op_activated)
{
si->op_activated = false;
signal_ext_sig_callback(si->conn_id, SCE_NP_SIGNALING_EVENT_EXT_PEER_DEACTIVATED);
}
} }
void signaling_handler::set_self_sig_info(SceNpId& npid) void signaling_handler::set_self_sig_info(SceNpId& npid)
{ {
std::lock_guard lock(data_mutex); std::lock_guard lock(data_mutex);
sig1_packet.V1.npid = npid; sig_packet.npid = npid;
}
void signaling_handler::set_self_sig2_info(u64 room_id, u16 member_id)
{
std::lock_guard lock(data_mutex);
sig2_packet.V2.room_id = room_id;
sig2_packet.V2.member_id = member_id;
} }
void signaling_handler::send_signaling_packet(signaling_packet& sp, u32 addr, u16 port) const void signaling_handler::send_signaling_packet(signaling_packet& sp, u32 addr, u16 port) const
@ -564,49 +561,35 @@ void signaling_handler::queue_signaling_packet(signaling_packet& sp, std::shared
std::shared_ptr<signaling_info> signaling_handler::get_signaling_ptr(const signaling_packet* sp) std::shared_ptr<signaling_info> signaling_handler::get_signaling_ptr(const signaling_packet* sp)
{ {
// V1 u32 conn_id;
if (sp->version == 1u)
{
char npid_buf[17]{}; char npid_buf[17]{};
memcpy(npid_buf, sp->V1.npid.handle.data, 16); memcpy(npid_buf, sp->npid.handle.data, 16);
std::string npid(npid_buf); std::string npid(npid_buf);
if (!npid_to_conn_id.contains(npid)) if (!npid_to_conn_id.contains(npid))
return nullptr; return nullptr;
const u32 conn_id = ::at32(npid_to_conn_id, npid); conn_id = ::at32(npid_to_conn_id, npid);
if (!sig1_peers.contains(conn_id))
if (!sig_peers.contains(conn_id))
{ {
sign_log.error("Discrepancy in signaling 1 data"); sign_log.error("Discrepancy in signaling data");
return nullptr; return nullptr;
} }
return ::at32(sig1_peers, conn_id); return ::at32(sig_peers, conn_id);
}
// V2
auto room_id = sp->V2.room_id;
auto member_id = sp->V2.member_id;
if (!sig2_peers.contains(room_id) || !::at32(sig2_peers, room_id).contains(member_id))
return nullptr;
return ::at32(::at32(sig2_peers, room_id), member_id);
} }
void signaling_handler::start_sig(u32 conn_id, u32 addr, u16 port) void signaling_handler::start_sig(u32 conn_id, u32 addr, u16 port)
{ {
std::lock_guard lock(data_mutex); std::lock_guard lock(data_mutex);
start_sig_nl(conn_id, addr, port); auto& sent_packet = sig_packet;
}
void signaling_handler::start_sig_nl(u32 conn_id, u32 addr, u16 port)
{
auto& sent_packet = sig1_packet;
sent_packet.command = signal_connect; sent_packet.command = signal_connect;
sent_packet.timestamp_sender = steady_clock::now().time_since_epoch().count(); sent_packet.timestamp_sender = steady_clock::now().time_since_epoch().count();
ensure(sig1_peers.contains(conn_id)); ensure(sig_peers.contains(conn_id));
std::shared_ptr<signaling_info> si = ::at32(sig1_peers, conn_id); std::shared_ptr<signaling_info> si = ::at32(sig_peers, conn_id);
si->addr = addr; si->addr = addr;
si->port = port; si->port = port;
@ -616,133 +599,113 @@ void signaling_handler::start_sig_nl(u32 conn_id, u32 addr, u16 port)
wake_up(); wake_up();
} }
void signaling_handler::stop_sig_nl(u32 conn_id)
{
if (!sig_peers.contains(conn_id))
return;
auto& sent_packet = sig_packet;
sent_packet.command = signal_finished;
std::shared_ptr<signaling_info> si = ::at32(sig_peers, conn_id);
send_signaling_packet(sent_packet, si->addr, si->port);
queue_signaling_packet(sent_packet, std::move(si), steady_clock::now() + REPEAT_FINISHED_DELAY);
}
void signaling_handler::stop_sig(u32 conn_id) void signaling_handler::stop_sig(u32 conn_id)
{ {
std::lock_guard lock(data_mutex); std::lock_guard lock(data_mutex);
if (!sig1_peers.contains(conn_id)) stop_sig_nl(conn_id);
return;
auto& sent_packet = sig1_packet;
sent_packet.command = signal_finished;
std::shared_ptr<signaling_info> si = ::at32(sig1_peers, conn_id);
send_signaling_packet(sent_packet, si->addr, si->port);
queue_signaling_packet(sent_packet, si, steady_clock::now() + REPEAT_FINISHED_DELAY);
}
void signaling_handler::start_sig2(u64 room_id, u16 member_id)
{
std::lock_guard lock(data_mutex);
auto& sent_packet = sig2_packet;
sent_packet.command = signal_connect;
sent_packet.timestamp_sender = steady_clock::now().time_since_epoch().count();
ensure(sig2_peers.contains(room_id));
const auto& sp = ::at32(sig2_peers, room_id);
ensure(sp.contains(member_id));
std::shared_ptr<signaling_info> si = ::at32(sp, member_id);
send_signaling_packet(sent_packet, si->addr, si->port);
queue_signaling_packet(sent_packet, si, steady_clock::now() + REPEAT_CONNECT_DELAY);
wake_up();
} }
void signaling_handler::disconnect_sig2_users(u64 room_id) void signaling_handler::disconnect_sig2_users(u64 room_id)
{ {
std::lock_guard lock(data_mutex); std::lock_guard lock(data_mutex);
if (!sig2_peers.contains(room_id)) for (auto& [conn_id, si] : sig_peers)
return;
auto& sent_packet = sig2_packet;
sent_packet.command = signal_finished;
for (const auto& member : ::at32(sig2_peers, room_id))
{ {
auto& si = member.second; if (si->room_id == room_id)
if (si->connStatus != SCE_NP_SIGNALING_CONN_STATUS_INACTIVE && !si->self)
{ {
send_signaling_packet(sent_packet, si->addr, si->port); stop_sig_nl(conn_id);
queue_signaling_packet(sent_packet, si, steady_clock::now() + REPEAT_FINISHED_DELAY);
} }
} }
} }
u32 signaling_handler::create_sig_infos(const SceNpId* npid) u32 signaling_handler::get_always_conn_id(const SceNpId& npid)
{ {
ensure(npid->handle.data[16] == 0); std::string npid_str(reinterpret_cast<const char*>(npid.handle.data));
std::string npid_str(reinterpret_cast<const char*>(npid->handle.data));
if (npid_to_conn_id.contains(npid_str)) if (npid_to_conn_id.contains(npid_str))
{
return ::at32(npid_to_conn_id, npid_str); return ::at32(npid_to_conn_id, npid_str);
}
const u32 conn_id = cur_conn_id++; const u32 conn_id = cur_conn_id++;
npid_to_conn_id.emplace(npid_str, conn_id); npid_to_conn_id.emplace(std::move(npid_str), conn_id);
sig1_peers.emplace(conn_id, std::make_shared<signaling_info>()); sig_peers.emplace(conn_id, std::make_shared<signaling_info>());
::at32(sig1_peers, conn_id)->version = 1; auto& si = ::at32(sig_peers, conn_id);
::at32(sig1_peers, conn_id)->conn_id = conn_id; si->conn_id = conn_id;
::at32(sig1_peers, conn_id)->npid = *npid; si->npid = npid;
return conn_id; return conn_id;
} }
u32 signaling_handler::init_sig_infos(const SceNpId* npid) u32 signaling_handler::init_sig1(const SceNpId& npid)
{ {
std::lock_guard lock(data_mutex); std::lock_guard lock(data_mutex);
const u32 conn_id = create_sig_infos(npid); const u32 conn_id = get_always_conn_id(npid);
if (sig1_peers[conn_id]->connStatus == SCE_NP_SIGNALING_CONN_STATUS_INACTIVE) if (sig_peers[conn_id]->conn_status == SCE_NP_SIGNALING_CONN_STATUS_INACTIVE)
{ {
sign_log.trace("Creating new sig1 connection and requesting infos from RPCN"); sign_log.trace("Creating new sig1 connection and requesting infos from RPCN");
sig1_peers[conn_id]->connStatus = SCE_NP_SIGNALING_CONN_STATUS_PENDING; sig_peers[conn_id]->conn_status = SCE_NP_SIGNALING_CONN_STATUS_PENDING;
// Request peer infos from RPCN // Request peer infos from RPCN
std::string npid_str(reinterpret_cast<const char*>(npid->handle.data)); std::string npid_str(reinterpret_cast<const char*>(npid.handle.data));
auto& nph = g_fxo->get<named_thread<np::np_handler>>(); auto& nph = g_fxo->get<named_thread<np::np_handler>>();
nph.req_sign_infos(npid_str, conn_id); nph.req_sign_infos(npid_str, conn_id);
} }
else
{
// Connection already exists(from passive connection)
if (sig1_peers[conn_id]->connStatus == SCE_NP_SIGNALING_CONN_STATUS_ACTIVE && sig1_peers[conn_id]->ext_status == ext_sign_peer)
{
sign_log.trace("Activating already peer activated connection");
sig1_peers[conn_id]->ext_status = ext_sign_mutual;
start_sig_nl(conn_id, sig1_peers[conn_id]->addr, sig1_peers[conn_id]->port);
signal_sig_callback(conn_id, SCE_NP_SIGNALING_EVENT_ESTABLISHED);
signal_ext_sig_callback(conn_id, SCE_NP_SIGNALING_EVENT_EXT_MUTUAL_ACTIVATED);
}
}
return conn_id; return conn_id;
} }
signaling_info signaling_handler::get_sig_infos(u32 conn_id) u32 signaling_handler::init_sig2(const SceNpId& npid, u64 room_id, u16 member_id)
{ {
std::lock_guard lock(data_mutex); std::lock_guard lock(data_mutex);
return *sig1_peers[conn_id]; u32 conn_id = get_always_conn_id(npid);
auto& si = ::at32(sig_peers, conn_id);
si->room_id = room_id;
si->member_id = member_id;
si->conn_status = SCE_NP_SIGNALING_CONN_STATUS_PENDING;
return conn_id;
} }
std::optional<u32> signaling_handler::get_conn_id_from_npid(const SceNpId* npid) std::optional<u32> signaling_handler::get_conn_id_from_npid(const SceNpId& npid)
{ {
std::lock_guard lock(data_mutex); std::lock_guard lock(data_mutex);
// Diff behaviour here depending on SDK version, 420+ always succeeds
return create_sig_infos(npid); std::string npid_str(reinterpret_cast<const char*>(npid.handle.data));
if (npid_to_conn_id.contains(npid_str))
return ::at32(npid_to_conn_id, npid_str);
return std::nullopt;
}
std::optional<signaling_info> signaling_handler::get_sig_infos(u32 conn_id)
{
std::lock_guard lock(data_mutex);
if (sig_peers.contains(conn_id))
return *::at32(sig_peers, conn_id);
return std::nullopt;
} }
std::optional<u32> signaling_handler::get_conn_id_from_addr(u32 addr, u16 port) std::optional<u32> signaling_handler::get_conn_id_from_addr(u32 addr, u16 port)
{ {
std::lock_guard lock(data_mutex); std::lock_guard lock(data_mutex);
for (const auto& [conn_id, conn_info] : sig1_peers) for (const auto& [conn_id, conn_info] : sig_peers)
{ {
if (conn_info && std::bit_cast<u32, be_t<u32>>(conn_info->addr) == addr && conn_info->port == port) if (conn_info && std::bit_cast<u32, be_t<u32>>(conn_info->addr) == addr && conn_info->port == port)
{ {
@ -752,36 +715,3 @@ std::optional<u32> signaling_handler::get_conn_id_from_addr(u32 addr, u16 port)
return std::nullopt; return std::nullopt;
} }
void signaling_handler::set_sig2_infos(u64 room_id, u16 member_id, s32 status, u32 addr, u16 port, const SceNpId& npid, bool self)
{
std::lock_guard lock(data_mutex);
if (!sig2_peers[room_id][member_id])
sig2_peers[room_id][member_id] = std::make_shared<signaling_info>();
auto& peer = sig2_peers[room_id][member_id];
peer->connStatus = status;
peer->addr = addr;
peer->port = port;
peer->self = self;
peer->version = 2;
peer->room_id = room_id;
peer->member_id = member_id;
peer->npid = npid;
}
signaling_info signaling_handler::get_sig2_infos(u64 room_id, u16 member_id)
{
std::lock_guard lock(data_mutex);
if (!sig2_peers[room_id][member_id])
{
sig2_peers[room_id][member_id] = std::make_shared<signaling_info>();
auto& peer = sig2_peers[room_id][member_id];
peer->room_id = room_id;
peer->member_id = member_id;
peer->version = 2;
}
return *sig2_peers[room_id][member_id];
}

View File

@ -9,16 +9,9 @@
#include <chrono> #include <chrono>
#include <optional> #include <optional>
enum ext_signaling_status : u8
{
ext_sign_none = 0,
ext_sign_peer = 1,
ext_sign_mutual = 2,
};
struct signaling_info struct signaling_info
{ {
s32 connStatus = SCE_NP_SIGNALING_CONN_STATUS_INACTIVE; s32 conn_status = SCE_NP_SIGNALING_CONN_STATUS_INACTIVE;
u32 addr = 0; u32 addr = 0;
u16 port = 0; u16 port = 0;
@ -29,12 +22,11 @@ struct signaling_info
// For handler // For handler
steady_clock::time_point time_last_msg_recvd = steady_clock::now(); steady_clock::time_point time_last_msg_recvd = steady_clock::now();
bool self = false; bool self = false;
u32 version = 0;
SceNpId npid{}; SceNpId npid{};
// Signaling // Signaling
u32 conn_id = 0; u32 conn_id = 0;
ext_signaling_status ext_status = ext_sign_none; bool op_activated = false;
// Matching2 // Matching2
u64 room_id = 0; u64 room_id = 0;
@ -68,16 +60,13 @@ public:
signaling_handler& operator=(thread_state); signaling_handler& operator=(thread_state);
void set_self_sig_info(SceNpId& npid); void set_self_sig_info(SceNpId& npid);
void set_self_sig2_info(u64 room_id, u16 member_id);
u32 init_sig_infos(const SceNpId* npid); u32 init_sig1(const SceNpId& npid);
signaling_info get_sig_infos(u32 conn_id); u32 init_sig2(const SceNpId& npid, u64 room_id, u16 member_id);
std::optional<u32> get_conn_id_from_npid(const SceNpId* npid); std::optional<signaling_info> get_sig_infos(u32 conn_id);
std::optional<u32> get_conn_id_from_npid(const SceNpId& npid);
std::optional<u32> get_conn_id_from_addr(u32 addr, u16 port); std::optional<u32> get_conn_id_from_addr(u32 addr, u16 port);
void set_sig2_infos(u64 room_id, u16 member_id, s32 status, u32 addr, u16 port, const SceNpId& npid, bool self = false);
signaling_info get_sig2_infos(u64 room_id, u16 member_id);
void set_sig_cb(u32 sig_cb_ctx, vm::ptr<SceNpSignalingHandler> sig_cb, vm::ptr<void> sig_cb_arg); void set_sig_cb(u32 sig_cb_ctx, vm::ptr<SceNpSignalingHandler> sig_cb, vm::ptr<void> sig_cb_arg);
void set_ext_sig_cb(u32 sig_ext_cb_ctx, vm::ptr<SceNpSignalingHandler> sig_ext_cb, vm::ptr<void> sig_ext_cb_arg); void set_ext_sig_cb(u32 sig_ext_cb_ctx, vm::ptr<SceNpSignalingHandler> sig_ext_cb, vm::ptr<void> sig_ext_cb_arg);
void set_sig2_cb(u16 sig2_cb_ctx, vm::ptr<SceNpMatching2SignalingCallback> sig2_cb, vm::ptr<void> sig2_cb_arg); void set_sig2_cb(u16 sig2_cb_ctx, vm::ptr<SceNpMatching2SignalingCallback> sig2_cb, vm::ptr<void> sig2_cb_arg);
@ -95,28 +84,18 @@ private:
static constexpr auto REPEAT_PING_DELAY = std::chrono::milliseconds(500); static constexpr auto REPEAT_PING_DELAY = std::chrono::milliseconds(500);
static constexpr auto REPEAT_FINISHED_DELAY = std::chrono::milliseconds(500); static constexpr auto REPEAT_FINISHED_DELAY = std::chrono::milliseconds(500);
static constexpr be_t<u32> SIGNALING_SIGNATURE = (static_cast<u32>('S') << 24 | static_cast<u32>('I') << 16 | static_cast<u32>('G') << 8 | static_cast<u32>('N')); static constexpr be_t<u32> SIGNALING_SIGNATURE = (static_cast<u32>('S') << 24 | static_cast<u32>('I') << 16 | static_cast<u32>('G') << 8 | static_cast<u32>('N'));
static constexpr le_t<u32> SIGNALING_VERSION = 3;
struct signaling_packet struct signaling_packet
{ {
be_t<u32> signature = SIGNALING_SIGNATURE; be_t<u32> signature = SIGNALING_SIGNATURE;
le_t<u32> version; le_t<u32> version = SIGNALING_VERSION;
le_t<u64> timestamp_sender; le_t<u64> timestamp_sender;
le_t<u64> timestamp_receiver; le_t<u64> timestamp_receiver;
le_t<SignalingCommand> command; le_t<SignalingCommand> command;
le_t<u32> sent_addr; le_t<u32> sent_addr;
le_t<u16> sent_port; le_t<u16> sent_port;
union
{
struct
{
SceNpId npid; SceNpId npid;
} V1;
struct
{
le_t<u64> room_id;
le_t<u16> member_id;
} V2;
};
}; };
struct queued_packet struct queued_packet
@ -137,33 +116,32 @@ private:
vm::ptr<SceNpMatching2SignalingCallback> sig2_cb{}; vm::ptr<SceNpMatching2SignalingCallback> sig2_cb{};
vm::ptr<void> sig2_cb_arg{}; vm::ptr<void> sig2_cb_arg{};
u32 create_sig_infos(const SceNpId* npid); u32 get_always_conn_id(const SceNpId& npid);
static void update_si_addr(std::shared_ptr<signaling_info>& si, u32 new_addr, u16 new_port); static void update_si_addr(std::shared_ptr<signaling_info>& si, u32 new_addr, u16 new_port);
static void update_si_mapped_addr(std::shared_ptr<signaling_info>& si, u32 new_addr, u16 new_port); static void update_si_mapped_addr(std::shared_ptr<signaling_info>& si, u32 new_addr, u16 new_port);
void update_si_status(std::shared_ptr<signaling_info>& si, s32 new_status, bool confirm_packet = false); static void update_room_info(std::shared_ptr<signaling_info>& si, u64 room_id, u16 member_id);
void update_si_status(std::shared_ptr<signaling_info>& si, s32 new_status);
void update_ext_si_status(std::shared_ptr<signaling_info>& si, bool op_activated);
void signal_sig_callback(u32 conn_id, int event); void signal_sig_callback(u32 conn_id, int event);
void signal_ext_sig_callback(u32 conn_id, int event) const; void signal_ext_sig_callback(u32 conn_id, int event) const;
void signal_sig2_callback(u64 room_id, u16 member_id, SceNpMatching2Event event) const; void signal_sig2_callback(u64 room_id, u16 member_id, SceNpMatching2Event event) const;
void start_sig_nl(u32 conn_id, u32 addr, u16 port);
static bool validate_signaling_packet(const signaling_packet* sp); static bool validate_signaling_packet(const signaling_packet* sp);
void reschedule_packet(std::shared_ptr<signaling_info>& si, SignalingCommand cmd, steady_clock::time_point new_timepoint); void reschedule_packet(std::shared_ptr<signaling_info>& si, SignalingCommand cmd, steady_clock::time_point new_timepoint);
void retire_packet(std::shared_ptr<signaling_info>& si, SignalingCommand cmd); void retire_packet(std::shared_ptr<signaling_info>& si, SignalingCommand cmd);
void retire_all_packets(std::shared_ptr<signaling_info>& si); void retire_all_packets(std::shared_ptr<signaling_info>& si);
void stop_sig_nl(u32 conn_id);
std::mutex data_mutex; std::mutex data_mutex;
std::condition_variable wakey; std::condition_variable wakey;
signaling_packet sig1_packet{.version = 1u}; signaling_packet sig_packet{};
signaling_packet sig2_packet{.version = 2u};
std::map<steady_clock::time_point, queued_packet> qpackets; // (wakeup time, packet) std::map<steady_clock::time_point, queued_packet> qpackets; // (wakeup time, packet)
u32 cur_conn_id = 1; u32 cur_conn_id = 1;
std::unordered_map<std::string, u32> npid_to_conn_id; // (npid, conn_id) std::unordered_map<std::string, u32> npid_to_conn_id; // (npid, conn_id)
std::unordered_map<u32, std::shared_ptr<signaling_info>> sig1_peers; // (conn_id, sig_info) std::unordered_map<u32, std::shared_ptr<signaling_info>> sig_peers; // (conn_id, sig_info)
std::unordered_map<u64, std::unordered_map<u16, std::shared_ptr<signaling_info>>> sig2_peers; // (room (member_id, sig_info))
void process_incoming_messages(); void process_incoming_messages();
std::shared_ptr<signaling_info> get_signaling_ptr(const signaling_packet* sp); std::shared_ptr<signaling_info> get_signaling_ptr(const signaling_packet* sp);

View File

@ -0,0 +1,59 @@
#include "stdafx.h"
#include "upnp_config.h"
#include "Utilities/File.h"
LOG_CHANNEL(upnp_cfg_log, "UPNP_CFG");
void cfg_upnp::load()
{
const std::string path = cfg_upnp::get_path();
fs::file cfg_file(path, fs::read);
if (cfg_file)
{
upnp_cfg_log.notice("Loading UPNP config. Path: %s", path);
from_string(cfg_file.to_string());
}
else
{
upnp_cfg_log.notice("UPNP config missing. Using default settings. Path: %s", path);
from_default();
}
}
void cfg_upnp::save() const
{
#ifdef _WIN32
const std::string path_to_cfg = fs::get_config_dir() + "config/";
if (!fs::create_path(path_to_cfg))
{
upnp_cfg_log.error("Could not create path: %s", path_to_cfg);
}
#endif
fs::pending_file cfg_file(cfg_upnp::get_path());
if (!cfg_file.file || (cfg_file.file.write(to_string()), !cfg_file.commit()))
{
upnp_cfg_log.error("Could not save config: %s (error=%s)", cfg_upnp::get_path(), fs::g_tls_error);
}
}
std::string cfg_upnp::get_device_url() const
{
return device_url.to_string();
}
void cfg_upnp::set_device_url(std::string_view url)
{
device_url.from_string(url);
}
std::string cfg_upnp::get_path()
{
#ifdef _WIN32
return fs::get_config_dir() + "config/upnp.yml";
#else
return fs::get_config_dir() + "upnp.yml";
#endif
}

View File

@ -0,0 +1,18 @@
#pragma once
#include "Utilities/Config.h"
struct cfg_upnp : cfg::node
{
cfg::string device_url{this, "DeviceUrl", ""};
void load();
void save() const;
std::string get_device_url() const;
void set_device_url(std::string_view url);
private:
static std::string get_path();
};

View File

@ -0,0 +1,186 @@
#include "stdafx.h"
#include "upnp_handler.h"
#include "util/logs.hpp"
#include <miniwget.h>
#include <upnpcommands.h>
LOG_CHANNEL(upnp_log, "UPNP");
upnp_handler::~upnp_handler()
{
std::lock_guard lock(m_mutex);
for (const auto& [protocol, prot_bindings] : m_bindings)
{
for (const auto& [internal_port, external_port] : prot_bindings)
{
remove_port_redir_external(external_port, protocol);
}
}
m_active = false;
}
void upnp_handler::upnp_enable()
{
std::lock_guard lock(m_mutex);
m_cfg.load();
auto check_igd = [&](const char* url) -> bool
{
int desc_xml_size = 0;
int status_code = 0;
m_igd_data = {};
m_igd_urls = {};
char* desc_xml = static_cast<char*>(miniwget(url, &desc_xml_size, 1, &status_code));
if (!desc_xml)
return false;
parserootdesc(desc_xml, desc_xml_size, &m_igd_data);
free(desc_xml);
desc_xml = nullptr;
GetUPNPUrls(&m_igd_urls, &m_igd_data, url, 1);
return true;
};
std::string dev_url = m_cfg.get_device_url();
if (!dev_url.empty())
{
if (check_igd(dev_url.c_str()))
{
upnp_log.notice("Saved UPNP(%s) enabled", dev_url);
m_active = true;
return;
}
upnp_log.error("Saved UPNP(%s) isn't available anymore", dev_url);
}
upnp_log.notice("Starting UPNP search");
int upnperror = 0;
UPNPDev* devlist = upnpDiscover(2000, nullptr, nullptr, 0, 0, 2, &upnperror);
if (!devlist)
{
upnp_log.error("No UPNP device was found");
return;
}
const UPNPDev* dev = devlist;
for (; dev; dev = dev->pNext)
{
if (strstr(dev->st, "InternetGatewayDevice"))
break;
}
if (dev)
{
int desc_xml_size = 0;
int status_code = 0;
char* desc_xml = static_cast<char*>(miniwget(dev->descURL, &desc_xml_size, 1, &status_code));
if (desc_xml)
{
IGDdatas igd_data{};
UPNPUrls igd_urls{};
parserootdesc(desc_xml, desc_xml_size, &igd_data);
free(desc_xml);
desc_xml = nullptr;
GetUPNPUrls(&igd_urls, &igd_data, dev->descURL, 1);
upnp_log.notice("Found UPnP device type:%s at %s", dev->st, dev->descURL);
m_cfg.set_device_url(dev->descURL);
m_cfg.save();
m_active = true;
}
else
{
upnp_log.error("Failed to retrieve UPNP xml for %s", dev->descURL);
}
}
else
{
upnp_log.error("No UPNP IGD device was found");
}
freeUPNPDevlist(devlist);
}
void upnp_handler::add_port_redir(std::string_view addr, u16 internal_port, std::string_view protocol)
{
if (!m_active)
return;
std::lock_guard lock(m_mutex);
u16 external_port = internal_port;
std::string internal_port_str = fmt::format("%d", internal_port);
int res = 0;
for (u16 external_port = internal_port; external_port < internal_port + 100; external_port++)
{
std::string external_port_str = fmt::format("%d", external_port);
res = UPNP_AddPortMapping(m_igd_urls.controlURL, m_igd_data.first.servicetype, external_port_str.c_str(), internal_port_str.c_str(), addr.data(), "RPCS3", protocol.data(), nullptr, nullptr);
if (res == UPNPCOMMAND_SUCCESS)
{
m_bindings[std::string(protocol)][internal_port] = external_port;
upnp_log.notice("Successfully bound %s:%d(%s) to IGD:%d", addr, internal_port, protocol, external_port);
return;
}
// need more testing, may vary per router, etc, for now assume port conflict silently
// else if (res != 718) // ConflictInMappingEntry
// {
// upnp_log.error("Failed to bind %s:%d(%s) to IGD:%d: %d", addr, internal_port, protocol, external_port, res);
// return;
// }
}
upnp_log.error("Failed to bind %s:%d(%s) to IGD:(%d=>%d): %d", addr, internal_port, protocol, internal_port, external_port, res);
}
void upnp_handler::remove_port_redir(u16 internal_port, std::string_view protocol)
{
if (!m_active)
return;
std::lock_guard lock(m_mutex);
const std::string str_protocol(protocol);
if (!m_bindings.contains(str_protocol) || !::at32(m_bindings, str_protocol).contains(internal_port))
{
upnp_log.error("tried to unbind port mapping %d to IGD(%s) but it isn't bound", internal_port, protocol);
return;
}
const u16 external_port = ::at32(::at32(m_bindings, str_protocol), internal_port);
remove_port_redir_external(external_port, protocol);
ensure(::at32(m_bindings, str_protocol).erase(internal_port));
upnp_log.notice("Successfully deleted port mapping %d to IGD:%d(%s)", internal_port, external_port, protocol);
}
void upnp_handler::remove_port_redir_external(u16 external_port, std::string_view protocol, bool verbose)
{
const std::string str_ext_port = fmt::format("%d", external_port);
if (int res = UPNP_DeletePortMapping(m_igd_urls.controlURL, m_igd_data.first.servicetype, str_ext_port.c_str(), protocol.data(), nullptr); res != 0 && verbose)
upnp_log.error("Failed to delete port mapping IGD:%s(%s): %d", str_ext_port, protocol, res);
}
bool upnp_handler::is_active() const
{
return m_active;
}

View File

@ -0,0 +1,32 @@
#pragma once
#include <unordered_map>
#include <miniupnpc.h>
#include "upnp_config.h"
#include "Utilities/mutex.h"
class upnp_handler
{
public:
~upnp_handler();
void upnp_enable();
void add_port_redir(std::string_view addr, u16 internal_port, std::string_view protocol);
void remove_port_redir(u16 internal_port, std::string_view protocol);
bool is_active() const;
private:
void remove_port_redir_external(u16 external_port, std::string_view protocol, bool verbose = true);
private:
atomic_t<bool> m_active = false;
shared_mutex m_mutex;
cfg_upnp m_cfg;
IGDdatas m_igd_data{};
UPNPUrls m_igd_urls{};
std::unordered_map<std::string, std::unordered_map<u16, u16>> m_bindings;
};

View File

@ -298,6 +298,7 @@ struct cfg_root : cfg::node
cfg::string bind_address{this, "Bind address", "0.0.0.0"}; cfg::string bind_address{this, "Bind address", "0.0.0.0"};
cfg::string dns{this, "DNS address", "8.8.8.8"}; cfg::string dns{this, "DNS address", "8.8.8.8"};
cfg::string swap_list{this, "IP swap list", ""}; cfg::string swap_list{this, "IP swap list", ""};
cfg::_bool upnp_enabled{this, "UPNP Enabled", false};
cfg::_enum<np_psn_status> psn_status{this, "PSN status", np_psn_status::disabled}; cfg::_enum<np_psn_status> psn_status{this, "PSN status", np_psn_status::disabled};
} net{this}; } net{this};

View File

@ -40,10 +40,10 @@
<ItemDefinitionGroup> <ItemDefinitionGroup>
<ClCompile> <ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<AdditionalIncludeDirectories>..\3rdparty\wolfssl\wolfssl;..\3rdparty\flatbuffers\include;..\3rdparty\libusb\libusb\libusb;..\3rdparty\yaml-cpp\yaml-cpp\include;..\3rdparty\SoundTouch\soundtouch\include;..\3rdparty\zlib\zlib;..\llvm\include;..\llvm_build\include;$(VULKAN_SDK)\Include</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\3rdparty\miniupnp\miniupnp\miniupnpc\include;..\3rdparty\wolfssl\wolfssl;..\3rdparty\flatbuffers\include;..\3rdparty\libusb\libusb\libusb;..\3rdparty\yaml-cpp\yaml-cpp\include;..\3rdparty\SoundTouch\soundtouch\include;..\3rdparty\zlib\zlib;..\llvm\include;..\llvm_build\include;$(VULKAN_SDK)\Include</AdditionalIncludeDirectories>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization> <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">HAVE_VULKAN;HAVE_SDL2;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MINIUPNP_STATICLIB;HAVE_VULKAN;HAVE_SDL2;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">HAVE_VULKAN;HAVE_SDL2;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MINIUPNP_STATICLIB;HAVE_VULKAN;HAVE_SDL2;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<PreBuildEvent> <PreBuildEvent>
<Command>cmd.exe /c "$(SolutionDir)\Utilities\git-version-gen.cmd"</Command> <Command>cmd.exe /c "$(SolutionDir)\Utilities\git-version-gen.cmd"</Command>
@ -82,6 +82,8 @@
<ClCompile Include="Emu\IPC_socket.cpp" /> <ClCompile Include="Emu\IPC_socket.cpp" />
<ClCompile Include="Emu\localized_string.cpp" /> <ClCompile Include="Emu\localized_string.cpp" />
<ClCompile Include="Emu\NP\rpcn_config.cpp" /> <ClCompile Include="Emu\NP\rpcn_config.cpp" />
<ClCompile Include="Emu\NP\upnp_config.cpp" />
<ClCompile Include="Emu\NP\upnp_handler.cpp" />
<ClCompile Include="Emu\perf_monitor.cpp" /> <ClCompile Include="Emu\perf_monitor.cpp" />
<ClCompile Include="Emu\RSX\Common\texture_cache.cpp" /> <ClCompile Include="Emu\RSX\Common\texture_cache.cpp" />
<ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu.cpp" /> <ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu.cpp" />
@ -516,6 +518,8 @@
<ClInclude Include="Emu\NP\generated\np2_structs_generated.h" /> <ClInclude Include="Emu\NP\generated\np2_structs_generated.h" />
<ClInclude Include="Emu\NP\np_handler.h" /> <ClInclude Include="Emu\NP\np_handler.h" />
<ClInclude Include="Emu\NP\signaling_handler.h" /> <ClInclude Include="Emu\NP\signaling_handler.h" />
<ClInclude Include="Emu\NP\upnp_config.h" />
<ClInclude Include="Emu\NP\upnp_handler.h" />
<ClInclude Include="Emu\NP\vport0.h" /> <ClInclude Include="Emu\NP\vport0.h" />
<ClInclude Include="Emu\NP\np_allocator.h" /> <ClInclude Include="Emu\NP\np_allocator.h" />
<ClInclude Include="Emu\NP\np_cache.h" /> <ClInclude Include="Emu\NP\np_cache.h" />

View File

@ -1138,6 +1138,12 @@
<ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_message_box.cpp"> <ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_message_box.cpp">
<Filter>Emu\GPU\RSX\Overlays\HomeMenu</Filter> <Filter>Emu\GPU\RSX\Overlays\HomeMenu</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\NP\upnp_handler.cpp">
<Filter>Emu\NP</Filter>
</ClCompile>
<ClCompile Include="Emu\NP\upnp_config.cpp">
<Filter>Emu\NP</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Crypto\aes.h"> <ClInclude Include="Crypto\aes.h">
@ -2290,6 +2296,12 @@
<ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_message_box.h"> <ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_message_box.h">
<Filter>Emu\GPU\RSX\Overlays\HomeMenu</Filter> <Filter>Emu\GPU\RSX\Overlays\HomeMenu</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\NP\upnp_handler.h">
<Filter>Emu\NP</Filter>
</ClInclude>
<ClInclude Include="Emu\NP\upnp_config.h">
<Filter>Emu\NP</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Emu\RSX\Program\GLSLSnippets\GPUDeswizzle.glsl"> <None Include="Emu\RSX\Program\GLSLSnippets\GPUDeswizzle.glsl">

View File

@ -79,7 +79,7 @@
<DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ObjectFileName>$(IntDir)</ObjectFileName> <ObjectFileName>$(IntDir)</ObjectFileName>
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<PreprocessorDefinitions>_WINDOWS;UNICODE;WIN32;WIN64;WIN32_LEAN_AND_MEAN;HAVE_VULKAN;HAVE_SDL2;WITH_DISCORD_RPC;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;NDEBUG;QT_WINEXTRAS_LIB;QT_CONCURRENT_LIB;QT_MULTIMEDIA_LIB;QT_MULTIMEDIAWIDGETS_LIB;QT_SVG_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_WINDOWS;UNICODE;WIN32;WIN64;WIN32_LEAN_AND_MEAN;HAVE_VULKAN;MINIUPNP_STATICLIB;HAVE_SDL2;WITH_DISCORD_RPC;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;NDEBUG;QT_WINEXTRAS_LIB;QT_CONCURRENT_LIB;QT_MULTIMEDIA_LIB;QT_MULTIMEDIAWIDGETS_LIB;QT_SVG_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessToFile>false</PreprocessToFile> <PreprocessToFile>false</PreprocessToFile>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName> <ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
<RuntimeTypeInfo>true</RuntimeTypeInfo> <RuntimeTypeInfo>true</RuntimeTypeInfo>
@ -88,7 +88,7 @@
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalDependencies>DbgHelp.lib;Ole32.lib;gdi32.lib;..\hidapi.lib;..\libusb-1.0.lib;winmm.lib;imm32.lib;ksuser.lib;version.lib;OpenAL32.lib;XAudio.lib;GLGSRender.lib;shlwapi.lib;VKGSRender.lib;vulkan-1.lib;wolfssl.lib;libcurl.lib;Wldap32.lib;glslang.lib;OSDependent.lib;OGLCompiler.lib;SPIRV.lib;MachineIndependent.lib;GenericCodeGen.lib;Advapi32.lib;user32.lib;zlib.lib;..\libpng16.lib;asmjit.lib;yaml-cpp.lib;discord-rpc.lib;emucore.lib;dxgi.lib;$(QTDIR)\lib\qtmain.lib;shell32.lib;$(QTDIR)\lib\Qt5Widgets.lib;$(QTDIR)\lib\Qt5Gui.lib;$(QTDIR)\lib\Qt5Core.lib;Qt5Core.lib;Qt5Gui.lib;Qt5Widgets.lib;Qt5WinExtras.lib;Qt5Concurrent.lib;7zlib.lib;SPIRV-Tools.lib;SPIRV-Tools-opt.lib;Qt5Multimedia.lib;Qt5MultimediaWidgets.lib;Qt5Svg.lib;libcubeb.lib;cubeb.lib;soundtouch.lib;Avrt.lib;SDL.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>DbgHelp.lib;Ole32.lib;gdi32.lib;..\hidapi.lib;..\libusb-1.0.lib;winmm.lib;miniupnpc_static.lib;imm32.lib;ksuser.lib;version.lib;OpenAL32.lib;XAudio.lib;GLGSRender.lib;shlwapi.lib;VKGSRender.lib;vulkan-1.lib;wolfssl.lib;libcurl.lib;Wldap32.lib;glslang.lib;OSDependent.lib;OGLCompiler.lib;SPIRV.lib;MachineIndependent.lib;GenericCodeGen.lib;Advapi32.lib;user32.lib;zlib.lib;..\libpng16.lib;asmjit.lib;yaml-cpp.lib;discord-rpc.lib;emucore.lib;dxgi.lib;$(QTDIR)\lib\qtmain.lib;shell32.lib;$(QTDIR)\lib\Qt5Widgets.lib;$(QTDIR)\lib\Qt5Gui.lib;$(QTDIR)\lib\Qt5Core.lib;Qt5Core.lib;Qt5Gui.lib;Qt5Widgets.lib;Qt5WinExtras.lib;Qt5Concurrent.lib;7zlib.lib;SPIRV-Tools.lib;SPIRV-Tools-opt.lib;Qt5Multimedia.lib;Qt5MultimediaWidgets.lib;Qt5Svg.lib;libcubeb.lib;cubeb.lib;soundtouch.lib;Avrt.lib;SDL.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\3rdparty\OpenAL\libs\Win64;..\3rdparty\glslang\build\hlsl\Release;..\3rdparty\glslang\build\SPIRV\Release;..\3rdparty\glslang\build\OGLCompilersDLL\Release;..\3rdparty\glslang\build\glslang\OSDependent\Windows\Release;..\3rdparty\glslang\build\glslang\Release;..\3rdparty\SPIRV\build\source\Release;..\3rdparty\SPIRV\build\source\opt\Release;..\lib\$(CONFIGURATION)-$(PLATFORM);..\3rdparty\XAudio2Redist\libs;..\3rdparty\discord-rpc\lib;$(QTDIR)\lib;%(AdditionalLibraryDirectories);$(VULKAN_SDK)\Lib</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\3rdparty\OpenAL\libs\Win64;..\3rdparty\glslang\build\hlsl\Release;..\3rdparty\glslang\build\SPIRV\Release;..\3rdparty\glslang\build\OGLCompilersDLL\Release;..\3rdparty\glslang\build\glslang\OSDependent\Windows\Release;..\3rdparty\glslang\build\glslang\Release;..\3rdparty\SPIRV\build\source\Release;..\3rdparty\SPIRV\build\source\opt\Release;..\lib\$(CONFIGURATION)-$(PLATFORM);..\3rdparty\XAudio2Redist\libs;..\3rdparty\discord-rpc\lib;$(QTDIR)\lib;%(AdditionalLibraryDirectories);$(VULKAN_SDK)\Lib</AdditionalLibraryDirectories>
<AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions>
<DataExecutionPrevention>true</DataExecutionPrevention> <DataExecutionPrevention>true</DataExecutionPrevention>
@ -130,7 +130,7 @@
<DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ObjectFileName>$(IntDir)</ObjectFileName> <ObjectFileName>$(IntDir)</ObjectFileName>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_WINDOWS;UNICODE;WIN32;WIN64;WIN32_LEAN_AND_MEAN;HAVE_VULKAN;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;QT_WINEXTRAS_LIB;QT_CONCURRENT_LIB;QT_MULTIMEDIA_LIB;QT_MULTIMEDIAWIDGETS_LIB;QT_SVG_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_WINDOWS;UNICODE;WIN32;WIN64;WIN32_LEAN_AND_MEAN;HAVE_VULKAN;MINIUPNP_STATICLIB;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;QT_WINEXTRAS_LIB;QT_CONCURRENT_LIB;QT_MULTIMEDIA_LIB;QT_MULTIMEDIAWIDGETS_LIB;QT_SVG_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessToFile>false</PreprocessToFile> <PreprocessToFile>false</PreprocessToFile>
<RuntimeTypeInfo>true</RuntimeTypeInfo> <RuntimeTypeInfo>true</RuntimeTypeInfo>
<SuppressStartupBanner>true</SuppressStartupBanner> <SuppressStartupBanner>true</SuppressStartupBanner>
@ -139,7 +139,7 @@
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName> <ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalDependencies>DbgHelp.lib;Ole32.lib;gdi32.lib;..\hidapi.lib;..\libusb-1.0.lib;winmm.lib;ksuser.lib;OpenAL32.lib;XAudio.lib;GLGSRender.lib;shlwapi.lib;VKGSRender.lib;vulkan-1.lib;wolfssl.lib;libcurl.lib;Wldap32.lib;glslangd.lib;OSDependentd.lib;OGLCompilerd.lib;SPIRVd.lib;MachineIndependentd.lib;GenericCodeGend.lib;Advapi32.lib;user32.lib;zlib.lib;..\libpng16.lib;asmjit.lib;yaml-cpp.lib;discord-rpc.lib;emucore.lib;dxgi.lib;$(QTDIR)\lib\qtmaind.lib;shell32.lib;$(QTDIR)\lib\Qt5Widgetsd.lib;$(QTDIR)\lib\Qt5Guid.lib;$(QTDIR)\lib\Qt5Cored.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Widgetsd.lib;Qt5WinExtrasd.lib;Qt5Concurrentd.lib;7zlib.lib;SPIRV-Tools.lib;SPIRV-Tools-opt.lib;Qt5Multimediad.lib;Qt5MultimediaWidgetsd.lib;Qt5Svgd.lib;libcubeb.lib;cubeb.lib;soundtouch.lib;Avrt.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>DbgHelp.lib;Ole32.lib;gdi32.lib;..\hidapi.lib;..\libusb-1.0.lib;winmm.lib;miniupnpc_static.lib;ksuser.lib;OpenAL32.lib;XAudio.lib;GLGSRender.lib;shlwapi.lib;VKGSRender.lib;vulkan-1.lib;wolfssl.lib;libcurl.lib;Wldap32.lib;glslangd.lib;OSDependentd.lib;OGLCompilerd.lib;SPIRVd.lib;MachineIndependentd.lib;GenericCodeGend.lib;Advapi32.lib;user32.lib;zlib.lib;..\libpng16.lib;asmjit.lib;yaml-cpp.lib;discord-rpc.lib;emucore.lib;dxgi.lib;$(QTDIR)\lib\qtmaind.lib;shell32.lib;$(QTDIR)\lib\Qt5Widgetsd.lib;$(QTDIR)\lib\Qt5Guid.lib;$(QTDIR)\lib\Qt5Cored.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Widgetsd.lib;Qt5WinExtrasd.lib;Qt5Concurrentd.lib;7zlib.lib;SPIRV-Tools.lib;SPIRV-Tools-opt.lib;Qt5Multimediad.lib;Qt5MultimediaWidgetsd.lib;Qt5Svgd.lib;libcubeb.lib;cubeb.lib;soundtouch.lib;Avrt.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\3rdparty\OpenAL\libs\Win64;..\3rdparty\glslang\build\hlsl\Debug;..\3rdparty\glslang\build\SPIRV\Debug;..\3rdparty\glslang\build\OGLCompilersDLL\Debug;..\3rdparty\glslang\build\glslang\OSDependent\Windows\Debug;..\3rdparty\glslang\build\glslang\Debug;..\3rdparty\SPIRV\build\source\opt\Debug;..\3rdparty\XAudio2Redist\libs;..\3rdparty\discord-rpc\lib;..\lib\$(CONFIGURATION)-$(PLATFORM);$(QTDIR)\lib;%(AdditionalLibraryDirectories);$(VULKAN_SDK)\Lib</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\3rdparty\OpenAL\libs\Win64;..\3rdparty\glslang\build\hlsl\Debug;..\3rdparty\glslang\build\SPIRV\Debug;..\3rdparty\glslang\build\OGLCompilersDLL\Debug;..\3rdparty\glslang\build\glslang\OSDependent\Windows\Debug;..\3rdparty\glslang\build\glslang\Debug;..\3rdparty\SPIRV\build\source\opt\Debug;..\3rdparty\XAudio2Redist\libs;..\3rdparty\discord-rpc\lib;..\lib\$(CONFIGURATION)-$(PLATFORM);$(QTDIR)\lib;%(AdditionalLibraryDirectories);$(VULKAN_SDK)\Lib</AdditionalLibraryDirectories>
<AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" /VERBOSE %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" /VERBOSE %(AdditionalOptions)</AdditionalOptions>
<DataExecutionPrevention>true</DataExecutionPrevention> <DataExecutionPrevention>true</DataExecutionPrevention>

View File

@ -173,7 +173,7 @@ usz downloader::update_buffer(char* data, usz size)
if (m_actual_download_size < 0) if (m_actual_download_size < 0)
{ {
if (curl_easy_getinfo(m_curl->get_curl(), CURLINFO_CONTENT_LENGTH_DOWNLOAD, &m_actual_download_size) == CURLE_OK && m_actual_download_size > 0) if (curl_easy_getinfo(m_curl->get_curl(), CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &m_actual_download_size) == CURLE_OK && m_actual_download_size > 0)
{ {
max = static_cast<int>(m_actual_download_size); max = static_cast<int>(m_actual_download_size);
} }

View File

@ -173,6 +173,7 @@ enum class emu_settings_type
IpSwapList, IpSwapList,
PSNStatus, PSNStatus,
BindAddress, BindAddress,
EnableUpnp,
// System // System
LicenseArea, LicenseArea,
@ -353,6 +354,7 @@ inline static const QMap<emu_settings_type, cfg_location> settings_location =
{ emu_settings_type::IpSwapList, { "Net", "IP swap list"}}, { emu_settings_type::IpSwapList, { "Net", "IP swap list"}},
{ emu_settings_type::PSNStatus, { "Net", "PSN status"}}, { emu_settings_type::PSNStatus, { "Net", "PSN status"}},
{ emu_settings_type::BindAddress, { "Net", "Bind address"}}, { emu_settings_type::BindAddress, { "Net", "Bind address"}},
{ emu_settings_type::EnableUpnp, { "Net", "UPNP Enabled"}},
// System // System
{ emu_settings_type::LicenseArea, { "System", "License Area"}}, { emu_settings_type::LicenseArea, { "System", "License Area"}},

View File

@ -1304,6 +1304,9 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> gui_settings, std
m_emu_settings->EnhanceLineEdit(ui->edit_swaps, emu_settings_type::IpSwapList); m_emu_settings->EnhanceLineEdit(ui->edit_swaps, emu_settings_type::IpSwapList);
SubscribeTooltip(ui->gb_edit_swaps, tooltips.settings.dns_swap); SubscribeTooltip(ui->gb_edit_swaps, tooltips.settings.dns_swap);
m_emu_settings->EnhanceCheckBox(ui->enable_upnp, emu_settings_type::EnableUpnp);
SubscribeTooltip(ui->enable_upnp, tooltips.settings.enable_upnp);
// Comboboxes // Comboboxes
m_emu_settings->EnhanceComboBox(ui->netStatusBox, emu_settings_type::InternetStatus); m_emu_settings->EnhanceComboBox(ui->netStatusBox, emu_settings_type::InternetStatus);
@ -1312,8 +1315,10 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> gui_settings, std
connect(ui->netStatusBox, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) connect(ui->netStatusBox, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index)
{ {
ui->edit_dns->setEnabled(index > 0); ui->edit_dns->setEnabled(index > 0);
ui->enable_upnp->setEnabled(index > 0);
}); });
ui->edit_dns->setEnabled(ui->netStatusBox->currentIndex() > 0); ui->edit_dns->setEnabled(ui->netStatusBox->currentIndex() > 0);
ui->enable_upnp->setEnabled(ui->netStatusBox->currentIndex() > 0);
m_emu_settings->EnhanceComboBox(ui->psnStatusBox, emu_settings_type::PSNStatus); m_emu_settings->EnhanceComboBox(ui->psnStatusBox, emu_settings_type::PSNStatus);
SubscribeTooltip(ui->gb_psnStatusBox, tooltips.settings.psn_status); SubscribeTooltip(ui->gb_psnStatusBox, tooltips.settings.psn_status);

View File

@ -2077,7 +2077,7 @@
<property name="title"> <property name="title">
<string>Network Configuration</string> <string>Network Configuration</string>
</property> </property>
<layout class="QVBoxLayout" name="gb_network_status_layout" stretch="0,0,0,0,0"> <layout class="QVBoxLayout" name="gb_network_status_layout" stretch="0,0,0,0,0,0">
<item> <item>
<widget class="QGroupBox" name="gb_netStatusBox"> <widget class="QGroupBox" name="gb_netStatusBox">
<property name="title"> <property name="title">
@ -2147,6 +2147,13 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="enable_upnp">
<property name="text">
<string>Enable UPNP</string>
</property>
</widget>
</item>
<item> <item>
<spacer name="networkTabSpacerLeft"> <spacer name="networkTabSpacerLeft">
<property name="orientation"> <property name="orientation">

View File

@ -230,6 +230,7 @@ public:
const QString dns = tr("DNS used to resolve hostnames by applications."); const QString dns = tr("DNS used to resolve hostnames by applications.");
const QString dns_swap = tr("DNS Swap List."); const QString dns_swap = tr("DNS Swap List.");
const QString bind = tr("Interface IP Address to bind to."); const QString bind = tr("Interface IP Address to bind to.");
const QString enable_upnp = tr("Enable UPNP.\nThis will automatically forward ports bound on 0.0.0.0 if your router has UPNP enabled.");
// system // system