Merge "Implement HttpSocket for Windows."

This commit is contained in:
John Bruce
2019-01-24 05:24:49 +00:00
committed by Android (Google) Code Review

View File

@@ -7,18 +7,27 @@
#include <cstring>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#ifdef _WIN32
# include "winsock2.h"
# include "ws2tcpip.h"
# define ERROR_ASYNC_COMPLETE WSAEWOULDBLOCK
#else
# include <netdb.h>
# include <netinet/in.h>
# include <sys/socket.h>
# include <unistd.h>
# define ERROR_ASYNC_COMPLETE EINPROGRESS
#endif
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/x509.h>
#include "log.h"
#include "platform.h"
namespace wvcdm {
@@ -117,6 +126,35 @@ bool SocketWait(int fd, bool for_read, int timeout_in_ms) {
return true;
}
int GetError() {
#ifdef _WIN32
return WSAGetLastError();
#else
return errno;
#endif
}
void ClearError() {
#ifdef _WIN32
WSASetLastError(0);
#else
errno = 0;
#endif
}
const char* GetErrorString() {
#ifdef _WIN32
static char buffer[2048];
const int flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
const int code = WSAGetLastError();
if (!FormatMessage(flags, nullptr, code, 0, buffer, sizeof(buffer), nullptr))
return "Unknown error";
return buffer;
#else
return strerror(errno);
#endif
}
} // namespace
// Parses the URL and extracts all relevant information.
@@ -181,7 +219,11 @@ HttpSocket::~HttpSocket() { CloseSocket(); }
void HttpSocket::CloseSocket() {
if (socket_fd_ != -1) {
#ifdef _WIN32
closesocket(socket_fd_);
#else
close(socket_fd_);
#endif
socket_fd_ = -1;
}
if (ssl_) {
@@ -199,6 +241,19 @@ bool HttpSocket::Connect(int timeout_in_ms) {
return false;
}
#ifdef _WIN32
static bool initialized = false;
if (!initialized) {
WSADATA ignored_data;
int err = WSAStartup(MAKEWORD(2, 2), &ignored_data);
if (err != 0) {
LOGE("Error in WSAStartup: %d", err);
return false;
}
initialized = true;
}
#endif
// lookup the server IP
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
@@ -218,11 +273,19 @@ bool HttpSocket::Connect(int timeout_in_ms) {
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", errno);
LOGE("cannot open socket, errno = %d", GetError());
return false;
}
// set the socket in non-blocking mode
#ifdef _WIN32
u_long mode = 1; // Non-blocking mode.
if (ioctlsocket(socket_fd_, FIONBIO, &mode) != 0) {
LOGE("ioctlsocket error, wsa error = %d", WSAGetLastError());
CloseSocket();
return false;
}
#else
int original_flags = fcntl(socket_fd_, F_GETFL, 0);
if (original_flags == -1) {
LOGE("fcntl error, errno = %d", errno);
@@ -234,6 +297,7 @@ bool HttpSocket::Connect(int timeout_in_ms) {
CloseSocket();
return false;
}
#endif
// connect to the server
ret = connect(socket_fd_, addr_info->ai_addr, addr_info->ai_addrlen);
@@ -242,9 +306,9 @@ bool HttpSocket::Connect(int timeout_in_ms) {
if (ret == 0) {
// connected right away.
} else {
if (errno != EINPROGRESS) {
if (GetError() != ERROR_ASYNC_COMPLETE) {
// failed right away.
LOGE("cannot connect to %s, errno = %d", domain_name_.c_str(), errno);
LOGE("cannot connect to %s, errno = %d", domain_name_.c_str(), GetError());
CloseSocket();
return false;
} else {
@@ -320,7 +384,7 @@ int HttpSocket::Read(char* data, int len, int timeout_in_ms) {
return -1;
}
errno = 0; // Reset errno, as we will depend on its value shortly.
ClearError(); // Reset errors, as we will depend on its value shortly.
int read;
if (secure_connect_) {
read = SSL_read(ssl_, data, to_read);
@@ -337,7 +401,7 @@ int HttpSocket::Read(char* data, int len, int timeout_in_ms) {
int ssl_error = SSL_get_error(ssl_, read);
if (ssl_error == SSL_ERROR_ZERO_RETURN ||
(ssl_error == SSL_ERROR_SYSCALL && errno == 0)) {
(ssl_error == SSL_ERROR_SYSCALL && GetError() == 0)) {
// The connection has been closed. No more data.
break;
} else if (IsRetryableSslError(ssl_error)) {
@@ -347,7 +411,7 @@ int HttpSocket::Read(char* data, int len, int timeout_in_ms) {
// Unrecoverable error. Log and abort.
LOGE("SSL_read returned %d, LibSSL Error = %d", read, ssl_error);
if (ssl_error == SSL_ERROR_SYSCALL) {
LOGE(" errno = %d = %s", errno, strerror(errno));
LOGE(" errno = %d = %s", GetError(), GetErrorString());
}
ERR_print_errors_cb(LogBoringSslError, NULL);
return -1;
@@ -359,7 +423,8 @@ int HttpSocket::Read(char* data, int len, int timeout_in_ms) {
break;
} else {
// Log the error received
LOGE("recv returned %d, errno = %d = %s", read, errno, strerror(errno));
LOGE("recv returned %d, errno = %d = %s", read, GetError(),
GetErrorString());
return -1;
}
}
@@ -397,7 +462,7 @@ int HttpSocket::Write(const char* data, int len, int timeout_in_ms) {
return -1;
}
} else {
LOGE("send returned %d, errno = %d", sent, errno);
LOGE("send returned %d, errno = %d", sent, GetError());
return -1;
}
}