2021-05-01 16:52:16 +00:00
|
|
|
#include "ppsspp_config.h"
|
|
|
|
#ifdef _WIN32
|
2021-05-01 15:36:25 +00:00
|
|
|
#include <winsock2.h>
|
|
|
|
#undef min
|
|
|
|
#undef max
|
|
|
|
#else
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cstring>
|
|
|
|
|
|
|
|
#ifndef MSG_NOSIGNAL
|
|
|
|
// Default value to 0x00 (do nothing) in systems where it's not supported.
|
|
|
|
#define MSG_NOSIGNAL 0x00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "Common/File/FileDescriptor.h"
|
|
|
|
#include "Common/Log.h"
|
|
|
|
#include "Common/Net/NetBuffer.h"
|
|
|
|
#include "Common/TimeUtil.h"
|
|
|
|
|
|
|
|
namespace net {
|
|
|
|
|
2023-07-21 15:50:49 +00:00
|
|
|
void RequestProgress::Update(int64_t downloaded, int64_t totalBytes, bool done) {
|
|
|
|
if (totalBytes) {
|
|
|
|
progress = (double)downloaded / (double)totalBytes;
|
|
|
|
} else {
|
|
|
|
progress = 0.01f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (callback) {
|
|
|
|
callback(downloaded, totalBytes, done);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-01 15:36:25 +00:00
|
|
|
bool Buffer::FlushSocket(uintptr_t sock, double timeout, bool *cancelled) {
|
|
|
|
static constexpr float CANCEL_INTERVAL = 0.25f;
|
|
|
|
for (size_t pos = 0, end = data_.size(); pos < end; ) {
|
|
|
|
bool ready = false;
|
2021-05-01 16:37:36 +00:00
|
|
|
double endTimeout = time_now_d() + timeout;
|
|
|
|
while (!ready) {
|
2021-05-01 15:36:25 +00:00
|
|
|
if (cancelled && *cancelled)
|
|
|
|
return false;
|
|
|
|
ready = fd_util::WaitUntilReady(sock, CANCEL_INTERVAL, true);
|
2021-05-01 16:37:36 +00:00
|
|
|
if (!ready && time_now_d() > endTimeout) {
|
2024-07-14 12:42:59 +00:00
|
|
|
ERROR_LOG(Log::IO, "FlushSocket timed out");
|
2021-05-01 16:37:36 +00:00
|
|
|
return false;
|
2021-05-01 15:36:25 +00:00
|
|
|
}
|
|
|
|
}
|
2024-05-12 00:43:13 +00:00
|
|
|
int sent = send(sock, &data_[pos], end - pos, MSG_NOSIGNAL);
|
2023-01-30 17:31:49 +00:00
|
|
|
// TODO: Do we need some retry logic here, instead of just giving up?
|
2021-05-01 15:36:25 +00:00
|
|
|
if (sent < 0) {
|
2024-07-14 12:42:59 +00:00
|
|
|
ERROR_LOG(Log::IO, "FlushSocket failed to send: %d", errno);
|
2021-05-01 15:36:25 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
pos += sent;
|
|
|
|
}
|
|
|
|
data_.resize(0);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-07-18 13:13:44 +00:00
|
|
|
bool Buffer::ReadAllWithProgress(int fd, int knownSize, RequestProgress *progress) {
|
2021-05-01 15:36:25 +00:00
|
|
|
static constexpr float CANCEL_INTERVAL = 0.25f;
|
|
|
|
std::vector<char> buf;
|
2021-05-01 17:19:27 +00:00
|
|
|
// We're non-blocking and reading from an OS buffer, so try to read as much as we can at a time.
|
2021-05-01 15:36:25 +00:00
|
|
|
if (knownSize >= 65536 * 16) {
|
|
|
|
buf.resize(65536);
|
|
|
|
} else if (knownSize >= 1024 * 16) {
|
|
|
|
buf.resize(knownSize / 16);
|
|
|
|
} else {
|
|
|
|
buf.resize(1024);
|
|
|
|
}
|
|
|
|
|
2021-05-01 17:40:34 +00:00
|
|
|
double st = time_now_d();
|
2021-05-01 15:36:25 +00:00
|
|
|
int total = 0;
|
|
|
|
while (true) {
|
|
|
|
bool ready = false;
|
2023-07-26 02:37:28 +00:00
|
|
|
|
|
|
|
// If we might need to cancel, check on a timer for it to be ready.
|
|
|
|
// After this, we'll block on reading so we do this while first if we have a cancel pointer.
|
|
|
|
while (!ready && progress && progress->cancelled) {
|
|
|
|
if (*progress->cancelled)
|
2021-05-01 15:36:25 +00:00
|
|
|
return false;
|
|
|
|
ready = fd_util::WaitUntilReady(fd, CANCEL_INTERVAL, false);
|
|
|
|
}
|
2023-07-26 02:37:28 +00:00
|
|
|
|
2024-05-12 00:43:13 +00:00
|
|
|
int retval = recv(fd, &buf[0], buf.size(), MSG_NOSIGNAL);
|
2021-05-01 15:36:25 +00:00
|
|
|
if (retval == 0) {
|
|
|
|
return true;
|
|
|
|
} else if (retval < 0) {
|
2021-05-01 16:52:16 +00:00
|
|
|
#if PPSSPP_PLATFORM(WINDOWS)
|
2021-09-26 06:26:38 +00:00
|
|
|
if (WSAGetLastError() != WSAEWOULDBLOCK) {
|
2021-05-01 16:52:16 +00:00
|
|
|
#else
|
2021-09-26 06:26:38 +00:00
|
|
|
if (errno != EWOULDBLOCK) {
|
2021-05-01 16:52:16 +00:00
|
|
|
#endif
|
2024-07-14 12:42:59 +00:00
|
|
|
ERROR_LOG(Log::IO, "Error reading from buffer: %i", retval);
|
2021-09-26 06:26:38 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Just try again on a would block error, not a real error.
|
|
|
|
continue;
|
2021-05-01 15:36:25 +00:00
|
|
|
}
|
|
|
|
char *p = Append((size_t)retval);
|
|
|
|
memcpy(p, &buf[0], retval);
|
|
|
|
total += retval;
|
2023-07-18 13:13:44 +00:00
|
|
|
if (progress) {
|
2023-07-18 13:52:14 +00:00
|
|
|
progress->Update(total, knownSize, false);
|
2023-07-18 13:13:44 +00:00
|
|
|
progress->kBps = (float)(total / (time_now_d() - st)) / 1024.0f;
|
|
|
|
}
|
2021-05-01 15:36:25 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Buffer::Read(int fd, size_t sz) {
|
|
|
|
char buf[1024];
|
|
|
|
int retval;
|
|
|
|
size_t received = 0;
|
2024-05-12 00:43:13 +00:00
|
|
|
while ((retval = recv(fd, buf, std::min(sz, sizeof(buf)), MSG_NOSIGNAL)) > 0) {
|
2021-05-01 15:36:25 +00:00
|
|
|
if (retval < 0) {
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
char *p = Append((size_t)retval);
|
|
|
|
memcpy(p, buf, retval);
|
|
|
|
sz -= retval;
|
|
|
|
received += retval;
|
|
|
|
if (sz == 0)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return (int)received;
|
|
|
|
}
|
|
|
|
|
2023-07-18 13:13:44 +00:00
|
|
|
} // namespace
|