Files
shadPS4/tests/network/test_net_kernel.cpp
T
georgemoralisandMetr1k 2a2f1003b0 Major net rewrite (#5236)
* p2p crypto schema

* adding p2p keyring

* p2p framing and testing

* fixups

* test fix

* missing definations

* implementation of host functions

* tcp/transport of p2p packets

* improvements in binding

* guest_net ,improvements and  test cases

* all mighty clang

* fixing macOS tests failures

* misc

* net_rewrite : net_errors , types and translation schemas

* updated fixed chunks transfer on windows

* bye bye old net

* small updates for the new net

* settings and tests

* net lib first draft

* allow more than 1 P2P instances on from same pc

* improved shadnet replies

* possible fix for jojo

* cleanup

* move net files to libaries/net

* fixed macOS tests

* mighty clang

* fixed cmakelists

* don't cosume inviation event on client (test code)

* fix macOS tests

* Large multi-file rework for Signaling and Matching2 network handling / optimization.  Consolidates Matching2-signaling and signaling to one process (signaling_handler)

General cleanup and consolidation of matching2 context management > nphandler

Removal of a lot

SIgnaling overall structure cleanup.

Matching2: added get and set roommemberdatainternal and the proper type / shadnet call / request / reply.

Consolidated signaling/matching2 typedefs to np_types2

Utilized Codex as a reviewer and for general cleanup.

* all mighty clang

* fixed member attributes

* fixed MAPPED address for matching signaling

* Fixed sceNpMatching2SignalingGetLocalNetInfo

* fixups on net core/library based on fw

* improved errno

* spilt p2p to net_p2p

* some cleanups

* fix for localinfo

* clang

* fix up

* cleanups

* cleanups

* added KernelFstat

* fixed fstat

* one more fix for fstat...

* cleanup old deprecated code

* cleanup

* General logging cleanup across NP changes.  Thanks Stephen!

* cleanup based on stephen's suggestions

* fixup

* fixing tests

* blah

* fixup

* improve memory pools

* cleaunp

* force https disable option

* clang

* @stephen's fixes

* added network field in settings and ported old network ones

---------

Co-authored-by: Metr1k <blackkn1ght1991@gmail.com>
2026-10-06 19:14:56 +03:00

163 lines
6.2 KiB
C++

// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// The net library inside the kernel: net ids are file descriptors from the kernel's file table,
// the kernel's close/read/write/fstat reach them, and the libkernel / libScePosix socket calls
// report errors the POSIX way (-1 and the kernel errno).
#include <cstring>
#include <gtest/gtest.h>
#include "common/singleton.h"
#include "core/emulator_settings.h"
#include "core/file_sys/fs.h"
#include "core/libraries/kernel/file_system.h"
#include "core/libraries/kernel/kernel.h"
#include "core/libraries/net/net.h"
#include "core/libraries/net/net_error.h"
#include "core/libraries/net/net_kernel.h"
#include "core/libraries/net/net_p2p.h"
#include "core/net/guest_net.h"
using namespace Libraries::Net;
using FDTable = Common::Singleton<Core::FileSys::HandleTable>;
namespace {
class NetKernel : public ::testing::Test {
protected:
static void SetUpTestSuite() {
FDTable::Instance()->CreateStdHandles();
InstallKernelIntegration();
ASSERT_EQ(sceNetInit(), 0);
}
static int Errno() {
return *Libraries::Kernel::__Error();
}
static OrbisNetSockaddrIn Loopback() {
OrbisNetSockaddrIn in{};
in.sin_len = sizeof(in);
in.sin_family = ORBIS_NET_AF_INET;
in.sin_addr = sceNetHtonl(0x7F000001);
return in;
}
};
TEST_F(NetKernel, SocketsAreFileDescriptors) {
const int fd = sys_socket(ORBIS_NET_AF_INET, ORBIS_NET_SOCK_DGRAM, 0);
ASSERT_GE(fd, 3); // after stdin, stdout, stderr
auto* file = FDTable::Instance()->GetFile(fd);
ASSERT_NE(file, nullptr);
EXPECT_EQ(file->type, Core::FileSys::FileType::Socket);
EXPECT_TRUE(file->is_opened);
// select() on it: a fresh UDP socket is writable, not readable.
Core::Net::SelectEntry sel[] = {{fd, Core::Net::Host::EvIn | Core::Net::Host::EvOut, 0}};
EXPECT_EQ(KernelSelect(sel, 0), 1);
EXPECT_EQ(sel[0].ready, Core::Net::Host::EvOut);
// write() and read() on the descriptor are send and recv.
auto addr = Loopback();
ASSERT_EQ(sys_bind(fd, reinterpret_cast<OrbisNetSockaddr*>(&addr), sizeof(addr)), 0);
u32 len = sizeof(addr);
ASSERT_EQ(sys_getsockname(fd, reinterpret_cast<OrbisNetSockaddr*>(&addr), &len), 0);
ASSERT_EQ(sys_connect(fd, reinterpret_cast<OrbisNetSockaddr*>(&addr), sizeof(addr)), 0);
EXPECT_EQ(KernelWrite(fd, "data", 4), 4);
char buf[8]{};
EXPECT_EQ(KernelRead(fd, buf, sizeof(buf)), 4);
EXPECT_STREQ(buf, "data");
Libraries::Kernel::OrbisKernelStat st{};
ASSERT_EQ(KernelFstat(fd, &st), 0);
EXPECT_EQ(st.st_mode & 0170000, 0140000); // S_IFSOCK
ASSERT_EQ(KernelClose(fd), 0);
EXPECT_EQ(FDTable::Instance()->GetFile(fd), nullptr);
EXPECT_FALSE(Core::Net::GetObjectKind(fd));
EXPECT_EQ(KernelClose(fd), -1);
EXPECT_EQ(Errno(), ORBIS_NET_EBADF);
EXPECT_EQ(sceNetSocketClose(fd), ORBIS_NET_ERROR_EBADF);
}
TEST_F(NetKernel, DescriptorsAreReused) {
const int a = sys_socket(ORBIS_NET_AF_INET, ORBIS_NET_SOCK_STREAM, 0);
ASSERT_EQ(sys_socketclose(a), 0); // the sceNet way frees the descriptor as well
EXPECT_EQ(FDTable::Instance()->GetFile(a), nullptr);
const int b = sys_socket(ORBIS_NET_AF_INET, ORBIS_NET_SOCK_STREAM, 0);
EXPECT_EQ(b, a); // lowest free descriptor, as the kernel hands them out
KernelClose(b);
}
TEST_F(NetKernel, PosixErrorsUseTheKernelErrno) {
*sceNetErrnoLoc() = 1234;
*Libraries::Kernel::__Error() = 0;
EXPECT_EQ(sys_listen(1234, 1), -1);
EXPECT_EQ(Errno(), ORBIS_NET_EBADF);
EXPECT_EQ(sys_socket(99, ORBIS_NET_SOCK_STREAM, 0), -1);
EXPECT_EQ(Errno(), ORBIS_NET_EPROTONOSUPPORT); // as sceNetSocket reports it
EXPECT_EQ(*sceNetErrnoLoc(), 1234);
char buf[4];
EXPECT_EQ(KernelRead(1234, buf, sizeof(buf)), -1);
EXPECT_EQ(*sceNetErrnoLoc(), 1234);
// The sceNet* call itself does set it.
EXPECT_EQ(sceNetListen(1234, 1), ORBIS_NET_ERROR_EBADF);
EXPECT_EQ(*sceNetErrnoLoc(), ORBIS_NET_EBADF);
EXPECT_EQ(sys_htons(0x1234), 0x3412);
}
TEST_F(NetKernel, SocketPair) {
int sv[2]{-1, -1};
EXPECT_EQ(sys_socketpair(ORBIS_NET_AF_INET, ORBIS_NET_SOCK_STREAM, 0, sv), -1);
EXPECT_EQ(Errno(), ORBIS_NET_EAFNOSUPPORT); // AF_UNIX only, as on FreeBSD
ASSERT_EQ(sys_socketpair(ORBIS_NET_AF_UNIX, ORBIS_NET_SOCK_STREAM, 0, sv), 0);
EXPECT_NE(FDTable::Instance()->GetFile(sv[0]), nullptr);
EXPECT_NE(FDTable::Instance()->GetFile(sv[1]), nullptr);
EXPECT_EQ(KernelWrite(sv[0], "abc", 3), 3);
char buf[4]{};
EXPECT_EQ(sys_recv(sv[1], buf, sizeof(buf), 0), 3);
EXPECT_STREQ(buf, "abc");
KernelClose(sv[0]);
KernelClose(sv[1]);
}
TEST_F(NetKernel, EpollsAndResolversCloseToo) {
const int ep = sceNetEpollCreate("ep", 0);
const s32 pool = sceNetPoolCreate("pool", 16 * 1024, 0);
const int rid = sceNetResolverCreate("rid", pool, 0);
ASSERT_GE(ep, 3);
ASSERT_GE(rid, 3);
EXPECT_NE(FDTable::Instance()->GetFile(ep), nullptr);
EXPECT_NE(FDTable::Instance()->GetFile(rid), nullptr);
// Descriptors, but nothing to select on: never ready, and not an error.
Core::Net::SelectEntry sel[] = {{ep, Core::Net::Host::EvIn, 0},
{rid, Core::Net::Host::EvIn, 0}};
EXPECT_EQ(KernelSelect(sel, 0), 0);
EXPECT_EQ(sel[0].ready, 0u);
char buf[4];
EXPECT_EQ(KernelRead(ep, buf, sizeof(buf)), -1); // not readable
EXPECT_EQ(KernelClose(ep), 0);
EXPECT_EQ(KernelClose(rid), 0);
EXPECT_EQ(FDTable::Instance()->GetFile(ep), nullptr);
EXPECT_EQ(FDTable::Instance()->GetFile(rid), nullptr);
EXPECT_EQ(sceNetResolverDestroy(rid), ORBIS_NET_ERROR_EBADF);
EXPECT_EQ(sceNetPoolDestroy(pool), ORBIS_OK); // close() gave the pool back
}
TEST_F(NetKernel, P2PPortComesFromTheSettings) {
EmulatorSettings.SetP2PPort(0); // any free port
EXPECT_EQ(GetP2PConfiguredPort(), 0);
ASSERT_TRUE(EnsureP2PTransport());
EXPECT_NE(GetP2PBoundPort(), 0);
EXPECT_EQ(GetP2PAdvertisedPort(), GetP2PBoundPort());
StopP2P(); // offline by default: no UPnP involved either way
EXPECT_FALSE(P2PTransportIsReady());
EmulatorSettings.SetP2PPort(70000); // not a port: the console's
EXPECT_EQ(GetP2PConfiguredPort(), 3658);
EmulatorSettings.SetP2PPort(3658);
}
} // namespace