1 #include "fdevent.h"
2 #include "buffer.h"
3 #include "log.h"
4 
5 #include <sys/types.h>
6 
7 #include <unistd.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <errno.h>
12 #include <signal.h>
13 #include <fcntl.h>
14 
15 #ifdef USE_LINUX_EPOLL
16 
17 # include <sys/epoll.h>
18 
fdevent_linux_sysepoll_free(fdevents * ev)19 static void fdevent_linux_sysepoll_free(fdevents *ev) {
20 	close(ev->epoll_fd);
21 	free(ev->epoll_events);
22 }
23 
fdevent_linux_sysepoll_event_del(fdevents * ev,int fde_ndx,int fd)24 static int fdevent_linux_sysepoll_event_del(fdevents *ev, int fde_ndx, int fd) {
25 	struct epoll_event ep;
26 
27 	if (fde_ndx < 0) return -1;
28 
29 	memset(&ep, 0, sizeof(ep));
30 
31 	ep.data.fd = fd;
32 	ep.data.ptr = NULL;
33 
34 	if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fd, &ep)) {
35 		log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
36 			"epoll_ctl failed: ", strerror(errno), ", dying");
37 
38 		SEGFAULT();
39 
40 		return 0;
41 	}
42 
43 
44 	return -1;
45 }
46 
fdevent_linux_sysepoll_event_set(fdevents * ev,int fde_ndx,int fd,int events)47 static int fdevent_linux_sysepoll_event_set(fdevents *ev, int fde_ndx, int fd, int events) {
48 	struct epoll_event ep;
49 	int add = 0;
50 
51 	if (fde_ndx == -1) add = 1;
52 
53 	memset(&ep, 0, sizeof(ep));
54 
55 	ep.events = 0;
56 
57 	if (events & FDEVENT_IN)  ep.events |= EPOLLIN;
58 	if (events & FDEVENT_OUT) ep.events |= EPOLLOUT;
59 
60 	/**
61 	 *
62 	 * with EPOLLET we don't get a FDEVENT_HUP
63 	 * if the close is delay after everything has
64 	 * sent.
65 	 *
66 	 */
67 
68 	ep.events |= EPOLLERR | EPOLLHUP /* | EPOLLET */;
69 
70 	ep.data.ptr = NULL;
71 	ep.data.fd = fd;
72 
73 	if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &ep)) {
74 		log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
75 			"epoll_ctl failed: ", strerror(errno), ", dying");
76 
77 		SEGFAULT();
78 
79 		return 0;
80 	}
81 
82 	return fd;
83 }
84 
fdevent_linux_sysepoll_poll(fdevents * ev,int timeout_ms)85 static int fdevent_linux_sysepoll_poll(fdevents *ev, int timeout_ms) {
86 	return epoll_wait(ev->epoll_fd, ev->epoll_events, ev->maxfds, timeout_ms);
87 }
88 
fdevent_linux_sysepoll_event_get_revent(fdevents * ev,size_t ndx)89 static int fdevent_linux_sysepoll_event_get_revent(fdevents *ev, size_t ndx) {
90 	int events = 0, e;
91 
92 	e = ev->epoll_events[ndx].events;
93 	if (e & EPOLLIN) events |= FDEVENT_IN;
94 	if (e & EPOLLOUT) events |= FDEVENT_OUT;
95 	if (e & EPOLLERR) events |= FDEVENT_ERR;
96 	if (e & EPOLLHUP) events |= FDEVENT_HUP;
97 	if (e & EPOLLPRI) events |= FDEVENT_PRI;
98 
99 	return events;
100 }
101 
fdevent_linux_sysepoll_event_get_fd(fdevents * ev,size_t ndx)102 static int fdevent_linux_sysepoll_event_get_fd(fdevents *ev, size_t ndx) {
103 # if 0
104 	log_error_write(ev->srv, __FILE__, __LINE__, "SD, D",
105 		"fdevent_linux_sysepoll_event_get_fd: ", (int) ndx, ev->epoll_events[ndx].data.fd);
106 # endif
107 
108 	return ev->epoll_events[ndx].data.fd;
109 }
110 
fdevent_linux_sysepoll_event_next_fdndx(fdevents * ev,int ndx)111 static int fdevent_linux_sysepoll_event_next_fdndx(fdevents *ev, int ndx) {
112 	size_t i;
113 
114 	UNUSED(ev);
115 
116 	i = (ndx < 0) ? 0 : ndx + 1;
117 
118 	return i;
119 }
120 
fdevent_linux_sysepoll_init(fdevents * ev)121 int fdevent_linux_sysepoll_init(fdevents *ev) {
122 	ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
123 #define SET(x) \
124 	ev->x = fdevent_linux_sysepoll_##x;
125 
126 	SET(free);
127 	SET(poll);
128 
129 	SET(event_del);
130 	SET(event_set);
131 
132 	SET(event_next_fdndx);
133 	SET(event_get_fd);
134 	SET(event_get_revent);
135 
136 	if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) {
137 		log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
138 			"epoll_create failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
139 
140 		return -1;
141 	}
142 
143 	if (-1 == fcntl(ev->epoll_fd, F_SETFD, FD_CLOEXEC)) {
144 		log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
145 			"fcntl on epoll-fd failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
146 
147 		close(ev->epoll_fd);
148 
149 		return -1;
150 	}
151 
152 	ev->epoll_events = malloc(ev->maxfds * sizeof(*ev->epoll_events));
153 
154 	return 0;
155 }
156 
157 #else
fdevent_linux_sysepoll_init(fdevents * ev)158 int fdevent_linux_sysepoll_init(fdevents *ev) {
159 	UNUSED(ev);
160 
161 	log_error_write(ev->srv, __FILE__, __LINE__, "S",
162 		"linux-sysepoll not supported, try to set server.event-handler = \"poll\" or \"select\"");
163 
164 	return -1;
165 }
166 #endif
167