From cd2decce51c32b8c0531a87ea849e9f8e80db0d3 Mon Sep 17 00:00:00 2001
From: Joursoir <chat@joursoir.net>
Date: Mon, 23 Nov 2020 20:07:36 +0300
Subject: server: add first (work with sockets) level of abstraction

---
 src/server/server.cpp  |  20 ++++++++++
 src/server/sockets.cpp | 101 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/server/sockets.hpp |  37 ++++++++++++++++++
 3 files changed, 158 insertions(+)
 create mode 100644 src/server/server.cpp
 create mode 100644 src/server/sockets.cpp
 create mode 100644 src/server/sockets.hpp

diff --git a/src/server/server.cpp b/src/server/server.cpp
new file mode 100644
index 0000000..6834ceb
--- /dev/null
+++ b/src/server/server.cpp
@@ -0,0 +1,20 @@
+#include <stdio.h>
+
+#include "chat.hpp"
+
+int main(int argc, char *argv[])
+{
+	/*	  Event-driven programming	  */
+	/*
+		1) selection event
+		2) event handling 
+	*/
+	EventSelector *selector = new EventSelector;
+	/*ChatServer *serv = ChatServer::Start(selector, port);
+	if(!serv) {
+		perror("server");
+		return 1;
+	}*/
+	selector->Run();
+	return 0;
+}
\ No newline at end of file
diff --git a/src/server/sockets.cpp b/src/server/sockets.cpp
new file mode 100644
index 0000000..1a52786
--- /dev/null
+++ b/src/server/sockets.cpp
@@ -0,0 +1,101 @@
+#include <errno.h>
+
+#include "sockets.hpp"
+
+#define INVALID_FD -1
+
+EventSelector::~EventSelector()
+{
+    if(fd_array)
+        delete[] fd_array;
+    if(fds)
+    	delete[] fds;
+}
+
+void EventSelector::Add(FdHandler *h)
+{
+	int fd = h->GetFd();
+	if(!fd_array) {
+		fd_array_len = fd > 23 ? fd + 1 : 24;
+		fd_array = new FdHandler*[fd_array_len];
+		// maybe use memset too?
+		fds = new struct pollfd[fd_array_len];
+
+		for(int i = 0; i < fd_array_len; i++) {
+			fd_array[i] = 0;
+			fds[i] = { INVALID_FD, 0, 0 };
+		}
+	}
+	if(fd >= fd_array_len) {
+		FdHandler **tmp_arr = new FdHandler*[fd+1];
+		struct pollfd *tmp_fds = new struct pollfd[fd+1];
+
+		for(int i = 0; i <= fd; i++) {
+			if(i < fd_array_len) {
+				tmp_arr[i] = fd_array[i];
+				tmp_fds[i] = fds[i];
+			}
+			else {
+				fd_array[i] = 0;
+				fds[i] = { INVALID_FD, 0, 0 };
+			}
+			fd_array_len = fd + 1;
+
+			delete[] fd_array;
+			fd_array = tmp_arr;
+			delete[] fds;
+			fds = tmp_fds;
+		}
+	}
+	if(fd > max_fd)
+		max_fd = fd;
+
+	fd_array[fd] = h;
+	fds[fd].fd = fd;
+	if(fd_array[fd]->WantRead())
+		fds[fd].events |= POLLIN;
+    if(fd_array[fd]->WantWrite())
+    	fds[fd].events |= POLLOUT;
+}
+
+bool EventSelector::Remove(FdHandler *h)
+{
+	int fd = h->GetFd();
+	if(fd >= fd_array_len || fd_array[fd] != h)
+        return false;
+
+    fd_array[fd] = 0;
+    fds[fd] = { INVALID_FD, 0, 0 };
+    if(fd == max_fd) {
+        while(max_fd >= 0 && !fd_array[max_fd])
+            max_fd--;
+    }
+
+    return true;
+}
+
+void EventSelector::Run()
+{
+    exit_flag = false;
+    do {
+        int res = poll(fds, max_fd, -1);
+
+        if(res < 0) {
+        	if(errno == EINTR)
+        		continue;
+        	else
+        		break;
+        }
+
+        if(res > 0) {
+        	for(int i = 0; i <= max_fd; i++) {
+        		if(!fd_array[i])
+        			continue;
+        		bool r = (fds[i].revents & POLLIN);
+        		bool w = (fds[i].revents & POLLOUT);
+        		if(r || w)
+        			fd_array[i]->Handle(r, w);
+        	}
+        }
+    } while(!exit_flag);
+}
\ No newline at end of file
diff --git a/src/server/sockets.hpp b/src/server/sockets.hpp
new file mode 100644
index 0000000..2f47e3b
--- /dev/null
+++ b/src/server/sockets.hpp
@@ -0,0 +1,37 @@
+#ifndef SOCKETS_H
+#define SOCKETS_H
+
+#include <unistd.h>
+#include <sys/poll.h>
+
+class FdHandler { // abstract class
+    int fd;
+public:
+    FdHandler(int i_fd) : fd(i_fd) {} 
+    virtual ~FdHandler() { close(fd); }
+
+    int GetFd() const { return fd; }
+
+    virtual bool WantRead() const { return true; }
+    virtual bool WantWrite() const { return false; }
+    virtual void Handle(bool r, bool w) = 0;
+};
+
+class EventSelector {
+    FdHandler **fd_array;
+    struct pollfd *fds;
+    int fd_array_len;
+    int max_fd;
+
+    bool exit_flag;
+public:
+    EventSelector() : fd_array(0), fds(0), max_fd(-1), exit_flag(false) {}
+    ~EventSelector();
+
+    void Add(FdHandler *h);
+    bool Remove(FdHandler *h);
+
+    void Run();
+    void BreakLoop() { exit_flag = true; }
+};
+#endif
\ No newline at end of file
-- 
cgit v1.2.3-18-g5258