From 0c8adc85f7373a85de8b3edc6cac87d5f7389bb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 11 Nov 2016 02:54:48 +0100 Subject: Move all the connect() logic from TCPSocketHandler into a subclass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way, TCPSocketHandler only deal with the message sending/receiving, not the connect() or anything else. This will be used for implementing servers (because when a client is accepted, we don’t need all the connect() and dns resolution stuff). --- louloulibs/network/dns_socket_handler.cpp | 5 + louloulibs/network/dns_socket_handler.hpp | 1 + louloulibs/network/socket_handler.hpp | 1 + louloulibs/network/tcp_client_socket_handler.cpp | 232 +++++++++++++++++++++++ louloulibs/network/tcp_client_socket_handler.hpp | 75 ++++++++ louloulibs/network/tcp_socket_handler.cpp | 230 ++-------------------- louloulibs/network/tcp_socket_handler.hpp | 93 ++------- louloulibs/xmpp/xmpp_component.cpp | 2 +- louloulibs/xmpp/xmpp_component.hpp | 4 +- 9 files changed, 350 insertions(+), 293 deletions(-) create mode 100644 louloulibs/network/tcp_client_socket_handler.cpp create mode 100644 louloulibs/network/tcp_client_socket_handler.hpp (limited to 'louloulibs') diff --git a/louloulibs/network/dns_socket_handler.cpp b/louloulibs/network/dns_socket_handler.cpp index 403a5be..af39f49 100644 --- a/louloulibs/network/dns_socket_handler.cpp +++ b/louloulibs/network/dns_socket_handler.cpp @@ -40,6 +40,11 @@ bool DNSSocketHandler::is_connected() const return true; } +bool DNSSocketHandler::is_connecting() const +{ + return false; +} + void DNSSocketHandler::remove_from_poller() { if (this->poller->is_managing_socket(this->socket)) diff --git a/louloulibs/network/dns_socket_handler.hpp b/louloulibs/network/dns_socket_handler.hpp index 0570196..14ba177 100644 --- a/louloulibs/network/dns_socket_handler.hpp +++ b/louloulibs/network/dns_socket_handler.hpp @@ -40,6 +40,7 @@ public: * Always true, see the comment for connect() */ bool is_connected() const override final; + bool is_connecting() const override final; void remove_from_poller(); private: diff --git a/louloulibs/network/socket_handler.hpp b/louloulibs/network/socket_handler.hpp index ea79a18..02e3b80 100644 --- a/louloulibs/network/socket_handler.hpp +++ b/louloulibs/network/socket_handler.hpp @@ -24,6 +24,7 @@ public: virtual void on_send() = 0; virtual void connect() = 0; virtual bool is_connected() const = 0; + virtual bool is_connecting() const = 0; socket_t get_socket() const { return this->socket; } diff --git a/louloulibs/network/tcp_client_socket_handler.cpp b/louloulibs/network/tcp_client_socket_handler.cpp new file mode 100644 index 0000000..2de9696 --- /dev/null +++ b/louloulibs/network/tcp_client_socket_handler.cpp @@ -0,0 +1,232 @@ +#include +#include +#include +#include + +#include + +#include +#include + +using namespace std::string_literals; + +TCPClientSocketHandler::TCPClientSocketHandler(std::shared_ptr poller): + TCPSocketHandler(poller), + hostname_resolution_failed(false), + connected(false), + connecting(false) +{} + +TCPClientSocketHandler::~TCPClientSocketHandler() +{ + this->close(); +} + +void TCPClientSocketHandler::init_socket(const struct addrinfo* rp) +{ + if (this->socket != -1) + ::close(this->socket); + if ((this->socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1) + throw std::runtime_error("Could not create socket: "s + strerror(errno)); + // Bind the socket to a specific address, if specified + if (!this->bind_addr.empty()) + { + // Convert the address from string format to a sockaddr that can be + // used in bind() + struct addrinfo* result; + int err = ::getaddrinfo(this->bind_addr.data(), nullptr, nullptr, &result); + if (err != 0 || !result) + log_error("Failed to bind socket to ", this->bind_addr, ": ", + gai_strerror(err)); + else + { + utils::ScopeGuard sg([result](){ freeaddrinfo(result); }); + struct addrinfo* rp; + int bind_error = 0; + for (rp = result; rp; rp = rp->ai_next) + { + if ((bind_error = ::bind(this->socket, + reinterpret_cast(rp->ai_addr), + rp->ai_addrlen)) == 0) + break; + } + if (!rp) + log_error("Failed to bind socket to ", this->bind_addr, ": ", + strerror(errno)); + else + log_info("Socket successfully bound to ", this->bind_addr); + } + } + int optval = 1; + if (::setsockopt(this->socket, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) == -1) + log_warning("Failed to enable TCP keepalive on socket: ", strerror(errno)); + // Set the socket on non-blocking mode. This is useful to receive a EAGAIN + // error when connect() would block, to not block the whole process if a + // remote is not responsive. + const int existing_flags = ::fcntl(this->socket, F_GETFL, 0); + if ((existing_flags == -1) || + (::fcntl(this->socket, F_SETFL, existing_flags | O_NONBLOCK) == -1)) + throw std::runtime_error("Could not initialize socket: "s + strerror(errno)); +} + +void TCPClientSocketHandler::connect(const std::string& address, const std::string& port, const bool tls) +{ + this->address = address; + this->port = port; + this->use_tls = tls; + + struct addrinfo* addr_res; + + if (!this->connecting) + { + // Get the addrinfo from getaddrinfo (or ares_gethostbyname), only if + // this is the first call of this function. + if (!this->resolver.is_resolved()) + { + log_info("Trying to connect to ", address, ":", port); + // Start the asynchronous process of resolving the hostname. Once + // the addresses have been found and `resolved` has been set to true + // (but connecting will still be false), TCPClientSocketHandler::connect() + // needs to be called, again. + this->resolver.resolve(address, port, + [this](const struct addrinfo*) + { + log_debug("Resolution success, calling connect() again"); + this->connect(); + }, + [this](const char*) + { + log_debug("Resolution failed, calling connect() again"); + this->connect(); + }); + return; + } + else + { + // The c-ares resolved the hostname and the available addresses + // where saved in the cares_addrinfo linked list. Now, just use + // this list to try to connect. + addr_res = this->resolver.get_result().get(); + if (!addr_res) + { + this->hostname_resolution_failed = true; + const auto msg = this->resolver.get_error_message(); + this->close(); + this->on_connection_failed(msg); + return ; + } + } + } + else + { // This function is called again, use the saved addrinfo structure, + // instead of re-doing the whole getaddrinfo process. + addr_res = &this->addrinfo; + } + + for (struct addrinfo* rp = addr_res; rp; rp = rp->ai_next) + { + if (!this->connecting) + { + try { + this->init_socket(rp); + } + catch (const std::runtime_error& error) { + log_error("Failed to init socket: ", error.what()); + break; + } + } + + this->display_resolved_ip(rp); + + if (::connect(this->socket, rp->ai_addr, rp->ai_addrlen) == 0 + || errno == EISCONN) + { + log_info("Connection success."); + TimedEventsManager::instance().cancel("connection_timeout"s + + std::to_string(this->socket)); + this->poller->add_socket_handler(this); + this->connected = true; + this->connecting = false; +#ifdef BOTAN_FOUND + if (this->use_tls) + this->start_tls(this->address, this->port); +#endif + this->connection_date = std::chrono::system_clock::now(); + + this->on_connected(); + return ; + } + else if (errno == EINPROGRESS || errno == EALREADY) + { // retry this process later, when the socket + // is ready to be written on. + this->connecting = true; + this->poller->add_socket_handler(this); + this->poller->watch_send_events(this); + // Save the addrinfo structure, to use it on the next call + this->ai_addrlen = rp->ai_addrlen; + memcpy(&this->ai_addr, rp->ai_addr, this->ai_addrlen); + memcpy(&this->addrinfo, rp, sizeof(struct addrinfo)); + this->addrinfo.ai_addr = reinterpret_cast(&this->ai_addr); + this->addrinfo.ai_next = nullptr; + // If the connection has not succeeded or failed in 5s, we consider + // it to have failed + TimedEventsManager::instance().add_event( + TimedEvent(std::chrono::steady_clock::now() + 5s, + std::bind(&TCPClientSocketHandler::on_connection_timeout, this), + "connection_timeout"s + std::to_string(this->socket))); + return ; + } + log_info("Connection failed:", strerror(errno)); + } + log_error("All connection attempts failed."); + this->close(); + this->on_connection_failed(strerror(errno)); + return ; +} + +void TCPClientSocketHandler::on_connection_timeout() +{ + this->close(); + this->on_connection_failed("connection timed out"); +} + +void TCPClientSocketHandler::connect() +{ + this->connect(this->address, this->port, this->use_tls); +} + +void TCPClientSocketHandler::close() +{ + TimedEventsManager::instance().cancel("connection_timeout"s + + std::to_string(this->socket)); + + TCPSocketHandler::close(); + + this->connected = false; + this->connecting = false; + this->port.clear(); + this->resolver.clear(); +} + +void TCPClientSocketHandler::display_resolved_ip(struct addrinfo* rp) const +{ + if (rp->ai_family == AF_INET) + log_debug("Trying IPv4 address ", addr_to_string(rp)); + else if (rp->ai_family == AF_INET6) + log_debug("Trying IPv6 address ", addr_to_string(rp)); +} + +bool TCPClientSocketHandler::is_connected() const +{ + return this->connected; +} + +bool TCPClientSocketHandler::is_connecting() const +{ + return this->connecting || this->resolver.is_resolving(); +} + +std::string TCPClientSocketHandler::get_port() const +{ + return this->port; +} diff --git a/louloulibs/network/tcp_client_socket_handler.hpp b/louloulibs/network/tcp_client_socket_handler.hpp new file mode 100644 index 0000000..7dd476c --- /dev/null +++ b/louloulibs/network/tcp_client_socket_handler.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include + +class TCPClientSocketHandler: public TCPSocketHandler +{ + public: + TCPClientSocketHandler(std::shared_ptr poller); + ~TCPClientSocketHandler(); + /** + * Connect to the remote server, and call on_connected() if this + * succeeds. If tls is true, we set use_tls to true and will also call + * start_tls() when the connection succeeds. + */ + void connect(const std::string& address, const std::string& port, const bool tls); + void connect() override final; + /** + * Called by a TimedEvent, when the connection did not succeed or fail + * after a given time. + */ + void on_connection_timeout(); + /** + * Called when the connection is successful. + */ + virtual void on_connected() = 0; + bool is_connected() const override; + bool is_connecting() const; + + std::string get_port() const; + + void close() override final; + std::chrono::system_clock::time_point connection_date; + + protected: + bool hostname_resolution_failed; + /** + * Address to bind the socket to, before calling connect(). + * If empty, it’s equivalent to binding to INADDR_ANY. + */ + std::string bind_addr; + /** + * Display the resolved IP, just for information purpose. + */ + void display_resolved_ip(struct addrinfo* rp) const; + private: + /** + * Initialize the socket with the parameters contained in the given + * addrinfo structure. + */ + void init_socket(const struct addrinfo* rp); + /** + * DNS resolver + */ + Resolver resolver; + /** + * Keep the details of the addrinfo returned by the resolver that + * triggered a EINPROGRESS error when connect()ing to it, to reuse it + * directly when connect() is called again. + */ + struct addrinfo addrinfo; + struct sockaddr_in6 ai_addr; + socklen_t ai_addrlen; + + /** + * Hostname we are connected/connecting to + */ + std::string address; + /** + * Port we are connected/connecting to + */ + std::string port; + + bool connected; + bool connecting; +}; diff --git a/louloulibs/network/tcp_socket_handler.cpp b/louloulibs/network/tcp_socket_handler.cpp index 1dddde5..5782f66 100644 --- a/louloulibs/network/tcp_socket_handler.cpp +++ b/louloulibs/network/tcp_socket_handler.cpp @@ -1,8 +1,6 @@ #include #include -#include -#include #include #include @@ -12,7 +10,6 @@ #include #include #include -#include #ifdef BOTAN_FOUND # include @@ -35,10 +32,7 @@ namespace ph = std::placeholders; TCPSocketHandler::TCPSocketHandler(std::shared_ptr poller): SocketHandler(poller, -1), - use_tls(false), - connected(false), - connecting(false), - hostname_resolution_failed(false) + use_tls(false) #ifdef BOTAN_FOUND ,credential_manager(this) #endif @@ -46,181 +40,13 @@ TCPSocketHandler::TCPSocketHandler(std::shared_ptr poller): TCPSocketHandler::~TCPSocketHandler() { - this->close(); -} - - -void TCPSocketHandler::init_socket(const struct addrinfo* rp) -{ + if (this->poller->is_managing_socket(this->get_socket())) + this->poller->remove_socket_handler(this->get_socket()); if (this->socket != -1) - ::close(this->socket); - if ((this->socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1) - throw std::runtime_error("Could not create socket: "s + strerror(errno)); - // Bind the socket to a specific address, if specified - if (!this->bind_addr.empty()) { - // Convert the address from string format to a sockaddr that can be - // used in bind() - struct addrinfo* result; - int err = ::getaddrinfo(this->bind_addr.data(), nullptr, nullptr, &result); - if (err != 0 || !result) - log_error("Failed to bind socket to ", this->bind_addr, ": ", - gai_strerror(err)); - else - { - utils::ScopeGuard sg([result](){ freeaddrinfo(result); }); - struct addrinfo* rp; - int bind_error = 0; - for (rp = result; rp; rp = rp->ai_next) - { - if ((bind_error = ::bind(this->socket, - reinterpret_cast(rp->ai_addr), - rp->ai_addrlen)) == 0) - break; - } - if (!rp) - log_error("Failed to bind socket to ", this->bind_addr, ": ", - strerror(errno)); - else - log_info("Socket successfully bound to ", this->bind_addr); - } - } - int optval = 1; - if (::setsockopt(this->socket, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) == -1) - log_warning("Failed to enable TCP keepalive on socket: ", strerror(errno)); - // Set the socket on non-blocking mode. This is useful to receive a EAGAIN - // error when connect() would block, to not block the whole process if a - // remote is not responsive. - const int existing_flags = ::fcntl(this->socket, F_GETFL, 0); - if ((existing_flags == -1) || - (::fcntl(this->socket, F_SETFL, existing_flags | O_NONBLOCK) == -1)) - throw std::runtime_error("Could not initialize socket: "s + strerror(errno)); -} - -void TCPSocketHandler::connect(const std::string& address, const std::string& port, const bool tls) -{ - this->address = address; - this->port = port; - this->use_tls = tls; - - struct addrinfo* addr_res; - - if (!this->connecting) - { - // Get the addrinfo from getaddrinfo (or ares_gethostbyname), only if - // this is the first call of this function. - if (!this->resolver.is_resolved()) - { - log_info("Trying to connect to ", address, ":", port); - // Start the asynchronous process of resolving the hostname. Once - // the addresses have been found and `resolved` has been set to true - // (but connecting will still be false), TCPSocketHandler::connect() - // needs to be called, again. - this->resolver.resolve(address, port, - [this](const struct addrinfo*) - { - log_debug("Resolution success, calling connect() again"); - this->connect(); - }, - [this](const char*) - { - log_debug("Resolution failed, calling connect() again"); - this->connect(); - }); - return; - } - else - { - // The c-ares resolved the hostname and the available addresses - // where saved in the cares_addrinfo linked list. Now, just use - // this list to try to connect. - addr_res = this->resolver.get_result().get(); - if (!addr_res) - { - this->hostname_resolution_failed = true; - const auto msg = this->resolver.get_error_message(); - this->close(); - this->on_connection_failed(msg); - return ; - } - } - } - else - { // This function is called again, use the saved addrinfo structure, - // instead of re-doing the whole getaddrinfo process. - addr_res = &this->addrinfo; - } - - for (struct addrinfo* rp = addr_res; rp; rp = rp->ai_next) - { - if (!this->connecting) - { - try { - this->init_socket(rp); - } - catch (const std::runtime_error& error) { - log_error("Failed to init socket: ", error.what()); - break; - } - } - - this->display_resolved_ip(rp); - - if (::connect(this->socket, rp->ai_addr, rp->ai_addrlen) == 0 - || errno == EISCONN) - { - log_info("Connection success."); - TimedEventsManager::instance().cancel("connection_timeout"s + - std::to_string(this->socket)); - this->poller->add_socket_handler(this); - this->connected = true; - this->connecting = false; -#ifdef BOTAN_FOUND - if (this->use_tls) - this->start_tls(); -#endif - this->connection_date = std::chrono::system_clock::now(); - - this->on_connected(); - return ; - } - else if (errno == EINPROGRESS || errno == EALREADY) - { // retry this process later, when the socket - // is ready to be written on. - this->connecting = true; - this->poller->add_socket_handler(this); - this->poller->watch_send_events(this); - // Save the addrinfo structure, to use it on the next call - this->ai_addrlen = rp->ai_addrlen; - memcpy(&this->ai_addr, rp->ai_addr, this->ai_addrlen); - memcpy(&this->addrinfo, rp, sizeof(struct addrinfo)); - this->addrinfo.ai_addr = reinterpret_cast(&this->ai_addr); - this->addrinfo.ai_next = nullptr; - // If the connection has not succeeded or failed in 5s, we consider - // it to have failed - TimedEventsManager::instance().add_event( - TimedEvent(std::chrono::steady_clock::now() + 5s, - std::bind(&TCPSocketHandler::on_connection_timeout, this), - "connection_timeout"s + std::to_string(this->socket))); - return ; - } - log_info("Connection failed:", strerror(errno)); + ::close(this->socket); + this->socket = -1; } - log_error("All connection attempts failed."); - this->close(); - this->on_connection_failed(strerror(errno)); - return ; -} - -void TCPSocketHandler::on_connection_timeout() -{ - this->close(); - this->on_connection_failed("connection timed out"); -} - -void TCPSocketHandler::connect() -{ - this->connect(this->address, this->port, this->use_tls); } void TCPSocketHandler::on_recv() @@ -267,13 +93,13 @@ ssize_t TCPSocketHandler::do_recv(void* recv_buf, const size_t buf_size) } else if (-1 == size) { - if (this->connecting) + if (this->is_connecting()) log_warning("Error connecting: ", strerror(errno)); else log_warning("Error while reading from socket: ", strerror(errno)); // Remember if we were connecting, or already connected when this // happened, because close() sets this->connecting to false - const auto were_connecting = this->connecting; + const auto were_connecting = this->is_connecting(); this->close(); if (were_connecting) this->on_connection_failed(strerror(errno)); @@ -333,29 +159,15 @@ void TCPSocketHandler::on_send() void TCPSocketHandler::close() { - TimedEventsManager::instance().cancel("connection_timeout"s + - std::to_string(this->socket)); - if (this->connected || this->connecting) + if (this->is_connected() || this->is_connecting()) this->poller->remove_socket_handler(this->get_socket()); if (this->socket != -1) { ::close(this->socket); this->socket = -1; } - this->connected = false; - this->connecting = false; this->in_buf.clear(); this->out_buf.clear(); - this->port.clear(); - this->resolver.clear(); -} - -void TCPSocketHandler::display_resolved_ip(struct addrinfo* rp) const -{ - if (rp->ai_family == AF_INET) - log_debug("Trying IPv4 address ", addr_to_string(rp)); - else if (rp->ai_family == AF_INET6) - log_debug("Trying IPv6 address ", addr_to_string(rp)); } void TCPSocketHandler::send_data(std::string&& data) @@ -379,45 +191,35 @@ void TCPSocketHandler::raw_send(std::string&& data) if (data.empty()) return ; this->out_buf.emplace_back(std::move(data)); - if (this->connected) + if (this->is_connected()) this->poller->watch_send_events(this); } void TCPSocketHandler::send_pending_data() { - if (this->connected && !this->out_buf.empty()) + if (this->is_connected() && !this->out_buf.empty()) this->poller->watch_send_events(this); } -bool TCPSocketHandler::is_connected() const -{ - return this->connected; -} - -bool TCPSocketHandler::is_connecting() const -{ - return this->connecting || this->resolver.is_resolving(); -} - bool TCPSocketHandler::is_using_tls() const { return this->use_tls; } -std::string TCPSocketHandler::get_port() const +void* TCPSocketHandler::get_receive_buffer(const size_t) const { - return this->port; + return nullptr; } -void* TCPSocketHandler::get_receive_buffer(const size_t) const +void TCPSocketHandler::consume_in_buffer(const std::size_t size) { - return nullptr; + this->in_buf = this->in_buf.substr(size, std::string::npos); } #ifdef BOTAN_FOUND -void TCPSocketHandler::start_tls() +void TCPSocketHandler::start_tls(const std::string& address, const std::string& port) { - Botan::TLS::Server_Information server_info(this->address, "irc", std::stoul(this->port)); + Botan::TLS::Server_Information server_info(address, "irc", std::stoul(port)); this->tls = std::make_unique( std::bind(&TCPSocketHandler::tls_output_fn, this, ph::_1, ph::_2), std::bind(&TCPSocketHandler::tls_data_cb, this, ph::_1, ph::_2), diff --git a/louloulibs/network/tcp_socket_handler.hpp b/louloulibs/network/tcp_socket_handler.hpp index 20a3e5a..d5e24ee 100644 --- a/louloulibs/network/tcp_socket_handler.hpp +++ b/louloulibs/network/tcp_socket_handler.hpp @@ -20,10 +20,8 @@ #include /** - * An interface, with a series of callbacks that should be implemented in - * subclasses that deal with a socket. These callbacks are called on various events - * (read/write/timeout, etc) when they are notified to a poller - * (select/poll/epoll etc) + * Does all the read/write, buffering etc. With optional tls. + * But doesn’t do any connect() or accept() or anything else. */ class TCPSocketHandler: public SocketHandler { @@ -36,13 +34,6 @@ public: TCPSocketHandler& operator=(const TCPSocketHandler&) = delete; TCPSocketHandler& operator=(TCPSocketHandler&&) = delete; - /** - * Connect to the remote server, and call on_connected() if this - * succeeds. If tls is true, we set use_tls to true and will also call - * start_tls() when the connection succeeds. - */ - void connect(const std::string& address, const std::string& port, const bool tls); - void connect() override final; /** * Reads raw data from the socket. And pass it to parse_in_buffer() * If we are using TLS on this connection, we call tls_recv() @@ -67,25 +58,7 @@ public: /** * Close the connection, remove us from the poller */ - void close(); - /** - * Called by a TimedEvent, when the connection did not succeed or fail - * after a given time. - */ - void on_connection_timeout(); - /** - * Called when the connection is successful. - */ - virtual void on_connected() = 0; - /** - * Called when the connection fails. Not when it is closed later, just at - * the connect() call. - */ - virtual void on_connection_failed(const std::string& reason) = 0; - /** - * Called when we detect a disconnection from the remote host. - */ - virtual void on_connection_close(const std::string& error) = 0; + virtual void close(); /** * Handle/consume (some of) the data received so far. The data to handle * may be in the in_buf buffer, or somewhere else, depending on what @@ -93,6 +66,9 @@ public: * should be truncated, only the unused data should be left untouched. * * The size argument is the size of the last chunk of data that was added to the buffer. + * + * The function should call consume_in_buffer, with the size that was consumed by the + * “parsing”, and thus to be removed from the input buffer. */ virtual void parse_in_buffer(const size_t size) = 0; #ifdef BOTAN_FOUND @@ -105,18 +81,9 @@ public: return true; } #endif - bool is_connected() const override final; - bool is_connecting() const; bool is_using_tls() const; - std::string get_port() const; - std::chrono::system_clock::time_point connection_date; private: - /** - * Initialize the socket with the parameters contained in the given - * addrinfo structure. - */ - void init_socket(const struct addrinfo* rp); /** * Reads from the socket into the provided buffer. If an error occurs * (read returns <= 0), the handling of the error is done here (close the @@ -137,12 +104,14 @@ private: void raw_send(std::string&& data); #ifdef BOTAN_FOUND + protected: /** * Create the TLS::Client object, with all the callbacks etc. This must be * called only when we know we are able to send TLS-encrypted data over * the socket. */ - void start_tls(); + void start_tls(const std::string& address, const std::string& port); + private: /** * An additional step to pass the data into our tls object to decrypt it * before passing it to parse_in_buffer. @@ -185,20 +154,11 @@ private: * Where data is added, when we want to send something to the client. */ std::vector out_buf; +protected: /** - * DNS resolver - */ - Resolver resolver; - /** - * Keep the details of the addrinfo returned by the resolver that - * triggered a EINPROGRESS error when connect()ing to it, to reuse it - * directly when connect() is called again. + * Whether we are using TLS on this connection or not. */ - struct addrinfo addrinfo; - struct sockaddr_in6 ai_addr; - socklen_t ai_addrlen; - -protected: + bool use_tls; /** * Where data read from the socket is added until we can extract a full * and meaningful “message” from it. @@ -207,9 +167,9 @@ protected: */ std::string in_buf; /** - * Whether we are using TLS on this connection or not. + * Remove the given “size” first bytes from our in_buf. */ - bool use_tls; + void consume_in_buffer(const std::size_t size); /** * Provide a buffer in which data can be directly received. This can be * used to avoid copying data into in_buf before using it. If no buffer @@ -219,31 +179,12 @@ protected: */ virtual void* get_receive_buffer(const size_t size) const; /** - * Hostname we are connected/connecting to - */ - std::string address; - /** - * Port we are connected/connecting to - */ - std::string port; - - bool connected; - bool connecting; - - bool hostname_resolution_failed; - - /** - * Address to bind the socket to, before calling connect(). - * If empty, it’s equivalent to binding to INADDR_ANY. + * Called when we detect a disconnection from the remote host. */ - std::string bind_addr; + virtual void on_connection_close(const std::string& error) = 0; + virtual void on_connection_failed(const std::string& error) = 0; private: - /** - * Display the resolved IP, just for information purpose. - */ - void display_resolved_ip(struct addrinfo* rp) const; - #ifdef BOTAN_FOUND /** * Botan stuff to manipulate a TLS session. diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index fa8b0a5..1d1c58b 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -39,7 +39,7 @@ static std::set kickable_errors{ }; XmppComponent::XmppComponent(std::shared_ptr poller, const std::string& hostname, const std::string& secret): - TCPSocketHandler(poller), + TCPClientSocketHandler(poller), ever_auth(false), first_connection_try(true), secret(secret), diff --git a/louloulibs/xmpp/xmpp_component.hpp b/louloulibs/xmpp/xmpp_component.hpp index 5f5f937..e3f8ce2 100644 --- a/louloulibs/xmpp/xmpp_component.hpp +++ b/louloulibs/xmpp/xmpp_component.hpp @@ -2,7 +2,7 @@ #include -#include +#include #include #include @@ -40,7 +40,7 @@ * * TODO: implement XEP-0225: Component Connections */ -class XmppComponent: public TCPSocketHandler +class XmppComponent: public TCPClientSocketHandler { public: explicit XmppComponent(std::shared_ptr poller, const std::string& hostname, const std::string& secret); -- cgit v1.2.3 From ed7e66471f7018f2e7e1c6a469e5cd758b913255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 11 Nov 2016 03:03:42 +0100 Subject: Add missing cstring include for strerror --- louloulibs/network/tcp_client_socket_handler.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/network/tcp_client_socket_handler.cpp b/louloulibs/network/tcp_client_socket_handler.cpp index 2de9696..f22d756 100644 --- a/louloulibs/network/tcp_client_socket_handler.cpp +++ b/louloulibs/network/tcp_client_socket_handler.cpp @@ -5,6 +5,7 @@ #include +#include #include #include @@ -27,7 +28,7 @@ void TCPClientSocketHandler::init_socket(const struct addrinfo* rp) if (this->socket != -1) ::close(this->socket); if ((this->socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1) - throw std::runtime_error("Could not create socket: "s + strerror(errno)); + throw std::runtime_error("Could not create socket: "s + std::strerror(errno)); // Bind the socket to a specific address, if specified if (!this->bind_addr.empty()) { @@ -66,7 +67,7 @@ void TCPClientSocketHandler::init_socket(const struct addrinfo* rp) const int existing_flags = ::fcntl(this->socket, F_GETFL, 0); if ((existing_flags == -1) || (::fcntl(this->socket, F_SETFL, existing_flags | O_NONBLOCK) == -1)) - throw std::runtime_error("Could not initialize socket: "s + strerror(errno)); + throw std::runtime_error("Could not initialize socket: "s + std::strerror(errno)); } void TCPClientSocketHandler::connect(const std::string& address, const std::string& port, const bool tls) @@ -176,11 +177,11 @@ void TCPClientSocketHandler::connect(const std::string& address, const std::stri "connection_timeout"s + std::to_string(this->socket))); return ; } - log_info("Connection failed:", strerror(errno)); + log_info("Connection failed:", std::strerror(errno)); } log_error("All connection attempts failed."); this->close(); - this->on_connection_failed(strerror(errno)); + this->on_connection_failed(std::strerror(errno)); return ; } -- cgit v1.2.3 From d872c2b49214c0a4db40a9e2d860802d9eedc563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 15 Nov 2016 00:23:19 +0100 Subject: Support the ident protocol fix #3211 --- louloulibs/network/resolver.hpp | 2 - louloulibs/network/tcp_client_socket_handler.cpp | 25 +++++++ louloulibs/network/tcp_client_socket_handler.hpp | 7 ++ louloulibs/network/tcp_server_socket.hpp | 86 ++++++++++++++++++++++++ 4 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 louloulibs/network/tcp_server_socket.hpp (limited to 'louloulibs') diff --git a/louloulibs/network/resolver.hpp b/louloulibs/network/resolver.hpp index 29e6f3a..7365f93 100644 --- a/louloulibs/network/resolver.hpp +++ b/louloulibs/network/resolver.hpp @@ -125,5 +125,3 @@ private: }; std::string addr_to_string(const struct addrinfo* rp); - - diff --git a/louloulibs/network/tcp_client_socket_handler.cpp b/louloulibs/network/tcp_client_socket_handler.cpp index f22d756..dc9221d 100644 --- a/louloulibs/network/tcp_client_socket_handler.cpp +++ b/louloulibs/network/tcp_client_socket_handler.cpp @@ -154,6 +154,25 @@ void TCPClientSocketHandler::connect(const std::string& address, const std::stri #endif this->connection_date = std::chrono::system_clock::now(); + // Get our local TCP port and store it + this->local_port = static_cast(-1); + if (rp->ai_family == AF_INET6) + { + struct sockaddr_in6 a; + socklen_t l = sizeof(a); + if (::getsockname(this->socket, (struct sockaddr*)&a, &l) != -1) + this->local_port = ::ntohs(a.sin6_port); + } + else if (rp->ai_family == AF_INET) + { + struct sockaddr_in a; + socklen_t l = sizeof(a); + if (::getsockname(this->socket, (struct sockaddr*)&a, &l) != -1) + this->local_port = ::ntohs(a.sin_port); + } + + log_debug("Local port: ", this->local_port, ", and remote port: ", this->port); + this->on_connected(); return ; } @@ -231,3 +250,9 @@ std::string TCPClientSocketHandler::get_port() const { return this->port; } + +bool TCPClientSocketHandler::match_port_pairt(const uint16_t local, const uint16_t remote) const +{ + const uint16_t remote_port = static_cast(std::stoi(this->port)); + return this->is_connected() && local == this->local_port && remote == remote_port; +} diff --git a/louloulibs/network/tcp_client_socket_handler.hpp b/louloulibs/network/tcp_client_socket_handler.hpp index 7dd476c..3ad8ec3 100644 --- a/louloulibs/network/tcp_client_socket_handler.hpp +++ b/louloulibs/network/tcp_client_socket_handler.hpp @@ -31,6 +31,11 @@ class TCPClientSocketHandler: public TCPSocketHandler void close() override final; std::chrono::system_clock::time_point connection_date; + /** + * Whether or not this connection is using the two given TCP ports. + */ + bool match_port_pairt(const uint16_t local, const uint16_t remote) const; + protected: bool hostname_resolution_failed; /** @@ -70,6 +75,8 @@ class TCPClientSocketHandler: public TCPSocketHandler */ std::string port; + uint16_t local_port; + bool connected; bool connecting; }; diff --git a/louloulibs/network/tcp_server_socket.hpp b/louloulibs/network/tcp_server_socket.hpp new file mode 100644 index 0000000..a54d3bf --- /dev/null +++ b/louloulibs/network/tcp_server_socket.hpp @@ -0,0 +1,86 @@ +#pragma once + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include + +using namespace std::string_literals; + +template +class TcpSocketServer: public SocketHandler +{ + public: + TcpSocketServer(std::shared_ptr poller, const uint16_t port): + SocketHandler(poller, -1) + { + if ((this->socket = ::socket(AF_INET6, SOCK_STREAM, 0)) == -1) + throw std::runtime_error("Could not create socket: "s + std::strerror(errno)); + + int opt = 1; + if (::setsockopt(this->socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) + throw std::runtime_error("Failed to set socket option: "s + std::strerror(errno)); + + struct sockaddr_in6 addr{}; + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(port); + addr.sin6_addr = IN6ADDR_ANY_INIT; + if ((::bind(this->socket, (const struct sockaddr*)&addr, sizeof(addr))) == -1) + { // If we can’t listen on this port, we just give up, but this is not fatal. + log_warning("Failed to bind on port ", std::to_string(port), ": ", std::strerror(errno)); + return; + } + + if ((::listen(this->socket, 10)) == -1) + throw std::runtime_error("listen() failed"); + + this->accept(); + } + ~TcpSocketServer() = default; + + void on_recv() override + { + // Accept a RemoteSocketType + int socket = ::accept(this->socket, nullptr, nullptr); + + auto client = std::make_unique(poller, socket, *this); + this->poller->add_socket_handler(client.get()); + this->sockets.push_back(std::move(client)); + } + + protected: + std::vector> sockets; + + private: + void accept() + { + this->poller->add_socket_handler(this); + } + void on_send() override + { + assert(false); + } + void connect() override + { + assert(false); + } + bool is_connected() const override + { + return true; + } + bool is_connecting() const override + { + return false; + } +}; -- cgit v1.2.3 From 4ab3cd653f3eb19ff82838f777984c9d16e64a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 15 Nov 2016 00:49:55 +0100 Subject: Fix some little compilation errors with some configs, from last commit --- louloulibs/network/tcp_client_socket_handler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/network/tcp_client_socket_handler.cpp b/louloulibs/network/tcp_client_socket_handler.cpp index dc9221d..2e90ea1 100644 --- a/louloulibs/network/tcp_client_socket_handler.cpp +++ b/louloulibs/network/tcp_client_socket_handler.cpp @@ -161,14 +161,14 @@ void TCPClientSocketHandler::connect(const std::string& address, const std::stri struct sockaddr_in6 a; socklen_t l = sizeof(a); if (::getsockname(this->socket, (struct sockaddr*)&a, &l) != -1) - this->local_port = ::ntohs(a.sin6_port); + this->local_port = ntohs(a.sin6_port); } else if (rp->ai_family == AF_INET) { struct sockaddr_in a; socklen_t l = sizeof(a); if (::getsockname(this->socket, (struct sockaddr*)&a, &l) != -1) - this->local_port = ::ntohs(a.sin_port); + this->local_port = ntohs(a.sin_port); } log_debug("Local port: ", this->local_port, ", and remote port: ", this->port); -- cgit v1.2.3 From ae445f0e599fc73559248595af06c9f04189f44b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 16 Nov 2016 20:02:44 +0100 Subject: Remove an unused variable --- louloulibs/network/tcp_client_socket_handler.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/network/tcp_client_socket_handler.cpp b/louloulibs/network/tcp_client_socket_handler.cpp index 2e90ea1..7f21e3f 100644 --- a/louloulibs/network/tcp_client_socket_handler.cpp +++ b/louloulibs/network/tcp_client_socket_handler.cpp @@ -43,10 +43,9 @@ void TCPClientSocketHandler::init_socket(const struct addrinfo* rp) { utils::ScopeGuard sg([result](){ freeaddrinfo(result); }); struct addrinfo* rp; - int bind_error = 0; for (rp = result; rp; rp = rp->ai_next) { - if ((bind_error = ::bind(this->socket, + if ((::bind(this->socket, reinterpret_cast(rp->ai_addr), rp->ai_addrlen)) == 0) break; -- cgit v1.2.3 From d90f75dc60d041cb602d3af1feb7e7445dcaecf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 16 Nov 2016 20:03:01 +0100 Subject: Trivial include cleanup --- louloulibs/network/tcp_server_socket.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/network/tcp_server_socket.hpp b/louloulibs/network/tcp_server_socket.hpp index a54d3bf..663ae5b 100644 --- a/louloulibs/network/tcp_server_socket.hpp +++ b/louloulibs/network/tcp_server_socket.hpp @@ -1,8 +1,8 @@ #pragma once #include -#include #include +#include #include @@ -11,8 +11,6 @@ #include #include -#include - #include #include -- cgit v1.2.3 From 9dd0cf8f7aee5c6d3be163246de9f0a5282e02e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 16 Nov 2016 20:28:48 +0100 Subject: =?UTF-8?q?Fix=20an=20error=20on=20gcc=204.9,=20because=20it=20is?= =?UTF-8?q?=20so=20stupid=20it=20can=E2=80=99t=20find=20operator""s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- louloulibs/network/tcp_server_socket.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/network/tcp_server_socket.hpp b/louloulibs/network/tcp_server_socket.hpp index 663ae5b..44d474c 100644 --- a/louloulibs/network/tcp_server_socket.hpp +++ b/louloulibs/network/tcp_server_socket.hpp @@ -14,8 +14,6 @@ #include #include -using namespace std::string_literals; - template class TcpSocketServer: public SocketHandler { @@ -24,11 +22,11 @@ class TcpSocketServer: public SocketHandler SocketHandler(poller, -1) { if ((this->socket = ::socket(AF_INET6, SOCK_STREAM, 0)) == -1) - throw std::runtime_error("Could not create socket: "s + std::strerror(errno)); + throw std::runtime_error(std::string{"Could not create socket: "} + std::strerror(errno)); int opt = 1; if (::setsockopt(this->socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) - throw std::runtime_error("Failed to set socket option: "s + std::strerror(errno)); + throw std::runtime_error(std::string{"Failed to set socket option: "} + std::strerror(errno)); struct sockaddr_in6 addr{}; addr.sin6_family = AF_INET6; -- cgit v1.2.3 From 42e85d921b0c5e10889d93c24b7ebf355287ee71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 16 Nov 2016 23:07:27 +0100 Subject: Remove some useless virtual method from SocketHandler --- louloulibs/network/dns_socket_handler.cpp | 9 --------- louloulibs/network/dns_socket_handler.hpp | 6 ------ louloulibs/network/socket_handler.hpp | 7 +++---- louloulibs/network/tcp_client_socket_handler.hpp | 2 +- louloulibs/network/tcp_server_socket.hpp | 12 ------------ louloulibs/network/tcp_socket_handler.hpp | 1 + 6 files changed, 5 insertions(+), 32 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/network/dns_socket_handler.cpp b/louloulibs/network/dns_socket_handler.cpp index af39f49..a69f59b 100644 --- a/louloulibs/network/dns_socket_handler.cpp +++ b/louloulibs/network/dns_socket_handler.cpp @@ -15,10 +15,6 @@ DNSSocketHandler::DNSSocketHandler(std::shared_ptr poller, { } -void DNSSocketHandler::connect() -{ -} - void DNSSocketHandler::on_recv() { // always stop watching send and read events. We will re-watch them if the @@ -40,11 +36,6 @@ bool DNSSocketHandler::is_connected() const return true; } -bool DNSSocketHandler::is_connecting() const -{ - return false; -} - void DNSSocketHandler::remove_from_poller() { if (this->poller->is_managing_socket(this->socket)) diff --git a/louloulibs/network/dns_socket_handler.hpp b/louloulibs/network/dns_socket_handler.hpp index 14ba177..e3fed0c 100644 --- a/louloulibs/network/dns_socket_handler.hpp +++ b/louloulibs/network/dns_socket_handler.hpp @@ -31,16 +31,10 @@ public: */ void on_recv() override final; void on_send() override final; - /** - * Do nothing, because we are always considered to be connected, since the - * connection is done by c-ares and not by us. - */ - void connect() override final; /** * Always true, see the comment for connect() */ bool is_connected() const override final; - bool is_connecting() const override final; void remove_from_poller(); private: diff --git a/louloulibs/network/socket_handler.hpp b/louloulibs/network/socket_handler.hpp index 02e3b80..607a106 100644 --- a/louloulibs/network/socket_handler.hpp +++ b/louloulibs/network/socket_handler.hpp @@ -20,11 +20,10 @@ public: SocketHandler& operator=(const SocketHandler&) = delete; SocketHandler& operator=(SocketHandler&&) = delete; - virtual void on_recv() = 0; - virtual void on_send() = 0; - virtual void connect() = 0; + virtual void on_recv() {} + virtual void on_send() {} + virtual void connect() {} virtual bool is_connected() const = 0; - virtual bool is_connecting() const = 0; socket_t get_socket() const { return this->socket; } diff --git a/louloulibs/network/tcp_client_socket_handler.hpp b/louloulibs/network/tcp_client_socket_handler.hpp index 3ad8ec3..72f68d0 100644 --- a/louloulibs/network/tcp_client_socket_handler.hpp +++ b/louloulibs/network/tcp_client_socket_handler.hpp @@ -24,7 +24,7 @@ class TCPClientSocketHandler: public TCPSocketHandler */ virtual void on_connected() = 0; bool is_connected() const override; - bool is_connecting() const; + bool is_connecting() const override; std::string get_port() const; diff --git a/louloulibs/network/tcp_server_socket.hpp b/louloulibs/network/tcp_server_socket.hpp index 44d474c..7ea49ab 100644 --- a/louloulibs/network/tcp_server_socket.hpp +++ b/louloulibs/network/tcp_server_socket.hpp @@ -63,20 +63,8 @@ class TcpSocketServer: public SocketHandler { this->poller->add_socket_handler(this); } - void on_send() override - { - assert(false); - } - void connect() override - { - assert(false); - } bool is_connected() const override { return true; } - bool is_connecting() const override - { - return false; - } }; diff --git a/louloulibs/network/tcp_socket_handler.hpp b/louloulibs/network/tcp_socket_handler.hpp index d5e24ee..85c30f5 100644 --- a/louloulibs/network/tcp_socket_handler.hpp +++ b/louloulibs/network/tcp_socket_handler.hpp @@ -105,6 +105,7 @@ private: #ifdef BOTAN_FOUND protected: + virtual bool is_connecting() const = 0; /** * Create the TLS::Client object, with all the callbacks etc. This must be * called only when we know we are able to send TLS-encrypted data over -- cgit v1.2.3 From 5cb534c960faed2ed4303cd32f45fa69e4db417e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 16 Nov 2016 23:13:37 +0100 Subject: move is_connecting outside of an ifdef --- louloulibs/network/tcp_socket_handler.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs') diff --git a/louloulibs/network/tcp_socket_handler.hpp b/louloulibs/network/tcp_socket_handler.hpp index 85c30f5..d5b9c33 100644 --- a/louloulibs/network/tcp_socket_handler.hpp +++ b/louloulibs/network/tcp_socket_handler.hpp @@ -103,9 +103,9 @@ private: */ void raw_send(std::string&& data); -#ifdef BOTAN_FOUND protected: virtual bool is_connecting() const = 0; +#ifdef BOTAN_FOUND /** * Create the TLS::Client object, with all the callbacks etc. This must be * called only when we know we are able to send TLS-encrypted data over -- cgit v1.2.3 From 5f9568ca201832e8060dbaab3b080a758567c947 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 2 Dec 2016 11:30:27 +0100 Subject: TLS: Enable ecc point compression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If available in Botan. There is an issue where, if botan supports it but we don’t enable it, then the TLS handshake may fail with some servers --- louloulibs/network/tcp_socket_handler.cpp | 2 +- louloulibs/network/tcp_socket_handler.hpp | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/network/tcp_socket_handler.cpp b/louloulibs/network/tcp_socket_handler.cpp index 5782f66..7c33ab8 100644 --- a/louloulibs/network/tcp_socket_handler.cpp +++ b/louloulibs/network/tcp_socket_handler.cpp @@ -16,7 +16,7 @@ # include Botan::AutoSeeded_RNG TCPSocketHandler::rng; -Botan::TLS::Policy TCPSocketHandler::policy; +BiboumiTLSPolicy TCPSocketHandler::policy; Botan::TLS::Session_Manager_In_Memory TCPSocketHandler::session_manager(TCPSocketHandler::rng); #endif diff --git a/louloulibs/network/tcp_socket_handler.hpp b/louloulibs/network/tcp_socket_handler.hpp index d5b9c33..c37e386 100644 --- a/louloulibs/network/tcp_socket_handler.hpp +++ b/louloulibs/network/tcp_socket_handler.hpp @@ -19,6 +19,17 @@ #include #include +class BiboumiTLSPolicy: public Botan::TLS::Policy +{ +public: +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33) + bool use_ecc_point_compression() const override + { + return true; + } +#endif +}; + /** * Does all the read/write, buffering etc. With optional tls. * But doesn’t do any connect() or accept() or anything else. @@ -191,7 +202,7 @@ private: * Botan stuff to manipulate a TLS session. */ static Botan::AutoSeeded_RNG rng; - static Botan::TLS::Policy policy; + static BiboumiTLSPolicy policy; static Botan::TLS::Session_Manager_In_Memory session_manager; protected: BasicCredentialsManager credential_manager; -- cgit v1.2.3 From 3f53db79c0f010dfb1ac1f4aa8ed098d42c5b96f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 2 Dec 2016 16:50:28 +0100 Subject: Use the new botan 1.11.32 Tls::Client API (but stay compatible with older ones) --- louloulibs/network/tcp_socket_handler.cpp | 20 ++++++++++++-------- louloulibs/network/tcp_socket_handler.hpp | 23 +++++++++++++++++------ 2 files changed, 29 insertions(+), 14 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/network/tcp_socket_handler.cpp b/louloulibs/network/tcp_socket_handler.cpp index 7c33ab8..27b098a 100644 --- a/louloulibs/network/tcp_socket_handler.cpp +++ b/louloulibs/network/tcp_socket_handler.cpp @@ -221,10 +221,14 @@ void TCPSocketHandler::start_tls(const std::string& address, const std::string& { Botan::TLS::Server_Information server_info(address, "irc", std::stoul(port)); this->tls = std::make_unique( - std::bind(&TCPSocketHandler::tls_output_fn, this, ph::_1, ph::_2), - std::bind(&TCPSocketHandler::tls_data_cb, this, ph::_1, ph::_2), - std::bind(&TCPSocketHandler::tls_alert_cb, this, ph::_1, ph::_2, ph::_3), - std::bind(&TCPSocketHandler::tls_handshake_cb, this, ph::_1), +# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,32) + *this, +# else + [this](const Botan::byte* data, size_t size) { this->tls_emit_data(data, size); }, + [this](const Botan::byte* data, size_t size) { this->tls_record_received(0, data, size); }, + [this](Botan::TLS::Alert alert, const Botan::byte*, size_t) { this->tls_alert(alert); }, + [this](const Botan::TLS::Session& session) { return this->tls_session_established(session); }, +# endif session_manager, this->credential_manager, policy, rng, server_info, Botan::TLS::Protocol_Version::latest_tls_version()); } @@ -277,7 +281,7 @@ void TCPSocketHandler::tls_send(std::string&& data) std::make_move_iterator(data.end())); } -void TCPSocketHandler::tls_data_cb(const Botan::byte* data, size_t size) +void TCPSocketHandler::tls_record_received(uint64_t, const Botan::byte *data, size_t size) { this->in_buf += std::string(reinterpret_cast(data), size); @@ -285,17 +289,17 @@ void TCPSocketHandler::tls_data_cb(const Botan::byte* data, size_t size) this->parse_in_buffer(size); } -void TCPSocketHandler::tls_output_fn(const Botan::byte* data, size_t size) +void TCPSocketHandler::tls_emit_data(const Botan::byte *data, size_t size) { this->raw_send(std::string(reinterpret_cast(data), size)); } -void TCPSocketHandler::tls_alert_cb(Botan::TLS::Alert alert, const Botan::byte*, size_t) +void TCPSocketHandler::tls_alert(Botan::TLS::Alert alert) { log_debug("tls_alert: ", alert.type_string()); } -bool TCPSocketHandler::tls_handshake_cb(const Botan::TLS::Session& session) +bool TCPSocketHandler::tls_session_established(const Botan::TLS::Session& session) { log_debug("Handshake with ", session.server_info().hostname(), " complete.", " Version: ", session.version().to_string(), diff --git a/louloulibs/network/tcp_socket_handler.hpp b/louloulibs/network/tcp_socket_handler.hpp index c37e386..c33c8f2 100644 --- a/louloulibs/network/tcp_socket_handler.hpp +++ b/louloulibs/network/tcp_socket_handler.hpp @@ -19,22 +19,33 @@ #include #include +#ifdef BOTAN_FOUND class BiboumiTLSPolicy: public Botan::TLS::Policy { public: -#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33) +# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33) bool use_ecc_point_compression() const override { return true; } -#endif +# endif }; +# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,32) +# define BOTAN_TLS_CALLBACKS_OVERRIDE override final +# else +# define BOTAN_TLS_CALLBACKS_OVERRIDE +# endif +#endif + /** * Does all the read/write, buffering etc. With optional tls. * But doesn’t do any connect() or accept() or anything else. */ class TCPSocketHandler: public SocketHandler +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,32) + ,public Botan::TLS::Callbacks +#endif { protected: ~TCPSocketHandler(); @@ -139,22 +150,22 @@ private: * Called by the tls object that some data has been decrypt. We call * parse_in_buffer() to handle that unencrypted data. */ - void tls_data_cb(const Botan::byte* data, size_t size); + void tls_record_received(uint64_t rec_no, const Botan::byte* data, size_t size) BOTAN_TLS_CALLBACKS_OVERRIDE; /** * Called by the tls object to indicate that some data has been encrypted * and is now ready to be sent on the socket as is. */ - void tls_output_fn(const Botan::byte* data, size_t size); + void tls_emit_data(const Botan::byte* data, size_t size) BOTAN_TLS_CALLBACKS_OVERRIDE; /** * Called by the tls object to indicate that a TLS alert has been * received. We don’t use it, we just log some message, at the moment. */ - void tls_alert_cb(Botan::TLS::Alert alert, const Botan::byte*, size_t); + void tls_alert(Botan::TLS::Alert alert) BOTAN_TLS_CALLBACKS_OVERRIDE; /** * Called by the tls object at the end of the TLS handshake. We don't do * anything here appart from logging the TLS session information. */ - bool tls_handshake_cb(const Botan::TLS::Session& session); + bool tls_session_established(const Botan::TLS::Session& session) BOTAN_TLS_CALLBACKS_OVERRIDE; /** * Called whenever the tls session goes from inactive to active. This * means that the handshake has just been successfully done, and we can -- cgit v1.2.3 From 732f53d798c86558e1e625c22e957243bb2d6467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 18 Nov 2016 20:54:41 +0100 Subject: Clean a few more things --- louloulibs/network/dns_handler.cpp | 1 - louloulibs/network/dns_handler.hpp | 3 ++- louloulibs/network/tcp_socket_handler.hpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/network/dns_handler.cpp b/louloulibs/network/dns_handler.cpp index fef0cfc..b1807b5 100644 --- a/louloulibs/network/dns_handler.cpp +++ b/louloulibs/network/dns_handler.cpp @@ -8,7 +8,6 @@ #include #include -#include DNSHandler DNSHandler::instance; diff --git a/louloulibs/network/dns_handler.hpp b/louloulibs/network/dns_handler.hpp index fd1729d..53a7799 100644 --- a/louloulibs/network/dns_handler.hpp +++ b/louloulibs/network/dns_handler.hpp @@ -20,8 +20,9 @@ class DNSSocketHandler; class DNSHandler { -public: +private: DNSHandler(); +public: ~DNSHandler() = default; DNSHandler(const DNSHandler&) = delete; DNSHandler(DNSHandler&&) = delete; diff --git a/louloulibs/network/tcp_socket_handler.hpp b/louloulibs/network/tcp_socket_handler.hpp index c33c8f2..5863d4a 100644 --- a/louloulibs/network/tcp_socket_handler.hpp +++ b/louloulibs/network/tcp_socket_handler.hpp @@ -204,8 +204,8 @@ protected: /** * Called when we detect a disconnection from the remote host. */ - virtual void on_connection_close(const std::string& error) = 0; - virtual void on_connection_failed(const std::string& error) = 0; + virtual void on_connection_close(const std::string&) {} + virtual void on_connection_failed(const std::string&) {} private: #ifdef BOTAN_FOUND -- cgit v1.2.3 From 3ef78f44180c9f6ed7a98672a69ea0f3b35b1eac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 4 Dec 2016 16:19:43 +0100 Subject: Add some missing botan includes --- louloulibs/network/tcp_socket_handler.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'louloulibs') diff --git a/louloulibs/network/tcp_socket_handler.hpp b/louloulibs/network/tcp_socket_handler.hpp index 5863d4a..8825a3a 100644 --- a/louloulibs/network/tcp_socket_handler.hpp +++ b/louloulibs/network/tcp_socket_handler.hpp @@ -1,6 +1,5 @@ #pragma once - #include "louloulibs.h" #include @@ -20,6 +19,11 @@ #include #ifdef BOTAN_FOUND + +# include +# include +# include + class BiboumiTLSPolicy: public Botan::TLS::Policy { public: -- cgit v1.2.3 From a66c67e291327c3ae5d6005a38c8d257b4333581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 4 Dec 2016 16:26:32 +0100 Subject: Add a missing ifdef botan --- louloulibs/network/tcp_socket_handler.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'louloulibs') diff --git a/louloulibs/network/tcp_socket_handler.hpp b/louloulibs/network/tcp_socket_handler.hpp index 8825a3a..a44036d 100644 --- a/louloulibs/network/tcp_socket_handler.hpp +++ b/louloulibs/network/tcp_socket_handler.hpp @@ -47,8 +47,10 @@ public: * But doesn’t do any connect() or accept() or anything else. */ class TCPSocketHandler: public SocketHandler -#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,32) +#ifdef BOTAN_FOUND +# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,32) ,public Botan::TLS::Callbacks +# endif #endif { protected: -- cgit v1.2.3 From 7784c568432231c737c789b065af6b81e038c54d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 4 Dec 2016 22:17:37 +0100 Subject: Update the verify_certificate_chain code to work with botan >= 1.11.34 as well --- louloulibs/network/credentials_manager.cpp | 35 +++++++++++++++++++++++------- louloulibs/network/credentials_manager.hpp | 15 +++++++++++++ louloulibs/network/tcp_socket_handler.cpp | 25 +++++++++++++++++++++ louloulibs/network/tcp_socket_handler.hpp | 9 ++++++++ 4 files changed, 76 insertions(+), 8 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/network/credentials_manager.cpp b/louloulibs/network/credentials_manager.cpp index ed04d24..289307b 100644 --- a/louloulibs/network/credentials_manager.cpp +++ b/louloulibs/network/credentials_manager.cpp @@ -37,6 +37,28 @@ void BasicCredentialsManager::set_trusted_fingerprint(const std::string& fingerp this->trusted_fingerprint = fingerprint; } +const std::string& BasicCredentialsManager::get_trusted_fingerprint() const +{ + return this->trusted_fingerprint; +} + +void check_tls_certificate(const std::vector& certs, + const std::string& hostname, const std::string& trusted_fingerprint, + std::exception_ptr exc) +{ + + if (!trusted_fingerprint.empty() && !certs.empty() && + trusted_fingerprint == certs[0].fingerprint() && + certs[0].matches_dns_name(hostname)) + // We trust the certificate, based on the trusted fingerprint and + // the fact that the hostname matches + return; + + if (exc) + std::rethrow_exception(exc); +} + +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,34) void BasicCredentialsManager::verify_certificate_chain(const std::string& type, const std::string& purported_hostname, const std::vector& certs) @@ -50,17 +72,14 @@ void BasicCredentialsManager::verify_certificate_chain(const std::string& type, catch (const std::exception& tls_exception) { log_warning("TLS certificate check failed: ", tls_exception.what()); - if (!this->trusted_fingerprint.empty() && !certs.empty() && - this->trusted_fingerprint == certs[0].fingerprint() && - certs[0].matches_dns_name(purported_hostname)) - // We trust the certificate, based on the trusted fingerprint and - // the fact that the hostname matches - return; - + std::exception_ptr exception_ptr{}; if (this->socket_handler->abort_on_invalid_cert()) - throw; + exception_ptr = std::current_exception(); + + check_tls_certificate(certs, purported_hostname, this->trusted_fingerprint, exception_ptr); } } +#endif bool BasicCredentialsManager::try_to_open_one_ca_bundle(const std::vector& paths) { diff --git a/louloulibs/network/credentials_manager.hpp b/louloulibs/network/credentials_manager.hpp index 7557372..29ee024 100644 --- a/louloulibs/network/credentials_manager.hpp +++ b/louloulibs/network/credentials_manager.hpp @@ -9,6 +9,18 @@ class TCPSocketHandler; +/** + * If the given cert isn’t valid, based on the given hostname + * and fingerprint, then throws the exception if it’s non-empty. + * + * Must be called after the standard (from Botan) way of + * checking the certificate, if we want to also accept certificates based + * on a trusted fingerprint. + */ +void check_tls_certificate(const std::vector& certs, + const std::string& hostname, const std::string& trusted_fingerprint, + std::exception_ptr exc); + class BasicCredentialsManager: public Botan::Credentials_Manager { public: @@ -19,12 +31,15 @@ public: BasicCredentialsManager& operator=(const BasicCredentialsManager&) = delete; BasicCredentialsManager& operator=(BasicCredentialsManager&&) = delete; +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,34) void verify_certificate_chain(const std::string& type, const std::string& purported_hostname, const std::vector&) override final; +#endif std::vector trusted_certificate_authorities(const std::string& type, const std::string& context) override final; void set_trusted_fingerprint(const std::string& fingerprint); + const std::string& get_trusted_fingerprint() const; private: const TCPSocketHandler* const socket_handler; diff --git a/louloulibs/network/tcp_socket_handler.cpp b/louloulibs/network/tcp_socket_handler.cpp index 27b098a..9d9a6aa 100644 --- a/louloulibs/network/tcp_socket_handler.cpp +++ b/louloulibs/network/tcp_socket_handler.cpp @@ -311,6 +311,31 @@ bool TCPSocketHandler::tls_session_established(const Botan::TLS::Session& sessio return true; } +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,34) +void TCPSocketHandler::tls_verify_cert_chain(const std::vector& cert_chain, + const std::vector>& ocsp_responses, + const std::vector& trusted_roots, + Botan::Usage_Type usage, const std::string& hostname, + const Botan::TLS::Policy& policy) +{ + log_debug("Checking remote certificate for hostname ", hostname); + try + { + Botan::TLS::Callbacks::tls_verify_cert_chain(cert_chain, ocsp_responses, trusted_roots, usage, hostname, policy); + log_debug("Certificate is valid"); + } + catch (const std::exception& tls_exception) + { + log_warning("TLS certificate check failed: ", tls_exception.what()); + std::exception_ptr exception_ptr{}; + if (this->abort_on_invalid_cert()) + exception_ptr = std::current_exception(); + + check_tls_certificate(cert_chain, hostname, this->credential_manager.get_trusted_fingerprint(), exception_ptr); + } +} +#endif + void TCPSocketHandler::on_tls_activated() { this->send_data({}); diff --git a/louloulibs/network/tcp_socket_handler.hpp b/louloulibs/network/tcp_socket_handler.hpp index a44036d..3c6ff71 100644 --- a/louloulibs/network/tcp_socket_handler.hpp +++ b/louloulibs/network/tcp_socket_handler.hpp @@ -172,6 +172,15 @@ private: * anything here appart from logging the TLS session information. */ bool tls_session_established(const Botan::TLS::Session& session) BOTAN_TLS_CALLBACKS_OVERRIDE; + +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,34) + void tls_verify_cert_chain(const std::vector& cert_chain, + const std::vector>& ocsp_responses, + const std::vector& trusted_roots, + Botan::Usage_Type usage, + const std::string& hostname, + const Botan::TLS::Policy& policy) BOTAN_TLS_CALLBACKS_OVERRIDE; +#endif /** * Called whenever the tls session goes from inactive to active. This * means that the handshake has just been successfully done, and we can -- cgit v1.2.3 From 75778f418751bf06687ccc99454683bb43a9daf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 7 Dec 2016 18:28:29 +0100 Subject: Add some missing includes --- louloulibs/network/resolver.cpp | 2 ++ louloulibs/utils/encoding.cpp | 1 + 2 files changed, 3 insertions(+) (limited to 'louloulibs') diff --git a/louloulibs/network/resolver.cpp b/louloulibs/network/resolver.cpp index 2987aaa..3847d87 100644 --- a/louloulibs/network/resolver.cpp +++ b/louloulibs/network/resolver.cpp @@ -2,6 +2,8 @@ #include #include #include +#include + #include using namespace std::string_literals; diff --git a/louloulibs/utils/encoding.cpp b/louloulibs/utils/encoding.cpp index 60f2212..087095f 100644 --- a/louloulibs/utils/encoding.cpp +++ b/louloulibs/utils/encoding.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From 807ac95e798185aca35d6b2f3bf425a9c8b03744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 8 Dec 2016 02:32:49 +0100 Subject: Use a portable way to get the relative paths into __FILENAME__ --- louloulibs/CMakeLists.txt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/CMakeLists.txt b/louloulibs/CMakeLists.txt index 908c35f..c5ed7a7 100644 --- a/louloulibs/CMakeLists.txt +++ b/louloulibs/CMakeLists.txt @@ -6,10 +6,6 @@ set(${PROJECT_NAME}_VERSION_SUFFIX "~dev") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -pedantic -Wall -Wextra") -# Define a __FILENAME__ macro to get the filename of each file, instead of -# the full path as in __FILE__ -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='\"$(subst ${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'") - # ## Look for external libraries # @@ -143,6 +139,14 @@ if(SYSTEMD_FOUND) target_link_libraries(xmpplib ${SYSTEMD_LIBRARIES}) endif() +# Define a __FILENAME__ macro with the relative path (from the base project directory) +# of each source file +file(GLOB_RECURSE source_all *.[hc]pp) +foreach(file ${source_all}) + file(RELATIVE_PATH shorter_file ${CMAKE_CURRENT_SOURCE_DIR} ${file}) + set_property(SOURCE ${file} APPEND PROPERTY COMPILE_DEFINITIONS __FILENAME__="${shorter_file}") +endforeach() + # ## Check if we have std::get_time # -- cgit v1.2.3 From 7a8b4e37a508e27af8da25008676e913fdf24ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 8 Dec 2016 02:53:39 +0100 Subject: In time.cpp, use the en_US.UTF-8 locale, instead of en_US.utf-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (which apparently doesn’t work on freebsd) --- louloulibs/utils/time.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs') diff --git a/louloulibs/utils/time.cpp b/louloulibs/utils/time.cpp index afd6117..e3c49ed 100644 --- a/louloulibs/utils/time.cpp +++ b/louloulibs/utils/time.cpp @@ -24,7 +24,7 @@ std::time_t parse_datetime(const std::string& stamp) std::tm t = {}; #ifdef HAS_GET_TIME std::istringstream ss(stamp); - ss.imbue(std::locale("en_US.utf-8")); + ss.imbue(std::locale("en_US.UTF-8")); std::string timezone; ss >> std::get_time(&t, format) >> timezone; -- cgit v1.2.3 From 7f2eb6073761ebddc37d7872e44d621d719d6828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 8 Dec 2016 18:41:12 +0100 Subject: Init some members of TcpClientSocketHandler --- louloulibs/network/tcp_client_socket_handler.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/network/tcp_client_socket_handler.hpp b/louloulibs/network/tcp_client_socket_handler.hpp index 72f68d0..75e1364 100644 --- a/louloulibs/network/tcp_client_socket_handler.hpp +++ b/louloulibs/network/tcp_client_socket_handler.hpp @@ -62,9 +62,9 @@ class TCPClientSocketHandler: public TCPSocketHandler * triggered a EINPROGRESS error when connect()ing to it, to reuse it * directly when connect() is called again. */ - struct addrinfo addrinfo; - struct sockaddr_in6 ai_addr; - socklen_t ai_addrlen; + struct addrinfo addrinfo{}; + struct sockaddr_in6 ai_addr{}; + socklen_t ai_addrlen{}; /** * Hostname we are connected/connecting to @@ -75,7 +75,7 @@ class TCPClientSocketHandler: public TCPSocketHandler */ std::string port; - uint16_t local_port; + uint16_t local_port{}; bool connected; bool connecting; -- cgit v1.2.3 From e1e740e35edeccfc04d2808fc215c6a12698305f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 8 Dec 2016 21:25:20 +0100 Subject: =?UTF-8?q?Don=E2=80=99t=20use=20global=20static=20members=20but?= =?UTF-8?q?=20functions=20that=20return=20a=20reference=20to=20an=20intern?= =?UTF-8?q?al=20static=20object?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/randombit/botan/issues/761 --- louloulibs/network/tcp_socket_handler.cpp | 26 ++++++++++++++++++++------ louloulibs/network/tcp_socket_handler.hpp | 7 ------- 2 files changed, 20 insertions(+), 13 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/network/tcp_socket_handler.cpp b/louloulibs/network/tcp_socket_handler.cpp index 9d9a6aa..6aef2b1 100644 --- a/louloulibs/network/tcp_socket_handler.cpp +++ b/louloulibs/network/tcp_socket_handler.cpp @@ -15,10 +15,24 @@ # include # include -Botan::AutoSeeded_RNG TCPSocketHandler::rng; -BiboumiTLSPolicy TCPSocketHandler::policy; -Botan::TLS::Session_Manager_In_Memory TCPSocketHandler::session_manager(TCPSocketHandler::rng); - +namespace +{ + Botan::AutoSeeded_RNG& get_rng() + { + static Botan::AutoSeeded_RNG rng{}; + return rng; + } + BiboumiTLSPolicy& get_policy() + { + static BiboumiTLSPolicy policy{}; + return policy; + } + Botan::TLS::Session_Manager_In_Memory& get_session_manager() + { + static Botan::TLS::Session_Manager_In_Memory session_manager{get_rng()}; + return session_manager; + } +} #endif #ifndef UIO_FASTIOV @@ -229,8 +243,8 @@ void TCPSocketHandler::start_tls(const std::string& address, const std::string& [this](Botan::TLS::Alert alert, const Botan::byte*, size_t) { this->tls_alert(alert); }, [this](const Botan::TLS::Session& session) { return this->tls_session_established(session); }, # endif - session_manager, this->credential_manager, policy, - rng, server_info, Botan::TLS::Protocol_Version::latest_tls_version()); + get_session_manager(), this->credential_manager, get_policy(), + get_rng(), server_info, Botan::TLS::Protocol_Version::latest_tls_version()); } void TCPSocketHandler::tls_recv() diff --git a/louloulibs/network/tcp_socket_handler.hpp b/louloulibs/network/tcp_socket_handler.hpp index 3c6ff71..7fc40c2 100644 --- a/louloulibs/network/tcp_socket_handler.hpp +++ b/louloulibs/network/tcp_socket_handler.hpp @@ -222,14 +222,7 @@ protected: virtual void on_connection_close(const std::string&) {} virtual void on_connection_failed(const std::string&) {} -private: #ifdef BOTAN_FOUND - /** - * Botan stuff to manipulate a TLS session. - */ - static Botan::AutoSeeded_RNG rng; - static BiboumiTLSPolicy policy; - static Botan::TLS::Session_Manager_In_Memory session_manager; protected: BasicCredentialsManager credential_manager; private: -- cgit v1.2.3 From e63f79169b2c031bdc1a4bb6ba8df34363e9e3c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 9 Dec 2016 01:34:46 +0100 Subject: Use an other implementation of a null_stream for the logger --- louloulibs/logger/logger.cpp | 8 ++++++-- louloulibs/logger/logger.hpp | 18 ++++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/logger/logger.cpp b/louloulibs/logger/logger.cpp index 7336579..92a3d9b 100644 --- a/louloulibs/logger/logger.cpp +++ b/louloulibs/logger/logger.cpp @@ -3,14 +3,18 @@ Logger::Logger(const int log_level): log_level(log_level), - stream(std::cout.rdbuf()) + stream(std::cout.rdbuf()), + null_buffer{}, + null_stream{&null_buffer} { } Logger::Logger(const int log_level, const std::string& log_file): log_level(log_level), ofstream(log_file.data(), std::ios_base::app), - stream(ofstream.rdbuf()) + stream(ofstream.rdbuf()), + null_buffer{}, + null_stream{&null_buffer} { } diff --git a/louloulibs/logger/logger.hpp b/louloulibs/logger/logger.hpp index 0893c77..b3284a6 100644 --- a/louloulibs/logger/logger.hpp +++ b/louloulibs/logger/logger.hpp @@ -33,15 +33,15 @@ # define __FILENAME__ __FILE__ #endif + /** - * Juste a structure representing a stream doing nothing with its input. + * A buffer, used to construct an ostream that does nothing + * when we output data in it */ -class nullstream: public std::ostream +class NullBuffer: public std::streambuf { -public: - nullstream(): - std::ostream(0) - { } + public: + int overflow(int c) { return c; } }; class Logger @@ -59,9 +59,11 @@ public: private: const int log_level; - std::ofstream ofstream; - nullstream null_stream; + std::ofstream ofstream{}; std::ostream stream; + + NullBuffer null_buffer; + std::ostream null_stream; }; #define WHERE __FILENAME__, ":", __LINE__, ":\t" -- cgit v1.2.3 From 4cc3dc03fc8419abde6e77dceda773a19a246c43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sat, 10 Dec 2016 03:58:27 +0100 Subject: =?UTF-8?q?The=20config=20module=20doesn=E2=80=99t=20use=20the=20l?= =?UTF-8?q?ogger=20at=20all?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- louloulibs/CMakeLists.txt | 1 - louloulibs/config/config.cpp | 7 +++---- louloulibs/config/config.hpp | 1 - 3 files changed, 3 insertions(+), 6 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/CMakeLists.txt b/louloulibs/CMakeLists.txt index c5ed7a7..2251eed 100644 --- a/louloulibs/CMakeLists.txt +++ b/louloulibs/CMakeLists.txt @@ -99,7 +99,6 @@ target_link_libraries(utils ${ICONV_LIBRARIES}) file(GLOB source_config config/*.[hc]pp) add_library(config STATIC ${source_config}) -target_link_libraries(config utils) # ## logger diff --git a/louloulibs/config/config.cpp b/louloulibs/config/config.cpp index 417981d..24a1c87 100644 --- a/louloulibs/config/config.cpp +++ b/louloulibs/config/config.cpp @@ -1,8 +1,7 @@ #include -#include +#include #include -#include #include @@ -66,7 +65,7 @@ bool Config::read_conf(const std::string& name) std::ifstream file(Config::filename.data()); if (!file.is_open()) { - log_error("Error while opening file ", filename, " for reading: ", strerror(errno)); + std::cerr << "Error while opening file " << filename << " for reading: " << strerror(errno) << std::endl; return false; } @@ -96,7 +95,7 @@ void Config::save_to_file() std::ofstream file(Config::filename.data()); if (file.fail()) { - log_error("Could not save config file."); + std::cerr << "Could not save config file." << std::endl; return ; } for (const auto& it: Config::values) diff --git a/louloulibs/config/config.hpp b/louloulibs/config/config.hpp index 6728df8..4e01281 100644 --- a/louloulibs/config/config.hpp +++ b/louloulibs/config/config.hpp @@ -15,7 +15,6 @@ #pragma once - #include #include #include -- cgit v1.2.3 From f9c31cb129b17d57281c87b549b382957dca425e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sat, 10 Dec 2016 03:59:26 +0100 Subject: The logger writes to std::clog --- louloulibs/logger/logger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs') diff --git a/louloulibs/logger/logger.cpp b/louloulibs/logger/logger.cpp index 92a3d9b..79f9e8f 100644 --- a/louloulibs/logger/logger.cpp +++ b/louloulibs/logger/logger.cpp @@ -3,7 +3,7 @@ Logger::Logger(const int log_level): log_level(log_level), - stream(std::cout.rdbuf()), + stream(std::clog.rdbuf()), null_buffer{}, null_stream{&null_buffer} { -- cgit v1.2.3 From c65ae4754921fe1f9888afc30d26ed11d5275258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 12 Dec 2016 00:36:59 +0100 Subject: Auto accept presence subscription --- louloulibs/xmpp/xmpp_component.hpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/xmpp/xmpp_component.hpp b/louloulibs/xmpp/xmpp_component.hpp index e3f8ce2..a9bac0f 100644 --- a/louloulibs/xmpp/xmpp_component.hpp +++ b/louloulibs/xmpp/xmpp_component.hpp @@ -178,10 +178,6 @@ public: const std::string& affiliation, const std::string& role, const std::string& jid_to); - /** - * Send a result IQ with the gateway disco informations. - */ - void send_self_disco_info(const std::string& id, const std::string& jid_to); /** * Send a result IQ with the given version, or the gateway version if the * passed string is empty. -- cgit v1.2.3 From 2e4a9fe4c78bb45de912d2e5b90106397d59348e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 13 Dec 2016 22:47:19 +0100 Subject: Include the optional node in the send_presence_error --- louloulibs/xmpp/xmpp_component.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'louloulibs') diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index 1d1c58b..c842701 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -524,7 +524,7 @@ void XmppComponent::send_presence_error(const std::string& muc_name, const std::string& type, const std::string& condition, const std::string& error_code, - const std::string& /* text */) + const std::string& text) { Stanza presence("presence"); presence["from"] = muc_name + "@" + this->served_hostname + "/" + nickname; @@ -536,6 +536,12 @@ void XmppComponent::send_presence_error(const std::string& muc_name, XmlNode error("error"); error["by"] = muc_name + "@" + this->served_hostname; error["type"] = type; + if (text.empty()) + { + XmlNode text_node("text"); + text_node["xmlns"] = STANZA_NS; + text_node.set_inner(text); + } if (!error_code.empty()) error["code"] = error_code; XmlNode subnode(condition); -- cgit v1.2.3 From 810c4343c72b0a5ac61155f2a71a969fc5f8ea9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 13 Dec 2016 23:01:32 +0100 Subject: Remove the useless nullptr argument for the XmlNode constructor --- louloulibs/xmpp/xmpp_component.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index c842701..32702d1 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -172,8 +172,8 @@ void XmppComponent::on_stanza(const Stanza& stanza) void XmppComponent::send_stream_error(const std::string& name, const std::string& explanation) { - XmlNode node("stream:error", nullptr); - XmlNode error(name, nullptr); + XmlNode node("stream:error"); + XmlNode error(name); error["xmlns"] = STREAM_NS; if (!explanation.empty()) error.set_inner(explanation); -- cgit v1.2.3 From 6b245ee64a828dd86da0acf6ffb56b618b170ca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 13 Dec 2016 23:37:43 +0100 Subject: Switch back to using std::cout instead of std::clog --- louloulibs/logger/logger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs') diff --git a/louloulibs/logger/logger.cpp b/louloulibs/logger/logger.cpp index 79f9e8f..92a3d9b 100644 --- a/louloulibs/logger/logger.cpp +++ b/louloulibs/logger/logger.cpp @@ -3,7 +3,7 @@ Logger::Logger(const int log_level): log_level(log_level), - stream(std::clog.rdbuf()), + stream(std::cout.rdbuf()), null_buffer{}, null_stream{&null_buffer} { -- cgit v1.2.3 From ca8618941240545f76fd8ec32e7acb31226ab2d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 13 Dec 2016 23:57:19 +0100 Subject: Include the element in stanza error when there IS a text --- louloulibs/xmpp/xmpp_component.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs') diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index 32702d1..cbd80c4 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -536,7 +536,7 @@ void XmppComponent::send_presence_error(const std::string& muc_name, XmlNode error("error"); error["by"] = muc_name + "@" + this->served_hostname; error["type"] = type; - if (text.empty()) + if (!text.empty()) { XmlNode text_node("text"); text_node["xmlns"] = STANZA_NS; -- cgit v1.2.3 From f512c9c666b2c629e8b9af29ec65c534e536e749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 14 Dec 2016 18:20:57 +0100 Subject: e2e: test connection failure --- louloulibs/xmpp/xmpp_component.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'louloulibs') diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index cbd80c4..f0b0de7 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -541,6 +541,7 @@ void XmppComponent::send_presence_error(const std::string& muc_name, XmlNode text_node("text"); text_node["xmlns"] = STANZA_NS; text_node.set_inner(text); + error.add_child(std::move(text_node)); } if (!error_code.empty()) error["code"] = error_code; -- cgit v1.2.3 From 5a5bb7f63222189ea0dcfbd387d5e34458ccefe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 14 Dec 2016 18:28:44 +0100 Subject: Introduce a XmlSubNode class that automatically adds itself into its parent --- louloulibs/xmpp/adhoc_command.cpp | 32 +- louloulibs/xmpp/adhoc_commands_handler.cpp | 30 +- louloulibs/xmpp/xmpp_component.cpp | 539 ++++++++++++++--------------- louloulibs/xmpp/xmpp_stanza.hpp | 14 + 4 files changed, 302 insertions(+), 313 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/xmpp/adhoc_command.cpp b/louloulibs/xmpp/adhoc_command.cpp index 99701d7..08d2d17 100644 --- a/louloulibs/xmpp/adhoc_command.cpp +++ b/louloulibs/xmpp/adhoc_command.cpp @@ -18,30 +18,24 @@ bool AdhocCommand::is_admin_only() const void PingStep1(XmppComponent&, AdhocSession&, XmlNode& command_node) { - XmlNode note("note"); + XmlSubNode note(command_node, "note"); note["type"] = "info"; note.set_inner("Pong"); - command_node.add_child(std::move(note)); } void HelloStep1(XmppComponent&, AdhocSession&, XmlNode& command_node) { - XmlNode x("jabber:x:data:x"); + XmlSubNode x(command_node, "jabber:x:data:x"); x["type"] = "form"; - XmlNode title("title"); + XmlSubNode title(x, "title"); title.set_inner("Configure your name."); - x.add_child(std::move(title)); - XmlNode instructions("instructions"); + XmlSubNode instructions(x, "instructions"); instructions.set_inner("Please provide your name."); - x.add_child(std::move(instructions)); - XmlNode name_field("field"); + XmlSubNode name_field(x, "field"); name_field["var"] = "name"; name_field["type"] = "text-single"; name_field["label"] = "Your name"; - XmlNode required("required"); - name_field.add_child(std::move(required)); - x.add_child(std::move(name_field)); - command_node.add_child(std::move(x)); + XmlSubNode required(name_field, "required"); } void HelloStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node) @@ -60,21 +54,18 @@ void HelloStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node) { if (const XmlNode* value = name_field->get_child("value", "jabber:x:data")) { - XmlNode note("note"); + command_node.delete_all_children(); + XmlSubNode note(command_node, "note"); note["type"] = "info"; note.set_inner("Hello "s + value->get_inner() + "!"s); - command_node.delete_all_children(); - command_node.add_child(std::move(note)); return; } } } command_node.delete_all_children(); - XmlNode error(ADHOC_NS":error"); + XmlSubNode error(command_node, ADHOC_NS":error"); error["type"] = "modify"; - XmlNode condition(STANZA_NS":bad-request"); - error.add_child(std::move(condition)); - command_node.add_child(std::move(error)); + XmlSubNode condition(error, STANZA_NS":bad-request"); session.terminate(); } @@ -82,8 +73,7 @@ void Reload(XmppComponent&, AdhocSession&, XmlNode& command_node) { ::reload_process(); command_node.delete_all_children(); - XmlNode note("note"); + XmlSubNode note(command_node, "note"); note["type"] = "info"; note.set_inner("Configuration reloaded."); - command_node.add_child(std::move(note)); } diff --git a/louloulibs/xmpp/adhoc_commands_handler.cpp b/louloulibs/xmpp/adhoc_commands_handler.cpp index 540cac0..d3ede2d 100644 --- a/louloulibs/xmpp/adhoc_commands_handler.cpp +++ b/louloulibs/xmpp/adhoc_commands_handler.cpp @@ -36,20 +36,16 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, co auto command_it = this->commands.find(node); if (command_it == this->commands.end()) { - XmlNode error(ADHOC_NS":error"); + XmlSubNode error(command_node, ADHOC_NS":error"); error["type"] = "cancel"; - XmlNode condition(STANZA_NS":item-not-found"); - error.add_child(std::move(condition)); - command_node.add_child(std::move(error)); + XmlSubNode condition(error, STANZA_NS":item-not-found"); } else if (command_it->second.is_admin_only() && Config::get("admin", "") != jid.local + "@" + jid.domain) { - XmlNode error(ADHOC_NS":error"); + XmlSubNode error(command_node, ADHOC_NS":error"); error["type"] = "cancel"; - XmlNode condition(STANZA_NS":forbidden"); - error.add_child(std::move(condition)); - command_node.add_child(std::move(error)); + XmlSubNode condition(error, STANZA_NS":forbidden"); } else { @@ -68,11 +64,9 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, co auto session_it = this->sessions.find(std::make_pair(sessionid, executor_jid)); if (session_it == this->sessions.end()) { - XmlNode error(ADHOC_NS":error"); + XmlSubNode error(command_node, ADHOC_NS":error"); error["type"] = "modify"; - XmlNode condition(STANZA_NS":bad-request"); - error.add_child(std::move(condition)); - command_node.add_child(std::move(error)); + XmlSubNode condition(error, STANZA_NS":bad-request"); } else if (action == "execute" || action == "next" || action == "complete") { @@ -90,10 +84,8 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, co else { command_node["status"] = "executing"; - XmlNode actions("actions"); - XmlNode next("next"); - actions.add_child(std::move(next)); - command_node.add_child(std::move(actions)); + XmlSubNode actions(command_node, "actions"); + XmlSubNode next(actions, "next"); } } else if (action == "cancel") @@ -104,11 +96,9 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, co } else // unsupported action { - XmlNode error(ADHOC_NS":error"); + XmlSubNode error(command_node, ADHOC_NS":error"); error["type"] = "modify"; - XmlNode condition(STANZA_NS":bad-request"); - error.add_child(std::move(condition)); - command_node.add_child(std::move(error)); + XmlSubNode condition(error, STANZA_NS":bad-request"); } } return command_node; diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index f0b0de7..e1b6131 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -172,12 +172,13 @@ void XmppComponent::on_stanza(const Stanza& stanza) void XmppComponent::send_stream_error(const std::string& name, const std::string& explanation) { - XmlNode node("stream:error"); - XmlNode error(name); - error["xmlns"] = STREAM_NS; - if (!explanation.empty()) - error.set_inner(explanation); - node.add_child(std::move(error)); + Stanza node("stream:error"); + { + XmlSubNode error(node, name); + error["xmlns"] = STREAM_NS; + if (!explanation.empty()) + error.set_inner(explanation); + } this->send_stanza(node); } @@ -187,31 +188,34 @@ void XmppComponent::send_stanza_error(const std::string& kind, const std::string const bool fulljid) { Stanza node(kind); - if (!to.empty()) - node["to"] = to; - if (!from.empty()) + { + if (!to.empty()) + node["to"] = to; + if (!from.empty()) + { + if (fulljid) + node["from"] = from; + else + node["from"] = from + "@" + this->served_hostname; + } + if (!id.empty()) + node["id"] = id; + node["type"] = "error"; { - if (fulljid) - node["from"] = from; - else - node["from"] = from + "@" + this->served_hostname; + XmlSubNode error(node, "error"); + error["type"] = error_type; + { + XmlSubNode inner_error(error, defined_condition); + inner_error["xmlns"] = STANZA_NS; + } + if (!text.empty()) + { + XmlSubNode text_node(error, "text"); + text_node["xmlns"] = STANZA_NS; + text_node.set_inner(text); + } } - if (!id.empty()) - node["id"] = id; - node["type"] = "error"; - XmlNode error("error"); - error["type"] = error_type; - XmlNode inner_error(defined_condition); - inner_error["xmlns"] = STANZA_NS; - error.add_child(std::move(inner_error)); - if (!text.empty()) - { - XmlNode text_node("text"); - text_node["xmlns"] = STANZA_NS; - text_node.set_inner(text); - error.add_child(std::move(text_node)); - } - node.add_child(std::move(error)); + } this->send_stanza(node); } @@ -264,38 +268,33 @@ void* XmppComponent::get_receive_buffer(const size_t size) const void XmppComponent::send_message(const std::string& from, Xmpp::body&& body, const std::string& to, const std::string& type, const bool fulljid, const bool nocopy) { - XmlNode node("message"); - node["to"] = to; - if (fulljid) - node["from"] = from; - else - node["from"] = from + "@" + this->served_hostname; - if (!type.empty()) - node["type"] = type; - XmlNode body_node("body"); - body_node.set_inner(std::get<0>(body)); - node.add_child(std::move(body_node)); - if (std::get<1>(body)) - { - XmlNode html("html"); - html["xmlns"] = XHTMLIM_NS; - // Pass the ownership of the pointer to this xmlnode - html.add_child(std::move(std::get<1>(body))); - node.add_child(std::move(html)); - } - - if (nocopy) - { - XmlNode private_node("private"); - private_node["xmlns"] = "urn:xmpp:carbons:2"; - node.add_child(std::move(private_node)); - - XmlNode nocopy("no-copy"); - nocopy["xmlns"] = "urn:xmpp:hints"; - node.add_child(std::move(nocopy)); - } - - this->send_stanza(node); + Stanza message("message"); + { + message["to"] = to; + if (fulljid) + message["from"] = from; + else + message["from"] = from + "@" + this->served_hostname; + if (!type.empty()) + message["type"] = type; + XmlSubNode body_node(message, "body"); + body_node.set_inner(std::get<0>(body)); + if (std::get<1>(body)) + { + XmlSubNode html(message, "html"); + html["xmlns"] = XHTMLIM_NS; + // Pass the ownership of the pointer to this xmlnode + html.add_child(std::move(std::get<1>(body))); + } + if (nocopy) + { + XmlSubNode private_node(message, "private"); + private_node["xmlns"] = "urn:xmpp:carbons:2"; + XmlSubNode nocopy(message, "no-copy"); + nocopy["xmlns"] = "urn:xmpp:hints"; + } + } + this->send_stanza(message); } void XmppComponent::send_user_join(const std::string& from, @@ -306,34 +305,33 @@ void XmppComponent::send_user_join(const std::string& from, const std::string& to, const bool self) { - XmlNode node("presence"); - node["to"] = to; - node["from"] = from + "@" + this->served_hostname + "/" + nick; - - XmlNode x("x"); - x["xmlns"] = MUC_USER_NS; - - XmlNode item("item"); - if (!affiliation.empty()) - item["affiliation"] = affiliation; - if (!role.empty()) - item["role"] = role; - if (!realjid.empty()) - { - const std::string preped_jid = jidprep(realjid); - if (!preped_jid.empty()) - item["jid"] = preped_jid; - } - x.add_child(std::move(item)); - - if (self) - { - XmlNode status("status"); - status["code"] = "110"; - x.add_child(std::move(status)); - } - node.add_child(std::move(x)); - this->send_stanza(node); + Stanza presence("presence"); + { + presence["to"] = to; + presence["from"] = from + "@" + this->served_hostname + "/" + nick; + + XmlSubNode x(presence, "x"); + x["xmlns"] = MUC_USER_NS; + + XmlSubNode item(x, "item"); + if (!affiliation.empty()) + item["affiliation"] = affiliation; + if (!role.empty()) + item["role"] = role; + if (!realjid.empty()) + { + const std::string preped_jid = jidprep(realjid); + if (!preped_jid.empty()) + item["jid"] = preped_jid; + } + + if (self) + { + XmlSubNode status(x, "status"); + status["code"] = "110"; + } + } + this->send_stanza(presence); } void XmppComponent::send_invalid_room_error(const std::string& muc_name, @@ -341,44 +339,43 @@ void XmppComponent::send_invalid_room_error(const std::string& muc_name, const std::string& to) { Stanza presence("presence"); - if (!muc_name.empty()) - presence["from"] = muc_name + "@" + this->served_hostname + "/" + nick; - else - presence["from"] = this->served_hostname; - presence["to"] = to; - presence["type"] = "error"; - XmlNode x("x"); - x["xmlns"] = MUC_NS; - presence.add_child(std::move(x)); - XmlNode error("error"); - error["by"] = muc_name + "@" + this->served_hostname; - error["type"] = "cancel"; - XmlNode item_not_found("item-not-found"); - item_not_found["xmlns"] = STANZA_NS; - error.add_child(std::move(item_not_found)); - XmlNode text("text"); - text["xmlns"] = STANZA_NS; - text["xml:lang"] = "en"; - text.set_inner(muc_name + - " is not a valid IRC channel name. A correct room jid is of the form: #%@" + - this->served_hostname); - error.add_child(std::move(text)); - presence.add_child(std::move(error)); + { + if (!muc_name.empty ()) + presence["from"] = muc_name + "@" + this->served_hostname + "/" + nick; + else + presence["from"] = this->served_hostname; + presence["to"] = to; + presence["type"] = "error"; + XmlSubNode x(presence, "x"); + x["xmlns"] = MUC_NS; + XmlSubNode error(presence, "error"); + error["by"] = muc_name + "@" + this->served_hostname; + error["type"] = "cancel"; + XmlSubNode item_not_found(error, "item-not-found"); + item_not_found["xmlns"] = STANZA_NS; + XmlSubNode text(error, "text"); + text["xmlns"] = STANZA_NS; + text["xml:lang"] = "en"; + text.set_inner(muc_name + + " is not a valid IRC channel name. A correct room jid is of the form: #%@" + + this->served_hostname); + } this->send_stanza(presence); } void XmppComponent::send_topic(const std::string& from, Xmpp::body&& topic, const std::string& to, const std::string& who) { - XmlNode message("message"); - message["to"] = to; - if (who.empty()) - message["from"] = from + "@" + this->served_hostname; - else - message["from"] = from + "@" + this->served_hostname + "/" + who; - message["type"] = "groupchat"; - XmlNode subject("subject"); - subject.set_inner(std::get<0>(topic)); - message.add_child(std::move(subject)); + Stanza message("message"); + { + message["to"] = to; + if (who.empty()) + message["from"] = from + "@" + this->served_hostname; + else + message["from"] = from + "@" + this->served_hostname + "/" + who; + message["type"] = "groupchat"; + XmlSubNode subject(message, "subject"); + subject.set_inner(std::get<0>(topic)); + } this->send_stanza(message); } @@ -391,16 +388,18 @@ void XmppComponent::send_muc_message(const std::string& muc_name, const std::str else // Message from the room itself message["from"] = muc_name + "@" + this->served_hostname; message["type"] = "groupchat"; - XmlNode body("body"); - body.set_inner(std::get<0>(xmpp_body)); - message.add_child(std::move(body)); + + { + XmlSubNode body(message, "body"); + body.set_inner(std::get<0>(xmpp_body)); + } + if (std::get<1>(xmpp_body)) { - XmlNode html("html"); + XmlSubNode html(message, "html"); html["xmlns"] = XHTMLIM_NS; // Pass the ownership of the pointer to this xmlnode html.add_child(std::move(std::get<1>(xmpp_body))); - message.add_child(std::move(html)); } this->send_stanza(message); } @@ -415,41 +414,41 @@ void XmppComponent::send_history_message(const std::string& muc_name, const std: message["from"] = muc_name + "@" + this->served_hostname; message["type"] = "groupchat"; - XmlNode body("body"); - body.set_inner(body_txt); - message.add_child(std::move(body)); - - XmlNode delay("delay"); - delay["xmlns"] = DELAY_NS; - delay["from"] = muc_name + "@" + this->served_hostname; - delay["stamp"] = utils::to_string(timestamp); + { + XmlSubNode body(message, "body"); + body.set_inner(body_txt); + } + { + XmlSubNode delay(message, "delay"); + delay["xmlns"] = DELAY_NS; + delay["from"] = muc_name + "@" + this->served_hostname; + delay["stamp"] = utils::to_string(timestamp); + } - message.add_child(std::move(delay)); this->send_stanza(message); } void XmppComponent::send_muc_leave(const std::string& muc_name, std::string&& nick, Xmpp::body&& message, const std::string& jid_to, const bool self) { Stanza presence("presence"); - presence["to"] = jid_to; - presence["from"] = muc_name + "@" + this->served_hostname + "/" + nick; - presence["type"] = "unavailable"; - const std::string message_str = std::get<0>(message); - XmlNode x("x"); - x["xmlns"] = MUC_USER_NS; - if (self) - { - XmlNode status("status"); - status["code"] = "110"; - x.add_child(std::move(status)); - } - presence.add_child(std::move(x)); - if (!message_str.empty()) - { - XmlNode status("status"); - status.set_inner(message_str); - presence.add_child(std::move(status)); - } + { + presence["to"] = jid_to; + presence["from"] = muc_name + "@" + this->served_hostname + "/" + nick; + presence["type"] = "unavailable"; + const std::string message_str = std::get<0>(message); + XmlSubNode x(presence, "x"); + x["xmlns"] = MUC_USER_NS; + if (self) + { + XmlSubNode status(x, "status"); + status["code"] = "110"; + } + if (!message_str.empty()) + { + XmlSubNode status(presence, "status"); + status.set_inner(message_str); + } + } this->send_stanza(presence); } @@ -462,24 +461,22 @@ void XmppComponent::send_nick_change(const std::string& muc_name, const bool self) { Stanza presence("presence"); - presence["to"] = jid_to; - presence["from"] = muc_name + "@" + this->served_hostname + "/" + old_nick; - presence["type"] = "unavailable"; - XmlNode x("x"); - x["xmlns"] = MUC_USER_NS; - XmlNode item("item"); - item["nick"] = new_nick; - x.add_child(std::move(item)); - XmlNode status("status"); - status["code"] = "303"; - x.add_child(std::move(status)); - if (self) - { - XmlNode status2("status"); - status2["code"] = "110"; - x.add_child(std::move(status2)); - } - presence.add_child(std::move(x)); + { + presence["to"] = jid_to; + presence["from"] = muc_name + "@" + this->served_hostname + "/" + old_nick; + presence["type"] = "unavailable"; + XmlSubNode x(presence, "x"); + x["xmlns"] = MUC_USER_NS; + XmlSubNode item(x, "item"); + item["nick"] = new_nick; + XmlSubNode status(x, "status"); + status["code"] = "303"; + if (self) + { + XmlSubNode status(x, "status"); + status["code"] = "110"; + } + } this->send_stanza(presence); this->send_user_join(muc_name, new_nick, "", affiliation, role, jid_to, self); @@ -489,32 +486,28 @@ void XmppComponent::kick_user(const std::string& muc_name, const std::string& ta const std::string& author, const std::string& jid_to, const bool self) { Stanza presence("presence"); - presence["from"] = muc_name + "@" + this->served_hostname + "/" + target; - presence["to"] = jid_to; - presence["type"] = "unavailable"; - XmlNode x("x"); - x["xmlns"] = MUC_USER_NS; - XmlNode item("item"); - item["affiliation"] = "none"; - item["role"] = "none"; - XmlNode actor("actor"); - actor["nick"] = author; - actor["jid"] = author; // backward compatibility with old clients - item.add_child(std::move(actor)); - XmlNode reason("reason"); - reason.set_inner(txt); - item.add_child(std::move(reason)); - x.add_child(std::move(item)); - XmlNode status("status"); - status["code"] = "307"; - x.add_child(std::move(status)); - if (self) - { - XmlNode status("status"); - status["code"] = "110"; - x.add_child(std::move(status)); - } - presence.add_child(std::move(x)); + { + presence["from"] = muc_name + "@" + this->served_hostname + "/" + target; + presence["to"] = jid_to; + presence["type"] = "unavailable"; + XmlSubNode x(presence, "x"); + x["xmlns"] = MUC_USER_NS; + XmlSubNode item(x, "item"); + item["affiliation"] = "none"; + item["role"] = "none"; + XmlSubNode actor(item, "actor"); + actor["nick"] = author; + actor["jid"] = author; // backward compatibility with old clients + XmlSubNode reason(item, "reason"); + reason.set_inner(txt); + XmlSubNode status(x, "status"); + status["code"] = "307"; + if (self) + { + XmlSubNode status(x, "status"); + status["code"] = "110"; + } + } this->send_stanza(presence); } @@ -527,28 +520,26 @@ void XmppComponent::send_presence_error(const std::string& muc_name, const std::string& text) { Stanza presence("presence"); - presence["from"] = muc_name + "@" + this->served_hostname + "/" + nickname; - presence["to"] = jid_to; - presence["type"] = "error"; - XmlNode x("x"); - x["xmlns"] = MUC_NS; - presence.add_child(std::move(x)); - XmlNode error("error"); - error["by"] = muc_name + "@" + this->served_hostname; - error["type"] = type; - if (!text.empty()) - { - XmlNode text_node("text"); - text_node["xmlns"] = STANZA_NS; - text_node.set_inner(text); - error.add_child(std::move(text_node)); - } - if (!error_code.empty()) - error["code"] = error_code; - XmlNode subnode(condition); - subnode["xmlns"] = STANZA_NS; - error.add_child(std::move(subnode)); - presence.add_child(std::move(error)); + { + presence["from"] = muc_name + "@" + this->served_hostname + "/" + nickname; + presence["to"] = jid_to; + presence["type"] = "error"; + XmlSubNode x(presence, "x"); + x["xmlns"] = MUC_NS; + XmlSubNode error(presence, "error"); + error["by"] = muc_name + "@" + this->served_hostname; + error["type"] = type; + if (!text.empty()) + { + XmlSubNode text_node(error, "text"); + text_node["xmlns"] = STANZA_NS; + text_node.set_inner(text); + } + if (!error_code.empty()) + error["code"] = error_code; + XmlSubNode subnode(error, condition); + subnode["xmlns"] = STANZA_NS; + } this->send_stanza(presence); } @@ -559,15 +550,15 @@ void XmppComponent::send_affiliation_role_change(const std::string& muc_name, const std::string& jid_to) { Stanza presence("presence"); - presence["from"] = muc_name + "@" + this->served_hostname + "/" + target; - presence["to"] = jid_to; - XmlNode x("x"); - x["xmlns"] = MUC_USER_NS; - XmlNode item("item"); - item["affiliation"] = affiliation; - item["role"] = role; - x.add_child(std::move(item)); - presence.add_child(std::move(x)); + { + presence["from"] = muc_name + "@" + this->served_hostname + "/" + target; + presence["to"] = jid_to; + XmlSubNode x(presence, "x"); + x["xmlns"] = MUC_USER_NS; + XmlSubNode item(x, "item"); + item["affiliation"] = affiliation; + item["role"] = role; + } this->send_stanza(presence); } @@ -579,27 +570,30 @@ void XmppComponent::send_version(const std::string& id, const std::string& jid_t iq["id"] = id; iq["to"] = jid_to; iq["from"] = jid_from; - XmlNode query("query"); - query["xmlns"] = VERSION_NS; - if (version.empty()) - { - XmlNode name("name"); - name.set_inner("biboumi"); - query.add_child(std::move(name)); - XmlNode version("version"); - version.set_inner(SOFTWARE_VERSION); - query.add_child(std::move(version)); - XmlNode os("os"); - os.set_inner(SYSTEM_NAME); - query.add_child(std::move(os)); + { + XmlSubNode query(iq, "query"); + query["xmlns"] = VERSION_NS; + if (version.empty()) + { + { + XmlSubNode name(query, "name"); + name.set_inner("biboumi"); + } + { + XmlSubNode version(query, "version"); + version.set_inner(SOFTWARE_VERSION); + } + { + XmlSubNode os(query, "os"); + os.set_inner(SYSTEM_NAME); + } } - else + else { - XmlNode name("name"); + XmlSubNode name(query, "name"); name.set_inner(version); - query.add_child(std::move(name)); } - iq.add_child(std::move(query)); + } this->send_stanza(iq); } @@ -608,24 +602,24 @@ void XmppComponent::send_adhoc_commands_list(const std::string& id, const std::s const bool with_admin_only, const AdhocCommandsHandler& adhoc_handler) { Stanza iq("iq"); - iq["type"] = "result"; - iq["id"] = id; - iq["to"] = requester_jid; - iq["from"] = from_jid; - XmlNode query("query"); - query["xmlns"] = DISCO_ITEMS_NS; - query["node"] = ADHOC_NS; - for (const auto& kv: adhoc_handler.get_commands()) - { - if (kv.second.is_admin_only() && !with_admin_only) - continue; - XmlNode item("item"); - item["jid"] = from_jid; - item["node"] = kv.first; - item["name"] = kv.second.name; - query.add_child(std::move(item)); - } - iq.add_child(std::move(query)); + { + iq["type"] = "result"; + iq["id"] = id; + iq["to"] = requester_jid; + iq["from"] = from_jid; + XmlSubNode query(iq, "query"); + query["xmlns"] = DISCO_ITEMS_NS; + query["node"] = ADHOC_NS; + for (const auto &kv: adhoc_handler.get_commands()) + { + if (kv.second.is_admin_only() && !with_admin_only) + continue; + XmlSubNode item(query, "item"); + item["jid"] = from_jid; + item["node"] = kv.first; + item["name"] = kv.second.name; + } + } this->send_stanza(iq); } @@ -633,13 +627,14 @@ void XmppComponent::send_iq_version_request(const std::string& from, const std::string& jid_to) { Stanza iq("iq"); - iq["type"] = "get"; - iq["id"] = "version_"s + XmppComponent::next_id(); - iq["from"] = from + "@" + this->served_hostname; - iq["to"] = jid_to; - XmlNode query("query"); - query["xmlns"] = VERSION_NS; - iq.add_child(std::move(query)); + { + iq["type"] = "get"; + iq["id"] = "version_"s + XmppComponent::next_id(); + iq["from"] = from + "@" + this->served_hostname; + iq["to"] = jid_to; + XmlSubNode query(iq, "query"); + query["xmlns"] = VERSION_NS; + } this->send_stanza(iq); } diff --git a/louloulibs/xmpp/xmpp_stanza.hpp b/louloulibs/xmpp/xmpp_stanza.hpp index 4ca758e..f4b3948 100644 --- a/louloulibs/xmpp/xmpp_stanza.hpp +++ b/louloulibs/xmpp/xmpp_stanza.hpp @@ -143,4 +143,18 @@ std::ostream& operator<<(std::ostream& os, const XmlNode& node); */ using Stanza = XmlNode; +class XmlSubNode: public XmlNode +{ +public: + XmlSubNode(XmlNode& parent_ref, const std::string& name): + XmlNode(name), + parent_to_add(parent_ref) + {} + ~XmlSubNode() + { + this->parent_to_add.add_child(std::move(*this)); + } +private: + XmlNode& parent_to_add; +}; \ No newline at end of file -- cgit v1.2.3 From 5b56007828f20c763df3f36ceed809188880663e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 6 Jan 2017 22:58:18 +0100 Subject: Use udns instead of c-ares fix #3226 --- louloulibs/CMakeLists.txt | 20 +- louloulibs/cmake/Modules/FindCARES.cmake | 37 --- louloulibs/cmake/Modules/FindUDNS.cmake | 37 +++ louloulibs/louloulibs.h.cmake | 2 +- louloulibs/network/dns_handler.cpp | 125 ++-------- louloulibs/network/dns_handler.hpp | 46 +--- louloulibs/network/dns_socket_handler.cpp | 32 ++- louloulibs/network/dns_socket_handler.hpp | 29 +-- louloulibs/network/resolver.cpp | 280 ++++++++++++++--------- louloulibs/network/resolver.hpp | 45 ++-- louloulibs/network/tcp_client_socket_handler.cpp | 6 +- 11 files changed, 294 insertions(+), 365 deletions(-) delete mode 100644 louloulibs/cmake/Modules/FindCARES.cmake create mode 100644 louloulibs/cmake/Modules/FindUDNS.cmake (limited to 'louloulibs') diff --git a/louloulibs/CMakeLists.txt b/louloulibs/CMakeLists.txt index 2251eed..f672833 100644 --- a/louloulibs/CMakeLists.txt +++ b/louloulibs/CMakeLists.txt @@ -33,10 +33,10 @@ elseif(NOT WITHOUT_BOTAN) find_package(BOTAN) endif() -if(WITH_CARES) - find_package(CARES REQUIRED) -elseif(NOT WITHOUT_CARES) - find_package(CARES) +if(WITH_UDNS) + find_package(UDNS REQUIRED) +elseif(NOT WITHOUT_UDNS) + find_package(UDNS) endif() # To be able to include the config.h file generated by cmake @@ -68,10 +68,10 @@ if(BOTAN_FOUND) set(BOTAN_INCLUDE_DIRS ${BOTAN_INCLUDE_DIRS} PARENT_SCOPE) endif() -if(CARES_FOUND) - include_directories(${CARES_INCLUDE_DIRS}) - set(CARES_FOUND ${CARES_FOUND} PARENT_SCOPE) - set(CARES_INCLUDE_DIRS ${CARES_INCLUDE_DIRS} PARENT_SCOPE) +if(UDNS_FOUND) + include_directories(${UDNS_INCLUDE_DIRS}) + set(UDNS_FOUND ${UDNS_FOUND} PARENT_SCOPE) + set(UDNS_INCLUDE_DIRS ${UDNS_INCLUDE_DIRS} PARENT_SCOPE) endif() set(POLLER_DOCSTRING "Choose the poller between POLL and EPOLL (Linux-only)") @@ -118,8 +118,8 @@ target_link_libraries(network logger) if(BOTAN_FOUND) target_link_libraries(network ${BOTAN_LIBRARIES}) endif() -if(CARES_FOUND) - target_link_libraries(network ${CARES_LIBRARIES}) +if(UDNS_FOUND) + target_link_libraries(network ${UDNS_LIBRARIES}) endif() # diff --git a/louloulibs/cmake/Modules/FindCARES.cmake b/louloulibs/cmake/Modules/FindCARES.cmake deleted file mode 100644 index c4c757a..0000000 --- a/louloulibs/cmake/Modules/FindCARES.cmake +++ /dev/null @@ -1,37 +0,0 @@ -# - Find c-ares -# Find the c-ares library, and more particularly the stringprep header. -# -# This module defines the following variables: -# CARES_FOUND - True if library and include directory are found -# If set to TRUE, the following are also defined: -# CARES_INCLUDE_DIRS - The directory where to find the header file -# CARES_LIBRARIES - Where to find the library file -# -# For conveniance, these variables are also set. They have the same values -# than the variables above. The user can thus choose his/her prefered way -# to write them. -# CARES_INCLUDE_DIR -# CARES_LIBRARY -# -# This file is in the public domain - -if(NOT CARES_FOUND) - find_path(CARES_INCLUDE_DIRS NAMES ares.h - DOC "The c-ares include directory") - - find_library(CARES_LIBRARIES NAMES cares - DOC "The c-ares library") - - # Use some standard module to handle the QUIETLY and REQUIRED arguments, and - # set CARES_FOUND to TRUE if these two variables are set. - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(CARES REQUIRED_VARS CARES_LIBRARIES CARES_INCLUDE_DIRS) - - # Compatibility for all the ways of writing these variables - if(CARES_FOUND) - set(CARES_INCLUDE_DIR ${CARES_INCLUDE_DIRS}) - set(CARES_LIBRARY ${CARES_LIBRARIES}) - endif() -endif() - -mark_as_advanced(CARES_INCLUDE_DIRS CARES_LIBRARIES) diff --git a/louloulibs/cmake/Modules/FindUDNS.cmake b/louloulibs/cmake/Modules/FindUDNS.cmake new file mode 100644 index 0000000..1d32cd3 --- /dev/null +++ b/louloulibs/cmake/Modules/FindUDNS.cmake @@ -0,0 +1,37 @@ +# - Find udns +# Find the udns library +# +# This module defines the following variables: +# UDNS_FOUND - True if library and include directory are found +# If set to TRUE, the following are also defined: +# UDNS_INCLUDE_DIRS - The directory where to find the header file +# UDNS_LIBRARIES - Where to find the library file +# +# For conveniance, these variables are also set. They have the same values +# as the variables above. The user can thus choose his/her prefered way +# to write them. +# UDNS_INCLUDE_DIR +# UDNS_LIBRARY +# +# This file is in the public domain + +if(NOT UDNS_FOUND) + find_path(UDNS_INCLUDE_DIRS NAMES udns.h + DOC "The udns include directory") + + find_library(UDNS_LIBRARIES NAMES udns + DOC "The udns library") + + # Use some standard module to handle the QUIETLY and REQUIRED arguments, and + # set UDNS_FOUND to TRUE if these two variables are set. + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(UDNS REQUIRED_VARS UDNS_LIBRARIES UDNS_INCLUDE_DIRS) + + # Compatibility for all the ways of writing these variables + if(UDNS_FOUND) + set(UDNS_INCLUDE_DIR ${UDNS_INCLUDE_DIRS}) + set(UDNS_LIBRARY ${UDNS_LIBRARIES}) + endif() +endif() + +mark_as_advanced(UDNS_INCLUDE_DIRS UDNS_LIBRARIES) diff --git a/louloulibs/louloulibs.h.cmake b/louloulibs/louloulibs.h.cmake index 6131b70..ebb9b9a 100644 --- a/louloulibs/louloulibs.h.cmake +++ b/louloulibs/louloulibs.h.cmake @@ -4,7 +4,7 @@ #cmakedefine SYSTEMD_FOUND #cmakedefine POLLER ${POLLER} #cmakedefine BOTAN_FOUND -#cmakedefine CARES_FOUND +#cmakedefine UDNS_FOUND #cmakedefine SOFTWARE_VERSION "${SOFTWARE_VERSION}" #cmakedefine PROJECT_NAME "${PROJECT_NAME}" #cmakedefine HAS_GET_TIME diff --git a/louloulibs/network/dns_handler.cpp b/louloulibs/network/dns_handler.cpp index b1807b5..ad0ad38 100644 --- a/louloulibs/network/dns_handler.cpp +++ b/louloulibs/network/dns_handler.cpp @@ -1,5 +1,5 @@ #include -#ifdef CARES_FOUND +#ifdef UDNS_FOUND #include #include @@ -7,123 +7,40 @@ #include -#include +#include -DNSHandler DNSHandler::instance; +#include + +class Resolver; using namespace std::string_literals; -DNSHandler::DNSHandler(): - socket_handlers{}, - channel{nullptr} -{ - int ares_error; - if ((ares_error = ::ares_library_init(ARES_LIB_INIT_ALL)) != 0) - throw std::runtime_error("Failed to initialize c-ares lib: "s + ares_strerror(ares_error)); - struct ares_options options = {}; - // The default timeout values are way too high - options.timeout = 1000; - options.tries = 3; - if ((ares_error = ::ares_init_options(&this->channel, - &options, - ARES_OPT_TIMEOUTMS|ARES_OPT_TRIES)) != ARES_SUCCESS) - throw std::runtime_error("Failed to initialize c-ares channel: "s + ares_strerror(ares_error)); -} -ares_channel& DNSHandler::get_channel() -{ - return this->channel; -} +std::unique_ptr DNSHandler::socket_handler{}; -void DNSHandler::destroy() +DNSHandler::DNSHandler(std::shared_ptr poller) { - this->remove_all_sockets_from_poller(); - this->socket_handlers.clear(); - ::ares_destroy(this->channel); - ::ares_library_cleanup(); + dns_init(nullptr, 0); + const auto socket = dns_open(nullptr); + if (socket == -1) + throw std::runtime_error("Failed to initialize udns socket: "s + strerror(errno)); + + DNSHandler::socket_handler = std::make_unique(poller, socket); } -void DNSHandler::gethostbyname(const std::string& name, ares_host_callback callback, - void* data, int family) +void DNSHandler::destroy() { - ::ares_gethostbyname(this->channel, name.data(), family, - callback, data); + DNSHandler::socket_handler.reset(nullptr); + dns_close(nullptr); } -void DNSHandler::watch_dns_sockets(std::shared_ptr& poller) +void DNSHandler::watch() { - fd_set readers; - fd_set writers; - - FD_ZERO(&readers); - FD_ZERO(&writers); - - int ndfs = ::ares_fds(this->channel, &readers, &writers); - // For each existing DNS socket, see if we are still supposed to watch it, - // if not then erase it - this->socket_handlers.erase( - std::remove_if(this->socket_handlers.begin(), this->socket_handlers.end(), - [&readers](const auto& dns_socket) - { - return !FD_ISSET(dns_socket->get_socket(), &readers); - }), - this->socket_handlers.end()); - - for (auto i = 0; i < ndfs; ++i) - { - bool read = FD_ISSET(i, &readers); - bool write = FD_ISSET(i, &writers); - // Look for the DNSSocketHandler with this fd - auto it = std::find_if(this->socket_handlers.begin(), - this->socket_handlers.end(), - [i](const auto& socket_handler) - { - return i == socket_handler->get_socket(); - }); - if (!read && !write) // No need to read or write to it - { // If found, erase it and stop watching it because it is not - // needed anymore - if (it != this->socket_handlers.end()) - // The socket destructor removes it from the poller - this->socket_handlers.erase(it); - } - else // We need to write and/or read to it - { // If not found, create it because we need to watch it - if (it == this->socket_handlers.end()) - { - this->socket_handlers.emplace(this->socket_handlers.begin(), - std::make_unique(poller, *this, i)); - it = this->socket_handlers.begin(); - } - poller->add_socket_handler(it->get()); - if (write) - poller->watch_send_events(it->get()); - } - } - // Cancel previous timer, if any. - TimedEventsManager::instance().cancel("DNS timeout"); - struct timeval tv; - struct timeval* tvp; - tvp = ::ares_timeout(this->channel, NULL, &tv); - if (tvp) - { - auto future_time = std::chrono::steady_clock::now() + std::chrono::seconds(tvp->tv_sec) + \ - std::chrono::microseconds(tvp->tv_usec); - TimedEventsManager::instance().add_event(TimedEvent(std::move(future_time), - [this]() - { - for (auto& dns_socket_handler: this->socket_handlers) - dns_socket_handler->on_recv(); - }, - "DNS timeout")); - } + DNSHandler::socket_handler->watch(); } -void DNSHandler::remove_all_sockets_from_poller() +void DNSHandler::unwatch() { - for (const auto& socket_handler: this->socket_handlers) - { - socket_handler->remove_from_poller(); - } + DNSHandler::socket_handler->unwatch(); } -#endif /* CARES_FOUND */ +#endif /* UDNS_FOUND */ diff --git a/louloulibs/network/dns_handler.hpp b/louloulibs/network/dns_handler.hpp index 53a7799..0148156 100644 --- a/louloulibs/network/dns_handler.hpp +++ b/louloulibs/network/dns_handler.hpp @@ -1,59 +1,37 @@ #pragma once #include -#ifdef CARES_FOUND +#ifdef UDNS_FOUND -class TCPSocketHandler; class Poller; -class DNSSocketHandler; -# include -# include -# include -# include +#include -/** - * Class managing DNS resolution. It should only be statically instanciated - * once in SocketHandler. It manages ares channel and calls various - * functions of that library. - */ +#include +#include +#include class DNSHandler { -private: - DNSHandler(); public: + DNSHandler(std::shared_ptr poller); ~DNSHandler() = default; + DNSHandler(const DNSHandler&) = delete; DNSHandler(DNSHandler&&) = delete; DNSHandler& operator=(const DNSHandler&) = delete; DNSHandler& operator=(DNSHandler&&) = delete; - void gethostbyname(const std::string& name, ares_host_callback callback, - void* socket_handler, int family); - /** - * Call ares_fds to know what fd needs to be watched by the poller, create - * or destroy DNSSocketHandlers depending on the result. - */ - void watch_dns_sockets(std::shared_ptr& poller); - /** - * Destroy and stop watching all the DNS sockets. Then de-init the channel - * and library. - */ void destroy(); - void remove_all_sockets_from_poller(); - ares_channel& get_channel(); - static DNSHandler instance; + static void watch(); + static void unwatch(); private: /** - * The list of sockets that needs to be watched, according to the last - * call to ares_fds. DNSSocketHandlers are added to it or removed from it - * in the watch_dns_sockets() method + * Manager for the socket returned by udns, that we need to watch with the poller */ - std::vector> socket_handlers; - ares_channel channel; + static std::unique_ptr socket_handler; }; -#endif /* CARES_FOUND */ +#endif /* UDNS_FOUND */ diff --git a/louloulibs/network/dns_socket_handler.cpp b/louloulibs/network/dns_socket_handler.cpp index a69f59b..ad744a9 100644 --- a/louloulibs/network/dns_socket_handler.cpp +++ b/louloulibs/network/dns_socket_handler.cpp @@ -1,34 +1,27 @@ #include -#ifdef CARES_FOUND +#ifdef UDNS_FOUND #include #include #include -#include +#include DNSSocketHandler::DNSSocketHandler(std::shared_ptr poller, - DNSHandler& handler, const socket_t socket): - SocketHandler(poller, socket), - handler(handler) + SocketHandler(poller, socket) { + poller->add_socket_handler(this); } -void DNSSocketHandler::on_recv() +DNSSocketHandler::~DNSSocketHandler() { - // always stop watching send and read events. We will re-watch them if the - // next call to ares_fds tell us to - this->handler.remove_all_sockets_from_poller(); - ::ares_process_fd(DNSHandler::instance.get_channel(), this->socket, ARES_SOCKET_BAD); + this->unwatch(); } -void DNSSocketHandler::on_send() +void DNSSocketHandler::on_recv() { - // always stop watching send and read events. We will re-watch them if the - // next call to ares_fds tell us to - this->handler.remove_all_sockets_from_poller(); - ::ares_process_fd(DNSHandler::instance.get_channel(), ARES_SOCKET_BAD, this->socket); + dns_ioevent(nullptr, 0); } bool DNSSocketHandler::is_connected() const @@ -36,10 +29,15 @@ bool DNSSocketHandler::is_connected() const return true; } -void DNSSocketHandler::remove_from_poller() +void DNSSocketHandler::unwatch() { if (this->poller->is_managing_socket(this->socket)) this->poller->remove_socket_handler(this->socket); } -#endif /* CARES_FOUND */ +void DNSSocketHandler::watch() +{ + this->poller->add_socket_handler(this); +} + +#endif /* UDNS_FOUND */ diff --git a/louloulibs/network/dns_socket_handler.hpp b/louloulibs/network/dns_socket_handler.hpp index e3fed0c..e12f145 100644 --- a/louloulibs/network/dns_socket_handler.hpp +++ b/louloulibs/network/dns_socket_handler.hpp @@ -1,44 +1,33 @@ #pragma once #include -#ifdef CARES_FOUND +#ifdef UDNS_FOUND #include -#include /** - * Manage a socket returned by ares_fds. We do not create, open or close the - * socket ourself: this is done by c-ares. We just call ares_process_fd() - * with the correct parameters, depending on what can be done on that socket - * (Poller reported it to be writable or readeable) + * Manage the UDP socket provided by udns, we do not create, open or close the + * socket ourself: this is done by udns. We only watch it for readability */ - -class DNSHandler; - class DNSSocketHandler: public SocketHandler { public: - explicit DNSSocketHandler(std::shared_ptr poller, DNSHandler& handler, const socket_t socket); - ~DNSSocketHandler() = default; + explicit DNSSocketHandler(std::shared_ptr poller, const socket_t socket); + ~DNSSocketHandler(); DNSSocketHandler(const DNSSocketHandler&) = delete; DNSSocketHandler(DNSSocketHandler&&) = delete; DNSSocketHandler& operator=(const DNSSocketHandler&) = delete; DNSSocketHandler& operator=(DNSSocketHandler&&) = delete; - /** - * Just call dns_process_fd, c-ares will do its work of send()ing or - * recv()ing the data it wants on that socket. - */ void on_recv() override final; - void on_send() override final; + /** * Always true, see the comment for connect() */ bool is_connected() const override final; - void remove_from_poller(); -private: - DNSHandler& handler; + void watch(); + void unwatch(); }; -#endif // CARES_FOUND +#endif // UDNS_FOUND diff --git a/louloulibs/network/resolver.cpp b/louloulibs/network/resolver.cpp index 3847d87..efb0cf0 100644 --- a/louloulibs/network/resolver.cpp +++ b/louloulibs/network/resolver.cpp @@ -1,19 +1,32 @@ #include +#include #include #include #include #include +#include +#include #include +#include +#include +#include using namespace std::string_literals; +static std::map dns_error_messages { + {DNS_E_TEMPFAIL, "Timeout while contacting DNS servers"}, + {DNS_E_PROTOCOL, "Misformatted DNS reply"}, + {DNS_E_NXDOMAIN, "Domain name not found"}, + {DNS_E_NOMEM, "Out of memory"}, + {DNS_E_BADQUERY, "Misformatted domain name"} +}; + Resolver::Resolver(): -#ifdef CARES_FOUND +#ifdef UDNS_FOUND resolved4(false), resolved6(false), resolving(false), - cares_addrinfo(nullptr), port{}, #endif resolved(false), @@ -26,15 +39,44 @@ void Resolver::resolve(const std::string& hostname, const std::string& port, { this->error_cb = error_cb; this->success_cb = success_cb; -#ifdef CARES_FOUND +#ifdef UDNS_FOUND this->port = port; #endif this->start_resolving(hostname, port); } -#ifdef CARES_FOUND -void Resolver::start_resolving(const std::string& hostname, const std::string&) +int Resolver::call_getaddrinfo(const char *name, const char* port, int flags) +{ + struct addrinfo hints; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags = flags; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + struct addrinfo* addr_res = nullptr; + const int res = ::getaddrinfo(name, port, + &hints, &addr_res); + + if (res == 0 && addr_res) + { + if (!this->addr) + this->addr.reset(addr_res); + else + { // Append this result at the end of the linked list + struct addrinfo *rp = this->addr.get(); + while (rp->ai_next) + rp = rp->ai_next; + rp->ai_next = addr_res; + } + } + + return res; +} + +#ifdef UDNS_FOUND +void Resolver::start_resolving(const std::string& hostname, const std::string& port) { this->resolving = true; this->resolved = false; @@ -42,48 +84,139 @@ void Resolver::start_resolving(const std::string& hostname, const std::string&) this->resolved6 = false; this->error_msg.clear(); - this->cares_addrinfo = nullptr; + this->addr.reset(nullptr); - auto hostname4_resolved = [](void* arg, int status, int, - struct hostent* hostent) + // We first try to use it as an IP address directly. We tell getaddrinfo + // to NOT use any DNS resolution. + if (this->call_getaddrinfo(hostname.data(), port.data(), AI_NUMERICHOST) == 0) { - Resolver* resolver = static_cast(arg); - resolver->on_hostname4_resolved(status, hostent); - }; - auto hostname6_resolved = [](void* arg, int status, int, - struct hostent* hostent) + this->on_resolved(); + return; + } + + // Then we look into /etc/hosts to translate the given hostname + const auto hosts = this->look_in_etc_hosts(hostname); + if (!hosts.empty()) + { + for (const auto &host: hosts) + this->call_getaddrinfo(host.data(), port.data(), AI_NUMERICHOST); + this->on_resolved(); + return; + } + + // And finally, we try a DNS resolution + auto hostname6_resolved = [](dns_ctx*, dns_rr_a6* result, void* data) + { + Resolver* resolver = static_cast(data); + resolver->on_hostname6_resolved(result); + }; + + auto hostname4_resolved = [](dns_ctx*, dns_rr_a4* result, void* data) + { + Resolver* resolver = static_cast(data); + resolver->on_hostname4_resolved(result); + }; + + DNSHandler::watch(); + auto res = dns_submit_a4(nullptr, hostname.data(), 0, hostname4_resolved, this); + if (!res) + this->on_hostname4_resolved(nullptr); + res = dns_submit_a6(nullptr, hostname.data(), 0, hostname6_resolved, this); + if (!res) + this->on_hostname6_resolved(nullptr); + + this->start_timer(); +} + +void Resolver::start_timer() +{ + const auto timeout = dns_timeouts(nullptr, -1, 0); + if (timeout < 0) + return; + TimedEvent event(std::chrono::steady_clock::now() + std::chrono::seconds(timeout), [this]() { this->start_timer(); }, "DNS"); + TimedEventsManager::instance().add_event(std::move(event)); +} + +std::vector Resolver::look_in_etc_hosts(const std::string &hostname) +{ + std::ifstream hosts("/etc/hosts"); + std::string line; + + std::vector results; + while (std::getline(hosts, line)) { - Resolver* resolver = static_cast(arg); - resolver->on_hostname6_resolved(status, hostent); - }; - - DNSHandler::instance.gethostbyname(hostname, hostname6_resolved, - this, AF_INET6); - DNSHandler::instance.gethostbyname(hostname, hostname4_resolved, - this, AF_INET); + if (line.empty()) + continue; + + std::string ip; + std::istringstream line_stream(line); + line_stream >> ip; + if (ip.empty() || ip[0] == '#') + continue; + + std::string host; + while (line_stream >> host && !host.empty() && host[0] != '#') + { + if (hostname == host) + { + results.push_back(ip); + break; + } + } + } + return results; } -void Resolver::on_hostname4_resolved(int status, struct hostent* hostent) +void Resolver::on_hostname4_resolved(dns_rr_a4 *result) { + if (dns_active(nullptr) == 0) + DNSHandler::unwatch(); + this->resolved4 = true; - if (status == ARES_SUCCESS) - this->fill_ares_addrinfo4(hostent); + + const auto status = dns_status(nullptr); + + if (status >= 0 && result) + { + char buf[INET6_ADDRSTRLEN]; + + for (auto i = 0; i < result->dnsa4_nrr; ++i) + { + inet_ntop(AF_INET, &result->dnsa4_addr[i], buf, sizeof(buf)); + this->call_getaddrinfo(buf, this->port.data(), AI_NUMERICHOST); + } + } else - this->error_msg = ::ares_strerror(status); + { + const auto error = dns_error_messages.find(status); + if (error != end(dns_error_messages)) + this->error_msg = error->second; + } - if (this->resolved4 && this->resolved6) + if (this->resolved6 && this->resolved4) this->on_resolved(); } -void Resolver::on_hostname6_resolved(int status, struct hostent* hostent) +void Resolver::on_hostname6_resolved(dns_rr_a6 *result) { + if (dns_active(nullptr) == 0) + DNSHandler::unwatch(); + this->resolved6 = true; - if (status == ARES_SUCCESS) - this->fill_ares_addrinfo6(hostent); - else - this->error_msg = ::ares_strerror(status); + char buf[INET6_ADDRSTRLEN]; + + const auto status = dns_status(nullptr); - if (this->resolved4 && this->resolved6) + if (status >= 0 && result) + { + for (auto i = 0; i < result->dnsa6_nrr; ++i) + { + inet_ntop(AF_INET6, &result->dnsa6_addr[i], buf, sizeof(buf)); + this->call_getaddrinfo(buf, this->port.data(), AI_NUMERICHOST); + } + } + + if (this->resolved6 && this->resolved4) this->on_resolved(); } @@ -91,100 +224,26 @@ void Resolver::on_resolved() { this->resolved = true; this->resolving = false; - if (!this->cares_addrinfo) + if (!this->addr) { if (this->error_cb) this->error_cb(this->error_msg.data()); } else { - this->addr.reset(this->cares_addrinfo); if (this->success_cb) this->success_cb(this->addr.get()); } } -void Resolver::fill_ares_addrinfo4(const struct hostent* hostent) -{ - struct addrinfo* prev = this->cares_addrinfo; - struct in_addr** address = reinterpret_cast(hostent->h_addr_list); - - while (*address) - { - // Create a new addrinfo list element, and fill it - struct addrinfo* current = new struct addrinfo; - current->ai_flags = 0; - current->ai_family = hostent->h_addrtype; - current->ai_socktype = SOCK_STREAM; - current->ai_protocol = 0; - current->ai_addrlen = sizeof(struct sockaddr_in); - - struct sockaddr_in* ai_addr = new struct sockaddr_in; - - ai_addr->sin_family = hostent->h_addrtype; - ai_addr->sin_port = htons(std::strtoul(this->port.data(), nullptr, 10)); - ai_addr->sin_addr.s_addr = (*address)->s_addr; - - current->ai_addr = reinterpret_cast(ai_addr); - current->ai_next = nullptr; - current->ai_canonname = nullptr; - - current->ai_next = prev; - this->cares_addrinfo = current; - prev = current; - ++address; - } -} - -void Resolver::fill_ares_addrinfo6(const struct hostent* hostent) -{ - struct addrinfo* prev = this->cares_addrinfo; - struct in6_addr** address = reinterpret_cast(hostent->h_addr_list); - - while (*address) - { - // Create a new addrinfo list element, and fill it - struct addrinfo* current = new struct addrinfo; - current->ai_flags = 0; - current->ai_family = hostent->h_addrtype; - current->ai_socktype = SOCK_STREAM; - current->ai_protocol = 0; - current->ai_addrlen = sizeof(struct sockaddr_in6); - - struct sockaddr_in6* ai_addr = new struct sockaddr_in6; - ai_addr->sin6_family = hostent->h_addrtype; - ai_addr->sin6_port = htons(std::strtoul(this->port.data(), nullptr, 10)); - ::memcpy(ai_addr->sin6_addr.s6_addr, (*address)->s6_addr, sizeof(ai_addr->sin6_addr.s6_addr)); - ai_addr->sin6_flowinfo = 0; - ai_addr->sin6_scope_id = 0; - - current->ai_addr = reinterpret_cast(ai_addr); - current->ai_canonname = nullptr; - - current->ai_next = prev; - this->cares_addrinfo = current; - prev = current; - ++address; - } -} - -#else // ifdef CARES_FOUND +#else // ifdef UDNS_FOUND void Resolver::start_resolving(const std::string& hostname, const std::string& port) { // If the resolution fails, the addr will be unset this->addr.reset(nullptr); - struct addrinfo hints; - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_flags = 0; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - struct addrinfo* addr_res = nullptr; - const int res = ::getaddrinfo(hostname.data(), port.data(), - &hints, &addr_res); + const auto res = this->call_getaddrinfo(hostname.data(), port.data(), 0); this->resolved = true; @@ -196,12 +255,11 @@ void Resolver::start_resolving(const std::string& hostname, const std::string& p } else { - this->addr.reset(addr_res); if (this->success_cb) this->success_cb(this->addr.get()); } } -#endif // ifdef CARES_FOUND +#endif // ifdef UDNS_FOUND std::string addr_to_string(const struct addrinfo* rp) { diff --git a/louloulibs/network/resolver.hpp b/louloulibs/network/resolver.hpp index 7365f93..f516da5 100644 --- a/louloulibs/network/resolver.hpp +++ b/louloulibs/network/resolver.hpp @@ -1,38 +1,31 @@ #pragma once - #include "louloulibs.h" #include +#include #include #include #include #include #include +#include class AddrinfoDeleter { public: void operator()(struct addrinfo* addr) { -#ifdef CARES_FOUND - while (addr) - { - delete addr->ai_addr; - auto next = addr->ai_next; - delete addr; - addr = next; - } -#else freeaddrinfo(addr); -#endif } }; + class Resolver { public: + using ErrorCallbackType = std::function; using SuccessCallbackType = std::function; @@ -45,7 +38,7 @@ public: bool is_resolving() const { -#ifdef CARES_FOUND +#ifdef UDNS_FOUND return this->resolving; #else return false; @@ -68,11 +61,10 @@ public: void clear() { -#ifdef CARES_FOUND +#ifdef UDNS_FOUND this->resolved6 = false; this->resolved4 = false; this->resolving = false; - this->cares_addrinfo = nullptr; this->port.clear(); #endif this->resolved = false; @@ -85,12 +77,18 @@ public: private: void start_resolving(const std::string& hostname, const std::string& port); -#ifdef CARES_FOUND - void on_hostname4_resolved(int status, struct hostent* hostent); - void on_hostname6_resolved(int status, struct hostent* hostent); + std::vector look_in_etc_hosts(const std::string& hostname); + /** + * Call getaddrinfo() on the given hostname or IP, and append the result + * to our internal addrinfo list. Return getaddrinfo()’s return value. + */ + int call_getaddrinfo(const char* name, const char* port, int flags); + +#ifdef UDNS_FOUND + void on_hostname4_resolved(dns_rr_a4 *result); + void on_hostname6_resolved(dns_rr_a6 *result); - void fill_ares_addrinfo4(const struct hostent* hostent); - void fill_ares_addrinfo6(const struct hostent* hostent); + void start_timer(); void on_resolved(); @@ -99,14 +97,6 @@ private: bool resolving; - /** - * When using c-ares to resolve the host asynchronously, we need the - * c-ares callbacks to fill a structure (a struct addrinfo, for - * compatibility with getaddrinfo and the rest of the code that works when - * c-ares is not used) with all returned values (for example an IPv6 and - * an IPv4). The pointer is given to the unique_ptr to manage its lifetime. - */ - struct addrinfo* cares_addrinfo; std::string port; #endif @@ -117,7 +107,6 @@ private: bool resolved; std::string error_msg; - std::unique_ptr addr; ErrorCallbackType error_cb; diff --git a/louloulibs/network/tcp_client_socket_handler.cpp b/louloulibs/network/tcp_client_socket_handler.cpp index 7f21e3f..4e6445c 100644 --- a/louloulibs/network/tcp_client_socket_handler.cpp +++ b/louloulibs/network/tcp_client_socket_handler.cpp @@ -79,7 +79,7 @@ void TCPClientSocketHandler::connect(const std::string& address, const std::stri if (!this->connecting) { - // Get the addrinfo from getaddrinfo (or ares_gethostbyname), only if + // Get the addrinfo from getaddrinfo (or using udns), only if // this is the first call of this function. if (!this->resolver.is_resolved()) { @@ -103,8 +103,8 @@ void TCPClientSocketHandler::connect(const std::string& address, const std::stri } else { - // The c-ares resolved the hostname and the available addresses - // where saved in the cares_addrinfo linked list. Now, just use + // The DNS resolver resolved the hostname and the available addresses + // where saved in the addrinfo linked list. Now, just use // this list to try to connect. addr_res = this->resolver.get_result().get(); if (!addr_res) -- cgit v1.2.3 From 17411e6b4499f57e2460cacb6b14765e5beef88f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 6 Jan 2017 23:09:17 +0100 Subject: Fix an use-after-free MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because we “delete all node” and then we use the content of one of these nodes we got earlier. --- louloulibs/xmpp/adhoc_command.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'louloulibs') diff --git a/louloulibs/xmpp/adhoc_command.cpp b/louloulibs/xmpp/adhoc_command.cpp index 08d2d17..825cc92 100644 --- a/louloulibs/xmpp/adhoc_command.cpp +++ b/louloulibs/xmpp/adhoc_command.cpp @@ -54,10 +54,11 @@ void HelloStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node) { if (const XmlNode* value = name_field->get_child("value", "jabber:x:data")) { + const std::string value_str = value->get_inner(); command_node.delete_all_children(); XmlSubNode note(command_node, "note"); note["type"] = "info"; - note.set_inner("Hello "s + value->get_inner() + "!"s); + note.set_inner("Hello "s + value_str + "!"s); return; } } -- cgit v1.2.3 From 6bf9cedbeb30740c267ea283058c93ed63648fc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 6 Jan 2017 23:13:47 +0100 Subject: Add a missing errno include --- louloulibs/network/dns_handler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs') diff --git a/louloulibs/network/dns_handler.cpp b/louloulibs/network/dns_handler.cpp index ad0ad38..fbd2763 100644 --- a/louloulibs/network/dns_handler.cpp +++ b/louloulibs/network/dns_handler.cpp @@ -8,7 +8,7 @@ #include #include - +#include #include class Resolver; -- cgit v1.2.3 From e31ff3e9e94d943d4f307eb6ab8cee7fbd11b565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 6 Jan 2017 23:45:26 +0100 Subject: Fix some issues found by sonar cube --- louloulibs/network/dns_handler.hpp | 2 +- louloulibs/xmpp/adhoc_commands_handler.cpp | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/network/dns_handler.hpp b/louloulibs/network/dns_handler.hpp index 0148156..78ffe4d 100644 --- a/louloulibs/network/dns_handler.hpp +++ b/louloulibs/network/dns_handler.hpp @@ -14,7 +14,7 @@ class Poller; class DNSHandler { public: - DNSHandler(std::shared_ptr poller); + explicit DNSHandler(std::shared_ptr poller); ~DNSHandler() = default; DNSHandler(const DNSHandler&) = delete; diff --git a/louloulibs/xmpp/adhoc_commands_handler.cpp b/louloulibs/xmpp/adhoc_commands_handler.cpp index d3ede2d..040d0ff 100644 --- a/louloulibs/xmpp/adhoc_commands_handler.cpp +++ b/louloulibs/xmpp/adhoc_commands_handler.cpp @@ -62,13 +62,8 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, co "adhocsession"s + sessionid + executor_jid)); } auto session_it = this->sessions.find(std::make_pair(sessionid, executor_jid)); - if (session_it == this->sessions.end()) - { - XmlSubNode error(command_node, ADHOC_NS":error"); - error["type"] = "modify"; - XmlSubNode condition(error, STANZA_NS":bad-request"); - } - else if (action == "execute" || action == "next" || action == "complete") + if ((session_it != this->sessions.end()) && + (action == "execute" || action == "next" || action == "complete")) { // execute the step AdhocSession& session = session_it->second; -- cgit v1.2.3 From 5e33b6184a842e2a2a7cff368c974edf496fb608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 10 Jan 2017 23:02:24 +0100 Subject: Look for botan-2 in addition to botan-1.11 --- louloulibs/cmake/Modules/FindBOTAN.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/cmake/Modules/FindBOTAN.cmake b/louloulibs/cmake/Modules/FindBOTAN.cmake index a12bd35..75f17dd 100644 --- a/louloulibs/cmake/Modules/FindBOTAN.cmake +++ b/louloulibs/cmake/Modules/FindBOTAN.cmake @@ -16,10 +16,10 @@ # This file is in the public domain find_path(BOTAN_INCLUDE_DIRS NAMES botan/botan.h - PATH_SUFFIXES botan-1.11 + PATH_SUFFIXES botan-1.11 botan-2 DOC "The botan include directory") -find_library(BOTAN_LIBRARIES NAMES botan botan-1.11 +find_library(BOTAN_LIBRARIES NAMES botan botan-1.11 botan-2 DOC "The botan library") # Use some standard module to handle the QUIETLY and REQUIRED arguments, and -- cgit v1.2.3 From 81b21bfc2660820d84040ecdd553b2e4a8ae3ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 10 Jan 2017 23:27:01 +0100 Subject: Update INSTALL.rst to talk about botan-2, and give priority to 2 over 1.11 --- louloulibs/cmake/Modules/FindBOTAN.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/cmake/Modules/FindBOTAN.cmake b/louloulibs/cmake/Modules/FindBOTAN.cmake index 75f17dd..26069f4 100644 --- a/louloulibs/cmake/Modules/FindBOTAN.cmake +++ b/louloulibs/cmake/Modules/FindBOTAN.cmake @@ -16,10 +16,10 @@ # This file is in the public domain find_path(BOTAN_INCLUDE_DIRS NAMES botan/botan.h - PATH_SUFFIXES botan-1.11 botan-2 + PATH_SUFFIXES botan-2 botan-1.11 DOC "The botan include directory") -find_library(BOTAN_LIBRARIES NAMES botan botan-1.11 botan-2 +find_library(BOTAN_LIBRARIES NAMES botan botan-2 botan-1.11 DOC "The botan library") # Use some standard module to handle the QUIETLY and REQUIRED arguments, and -- cgit v1.2.3 From dd129366575f371bcec51b7303bfb273d6edc8a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 19 Jan 2017 18:41:29 +0100 Subject: Do not require revocation info for a certificate to be valid If anyone has any reason to believe this is a bad idea, please let me know. --- louloulibs/network/tcp_socket_handler.hpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'louloulibs') diff --git a/louloulibs/network/tcp_socket_handler.hpp b/louloulibs/network/tcp_socket_handler.hpp index 7fc40c2..600405d 100644 --- a/louloulibs/network/tcp_socket_handler.hpp +++ b/louloulibs/network/tcp_socket_handler.hpp @@ -32,6 +32,10 @@ public: { return true; } + bool require_cert_revocation_info() const override + { + return false; + } # endif }; -- cgit v1.2.3 From a5d35c2455d9e3e5724c9a906deb1b58e5a5f87b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 31 Jan 2017 23:47:45 +0100 Subject: Add some missing ifndef for udns --- louloulibs/network/resolver.cpp | 6 +++++- louloulibs/network/resolver.hpp | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/network/resolver.cpp b/louloulibs/network/resolver.cpp index efb0cf0..0655b1b 100644 --- a/louloulibs/network/resolver.cpp +++ b/louloulibs/network/resolver.cpp @@ -4,7 +4,9 @@ #include #include #include -#include +#ifdef UDNS_FOUND +# include +#endif #include #include @@ -14,6 +16,7 @@ using namespace std::string_literals; +#ifdef UDNS_FOUND static std::map dns_error_messages { {DNS_E_TEMPFAIL, "Timeout while contacting DNS servers"}, {DNS_E_PROTOCOL, "Misformatted DNS reply"}, @@ -21,6 +24,7 @@ static std::map dns_error_messages { {DNS_E_NOMEM, "Out of memory"}, {DNS_E_BADQUERY, "Misformatted domain name"} }; +#endif Resolver::Resolver(): #ifdef UDNS_FOUND diff --git a/louloulibs/network/resolver.hpp b/louloulibs/network/resolver.hpp index f516da5..800c7ec 100644 --- a/louloulibs/network/resolver.hpp +++ b/louloulibs/network/resolver.hpp @@ -10,7 +10,9 @@ #include #include #include -#include +#ifdef UDNS_FOUND +# include +#endif class AddrinfoDeleter { -- cgit v1.2.3 From 479b7189935baa4ca9c9d2a5525bdb1fbd8b9fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 1 Feb 2017 18:37:51 +0100 Subject: Only use the C.UTF-8 LANG value --- louloulibs/utils/time.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs') diff --git a/louloulibs/utils/time.cpp b/louloulibs/utils/time.cpp index e3c49ed..d9c4381 100644 --- a/louloulibs/utils/time.cpp +++ b/louloulibs/utils/time.cpp @@ -24,7 +24,7 @@ std::time_t parse_datetime(const std::string& stamp) std::tm t = {}; #ifdef HAS_GET_TIME std::istringstream ss(stamp); - ss.imbue(std::locale("en_US.UTF-8")); + ss.imbue(std::locale("C.UTF-8")); std::string timezone; ss >> std::get_time(&t, format) >> timezone; -- cgit v1.2.3 From 835c650ef5a7297cc8bd0d6e0799186e6a5d2126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 1 Feb 2017 20:33:16 +0100 Subject: Actually, just use the C locale for the date formats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don’t need any UTF-8 support here, and it’s more portable --- louloulibs/utils/time.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs') diff --git a/louloulibs/utils/time.cpp b/louloulibs/utils/time.cpp index d9c4381..e9f3943 100644 --- a/louloulibs/utils/time.cpp +++ b/louloulibs/utils/time.cpp @@ -24,7 +24,7 @@ std::time_t parse_datetime(const std::string& stamp) std::tm t = {}; #ifdef HAS_GET_TIME std::istringstream ss(stamp); - ss.imbue(std::locale("C.UTF-8")); + ss.imbue(std::locale("C")); std::string timezone; ss >> std::get_time(&t, format) >> timezone; -- cgit v1.2.3 From 7f08cf83aa5db58bfac004dddae565e6536eeb2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 15 Feb 2017 01:02:27 +0100 Subject: Little scopeguard cleanup, and add a test --- louloulibs/utils/encoding.cpp | 4 ++-- louloulibs/utils/scopeguard.hpp | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/utils/encoding.cpp b/louloulibs/utils/encoding.cpp index 087095f..aa91dac 100644 --- a/louloulibs/utils/encoding.cpp +++ b/louloulibs/utils/encoding.cpp @@ -152,7 +152,7 @@ namespace utils throw std::runtime_error("Cannot convert into UTF-8"); // Make sure cd is always closed when we leave this function - const auto sg = utils::make_scope_guard([&cd](auto&&){ iconv_close(cd); }); + const auto sg = utils::make_scope_guard([&cd](){ iconv_close(cd); }); size_t inbytesleft = str.size(); @@ -169,7 +169,7 @@ namespace utils char* outbuf_ptr = outbuf; // Make sure outbuf is always deleted when we leave this function - const auto sg2 = utils::make_scope_guard([outbuf](auto&&){ delete[] outbuf; }); + const auto sg2 = utils::make_scope_guard([outbuf](){ delete[] outbuf; }); bool done = false; while (done == false) diff --git a/louloulibs/utils/scopeguard.hpp b/louloulibs/utils/scopeguard.hpp index cd0e89e..e697fc3 100644 --- a/louloulibs/utils/scopeguard.hpp +++ b/louloulibs/utils/scopeguard.hpp @@ -87,9 +87,11 @@ private: }; template -auto make_scope_guard(F&& f) +auto make_scope_guard(F f) { - return std::unique_ptr>{(void*)1, std::forward(f)}; + static struct Empty {} empty; + auto deleter = [f = std::move(f)](Empty*) { f(); }; + return std::unique_ptr{&empty, std::move(deleter)}; } } -- cgit v1.2.3 From fef585ad6699042e594f407afe78df1e40344efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 15 Feb 2017 01:05:42 +0100 Subject: Surround ipv6 with [], and properly cleanup otherwise invalid domains fix #2694 (yeah, it was closed, but it was badly fixed) --- louloulibs/xmpp/jid.cpp | 74 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 11 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/xmpp/jid.cpp b/louloulibs/xmpp/jid.cpp index 7b62f3e..d17d4e9 100644 --- a/louloulibs/xmpp/jid.cpp +++ b/louloulibs/xmpp/jid.cpp @@ -6,6 +6,9 @@ #include #ifdef LIBIDN_FOUND #include + #include + #include + #include #endif #include @@ -58,19 +61,68 @@ std::string jidprep(const std::string& original) char domain[max_jid_part_len] = {}; memcpy(domain, jid.domain.data(), std::min(max_jid_part_len, jid.domain.size())); - rc = static_cast(::stringprep(domain, max_jid_part_len, - static_cast(0), stringprep_nameprep)); - if (rc != STRINGPREP_OK) + { - log_error(error_msg + stringprep_strerror(rc)); - return ""; + // Using getaddrinfo, check if the domain part is a valid IPv4 (then use + // it as is), or IPv6 (surround it with []), or a domain name (run + // nameprep) + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = AF_UNSPEC; + + struct addrinfo* res = nullptr; + auto addrinfo_deleter = utils::make_scope_guard([res]() { if (res) freeaddrinfo(res); }); + if (::getaddrinfo(domain, nullptr, &hints, &res) || !res || + (res->ai_family != AF_INET && res->ai_family != AF_INET6)) + { // Not an IP, run nameprep on it + rc = static_cast(::stringprep(domain, max_jid_part_len, + static_cast(0), stringprep_nameprep)); + if (rc != STRINGPREP_OK) + { + log_error(error_msg + stringprep_strerror(rc)); + return ""; + } + + // Make sure it contains only allowed characters + using std::begin; + using std::end; + char* domain_end = domain + ::strlen(domain); + std::replace_if(std::begin(domain), domain + ::strlen(domain), + [](const char c) -> bool + { + return !((c >= 'a' && c <= 'z') || c == '-' || + (c >= '0' && c <= '9') || c == '.'); + }, '-'); + // Make sure there are no doubled - or . + std::set special_chars{'-', '.'}; + domain_end = std::unique(begin(domain), domain + ::strlen(domain), [&special_chars](const char& a, const char& b) -> bool + { + return special_chars.count(a) && special_chars.count(b); + }); + // remove leading and trailing -. if any + if (domain_end != domain && special_chars.count(*(domain_end - 1))) + --domain_end; + if (domain_end != domain && special_chars.count(domain[0])) + { + std::memmove(domain, domain + 1, domain_end - domain + 1); + --domain_end; + } + // And if the final result is an empty string, return a dummy hostname + if (domain_end == domain) + ::strcpy(domain, "empty"); + else + *domain_end = '\0'; + } + else if (res->ai_family == AF_INET6) + { // IPv6, surround it with []. The length is always enough: + // the longest possible IPv6 is way shorter than max_jid_part_len + ::memmove(domain + 1, domain, jid.domain.size()); + domain[0] = '['; + domain[jid.domain.size() + 1] = ']'; + } } - std::replace_if(std::begin(domain), domain + ::strlen(domain), - [](const char c) -> bool - { - return !((c >= 'a' && c <= 'z') || c == '-' || - (c >= '0' && c <= '9') || c == '.'); - }, '-'); + // If there is no resource, stop here if (jid.resource.empty()) -- cgit v1.2.3 From 561bbe9c145a80befc5b98c9865881e7f5d57648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 15 Feb 2017 01:19:36 +0100 Subject: Fix a leak on getaddrinfo, thank you LeakSanitizer! --- louloulibs/xmpp/jid.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/xmpp/jid.cpp b/louloulibs/xmpp/jid.cpp index d17d4e9..493ddc1 100644 --- a/louloulibs/xmpp/jid.cpp +++ b/louloulibs/xmpp/jid.cpp @@ -71,10 +71,10 @@ std::string jidprep(const std::string& original) hints.ai_flags = AI_NUMERICHOST; hints.ai_family = AF_UNSPEC; - struct addrinfo* res = nullptr; - auto addrinfo_deleter = utils::make_scope_guard([res]() { if (res) freeaddrinfo(res); }); - if (::getaddrinfo(domain, nullptr, &hints, &res) || !res || - (res->ai_family != AF_INET && res->ai_family != AF_INET6)) + struct addrinfo* addr_res = nullptr; + const auto ret = ::getaddrinfo(domain, nullptr, &hints, &addr_res); + auto addrinfo_deleter = utils::make_scope_guard([addr_res] { freeaddrinfo(addr_res); }); + if (ret || !addr_res || (addr_res->ai_family != AF_INET && addr_res->ai_family != AF_INET6)) { // Not an IP, run nameprep on it rc = static_cast(::stringprep(domain, max_jid_part_len, static_cast(0), stringprep_nameprep)); @@ -114,7 +114,7 @@ std::string jidprep(const std::string& original) else *domain_end = '\0'; } - else if (res->ai_family == AF_INET6) + else if (addr_res->ai_family == AF_INET6) { // IPv6, surround it with []. The length is always enough: // the longest possible IPv6 is way shorter than max_jid_part_len ::memmove(domain + 1, domain, jid.domain.size()); -- cgit v1.2.3 From efb8a11c5763632eee0fffea190a90712c6373f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 15 Feb 2017 01:27:45 +0100 Subject: Add missing include --- louloulibs/xmpp/jid.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'louloulibs') diff --git a/louloulibs/xmpp/jid.cpp b/louloulibs/xmpp/jid.cpp index 493ddc1..5862599 100644 --- a/louloulibs/xmpp/jid.cpp +++ b/louloulibs/xmpp/jid.cpp @@ -6,6 +6,8 @@ #include #ifdef LIBIDN_FOUND #include + #include + #include #include #include #include -- cgit v1.2.3 From 679bf94192695f2d6e7fe7e991bf490f95f63d25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 15 Feb 2017 01:46:29 +0100 Subject: Only call freeaddrinfo if an actual addrinfo struct has been allocated --- louloulibs/xmpp/jid.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs') diff --git a/louloulibs/xmpp/jid.cpp b/louloulibs/xmpp/jid.cpp index 5862599..46e01ea 100644 --- a/louloulibs/xmpp/jid.cpp +++ b/louloulibs/xmpp/jid.cpp @@ -75,7 +75,7 @@ std::string jidprep(const std::string& original) struct addrinfo* addr_res = nullptr; const auto ret = ::getaddrinfo(domain, nullptr, &hints, &addr_res); - auto addrinfo_deleter = utils::make_scope_guard([addr_res] { freeaddrinfo(addr_res); }); + auto addrinfo_deleter = utils::make_scope_guard([addr_res] { if (addr_res) freeaddrinfo(addr_res); }); if (ret || !addr_res || (addr_res->ai_family != AF_INET && addr_res->ai_family != AF_INET6)) { // Not an IP, run nameprep on it rc = static_cast(::stringprep(domain, max_jid_part_len, -- cgit v1.2.3 From d81cbc4a33ee2c28628ccb632af9ae1b27e84d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 27 Feb 2017 18:01:20 +0100 Subject: Use uname() instead of CMAKE_SYSTEM fix #3235 --- louloulibs/louloulibs.h.cmake | 1 - louloulibs/utils/system.cpp | 21 +++++++++++++++++++++ louloulibs/utils/system.hpp | 8 ++++++++ louloulibs/xmpp/xmpp_component.cpp | 3 ++- 4 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 louloulibs/utils/system.cpp create mode 100644 louloulibs/utils/system.hpp (limited to 'louloulibs') diff --git a/louloulibs/louloulibs.h.cmake b/louloulibs/louloulibs.h.cmake index ebb9b9a..e2b2e25 100644 --- a/louloulibs/louloulibs.h.cmake +++ b/louloulibs/louloulibs.h.cmake @@ -1,4 +1,3 @@ -#define SYSTEM_NAME "${CMAKE_SYSTEM}" #cmakedefine ICONV_SECOND_ARGUMENT_IS_CONST #cmakedefine LIBIDN_FOUND #cmakedefine SYSTEMD_FOUND diff --git a/louloulibs/utils/system.cpp b/louloulibs/utils/system.cpp new file mode 100644 index 0000000..c0bee11 --- /dev/null +++ b/louloulibs/utils/system.cpp @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +using namespace std::string_literals; + +namespace utils +{ +std::string get_system_name() +{ + struct utsname uts; + const int res = ::uname(&uts); + if (res == -1) + { + log_error("uname failed: ", std::strerror(errno)); + return "Unknown"; + } + return uts.sysname + " "s + uts.release; +} +} \ No newline at end of file diff --git a/louloulibs/utils/system.hpp b/louloulibs/utils/system.hpp new file mode 100644 index 0000000..7ea1677 --- /dev/null +++ b/louloulibs/utils/system.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace utils +{ +std::string get_system_name(); +} \ No newline at end of file diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index e1b6131..e40b1e4 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -585,7 +586,7 @@ void XmppComponent::send_version(const std::string& id, const std::string& jid_t } { XmlSubNode os(query, "os"); - os.set_inner(SYSTEM_NAME); + os.set_inner(utils::get_system_name()); } } else -- cgit v1.2.3 From fa3d44e7aaf43487f8fed62c9398ade6fa797acb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 28 Feb 2017 23:34:11 +0100 Subject: Use AI_NUMERICHOST when using getaddrinfo to bind() our client sockets --- louloulibs/network/tcp_client_socket_handler.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'louloulibs') diff --git a/louloulibs/network/tcp_client_socket_handler.cpp b/louloulibs/network/tcp_client_socket_handler.cpp index 4e6445c..530c3d9 100644 --- a/louloulibs/network/tcp_client_socket_handler.cpp +++ b/louloulibs/network/tcp_client_socket_handler.cpp @@ -35,7 +35,11 @@ void TCPClientSocketHandler::init_socket(const struct addrinfo* rp) // Convert the address from string format to a sockaddr that can be // used in bind() struct addrinfo* result; - int err = ::getaddrinfo(this->bind_addr.data(), nullptr, nullptr, &result); + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = AF_UNSPEC; + int err = ::getaddrinfo(this->bind_addr.data(), nullptr, &hints, &result); if (err != 0 || !result) log_error("Failed to bind socket to ", this->bind_addr, ": ", gai_strerror(err)); -- cgit v1.2.3 From 99a4ddedaf903d27b781341108433ae2d9533ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 6 Mar 2017 00:51:43 +0100 Subject: Remove the embedded sha1 code, and use one of botan or gcrypt This adds a hard dependency on one of Botan or gcrypt. Botan is already a recommended dependency, and gcrypt is probably packaged almost everywhere, so this should not be a big deal. ref #3241 --- louloulibs/CMakeLists.txt | 11 +++ louloulibs/cmake/Modules/FindGCRYPT.cmake | 35 +++++++ louloulibs/louloulibs.h.cmake | 1 + louloulibs/utils/sha1.cpp | 151 ++++++------------------------ louloulibs/utils/sha1.hpp | 34 +------ louloulibs/xmpp/auth.cpp | 15 +-- 6 files changed, 82 insertions(+), 165 deletions(-) create mode 100644 louloulibs/cmake/Modules/FindGCRYPT.cmake (limited to 'louloulibs') diff --git a/louloulibs/CMakeLists.txt b/louloulibs/CMakeLists.txt index f672833..2268571 100644 --- a/louloulibs/CMakeLists.txt +++ b/louloulibs/CMakeLists.txt @@ -33,6 +33,10 @@ elseif(NOT WITHOUT_BOTAN) find_package(BOTAN) endif() +if(NOT BOTAN_FOUND) + find_package(GCRYPT REQUIRED) +endif() + if(WITH_UDNS) find_package(UDNS REQUIRED) elseif(NOT WITHOUT_UDNS) @@ -67,6 +71,11 @@ if(BOTAN_FOUND) set(BOTAN_FOUND ${BOTAN_FOUND} PARENT_SCOPE) set(BOTAN_INCLUDE_DIRS ${BOTAN_INCLUDE_DIRS} PARENT_SCOPE) endif() +if(GCRYPT_FOUND) + include_directories(SYSTEM ${GCRYPT_INCLUDE_DIRS}) + set(GCRYPT_FOUND ${GCRYPT_FOUND} PARENT_SCOPE) + set(GCRYPT_INCLUDE_DIRS ${GCRYPT_INCLUDE_DIRS} PARENT_SCOPE) +endif() if(UDNS_FOUND) include_directories(${UDNS_INCLUDE_DIRS}) @@ -117,6 +126,8 @@ add_library(network STATIC ${source_network}) target_link_libraries(network logger) if(BOTAN_FOUND) target_link_libraries(network ${BOTAN_LIBRARIES}) +elseif(GCRYPT_FOUND) + target_link_libraries(network ${GCRYPT_LIBRARIES}) endif() if(UDNS_FOUND) target_link_libraries(network ${UDNS_LIBRARIES}) diff --git a/louloulibs/cmake/Modules/FindGCRYPT.cmake b/louloulibs/cmake/Modules/FindGCRYPT.cmake new file mode 100644 index 0000000..bb1bc67 --- /dev/null +++ b/louloulibs/cmake/Modules/FindGCRYPT.cmake @@ -0,0 +1,35 @@ +# - Find gcrypt +# Find the gcrypt cryptographic library +# +# This module defines the following variables: +# GCRYPT_FOUND - True if library and include directory are found +# If set to TRUE, the following are also defined: +# GCRYPT_INCLUDE_DIRS - The directory where to find the header file +# GCRYPT_LIBRARIES - Where to find the library file +# +# For conveniance, these variables are also set. They have the same values +# than the variables above. The user can thus choose his/her prefered way +# to write them. +# GCRYPT_LIBRARY +# GCRYPT_INCLUDE_DIR +# +# This file is in the public domain + +find_path(GCRYPT_INCLUDE_DIRS NAMES gcrypt.h + PATH_SUFFIXES gcrypt + DOC "The gcrypt include directory") + +find_library(GCRYPT_LIBRARIES NAMES gcrypt + DOC "The gcrypt library") + +# Use some standard module to handle the QUIETLY and REQUIRED arguments, and +# set GCRYPT_FOUND to TRUE if these two variables are set. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GCRYPT REQUIRED_VARS GCRYPT_LIBRARIES GCRYPT_INCLUDE_DIRS) + +if(GCRYPT_FOUND) + set(GCRYPT_LIBRARY ${GCRYPT_LIBRARIES}) + set(GCRYPT_INCLUDE_DIR ${GCRYPT_INCLUDE_DIRS}) +endif() + +mark_as_advanced(GCRYPT_INCLUDE_DIRS GCRYPT_LIBRARIES) diff --git a/louloulibs/louloulibs.h.cmake b/louloulibs/louloulibs.h.cmake index e2b2e25..5777d92 100644 --- a/louloulibs/louloulibs.h.cmake +++ b/louloulibs/louloulibs.h.cmake @@ -3,6 +3,7 @@ #cmakedefine SYSTEMD_FOUND #cmakedefine POLLER ${POLLER} #cmakedefine BOTAN_FOUND +#cmakedefine GCRYPT_FOUND #cmakedefine UDNS_FOUND #cmakedefine SOFTWARE_VERSION "${SOFTWARE_VERSION}" #cmakedefine PROJECT_NAME "${PROJECT_NAME}" diff --git a/louloulibs/utils/sha1.cpp b/louloulibs/utils/sha1.cpp index f75bc2a..71ad18d 100644 --- a/louloulibs/utils/sha1.cpp +++ b/louloulibs/utils/sha1.cpp @@ -1,121 +1,32 @@ -/* This code is public-domain - it is based on libcrypt - * placed in the public domain by Wei Dai and other contributors. - */ - -#include "sha1.hpp" - -#define SHA1_K0 0x5a827999 -#define SHA1_K20 0x6ed9eba1 -#define SHA1_K40 0x8f1bbcdc -#define SHA1_K60 0xca62c1d6 - -const uint8_t sha1InitState[] = { - 0x01,0x23,0x45,0x67, // H0 - 0x89,0xab,0xcd,0xef, // H1 - 0xfe,0xdc,0xba,0x98, // H2 - 0x76,0x54,0x32,0x10, // H3 - 0xf0,0xe1,0xd2,0xc3 // H4 -}; - -void sha1_init(sha1nfo *s) { - memcpy(s->state.b,sha1InitState,HASH_LENGTH); - s->byteCount = 0; - s->bufferOffset = 0; -} - -uint32_t sha1_rol32(uint32_t number, uint8_t bits) { - return ((number << bits) | (number >> (32-bits))); -} - -void sha1_hashBlock(sha1nfo *s) { - uint8_t i; - uint32_t a,b,c,d,e,t; - - a=s->state.w[0]; - b=s->state.w[1]; - c=s->state.w[2]; - d=s->state.w[3]; - e=s->state.w[4]; - for (i=0; i<80; i++) { - if (i>=16) { - t = s->buffer.w[(i+13)&15] ^ s->buffer.w[(i+8)&15] ^ s->buffer.w[(i+2)&15] ^ s->buffer.w[i&15]; - s->buffer.w[i&15] = sha1_rol32(t,1); - } - if (i<20) { - t = (d ^ (b & (c ^ d))) + SHA1_K0; - } else if (i<40) { - t = (b ^ c ^ d) + SHA1_K20; - } else if (i<60) { - t = ((b & c) | (d & (b | c))) + SHA1_K40; - } else { - t = (b ^ c ^ d) + SHA1_K60; - } - t+=sha1_rol32(a,5) + e + s->buffer.w[i&15]; - e=d; - d=c; - c=sha1_rol32(b,30); - b=a; - a=t; - } - s->state.w[0] += a; - s->state.w[1] += b; - s->state.w[2] += c; - s->state.w[3] += d; - s->state.w[4] += e; -} - -void sha1_addUncounted(sha1nfo *s, uint8_t data) { - s->buffer.b[s->bufferOffset ^ 3] = data; - s->bufferOffset++; - if (s->bufferOffset == BLOCK_LENGTH) { - sha1_hashBlock(s); - s->bufferOffset = 0; - } -} - -void sha1_writebyte(sha1nfo *s, uint8_t data) { - ++s->byteCount; - sha1_addUncounted(s, data); -} - -void sha1_write(sha1nfo *s, const char *data, size_t len) { - for (;len--;) sha1_writebyte(s, (uint8_t) *data++); -} - -void sha1_pad(sha1nfo *s) { - // Implement SHA-1 padding (fips180-2 §5.1.1) - - // Pad with 0x80 followed by 0x00 until the end of the block - sha1_addUncounted(s, 0x80); - while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00); - - // Append length in the last 8 bytes - sha1_addUncounted(s, 0); // We're only using 32 bit lengths - sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths - sha1_addUncounted(s, 0); // So zero pad the top bits - sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8 - sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as - sha1_addUncounted(s, s->byteCount >> 13); // byte. - sha1_addUncounted(s, s->byteCount >> 5); - sha1_addUncounted(s, s->byteCount << 3); -} - -uint8_t* sha1_result(sha1nfo *s) { - int i; - // Pad to complete the last block - sha1_pad(s); - - // Swap byte order back - for (i=0; i<5; i++) { - uint32_t a,b; - a=s->state.w[i]; - b=a<<24; - b|=(a<<8) & 0x00ff0000; - b|=(a>>8) & 0x0000ff00; - b|=a>>24; - s->state.w[i]=b; - } - - // Return pointer to hash (20 characters) - return s->state.b; +#include + +#include + +#ifdef BOTAN_FOUND +# include +# include +#endif +#ifdef GCRYPT_FOUND +# include +# include +# include +# include +#endif + +std::string sha1(const std::string& input) +{ +#ifdef BOTAN_FOUND + auto sha1 = Botan::HashFunction::create_or_throw("SHA-1"); + sha1->update(input); + return Botan::hex_encode(sha1->final(), false); +#endif +#ifdef GCRYPT_FOUND + const auto hash_length = gcry_md_get_algo_dlen(GCRY_MD_SHA1); + std::vector output(hash_length, {}); + gcry_md_hash_buffer(GCRY_MD_SHA1, output.data(), input.data(), input.size()); + std::ostringstream digest; + for (std::size_t i = 0; i < hash_length; i++) + digest << std::hex << std::setfill('0') << std::setw(2) << static_cast(output[i]); + return digest.str(); +#endif } diff --git a/louloulibs/utils/sha1.hpp b/louloulibs/utils/sha1.hpp index d436782..6c551ac 100644 --- a/louloulibs/utils/sha1.hpp +++ b/louloulibs/utils/sha1.hpp @@ -1,33 +1,5 @@ -/* This code is public-domain - it is based on libcrypt - * placed in the public domain by Wei Dai and other contributors. - */ +#pragma once -#include -#include +#include -#define HASH_LENGTH 20 -#define BLOCK_LENGTH 64 - -union _buffer { - uint8_t b[BLOCK_LENGTH]; - uint32_t w[BLOCK_LENGTH/4]; -}; - -union _state { - uint8_t b[HASH_LENGTH]; - uint32_t w[HASH_LENGTH/4]; -}; - -typedef struct sha1nfo { - union _buffer buffer; - uint8_t bufferOffset; - union _state state; - uint32_t byteCount; - uint8_t keyBuffer[BLOCK_LENGTH]; - uint8_t innerHash[HASH_LENGTH]; -} sha1nfo; - -void sha1_init(sha1nfo *s); -void sha1_writebyte(sha1nfo *s, uint8_t data); -void sha1_write(sha1nfo *s, const char *data, size_t len); -uint8_t* sha1_result(sha1nfo *s); +std::string sha1(const std::string& input); diff --git a/louloulibs/xmpp/auth.cpp b/louloulibs/xmpp/auth.cpp index c20f95d..8a34a4e 100644 --- a/louloulibs/xmpp/auth.cpp +++ b/louloulibs/xmpp/auth.cpp @@ -2,20 +2,7 @@ #include -#include -#include - std::string get_handshake_digest(const std::string& stream_id, const std::string& secret) { - sha1nfo sha1; - sha1_init(&sha1); - sha1_write(&sha1, stream_id.data(), stream_id.size()); - sha1_write(&sha1, secret.data(), secret.size()); - const uint8_t* result = sha1_result(&sha1); - - std::ostringstream digest; - for (int i = 0; i < HASH_LENGTH; i++) - digest << std::hex << std::setfill('0') << std::setw(2) << static_cast(result[i]); - - return digest.str(); + return sha1(stream_id + secret); } -- cgit v1.2.3 From 6cb7787512a5e02ad2100dbdef734b36d8a8f0d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 7 Mar 2017 17:47:10 +0100 Subject: Small resolver refactor Makes the codecoverage deterministic (it does not depend on the order of v4/v6 resolution) --- louloulibs/network/resolver.cpp | 17 ++++++++--------- louloulibs/network/resolver.hpp | 4 ++++ 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/network/resolver.cpp b/louloulibs/network/resolver.cpp index 0655b1b..27a515e 100644 --- a/louloulibs/network/resolver.cpp +++ b/louloulibs/network/resolver.cpp @@ -113,12 +113,14 @@ void Resolver::start_resolving(const std::string& hostname, const std::string& p { Resolver* resolver = static_cast(data); resolver->on_hostname6_resolved(result); + resolver->after_resolved(); }; auto hostname4_resolved = [](dns_ctx*, dns_rr_a4* result, void* data) { Resolver* resolver = static_cast(data); resolver->on_hostname4_resolved(result); + resolver->after_resolved(); }; DNSHandler::watch(); @@ -173,9 +175,6 @@ std::vector Resolver::look_in_etc_hosts(const std::string &hostname void Resolver::on_hostname4_resolved(dns_rr_a4 *result) { - if (dns_active(nullptr) == 0) - DNSHandler::unwatch(); - this->resolved4 = true; const auto status = dns_status(nullptr); @@ -196,16 +195,10 @@ void Resolver::on_hostname4_resolved(dns_rr_a4 *result) if (error != end(dns_error_messages)) this->error_msg = error->second; } - - if (this->resolved6 && this->resolved4) - this->on_resolved(); } void Resolver::on_hostname6_resolved(dns_rr_a6 *result) { - if (dns_active(nullptr) == 0) - DNSHandler::unwatch(); - this->resolved6 = true; char buf[INET6_ADDRSTRLEN]; @@ -219,6 +212,12 @@ void Resolver::on_hostname6_resolved(dns_rr_a6 *result) this->call_getaddrinfo(buf, this->port.data(), AI_NUMERICHOST); } } +} + +void Resolver::after_resolved() +{ + if (dns_active(nullptr) == 0) + DNSHandler::unwatch(); if (this->resolved6 && this->resolved4) this->on_resolved(); diff --git a/louloulibs/network/resolver.hpp b/louloulibs/network/resolver.hpp index 800c7ec..a560819 100644 --- a/louloulibs/network/resolver.hpp +++ b/louloulibs/network/resolver.hpp @@ -89,6 +89,10 @@ private: #ifdef UDNS_FOUND void on_hostname4_resolved(dns_rr_a4 *result); void on_hostname6_resolved(dns_rr_a6 *result); + /** + * Called after one record (4 or 6) has been resolved. + */ + void after_resolved(); void start_timer(); -- cgit v1.2.3 From cd92baae3f0de8b841b5bbfdb02e4fa95acd52c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 7 Mar 2017 18:27:27 +0100 Subject: Little refactor in timed_events Also makes the coverage code deterministic --- louloulibs/utils/timed_events.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/utils/timed_events.cpp b/louloulibs/utils/timed_events.cpp index 68d009c..5077199 100644 --- a/louloulibs/utils/timed_events.cpp +++ b/louloulibs/utils/timed_events.cpp @@ -32,10 +32,8 @@ bool TimedEvent::is_after(const std::chrono::steady_clock::time_point& time_poin std::chrono::milliseconds TimedEvent::get_timeout() const { - auto now = std::chrono::steady_clock::now(); - if (now > this->time_point) - return std::chrono::milliseconds(0); - return std::chrono::duration_cast(this->time_point - now); + auto diff = std::chrono::duration_cast(this->time_point - std::chrono::steady_clock::now()); + return std::max(diff, 0ms); } void TimedEvent::execute() const -- cgit v1.2.3 From f0bc6c83a8eb548d0a3edbf7c16a6922bfd24ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 8 Mar 2017 19:04:15 +0100 Subject: Pass the shared_ptr by reference, to avoid useless copies --- louloulibs/network/dns_handler.cpp | 2 +- louloulibs/network/dns_handler.hpp | 2 +- louloulibs/network/dns_socket_handler.cpp | 2 +- louloulibs/network/dns_socket_handler.hpp | 2 +- louloulibs/network/socket_handler.hpp | 2 +- louloulibs/network/tcp_client_socket_handler.cpp | 2 +- louloulibs/network/tcp_client_socket_handler.hpp | 2 +- louloulibs/network/tcp_server_socket.hpp | 2 +- louloulibs/network/tcp_socket_handler.cpp | 2 +- louloulibs/network/tcp_socket_handler.hpp | 2 +- louloulibs/xmpp/xmpp_component.cpp | 2 +- louloulibs/xmpp/xmpp_component.hpp | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/network/dns_handler.cpp b/louloulibs/network/dns_handler.cpp index fbd2763..641c087 100644 --- a/louloulibs/network/dns_handler.cpp +++ b/louloulibs/network/dns_handler.cpp @@ -17,7 +17,7 @@ using namespace std::string_literals; std::unique_ptr DNSHandler::socket_handler{}; -DNSHandler::DNSHandler(std::shared_ptr poller) +DNSHandler::DNSHandler(std::shared_ptr& poller) { dns_init(nullptr, 0); const auto socket = dns_open(nullptr); diff --git a/louloulibs/network/dns_handler.hpp b/louloulibs/network/dns_handler.hpp index 78ffe4d..416f85f 100644 --- a/louloulibs/network/dns_handler.hpp +++ b/louloulibs/network/dns_handler.hpp @@ -14,7 +14,7 @@ class Poller; class DNSHandler { public: - explicit DNSHandler(std::shared_ptr poller); + explicit DNSHandler(std::shared_ptr& poller); ~DNSHandler() = default; DNSHandler(const DNSHandler&) = delete; diff --git a/louloulibs/network/dns_socket_handler.cpp b/louloulibs/network/dns_socket_handler.cpp index ad744a9..84e5625 100644 --- a/louloulibs/network/dns_socket_handler.cpp +++ b/louloulibs/network/dns_socket_handler.cpp @@ -7,7 +7,7 @@ #include -DNSSocketHandler::DNSSocketHandler(std::shared_ptr poller, +DNSSocketHandler::DNSSocketHandler(std::shared_ptr& poller, const socket_t socket): SocketHandler(poller, socket) { diff --git a/louloulibs/network/dns_socket_handler.hpp b/louloulibs/network/dns_socket_handler.hpp index e12f145..fc5f41f 100644 --- a/louloulibs/network/dns_socket_handler.hpp +++ b/louloulibs/network/dns_socket_handler.hpp @@ -12,7 +12,7 @@ class DNSSocketHandler: public SocketHandler { public: - explicit DNSSocketHandler(std::shared_ptr poller, const socket_t socket); + explicit DNSSocketHandler(std::shared_ptr& poller, const socket_t socket); ~DNSSocketHandler(); DNSSocketHandler(const DNSSocketHandler&) = delete; DNSSocketHandler(DNSSocketHandler&&) = delete; diff --git a/louloulibs/network/socket_handler.hpp b/louloulibs/network/socket_handler.hpp index 607a106..6a7220e 100644 --- a/louloulibs/network/socket_handler.hpp +++ b/louloulibs/network/socket_handler.hpp @@ -10,7 +10,7 @@ using socket_t = int; class SocketHandler { public: - explicit SocketHandler(std::shared_ptr poller, const socket_t socket): + explicit SocketHandler(std::shared_ptr& poller, const socket_t socket): poller(poller), socket(socket) {} diff --git a/louloulibs/network/tcp_client_socket_handler.cpp b/louloulibs/network/tcp_client_socket_handler.cpp index 530c3d9..4628703 100644 --- a/louloulibs/network/tcp_client_socket_handler.cpp +++ b/louloulibs/network/tcp_client_socket_handler.cpp @@ -11,7 +11,7 @@ using namespace std::string_literals; -TCPClientSocketHandler::TCPClientSocketHandler(std::shared_ptr poller): +TCPClientSocketHandler::TCPClientSocketHandler(std::shared_ptr& poller): TCPSocketHandler(poller), hostname_resolution_failed(false), connected(false), diff --git a/louloulibs/network/tcp_client_socket_handler.hpp b/louloulibs/network/tcp_client_socket_handler.hpp index 75e1364..74caca9 100644 --- a/louloulibs/network/tcp_client_socket_handler.hpp +++ b/louloulibs/network/tcp_client_socket_handler.hpp @@ -5,7 +5,7 @@ class TCPClientSocketHandler: public TCPSocketHandler { public: - TCPClientSocketHandler(std::shared_ptr poller); + TCPClientSocketHandler(std::shared_ptr& poller); ~TCPClientSocketHandler(); /** * Connect to the remote server, and call on_connected() if this diff --git a/louloulibs/network/tcp_server_socket.hpp b/louloulibs/network/tcp_server_socket.hpp index 7ea49ab..c511962 100644 --- a/louloulibs/network/tcp_server_socket.hpp +++ b/louloulibs/network/tcp_server_socket.hpp @@ -18,7 +18,7 @@ template class TcpSocketServer: public SocketHandler { public: - TcpSocketServer(std::shared_ptr poller, const uint16_t port): + TcpSocketServer(std::shared_ptr& poller, const uint16_t port): SocketHandler(poller, -1) { if ((this->socket = ::socket(AF_INET6, SOCK_STREAM, 0)) == -1) diff --git a/louloulibs/network/tcp_socket_handler.cpp b/louloulibs/network/tcp_socket_handler.cpp index 6aef2b1..7eebae0 100644 --- a/louloulibs/network/tcp_socket_handler.cpp +++ b/louloulibs/network/tcp_socket_handler.cpp @@ -44,7 +44,7 @@ using namespace std::chrono_literals; namespace ph = std::placeholders; -TCPSocketHandler::TCPSocketHandler(std::shared_ptr poller): +TCPSocketHandler::TCPSocketHandler(std::shared_ptr& poller): SocketHandler(poller, -1), use_tls(false) #ifdef BOTAN_FOUND diff --git a/louloulibs/network/tcp_socket_handler.hpp b/louloulibs/network/tcp_socket_handler.hpp index 600405d..3ee2f47 100644 --- a/louloulibs/network/tcp_socket_handler.hpp +++ b/louloulibs/network/tcp_socket_handler.hpp @@ -60,7 +60,7 @@ class TCPSocketHandler: public SocketHandler protected: ~TCPSocketHandler(); public: - explicit TCPSocketHandler(std::shared_ptr poller); + explicit TCPSocketHandler(std::shared_ptr& poller); TCPSocketHandler(const TCPSocketHandler&) = delete; TCPSocketHandler(TCPSocketHandler&&) = delete; TCPSocketHandler& operator=(const TCPSocketHandler&) = delete; diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index e40b1e4..5d98e58 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -39,7 +39,7 @@ static std::set kickable_errors{ "malformed-error" }; -XmppComponent::XmppComponent(std::shared_ptr poller, const std::string& hostname, const std::string& secret): +XmppComponent::XmppComponent(std::shared_ptr& poller, const std::string& hostname, const std::string& secret): TCPClientSocketHandler(poller), ever_auth(false), first_connection_try(true), diff --git a/louloulibs/xmpp/xmpp_component.hpp b/louloulibs/xmpp/xmpp_component.hpp index a9bac0f..16d7480 100644 --- a/louloulibs/xmpp/xmpp_component.hpp +++ b/louloulibs/xmpp/xmpp_component.hpp @@ -43,7 +43,7 @@ class XmppComponent: public TCPClientSocketHandler { public: - explicit XmppComponent(std::shared_ptr poller, const std::string& hostname, const std::string& secret); + explicit XmppComponent(std::shared_ptr& poller, const std::string& hostname, const std::string& secret); virtual ~XmppComponent() = default; XmppComponent(const XmppComponent&) = delete; -- cgit v1.2.3 From 0205076106604372e79130691dcfb7aca15b5055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 8 Mar 2017 19:04:54 +0100 Subject: Reduce the scope of a variable --- louloulibs/network/resolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs') diff --git a/louloulibs/network/resolver.cpp b/louloulibs/network/resolver.cpp index 27a515e..3558800 100644 --- a/louloulibs/network/resolver.cpp +++ b/louloulibs/network/resolver.cpp @@ -200,12 +200,12 @@ void Resolver::on_hostname4_resolved(dns_rr_a4 *result) void Resolver::on_hostname6_resolved(dns_rr_a6 *result) { this->resolved6 = true; - char buf[INET6_ADDRSTRLEN]; const auto status = dns_status(nullptr); if (status >= 0 && result) { + char buf[INET6_ADDRSTRLEN]; for (auto i = 0; i < result->dnsa6_nrr; ++i) { inet_ntop(AF_INET6, &result->dnsa6_addr[i], buf, sizeof(buf)); -- cgit v1.2.3 From d44125371fb9f170ea708e96682ad376a45fc293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 9 Mar 2017 18:49:48 +0100 Subject: Free the result pointer provided by udns Fix a memory leak that would occur on every DNS request, when using udns --- louloulibs/network/resolver.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'louloulibs') diff --git a/louloulibs/network/resolver.cpp b/louloulibs/network/resolver.cpp index 3558800..db7fb32 100644 --- a/louloulibs/network/resolver.cpp +++ b/louloulibs/network/resolver.cpp @@ -114,6 +114,7 @@ void Resolver::start_resolving(const std::string& hostname, const std::string& p Resolver* resolver = static_cast(data); resolver->on_hostname6_resolved(result); resolver->after_resolved(); + std::free(result); }; auto hostname4_resolved = [](dns_ctx*, dns_rr_a4* result, void* data) @@ -121,6 +122,7 @@ void Resolver::start_resolving(const std::string& hostname, const std::string& p Resolver* resolver = static_cast(data); resolver->on_hostname4_resolved(result); resolver->after_resolved(); + std::free(result); }; DNSHandler::watch(); -- cgit v1.2.3 From 2013ed6f98c0bffdb00fe06df5dca1d1ad422305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 10 Mar 2017 10:20:03 +0100 Subject: cmake: Remove the intermediate static libs Should compile faster (and also take less space on disk) --- louloulibs/CMakeLists.txt | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/CMakeLists.txt b/louloulibs/CMakeLists.txt index 2268571..4c37c20 100644 --- a/louloulibs/CMakeLists.txt +++ b/louloulibs/CMakeLists.txt @@ -51,8 +51,11 @@ include_directories(${ICONV_INCLUDE_DIRS}) include_directories(${LIBUUID_INCLUDE_DIRS}) set(EXPAT_INCLUDE_DIRS ${EXPAT_INCLUDE_DIRS} PARENT_SCOPE) +set(EXPAT_LIBRARIES ${EXPAT_LIBRARIES} PARENT_SCOPE) set(ICONV_INCLUDE_DIRS ${ICONV_INCLUDE_DIRS} PARENT_SCOPE) +set(ICONV_LIBRARIES ${ICONV_LIBRARIES} PARENT_SCOPE) set(LIBUUID_INCLUDE_DIRS ${LIBUUID_INCLUDE_DIRS} PARENT_SCOPE) +set(LIBUUID_LIBRARIES ${LIBUUID_LIBRARIES} PARENT_SCOPE) if(LIBIDN_FOUND) include_directories(${LIBIDN_INCLUDE_DIRS}) @@ -99,55 +102,35 @@ endif() # file(GLOB source_utils utils/*.[hc]pp) -add_library(utils STATIC ${source_utils}) -target_link_libraries(utils ${ICONV_LIBRARIES}) +add_library(utils OBJECT ${source_utils}) # ## config # file(GLOB source_config config/*.[hc]pp) -add_library(config STATIC ${source_config}) +add_library(config OBJECT ${source_config}) # ## logger # file(GLOB source_logger logger/*.[hc]pp) -add_library(logger STATIC ${source_logger}) -target_link_libraries(logger config) +add_library(logger OBJECT ${source_logger}) # ## network # file(GLOB source_network network/*.[hc]pp) -add_library(network STATIC ${source_network}) -target_link_libraries(network logger) -if(BOTAN_FOUND) - target_link_libraries(network ${BOTAN_LIBRARIES}) -elseif(GCRYPT_FOUND) - target_link_libraries(network ${GCRYPT_LIBRARIES}) -endif() -if(UDNS_FOUND) - target_link_libraries(network ${UDNS_LIBRARIES}) -endif() +add_library(network OBJECT ${source_network}) # ## xmpplib # file(GLOB source_xmpplib xmpp/*.[hc]pp) -add_library(xmpplib STATIC ${source_xmpplib}) -target_link_libraries(xmpplib network utils logger - ${EXPAT_LIBRARIES} - ${LIBUUID_LIBRARIES}) -if(LIBIDN_FOUND) - target_link_libraries(xmpplib ${LIBIDN_LIBRARIES}) -endif() -if(SYSTEMD_FOUND) - target_link_libraries(xmpplib ${SYSTEMD_LIBRARIES}) -endif() +add_library(xmpplib OBJECT ${source_xmpplib}) # Define a __FILENAME__ macro with the relative path (from the base project directory) # of each source file -- cgit v1.2.3 From 2b6b577375cad899bcd4c00b8ea91fb5ef4c907c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 10 Mar 2017 11:11:08 +0100 Subject: cmake: do not use intermediate libraries at all (not even OBJECTS) --- louloulibs/CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/CMakeLists.txt b/louloulibs/CMakeLists.txt index 4c37c20..e1e402f 100644 --- a/louloulibs/CMakeLists.txt +++ b/louloulibs/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 3.0) set(${PROJECT_NAME}_VERSION_MAJOR 1) set(${PROJECT_NAME}_VERSION_MINOR 0) @@ -102,35 +102,35 @@ endif() # file(GLOB source_utils utils/*.[hc]pp) -add_library(utils OBJECT ${source_utils}) +set(source_utils ${source_utils} PARENT_SCOPE) # ## config # file(GLOB source_config config/*.[hc]pp) -add_library(config OBJECT ${source_config}) +set(source_config ${source_config} PARENT_SCOPE) # ## logger # file(GLOB source_logger logger/*.[hc]pp) -add_library(logger OBJECT ${source_logger}) +set(source_logger ${source_logger} PARENT_SCOPE) # ## network # file(GLOB source_network network/*.[hc]pp) -add_library(network OBJECT ${source_network}) +set(source_network ${source_network} PARENT_SCOPE) # ## xmpplib # file(GLOB source_xmpplib xmpp/*.[hc]pp) -add_library(xmpplib OBJECT ${source_xmpplib}) +set(source_xmpplib ${source_xmpplib} PARENT_SCOPE) # Define a __FILENAME__ macro with the relative path (from the base project directory) # of each source file -- cgit v1.2.3 From a6f6e36594979a83ad16b3c4de350ed95e79daf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 12 Mar 2017 16:51:19 +0100 Subject: cmake: Improve the usage of PARENT_SCOPE --- louloulibs/CMakeLists.txt | 40 ++---------------------------- louloulibs/cmake/Modules/FindBOTAN.cmake | 33 +++++++++++++++--------- louloulibs/cmake/Modules/FindGCRYPT.cmake | 30 +++++++++++++--------- louloulibs/cmake/Modules/FindICONV.cmake | 9 ++++--- louloulibs/cmake/Modules/FindLIBIDN.cmake | 7 +++--- louloulibs/cmake/Modules/FindLIBUUID.cmake | 5 ++-- louloulibs/cmake/Modules/FindSYSTEMD.cmake | 7 +++--- louloulibs/cmake/Modules/FindUDNS.cmake | 5 ++-- 8 files changed, 60 insertions(+), 76 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/CMakeLists.txt b/louloulibs/CMakeLists.txt index e1e402f..80b1f5f 100644 --- a/louloulibs/CMakeLists.txt +++ b/louloulibs/CMakeLists.txt @@ -10,10 +10,10 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -pedantic -Wall -Wextra") ## Look for external libraries # set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/") -include(FindEXPAT) -find_package(EXPAT REQUIRED) find_package(ICONV REQUIRED) find_package(LIBUUID REQUIRED) +find_package(EXPAT REQUIRED) +set(EXPAT_FOUND ${EXPAT_FOUND} PARENT_SCOPE) if(WITH_LIBIDN) find_package(LIBIDN REQUIRED) @@ -50,42 +50,6 @@ include_directories(${EXPAT_INCLUDE_DIRS}) include_directories(${ICONV_INCLUDE_DIRS}) include_directories(${LIBUUID_INCLUDE_DIRS}) -set(EXPAT_INCLUDE_DIRS ${EXPAT_INCLUDE_DIRS} PARENT_SCOPE) -set(EXPAT_LIBRARIES ${EXPAT_LIBRARIES} PARENT_SCOPE) -set(ICONV_INCLUDE_DIRS ${ICONV_INCLUDE_DIRS} PARENT_SCOPE) -set(ICONV_LIBRARIES ${ICONV_LIBRARIES} PARENT_SCOPE) -set(LIBUUID_INCLUDE_DIRS ${LIBUUID_INCLUDE_DIRS} PARENT_SCOPE) -set(LIBUUID_LIBRARIES ${LIBUUID_LIBRARIES} PARENT_SCOPE) - -if(LIBIDN_FOUND) - include_directories(${LIBIDN_INCLUDE_DIRS}) - set(LIBDIN_FOUND ${LIBDIN_FOUND} PARENT_SCOPE) - set(LIBDIN_INCLUDE_DIRS ${LIBDIN_INCLUDE_DIRS} PARENT_SCOPE) -endif() - -if(SYSTEMD_FOUND) - include_directories(${SYSTEMD_INCLUDE_DIRS}) - set(SYSTEMD_FOUND ${SYSTEMD_FOUND} PARENT_SCOPE) - set(SYSTEMD_INCLUDE_DIRS ${SYSTEMD_INCLUDE_DIRS} PARENT_SCOPE) -endif() - -if(BOTAN_FOUND) - include_directories(SYSTEM ${BOTAN_INCLUDE_DIRS}) - set(BOTAN_FOUND ${BOTAN_FOUND} PARENT_SCOPE) - set(BOTAN_INCLUDE_DIRS ${BOTAN_INCLUDE_DIRS} PARENT_SCOPE) -endif() -if(GCRYPT_FOUND) - include_directories(SYSTEM ${GCRYPT_INCLUDE_DIRS}) - set(GCRYPT_FOUND ${GCRYPT_FOUND} PARENT_SCOPE) - set(GCRYPT_INCLUDE_DIRS ${GCRYPT_INCLUDE_DIRS} PARENT_SCOPE) -endif() - -if(UDNS_FOUND) - include_directories(${UDNS_INCLUDE_DIRS}) - set(UDNS_FOUND ${UDNS_FOUND} PARENT_SCOPE) - set(UDNS_INCLUDE_DIRS ${UDNS_INCLUDE_DIRS} PARENT_SCOPE) -endif() - set(POLLER_DOCSTRING "Choose the poller between POLL and EPOLL (Linux-only)") if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") set(POLLER "EPOLL" CACHE STRING ${POLLER_DOCSTRING}) diff --git a/louloulibs/cmake/Modules/FindBOTAN.cmake b/louloulibs/cmake/Modules/FindBOTAN.cmake index 26069f4..27f82a7 100644 --- a/louloulibs/cmake/Modules/FindBOTAN.cmake +++ b/louloulibs/cmake/Modules/FindBOTAN.cmake @@ -15,21 +15,30 @@ # # This file is in the public domain -find_path(BOTAN_INCLUDE_DIRS NAMES botan/botan.h - PATH_SUFFIXES botan-2 botan-1.11 - DOC "The botan include directory") +include(FindPkgConfig) +pkg_check_modules(BOTAN botan-2) +if(NOT BOTAN_FOUND) + pkg_check_modules(BOTAN botan-1.11) +endif() + +if(NOT BOTAN_FOUND) + find_path(BOTAN_INCLUDE_DIRS NAMES botan/botan.h + PATH_SUFFIXES botan-2 botan-1.11 + DOC "The botan include directory") -find_library(BOTAN_LIBRARIES NAMES botan botan-2 botan-1.11 - DOC "The botan library") + find_library(BOTAN_LIBRARIES NAMES botan botan-2 botan-1.11 + DOC "The botan library") -# Use some standard module to handle the QUIETLY and REQUIRED arguments, and -# set BOTAN_FOUND to TRUE if these two variables are set. -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(BOTAN REQUIRED_VARS BOTAN_LIBRARIES BOTAN_INCLUDE_DIRS) + # Use some standard module to handle the QUIETLY and REQUIRED arguments, and + # set BOTAN_FOUND to TRUE if these two variables are set. + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(BOTAN REQUIRED_VARS BOTAN_LIBRARIES BOTAN_INCLUDE_DIRS) -if(BOTAN_FOUND) - set(BOTAN_LIBRARY ${BOTAN_LIBRARIES}) - set(BOTAN_INCLUDE_DIR ${BOTAN_INCLUDE_DIRS}) + if(BOTAN_FOUND) + set(BOTAN_LIBRARY ${BOTAN_LIBRARIES} PARENT_SCOPE) + set(BOTAN_INCLUDE_DIR ${BOTAN_INCLUDE_DIRS} PARENT_SCOPE) + set(BOTAN_FOUND ${BOTAN_FOUND} PARENT_SCOPE) + endif() endif() mark_as_advanced(BOTAN_INCLUDE_DIRS BOTAN_LIBRARIES) diff --git a/louloulibs/cmake/Modules/FindGCRYPT.cmake b/louloulibs/cmake/Modules/FindGCRYPT.cmake index bb1bc67..62f5c7a 100644 --- a/louloulibs/cmake/Modules/FindGCRYPT.cmake +++ b/louloulibs/cmake/Modules/FindGCRYPT.cmake @@ -15,21 +15,27 @@ # # This file is in the public domain -find_path(GCRYPT_INCLUDE_DIRS NAMES gcrypt.h - PATH_SUFFIXES gcrypt - DOC "The gcrypt include directory") +include(FindPkgConfig) +pkg_check_modules(GCRYPT gcrypt) -find_library(GCRYPT_LIBRARIES NAMES gcrypt - DOC "The gcrypt library") +if(NOT GCRYPT_FOUND) + find_path(GCRYPT_INCLUDE_DIRS NAMES gcrypt.h + PATH_SUFFIXES gcrypt + DOC "The gcrypt include directory") -# Use some standard module to handle the QUIETLY and REQUIRED arguments, and -# set GCRYPT_FOUND to TRUE if these two variables are set. -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(GCRYPT REQUIRED_VARS GCRYPT_LIBRARIES GCRYPT_INCLUDE_DIRS) + find_library(GCRYPT_LIBRARIES NAMES gcrypt + DOC "The gcrypt library") -if(GCRYPT_FOUND) - set(GCRYPT_LIBRARY ${GCRYPT_LIBRARIES}) - set(GCRYPT_INCLUDE_DIR ${GCRYPT_INCLUDE_DIRS}) + # Use some standard module to handle the QUIETLY and REQUIRED arguments, and + # set GCRYPT_FOUND to TRUE if these two variables are set. + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(GCRYPT REQUIRED_VARS GCRYPT_LIBRARIES GCRYPT_INCLUDE_DIRS) + + if(GCRYPT_FOUND) + set(GCRYPT_LIBRARY ${GCRYPT_LIBRARIES} PARENT_SCOPE) + set(GCRYPT_INCLUDE_DIR ${GCRYPT_INCLUDE_DIRS} PARENT_SCOPE) + set(GCRYPT_FOUND ${GCRYPT_FOUND} PARENT_SCOPE) + endif() endif() mark_as_advanced(GCRYPT_INCLUDE_DIRS GCRYPT_LIBRARIES) diff --git a/louloulibs/cmake/Modules/FindICONV.cmake b/louloulibs/cmake/Modules/FindICONV.cmake index 7ca173f..9e5bde6 100644 --- a/louloulibs/cmake/Modules/FindICONV.cmake +++ b/louloulibs/cmake/Modules/FindICONV.cmake @@ -52,9 +52,10 @@ if(ICONV_FOUND) return 0;}" ICONV_SECOND_ARGUMENT_IS_CONST) -# Compatibility for all the ways of writing these variables - set(ICONV_LIBRARY ${ICONV_LIBRARIES}) - set(ICONV_INCLUDE_DIR ${ICONV_INCLUDE_DIRS}) + # Compatibility for all the ways of writing these variables + set(ICONV_LIBRARY ${ICONV_LIBRARIES} PARENT_SCOPE) + set(ICONV_INCLUDE_DIR ${ICONV_INCLUDE_DIRS} PARENT_SCOPE) + set(ICONV_FOUND ${ICONV_FOUND} PARENT_SCOPE) endif() -mark_as_advanced(ICONV_INCLUDE_DIRS ICONV_LIBRARIES ICONV_SECOND_ARGUMENT_IS_CONST) \ No newline at end of file +mark_as_advanced(ICONV_INCLUDE_DIRS ICONV_LIBRARIES ICONV_SECOND_ARGUMENT_IS_CONST) diff --git a/louloulibs/cmake/Modules/FindLIBIDN.cmake b/louloulibs/cmake/Modules/FindLIBIDN.cmake index 611a6a8..716714f 100644 --- a/louloulibs/cmake/Modules/FindLIBIDN.cmake +++ b/louloulibs/cmake/Modules/FindLIBIDN.cmake @@ -33,9 +33,10 @@ if(NOT LIBIDN_FOUND) # Compatibility for all the ways of writing these variables if(LIBIDN_FOUND) - set(LIBIDN_INCLUDE_DIR ${LIBIDN_INCLUDE_DIRS}) - set(LIBIDN_LIBRARY ${LIBIDN_LIBRARIES}) + set(LIBIDN_INCLUDE_DIR ${LIBIDN_INCLUDE_DIRS} PARENT_SCOPE) + set(LIBIDN_LIBRARY ${LIBIDN_LIBRARIES} PARENT_SCOPE) + set(LIBIDN_FOUND ${LIBIDN_FOUND} PARENT_SCOPE) endif() endif() -mark_as_advanced(LIBIDN_INCLUDE_DIRS LIBIDN_LIBRARIES) \ No newline at end of file +mark_as_advanced(LIBIDN_INCLUDE_DIRS LIBIDN_LIBRARIES) diff --git a/louloulibs/cmake/Modules/FindLIBUUID.cmake b/louloulibs/cmake/Modules/FindLIBUUID.cmake index f344249..9269978 100644 --- a/louloulibs/cmake/Modules/FindLIBUUID.cmake +++ b/louloulibs/cmake/Modules/FindLIBUUID.cmake @@ -33,8 +33,9 @@ if(NOT LIBUUID_FOUND) # Compatibility for all the ways of writing these variables if(LIBUUID_FOUND) - set(LIBUUID_INCLUDE_DIR ${LIBUUID_INCLUDE_DIRS}) - set(LIBUUID_LIBRARY ${LIBUUID_LIBRARIES}) + set(LIBUUID_INCLUDE_DIR ${LIBUUID_INCLUDE_DIRS} PARENT_SCOPE) + set(LIBUUID_LIBRARY ${LIBUUID_LIBRARIES} PARENT_SCOPE) + set(LIBUUID_FOUND ${LIBUUID_FOUND} PARENT_SCOPE) endif() endif() diff --git a/louloulibs/cmake/Modules/FindSYSTEMD.cmake b/louloulibs/cmake/Modules/FindSYSTEMD.cmake index c7decde..43db6c4 100644 --- a/louloulibs/cmake/Modules/FindSYSTEMD.cmake +++ b/louloulibs/cmake/Modules/FindSYSTEMD.cmake @@ -31,9 +31,10 @@ if(NOT SYSTEMD_FOUND) find_package_handle_standard_args(SYSTEMD REQUIRED_VARS SYSTEMD_LIBRARIES SYSTEMD_INCLUDE_DIRS) if(SYSTEMD_FOUND) - set(SYSTEMD_LIBRARY ${SYSTEMD_LIBRARIES}) - set(SYSTEMD_INCLUDE_DIR ${SYSTEMD_INCLUDE_DIRS}) + set(SYSTEMD_LIBRARY ${SYSTEMD_LIBRARIES} PARENT_SCOPE) + set(SYSTEMD_INCLUDE_DIR ${SYSTEMD_INCLUDE_DIRS} PARENT_SCOPE) + set(SYSTEMD_FOUND ${SYSTEMD_FOUND} PARENT_SCOPE) endif() endif() -mark_as_advanced(SYSTEMD_INCLUDE_DIRS SYSTEMD_LIBRARIES) \ No newline at end of file +mark_as_advanced(SYSTEMD_INCLUDE_DIRS SYSTEMD_LIBRARIES) diff --git a/louloulibs/cmake/Modules/FindUDNS.cmake b/louloulibs/cmake/Modules/FindUDNS.cmake index 1d32cd3..33fbc4c 100644 --- a/louloulibs/cmake/Modules/FindUDNS.cmake +++ b/louloulibs/cmake/Modules/FindUDNS.cmake @@ -29,8 +29,9 @@ if(NOT UDNS_FOUND) # Compatibility for all the ways of writing these variables if(UDNS_FOUND) - set(UDNS_INCLUDE_DIR ${UDNS_INCLUDE_DIRS}) - set(UDNS_LIBRARY ${UDNS_LIBRARIES}) + set(UDNS_INCLUDE_DIR ${UDNS_INCLUDE_DIRS} PARENT_SCOPE) + set(UDNS_LIBRARY ${UDNS_LIBRARIES} PARENT_SCOPE) + set(UDNS_FOUND ${UDNS_FOUND} PARENT_SCOPE) endif() endif() -- cgit v1.2.3 From ef08e53b7e5dd3fcd27859af5183575008715c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 12 Mar 2017 16:52:27 +0100 Subject: make: trivial quote fix --- louloulibs/CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'louloulibs') diff --git a/louloulibs/CMakeLists.txt b/louloulibs/CMakeLists.txt index 80b1f5f..b3056f2 100644 --- a/louloulibs/CMakeLists.txt +++ b/louloulibs/CMakeLists.txt @@ -44,8 +44,9 @@ elseif(NOT WITHOUT_UDNS) endif() # To be able to include the config.h file generated by cmake -include_directories("${CMAKE_CURRENT_BINARY_DIR}") -include_directories("${CMAKE_CURRENT_SOURCE_DIR}") +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + include_directories(${EXPAT_INCLUDE_DIRS}) include_directories(${ICONV_INCLUDE_DIRS}) include_directories(${LIBUUID_INCLUDE_DIRS}) -- cgit v1.2.3 From 0ab40dc1ab4e689921da54080b135e1d22b1c586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 14 Mar 2017 21:45:23 +0100 Subject: Refactoring louloulibs and cmake Use OBJECT libraries Remove the louloulibs directory Write FOUND variables in the cache --- louloulibs/CMakeLists.txt | 129 ----- louloulibs/cmake/Modules/FindBOTAN.cmake | 44 -- louloulibs/cmake/Modules/FindGCRYPT.cmake | 41 -- louloulibs/cmake/Modules/FindICONV.cmake | 61 -- louloulibs/cmake/Modules/FindLIBIDN.cmake | 42 -- louloulibs/cmake/Modules/FindLIBUUID.cmake | 42 -- louloulibs/cmake/Modules/FindSYSTEMD.cmake | 40 -- louloulibs/cmake/Modules/FindUDNS.cmake | 38 -- louloulibs/config/config.cpp | 103 ---- louloulibs/config/config.hpp | 93 ---- louloulibs/logger/logger.cpp | 42 -- louloulibs/logger/logger.hpp | 128 ----- louloulibs/louloulibs.h.cmake | 11 - louloulibs/network/credentials_manager.cpp | 140 ----- louloulibs/network/credentials_manager.hpp | 55 -- louloulibs/network/dns_handler.cpp | 46 -- louloulibs/network/dns_handler.hpp | 37 -- louloulibs/network/dns_socket_handler.cpp | 43 -- louloulibs/network/dns_socket_handler.hpp | 33 -- louloulibs/network/poller.cpp | 234 -------- louloulibs/network/poller.hpp | 98 ---- louloulibs/network/resolver.cpp | 281 ---------- louloulibs/network/resolver.hpp | 122 ---- louloulibs/network/socket_handler.hpp | 42 -- louloulibs/network/tcp_client_socket_handler.cpp | 261 --------- louloulibs/network/tcp_client_socket_handler.hpp | 82 --- louloulibs/network/tcp_server_socket.hpp | 70 --- louloulibs/network/tcp_socket_handler.cpp | 358 ------------ louloulibs/network/tcp_socket_handler.hpp | 251 --------- louloulibs/utils/encoding.cpp | 254 --------- louloulibs/utils/encoding.hpp | 43 -- louloulibs/utils/get_first_non_empty.cpp | 11 - louloulibs/utils/get_first_non_empty.hpp | 20 - louloulibs/utils/revstr.cpp | 9 - louloulibs/utils/revstr.hpp | 11 - louloulibs/utils/scopeguard.hpp | 98 ---- louloulibs/utils/sha1.cpp | 32 -- louloulibs/utils/sha1.hpp | 5 - louloulibs/utils/split.cpp | 19 - louloulibs/utils/split.hpp | 12 - louloulibs/utils/string.cpp | 28 - louloulibs/utils/string.hpp | 10 - louloulibs/utils/system.cpp | 21 - louloulibs/utils/system.hpp | 8 - louloulibs/utils/time.cpp | 70 --- louloulibs/utils/time.hpp | 10 - louloulibs/utils/timed_events.cpp | 47 -- louloulibs/utils/timed_events.hpp | 132 ----- louloulibs/utils/timed_events_manager.cpp | 73 --- louloulibs/utils/tolower.cpp | 13 - louloulibs/utils/tolower.hpp | 11 - louloulibs/utils/xdg.cpp | 29 - louloulibs/utils/xdg.hpp | 14 - louloulibs/xmpp/adhoc_command.cpp | 80 --- louloulibs/xmpp/adhoc_command.hpp | 44 -- louloulibs/xmpp/adhoc_commands_handler.cpp | 111 ---- louloulibs/xmpp/adhoc_commands_handler.hpp | 71 --- louloulibs/xmpp/adhoc_session.cpp | 35 -- louloulibs/xmpp/adhoc_session.hpp | 88 --- louloulibs/xmpp/auth.cpp | 8 - louloulibs/xmpp/auth.hpp | 6 - louloulibs/xmpp/body.hpp | 12 - louloulibs/xmpp/jid.cpp | 153 ------ louloulibs/xmpp/jid.hpp | 49 -- louloulibs/xmpp/xmpp_component.cpp | 672 ----------------------- louloulibs/xmpp/xmpp_component.hpp | 245 --------- louloulibs/xmpp/xmpp_parser.cpp | 172 ------ louloulibs/xmpp/xmpp_parser.hpp | 133 ----- louloulibs/xmpp/xmpp_stanza.cpp | 229 -------- louloulibs/xmpp/xmpp_stanza.hpp | 160 ------ 70 files changed, 6215 deletions(-) delete mode 100644 louloulibs/CMakeLists.txt delete mode 100644 louloulibs/cmake/Modules/FindBOTAN.cmake delete mode 100644 louloulibs/cmake/Modules/FindGCRYPT.cmake delete mode 100644 louloulibs/cmake/Modules/FindICONV.cmake delete mode 100644 louloulibs/cmake/Modules/FindLIBIDN.cmake delete mode 100644 louloulibs/cmake/Modules/FindLIBUUID.cmake delete mode 100644 louloulibs/cmake/Modules/FindSYSTEMD.cmake delete mode 100644 louloulibs/cmake/Modules/FindUDNS.cmake delete mode 100644 louloulibs/config/config.cpp delete mode 100644 louloulibs/config/config.hpp delete mode 100644 louloulibs/logger/logger.cpp delete mode 100644 louloulibs/logger/logger.hpp delete mode 100644 louloulibs/louloulibs.h.cmake delete mode 100644 louloulibs/network/credentials_manager.cpp delete mode 100644 louloulibs/network/credentials_manager.hpp delete mode 100644 louloulibs/network/dns_handler.cpp delete mode 100644 louloulibs/network/dns_handler.hpp delete mode 100644 louloulibs/network/dns_socket_handler.cpp delete mode 100644 louloulibs/network/dns_socket_handler.hpp delete mode 100644 louloulibs/network/poller.cpp delete mode 100644 louloulibs/network/poller.hpp delete mode 100644 louloulibs/network/resolver.cpp delete mode 100644 louloulibs/network/resolver.hpp delete mode 100644 louloulibs/network/socket_handler.hpp delete mode 100644 louloulibs/network/tcp_client_socket_handler.cpp delete mode 100644 louloulibs/network/tcp_client_socket_handler.hpp delete mode 100644 louloulibs/network/tcp_server_socket.hpp delete mode 100644 louloulibs/network/tcp_socket_handler.cpp delete mode 100644 louloulibs/network/tcp_socket_handler.hpp delete mode 100644 louloulibs/utils/encoding.cpp delete mode 100644 louloulibs/utils/encoding.hpp delete mode 100644 louloulibs/utils/get_first_non_empty.cpp delete mode 100644 louloulibs/utils/get_first_non_empty.hpp delete mode 100644 louloulibs/utils/revstr.cpp delete mode 100644 louloulibs/utils/revstr.hpp delete mode 100644 louloulibs/utils/scopeguard.hpp delete mode 100644 louloulibs/utils/sha1.cpp delete mode 100644 louloulibs/utils/sha1.hpp delete mode 100644 louloulibs/utils/split.cpp delete mode 100644 louloulibs/utils/split.hpp delete mode 100644 louloulibs/utils/string.cpp delete mode 100644 louloulibs/utils/string.hpp delete mode 100644 louloulibs/utils/system.cpp delete mode 100644 louloulibs/utils/system.hpp delete mode 100644 louloulibs/utils/time.cpp delete mode 100644 louloulibs/utils/time.hpp delete mode 100644 louloulibs/utils/timed_events.cpp delete mode 100644 louloulibs/utils/timed_events.hpp delete mode 100644 louloulibs/utils/timed_events_manager.cpp delete mode 100644 louloulibs/utils/tolower.cpp delete mode 100644 louloulibs/utils/tolower.hpp delete mode 100644 louloulibs/utils/xdg.cpp delete mode 100644 louloulibs/utils/xdg.hpp delete mode 100644 louloulibs/xmpp/adhoc_command.cpp delete mode 100644 louloulibs/xmpp/adhoc_command.hpp delete mode 100644 louloulibs/xmpp/adhoc_commands_handler.cpp delete mode 100644 louloulibs/xmpp/adhoc_commands_handler.hpp delete mode 100644 louloulibs/xmpp/adhoc_session.cpp delete mode 100644 louloulibs/xmpp/adhoc_session.hpp delete mode 100644 louloulibs/xmpp/auth.cpp delete mode 100644 louloulibs/xmpp/auth.hpp delete mode 100644 louloulibs/xmpp/body.hpp delete mode 100644 louloulibs/xmpp/jid.cpp delete mode 100644 louloulibs/xmpp/jid.hpp delete mode 100644 louloulibs/xmpp/xmpp_component.cpp delete mode 100644 louloulibs/xmpp/xmpp_component.hpp delete mode 100644 louloulibs/xmpp/xmpp_parser.cpp delete mode 100644 louloulibs/xmpp/xmpp_parser.hpp delete mode 100644 louloulibs/xmpp/xmpp_stanza.cpp delete mode 100644 louloulibs/xmpp/xmpp_stanza.hpp (limited to 'louloulibs') diff --git a/louloulibs/CMakeLists.txt b/louloulibs/CMakeLists.txt deleted file mode 100644 index b3056f2..0000000 --- a/louloulibs/CMakeLists.txt +++ /dev/null @@ -1,129 +0,0 @@ -cmake_minimum_required(VERSION 3.0) - -set(${PROJECT_NAME}_VERSION_MAJOR 1) -set(${PROJECT_NAME}_VERSION_MINOR 0) -set(${PROJECT_NAME}_VERSION_SUFFIX "~dev") - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -pedantic -Wall -Wextra") - -# -## Look for external libraries -# -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/") -find_package(ICONV REQUIRED) -find_package(LIBUUID REQUIRED) -find_package(EXPAT REQUIRED) -set(EXPAT_FOUND ${EXPAT_FOUND} PARENT_SCOPE) - -if(WITH_LIBIDN) - find_package(LIBIDN REQUIRED) -elseif(NOT WITHOUT_LIBIDN) - find_package(LIBIDN) -endif() - -if(WITH_SYSTEMD) - find_package(SYSTEMD REQUIRED) -elseif(NOT WITHOUT_SYSTEMD) - find_package(SYSTEMD) -endif() - -if(WITH_BOTAN) - find_package(BOTAN REQUIRED) -elseif(NOT WITHOUT_BOTAN) - find_package(BOTAN) -endif() - -if(NOT BOTAN_FOUND) - find_package(GCRYPT REQUIRED) -endif() - -if(WITH_UDNS) - find_package(UDNS REQUIRED) -elseif(NOT WITHOUT_UDNS) - find_package(UDNS) -endif() - -# To be able to include the config.h file generated by cmake -include_directories(${CMAKE_CURRENT_BINARY_DIR}) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) - -include_directories(${EXPAT_INCLUDE_DIRS}) -include_directories(${ICONV_INCLUDE_DIRS}) -include_directories(${LIBUUID_INCLUDE_DIRS}) - -set(POLLER_DOCSTRING "Choose the poller between POLL and EPOLL (Linux-only)") -if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - set(POLLER "EPOLL" CACHE STRING ${POLLER_DOCSTRING}) -else() - set(POLLER "POLL" CACHE STRING ${POLLER_DOCSTRING}) -endif() -if((NOT ${POLLER} MATCHES "POLL") AND - (NOT ${POLLER} MATCHES "EPOLL")) - message(FATAL_ERROR "POLLER must be either POLL or EPOLL") -endif() - -# -## utils -# -file(GLOB source_utils - utils/*.[hc]pp) -set(source_utils ${source_utils} PARENT_SCOPE) - -# -## config -# -file(GLOB source_config - config/*.[hc]pp) -set(source_config ${source_config} PARENT_SCOPE) - -# -## logger -# -file(GLOB source_logger - logger/*.[hc]pp) -set(source_logger ${source_logger} PARENT_SCOPE) - -# -## network -# -file(GLOB source_network - network/*.[hc]pp) -set(source_network ${source_network} PARENT_SCOPE) - -# -## xmpplib -# -file(GLOB source_xmpplib - xmpp/*.[hc]pp) -set(source_xmpplib ${source_xmpplib} PARENT_SCOPE) - -# Define a __FILENAME__ macro with the relative path (from the base project directory) -# of each source file -file(GLOB_RECURSE source_all *.[hc]pp) -foreach(file ${source_all}) - file(RELATIVE_PATH shorter_file ${CMAKE_CURRENT_SOURCE_DIR} ${file}) - set_property(SOURCE ${file} APPEND PROPERTY COMPILE_DEFINITIONS __FILENAME__="${shorter_file}") -endforeach() - -# -## Check if we have std::get_time -# -include(CheckCXXSourceCompiles) - -check_cxx_source_compiles(" - #include - int main() - { std::get_time(nullptr, \"\"); }" - HAS_GET_TIME) - -mark_as_advanced(HAS_GET_TIME) - -check_cxx_source_compiles(" - #include - int main() - { std::put_time(nullptr, \"\"); }" - HAS_PUT_TIME) - -mark_as_advanced(HAS_PUT_TIME) - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/louloulibs.h.cmake ${CMAKE_BINARY_DIR}/src/louloulibs.h) diff --git a/louloulibs/cmake/Modules/FindBOTAN.cmake b/louloulibs/cmake/Modules/FindBOTAN.cmake deleted file mode 100644 index 27f82a7..0000000 --- a/louloulibs/cmake/Modules/FindBOTAN.cmake +++ /dev/null @@ -1,44 +0,0 @@ -# - Find botan -# Find the botan cryptographic library -# -# This module defines the following variables: -# BOTAN_FOUND - True if library and include directory are found -# If set to TRUE, the following are also defined: -# BOTAN_INCLUDE_DIRS - The directory where to find the header file -# BOTAN_LIBRARIES - Where to find the library file -# -# For conveniance, these variables are also set. They have the same values -# than the variables above. The user can thus choose his/her prefered way -# to write them. -# BOTAN_LIBRARY -# BOTAN_INCLUDE_DIR -# -# This file is in the public domain - -include(FindPkgConfig) -pkg_check_modules(BOTAN botan-2) -if(NOT BOTAN_FOUND) - pkg_check_modules(BOTAN botan-1.11) -endif() - -if(NOT BOTAN_FOUND) - find_path(BOTAN_INCLUDE_DIRS NAMES botan/botan.h - PATH_SUFFIXES botan-2 botan-1.11 - DOC "The botan include directory") - - find_library(BOTAN_LIBRARIES NAMES botan botan-2 botan-1.11 - DOC "The botan library") - - # Use some standard module to handle the QUIETLY and REQUIRED arguments, and - # set BOTAN_FOUND to TRUE if these two variables are set. - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(BOTAN REQUIRED_VARS BOTAN_LIBRARIES BOTAN_INCLUDE_DIRS) - - if(BOTAN_FOUND) - set(BOTAN_LIBRARY ${BOTAN_LIBRARIES} PARENT_SCOPE) - set(BOTAN_INCLUDE_DIR ${BOTAN_INCLUDE_DIRS} PARENT_SCOPE) - set(BOTAN_FOUND ${BOTAN_FOUND} PARENT_SCOPE) - endif() -endif() - -mark_as_advanced(BOTAN_INCLUDE_DIRS BOTAN_LIBRARIES) diff --git a/louloulibs/cmake/Modules/FindGCRYPT.cmake b/louloulibs/cmake/Modules/FindGCRYPT.cmake deleted file mode 100644 index 62f5c7a..0000000 --- a/louloulibs/cmake/Modules/FindGCRYPT.cmake +++ /dev/null @@ -1,41 +0,0 @@ -# - Find gcrypt -# Find the gcrypt cryptographic library -# -# This module defines the following variables: -# GCRYPT_FOUND - True if library and include directory are found -# If set to TRUE, the following are also defined: -# GCRYPT_INCLUDE_DIRS - The directory where to find the header file -# GCRYPT_LIBRARIES - Where to find the library file -# -# For conveniance, these variables are also set. They have the same values -# than the variables above. The user can thus choose his/her prefered way -# to write them. -# GCRYPT_LIBRARY -# GCRYPT_INCLUDE_DIR -# -# This file is in the public domain - -include(FindPkgConfig) -pkg_check_modules(GCRYPT gcrypt) - -if(NOT GCRYPT_FOUND) - find_path(GCRYPT_INCLUDE_DIRS NAMES gcrypt.h - PATH_SUFFIXES gcrypt - DOC "The gcrypt include directory") - - find_library(GCRYPT_LIBRARIES NAMES gcrypt - DOC "The gcrypt library") - - # Use some standard module to handle the QUIETLY and REQUIRED arguments, and - # set GCRYPT_FOUND to TRUE if these two variables are set. - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(GCRYPT REQUIRED_VARS GCRYPT_LIBRARIES GCRYPT_INCLUDE_DIRS) - - if(GCRYPT_FOUND) - set(GCRYPT_LIBRARY ${GCRYPT_LIBRARIES} PARENT_SCOPE) - set(GCRYPT_INCLUDE_DIR ${GCRYPT_INCLUDE_DIRS} PARENT_SCOPE) - set(GCRYPT_FOUND ${GCRYPT_FOUND} PARENT_SCOPE) - endif() -endif() - -mark_as_advanced(GCRYPT_INCLUDE_DIRS GCRYPT_LIBRARIES) diff --git a/louloulibs/cmake/Modules/FindICONV.cmake b/louloulibs/cmake/Modules/FindICONV.cmake deleted file mode 100644 index 9e5bde6..0000000 --- a/louloulibs/cmake/Modules/FindICONV.cmake +++ /dev/null @@ -1,61 +0,0 @@ -# - Find iconv -# Find the iconv (character set conversion) library -# -# This module defines the following variables: -# ICONV_FOUND - True if library and include directory are found -# If set to TRUE, the following are also defined: -# ICONV_INCLUDE_DIRS - The directory where to find the header file -# ICONV_LIBRARIES - Where to find the library file -# ICONV_SECOND_ARGUMENT_IS_CONST - The second argument for iconv() is const -# -# For conveniance, these variables are also set. They have the same values -# than the variables above. The user can thus choose his/her prefered way -# to write them. -# ICONV_LIBRARY -# ICONV_INCLUDE_DIR -# -# This file is in the public domain - -find_path(ICONV_INCLUDE_DIRS NAMES iconv.h - DOC "The iconv include directory") - -find_library(ICONV_LIBRARIES NAMES iconv libiconv libiconv-2 c - DOC "The iconv library") - -# Use some standard module to handle the QUIETLY and REQUIRED arguments, and -# set ICONV_FOUND to TRUE if these two variables are set. -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Iconv REQUIRED_VARS ICONV_LIBRARIES ICONV_INCLUDE_DIRS) - -# Check if the prototype is -# size_t iconv(iconv_t cd, char** inbuf, size_t* inbytesleft, -# char** outbuf, size_t* outbytesleft); -# or -# size_t iconv (iconv_t cd, const char** inbuf, size_t* inbytesleft, -# char** outbuf, size_t* outbytesleft); -if(ICONV_FOUND) - include(CheckCXXSourceCompiles) - - # Set the parameters needed to compile the following code. - set(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIRS}) - set(CMAKE_REQUIRED_LIBRARIES ${ICONV_LIBRARIES}) - - check_cxx_source_compiles(" - #include - int main(){ - iconv_t conv = 0; - const char* in = 0; - size_t ilen = 0; - char* out = 0; - size_t olen = 0; - iconv(conv, &in, &ilen, &out, &olen); - return 0;}" - ICONV_SECOND_ARGUMENT_IS_CONST) - - # Compatibility for all the ways of writing these variables - set(ICONV_LIBRARY ${ICONV_LIBRARIES} PARENT_SCOPE) - set(ICONV_INCLUDE_DIR ${ICONV_INCLUDE_DIRS} PARENT_SCOPE) - set(ICONV_FOUND ${ICONV_FOUND} PARENT_SCOPE) -endif() - -mark_as_advanced(ICONV_INCLUDE_DIRS ICONV_LIBRARIES ICONV_SECOND_ARGUMENT_IS_CONST) diff --git a/louloulibs/cmake/Modules/FindLIBIDN.cmake b/louloulibs/cmake/Modules/FindLIBIDN.cmake deleted file mode 100644 index 716714f..0000000 --- a/louloulibs/cmake/Modules/FindLIBIDN.cmake +++ /dev/null @@ -1,42 +0,0 @@ -# - Find libidn -# Find the libidn library, and more particularly the stringprep header. -# -# This module defines the following variables: -# LIBIDN_FOUND - True if library and include directory are found -# If set to TRUE, the following are also defined: -# LIBIDN_INCLUDE_DIRS - The directory where to find the header file -# LIBIDN_LIBRARIES - Where to find the library file -# -# For conveniance, these variables are also set. They have the same values -# than the variables above. The user can thus choose his/her prefered way -# to write them. -# LIBIDN_INCLUDE_DIR -# LIBIDN_LIBRARY -# -# This file is in the public domain - -include(FindPkgConfig) -pkg_check_modules(LIBIDN libidn) - -if(NOT LIBIDN_FOUND) - find_path(LIBIDN_INCLUDE_DIRS NAMES stringprep.h - DOC "The libidn include directory") - - # The library containing the stringprep module is libidn - find_library(LIBIDN_LIBRARIES NAMES idn - DOC "The libidn library") - - # Use some standard module to handle the QUIETLY and REQUIRED arguments, and - # set LIBIDN_FOUND to TRUE if these two variables are set. - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(LIBIDN REQUIRED_VARS LIBIDN_LIBRARIES LIBIDN_INCLUDE_DIRS) - - # Compatibility for all the ways of writing these variables - if(LIBIDN_FOUND) - set(LIBIDN_INCLUDE_DIR ${LIBIDN_INCLUDE_DIRS} PARENT_SCOPE) - set(LIBIDN_LIBRARY ${LIBIDN_LIBRARIES} PARENT_SCOPE) - set(LIBIDN_FOUND ${LIBIDN_FOUND} PARENT_SCOPE) - endif() -endif() - -mark_as_advanced(LIBIDN_INCLUDE_DIRS LIBIDN_LIBRARIES) diff --git a/louloulibs/cmake/Modules/FindLIBUUID.cmake b/louloulibs/cmake/Modules/FindLIBUUID.cmake deleted file mode 100644 index 9269978..0000000 --- a/louloulibs/cmake/Modules/FindLIBUUID.cmake +++ /dev/null @@ -1,42 +0,0 @@ -# - Find libuuid -# Find the libuuid library -# -# This module defines the following variables: -# LIBUUID_FOUND - True if library and include directory are found -# If set to TRUE, the following are also defined: -# LIBUUID_INCLUDE_DIRS - The directory where to find the header file -# LIBUUID_LIBRARIES - Where to find the library file -# -# For conveniance, these variables are also set. They have the same values -# than the variables above. The user can thus choose his/her prefered way -# to write them. -# LIBUUID_INCLUDE_DIR -# LIBUUID_LIBRARY -# -# This file is in the public domain - -include(FindPkgConfig) -pkg_check_modules(LIBUUID uuid) - -if(NOT LIBUUID_FOUND) - find_path(LIBUUID_INCLUDE_DIRS NAMES uuid/uuid.h - PATH_SUFFIXES uuid - DOC "The libuuid include directory") - - find_library(LIBUUID_LIBRARIES NAMES uuid - DOC "The libuuid library") - - # Use some standard module to handle the QUIETLY and REQUIRED arguments, and - # set LIBUUID_FOUND to TRUE if these two variables are set. - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(LIBUUID REQUIRED_VARS LIBUUID_LIBRARIES LIBUUID_INCLUDE_DIRS) - - # Compatibility for all the ways of writing these variables - if(LIBUUID_FOUND) - set(LIBUUID_INCLUDE_DIR ${LIBUUID_INCLUDE_DIRS} PARENT_SCOPE) - set(LIBUUID_LIBRARY ${LIBUUID_LIBRARIES} PARENT_SCOPE) - set(LIBUUID_FOUND ${LIBUUID_FOUND} PARENT_SCOPE) - endif() -endif() - -mark_as_advanced(LIBUUID_INCLUDE_DIRS LIBUUID_LIBRARIES) diff --git a/louloulibs/cmake/Modules/FindSYSTEMD.cmake b/louloulibs/cmake/Modules/FindSYSTEMD.cmake deleted file mode 100644 index 43db6c4..0000000 --- a/louloulibs/cmake/Modules/FindSYSTEMD.cmake +++ /dev/null @@ -1,40 +0,0 @@ -# - Find SystemdDaemon -# Find the systemd daemon library -# -# This module defines the following variables: -# SYSTEMD_FOUND - True if library and include directory are found -# If set to TRUE, the following are also defined: -# SYSTEMD_INCLUDE_DIRS - The directory where to find the header file -# SYSTEMD_LIBRARIES - Where to find the library file -# -# For conveniance, these variables are also set. They have the same values -# than the variables above. The user can thus choose his/her prefered way -# to write them. -# SYSTEMD_LIBRARY -# SYSTEMD_INCLUDE_DIR -# -# This file is in the public domain - -include(FindPkgConfig) -pkg_check_modules(SYSTEMD libsystemd) - -if(NOT SYSTEMD_FOUND) - find_path(SYSTEMD_INCLUDE_DIRS NAMES systemd/sd-daemon.h - DOC "The Systemd include directory") - - find_library(SYSTEMD_LIBRARIES NAMES systemd - DOC "The Systemd library") - - # Use some standard module to handle the QUIETLY and REQUIRED arguments, and - # set SYSTEMD_FOUND to TRUE if these two variables are set. - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(SYSTEMD REQUIRED_VARS SYSTEMD_LIBRARIES SYSTEMD_INCLUDE_DIRS) - - if(SYSTEMD_FOUND) - set(SYSTEMD_LIBRARY ${SYSTEMD_LIBRARIES} PARENT_SCOPE) - set(SYSTEMD_INCLUDE_DIR ${SYSTEMD_INCLUDE_DIRS} PARENT_SCOPE) - set(SYSTEMD_FOUND ${SYSTEMD_FOUND} PARENT_SCOPE) - endif() -endif() - -mark_as_advanced(SYSTEMD_INCLUDE_DIRS SYSTEMD_LIBRARIES) diff --git a/louloulibs/cmake/Modules/FindUDNS.cmake b/louloulibs/cmake/Modules/FindUDNS.cmake deleted file mode 100644 index 33fbc4c..0000000 --- a/louloulibs/cmake/Modules/FindUDNS.cmake +++ /dev/null @@ -1,38 +0,0 @@ -# - Find udns -# Find the udns library -# -# This module defines the following variables: -# UDNS_FOUND - True if library and include directory are found -# If set to TRUE, the following are also defined: -# UDNS_INCLUDE_DIRS - The directory where to find the header file -# UDNS_LIBRARIES - Where to find the library file -# -# For conveniance, these variables are also set. They have the same values -# as the variables above. The user can thus choose his/her prefered way -# to write them. -# UDNS_INCLUDE_DIR -# UDNS_LIBRARY -# -# This file is in the public domain - -if(NOT UDNS_FOUND) - find_path(UDNS_INCLUDE_DIRS NAMES udns.h - DOC "The udns include directory") - - find_library(UDNS_LIBRARIES NAMES udns - DOC "The udns library") - - # Use some standard module to handle the QUIETLY and REQUIRED arguments, and - # set UDNS_FOUND to TRUE if these two variables are set. - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(UDNS REQUIRED_VARS UDNS_LIBRARIES UDNS_INCLUDE_DIRS) - - # Compatibility for all the ways of writing these variables - if(UDNS_FOUND) - set(UDNS_INCLUDE_DIR ${UDNS_INCLUDE_DIRS} PARENT_SCOPE) - set(UDNS_LIBRARY ${UDNS_LIBRARIES} PARENT_SCOPE) - set(UDNS_FOUND ${UDNS_FOUND} PARENT_SCOPE) - endif() -endif() - -mark_as_advanced(UDNS_INCLUDE_DIRS UDNS_LIBRARIES) diff --git a/louloulibs/config/config.cpp b/louloulibs/config/config.cpp deleted file mode 100644 index 24a1c87..0000000 --- a/louloulibs/config/config.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include - -#include -#include - -#include - -std::string Config::filename{}; -std::map Config::values{}; -std::vector Config::callbacks{}; - -std::string Config::get(const std::string& option, const std::string& def) -{ - auto it = Config::values.find(option); - - if (it == Config::values.end()) - return def; - return it->second; -} - -int Config::get_int(const std::string& option, const int& def) -{ - std::string res = Config::get(option, ""); - if (!res.empty()) - return std::atoi(res.c_str()); - else - return def; -} - -void Config::set(const std::string& option, const std::string& value, bool save) -{ - Config::values[option] = value; - if (save) - { - Config::save_to_file(); - Config::trigger_configuration_change(); - } -} - -void Config::connect(t_config_changed_callback callback) -{ - Config::callbacks.push_back(callback); -} - -void Config::clear() -{ - Config::values.clear(); -} - -/** - * Private methods - */ -void Config::trigger_configuration_change() -{ - std::vector::iterator it; - for (it = Config::callbacks.begin(); it < Config::callbacks.end(); ++it) - (*it)(); -} - -bool Config::read_conf(const std::string& name) -{ - if (!name.empty()) - Config::filename = name; - - std::ifstream file(Config::filename.data()); - if (!file.is_open()) - { - std::cerr << "Error while opening file " << filename << " for reading: " << strerror(errno) << std::endl; - return false; - } - - Config::clear(); - - std::string line; - size_t pos; - std::string option; - std::string value; - while (file.good()) - { - std::getline(file, line); - if (line == "" || line[0] == '#') - continue ; - pos = line.find('='); - if (pos == std::string::npos) - continue ; - option = line.substr(0, pos); - value = line.substr(pos+1); - Config::values[option] = value; - } - return true; -} - -void Config::save_to_file() -{ - std::ofstream file(Config::filename.data()); - if (file.fail()) - { - std::cerr << "Could not save config file." << std::endl; - return ; - } - for (const auto& it: Config::values) - file << it.first << "=" << it.second << '\n'; -} diff --git a/louloulibs/config/config.hpp b/louloulibs/config/config.hpp deleted file mode 100644 index 4e01281..0000000 --- a/louloulibs/config/config.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Read the config file and save all the values in a map. - * Also, a singleton. - * - * Use Config::filename = "bla" to set the filename you want to use. - * - * If you want to exit if the file does not exist when it is open for - * reading, set Config::file_must_exist = true. - * - * Config::get() can then be used to access the values in the conf. - * - * Use Config::close() when you're done getting/setting value. This will - * save the config into the file. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -typedef std::function t_config_changed_callback; - -class Config -{ -public: - Config() = default; - ~Config() = default; - Config(const Config&) = delete; - Config& operator=(const Config&) = delete; - Config(Config&&) = delete; - Config& operator=(Config&&) = delete; - - /** - * returns a value from the config. If it doesn’t exist, use - * the second argument as the default. - */ - static std::string get(const std::string&, const std::string&); - /** - * returns a value from the config. If it doesn’t exist, use - * the second argument as the default. - */ - static int get_int(const std::string&, const int&); - /** - * Set a value for the given option. And write all the config - * in the file from which it was read if save is true. - */ - static void set(const std::string&, const std::string&, bool save = false); - /** - * Adds a function to a list. This function will be called whenever a - * configuration change occurs (when set() is called, or when the initial - * conf is read) - */ - static void connect(t_config_changed_callback); - /** - * Destroy the instance, forcing it to be recreated (with potentially - * different parameters) the next time it’s needed. - */ - static void clear(); - /** - * Read the configuration file at the given path. - */ - static bool read_conf(const std::string& name=""); - /** - * Get the filename - */ - static const std::string& get_filename() - { return Config::filename; } - -private: - /** - * Set the value of the filename to use, before calling any method. - */ - static std::string filename; - /** - * Write all the config values into the configuration file - */ - static void save_to_file(); - /** - * Call all the callbacks previously registered using connect(). - * This is used to notify any class that a configuration change occured. - */ - static void trigger_configuration_change(); - - static std::map values; - static std::vector callbacks; - -}; - - diff --git a/louloulibs/logger/logger.cpp b/louloulibs/logger/logger.cpp deleted file mode 100644 index 92a3d9b..0000000 --- a/louloulibs/logger/logger.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include - -Logger::Logger(const int log_level): - log_level(log_level), - stream(std::cout.rdbuf()), - null_buffer{}, - null_stream{&null_buffer} -{ -} - -Logger::Logger(const int log_level, const std::string& log_file): - log_level(log_level), - ofstream(log_file.data(), std::ios_base::app), - stream(ofstream.rdbuf()), - null_buffer{}, - null_stream{&null_buffer} -{ -} - -std::unique_ptr& Logger::instance() -{ - static std::unique_ptr instance; - - if (!instance) - { - const std::string log_file = Config::get("log_file", ""); - const int log_level = Config::get_int("log_level", 0); - if (log_file.empty()) - instance = std::make_unique(log_level); - else - instance = std::make_unique(log_level, log_file); - } - return instance; -} - -std::ostream& Logger::get_stream(const int lvl) -{ - if (lvl >= this->log_level) - return this->stream; - return this->null_stream; -} diff --git a/louloulibs/logger/logger.hpp b/louloulibs/logger/logger.hpp deleted file mode 100644 index b3284a6..0000000 --- a/louloulibs/logger/logger.hpp +++ /dev/null @@ -1,128 +0,0 @@ -#pragma once - - -/** - * Singleton used in logger macros to write into files or stdout, with - * various levels of severity. - * Only the macros should be used. - * @class Logger - */ - -#include -#include -#include - -#define debug_lvl 0 -#define info_lvl 1 -#define warning_lvl 2 -#define error_lvl 3 - -#include "louloulibs.h" -#ifdef SYSTEMD_FOUND -# include -#else -# define SD_DEBUG "[DEBUG]: " -# define SD_INFO "[INFO]: " -# define SD_WARNING "[WARNING]: " -# define SD_ERR "[ERROR]: " -#endif - -// Macro defined to get the filename instead of the full path. But if it is -// not properly defined by the build system, we fallback to __FILE__ -#ifndef __FILENAME__ -# define __FILENAME__ __FILE__ -#endif - - -/** - * A buffer, used to construct an ostream that does nothing - * when we output data in it - */ -class NullBuffer: public std::streambuf -{ - public: - int overflow(int c) { return c; } -}; - -class Logger -{ -public: - static std::unique_ptr& instance(); - std::ostream& get_stream(const int); - Logger(const int log_level, const std::string& log_file); - Logger(const int log_level); - - Logger(const Logger&) = delete; - Logger& operator=(const Logger&) = delete; - Logger(Logger&&) = delete; - Logger& operator=(Logger&&) = delete; - -private: - const int log_level; - std::ofstream ofstream{}; - std::ostream stream; - - NullBuffer null_buffer; - std::ostream null_stream; -}; - -#define WHERE __FILENAME__, ":", __LINE__, ":\t" - -namespace logging_details -{ - template - void log(std::ostream& os, const T& arg) - { - os << arg << std::endl; - } - - template - void log(std::ostream& os, const T& first, U&&... rest) - { - os << first; - log(os, std::forward(rest)...); - } - - template - void log_debug(U&&... args) - { - auto& os = Logger::instance()->get_stream(debug_lvl); - os << SD_DEBUG; - log(os, std::forward(args)...); - } - - template - void log_info(U&&... args) - { - auto& os = Logger::instance()->get_stream(info_lvl); - os << SD_INFO; - log(os, std::forward(args)...); - } - - template - void log_warning(U&&... args) - { - auto& os = Logger::instance()->get_stream(warning_lvl); - os << SD_WARNING; - log(os, std::forward(args)...); - } - - template - void log_error(U&&... args) - { - auto& os = Logger::instance()->get_stream(error_lvl); - os << SD_ERR; - log(os, std::forward(args)...); - } -} - -#define log_info(...) logging_details::log_info(WHERE, __VA_ARGS__) - -#define log_warning(...) logging_details::log_warning(WHERE, __VA_ARGS__) - -#define log_error(...) logging_details::log_error(WHERE, __VA_ARGS__) - -#define log_debug(...) logging_details::log_debug(WHERE, __VA_ARGS__) - - - diff --git a/louloulibs/louloulibs.h.cmake b/louloulibs/louloulibs.h.cmake deleted file mode 100644 index 5777d92..0000000 --- a/louloulibs/louloulibs.h.cmake +++ /dev/null @@ -1,11 +0,0 @@ -#cmakedefine ICONV_SECOND_ARGUMENT_IS_CONST -#cmakedefine LIBIDN_FOUND -#cmakedefine SYSTEMD_FOUND -#cmakedefine POLLER ${POLLER} -#cmakedefine BOTAN_FOUND -#cmakedefine GCRYPT_FOUND -#cmakedefine UDNS_FOUND -#cmakedefine SOFTWARE_VERSION "${SOFTWARE_VERSION}" -#cmakedefine PROJECT_NAME "${PROJECT_NAME}" -#cmakedefine HAS_GET_TIME -#cmakedefine HAS_PUT_TIME diff --git a/louloulibs/network/credentials_manager.cpp b/louloulibs/network/credentials_manager.cpp deleted file mode 100644 index 289307b..0000000 --- a/louloulibs/network/credentials_manager.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include "louloulibs.h" - -#ifdef BOTAN_FOUND -#include -#include -#include -#include -#include - -#ifdef USE_DATABASE -# include -#endif - -/** - * TODO find a standard way to find that out. - */ -static const std::vector default_cert_files = { - "/etc/ssl/certs/ca-bundle.crt", - "/etc/pki/tls/certs/ca-bundle.crt", - "/etc/ssl/certs/ca-certificates.crt", - "/etc/ca-certificates/extracted/tls-ca-bundle.pem" -}; - -Botan::Certificate_Store_In_Memory BasicCredentialsManager::certificate_store; -bool BasicCredentialsManager::certs_loaded = false; - -BasicCredentialsManager::BasicCredentialsManager(const TCPSocketHandler* const socket_handler): - Botan::Credentials_Manager(), - socket_handler(socket_handler), - trusted_fingerprint{} -{ - BasicCredentialsManager::load_certs(); -} - -void BasicCredentialsManager::set_trusted_fingerprint(const std::string& fingerprint) -{ - this->trusted_fingerprint = fingerprint; -} - -const std::string& BasicCredentialsManager::get_trusted_fingerprint() const -{ - return this->trusted_fingerprint; -} - -void check_tls_certificate(const std::vector& certs, - const std::string& hostname, const std::string& trusted_fingerprint, - std::exception_ptr exc) -{ - - if (!trusted_fingerprint.empty() && !certs.empty() && - trusted_fingerprint == certs[0].fingerprint() && - certs[0].matches_dns_name(hostname)) - // We trust the certificate, based on the trusted fingerprint and - // the fact that the hostname matches - return; - - if (exc) - std::rethrow_exception(exc); -} - -#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,34) -void BasicCredentialsManager::verify_certificate_chain(const std::string& type, - const std::string& purported_hostname, - const std::vector& certs) -{ - log_debug("Checking remote certificate (", type, ") for hostname ", purported_hostname); - try - { - Botan::Credentials_Manager::verify_certificate_chain(type, purported_hostname, certs); - log_debug("Certificate is valid"); - } - catch (const std::exception& tls_exception) - { - log_warning("TLS certificate check failed: ", tls_exception.what()); - std::exception_ptr exception_ptr{}; - if (this->socket_handler->abort_on_invalid_cert()) - exception_ptr = std::current_exception(); - - check_tls_certificate(certs, purported_hostname, this->trusted_fingerprint, exception_ptr); - } -} -#endif - -bool BasicCredentialsManager::try_to_open_one_ca_bundle(const std::vector& paths) -{ - for (const auto& path: paths) - { - try - { - Botan::DataSource_Stream bundle(path); - log_debug("Using ca bundle: ", path); - while (!bundle.end_of_data() && bundle.check_available(27)) - { - // TODO: remove this work-around for Botan 1.11.29 - // https://github.com/randombit/botan/issues/438#issuecomment-192866796 - // Note that every certificate that fails to be transcoded into latin-1 - // will be ignored. As a result, some TLS connection may be refused - // because the certificate is signed by an issuer that was ignored. - try { - Botan::X509_Certificate cert(bundle); - BasicCredentialsManager::certificate_store.add_certificate(std::move(cert)); - } catch (const Botan::Decoding_Error& error) { - continue; - } - } - // Only use the first file that can successfully be read. - return true; - } - catch (const Botan::Stream_IO_Error& e) - { - log_debug(e.what()); - } - } - return false; -} - -void BasicCredentialsManager::load_certs() -{ - // Only load the certificates the first time - if (BasicCredentialsManager::certs_loaded) - return; - const std::string conf_path = Config::get("ca_file", ""); - std::vector paths; - if (conf_path.empty()) - paths = default_cert_files; - else - paths.push_back(conf_path); - - if (BasicCredentialsManager::try_to_open_one_ca_bundle(paths)) - BasicCredentialsManager::certs_loaded = true; - else - log_warning("The CA could not be loaded, TLS negociation will probably fail."); -} - -std::vector BasicCredentialsManager::trusted_certificate_authorities(const std::string&, const std::string&) -{ - return {&this->certificate_store}; -} - -#endif diff --git a/louloulibs/network/credentials_manager.hpp b/louloulibs/network/credentials_manager.hpp deleted file mode 100644 index 29ee024..0000000 --- a/louloulibs/network/credentials_manager.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include "louloulibs.h" - -#ifdef BOTAN_FOUND - -#include -#include - -class TCPSocketHandler; - -/** - * If the given cert isn’t valid, based on the given hostname - * and fingerprint, then throws the exception if it’s non-empty. - * - * Must be called after the standard (from Botan) way of - * checking the certificate, if we want to also accept certificates based - * on a trusted fingerprint. - */ -void check_tls_certificate(const std::vector& certs, - const std::string& hostname, const std::string& trusted_fingerprint, - std::exception_ptr exc); - -class BasicCredentialsManager: public Botan::Credentials_Manager -{ -public: - BasicCredentialsManager(const TCPSocketHandler* const socket_handler); - - BasicCredentialsManager(BasicCredentialsManager&&) = delete; - BasicCredentialsManager(const BasicCredentialsManager&) = delete; - BasicCredentialsManager& operator=(const BasicCredentialsManager&) = delete; - BasicCredentialsManager& operator=(BasicCredentialsManager&&) = delete; - -#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,34) - void verify_certificate_chain(const std::string& type, - const std::string& purported_hostname, - const std::vector&) override final; -#endif - std::vector trusted_certificate_authorities(const std::string& type, - const std::string& context) override final; - void set_trusted_fingerprint(const std::string& fingerprint); - const std::string& get_trusted_fingerprint() const; - -private: - const TCPSocketHandler* const socket_handler; - - static bool try_to_open_one_ca_bundle(const std::vector& paths); - static void load_certs(); - static Botan::Certificate_Store_In_Memory certificate_store; - static bool certs_loaded; - std::string trusted_fingerprint; -}; - -#endif //BOTAN_FOUND - diff --git a/louloulibs/network/dns_handler.cpp b/louloulibs/network/dns_handler.cpp deleted file mode 100644 index 641c087..0000000 --- a/louloulibs/network/dns_handler.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -#ifdef UDNS_FOUND - -#include -#include -#include - -#include - -#include -#include -#include - -class Resolver; - -using namespace std::string_literals; - -std::unique_ptr DNSHandler::socket_handler{}; - -DNSHandler::DNSHandler(std::shared_ptr& poller) -{ - dns_init(nullptr, 0); - const auto socket = dns_open(nullptr); - if (socket == -1) - throw std::runtime_error("Failed to initialize udns socket: "s + strerror(errno)); - - DNSHandler::socket_handler = std::make_unique(poller, socket); -} - -void DNSHandler::destroy() -{ - DNSHandler::socket_handler.reset(nullptr); - dns_close(nullptr); -} - -void DNSHandler::watch() -{ - DNSHandler::socket_handler->watch(); -} - -void DNSHandler::unwatch() -{ - DNSHandler::socket_handler->unwatch(); -} - -#endif /* UDNS_FOUND */ diff --git a/louloulibs/network/dns_handler.hpp b/louloulibs/network/dns_handler.hpp deleted file mode 100644 index 416f85f..0000000 --- a/louloulibs/network/dns_handler.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#ifdef UDNS_FOUND - -class Poller; - -#include - -#include -#include -#include - -class DNSHandler -{ -public: - explicit DNSHandler(std::shared_ptr& poller); - ~DNSHandler() = default; - - DNSHandler(const DNSHandler&) = delete; - DNSHandler(DNSHandler&&) = delete; - DNSHandler& operator=(const DNSHandler&) = delete; - DNSHandler& operator=(DNSHandler&&) = delete; - - void destroy(); - - static void watch(); - static void unwatch(); - -private: - /** - * Manager for the socket returned by udns, that we need to watch with the poller - */ - static std::unique_ptr socket_handler; -}; - -#endif /* UDNS_FOUND */ diff --git a/louloulibs/network/dns_socket_handler.cpp b/louloulibs/network/dns_socket_handler.cpp deleted file mode 100644 index 84e5625..0000000 --- a/louloulibs/network/dns_socket_handler.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#ifdef UDNS_FOUND - -#include -#include -#include - -#include - -DNSSocketHandler::DNSSocketHandler(std::shared_ptr& poller, - const socket_t socket): - SocketHandler(poller, socket) -{ - poller->add_socket_handler(this); -} - -DNSSocketHandler::~DNSSocketHandler() -{ - this->unwatch(); -} - -void DNSSocketHandler::on_recv() -{ - dns_ioevent(nullptr, 0); -} - -bool DNSSocketHandler::is_connected() const -{ - return true; -} - -void DNSSocketHandler::unwatch() -{ - if (this->poller->is_managing_socket(this->socket)) - this->poller->remove_socket_handler(this->socket); -} - -void DNSSocketHandler::watch() -{ - this->poller->add_socket_handler(this); -} - -#endif /* UDNS_FOUND */ diff --git a/louloulibs/network/dns_socket_handler.hpp b/louloulibs/network/dns_socket_handler.hpp deleted file mode 100644 index fc5f41f..0000000 --- a/louloulibs/network/dns_socket_handler.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include -#ifdef UDNS_FOUND - -#include - -/** - * Manage the UDP socket provided by udns, we do not create, open or close the - * socket ourself: this is done by udns. We only watch it for readability - */ -class DNSSocketHandler: public SocketHandler -{ -public: - explicit DNSSocketHandler(std::shared_ptr& poller, const socket_t socket); - ~DNSSocketHandler(); - DNSSocketHandler(const DNSSocketHandler&) = delete; - DNSSocketHandler(DNSSocketHandler&&) = delete; - DNSSocketHandler& operator=(const DNSSocketHandler&) = delete; - DNSSocketHandler& operator=(DNSSocketHandler&&) = delete; - - void on_recv() override final; - - /** - * Always true, see the comment for connect() - */ - bool is_connected() const override final; - - void watch(); - void unwatch(); -}; - -#endif // UDNS_FOUND diff --git a/louloulibs/network/poller.cpp b/louloulibs/network/poller.cpp deleted file mode 100644 index 9f5bcfb..0000000 --- a/louloulibs/network/poller.cpp +++ /dev/null @@ -1,234 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -Poller::Poller() -{ -#if POLLER == POLL - this->nfds = 0; -#elif POLLER == EPOLL - this->epfd = ::epoll_create1(0); - if (this->epfd == -1) - { - log_error("epoll failed: ", strerror(errno)); - throw std::runtime_error("Could not create epoll instance"); - } -#endif -} - -Poller::~Poller() -{ -#if POLLER == EPOLL - if (this->epfd > 0) - ::close(this->epfd); -#endif -} - -void Poller::add_socket_handler(SocketHandler* socket_handler) -{ - // Don't do anything if the socket is already managed - const auto it = this->socket_handlers.find(socket_handler->get_socket()); - if (it != this->socket_handlers.end()) - return ; - - this->socket_handlers.emplace(socket_handler->get_socket(), socket_handler); - - // We always watch all sockets for receive events -#if POLLER == POLL - this->fds[this->nfds].fd = socket_handler->get_socket(); - this->fds[this->nfds].events = POLLIN; - this->nfds++; -#endif -#if POLLER == EPOLL - struct epoll_event event = {EPOLLIN, {socket_handler}}; - const int res = ::epoll_ctl(this->epfd, EPOLL_CTL_ADD, socket_handler->get_socket(), &event); - if (res == -1) - { - log_error("epoll_ctl failed: ", strerror(errno)); - throw std::runtime_error("Could not add socket to epoll"); - } -#endif -} - -void Poller::remove_socket_handler(const socket_t socket) -{ - const auto it = this->socket_handlers.find(socket); - if (it == this->socket_handlers.end()) - throw std::runtime_error("Trying to remove a SocketHandler that is not managed"); - this->socket_handlers.erase(it); - -#if POLLER == POLL - for (size_t i = 0; i < this->nfds; i++) - { - if (this->fds[i].fd == socket) - { - // Move all subsequent pollfd by one on the left, erasing the - // value of the one we remove - for (size_t j = i; j < this->nfds - 1; ++j) - { - this->fds[j].fd = this->fds[j+1].fd; - this->fds[j].events= this->fds[j+1].events; - } - this->nfds--; - } - } -#elif POLLER == EPOLL - const int res = ::epoll_ctl(this->epfd, EPOLL_CTL_DEL, socket, nullptr); - if (res == -1) - { - log_error("epoll_ctl failed: ", strerror(errno)); - throw std::runtime_error("Could not remove socket from epoll"); - } -#endif -} - -void Poller::watch_send_events(SocketHandler* socket_handler) -{ -#if POLLER == POLL - for (size_t i = 0; i < this->nfds; ++i) - { - if (this->fds[i].fd == socket_handler->get_socket()) - { - this->fds[i].events = POLLIN|POLLOUT; - return; - } - } - throw std::runtime_error("Cannot watch a non-registered socket for send events"); -#elif POLLER == EPOLL - struct epoll_event event = {EPOLLIN|EPOLLOUT, {socket_handler}}; - const int res = ::epoll_ctl(this->epfd, EPOLL_CTL_MOD, socket_handler->get_socket(), &event); - if (res == -1) - { - log_error("epoll_ctl failed: ", strerror(errno)); - throw std::runtime_error("Could not modify socket flags in epoll"); - } -#endif -} - -void Poller::stop_watching_send_events(SocketHandler* socket_handler) -{ -#if POLLER == POLL - for (size_t i = 0; i <= this->nfds; ++i) - { - if (this->fds[i].fd == socket_handler->get_socket()) - { - this->fds[i].events = POLLIN; - return; - } - } - throw std::runtime_error("Cannot watch a non-registered socket for send events"); -#elif POLLER == EPOLL - struct epoll_event event = {EPOLLIN, {socket_handler}}; - const int res = ::epoll_ctl(this->epfd, EPOLL_CTL_MOD, socket_handler->get_socket(), &event); - if (res == -1) - { - log_error("epoll_ctl failed: ", strerror(errno)); - throw std::runtime_error("Could not modify socket flags in epoll"); - } -#endif -} - -int Poller::poll(const std::chrono::milliseconds& timeout) -{ - if (this->socket_handlers.empty() && timeout == utils::no_timeout) - return -1; -#if POLLER == POLL - // Convert our nice timeout into this ugly struct - struct timespec timeout_ts; - struct timespec* timeout_tsp; - if (timeout > 0s) - { - auto seconds = std::chrono::duration_cast(timeout); - timeout_ts.tv_sec = seconds.count(); - timeout_ts.tv_nsec = std::chrono::duration_cast(timeout - seconds).count(); - timeout_tsp = &timeout_ts; - } - else - timeout_tsp = nullptr; - - // Unblock all signals, only during the ppoll call - sigset_t empty_signal_set; - sigemptyset(&empty_signal_set); - int nb_events = ::ppoll(this->fds, this->nfds, timeout_tsp, - &empty_signal_set); - if (nb_events < 0) - { - if (errno == EINTR) - return true; - log_error("poll failed: ", strerror(errno)); - throw std::runtime_error("Poll failed"); - } - // We cannot possibly have more ready events than the number of fds we are - // watching - assert(static_cast(nb_events) <= this->nfds); - for (size_t i = 0; i < this->nfds && nb_events != 0; ++i) - { - auto socket_handler = this->socket_handlers.at(this->fds[i].fd); - if (this->fds[i].revents == 0) - continue; - else if (this->fds[i].revents & POLLIN && socket_handler->is_connected()) - { - socket_handler->on_recv(); - nb_events--; - } - else if (this->fds[i].revents & POLLOUT && socket_handler->is_connected()) - { - socket_handler->on_send(); - nb_events--; - } - else if (this->fds[i].revents & POLLOUT || - this->fds[i].revents & POLLIN) - { - socket_handler->connect(); - nb_events--; - } - } - return 1; -#elif POLLER == EPOLL - static const size_t max_events = 12; - struct epoll_event revents[max_events]; - // Unblock all signals, only during the epoll_pwait call - sigset_t empty_signal_set; - sigemptyset(&empty_signal_set); - const int nb_events = ::epoll_pwait(this->epfd, revents, max_events, timeout.count(), - &empty_signal_set); - if (nb_events == -1) - { - if (errno == EINTR) - return 0; - log_error("epoll wait: ", strerror(errno)); - throw std::runtime_error("Epoll_wait failed"); - } - for (int i = 0; i < nb_events; ++i) - { - auto socket_handler = static_cast(revents[i].data.ptr); - if (revents[i].events & EPOLLIN && socket_handler->is_connected()) - socket_handler->on_recv(); - else if (revents[i].events & EPOLLOUT && socket_handler->is_connected()) - socket_handler->on_send(); - else if (revents[i].events & EPOLLOUT) - socket_handler->connect(); - } - return nb_events; -#endif -} - -size_t Poller::size() const -{ - return this->socket_handlers.size(); -} - -bool Poller::is_managing_socket(const socket_t socket) const -{ - return (this->socket_handlers.find(socket) != this->socket_handlers.end()); -} diff --git a/louloulibs/network/poller.hpp b/louloulibs/network/poller.hpp deleted file mode 100644 index e39e438..0000000 --- a/louloulibs/network/poller.hpp +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once - - -#include - -#include -#include -#include - -#define POLL 1 -#define EPOLL 2 -#define KQUEUE 3 -#include -#ifndef POLLER - #define POLLER POLL -#endif - -#if POLLER == POLL - #include - #define MAX_POLL_FD_NUMBER 4096 -#elif POLLER == EPOLL - #include -#else - #error Invalid POLLER value -#endif - -/** - * We pass some SocketHandlers to this Poller, which uses - * poll/epoll/kqueue/select etc to wait for events on these SocketHandlers, - * and call the callbacks when event occurs. - * - * TODO: support these pollers: - * - kqueue(2) - */ - -class Poller -{ -public: - explicit Poller(); - ~Poller(); - Poller(const Poller&) = delete; - Poller(Poller&&) = delete; - Poller& operator=(const Poller&) = delete; - Poller& operator=(Poller&&) = delete; - /** - * Add a SocketHandler to be monitored by this Poller. All receive events - * are always automatically watched. - */ - void add_socket_handler(SocketHandler* socket_handler); - /** - * Remove (and stop managing) a SocketHandler, designated by the given socket_t. - */ - void remove_socket_handler(const socket_t socket); - /** - * Signal the poller that he needs to watch for send events for the given - * SocketHandler. - */ - void watch_send_events(SocketHandler* socket_handler); - /** - * Signal the poller that he needs to stop watching for send events for - * this SocketHandler. - */ - void stop_watching_send_events(SocketHandler* socket_handler); - /** - * Wait for all watched events, and call the SocketHandlers' callbacks - * when one is ready. Returns if nothing happened before the provided - * timeout. If the timeout is 0, it waits forever. If there is no - * watched event, returns -1 immediately, ignoring the timeout value. - * Otherwise, returns the number of event handled. If 0 is returned this - * means that we were interrupted by a signal, or the timeout occured. - */ - int poll(const std::chrono::milliseconds& timeout); - /** - * Returns the number of SocketHandlers managed by the poller. - */ - size_t size() const; - /** - * Whether the given socket is managed by the poller - */ - bool is_managing_socket(const socket_t socket) const; - -private: - /** - * A "list" of all the SocketHandlers that we manage, indexed by socket, - * because that's what is returned by select/poll/etc when an event - * occures. - */ - std::unordered_map socket_handlers; - -#if POLLER == POLL - struct pollfd fds[MAX_POLL_FD_NUMBER]; - nfds_t nfds; -#elif POLLER == EPOLL - int epfd; -#endif -}; - - diff --git a/louloulibs/network/resolver.cpp b/louloulibs/network/resolver.cpp deleted file mode 100644 index db7fb32..0000000 --- a/louloulibs/network/resolver.cpp +++ /dev/null @@ -1,281 +0,0 @@ -#include -#include -#include -#include -#include -#include -#ifdef UDNS_FOUND -# include -#endif - -#include -#include -#include -#include -#include - -using namespace std::string_literals; - -#ifdef UDNS_FOUND -static std::map dns_error_messages { - {DNS_E_TEMPFAIL, "Timeout while contacting DNS servers"}, - {DNS_E_PROTOCOL, "Misformatted DNS reply"}, - {DNS_E_NXDOMAIN, "Domain name not found"}, - {DNS_E_NOMEM, "Out of memory"}, - {DNS_E_BADQUERY, "Misformatted domain name"} -}; -#endif - -Resolver::Resolver(): -#ifdef UDNS_FOUND - resolved4(false), - resolved6(false), - resolving(false), - port{}, -#endif - resolved(false), - error_msg{} -{ -} - -void Resolver::resolve(const std::string& hostname, const std::string& port, - SuccessCallbackType success_cb, ErrorCallbackType error_cb) -{ - this->error_cb = error_cb; - this->success_cb = success_cb; -#ifdef UDNS_FOUND - this->port = port; -#endif - - this->start_resolving(hostname, port); -} - -int Resolver::call_getaddrinfo(const char *name, const char* port, int flags) -{ - struct addrinfo hints; - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_flags = flags; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - struct addrinfo* addr_res = nullptr; - const int res = ::getaddrinfo(name, port, - &hints, &addr_res); - - if (res == 0 && addr_res) - { - if (!this->addr) - this->addr.reset(addr_res); - else - { // Append this result at the end of the linked list - struct addrinfo *rp = this->addr.get(); - while (rp->ai_next) - rp = rp->ai_next; - rp->ai_next = addr_res; - } - } - - return res; -} - -#ifdef UDNS_FOUND -void Resolver::start_resolving(const std::string& hostname, const std::string& port) -{ - this->resolving = true; - this->resolved = false; - this->resolved4 = false; - this->resolved6 = false; - - this->error_msg.clear(); - this->addr.reset(nullptr); - - // We first try to use it as an IP address directly. We tell getaddrinfo - // to NOT use any DNS resolution. - if (this->call_getaddrinfo(hostname.data(), port.data(), AI_NUMERICHOST) == 0) - { - this->on_resolved(); - return; - } - - // Then we look into /etc/hosts to translate the given hostname - const auto hosts = this->look_in_etc_hosts(hostname); - if (!hosts.empty()) - { - for (const auto &host: hosts) - this->call_getaddrinfo(host.data(), port.data(), AI_NUMERICHOST); - this->on_resolved(); - return; - } - - // And finally, we try a DNS resolution - auto hostname6_resolved = [](dns_ctx*, dns_rr_a6* result, void* data) - { - Resolver* resolver = static_cast(data); - resolver->on_hostname6_resolved(result); - resolver->after_resolved(); - std::free(result); - }; - - auto hostname4_resolved = [](dns_ctx*, dns_rr_a4* result, void* data) - { - Resolver* resolver = static_cast(data); - resolver->on_hostname4_resolved(result); - resolver->after_resolved(); - std::free(result); - }; - - DNSHandler::watch(); - auto res = dns_submit_a4(nullptr, hostname.data(), 0, hostname4_resolved, this); - if (!res) - this->on_hostname4_resolved(nullptr); - res = dns_submit_a6(nullptr, hostname.data(), 0, hostname6_resolved, this); - if (!res) - this->on_hostname6_resolved(nullptr); - - this->start_timer(); -} - -void Resolver::start_timer() -{ - const auto timeout = dns_timeouts(nullptr, -1, 0); - if (timeout < 0) - return; - TimedEvent event(std::chrono::steady_clock::now() + std::chrono::seconds(timeout), [this]() { this->start_timer(); }, "DNS"); - TimedEventsManager::instance().add_event(std::move(event)); -} - -std::vector Resolver::look_in_etc_hosts(const std::string &hostname) -{ - std::ifstream hosts("/etc/hosts"); - std::string line; - - std::vector results; - while (std::getline(hosts, line)) - { - if (line.empty()) - continue; - - std::string ip; - std::istringstream line_stream(line); - line_stream >> ip; - if (ip.empty() || ip[0] == '#') - continue; - - std::string host; - while (line_stream >> host && !host.empty() && host[0] != '#') - { - if (hostname == host) - { - results.push_back(ip); - break; - } - } - } - return results; -} - -void Resolver::on_hostname4_resolved(dns_rr_a4 *result) -{ - this->resolved4 = true; - - const auto status = dns_status(nullptr); - - if (status >= 0 && result) - { - char buf[INET6_ADDRSTRLEN]; - - for (auto i = 0; i < result->dnsa4_nrr; ++i) - { - inet_ntop(AF_INET, &result->dnsa4_addr[i], buf, sizeof(buf)); - this->call_getaddrinfo(buf, this->port.data(), AI_NUMERICHOST); - } - } - else - { - const auto error = dns_error_messages.find(status); - if (error != end(dns_error_messages)) - this->error_msg = error->second; - } -} - -void Resolver::on_hostname6_resolved(dns_rr_a6 *result) -{ - this->resolved6 = true; - - const auto status = dns_status(nullptr); - - if (status >= 0 && result) - { - char buf[INET6_ADDRSTRLEN]; - for (auto i = 0; i < result->dnsa6_nrr; ++i) - { - inet_ntop(AF_INET6, &result->dnsa6_addr[i], buf, sizeof(buf)); - this->call_getaddrinfo(buf, this->port.data(), AI_NUMERICHOST); - } - } -} - -void Resolver::after_resolved() -{ - if (dns_active(nullptr) == 0) - DNSHandler::unwatch(); - - if (this->resolved6 && this->resolved4) - this->on_resolved(); -} - -void Resolver::on_resolved() -{ - this->resolved = true; - this->resolving = false; - if (!this->addr) - { - if (this->error_cb) - this->error_cb(this->error_msg.data()); - } - else - { - if (this->success_cb) - this->success_cb(this->addr.get()); - } -} - -#else // ifdef UDNS_FOUND - -void Resolver::start_resolving(const std::string& hostname, const std::string& port) -{ - // If the resolution fails, the addr will be unset - this->addr.reset(nullptr); - - const auto res = this->call_getaddrinfo(hostname.data(), port.data(), 0); - - this->resolved = true; - - if (res != 0) - { - this->error_msg = gai_strerror(res); - if (this->error_cb) - this->error_cb(this->error_msg.data()); - } - else - { - if (this->success_cb) - this->success_cb(this->addr.get()); - } -} -#endif // ifdef UDNS_FOUND - -std::string addr_to_string(const struct addrinfo* rp) -{ - char buf[INET6_ADDRSTRLEN]; - if (rp->ai_family == AF_INET) - return ::inet_ntop(rp->ai_family, - &reinterpret_cast(rp->ai_addr)->sin_addr, - buf, sizeof(buf)); - else if (rp->ai_family == AF_INET6) - return ::inet_ntop(rp->ai_family, - &reinterpret_cast(rp->ai_addr)->sin6_addr, - buf, sizeof(buf)); - return {}; -} diff --git a/louloulibs/network/resolver.hpp b/louloulibs/network/resolver.hpp deleted file mode 100644 index a560819..0000000 --- a/louloulibs/network/resolver.hpp +++ /dev/null @@ -1,122 +0,0 @@ -#pragma once - -#include "louloulibs.h" - -#include -#include -#include -#include - -#include -#include -#include -#ifdef UDNS_FOUND -# include -#endif - -class AddrinfoDeleter -{ - public: - void operator()(struct addrinfo* addr) - { - freeaddrinfo(addr); - } -}; - - -class Resolver -{ -public: - - using ErrorCallbackType = std::function; - using SuccessCallbackType = std::function; - - Resolver(); - ~Resolver() = default; - Resolver(const Resolver&) = delete; - Resolver(Resolver&&) = delete; - Resolver& operator=(const Resolver&) = delete; - Resolver& operator=(Resolver&&) = delete; - - bool is_resolving() const - { -#ifdef UDNS_FOUND - return this->resolving; -#else - return false; -#endif - } - - bool is_resolved() const - { - return this->resolved; - } - - const auto& get_result() const - { - return this->addr; - } - std::string get_error_message() const - { - return this->error_msg; - } - - void clear() - { -#ifdef UDNS_FOUND - this->resolved6 = false; - this->resolved4 = false; - this->resolving = false; - this->port.clear(); -#endif - this->resolved = false; - this->addr.reset(); - this->error_msg.clear(); - } - - void resolve(const std::string& hostname, const std::string& port, - SuccessCallbackType success_cb, ErrorCallbackType error_cb); - -private: - void start_resolving(const std::string& hostname, const std::string& port); - std::vector look_in_etc_hosts(const std::string& hostname); - /** - * Call getaddrinfo() on the given hostname or IP, and append the result - * to our internal addrinfo list. Return getaddrinfo()’s return value. - */ - int call_getaddrinfo(const char* name, const char* port, int flags); - -#ifdef UDNS_FOUND - void on_hostname4_resolved(dns_rr_a4 *result); - void on_hostname6_resolved(dns_rr_a6 *result); - /** - * Called after one record (4 or 6) has been resolved. - */ - void after_resolved(); - - void start_timer(); - - void on_resolved(); - - bool resolved4; - bool resolved6; - - bool resolving; - - std::string port; - -#endif - /** - * Tells if we finished the resolution process. It doesn't indicate if it - * was successful (it is true even if the result is an error). - */ - bool resolved; - std::string error_msg; - - std::unique_ptr addr; - - ErrorCallbackType error_cb; - SuccessCallbackType success_cb; -}; - -std::string addr_to_string(const struct addrinfo* rp); diff --git a/louloulibs/network/socket_handler.hpp b/louloulibs/network/socket_handler.hpp deleted file mode 100644 index 6a7220e..0000000 --- a/louloulibs/network/socket_handler.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include -#include - -class Poller; - -using socket_t = int; - -class SocketHandler -{ -public: - explicit SocketHandler(std::shared_ptr& poller, const socket_t socket): - poller(poller), - socket(socket) - {} - virtual ~SocketHandler() = default; - SocketHandler(const SocketHandler&) = delete; - SocketHandler(SocketHandler&&) = delete; - SocketHandler& operator=(const SocketHandler&) = delete; - SocketHandler& operator=(SocketHandler&&) = delete; - - virtual void on_recv() {} - virtual void on_send() {} - virtual void connect() {} - virtual bool is_connected() const = 0; - - socket_t get_socket() const - { return this->socket; } - -protected: - /** - * A pointer to the poller that manages us, because we need to communicate - * with it. - */ - std::shared_ptr poller; - /** - * The handled socket. - */ - socket_t socket; -}; - diff --git a/louloulibs/network/tcp_client_socket_handler.cpp b/louloulibs/network/tcp_client_socket_handler.cpp deleted file mode 100644 index 4628703..0000000 --- a/louloulibs/network/tcp_client_socket_handler.cpp +++ /dev/null @@ -1,261 +0,0 @@ -#include -#include -#include -#include - -#include - -#include -#include -#include - -using namespace std::string_literals; - -TCPClientSocketHandler::TCPClientSocketHandler(std::shared_ptr& poller): - TCPSocketHandler(poller), - hostname_resolution_failed(false), - connected(false), - connecting(false) -{} - -TCPClientSocketHandler::~TCPClientSocketHandler() -{ - this->close(); -} - -void TCPClientSocketHandler::init_socket(const struct addrinfo* rp) -{ - if (this->socket != -1) - ::close(this->socket); - if ((this->socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1) - throw std::runtime_error("Could not create socket: "s + std::strerror(errno)); - // Bind the socket to a specific address, if specified - if (!this->bind_addr.empty()) - { - // Convert the address from string format to a sockaddr that can be - // used in bind() - struct addrinfo* result; - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_NUMERICHOST; - hints.ai_family = AF_UNSPEC; - int err = ::getaddrinfo(this->bind_addr.data(), nullptr, &hints, &result); - if (err != 0 || !result) - log_error("Failed to bind socket to ", this->bind_addr, ": ", - gai_strerror(err)); - else - { - utils::ScopeGuard sg([result](){ freeaddrinfo(result); }); - struct addrinfo* rp; - for (rp = result; rp; rp = rp->ai_next) - { - if ((::bind(this->socket, - reinterpret_cast(rp->ai_addr), - rp->ai_addrlen)) == 0) - break; - } - if (!rp) - log_error("Failed to bind socket to ", this->bind_addr, ": ", - strerror(errno)); - else - log_info("Socket successfully bound to ", this->bind_addr); - } - } - int optval = 1; - if (::setsockopt(this->socket, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) == -1) - log_warning("Failed to enable TCP keepalive on socket: ", strerror(errno)); - // Set the socket on non-blocking mode. This is useful to receive a EAGAIN - // error when connect() would block, to not block the whole process if a - // remote is not responsive. - const int existing_flags = ::fcntl(this->socket, F_GETFL, 0); - if ((existing_flags == -1) || - (::fcntl(this->socket, F_SETFL, existing_flags | O_NONBLOCK) == -1)) - throw std::runtime_error("Could not initialize socket: "s + std::strerror(errno)); -} - -void TCPClientSocketHandler::connect(const std::string& address, const std::string& port, const bool tls) -{ - this->address = address; - this->port = port; - this->use_tls = tls; - - struct addrinfo* addr_res; - - if (!this->connecting) - { - // Get the addrinfo from getaddrinfo (or using udns), only if - // this is the first call of this function. - if (!this->resolver.is_resolved()) - { - log_info("Trying to connect to ", address, ":", port); - // Start the asynchronous process of resolving the hostname. Once - // the addresses have been found and `resolved` has been set to true - // (but connecting will still be false), TCPClientSocketHandler::connect() - // needs to be called, again. - this->resolver.resolve(address, port, - [this](const struct addrinfo*) - { - log_debug("Resolution success, calling connect() again"); - this->connect(); - }, - [this](const char*) - { - log_debug("Resolution failed, calling connect() again"); - this->connect(); - }); - return; - } - else - { - // The DNS resolver resolved the hostname and the available addresses - // where saved in the addrinfo linked list. Now, just use - // this list to try to connect. - addr_res = this->resolver.get_result().get(); - if (!addr_res) - { - this->hostname_resolution_failed = true; - const auto msg = this->resolver.get_error_message(); - this->close(); - this->on_connection_failed(msg); - return ; - } - } - } - else - { // This function is called again, use the saved addrinfo structure, - // instead of re-doing the whole getaddrinfo process. - addr_res = &this->addrinfo; - } - - for (struct addrinfo* rp = addr_res; rp; rp = rp->ai_next) - { - if (!this->connecting) - { - try { - this->init_socket(rp); - } - catch (const std::runtime_error& error) { - log_error("Failed to init socket: ", error.what()); - break; - } - } - - this->display_resolved_ip(rp); - - if (::connect(this->socket, rp->ai_addr, rp->ai_addrlen) == 0 - || errno == EISCONN) - { - log_info("Connection success."); - TimedEventsManager::instance().cancel("connection_timeout"s + - std::to_string(this->socket)); - this->poller->add_socket_handler(this); - this->connected = true; - this->connecting = false; -#ifdef BOTAN_FOUND - if (this->use_tls) - this->start_tls(this->address, this->port); -#endif - this->connection_date = std::chrono::system_clock::now(); - - // Get our local TCP port and store it - this->local_port = static_cast(-1); - if (rp->ai_family == AF_INET6) - { - struct sockaddr_in6 a; - socklen_t l = sizeof(a); - if (::getsockname(this->socket, (struct sockaddr*)&a, &l) != -1) - this->local_port = ntohs(a.sin6_port); - } - else if (rp->ai_family == AF_INET) - { - struct sockaddr_in a; - socklen_t l = sizeof(a); - if (::getsockname(this->socket, (struct sockaddr*)&a, &l) != -1) - this->local_port = ntohs(a.sin_port); - } - - log_debug("Local port: ", this->local_port, ", and remote port: ", this->port); - - this->on_connected(); - return ; - } - else if (errno == EINPROGRESS || errno == EALREADY) - { // retry this process later, when the socket - // is ready to be written on. - this->connecting = true; - this->poller->add_socket_handler(this); - this->poller->watch_send_events(this); - // Save the addrinfo structure, to use it on the next call - this->ai_addrlen = rp->ai_addrlen; - memcpy(&this->ai_addr, rp->ai_addr, this->ai_addrlen); - memcpy(&this->addrinfo, rp, sizeof(struct addrinfo)); - this->addrinfo.ai_addr = reinterpret_cast(&this->ai_addr); - this->addrinfo.ai_next = nullptr; - // If the connection has not succeeded or failed in 5s, we consider - // it to have failed - TimedEventsManager::instance().add_event( - TimedEvent(std::chrono::steady_clock::now() + 5s, - std::bind(&TCPClientSocketHandler::on_connection_timeout, this), - "connection_timeout"s + std::to_string(this->socket))); - return ; - } - log_info("Connection failed:", std::strerror(errno)); - } - log_error("All connection attempts failed."); - this->close(); - this->on_connection_failed(std::strerror(errno)); - return ; -} - -void TCPClientSocketHandler::on_connection_timeout() -{ - this->close(); - this->on_connection_failed("connection timed out"); -} - -void TCPClientSocketHandler::connect() -{ - this->connect(this->address, this->port, this->use_tls); -} - -void TCPClientSocketHandler::close() -{ - TimedEventsManager::instance().cancel("connection_timeout"s + - std::to_string(this->socket)); - - TCPSocketHandler::close(); - - this->connected = false; - this->connecting = false; - this->port.clear(); - this->resolver.clear(); -} - -void TCPClientSocketHandler::display_resolved_ip(struct addrinfo* rp) const -{ - if (rp->ai_family == AF_INET) - log_debug("Trying IPv4 address ", addr_to_string(rp)); - else if (rp->ai_family == AF_INET6) - log_debug("Trying IPv6 address ", addr_to_string(rp)); -} - -bool TCPClientSocketHandler::is_connected() const -{ - return this->connected; -} - -bool TCPClientSocketHandler::is_connecting() const -{ - return this->connecting || this->resolver.is_resolving(); -} - -std::string TCPClientSocketHandler::get_port() const -{ - return this->port; -} - -bool TCPClientSocketHandler::match_port_pairt(const uint16_t local, const uint16_t remote) const -{ - const uint16_t remote_port = static_cast(std::stoi(this->port)); - return this->is_connected() && local == this->local_port && remote == remote_port; -} diff --git a/louloulibs/network/tcp_client_socket_handler.hpp b/louloulibs/network/tcp_client_socket_handler.hpp deleted file mode 100644 index 74caca9..0000000 --- a/louloulibs/network/tcp_client_socket_handler.hpp +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include - -class TCPClientSocketHandler: public TCPSocketHandler -{ - public: - TCPClientSocketHandler(std::shared_ptr& poller); - ~TCPClientSocketHandler(); - /** - * Connect to the remote server, and call on_connected() if this - * succeeds. If tls is true, we set use_tls to true and will also call - * start_tls() when the connection succeeds. - */ - void connect(const std::string& address, const std::string& port, const bool tls); - void connect() override final; - /** - * Called by a TimedEvent, when the connection did not succeed or fail - * after a given time. - */ - void on_connection_timeout(); - /** - * Called when the connection is successful. - */ - virtual void on_connected() = 0; - bool is_connected() const override; - bool is_connecting() const override; - - std::string get_port() const; - - void close() override final; - std::chrono::system_clock::time_point connection_date; - - /** - * Whether or not this connection is using the two given TCP ports. - */ - bool match_port_pairt(const uint16_t local, const uint16_t remote) const; - - protected: - bool hostname_resolution_failed; - /** - * Address to bind the socket to, before calling connect(). - * If empty, it’s equivalent to binding to INADDR_ANY. - */ - std::string bind_addr; - /** - * Display the resolved IP, just for information purpose. - */ - void display_resolved_ip(struct addrinfo* rp) const; - private: - /** - * Initialize the socket with the parameters contained in the given - * addrinfo structure. - */ - void init_socket(const struct addrinfo* rp); - /** - * DNS resolver - */ - Resolver resolver; - /** - * Keep the details of the addrinfo returned by the resolver that - * triggered a EINPROGRESS error when connect()ing to it, to reuse it - * directly when connect() is called again. - */ - struct addrinfo addrinfo{}; - struct sockaddr_in6 ai_addr{}; - socklen_t ai_addrlen{}; - - /** - * Hostname we are connected/connecting to - */ - std::string address; - /** - * Port we are connected/connecting to - */ - std::string port; - - uint16_t local_port{}; - - bool connected; - bool connecting; -}; diff --git a/louloulibs/network/tcp_server_socket.hpp b/louloulibs/network/tcp_server_socket.hpp deleted file mode 100644 index c511962..0000000 --- a/louloulibs/network/tcp_server_socket.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include - -template -class TcpSocketServer: public SocketHandler -{ - public: - TcpSocketServer(std::shared_ptr& poller, const uint16_t port): - SocketHandler(poller, -1) - { - if ((this->socket = ::socket(AF_INET6, SOCK_STREAM, 0)) == -1) - throw std::runtime_error(std::string{"Could not create socket: "} + std::strerror(errno)); - - int opt = 1; - if (::setsockopt(this->socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) - throw std::runtime_error(std::string{"Failed to set socket option: "} + std::strerror(errno)); - - struct sockaddr_in6 addr{}; - addr.sin6_family = AF_INET6; - addr.sin6_port = htons(port); - addr.sin6_addr = IN6ADDR_ANY_INIT; - if ((::bind(this->socket, (const struct sockaddr*)&addr, sizeof(addr))) == -1) - { // If we can’t listen on this port, we just give up, but this is not fatal. - log_warning("Failed to bind on port ", std::to_string(port), ": ", std::strerror(errno)); - return; - } - - if ((::listen(this->socket, 10)) == -1) - throw std::runtime_error("listen() failed"); - - this->accept(); - } - ~TcpSocketServer() = default; - - void on_recv() override - { - // Accept a RemoteSocketType - int socket = ::accept(this->socket, nullptr, nullptr); - - auto client = std::make_unique(poller, socket, *this); - this->poller->add_socket_handler(client.get()); - this->sockets.push_back(std::move(client)); - } - - protected: - std::vector> sockets; - - private: - void accept() - { - this->poller->add_socket_handler(this); - } - bool is_connected() const override - { - return true; - } -}; diff --git a/louloulibs/network/tcp_socket_handler.cpp b/louloulibs/network/tcp_socket_handler.cpp deleted file mode 100644 index 7eebae0..0000000 --- a/louloulibs/network/tcp_socket_handler.cpp +++ /dev/null @@ -1,358 +0,0 @@ -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#ifdef BOTAN_FOUND -# include -# include - -namespace -{ - Botan::AutoSeeded_RNG& get_rng() - { - static Botan::AutoSeeded_RNG rng{}; - return rng; - } - BiboumiTLSPolicy& get_policy() - { - static BiboumiTLSPolicy policy{}; - return policy; - } - Botan::TLS::Session_Manager_In_Memory& get_session_manager() - { - static Botan::TLS::Session_Manager_In_Memory session_manager{get_rng()}; - return session_manager; - } -} -#endif - -#ifndef UIO_FASTIOV -# define UIO_FASTIOV 8 -#endif - -using namespace std::string_literals; -using namespace std::chrono_literals; - -namespace ph = std::placeholders; - -TCPSocketHandler::TCPSocketHandler(std::shared_ptr& poller): - SocketHandler(poller, -1), - use_tls(false) -#ifdef BOTAN_FOUND - ,credential_manager(this) -#endif -{} - -TCPSocketHandler::~TCPSocketHandler() -{ - if (this->poller->is_managing_socket(this->get_socket())) - this->poller->remove_socket_handler(this->get_socket()); - if (this->socket != -1) - { - ::close(this->socket); - this->socket = -1; - } -} - -void TCPSocketHandler::on_recv() -{ -#ifdef BOTAN_FOUND - if (this->use_tls) - this->tls_recv(); - else -#endif - this->plain_recv(); -} - -void TCPSocketHandler::plain_recv() -{ - static constexpr size_t buf_size = 4096; - char buf[buf_size]; - void* recv_buf = this->get_receive_buffer(buf_size); - - if (recv_buf == nullptr) - recv_buf = buf; - - const ssize_t size = this->do_recv(recv_buf, buf_size); - - if (size > 0) - { - if (buf == recv_buf) - { - // data needs to be placed in the in_buf string, because no buffer - // was provided to receive that data directly. The in_buf buffer - // will be handled in parse_in_buffer() - this->in_buf += std::string(buf, size); - } - this->parse_in_buffer(size); - } -} - -ssize_t TCPSocketHandler::do_recv(void* recv_buf, const size_t buf_size) -{ - ssize_t size = ::recv(this->socket, recv_buf, buf_size, 0); - if (0 == size) - { - this->on_connection_close(""); - this->close(); - } - else if (-1 == size) - { - if (this->is_connecting()) - log_warning("Error connecting: ", strerror(errno)); - else - log_warning("Error while reading from socket: ", strerror(errno)); - // Remember if we were connecting, or already connected when this - // happened, because close() sets this->connecting to false - const auto were_connecting = this->is_connecting(); - this->close(); - if (were_connecting) - this->on_connection_failed(strerror(errno)); - else - this->on_connection_close(strerror(errno)); - } - return size; -} - -void TCPSocketHandler::on_send() -{ - struct iovec msg_iov[UIO_FASTIOV] = {}; - struct msghdr msg{nullptr, 0, - msg_iov, - 0, nullptr, 0, 0}; - for (const std::string& s: this->out_buf) - { - // unconsting the content of s is ok, sendmsg will never modify it - msg_iov[msg.msg_iovlen].iov_base = const_cast(s.data()); - msg_iov[msg.msg_iovlen].iov_len = s.size(); - msg.msg_iovlen++; - if (msg.msg_iovlen == UIO_FASTIOV) - break; - } - ssize_t res = ::sendmsg(this->socket, &msg, MSG_NOSIGNAL); - if (res < 0) - { - log_error("sendmsg failed: ", strerror(errno)); - this->on_connection_close(strerror(errno)); - this->close(); - } - else - { - // remove all the strings that were successfully sent. - auto it = this->out_buf.begin(); - while (it != this->out_buf.end()) - { - if (static_cast(res) >= it->size()) - { - res -= it->size(); - ++it; - } - else - { - // If one string has partially been sent, we use substr to - // crop it - if (res > 0) - *it = it->substr(res, std::string::npos); - break; - } - } - this->out_buf.erase(this->out_buf.begin(), it); - if (this->out_buf.empty()) - this->poller->stop_watching_send_events(this); - } -} - -void TCPSocketHandler::close() -{ - if (this->is_connected() || this->is_connecting()) - this->poller->remove_socket_handler(this->get_socket()); - if (this->socket != -1) - { - ::close(this->socket); - this->socket = -1; - } - this->in_buf.clear(); - this->out_buf.clear(); -} - -void TCPSocketHandler::send_data(std::string&& data) -{ -#ifdef BOTAN_FOUND - if (this->use_tls) - try { - this->tls_send(std::move(data)); - } catch (const Botan::TLS::TLS_Exception& e) { - this->on_connection_close("TLS error: "s + e.what()); - this->close(); - return ; - } - else -#endif - this->raw_send(std::move(data)); -} - -void TCPSocketHandler::raw_send(std::string&& data) -{ - if (data.empty()) - return ; - this->out_buf.emplace_back(std::move(data)); - if (this->is_connected()) - this->poller->watch_send_events(this); -} - -void TCPSocketHandler::send_pending_data() -{ - if (this->is_connected() && !this->out_buf.empty()) - this->poller->watch_send_events(this); -} - -bool TCPSocketHandler::is_using_tls() const -{ - return this->use_tls; -} - -void* TCPSocketHandler::get_receive_buffer(const size_t) const -{ - return nullptr; -} - -void TCPSocketHandler::consume_in_buffer(const std::size_t size) -{ - this->in_buf = this->in_buf.substr(size, std::string::npos); -} - -#ifdef BOTAN_FOUND -void TCPSocketHandler::start_tls(const std::string& address, const std::string& port) -{ - Botan::TLS::Server_Information server_info(address, "irc", std::stoul(port)); - this->tls = std::make_unique( -# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,32) - *this, -# else - [this](const Botan::byte* data, size_t size) { this->tls_emit_data(data, size); }, - [this](const Botan::byte* data, size_t size) { this->tls_record_received(0, data, size); }, - [this](Botan::TLS::Alert alert, const Botan::byte*, size_t) { this->tls_alert(alert); }, - [this](const Botan::TLS::Session& session) { return this->tls_session_established(session); }, -# endif - get_session_manager(), this->credential_manager, get_policy(), - get_rng(), server_info, Botan::TLS::Protocol_Version::latest_tls_version()); -} - -void TCPSocketHandler::tls_recv() -{ - static constexpr size_t buf_size = 4096; - Botan::byte recv_buf[buf_size]; - - const ssize_t size = this->do_recv(recv_buf, buf_size); - if (size > 0) - { - const bool was_active = this->tls->is_active(); - try { - this->tls->received_data(recv_buf, static_cast(size)); - } catch (const Botan::TLS::TLS_Exception& e) { - // May happen if the server sends malformed TLS data (buggy server, - // or more probably we are just connected to a server that sends - // plain-text) - this->on_connection_close("TLS error: "s + e.what()); - this->close(); - return ; - } - if (!was_active && this->tls->is_active()) - this->on_tls_activated(); - } -} - -void TCPSocketHandler::tls_send(std::string&& data) -{ - // We may not be connected yet, or the tls session has - // not yet been negociated - if (this->tls && this->tls->is_active()) - { - const bool was_active = this->tls->is_active(); - if (!this->pre_buf.empty()) - { - this->tls->send(this->pre_buf.data(), this->pre_buf.size()); - this->pre_buf.clear(); - } - if (!data.empty()) - this->tls->send(reinterpret_cast(data.data()), - data.size()); - if (!was_active && this->tls->is_active()) - this->on_tls_activated(); - } - else - this->pre_buf.insert(this->pre_buf.end(), - std::make_move_iterator(data.begin()), - std::make_move_iterator(data.end())); -} - -void TCPSocketHandler::tls_record_received(uint64_t, const Botan::byte *data, size_t size) -{ - this->in_buf += std::string(reinterpret_cast(data), - size); - if (!this->in_buf.empty()) - this->parse_in_buffer(size); -} - -void TCPSocketHandler::tls_emit_data(const Botan::byte *data, size_t size) -{ - this->raw_send(std::string(reinterpret_cast(data), size)); -} - -void TCPSocketHandler::tls_alert(Botan::TLS::Alert alert) -{ - log_debug("tls_alert: ", alert.type_string()); -} - -bool TCPSocketHandler::tls_session_established(const Botan::TLS::Session& session) -{ - log_debug("Handshake with ", session.server_info().hostname(), " complete.", - " Version: ", session.version().to_string(), - " using ", session.ciphersuite().to_string()); - if (!session.session_id().empty()) - log_debug("Session ID ", Botan::hex_encode(session.session_id())); - if (!session.session_ticket().empty()) - log_debug("Session ticket ", Botan::hex_encode(session.session_ticket())); - return true; -} - -#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,34) -void TCPSocketHandler::tls_verify_cert_chain(const std::vector& cert_chain, - const std::vector>& ocsp_responses, - const std::vector& trusted_roots, - Botan::Usage_Type usage, const std::string& hostname, - const Botan::TLS::Policy& policy) -{ - log_debug("Checking remote certificate for hostname ", hostname); - try - { - Botan::TLS::Callbacks::tls_verify_cert_chain(cert_chain, ocsp_responses, trusted_roots, usage, hostname, policy); - log_debug("Certificate is valid"); - } - catch (const std::exception& tls_exception) - { - log_warning("TLS certificate check failed: ", tls_exception.what()); - std::exception_ptr exception_ptr{}; - if (this->abort_on_invalid_cert()) - exception_ptr = std::current_exception(); - - check_tls_certificate(cert_chain, hostname, this->credential_manager.get_trusted_fingerprint(), exception_ptr); - } -} -#endif - -void TCPSocketHandler::on_tls_activated() -{ - this->send_data({}); -} - -#endif // BOTAN_FOUND diff --git a/louloulibs/network/tcp_socket_handler.hpp b/louloulibs/network/tcp_socket_handler.hpp deleted file mode 100644 index 3ee2f47..0000000 --- a/louloulibs/network/tcp_socket_handler.hpp +++ /dev/null @@ -1,251 +0,0 @@ -#pragma once - -#include "louloulibs.h" - -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#ifdef BOTAN_FOUND - -# include -# include -# include - -class BiboumiTLSPolicy: public Botan::TLS::Policy -{ -public: -# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33) - bool use_ecc_point_compression() const override - { - return true; - } - bool require_cert_revocation_info() const override - { - return false; - } -# endif -}; - -# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,32) -# define BOTAN_TLS_CALLBACKS_OVERRIDE override final -# else -# define BOTAN_TLS_CALLBACKS_OVERRIDE -# endif -#endif - -/** - * Does all the read/write, buffering etc. With optional tls. - * But doesn’t do any connect() or accept() or anything else. - */ -class TCPSocketHandler: public SocketHandler -#ifdef BOTAN_FOUND -# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,32) - ,public Botan::TLS::Callbacks -# endif -#endif -{ -protected: - ~TCPSocketHandler(); -public: - explicit TCPSocketHandler(std::shared_ptr& poller); - TCPSocketHandler(const TCPSocketHandler&) = delete; - TCPSocketHandler(TCPSocketHandler&&) = delete; - TCPSocketHandler& operator=(const TCPSocketHandler&) = delete; - TCPSocketHandler& operator=(TCPSocketHandler&&) = delete; - - /** - * Reads raw data from the socket. And pass it to parse_in_buffer() - * If we are using TLS on this connection, we call tls_recv() - */ - void on_recv() override final; - /** - * Write as much data from out_buf as possible, in the socket. - */ - void on_send() override final; - /** - * Add the given data to out_buf and tell our poller that we want to be - * notified when a send event is ready. - * - * This can be overriden if we want to modify the data before sending - * it. For example if we want to encrypt it. - */ - void send_data(std::string&& data); - /** - * Watch the socket for send events, if our out buffer is not empty. - */ - void send_pending_data(); - /** - * Close the connection, remove us from the poller - */ - virtual void close(); - /** - * Handle/consume (some of) the data received so far. The data to handle - * may be in the in_buf buffer, or somewhere else, depending on what - * get_receive_buffer() returned. If some data is used from in_buf, it - * should be truncated, only the unused data should be left untouched. - * - * The size argument is the size of the last chunk of data that was added to the buffer. - * - * The function should call consume_in_buffer, with the size that was consumed by the - * “parsing”, and thus to be removed from the input buffer. - */ - virtual void parse_in_buffer(const size_t size) = 0; -#ifdef BOTAN_FOUND - /** - * Tell whether the credential manager should cancel the connection when the - * certificate is invalid. - */ - virtual bool abort_on_invalid_cert() const - { - return true; - } -#endif - bool is_using_tls() const; - -private: - /** - * Reads from the socket into the provided buffer. If an error occurs - * (read returns <= 0), the handling of the error is done here (close the - * connection, log a message, etc). - * - * Returns the value returned by ::recv(), so the buffer should not be - * used if it’s not positive. - */ - ssize_t do_recv(void* recv_buf, const size_t buf_size); - /** - * Reads data from the socket and calls parse_in_buffer with it. - */ - void plain_recv(); - /** - * Mark the given data as ready to be sent, as-is, on the socket, as soon - * as we can. - */ - void raw_send(std::string&& data); - - protected: - virtual bool is_connecting() const = 0; -#ifdef BOTAN_FOUND - /** - * Create the TLS::Client object, with all the callbacks etc. This must be - * called only when we know we are able to send TLS-encrypted data over - * the socket. - */ - void start_tls(const std::string& address, const std::string& port); - private: - /** - * An additional step to pass the data into our tls object to decrypt it - * before passing it to parse_in_buffer. - */ - void tls_recv(); - /** - * Pass the data to the tls object in order to encrypt it. The tls object - * will then call raw_send as a callback whenever data as been encrypted - * and can be sent on the socket. - */ - void tls_send(std::string&& data); - /** - * Called by the tls object that some data has been decrypt. We call - * parse_in_buffer() to handle that unencrypted data. - */ - void tls_record_received(uint64_t rec_no, const Botan::byte* data, size_t size) BOTAN_TLS_CALLBACKS_OVERRIDE; - /** - * Called by the tls object to indicate that some data has been encrypted - * and is now ready to be sent on the socket as is. - */ - void tls_emit_data(const Botan::byte* data, size_t size) BOTAN_TLS_CALLBACKS_OVERRIDE; - /** - * Called by the tls object to indicate that a TLS alert has been - * received. We don’t use it, we just log some message, at the moment. - */ - void tls_alert(Botan::TLS::Alert alert) BOTAN_TLS_CALLBACKS_OVERRIDE; - /** - * Called by the tls object at the end of the TLS handshake. We don't do - * anything here appart from logging the TLS session information. - */ - bool tls_session_established(const Botan::TLS::Session& session) BOTAN_TLS_CALLBACKS_OVERRIDE; - -#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,34) - void tls_verify_cert_chain(const std::vector& cert_chain, - const std::vector>& ocsp_responses, - const std::vector& trusted_roots, - Botan::Usage_Type usage, - const std::string& hostname, - const Botan::TLS::Policy& policy) BOTAN_TLS_CALLBACKS_OVERRIDE; -#endif - /** - * Called whenever the tls session goes from inactive to active. This - * means that the handshake has just been successfully done, and we can - * now proceed to send any available data into our tls object. - */ - void on_tls_activated(); -#endif // BOTAN_FOUND - /** - * Where data is added, when we want to send something to the client. - */ - std::vector out_buf; -protected: - /** - * Whether we are using TLS on this connection or not. - */ - bool use_tls; - /** - * Where data read from the socket is added until we can extract a full - * and meaningful “message” from it. - * - * TODO: something more efficient than a string. - */ - std::string in_buf; - /** - * Remove the given “size” first bytes from our in_buf. - */ - void consume_in_buffer(const std::size_t size); - /** - * Provide a buffer in which data can be directly received. This can be - * used to avoid copying data into in_buf before using it. If no buffer - * needs to be provided, nullptr is returned (the default implementation - * does that), in that case our internal in_buf will be used to save the - * data until it can be used by parse_in_buffer(). - */ - virtual void* get_receive_buffer(const size_t size) const; - /** - * Called when we detect a disconnection from the remote host. - */ - virtual void on_connection_close(const std::string&) {} - virtual void on_connection_failed(const std::string&) {} - -#ifdef BOTAN_FOUND -protected: - BasicCredentialsManager credential_manager; -private: - /** - * We use a unique_ptr because we may not want to create the object at - * all. The Botan::TLS::Client object generates a handshake message and - * calls the output_fn callback with it as soon as it is created. - * Therefore, we do not want to create it if we do not intend to send any - * TLS-encrypted message. We create the object only when needed (for - * example after we have negociated a TLS session using a STARTTLS - * message, or stuf like that). - * - * See start_tls for the method where this object is created. - */ - std::unique_ptr tls; - /** - * An additional buffer to keep data that the user wants to send, but - * cannot because the handshake is not done. - */ - std::vector pre_buf; -#endif // BOTAN_FOUND -}; diff --git a/louloulibs/utils/encoding.cpp b/louloulibs/utils/encoding.cpp deleted file mode 100644 index aa91dac..0000000 --- a/louloulibs/utils/encoding.cpp +++ /dev/null @@ -1,254 +0,0 @@ -#include - -#include - -#include - -#include -#include -#include -#include - -#include -#include - -/** - * The UTF-8-encoded character used as a place holder when a character conversion fails. - * This is U+FFFD � "replacement character" - */ -static const char* invalid_char = "\xef\xbf\xbd"; -static const size_t invalid_char_len = 3; - -namespace utils -{ - /** - * Based on http://en.wikipedia.org/wiki/UTF-8#Description - */ - std::size_t get_next_codepoint_size(const unsigned char c) - { - if ((c & 0b11111000) == 0b11110000) // 4 bytes: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - return 4; - else if ((c & 0b11110000) == 0b11100000) // 3 bytes: 1110xxx 10xxxxxx 10xxxxxx - return 3; - else if ((c & 0b11100000) == 0b11000000) // 2 bytes: 110xxxxx 10xxxxxx - return 2; - return 1; // 1 byte: 0xxxxxxx - } - - bool is_valid_utf8(const char* s) - { - if (!s) - return false; - - const unsigned char* str = reinterpret_cast(s); - - while (*str) - { - const auto codepoint_size = get_next_codepoint_size(str[0]); - if (codepoint_size == 4) - { - if (!str[1] || !str[2] || !str[3] - || ((str[1] & 0b11000000) != 0b10000000) - || ((str[2] & 0b11000000) != 0b10000000) - || ((str[3] & 0b11000000) != 0b10000000)) - return false; - } - else if (codepoint_size == 3) - { - if (!str[1] || !str[2] - || ((str[1] & 0b11000000) != 0b10000000) - || ((str[2] & 0b11000000) != 0b10000000)) - return false; - } - else if (codepoint_size == 2) - { - if (!str[1] || - ((str[1] & 0b11000000) != 0b10000000)) - return false; - } - else if ((str[0] & 0b10000000) != 0) - return false; - str += codepoint_size; - } - return true; - } - - std::string remove_invalid_xml_chars(const std::string& original) - { - // The given string MUST be a valid utf-8 string - std::vector res(original.size(), '\0'); - - // pointer where we write valid chars - char* r = res.data(); - - const char* str = original.c_str(); - std::bitset<20> codepoint; - - while (*str) - { - // 4 bytes: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - if ((str[0] & 0b11111000) == 0b11110000) - { - codepoint = ((str[0] & 0b00000111) << 18); - codepoint |= ((str[1] & 0b00111111) << 12); - codepoint |= ((str[2] & 0b00111111) << 6 ); - codepoint |= ((str[3] & 0b00111111) << 0 ); - if (codepoint.to_ulong() <= 0x10FFFF) - { - ::memcpy(r, str, 4); - r += 4; - } - str += 4; - } - // 3 bytes: 1110xxx 10xxxxxx 10xxxxxx - else if ((str[0] & 0b11110000) == 0b11100000) - { - codepoint = ((str[0] & 0b00001111) << 12); - codepoint |= ((str[1] & 0b00111111) << 6); - codepoint |= ((str[2] & 0b00111111) << 0 ); - if (codepoint.to_ulong() <= 0xD7FF || - (codepoint.to_ulong() >= 0xE000 && codepoint.to_ulong() <= 0xFFFD)) - { - ::memcpy(r, str, 3); - r += 3; - } - str += 3; - } - // 2 bytes: 110xxxxx 10xxxxxx - else if (((str[0]) & 0b11100000) == 0b11000000) - { - // All 2 bytes char are valid, don't even bother calculating - // the codepoint - ::memcpy(r, str, 2); - r += 2; - str += 2; - } - // 1 byte: 0xxxxxxx - else if ((str[0] & 0b10000000) == 0) - { - codepoint = ((str[0] & 0b01111111)); - if (codepoint.to_ulong() == 0x09 || - codepoint.to_ulong() == 0x0A || - codepoint.to_ulong() == 0x0D || - codepoint.to_ulong() >= 0x20) - { - ::memcpy(r, str, 1); - r += 1; - } - str += 1; - } - else - throw std::runtime_error("Invalid UTF-8 passed to remove_invalid_xml_chars"); - } - return {res.data(), static_cast(r - res.data())}; - } - - std::string convert_to_utf8(const std::string& str, const char* charset) - { - std::string res; - - const iconv_t cd = iconv_open("UTF-8", charset); - if (cd == (iconv_t)-1) - throw std::runtime_error("Cannot convert into UTF-8"); - - // Make sure cd is always closed when we leave this function - const auto sg = utils::make_scope_guard([&cd](){ iconv_close(cd); }); - - size_t inbytesleft = str.size(); - - // iconv will not attempt to modify this buffer, but some plateform - // require a char** anyway -#ifdef ICONV_SECOND_ARGUMENT_IS_CONST - const char* inbuf_ptr = str.c_str(); -#else - char* inbuf_ptr = const_cast(str.c_str()); -#endif - - size_t outbytesleft = str.size() * 4; - char* outbuf = new char[outbytesleft]; - char* outbuf_ptr = outbuf; - - // Make sure outbuf is always deleted when we leave this function - const auto sg2 = utils::make_scope_guard([outbuf](){ delete[] outbuf; }); - - bool done = false; - while (done == false) - { - size_t error = iconv(cd, &inbuf_ptr, &inbytesleft, &outbuf_ptr, &outbytesleft); - if ((size_t)-1 == error) - { - switch (errno) - { - case EILSEQ: - // Invalid byte found. Insert a placeholder instead of the - // converted character, jump one byte and continue - memcpy(outbuf_ptr, invalid_char, invalid_char_len); - outbuf_ptr += invalid_char_len; - inbytesleft--; - inbuf_ptr++; - break; - case EINVAL: - // A multibyte sequence is not terminated, but we can't - // provide any more data, so we just add a placeholder to - // indicate that the character is not properly converted, - // and we stop the conversion - memcpy(outbuf_ptr, invalid_char, invalid_char_len); - outbuf_ptr += invalid_char_len; - outbuf_ptr++; - done = true; - break; - case E2BIG: // This should never happen - default: // This should happen even neverer - done = true; - break; - } - } - else - { - // The conversion finished without any error, stop converting - done = true; - } - } - // Terminate the converted buffer, and copy that buffer it into the - // string we return - *outbuf_ptr = '\0'; - res = outbuf; - return res; - } - -} - -namespace xep0106 -{ - static const std::map encode_map = { - {' ', "\\20"}, - {'"', "\\22"}, - {'&', "\\26"}, - {'\'',"\\27"}, - {'/', "\\2f"}, - {':', "\\3a"}, - {'<', "\\3c"}, - {'>', "\\3e"}, - {'@', "\\40"}, - }; - - void decode(std::string& s) - { - std::string::size_type pos; - for (const auto& pair: encode_map) - while ((pos = s.find(pair.second)) != std::string::npos) - s.replace(pos, pair.second.size(), - 1, pair.first); - } - - void encode(std::string& s) - { - std::string::size_type pos; - while ((pos = s.find_first_of(" \"&'/:<>@")) != std::string::npos) - { - auto it = encode_map.find(s[pos]); - assert(it != encode_map.end()); - s.replace(pos, 1, it->second); - } - } -} diff --git a/louloulibs/utils/encoding.hpp b/louloulibs/utils/encoding.hpp deleted file mode 100644 index 586edd8..0000000 --- a/louloulibs/utils/encoding.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - - -#include - -namespace utils -{ - /** - * Return the size, in bytes, of the next UTF-8 codepoint, based on - * the given char. - */ - std::size_t get_next_codepoint_size(const unsigned char c); - /** - * Returns true if the given null-terminated string is valid utf-8. - * - * Based on http://en.wikipedia.org/wiki/UTF-8#Description - */ - bool is_valid_utf8(const char* s); - /** - * Remove all invalid codepoints from the given utf-8-encoded string. - * The value returned is a copy of the string, without the removed chars. - * - * See http://www.w3.org/TR/xml/#charsets for the list of valid characters - * in XML. - */ - std::string remove_invalid_xml_chars(const std::string& original); - /** - * Convert the given string (encoded is "encoding") into valid utf-8. - * If some decoding fails, insert an utf-8 placeholder character instead. - */ - std::string convert_to_utf8(const std::string& str, const char* encoding); -} - -namespace xep0106 -{ - /** - * Decode and encode inplace. - */ - void decode(std::string&); - void encode(std::string&); -} - - diff --git a/louloulibs/utils/get_first_non_empty.cpp b/louloulibs/utils/get_first_non_empty.cpp deleted file mode 100644 index 5b3bedb..0000000 --- a/louloulibs/utils/get_first_non_empty.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include - -bool is_empty(const std::string& val) -{ - return val.empty(); -} - -bool is_empty(const int& val) -{ - return val == 0; -} diff --git a/louloulibs/utils/get_first_non_empty.hpp b/louloulibs/utils/get_first_non_empty.hpp deleted file mode 100644 index a38f5fb..0000000 --- a/louloulibs/utils/get_first_non_empty.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -bool is_empty(const std::string& val); -bool is_empty(const int& val); - -template -T get_first_non_empty(T&& last) -{ - return last; -} - -template -T get_first_non_empty(T&& first, Args&&... args) -{ - if (!is_empty(first)) - return first; - return get_first_non_empty(std::forward(args)...); -} diff --git a/louloulibs/utils/revstr.cpp b/louloulibs/utils/revstr.cpp deleted file mode 100644 index 87fd801..0000000 --- a/louloulibs/utils/revstr.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include - -namespace utils -{ - std::string revstr(const std::string& original) - { - return {original.rbegin(), original.rend()}; - } -} diff --git a/louloulibs/utils/revstr.hpp b/louloulibs/utils/revstr.hpp deleted file mode 100644 index 8e521ea..0000000 --- a/louloulibs/utils/revstr.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - - -#include - -namespace utils -{ - std::string revstr(const std::string& original); -} - - diff --git a/louloulibs/utils/scopeguard.hpp b/louloulibs/utils/scopeguard.hpp deleted file mode 100644 index e697fc3..0000000 --- a/louloulibs/utils/scopeguard.hpp +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once - -#include -#include -#include - -/** - * A class to be used to make sure some functions are called when the scope - * is left, because they will be called in the ScopeGuard's destructor. It - * can for example be used to delete some pointer whenever any exception is - * called. Example: - - * { - * ScopeGuard scope; - * int* number = new int(2); - * scope.add_callback([number]() { delete number; }); - * // Do some other stuff with the number. But these stuff might throw an exception: - * throw std::runtime_error("Some error not caught here, but in our caller"); - * return true; - * } - - * In this example, our pointer will always be deleted, even when the - * exception is thrown. If we want the functions to be called only when the - * scope is left because of an unexpected exception, we can use - * ScopeGuard::disable(); - */ - -namespace utils -{ - -class ScopeGuard -{ -public: - /** - * The constructor can take a callback. But additional callbacks can be - * added later with add_callback() - */ - explicit ScopeGuard(std::function&& func): - enabled(true) - { - this->add_callback(std::move(func)); - } - - ScopeGuard(const ScopeGuard&) = delete; - ScopeGuard& operator=(ScopeGuard&&) = delete; - ScopeGuard(ScopeGuard&&) = delete; - ScopeGuard& operator=(const ScopeGuard&) = delete; - - /** - * default constructor, the scope guard is enabled but empty, use - * add_callback() - */ - explicit ScopeGuard(): - enabled(true) - { - } - /** - * Call all callbacks in the desctructor, unless it has been disabled. - */ - ~ScopeGuard() - { - if (this->enabled) - for (auto& func: this->callbacks) - func(); - } - /** - * Add a callback to be called in our destructor, one scope guard can be - * used for more than one task, if needed. - */ - void add_callback(std::function&& func) - { - this->callbacks.emplace_back(std::move(func)); - } - /** - * Disable that scope guard, nothing will be done when the scope is - * exited. - */ - void disable() - { - this->enabled = false; - } - -private: - bool enabled; - std::vector> callbacks; - -}; - -template -auto make_scope_guard(F f) -{ - static struct Empty {} empty; - auto deleter = [f = std::move(f)](Empty*) { f(); }; - return std::unique_ptr{&empty, std::move(deleter)}; -} - -} - diff --git a/louloulibs/utils/sha1.cpp b/louloulibs/utils/sha1.cpp deleted file mode 100644 index 71ad18d..0000000 --- a/louloulibs/utils/sha1.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include - -#include - -#ifdef BOTAN_FOUND -# include -# include -#endif -#ifdef GCRYPT_FOUND -# include -# include -# include -# include -#endif - -std::string sha1(const std::string& input) -{ -#ifdef BOTAN_FOUND - auto sha1 = Botan::HashFunction::create_or_throw("SHA-1"); - sha1->update(input); - return Botan::hex_encode(sha1->final(), false); -#endif -#ifdef GCRYPT_FOUND - const auto hash_length = gcry_md_get_algo_dlen(GCRY_MD_SHA1); - std::vector output(hash_length, {}); - gcry_md_hash_buffer(GCRY_MD_SHA1, output.data(), input.data(), input.size()); - std::ostringstream digest; - for (std::size_t i = 0; i < hash_length; i++) - digest << std::hex << std::setfill('0') << std::setw(2) << static_cast(output[i]); - return digest.str(); -#endif -} diff --git a/louloulibs/utils/sha1.hpp b/louloulibs/utils/sha1.hpp deleted file mode 100644 index 6c551ac..0000000 --- a/louloulibs/utils/sha1.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include - -std::string sha1(const std::string& input); diff --git a/louloulibs/utils/split.cpp b/louloulibs/utils/split.cpp deleted file mode 100644 index 80f8dae..0000000 --- a/louloulibs/utils/split.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include - -namespace utils -{ - std::vector split(const std::string& s, const char delim, const bool allow_empty) - { - std::vector ret; - std::stringstream ss(s); - std::string item; - while (std::getline(ss, item, delim)) - { - if (item.empty() && !allow_empty) - continue ; - ret.emplace_back(std::move(item)); - } - return ret; - } -} diff --git a/louloulibs/utils/split.hpp b/louloulibs/utils/split.hpp deleted file mode 100644 index 3755ef8..0000000 --- a/louloulibs/utils/split.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - - -#include -#include - -namespace utils -{ - std::vector split(const std::string &s, const char delim, const bool allow_empty=true); -} - - diff --git a/louloulibs/utils/string.cpp b/louloulibs/utils/string.cpp deleted file mode 100644 index 635e71a..0000000 --- a/louloulibs/utils/string.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include - -bool to_bool(const std::string& val) -{ - return (val == "1" || val == "true"); -} - -std::vector cut(const std::string& val, const std::size_t size) -{ - std::vector res; - std::string::size_type pos = 0; - while (pos < val.size()) - { - // Get the number of chars, <= size, that contain only whole - // UTF-8 codepoints. - std::size_t s = 0; - auto codepoint_size = utils::get_next_codepoint_size(val[pos + s]); - while (s + codepoint_size <= size && pos + s < val.size()) - { - s += codepoint_size; - codepoint_size = utils::get_next_codepoint_size(val[pos + s]); - } - res.emplace_back(val.substr(pos, s)); - pos += s; - } - return res; -} diff --git a/louloulibs/utils/string.hpp b/louloulibs/utils/string.hpp deleted file mode 100644 index 84ba101..0000000 --- a/louloulibs/utils/string.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - - -#include -#include - -bool to_bool(const std::string& val); -std::vector cut(const std::string& val, const std::size_t size); - - diff --git a/louloulibs/utils/system.cpp b/louloulibs/utils/system.cpp deleted file mode 100644 index c0bee11..0000000 --- a/louloulibs/utils/system.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include -#include - -using namespace std::string_literals; - -namespace utils -{ -std::string get_system_name() -{ - struct utsname uts; - const int res = ::uname(&uts); - if (res == -1) - { - log_error("uname failed: ", std::strerror(errno)); - return "Unknown"; - } - return uts.sysname + " "s + uts.release; -} -} \ No newline at end of file diff --git a/louloulibs/utils/system.hpp b/louloulibs/utils/system.hpp deleted file mode 100644 index 7ea1677..0000000 --- a/louloulibs/utils/system.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -namespace utils -{ -std::string get_system_name(); -} \ No newline at end of file diff --git a/louloulibs/utils/time.cpp b/louloulibs/utils/time.cpp deleted file mode 100644 index e9f3943..0000000 --- a/louloulibs/utils/time.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include -#include - -#include -#include -#include - -#include "louloulibs.h" - -namespace utils -{ -std::string to_string(const std::time_t& timestamp) -{ - constexpr std::size_t stamp_size = 21; - char date_buf[stamp_size]; - if (std::strftime(date_buf, stamp_size, "%FT%TZ", std::gmtime(×tamp)) != stamp_size - 1) - return ""; - return {std::begin(date_buf), std::end(date_buf) - 1}; -} - -std::time_t parse_datetime(const std::string& stamp) -{ - static const char* format = "%Y-%m-%dT%H:%M:%S"; - std::tm t = {}; -#ifdef HAS_GET_TIME - std::istringstream ss(stamp); - ss.imbue(std::locale("C")); - - std::string timezone; - ss >> std::get_time(&t, format) >> timezone; - if (ss.fail()) - return -1; -#else - /* Y - m - d T H : M : S */ - constexpr std::size_t stamp_size_without_tz = 4 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2; - if (!strptime(stamp.data(), format, &t)) { - return -1; - } - const std::string timezone(stamp.data() + stamp_size_without_tz); -#endif - - if (timezone.empty()) - return -1; - - if (timezone.compare(0, 1, "Z") != 0) - { - std::stringstream tz_ss; - tz_ss << timezone; - int multiplier = -1; - char prefix; - int hours; - char sep; - int minutes; - tz_ss >> prefix >> hours >> sep >> minutes; - if (tz_ss.fail()) - return -1; - if (prefix == '-') - multiplier = +1; - else if (prefix != '+') - return -1; - - t.tm_hour += multiplier * hours; - t.tm_min += multiplier * minutes; - } - return ::timegm(&t); -} - -} - - diff --git a/louloulibs/utils/time.hpp b/louloulibs/utils/time.hpp deleted file mode 100644 index c71cd9c..0000000 --- a/louloulibs/utils/time.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include -#include - -namespace utils -{ -std::string to_string(const std::time_t& timestamp); -std::time_t parse_datetime(const std::string& stamp); -} \ No newline at end of file diff --git a/louloulibs/utils/timed_events.cpp b/louloulibs/utils/timed_events.cpp deleted file mode 100644 index 5077199..0000000 --- a/louloulibs/utils/timed_events.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include - -TimedEvent::TimedEvent(std::chrono::steady_clock::time_point&& time_point, - std::function callback, const std::string& name): - time_point(std::move(time_point)), - callback(callback), - repeat(false), - repeat_delay(0), - name(name) -{ -} - -TimedEvent::TimedEvent(std::chrono::milliseconds&& duration, - std::function callback, const std::string& name): - time_point(std::chrono::steady_clock::now() + duration), - callback(callback), - repeat(true), - repeat_delay(std::move(duration)), - name(name) -{ -} - -bool TimedEvent::is_after(const TimedEvent& other) const -{ - return this->is_after(other.time_point); -} - -bool TimedEvent::is_after(const std::chrono::steady_clock::time_point& time_point) const -{ - return this->time_point > time_point; -} - -std::chrono::milliseconds TimedEvent::get_timeout() const -{ - auto diff = std::chrono::duration_cast(this->time_point - std::chrono::steady_clock::now()); - return std::max(diff, 0ms); -} - -void TimedEvent::execute() const -{ - this->callback(); -} - -const std::string& TimedEvent::get_name() const -{ - return this->name; -} diff --git a/louloulibs/utils/timed_events.hpp b/louloulibs/utils/timed_events.hpp deleted file mode 100644 index 6e28206..0000000 --- a/louloulibs/utils/timed_events.hpp +++ /dev/null @@ -1,132 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -using namespace std::literals::chrono_literals; - -namespace utils { -static constexpr std::chrono::milliseconds no_timeout = std::chrono::milliseconds(-1); -} - -class TimedEventsManager; - -/** - * A callback with an associated date. - */ - -class TimedEvent -{ - friend class TimedEventsManager; -public: - /** - * An event the occurs only once, at the given time_point - */ - explicit TimedEvent(std::chrono::steady_clock::time_point&& time_point, - std::function callback, const std::string& name=""); - explicit TimedEvent(std::chrono::milliseconds&& duration, - std::function callback, const std::string& name=""); - - explicit TimedEvent(TimedEvent&&) = default; - TimedEvent& operator=(TimedEvent&&) = default; - ~TimedEvent() = default; - - TimedEvent(const TimedEvent&) = delete; - TimedEvent& operator=(const TimedEvent&) = delete; - - /** - * Whether or not this event happens after the other one. - */ - bool is_after(const TimedEvent& other) const; - bool is_after(const std::chrono::steady_clock::time_point& time_point) const; - /** - * Return the duration difference between now and the event time point. - * If the difference would be negative (i.e. the event is expired), the - * returned value is 0 instead. The value cannot then be negative. - */ - std::chrono::milliseconds get_timeout() const; - void execute() const; - const std::string& get_name() const; - -private: - /** - * The next time point at which the event is executed. - */ - std::chrono::steady_clock::time_point time_point; - /** - * The function to execute. - */ - std::function callback; - /** - * Whether or not this events repeats itself until it is destroyed. - */ - bool repeat; - /** - * This value is added to the time_point each time the event is executed, - * if repeat is true. Otherwise it is ignored. - */ - std::chrono::milliseconds repeat_delay; - /** - * A name that is used to identify that event. If you want to find your - * event (for example if you want to cancel it), the name should be - * unique. - */ - std::string name; -}; - -/** - * A class managing a list of TimedEvents. - * They are sorted, new events can be added, removed, fetch, etc. - */ - -class TimedEventsManager -{ -public: - ~TimedEventsManager() = default; - - TimedEventsManager(const TimedEventsManager&) = delete; - TimedEventsManager(TimedEventsManager&&) = delete; - TimedEventsManager& operator=(const TimedEventsManager&) = delete; - TimedEventsManager& operator=(TimedEventsManager&&) = delete; - - /** - * Return the unique instance of this class - */ - static TimedEventsManager& instance(); - /** - * Add an event to the list of managed events. The list is sorted after - * this call. - */ - void add_event(TimedEvent&& event); - /** - * Returns the duration, in milliseconds, between now and the next - * available event. If the event is already expired (the duration is - * negative), 0 is returned instead (as in “it's not too late, execute it - * now”) - * Returns a negative value if no event is available. - */ - std::chrono::milliseconds get_timeout() const; - /** - * Execute all the expired events (if their expiration time is exactly - * now, or before now). The event is then removed from the list. If the - * event does repeat, its expiration time is updated and it is reinserted - * in the list at the correct position. - * Returns the number of executed events. - */ - std::size_t execute_expired_events(); - /** - * Remove (and thus cancel) all the timed events with the given name. - * Returns the number of canceled events. - */ - std::size_t cancel(const std::string& name); - /** - * Return the number of managed events. - */ - std::size_t size() const; - -private: - std::vector events; - explicit TimedEventsManager() = default; -}; diff --git a/louloulibs/utils/timed_events_manager.cpp b/louloulibs/utils/timed_events_manager.cpp deleted file mode 100644 index 67d61fe..0000000 --- a/louloulibs/utils/timed_events_manager.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include - -TimedEventsManager& TimedEventsManager::instance() -{ - static TimedEventsManager inst; - return inst; -} - -void TimedEventsManager::add_event(TimedEvent&& event) -{ - for (auto it = this->events.begin(); it != this->events.end(); ++it) - { - if (it->is_after(event)) - { - this->events.emplace(it, std::move(event)); - return; - } - } - this->events.emplace_back(std::move(event)); -} - -std::chrono::milliseconds TimedEventsManager::get_timeout() const -{ - if (this->events.empty()) - return utils::no_timeout; - return this->events.front().get_timeout(); -} - -std::size_t TimedEventsManager::execute_expired_events() -{ - std::size_t count = 0; - const auto now = std::chrono::steady_clock::now(); - for (auto it = this->events.begin(); it != this->events.end();) - { - if (!it->is_after(now)) - { - TimedEvent copy(std::move(*it)); - it = this->events.erase(it); - ++count; - copy.execute(); - if (copy.repeat) - { - copy.time_point += copy.repeat_delay; - this->add_event(std::move(copy)); - } - continue; - } - else - break; - } - return count; -} - -std::size_t TimedEventsManager::cancel(const std::string& name) -{ - std::size_t res = 0; - for (auto it = this->events.begin(); it != this->events.end();) - { - if (it->get_name() == name) - { - it = this->events.erase(it); - res++; - } - else - ++it; - } - return res; -} - -std::size_t TimedEventsManager::size() const -{ - return this->events.size(); -} diff --git a/louloulibs/utils/tolower.cpp b/louloulibs/utils/tolower.cpp deleted file mode 100644 index 3e518bd..0000000 --- a/louloulibs/utils/tolower.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include - -namespace utils -{ - std::string tolower(const std::string& original) - { - std::string res; - res.reserve(original.size()); - for (const char c: original) - res += static_cast(std::tolower(c)); - return res; - } -} diff --git a/louloulibs/utils/tolower.hpp b/louloulibs/utils/tolower.hpp deleted file mode 100644 index 650e05d..0000000 --- a/louloulibs/utils/tolower.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - - -#include - -namespace utils -{ - std::string tolower(const std::string& original); -} - - diff --git a/louloulibs/utils/xdg.cpp b/louloulibs/utils/xdg.cpp deleted file mode 100644 index 48212a1..0000000 --- a/louloulibs/utils/xdg.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include - -#include "louloulibs.h" - -std::string xdg_path(const std::string& filename, const char* env_var) -{ - const char* xdg_home = ::getenv(env_var); - if (xdg_home && xdg_home[0] == '/') - return std::string{xdg_home} + "/" PROJECT_NAME "/" + filename; - else - { - const char* home = ::getenv("HOME"); - if (home) - return std::string{home} + "/" ".config" "/" PROJECT_NAME "/" + filename; - else - return filename; - } -} - -std::string xdg_config_path(const std::string& filename) -{ - return xdg_path(filename, "XDG_CONFIG_HOME"); -} - -std::string xdg_data_path(const std::string& filename) -{ - return xdg_path(filename, "XDG_DATA_HOME"); -} diff --git a/louloulibs/utils/xdg.hpp b/louloulibs/utils/xdg.hpp deleted file mode 100644 index 56e11da..0000000 --- a/louloulibs/utils/xdg.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - - -#include - -/** - * Returns a path for the given filename, according to the XDG base - * directory specification, see - * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html - */ -std::string xdg_config_path(const std::string& filename); -std::string xdg_data_path(const std::string& filename); - - diff --git a/louloulibs/xmpp/adhoc_command.cpp b/louloulibs/xmpp/adhoc_command.cpp deleted file mode 100644 index 825cc92..0000000 --- a/louloulibs/xmpp/adhoc_command.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include -#include -#include - -using namespace std::string_literals; - -AdhocCommand::AdhocCommand(std::vector&& callbacks, const std::string& name, const bool admin_only): - name(name), - callbacks(std::move(callbacks)), - admin_only(admin_only) -{ -} - -bool AdhocCommand::is_admin_only() const -{ - return this->admin_only; -} - -void PingStep1(XmppComponent&, AdhocSession&, XmlNode& command_node) -{ - XmlSubNode note(command_node, "note"); - note["type"] = "info"; - note.set_inner("Pong"); -} - -void HelloStep1(XmppComponent&, AdhocSession&, XmlNode& command_node) -{ - XmlSubNode x(command_node, "jabber:x:data:x"); - x["type"] = "form"; - XmlSubNode title(x, "title"); - title.set_inner("Configure your name."); - XmlSubNode instructions(x, "instructions"); - instructions.set_inner("Please provide your name."); - XmlSubNode name_field(x, "field"); - name_field["var"] = "name"; - name_field["type"] = "text-single"; - name_field["label"] = "Your name"; - XmlSubNode required(name_field, "required"); -} - -void HelloStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node) -{ - // Find out if the name was provided in the form. - if (const XmlNode* x = command_node.get_child("x", "jabber:x:data")) - { - const XmlNode* name_field = nullptr; - for (const XmlNode* field: x->get_children("field", "jabber:x:data")) - if (field->get_tag("var") == "name") - { - name_field = field; - break; - } - if (name_field) - { - if (const XmlNode* value = name_field->get_child("value", "jabber:x:data")) - { - const std::string value_str = value->get_inner(); - command_node.delete_all_children(); - XmlSubNode note(command_node, "note"); - note["type"] = "info"; - note.set_inner("Hello "s + value_str + "!"s); - return; - } - } - } - command_node.delete_all_children(); - XmlSubNode error(command_node, ADHOC_NS":error"); - error["type"] = "modify"; - XmlSubNode condition(error, STANZA_NS":bad-request"); - session.terminate(); -} - -void Reload(XmppComponent&, AdhocSession&, XmlNode& command_node) -{ - ::reload_process(); - command_node.delete_all_children(); - XmlSubNode note(command_node, "note"); - note["type"] = "info"; - note.set_inner("Configuration reloaded."); -} diff --git a/louloulibs/xmpp/adhoc_command.hpp b/louloulibs/xmpp/adhoc_command.hpp deleted file mode 100644 index 7c4de47..0000000 --- a/louloulibs/xmpp/adhoc_command.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -/** - * Describe an ad-hoc command. - * - * Can only have zero or one step for now. When execution is requested, it - * can return a result immediately, or provide a form to be filled, and - * provide a result once the filled form is received. - */ - -#include - -#include -#include - -class AdhocCommand -{ - friend class AdhocSession; -public: - AdhocCommand(std::vector&& callback, const std::string& name, const bool admin_only); - ~AdhocCommand() = default; - AdhocCommand(const AdhocCommand&) = default; - AdhocCommand(AdhocCommand&&) = default; - AdhocCommand& operator=(AdhocCommand&&) = delete; - AdhocCommand& operator=(const AdhocCommand&) = delete; - - const std::string name; - - bool is_admin_only() const; - -private: - /** - * A command may have one or more steps. Each step is a different - * callback, inserting things into a XmlNode and calling - * methods of an AdhocSession. - */ - std::vector callbacks; - const bool admin_only; -}; - -void PingStep1(XmppComponent&, AdhocSession& session, XmlNode& command_node); -void HelloStep1(XmppComponent&, AdhocSession& session, XmlNode& command_node); -void HelloStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node); -void Reload(XmppComponent&, AdhocSession& session, XmlNode& command_node); diff --git a/louloulibs/xmpp/adhoc_commands_handler.cpp b/louloulibs/xmpp/adhoc_commands_handler.cpp deleted file mode 100644 index 040d0ff..0000000 --- a/louloulibs/xmpp/adhoc_commands_handler.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include -#include - -#include -#include -#include -#include - -#include - -using namespace std::string_literals; - -const std::map& AdhocCommandsHandler::get_commands() const -{ - return this->commands; -} - -void AdhocCommandsHandler::add_command(std::string name, AdhocCommand command) -{ - const auto found = this->commands.find(name); - if (found != this->commands.end()) - throw std::runtime_error("Trying to add an ad-hoc command that already exist: "s + name); - this->commands.emplace(std::make_pair(std::move(name), std::move(command))); -} - -XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, const std::string& to, XmlNode command_node) -{ - std::string action = command_node.get_tag("action"); - if (action.empty()) - action = "execute"; - command_node.del_tag("action"); - - Jid jid(executor_jid); - - const std::string node = command_node.get_tag("node"); - auto command_it = this->commands.find(node); - if (command_it == this->commands.end()) - { - XmlSubNode error(command_node, ADHOC_NS":error"); - error["type"] = "cancel"; - XmlSubNode condition(error, STANZA_NS":item-not-found"); - } - else if (command_it->second.is_admin_only() && - Config::get("admin", "") != jid.local + "@" + jid.domain) - { - XmlSubNode error(command_node, ADHOC_NS":error"); - error["type"] = "cancel"; - XmlSubNode condition(error, STANZA_NS":forbidden"); - } - else - { - std::string sessionid = command_node.get_tag("sessionid"); - if (sessionid.empty()) - { // create a new session, with a new id - sessionid = XmppComponent::next_id(); - command_node["sessionid"] = sessionid; - this->sessions.emplace(std::piecewise_construct, - std::forward_as_tuple(sessionid, executor_jid), - std::forward_as_tuple(command_it->second, executor_jid, to)); - TimedEventsManager::instance().add_event(TimedEvent(std::chrono::steady_clock::now() + 3600s, - std::bind(&AdhocCommandsHandler::remove_session, this, sessionid, executor_jid), - "adhocsession"s + sessionid + executor_jid)); - } - auto session_it = this->sessions.find(std::make_pair(sessionid, executor_jid)); - if ((session_it != this->sessions.end()) && - (action == "execute" || action == "next" || action == "complete")) - { - // execute the step - AdhocSession& session = session_it->second; - const AdhocStep& step = session.get_next_step(); - step(this->xmpp_component, session, command_node); - if (session.remaining_steps() == 0 || - session.is_terminated()) - { - this->sessions.erase(session_it); - command_node["status"] = "completed"; - TimedEventsManager::instance().cancel("adhocsession"s + sessionid + executor_jid); - } - else - { - command_node["status"] = "executing"; - XmlSubNode actions(command_node, "actions"); - XmlSubNode next(actions, "next"); - } - } - else if (action == "cancel") - { - this->sessions.erase(session_it); - command_node["status"] = "canceled"; - TimedEventsManager::instance().cancel("adhocsession"s + sessionid + executor_jid); - } - else // unsupported action - { - XmlSubNode error(command_node, ADHOC_NS":error"); - error["type"] = "modify"; - XmlSubNode condition(error, STANZA_NS":bad-request"); - } - } - return command_node; -} - -void AdhocCommandsHandler::remove_session(const std::string& session_id, const std::string& initiator_jid) -{ - auto session_it = this->sessions.find(std::make_pair(session_id, initiator_jid)); - if (session_it != this->sessions.end()) - { - this->sessions.erase(session_it); - return ; - } - log_error("Tried to remove ad-hoc session for [", session_id, ", ", initiator_jid, "] but none found"); -} diff --git a/louloulibs/xmpp/adhoc_commands_handler.hpp b/louloulibs/xmpp/adhoc_commands_handler.hpp deleted file mode 100644 index e37d913..0000000 --- a/louloulibs/xmpp/adhoc_commands_handler.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - -/** - * Manage a list of available AdhocCommands and the list of ongoing - * AdhocCommandSessions. - */ - -#include -#include - -#include -#include -#include - -class AdhocCommandsHandler -{ -public: - explicit AdhocCommandsHandler(XmppComponent& xmpp_component): - xmpp_component(xmpp_component), - commands{} - { } - ~AdhocCommandsHandler() = default; - - AdhocCommandsHandler(const AdhocCommandsHandler&) = delete; - AdhocCommandsHandler(AdhocCommandsHandler&&) = delete; - AdhocCommandsHandler& operator=(const AdhocCommandsHandler&) = delete; - AdhocCommandsHandler& operator=(AdhocCommandsHandler&&) = delete; - - /** - * Returns the list of available commands. - */ - const std::map& get_commands() const; - /** - * Add a command into the list, associated with the given name - */ - void add_command(std::string name, AdhocCommand command); - /** - * Find the requested command, create a new session or use an existing - * one, and process the request (provide a new form, an error, or a - * result). - * - * Returns a (moved) XmlNode that will be inserted in the iq response. It - * should be a node containing one or more useful children. If - * it contains an node, the iq response will have an error type. - * - * Takes a copy of the node so we can actually edit it and use - * it as our return value. - */ - XmlNode handle_request(const std::string& executor_jid, const std::string& to, XmlNode command_node); - /** - * Remove the session from the list. This is done to avoid filling the - * memory with waiting session (for example due to a client that starts - * multi-steps command but never finishes them). - */ - void remove_session(const std::string& session_id, const std::string& initiator_jid); -private: - /** - * To access basically anything in the gateway. - */ - XmppComponent& xmpp_component; - /** - * The list of all available commands. - */ - std::map commands; - /** - * The list of all currently on-going commands. - * - * Of the form: {{session_id, owner_jid}, session}. - */ - std::map, AdhocSession> sessions; -}; diff --git a/louloulibs/xmpp/adhoc_session.cpp b/louloulibs/xmpp/adhoc_session.cpp deleted file mode 100644 index dda4bea..0000000 --- a/louloulibs/xmpp/adhoc_session.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include - -#include - -AdhocSession::AdhocSession(const AdhocCommand& command, const std::string& owner_jid, - const std::string& to_jid): - command(command), - owner_jid(owner_jid), - to_jid(to_jid), - current_step(0), - terminated(false) -{ -} - -const AdhocStep& AdhocSession::get_next_step() -{ - assert(this->current_step < this->command.callbacks.size()); - return this->command.callbacks[this->current_step++]; -} - -size_t AdhocSession::remaining_steps() const -{ - return this->command.callbacks.size() - this->current_step; -} - -bool AdhocSession::is_terminated() const -{ - return this->terminated; -} - -void AdhocSession::terminate() -{ - this->terminated = true; -} diff --git a/louloulibs/xmpp/adhoc_session.hpp b/louloulibs/xmpp/adhoc_session.hpp deleted file mode 100644 index 0de8d13..0000000 --- a/louloulibs/xmpp/adhoc_session.hpp +++ /dev/null @@ -1,88 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -class XmppComponent; - -class AdhocCommand; -class AdhocSession; - -/** - * A function executed as an ad-hoc command step. It takes a - * XmlNode and modifies it accordingly (inserting for example an - * node, or a data form…). - */ -using AdhocStep = std::function; - -class AdhocSession -{ -public: - explicit AdhocSession(const AdhocCommand& command, const std::string& owner_jid, - const std::string& to_jid); - ~AdhocSession() = default; - - AdhocSession(const AdhocSession&) = delete; - AdhocSession(AdhocSession&&) = delete; - AdhocSession& operator=(const AdhocSession&) = delete; - AdhocSession& operator=(AdhocSession&&) = delete; - - /** - * Return the function to be executed, found in our AdhocCommand, for the - * current_step. And increment the current_step. - */ - const AdhocStep& get_next_step(); - /** - * Return the number of remaining steps. - */ - size_t remaining_steps() const; - /** - * This may be modified by an AdhocStep, to indicate that this session - * should no longer exist, because we encountered an error, and we can't - * execute any more step of it. - */ - void terminate(); - bool is_terminated() const; - std::string get_target_jid() const - { - return this->to_jid; - } - std::string get_owner_jid() const - { - return this->owner_jid; - } - -private: - /** - * A reference of the command concerned by this session. Used for example - * to get the next step of that command, things like that. - */ - const AdhocCommand& command; - /** - * The full JID of the XMPP user that created this session by executing - * the first step of a command. Only that JID must be allowed to access - * this session. - */ - const std::string& owner_jid; - /** - * The 'to' attribute in the request stanza. This is the target of the current session. - */ - const std::string& to_jid; - /** - * The current step we are at. It starts at zero. It is used to index the - * associated AdhocCommand::callbacks vector. - */ - size_t current_step; - bool terminated; - -public: - /** - * A map to store various things that we may want to remember between two - * steps of the same session. A step can insert any value associated to - * any key in there. - */ - std::map vars; -}; diff --git a/louloulibs/xmpp/auth.cpp b/louloulibs/xmpp/auth.cpp deleted file mode 100644 index 8a34a4e..0000000 --- a/louloulibs/xmpp/auth.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include - -#include - -std::string get_handshake_digest(const std::string& stream_id, const std::string& secret) -{ - return sha1(stream_id + secret); -} diff --git a/louloulibs/xmpp/auth.hpp b/louloulibs/xmpp/auth.hpp deleted file mode 100644 index 34a2116..0000000 --- a/louloulibs/xmpp/auth.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include - -std::string get_handshake_digest(const std::string& stream_id, const std::string& secret); - diff --git a/louloulibs/xmpp/body.hpp b/louloulibs/xmpp/body.hpp deleted file mode 100644 index 068d1a4..0000000 --- a/louloulibs/xmpp/body.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - - -namespace Xmpp -{ -// Contains: -// - an XMPP-valid UTF-8 body -// - an XML node representing the XHTML-IM body, or null - using body = std::tuple>; -} - - diff --git a/louloulibs/xmpp/jid.cpp b/louloulibs/xmpp/jid.cpp deleted file mode 100644 index 46e01ea..0000000 --- a/louloulibs/xmpp/jid.cpp +++ /dev/null @@ -1,153 +0,0 @@ -#include -#include -#include -#include - -#include -#ifdef LIBIDN_FOUND - #include - #include - #include - #include - #include - #include -#endif - -#include - -Jid::Jid(const std::string& jid) -{ - std::string::size_type slash = jid.find('/'); - if (slash != std::string::npos) - { - this->resource = jid.substr(slash + 1); - } - - std::string::size_type at = jid.find('@'); - if (at != std::string::npos && at < slash) - { - this->local = jid.substr(0, at); - at++; - } - else - at = 0; - - this->domain = jid.substr(at, slash - at); -} - -static constexpr size_t max_jid_part_len = 1023; - -std::string jidprep(const std::string& original) -{ -#ifdef LIBIDN_FOUND - using CacheType = std::map; - static CacheType cache; - std::pair cached = cache.insert({original, {}}); - if (std::get<1>(cached) == false) - { // Insertion failed: the result is already in the cache, return it - return std::get<0>(cached)->second; - } - - const std::string error_msg("Failed to convert " + original + " into a valid JID:"); - Jid jid(original); - - char local[max_jid_part_len] = {}; - memcpy(local, jid.local.data(), std::min(max_jid_part_len, jid.local.size())); - Stringprep_rc rc = static_cast(::stringprep(local, max_jid_part_len, - static_cast(0), stringprep_xmpp_nodeprep)); - if (rc != STRINGPREP_OK) - { - log_error(error_msg + stringprep_strerror(rc)); - return ""; - } - - char domain[max_jid_part_len] = {}; - memcpy(domain, jid.domain.data(), std::min(max_jid_part_len, jid.domain.size())); - - { - // Using getaddrinfo, check if the domain part is a valid IPv4 (then use - // it as is), or IPv6 (surround it with []), or a domain name (run - // nameprep) - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_NUMERICHOST; - hints.ai_family = AF_UNSPEC; - - struct addrinfo* addr_res = nullptr; - const auto ret = ::getaddrinfo(domain, nullptr, &hints, &addr_res); - auto addrinfo_deleter = utils::make_scope_guard([addr_res] { if (addr_res) freeaddrinfo(addr_res); }); - if (ret || !addr_res || (addr_res->ai_family != AF_INET && addr_res->ai_family != AF_INET6)) - { // Not an IP, run nameprep on it - rc = static_cast(::stringprep(domain, max_jid_part_len, - static_cast(0), stringprep_nameprep)); - if (rc != STRINGPREP_OK) - { - log_error(error_msg + stringprep_strerror(rc)); - return ""; - } - - // Make sure it contains only allowed characters - using std::begin; - using std::end; - char* domain_end = domain + ::strlen(domain); - std::replace_if(std::begin(domain), domain + ::strlen(domain), - [](const char c) -> bool - { - return !((c >= 'a' && c <= 'z') || c == '-' || - (c >= '0' && c <= '9') || c == '.'); - }, '-'); - // Make sure there are no doubled - or . - std::set special_chars{'-', '.'}; - domain_end = std::unique(begin(domain), domain + ::strlen(domain), [&special_chars](const char& a, const char& b) -> bool - { - return special_chars.count(a) && special_chars.count(b); - }); - // remove leading and trailing -. if any - if (domain_end != domain && special_chars.count(*(domain_end - 1))) - --domain_end; - if (domain_end != domain && special_chars.count(domain[0])) - { - std::memmove(domain, domain + 1, domain_end - domain + 1); - --domain_end; - } - // And if the final result is an empty string, return a dummy hostname - if (domain_end == domain) - ::strcpy(domain, "empty"); - else - *domain_end = '\0'; - } - else if (addr_res->ai_family == AF_INET6) - { // IPv6, surround it with []. The length is always enough: - // the longest possible IPv6 is way shorter than max_jid_part_len - ::memmove(domain + 1, domain, jid.domain.size()); - domain[0] = '['; - domain[jid.domain.size() + 1] = ']'; - } - } - - - // If there is no resource, stop here - if (jid.resource.empty()) - { - std::get<0>(cached)->second = std::string(local) + "@" + domain; - return std::get<0>(cached)->second; - } - - // Otherwise, also process the resource part - char resource[max_jid_part_len] = {}; - memcpy(resource, jid.resource.data(), std::min(max_jid_part_len, jid.resource.size())); - rc = static_cast(::stringprep(resource, max_jid_part_len, - static_cast(0), stringprep_xmpp_resourceprep)); - if (rc != STRINGPREP_OK) - { - log_error(error_msg + stringprep_strerror(rc)); - return ""; - } - std::get<0>(cached)->second = std::string(local) + "@" + domain + "/" + resource; - return std::get<0>(cached)->second; - -#else - (void)original; - return ""; -#endif -} diff --git a/louloulibs/xmpp/jid.hpp b/louloulibs/xmpp/jid.hpp deleted file mode 100644 index 85e835c..0000000 --- a/louloulibs/xmpp/jid.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - - -#include - -/** - * Parse a JID into its different subart - */ -class Jid -{ -public: - explicit Jid(const std::string& jid); - - Jid(const Jid&) = delete; - Jid(Jid&&) = delete; - Jid& operator=(const Jid&) = delete; - Jid& operator=(Jid&&) = delete; - - std::string domain; - std::string local; - std::string resource; - - std::string bare() const - { - return this->local + "@" + this->domain; - } - std::string full() const - { - std::string res = this->domain; - if (!this->local.empty()) - res = this->local + "@" + this->domain; - if (!this->resource.empty()) - res += "/" + this->resource; - return res; - } -}; - -/** - * Prepare the given UTF-8 string according to the XMPP node stringprep - * identifier profile. This is used to send properly-formed JID to the XMPP - * server. - * - * If the stringprep library is not found, we return an empty string. When - * this function is used, the result must always be checked for an empty - * value, and if this is the case it must not be used as a JID. - */ -std::string jidprep(const std::string& original); - - diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp deleted file mode 100644 index 5d98e58..0000000 --- a/louloulibs/xmpp/xmpp_component.cpp +++ /dev/null @@ -1,672 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include - -#include -#ifdef SYSTEMD_FOUND -# include -#endif - -using namespace std::string_literals; - -static std::set kickable_errors{ - "gone", - "internal-server-error", - "item-not-found", - "jid-malformed", - "recipient-unavailable", - "redirect", - "remote-server-not-found", - "remote-server-timeout", - "service-unavailable", - "malformed-error" - }; - -XmppComponent::XmppComponent(std::shared_ptr& poller, const std::string& hostname, const std::string& secret): - TCPClientSocketHandler(poller), - ever_auth(false), - first_connection_try(true), - secret(secret), - authenticated(false), - doc_open(false), - served_hostname(hostname), - stanza_handlers{}, - adhoc_commands_handler(*this) -{ - this->parser.add_stream_open_callback(std::bind(&XmppComponent::on_remote_stream_open, this, - std::placeholders::_1)); - this->parser.add_stanza_callback(std::bind(&XmppComponent::on_stanza, this, - std::placeholders::_1)); - this->parser.add_stream_close_callback(std::bind(&XmppComponent::on_remote_stream_close, this, - std::placeholders::_1)); - this->stanza_handlers.emplace("handshake", - std::bind(&XmppComponent::handle_handshake, this,std::placeholders::_1)); - this->stanza_handlers.emplace("error", - std::bind(&XmppComponent::handle_error, this,std::placeholders::_1)); -} - -void XmppComponent::start() -{ - this->connect(Config::get("xmpp_server_ip", "127.0.0.1"), Config::get("port", "5347"), false); -} - -bool XmppComponent::is_document_open() const -{ - return this->doc_open; -} - -void XmppComponent::send_stanza(const Stanza& stanza) -{ - std::string str = stanza.to_string(); - log_debug("XMPP SENDING: ", str); - this->send_data(std::move(str)); -} - -void XmppComponent::on_connection_failed(const std::string& reason) -{ - this->first_connection_try = false; - log_error("Failed to connect to the XMPP server: ", reason); -#ifdef SYSTEMD_FOUND - sd_notifyf(0, "STATUS=Failed to connect to the XMPP server: %s", reason.data()); -#endif -} - -void XmppComponent::on_connected() -{ - log_info("connected to XMPP server"); - this->first_connection_try = true; - auto data = ""; - log_debug("XMPP SENDING: ", data); - this->send_data(std::move(data)); - this->doc_open = true; - // We may have some pending data to send: this happens when we try to send - // some data before we are actually connected. We send that data right now, if any - this->send_pending_data(); -} - -void XmppComponent::on_connection_close(const std::string& error) -{ - if (error.empty()) - log_info("XMPP server closed connection"); - else - log_info("XMPP server closed connection: ", error); -} - -void XmppComponent::parse_in_buffer(const size_t size) -{ - if (!this->in_buf.empty()) - { // This may happen if the parser could not allocate enough space for - // us. We try to feed it the data that was read into our in_buf - // instead. If this fails again we are in trouble. - this->parser.feed(this->in_buf.data(), this->in_buf.size(), false); - this->in_buf.clear(); - } - else - { // Just tell the parser to parse the data that was placed into the - // buffer it provided to us with GetBuffer - this->parser.parse(size, false); - } -} - -void XmppComponent::on_remote_stream_open(const XmlNode& node) -{ - log_debug("XMPP RECEIVING: ", node.to_string()); - this->stream_id = node.get_tag("id"); - if (this->stream_id.empty()) - { - log_error("Error: no attribute 'id' found"); - this->send_stream_error("bad-format", "missing 'id' attribute"); - this->close_document(); - return ; - } - - // Try to authenticate - auto data = ""s + get_handshake_digest(this->stream_id, this->secret) + ""; - log_debug("XMPP SENDING: ", data); - this->send_data(std::move(data)); -} - -void XmppComponent::on_remote_stream_close(const XmlNode& node) -{ - log_debug("XMPP RECEIVING: ", node.to_string()); - this->doc_open = false; -} - -void XmppComponent::reset() -{ - this->parser.reset(); -} - -void XmppComponent::on_stanza(const Stanza& stanza) -{ - log_debug("XMPP RECEIVING: ", stanza.to_string()); - std::function handler; - try - { - handler = this->stanza_handlers.at(stanza.get_name()); - } - catch (const std::out_of_range& exception) - { - log_warning("No handler for stanza of type ", stanza.get_name()); - return; - } - handler(stanza); -} - -void XmppComponent::send_stream_error(const std::string& name, const std::string& explanation) -{ - Stanza node("stream:error"); - { - XmlSubNode error(node, name); - error["xmlns"] = STREAM_NS; - if (!explanation.empty()) - error.set_inner(explanation); - } - this->send_stanza(node); -} - -void XmppComponent::send_stanza_error(const std::string& kind, const std::string& to, const std::string& from, - const std::string& id, const std::string& error_type, - const std::string& defined_condition, const std::string& text, - const bool fulljid) -{ - Stanza node(kind); - { - if (!to.empty()) - node["to"] = to; - if (!from.empty()) - { - if (fulljid) - node["from"] = from; - else - node["from"] = from + "@" + this->served_hostname; - } - if (!id.empty()) - node["id"] = id; - node["type"] = "error"; - { - XmlSubNode error(node, "error"); - error["type"] = error_type; - { - XmlSubNode inner_error(error, defined_condition); - inner_error["xmlns"] = STANZA_NS; - } - if (!text.empty()) - { - XmlSubNode text_node(error, "text"); - text_node["xmlns"] = STANZA_NS; - text_node.set_inner(text); - } - } - } - this->send_stanza(node); -} - -void XmppComponent::close_document() -{ - log_debug("XMPP SENDING: "); - this->send_data(""); - this->doc_open = false; -} - -void XmppComponent::handle_handshake(const Stanza&) -{ - this->authenticated = true; - this->ever_auth = true; - log_info("Authenticated with the XMPP server"); -#ifdef SYSTEMD_FOUND - sd_notify(0, "READY=1"); - // Install an event that sends a keepalive to systemd. If biboumi crashes - // or hangs for too long, systemd will restart it. - uint64_t usec; - if (sd_watchdog_enabled(0, &usec) > 0) - { - TimedEventsManager::instance().add_event(TimedEvent( - std::chrono::duration_cast(std::chrono::microseconds(usec / 2)), - []() { sd_notify(0, "WATCHDOG=1"); })); - } -#endif - this->after_handshake(); -} - -void XmppComponent::handle_error(const Stanza& stanza) -{ - const XmlNode* text = stanza.get_child("text", STREAMS_NS); - std::string error_message("Unspecified error"); - if (text) - error_message = text->get_inner(); - log_error("Stream error received from the XMPP server: ", error_message); -#ifdef SYSTEMD_FOUND - if (!this->ever_auth) - sd_notifyf(0, "STATUS=Failed to authenticate to the XMPP server: %s", error_message.data()); -#endif - -} - -void* XmppComponent::get_receive_buffer(const size_t size) const -{ - return this->parser.get_buffer(size); -} - -void XmppComponent::send_message(const std::string& from, Xmpp::body&& body, const std::string& to, - const std::string& type, const bool fulljid, const bool nocopy) -{ - Stanza message("message"); - { - message["to"] = to; - if (fulljid) - message["from"] = from; - else - message["from"] = from + "@" + this->served_hostname; - if (!type.empty()) - message["type"] = type; - XmlSubNode body_node(message, "body"); - body_node.set_inner(std::get<0>(body)); - if (std::get<1>(body)) - { - XmlSubNode html(message, "html"); - html["xmlns"] = XHTMLIM_NS; - // Pass the ownership of the pointer to this xmlnode - html.add_child(std::move(std::get<1>(body))); - } - if (nocopy) - { - XmlSubNode private_node(message, "private"); - private_node["xmlns"] = "urn:xmpp:carbons:2"; - XmlSubNode nocopy(message, "no-copy"); - nocopy["xmlns"] = "urn:xmpp:hints"; - } - } - this->send_stanza(message); -} - -void XmppComponent::send_user_join(const std::string& from, - const std::string& nick, - const std::string& realjid, - const std::string& affiliation, - const std::string& role, - const std::string& to, - const bool self) -{ - Stanza presence("presence"); - { - presence["to"] = to; - presence["from"] = from + "@" + this->served_hostname + "/" + nick; - - XmlSubNode x(presence, "x"); - x["xmlns"] = MUC_USER_NS; - - XmlSubNode item(x, "item"); - if (!affiliation.empty()) - item["affiliation"] = affiliation; - if (!role.empty()) - item["role"] = role; - if (!realjid.empty()) - { - const std::string preped_jid = jidprep(realjid); - if (!preped_jid.empty()) - item["jid"] = preped_jid; - } - - if (self) - { - XmlSubNode status(x, "status"); - status["code"] = "110"; - } - } - this->send_stanza(presence); -} - -void XmppComponent::send_invalid_room_error(const std::string& muc_name, - const std::string& nick, - const std::string& to) -{ - Stanza presence("presence"); - { - if (!muc_name.empty ()) - presence["from"] = muc_name + "@" + this->served_hostname + "/" + nick; - else - presence["from"] = this->served_hostname; - presence["to"] = to; - presence["type"] = "error"; - XmlSubNode x(presence, "x"); - x["xmlns"] = MUC_NS; - XmlSubNode error(presence, "error"); - error["by"] = muc_name + "@" + this->served_hostname; - error["type"] = "cancel"; - XmlSubNode item_not_found(error, "item-not-found"); - item_not_found["xmlns"] = STANZA_NS; - XmlSubNode text(error, "text"); - text["xmlns"] = STANZA_NS; - text["xml:lang"] = "en"; - text.set_inner(muc_name + - " is not a valid IRC channel name. A correct room jid is of the form: #%@" + - this->served_hostname); - } - this->send_stanza(presence); -} - -void XmppComponent::send_topic(const std::string& from, Xmpp::body&& topic, const std::string& to, const std::string& who) -{ - Stanza message("message"); - { - message["to"] = to; - if (who.empty()) - message["from"] = from + "@" + this->served_hostname; - else - message["from"] = from + "@" + this->served_hostname + "/" + who; - message["type"] = "groupchat"; - XmlSubNode subject(message, "subject"); - subject.set_inner(std::get<0>(topic)); - } - this->send_stanza(message); -} - -void XmppComponent::send_muc_message(const std::string& muc_name, const std::string& nick, Xmpp::body&& xmpp_body, const std::string& jid_to) -{ - Stanza message("message"); - message["to"] = jid_to; - if (!nick.empty()) - message["from"] = muc_name + "@" + this->served_hostname + "/" + nick; - else // Message from the room itself - message["from"] = muc_name + "@" + this->served_hostname; - message["type"] = "groupchat"; - - { - XmlSubNode body(message, "body"); - body.set_inner(std::get<0>(xmpp_body)); - } - - if (std::get<1>(xmpp_body)) - { - XmlSubNode html(message, "html"); - html["xmlns"] = XHTMLIM_NS; - // Pass the ownership of the pointer to this xmlnode - html.add_child(std::move(std::get<1>(xmpp_body))); - } - this->send_stanza(message); -} - -void XmppComponent::send_history_message(const std::string& muc_name, const std::string& nick, const std::string& body_txt, const std::string& jid_to, std::time_t timestamp) -{ - Stanza message("message"); - message["to"] = jid_to; - if (!nick.empty()) - message["from"] = muc_name + "@" + this->served_hostname + "/" + nick; - else - message["from"] = muc_name + "@" + this->served_hostname; - message["type"] = "groupchat"; - - { - XmlSubNode body(message, "body"); - body.set_inner(body_txt); - } - { - XmlSubNode delay(message, "delay"); - delay["xmlns"] = DELAY_NS; - delay["from"] = muc_name + "@" + this->served_hostname; - delay["stamp"] = utils::to_string(timestamp); - } - - this->send_stanza(message); -} - -void XmppComponent::send_muc_leave(const std::string& muc_name, std::string&& nick, Xmpp::body&& message, const std::string& jid_to, const bool self) -{ - Stanza presence("presence"); - { - presence["to"] = jid_to; - presence["from"] = muc_name + "@" + this->served_hostname + "/" + nick; - presence["type"] = "unavailable"; - const std::string message_str = std::get<0>(message); - XmlSubNode x(presence, "x"); - x["xmlns"] = MUC_USER_NS; - if (self) - { - XmlSubNode status(x, "status"); - status["code"] = "110"; - } - if (!message_str.empty()) - { - XmlSubNode status(presence, "status"); - status.set_inner(message_str); - } - } - this->send_stanza(presence); -} - -void XmppComponent::send_nick_change(const std::string& muc_name, - const std::string& old_nick, - const std::string& new_nick, - const std::string& affiliation, - const std::string& role, - const std::string& jid_to, - const bool self) -{ - Stanza presence("presence"); - { - presence["to"] = jid_to; - presence["from"] = muc_name + "@" + this->served_hostname + "/" + old_nick; - presence["type"] = "unavailable"; - XmlSubNode x(presence, "x"); - x["xmlns"] = MUC_USER_NS; - XmlSubNode item(x, "item"); - item["nick"] = new_nick; - XmlSubNode status(x, "status"); - status["code"] = "303"; - if (self) - { - XmlSubNode status(x, "status"); - status["code"] = "110"; - } - } - this->send_stanza(presence); - - this->send_user_join(muc_name, new_nick, "", affiliation, role, jid_to, self); -} - -void XmppComponent::kick_user(const std::string& muc_name, const std::string& target, const std::string& txt, - const std::string& author, const std::string& jid_to, const bool self) -{ - Stanza presence("presence"); - { - presence["from"] = muc_name + "@" + this->served_hostname + "/" + target; - presence["to"] = jid_to; - presence["type"] = "unavailable"; - XmlSubNode x(presence, "x"); - x["xmlns"] = MUC_USER_NS; - XmlSubNode item(x, "item"); - item["affiliation"] = "none"; - item["role"] = "none"; - XmlSubNode actor(item, "actor"); - actor["nick"] = author; - actor["jid"] = author; // backward compatibility with old clients - XmlSubNode reason(item, "reason"); - reason.set_inner(txt); - XmlSubNode status(x, "status"); - status["code"] = "307"; - if (self) - { - XmlSubNode status(x, "status"); - status["code"] = "110"; - } - } - this->send_stanza(presence); -} - -void XmppComponent::send_presence_error(const std::string& muc_name, - const std::string& nickname, - const std::string& jid_to, - const std::string& type, - const std::string& condition, - const std::string& error_code, - const std::string& text) -{ - Stanza presence("presence"); - { - presence["from"] = muc_name + "@" + this->served_hostname + "/" + nickname; - presence["to"] = jid_to; - presence["type"] = "error"; - XmlSubNode x(presence, "x"); - x["xmlns"] = MUC_NS; - XmlSubNode error(presence, "error"); - error["by"] = muc_name + "@" + this->served_hostname; - error["type"] = type; - if (!text.empty()) - { - XmlSubNode text_node(error, "text"); - text_node["xmlns"] = STANZA_NS; - text_node.set_inner(text); - } - if (!error_code.empty()) - error["code"] = error_code; - XmlSubNode subnode(error, condition); - subnode["xmlns"] = STANZA_NS; - } - this->send_stanza(presence); -} - -void XmppComponent::send_affiliation_role_change(const std::string& muc_name, - const std::string& target, - const std::string& affiliation, - const std::string& role, - const std::string& jid_to) -{ - Stanza presence("presence"); - { - presence["from"] = muc_name + "@" + this->served_hostname + "/" + target; - presence["to"] = jid_to; - XmlSubNode x(presence, "x"); - x["xmlns"] = MUC_USER_NS; - XmlSubNode item(x, "item"); - item["affiliation"] = affiliation; - item["role"] = role; - } - this->send_stanza(presence); -} - -void XmppComponent::send_version(const std::string& id, const std::string& jid_to, const std::string& jid_from, - const std::string& version) -{ - Stanza iq("iq"); - iq["type"] = "result"; - iq["id"] = id; - iq["to"] = jid_to; - iq["from"] = jid_from; - { - XmlSubNode query(iq, "query"); - query["xmlns"] = VERSION_NS; - if (version.empty()) - { - { - XmlSubNode name(query, "name"); - name.set_inner("biboumi"); - } - { - XmlSubNode version(query, "version"); - version.set_inner(SOFTWARE_VERSION); - } - { - XmlSubNode os(query, "os"); - os.set_inner(utils::get_system_name()); - } - } - else - { - XmlSubNode name(query, "name"); - name.set_inner(version); - } - } - this->send_stanza(iq); -} - -void XmppComponent::send_adhoc_commands_list(const std::string& id, const std::string& requester_jid, - const std::string& from_jid, - const bool with_admin_only, const AdhocCommandsHandler& adhoc_handler) -{ - Stanza iq("iq"); - { - iq["type"] = "result"; - iq["id"] = id; - iq["to"] = requester_jid; - iq["from"] = from_jid; - XmlSubNode query(iq, "query"); - query["xmlns"] = DISCO_ITEMS_NS; - query["node"] = ADHOC_NS; - for (const auto &kv: adhoc_handler.get_commands()) - { - if (kv.second.is_admin_only() && !with_admin_only) - continue; - XmlSubNode item(query, "item"); - item["jid"] = from_jid; - item["node"] = kv.first; - item["name"] = kv.second.name; - } - } - this->send_stanza(iq); -} - -void XmppComponent::send_iq_version_request(const std::string& from, - const std::string& jid_to) -{ - Stanza iq("iq"); - { - iq["type"] = "get"; - iq["id"] = "version_"s + XmppComponent::next_id(); - iq["from"] = from + "@" + this->served_hostname; - iq["to"] = jid_to; - XmlSubNode query(iq, "query"); - query["xmlns"] = VERSION_NS; - } - this->send_stanza(iq); -} - -void XmppComponent::send_iq_result_full_jid(const std::string& id, const std::string& to_jid, const std::string& from_full_jid) -{ - Stanza iq("iq"); - iq["from"] = from_full_jid; - iq["to"] = to_jid; - iq["id"] = id; - iq["type"] = "result"; - this->send_stanza(iq); -} - -void XmppComponent::send_iq_result(const std::string& id, const std::string& to_jid, const std::string& from_local_part) -{ - Stanza iq("iq"); - if (!from_local_part.empty()) - iq["from"] = from_local_part + "@" + this->served_hostname; - else - iq["from"] = this->served_hostname; - iq["to"] = to_jid; - iq["id"] = id; - iq["type"] = "result"; - this->send_stanza(iq); -} - -std::string XmppComponent::next_id() -{ - char uuid_str[37]; - uuid_t uuid; - uuid_generate(uuid); - uuid_unparse(uuid, uuid_str); - return uuid_str; -} diff --git a/louloulibs/xmpp/xmpp_component.hpp b/louloulibs/xmpp/xmpp_component.hpp deleted file mode 100644 index 16d7480..0000000 --- a/louloulibs/xmpp/xmpp_component.hpp +++ /dev/null @@ -1,245 +0,0 @@ -#pragma once - - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define STREAM_NS "http://etherx.jabber.org/streams" -#define COMPONENT_NS "jabber:component:accept" -#define MUC_NS "http://jabber.org/protocol/muc" -#define MUC_USER_NS MUC_NS"#user" -#define MUC_ADMIN_NS MUC_NS"#admin" -#define DISCO_NS "http://jabber.org/protocol/disco" -#define DISCO_ITEMS_NS DISCO_NS"#items" -#define DISCO_INFO_NS DISCO_NS"#info" -#define XHTMLIM_NS "http://jabber.org/protocol/xhtml-im" -#define STANZA_NS "urn:ietf:params:xml:ns:xmpp-stanzas" -#define STREAMS_NS "urn:ietf:params:xml:ns:xmpp-streams" -#define VERSION_NS "jabber:iq:version" -#define ADHOC_NS "http://jabber.org/protocol/commands" -#define PING_NS "urn:xmpp:ping" -#define DELAY_NS "urn:xmpp:delay" -#define MAM_NS "urn:xmpp:mam:1" -#define FORWARD_NS "urn:xmpp:forward:0" -#define CLIENT_NS "jabber:client" -#define DATAFORM_NS "jabber:x:data" -#define RSM_NS "http://jabber.org/protocol/rsm" -#define MUC_TRAFFIC_NS "http://jabber.org/protocol/muc#traffic" - -/** - * An XMPP component, communicating with an XMPP server using the protocole - * described in XEP-0114: Jabber Component Protocol - * - * TODO: implement XEP-0225: Component Connections - */ -class XmppComponent: public TCPClientSocketHandler -{ -public: - explicit XmppComponent(std::shared_ptr& poller, const std::string& hostname, const std::string& secret); - virtual ~XmppComponent() = default; - - XmppComponent(const XmppComponent&) = delete; - XmppComponent(XmppComponent&&) = delete; - XmppComponent& operator=(const XmppComponent&) = delete; - XmppComponent& operator=(XmppComponent&&) = delete; - - void on_connection_failed(const std::string& reason) override final; - void on_connected() override final; - void on_connection_close(const std::string& error) override final; - void parse_in_buffer(const size_t size) override final; - - /** - * Returns a unique id, to be used in the 'id' element of our iq stanzas. - */ - static std::string next_id(); - bool is_document_open() const; - /** - * Connect to the XMPP server. - */ - void start(); - /** - * Reset the component so we can use the component on a new XMPP stream - */ - void reset(); - /** - * Serialize the stanza and add it to the out_buf to be sent to the - * server. - */ - void send_stanza(const Stanza& stanza); - /** - * Handle the opening of the remote stream - */ - void on_remote_stream_open(const XmlNode& node); - /** - * Handle the closing of the remote stream - */ - void on_remote_stream_close(const XmlNode& node); - /** - * Handle received stanzas - */ - void on_stanza(const Stanza& stanza); - /** - * Send an error stanza. Message being the name of the element inside the - * stanza, and explanation being a short human-readable sentence - * describing the error. - */ - void send_stream_error(const std::string& message, const std::string& explanation); - /** - * Send error stanza, described in http://xmpp.org/rfcs/rfc6120.html#stanzas-error - */ - void send_stanza_error(const std::string& kind, const std::string& to, const std::string& from, - const std::string& id, const std::string& error_type, - const std::string& defined_condition, const std::string& text, - const bool fulljid=true); - /** - * Send the closing signal for our document (not closing the connection though). - */ - void close_document(); - /** - * Send a message from from@served_hostname, with the given body - * - * If fulljid is false, the provided 'from' doesn't contain the - * server-part of the JID and must be added. - */ - void send_message(const std::string& from, Xmpp::body&& body, const std::string& to, - const std::string& type, const bool fulljid, const bool nocopy=false); - /** - * Send a join from a new participant - */ - void send_user_join(const std::string& from, - const std::string& nick, - const std::string& realjid, - const std::string& affiliation, - const std::string& role, - const std::string& to, - const bool self); - /** - * Send an error to indicate that the user tried to join an invalid room - */ - void send_invalid_room_error(const std::string& muc_jid, - const std::string& nick, - const std::string& to); - /** - * Send the MUC topic to the user - */ - void send_topic(const std::string& from, Xmpp::body&& xmpp_topic, const std::string& to, const std::string& who); - /** - * Send a (non-private) message to the MUC - */ - void send_muc_message(const std::string& muc_name, const std::string& nick, Xmpp::body&& body, const std::string& jid_to); - /** - * Send a message, with a element, part of a MUC history - */ - void send_history_message(const std::string& muc_name, const std::string& nick, const std::string& body, - const std::string& jid_to, const std::time_t timestamp); - /** - * Send an unavailable presence for this nick - */ - void send_muc_leave(const std::string& muc_name, std::string&& nick, Xmpp::body&& message, const std::string& jid_to, const bool self); - /** - * Indicate that a participant changed his nick - */ - void send_nick_change(const std::string& muc_name, - const std::string& old_nick, - const std::string& new_nick, - const std::string& affiliation, - const std::string& role, - const std::string& jid_to, - const bool self); - /** - * An user is kicked from a room - */ - void kick_user(const std::string& muc_name, const std::string& target, const std::string& reason, - const std::string& author, const std::string& jid_to, const bool self); - /** - * Send a generic presence error - */ - void send_presence_error(const std::string& muc_name, - const std::string& nickname, - const std::string& jid_to, - const std::string& type, - const std::string& condition, - const std::string& error_code, - const std::string& text); - /** - * Send a presence from the MUC indicating a change in the role and/or - * affiliation of a participant - */ - void send_affiliation_role_change(const std::string& muc_name, - const std::string& target, - const std::string& affiliation, - const std::string& role, - const std::string& jid_to); - /** - * Send a result IQ with the given version, or the gateway version if the - * passed string is empty. - */ - void send_version(const std::string& id, const std::string& jid_to, const std::string& jid_from, - const std::string& version=""); - /** - * Send the list of all available ad-hoc commands to that JID. The list is - * different depending on what JID made the request. - */ - void send_adhoc_commands_list(const std::string& id, const std::string& requester_jid, const std::string& from_jid, - const bool with_admin_only, const AdhocCommandsHandler& adhoc_handler); - /** - * Send an iq version request - */ - void send_iq_version_request(const std::string& from, - const std::string& jid_to); - /** - * Send an empty iq of type result - */ - void send_iq_result(const std::string& id, const std::string& to_jid, const std::string& from); - void send_iq_result_full_jid(const std::string& id, const std::string& to_jid, - const std::string& from_full_jid); - - void handle_handshake(const Stanza& stanza); - void handle_error(const Stanza& stanza); - - virtual void after_handshake() {} - - const std::string& get_served_hostname() const - { return this->served_hostname; } - - /** - * Whether or not we ever succeeded our authentication to the XMPP server - */ - bool ever_auth; - /** - * Whether or not this is the first consecutive try on connecting to the - * XMPP server. We use this to delay the connection attempt for a few - * seconds, if it is not the first try. - */ - bool first_connection_try; - -private: - /** - * Return a buffer provided by the XML parser, to read data directly into - * it, and avoiding some unnecessary copy. - */ - void* get_receive_buffer(const size_t size) const override final; - XmppParser parser; - std::string stream_id; - std::string secret; - bool authenticated; - /** - * Whether or not OUR XMPP document is open - */ - bool doc_open; -protected: - std::string served_hostname; - - std::unordered_map> stanza_handlers; - AdhocCommandsHandler adhoc_commands_handler; -}; - - diff --git a/louloulibs/xmpp/xmpp_parser.cpp b/louloulibs/xmpp/xmpp_parser.cpp deleted file mode 100644 index 0488be9..0000000 --- a/louloulibs/xmpp/xmpp_parser.cpp +++ /dev/null @@ -1,172 +0,0 @@ -#include -#include - -#include - -/** - * Expat handlers. Called by the Expat library, never by ourself. - * They just forward the call to the XmppParser corresponding methods. - */ - -static void start_element_handler(void* user_data, const XML_Char* name, const XML_Char** atts) -{ - static_cast(user_data)->start_element(name, atts); -} - -static void end_element_handler(void* user_data, const XML_Char* name) -{ - static_cast(user_data)->end_element(name); -} - -static void character_data_handler(void *user_data, const XML_Char *s, int len) -{ - static_cast(user_data)->char_data(s, len); -} - -/** - * XmppParser class - */ - -XmppParser::XmppParser(): - level(0), - current_node(nullptr), - root(nullptr) -{ - this->init_xml_parser(); -} - -void XmppParser::init_xml_parser() -{ - // Create the expat parser - this->parser = XML_ParserCreateNS("UTF-8", ':'); - XML_SetUserData(this->parser, static_cast(this)); - - // Install Expat handlers - XML_SetElementHandler(this->parser, &start_element_handler, &end_element_handler); - XML_SetCharacterDataHandler(this->parser, &character_data_handler); -} - -XmppParser::~XmppParser() -{ - XML_ParserFree(this->parser); -} - -int XmppParser::feed(const char* data, const int len, const bool is_final) -{ - int res = XML_Parse(this->parser, data, len, is_final); - if (res == XML_STATUS_ERROR && - (XML_GetErrorCode(this->parser) != XML_ERROR_FINISHED)) - log_error("Xml_Parse encountered an error: ", - XML_ErrorString(XML_GetErrorCode(this->parser))); - return res; -} - -int XmppParser::parse(const int len, const bool is_final) -{ - int res = XML_ParseBuffer(this->parser, len, is_final); - if (res == XML_STATUS_ERROR) - log_error("Xml_Parsebuffer encountered an error: ", - XML_ErrorString(XML_GetErrorCode(this->parser))); - return res; -} - -void XmppParser::reset() -{ - XML_ParserFree(this->parser); - this->init_xml_parser(); - this->current_node = nullptr; - this->root.reset(nullptr); - this->level = 0; -} - -void* XmppParser::get_buffer(const size_t size) const -{ - return XML_GetBuffer(this->parser, static_cast(size)); -} - -void XmppParser::start_element(const XML_Char* name, const XML_Char** attribute) -{ - this->level++; - - auto new_node = std::make_unique(name, this->current_node); - auto new_node_ptr = new_node.get(); - if (this->current_node) - this->current_node->add_child(std::move(new_node)); - else - this->root = std::move(new_node); - this->current_node = new_node_ptr; - for (size_t i = 0; attribute[i]; i += 2) - this->current_node->set_attribute(attribute[i], attribute[i+1]); - if (this->level == 1) - this->stream_open_event(*this->current_node); -} - -void XmppParser::end_element(const XML_Char*) -{ - this->level--; - if (this->level == 0) - { // End of the whole stream - this->stream_close_event(*this->current_node); - this->current_node = nullptr; - this->root.reset(); - } - else - { - auto parent = this->current_node->get_parent(); - if (this->level == 1) - { // End of a stanza - this->stanza_event(*this->current_node); - // Note: deleting all the children of our parent deletes ourself, - // so current_node is an invalid pointer after this line - parent->delete_all_children(); - } - this->current_node = parent; - } -} - -void XmppParser::char_data(const XML_Char* data, const size_t len) -{ - if (this->current_node->has_children()) - this->current_node->get_last_child()->add_to_tail({data, len}); - else - this->current_node->add_to_inner({data, len}); -} - -void XmppParser::stanza_event(const Stanza& stanza) const -{ - for (const auto& callback: this->stanza_callbacks) - { - try { - callback(stanza); - } catch (const std::exception& e) { - log_error("Unhandled exception: ", e.what()); - } - } -} - -void XmppParser::stream_open_event(const XmlNode& node) const -{ - for (const auto& callback: this->stream_open_callbacks) - callback(node); -} - -void XmppParser::stream_close_event(const XmlNode& node) const -{ - for (const auto& callback: this->stream_close_callbacks) - callback(node); -} - -void XmppParser::add_stanza_callback(std::function&& callback) -{ - this->stanza_callbacks.emplace_back(std::move(callback)); -} - -void XmppParser::add_stream_open_callback(std::function&& callback) -{ - this->stream_open_callbacks.emplace_back(std::move(callback)); -} - -void XmppParser::add_stream_close_callback(std::function&& callback) -{ - this->stream_close_callbacks.emplace_back(std::move(callback)); -} diff --git a/louloulibs/xmpp/xmpp_parser.hpp b/louloulibs/xmpp/xmpp_parser.hpp deleted file mode 100644 index 9d67228..0000000 --- a/louloulibs/xmpp/xmpp_parser.hpp +++ /dev/null @@ -1,133 +0,0 @@ -#pragma once - - -#include - -#include - -#include - -/** - * A SAX XML parser that builds XML nodes and spawns events when a complete - * stanza is received (an element of level 2), or when the document is - * opened/closed (an element of level 1) - * - * After a stanza_event has been spawned, we delete the whole stanza. This - * means that even with a very long document (in XMPP the document is - * potentially infinite), the memory is never exhausted as long as each - * stanza is reasonnably short. - * - * The element names generated by expat contain the namespace of the - * element, a colon (':') and then the actual name of the element. To get - * an element "x" with a namespace of "http://jabber.org/protocol/muc", you - * just look for an XmlNode named "http://jabber.org/protocol/muc:x" - * - * TODO: enforce the size-limit for the stanza (limit the number of childs - * it can contain). For example forbid the parser going further than level - * 20 (arbitrary number here), and each XML node to have more than 15 childs - * (arbitrary number again). - */ -class XmppParser -{ -public: - explicit XmppParser(); - ~XmppParser(); - XmppParser(const XmppParser&) = delete; - XmppParser& operator=(const XmppParser&) = delete; - XmppParser(XmppParser&&) = delete; - XmppParser& operator=(XmppParser&&) = delete; - -public: - /** - * Feed the parser with some XML data - */ - int feed(const char* data, const int len, const bool is_final); - /** - * Parse the data placed in the parser buffer - */ - int parse(const int size, const bool is_final); - /** - * Reset the parser, so it can be used from scratch afterward - */ - void reset(); - /** - * Get a buffer provided by the xml parser. - */ - void* get_buffer(const size_t size) const; - /** - * Add one callback for the various events that this parser can spawn. - */ - void add_stanza_callback(std::function&& callback); - void add_stream_open_callback(std::function&& callback); - void add_stream_close_callback(std::function&& callback); - - /** - * Called when a new XML element has been opened. We instanciate a new - * XmlNode and set it as our current node. The parent of this new node is - * the previous "current" node. We have all the element's attributes in - * this event. - * - * We spawn a stream_event with this node if this is a level-1 element. - */ - void start_element(const XML_Char* name, const XML_Char** attribute); - /** - * Called when an XML element has been closed. We close the current_node, - * set our current_node as the parent of the current_node, and if that was - * a level-2 element we spawn a stanza_event with this node. - * - * And we then delete the stanza (and everything under it, its children, - * attribute, etc). - */ - void end_element(const XML_Char* name); - /** - * Some inner or tail data has been parsed - */ - void char_data(const XML_Char* data, const size_t len); - /** - * Calls all the stanza_callbacks one by one. - */ - void stanza_event(const Stanza& stanza) const; - /** - * Calls all the stream_open_callbacks one by one. Note: the passed node is not - * closed yet. - */ - void stream_open_event(const XmlNode& node) const; - /** - * Calls all the stream_close_callbacks one by one. - */ - void stream_close_event(const XmlNode& node) const; - -private: - /** - * Init the XML parser and install the callbacks - */ - void init_xml_parser(); - - /** - * Expat structure. - */ - XML_Parser parser; - /** - * The current depth in the XML document - */ - size_t level; - /** - * The deepest XML node opened but not yet closed (to which we are adding - * new children, inner or tail) - */ - XmlNode* current_node; - /** - * The root node has no parent, so we keep it here: the XmppParser object - * is its owner. - */ - std::unique_ptr root; - /** - * A list of callbacks to be called on an *_event, receiving the - * concerned Stanza/XmlNode. - */ - std::vector> stanza_callbacks; - std::vector> stream_open_callbacks; - std::vector> stream_close_callbacks; -}; - - diff --git a/louloulibs/xmpp/xmpp_stanza.cpp b/louloulibs/xmpp/xmpp_stanza.cpp deleted file mode 100644 index ac6ce9b..0000000 --- a/louloulibs/xmpp/xmpp_stanza.cpp +++ /dev/null @@ -1,229 +0,0 @@ -#include - -#include -#include - -#include -#include -#include - -#include - -std::string xml_escape(const std::string& data) -{ - std::string res; - res.reserve(data.size()); - for (size_t pos = 0; pos != data.size(); ++pos) - { - switch(data[pos]) - { - case '&': - res += "&"; - break; - case '<': - res += "<"; - break; - case '>': - res += ">"; - break; - case '\"': - res += """; - break; - case '\'': - res += "'"; - break; - default: - res += data[pos]; - break; - } - } - return res; -} - -std::string sanitize(const std::string& data, const std::string& encoding) -{ - if (utils::is_valid_utf8(data.data())) - return xml_escape(utils::remove_invalid_xml_chars(data)); - else - return xml_escape(utils::remove_invalid_xml_chars(utils::convert_to_utf8(data, encoding.data()))); -} - -XmlNode::XmlNode(const std::string& name, XmlNode* parent): - parent(parent) -{ - // split the namespace and the name - auto n = name.rfind(":"); - if (n == std::string::npos) - this->name = name; - else - { - this->name = name.substr(n+1); - this->attributes["xmlns"] = name.substr(0, n); - } -} - -XmlNode::XmlNode(const std::string& name): - XmlNode(name, nullptr) -{ -} - -void XmlNode::delete_all_children() -{ - this->children.clear(); -} - -void XmlNode::set_attribute(const std::string& name, const std::string& value) -{ - this->attributes[name] = value; -} - -void XmlNode::set_tail(const std::string& data) -{ - this->tail = data; -} - -void XmlNode::add_to_tail(const std::string& data) -{ - this->tail += data; -} - -void XmlNode::set_inner(const std::string& data) -{ - this->inner = data; -} - -void XmlNode::add_to_inner(const std::string& data) -{ - this->inner += data; -} - -std::string XmlNode::get_inner() const -{ - return this->inner; -} - -std::string XmlNode::get_tail() const -{ - return this->tail; -} - -const XmlNode* XmlNode::get_child(const std::string& name, const std::string& xmlns) const -{ - for (const auto& child: this->children) - { - if (child->name == name && child->get_tag("xmlns") == xmlns) - return child.get(); - } - return nullptr; -} - -std::vector XmlNode::get_children(const std::string& name, const std::string& xmlns) const -{ - std::vector res; - for (const auto& child: this->children) - { - if (child->name == name && child->get_tag("xmlns") == xmlns) - res.push_back(child.get()); - } - return res; -} - -XmlNode* XmlNode::add_child(std::unique_ptr child) -{ - child->parent = this; - auto ret = child.get(); - this->children.push_back(std::move(child)); - return ret; -} - -XmlNode* XmlNode::add_child(XmlNode&& child) -{ - auto new_node = std::make_unique(std::move(child)); - return this->add_child(std::move(new_node)); -} - -XmlNode* XmlNode::add_child(const XmlNode& child) -{ - auto new_node = std::make_unique(child); - return this->add_child(std::move(new_node)); -} - -XmlNode* XmlNode::get_last_child() const -{ - return this->children.back().get(); -} - -XmlNode* XmlNode::get_parent() const -{ - return this->parent; -} - -void XmlNode::set_name(const std::string& name) -{ - this->name = name; -} - -void XmlNode::set_name(std::string&& name) -{ - this->name = std::move(name); -} - -const std::string XmlNode::get_name() const -{ - return this->name; -} - -std::string XmlNode::to_string() const -{ - std::ostringstream res; - res << "<" << this->name; - for (const auto& it: this->attributes) - res << " " << it.first << "='" << sanitize(it.second) + "'"; - if (!this->has_children() && this->inner.empty()) - res << "/>"; - else - { - res << ">" + sanitize(this->inner); - for (const auto& child: this->children) - res << child->to_string(); - res << "get_name() << ">"; - } - res << sanitize(this->tail); - return res.str(); -} - -bool XmlNode::has_children() const -{ - return !this->children.empty(); -} - -const std::string& XmlNode::get_tag(const std::string& name) const -{ - try - { - const auto& value = this->attributes.at(name); - return value; - } - catch (const std::out_of_range& e) - { - static const std::string def{}; - return def; - } -} - -bool XmlNode::del_tag(const std::string& name) -{ - if (this->attributes.erase(name) != 0) - return true; - return false; -} - -std::string& XmlNode::operator[](const std::string& name) -{ - return this->attributes[name]; -} - -std::ostream& operator<<(std::ostream& os, const XmlNode& node) -{ - return os << node.to_string(); -} diff --git a/louloulibs/xmpp/xmpp_stanza.hpp b/louloulibs/xmpp/xmpp_stanza.hpp deleted file mode 100644 index f4b3948..0000000 --- a/louloulibs/xmpp/xmpp_stanza.hpp +++ /dev/null @@ -1,160 +0,0 @@ -#pragma once - - -#include -#include -#include -#include - -std::string xml_escape(const std::string& data); -std::string xml_unescape(const std::string& data); -std::string sanitize(const std::string& data, const std::string& encoding = "ISO-8859-1"); - -/** - * Represent an XML node. It has - * - A parent XML node (in the case of the first-level nodes, the parent is - nullptr) - * - zero, one or more children XML nodes - * - A name - * - A map of attributes - * - inner data (text inside the node) - * - tail data (text just after the node) - */ -class XmlNode -{ -public: - explicit XmlNode(const std::string& name, XmlNode* parent); - explicit XmlNode(const std::string& name); - /** - * The copy constructor does not copy the parent attribute. The children - * nodes are all copied recursively. - */ - XmlNode(const XmlNode& node): - name(node.name), - parent(nullptr), - attributes(node.attributes), - children{}, - inner(node.inner), - tail(node.tail) - { - for (const auto& child: node.children) - this->add_child(std::make_unique(*child)); - } - - XmlNode(XmlNode&& node) = default; - XmlNode& operator=(const XmlNode&) = delete; - XmlNode& operator=(XmlNode&&) = delete; - - ~XmlNode() = default; - - void delete_all_children(); - void set_attribute(const std::string& name, const std::string& value); - /** - * Set the content of the tail, that is the text just after this node - */ - void set_tail(const std::string& data); - /** - * Append the given data to the content of the tail. This exists because - * the expat library may provide the complete text of an element in more - * than one call - */ - void add_to_tail(const std::string& data); - /** - * Set the content of the inner, that is the text inside this node. - */ - void set_inner(const std::string& data); - /** - * Append the given data to the content of the inner. For the reason - * described in add_to_tail comment. - */ - void add_to_inner(const std::string& data); - /** - * Get the content of inner - */ - std::string get_inner() const; - /** - * Get the content of the tail - */ - std::string get_tail() const; - /** - * Get a pointer to the first child element with that name and that xml namespace - */ - const XmlNode* get_child(const std::string& name, const std::string& xmlns) const; - /** - * Get a vector of all the children that have that name and that xml namespace. - */ - std::vector get_children(const std::string& name, const std::string& xmlns) const; - /** - * Add a node child to this node. Assign this node to the child’s parent. - * Returns a pointer to the newly added child. - */ - XmlNode* add_child(std::unique_ptr child); - XmlNode* add_child(XmlNode&& child); - XmlNode* add_child(const XmlNode& child); - /** - * Returns the last of the children. If the node doesn't have any child, - * the behaviour is undefined. The user should make sure this is the case - * by calling has_children() for example. - */ - XmlNode* get_last_child() const; - XmlNode* get_parent() const; - void set_name(const std::string& name); - void set_name(std::string&& name); - const std::string get_name() const; - /** - * Serialize the stanza into a string - */ - std::string to_string() const; - /** - * Whether or not this node has at least one child (if not, this is a leaf - * node) - */ - bool has_children() const; - /** - * Gets the value for the given attribute, returns an empty string if the - * node as no such attribute. - */ - const std::string& get_tag(const std::string& name) const; - /** - * Remove the attribute of the node. Does nothing if that attribute is not - * present. Returns true if the tag was removed, false if it was absent. - */ - bool del_tag(const std::string& name); - /** - * Use this to set an attribute's value, like node["id"] = "12"; - */ - std::string& operator[](const std::string& name); - -private: - std::string name; - XmlNode* parent; - std::map attributes; - std::vector> children; - std::string inner; - std::string tail; -}; - -std::ostream& operator<<(std::ostream& os, const XmlNode& node); - -/** - * An XMPP stanza is just an XML node of level 2 in the XMPP document (the - * level 1 ones are the , and the ones above 2 are just the - * content of the stanzas) - */ -using Stanza = XmlNode; - -class XmlSubNode: public XmlNode -{ -public: - XmlSubNode(XmlNode& parent_ref, const std::string& name): - XmlNode(name), - parent_to_add(parent_ref) - {} - - ~XmlSubNode() - { - this->parent_to_add.add_child(std::move(*this)); - } -private: - XmlNode& parent_to_add; -}; \ No newline at end of file -- cgit v1.2.3