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