Merge "Implement HttpSocket for Windows."
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user