SocketHandlers own the poller and add themself into it only when the socket is created

We want to call socket() with the parameters provided by getaddrinfo, so we
can’t addd the fd into the poller immediately. We need to wait the
connection attempt, and then the SocketHandler can call add_socket_handler
itself, if the connection succeeds, or is in progress.
This commit is contained in:
Florent Le Coz
2014-05-27 01:01:44 +02:00
parent 6b0ffb5fc2
commit 5507adbe94
11 changed files with 29 additions and 39 deletions
+2 -3
View File
@@ -14,7 +14,7 @@ using namespace std::string_literals;
static const char* action_prefix = "\01ACTION "; static const char* action_prefix = "\01ACTION ";
Bridge::Bridge(const std::string& user_jid, XmppComponent* xmpp, Poller* poller): Bridge::Bridge(const std::string& user_jid, XmppComponent* xmpp, std::shared_ptr<Poller> poller):
user_jid(user_jid), user_jid(user_jid),
xmpp(xmpp), xmpp(xmpp),
poller(poller) poller(poller)
@@ -81,9 +81,8 @@ IrcClient* Bridge::get_irc_client(const std::string& hostname, const std::string
} }
catch (const std::out_of_range& exception) catch (const std::out_of_range& exception)
{ {
this->irc_clients.emplace(hostname, std::make_shared<IrcClient>(hostname, username, this)); this->irc_clients.emplace(hostname, std::make_shared<IrcClient>(this->poller, hostname, username, this));
std::shared_ptr<IrcClient> irc = this->irc_clients.at(hostname); std::shared_ptr<IrcClient> irc = this->irc_clients.at(hostname);
this->poller->add_socket_handler(irc);
return irc.get(); return irc.get();
} }
} }
+2 -3
View File
@@ -22,7 +22,7 @@ class Poller;
class Bridge class Bridge
{ {
public: public:
explicit Bridge(const std::string& user_jid, XmppComponent* xmpp, Poller* poller); explicit Bridge(const std::string& user_jid, XmppComponent* xmpp, std::shared_ptr<Poller> poller);
~Bridge(); ~Bridge();
/** /**
* QUIT all connected IRC servers. * QUIT all connected IRC servers.
@@ -146,9 +146,8 @@ private:
/** /**
* Poller, to give it the IrcClients that we spawn, to make it manage * Poller, to give it the IrcClients that we spawn, to make it manage
* their sockets. * their sockets.
* We don't own it.
*/ */
Poller* poller; std::shared_ptr<Poller> poller;
Bridge(const Bridge&) = delete; Bridge(const Bridge&) = delete;
Bridge(Bridge&& other) = delete; Bridge(Bridge&& other) = delete;
+2 -1
View File
@@ -13,7 +13,8 @@
#include <string> #include <string>
using namespace std::string_literals; using namespace std::string_literals;
IrcClient::IrcClient(const std::string& hostname, const std::string& username, Bridge* bridge): IrcClient::IrcClient(std::shared_ptr<Poller> poller, const std::string& hostname, const std::string& username, Bridge* bridge):
SocketHandler(poller),
hostname(hostname), hostname(hostname),
username(username), username(username),
current_nick(username), current_nick(username),
+2 -1
View File
@@ -8,6 +8,7 @@
#include <network/socket_handler.hpp> #include <network/socket_handler.hpp>
#include <unordered_map> #include <unordered_map>
#include <memory>
#include <vector> #include <vector>
#include <string> #include <string>
#include <map> #include <map>
@@ -23,7 +24,7 @@ class Bridge;
class IrcClient: public SocketHandler class IrcClient: public SocketHandler
{ {
public: public:
explicit IrcClient(const std::string& hostname, const std::string& username, Bridge* bridge); explicit IrcClient(std::shared_ptr<Poller> poller, const std::string& hostname, const std::string& username, Bridge* bridge);
~IrcClient(); ~IrcClient();
/** /**
* Connect to the IRC server * Connect to the IRC server
+6 -7
View File
@@ -61,11 +61,11 @@ int main(int ac, char** av)
return config_help("password"); return config_help("password");
if (hostname.empty()) if (hostname.empty())
return config_help("hostname"); return config_help("hostname");
std::shared_ptr<XmppComponent> xmpp_component =
std::make_shared<XmppComponent>(hostname, password);
Poller p; auto p = std::make_shared<Poller>();
p.add_socket_handler(xmpp_component); auto xmpp_component = std::make_shared<XmppComponent>(p,
hostname,
password);
// Install the signals used to exit the process cleanly, or reload the // Install the signals used to exit the process cleanly, or reload the
// config // config
@@ -91,7 +91,7 @@ int main(int ac, char** av)
xmpp_component->start(); xmpp_component->start();
const std::chrono::milliseconds timeout(-1); const std::chrono::milliseconds timeout(-1);
while (p.poll(timeout) != -1) while (p->poll(timeout) != -1)
{ {
// Check for empty irc_clients (not connected, or with no joined // Check for empty irc_clients (not connected, or with no joined
// channel) and remove them // channel) and remove them
@@ -123,14 +123,13 @@ int main(int ac, char** av)
!xmpp_component->is_connecting()) !xmpp_component->is_connecting())
{ {
xmpp_component->reset(); xmpp_component->reset();
p.add_socket_handler(xmpp_component);
xmpp_component->start(); xmpp_component->start();
} }
// If the only existing connection is the one to the XMPP component: // If the only existing connection is the one to the XMPP component:
// close the XMPP stream. // close the XMPP stream.
if (exiting && xmpp_component->is_connecting()) if (exiting && xmpp_component->is_connecting())
xmpp_component->close(); xmpp_component->close();
if (exiting && p.size() == 1 && xmpp_component->is_document_open()) if (exiting && p->size() == 1 && xmpp_component->is_document_open())
xmpp_component->close_document(); xmpp_component->close_document();
} }
log_info("All connection cleanely closed, have a nice day."); log_info("All connection cleanely closed, have a nice day.");
+4 -5
View File
@@ -27,15 +27,14 @@ Poller::~Poller()
{ {
} }
void Poller::add_socket_handler(std::shared_ptr<SocketHandler> socket_handler) void Poller::add_socket_handler(SocketHandler* socket_handler)
{ {
// Raise an error if that socket is already in the list // Don't do anything if the socket is already managed
const auto it = this->socket_handlers.find(socket_handler->get_socket()); const auto it = this->socket_handlers.find(socket_handler->get_socket());
if (it != this->socket_handlers.end()) if (it != this->socket_handlers.end())
throw std::runtime_error("Trying to insert SocketHandler already managed"); return ;
this->socket_handlers.emplace(socket_handler->get_socket(), socket_handler); this->socket_handlers.emplace(socket_handler->get_socket(), socket_handler);
socket_handler->set_poller(this);
// We always watch all sockets for receive events // We always watch all sockets for receive events
#if POLLER == POLL #if POLLER == POLL
@@ -44,7 +43,7 @@ void Poller::add_socket_handler(std::shared_ptr<SocketHandler> socket_handler)
this->nfds++; this->nfds++;
#endif #endif
#if POLLER == EPOLL #if POLLER == EPOLL
struct epoll_event event = {EPOLLIN, {socket_handler.get()}}; struct epoll_event event = {EPOLLIN, {socket_handler}};
const int res = ::epoll_ctl(this->epfd, EPOLL_CTL_ADD, socket_handler->get_socket(), &event); const int res = ::epoll_ctl(this->epfd, EPOLL_CTL_ADD, socket_handler->get_socket(), &event);
if (res == -1) if (res == -1)
{ {
+2 -2
View File
@@ -42,7 +42,7 @@ public:
* Add a SocketHandler to be monitored by this Poller. All receive events * Add a SocketHandler to be monitored by this Poller. All receive events
* are always automatically watched. * are always automatically watched.
*/ */
void add_socket_handler(std::shared_ptr<SocketHandler> socket_handler); void add_socket_handler(SocketHandler* socket_handler);
/** /**
* Remove (and stop managing) a SocketHandler, designed by the given socket_t. * Remove (and stop managing) a SocketHandler, designed by the given socket_t.
*/ */
@@ -77,7 +77,7 @@ private:
* because that's what is returned by select/poll/etc when an event * because that's what is returned by select/poll/etc when an event
* occures. * occures.
*/ */
std::unordered_map<socket_t, std::shared_ptr<SocketHandler>> socket_handlers; std::unordered_map<socket_t, SocketHandler*> socket_handlers;
#if POLLER == POLL #if POLLER == POLL
struct pollfd fds[MAX_POLL_FD_NUMBER]; struct pollfd fds[MAX_POLL_FD_NUMBER];
+3 -9
View File
@@ -23,8 +23,8 @@ using namespace std::string_literals;
# define UIO_FASTIOV 8 # define UIO_FASTIOV 8
#endif #endif
SocketHandler::SocketHandler(): SocketHandler::SocketHandler(std::shared_ptr<Poller> poller):
poller(nullptr), poller(poller),
connected(false), connected(false),
connecting(false) connecting(false)
{ {
@@ -107,6 +107,7 @@ void SocketHandler::connect(const std::string& address, const std::string& port)
|| errno == EISCONN) || errno == EISCONN)
{ {
log_info("Connection success."); log_info("Connection success.");
this->poller->add_socket_handler(this);
this->connected = true; this->connected = true;
this->connecting = false; this->connecting = false;
this->on_connected(); this->on_connected();
@@ -134,11 +135,6 @@ void SocketHandler::connect()
this->connect(this->address, this->port); this->connect(this->address, this->port);
} }
void SocketHandler::set_poller(Poller* poller)
{
this->poller = poller;
}
void SocketHandler::on_recv() void SocketHandler::on_recv()
{ {
static constexpr size_t buf_size = 4096; static constexpr size_t buf_size = 4096;
@@ -231,8 +227,6 @@ void SocketHandler::close()
this->port.clear(); this->port.clear();
this->poller->remove_socket_handler(this->get_socket()); this->poller->remove_socket_handler(this->get_socket());
::close(this->socket); ::close(this->socket);
// recreate the socket for a potential future usage
this->init_socket();
} }
socket_t SocketHandler::get_socket() const socket_t SocketHandler::get_socket() const
+3 -6
View File
@@ -6,6 +6,7 @@
#include <netdb.h> #include <netdb.h>
#include <utility> #include <utility>
#include <memory>
#include <string> #include <string>
#include <list> #include <list>
@@ -22,7 +23,7 @@ class Poller;
class SocketHandler class SocketHandler
{ {
public: public:
explicit SocketHandler(); explicit SocketHandler(std::shared_ptr<Poller> poller);
virtual ~SocketHandler() {} virtual ~SocketHandler() {}
/** /**
* (re-)Initialize the socket * (re-)Initialize the socket
@@ -33,10 +34,6 @@ public:
*/ */
void connect(const std::string& address, const std::string& port); void connect(const std::string& address, const std::string& port);
void connect(); void connect();
/**
* Set the pointer to the given Poller, to communicate with it.
*/
void set_poller(Poller* poller);
/** /**
* Reads data in our in_buf and the call parse_in_buf, for the implementor * Reads data in our in_buf and the call parse_in_buf, for the implementor
* to handle the data received so far. * to handle the data received so far.
@@ -119,7 +116,7 @@ protected:
* And a raw pointer because we are not owning it, it is owning us * And a raw pointer because we are not owning it, it is owning us
* (actually it is sharing our ownership with a Bridge). * (actually it is sharing our ownership with a Bridge).
*/ */
Poller* poller; std::shared_ptr<Poller> poller;
/** /**
* Hostname we are connected/connecting to * Hostname we are connected/connecting to
*/ */
+2 -1
View File
@@ -47,7 +47,8 @@ static std::set<std::string> kickable_errors{
"malformed-error" "malformed-error"
}; };
XmppComponent::XmppComponent(const std::string& hostname, const std::string& secret): XmppComponent::XmppComponent(std::shared_ptr<Poller> poller, const std::string& hostname, const std::string& secret):
SocketHandler(poller),
ever_auth(false), ever_auth(false),
last_auth(false), last_auth(false),
served_hostname(hostname), served_hostname(hostname),
+1 -1
View File
@@ -18,7 +18,7 @@
class XmppComponent: public SocketHandler class XmppComponent: public SocketHandler
{ {
public: public:
explicit XmppComponent(const std::string& hostname, const std::string& secret); explicit XmppComponent(std::shared_ptr<Poller> poller, const std::string& hostname, const std::string& secret);
~XmppComponent(); ~XmppComponent();
void on_connection_failed(const std::string& reason) override final; void on_connection_failed(const std::string& reason) override final;