~singpolyma/biboumi

70a58a8f7152e775a1c6cdc15b3c9f23a7719f85 — Florent Le Coz 10 years ago e7a441e + b729085
Merge branch 'epolletc'
M CMakeLists.txt => CMakeLists.txt +7 -1
@@ 24,6 24,12 @@ include_directories(${ICONV_INCLUDE_DIR})
# coming from these headers.
include_directories(SYSTEM ${CRYPTO++_INCLUDE_DIR})

set(POLLER "POLL" CACHE STRING
  "Choose the poller between POLL and EPOLL (Linux-only)")
if((NOT ${POLLER} MATCHES "POLL") AND
    (NOT ${POLLER} MATCHES "EPOLL"))
  message(FATAL_ERROR "POLLER must be either POLL or EPOLL")
endif()
#
## utils
#


@@ 95,4 101,4 @@ target_link_libraries(test
  utils
  config)

CONFIGURE_FILE(config.h.cmake src/config.h @ONLY)
configure_file(config.h.cmake src/config.h)

M config.h.cmake => config.h.cmake +1 -0
@@ 1,1 1,2 @@
#cmakedefine ICONV_SECOND_ARGUMENT_IS_CONST
#cmakedefine POLLER ${POLLER}

M src/irc/irc_client.cpp => src/irc/irc_client.cpp +21 -0
@@ 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];

M src/irc/irc_client.hpp => src/irc/irc_client.hpp +23 -2
@@ 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},

M src/network/poller.cpp => src/network/poller.cpp +69 -4
@@ 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;
}

M src/network/poller.hpp => src/network/poller.hpp +14 -10
@@ 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;