summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/irc/irc_client.cpp21
-rw-r--r--src/irc/irc_client.hpp25
-rw-r--r--src/network/poller.cpp73
-rw-r--r--src/network/poller.hpp24
4 files changed, 127 insertions, 16 deletions
diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp
index 82abbd9..f339580 100644
--- a/src/irc/irc_client.cpp
+++ b/src/irc/irc_client.cpp
@@ -222,6 +222,27 @@ void IrcClient::on_channel_message(const IrcMessage& message)
this->bridge->send_message(iid, nick, body, muc);
}
+void IrcClient::empty_motd(const IrcMessage& message)
+{
+ (void)message;
+ this->motd.erase();
+}
+
+void IrcClient::on_motd_line(const IrcMessage& message)
+{
+ const std::string body = message.arguments[1];
+ // We could send the MOTD without a line break between each IRC-message,
+ // but sometimes it contains some ASCII art, we use line breaks to keep
+ // them intact.
+ this->motd += body+"\n";
+}
+
+void IrcClient::send_motd(const IrcMessage& message)
+{
+ (void)message;
+ this->bridge->send_xmpp_message(this->hostname, "", this->motd);
+}
+
void IrcClient::on_topic_received(const IrcMessage& message)
{
const std::string chan_name = message.arguments[1];
diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp
index 3b22fa0..aa420f4 100644
--- a/src/irc/irc_client.hpp
+++ b/src/irc/irc_client.hpp
@@ -100,6 +100,18 @@ public:
*/
void forward_server_message(const IrcMessage& message);
/**
+ * Just empty the motd we kept as a string
+ */
+ void empty_motd(const IrcMessage& message);
+ /**
+ * Send the MOTD string as one single "big" message
+ */
+ void send_motd(const IrcMessage& message);
+ /**
+ * Append this line to the MOTD
+ */
+ void on_motd_line(const IrcMessage& message);
+ /**
* Forward the join of an other user into an IRC channel, and save the
* IrcUsers in the IrcChannel
*/
@@ -172,6 +184,11 @@ private:
*/
std::vector<std::string> channels_to_join;
bool welcomed;
+ /**
+ * Each motd line received is appended to this string, which we send when
+ * the motd is completely received
+ */
+ std::string motd;
IrcClient(const IrcClient&) = delete;
IrcClient(IrcClient&&) = delete;
IrcClient& operator=(const IrcClient&) = delete;
@@ -186,8 +203,12 @@ typedef void (IrcClient::*irc_callback_t)(const IrcMessage&);
static const std::unordered_map<std::string, irc_callback_t> irc_callbacks = {
{"NOTICE", &IrcClient::forward_server_message},
- {"375", &IrcClient::forward_server_message},
- {"372", &IrcClient::forward_server_message},
+ {"RPL_MOTDSTART", &IrcClient::empty_motd},
+ {"375", &IrcClient::empty_motd},
+ {"RPL_MOTD", &IrcClient::on_motd_line},
+ {"372", &IrcClient::on_motd_line},
+ {"RPL_MOTDEND", &IrcClient::send_motd},
+ {"376", &IrcClient::send_motd},
{"JOIN", &IrcClient::on_channel_join},
{"PRIVMSG", &IrcClient::on_channel_message},
{"353", &IrcClient::set_and_forward_user_list},
diff --git a/src/network/poller.cpp b/src/network/poller.cpp
index e790e60..023fb12 100644
--- a/src/network/poller.cpp
+++ b/src/network/poller.cpp
@@ -12,6 +12,13 @@ Poller::Poller()
#if POLLER == POLL
memset(this->fds, 0, sizeof(this->fds));
this->nfds = 0;
+#elif POLLER == EPOLL
+ this->epfd = ::epoll_create1(0);
+ if (this->epfd == -1)
+ {
+ perror("epoll");
+ throw std::runtime_error("Could not create epoll instance");
+ }
#endif
}
@@ -36,6 +43,17 @@ void Poller::add_socket_handler(std::shared_ptr<SocketHandler> socket_handler)
this->fds[this->nfds].events = POLLIN;
this->nfds++;
#endif
+#if POLLER == EPOLL
+ struct epoll_event event;
+ event.data.ptr = socket_handler.get();
+ event.events = EPOLLIN;
+ const int res = ::epoll_ctl(this->epfd, EPOLL_CTL_ADD, socket_handler->get_socket(), &event);
+ if (res == -1)
+ {
+ perror("epoll_ctl");
+ throw std::runtime_error("Could not add socket to epoll");
+ }
+#endif
}
void Poller::remove_socket_handler(const socket_t socket)
@@ -44,6 +62,8 @@ void Poller::remove_socket_handler(const socket_t 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)
@@ -58,9 +78,17 @@ void Poller::remove_socket_handler(const socket_t socket)
this->nfds--;
}
}
+#elif POLLER == EPOLL
+ const int res = ::epoll_ctl(this->epfd, EPOLL_CTL_DEL, socket, nullptr);
+ if (res == -1)
+ {
+ perror("epoll_ctl");
+ throw std::runtime_error("Could not remove socket from epoll");
+ }
+#endif
}
-void Poller::watch_send_events(const SocketHandler* const socket_handler)
+void Poller::watch_send_events(SocketHandler* socket_handler)
{
#if POLLER == POLL
for (size_t i = 0; i <= this->nfds; ++i)
@@ -71,11 +99,21 @@ void Poller::watch_send_events(const SocketHandler* const socket_handler)
return;
}
}
-#endif
throw std::runtime_error("Cannot watch a non-registered socket for send events");
+#elif POLLER == EPOLL
+ struct epoll_event event;
+ event.data.ptr = socket_handler;
+ event.events = EPOLLIN|EPOLLOUT;
+ const int res = ::epoll_ctl(this->epfd, EPOLL_CTL_MOD, socket_handler->get_socket(), &event);
+ if (res == -1)
+ {
+ perror("epoll_ctl");
+ throw std::runtime_error("Could not modify socket flags in epoll");
+ }
+#endif
}
-void Poller::stop_watching_send_events(const SocketHandler* const socket_handler)
+void Poller::stop_watching_send_events(SocketHandler* socket_handler)
{
#if POLLER == POLL
for (size_t i = 0; i <= this->nfds; ++i)
@@ -86,8 +124,18 @@ void Poller::stop_watching_send_events(const SocketHandler* const socket_handler
return;
}
}
-#endif
throw std::runtime_error("Cannot watch a non-registered socket for send events");
+#elif POLLER == EPOLL
+ struct epoll_event event;
+ event.data.ptr = socket_handler;
+ event.events = EPOLLIN;
+ const int res = ::epoll_ctl(this->epfd, EPOLL_CTL_MOD, socket_handler->get_socket(), &event);
+ if (res == -1)
+ {
+ perror("epoll_ctl");
+ throw std::runtime_error("Could not modify socket flags in epoll");
+ }
+#endif
}
bool Poller::poll()
@@ -121,6 +169,23 @@ bool Poller::poll()
res--;
}
}
+#elif POLLER == EPOLL
+ static const size_t max_events = 12;
+ struct epoll_event revents[max_events];
+ const int nb_events = epoll_wait(this->epfd, revents, max_events, -1);
+ if (nb_events == -1)
+ {
+ perror("epoll_wait");
+ throw std::runtime_error("Epoll_wait failed");
+ }
+ for (int i = 0; i < nb_events; ++i)
+ {
+ auto socket_handler = static_cast<SocketHandler*>(revents[i].data.ptr);
+ if (revents[i].events & EPOLLIN)
+ socket_handler->on_recv();
+ if (revents[i].events & EPOLLOUT)
+ socket_handler->on_send();
+ }
#endif
return true;
}
diff --git a/src/network/poller.hpp b/src/network/poller.hpp
index 319236b..fe52fda 100644
--- a/src/network/poller.hpp
+++ b/src/network/poller.hpp
@@ -9,27 +9,29 @@
#define POLL 1
#define EPOLL 2
#define KQUEUE 3
-
-#define POLLER POLL
+#include <config.h>
+#ifndef POLLER
+ #define POLLER POLL
+#endif
#if POLLER == POLL
#include <poll.h>
- // TODO, dynamic size, without artificial limit
#define MAX_POLL_FD_NUMBER 4096
+#elif POLLER == EPOLL
+ #include <sys/epoll.h>
+#else
+ #error Invalid POLLER value
#endif
/**
- * We pass some SocketHandlers to this the Poller, which uses
+ * 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 for all these pollers:
- * - poll(2) (mandatory)
- * - epoll(7)
+ * TODO: support these pollers:
* - kqueue(2)
*/
-
class Poller
{
public:
@@ -48,12 +50,12 @@ public:
* Signal the poller that he needs to watch for send events for the given
* SocketHandler.
*/
- void watch_send_events(const SocketHandler* const socket_handler);
+ 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(const SocketHandler* const socket_handler);
+ void stop_watching_send_events(SocketHandler* socket_handler);
/**
* Wait for all watched events, and call the SocketHandlers' callbacks
* when one is ready.
@@ -72,6 +74,8 @@ private:
#if POLLER == POLL
struct pollfd fds[MAX_POLL_FD_NUMBER];
nfds_t nfds;
+#elif POLLER == EPOLL
+ int epfd;
#endif
Poller(const Poller&) = delete;