]> jfr.im git - irc/quakenet/newserv.git/blob - core/events-epoll.c
CHANSERV: tell user when they can't attempts to auth any more, and drop max attempts...
[irc/quakenet/newserv.git] / core / events-epoll.c
1 /*
2 * events.c: the event handling core, epoll() version
3 */
4
5 #include <stdio.h>
6 #include <sys/poll.h>
7 #include <sys/epoll.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <string.h>
11 #include <errno.h>
12
13 #include "../lib/array.h"
14 #include "events.h"
15 #include "error.h"
16 #include "hooks.h"
17
18 /* We need to track the handler for each fd - epoll() can
19 * return an fd or a pointer but not both :(. We'll keep the
20 * fd in the epoll_data structure for simplicity. */
21
22 typedef struct {
23 FDHandler handler;
24 } reghandler;
25
26 reghandler *eventhandlers;
27
28 unsigned int maxfds;
29
30 int eventadds;
31 int eventdels;
32 int eventexes;
33
34 /* How many fds are currently registered */
35 int regfds;
36 int epollfd;
37
38 void eventstats(int hooknum, void *arg);
39
40 void inithandlers() {
41 regfds=0;
42 eventadds=eventdels=eventexes=0;
43 maxfds=STARTFDS;
44 eventhandlers=(reghandler *)malloc(maxfds*sizeof(reghandler));
45 memset(eventhandlers,0,maxfds*sizeof(reghandler));
46
47 /* Get an epoll FD */
48 if ((epollfd=epoll_create(STARTFDS))<0) {
49 Error("events",ERR_STOP,"Unable to initialise epoll.");
50 }
51
52 registerhook(HOOK_CORE_STATSREQUEST, &eventstats);
53 }
54
55 void finihandlers() {
56 deregisterhook(HOOK_CORE_STATSREQUEST, &eventstats);
57 free(eventhandlers);
58 }
59
60 /*
61 * checkindex():
62 * Given the number of a new file descriptor, makes sure that the array
63 * will be big enough to deal with it.
64 */
65
66 void checkindex(unsigned index) {
67 int oldmax=maxfds;
68
69 if (index<maxfds) {
70 return;
71 }
72
73 while (maxfds<=index) {
74 maxfds+=GROWFDS;
75 }
76
77 eventhandlers=(reghandler *)realloc((void *)eventhandlers,maxfds*sizeof(reghandler));
78 memset(&eventhandlers[oldmax],0,(maxfds-oldmax)*sizeof(reghandler));
79 }
80
81 /*
82 * polltoepoll():
83 * Converts a poll-style event variable to an epoll one.
84 */
85 unsigned int polltoepoll(short events) {
86 unsigned int epe=EPOLLERR|EPOLLHUP; /* Default event mask */
87
88 if (events & POLLIN) epe |= EPOLLIN;
89 if (events & POLLOUT) epe |= EPOLLOUT;
90 if (events & POLLPRI) epe |= EPOLLPRI;
91
92 return epe;
93 }
94
95 short epolltopoll(unsigned int events) {
96 short e=0;
97
98 if (events & EPOLLIN) e |= POLLIN;
99 if (events & EPOLLOUT) e |= POLLOUT;
100 if (events & EPOLLERR) e |= POLLERR;
101 if (events & EPOLLPRI) e |= POLLPRI;
102 if (events & EPOLLHUP) e |= POLLHUP;
103
104 return e;
105 }
106
107 /*
108 * registerhandler():
109 * Add an fd to the epoll array.
110 */
111
112 int registerhandler(int fd, short events, FDHandler handler) {
113 struct epoll_event epe;
114
115 checkindex(fd);
116
117 /* Check that it's not already registered */
118 if (eventhandlers[fd].handler!=NULL) {
119 Error("events",ERR_WARNING,"Attempting to register already-registered fd %d.",fd);
120 return 1;
121 }
122
123 eventhandlers[fd].handler=handler;
124
125 memset(&epe, 0, sizeof(epe));
126 epe.data.fd=fd;
127 epe.events=polltoepoll(events);
128
129 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &epe)) {
130 Error("events",ERR_WARNING,"Error %d adding fd %d to epoll (events=%d)",errno,fd,epe.events);
131 return 1;
132 }
133
134 eventadds++;
135 regfds++;
136 return 0;
137 }
138
139 /*
140 * deregisterhandler():
141 * Remove an fd from the poll() array.
142 *
143 * The poll() version can't save any time if doclose is set, so
144 * we just do the same work and then close the socket if it's set.
145 *
146 * Now O(1)
147 */
148
149
150 int deregisterhandler(int fd, int doclose) {
151 struct epoll_event epe;
152
153 checkindex(fd);
154
155 /* Check that the handler exists */
156 if (eventhandlers[fd].handler==NULL) {
157 Error("events",ERR_WARNING,"Attempt to deregister unregistered fd: %d",fd);
158 return 1;
159 }
160
161 eventhandlers[fd].handler=NULL;
162
163 if (epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &epe)) {
164 Error("events",ERR_WARNING,"Error deleting FD %d from epoll: %d",fd,errno);
165 }
166
167 if (doclose) {
168 close(fd);
169 }
170
171 eventdels++;
172 regfds--;
173
174 return 0;
175 }
176
177 /*
178 * handleevents():
179 * Call epoll_wait() and handle and call appropiate handlers
180 * for any sockets that come up.
181 */
182
183 int handleevents(int timeout) {
184 int i,res;
185 struct epoll_event epes[100];
186
187 res=epoll_wait(epollfd, epes, 100, timeout);
188
189 if (res<0) {
190 Error("events",ERR_WARNING,"Error in epoll_wait(): %d",errno);
191 return 1;
192 }
193
194 for (i=0;i<res;i++) {
195 (eventhandlers[epes[i].data.fd].handler)(epes[i].data.fd, epolltopoll(epes[i].events));
196 eventexes++;
197 }
198
199 return 0;
200 }
201
202 void eventstats(int hooknum, void *arg) {
203 char buf[512];
204 long level=(long) arg;
205
206 if (level>5) {
207 sprintf(buf,"Events :%7d fds registered, %7d fds deregistered",eventadds,eventdels);
208 triggerhook(HOOK_CORE_STATSREPLY,(void *)buf);
209 sprintf(buf,"Events :%7d events triggered, %6d fds active",eventexes,regfds);
210 triggerhook(HOOK_CORE_STATSREPLY,(void *)buf);
211 }
212 }