Source release 16.3.0
This commit is contained in:
@@ -8,7 +8,8 @@
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cstring>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include "winsock2.h"
|
||||
@@ -33,6 +34,11 @@ namespace wvcdm {
|
||||
|
||||
namespace {
|
||||
|
||||
// Number of attempts to identify an Internet host and a service should the
|
||||
// host's nameserver be temporarily unavailable. See getaddrinfo(3) for
|
||||
// more info.
|
||||
constexpr size_t kMaxNameserverAttempts = 2;
|
||||
|
||||
// Helper function to tokenize a string. This makes it easier to avoid silly
|
||||
// parsing bugs that creep in easily when each part of the string is parsed
|
||||
// with its own piece of code.
|
||||
@@ -71,6 +77,17 @@ bool IsRetryableSslError(int ssl_error) {
|
||||
ssl_error != SSL_ERROR_SSL;
|
||||
}
|
||||
|
||||
// Ensures that the SSL library is only initialized once.
|
||||
void InitSslLibrary() {
|
||||
static bool ssl_initialized = false;
|
||||
static std::mutex ssl_init_mutex;
|
||||
std::lock_guard<std::mutex> guard(ssl_init_mutex);
|
||||
if (!ssl_initialized) {
|
||||
SSL_library_init();
|
||||
ssl_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// unused, may be useful for debugging SSL-related issues.
|
||||
void ShowServerCertificate(const SSL* ssl) {
|
||||
@@ -211,7 +228,7 @@ HttpSocket::HttpSocket(const std::string& url)
|
||||
: socket_fd_(-1), ssl_(nullptr), ssl_ctx_(nullptr) {
|
||||
valid_url_ = ParseUrl(url, &scheme_, &secure_connect_, &domain_name_, &port_,
|
||||
&resource_path_);
|
||||
SSL_library_init();
|
||||
InitSslLibrary();
|
||||
}
|
||||
|
||||
HttpSocket::~HttpSocket() { CloseSocket(); }
|
||||
@@ -237,6 +254,12 @@ void HttpSocket::CloseSocket() {
|
||||
|
||||
bool HttpSocket::Connect(int timeout_in_ms) {
|
||||
if (!valid_url_) {
|
||||
LOGE("URL is invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (socket_fd_ != -1) {
|
||||
LOGE("Socket already connected");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -259,24 +282,42 @@ bool HttpSocket::Connect(int timeout_in_ms) {
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG;
|
||||
|
||||
struct addrinfo* addr_info = nullptr;
|
||||
int ret =
|
||||
getaddrinfo(domain_name_.c_str(), port_.c_str(), &hints, &addr_info);
|
||||
|
||||
int ret = EAI_AGAIN;
|
||||
for (size_t attempt = 1;
|
||||
attempt <= kMaxNameserverAttempts && ret == EAI_AGAIN; ++attempt) {
|
||||
if (attempt > 1) {
|
||||
LOGW(
|
||||
"Nameserver is temporarily unavailable, waiting to try again: "
|
||||
"attempt = %zu",
|
||||
attempt);
|
||||
sleep(1);
|
||||
}
|
||||
ret = getaddrinfo(domain_name_.c_str(), port_.c_str(), &hints, &addr_info);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
LOGE("getaddrinfo failed, errno = %d", ret);
|
||||
if (ret == EAI_SYSTEM) {
|
||||
// EAI_SYSTEM implies an underlying system issue. Error is
|
||||
// specified by |errno|.
|
||||
LOGE("getaddrinfo failed due to system error: errno = %d", GetError());
|
||||
} else {
|
||||
// Error is specified by return value.
|
||||
LOGE("getaddrinfo failed: ret = %d", ret);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// get a socket
|
||||
// Open a socket.
|
||||
socket_fd_ = socket(addr_info->ai_family, addr_info->ai_socktype,
|
||||
addr_info->ai_protocol);
|
||||
if (socket_fd_ < 0) {
|
||||
LOGE("cannot open socket, errno = %d", GetError());
|
||||
LOGE("Cannot open socket: errno = %d", GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// set the socket in non-blocking mode
|
||||
// Set the socket in non-blocking mode.
|
||||
#ifdef _WIN32
|
||||
u_long mode = 1; // Non-blocking mode.
|
||||
if (ioctlsocket(socket_fd_, FIONBIO, &mode) != 0) {
|
||||
@@ -285,7 +326,7 @@ bool HttpSocket::Connect(int timeout_in_ms) {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
int original_flags = fcntl(socket_fd_, F_GETFL, 0);
|
||||
const int original_flags = fcntl(socket_fd_, F_GETFL, 0);
|
||||
if (original_flags == -1) {
|
||||
LOGE("fcntl error, errno = %d", errno);
|
||||
CloseSocket();
|
||||
@@ -301,9 +342,10 @@ bool HttpSocket::Connect(int timeout_in_ms) {
|
||||
// connect to the server
|
||||
ret = connect(socket_fd_, addr_info->ai_addr, addr_info->ai_addrlen);
|
||||
freeaddrinfo(addr_info);
|
||||
addr_info = nullptr;
|
||||
|
||||
if (ret == 0) {
|
||||
// connected right away.
|
||||
// Connected right away.
|
||||
} else {
|
||||
if (GetError() != ERROR_ASYNC_COMPLETE) {
|
||||
// failed right away.
|
||||
@@ -336,6 +378,8 @@ bool HttpSocket::Connect(int timeout_in_ms) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// |BIO_NOCLOSE| prevents closing the socket from being closed when
|
||||
// the BIO is freed.
|
||||
BIO* a_bio = BIO_new_socket(socket_fd_, BIO_NOCLOSE);
|
||||
if (!a_bio) {
|
||||
LOGE("BIO_new_socket error");
|
||||
@@ -354,9 +398,9 @@ bool HttpSocket::Connect(int timeout_in_ms) {
|
||||
CloseSocket();
|
||||
return false;
|
||||
}
|
||||
bool for_read = ssl_err == SSL_ERROR_WANT_READ;
|
||||
const bool for_read = (ssl_err == SSL_ERROR_WANT_READ);
|
||||
if (!SocketWait(socket_fd_, for_read, timeout_in_ms)) {
|
||||
LOGE("cannot connect to %s", domain_name_.c_str());
|
||||
LOGE("Cannot connect securely to %s", domain_name_.c_str());
|
||||
CloseSocket();
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user