]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengines/socketengine_poll.cpp
Add poll to build system if kqueue/epoll/ports are not used, above select.
[user/henk/code/inspircd.git] / src / socketengines / socketengine_poll.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15 #include "exitcodes.h"
16 #include "socketengines/socketengine_poll.h"
17
18 PollEngine::PollEngine(InspIRCd* Instance) : SocketEngine(Instance)
19 {
20         // Poll requires no special setup (which is nice).
21         CurrentSetSize = 0;
22
23         ref = new EventHandler* [GetMaxFds()];
24         events = new struct epoll_event[GetMaxFds()];
25
26         memset(&events, 0, GetMaxFds() * sizeof(struct pollfds*));
27 }
28
29 PollEngine::~PollEngine()
30 {
31         // No destruction required, either.
32         delete[] ref;
33         delete[] events;
34 }
35
36 bool PollEngine::AddFd(EventHandler* eh)
37 {
38         int fd = eh->GetFd();
39         if ((fd < 0) || (fd > GetMaxFds() - 1))
40         {
41                 ServerInstance->Logs->Log("SOCKET",DEBUG,"AddFd out of range: (fd: %d, max: %d)", fd, GetMaxFds());
42                 return false;
43         }
44
45         if (GetRemainingFds() <= 1)
46         {
47                 ServerInstance->Logs->Log("SOCKET",DEBUG,"No remaining FDs cannot add fd: %d", fd);
48                 return false;
49         }
50
51         if (ref[fd])
52         {
53                 ServerInstance->Logs->Log("SOCKET",DEBUG,"Attempt to add duplicate fd: %d", fd);
54                 return false;
55         }
56
57         ref[fd] = eh;
58         events[fd]->fd = fd;
59         if (eh->Readable())
60         {
61                 events[fd]->events = POLLIN;
62         }
63         else
64         {
65                 events[fd]->events = POLLOUT;
66         }
67
68         ServerInstance->Log(DEBUG,"New file descriptor: %d (%d)", fd, events[fd]->events);
69         CurrentSetSize++;
70         return true;
71 }
72
73 void PollEngine::WantWrite(EventHandler* eh)
74 {
75         events[eh->GetFd()]->events = POLLIN | POLLOUT;
76 }
77
78 bool PollEngine::DelFd(EventHandler* eh, bool force)
79 {
80         int fd = eh->GetFd();
81         if ((fd < 0) || (fd > MAX_DESCRIPTORS))
82         {
83                 ServerInstance->Logs->Log("SOCKET",DEBUG,"DelFd out of range: (fd: %d, max: %d)", fd, GetMaxFds());
84                 return false;
85         }
86
87         events[fd]->fd = -1;
88         events[fd]->events = 0;
89
90         CurrentSetSize--;
91         ref[fd] = NULL;
92
93         ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd);
94         return true;
95 }
96
97 int PollEngine::GetMaxFds()
98 {
99         if (MAX_DESCRIPTORS)
100                 return MAX_DESCRIPTORS;
101
102         int max = ulimit(4, 0);
103         if (max > 0)
104         {
105                 MAX_DESCRIPTORS = max;
106                 return max;
107         }
108         else
109         {
110                 ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets!");
111                 printf("ERROR: Can't determine maximum number of open sockets!\n");
112                 ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE);
113         }
114         return 0;
115 }
116
117 int PollEngine::GetRemainingFds()
118 {
119         return MAX_DESCRIPTORS - CurrentSetSize;
120 }
121
122 int PollEngine::DispatchEvents()
123 {
124         int i = poll(events, GetMaxFds() - 1, 1000);
125         int fd = 0;
126         socklen_t codesize = sizeof(int);
127         int errcode;
128         int processed = 0;
129
130         if (i > 0)
131         {
132                 for (fd = 0; fd < GetMaxFds() - 1 && processed != i; fd++)
133                 {
134                         if (events[fd].revents)
135                                 processed++;
136
137                         if (events[fd].revents & POLLHUP)
138                         {
139                                 if (ref[fd])
140                                         ref[fd]->HandleEvent(EVENT_ERROR, 0);
141                                 continue;
142                         }
143
144                         if (events[fd].revents & POLLERR)
145                         {
146                                 // Get error number
147                                 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
148                                         errcode = errno;
149                                 if (ref[fd])
150                                         ref[fd]->HandleEvent(EVENT_ERROR, errcode);
151                                 continue;
152                         }
153
154                         if (events[fd].revents & POLLOUT)
155                         {
156                                 // Switch to wanting read again
157                                 // event handlers have to request to write again if they need it
158                                 events[fd].events = POLLIN;
159
160
161                                 if (ref[fd])
162                                         ref[fd]->HandleEvent(EVENT_WRITE);
163                         }
164
165                         if (events[fd].revents & POLLIN)
166                         {
167                                 if (ref[fd])
168                                         ref[fd]->HandleEvent(EVENT_READ);
169                         }
170                 }
171         }
172
173         return i;
174 }
175
176 std::string PollEngine::GetName()
177 {
178         return "poll";
179 }
180