summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/irc/irc_client.cpp2
-rw-r--r--src/irc/irc_client.hpp4
-rw-r--r--src/main.cpp1
-rw-r--r--src/network/socket_handler.hpp273
-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.hpp261
-rw-r--r--src/xmpp/xmpp_component.cpp2
-rw-r--r--src/xmpp/xmpp_component.hpp4
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);