]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengines/socketengine_epoll.cpp
Run configure -update on all svn/git changes
[user/henk/code/inspircd.git] / src / socketengines / socketengine_epoll.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2009 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/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_epoll.h"
17 #include <ulimit.h>
18
19 EPollEngine::EPollEngine()
20 {
21         MAX_DESCRIPTORS = 0;
22         // This is not a maximum, just a hint at the eventual number of sockets that may be polled.
23         EngineHandle = epoll_create(GetMaxFds() / 4);
24
25         if (EngineHandle == -1)
26         {
27                 ServerInstance->Logs->Log("SOCKET",DEFAULT, "ERROR: Could not initialize socket engine: %s", strerror(errno));
28                 ServerInstance->Logs->Log("SOCKET",DEFAULT, "ERROR: Your kernel probably does not have the proper features. This is a fatal error, exiting now.");
29                 printf("ERROR: Could not initialize socket engine: %s\n", strerror(errno));
30                 printf("ERROR: Your kernel probably does not have the proper features. This is a fatal error, exiting now.\n");
31                 ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE);
32         }
33         CurrentSetSize = 0;
34
35         ref = new EventHandler* [GetMaxFds()];
36         events = new struct epoll_event[GetMaxFds()];
37
38         memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
39 }
40
41 EPollEngine::~EPollEngine()
42 {
43         this->Close(EngineHandle);
44         delete[] ref;
45         delete[] events;
46 }
47
48 bool EPollEngine::AddFd(EventHandler* eh, bool writeFirst)
49 {
50         int fd = eh->GetFd();
51         if ((fd < 0) || (fd > GetMaxFds() - 1))
52         {
53                 ServerInstance->Logs->Log("SOCKET",DEBUG,"AddFd out of range: (fd: %d, max: %d)", fd, GetMaxFds());
54                 return false;
55         }
56
57         if (GetRemainingFds() <= 1)
58         {
59                 ServerInstance->Logs->Log("SOCKET",DEBUG,"No remaining FDs cannot add fd: %d", fd);
60                 return false;
61         }
62
63         if (ref[fd])
64         {
65                 ServerInstance->Logs->Log("SOCKET",DEBUG,"Attempt to add duplicate fd: %d", fd);
66                 return false;
67         }
68
69         struct epoll_event ev;
70         memset(&ev,0,sizeof(ev));
71         ev.events = writeFirst ? EPOLLOUT : EPOLLIN;
72         ev.data.fd = fd;
73         int i = epoll_ctl(EngineHandle, EPOLL_CTL_ADD, fd, &ev);
74         if (i < 0)
75         {
76                 ServerInstance->Logs->Log("SOCKET",DEBUG,"Error adding fd: %d to socketengine: %s", fd, strerror(errno));
77                 return false;
78         }
79
80         ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
81
82         ref[fd] = eh;
83         CurrentSetSize++;
84         return true;
85 }
86
87 void EPollEngine::WantWrite(EventHandler* eh)
88 {
89         /** Use oneshot so that the system removes the writeable
90          * status for us and saves us a call.
91          */
92         struct epoll_event ev;
93         memset(&ev,0,sizeof(ev));
94         ev.events = EPOLLIN | EPOLLOUT;
95         ev.data.fd = eh->GetFd();
96         epoll_ctl(EngineHandle, EPOLL_CTL_MOD, eh->GetFd(), &ev);
97 }
98
99 bool EPollEngine::DelFd(EventHandler* eh, bool force)
100 {
101         int fd = eh->GetFd();
102         if ((fd < 0) || (fd > GetMaxFds() - 1))
103         {
104                 ServerInstance->Logs->Log("SOCKET",DEBUG,"DelFd out of range: (fd: %d, max: %d)", fd, GetMaxFds());
105                 return false;
106         }
107
108         struct epoll_event ev;
109         memset(&ev,0,sizeof(ev));
110         ev.data.fd = fd;
111         int i = epoll_ctl(EngineHandle, EPOLL_CTL_DEL, fd, &ev);
112
113         if (i < 0 && !force)
114         {
115                 ServerInstance->Logs->Log("SOCKET",DEBUG,"Cant remove socket: %s", strerror(errno));
116                 return false;
117         }
118
119         ref[fd] = NULL;
120         CurrentSetSize--;
121
122         ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
123         return true;
124 }
125
126 int EPollEngine::GetMaxFds()
127 {
128         if (MAX_DESCRIPTORS)
129                 return MAX_DESCRIPTORS;
130
131         int max = ulimit(4, 0);
132         if (max > 0)
133         {
134                 MAX_DESCRIPTORS = max;
135                 return max;
136         }
137         else
138         {
139                 ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets!");
140                 printf("ERROR: Can't determine maximum number of open sockets!\n");
141                 ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE);
142         }
143         return 0;
144 }
145
146 int EPollEngine::GetRemainingFds()
147 {
148         return GetMaxFds() - CurrentSetSize;
149 }
150
151 int EPollEngine::DispatchEvents()
152 {
153         socklen_t codesize = sizeof(int);
154         int errcode;
155         int i = epoll_wait(EngineHandle, events, GetMaxFds() - 1, 1000);
156
157         TotalEvents += i;
158
159         for (int j = 0; j < i; j++)
160         {
161                 if (events[j].events & EPOLLHUP)
162                 {
163                         ErrorEvents++;
164                         if (ref[events[j].data.fd])
165                                 ref[events[j].data.fd]->HandleEvent(EVENT_ERROR, 0);
166                         continue;
167                 }
168                 if (events[j].events & EPOLLERR)
169                 {
170                         ErrorEvents++;
171                         /* Get error number */
172                         if (getsockopt(events[j].data.fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
173                                 errcode = errno;
174                         if (ref[events[j].data.fd])
175                                 ref[events[j].data.fd]->HandleEvent(EVENT_ERROR, errcode);
176                         continue;
177                 }
178                 if (events[j].events & EPOLLOUT)
179                 {
180                         WriteEvents++;
181                         struct epoll_event ev;
182                         memset(&ev,0,sizeof(ev));
183                         ev.events = EPOLLIN;
184                         ev.data.fd = events[j].data.fd;
185                         epoll_ctl(EngineHandle, EPOLL_CTL_MOD, events[j].data.fd, &ev);
186                         if (ref[events[j].data.fd])
187                                 ref[events[j].data.fd]->HandleEvent(EVENT_WRITE);
188                 }
189                 else
190                 {
191                         ReadEvents++;
192                         if (ref[events[j].data.fd])
193                                 ref[events[j].data.fd]->HandleEvent(EVENT_READ);
194                 }
195         }
196
197         return i;
198 }
199
200 std::string EPollEngine::GetName()
201 {
202         return "epoll";
203 }
204