2 #include "missing_accept4.h"
3 #include "sock_for_fd.h"
5 static VALUE localhost
;
6 static VALUE cClientSocket
;
7 static VALUE cKgio_Socket
;
8 static VALUE mSocketMethods
;
9 static VALUE iv_kgio_addr
;
11 #if defined(__linux__)
12 static int accept4_flags
= SOCK_CLOEXEC
;
14 static int accept4_flags
= SOCK_CLOEXEC
| SOCK_NONBLOCK
;
20 struct sockaddr
*addr
;
25 * Sets the default class for newly accepted sockets. This is
26 * legacy behavior, kgio_accept and kgio_tryaccept now take optional
27 * class arguments to override this value.
29 static VALUE
set_accepted(VALUE klass
, VALUE aclass
)
34 aclass
= cKgio_Socket
;
36 tmp
= rb_funcall(aclass
, rb_intern("included_modules"), 0, 0);
37 tmp
= rb_funcall(tmp
, rb_intern("include?"), 1, mSocketMethods
);
40 rb_raise(rb_eTypeError
,
41 "class must include Kgio::SocketMethods");
43 cClientSocket
= aclass
;
49 * Returns the default class for newly accepted sockets when kgio_accept
50 * or kgio_tryaccept are not passed arguments
52 static VALUE
get_accepted(VALUE klass
)
57 static VALUE
xaccept(void *ptr
)
59 struct accept_args
*a
= ptr
;
62 rv
= accept_fn(a
->fd
, a
->addr
, a
->addrlen
, a
->flags
);
63 if (rv
== -1 && errno
== ENOSYS
&& accept_fn
!= my_accept4
) {
64 accept_fn
= my_accept4
;
65 rv
= accept_fn(a
->fd
, a
->addr
, a
->addrlen
, a
->flags
);
71 #ifdef HAVE_RB_THREAD_BLOCKING_REGION
73 # include "blocking_io_region.h"
75 * Try to use a (real) blocking accept() since that can prevent
76 * thundering herds under Linux:
77 * http://www.citi.umich.edu/projects/linux-scalability/reports/accept.html
79 * So we periodically disable non-blocking, but not too frequently
80 * because other processes may set non-blocking (especially during
81 * a process upgrade) with Rainbows! concurrency model changes.
83 static int thread_accept(struct accept_args
*a
, int force_nonblock
)
86 set_nonblocking(a
->fd
);
87 return (int)rb_thread_io_blocking_region(xaccept
, a
, a
->fd
);
90 static void set_blocking_or_block(int fd
)
92 static time_t last_set_blocking
;
93 time_t now
= time(NULL
);
95 if (last_set_blocking
== 0) {
96 last_set_blocking
= now
;
97 (void)rb_io_wait_readable(fd
);
98 } else if ((now
- last_set_blocking
) <= 5) {
99 (void)rb_io_wait_readable(fd
);
101 int flags
= fcntl(fd
, F_GETFL
);
103 rb_sys_fail("fcntl(F_GETFL)");
104 if (flags
& O_NONBLOCK
) {
105 flags
= fcntl(fd
, F_SETFL
, flags
& ~O_NONBLOCK
);
107 rb_sys_fail("fcntl(F_SETFL)");
109 last_set_blocking
= now
;
112 #else /* ! HAVE_RB_THREAD_BLOCKING_REGION */
113 # include <rubysig.h>
114 static int thread_accept(struct accept_args
*a
, int force_nonblock
)
118 /* always use non-blocking accept() under 1.8 for green threads */
119 set_nonblocking(a
->fd
);
121 rv
= (int)xaccept(a
);
125 #define set_blocking_or_block(fd) (void)rb_io_wait_readable(fd)
126 #endif /* ! HAVE_RB_THREAD_BLOCKING_REGION */
128 static VALUE
acceptor(int argc
, const VALUE
*argv
)
131 return cClientSocket
; /* default, legacy behavior */
135 rb_raise(rb_eArgError
, "wrong number of arguments (%d for 1)", argc
);
138 #if defined(__linux__)
139 # define post_accept kgio_autopush_accept
141 # define post_accept(a,b) for(;0;)
145 my_accept(VALUE accept_io
, VALUE klass
,
146 struct sockaddr
*addr
, socklen_t
*addrlen
, int nonblock
)
150 struct accept_args a
;
152 a
.fd
= my_fileno(accept_io
);
155 a
.flags
= accept4_flags
;
157 client
= thread_accept(&a
, nonblock
);
163 set_blocking_or_block(a
.fd
);
166 #endif /* ECONNABORTED */
180 client
= thread_accept(&a
, nonblock
);
185 rb_sys_fail("accept");
188 client_io
= sock_for_fd(klass
, client
);
189 post_accept(accept_io
, client_io
);
193 static VALUE
in_addr_set(VALUE io
, struct sockaddr_storage
*addr
, socklen_t len
)
199 switch (addr
->ss_family
) {
201 host_len
= (long)INET_ADDRSTRLEN
;
204 host_len
= (long)INET6_ADDRSTRLEN
;
207 rb_raise(rb_eRuntimeError
, "unsupported address family");
209 host
= rb_str_new(NULL
, host_len
);
210 host_ptr
= RSTRING_PTR(host
);
211 rc
= getnameinfo((struct sockaddr
*)addr
, len
,
212 host_ptr
, host_len
, NULL
, 0, NI_NUMERICHOST
);
214 rb_raise(rb_eRuntimeError
, "getnameinfo: %s", gai_strerror(rc
));
215 rb_str_set_len(host
, strlen(host_ptr
));
216 return rb_ivar_set(io
, iv_kgio_addr
, host
);
222 * io.kgio_addr! => refreshes the given sock address
224 static VALUE
addr_bang(VALUE io
)
226 int fd
= my_fileno(io
);
227 struct sockaddr_storage addr
;
228 socklen_t len
= sizeof(struct sockaddr_storage
);
230 if (getpeername(fd
, (struct sockaddr
*)&addr
, &len
) != 0)
231 rb_sys_fail("getpeername");
233 if (addr
.ss_family
== AF_UNIX
)
234 return rb_ivar_set(io
, iv_kgio_addr
, localhost
);
236 return in_addr_set(io
, &addr
, len
);
242 * server = Kgio::TCPServer.new('0.0.0.0', 80)
243 * server.kgio_tryaccept -> Kgio::Socket or nil
245 * Initiates a non-blocking accept and returns a generic Kgio::Socket
246 * object with the kgio_addr attribute set to the IP address of the
247 * connected client on success.
249 * Returns nil on EAGAIN, and raises on other errors.
251 * An optional class argument may be specified to override the
252 * Kgio::Socket-class return value:
254 * server.kgio_tryaccept(MySocket) -> MySocket
256 static VALUE
tcp_tryaccept(int argc
, VALUE
*argv
, VALUE io
)
258 struct sockaddr_storage addr
;
259 socklen_t addrlen
= sizeof(struct sockaddr_storage
);
260 VALUE klass
= acceptor(argc
, argv
);
261 VALUE rv
= my_accept(io
, klass
, (struct sockaddr
*)&addr
, &addrlen
, 1);
264 in_addr_set(rv
, &addr
, addrlen
);
271 * server = Kgio::TCPServer.new('0.0.0.0', 80)
272 * server.kgio_accept -> Kgio::Socket or nil
274 * Initiates a blocking accept and returns a generic Kgio::Socket
275 * object with the kgio_addr attribute set to the IP address of
276 * the client on success.
278 * On Ruby implementations using native threads, this can use a blocking
279 * accept(2) (or accept4(2)) system call to avoid thundering herds.
281 * An optional class argument may be specified to override the
282 * Kgio::Socket-class return value:
284 * server.kgio_accept(MySocket) -> MySocket
286 static VALUE
tcp_accept(int argc
, VALUE
*argv
, VALUE io
)
288 struct sockaddr_storage addr
;
289 socklen_t addrlen
= sizeof(struct sockaddr_storage
);
290 VALUE klass
= acceptor(argc
, argv
);
291 VALUE rv
= my_accept(io
, klass
, (struct sockaddr
*)&addr
, &addrlen
, 0);
293 in_addr_set(rv
, &addr
, addrlen
);
300 * server = Kgio::UNIXServer.new("/path/to/unix/socket")
301 * server.kgio_tryaccept -> Kgio::Socket or nil
303 * Initiates a non-blocking accept and returns a generic Kgio::Socket
304 * object with the kgio_addr attribute set (to the value of
305 * Kgio::LOCALHOST) on success.
307 * Returns nil on EAGAIN, and raises on other errors.
309 * An optional class argument may be specified to override the
310 * Kgio::Socket-class return value:
312 * server.kgio_tryaccept(MySocket) -> MySocket
314 static VALUE
unix_tryaccept(int argc
, VALUE
*argv
, VALUE io
)
316 VALUE klass
= acceptor(argc
, argv
);
317 VALUE rv
= my_accept(io
, klass
, NULL
, NULL
, 1);
320 rb_ivar_set(rv
, iv_kgio_addr
, localhost
);
327 * server = Kgio::UNIXServer.new("/path/to/unix/socket")
328 * server.kgio_accept -> Kgio::Socket or nil
330 * Initiates a blocking accept and returns a generic Kgio::Socket
331 * object with the kgio_addr attribute set (to the value of
332 * Kgio::LOCALHOST) on success.
334 * On Ruby implementations using native threads, this can use a blocking
335 * accept(2) (or accept4(2)) system call to avoid thundering herds.
337 * An optional class argument may be specified to override the
338 * Kgio::Socket-class return value:
340 * server.kgio_accept(MySocket) -> MySocket
342 static VALUE
unix_accept(int argc
, VALUE
*argv
, VALUE io
)
344 VALUE klass
= acceptor(argc
, argv
);
345 VALUE rv
= my_accept(io
, klass
, NULL
, NULL
, 0);
347 rb_ivar_set(rv
, iv_kgio_addr
, localhost
);
354 * Kgio.accept_cloexec? -> true or false
356 * Returns true if newly accepted Kgio::Sockets are created with the
357 * FD_CLOEXEC file descriptor flag, false if not.
359 static VALUE
get_cloexec(VALUE mod
)
361 return (accept4_flags
& SOCK_CLOEXEC
) == SOCK_CLOEXEC
? Qtrue
: Qfalse
;
368 * Kgio.accept_nonblock? -> true or false
370 * Returns true if newly accepted Kgio::Sockets are created with the
371 * O_NONBLOCK file status flag, false if not.
373 static VALUE
get_nonblock(VALUE mod
)
375 return (accept4_flags
& SOCK_NONBLOCK
)==SOCK_NONBLOCK
? Qtrue
: Qfalse
;
381 * Kgio.accept_cloexec = true
382 * Kgio.accept_cloexec = false
384 * Sets whether or not Kgio::Socket objects created by
385 * TCPServer#kgio_accept,
386 * TCPServer#kgio_tryaccept,
387 * UNIXServer#kgio_accept,
388 * and UNIXServer#kgio_tryaccept
389 * are created with the FD_CLOEXEC file descriptor flag.
391 * This is on by default, as there is little reason to deal to enable
392 * it for client sockets on a socket server.
394 static VALUE
set_cloexec(VALUE mod
, VALUE boolean
)
396 switch (TYPE(boolean
)) {
398 accept4_flags
|= SOCK_CLOEXEC
;
401 accept4_flags
&= ~SOCK_CLOEXEC
;
404 rb_raise(rb_eTypeError
, "not true or false");
411 * Kgio.accept_nonblock = true
412 * Kgio.accept_nonblock = false
414 * Sets whether or not Kgio::Socket objects created by
415 * TCPServer#kgio_accept,
416 * TCPServer#kgio_tryaccept,
417 * UNIXServer#kgio_accept,
418 * and UNIXServer#kgio_tryaccept
419 * are created with the O_NONBLOCK file status flag.
421 * This defaults to +false+ for GNU/Linux where MSG_DONTWAIT is
422 * available (and on newer GNU/Linux, accept4() may also set
423 * the non-blocking flag. This defaults to +true+ on non-GNU/Linux
426 static VALUE
set_nonblock(VALUE mod
, VALUE boolean
)
428 switch (TYPE(boolean
)) {
430 accept4_flags
|= SOCK_NONBLOCK
;
433 accept4_flags
&= ~SOCK_NONBLOCK
;
436 rb_raise(rb_eTypeError
, "not true or false");
440 void init_kgio_accept(void)
442 VALUE cUNIXServer
, cTCPServer
;
443 VALUE mKgio
= rb_define_module("Kgio");
445 localhost
= rb_const_get(mKgio
, rb_intern("LOCALHOST"));
446 cKgio_Socket
= rb_const_get(mKgio
, rb_intern("Socket"));
447 cClientSocket
= cKgio_Socket
;
448 mSocketMethods
= rb_const_get(mKgio
, rb_intern("SocketMethods"));
450 rb_define_method(mSocketMethods
, "kgio_addr!", addr_bang
, 0);
452 rb_define_singleton_method(mKgio
, "accept_cloexec?", get_cloexec
, 0);
453 rb_define_singleton_method(mKgio
, "accept_cloexec=", set_cloexec
, 1);
454 rb_define_singleton_method(mKgio
, "accept_nonblock?", get_nonblock
, 0);
455 rb_define_singleton_method(mKgio
, "accept_nonblock=", set_nonblock
, 1);
456 rb_define_singleton_method(mKgio
, "accept_class=", set_accepted
, 1);
457 rb_define_singleton_method(mKgio
, "accept_class", get_accepted
, 0);
460 * Document-class: Kgio::UNIXServer
462 * Kgio::UNIXServer should be used in place of the plain UNIXServer
463 * when kgio_accept and kgio_tryaccept methods are needed.
465 cUNIXServer
= rb_const_get(rb_cObject
, rb_intern("UNIXServer"));
466 cUNIXServer
= rb_define_class_under(mKgio
, "UNIXServer", cUNIXServer
);
467 rb_define_method(cUNIXServer
, "kgio_tryaccept", unix_tryaccept
, -1);
468 rb_define_method(cUNIXServer
, "kgio_accept", unix_accept
, -1);
471 * Document-class: Kgio::TCPServer
473 * Kgio::TCPServer should be used in place of the plain TCPServer
474 * when kgio_accept and kgio_tryaccept methods are needed.
476 cTCPServer
= rb_const_get(rb_cObject
, rb_intern("TCPServer"));
477 cTCPServer
= rb_define_class_under(mKgio
, "TCPServer", cTCPServer
);
479 rb_define_method(cTCPServer
, "kgio_tryaccept", tcp_tryaccept
, -1);
480 rb_define_method(cTCPServer
, "kgio_accept", tcp_accept
, -1);
482 iv_kgio_addr
= rb_intern("@kgio_addr");