2012-06-03 17:01:08 +00:00
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
#include <winsock2.h>
|
|
|
|
#undef min
|
|
|
|
#undef max
|
|
|
|
#else
|
|
|
|
#include <sys/socket.h>
|
2013-03-02 06:50:14 +00:00
|
|
|
#include <unistd.h>
|
2012-06-03 17:01:08 +00:00
|
|
|
#endif
|
|
|
|
|
2018-10-16 21:18:57 +00:00
|
|
|
#ifndef MSG_NOSIGNAL
|
|
|
|
// Default value to 0x00 (do nothing) in systems where it's not supported.
|
|
|
|
#define MSG_NOSIGNAL 0x00
|
|
|
|
#endif
|
|
|
|
|
2020-10-04 18:48:47 +00:00
|
|
|
#include "Common/File/FileDescriptor.h"
|
2020-09-29 11:02:02 +00:00
|
|
|
#include "Common/TimeUtil.h"
|
|
|
|
#include "Common/Buffer.h"
|
2020-08-15 13:51:41 +00:00
|
|
|
#include "Common/Log.h"
|
|
|
|
|
2012-06-03 17:01:08 +00:00
|
|
|
Buffer::Buffer() { }
|
|
|
|
Buffer::~Buffer() { }
|
|
|
|
|
2020-09-29 08:24:41 +00:00
|
|
|
char *Buffer::Append(size_t length) {
|
2020-02-06 23:09:42 +00:00
|
|
|
if (length > 0) {
|
|
|
|
size_t old_size = data_.size();
|
|
|
|
data_.resize(old_size + length);
|
|
|
|
return &data_[0] + old_size;
|
|
|
|
} else {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2012-06-03 17:01:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Buffer::Append(const std::string &str) {
|
|
|
|
char *ptr = Append(str.size());
|
|
|
|
memcpy(ptr, str.data(), str.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Buffer::Append(const char *str) {
|
|
|
|
size_t len = strlen(str);
|
|
|
|
char *dest = Append(len);
|
|
|
|
memcpy(dest, str, len);
|
|
|
|
}
|
|
|
|
|
2013-06-25 02:36:53 +00:00
|
|
|
void Buffer::Append(const Buffer &other) {
|
|
|
|
size_t len = other.size();
|
2020-02-06 23:09:42 +00:00
|
|
|
if (len > 0) {
|
|
|
|
char *dest = Append(len);
|
|
|
|
memcpy(dest, &other.data_[0], len);
|
|
|
|
}
|
2013-06-25 02:36:53 +00:00
|
|
|
}
|
|
|
|
|
2012-06-03 17:01:08 +00:00
|
|
|
void Buffer::AppendValue(int value) {
|
|
|
|
char buf[16];
|
|
|
|
// This is slow.
|
|
|
|
sprintf(buf, "%i", value);
|
|
|
|
Append(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Buffer::Take(size_t length, std::string *dest) {
|
2013-06-25 02:36:53 +00:00
|
|
|
if (length > data_.size()) {
|
2020-08-15 13:51:41 +00:00
|
|
|
ERROR_LOG(IO, "Truncating length in Buffer::Take()");
|
2013-06-25 02:36:53 +00:00
|
|
|
length = data_.size();
|
|
|
|
}
|
|
|
|
dest->resize(length);
|
2013-06-04 20:05:17 +00:00
|
|
|
if (length > 0) {
|
2014-11-24 00:12:54 +00:00
|
|
|
Take(length, &(*dest)[0]);
|
2013-06-04 20:05:17 +00:00
|
|
|
}
|
2012-06-03 17:01:08 +00:00
|
|
|
}
|
|
|
|
|
2014-11-24 00:12:54 +00:00
|
|
|
void Buffer::Take(size_t length, char *dest) {
|
|
|
|
memcpy(dest, &data_[0], length);
|
2014-11-24 15:47:57 +00:00
|
|
|
data_.erase(data_.begin(), data_.begin() + length);
|
2014-11-24 00:12:54 +00:00
|
|
|
}
|
|
|
|
|
2012-06-03 17:01:08 +00:00
|
|
|
int Buffer::TakeLineCRLF(std::string *dest) {
|
|
|
|
int after_next_line = OffsetToAfterNextCRLF();
|
|
|
|
if (after_next_line < 0)
|
|
|
|
return after_next_line;
|
|
|
|
else {
|
|
|
|
Take(after_next_line - 2, dest);
|
|
|
|
Skip(2); // Skip the CRLF
|
|
|
|
return after_next_line - 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Buffer::Skip(size_t length) {
|
2013-06-25 02:36:53 +00:00
|
|
|
if (length > data_.size()) {
|
2020-08-15 13:51:41 +00:00
|
|
|
ERROR_LOG(IO, "Truncating length in Buffer::Skip()");
|
2013-06-25 02:36:53 +00:00
|
|
|
length = data_.size();
|
|
|
|
}
|
|
|
|
data_.erase(data_.begin(), data_.begin() + length);
|
2012-06-03 17:01:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int Buffer::SkipLineCRLF() {
|
|
|
|
int after_next_line = OffsetToAfterNextCRLF();
|
|
|
|
if (after_next_line < 0)
|
|
|
|
return after_next_line;
|
|
|
|
else {
|
|
|
|
Skip(after_next_line);
|
|
|
|
return after_next_line - 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int Buffer::OffsetToAfterNextCRLF() {
|
2013-05-31 21:04:42 +00:00
|
|
|
for (int i = 0; i < (int)data_.size() - 1; i++) {
|
2012-06-03 17:01:08 +00:00
|
|
|
if (data_[i] == '\r' && data_[i + 1] == '\n') {
|
|
|
|
return i + 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Buffer::Printf(const char *fmt, ...) {
|
2013-06-25 02:36:53 +00:00
|
|
|
char buffer[2048];
|
2012-06-03 17:01:08 +00:00
|
|
|
va_list vl;
|
|
|
|
va_start(vl, fmt);
|
2020-09-29 08:24:41 +00:00
|
|
|
size_t retval = vsnprintf(buffer, sizeof(buffer), fmt, vl);
|
|
|
|
if ((int)retval >= (int)sizeof(buffer)) {
|
2012-06-03 17:01:08 +00:00
|
|
|
// Output was truncated. TODO: Do something.
|
2020-08-15 13:51:41 +00:00
|
|
|
ERROR_LOG(IO, "Buffer::Printf truncated output");
|
2013-06-25 02:36:53 +00:00
|
|
|
}
|
|
|
|
if (retval < 0) {
|
2020-08-15 13:51:41 +00:00
|
|
|
ERROR_LOG(IO, "Buffer::Printf failed");
|
2012-06-03 17:01:08 +00:00
|
|
|
}
|
|
|
|
va_end(vl);
|
|
|
|
char *ptr = Append(retval);
|
|
|
|
memcpy(ptr, buffer, retval);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Buffer::Flush(int fd) {
|
|
|
|
// Look into using send() directly.
|
2020-09-29 08:24:41 +00:00
|
|
|
bool success = data_.size() == fd_util::WriteLine(fd, &data_[0], data_.size());
|
2012-06-03 17:01:08 +00:00
|
|
|
if (success) {
|
|
|
|
data_.resize(0);
|
|
|
|
}
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2013-05-31 21:04:42 +00:00
|
|
|
bool Buffer::FlushToFile(const char *filename) {
|
|
|
|
FILE *f = fopen(filename, "wb");
|
|
|
|
if (!f)
|
|
|
|
return false;
|
|
|
|
if (data_.size()) {
|
|
|
|
fwrite(&data_[0], 1, data_.size(), f);
|
|
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-07-05 04:17:59 +00:00
|
|
|
bool Buffer::FlushSocket(uintptr_t sock, double timeout, bool *cancelled) {
|
|
|
|
static constexpr float CANCEL_INTERVAL = 0.25f;
|
2014-07-12 21:58:42 +00:00
|
|
|
for (size_t pos = 0, end = data_.size(); pos < end; ) {
|
2020-07-05 04:17:59 +00:00
|
|
|
bool ready = false;
|
|
|
|
double leftTimeout = timeout;
|
|
|
|
while (!ready && (leftTimeout >= 0 || cancelled)) {
|
|
|
|
if (cancelled && *cancelled)
|
|
|
|
return false;
|
|
|
|
ready = fd_util::WaitUntilReady(sock, CANCEL_INTERVAL, true);
|
|
|
|
if (!ready && leftTimeout >= 0.0) {
|
|
|
|
leftTimeout -= CANCEL_INTERVAL;
|
|
|
|
if (leftTimeout < 0) {
|
2020-08-15 13:51:41 +00:00
|
|
|
ERROR_LOG(IO, "FlushSocket timed out");
|
2020-07-05 04:17:59 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2018-12-27 18:15:58 +00:00
|
|
|
}
|
2018-10-16 20:57:58 +00:00
|
|
|
int sent = send(sock, &data_[pos], (int)(end - pos), MSG_NOSIGNAL);
|
2014-07-12 21:58:42 +00:00
|
|
|
if (sent < 0) {
|
2020-08-15 13:51:41 +00:00
|
|
|
ERROR_LOG(IO, "FlushSocket failed");
|
2014-07-12 21:58:42 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
pos += sent;
|
2013-03-01 07:48:19 +00:00
|
|
|
|
2014-07-12 21:58:42 +00:00
|
|
|
// Buffer full, don't spin.
|
2018-12-27 18:15:58 +00:00
|
|
|
if (sent == 0 && timeout < 0.0) {
|
2014-07-12 21:58:42 +00:00
|
|
|
sleep_ms(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
data_.resize(0);
|
|
|
|
return true;
|
2012-06-03 17:01:08 +00:00
|
|
|
}
|
|
|
|
|
2014-12-31 17:36:00 +00:00
|
|
|
bool Buffer::ReadAll(int fd, int hintSize) {
|
|
|
|
std::vector<char> buf;
|
|
|
|
if (hintSize >= 65536 * 16) {
|
|
|
|
buf.resize(65536);
|
|
|
|
} else if (hintSize >= 1024 * 16) {
|
|
|
|
buf.resize(hintSize / 16);
|
|
|
|
} else {
|
2020-02-06 23:09:42 +00:00
|
|
|
buf.resize(4096);
|
2014-12-31 17:36:00 +00:00
|
|
|
}
|
|
|
|
|
2013-05-31 21:04:42 +00:00
|
|
|
while (true) {
|
2014-12-31 18:25:50 +00:00
|
|
|
int retval = recv(fd, &buf[0], (int)buf.size(), 0);
|
2014-12-31 17:36:00 +00:00
|
|
|
if (retval == 0) {
|
|
|
|
break;
|
|
|
|
} else if (retval < 0) {
|
2020-08-15 13:51:41 +00:00
|
|
|
ERROR_LOG(IO, "Error reading from buffer: %i", retval);
|
2013-05-31 21:04:42 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
char *p = Append((size_t)retval);
|
2014-12-31 18:25:50 +00:00
|
|
|
memcpy(p, &buf[0], retval);
|
2013-05-31 21:04:42 +00:00
|
|
|
}
|
|
|
|
return true;
|
2012-06-03 17:01:08 +00:00
|
|
|
}
|
|
|
|
|
2017-03-06 14:43:38 +00:00
|
|
|
bool Buffer::ReadAllWithProgress(int fd, int knownSize, float *progress, bool *cancelled) {
|
2020-07-05 04:17:59 +00:00
|
|
|
static constexpr float CANCEL_INTERVAL = 0.25f;
|
2014-12-31 17:36:00 +00:00
|
|
|
std::vector<char> buf;
|
|
|
|
if (knownSize >= 65536 * 16) {
|
|
|
|
buf.resize(65536);
|
|
|
|
} else if (knownSize >= 1024 * 16) {
|
|
|
|
buf.resize(knownSize / 16);
|
|
|
|
} else {
|
|
|
|
buf.resize(1024);
|
|
|
|
}
|
|
|
|
|
2013-11-29 15:31:19 +00:00
|
|
|
int total = 0;
|
|
|
|
while (true) {
|
2020-07-05 04:17:59 +00:00
|
|
|
bool ready = false;
|
|
|
|
while (!ready && cancelled) {
|
|
|
|
if (*cancelled)
|
|
|
|
return false;
|
|
|
|
ready = fd_util::WaitUntilReady(fd, CANCEL_INTERVAL, false);
|
|
|
|
}
|
2014-12-31 18:25:50 +00:00
|
|
|
int retval = recv(fd, &buf[0], (int)buf.size(), 0);
|
2013-11-29 15:31:19 +00:00
|
|
|
if (retval == 0) {
|
|
|
|
return true;
|
|
|
|
} else if (retval < 0) {
|
2020-08-15 13:51:41 +00:00
|
|
|
ERROR_LOG(IO, "Error reading from buffer: %i", retval);
|
2013-11-29 15:31:19 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
char *p = Append((size_t)retval);
|
2014-12-31 18:25:50 +00:00
|
|
|
memcpy(p, &buf[0], retval);
|
2013-11-29 15:31:19 +00:00
|
|
|
total += retval;
|
2020-07-05 04:17:59 +00:00
|
|
|
if (progress)
|
|
|
|
*progress = (float)total / (float)knownSize;
|
2013-11-29 15:31:19 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Buffer::Read(int fd, size_t sz) {
|
2013-06-03 23:24:49 +00:00
|
|
|
char buf[1024];
|
|
|
|
int retval;
|
|
|
|
size_t received = 0;
|
2014-11-16 15:44:32 +00:00
|
|
|
while ((retval = recv(fd, buf, (int)std::min(sz, sizeof(buf)), 0)) > 0) {
|
2013-11-29 15:31:19 +00:00
|
|
|
if (retval < 0) {
|
|
|
|
return retval;
|
|
|
|
}
|
2013-06-03 23:24:49 +00:00
|
|
|
char *p = Append((size_t)retval);
|
|
|
|
memcpy(p, buf, retval);
|
|
|
|
sz -= retval;
|
|
|
|
received += retval;
|
|
|
|
if (sz == 0)
|
|
|
|
return 0;
|
|
|
|
}
|
2014-11-16 15:44:32 +00:00
|
|
|
return (int)received;
|
2012-06-03 17:01:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Buffer::PeekAll(std::string *dest) {
|
2013-06-03 23:24:49 +00:00
|
|
|
dest->resize(data_.size());
|
|
|
|
memcpy(&(*dest)[0], &data_[0], data_.size());
|
2013-11-29 15:31:19 +00:00
|
|
|
}
|