summaryrefslogtreecommitdiff
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/poller.cpp96
-rw-r--r--src/network/poller.hpp72
-rw-r--r--src/network/socket_handler.hpp62
3 files changed, 230 insertions, 0 deletions
diff --git a/src/network/poller.cpp b/src/network/poller.cpp
new file mode 100644
index 0000000..c7d9eb2
--- /dev/null
+++ b/src/network/poller.cpp
@@ -0,0 +1,96 @@
+#include <network/poller.hpp>
+
+#include <assert.h>
+#include <cstring>
+#include <iostream>
+
+
+Poller::Poller()
+{
+ std::cout << "Poller()" << std::endl;
+#if POLLER == POLL
+ memset(this->fds, 0, sizeof(this->fds));
+ this->nfds = 0;
+#endif
+}
+
+Poller::~Poller()
+{
+ std::cout << "~Poller()" << std::endl;
+}
+
+void Poller::add_socket_handler(std::shared_ptr<SocketHandler> socket_handler)
+{
+ // Raise an error if that socket is already in the list
+ const auto it = this->socket_handlers.find(socket_handler->get_socket());
+ if (it != this->socket_handlers.end())
+ throw std::runtime_error("Trying to insert SocketHandler already managed");
+
+ this->socket_handlers.emplace(socket_handler->get_socket(), socket_handler);
+ socket_handler->set_poller(this);
+
+ // We always watch all sockets for receive events
+#if POLLER == POLL
+ this->fds[this->nfds].fd = socket_handler->get_socket();
+ this->fds[this->nfds].events = POLLIN;
+ this->nfds++;
+#endif
+}
+
+void Poller::remove_socket_handler(const socket_t socket)
+{
+ const auto it = this->socket_handlers.find(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);
+ for (size_t i = 0; i < this->nfds; i++)
+ {
+ if (this->fds[i].fd == socket)
+ {
+ // Move all subsequent pollfd by one on the left, erasing the
+ // value of the one we remove
+ for (size_t j = i; j < this->nfds - 1; ++j)
+ {
+ this->fds[j].fd = this->fds[j+1].fd;
+ this->fds[j].events= this->fds[j+1].events;
+ }
+ this->nfds--;
+ }
+ }
+}
+
+void Poller::poll()
+{
+#if POLLER == POLL
+ std::cout << "Polling:" << std::endl;
+ for (size_t i = 0; i < this->nfds; ++i)
+ std::cout << "pollfd[" << i << "]: (" << this->fds[i].fd << ")" << std::endl;
+ int res = ::poll(this->fds, this->nfds, -1);
+ if (res < 0)
+ {
+ perror("poll");
+ throw std::runtime_error("Poll failed");
+ }
+ // We cannot possibly have more ready events than the number of fds we are
+ // watching
+ assert(static_cast<unsigned int>(res) <= this->nfds);
+ for (size_t i = 0; i <= this->nfds && res != 0; ++i)
+ {
+ if (this->fds[i].revents == 0)
+ continue;
+ else if (this->fds[i].revents & POLLIN)
+ {
+ auto socket_handler = this->socket_handlers.at(this->fds[i].fd);
+ socket_handler->on_recv();
+ res--;
+ }
+ else if (this->fds[i].revents & POLLOUT)
+ {
+ auto socket_handler = this->socket_handlers.at(this->fds[i].fd);
+ socket_handler->on_send();
+ res--;
+ }
+ }
+#endif
+}
+
diff --git a/src/network/poller.hpp b/src/network/poller.hpp
new file mode 100644
index 0000000..46a184e
--- /dev/null
+++ b/src/network/poller.hpp
@@ -0,0 +1,72 @@
+#ifndef POLLER_INCLUDED
+# define POLLER_INCLUDED
+
+#include <network/socket_handler.hpp>
+
+#include <unordered_map>
+#include <memory>
+
+#define POLL 1
+#define EPOLL 2
+#define KQUEUE 3
+
+#define POLLER POLL
+
+#if POLLER == POLL
+ #include <poll.h>
+ // TODO, dynamic size, without artificial limit
+ #define MAX_POLL_FD_NUMBER 4096
+#endif
+
+/**
+ * We pass some SocketHandlers to this the 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)
+ * - kqueue(2)
+ */
+
+
+class Poller
+{
+public:
+ explicit Poller();
+ ~Poller();
+ /**
+ * Add a SocketHandler to be monitored by this Poller. All receive events
+ * are always automatically watched.
+ */
+ void add_socket_handler(std::shared_ptr<SocketHandler> socket_handler);
+ /**
+ * Remove (and stop managing) a SocketHandler, designed by the given socket_t.
+ */
+ void remove_socket_handler(const socket_t socket);
+ /**
+ * Wait for all watched events, and call the SocketHandlers' callbacks
+ * when one is ready.
+ */
+ void poll();
+
+private:
+ /**
+ * A "list" of all the SocketHandlers that we manage, indexed by socket,
+ * because that's what is returned by select/poll/etc when an event
+ * occures.
+ */
+ std::unordered_map<socket_t, std::shared_ptr<SocketHandler>> socket_handlers;
+
+#if POLLER == POLL
+ struct pollfd fds[MAX_POLL_FD_NUMBER];
+ nfds_t nfds;
+#endif
+
+ Poller(const Poller&) = delete;
+ Poller(Poller&&) = delete;
+ Poller& operator=(const Poller&) = delete;
+ Poller& operator=(Poller&&) = delete;
+};
+
+#endif // POLLER_INCLUDED
diff --git a/src/network/socket_handler.hpp b/src/network/socket_handler.hpp
new file mode 100644
index 0000000..165f732
--- /dev/null
+++ b/src/network/socket_handler.hpp
@@ -0,0 +1,62 @@
+#ifndef SOCKET_HANDLER_INCLUDED
+# define SOCKET_HANDLER_INCLUDED
+
+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
+{
+public:
+ explicit SocketHandler():
+ poller(nullptr)
+ {}
+ /**
+ * Set the pointer to the given Poller, to communicate with it.
+ */
+ void set_poller(Poller* poller)
+ {
+ this->poller = poller;
+ };
+ /**
+ * Happens when the socket is ready to be received from.
+ */
+ virtual void on_recv() = 0;
+ /**
+ * Happens when the socket is ready to be written to.
+ */
+ virtual void on_send() = 0;
+ /**
+ * Returns the socket that should be handled by the poller.
+ */
+ virtual socket_t get_socket() const = 0;
+ /**
+ * Close the connection.
+ */
+ virtual void close() = 0;
+
+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).
+ */
+ Poller* poller;
+
+private:
+ SocketHandler(const SocketHandler&) = delete;
+ SocketHandler(SocketHandler&&) = delete;
+ SocketHandler& operator=(const SocketHandler&) = delete;
+ SocketHandler& operator=(SocketHandler&&) = delete;
+};
+
+#endif // SOCKET_HANDLER_INCLUDED