2018-09-27 14:56:48 -07:00
|
|
|
/*
|
|
|
|
* IXSocket.cpp
|
|
|
|
* Author: Benjamin Sergeant
|
|
|
|
* Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "IXSocket.h"
|
2019-09-23 10:25:23 -07:00
|
|
|
|
2019-01-05 20:38:43 -08:00
|
|
|
#include "IXNetSystem.h"
|
2019-03-14 18:37:38 -07:00
|
|
|
#include "IXSelectInterrupt.h"
|
|
|
|
#include "IXSelectInterruptFactory.h"
|
2019-09-23 10:25:23 -07:00
|
|
|
#include "IXSocketConnect.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdint.h>
|
2018-09-27 14:56:48 -07:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2018-10-08 21:42:45 -07:00
|
|
|
#include <sys/types.h>
|
|
|
|
|
2019-04-16 18:51:57 +03:00
|
|
|
#ifdef min
|
|
|
|
#undef min
|
|
|
|
#endif
|
|
|
|
|
2019-02-20 18:59:07 -08:00
|
|
|
namespace ix
|
2018-09-27 14:56:48 -07:00
|
|
|
{
|
2019-01-24 12:42:49 -08:00
|
|
|
const int Socket::kDefaultPollNoTimeout = -1; // No poll timeout by default
|
|
|
|
const int Socket::kDefaultPollTimeout = kDefaultPollNoTimeout;
|
2019-03-14 15:03:57 -07:00
|
|
|
const uint64_t Socket::kSendRequest = 1;
|
|
|
|
const uint64_t Socket::kCloseRequest = 2;
|
2019-03-02 21:11:16 -08:00
|
|
|
constexpr size_t Socket::kChunkSize;
|
2019-01-24 12:42:49 -08:00
|
|
|
|
2019-09-23 10:25:23 -07:00
|
|
|
Socket::Socket(int fd)
|
|
|
|
: _sockfd(fd)
|
|
|
|
, _selectInterrupt(createSelectInterrupt())
|
2018-09-27 14:56:48 -07:00
|
|
|
{
|
2019-03-04 13:40:00 -08:00
|
|
|
;
|
2018-09-27 14:56:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
Socket::~Socket()
|
|
|
|
{
|
|
|
|
close();
|
|
|
|
}
|
|
|
|
|
2019-06-25 10:16:40 -07:00
|
|
|
PollResultType Socket::poll(bool readyToRead,
|
|
|
|
int timeoutMs,
|
|
|
|
int sockfd,
|
2020-03-24 10:00:41 -07:00
|
|
|
const SelectInterruptPtr& selectInterrupt)
|
2019-03-04 13:40:00 -08:00
|
|
|
{
|
2019-06-25 17:11:27 -07:00
|
|
|
//
|
2019-10-01 15:43:37 -07:00
|
|
|
// We used to use ::select to poll but on Android 9 we get large fds out of
|
|
|
|
// ::connect which crash in FD_SET as they are larger than FD_SETSIZE. Switching
|
|
|
|
// to ::poll does fix that.
|
2019-06-25 17:11:27 -07:00
|
|
|
//
|
2019-10-01 15:43:37 -07:00
|
|
|
// However poll isn't as portable as select and has bugs on Windows, so we
|
2020-01-09 12:26:57 -08:00
|
|
|
// have a shim to fallback to select on those platforms. See
|
2019-10-01 15:43:37 -07:00
|
|
|
// https://github.com/mpv-player/mpv/pull/5203/files for such a select wrapper.
|
2019-06-25 17:11:27 -07:00
|
|
|
//
|
2019-08-22 10:34:17 -07:00
|
|
|
nfds_t nfds = 1;
|
2019-06-25 17:11:27 -07:00
|
|
|
struct pollfd fds[2];
|
2020-01-09 13:45:58 -08:00
|
|
|
memset(fds, 0, sizeof(fds));
|
2019-06-25 17:11:27 -07:00
|
|
|
|
|
|
|
fds[0].fd = sockfd;
|
|
|
|
fds[0].events = (readyToRead) ? POLLIN : POLLOUT;
|
2020-01-09 13:45:58 -08:00
|
|
|
|
2020-01-13 16:44:10 -08:00
|
|
|
// this is ignored by poll, but our select based poll wrapper on Windows needs it
|
2019-06-25 17:11:27 -07:00
|
|
|
fds[0].events |= POLLERR;
|
2019-02-20 18:59:07 -08:00
|
|
|
|
2019-03-14 18:37:38 -07:00
|
|
|
// File descriptor used to interrupt select when needed
|
2019-06-25 15:41:39 -07:00
|
|
|
int interruptFd = -1;
|
|
|
|
if (selectInterrupt)
|
2019-03-13 23:09:45 -07:00
|
|
|
{
|
2019-06-25 15:41:39 -07:00
|
|
|
interruptFd = selectInterrupt->getFd();
|
|
|
|
|
|
|
|
if (interruptFd != -1)
|
|
|
|
{
|
2019-06-25 17:11:27 -07:00
|
|
|
nfds = 2;
|
|
|
|
fds[1].fd = interruptFd;
|
|
|
|
fds[1].events = POLLIN;
|
2019-06-25 15:41:39 -07:00
|
|
|
}
|
2019-03-13 23:09:45 -07:00
|
|
|
}
|
2019-01-26 20:57:48 -08:00
|
|
|
|
2019-09-08 11:14:49 -07:00
|
|
|
int ret = ix::poll(fds, nfds, timeoutMs);
|
2019-03-13 23:09:45 -07:00
|
|
|
|
2019-03-19 09:29:57 -07:00
|
|
|
PollResultType pollResult = PollResultType::ReadyForRead;
|
2019-03-13 23:09:45 -07:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
2019-03-19 09:29:57 -07:00
|
|
|
pollResult = PollResultType::Error;
|
2019-03-13 23:09:45 -07:00
|
|
|
}
|
|
|
|
else if (ret == 0)
|
|
|
|
{
|
2019-03-19 09:29:57 -07:00
|
|
|
pollResult = PollResultType::Timeout;
|
2019-03-13 23:09:45 -07:00
|
|
|
}
|
2019-06-25 17:11:27 -07:00
|
|
|
else if (interruptFd != -1 && fds[1].revents & POLLIN)
|
2019-03-13 23:09:45 -07:00
|
|
|
{
|
2019-06-25 15:41:39 -07:00
|
|
|
uint64_t value = selectInterrupt->read();
|
2019-03-13 23:09:45 -07:00
|
|
|
|
|
|
|
if (value == kSendRequest)
|
|
|
|
{
|
2019-03-19 09:29:57 -07:00
|
|
|
pollResult = PollResultType::SendRequest;
|
2019-03-13 23:09:45 -07:00
|
|
|
}
|
|
|
|
else if (value == kCloseRequest)
|
|
|
|
{
|
2019-03-19 09:29:57 -07:00
|
|
|
pollResult = PollResultType::CloseRequest;
|
2019-03-13 23:09:45 -07:00
|
|
|
}
|
|
|
|
}
|
2019-06-25 17:11:27 -07:00
|
|
|
else if (sockfd != -1 && readyToRead && fds[0].revents & POLLIN)
|
2019-03-18 14:25:27 -07:00
|
|
|
{
|
2019-03-19 09:29:57 -07:00
|
|
|
pollResult = PollResultType::ReadyForRead;
|
2019-03-18 22:00:08 -07:00
|
|
|
}
|
2019-06-25 17:11:27 -07:00
|
|
|
else if (sockfd != -1 && !readyToRead && fds[0].revents & POLLOUT)
|
2019-03-18 22:00:08 -07:00
|
|
|
{
|
2019-03-19 09:29:57 -07:00
|
|
|
pollResult = PollResultType::ReadyForWrite;
|
2019-06-25 15:41:39 -07:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
// On connect error, in async mode, windows will write to the exceptions fds
|
2019-06-25 17:11:27 -07:00
|
|
|
if (fds[0].revents & POLLERR)
|
2019-06-25 15:41:39 -07:00
|
|
|
{
|
|
|
|
pollResult = PollResultType::Error;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int optval = -1;
|
|
|
|
socklen_t optlen = sizeof(optval);
|
|
|
|
|
|
|
|
// getsockopt() puts the errno value for connect into optval so 0
|
|
|
|
// means no-error.
|
2019-09-23 10:25:23 -07:00
|
|
|
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1 || optval != 0)
|
2019-06-25 15:41:39 -07:00
|
|
|
{
|
|
|
|
pollResult = PollResultType::Error;
|
2019-08-13 10:49:11 -07:00
|
|
|
|
|
|
|
// set errno to optval so that external callers can have an
|
|
|
|
// appropriate error description when calling strerror
|
|
|
|
errno = optval;
|
2019-06-25 15:41:39 -07:00
|
|
|
}
|
|
|
|
#endif
|
2019-03-18 14:25:27 -07:00
|
|
|
}
|
2020-01-09 13:45:58 -08:00
|
|
|
else if (sockfd != -1 && (fds[0].revents & POLLERR || fds[0].revents & POLLHUP ||
|
|
|
|
fds[0].revents & POLLNVAL))
|
2020-01-09 12:26:57 -08:00
|
|
|
{
|
|
|
|
pollResult = PollResultType::Error;
|
|
|
|
}
|
2019-03-13 23:09:45 -07:00
|
|
|
|
|
|
|
return pollResult;
|
2018-09-27 14:56:48 -07:00
|
|
|
}
|
|
|
|
|
2019-03-18 17:54:51 -07:00
|
|
|
PollResultType Socket::isReadyToRead(int timeoutMs)
|
2019-03-18 14:25:27 -07:00
|
|
|
{
|
2019-05-22 18:58:22 -07:00
|
|
|
if (_sockfd == -1)
|
|
|
|
{
|
|
|
|
return PollResultType::Error;
|
|
|
|
}
|
|
|
|
|
2019-03-18 14:25:27 -07:00
|
|
|
bool readyToRead = true;
|
2019-06-25 15:41:39 -07:00
|
|
|
return poll(readyToRead, timeoutMs, _sockfd, _selectInterrupt);
|
2019-03-18 14:25:27 -07:00
|
|
|
}
|
|
|
|
|
2019-03-18 17:54:51 -07:00
|
|
|
PollResultType Socket::isReadyToWrite(int timeoutMs)
|
2019-03-18 14:25:27 -07:00
|
|
|
{
|
2019-05-22 18:58:22 -07:00
|
|
|
if (_sockfd == -1)
|
|
|
|
{
|
|
|
|
return PollResultType::Error;
|
|
|
|
}
|
|
|
|
|
2019-03-18 14:25:27 -07:00
|
|
|
bool readyToRead = false;
|
2019-06-25 15:41:39 -07:00
|
|
|
return poll(readyToRead, timeoutMs, _sockfd, _selectInterrupt);
|
2019-03-18 14:25:27 -07:00
|
|
|
}
|
|
|
|
|
2019-03-13 23:09:45 -07:00
|
|
|
// Wake up from poll/select by writing to the pipe which is watched by select
|
2019-05-13 22:16:49 -07:00
|
|
|
bool Socket::wakeUpFromPoll(uint64_t wakeUpCode)
|
2018-09-27 14:56:48 -07:00
|
|
|
{
|
2019-03-14 18:37:38 -07:00
|
|
|
return _selectInterrupt->notify(wakeUpCode);
|
2018-09-27 14:56:48 -07:00
|
|
|
}
|
|
|
|
|
2019-10-01 15:43:37 -07:00
|
|
|
bool Socket::accept(std::string& errMsg)
|
|
|
|
{
|
|
|
|
if (_sockfd == -1)
|
|
|
|
{
|
|
|
|
errMsg = "Socket is uninitialized";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-09-27 14:56:48 -07:00
|
|
|
bool Socket::connect(const std::string& host,
|
|
|
|
int port,
|
2018-12-09 17:56:20 -08:00
|
|
|
std::string& errMsg,
|
2018-12-14 16:28:11 -08:00
|
|
|
const CancellationRequest& isCancellationRequested)
|
2018-09-27 14:56:48 -07:00
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(_socketMutex);
|
|
|
|
|
2019-03-14 18:37:38 -07:00
|
|
|
if (!_selectInterrupt->clear()) return false;
|
2018-09-27 14:56:48 -07:00
|
|
|
|
2018-12-09 17:56:20 -08:00
|
|
|
_sockfd = SocketConnect::connect(host, port, errMsg, isCancellationRequested);
|
2018-09-27 14:56:48 -07:00
|
|
|
return _sockfd != -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Socket::close()
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(_socketMutex);
|
|
|
|
|
|
|
|
if (_sockfd == -1) return;
|
|
|
|
|
2018-10-08 21:42:45 -07:00
|
|
|
closeSocket(_sockfd);
|
2018-09-27 14:56:48 -07:00
|
|
|
_sockfd = -1;
|
|
|
|
}
|
|
|
|
|
2019-01-05 20:53:50 -08:00
|
|
|
ssize_t Socket::send(char* buffer, size_t length)
|
2018-09-27 14:56:48 -07:00
|
|
|
{
|
|
|
|
int flags = 0;
|
|
|
|
#ifdef MSG_NOSIGNAL
|
|
|
|
flags = MSG_NOSIGNAL;
|
|
|
|
#endif
|
|
|
|
|
2019-01-05 20:53:50 -08:00
|
|
|
return ::send(_sockfd, buffer, length, flags);
|
2018-09-27 14:56:48 -07:00
|
|
|
}
|
|
|
|
|
2019-01-05 20:53:50 -08:00
|
|
|
ssize_t Socket::send(const std::string& buffer)
|
2018-09-27 14:56:48 -07:00
|
|
|
{
|
2019-09-23 10:25:23 -07:00
|
|
|
return send((char*) &buffer[0], buffer.size());
|
2018-09-27 14:56:48 -07:00
|
|
|
}
|
|
|
|
|
2019-01-05 20:53:50 -08:00
|
|
|
ssize_t Socket::recv(void* buffer, size_t length)
|
2018-09-27 14:56:48 -07:00
|
|
|
{
|
|
|
|
int flags = 0;
|
|
|
|
#ifdef MSG_NOSIGNAL
|
|
|
|
flags = MSG_NOSIGNAL;
|
|
|
|
#endif
|
|
|
|
|
2019-01-05 20:53:50 -08:00
|
|
|
return ::recv(_sockfd, (char*) buffer, length, flags);
|
2018-09-27 14:56:48 -07:00
|
|
|
}
|
|
|
|
|
2019-01-04 17:28:13 -08:00
|
|
|
int Socket::getErrno()
|
2018-10-08 21:42:45 -07:00
|
|
|
{
|
2019-05-06 22:22:57 +03:00
|
|
|
int err;
|
|
|
|
|
2018-10-08 21:42:45 -07:00
|
|
|
#ifdef _WIN32
|
2019-05-06 22:22:57 +03:00
|
|
|
err = WSAGetLastError();
|
2018-10-08 21:42:45 -07:00
|
|
|
#else
|
2019-05-06 22:22:57 +03:00
|
|
|
err = errno;
|
2018-10-08 21:42:45 -07:00
|
|
|
#endif
|
2019-05-06 22:22:57 +03:00
|
|
|
|
|
|
|
return err;
|
2018-10-08 21:42:45 -07:00
|
|
|
}
|
|
|
|
|
2019-05-06 19:13:42 +03:00
|
|
|
bool Socket::isWaitNeeded()
|
|
|
|
{
|
|
|
|
int err = getErrno();
|
|
|
|
|
2019-05-06 22:22:57 +03:00
|
|
|
if (err == EWOULDBLOCK || err == EAGAIN || err == EINPROGRESS)
|
2019-05-06 19:13:42 +03:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-10-08 21:42:45 -07:00
|
|
|
void Socket::closeSocket(int fd)
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
closesocket(fd);
|
|
|
|
#else
|
|
|
|
::close(fd);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-03-14 18:37:38 -07:00
|
|
|
bool Socket::init(std::string& errorMsg)
|
2018-10-08 21:42:45 -07:00
|
|
|
{
|
2019-03-14 18:37:38 -07:00
|
|
|
return _selectInterrupt->init(errorMsg);
|
2018-10-08 21:42:45 -07:00
|
|
|
}
|
2019-01-02 07:45:07 -08:00
|
|
|
|
2019-03-02 15:16:46 -08:00
|
|
|
bool Socket::writeBytes(const std::string& str,
|
|
|
|
const CancellationRequest& isCancellationRequested)
|
|
|
|
{
|
2019-06-26 16:25:07 -07:00
|
|
|
int offset = 0;
|
2019-06-23 14:54:21 -07:00
|
|
|
int len = (int) str.size();
|
|
|
|
|
2019-03-02 15:16:46 -08:00
|
|
|
while (true)
|
|
|
|
{
|
2019-03-20 14:29:02 -07:00
|
|
|
if (isCancellationRequested && isCancellationRequested()) return false;
|
2019-03-02 15:16:46 -08:00
|
|
|
|
2019-09-23 10:25:23 -07:00
|
|
|
ssize_t ret = send((char*) &str[offset], len);
|
2019-03-02 15:16:46 -08:00
|
|
|
|
|
|
|
// We wrote some bytes, as needed, all good.
|
|
|
|
if (ret > 0)
|
|
|
|
{
|
2019-06-23 14:54:21 -07:00
|
|
|
if (ret == len)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-06-26 16:25:07 -07:00
|
|
|
offset += ret;
|
2019-06-25 15:41:39 -07:00
|
|
|
len -= ret;
|
2019-06-23 14:54:21 -07:00
|
|
|
continue;
|
|
|
|
}
|
2019-03-02 15:16:46 -08:00
|
|
|
}
|
2019-03-20 14:29:02 -07:00
|
|
|
// There is possibly something to be writen, try again
|
2019-05-06 19:13:42 +03:00
|
|
|
else if (ret < 0 && Socket::isWaitNeeded())
|
2019-03-02 15:16:46 -08:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// There was an error during the write, abort
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-23 10:25:23 -07:00
|
|
|
bool Socket::readByte(void* buffer, const CancellationRequest& isCancellationRequested)
|
2019-01-02 07:45:07 -08:00
|
|
|
{
|
|
|
|
while (true)
|
|
|
|
{
|
2019-03-20 14:29:02 -07:00
|
|
|
if (isCancellationRequested && isCancellationRequested()) return false;
|
2019-01-02 07:45:07 -08:00
|
|
|
|
2019-01-05 21:10:08 -08:00
|
|
|
ssize_t ret;
|
2019-01-02 07:45:07 -08:00
|
|
|
ret = recv(buffer, 1);
|
|
|
|
|
|
|
|
// We read one byte, as needed, all good.
|
|
|
|
if (ret == 1)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// There is possibly something to be read, try again
|
2019-05-06 19:13:42 +03:00
|
|
|
else if (ret < 0 && Socket::isWaitNeeded())
|
2019-01-02 07:45:07 -08:00
|
|
|
{
|
2019-03-18 14:25:27 -07:00
|
|
|
// Wait with a 1ms timeout until the socket is ready to read.
|
2019-03-04 13:40:00 -08:00
|
|
|
// This way we are not busy looping
|
2019-03-19 09:29:57 -07:00
|
|
|
if (isReadyToRead(1) == PollResultType::Error)
|
2019-03-04 13:40:00 -08:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2019-01-02 07:45:07 -08:00
|
|
|
}
|
|
|
|
// There was an error during the read, abort
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-02 15:16:46 -08:00
|
|
|
std::pair<bool, std::string> Socket::readLine(
|
|
|
|
const CancellationRequest& isCancellationRequested)
|
2019-01-02 16:08:32 -08:00
|
|
|
{
|
2019-01-03 18:47:01 -08:00
|
|
|
char c;
|
|
|
|
std::string line;
|
|
|
|
line.reserve(64);
|
2019-01-02 16:08:32 -08:00
|
|
|
|
2019-09-23 10:25:23 -07:00
|
|
|
for (int i = 0; i < 2 || (line[i - 2] != '\r' && line[i - 1] != '\n'); ++i)
|
2019-01-02 16:08:32 -08:00
|
|
|
{
|
2019-01-03 18:47:01 -08:00
|
|
|
if (!readByte(&c, isCancellationRequested))
|
2019-01-02 16:08:32 -08:00
|
|
|
{
|
2019-03-02 11:01:51 -08:00
|
|
|
// Return what we were able to read
|
|
|
|
return std::make_pair(false, line);
|
2019-01-03 18:47:01 -08:00
|
|
|
}
|
2019-01-02 16:08:32 -08:00
|
|
|
|
2019-01-03 18:47:01 -08:00
|
|
|
line += c;
|
2019-01-02 16:08:32 -08:00
|
|
|
}
|
|
|
|
|
2019-01-03 18:47:01 -08:00
|
|
|
return std::make_pair(true, line);
|
2019-01-02 16:08:32 -08:00
|
|
|
}
|
2019-03-02 11:01:51 -08:00
|
|
|
|
|
|
|
std::pair<bool, std::string> Socket::readBytes(
|
|
|
|
size_t length,
|
2019-03-02 21:11:16 -08:00
|
|
|
const OnProgressCallback& onProgressCallback,
|
2019-03-02 11:01:51 -08:00
|
|
|
const CancellationRequest& isCancellationRequested)
|
|
|
|
{
|
2019-03-04 13:40:00 -08:00
|
|
|
if (_readBuffer.empty())
|
|
|
|
{
|
|
|
|
_readBuffer.resize(kChunkSize);
|
|
|
|
}
|
|
|
|
|
2019-03-02 21:11:16 -08:00
|
|
|
std::vector<uint8_t> output;
|
|
|
|
while (output.size() != length)
|
2019-03-02 15:16:46 -08:00
|
|
|
{
|
2019-03-20 14:29:02 -07:00
|
|
|
if (isCancellationRequested && isCancellationRequested())
|
|
|
|
{
|
2020-04-14 21:50:26 -07:00
|
|
|
const std::string errorMsg("Cancellation Requested");
|
|
|
|
return std::make_pair(false, errorMsg);
|
2019-03-20 14:29:02 -07:00
|
|
|
}
|
2019-03-02 21:11:16 -08:00
|
|
|
|
2019-03-20 14:29:02 -07:00
|
|
|
size_t size = std::min(kChunkSize, length - output.size());
|
2019-09-23 10:25:23 -07:00
|
|
|
ssize_t ret = recv((char*) &_readBuffer[0], size);
|
2019-03-02 15:16:46 -08:00
|
|
|
|
2019-09-21 09:23:58 -07:00
|
|
|
if (ret > 0)
|
2019-03-02 15:16:46 -08:00
|
|
|
{
|
2019-09-23 10:25:23 -07:00
|
|
|
output.insert(output.end(), _readBuffer.begin(), _readBuffer.begin() + ret);
|
2019-03-02 11:01:51 -08:00
|
|
|
}
|
2019-09-21 09:23:58 -07:00
|
|
|
else if (ret <= 0 && !Socket::isWaitNeeded())
|
|
|
|
{
|
2020-04-14 21:50:26 -07:00
|
|
|
const std::string errorMsg("Recv Error");
|
|
|
|
return std::make_pair(false, errorMsg);
|
2019-09-21 09:23:58 -07:00
|
|
|
}
|
2019-03-02 11:01:51 -08:00
|
|
|
|
2019-03-02 21:11:16 -08:00
|
|
|
if (onProgressCallback) onProgressCallback((int) output.size(), (int) length);
|
|
|
|
|
2019-03-18 14:25:27 -07:00
|
|
|
// Wait with a 1ms timeout until the socket is ready to read.
|
2019-03-04 13:40:00 -08:00
|
|
|
// This way we are not busy looping
|
2019-03-19 09:29:57 -07:00
|
|
|
if (isReadyToRead(1) == PollResultType::Error)
|
2019-03-18 14:25:27 -07:00
|
|
|
{
|
2020-04-14 21:50:26 -07:00
|
|
|
const std::string errorMsg("Poll Error");
|
|
|
|
return std::make_pair(false, errorMsg);
|
2019-03-18 14:25:27 -07:00
|
|
|
}
|
2019-03-02 11:01:51 -08:00
|
|
|
}
|
|
|
|
|
2019-09-23 10:25:23 -07:00
|
|
|
return std::make_pair(true, std::string(output.begin(), output.end()));
|
2019-03-02 11:01:51 -08:00
|
|
|
}
|
2019-09-23 10:25:23 -07:00
|
|
|
} // namespace ix
|