Added HttpsClient.
This commit is contained in:
parent
6812d22d63
commit
c823c54f9b
5 changed files with 272 additions and 20 deletions
|
@ -13,6 +13,10 @@ if (WITH_TLS)
|
||||||
if (OPENSSL_FOUND)
|
if (OPENSSL_FOUND)
|
||||||
set(TLS_SOURCES src/base/net/stratum/Tls.h src/base/net/stratum/Tls.cpp)
|
set(TLS_SOURCES src/base/net/stratum/Tls.h src/base/net/stratum/Tls.cpp)
|
||||||
include_directories(${OPENSSL_INCLUDE_DIR})
|
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||||
|
|
||||||
|
if (WITH_HTTP)
|
||||||
|
set(TLS_SOURCES ${TLS_SOURCES} src/base/net/http/HttpsClient.h src/base/net/http/HttpsClient.cpp)
|
||||||
|
endif()
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "OpenSSL NOT found: use `-DWITH_TLS=OFF` to build without TLS support")
|
message(FATAL_ERROR "OpenSSL NOT found: use `-DWITH_TLS=OFF` to build without TLS support")
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -43,9 +43,9 @@ static const char *kCRLF = "\r\n";
|
||||||
class WriteBaton : public Baton<uv_write_t>
|
class WriteBaton : public Baton<uv_write_t>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
inline WriteBaton(const std::stringstream &ss, std::string &&body) :
|
inline WriteBaton(const std::string &header, std::string &&body) :
|
||||||
m_body(body),
|
m_body(body),
|
||||||
m_header(ss.str())
|
m_header(header)
|
||||||
{
|
{
|
||||||
bufs[0].len = m_header.size();
|
bufs[0].len = m_header.size();
|
||||||
bufs[0].base = const_cast<char *>(m_header.c_str());
|
bufs[0].base = const_cast<char *>(m_header.c_str());
|
||||||
|
@ -77,9 +77,9 @@ private:
|
||||||
} // namespace xmrig
|
} // namespace xmrig
|
||||||
|
|
||||||
|
|
||||||
xmrig::HttpClient::HttpClient(const String &host, uint16_t port, int method, const String &url, IHttpListener *listener, const char *data, size_t size) :
|
xmrig::HttpClient::HttpClient(int method, const String &url, IHttpListener *listener, const char *data, size_t size) :
|
||||||
HttpContext(HTTP_RESPONSE, listener),
|
HttpContext(HTTP_RESPONSE, listener),
|
||||||
m_port(port)
|
m_port(0)
|
||||||
{
|
{
|
||||||
this->method = method;
|
this->method = method;
|
||||||
this->url = url;
|
this->url = url;
|
||||||
|
@ -89,8 +89,6 @@ xmrig::HttpClient::HttpClient(const String &host, uint16_t port, int method, con
|
||||||
}
|
}
|
||||||
|
|
||||||
m_dns = new Dns(this);
|
m_dns = new Dns(this);
|
||||||
|
|
||||||
status = m_dns->resolve(host);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -100,6 +98,20 @@ xmrig::HttpClient::~HttpClient()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool xmrig::HttpClient::connect(const String &host, uint16_t port)
|
||||||
|
{
|
||||||
|
m_port = port;
|
||||||
|
|
||||||
|
return m_dns->resolve(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const xmrig::String &xmrig::HttpClient::host() const
|
||||||
|
{
|
||||||
|
return m_dns->host();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void xmrig::HttpClient::onResolved(const Dns &dns, int status)
|
void xmrig::HttpClient::onResolved(const Dns &dns, int status)
|
||||||
{
|
{
|
||||||
this->status = status;
|
this->status = status;
|
||||||
|
@ -119,7 +131,7 @@ void xmrig::HttpClient::onResolved(const Dns &dns, int status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void xmrig::HttpClient::send()
|
void xmrig::HttpClient::handshake()
|
||||||
{
|
{
|
||||||
headers.insert({ "Host", m_dns->host().data() });
|
headers.insert({ "Host", m_dns->host().data() });
|
||||||
headers.insert({ "Connection", "close" });
|
headers.insert({ "Connection", "close" });
|
||||||
|
@ -140,7 +152,21 @@ void xmrig::HttpClient::send()
|
||||||
|
|
||||||
headers.clear();
|
headers.clear();
|
||||||
|
|
||||||
WriteBaton *baton = new WriteBaton(ss, std::move(body));
|
write(ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void xmrig::HttpClient::read(const char *data, size_t size)
|
||||||
|
{
|
||||||
|
if (parse(data, size) < size) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void xmrig::HttpClient::write(const std::string &header)
|
||||||
|
{
|
||||||
|
WriteBaton *baton = new WriteBaton(header, std::move(body));
|
||||||
uv_write(&baton->req, stream(), baton->bufs, baton->count(), WriteBaton::onWrite);
|
uv_write(&baton->req, stream(), baton->bufs, baton->count(), WriteBaton::onWrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,12 +203,7 @@ void xmrig::HttpClient::onConnect(uv_connect_t *req, int status)
|
||||||
HttpClient *client = static_cast<HttpClient*>(tcp->data);
|
HttpClient *client = static_cast<HttpClient*>(tcp->data);
|
||||||
|
|
||||||
if (nread >= 0) {
|
if (nread >= 0) {
|
||||||
const size_t size = static_cast<size_t>(nread);
|
client->read(buf->base, static_cast<size_t>(nread));
|
||||||
const size_t parsed = client->parse(buf->base, size);
|
|
||||||
|
|
||||||
if (parsed < size) {
|
|
||||||
client->close();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (nread != UV_EOF) {
|
if (nread != UV_EOF) {
|
||||||
LOG_ERR("[%s:%d] read error: \"%s\"", client->m_dns->host().data(), client->m_port, uv_strerror(static_cast<int>(nread)));
|
LOG_ERR("[%s:%d] read error: \"%s\"", client->m_dns->host().data(), client->m_port, uv_strerror(static_cast<int>(nread)));
|
||||||
|
@ -194,5 +215,5 @@ void xmrig::HttpClient::onConnect(uv_connect_t *req, int status)
|
||||||
delete [] buf->base;
|
delete [] buf->base;
|
||||||
});
|
});
|
||||||
|
|
||||||
client->send();
|
client->handshake();
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,15 +41,22 @@ class String;
|
||||||
class HttpClient : public HttpContext, public IDnsListener
|
class HttpClient : public HttpContext, public IDnsListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HttpClient(const String &host, uint16_t port, int method, const String &url, IHttpListener *listener, const char *data = nullptr, size_t size = 0);
|
HttpClient(int method, const String &url, IHttpListener *listener, const char *data = nullptr, size_t size = 0);
|
||||||
~HttpClient();
|
~HttpClient() override;
|
||||||
|
|
||||||
|
inline uint16_t port() const { return m_port; }
|
||||||
|
|
||||||
|
bool connect(const String &host, uint16_t port);
|
||||||
|
const String &host() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void onResolved(const Dns &dns, int status);
|
void onResolved(const Dns &dns, int status) override;
|
||||||
|
|
||||||
|
virtual void handshake();
|
||||||
|
virtual void read(const char *data, size_t size);
|
||||||
|
virtual void write(const std::string &header);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void send();
|
|
||||||
|
|
||||||
static void onConnect(uv_connect_t *req, int status);
|
static void onConnect(uv_connect_t *req, int status);
|
||||||
|
|
||||||
Dns *m_dns;
|
Dns *m_dns;
|
||||||
|
|
150
src/base/net/http/HttpsClient.cpp
Normal file
150
src/base/net/http/HttpsClient.cpp
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
/* XMRig
|
||||||
|
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||||
|
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||||
|
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||||
|
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||||
|
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||||
|
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
||||||
|
* Copyright 2014-2019 heapwolf <https://github.com/heapwolf>
|
||||||
|
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
|
||||||
|
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <uv.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "base/net/http/HttpsClient.h"
|
||||||
|
#include "base/tools/String.h"
|
||||||
|
|
||||||
|
|
||||||
|
xmrig::HttpsClient::HttpsClient(int method, const String &url, IHttpListener *listener, const char *data, size_t size) :
|
||||||
|
HttpClient(method, url, listener, data, size),
|
||||||
|
m_ready(false),
|
||||||
|
m_buf(),
|
||||||
|
m_ssl(nullptr)
|
||||||
|
{
|
||||||
|
m_ctx = SSL_CTX_new(SSLv23_method());
|
||||||
|
assert(m_ctx != nullptr);
|
||||||
|
|
||||||
|
if (!m_ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_writeBio = BIO_new(BIO_s_mem());
|
||||||
|
m_readBio = BIO_new(BIO_s_mem());
|
||||||
|
SSL_CTX_set_options(m_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
xmrig::HttpsClient::~HttpsClient()
|
||||||
|
{
|
||||||
|
if (m_ctx) {
|
||||||
|
SSL_CTX_free(m_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_ssl) {
|
||||||
|
SSL_free(m_ssl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void xmrig::HttpsClient::handshake()
|
||||||
|
{
|
||||||
|
m_ssl = SSL_new(m_ctx);
|
||||||
|
assert(m_ssl != nullptr);
|
||||||
|
|
||||||
|
if (!m_ssl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SSL_set_connect_state(m_ssl);
|
||||||
|
SSL_set_bio(m_ssl, m_readBio, m_writeBio);
|
||||||
|
SSL_set_tlsext_host_name(m_ssl, host().data());
|
||||||
|
|
||||||
|
SSL_do_handshake(m_ssl);
|
||||||
|
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void xmrig::HttpsClient::read(const char *data, size_t size)
|
||||||
|
{
|
||||||
|
BIO_write(m_readBio, data, size);
|
||||||
|
|
||||||
|
if (!SSL_is_init_finished(m_ssl)) {
|
||||||
|
const int rc = SSL_connect(m_ssl);
|
||||||
|
|
||||||
|
if (rc < 0 && SSL_get_error(m_ssl, rc) == SSL_ERROR_WANT_READ) {
|
||||||
|
flush();
|
||||||
|
} else if (rc == 1) {
|
||||||
|
X509 *cert = SSL_get_peer_certificate(m_ssl);
|
||||||
|
if (!verify(cert)) {
|
||||||
|
X509_free(cert);
|
||||||
|
return close();
|
||||||
|
}
|
||||||
|
|
||||||
|
X509_free(cert);
|
||||||
|
m_ready = true;
|
||||||
|
|
||||||
|
HttpClient::handshake();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bytes_read = 0;
|
||||||
|
while ((bytes_read = SSL_read(m_ssl, m_buf, sizeof(m_buf))) > 0) {
|
||||||
|
HttpClient::read(m_buf, static_cast<size_t>(bytes_read));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void xmrig::HttpsClient::write(const std::string &header)
|
||||||
|
{
|
||||||
|
SSL_write(m_ssl, (header + body).c_str(), header.size() + body.size());
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool xmrig::HttpsClient::verify(X509 *cert) const
|
||||||
|
{
|
||||||
|
return cert != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void xmrig::HttpsClient::flush()
|
||||||
|
{
|
||||||
|
uv_buf_t buf;
|
||||||
|
buf.len = BIO_get_mem_data(m_writeBio, &buf.base);
|
||||||
|
|
||||||
|
if (buf.len == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
if (uv_is_writable(stream())) {
|
||||||
|
result = uv_try_write(stream(), &buf, 1) == buf.len;
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) BIO_reset(m_writeBio);
|
||||||
|
}
|
70
src/base/net/http/HttpsClient.h
Normal file
70
src/base/net/http/HttpsClient.h
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/* XMRig
|
||||||
|
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||||
|
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||||
|
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||||
|
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||||
|
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||||
|
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
||||||
|
* Copyright 2014-2019 heapwolf <https://github.com/heapwolf>
|
||||||
|
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
|
||||||
|
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef XMRIG_HTTPSCLIENT_H
|
||||||
|
#define XMRIG_HTTPSCLIENT_H
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bio_st BIO;
|
||||||
|
typedef struct ssl_ctx_st SSL_CTX;
|
||||||
|
typedef struct ssl_st SSL;
|
||||||
|
typedef struct x509_st X509;
|
||||||
|
|
||||||
|
|
||||||
|
#include "base/net/http/HttpClient.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace xmrig {
|
||||||
|
|
||||||
|
|
||||||
|
class HttpsClient : public HttpClient
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HttpsClient(int method, const String &url, IHttpListener *listener, const char *data = nullptr, size_t size = 0);
|
||||||
|
~HttpsClient() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void handshake() override;
|
||||||
|
void read(const char *data, size_t size) override;
|
||||||
|
void write(const std::string &header) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool verify(X509 *cert) const;
|
||||||
|
void flush();
|
||||||
|
|
||||||
|
BIO *m_readBio;
|
||||||
|
BIO *m_writeBio;
|
||||||
|
bool m_ready;
|
||||||
|
char m_buf[1024 * 2];
|
||||||
|
SSL *m_ssl;
|
||||||
|
SSL_CTX *m_ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace xmrig
|
||||||
|
|
||||||
|
|
||||||
|
#endif // XMRIG_HTTPSCLIENT_H
|
Loading…
Add table
Add a link
Reference in a new issue