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