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