diff --git a/CMakeLists.txt b/CMakeLists.txt index ce08ccb5..50cd444f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,8 @@ include (cmake/cpu.cmake) set(SOURCES src/api/NetworkState.cpp src/App.cpp + src/3rdparty/clib-net/deps/buffer/buffer.c + src/3rdparty/clib-net/src/net.c src/net/Client.cpp src/net/Job.cpp src/net/Network.cpp @@ -117,12 +119,7 @@ if (WITH_SSL_TLS) if (OPENSSL_FOUND) include_directories(${OPENSSL_INCLUDE_DIR}) - - include_directories(src/3rdparty/evt-tls) - include_directories(src/3rdparty/evt-tls/api) - set(SOURCES_SSL_TLS - src/3rdparty/evt-tls/src/uv_tls.c - src/3rdparty/evt-tls/src/evt_tls.c) + set(SOURCES_SSL_TLS src/3rdparty/clib-net/src/tls.c) else() message(FATAL_ERROR "OpenSSL NOT found: use `-DWITH_SSL_TLS=OFF` to build without SSL/TLS support") endif() @@ -176,7 +173,7 @@ if (WITH_CC_SERVER) if (MHD_FOUND) include_directories(${MHD_INCLUDE_DIRS}) else() - message(FATAL_ERROR "microhttpd NOT found: use `-DWITH_CC=OFF` to build without CC Server support") + message(FATAL_ERROR "microhttpd NOT found: use `-DWITH_CC_SERVER=OFF` to build without CC Server support") endif() set(SOURCES_CC_SERVER @@ -204,18 +201,24 @@ endif() include_directories(src) include_directories(src/3rdparty) include_directories(${UV_INCLUDE_DIR}) +include_directories(src/3rdparty/clib-net/include) +include_directories(src/3rdparty/clib-net/deps) add_library(xmrig_common STATIC ${SOURCES_COMMON}) add_library(xmrig_os_dependencies STATIC ${SOURCES_OS} ${SOURCES_SYSLOG}) add_library(xmrig_cpuid STATIC ${SOURCES_CPUID}) +if (WITH_SSL_TLS) + add_library(xmrig_tls STATIC ${SOURCES_SSL_TLS}) +endif (WITH_SSL_TLS) + if (WITH_CC_SERVER OR WITH_CC_CLIENT) add_library(xmrig_cc_common STATIC ${SOURCES_CC_COMMON}) endif (WITH_CC_SERVER OR WITH_CC_CLIENT) -add_executable(xmrigMiner ${SOURCES} ${SOURCES_CRYPTO} ${HTTPD_SOURCES} ${SOURCES_CC_CLIENT} ${SOURCES_SSL_TLS} res/app.rc) +add_executable(xmrigMiner ${SOURCES} ${SOURCES_CRYPTO} ${HTTPD_SOURCES} ${SOURCES_CC_CLIENT} res/app.rc) -target_link_libraries(xmrigMiner xmrig_common xmrig_os_dependencies xmrig_cpuid +target_link_libraries(xmrigMiner xmrig_tls xmrig_common xmrig_os_dependencies xmrig_cpuid ${UV_LIBRARIES} ${MHD_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB} ${OPENSSL_LIBRARIES}) if (WITH_CC_CLIENT) @@ -228,7 +231,7 @@ if (WITH_CC_SERVER AND MHD_FOUND) add_library(xmrig_common_cc STATIC ${SOURCES_COMMON}) add_executable(xmrigCCServer ${SOURCES_CC_SERVER} res/app.rc) target_link_libraries(xmrigCCServer - xmrig_common_cc xmrig_os_dependencies xmrig_cpuid xmrig_cc_common + xmrig_common_cc xmrig_os_dependencies xmrig_cpuid xmrig_cc_common xmrig_tls ${UV_LIBRARIES} ${MHD_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB}) set_target_properties(xmrig_common_cc PROPERTIES COMPILE_FLAGS "-DXMRIG_CC_SERVER ${SHARED_FLAGS}") set_target_properties(xmrigCCServer PROPERTIES COMPILE_FLAGS "-DXMRIG_CC_SERVER ${SHARED_FLAGS}") diff --git a/src/api/NetworkState.cpp b/src/api/NetworkState.cpp index bae290d0..374d1e1a 100644 --- a/src/api/NetworkState.cpp +++ b/src/api/NetworkState.cpp @@ -94,7 +94,7 @@ void NetworkState::add(const SubmitResult &result, const char *error) } -void NetworkState::setPool(const char *host, int port, const char *ip) +void NetworkState::setPool(const char *host, int port) { snprintf(pool, sizeof(pool) - 1, "%s:%d", host, port); diff --git a/src/api/NetworkState.h b/src/api/NetworkState.h index d0998074..0aa8c09e 100644 --- a/src/api/NetworkState.h +++ b/src/api/NetworkState.h @@ -41,7 +41,7 @@ public: uint32_t avgTime() const; uint32_t latency() const; void add(const SubmitResult &result, const char *error); - void setPool(const char *host, int port, const char *ip); + void setPool(const char *host, int port); void stop(); char pool[256]; diff --git a/src/net/Client.cpp b/src/net/Client.cpp index 8e8ebcfd..062997c3 100644 --- a/src/net/Client.cpp +++ b/src/net/Client.cpp @@ -5,6 +5,7 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2016-2017 XMRig + * Copyright 2018- BenDr0id * * * This program is free software: you can redistribute it and/or modify @@ -23,15 +24,13 @@ #include #include -#include #include #include - +#include #include "interfaces/IClientListener.h" #include "log/Log.h" #include "net/Client.h" -#include "net/Url.h" #include "rapidjson/document.h" #include "rapidjson/error/en.h" #include "rapidjson/stringbuffer.h" @@ -61,20 +60,8 @@ Client::Client(int id, const char *agent, IClientListener *listener) : m_retryPause(5000), m_failures(0), m_recvBufPos(0), - m_state(UnconnectedState), - m_expire(0), - m_stream(nullptr), - m_socket(nullptr) + m_expire(0) { - memset(m_ip, 0, sizeof(m_ip)); - memset(&m_hints, 0, sizeof(m_hints)); - - m_resolver.data = this; - - m_hints.ai_family = PF_INET; - m_hints.ai_socktype = SOCK_STREAM; - m_hints.ai_protocol = IPPROTO_TCP; - m_recvBuf.base = m_buf; m_recvBuf.len = sizeof(m_buf); @@ -87,13 +74,9 @@ Client::Client(int id, const char *agent, IClientListener *listener) : Client::~Client() { - delete m_socket; -} - - -void Client::connect() -{ - resolve(m_url.host()); + if (m_net) { + net_free(m_net); + } } @@ -105,7 +88,7 @@ void Client::connect() void Client::connect(const Url *url) { setUrl(url); - resolve(m_url.host()); + connect(); } @@ -138,13 +121,11 @@ void Client::tick(uint64_t now) return; } - if (m_state == ConnectedState) { + if (m_net) { LOG_DEBUG_ERR("[%s:%u] timeout", m_url.host(), m_url.port()); - close(); + reconnect(); } - - - if (m_state == ConnectingState) { + else { connect(); } } @@ -247,41 +228,15 @@ bool Client::parseLogin(const rapidjson::Value &result, int *code) return parseJob(result["job"], code); } - -int Client::resolve(const char *host) -{ - setState(HostLookupState); - - m_expire = 0; - m_recvBufPos = 0; - - if (m_failures == -1) { - m_failures = 0; - } - - const int r = uv_getaddrinfo(uv_default_loop(), &m_resolver, Client::onResolved, host, NULL, &m_hints); - if (r) { - if (!m_quiet) { - LOG_ERR("[%s:%u] getaddrinfo error: \"%s\"", host, m_url.port(), uv_strerror(r)); - } - return 1; - } - - return 0; -} - - int64_t Client::send(size_t size) { - LOG_DEBUG("[%s:%u] send (%d bytes): \"%s\"", m_url.host(), m_url.port(), size, m_sendBuf); - if (state() != ConnectedState || !uv_is_writable(m_stream)) { - LOG_DEBUG_ERR("[%s:%u] send failed, invalid state: %d", m_url.host(), m_url.port(), m_state); + LOG_DEBUG("[%s:%u] send (%d bytes): \"%s\"", m_url.host(), m_url.port(), size, buf); + if (!m_net) { + LOG_DEBUG_ERR("[%s:%u] send failed", m_url.host(), m_url.port()); return -1; } - uv_buf_t buf = uv_buf_init(m_sendBuf, (unsigned int) size); - - if (uv_try_write(m_stream, &buf, 1) < 0) { + if (net_write2(m_net, m_sendBuf, static_cast(size)) < 0) { close(); return -1; } @@ -293,42 +248,93 @@ int64_t Client::send(size_t size) void Client::close() { - if (m_state == UnconnectedState || m_state == ClosingState || !m_socket) { + if (m_net) { + auto client = getClient(m_net->data); + + net_free(m_net); + + m_net = nullptr; + + client->reconnect(); + } +} + + +void Client::connect() +{ + m_net = net_new(const_cast(m_url.host()), m_url.port()); + m_net->data = this; + m_net->conn_cb = Client::onConnect; + m_net->read_cb = Client::onRead; + m_net->error_cb = Client::onError; + +#ifndef XMRIG_NO_SSL_TLS + if (m_url.isTls()) { + tls_ctx* tls_ctx = tls_ctx_new(); + net_set_tls(m_net, tls_ctx); + } +#endif + + net_connect(m_net); +} + +void Client::onRead(net_t *net, size_t size, char *buf) +{ + auto client = getClient(net->data); + + if (size < 0) { + if (size != UV_EOF && !client->m_quiet) { + LOG_ERR("[%s:%u] read error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror((int) size)); + } + + return client->close(); + } + + client->m_recvBufPos += size; + + char* end; + char* start = buf; + size_t remaining = client->m_recvBufPos; + + while ((end = static_cast(memchr(start, '\n', remaining))) != nullptr) { + end++; + size_t len = end - start; + client->parse(start, len); + + remaining -= len; + start = end; + } + + if (remaining == 0) { + client->m_recvBufPos = 0; return; } - setState(ClosingState); + if (start == buf) { + return; + } - if (uv_is_closing(reinterpret_cast(m_socket)) == 0) { - uv_close(reinterpret_cast(m_socket), Client::onClose); + memcpy(buf, start, remaining); + client->m_recvBufPos = remaining; +} + +void Client::onConnect(net_t *net) { + auto client = getClient(net->data); + client->login(); +} + +void Client::onError(net_t *net, int err, char *errStr) +{ + if (net) { + auto client = getClient(net->data); + if (!client->m_quiet) { + LOG_ERR("[%s:%u] error: \"%s\"", client->m_url.host(), client->m_url.port(), errStr); + } + + client->close(); } } - -void Client::connect(struct sockaddr *addr) -{ - setState(ConnectingState); - - reinterpret_cast(addr)->sin_port = htons(m_url.port()); - delete m_socket; - - uv_connect_t *req = new uv_connect_t; - req->data = this; - - m_socket = new uv_tcp_t; - m_socket->data = this; - - uv_tcp_init(uv_default_loop(), m_socket); - uv_tcp_nodelay(m_socket, 1); - -# ifndef WIN32 - uv_tcp_keepalive(m_socket, 1, 60); -# endif - - uv_tcp_connect(req, m_socket, reinterpret_cast(addr), Client::onConnect); -} - - void Client::login() { m_results.clear(); @@ -480,9 +486,7 @@ void Client::ping() } -void Client::reconnect() -{ - setState(ConnectingState); +void Client::reconnect() { # ifndef XMRIG_PROXY_PROJECT if (m_url.isKeepAlive()) { @@ -500,19 +504,6 @@ void Client::reconnect() m_expire = uv_now(uv_default_loop()) + m_retryPause; } - -void Client::setState(SocketState state) -{ - LOG_DEBUG("[%s:%u] state: %d", m_url.host(), m_url.port(), state); - - if (m_state == state) { - return; - } - - m_state = state; -} - - void Client::startTimeout() { m_expire = 0; @@ -525,127 +516,3 @@ void Client::startTimeout() uv_timer_start(&m_keepAliveTimer, [](uv_timer_t *handle) { getClient(handle->data)->ping(); }, kKeepAliveTimeout, 0); # endif } - - -void Client::onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) -{ - auto client = getClient(handle->data); - - buf->base = &client->m_recvBuf.base[client->m_recvBufPos]; - buf->len = client->m_recvBuf.len - client->m_recvBufPos; -} - - -void Client::onClose(uv_handle_t *handle) -{ - auto client = getClient(handle->data); - - delete client->m_socket; - - client->m_stream = nullptr; - client->m_socket = nullptr; - client->setState(UnconnectedState); - - client->reconnect(); -} - - -void Client::onConnect(uv_connect_t *req, int status) -{ - auto client = getClient(req->data); - if (status < 0) { - if (!client->m_quiet) { - LOG_ERR("[%s:%u] connect error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror(status)); - } - - delete req; - client->close(); - return; - } - - client->m_stream = static_cast(req->handle); - client->m_stream->data = req->data; - client->setState(ConnectedState); - - uv_read_start(client->m_stream, Client::onAllocBuffer, Client::onRead); - delete req; - - client->login(); -} - - -void Client::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) -{ - auto client = getClient(stream->data); - if (nread < 0) { - if (nread != UV_EOF && !client->m_quiet) { - LOG_ERR("[%s:%u] read error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror((int) nread)); - } - - return client->close(); - } - - if ((size_t) nread > (sizeof(m_buf) - 8 - client->m_recvBufPos)) { - return client->close(); - } - - client->m_recvBufPos += nread; - - char* end; - char* start = buf->base; - size_t remaining = client->m_recvBufPos; - - while ((end = static_cast(memchr(start, '\n', remaining))) != nullptr) { - end++; - size_t len = end - start; - client->parse(start, len); - - remaining -= len; - start = end; - } - - if (remaining == 0) { - client->m_recvBufPos = 0; - return; - } - - if (start == buf->base) { - return; - } - - memcpy(buf->base, start, remaining); - client->m_recvBufPos = remaining; -} - - -void Client::onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res) -{ - auto client = getClient(req->data); - if (status < 0) { - LOG_ERR("[%s:%u] DNS error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror(status)); - return client->reconnect(); - } - - addrinfo *ptr = res; - std::vector ipv4; - - while (ptr != nullptr) { - if (ptr->ai_family == AF_INET) { - ipv4.push_back(ptr); - } - - ptr = ptr->ai_next; - } - - if (ipv4.empty()) { - LOG_ERR("[%s:%u] DNS error: \"No IPv4 records found\"", client->m_url.host(), client->m_url.port()); - return client->reconnect(); - } - - ptr = ipv4[rand() % ipv4.size()]; - - uv_ip4_name(reinterpret_cast(ptr->ai_addr), client->m_ip, 16); - - client->connect(ptr->ai_addr); - uv_freeaddrinfo(res); -} diff --git a/src/net/Client.h b/src/net/Client.h index f66f079c..00a90055 100644 --- a/src/net/Client.h +++ b/src/net/Client.h @@ -5,6 +5,7 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2016-2017 XMRig + * Copyright 2018- BenDr0id * * * This program is free software: you can redistribute it and/or modify @@ -35,6 +36,14 @@ #include "net/Url.h" #include "rapidjson/fwd.h" +extern "C" +{ +#include "net.h" + +#ifndef XMRIG_NO_SSL_TLS +#include "tls.h" +#endif +} class IClientListener; class JobResult; @@ -43,14 +52,6 @@ class JobResult; class Client { public: - enum SocketState { - UnconnectedState, - HostLookupState, - ConnectingState, - ConnectedState, - ClosingState - }; - constexpr static int kResponseTimeout = 20 * 1000; constexpr static int kKeepAliveTimeout = 60 * 1000; @@ -64,12 +65,9 @@ public: void setUrl(const Url *url); void tick(uint64_t now); - inline bool isReady() const { return m_state == ConnectedState && m_failures == 0; } inline const char *host() const { return m_url.host(); } - inline const char *ip() const { return m_ip; } inline const Job &job() const { return m_job; } inline int id() const { return m_id; } - inline SocketState state() const { return m_state; } inline uint16_t port() const { return m_url.port(); } inline void setQuiet(bool quiet) { m_quiet = quiet; } inline void setRetryPause(int ms) { m_retryPause = ms; } @@ -78,31 +76,24 @@ private: bool isCriticalError(const char *message); bool parseJob(const rapidjson::Value ¶ms, int *code); bool parseLogin(const rapidjson::Value &result, int *code); - int resolve(const char *host); int64_t send(size_t size); void close(); - void connect(struct sockaddr *addr); void login(); void parse(char *line, size_t len); void parseNotification(const char *method, const rapidjson::Value ¶ms, const rapidjson::Value &error); void parseResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error); void ping(); void reconnect(); - void setState(SocketState state); void startTimeout(); - static void onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf); - static void onClose(uv_handle_t *handle); - static void onConnect(uv_connect_t *req, int status); - static void onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); - static void onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res); + static void onRead(net_t *net, size_t read, char *buf); + static void onConnect(net_t *net); + static void onError(net_t *net, int err, char *errStr); static inline Client *getClient(void *data) { return static_cast(data); } - addrinfo m_hints; bool m_quiet; char m_buf[2048]; - char m_ip[17]; char m_rpcId[64]; char m_sendBuf[768]; const char *m_agent; @@ -112,15 +103,13 @@ private: int64_t m_failures; Job m_job; size_t m_recvBufPos; - SocketState m_state; static int64_t m_sequence; std::map m_results; uint64_t m_expire; Url m_url; uv_buf_t m_recvBuf; - uv_getaddrinfo_t m_resolver; - uv_stream_t *m_stream; - uv_tcp_t *m_socket; + + net_t* m_net; # ifndef XMRIG_PROXY_PROJECT uv_timer_t m_keepAliveTimer; diff --git a/src/net/Network.cpp b/src/net/Network.cpp index 60fc91a2..af21d0ad 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -56,6 +56,10 @@ Network::Network(const Options *options) : const std::vector &pools = options->pools(); +#ifndef XMRIG_NO_SSL_TLS + ssl_init(); +#endif + if (pools.size() > 1) { m_strategy = new FailoverStrategy(pools, Platform::userAgent(), this); } @@ -76,6 +80,9 @@ Network::Network(const Options *options) : Network::~Network() { +#ifndef XMRIG_NO_SSL_TLS + ssl_destroy(); +#endif } @@ -102,9 +109,8 @@ void Network::onActive(Client *client) return; } - m_state.setPool(client->host(), client->port(), client->ip()); - - LOG_INFO(m_options->colors() ? "\x1B[01;37muse pool \x1B[01;36m%s:%d \x1B[01;30m%s" : "use pool %s:%d %s", client->host(), client->port(), client->ip()); + m_state.setPool(client->host(), client->port()); + LOG_INFO(m_options->colors() ? "\x1B[01;37muse pool \x1B[01;36m%s:%d" : "use pool %s:%d", client->host(), client->port()); } diff --git a/src/net/Url.h b/src/net/Url.h index ee588c25..92951900 100644 --- a/src/net/Url.h +++ b/src/net/Url.h @@ -37,7 +37,7 @@ public: Url(); Url(const char *url); - Url(const char *host, uint16_t port, const char *user = nullptr, const char *password = nullptr, bool tls = false, bool keepAlive = false, bool nicehash = false ); + Url(const char *host, uint16_t port, const char *user = nullptr, const char *password = nullptr, bool tls = false, bool keepAlive = false, bool nicehash = false ); ~Url(); inline bool isTls() const { return m_tls; } diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp index 3f795190..ad64a8e5 100644 --- a/src/net/strategies/DonateStrategy.cpp +++ b/src/net/strategies/DonateStrategy.cpp @@ -49,7 +49,11 @@ DonateStrategy::DonateStrategy(const char *agent, IStrategyListener *listener) : keccak(reinterpret_cast(user), static_cast(strlen(user)), hash, sizeof(hash)); Job::toHex(hash, 32, userId); - Url *url = new Url("donate.graef.in", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 80 : 443, userId, nullptr, false, true); +#ifndef XMRIG_NO_SSL_TLS + Url *url = new Url("donate.graef.in", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 8080 : 8081, userId, nullptr, true, false, true); +#else + Url *url = new Url("donate.graef.in", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 80 : 443, userId, nullptr, false, false, true); +#endif m_client = new Client(-1, agent, this); m_client->setUrl(url);