Merge "Implement HttpSocket for Windows."
This commit is contained in:
@@ -7,18 +7,27 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <netdb.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.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/bio.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
|
|
||||||
@@ -117,6 +126,35 @@ bool SocketWait(int fd, bool for_read, int timeout_in_ms) {
|
|||||||
return true;
|
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
|
} // namespace
|
||||||
|
|
||||||
// Parses the URL and extracts all relevant information.
|
// Parses the URL and extracts all relevant information.
|
||||||
@@ -181,7 +219,11 @@ HttpSocket::~HttpSocket() { CloseSocket(); }
|
|||||||
|
|
||||||
void HttpSocket::CloseSocket() {
|
void HttpSocket::CloseSocket() {
|
||||||
if (socket_fd_ != -1) {
|
if (socket_fd_ != -1) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
closesocket(socket_fd_);
|
||||||
|
#else
|
||||||
close(socket_fd_);
|
close(socket_fd_);
|
||||||
|
#endif
|
||||||
socket_fd_ = -1;
|
socket_fd_ = -1;
|
||||||
}
|
}
|
||||||
if (ssl_) {
|
if (ssl_) {
|
||||||
@@ -199,6 +241,19 @@ bool HttpSocket::Connect(int timeout_in_ms) {
|
|||||||
return false;
|
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
|
// lookup the server IP
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
memset(&hints, 0, sizeof(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,
|
socket_fd_ = socket(addr_info->ai_family, addr_info->ai_socktype,
|
||||||
addr_info->ai_protocol);
|
addr_info->ai_protocol);
|
||||||
if (socket_fd_ < 0) {
|
if (socket_fd_ < 0) {
|
||||||
LOGE("cannot open socket, errno = %d", errno);
|
LOGE("cannot open socket, errno = %d", GetError());
|
||||||
return false;
|
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) {
|
||||||
|
LOGE("ioctlsocket error, wsa error = %d", WSAGetLastError());
|
||||||
|
CloseSocket();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
int original_flags = fcntl(socket_fd_, F_GETFL, 0);
|
int original_flags = fcntl(socket_fd_, F_GETFL, 0);
|
||||||
if (original_flags == -1) {
|
if (original_flags == -1) {
|
||||||
LOGE("fcntl error, errno = %d", errno);
|
LOGE("fcntl error, errno = %d", errno);
|
||||||
@@ -234,6 +297,7 @@ bool HttpSocket::Connect(int timeout_in_ms) {
|
|||||||
CloseSocket();
|
CloseSocket();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// connect to the server
|
// connect to the server
|
||||||
ret = connect(socket_fd_, addr_info->ai_addr, addr_info->ai_addrlen);
|
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) {
|
if (ret == 0) {
|
||||||
// connected right away.
|
// connected right away.
|
||||||
} else {
|
} else {
|
||||||
if (errno != EINPROGRESS) {
|
if (GetError() != ERROR_ASYNC_COMPLETE) {
|
||||||
// failed right away.
|
// 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();
|
CloseSocket();
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
@@ -320,7 +384,7 @@ int HttpSocket::Read(char* data, int len, int timeout_in_ms) {
|
|||||||
return -1;
|
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;
|
int read;
|
||||||
if (secure_connect_) {
|
if (secure_connect_) {
|
||||||
read = SSL_read(ssl_, data, to_read);
|
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);
|
int ssl_error = SSL_get_error(ssl_, read);
|
||||||
|
|
||||||
if (ssl_error == SSL_ERROR_ZERO_RETURN ||
|
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.
|
// The connection has been closed. No more data.
|
||||||
break;
|
break;
|
||||||
} else if (IsRetryableSslError(ssl_error)) {
|
} 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.
|
// Unrecoverable error. Log and abort.
|
||||||
LOGE("SSL_read returned %d, LibSSL Error = %d", read, ssl_error);
|
LOGE("SSL_read returned %d, LibSSL Error = %d", read, ssl_error);
|
||||||
if (ssl_error == SSL_ERROR_SYSCALL) {
|
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);
|
ERR_print_errors_cb(LogBoringSslError, NULL);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -359,7 +423,8 @@ int HttpSocket::Read(char* data, int len, int timeout_in_ms) {
|
|||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
// Log the error received
|
// 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;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,7 +462,7 @@ int HttpSocket::Write(const char* data, int len, int timeout_in_ms) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOGE("send returned %d, errno = %d", sent, errno);
|
LOGE("send returned %d, errno = %d", sent, GetError());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user