mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-16 07:50:28 +02:00
Socket waits now block in select() on the socket plus a wake or cancel socket (Common/Net/Cancel), so a stop or cancel ends them at once. - HTTP: cancel flags become net::CancelToken; Connect waits once on all addresses, receives wait instead of spinning, no DNS retry sleep. - Adhoc: the friend finder and adhoc server block on their sockets with a wake socket and a deadline; matching runs on a CoreTiming tick instead of two threads (savestate section bumped). - sceNetInet select/poll check without blocking and park the HLE thread, re-checked from a CoreTiming event until ready or the emulated timeout. - Vendor the aemu_postoffice client (was a submodule) with no sleeps: waits on the socket, close via shutdown and an eventcount, cancelable connects, and lock-free session slot claims. - PortManager waits without a timeout; PSP_InitWait replaces the headless boot poll. - TimeUtil: sleep_us/sleep_ms only outside the core; sleep_precise, sleep_random, yield and the Windows timer period are gone. - Unit test for the socket waits.
154 lines
5.0 KiB
C++
154 lines
5.0 KiB
C++
#pragma once
|
|
|
|
#include <atomic>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <thread>
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include "Common/File/Path.h"
|
|
#include "Common/Net/NetBuffer.h"
|
|
#include "Common/Net/Resolve.h"
|
|
#include "Common/Net/HTTPRequest.h"
|
|
|
|
namespace net {
|
|
|
|
typedef std::function<std::string(const std::string &)> ResolveFunc;
|
|
|
|
class Connection {
|
|
public:
|
|
virtual ~Connection();
|
|
|
|
explicit Connection(ResolveFunc func) : customResolve_(std::move(func)) {}
|
|
|
|
// Inits the addrinfo chain.
|
|
bool Resolve(const char *host, int port, DNSType type = DNSType::ANY);
|
|
|
|
bool Connect(int maxTries = 2, double timeout = 20.0f, const net::CancelToken *cancel = nullptr);
|
|
void Disconnect();
|
|
|
|
// TODO: Try to expose this less.
|
|
uintptr_t sock() const { return sock_; }
|
|
|
|
std::string GetLocalIpAsString() const;
|
|
|
|
protected:
|
|
// Store the remote host here, so we can send it along through HTTP/1.1 requests.
|
|
// TODO: Move to http::client?
|
|
std::string host_;
|
|
int port_ = -1;
|
|
|
|
addrinfo *resolved_ = nullptr;
|
|
|
|
private:
|
|
uintptr_t sock_ = -1;
|
|
ResolveFunc customResolve_;
|
|
};
|
|
|
|
} // namespace net
|
|
|
|
namespace http {
|
|
|
|
// Ignores line folding (deprecated), but respects field combining.
|
|
// Don't use for Set-Cookie, which is a special header per RFC 7230.
|
|
bool GetHeaderValue(const std::vector<std::string> &responseHeaders, std::string_view header, std::string *value);
|
|
|
|
class RequestParams {
|
|
public:
|
|
RequestParams() = default;
|
|
explicit RequestParams(const char *r) : resource(r) {}
|
|
RequestParams(std::string r, const char *a) : resource(std::move(r)), acceptMime(a) {}
|
|
|
|
std::string resource;
|
|
const char *acceptMime = "*/*";
|
|
};
|
|
|
|
class Client : public net::Connection {
|
|
public:
|
|
Client(net::ResolveFunc func);
|
|
~Client();
|
|
|
|
// Return value is the HTTP return code. 200 means OK. < 0 means some local error.
|
|
int GET(const RequestParams &req, Buffer *output, net::RequestProgress *progress);
|
|
int GET(const RequestParams &req, Buffer *output, std::vector<std::string> &responseHeaders, net::RequestProgress *progress);
|
|
|
|
// Return value is the HTTP return code.
|
|
int POST(const RequestParams &req, std::string_view data, std::string_view mime, Buffer *output, net::RequestProgress *progress);
|
|
int POST(const RequestParams &req, std::string_view data, Buffer *output, net::RequestProgress *progress);
|
|
|
|
// HEAD, PUT, DELETE aren't implemented yet, but can be done with SendRequest.
|
|
|
|
int SendRequest(const char *method, const RequestParams &req, const char *otherHeaders, net::RequestProgress *progress);
|
|
int SendRequestWithData(const char *method, const RequestParams &req, std::string_view data, const char *otherHeaders, net::RequestProgress *progress);
|
|
int ReadResponseHeaders(net::Buffer *readbuf, std::vector<std::string> &responseHeaders, net::RequestProgress *progress, std::string *statusLine = nullptr);
|
|
// If your response contains a response, you must read it.
|
|
int ReadResponseEntity(net::Buffer *readbuf, const std::vector<std::string> &responseHeaders, Buffer *output, net::RequestProgress *progress);
|
|
|
|
void SetDataTimeout(double t) {
|
|
headerTimeout_ = t;
|
|
}
|
|
|
|
void SetUserAgent(std::string_view value) {
|
|
userAgent_ = value;
|
|
}
|
|
|
|
void SetHttpVersion(const char *version) {
|
|
httpVersion_ = version;
|
|
}
|
|
|
|
protected:
|
|
std::string userAgent_;
|
|
const char* httpVersion_;
|
|
double headerTimeout_ = 900.0;
|
|
};
|
|
|
|
// Really an asynchronous request.
|
|
class HTTPRequest : public Request {
|
|
public:
|
|
HTTPRequest(RequestMethod method, std::string_view url, std::string_view postData, std::string_view postMime, const Path &outfile, RequestFlags flags, net::ResolveFunc customResolve, std::string_view name = "");
|
|
~HTTPRequest();
|
|
|
|
void Start() override;
|
|
void Join() override;
|
|
|
|
bool Done() override { return completed_; }
|
|
bool Failed() const override { return failed_; }
|
|
|
|
private:
|
|
void Do(); // Actually does the download. Runs on thread.
|
|
int Perform(const std::string &url);
|
|
std::string RedirectLocation(const std::string &baseUrl) const;
|
|
void SetFailed(int code);
|
|
|
|
std::string postData_;
|
|
std::thread thread_;
|
|
std::string postMime_;
|
|
// Set last on the download thread, after the result code and buffer. Atomic, so that once
|
|
// Done() sees it, those are visible too.
|
|
std::atomic<bool> completed_{false};
|
|
bool failed_ = false;
|
|
net::ResolveFunc customResolve_;
|
|
};
|
|
|
|
// Fake request for cache hits.
|
|
// The download manager uses this when caching was requested, and a new-enough file was present in the cache directory.
|
|
// This is simply a finished request, that can still be queried like a normal one so users don't know it came from the cache.
|
|
class CachedRequest : public Request {
|
|
public:
|
|
CachedRequest(RequestMethod method, std::string_view url, std::string_view name, RequestFlags flags, std::string_view responseData)
|
|
: Request(method, url, name, Path(), flags)
|
|
{
|
|
buffer_.Append(responseData);
|
|
}
|
|
void Start() override {}
|
|
void Join() override {}
|
|
bool Done() override { return true; }
|
|
bool Failed() const override { return false; }
|
|
};
|
|
|
|
std::string RemoveHttpsIfNeeded(std::string_view url);
|
|
|
|
} // namespace http
|