|
|
|
@ -799,6 +799,7 @@ enum class Error {
|
|
|
|
|
SSLServerVerification,
|
|
|
|
|
UnsupportedMultipartBoundaryChars,
|
|
|
|
|
Compression,
|
|
|
|
|
ConnectionTimeout,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::string to_string(const Error error);
|
|
|
|
@ -1594,6 +1595,7 @@ inline std::string to_string(const Error error) {
|
|
|
|
|
case Error::UnsupportedMultipartBoundaryChars:
|
|
|
|
|
return "UnsupportedMultipartBoundaryChars";
|
|
|
|
|
case Error::Compression: return "Compression";
|
|
|
|
|
case Error::ConnectionTimeout: return "ConnectionTimeout";
|
|
|
|
|
case Error::Unknown: return "Unknown";
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
@ -2313,7 +2315,7 @@ inline ssize_t select_write(socket_t sock, time_t sec, time_t usec) {
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) {
|
|
|
|
|
inline Error wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) {
|
|
|
|
|
#ifdef CPPHTTPLIB_USE_POLL
|
|
|
|
|
struct pollfd pfd_read;
|
|
|
|
|
pfd_read.fd = sock;
|
|
|
|
@ -2323,17 +2325,23 @@ inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) {
|
|
|
|
|
|
|
|
|
|
auto poll_res = handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
|
|
|
|
|
|
|
|
|
|
if (poll_res == 0) {
|
|
|
|
|
return Error::ConnectionTimeout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (poll_res > 0 && pfd_read.revents & (POLLIN | POLLOUT)) {
|
|
|
|
|
int error = 0;
|
|
|
|
|
socklen_t len = sizeof(error);
|
|
|
|
|
auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
|
|
|
|
|
reinterpret_cast<char *>(&error), &len);
|
|
|
|
|
return res >= 0 && !error;
|
|
|
|
|
auto successful = res >= 0 && !error;
|
|
|
|
|
return successful ? Error::Success : Error::Connection;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return Error::Connection;
|
|
|
|
|
#else
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
|
if (sock >= FD_SETSIZE) { return false; }
|
|
|
|
|
if (sock >= FD_SETSIZE) { return Error::Connection; }
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
fd_set fdsr;
|
|
|
|
@ -2351,14 +2359,19 @@ inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) {
|
|
|
|
|
return select(static_cast<int>(sock + 1), &fdsr, &fdsw, &fdse, &tv);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (ret == 0) {
|
|
|
|
|
return Error::ConnectionTimeout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ret > 0 && (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) {
|
|
|
|
|
int error = 0;
|
|
|
|
|
socklen_t len = sizeof(error);
|
|
|
|
|
return getsockopt(sock, SOL_SOCKET, SO_ERROR,
|
|
|
|
|
reinterpret_cast<char *>(&error), &len) >= 0 &&
|
|
|
|
|
!error;
|
|
|
|
|
auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
|
|
|
|
|
reinterpret_cast<char *>(&error), &len);
|
|
|
|
|
auto successful = res >= 0 && !error;
|
|
|
|
|
return successful ? Error::Success : Error::Connection;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
return Error::Connection;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2684,12 +2697,15 @@ inline socket_t create_client_socket(
|
|
|
|
|
::connect(sock2, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen));
|
|
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
if (is_connection_error() ||
|
|
|
|
|
!wait_until_socket_is_ready(sock2, connection_timeout_sec,
|
|
|
|
|
connection_timeout_usec)) {
|
|
|
|
|
if (is_connection_error()) {
|
|
|
|
|
error = Error::Connection;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
error = wait_until_socket_is_ready(sock2, connection_timeout_sec,
|
|
|
|
|
connection_timeout_usec);
|
|
|
|
|
if (error != Error::Success) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set_nonblocking(sock2, false);
|
|
|
|
|