start SSL
This commit is contained in:
+20
-1
@@ -62,6 +62,7 @@ check_function_exists(pselect HAVE_PSELECT)
|
|||||||
check_function_exists(ppoll HAVE_PPOLL)
|
check_function_exists(ppoll HAVE_PPOLL)
|
||||||
check_include_file(linux/serial.h HAVE_LINUX_SERIAL -DHAVE_LINUX_SERIAL=1)
|
check_include_file(linux/serial.h HAVE_LINUX_SERIAL -DHAVE_LINUX_SERIAL=1)
|
||||||
check_include_file(dev/usb/uftdiio.h HAVE_FREEBSD_UFTDI -DHAVE_FREEBSD_UFTDI=1)
|
check_include_file(dev/usb/uftdiio.h HAVE_FREEBSD_UFTDI -DHAVE_FREEBSD_UFTDI=1)
|
||||||
|
|
||||||
check_function_exists(argp_parse HAVE_ARGP)
|
check_function_exists(argp_parse HAVE_ARGP)
|
||||||
if(NOT HAVE_ARGP)
|
if(NOT HAVE_ARGP)
|
||||||
find_library(LIB_ARGP argp)
|
find_library(LIB_ARGP argp)
|
||||||
@@ -77,11 +78,13 @@ if(NOT coverage STREQUAL OFF)
|
|||||||
link_libraries(gcov)
|
link_libraries(gcov)
|
||||||
message(STATUS "coverage enabled")
|
message(STATUS "coverage enabled")
|
||||||
endif(NOT coverage STREQUAL OFF)
|
endif(NOT coverage STREQUAL OFF)
|
||||||
|
|
||||||
option(contrib "disable inclusion of contributed sources." ON)
|
option(contrib "disable inclusion of contributed sources." ON)
|
||||||
if(contrib STREQUAL ON)
|
if(contrib STREQUAL ON)
|
||||||
set(HAVE_CONTRIB ON)
|
set(HAVE_CONTRIB ON)
|
||||||
message(STATUS "contrib enabled")
|
message(STATUS "contrib enabled")
|
||||||
endif(contrib STREQUAL ON)
|
endif(contrib STREQUAL ON)
|
||||||
|
|
||||||
find_library(HAVE_MQTT mosquitto)
|
find_library(HAVE_MQTT mosquitto)
|
||||||
if(HAVE_MQTT)
|
if(HAVE_MQTT)
|
||||||
option(mqtt "disable support for MQTT handling." ON)
|
option(mqtt "disable support for MQTT handling." ON)
|
||||||
@@ -90,7 +93,23 @@ if(HAVE_MQTT)
|
|||||||
else(mqtt STREQUAL ON)
|
else(mqtt STREQUAL ON)
|
||||||
unset(HAVE_MQTT)
|
unset(HAVE_MQTT)
|
||||||
endif(mqtt STREQUAL ON)
|
endif(mqtt STREQUAL ON)
|
||||||
endif(HAVE_MQTT)
|
endif(HAVE_MQTT)
|
||||||
|
|
||||||
|
find_library(HAVE_SSL ssl)
|
||||||
|
find_library(LIB_CRYPTO crypto)
|
||||||
|
if(HAVE_SSL)
|
||||||
|
if(LIB_CRYPTO)
|
||||||
|
option(ssl "disable support for SSL." ON)
|
||||||
|
if(ssl STREQUAL ON)
|
||||||
|
message(STATUS "SSL enabled")
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES} ${HAVE_SSL} ${LIB_CRYPTO}")
|
||||||
|
else(ssl STREQUAL ON)
|
||||||
|
unset(HAVE_SSL)
|
||||||
|
endif(ssl STREQUAL ON)
|
||||||
|
else(LIB_CRYPTO)
|
||||||
|
message(FATAL_ERROR "crypto library not available")
|
||||||
|
endif(LIB_CRYPTO)
|
||||||
|
endif(HAVE_SSL)
|
||||||
|
|
||||||
check_cxx_source_runs("
|
check_cxx_source_runs("
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
/* Defined if MQTT handling is enabled. */
|
/* Defined if MQTT handling is enabled. */
|
||||||
#cmakedefine HAVE_MQTT
|
#cmakedefine HAVE_MQTT
|
||||||
|
|
||||||
|
/* Defined if SSL is enabled. */
|
||||||
|
#cmakedefine HAVE_SSL
|
||||||
|
|
||||||
/* Defined if ppoll() is available. */
|
/* Defined if ppoll() is available. */
|
||||||
#cmakedefine HAVE_PPOLL
|
#cmakedefine HAVE_PPOLL
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ if(HAVE_MQTT)
|
|||||||
set(ebusd_LIBS ${ebusd_LIBS} mosquitto)
|
set(ebusd_LIBS ${ebusd_LIBS} mosquitto)
|
||||||
endif(HAVE_MQTT)
|
endif(HAVE_MQTT)
|
||||||
|
|
||||||
|
if(HAVE_SSL)
|
||||||
|
set(ebusd_LIBS ${ebusd_LIBS} ssl crypto)
|
||||||
|
endif(HAVE_SSL)
|
||||||
|
|
||||||
if(HAVE_CONTRIB)
|
if(HAVE_CONTRIB)
|
||||||
set(ebusd_LIBS ${ebusd_LIBS} ebuscontrib)
|
set(ebusd_LIBS ${ebusd_LIBS} ebuscontrib)
|
||||||
endif(HAVE_CONTRIB)
|
endif(HAVE_CONTRIB)
|
||||||
|
|||||||
+7
-3
@@ -65,7 +65,11 @@ using std::cout;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** the default path of the configuration files. */
|
/** the default path of the configuration files. */
|
||||||
|
#ifdef HAVE_SSL
|
||||||
|
#define CONFIG_PATH "https://cfg.ebusd.eu/"
|
||||||
|
#else
|
||||||
#define CONFIG_PATH "http://cfg.ebusd.eu/"
|
#define CONFIG_PATH "http://cfg.ebusd.eu/"
|
||||||
|
#endif
|
||||||
|
|
||||||
/** the opened PID file, or nullptr. */
|
/** the opened PID file, or nullptr. */
|
||||||
static FILE* pidFile = nullptr;
|
static FILE* pidFile = nullptr;
|
||||||
@@ -189,7 +193,7 @@ static const struct argp_option argpoptions[] = {
|
|||||||
{"latency", O_DEVLAT, "MSEC", 0, "Extra transfer latency in ms [0]", 0 },
|
{"latency", O_DEVLAT, "MSEC", 0, "Extra transfer latency in ms [0]", 0 },
|
||||||
|
|
||||||
{nullptr, 0, nullptr, 0, "Message configuration options:", 2 },
|
{nullptr, 0, nullptr, 0, "Message configuration options:", 2 },
|
||||||
{"configpath", 'c', "PATH", 0, "Read CSV config files from PATH (local folder or HTTP URL) [" CONFIG_PATH
|
{"configpath", 'c', "PATH", 0, "Read CSV config files from PATH (local folder or HTTPS URL) [" CONFIG_PATH
|
||||||
"]", 0 },
|
"]", 0 },
|
||||||
{"scanconfig", 's', "ADDR", OPTION_ARG_OPTIONAL, "Pick CSV config files matching initial scan (ADDR="
|
{"scanconfig", 's', "ADDR", OPTION_ARG_OPTIONAL, "Pick CSV config files matching initial scan (ADDR="
|
||||||
"\"none\" or empty for no initial scan message, \"full\" for full scan, or a single hex address to scan, "
|
"\"none\" or empty for no initial scan message, \"full\" for full scan, or a single hex address to scan, "
|
||||||
@@ -308,7 +312,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// Message configuration options:
|
// Message configuration options:
|
||||||
case 'c': // --configpath=http://cfg.ebusd.eu/
|
case 'c': // --configpath=https://cfg.ebusd.eu/
|
||||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||||
argp_error(state, "invalid configpath");
|
argp_error(state, "invalid configpath");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
@@ -1307,7 +1311,7 @@ int main(int argc, char* argv[]) {
|
|||||||
logError(lf_main, "invalid configPath URL");
|
logError(lf_main, "invalid configPath URL");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (!s_configHttpClient.connect(configHost, configPort, PACKAGE_NAME "/" PACKAGE_VERSION)) {
|
if (!s_configHttpClient.connect(configHost, configPort, proto=="https", PACKAGE_NAME "/" PACKAGE_VERSION)) {
|
||||||
logError(lf_main, "invalid configPath URL");
|
logError(lf_main, "invalid configPath URL");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -41,7 +41,7 @@ struct options {
|
|||||||
bool initialSend; //!< send an initial escape symbol after connecting device
|
bool initialSend; //!< send an initial escape symbol after connecting device
|
||||||
unsigned int extraLatency; //!< extra transfer latency in ms [0 for USB, 10 for IP]
|
unsigned int extraLatency; //!< extra transfer latency in ms [0 for USB, 10 for IP]
|
||||||
|
|
||||||
const char* configPath; //!< path to CSV configuration files [http://cfg.ebusd.eu/]
|
const char* configPath; //!< path to CSV configuration files [https://cfg.ebusd.eu/]
|
||||||
bool scanConfig; //!< pick configuration files matching initial scan
|
bool scanConfig; //!< pick configuration files matching initial scan
|
||||||
/** the initial address to scan for scanconfig
|
/** the initial address to scan for scanconfig
|
||||||
* (@a ESC=none, 0xfe=broadcast ident, @a SYN=full scan, else: single slave address). */
|
* (@a ESC=none, 0xfe=broadcast ident, @a SYN=full scan, else: single slave address). */
|
||||||
|
|||||||
@@ -332,7 +332,13 @@ void MainLoop::run() {
|
|||||||
}
|
}
|
||||||
if (m_runUpdateCheck && !m_shutdown && now > nextCheckRun) {
|
if (m_runUpdateCheck && !m_shutdown && now > nextCheckRun) {
|
||||||
HttpClient client;
|
HttpClient client;
|
||||||
if (!client.connect("upd.ebusd.eu", 80, PACKAGE_NAME "/" PACKAGE_VERSION)) {
|
if (!client.connect("upd.ebusd.eu",
|
||||||
|
#ifdef HAVE_SSL
|
||||||
|
443, true,
|
||||||
|
#else
|
||||||
|
80, false,
|
||||||
|
#endif
|
||||||
|
PACKAGE_NAME "/" PACKAGE_VERSION)) {
|
||||||
logError(lf_main, "update check connect error");
|
logError(lf_main, "update check connect error");
|
||||||
} else {
|
} else {
|
||||||
ostringstream ostr;
|
ostringstream ostr;
|
||||||
|
|||||||
@@ -17,9 +17,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib/utils/httpclient.h"
|
#include "lib/utils/httpclient.h"
|
||||||
|
#include "lib/utils/log.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <csignal>
|
||||||
|
|
||||||
namespace ebusd {
|
namespace ebusd {
|
||||||
|
|
||||||
@@ -28,6 +30,189 @@ using std::ostringstream;
|
|||||||
using std::dec;
|
using std::dec;
|
||||||
using std::hex;
|
using std::hex;
|
||||||
|
|
||||||
|
#ifdef HAVE_SSL
|
||||||
|
|
||||||
|
bool checkError(const char* call) {
|
||||||
|
unsigned long err = ERR_get_error();
|
||||||
|
if (err) {
|
||||||
|
const char *const str = ERR_reason_error_string(err);
|
||||||
|
logError(lf_network, "SSL error %s: %ld=%s", call, err, str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isError(const char* call, bool result) {
|
||||||
|
if (checkError(call)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!result) {
|
||||||
|
logError(lf_network, "SSL error %s: invalid result", call);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isError(const char* call, long result, long expected) {
|
||||||
|
if (checkError(call)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (result!=expected) {
|
||||||
|
logError(lf_network, "SSL error %s: invalid result %d", call, result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SSLSocket::~SSLSocket() {
|
||||||
|
BIO_free_all(m_bio);
|
||||||
|
if (m_ctx) {
|
||||||
|
SSL_CTX_free(m_ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t SSLSocket::send(const char* data, size_t len) {
|
||||||
|
do {
|
||||||
|
size_t part = 0;
|
||||||
|
int res = BIO_write_ex(m_bio, data, len, &part);
|
||||||
|
if (res==1) {
|
||||||
|
return static_cast<signed>(part);
|
||||||
|
}
|
||||||
|
if (!BIO_should_retry(m_bio)) {
|
||||||
|
if (isError("write", true)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
usleep(50000);
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t SSLSocket::recv(char* data, size_t len) {
|
||||||
|
do {
|
||||||
|
size_t part = 0;
|
||||||
|
int res = BIO_read_ex(m_bio, data, len, &part);
|
||||||
|
if (res==1) {
|
||||||
|
return static_cast<signed>(part);
|
||||||
|
}
|
||||||
|
if (!BIO_should_retry(m_bio)) {
|
||||||
|
if (isError("read", true)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
usleep(50000);
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SSLSocket::isValid() {
|
||||||
|
return !BIO_eof(m_bio);
|
||||||
|
}
|
||||||
|
|
||||||
|
SSLSocket* SSLSocket::connect(const string& host, const uint16_t& port, const bool https, int timeout) {
|
||||||
|
BIO *bio = nullptr;
|
||||||
|
SSL_CTX *ctx = nullptr;
|
||||||
|
ostringstream ostr;
|
||||||
|
ostr << host << ':' << static_cast<unsigned>(port);
|
||||||
|
const string hostPort = ostr.str();
|
||||||
|
if (!https) {
|
||||||
|
do {
|
||||||
|
bio = BIO_new_connect(hostPort.c_str());
|
||||||
|
if (isError("connect", bio)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
BIO_set_nbio(bio, 1); // set non-blocking
|
||||||
|
return new SSLSocket(nullptr, bio);
|
||||||
|
} while (false);
|
||||||
|
} else {
|
||||||
|
SSL *ssl = nullptr;
|
||||||
|
do {
|
||||||
|
const SSL_METHOD *method = SSLv23_method();
|
||||||
|
if (isError("method", method)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ctx = SSL_CTX_new(method);
|
||||||
|
if (isError("ctx_new", ctx)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, nullptr);
|
||||||
|
if (isError("verify_loc", SSL_CTX_load_verify_locations(ctx, nullptr, "/etc/ssl/certs"), 1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SSL_CTX_set_verify_depth(ctx, 2);
|
||||||
|
const long flags = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
|
||||||
|
SSL_CTX_set_options(ctx, flags);
|
||||||
|
bio = BIO_new_ssl_connect(ctx);
|
||||||
|
if (isError("new_ssl_connect", bio)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isError("conn_hostname", BIO_set_conn_hostname(bio, hostPort.c_str()), 1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
BIO_set_nbio(bio, 1); // set non-blocking
|
||||||
|
BIO_get_ssl(bio, &ssl);
|
||||||
|
if (isError("get_ssl", ssl)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const char *hostname = host.c_str();
|
||||||
|
if (isError("tlsext_host_name", SSL_set_tlsext_host_name(ssl, hostname), 1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
time_t until = time(nullptr) + (timeout<=0 ? 1 : timeout);
|
||||||
|
long res = BIO_do_connect(bio);
|
||||||
|
while (res != 1 && BIO_should_retry(bio) && time(nullptr)<until) {
|
||||||
|
usleep(50000);
|
||||||
|
res = BIO_do_connect(bio);
|
||||||
|
}
|
||||||
|
if (isError("connect", res, 1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
X509 *cert = SSL_get_peer_certificate(ssl);
|
||||||
|
if (cert) {
|
||||||
|
X509_free(cert);
|
||||||
|
}
|
||||||
|
if (isError("peer_cert", cert)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isError("verify", SSL_get_verify_result(ssl), X509_V_OK)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// check hostname
|
||||||
|
X509_NAME *sname = X509_get_subject_name(cert);
|
||||||
|
if (isError("subject_name", sname)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
char peerName[64];
|
||||||
|
if (isError("extract subject", X509_NAME_get_text_by_NID(sname, NID_commonName, peerName, sizeof(peerName)) > 0)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isError("subject", strcmp(peerName, hostname), 0)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return new SSLSocket(ctx, bio);
|
||||||
|
} while (false);
|
||||||
|
}
|
||||||
|
if (bio) {
|
||||||
|
BIO_free_all(bio);
|
||||||
|
}
|
||||||
|
if (ctx) {
|
||||||
|
SSL_CTX_free(ctx);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpClient::initialize() {
|
||||||
|
SSL_library_init();
|
||||||
|
SSL_load_error_strings();
|
||||||
|
signal(SIGPIPE, SIG_IGN); // needed to avoid SIGPIPE when writing to a closed pipe
|
||||||
|
}
|
||||||
|
#else // HAVE_SSL
|
||||||
|
void HttpClient::initialize() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
#endif // HAVE_SSL
|
||||||
|
|
||||||
bool HttpClient::parseUrl(const string& url, string* proto, string* host, uint16_t* port, string* uri) {
|
bool HttpClient::parseUrl(const string& url, string* proto, string* host, uint16_t* port, string* uri) {
|
||||||
size_t hostPos = url.find("://");
|
size_t hostPos = url.find("://");
|
||||||
if (hostPos == string::npos) {
|
if (hostPos == string::npos) {
|
||||||
@@ -35,9 +220,16 @@ bool HttpClient::parseUrl(const string& url, string* proto, string* host, uint16
|
|||||||
}
|
}
|
||||||
*proto = url.substr(0, hostPos);
|
*proto = url.substr(0, hostPos);
|
||||||
hostPos += 3;
|
hostPos += 3;
|
||||||
|
bool isSsl = *proto == "https";
|
||||||
|
#ifdef HAVE_SSL
|
||||||
|
if (!isSsl && *proto != "http") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (*proto != "http") {
|
if (*proto != "http") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
size_t pos = url.find('/', hostPos);
|
size_t pos = url.find('/', hostPos);
|
||||||
if (pos == hostPos) {
|
if (pos == hostPos) {
|
||||||
return false;
|
return false;
|
||||||
@@ -56,7 +248,7 @@ bool HttpClient::parseUrl(const string& url, string* proto, string* host, uint16
|
|||||||
if (pos == 0) {
|
if (pos == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*port = 80;
|
*port = isSsl ? 443 : 80;
|
||||||
if (pos != string::npos) {
|
if (pos != string::npos) {
|
||||||
char* strEnd = nullptr;
|
char* strEnd = nullptr;
|
||||||
unsigned long value = strtoul(host->c_str()+pos+1, &strEnd, 10);
|
unsigned long value = strtoul(host->c_str()+pos+1, &strEnd, 10);
|
||||||
@@ -69,9 +261,16 @@ bool HttpClient::parseUrl(const string& url, string* proto, string* host, uint16
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HttpClient::connect(const string& host, const uint16_t port, const string& userAgent, const int timeout) {
|
bool HttpClient::connect(const string& host, const uint16_t port, const bool https, const string& userAgent, const int timeout) {
|
||||||
disconnect();
|
disconnect();
|
||||||
m_socket = m_client.connect(host, port, timeout);
|
#ifdef HAVE_SSL
|
||||||
|
m_socket = SSLSocket::connect(host, port, https, timeout);
|
||||||
|
#else
|
||||||
|
if (https) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_socket = TCPSocket::connect(host, port, timeout);
|
||||||
|
#endif
|
||||||
if (!m_socket) {
|
if (!m_socket) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -87,7 +286,7 @@ bool HttpClient::reconnect() {
|
|||||||
if (m_host.empty() || !m_port) {
|
if (m_host.empty() || !m_port) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_socket = m_client.connect(m_host, m_port, m_timeout);
|
m_socket = SocketClass::connect(m_host, m_port, m_timeout);
|
||||||
if (!m_socket) {
|
if (!m_socket) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,11 +19,20 @@
|
|||||||
#ifndef LIB_UTILS_HTTPCLIENT_H_
|
#ifndef LIB_UTILS_HTTPCLIENT_H_
|
||||||
#define LIB_UTILS_HTTPCLIENT_H_
|
#define LIB_UTILS_HTTPCLIENT_H_
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "lib/utils/tcpsocket.h"
|
#include "lib/utils/tcpsocket.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_SSL
|
||||||
|
# include <openssl/ssl.h>
|
||||||
|
# include <openssl/bio.h>
|
||||||
|
# include <openssl/err.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/** typedef for referencing @a sockaddr_in within namespace. */
|
/** typedef for referencing @a sockaddr_in within namespace. */
|
||||||
typedef struct sockaddr_in socketaddress;
|
typedef struct sockaddr_in socketaddress;
|
||||||
@@ -35,6 +44,70 @@ namespace ebusd {
|
|||||||
using std::string;
|
using std::string;
|
||||||
using std::ifstream;
|
using std::ifstream;
|
||||||
|
|
||||||
|
#ifdef HAVE_SSL
|
||||||
|
class SSLSocket {
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
* @param ctx the SSL_CTX for cleanup, or nullptr.
|
||||||
|
* @param bio the BIO instance, or nullptr.
|
||||||
|
*/
|
||||||
|
SSLSocket(SSL_CTX *ctx, BIO *bio) : m_ctx(ctx), m_bio(bio) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Destructor.
|
||||||
|
*/
|
||||||
|
virtual ~SSLSocket();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect to the host on the specified port.
|
||||||
|
* @param host the host name or ip address to connect to.
|
||||||
|
* @param port the port number.
|
||||||
|
* @param https true for HTTPS, false for HTTP.
|
||||||
|
* @param timeout the connect, send, and receive timeout in seconds, or 0 for blocking mode.
|
||||||
|
* @return the connected SSLSocket, or nullptr on error.
|
||||||
|
*/
|
||||||
|
static SSLSocket* connect(const string& server, const uint16_t& port, const bool https, int timeout = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write bytes to the socket.
|
||||||
|
* @param data the data to send.
|
||||||
|
* @param len number of bytes to send.
|
||||||
|
* @return number of bytes written, or -1 on error.
|
||||||
|
*/
|
||||||
|
ssize_t send(const char* data, size_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read bytes from the socket.
|
||||||
|
* @param data the buffer for the received bytes.
|
||||||
|
* @param len size of the buffer.
|
||||||
|
* @return number of bytes read, or -1 on error.
|
||||||
|
*/
|
||||||
|
ssize_t recv(char* data, size_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the socket is still valid.
|
||||||
|
* @return true if the socket is still valid.
|
||||||
|
*/
|
||||||
|
bool isValid();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** the SSL_CTX for cleanup, or nullptr. */
|
||||||
|
SSL_CTX *m_ctx;
|
||||||
|
|
||||||
|
/** the BIO instance for communication. */
|
||||||
|
BIO *m_bio;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SocketClass SSLSocket
|
||||||
|
|
||||||
|
#else // HAVE_SSL
|
||||||
|
|
||||||
|
#define SocketClass TCPSocket
|
||||||
|
|
||||||
|
#endif // HAVE_SSL
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for handling HTTP client requests.
|
* Helper class for handling HTTP client requests.
|
||||||
*/
|
*/
|
||||||
@@ -43,7 +116,7 @@ class HttpClient {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*/
|
*/
|
||||||
HttpClient() : m_port(0), m_timeout(0), m_socket(nullptr), m_bufferSize(0), m_buffer(nullptr) {}
|
HttpClient() : m_socket(nullptr), m_port(0), m_timeout(0), m_bufferSize(0), m_buffer(nullptr) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destructor.
|
* Destructor.
|
||||||
@@ -56,6 +129,11 @@ class HttpClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize HttpClient.
|
||||||
|
*/
|
||||||
|
static void initialize();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse an HTTP URL.
|
* Parse an HTTP URL.
|
||||||
* @param url the URL to parse.
|
* @param url the URL to parse.
|
||||||
@@ -71,11 +149,12 @@ class HttpClient {
|
|||||||
* Connect to the specified server.
|
* Connect to the specified server.
|
||||||
* @param host the host name to connect to.
|
* @param host the host name to connect to.
|
||||||
* @param port the port to connect to.
|
* @param port the port to connect to.
|
||||||
|
* @param https true for HTTPS, false for HTTP.
|
||||||
* @param timeout the timeout in seconds, defaults to 5 seconds.
|
* @param timeout the timeout in seconds, defaults to 5 seconds.
|
||||||
* @param userAgent the optional user agent to send in the request header.
|
* @param userAgent the optional user agent to send in the request header.
|
||||||
* @return true on success, false on connect failure.
|
* @return true on success, false on connect failure.
|
||||||
*/
|
*/
|
||||||
bool connect(const string& host, uint16_t port, const string& userAgent = "", int timeout = 5);
|
bool connect(const string& host, uint16_t port, const bool https = false, const string& userAgent = "", int timeout = 5);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Re-connect to the last specified server.
|
* Re-connect to the last specified server.
|
||||||
@@ -135,8 +214,8 @@ class HttpClient {
|
|||||||
size_t readUntil(const string& delim, const size_t length, string* result);
|
size_t readUntil(const string& delim, const size_t length, string* result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** the @a TCPClient handling the traffic. */
|
/** the currently connected socket. */
|
||||||
TCPClient m_client;
|
SocketClass* m_socket;
|
||||||
|
|
||||||
/** the name of the host last successfully connected to. */
|
/** the name of the host last successfully connected to. */
|
||||||
string m_host;
|
string m_host;
|
||||||
@@ -150,9 +229,6 @@ class HttpClient {
|
|||||||
/** the optional user agent to send in the request header. */
|
/** the optional user agent to send in the request header. */
|
||||||
string m_userAgent;
|
string m_userAgent;
|
||||||
|
|
||||||
/** the currently connected socket. */
|
|
||||||
TCPSocket* m_socket;
|
|
||||||
|
|
||||||
/** the size of the @a m_buffer. */
|
/** the size of the @a m_buffer. */
|
||||||
size_t m_bufferSize;
|
size_t m_bufferSize;
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ bool TCPSocket::isValid() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TCPSocket* TCPClient::connect(const string& server, const uint16_t& port, int timeout) {
|
TCPSocket* TCPSocket::connect(const string& server, const uint16_t& port, int timeout) {
|
||||||
socketaddress address;
|
socketaddress address;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ using std::string;
|
|||||||
* Class for low level TCP socket operations (open, close, send, receive).
|
* Class for low level TCP socket operations (open, close, send, receive).
|
||||||
*/
|
*/
|
||||||
class TCPSocket {
|
class TCPSocket {
|
||||||
friend class TCPClient;
|
|
||||||
friend class TCPServer;
|
friend class TCPServer;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -62,6 +61,15 @@ class TCPSocket {
|
|||||||
*/
|
*/
|
||||||
~TCPSocket() { close(m_sfd); }
|
~TCPSocket() { close(m_sfd); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* initiate a tcp socket connection to a listening server.
|
||||||
|
* @param server the server name or ip address to connect.
|
||||||
|
* @param port the tcp port.
|
||||||
|
* @param timeout the connect, send, and receive timeout in seconds, or 0.
|
||||||
|
* @return pointer to an opened tcp socket.
|
||||||
|
*/
|
||||||
|
static TCPSocket* connect(const string& server, const uint16_t& port, int timeout = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write bytes to opened file descriptor.
|
* Write bytes to opened file descriptor.
|
||||||
* @param buffer data to send.
|
* @param buffer data to send.
|
||||||
@@ -125,21 +133,6 @@ class TCPSocket {
|
|||||||
string m_ip;
|
string m_ip;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* class to initiate a TCP socket connection to a listening server.
|
|
||||||
*/
|
|
||||||
class TCPClient {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* initiate a tcp socket connection to a listening server.
|
|
||||||
* @param server the server name or ip address to connect.
|
|
||||||
* @param port the tcp port.
|
|
||||||
* @param timeout the connect, send, and receive timeout in seconds, or 0.
|
|
||||||
* @return pointer to an opened tcp socket.
|
|
||||||
*/
|
|
||||||
TCPSocket* connect(const string& server, const uint16_t& port, int timeout = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class for a TCP based network server.
|
* class for a TCP based network server.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -261,8 +261,7 @@ string fetchData(ebusd::TCPSocket* socket, bool &listening, uint16_t timeout, bo
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool connect(const char* host, uint16_t port, uint16_t timeout, char* const *args, int argCount) {
|
bool connect(const char* host, uint16_t port, uint16_t timeout, char* const *args, int argCount) {
|
||||||
TCPClient* client = new TCPClient();
|
TCPSocket* socket = TCPSocket::connect(host, port, timeout);
|
||||||
TCPSocket* socket = client->connect(host, port, timeout);
|
|
||||||
bool ret;
|
bool ret;
|
||||||
|
|
||||||
bool once = args != nullptr && argCount > 0;
|
bool once = args != nullptr && argCount > 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user