]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengines/socketengine_poll.cpp
c05ed25fa4a2b80674ac87c0463ffd7c9ccb7d92
[user/henk/code/inspircd.git] / src / socketengines / socketengine_poll.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2009 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 #include <ulimit.h>
18 #ifdef __FreeBSD__
19         #include <sys/sysctl.h>
20 #endif
21
22 PollEngine::PollEngine(InspIRCd* Instance) : SocketEngine(Instance)
23 {
24         // Poll requires no special setup (which is nice).
25         CurrentSetSize = 0;
26         MAX_DESCRIPTORS = 0;
27
28         ref = new EventHandler* [GetMaxFds()];
29         events = new struct pollfd[GetMaxFds()];
30
31         memset(events, 0, GetMaxFds() * sizeof(struct pollfd));
32         memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
33 }
34
35 PollEngine::~PollEngine()
36 {
37         // No destruction required, either.
38         delete[] ref;
39         delete[] events;
40 }
41
42 bool PollEngine::AddFd(EventHandler* eh)
43 {
44         int fd = eh->GetFd();
45         if ((fd < 0) || (fd > GetMaxFds() - 1))
46         {
47                 ServerInstance->Logs->Log("SOCKET",DEBUG,"AddFd out of range: (fd: %d, max: %d)", fd, GetMaxFds());
48                 return false;
49         }
50
51         if (GetRemainingFds() <= 1)
52         {
53                 ServerInstance->Logs->Log("SOCKET",DEBUG,"No remaining FDs cannot add fd: %d", fd);
54                 return false;
55         }
56
57         if (ref[fd])
58         {
59                 ServerInstance->Logs->Log("SOCKET",DEBUG,"Attempt to add duplicate fd: %d", fd);
60                 return false;
61         }
62
63         ref[fd] = eh;
64         events[fd].fd = fd;
65         if (eh->Readable())
66         {
67                 events[fd].events = POLLIN;
68         }
69         else
70         {
71                 events[fd].events = POLLOUT;
72         }
73
74         ServerInstance->Logs->Log("SOCKET", DEBUG,"New file descriptor: %d (%d)", fd, events[fd].events);
75         CurrentSetSize++;
76         return true;
77 }
78
79 void PollEngine::WantWrite(EventHandler* eh)
80 {
81         events[eh->GetFd()].events = POLLIN | POLLOUT;
82 }
83
84 bool PollEngine::DelFd(EventHandler* eh, bool force)
85 {
86         int fd = eh->GetFd();
87         if ((fd < 0) || (fd > MAX_DESCRIPTORS))
88         {
89                 ServerInstance->Logs->Log("SOCKET", DEBUG, "DelFd out of range: (fd: %d, max: %d)", fd, GetMaxFds());
90                 return false;
91         }
92
93         events[fd].fd = -1;
94         events[fd].events = 0;
95
96         CurrentSetSize--;
97         ref[fd] = NULL;
98
99         ServerInstance->Logs->Log("SOCKET", DEBUG, "Remove file descriptor: %d", fd);
100         return true;
101 }
102
103 int PollEngine::GetMaxFds()
104 {
105 #ifndef __FreeBSD__
106         if (MAX_DESCRIPTORS)
107                 return MAX_DESCRIPTORS;
108
109         int max = ulimit(4, 0);
110         if (max > 0)
111         {
112                 MAX_DESCRIPTORS = max;
113                 return max;
114         }
115         else
116         {
117                 MAX_DESCRIPTORS = 0;
118                 ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets: %s", strerror(errno));
119                 printf("ERROR: Can't determine maximum number of open sockets: %s\n", strerror(errno)));
120                 ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE);
121         }
122         return 0;
123 #else
124         if (!MAX_DESCRIPTORS)
125         {
126                 int mib[2], maxfiles;
127                 size_t len;
128
129                 mib[0] = CTL_KERN;
130                 mib[1] = KERN_MAXFILES;
131                 len = sizeof(maxfiles);
132                 sysctl(mib, 2, &maxfiles, &len, NULL, 0);
133                 MAX_DESCRIPTORS = maxfiles;
134                 return maxfiles;
135         }
136         return MAX_DESCRIPTORS;
137 #endif
138 }
139
140 int PollEngine::GetRemainingFds()
141 {
142         return MAX_DESCRIPTORS - CurrentSetSize;
143 }
144
145 int PollEngine::DispatchEvents()
146 {
147         int i = poll(events, GetMaxFds() - 1, 1000);
148         int fd = 0;
149         socklen_t codesize = sizeof(int);
150         int errcode;
151         int processed = 0;
152
153         if (i > 0)
154         {
155                 for (fd = 0; fd < GetMaxFds() - 1 && processed != i; fd++)
156                 {
157                         if (events[fd].revents)
158                                 processed++;
159
160                         if (events[fd].revents & POLLHUP)
161                         {
162                                 if (ref[fd])
163                                         ref[fd]->HandleEvent(EVENT_ERROR, 0);
164                                 continue;
165                         }
166
167                         if (events[fd].revents & POLLERR)
168                         {
169                                 // Get error number
170                                 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
171                                         errcode = errno;
172                                 if (ref[fd])
173                                         ref[fd]->HandleEvent(EVENT_ERROR, errcode);
174                                 continue;
175                         }
176
177                         if (events[fd].revents & POLLOUT)
178                         {
179                                 // Switch to wanting read again
180                                 // event handlers have to request to write again if they need it
181                                 events[fd].events = POLLIN;
182
183
184                                 if (ref[fd])
185                                         ref[fd]->HandleEvent(EVENT_WRITE);
186                         }
187
188                         if (events[fd].revents & POLLIN)
189                         {
190                                 if (ref[fd])
191                                         ref[fd]->HandleEvent(EVENT_READ);
192                         }
193                 }
194         }
195
196         return i;
197 }
198
199 std::string PollEngine::GetName()
200 {
201         return "poll";
202 }
203