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 fd_close_on_exec(fd
);
274 if ((ev
) && (ev
->fcntl_set
)) return ev
->fcntl_set(ev
, fd
);
276 return fcntl(fd
, F_SETFL
, O_NONBLOCK
| O_RDWR
);
283 int fdevent_event_next_fdndx(fdevents
*ev
, int ndx
) {
284 if (ev
->event_next_fdndx
) return ev
->event_next_fdndx(ev
, ndx
);
290 #include <netinet/tcp.h>
291 #if (defined(__APPLE__) && defined(__MACH__)) \
292 || defined(__FreeBSD__) || defined(__NetBSD__) \
293 || defined(__OpenBSD__) || defined(__DragonFly__)
294 #include <netinet/tcp_fsm.h>
297 /* fd must be TCP socket (AF_INET, AF_INET6), end-of-stream recv() 0 bytes */
298 int fdevent_is_tcp_half_closed(int fd
) {
299 #ifdef TCP_CONNECTION_INFO /* Darwin */
300 struct tcp_connection_info tcpi
;
301 socklen_t tlen
= sizeof(tcpi
);
302 return (0 == getsockopt(fd
, IPPROTO_TCP
, TCP_CONNECTION_INFO
, &tcpi
, &tlen
)
303 && tcpi
.tcpi_state
== TCPS_CLOSE_WAIT
);
304 #elif defined(TCP_INFO) && defined(TCPS_CLOSE_WAIT)
305 /* FreeBSD, NetBSD (not present in OpenBSD or DragonFlyBSD) */
306 struct tcp_info tcpi
;
307 socklen_t tlen
= sizeof(tcpi
);
308 return (0 == getsockopt(fd
, IPPROTO_TCP
, TCP_INFO
, &tcpi
, &tlen
)
309 && tcpi
.tcpi_state
== TCPS_CLOSE_WAIT
);
310 #elif defined(TCP_INFO) && defined(__linux__)
311 /* Linux (TCP_CLOSE_WAIT is enum, so can not #ifdef TCP_CLOSE_WAIT) */
312 struct tcp_info tcpi
;
313 socklen_t tlen
= sizeof(tcpi
);/*SOL_TCP == IPPROTO_TCP*/
314 return (0 == getsockopt(fd
, SOL_TCP
, TCP_INFO
, &tcpi
, &tlen
)
315 && tcpi
.tcpi_state
== TCP_CLOSE_WAIT
);
318 /*(0 != getpeername() error might indicate TCP RST, but success
319 * would not differentiate between half-close and full-close)*/
320 return 0; /* false (not half-closed) or TCP state unknown */