From 00339cf0102110e89c6fbb7a17c0d8c56b30940b Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Thu, 21 May 2026 20:57:55 +0300 Subject: [PATCH] http part6 (#4460) * added http* epolls * changed info to debug * one more info to debug * helper function --- src/core/libraries/network/http.cpp | 379 +++++++++++++++++++++++++--- src/core/libraries/network/http.h | 19 +- 2 files changed, 356 insertions(+), 42 deletions(-) diff --git a/src/core/libraries/network/http.cpp b/src/core/libraries/network/http.cpp index 6282fb10a..6e6961d75 100644 --- a/src/core/libraries/network/http.cpp +++ b/src/core/libraries/network/http.cpp @@ -3,8 +3,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -41,11 +43,21 @@ struct HttpSettings { bool nonblock = false; // false = blocking (default), true = nonblock (EAGAIN) }; +struct Epoll { + int ctx_id = 0; + std::deque events; + std::condition_variable cv; + bool destroyed = false; + bool abort_requested = false; +}; + struct HttpTemplate { std::string user_agent; int http_version; int auto_proxy_conf; HttpSettings settings; + int epoll_id = 0; + void* epoll_user_arg = nullptr; }; struct HttpConnection { @@ -58,6 +70,8 @@ struct HttpConnection { bool keep_alive = false; // Game-controlled keep-alive intent. bool is_secure = false; // True if scheme == "https". HttpSettings settings; + int epoll_id = 0; + void* epoll_user_arg = nullptr; }; struct HttpResponse { @@ -82,6 +96,8 @@ struct HttpRequest { HttpResponse res; std::condition_variable cv; // waiters in blocking getters block on this // notified when state leaves Sending. + int epoll_id = 0; + void* epoll_user_arg = nullptr; }; struct HttpState { @@ -93,6 +109,7 @@ struct HttpState { std::unordered_map templates; std::unordered_map connections; std::unordered_map> requests; + std::unordered_map> epolls; std::atomic shutting_down{false}; }; @@ -119,6 +136,38 @@ static HttpSettings* ResolveSettings(int id, const char*& level) { return nullptr; } +static OrbisHttpEpollHandle EncodeEpollHandle(int id) { + return reinterpret_cast(static_cast(id)); +} + +static int DecodeEpollHandle(OrbisHttpEpollHandle eh) { + return static_cast(reinterpret_cast(eh)); +} + +// Resolve the (epoll_id*, epoll_user_arg*) pair on a template/connection/request +static bool ResolveEpollBinding(int id, int*& epoll_id_out, void**& user_arg_out, + const char*& level) { + if (auto it = g_state.templates.find(id); it != g_state.templates.end()) { + epoll_id_out = &it->second.epoll_id; + user_arg_out = &it->second.epoll_user_arg; + level = "template"; + return true; + } + if (auto it = g_state.connections.find(id); it != g_state.connections.end()) { + epoll_id_out = &it->second.epoll_id; + user_arg_out = &it->second.epoll_user_arg; + level = "connection"; + return true; + } + if (auto it = g_state.requests.find(id); it != g_state.requests.end()) { + epoll_id_out = &it->second->epoll_id; + user_arg_out = &it->second->epoll_user_arg; + level = "request"; + return true; + } + return false; +} + // Populate a response object with the shape a transport-level failure produces: // no status line, no headers, no body. Used by the no-internet path. static void SynthesizeTransportFailureResponse(HttpResponse& res) { @@ -130,6 +179,40 @@ static void SynthesizeTransportFailureResponse(HttpResponse& res) { res.all_headers_blob.clear(); } +// Map common HTTP status codes to strings for logs. +static std::string HttpStatusLabel(int sc) { + switch (sc) { + case 0: + return "0 (no status)"; + case 200: + return "200 OK"; + case 204: + return "204 No Content"; + case 301: + return "301 Moved Permanently"; + case 302: + return "302 Found"; + case 304: + return "304 Not Modified"; + case 400: + return "400 Bad Request"; + case 401: + return "401 Unauthorized"; + case 403: + return "403 Forbidden"; + case 404: + return "404 Not Found"; + case 500: + return "500 Internal Server Error"; + case 502: + return "502 Bad Gateway"; + case 503: + return "503 Service Unavailable"; + default: + return std::to_string(sc); + } +} + static int WaitForResponseReady(HttpRequest& req, std::unique_lock& lock) { if (req.state == HttpRequestState::Aborted) { return ORBIS_HTTP_ERROR_ABORTED; @@ -218,11 +301,6 @@ static bool ContainsCrLf(const char* s) { // TODO/WIP/Stubbed functions //*********************************** -int PS4_SYSV_ABI sceHttpAbortWaitRequest(OrbisHttpEpollHandle eh) { - LOG_ERROR(Lib_Http, "(STUBBED) called eh={}", fmt::ptr(eh)); - return ORBIS_OK; -} - int PS4_SYSV_ABI sceHttpAddCookie(int libhttpCtxId, const char* url, const char* cookie, u64 cookieLength) { LOG_ERROR(Lib_Http, "(STUBBED) called libhttpCtxId={}, url={}, cookie={}, cookieLength={}", @@ -321,6 +399,8 @@ int PS4_SYSV_ABI sceHttpCreateConnection(int tmplId, const char* serverName, con conn.url = scheme_str + "://" + serverName + ":" + std::to_string(port); if (auto tmpl_it = g_state.templates.find(tmplId); tmpl_it != g_state.templates.end()) { conn.settings = tmpl_it->second.settings; + conn.epoll_id = tmpl_it->second.epoll_id; + conn.epoll_user_arg = tmpl_it->second.epoll_user_arg; } g_state.connections.emplace(conn_id, std::move(conn)); LOG_INFO(Lib_Http, "created connection connId={} url={}", conn_id, @@ -396,6 +476,8 @@ int PS4_SYSV_ABI sceHttpCreateConnectionWithURL(int tmplId, const char* url, boo conn.is_secure = is_secure; if (auto tmpl_it = g_state.templates.find(tmplId); tmpl_it != g_state.templates.end()) { conn.settings = tmpl_it->second.settings; + conn.epoll_id = tmpl_it->second.epoll_id; + conn.epoll_user_arg = tmpl_it->second.epoll_user_arg; } g_state.connections.emplace(conn_id, std::move(conn)); LOG_INFO(Lib_Http, "created connection connId={} host={} port={} scheme={}", conn_id, @@ -403,11 +485,6 @@ int PS4_SYSV_ABI sceHttpCreateConnectionWithURL(int tmplId, const char* url, boo return conn_id; } -int PS4_SYSV_ABI sceHttpCreateEpoll(int libhttpCtxId, OrbisHttpEpollHandle* eh) { - LOG_ERROR(Lib_Http, "(STUBBED) called libhttpCtxId={}, eh={}", libhttpCtxId, fmt::ptr(eh)); - return ORBIS_OK; -} - int PS4_SYSV_ABI sceHttpCreateRequest(int connId, int method, const char* path, u64 contentLength) { LOG_INFO(Lib_Http, "called connId={}, method={}, path={}, contentLength={}", connId, method, path ? path : "(null)", contentLength); @@ -473,6 +550,8 @@ int PS4_SYSV_ABI sceHttpCreateRequestWithURL(int connId, s32 method, const char* req->url = url; req->content_length = contentLength; req->settings = conn_it->second.settings; + req->epoll_id = conn_it->second.epoll_id; + req->epoll_user_arg = conn_it->second.epoll_user_arg; g_state.requests.emplace(req_id, std::move(req)); LOG_INFO(Lib_Http, "created request reqId={}", req_id); return req_id; @@ -541,11 +620,6 @@ int PS4_SYSV_ABI sceHttpDbgShowStat() { return ORBIS_OK; } -int PS4_SYSV_ABI sceHttpDestroyEpoll(int libhttpCtxId, OrbisHttpEpollHandle eh) { - LOG_ERROR(Lib_Http, "(STUBBED) called libhttpCtxId={}, eh={}", libhttpCtxId, fmt::ptr(eh)); - return ORBIS_OK; -} - int PS4_SYSV_ABI sceHttpGetAcceptEncodingGZIPEnabled(int id, int* isEnable) { LOG_ERROR(Lib_Http, "(STUBBED) called id={}, isEnable={}", id, fmt::ptr(isEnable)); return ORBIS_OK; @@ -582,12 +656,6 @@ int PS4_SYSV_ABI sceHttpGetCookieStats(int libhttpCtxId, OrbisHttpCookieStats* s return ORBIS_OK; } -int PS4_SYSV_ABI sceHttpGetEpoll(int id, OrbisHttpEpollHandle* eh, void** userArg) { - LOG_ERROR(Lib_Http, "(STUBBED) called id={}, eh={}, userArg={}", id, fmt::ptr(eh), - fmt::ptr(userArg)); - return ORBIS_OK; -} - int PS4_SYSV_ABI sceHttpGetEpollId() { LOG_ERROR(Lib_Http, "(STUBBED) called"); return ORBIS_OK; @@ -660,7 +728,7 @@ int PS4_SYSV_ABI sceHttpSendRequest(int reqId, const void* postData, u64 size) { LOG_ERROR(Lib_Http, "Request was aborted (reqId={})", reqId); return ORBIS_HTTP_ERROR_ABORTED; } - // Created -> Sending. Worker thread will move to Sent. + // Created to Sending. Worker thread will move to Sent. req.state = HttpRequestState::Sending; req_ptr = it->second; } @@ -689,6 +757,24 @@ int PS4_SYSV_ABI sceHttpSendRequest(int reqId, const void* postData, u64 size) { LOG_INFO(Lib_Http, "(TRANSPORT FAIL) reqId={} -> 0 (body 0 bytes, errno={:#x})", reqId, static_cast(req_ptr->last_errno)); req_ptr->cv.notify_all(); + // If this request is bound to an epoll, push a failure-shaped event so + // sceHttpWaitRequest callers see the completion (with errored bits). + if (req_ptr->epoll_id != 0) { + auto epoll_it = g_state.epolls.find(req_ptr->epoll_id); + if (epoll_it != g_state.epolls.end() && !epoll_it->second->destroyed) { + constexpr u32 FailureEventBits = + ORBIS_HTTP_NB_EVENT_RESOLVER_ERR | ORBIS_HTTP_NB_EVENT_HUP; + OrbisHttpNBEvent ev{}; + ev.events = FailureEventBits; + ev.eventDetail = FailureEventBits; + ev.id = reqId; + ev.userArg = req_ptr->epoll_user_arg; + epoll_it->second->events.push_back(ev); + epoll_it->second->cv.notify_all(); + LOG_DEBUG(Lib_Http, "pushed failure epoll event for reqId={} on epoll={}", reqId, + req_ptr->epoll_id); + } + } }).detach(); return ORBIS_OK; @@ -765,12 +851,6 @@ int PS4_SYSV_ABI sceHttpSetDelayBuildRequestEnabled(int id, int isEnable) { return ORBIS_OK; } -int PS4_SYSV_ABI sceHttpSetEpoll(int id, OrbisHttpEpollHandle eh, void* userArg) { - LOG_ERROR(Lib_Http, "(STUBBED) called id={}, eh={}, userArg={}", id, fmt::ptr(eh), - fmt::ptr(userArg)); - return ORBIS_OK; -} - int PS4_SYSV_ABI sceHttpSetEpollId() { LOG_ERROR(Lib_Http, "(STUBBED) called"); return ORBIS_OK; @@ -903,9 +983,14 @@ int PS4_SYSV_ABI sceHttpTerm(int libhttpCtxId) { req_ptr->state = HttpRequestState::Aborted; req_ptr->cv.notify_all(); // wake blocked waiters before wiping the map } + for (auto& [id, epoll_ptr] : g_state.epolls) { + epoll_ptr->destroyed = true; + epoll_ptr->cv.notify_all(); // wake any sceHttpWaitRequest blocker + } g_state.requests.clear(); g_state.connections.clear(); g_state.templates.clear(); + g_state.epolls.clear(); g_state.inited = false; } else { LOG_INFO(Lib_Http, "ctxId={} terminated, {} contexts still active", libhttpCtxId, @@ -914,16 +999,85 @@ int PS4_SYSV_ABI sceHttpTerm(int libhttpCtxId) { return ORBIS_OK; } -int PS4_SYSV_ABI sceHttpUnsetEpoll(int id) { - LOG_ERROR(Lib_Http, "(STUBBED) called id={}", id); - return ORBIS_OK; -} - int PS4_SYSV_ABI sceHttpWaitRequest(OrbisHttpEpollHandle eh, OrbisHttpNBEvent* nbev, int maxevents, int timeout) { - LOG_ERROR(Lib_Http, "(STUBBED) called eh={}, nbev={}, maxevents={}, timeout={}", fmt::ptr(eh), + LOG_DEBUG(Lib_Http, "called eh={}, nbev={}, maxevents={}, timeout={}", fmt::ptr(eh), fmt::ptr(nbev), maxevents, timeout); - return ORBIS_OK; + std::unique_lock lock(g_state.m_mutex); + if (!g_state.inited) { + LOG_ERROR(Lib_Http, "Not initialized"); + return ORBIS_HTTP_ERROR_BEFORE_INIT; + } + if (maxevents <= 0 || !eh || !nbev) { + LOG_ERROR(Lib_Http, "InvalidValue (maxevents={}, eh={}, nbev={})", maxevents, fmt::ptr(eh), + fmt::ptr(nbev)); + return ORBIS_HTTP_ERROR_INVALID_VALUE; + } + int epoll_id = DecodeEpollHandle(eh); + auto it = g_state.epolls.find(epoll_id); + if (it == g_state.epolls.end()) { + LOG_ERROR(Lib_Http, "Invalid epoll handle (id={})", epoll_id); + return ORBIS_HTTP_ERROR_INVALID_ID; + } + auto epoll_ptr = it->second; + + // if the epoll's abort flag is + // already set, return Aborted immediately without draining or waiting. + if (epoll_ptr->abort_requested) { + LOG_INFO(Lib_Http, "epoll id={} already aborted, returning ABORTED", epoll_id); + return ORBIS_HTTP_ERROR_ABORTED; + } + + auto drain_into_output = [&]() -> int { + int count = 0; + while (count < maxevents && !epoll_ptr->events.empty()) { + nbev[count] = epoll_ptr->events.front(); + epoll_ptr->events.pop_front(); + ++count; + } + return count; + }; + + // Events already queued: drain and return immediately. + int already = drain_into_output(); + if (already > 0) { + LOG_INFO(Lib_Http, "epoll id={} returned {} events (no wait)", epoll_id, already); + return already; + } + + // No events queued. Behavior depends on timeout. + if (timeout == 0) { + // Poll mode: don't wait, just return 0. + return 0; + } + if (epoll_ptr->destroyed || g_state.shutting_down.load()) { + // Don't wait if we already know we'd be woken right away. + return 0; + } + + auto predicate = [&]() { + return !epoll_ptr->events.empty() || epoll_ptr->destroyed || epoll_ptr->abort_requested || + g_state.shutting_down.load(); + }; + if (timeout < 0) { + epoll_ptr->cv.wait(lock, predicate); + } else { + epoll_ptr->cv.wait_for(lock, std::chrono::microseconds(timeout), predicate); + } + + // If AbortWaitRequest fired during the wait, return ABORTED + if (epoll_ptr->abort_requested) { + LOG_INFO(Lib_Http, "epoll id={} woken by abort, returning ABORTED", epoll_id); + return ORBIS_HTTP_ERROR_ABORTED; + } + int count = drain_into_output(); + if (epoll_ptr->destroyed) { + LOG_INFO(Lib_Http, "epoll id={} woken because destroyed; returning {} events", epoll_id, + count); + } else { + LOG_INFO(Lib_Http, "epoll id={} returned {} events after wait", epoll_id, count); + } + return count; } int PS4_SYSV_ABI sceHttpUriCopy() { @@ -934,6 +1088,157 @@ int PS4_SYSV_ABI sceHttpUriCopy() { //*********************************** // Non-blocking processing functions //*********************************** +int PS4_SYSV_ABI sceHttpCreateEpoll(int libhttpCtxId, OrbisHttpEpollHandle* eh) { + LOG_INFO(Lib_Http, "called libhttpCtxId={}, eh={}", libhttpCtxId, fmt::ptr(eh)); + std::lock_guard lock(g_state.m_mutex); + if (!g_state.inited) { + LOG_ERROR(Lib_Http, "Not initialized"); + return ORBIS_HTTP_ERROR_BEFORE_INIT; + } + if (!g_state.active_contexts.contains(libhttpCtxId)) { + LOG_ERROR(Lib_Http, "Invalid libhttpCtxId={}", libhttpCtxId); + return ORBIS_HTTP_ERROR_INVALID_ID; + } + if (!eh) { + LOG_ERROR(Lib_Http, "eh output pointer is null"); + return ORBIS_HTTP_ERROR_INVALID_VALUE; + } + int epoll_id = ++g_state.next_obj_id; + auto epoll = std::make_shared(); + epoll->ctx_id = libhttpCtxId; + g_state.epolls.emplace(epoll_id, std::move(epoll)); + *eh = EncodeEpollHandle(epoll_id); + LOG_INFO(Lib_Http, "created epoll id={} (handle={})", epoll_id, fmt::ptr(*eh)); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceHttpDestroyEpoll(int libhttpCtxId, OrbisHttpEpollHandle eh) { + LOG_INFO(Lib_Http, "called libhttpCtxId={}, eh={}", libhttpCtxId, fmt::ptr(eh)); + std::lock_guard lock(g_state.m_mutex); + if (!g_state.inited) { + LOG_ERROR(Lib_Http, "Not initialized"); + return ORBIS_HTTP_ERROR_BEFORE_INIT; + } + if (!g_state.active_contexts.contains(libhttpCtxId)) { + LOG_ERROR(Lib_Http, "Invalid libhttpCtxId={}", libhttpCtxId); + return ORBIS_HTTP_ERROR_INVALID_ID; + } + if (!eh) { + LOG_ERROR(Lib_Http, "eh is null"); + return ORBIS_HTTP_ERROR_INVALID_VALUE; + } + int epoll_id = DecodeEpollHandle(eh); + auto it = g_state.epolls.find(epoll_id); + if (it == g_state.epolls.end()) { + LOG_ERROR(Lib_Http, "Invalid epoll handle (id={})", epoll_id); + return ORBIS_HTTP_ERROR_INVALID_ID; + } + if (it->second->ctx_id != libhttpCtxId) { + LOG_ERROR(Lib_Http, "ctxId mismatch: epoll ctx_id={} but caller passed {}", + it->second->ctx_id, libhttpCtxId); + } + auto epoll_ptr = it->second; + epoll_ptr->destroyed = true; + epoll_ptr->cv.notify_all(); + g_state.epolls.erase(it); + LOG_INFO(Lib_Http, "destroyed epoll id={}", epoll_id); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceHttpGetEpoll(int id, OrbisHttpEpollHandle* eh, void** userArg) { + LOG_INFO(Lib_Http, "called id={}, eh={}, userArg={}", id, fmt::ptr(eh), fmt::ptr(userArg)); + std::lock_guard lock(g_state.m_mutex); + if (!g_state.inited) { + LOG_ERROR(Lib_Http, "Not initialized"); + return ORBIS_HTTP_ERROR_BEFORE_INIT; + } + if (!eh) { + LOG_ERROR(Lib_Http, "eh output pointer is null"); + return ORBIS_HTTP_ERROR_INVALID_VALUE; + } + int* src_epoll_id = nullptr; + void** src_user_arg = nullptr; + const char* level = ""; + if (!ResolveEpollBinding(id, src_epoll_id, src_user_arg, level)) { + LOG_ERROR(Lib_Http, "Invalid id={} (not a template, connection, or request)", id); + return ORBIS_HTTP_ERROR_INVALID_ID; + } + *eh = EncodeEpollHandle(*src_epoll_id); + if (userArg) { + *userArg = *src_user_arg; + } + LOG_INFO(Lib_Http, "got epoll id={} userArg={} from {} id={}", *src_epoll_id, + fmt::ptr(*src_user_arg), level, id); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceHttpSetEpoll(int id, OrbisHttpEpollHandle eh, void* userArg) { + LOG_INFO(Lib_Http, "called id={}, eh={}, userArg={}", id, fmt::ptr(eh), fmt::ptr(userArg)); + std::lock_guard lock(g_state.m_mutex); + if (!g_state.inited) { + LOG_ERROR(Lib_Http, "Not initialized"); + return ORBIS_HTTP_ERROR_BEFORE_INIT; + } + int epoll_id = DecodeEpollHandle(eh); + if (!g_state.epolls.contains(epoll_id)) { + LOG_ERROR(Lib_Http, "Invalid epoll handle (id={})", epoll_id); + return ORBIS_HTTP_ERROR_INVALID_ID; + } + int* target_epoll_id = nullptr; + void** target_user_arg = nullptr; + const char* level = ""; + if (!ResolveEpollBinding(id, target_epoll_id, target_user_arg, level)) { + LOG_ERROR(Lib_Http, "Invalid id={} (not a template, connection, or request)", id); + return ORBIS_HTTP_ERROR_INVALID_ID; + } + *target_epoll_id = epoll_id; + *target_user_arg = userArg; + LOG_INFO(Lib_Http, "set epoll={} userArg={} at {} level (id={})", epoll_id, fmt::ptr(userArg), + level, id); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceHttpUnsetEpoll(int id) { + LOG_INFO(Lib_Http, "called id={}", id); + std::lock_guard lock(g_state.m_mutex); + if (!g_state.inited) { + LOG_ERROR(Lib_Http, "Not initialized"); + return ORBIS_HTTP_ERROR_BEFORE_INIT; + } + auto it = g_state.requests.find(id); + if (it == g_state.requests.end()) { + LOG_ERROR(Lib_Http, "Invalid reqId={}", id); + return ORBIS_HTTP_ERROR_INVALID_ID; + } + it->second->epoll_id = 0; + it->second->epoll_user_arg = nullptr; + LOG_INFO(Lib_Http, "cleared epoll binding from reqId={}", id); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceHttpAbortWaitRequest(OrbisHttpEpollHandle eh) { + LOG_INFO(Lib_Http, "called eh={}", fmt::ptr(eh)); + std::lock_guard lock(g_state.m_mutex); + if (!g_state.inited) { + LOG_ERROR(Lib_Http, "Not initialized"); + return ORBIS_HTTP_ERROR_BEFORE_INIT; + } + if (!eh) { + LOG_ERROR(Lib_Http, "eh is null"); + return ORBIS_HTTP_ERROR_INVALID_VALUE; + } + int epoll_id = DecodeEpollHandle(eh); + auto it = g_state.epolls.find(epoll_id); + if (it == g_state.epolls.end()) { + LOG_ERROR(Lib_Http, "Invalid epoll handle (id={})", epoll_id); + return ORBIS_HTTP_ERROR_INVALID_ID; + } + it->second->abort_requested = true; + it->second->cv.notify_all(); + LOG_INFO(Lib_Http, "epoll id={} abort requested", epoll_id); + return ORBIS_OK; +} + int PS4_SYSV_ABI sceHttpGetNonblock(int id, int* isEnable) { LOG_INFO(Lib_Http, "called id={}, isEnable={}", id, fmt::ptr(isEnable)); std::lock_guard lock(g_state.m_mutex); @@ -1224,7 +1529,7 @@ int PS4_SYSV_ABI sceHttpGetResponseContentLength(int reqId, int* result, u64* co } int PS4_SYSV_ABI sceHttpGetStatusCode(int reqId, int* statusCode) { - LOG_INFO(Lib_Http, "called reqId={}, statusCode={}", reqId, fmt::ptr(statusCode)); + LOG_INFO(Lib_Http, "called reqId={}", reqId); std::unique_lock lock(g_state.m_mutex); if (!g_state.inited) { LOG_ERROR(Lib_Http, "Not initialized"); @@ -1256,7 +1561,7 @@ int PS4_SYSV_ABI sceHttpGetStatusCode(int reqId, int* statusCode) { return ORBIS_HTTP_ERROR_BEFORE_SEND; } *statusCode = req.res.status_code; - LOG_INFO(Lib_Http, "reqId={} status={}", reqId, req.res.status_code); + LOG_INFO(Lib_Http, "reqId={} status={}", reqId, HttpStatusLabel(req.res.status_code)); return ORBIS_OK; } diff --git a/src/core/libraries/network/http.h b/src/core/libraries/network/http.h index 0fdc2033e..9931de034 100644 --- a/src/core/libraries/network/http.h +++ b/src/core/libraries/network/http.h @@ -13,6 +13,15 @@ class SymbolsResolver; namespace Libraries::Http { +enum OrbisHttpNBEvents : u32 { + ORBIS_HTTP_NB_EVENT_IN = 0x00000001U, // Ready to receive (response data available). + ORBIS_HTTP_NB_EVENT_OUT = 0x00000002U, // Ready to send. + ORBIS_HTTP_NB_EVENT_SOCK_ERR = 0x00000008U, // Socket-level error during send/recv. + ORBIS_HTTP_NB_EVENT_HUP = 0x00000010U, // Request interrupted by the application. + ORBIS_HTTP_NB_EVENT_RESOLVED = 0x00010000U, // DNS resolution completed. + ORBIS_HTTP_NB_EVENT_RESOLVER_ERR = 0x00020000U, // DNS resolution failed. +}; + enum OrbisHttpsFlags : u32 { ORBIS_HTTPS_FLAG_SERVER_VERIFY = 0x01, ORBIS_HTTPS_FLAG_CLIENT_VERIFY = 0x02, @@ -129,7 +138,6 @@ using OrbisHttpsCallback = int(PS4_SYSV_ABI*)(int libsslCtxId, u32 verifyErr, vo using OrbisHttpsCaList = Libraries::Ssl::OrbisSslCaList; // Functions -int PS4_SYSV_ABI sceHttpAbortWaitRequest(OrbisHttpEpollHandle eh); int PS4_SYSV_ABI sceHttpAddCookie(int libhttpCtxId, const char* url, const char* cookie, u64 cookieLength); int PS4_SYSV_ABI sceHttpAddQuery(); @@ -146,7 +154,6 @@ int PS4_SYSV_ABI sceHttpCookieImport(int libhttpCtxId, const void* buffer, u64 b int PS4_SYSV_ABI sceHttpCreateConnection(int tmplId, const char* serverName, const char* scheme, u16 port, int isEnableKeepalive); int PS4_SYSV_ABI sceHttpCreateConnectionWithURL(int tmplId, const char* url, bool enableKeepalive); -int PS4_SYSV_ABI sceHttpCreateEpoll(int libhttpCtxId, OrbisHttpEpollHandle* eh); int PS4_SYSV_ABI sceHttpCreateRequest(int connId, int method, const char* path, u64 contentLength); int PS4_SYSV_ABI sceHttpCreateRequestWithURL(int connId, s32 method, const char* url, u64 contentLength); @@ -160,7 +167,6 @@ int PS4_SYSV_ABI sceHttpDbgShowConnectionStat(); int PS4_SYSV_ABI sceHttpDbgShowMemoryPoolStat(); int PS4_SYSV_ABI sceHttpDbgShowRequestStat(); int PS4_SYSV_ABI sceHttpDbgShowStat(); -int PS4_SYSV_ABI sceHttpDestroyEpoll(int libhttpCtxId, OrbisHttpEpollHandle eh); int PS4_SYSV_ABI sceHttpGetAcceptEncodingGZIPEnabled(int id, int* isEnable); int PS4_SYSV_ABI sceHttpGetAuthEnabled(int id, int* isEnable); int PS4_SYSV_ABI sceHttpGetConnectionStat(); @@ -168,7 +174,6 @@ int PS4_SYSV_ABI sceHttpGetCookie(int libhttpCtxId, const char* url, char* cooki u64 prepared, int isSecure); int PS4_SYSV_ABI sceHttpGetCookieEnabled(int id, int* isEnable); int PS4_SYSV_ABI sceHttpGetCookieStats(int libhttpCtxId, OrbisHttpCookieStats* stats); -int PS4_SYSV_ABI sceHttpGetEpoll(int id, OrbisHttpEpollHandle* eh, void** userArg); int PS4_SYSV_ABI sceHttpGetEpollId(); int PS4_SYSV_ABI sceHttpGetMemoryPoolStats(int libhttpCtxId, OrbisHttpMemoryPoolStats* currentStat); int PS4_SYSV_ABI sceHttpGetRegisteredCtxIds(); @@ -218,13 +223,17 @@ int PS4_SYSV_ABI sceHttpsSetSslCallback(int id, OrbisHttpsCallback cbfunc, void* int PS4_SYSV_ABI sceHttpsSetSslVersion(int id, int version); int PS4_SYSV_ABI sceHttpsUnloadCert(int libhttpCtxId); int PS4_SYSV_ABI sceHttpTerm(int libhttpCtxId); -int PS4_SYSV_ABI sceHttpUnsetEpoll(int id); int PS4_SYSV_ABI sceHttpWaitRequest(OrbisHttpEpollHandle eh, OrbisHttpNBEvent* nbev, int maxevents, int timeout); int PS4_SYSV_ABI sceHttpUriCopy(); //*********************************** // Non-blocking processing functions //*********************************** +int PS4_SYSV_ABI sceHttpCreateEpoll(int libhttpCtxId, OrbisHttpEpollHandle* eh); +int PS4_SYSV_ABI sceHttpDestroyEpoll(int libhttpCtxId, OrbisHttpEpollHandle eh); +int PS4_SYSV_ABI sceHttpGetEpoll(int id, OrbisHttpEpollHandle* eh, void** userArg); +int PS4_SYSV_ABI sceHttpUnsetEpoll(int id); +int PS4_SYSV_ABI sceHttpAbortWaitRequest(OrbisHttpEpollHandle eh); int PS4_SYSV_ABI sceHttpGetNonblock(int id, int* isEnable); int PS4_SYSV_ABI sceHttpSetNonblock(int id, int isEnable); int PS4_SYSV_ABI sceHttpTryGetNonblock(int id, int* isEnable);