17 fdevents
*fdevent_init(server
*srv
, size_t maxfds
, fdevent_handler_t type
) {
20 ev
= calloc(1, sizeof(*ev
));
21 force_assert(NULL
!= ev
);
23 ev
->fdarray
= calloc(maxfds
, sizeof(*ev
->fdarray
));
24 force_assert(NULL
!= ev
->fdarray
);
29 case FDEVENT_HANDLER_POLL
:
30 if (0 != fdevent_poll_init(ev
)) {
31 log_error_write(srv
, __FILE__
, __LINE__
, "S",
32 "event-handler poll failed");
36 case FDEVENT_HANDLER_SELECT
:
37 if (0 != fdevent_select_init(ev
)) {
38 log_error_write(srv
, __FILE__
, __LINE__
, "S",
39 "event-handler select failed");
43 case FDEVENT_HANDLER_LINUX_SYSEPOLL
:
44 if (0 != fdevent_linux_sysepoll_init(ev
)) {
45 log_error_write(srv
, __FILE__
, __LINE__
, "S",
46 "event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"");
50 case FDEVENT_HANDLER_SOLARIS_DEVPOLL
:
51 if (0 != fdevent_solaris_devpoll_init(ev
)) {
52 log_error_write(srv
, __FILE__
, __LINE__
, "S",
53 "event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"");
57 case FDEVENT_HANDLER_SOLARIS_PORT
:
58 if (0 != fdevent_solaris_port_init(ev
)) {
59 log_error_write(srv
, __FILE__
, __LINE__
, "S",
60 "event-handler solaris-eventports failed, try to set server.event-handler = \"poll\" or \"select\"");
64 case FDEVENT_HANDLER_FREEBSD_KQUEUE
:
65 if (0 != fdevent_freebsd_kqueue_init(ev
)) {
66 log_error_write(srv
, __FILE__
, __LINE__
, "S",
67 "event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"");
71 case FDEVENT_HANDLER_LIBEV
:
72 if (0 != fdevent_libev_init(ev
)) {
73 log_error_write(srv
, __FILE__
, __LINE__
, "S",
74 "event-handler libev failed, try to set server.event-handler = \"poll\" or \"select\"");
78 case FDEVENT_HANDLER_UNSET
:
86 log_error_write(srv
, __FILE__
, __LINE__
, "S",
87 "event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"");
91 void fdevent_free(fdevents
*ev
) {
95 if (ev
->free
) ev
->free(ev
);
97 for (i
= 0; i
< ev
->maxfds
; i
++) {
98 if (ev
->fdarray
[i
] > (fdnode
*)0x2) free(ev
->fdarray
[i
]);
105 int fdevent_reset(fdevents
*ev
) {
106 if (ev
->reset
) return ev
->reset(ev
);
111 static fdnode
*fdnode_init(void) {
114 fdn
= calloc(1, sizeof(*fdn
));
115 force_assert(NULL
!= fdn
);
120 static void fdnode_free(fdnode
*fdn
) {
124 int fdevent_register(fdevents
*ev
, int fd
, fdevent_handler handler
, void *ctx
) {
128 fdn
->handler
= handler
;
131 fdn
->handler_ctx
= NULL
;
134 ev
->fdarray
[fd
] = fdn
;
139 int fdevent_unregister(fdevents
*ev
, int fd
) {
143 fdn
= ev
->fdarray
[fd
];
147 ev
->fdarray
[fd
] = NULL
;
152 void fdevent_sched_close(fdevents
*ev
, int fd
, int issock
) {
154 ev
->fdarray
[fd
] = (issock
? (fdnode
*)0x1 : (fdnode
*)0x2);
155 if (ev
->highfd
< fd
) ev
->highfd
= fd
;
158 void fdevent_sched_run(server
*srv
, fdevents
*ev
) {
159 const int highfd
= ev
->highfd
;
160 for (int fd
= 0; fd
<= highfd
; ++fd
) {
161 fdnode
* const fdn
= ev
->fdarray
[fd
];
163 if (!((uintptr_t)fdn
& 0x3)) continue;
165 if (fdn
== (fdnode
*)0x1) {
166 rc
= closesocket(fd
);
168 else if (fdn
== (fdnode
*)0x2) {
176 log_error_write(srv
, __FILE__
, __LINE__
, "sds", "close failed ", fd
, strerror(errno
));
179 ev
->fdarray
[fd
] = NULL
;
185 void fdevent_event_del(fdevents
*ev
, int *fde_ndx
, int fd
) {
186 if (-1 == fd
) return;
187 if (ev
->fdarray
[fd
] <= (fdnode
*)0x2) return;
189 if (ev
->event_del
) *fde_ndx
= ev
->event_del(ev
, *fde_ndx
, fd
);
190 ev
->fdarray
[fd
]->events
= 0;
193 void fdevent_event_set(fdevents
*ev
, int *fde_ndx
, int fd
, int events
) {
194 if (-1 == fd
) return;
196 /*(Note: skips registering with kernel if initial events is 0,
197 * so caller should pass non-zero events for initial registration.
198 * If never registered due to never being called with non-zero events,
199 * then FDEVENT_HUP or FDEVENT_ERR will never be returned.) */
200 if (ev
->fdarray
[fd
]->events
== events
) return;/*(no change; nothing to do)*/
202 if (ev
->event_set
) *fde_ndx
= ev
->event_set(ev
, *fde_ndx
, fd
, events
);
203 ev
->fdarray
[fd
]->events
= events
;
206 void fdevent_event_add(fdevents
*ev
, int *fde_ndx
, int fd
, int event
) {
208 if (-1 == fd
) return;
210 events
= ev
->fdarray
[fd
]->events
;
211 if ((events
& event
) || 0 == event
) return; /*(no change; nothing to do)*/
214 if (ev
->event_set
) *fde_ndx
= ev
->event_set(ev
, *fde_ndx
, fd
, events
);
215 ev
->fdarray
[fd
]->events
= events
;
218 void fdevent_event_clr(fdevents
*ev
, int *fde_ndx
, int fd
, int event
) {
220 if (-1 == fd
) return;
222 events
= ev
->fdarray
[fd
]->events
;
223 if (!(events
& event
)) return; /*(no change; nothing to do)*/
226 if (ev
->event_set
) *fde_ndx
= ev
->event_set(ev
, *fde_ndx
, fd
, events
);
227 ev
->fdarray
[fd
]->events
= events
;
230 int fdevent_poll(fdevents
*ev
, int timeout_ms
) {
231 if (ev
->poll
== NULL
) SEGFAULT();
232 return ev
->poll(ev
, timeout_ms
);
235 int fdevent_event_get_revent(fdevents
*ev
, size_t ndx
) {
236 if (ev
->event_get_revent
== NULL
) SEGFAULT();
238 return ev
->event_get_revent(ev
, ndx
);
241 int fdevent_event_get_fd(fdevents
*ev
, size_t ndx
) {
242 if (ev
->event_get_fd
== NULL
) SEGFAULT();
244 return ev
->event_get_fd(ev
, ndx
);
247 fdevent_handler
fdevent_get_handler(fdevents
*ev
, int fd
) {
248 if (ev
->fdarray
[fd
] == NULL
) SEGFAULT();
249 if ((uintptr_t)ev
->fdarray
[fd
] & 0x3) return NULL
;
250 if (ev
->fdarray
[fd
]->fd
!= fd
) SEGFAULT();
252 return ev
->fdarray
[fd
]->handler
;
255 void * fdevent_get_context(fdevents
*ev
, int fd
) {
256 if (ev
->fdarray
[fd
] == NULL
) SEGFAULT();
257 if ((uintptr_t)ev
->fdarray
[fd
] & 0x3) return NULL
;
258 if (ev
->fdarray
[fd
]->fd
!= fd
) SEGFAULT();
260 return ev
->fdarray
[fd
]->ctx
;
263 void fd_close_on_exec(int fd
) {
266 force_assert(-1 != fcntl(fd
, F_SETFD
, FD_CLOEXEC
));
272 int fdevent_fcntl_set(fdevents
*ev
, int fd
) {
273 return ((ev
) && (ev
->fcntl_set
)) ? ev
->fcntl_set(ev
, fd
) : 0;
276 int fdevent_fcntl_set_nb(fdevents
*ev
, int fd
) {
277 if ((ev
) && (ev
->fcntl_set
)) return ev
->fcntl_set(ev
, fd
);
279 return fcntl(fd
, F_SETFL
, O_NONBLOCK
| O_RDWR
);
285 int fdevent_fcntl_set_nb_cloexec(fdevents
*ev
, int fd
) {
286 fd_close_on_exec(fd
);
287 return fdevent_fcntl_set_nb(ev
, fd
);
290 int fdevent_fcntl_set_nb_cloexec_sock(fdevents
*ev
, int fd
) {
291 #if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
292 return ((ev
) && (ev
->fcntl_set
)) ? ev
->fcntl_set(ev
, fd
) : 0;
294 return fdevent_fcntl_set_nb_cloexec(ev
, fd
);
298 int fdevent_socket_cloexec(int domain
, int type
, int protocol
) {
300 return socket(domain
, type
| SOCK_CLOEXEC
, protocol
);
303 if (-1 != (fd
= socket(domain
, type
, protocol
))) {
305 fcntl(fd
, F_SETFD
, FD_CLOEXEC
);
312 int fdevent_socket_nb_cloexec(int domain
, int type
, int protocol
) {
314 return socket(domain
, type
| SOCK_CLOEXEC
| SOCK_NONBLOCK
, protocol
);
317 if (-1 != (fd
= socket(domain
, type
, protocol
))) {
319 fcntl(fd
, F_SETFD
, FD_CLOEXEC
);
322 fcntl(fd
, F_SETFL
, O_NONBLOCK
| O_RDWR
);
333 int fdevent_open_cloexec(const char *pathname
, int flags
, mode_t mode
) {
335 return open(pathname
, flags
| O_CLOEXEC
| O_NOCTTY
, mode
);
337 int fd
= open(pathname
, flags
| O_NOCTTY
, mode
);
340 fcntl(fd
, F_SETFD
, FD_CLOEXEC
);
347 int fdevent_event_next_fdndx(fdevents
*ev
, int ndx
) {
348 if (ev
->event_next_fdndx
) return ev
->event_next_fdndx(ev
, ndx
);
354 #include <netinet/tcp.h>
355 #if (defined(__APPLE__) && defined(__MACH__)) \
356 || defined(__FreeBSD__) || defined(__NetBSD__) \
357 || defined(__OpenBSD__) || defined(__DragonFly__)
358 #include <netinet/tcp_fsm.h>
361 /* fd must be TCP socket (AF_INET, AF_INET6), end-of-stream recv() 0 bytes */
362 int fdevent_is_tcp_half_closed(int fd
) {
363 #ifdef TCP_CONNECTION_INFO /* Darwin */
364 struct tcp_connection_info tcpi
;
365 socklen_t tlen
= sizeof(tcpi
);
366 return (0 == getsockopt(fd
, IPPROTO_TCP
, TCP_CONNECTION_INFO
, &tcpi
, &tlen
)
367 && tcpi
.tcpi_state
== TCPS_CLOSE_WAIT
);
368 #elif defined(TCP_INFO) && defined(TCPS_CLOSE_WAIT)
369 /* FreeBSD, NetBSD (not present in OpenBSD or DragonFlyBSD) */
370 struct tcp_info tcpi
;
371 socklen_t tlen
= sizeof(tcpi
);
372 return (0 == getsockopt(fd
, IPPROTO_TCP
, TCP_INFO
, &tcpi
, &tlen
)
373 && tcpi
.tcpi_state
== TCPS_CLOSE_WAIT
);
374 #elif defined(TCP_INFO) && defined(__linux__)
375 /* Linux (TCP_CLOSE_WAIT is enum, so can not #ifdef TCP_CLOSE_WAIT) */
376 struct tcp_info tcpi
;
377 socklen_t tlen
= sizeof(tcpi
);/*SOL_TCP == IPPROTO_TCP*/
378 return (0 == getsockopt(fd
, SOL_TCP
, TCP_INFO
, &tcpi
, &tlen
)
379 && tcpi
.tcpi_state
== TCP_CLOSE_WAIT
);
382 /*(0 != getpeername() error might indicate TCP RST, but success
383 * would not differentiate between half-close and full-close)*/
384 return 0; /* false (not half-closed) or TCP state unknown */