#include "ppsspp_config.h" #include #include #include "Common/Net/SocketCompat.h" #if _MSC_VER #pragma warning(disable:4267) #endif #include "Common/File/FileDescriptor.h" #include "Common/Log.h" #include "Common/Net/NetBuffer.h" #include "Common/TimeUtil.h" namespace net { 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); } } bool Buffer::FlushSocket(uintptr_t sock, double timeout, const CancelToken *cancel) { data_.iterate_blocks([&](const char *data, size_t size) { for (size_t pos = 0, end = size; pos < end; ) { // The timeout applies to each send, not the whole flush. const WaitResult wait = WaitSocket(sock, true, timeout, cancel); if (wait == WaitResult::TIMEOUT) { ERROR_LOG(Log::IO, "FlushSocket timed out"); return false; } else if (wait != WaitResult::READY) { return false; } int sent = send(sock, &data[pos], end - pos, MSG_NOSIGNAL); // TODO: Do we need some retry logic here, instead of just giving up? if (sent < 0) { ERROR_LOG(Log::IO, "FlushSocket failed to send: errno=%d", errno); return false; } pos += sent; } return true; }); data_.clear(); return true; } bool Buffer::ReadAllWithProgress(int fd, int knownSize, RequestProgress *progress) { std::vector buf; // We're non-blocking and reading from an OS buffer, so try to read as much as we can at a time. if (knownSize >= 65536 * 16) { buf.resize(65536); } else if (knownSize >= 1024 * 16) { buf.resize(knownSize / 16); } else { buf.resize(1024); } double st = time_now_d(); int total = 0; while (true) { // Block until there's data, the end of the stream, or a cancel. const WaitResult wait = WaitSocket(fd, false, -1.0, progress ? progress->cancel : nullptr); if (wait != WaitResult::READY) return false; int retval = recv(fd, &buf[0], buf.size(), MSG_NOSIGNAL); if (retval == 0) { return true; } else if (retval < 0) { if (socket_errno != EWOULDBLOCK) { ERROR_LOG(Log::IO, "Error reading from buffer: %i", retval); return false; } // Just try again on a would block error, not a real error. continue; } char *p = Append((size_t)retval); memcpy(p, &buf[0], retval); total += retval; if (progress) { progress->Update(total, knownSize, false); progress->kBps = (float)(total / (time_now_d() - st)) / 1024.0f; } } return true; } int Buffer::Read(int fd, size_t sz) { char buf[4096]; int retval; size_t received = 0; while ((retval = recv(fd, buf, std::min(sz, sizeof(buf)), MSG_NOSIGNAL)) > 0) { 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; } } // namespace