diff options
-rw-r--r-- | src/irc/irc_client.cpp | 2 | ||||
-rw-r--r-- | src/irc/irc_client.hpp | 4 | ||||
-rw-r--r-- | src/main.cpp | 1 | ||||
-rw-r--r-- | src/network/socket_handler.hpp | 273 | ||||
-rw-r--r-- | src/network/tcp_socket_handler.cpp (renamed from src/network/socket_handler.cpp) | 76 | ||||
-rw-r--r-- | src/network/tcp_socket_handler.hpp | 261 | ||||
-rw-r--r-- | src/xmpp/xmpp_component.cpp | 2 | ||||
-rw-r--r-- | src/xmpp/xmpp_component.hpp | 4 |
8 files changed, 321 insertions, 302 deletions
diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index d179aaa..6468094 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -20,7 +20,7 @@ using namespace std::string_literals; using namespace std::chrono_literals; IrcClient::IrcClient(std::shared_ptr<Poller> poller, const std::string& hostname, const std::string& username, Bridge* bridge): - SocketHandler(poller), + TCPSocketHandler(poller), hostname(hostname), username(username), current_nick(username), diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 7dff1db..afa6437 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -5,7 +5,7 @@ #include <irc/irc_channel.hpp> #include <irc/iid.hpp> -#include <network/socket_handler.hpp> +#include <network/tcp_socket_handler.hpp> #include <unordered_map> #include <memory> @@ -21,7 +21,7 @@ class Bridge; * Represent one IRC client, i.e. an endpoint connected to a single IRC * server, through a TCP socket, receiving and sending commands to it. */ -class IrcClient: public SocketHandler +class IrcClient: public TCPSocketHandler { public: explicit IrcClient(std::shared_ptr<Poller> poller, const std::string& hostname, const std::string& username, Bridge* bridge); diff --git a/src/main.cpp b/src/main.cpp index 2e2f1b2..d9f6a9f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,3 +1,4 @@ +#include <network/tcp_socket_handler.hpp> #include <xmpp/xmpp_component.hpp> #include <utils/timed_events.hpp> #include <network/poller.hpp> diff --git a/src/network/socket_handler.hpp b/src/network/socket_handler.hpp index b4cb6f2..9a894a4 100644 --- a/src/network/socket_handler.hpp +++ b/src/network/socket_handler.hpp @@ -1,280 +1,43 @@ -#ifndef SOCKET_HANDLER_INCLUDED -# define SOCKET_HANDLER_INCLUDED +#ifndef SOCKET_HANDLER_HPP +# define SOCKET_HANDLER_HPP -#include <logger/logger.hpp> - -#include <sys/types.h> -#include <sys/socket.h> -#include <netdb.h> - -#include <utility> #include <memory> -#include <string> -#include <list> - -#include "config.h" -#ifdef BOTAN_FOUND -# include <botan/botan.h> -# include <botan/tls_client.h> - -/** - * A very simple credential manager that accepts any certificate. - */ -class Permissive_Credentials_Manager: public Botan::Credentials_Manager -{ -public: - void verify_certificate_chain(const std::string& type, const std::string& purported_hostname, const std::vector<Botan::X509_Certificate>&) - { // TODO: Offer the admin to disallow connection on untrusted - // certificates - log_debug("Checking remote certificate (" << type << ") for hostname " << purported_hostname); - } -}; -#endif // BOTAN_FOUND +class Poller; typedef int socket_t; -class Poller; - -/** - * 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) - */ class SocketHandler { -protected: - ~SocketHandler() {} - public: - explicit SocketHandler(std::shared_ptr<Poller> poller); - /** - * 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(); - /** - * 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(); - /** - * Write as much data from out_buf as possible, in the socket. - */ - void on_send(); - /** - * 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(); - /** - * Returns the socket that should be handled by the poller. - */ - socket_t get_socket() const; - /** - * 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() = 0; - /** - * 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. - */ - virtual void parse_in_buffer(const size_t size) = 0; - bool is_connected() const; - bool is_connecting() const; - -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 - * 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); - -#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(); - /** - * 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_data_cb(const Botan::byte* data, size_t size); - /** - * 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); - /** - * 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); - /** - * 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); - /** - * 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 - /** - * The handled socket. - */ - socket_t socket; - /** - * Where data is added, when we want to send something to the client. - */ - std::list<std::string> out_buf; - /** - * Keep the details of the addrinfo the triggered a EINPROGRESS error when - * connect()ing to it, to reuse it directly when connect() is called - * again. - */ - struct addrinfo addrinfo; - struct sockaddr ai_addr; - socklen_t ai_addrlen; + explicit SocketHandler(std::shared_ptr<Poller> poller, const socket_t socket): + poller(poller), + socket(socket) + {} + virtual ~SocketHandler() {} + virtual void on_recv() = 0; + virtual void on_send() = 0; + virtual void connect() = 0; + 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, sometimes (for example to tell it that he now needs to watch - * write events for us). Do not ever try to delete it. - * - * And a raw pointer because we are not owning it, it is owning us - * (actually it is sharing our ownership with a Bridge). + * with it. */ std::shared_ptr<Poller> poller; /** - * 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; - /** - * Whether we are using TLS on this connection or not. - */ - bool use_tls; - /** - * 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; - /** - * Hostname we are connected/connecting to - */ - std::string address; - /** - * Port we are connected/connecting to + * The handled socket. */ - std::string port; - - bool connected; - bool connecting; + socket_t socket; private: SocketHandler(const SocketHandler&) = delete; SocketHandler(SocketHandler&&) = delete; SocketHandler& operator=(const SocketHandler&) = delete; SocketHandler& operator=(SocketHandler&&) = delete; - -#ifdef BOTAN_FOUND - /** - * Botan stuff to manipulate a TLS session. - */ - static Botan::AutoSeeded_RNG rng; - static Permissive_Credentials_Manager credential_manager; - static Botan::TLS::Policy policy; - static Botan::TLS::Session_Manager_In_Memory session_manager; - /** - * 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 as - * soon and calls the output_fn callback with it as soon as it is - * created. Therefore, we do not want to create it if do not intend to do - * 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<Botan::TLS::Client> tls; - /** - * An additional buffer to keep data that the user wants to send, but - * cannot because the handshake is not done. - */ - std::string pre_buf; -#endif // BOTAN_FOUND }; -#endif // SOCKET_HANDLER_INCLUDED +#endif // SOCKET_HANDLER_HPP diff --git a/src/network/socket_handler.cpp b/src/network/tcp_socket_handler.cpp index 52297e4..d9432a6 100644 --- a/src/network/socket_handler.cpp +++ b/src/network/tcp_socket_handler.cpp @@ -1,4 +1,4 @@ -#include <network/socket_handler.hpp> +#include <network/tcp_socket_handler.hpp> #include <utils/timed_events.hpp> #include <utils/scopeguard.hpp> @@ -21,10 +21,10 @@ #ifdef BOTAN_FOUND # include <botan/hex.h> -Botan::AutoSeeded_RNG SocketHandler::rng; -Permissive_Credentials_Manager SocketHandler::credential_manager; -Botan::TLS::Policy SocketHandler::policy; -Botan::TLS::Session_Manager_In_Memory SocketHandler::session_manager(SocketHandler::rng); +Botan::AutoSeeded_RNG TCPSocketHandler::rng; +Permissive_Credentials_Manager TCPSocketHandler::credential_manager; +Botan::TLS::Policy TCPSocketHandler::policy; +Botan::TLS::Session_Manager_In_Memory TCPSocketHandler::session_manager(TCPSocketHandler::rng); #endif @@ -37,15 +37,14 @@ using namespace std::chrono_literals; namespace ph = std::placeholders; -SocketHandler::SocketHandler(std::shared_ptr<Poller> poller): - socket(-1), - poller(poller), +TCPSocketHandler::TCPSocketHandler(std::shared_ptr<Poller> poller): + SocketHandler(poller, -1), use_tls(false), connected(false), connecting(false) {} -void SocketHandler::init_socket(const struct addrinfo* rp) +void TCPSocketHandler::init_socket(const struct addrinfo* rp) { 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)); @@ -61,7 +60,7 @@ void SocketHandler::init_socket(const struct addrinfo* rp) throw std::runtime_error("Could not initialize socket: "s + strerror(errno)); } -void SocketHandler::connect(const std::string& address, const std::string& port, const bool tls) +void TCPSocketHandler::connect(const std::string& address, const std::string& port, const bool tls) { this->address = address; this->port = port; @@ -146,7 +145,7 @@ void SocketHandler::connect(const std::string& address, const std::string& port, // it to have failed TimedEventsManager::instance().add_event( TimedEvent(std::chrono::steady_clock::now() + 5s, - std::bind(&SocketHandler::on_connection_timeout, this), + std::bind(&TCPSocketHandler::on_connection_timeout, this), "connection_timeout"s + std::to_string(this->socket))); return ; } @@ -158,18 +157,18 @@ void SocketHandler::connect(const std::string& address, const std::string& port, return ; } -void SocketHandler::on_connection_timeout() +void TCPSocketHandler::on_connection_timeout() { this->close(); this->on_connection_failed("connection timed out"); } -void SocketHandler::connect() +void TCPSocketHandler::connect() { this->connect(this->address, this->port, this->use_tls); } -void SocketHandler::on_recv() +void TCPSocketHandler::on_recv() { #ifdef BOTAN_FOUND if (this->use_tls) @@ -179,7 +178,7 @@ void SocketHandler::on_recv() this->plain_recv(); } -void SocketHandler::plain_recv() +void TCPSocketHandler::plain_recv() { static constexpr size_t buf_size = 4096; char buf[buf_size]; @@ -203,7 +202,7 @@ void SocketHandler::plain_recv() } } -ssize_t SocketHandler::do_recv(void* recv_buf, const size_t buf_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) @@ -228,7 +227,7 @@ ssize_t SocketHandler::do_recv(void* recv_buf, const size_t buf_size) return size; } -void SocketHandler::on_send() +void TCPSocketHandler::on_send() { struct iovec msg_iov[UIO_FASTIOV] = {}; struct msghdr msg{nullptr, 0, @@ -274,7 +273,7 @@ void SocketHandler::on_send() } } -void SocketHandler::close() +void TCPSocketHandler::close() { TimedEventsManager::instance().cancel("connection_timeout"s + std::to_string(this->socket)); @@ -292,12 +291,7 @@ void SocketHandler::close() this->port.clear(); } -socket_t SocketHandler::get_socket() const -{ - return this->socket; -} - -void SocketHandler::send_data(std::string&& data) +void TCPSocketHandler::send_data(std::string&& data) { #ifdef BOTAN_FOUND if (this->use_tls) @@ -307,7 +301,7 @@ void SocketHandler::send_data(std::string&& data) this->raw_send(std::move(data)); } -void SocketHandler::raw_send(std::string&& data) +void TCPSocketHandler::raw_send(std::string&& data) { if (data.empty()) return ; @@ -316,41 +310,41 @@ void SocketHandler::raw_send(std::string&& data) this->poller->watch_send_events(this); } -void SocketHandler::send_pending_data() +void TCPSocketHandler::send_pending_data() { if (this->connected && !this->out_buf.empty()) this->poller->watch_send_events(this); } -bool SocketHandler::is_connected() const +bool TCPSocketHandler::is_connected() const { return this->connected; } -bool SocketHandler::is_connecting() const +bool TCPSocketHandler::is_connecting() const { return this->connecting; } -void* SocketHandler::get_receive_buffer(const size_t) const +void* TCPSocketHandler::get_receive_buffer(const size_t) const { return nullptr; } #ifdef BOTAN_FOUND -void SocketHandler::start_tls() +void TCPSocketHandler::start_tls() { Botan::TLS::Server_Information server_info(this->address, "irc", std::stoul(this->port)); this->tls = std::make_unique<Botan::TLS::Client>( - std::bind(&SocketHandler::tls_output_fn, this, ph::_1, ph::_2), - std::bind(&SocketHandler::tls_data_cb, this, ph::_1, ph::_2), - std::bind(&SocketHandler::tls_alert_cb, this, ph::_1, ph::_2, ph::_3), - std::bind(&SocketHandler::tls_handshake_cb, this, ph::_1), + 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), session_manager, credential_manager, policy, rng, server_info, Botan::TLS::Protocol_Version::latest_tls_version()); } -void SocketHandler::tls_recv() +void TCPSocketHandler::tls_recv() { static constexpr size_t buf_size = 4096; char recv_buf[buf_size]; @@ -366,7 +360,7 @@ void SocketHandler::tls_recv() } } -void SocketHandler::tls_send(std::string&& data) +void TCPSocketHandler::tls_send(std::string&& data) { if (this->tls->is_active()) { @@ -387,7 +381,7 @@ void SocketHandler::tls_send(std::string&& data) this->pre_buf += data; } -void SocketHandler::tls_data_cb(const Botan::byte* data, size_t size) +void TCPSocketHandler::tls_data_cb(const Botan::byte* data, size_t size) { this->in_buf += std::string(reinterpret_cast<const char*>(data), size); @@ -395,17 +389,17 @@ void SocketHandler::tls_data_cb(const Botan::byte* data, size_t size) this->parse_in_buffer(size); } -void SocketHandler::tls_output_fn(const Botan::byte* data, size_t size) +void TCPSocketHandler::tls_output_fn(const Botan::byte* data, size_t size) { this->raw_send(std::string(reinterpret_cast<const char*>(data), size)); } -void SocketHandler::tls_alert_cb(Botan::TLS::Alert alert, const Botan::byte*, size_t) +void TCPSocketHandler::tls_alert_cb(Botan::TLS::Alert alert, const Botan::byte*, size_t) { log_debug("tls_alert: " << alert.type_string()); } -bool SocketHandler::tls_handshake_cb(const Botan::TLS::Session& session) +bool TCPSocketHandler::tls_handshake_cb(const Botan::TLS::Session& session) { log_debug("Handshake with " << session.server_info().hostname() << " complete." << " Version: " << session.version().to_string() @@ -417,7 +411,7 @@ bool SocketHandler::tls_handshake_cb(const Botan::TLS::Session& session) return true; } -void SocketHandler::on_tls_activated() +void TCPSocketHandler::on_tls_activated() { this->send_data(""); } diff --git a/src/network/tcp_socket_handler.hpp b/src/network/tcp_socket_handler.hpp new file mode 100644 index 0000000..8416690 --- /dev/null +++ b/src/network/tcp_socket_handler.hpp @@ -0,0 +1,261 @@ +#ifndef SOCKET_HANDLER_INCLUDED +# define SOCKET_HANDLER_INCLUDED + +#include <network/socket_handler.hpp> + +#include <logger/logger.hpp> + +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> + +#include <utility> +#include <memory> +#include <string> +#include <list> + +#include "config.h" + +#ifdef BOTAN_FOUND +# include <botan/botan.h> +# include <botan/tls_client.h> + +/** + * A very simple credential manager that accepts any certificate. + */ +class Permissive_Credentials_Manager: public Botan::Credentials_Manager +{ +public: + void verify_certificate_chain(const std::string& type, const std::string& purported_hostname, const std::vector<Botan::X509_Certificate>&) + { // TODO: Offer the admin to disallow connection on untrusted + // certificates + log_debug("Checking remote certificate (" << type << ") for hostname " << purported_hostname); + } +}; +#endif // BOTAN_FOUND + +/** + * 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) + */ +class TCPSocketHandler: public SocketHandler +{ +protected: + ~TCPSocketHandler() {} + +public: + explicit TCPSocketHandler(std::shared_ptr<Poller> poller); + /** + * 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(); + /** + * 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(); + /** + * Write as much data from out_buf as possible, in the socket. + */ + void on_send(); + /** + * 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 + */ + 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() = 0; + /** + * 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. + */ + virtual void parse_in_buffer(const size_t size) = 0; + bool is_connected() const; + bool is_connecting() const; + +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 + * 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); + +#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(); + /** + * 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_data_cb(const Botan::byte* data, size_t size); + /** + * 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); + /** + * 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); + /** + * 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); + /** + * 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::list<std::string> out_buf; + /** + * Keep the details of the addrinfo the triggered a EINPROGRESS error when + * connect()ing to it, to reuse it directly when connect() is called + * again. + */ + struct addrinfo addrinfo; + struct sockaddr ai_addr; + socklen_t ai_addrlen; + +protected: + /** + * 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; + /** + * Whether we are using TLS on this connection or not. + */ + bool use_tls; + /** + * 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; + /** + * Hostname we are connected/connecting to + */ + std::string address; + /** + * Port we are connected/connecting to + */ + std::string port; + + bool connected; + bool connecting; + +private: + TCPSocketHandler(const TCPSocketHandler&) = delete; + TCPSocketHandler(TCPSocketHandler&&) = delete; + TCPSocketHandler& operator=(const TCPSocketHandler&) = delete; + TCPSocketHandler& operator=(TCPSocketHandler&&) = delete; + +#ifdef BOTAN_FOUND + /** + * Botan stuff to manipulate a TLS session. + */ + static Botan::AutoSeeded_RNG rng; + static Permissive_Credentials_Manager credential_manager; + static Botan::TLS::Policy policy; + static Botan::TLS::Session_Manager_In_Memory session_manager; + /** + * 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 as + * soon and calls the output_fn callback with it as soon as it is + * created. Therefore, we do not want to create it if do not intend to do + * 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<Botan::TLS::Client> tls; + /** + * An additional buffer to keep data that the user wants to send, but + * cannot because the handshake is not done. + */ + std::string pre_buf; +#endif // BOTAN_FOUND +}; + +#endif // SOCKET_HANDLER_INCLUDED diff --git a/src/xmpp/xmpp_component.cpp b/src/xmpp/xmpp_component.cpp index 1e8f9e0..51d65aa 100644 --- a/src/xmpp/xmpp_component.cpp +++ b/src/xmpp/xmpp_component.cpp @@ -37,7 +37,7 @@ static std::set<std::string> kickable_errors{ }; XmppComponent::XmppComponent(std::shared_ptr<Poller> poller, const std::string& hostname, const std::string& secret): - SocketHandler(poller), + TCPSocketHandler(poller), ever_auth(false), last_auth(false), served_hostname(hostname), diff --git a/src/xmpp/xmpp_component.hpp b/src/xmpp/xmpp_component.hpp index ce594ec..42cdb8a 100644 --- a/src/xmpp/xmpp_component.hpp +++ b/src/xmpp/xmpp_component.hpp @@ -2,7 +2,7 @@ # define XMPP_COMPONENT_INCLUDED #include <xmpp/adhoc_commands_handler.hpp> -#include <network/socket_handler.hpp> +#include <network/tcp_socket_handler.hpp> #include <xmpp/xmpp_parser.hpp> #include <bridge/bridge.hpp> @@ -30,7 +30,7 @@ * * TODO: implement XEP-0225: Component Connections */ -class XmppComponent: public SocketHandler +class XmppComponent: public TCPSocketHandler { public: explicit XmppComponent(std::shared_ptr<Poller> poller, const std::string& hostname, const std::string& secret); |