diff --git a/modules/libSceNet/CMakeLists.txt b/modules/libSceNet/CMakeLists.txt index 4fe48e9..4850422 100644 --- a/modules/libSceNet/CMakeLists.txt +++ b/modules/libSceNet/CMakeLists.txt @@ -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}) diff --git a/modules/libSceNet/codes.h b/modules/libSceNet/codes.h index e531840..abb30e9 100644 --- a/modules/libSceNet/codes.h +++ b/modules/libSceNet/codes.h @@ -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; \ No newline at end of file +constexpr size_t SCE_NET_RESOLVER_HOSTNAME_LEN_MAX = 255; diff --git a/modules/libSceNet/entry.cpp b/modules/libSceNet/entry.cpp index 93e657a..5d3e8eb 100644 --- a/modules/libSceNet/entry.cpp +++ b/modules/libSceNet/entry.cpp @@ -2,7 +2,6 @@ #include "logging.h" #include "types.h" -#define WIN32_LEAN_AND_MEAN #include #include @@ -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; } diff --git a/modules/libSceNet/epoll.cpp b/modules/libSceNet/epoll.cpp index bf1f36e..2317703 100644 --- a/modules/libSceNet/epoll.cpp +++ b/modules/libSceNet/epoll.cpp @@ -3,7 +3,6 @@ #include "types.h" #include "wepoll.h" -#define WIN32_LEAN_AND_MEAN #include #include diff --git a/modules/libSceNet/resolver.cpp b/modules/libSceNet/resolver.cpp index 906442f..9cd2397 100644 --- a/modules/libSceNet/resolver.cpp +++ b/modules/libSceNet/resolver.cpp @@ -1,49 +1,226 @@ #include "common.h" +#include "config_emu.h" #include "logging.h" #include "resolverTypes.h" +#include "socketTypes.h" + +#include +#include +#include + +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 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(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; } } diff --git a/modules/libSceNet/socket.cpp b/modules/libSceNet/socket.cpp index b553fff..bb6d0b3 100644 --- a/modules/libSceNet/socket.cpp +++ b/modules/libSceNet/socket.cpp @@ -1,13 +1,15 @@ #include "common.h" #include "logging.h" #include "socketTypes.h" -LOG_DEFINE_MODULE(libSceNet); -#define WIN32_LEAN_AND_MEAN #include #include +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; diff --git a/modules/libSceNpToolkit2/entry.cpp b/modules/libSceNpToolkit2/entry.cpp index 963848a..f44b66b 100644 --- a/modules/libSceNpToolkit2/entry.cpp +++ b/modules/libSceNpToolkit2/entry.cpp @@ -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::Response() + * + */ + +EXPORT SYSV_ABI int32_t __NID(_ZN3sce7Toolkit2NP2V24Core8ResponseINS2_11UserProfile10NpProfilesEEC1Ev)() { + LOG_USE_MODULE(libSceNpToolkit2); + LOG_ERR(L"todo %S", __FUNCTION__); + return Ok; +} } diff --git a/tools/config_emu/config_emu.cpp b/tools/config_emu/config_emu.cpp index 9916ccc..c06d25d 100644 --- a/tools/config_emu/config_emu.cpp +++ b/tools/config_emu/config_emu.cpp @@ -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 _future; - Item(std::string_view name): _name(name) {} + Item(std::string_view name, bool df = false): _name(name), _dontfix(df) {} std::pair, 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, 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); } diff --git a/tools/config_emu/config_emu.h b/tools/config_emu/config_emu.h index ff737b8..9d1db00 100644 --- a/tools/config_emu/config_emu.h +++ b/tools/config_emu/config_emu.h @@ -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 {