summaryrefslogtreecommitdiffstats
path: root/src/server/sockets.cpp
blob: 7c995f0608ca62fca05a95385488ef63720c624e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include <errno.h>
#include <stdio.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, -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);
}