Merge pull request #82 from igor725/resolver

libSceNet| Resolver
This commit is contained in:
SysRay 2024-04-13 11:10:13 +02:00 committed by GitHub
commit f9634d9543
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 237 additions and 26 deletions

View File

@ -6,6 +6,8 @@ project(${libName})
add_library(${libName} SHARED entry.cpp wepoll.c epoll.cpp socket.cpp resolver.cpp)
target_link_libraries(${libName} ws2_32)
add_dependencies(${libName} boost config_emu)
target_compile_definitions(${libName} PUBLIC BOOST_ALL_NO_LIB WIN32_LEAN_AND_MEAN)
target_link_libraries(${libName} ws2_32 libboost_thread config_emu.lib)
setupModule(${libName})

View File

@ -124,10 +124,19 @@ constexpr int32_t ERROR_RESOLVER_ENOTFOUND = -2143223317;
constexpr int32_t ERROR_RESOLVER_ENOTINIT = -2143223316;
} // namespace Err
namespace NetErrNo {
constexpr int32_t SCE_NET_EINTR = 4;
constexpr int32_t SCE_NET_EBADF = 9;
constexpr int32_t SCE_NET_EINVAL = 22;
constexpr int32_t SCE_NET_EPROTONOSUPPORT = 43;
constexpr int32_t SCE_NET_ENAMETOOLONG = 63;
constexpr int32_t SCE_NET_RESOLVER_ETIMEDOUT = 226;
}; // namespace NetErrNo
constexpr size_t SCE_NET_ETHER_ADDR_LEN = 6;
constexpr size_t SCE_NET_ETHER_ADDRSTRLEN = 18;
constexpr size_t SCE_NET_RESOLVER_MULTIPLE_RECORDS_MAX = 16;
constexpr size_t SCE_NET_RESOLVER_PORT = 53;
constexpr size_t SCE_NET_RESOLVER_HOSTNAME_LEN_MAX = 255;
constexpr size_t SCE_NET_RESOLVER_HOSTNAME_LEN_MAX = 255;

View File

