mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-13 17:49:29 +01:00
Merge pull request #22932 from hrydgard/http-ids-npauth-ticket
sceHttp: Stable ids; NpAuth: Return the ticket param asked for
This commit is contained in:
5 files changed
+242
-157
No files matched your search
+123
-119
@@ -35,7 +35,53 @@
|
||||
#include "Common/Net/HTTPClient.h"
|
||||
|
||||
|
||||
static std::vector<std::shared_ptr<HTTPTemplate>> httpObjects;
|
||||
// Templates, connections and requests are numbered separately, with the kind in the top byte
|
||||
// (1, 0x01000001, 0x02000001). A new object takes the lowest free number (tests/net/http/ids).
|
||||
enum HttpIdKind {
|
||||
HTTP_ID_TEMPLATE = 0,
|
||||
HTTP_ID_CONNECTION = 1,
|
||||
HTTP_ID_REQUEST = 2,
|
||||
HTTP_ID_KIND_COUNT,
|
||||
};
|
||||
|
||||
static std::vector<std::shared_ptr<HTTPTemplate>> httpObjects[HTTP_ID_KIND_COUNT];
|
||||
|
||||
static HTTPTemplate *GetHttpObject(int id) {
|
||||
const u32 kind = (u32)id >> 24;
|
||||
const u32 number = (u32)id & 0x00FFFFFF;
|
||||
if (kind >= HTTP_ID_KIND_COUNT || number == 0 || number > httpObjects[kind].size())
|
||||
return nullptr;
|
||||
return httpObjects[kind][number - 1].get();
|
||||
}
|
||||
|
||||
static bool IsHttpId(int id, HttpIdKind kind) {
|
||||
return ((u32)id >> 24) == (u32)kind && GetHttpObject(id) != nullptr;
|
||||
}
|
||||
|
||||
static HTTPRequest *GetHttpRequest(int id) {
|
||||
return IsHttpId(id, HTTP_ID_REQUEST) ? static_cast<HTTPRequest *>(GetHttpObject(id)) : nullptr;
|
||||
}
|
||||
|
||||
static int AddHttpObject(HttpIdKind kind, std::shared_ptr<HTTPTemplate> obj) {
|
||||
auto &objects = httpObjects[kind];
|
||||
size_t index = 0;
|
||||
while (index < objects.size() && objects[index])
|
||||
index++;
|
||||
if (index == objects.size())
|
||||
objects.push_back(obj);
|
||||
else
|
||||
objects[index] = obj;
|
||||
return ((int)kind << 24) | (int)(index + 1);
|
||||
}
|
||||
|
||||
static void RemoveHttpObject(int id) {
|
||||
httpObjects[(u32)id >> 24][((u32)id & 0x00FFFFFF) - 1].reset();
|
||||
}
|
||||
|
||||
static void ClearHttpObjects() {
|
||||
for (auto &objects : httpObjects)
|
||||
objects.clear();
|
||||
}
|
||||
static std::mutex httpLock;
|
||||
|
||||
bool httpInited = false;
|
||||
@@ -65,13 +111,14 @@ int HTTPTemplate::addRequestHeader(const char* name, const char* value, u32 mode
|
||||
}
|
||||
|
||||
int HTTPTemplate::removeRequestHeader(const char* name) {
|
||||
requestHeaders_.erase(name);
|
||||
if (requestHeaders_.erase(name) == 0)
|
||||
return SCE_HTTP_ERROR_NOT_FOUND;
|
||||
return 0;
|
||||
}
|
||||
|
||||
HTTPConnection::HTTPConnection(int templateID, const char* hostString, const char* scheme, u32 port, int enableKeepalive) {
|
||||
// Copy base data as initial base value for this
|
||||
HTTPTemplate::operator=(*httpObjects[templateID - 1LL]);
|
||||
HTTPTemplate::operator=(*GetHttpObject(templateID));
|
||||
|
||||
// Initialize
|
||||
this->templateID = templateID;
|
||||
@@ -84,7 +131,7 @@ HTTPConnection::HTTPConnection(int templateID, const char* hostString, const cha
|
||||
HTTPRequest::HTTPRequest(int connectionID, int method, const char *url, u64 contentLength, net::ResolveFunc customResolver) : client(customResolver) {
|
||||
// Copy base data as initial base value for this
|
||||
// Since dynamic_cast/dynamic_pointer_cast/typeid requires RTTI to be enabled (ie. /GR instead of /GR- on msvc, enabled by default on most compilers), so we can only use static_cast here
|
||||
HTTPConnection::operator=(static_cast<HTTPConnection&>(*httpObjects[connectionID - 1LL]));
|
||||
HTTPConnection::operator=(*static_cast<HTTPConnection *>(GetHttpObject(connectionID)));
|
||||
|
||||
// Initialize
|
||||
this->connectionID = connectionID;
|
||||
@@ -103,10 +150,6 @@ HTTPRequest::~HTTPRequest() {
|
||||
}
|
||||
|
||||
int HTTPRequest::getResponseContentLength() {
|
||||
// FIXME: Will sceHttpGetContentLength returns an error if the request was not sent yet?
|
||||
//if (progress_.progress == 0.0f)
|
||||
// return SCE_HTTP_ERROR_BEFORE_SEND;
|
||||
|
||||
entityLength_ = -1; // FIXME: should we default to 0 instead?
|
||||
for (std::string& line : responseHeaders_) {
|
||||
if (startsWithNoCase(line, "Content-Length")) {
|
||||
@@ -129,17 +172,10 @@ int HTTPRequest::abortRequest() {
|
||||
}
|
||||
|
||||
int HTTPRequest::getStatusCode() {
|
||||
// FIXME: Will sceHttpGetStatusCode returns an error if the request was not sent yet?
|
||||
//if (progress_.progress == 0.0f)
|
||||
// return SCE_HTTP_ERROR_BEFORE_SEND;
|
||||
return responseCode_;
|
||||
}
|
||||
|
||||
int HTTPRequest::getAllResponseHeaders(u32 headerAddrPtr, u32 headerSizePtr) {
|
||||
// FIXME: Will sceHttpGetAllHeader returns an error if the request was not sent yet?
|
||||
//if (progress_.progress == 0.0f)
|
||||
// return SCE_HTTP_ERROR_BEFORE_SEND;
|
||||
|
||||
const char* const delim = "\r\n";
|
||||
std::ostringstream imploded;
|
||||
std::copy(responseHeaders_.begin(), responseHeaders_.end(), std::ostream_iterator<std::string>(imploded, delim));
|
||||
@@ -191,9 +227,6 @@ int HTTPRequest::getAllResponseHeaders(u32 headerAddrPtr, u32 headerSizePtr) {
|
||||
}
|
||||
|
||||
int HTTPRequest::readData(u32 destDataPtr, u32 size) {
|
||||
// FIXME: Will sceHttpReadData returns an error if the request was not sent yet?
|
||||
//if (progress_.progress == 0.0f)
|
||||
// return SCE_HTTP_ERROR_BEFORE_SEND;
|
||||
u32 sz = std::min(size, (u32)responseContent_.size());
|
||||
if (sz > 0) {
|
||||
Memory::MemcpyUnchecked(destDataPtr, responseContent_.c_str(), sz);
|
||||
@@ -289,6 +322,7 @@ int HTTPRequest::sendRequest(u32 postDataPtr, u32 postDataSize) {
|
||||
return SCE_HTTP_ERROR_ABORTED;
|
||||
}
|
||||
|
||||
sent_ = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -301,23 +335,19 @@ void __HttpShutdown() {
|
||||
httpsInited = false;
|
||||
httpCacheInited = false;
|
||||
|
||||
for (const auto& it : httpObjects) {
|
||||
if (it->className() == name_HTTPRequest)
|
||||
for (const auto& it : httpObjects[HTTP_ID_REQUEST]) {
|
||||
if (it)
|
||||
(static_cast<HTTPRequest*>(it.get()))->abortRequest();
|
||||
}
|
||||
httpObjects.clear();
|
||||
ClearHttpObjects();
|
||||
}
|
||||
|
||||
// id: ID of the template or connection
|
||||
// id: ID of a template
|
||||
int sceHttpSetResolveRetry(int id, int retryCount) {
|
||||
if (id <= 0 || id > (int)httpObjects.size())
|
||||
if (!IsHttpId(id, HTTP_ID_TEMPLATE))
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
const auto& conn = httpObjects[id - 1LL];
|
||||
if (!(conn->className() == name_HTTPTemplate || conn->className() == name_HTTPConnection))
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id (%s)", conn->className());
|
||||
|
||||
conn->setResolveRetry(retryCount);
|
||||
GetHttpObject(id)->setResolveRetry(retryCount);
|
||||
return hleLogDebug(Log::sceNet, 0);
|
||||
}
|
||||
|
||||
@@ -327,9 +357,7 @@ static int sceHttpInit(MIPSState *mips, int poolSize) {
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_ALREADY_INITED, "http already inited");
|
||||
|
||||
std::lock_guard<std::mutex> guard(httpLock);
|
||||
httpObjects.clear();
|
||||
// Reserve at least 1 element to prevent ::begin() from returning null when no element has been added yet
|
||||
httpObjects.reserve(1);
|
||||
ClearHttpObjects();
|
||||
httpInited = true;
|
||||
return hleLogDebug(Log::sceNet, 0);
|
||||
}
|
||||
@@ -337,7 +365,7 @@ static int sceHttpInit(MIPSState *mips, int poolSize) {
|
||||
static int sceHttpEnd() {
|
||||
WARN_LOG(Log::sceNet, "UNTESTED sceHttpEnd()");
|
||||
std::lock_guard<std::mutex> guard(httpLock);
|
||||
httpObjects.clear();
|
||||
ClearHttpObjects();
|
||||
httpInited = false;
|
||||
return hleLogDebug(Log::sceNet, 0);
|
||||
}
|
||||
@@ -369,13 +397,15 @@ static u32 sceHttpGetProxy(u32 id, u32 activateFlagPtr, u32 modePtr, u32 proxyHo
|
||||
|
||||
static int sceHttpGetStatusCode(int requestID, u32 statusCodePtr) {
|
||||
WARN_LOG(Log::sceNet, "UNTESTED sceHttpGetStatusCode(%d, %x)", requestID, statusCodePtr);
|
||||
if (requestID <= 0 || requestID > (int)httpObjects.size())
|
||||
HTTPRequest *req = GetHttpRequest(requestID);
|
||||
if (!req)
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
if (!Memory::IsValidRange(statusCodePtr, 4))
|
||||
return hleLogError(Log::sceNet, -1, "invalid arg"); //SCE_HTTP_ERROR_INVALID_VALUE;
|
||||
|
||||
const auto& req = (HTTPRequest*)httpObjects[requestID - 1LL].get();
|
||||
if (!req->wasSent())
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_BEFORE_SEND, "not sent");
|
||||
// FIXME: According to JPCSP, try to connect the request first
|
||||
//req->connect();
|
||||
int status = req->getStatusCode();
|
||||
@@ -389,13 +419,15 @@ static int sceHttpGetStatusCode(int requestID, u32 statusCodePtr) {
|
||||
// Games will repeatedly called sceHttpReadData until it returns (the size read into the data buffer) 0
|
||||
// FIXME: sceHttpReadData seems to be blocking current thread, since hleDelayResult can make Download progressbar to moves progressively instead of instantly jump to 100%
|
||||
static int sceHttpReadData(int requestID, u32 dataPtr, u32 dataSize) {
|
||||
if (requestID <= 0 || requestID > (int)httpObjects.size())
|
||||
HTTPRequest *req = GetHttpRequest(requestID);
|
||||
if (!req)
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
if (!Memory::IsValidRange(dataPtr, dataSize))
|
||||
return hleLogError(Log::sceNet, -1, "invalid arg"); // SCE_HTTP_ERROR_INVALID_VALUE
|
||||
|
||||
const auto& req = (HTTPRequest*)httpObjects[requestID - 1LL].get();
|
||||
if (!req->wasSent())
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_BEFORE_SEND, "not sent");
|
||||
// FIXME: According to JPCSP, try to connect the request first
|
||||
//req->connect();
|
||||
|
||||
@@ -420,13 +452,12 @@ static int sceHttpSendRequest(int requestID, u32 dataPtr, u32 dataSize) {
|
||||
if (!httpInited)
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_BEFORE_INIT, "http not initialized yet");
|
||||
|
||||
if (requestID <= 0 || requestID > (int)httpObjects.size())
|
||||
HTTPRequest *req = GetHttpRequest(requestID);
|
||||
if (!req)
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
if (dataSize > 0 && !Memory::IsValidRange(dataPtr, dataSize))
|
||||
return hleLogError(Log::sceNet, -1, "invalid arg"); // SCE_HTTP_ERROR_INVALID_VALUE
|
||||
|
||||
const auto& req = (HTTPRequest*)httpObjects[requestID - 1LL].get();
|
||||
// Internally try to connect, and get response headers (at least the status code?)
|
||||
int retval = req->sendRequest(dataPtr, dataSize);
|
||||
return hleLogDebug(Log::sceNet, retval);
|
||||
@@ -434,54 +465,53 @@ static int sceHttpSendRequest(int requestID, u32 dataPtr, u32 dataSize) {
|
||||
|
||||
static int sceHttpDeleteRequest(int requestID) {
|
||||
std::lock_guard<std::mutex> guard(httpLock);
|
||||
if (requestID <= 0 || requestID > (int)httpObjects.size())
|
||||
if (!IsHttpId(requestID, HTTP_ID_REQUEST))
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
if (httpObjects[requestID - 1LL]->className() != name_HTTPRequest)
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
httpObjects.erase(httpObjects.begin() + requestID - 1);
|
||||
RemoveHttpObject(requestID);
|
||||
return hleLogDebug(Log::sceNet, 0);
|
||||
}
|
||||
|
||||
// id: ID of the template, connection or request
|
||||
static int sceHttpDeleteHeader(int id, const char *name) {
|
||||
if (id <= 0 || id > (int)httpObjects.size())
|
||||
HTTPTemplate *obj = GetHttpObject(id);
|
||||
if (!obj)
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
if (!name)
|
||||
return hleLogError(Log::sceNet, -1, "invalid name"); // SCE_HTTP_ERROR_INVALID_VALUE
|
||||
|
||||
const auto& req = (HTTPRequest*)httpObjects[id - 1LL].get();
|
||||
return req->removeRequestHeader(name);
|
||||
return obj->removeRequestHeader(name);
|
||||
}
|
||||
|
||||
static int sceHttpDeleteConnection(int connectionID) {
|
||||
std::lock_guard<std::mutex> guard(httpLock);
|
||||
if (connectionID <= 0 || connectionID > (int)httpObjects.size())
|
||||
if (!IsHttpId(connectionID, HTTP_ID_CONNECTION))
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
if (httpObjects[connectionID - 1LL]->className() != name_HTTPConnection)
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
for (const auto &it : httpObjects[HTTP_ID_REQUEST]) {
|
||||
if (it && static_cast<HTTPRequest *>(it.get())->getConnectionID() == connectionID)
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_CONNECTION_HAS_REQUESTS, "connection has requests");
|
||||
}
|
||||
|
||||
httpObjects.erase(httpObjects.begin() + connectionID - 1);
|
||||
RemoveHttpObject(connectionID);
|
||||
return hleLogDebug(Log::sceNet, 0);
|
||||
}
|
||||
|
||||
// id: ID of the template, connection or request
|
||||
// id: ID of the template or connection
|
||||
static int sceHttpSetConnectTimeOut(int id, u32 timeout) {
|
||||
if (id <= 0 || id > (int)httpObjects.size())
|
||||
if (!IsHttpId(id, HTTP_ID_TEMPLATE) && !IsHttpId(id, HTTP_ID_CONNECTION))
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
auto& conn = httpObjects[id - 1LL];
|
||||
conn->setConnectTimeout(timeout);
|
||||
GetHttpObject(id)->setConnectTimeout(timeout);
|
||||
return hleLogDebug(Log::sceNet, 0);
|
||||
}
|
||||
|
||||
// id: ID of the template, connection or request
|
||||
// id: ID of the template or connection
|
||||
static int sceHttpSetSendTimeOut(int id, u32 timeout) {
|
||||
if (id <= 0 || id > (int)httpObjects.size())
|
||||
if (!IsHttpId(id, HTTP_ID_TEMPLATE) && !IsHttpId(id, HTTP_ID_CONNECTION))
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
auto& conn = httpObjects[id - 1LL];
|
||||
conn->setSendTimeout(timeout);
|
||||
GetHttpObject(id)->setSendTimeout(timeout);
|
||||
return hleLogDebug(Log::sceNet, 0);
|
||||
}
|
||||
|
||||
@@ -533,17 +563,11 @@ static int sceHttpsDisableOption(int id) {
|
||||
static int sceHttpCreateRequest(int connectionID, int method, const char *path, u64 contentLength) {
|
||||
WARN_LOG(Log::sceNet, "UNTESTED sceHttpCreateRequest(%d, %d, %s, %llx)", connectionID, method, safe_string(path), contentLength);
|
||||
std::lock_guard<std::mutex> guard(httpLock);
|
||||
if (connectionID <= 0 || connectionID > (int)httpObjects.size())
|
||||
// Any method is accepted here.
|
||||
if (!IsHttpId(connectionID, HTTP_ID_CONNECTION))
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
if (httpObjects[connectionID - 1LL]->className() != name_HTTPConnection)
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
if (method < PSPHttpMethod::PSP_HTTP_METHOD_GET || method > PSPHttpMethod::PSP_HTTP_METHOD_HEAD)
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_UNKNOWN_METHOD, "unknown method");
|
||||
|
||||
httpObjects.emplace_back(std::make_shared<HTTPRequest>(connectionID, method, path ? path : "", contentLength, &ProcessHostnameWithInfraDNS));
|
||||
int retid = (int)httpObjects.size();
|
||||
int retid = AddHttpObject(HTTP_ID_REQUEST, std::make_shared<HTTPRequest>(connectionID, method, path ? path : "", contentLength, &ProcessHostnameWithInfraDNS));
|
||||
return hleLogDebug(Log::sceNet, retid);
|
||||
}
|
||||
|
||||
@@ -551,16 +575,12 @@ static int sceHttpCreateRequest(int connectionID, int method, const char *path,
|
||||
static int sceHttpCreateConnection(int templateID, const char *hostString, const char *scheme, u32 port, int enableKeepalive) {
|
||||
WARN_LOG(Log::sceNet, "UNTESTED sceHttpCreateConnection(%d, %s, %s, %d, %d)", templateID, safe_string(hostString), safe_string(scheme), port, enableKeepalive);
|
||||
std::lock_guard<std::mutex> guard(httpLock);
|
||||
if (templateID <= 0 || templateID > (int)httpObjects.size())
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
if (httpObjects[templateID - 1LL]->className() != name_HTTPTemplate)
|
||||
if (!IsHttpId(templateID, HTTP_ID_TEMPLATE))
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
// TODO: Look up hostString in DNS here.
|
||||
|
||||
httpObjects.emplace_back(std::make_shared<HTTPConnection>(templateID, hostString ? hostString : "", scheme ? scheme : "", port, enableKeepalive));
|
||||
int retid = (int)httpObjects.size();
|
||||
int retid = AddHttpObject(HTTP_ID_CONNECTION, std::make_shared<HTTPConnection>(templateID, hostString ? hostString : "", scheme ? scheme : "", port, enableKeepalive));
|
||||
return hleLogDebug(Log::sceNet, retid);
|
||||
}
|
||||
|
||||
@@ -577,32 +597,31 @@ static int sceHttpGetNetworkErrno(int request, u32 errNumPtr) {
|
||||
// id: ID of the template, connection or request
|
||||
static int sceHttpAddExtraHeader(int id, const char *name, const char *value, int unknown) {
|
||||
WARN_LOG(Log::sceNet, "UNTESTED sceHttpAddExtraHeader(%d, %s, %s, %d)", id, safe_string(name), safe_string(value), unknown);
|
||||
if (id <= 0 || id > (int)httpObjects.size())
|
||||
HTTPTemplate *obj = GetHttpObject(id);
|
||||
if (!obj)
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
if (!name || !value)
|
||||
return hleLogError(Log::sceNet, -1, "invalid header"); // SCE_HTTP_ERROR_INVALID_VALUE
|
||||
|
||||
const auto& req = (HTTPRequest*)httpObjects[id - 1LL].get();
|
||||
return req->addRequestHeader(name, value, unknown);
|
||||
return obj->addRequestHeader(name, value, unknown);
|
||||
}
|
||||
|
||||
static int sceHttpAbortRequest(int requestID) {
|
||||
WARN_LOG(Log::sceNet, "UNTESTED sceHttpAbortRequest(%d)", requestID);
|
||||
if (requestID <= 0 || requestID > (int)httpObjects.size())
|
||||
HTTPRequest *req = GetHttpRequest(requestID);
|
||||
if (!req)
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
const auto& req = (HTTPRequest*)httpObjects[requestID - 1LL].get();
|
||||
return req->abortRequest();
|
||||
}
|
||||
|
||||
static int sceHttpDeleteTemplate(int templateID) {
|
||||
WARN_LOG(Log::sceNet, "UNTESTED sceHttpDeleteTemplate(%d)", templateID);
|
||||
std::lock_guard<std::mutex> guard(httpLock);
|
||||
if (templateID <= 0 || templateID > (int)httpObjects.size())
|
||||
// Its connections stay usable.
|
||||
if (!IsHttpId(templateID, HTTP_ID_TEMPLATE))
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
if (httpObjects[templateID - 1LL]->className() != name_HTTPTemplate)
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
httpObjects.erase(httpObjects.begin() + templateID - 1);
|
||||
RemoveHttpObject(templateID);
|
||||
return hleLogDebug(Log::sceNet, 0);
|
||||
}
|
||||
|
||||
@@ -611,17 +630,13 @@ static int sceHttpSetMallocFunction(u32 mallocFuncPtr, u32 freeFuncPtr, u32 real
|
||||
return 0;
|
||||
}
|
||||
|
||||
// id: ID of the template or connection
|
||||
// id: ID of a template
|
||||
static int sceHttpSetResolveTimeOut(int id, u32 timeout) {
|
||||
ERROR_LOG(Log::sceNet, "UNIMPL sceHttpSetResolveTimeOut(%d, %d)", id, timeout);
|
||||
if (id <= 0 || id > (int)httpObjects.size())
|
||||
if (!IsHttpId(id, HTTP_ID_TEMPLATE))
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
const auto& conn = httpObjects[id - 1LL];
|
||||
if (!(conn->className() == name_HTTPTemplate || conn->className() == name_HTTPConnection))
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id (%s)", conn->className());
|
||||
|
||||
conn->setResolveTimeout(timeout);
|
||||
GetHttpObject(id)->setResolveTimeout(timeout);
|
||||
return hleLogDebug(Log::sceNet, 0);
|
||||
}
|
||||
|
||||
@@ -680,8 +695,7 @@ static int sceHttpCreateTemplate(MIPSState *mips, const char *userAgent, int htt
|
||||
// Reporting to find more games to be tested
|
||||
WARN_LOG_REPORT_ONCE(sceHttpCreateTemplate, Log::sceNet, "UNTESTED sceHttpCreateTemplate(%s, %d, %d)", safe_string(userAgent), httpVer, autoProxyConf);
|
||||
std::lock_guard<std::mutex> guard(httpLock);
|
||||
httpObjects.push_back(std::make_shared<HTTPTemplate>(userAgent? userAgent:"", httpVer, autoProxyConf));
|
||||
int retid = (int)httpObjects.size();
|
||||
int retid = AddHttpObject(HTTP_ID_TEMPLATE, std::make_shared<HTTPTemplate>(userAgent? userAgent:"", httpVer, autoProxyConf));
|
||||
return hleLogDebug(Log::sceNet, retid);
|
||||
}
|
||||
|
||||
@@ -689,53 +703,39 @@ static int sceHttpCreateTemplate(MIPSState *mips, const char *userAgent, int htt
|
||||
static int sceHttpCreateRequestWithURL(int connectionID, int method, const char *url, u64 contentLength) {
|
||||
WARN_LOG(Log::sceNet, "UNTESTED sceHttpCreateRequestWithURL(%d, %d, %s, %llx)", connectionID, method, safe_string(url), contentLength);
|
||||
std::lock_guard<std::mutex> guard(httpLock);
|
||||
if (connectionID <= 0 || connectionID > (int)httpObjects.size())
|
||||
// Any method is accepted here.
|
||||
if (!IsHttpId(connectionID, HTTP_ID_CONNECTION))
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
if (httpObjects[connectionID - 1LL]->className() != name_HTTPConnection)
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
if (method < PSPHttpMethod::PSP_HTTP_METHOD_GET || method > PSPHttpMethod::PSP_HTTP_METHOD_HEAD)
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_UNKNOWN_METHOD, "unknown method");
|
||||
|
||||
Url baseURL(url ? url : "");
|
||||
if (!baseURL.Valid())
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_URL, "invalid url");
|
||||
|
||||
httpObjects.emplace_back(std::make_shared<HTTPRequest>(connectionID, method, url ? url : "", contentLength, &ProcessHostnameWithInfraDNS));
|
||||
int retid = (int)httpObjects.size();
|
||||
int retid = AddHttpObject(HTTP_ID_REQUEST, std::make_shared<HTTPRequest>(connectionID, method, url ? url : "", contentLength, &ProcessHostnameWithInfraDNS));
|
||||
return hleLogDebug(Log::sceNet, retid);
|
||||
}
|
||||
|
||||
static int sceHttpCreateConnectionWithURL(int templateID, const char *url, int enableKeepalive) {
|
||||
WARN_LOG(Log::sceNet, "UNTESTED sceHttpCreateConnectionWithURL(%d, %s, %d)", templateID, safe_string(url), enableKeepalive);
|
||||
std::lock_guard<std::mutex> guard(httpLock);
|
||||
if (templateID <= 0 || templateID > (int)httpObjects.size())
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
if (httpObjects[templateID - 1LL]->className() != name_HTTPTemplate)
|
||||
if (!IsHttpId(templateID, HTTP_ID_TEMPLATE))
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
Url baseURL(url ? url: "");
|
||||
if (!baseURL.Valid())
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_URL, "invalid url");
|
||||
|
||||
httpObjects.emplace_back(std::make_shared<HTTPConnection>(templateID, baseURL.Host().c_str(), baseURL.Protocol().c_str(), baseURL.Port(), enableKeepalive));
|
||||
int retid = (int)httpObjects.size();
|
||||
int retid = AddHttpObject(HTTP_ID_CONNECTION, std::make_shared<HTTPConnection>(templateID, baseURL.Host().c_str(), baseURL.Protocol().c_str(), baseURL.Port(), enableKeepalive));
|
||||
return hleLogDebug(Log::sceNet, retid);
|
||||
}
|
||||
|
||||
// id: ID of the template or connection
|
||||
static int sceHttpSetRecvTimeOut(int id, u32 timeout) {
|
||||
WARN_LOG(Log::sceNet, "UNTESTED sceHttpSetRecvTimeOut(%d, %d)", id, timeout);
|
||||
if (id <= 0 || id > (int)httpObjects.size())
|
||||
if (!IsHttpId(id, HTTP_ID_TEMPLATE) && !IsHttpId(id, HTTP_ID_CONNECTION))
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
const auto& conn = httpObjects[id - 1LL];
|
||||
if (!(conn->className() == name_HTTPTemplate || conn->className() == name_HTTPConnection))
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id (%s)", conn->className());
|
||||
|
||||
conn->setRecvTimeout(timeout);
|
||||
GetHttpObject(id)->setRecvTimeout(timeout);
|
||||
return hleLogDebug(Log::sceNet, 0);
|
||||
}
|
||||
|
||||
@@ -743,7 +743,8 @@ static int sceHttpSetRecvTimeOut(int id, u32 timeout) {
|
||||
// Note: Megaman PoweredUp seems to have an invalid address stored at the headerAddrPtr location, may be the game expecting us (network library) to give them a valid header address?
|
||||
static int sceHttpGetAllHeader(int requestID, u32 headerAddrPtr, u32 headerSizePtr) {
|
||||
WARN_LOG(Log::sceNet, "UNTESTED sceHttpGetAllHeader(%d, %x, %x)", requestID, headerAddrPtr, headerSizePtr);
|
||||
if (requestID <= 0 || requestID > (int)httpObjects.size())
|
||||
HTTPRequest *req = GetHttpRequest(requestID);
|
||||
if (!req)
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
if (!Memory::IsValidRange(headerAddrPtr, 4))
|
||||
@@ -752,7 +753,8 @@ static int sceHttpGetAllHeader(int requestID, u32 headerAddrPtr, u32 headerSizeP
|
||||
if (!Memory::IsValidRange(headerSizePtr, 4))
|
||||
return hleLogError(Log::sceNet, -1, "invalid arg"); //SCE_HTTP_ERROR_INVALID_VALUE;
|
||||
|
||||
const auto& req = (HTTPRequest*)httpObjects[requestID - 1LL].get();
|
||||
if (!req->wasSent())
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_BEFORE_SEND, "not sent");
|
||||
// FIXME: According to JPCSP, try to connect the request first
|
||||
//req->connect();
|
||||
int retval = req->getAllResponseHeaders(headerAddrPtr, headerSizePtr);
|
||||
@@ -762,13 +764,15 @@ static int sceHttpGetAllHeader(int requestID, u32 headerAddrPtr, u32 headerSizeP
|
||||
// FIXME: contentLength is SceULong64 but this contentLengthPtr argument should be a 32bit pointer instead of 64bit, right?
|
||||
static int sceHttpGetContentLength(int requestID, u32 contentLengthPtr) {
|
||||
WARN_LOG(Log::sceNet, "UNTESTED sceHttpGetContentLength(%d, %x)", requestID, contentLengthPtr);
|
||||
if (requestID <= 0 || requestID > (int)httpObjects.size())
|
||||
HTTPRequest *req = GetHttpRequest(requestID);
|
||||
if (!req)
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_INVALID_ID, "invalid id");
|
||||
|
||||
if (!Memory::IsValidRange(contentLengthPtr, 8))
|
||||
return hleLogError(Log::sceNet, -1, "invalid arg"); //SCE_HTTP_ERROR_INVALID_VALUE;
|
||||
|
||||
const auto& req = (HTTPRequest*)httpObjects[requestID - 1LL].get();
|
||||
if (!req->wasSent())
|
||||
return hleLogError(Log::sceNet, SCE_HTTP_ERROR_BEFORE_SEND, "not sent");
|
||||
// FIXME: According to JPCSP, try to connect the request first
|
||||
//req->connect();
|
||||
int len = req->getResponseContentLength();
|
||||
|
||||
@@ -52,6 +52,8 @@ enum SceHttpErrorCode {
|
||||
SCE_HTTP_ERROR_BAD_RESPONSE = 0x80431064,
|
||||
SCE_HTTP_ERROR_BEFORE_SEND = 0x80431065,
|
||||
SCE_HTTP_ERROR_AFTER_SEND = 0x80431066,
|
||||
// sceHttpDeleteConnection, while the connection has requests (tests/net/http/ids).
|
||||
SCE_HTTP_ERROR_CONNECTION_HAS_REQUESTS = 0x80431067,
|
||||
SCE_HTTP_ERROR_TIMEOUT = 0x80431068,
|
||||
SCE_HTTP_ERROR_UNKOWN_AUTH_TYPE = 0x80431069,
|
||||
SCE_HTTP_ERROR_INVALID_VERSION = 0x8043106A,
|
||||
@@ -258,6 +260,7 @@ private:
|
||||
u32 headerAddr_ = 0;
|
||||
u32 headerSize_ = 0;
|
||||
bool cancelled_ = false;
|
||||
bool sent_ = false;
|
||||
int responseCode_ = -1;
|
||||
int entityLength_ = -1;
|
||||
|
||||
@@ -275,6 +278,8 @@ public:
|
||||
|
||||
void setInternalHeaderAddr(u32 addr) { headerAddr_ = addr; }
|
||||
int getConnectionID() { return connectionID; }
|
||||
// Until a send succeeds, the calls that read the response fail with SCE_HTTP_ERROR_BEFORE_SEND.
|
||||
bool wasSent() const { return sent_; }
|
||||
int getResponseRemainingContentLength() { return (int)responseContent_.size(); }
|
||||
|
||||
int getResponseContentLength();
|
||||
|
||||
+111
-37
@@ -431,14 +431,13 @@ int sceNpAuthGetTicket(u32 requestId, u32 bufferAddr, u32 length) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_AUTH_ERROR_UNKNOWN, "Missing npOnlineId");
|
||||
}
|
||||
|
||||
int result = length;
|
||||
// Built here, then copied once we know it fits.
|
||||
u8 staging[512]{};
|
||||
// Built here and copied out, since the buffer can be shorter than the ticket.
|
||||
u8 ticketBuf[0xF0 + sizeof(SceNpTicketHeader)]{};
|
||||
SceNpTicket ticket = {};
|
||||
// Dummy Login ticket returned as Login response. Dummy ticket contents were taken from https://www.psdevwiki.com/ps3/X-I-5-Ticket
|
||||
ticket.header.version = TICKET_VER_2_1;
|
||||
ticket.header.size = 0xF0; // size excluding the header
|
||||
u8 *buf = staging + sizeof(ticket);
|
||||
u8 *buf = ticketBuf + sizeof(ticket);
|
||||
int ofs = 0;
|
||||
ofs += writeTicketParam(buf, PARAM_TYPE_STRING_ASCII, "\x4c\x47\x56\x3b\x81\x39\x4a\x22\xd8\x6b\xc1\x57\x71\x6e\xfd\xb8\xab\x63\xcc\x51", 20); // 20 random letters, token key or SceNpSignature?
|
||||
ofs += writeTicketU32Param(buf + ofs, PARAM_TYPE_INT, 0x0100); // a flags?
|
||||
@@ -464,24 +463,23 @@ int sceNpAuthGetTicket(u32 requestId, u32 bufferAddr, u32 length) {
|
||||
ofs += writeTicketParam(buf + ofs, PARAM_TYPE_NULL);
|
||||
ticket.section.type = SECTION_TYPE_BODY;
|
||||
ticket.section.size = ofs;
|
||||
memcpy(staging, &ticket, sizeof(SceNpTicket));
|
||||
memcpy(ticketBuf, &ticket, sizeof(SceNpTicket));
|
||||
SceNpTicketSection footer = { SECTION_TYPE_FOOTER, 32 }; // footer section? ie. 32-bytes on version 2.1 containing 4-chars ASCII + 20-chars ASCII
|
||||
memcpy(buf + ofs, &footer, sizeof(SceNpTicketSection));
|
||||
ofs += sizeof(footer);
|
||||
ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, "\x34\xcd\x3c\xa9", 4);
|
||||
ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, "\x3a\x4b\x42\x66\x92\xda\x6b\x7c\xb7\x4c\xe8\xd9\x4f\x2b\x77\x15\x91\xb8\xa4\xa9", 20); // 20 random letters, token key or SceNpSignature?
|
||||
// includes Language list? (36 zero bytes, staging is zeroed)
|
||||
const u32 total = (u32)sizeof(ticket) + ofs + 36;
|
||||
_dbg_assert_(total <= sizeof(staging));
|
||||
// includes Language list? (36 zero bytes, left by the initializer)
|
||||
_dbg_assert_(sizeof(ticket) + ofs + 36 == sizeof(ticketBuf));
|
||||
|
||||
// The whole ticket gets written, even if length is shorter.
|
||||
if (!Memory::IsValidRange(bufferAddr, std::max(length, total))) {
|
||||
// Like JPCSP's real ticket path, copy what fits.
|
||||
if (!Memory::IsValidRange(bufferAddr, length)) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid buffer");
|
||||
}
|
||||
Memory::Memset(bufferAddr, 0, length, "NpAuthGetTicket");
|
||||
Memory::Memcpy(bufferAddr, staging, total, "NpAuthGetTicket");
|
||||
Memory::Memcpy(bufferAddr, ticketBuf, std::min(length, (u32)sizeof(ticketBuf)), "NpAuthGetTicket");
|
||||
|
||||
result = ticket.header.size + sizeof(ticket.header); // dummy ticket is 248 bytes
|
||||
const int result = (int)sizeof(ticketBuf); // dummy ticket is 248 bytes
|
||||
|
||||
return hleLogWarning(Log::sceNet, result);
|
||||
}
|
||||
@@ -524,43 +522,119 @@ int sceNpAuthDestroyRequest(int requestId)
|
||||
return hleNoLog(0);
|
||||
}
|
||||
|
||||
// Tickets are big-endian, and params needn't be aligned.
|
||||
static u16 ReadTicketU16(u32 addr) {
|
||||
return ((u16)Memory::ReadUnchecked_U8(addr) << 8) | Memory::ReadUnchecked_U8(addr + 1);
|
||||
}
|
||||
|
||||
static u32 ReadTicketU32(u32 addr) {
|
||||
return ((u32)ReadTicketU16(addr) << 16) | ReadTicketU16(addr + 2);
|
||||
}
|
||||
|
||||
// Writes one param's value into the 256-byte output, as GetTicketParam does for every param it
|
||||
// walks past. A NULL param leaves the output alone, any other clears it first, and a type with no
|
||||
// value (unknown ones) leaves it clear. Numbers are read at their full size whatever length the
|
||||
// param gives.
|
||||
static void WriteTicketParamValue(u32 bufferPtr, u16 type, u32 valuePtr, u32 length) {
|
||||
const u32 PARAM_BUFFER_MAX_SIZE = 256;
|
||||
if (type == PARAM_TYPE_NULL) {
|
||||
return;
|
||||
}
|
||||
Memory::Memset(bufferPtr, 0, PARAM_BUFFER_MAX_SIZE, "NpAuthGetTicketParam");
|
||||
|
||||
u32 readSize = 0;
|
||||
switch (type) {
|
||||
case PARAM_TYPE_INT: readSize = 4; break;
|
||||
case PARAM_TYPE_LONG: case PARAM_TYPE_DATE: readSize = 8; break;
|
||||
case PARAM_TYPE_STRING: case PARAM_TYPE_STRING_ASCII: readSize = std::min(length, PARAM_BUFFER_MAX_SIZE - 1); break;
|
||||
case 0x3011: readSize = 4; break;
|
||||
default: return;
|
||||
}
|
||||
if (!Memory::IsValidRange(valuePtr, readSize)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case PARAM_TYPE_INT:
|
||||
Memory::WriteUnchecked_U32(ReadTicketU32(valuePtr), bufferPtr);
|
||||
break;
|
||||
case PARAM_TYPE_LONG:
|
||||
case PARAM_TYPE_DATE:
|
||||
Memory::WriteUnchecked_U64(((u64)ReadTicketU32(valuePtr) << 32) | ReadTicketU32(valuePtr + 4), bufferPtr);
|
||||
break;
|
||||
case 0x3011:
|
||||
// A big-endian u16 followed by two bytes as they are.
|
||||
Memory::WriteUnchecked_U16(ReadTicketU16(valuePtr), bufferPtr);
|
||||
Memory::Memcpy(bufferPtr + 2, valuePtr + 2, 2, "NpAuthGetTicketParam");
|
||||
break;
|
||||
default:
|
||||
// The terminator is left by the clear.
|
||||
Memory::Memcpy(bufferPtr, valuePtr, readSize, "NpAuthGetTicketParam");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Behaviour from tests/net/npauth/ticketparam.
|
||||
int sceNpAuthGetTicketParam(u32 ticketBufPtr, int ticketLen, int paramNum, u32 bufferPtr)
|
||||
{
|
||||
const u32 PARAM_BUFFER_MAX_SIZE = 256;
|
||||
// The type each param has to have. Param 11 is never found.
|
||||
static const u16 paramTypes[NUMBER_PARAMETERS - 1] = {
|
||||
PARAM_TYPE_STRING_ASCII, PARAM_TYPE_INT, PARAM_TYPE_DATE, PARAM_TYPE_DATE, PARAM_TYPE_LONG, PARAM_TYPE_STRING,
|
||||
PARAM_TYPE_STRING_ASCII, PARAM_TYPE_STRING, PARAM_TYPE_STRING_ASCII, PARAM_TYPE_INT, PARAM_TYPE_DATE,
|
||||
};
|
||||
|
||||
if (!Memory::IsValidRange(bufferPtr, PARAM_BUFFER_MAX_SIZE)) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_MANAGER_ERROR_INVALID_ARGUMENT, "invalid buffer");
|
||||
}
|
||||
Memory::Memset(bufferPtr, 0, PARAM_BUFFER_MAX_SIZE); // JPCSP: This clear is always done, even when an error is returned
|
||||
if (paramNum < 0 || paramNum >= NUMBER_PARAMETERS) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_MANAGER_ERROR_INVALID_ARGUMENT);
|
||||
// Cleared even when an error is returned.
|
||||
Memory::Memset(bufferPtr, 0, PARAM_BUFFER_MAX_SIZE, "NpAuthGetTicketParam");
|
||||
if (ticketLen < 4 || ticketLen > 0x10000) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_MANAGER_ERROR_INVALID_TICKET_SIZE, "invalid ticket size");
|
||||
}
|
||||
if (ticketLen < (int)sizeof(SceNpTicket) || !Memory::IsValidRange(ticketBufPtr, ticketLen)) {
|
||||
if (paramNum < 0 || paramNum >= NUMBER_PARAMETERS) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_MANAGER_ERROR_INVALID_ARGUMENT, "invalid param");
|
||||
}
|
||||
if (!Memory::IsValidRange(ticketBufPtr, ticketLen)) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_MANAGER_ERROR_INVALID_ARGUMENT, "invalid ticket");
|
||||
}
|
||||
|
||||
const SceNpTicket *ticket = (const SceNpTicket *)Memory::GetPointerUnchecked(ticketBufPtr);
|
||||
const u32 ticketEnd = ticketBufPtr + ticketLen;
|
||||
u32 inbuf = ticketBufPtr;
|
||||
inbuf += sizeof(ticket->header);
|
||||
inbuf += ticket->section.size + sizeof(ticket->section);
|
||||
u32 outbuf = bufferPtr;
|
||||
for (int i = 0; i < paramNum; i++) {
|
||||
// Only copy params that are inside the ticket and fit in the output.
|
||||
if (inbuf < ticketBufPtr || inbuf + sizeof(SceNpTicketParamData) > ticketEnd)
|
||||
break;
|
||||
const SceNpTicketParamData *ticketParam = (const SceNpTicketParamData *)Memory::GetPointerUnchecked(inbuf);
|
||||
u32 sz = (u32)sizeof(SceNpTicketParamData) + ticketParam->length;
|
||||
if (sz > ticketEnd - inbuf || sz > PARAM_BUFFER_MAX_SIZE - (outbuf - bufferPtr))
|
||||
break;
|
||||
Memory::MemcpyUnchecked(outbuf, inbuf, sz);
|
||||
DEBUG_LOG(Log::sceNet, "%s - Param #%d: Type = %04x, Length = %u", __FUNCTION__, i, static_cast<unsigned int>(ticketParam->type), static_cast<unsigned int>(ticketParam->length));
|
||||
outbuf += sz;
|
||||
inbuf += sz;
|
||||
if (outbuf - bufferPtr >= PARAM_BUFFER_MAX_SIZE || inbuf - ticketBufPtr >= (u32)ticketLen)
|
||||
break;
|
||||
// Major version in the top nibble, minor in the next byte: 2.1 and 3.0 are accepted.
|
||||
const u32 version = ReadTicketU32(ticketBufPtr);
|
||||
const u32 major = version >> 28;
|
||||
const u32 minor = (version >> 16) & 0xFF;
|
||||
if (!(major == 2 && minor == 1) && !(major == 3 && minor == 0)) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_AUTH_ERROR_INVALID_TICKET_VERSION, "unsupported ticket version %08x", version);
|
||||
}
|
||||
if (paramNum == NUMBER_PARAMETERS - 1) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_AUTH_ERROR_TICKET_PARAM_NOT_FOUND);
|
||||
}
|
||||
// The header's size and the section's size aren't used.
|
||||
if (ticketLen < (int)sizeof(SceNpTicket) || ReadTicketU16(ticketBufPtr + 8) != SECTION_TYPE_BODY) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_UTIL_ERROR_PARSER_FAILED, "no body section");
|
||||
}
|
||||
|
||||
return hleLogWarning(Log::sceNet, 0);
|
||||
// Every param up to the one asked for is written out in turn, so a failure leaves the last
|
||||
// one written in the buffer.
|
||||
const u32 ticketEnd = ticketBufPtr + (u32)ticketLen;
|
||||
u32 inbuf = ticketBufPtr + (u32)sizeof(SceNpTicket);
|
||||
for (int i = 0; i <= paramNum; i++) {
|
||||
if (inbuf + sizeof(SceNpTicketParamData) > ticketEnd) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_UTIL_ERROR_PARSER_FAILED, "ticket ends before param %d", i);
|
||||
}
|
||||
const u16 type = ReadTicketU16(inbuf);
|
||||
const u32 length = ReadTicketU16(inbuf + 2);
|
||||
const u32 valuePtr = inbuf + (u32)sizeof(SceNpTicketParamData);
|
||||
if (valuePtr + length > ticketEnd) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_UTIL_ERROR_PARSER_FAILED, "param %d runs past the ticket", i);
|
||||
}
|
||||
WriteTicketParamValue(bufferPtr, type, valuePtr, length);
|
||||
if (type != paramTypes[i]) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_UTIL_ERROR_PARSER_FAILED, "param %d has type %04x", i, type);
|
||||
}
|
||||
inbuf = valuePtr + length;
|
||||
}
|
||||
return hleLogDebug(Log::sceNet, 0);
|
||||
}
|
||||
|
||||
const HLEFunction sceNpAuth[] = {
|
||||
|
||||
+1
-1
Submodule pspautotests updated: 1a9e6c31cf...70e72391e9.
Reference in new issue
Block a user