Source release 16.3.0

This commit is contained in:
John W. Bruce
2020-07-24 14:30:03 -07:00
parent b830b1d1fb
commit 160df9f57a
74 changed files with 4632 additions and 2561 deletions

View File

@@ -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;
}