@ -2,7 +2,6 @@
#include "logging.h"
#include "types.h"
#define WIN32_LEAN_AND_MEAN
#include <WS2tcpip.h>
#include <WinSock2.h>
@ -24,7 +23,6 @@ extern "C" {
EXPORT const char* MODULE_NAME = "libSceNet";
EXPORT SYSV_ABI int* sceNetErrnoLoc() {
g_net_errno = sce_WSAGetLastError();
return &g_net_errno;
}

View File

@ -3,7 +3,6 @@
#include "types.h"
#include "wepoll.h"
#define WIN32_LEAN_AND_MEAN
#include <WinSock2.h>
#include <unordered_map>

View File

@ -1,49 +1,226 @@
#include "common.h"
#include "config_emu.h"
#include "logging.h"
#include "resolverTypes.h"
#include "socketTypes.h"
#include <Windows.h>
#include <boost/asio.hpp>
#include <unordered_map>
using namespace boost::asio;
LOG_DEFINE_MODULE(libSceNet);
namespace {} // namespace
namespace {
#define TEST_RESOLVER \
if (rid < 0 || rid > 127 || g_resolvers[rid] == nullptr) return Err::ERROR_EINVAL
extern "C" int* sceNetErrnoLoc();
static io_service svc;
struct Resolver {
char name[32];
ip::tcp::resolver res;
bool interrupted;
int internError;
Resolver(): res(svc), interrupted(false), name() {}
};
static Resolver* g_resolvers[128] = {nullptr};
class PreMap {
std::unordered_map<std::string, SceNetInAddr_t> m_mapAddrs;
public:
PreMap() {
LOG_USE_MODULE(libSceNet);
auto [lock, jData] = accessConfig()->accessModule(ConfigModFlag::RESOLVE);
if ((*jData).is_object()) {
for (auto [key, value]: (*jData).items()) {
try {
SceNetInAddr_t addr;
if (value.is_number_integer()) {
value.get_to(addr);
} else {
std::string saddr;
value.get_to(saddr);
addr = ip::address_v4::from_string(saddr).to_ulong();
}
m_mapAddrs.insert(std::pair<std::string, SceNetInAddr_t>(key, addr));
} catch (json::exception& ex) {
LOG_ERR(L"Invalid resolve.json field: %S", key.c_str());
}
}
return;
}
LOG_ERR(L"Something wrong with your resolve.json!");
}
SceNetInAddr_t search(const std::string& hostname) {
auto it = m_mapAddrs.find(hostname);
if (it != m_mapAddrs.end()) {
return it->second;
}
return 0x00000000;
}
std::string_view const reverse_search(const SceNetInAddr_t addr) {
auto it = std::find_if(m_mapAddrs.begin(), m_mapAddrs.end(), [&addr](auto&& p) { return p.second == addr; });
if (it == m_mapAddrs.end()) return "";
return it->first;
}
};
PreMap& getPreMap() {
static PreMap imp;
return imp;
}
} // namespace
extern "C" {
EXPORT SYSV_ABI SceNetId sceNetResolverCreate(const char* name, int memid, int flags) {
if (flags != 0) {
*sceNetErrnoLoc() = NetErrNo::SCE_NET_EINVAL;
return -1;
}
LOG_USE_MODULE(libSceNet);
LOG_ERR(L"todo %S", __FUNCTION__);
static size_t count = 0;
return ++count;
LOG_TRACE(L"new resolver: %S (memid: %d, flags: %d)", name, memid, flags);
static size_t count = 0;
g_resolvers[++count] = new Resolver();
if (auto namelen = ::strlen(name)) {
if (namelen > sizeof(Resolver::name) - 1) {
*sceNetErrnoLoc() = NetErrNo::SCE_NET_ENAMETOOLONG;
return -1;
}
::strncpy_s(g_resolvers[count]->name, name, namelen);
}
return count;
}
EXPORT SYSV_ABI int sceNetResolverStartNtoa(SceNetId rid, const char* hostname, SceNetInAddr_t* addr, int timeout, int retry, int flags) {
EXPORT SYSV_ABI int sceNetResolverStartNtoa(SceNetId rid, const char* hostname, SceNetInAddr_t* addr, int timeout, int retries, int flags) {
LOG_USE_MODULE(libSceNet);
LOG_ERR(L"todo %S", __FUNCTION__);
TEST_RESOLVER;
auto resolver = g_resolvers[rid];
resolver->internError = 0;
{
std::string _hostname(hostname);
if (auto _raddr = getPreMap().search(_hostname)) {
*addr = _raddr;
return Ok;
}
}
ip::tcp::resolver::query query(ip::tcp::v4(), hostname, "0");
for (int cretr = 0; cretr < retries; ++cretr) {
if (resolver->interrupted) {
*sceNetErrnoLoc() = NetErrNo::SCE_NET_EINTR;
return Err::ERROR_EFAULT;
}
try {
auto it = resolver->res.resolve(query);
*addr = (*it).endpoint().address().to_v4().to_uint();
return Ok;
} catch (boost::system::system_error& ex) {
LOG_ERR(L"%S: failed to resolve %S (%d/%d): %S", __FUNCTION__, hostname, cretr, retries, ex.what());
}
}
*sceNetErrnoLoc() = NetErrNo::SCE_NET_RESOLVER_ETIMEDOUT;
return getErr(ErrCode::_ETIMEDOUT);
}
EXPORT SYSV_ABI int sceNetResolverStartAton(SceNetId rid, const SceNetInAddr_t* addr, char* hostname, int len, int timeout, int retry, int flags) {
TEST_RESOLVER;
LOG_USE_MODULE(libSceNet);
LOG_ERR(L"todo %S", __FUNCTION__);
auto resolver = g_resolvers[rid];
resolver->internError = 0;
{
auto _hn = getPreMap().reverse_search(*addr);
if (auto _hnlen = _hn.length()) {
if (len <= _hnlen) return Err::ERROR_EINVAL;
_hn.copy(hostname, _hnlen + 1);
return Ok;
}
}
*sceNetErrnoLoc() = NetErrNo::SCE_NET_RESOLVER_ETIMEDOUT;
return getErr(ErrCode::_ETIMEDOUT);
}
EXPORT SYSV_ABI int sceNetResolverStartNtoaMultipleRecords(SceNetId rid, const char* hostname, SceNetResolverInfo* info, int timeout, int retry, int flags) {
EXPORT SYSV_ABI int sceNetResolverStartNtoaMultipleRecords(SceNetId rid, const char* hostname, SceNetResolverInfo* info, int timeout, int retries, int flags) {
LOG_USE_MODULE(libSceNet);
LOG_ERR(L"todo %S", __FUNCTION__);
TEST_RESOLVER;
auto resolver = g_resolvers[rid];
resolver->internError = 0;
{
std::string _hostname(hostname);
if (auto _raddr = getPreMap().search(_hostname)) {
info->addrs[0].af = SCE_NET_AF_INET;
info->addrs[0].un.addr = _raddr;
info->records = 1;
return Ok;
}
}
ip::tcp::resolver::query query(ip::tcp::v4(), hostname, "0");
info->records = 0;
for (int cretr = 0; cretr < retries; ++cretr) {
// todo: should set sce_net_errno
if (resolver->interrupted) {
resolver->internError = NetErrNo::SCE_NET_EINTR;
return Err::ERROR_EFAULT;
}
try {
for (auto addr: resolver->res.resolve(query)) {
auto& iaddr = info->addrs[info->records++];
iaddr.af = SCE_NET_AF_INET;
iaddr.un.addr = addr.endpoint().address().to_v4().to_uint();
if (info->records == SCE_NET_RESOLVER_MULTIPLE_RECORDS_MAX) break;
}
info->records -= 1; // We should decrease value by 1 to get the actual records count
info->dns4records = info->records;
return Ok;
} catch (boost::system::system_error& ex) {
LOG_ERR(L"%S: failed to resolve %S (%d/%d): %S", __FUNCTION__, hostname, cretr, retries, ex.what());
}
}
*sceNetErrnoLoc() = NetErrNo::SCE_NET_RESOLVER_ETIMEDOUT;
return getErr(ErrCode::_ETIMEDOUT);
}
EXPORT SYSV_ABI int sceNetResolverGetError(SceNetId rid, int* result) {
TEST_RESOLVER;
LOG_USE_MODULE(libSceNet);
LOG_ERR(L"todo %S", __FUNCTION__);
*result = (int)ErrCode::_ETIMEDOUT;
*result = g_resolvers[rid]->internError;
return Ok;
}
EXPORT SYSV_ABI int sceNetResolverDestroy(SceNetId rid) {
TEST_RESOLVER;
delete g_resolvers[rid];
g_resolvers[rid] = nullptr;
return Ok;
}
EXPORT SYSV_ABI int sceNetResolverAbort(SceNetId rid, int flags) {
TEST_RESOLVER;
g_resolvers[rid]->interrupted = true;
return Ok;
}
}

View File

@ -1,13 +1,15 @@
#include "common.h"
#include "logging.h"
#include "socketTypes.h"
LOG_DEFINE_MODULE(libSceNet);
#define WIN32_LEAN_AND_MEAN
#include <WS2tcpip.h>
#include <mutex>
LOG_DEFINE_MODULE(libSceNet);
namespace {
extern "C" int* sceNetErrnoLoc();
static inline int32_t sce_WSAGetLastError() {
auto win_err = (uint32_t)WSAGetLastError();
if (win_err == WSANOTINITIALISED) return Err::ERROR_ENOTINIT;
@ -18,14 +20,20 @@ static inline int32_t sce_WSAGetLastError() {
extern "C" {
EXPORT SYSV_ABI SceNetId sceNetSocket(const char* name, int family, int type, int protocol) {
if (family != SCE_NET_AF_INET) return Err::ERROR_EINVAL;
if (family != SCE_NET_AF_INET) {
*sceNetErrnoLoc() = NetErrNo::SCE_NET_EPROTONOSUPPORT;
return Err::ERROR_EINVAL;
}
switch (type) {
case SCE_NET_SOCK_STREAM:
case SCE_NET_SOCK_DGRAM:
case SCE_NET_SOCK_RAW: return socket(AF_INET, type, protocol);
default: return Err::ERROR_EPROTOTYPE;
default: {
*sceNetErrnoLoc() = NetErrNo::SCE_NET_EPROTONOSUPPORT;
return Err::ERROR_EPROTOTYPE;
}
}
return Ok;

View File

@ -397,4 +397,15 @@ EXPORT SYSV_ABI int32_t __NID(_ZNK3sce7Toolkit2NP2V24Core12ResponseBase8getState
LOG_ERR(L"todo %S", __FUNCTION__);
return Ok;
}
/**
* @brief sce::Toolkit::NP::V2::Core::Response<sce::Toolkit::NP::V2::UserProfile::NpProfiles>::Response()
*
*/
EXPORT SYSV_ABI int32_t __NID(_ZN3sce7Toolkit2NP2V24Core8ResponseINS2_11UserProfile10NpProfilesEEC1Ev)() {
LOG_USE_MODULE(libSceNpToolkit2);
LOG_ERR(L"todo %S", __FUNCTION__);
return Ok;
}
}

View File

@ -10,11 +10,12 @@ class Item {
public:
std::string_view const _name;
bool _dontfix; // If this flag is set then load function won't try fix the file according to default object
json _json;
boost::mutex _mutex;
std::future<void> _future;
Item(std::string_view name): _name(name) {}
Item(std::string_view name, bool df = false): _name(name), _dontfix(df) {}
std::pair<boost::unique_lock<boost::mutex>, json*> access() {
_future.wait();
@ -42,6 +43,7 @@ class Config: public IConfig {
Item m_audio = {"audio.json"};
Item m_controls = {"controls.json"};
Item m_general = {"general.json"};
Item m_resolve = {"resolve.json", true /*dontfix flag*/};
public:
Config();
@ -64,6 +66,7 @@ std::pair<boost::unique_lock<boost::mutex>, json*> Config::accessModule(ConfigMo
case ConfigModFlag::AUDIO: return m_audio.access();
case ConfigModFlag::CONTROLS: return m_controls.access();
case ConfigModFlag::GENERAL: return m_general.access();
case ConfigModFlag::RESOLVE: return m_resolve.access();
default: printf("Invalid bit flag!\n"); exit(1);
}
@ -79,6 +82,7 @@ bool Config::save(uint32_t flags) {
if (flags & (uint32_t)ConfigModFlag::AUDIO) result &= m_audio.save();
if (flags & (uint32_t)ConfigModFlag::CONTROLS) result &= m_controls.save();
if (flags & (uint32_t)ConfigModFlag::GENERAL) result &= m_general.save();
if (flags & (uint32_t)ConfigModFlag::RESOLVE) result &= m_resolve.save();
return true;
}
@ -153,7 +157,7 @@ Config::Config() {
return missing;
};
if (fixMissing(item->_json, defaults)) {
if (!item->_dontfix && fixMissing(item->_json, defaults)) {
should_resave = true;
printf("%s: some missing parameters has been added!\n", item->_name.data());
}
@ -177,7 +181,7 @@ Config::Config() {
return unused;
};
if (removeUnused(item->_json, defaults)) {
if (!item->_dontfix && removeUnused(item->_json, defaults)) {
should_backup = true;
should_resave = true;
printf("%s: some unused parameters has been removed!\n", item->_name.data());
@ -224,4 +228,6 @@ Config::Config() {
m_general._future = std::async(std::launch::async, load, &m_general,
json({{"systemlang", 1}, {"userIndex", 1}, {"profiles", json::array({defaultprof, defaultprof, defaultprof, defaultprof})}}),
ConfigModFlag::GENERAL);
m_resolve._future = std::async(std::launch::async | std::launch::deferred, load, &m_resolve, json({{"localhost", "127.0.0.1"}}), ConfigModFlag::RESOLVE);
}

View File

@ -8,11 +8,12 @@ using json = nlohmann::json;
enum class ConfigModFlag : uint32_t {
NONE = 0,
LOGGING = 2 << 0,
GRAPHICS = 2 << 1,
AUDIO = 2 << 2,
CONTROLS = 2 << 3,
GENERAL = 2 << 4,
LOGGING = 1 << 0,
GRAPHICS = 1 << 1,
AUDIO = 1 << 2,
CONTROLS = 1 << 3,
GENERAL = 1 << 4,
RESOLVE = 1 << 5,
};
class IConfig {