2 #include "missing_accept4.h"
3 #include "sock_for_fd.h"
7 static VALUE localhost
;
8 static VALUE cClientSocket
;
9 static VALUE cKgio_Socket
;
10 static VALUE mSocketMethods
;
11 static VALUE iv_kgio_addr
;
13 #if defined(__linux__)
14 static int accept4_flags
= SOCK_CLOEXEC
;
16 static int accept4_flags
= SOCK_CLOEXEC
| SOCK_NONBLOCK
;
22 struct sockaddr
*addr
;
29 * Sets the default class for newly accepted sockets. This is
30 * legacy behavior, kgio_accept and kgio_tryaccept now take optional
31 * class arguments to override this value.
33 static VALUE
set_accepted(VALUE klass
, VALUE aclass
)
38 aclass
= cKgio_Socket
;
40 tmp
= rb_funcall(aclass
, rb_intern("included_modules"), 0, 0);
41 tmp
= rb_funcall(tmp
, rb_intern("include?"), 1, mSocketMethods
);
44 rb_raise(rb_eTypeError
,
45 "class must include Kgio::SocketMethods");
47 cClientSocket
= aclass
;
53 * Returns the default class for newly accepted sockets when kgio_accept
54 * or kgio_tryaccept are not passed arguments
56 static VALUE
get_accepted(VALUE klass
)
62 * accept() wrapper that'll fall back on accept() if we were built on
63 * a system with accept4() but run on a system without accept4()
65 static VALUE
xaccept(void *ptr
)
67 struct accept_args
*a
= ptr
;
70 rv
= accept_fn(a
->fd
, a
->addr
, a
->addrlen
, a
->flags
);
71 if (rv
== -1 && errno
== ENOSYS
&& accept_fn
!= my_accept4
) {
72 accept_fn
= my_accept4
;
73 rv
= accept_fn(a
->fd
, a
->addr
, a
->addrlen
, a
->flags
);
79 #ifdef HAVE_RB_THREAD_BLOCKING_REGION
81 # include "blocking_io_region.h"
83 * Try to use a (real) blocking accept() since that can prevent
84 * thundering herds under Linux:
85 * http://www.citi.umich.edu/projects/linux-scalability/reports/accept.html
87 * So we periodically disable non-blocking, but not too frequently
88 * because other processes may set non-blocking (especially during
89 * a process upgrade) with Rainbows! concurrency model changes.
91 static int thread_accept(struct accept_args
*a
, int force_nonblock
)
94 set_nonblocking(a
->fd
);
95 return (int)rb_thread_io_blocking_region(xaccept
, a
, a
->fd
);
98 static void set_blocking_or_block(int fd
)
100 static time_t last_set_blocking
;
101 time_t now
= time(NULL
);
103 if (last_set_blocking
== 0) {
104 last_set_blocking
= now
;
105 (void)rb_io_wait_readable(fd
);
106 } else if ((now
- last_set_blocking
) <= 5) {
107 (void)rb_io_wait_readable(fd
);
109 int flags
= fcntl(fd
, F_GETFL
);
111 rb_sys_fail("fcntl(F_GETFL)");
112 if (flags
& O_NONBLOCK
) {
113 flags
= fcntl(fd
, F_SETFL
, flags
& ~O_NONBLOCK
);
115 rb_sys_fail("fcntl(F_SETFL)");
117 last_set_blocking
= now
;
120 #else /* ! HAVE_RB_THREAD_BLOCKING_REGION */
121 # include <rubysig.h>
122 static int thread_accept(struct accept_args
*a
, int force_nonblock
)
126 /* always use non-blocking accept() under 1.8 for green threads */
127 set_nonblocking(a
->fd
);
129 rv
= (int)xaccept(a
);
133 #define set_blocking_or_block(fd) (void)rb_io_wait_readable(fd)
134 #endif /* ! HAVE_RB_THREAD_BLOCKING_REGION */
137 prepare_accept(struct accept_args
*a
, VALUE self
, int argc
, const VALUE
*argv
)
139 a
->fd
= my_fileno(self
);
144 a
->flags
= NUM2INT(argv
[1]);
145 a
->accepted_class
= NIL_P(argv
[0]) ? cClientSocket
: argv
[0];
147 case 0: /* default, legacy behavior */
148 a
->flags
= accept4_flags
;
149 a
->accepted_class
= cClientSocket
;
152 a
->flags
= accept4_flags
;
153 a
->accepted_class
= NIL_P(argv
[0]) ? cClientSocket
: argv
[0];
157 rb_raise(rb_eArgError
, "wrong number of arguments (%d for 1)", argc
);
160 static VALUE
in_addr_set(VALUE io
, struct sockaddr_storage
*addr
, socklen_t len
)
166 switch (addr
->ss_family
) {
168 host_len
= (long)INET_ADDRSTRLEN
;
171 host_len
= (long)INET6_ADDRSTRLEN
;
174 rb_raise(rb_eRuntimeError
, "unsupported address family");
176 host
= rb_str_new(NULL
, host_len
);
177 host_ptr
= RSTRING_PTR(host
);
178 rc
= getnameinfo((struct sockaddr
*)addr
, len
,
179 host_ptr
, host_len
, NULL
, 0, NI_NUMERICHOST
);
181 rb_raise(rb_eRuntimeError
, "getnameinfo: %s", gai_strerror(rc
));
182 rb_str_set_len(host
, strlen(host_ptr
));
183 return rb_ivar_set(io
, iv_kgio_addr
, host
);
186 #if defined(__linux__)
187 # define post_accept kgio_autopush_accept
189 # define post_accept(a,b) for(;0;)
193 my_accept(struct accept_args
*a
, int force_nonblock
)
200 client_fd
= thread_accept(a
, force_nonblock
);
201 if (client_fd
== -1) {
206 a
->fd
= my_fileno(a
->accept_io
);
208 set_blocking_or_block(a
->fd
);
211 #endif /* ECONNABORTED */
216 a
->fd
= my_fileno(a
->accept_io
);
231 rb_sys_fail("accept");
234 client_io
= sock_for_fd(a
->accepted_class
, client_fd
);
235 post_accept(a
->accept_io
, client_io
);
238 in_addr_set(client_io
,
239 (struct sockaddr_storage
*)a
->addr
, *a
->addrlen
);
241 rb_ivar_set(client_io
, iv_kgio_addr
, localhost
);
248 * io.kgio_addr! => refreshes the given sock address
250 static VALUE
addr_bang(VALUE io
)
252 int fd
= my_fileno(io
);
253 struct sockaddr_storage addr
;
254 socklen_t len
= sizeof(struct sockaddr_storage
);
256 if (getpeername(fd
, (struct sockaddr
*)&addr
, &len
) != 0)
257 rb_sys_fail("getpeername");
259 if (addr
.ss_family
== AF_UNIX
)
260 return rb_ivar_set(io
, iv_kgio_addr
, localhost
);
262 return in_addr_set(io
, &addr
, len
);
268 * server = Kgio::TCPServer.new('0.0.0.0', 80)
269 * server.kgio_tryaccept -> Kgio::Socket or nil
270 * server.kgio_tryaccept(klass = MySocket) -> MySocket or nil
271 * server.kgio_tryaccept(nil, flags) -> Kgio::Socket or nil
273 * Initiates a non-blocking accept and returns a generic Kgio::Socket
274 * object with the kgio_addr attribute set to the IP address of the
275 * connected client on success.
277 * Returns nil on EAGAIN, and raises on other errors.
279 * An optional +klass+ argument may be specified to override the
280 * Kgio::Socket-class on a successful return value.
282 * An optional +flags+ argument may also be specifed to override the
283 * value of +Kgio.accept_cloexec+ and +Kgio.accept_nonblock+. +flags+
284 * is a bitmask that may contain any combination of:
286 * - Fcntl::FD_CLOEXEC - close-on-exec flag
287 * - IO::NONBLOCK - non-blocking flag
289 static VALUE
tcp_tryaccept(int argc
, VALUE
*argv
, VALUE self
)
291 struct sockaddr_storage addr
;
292 socklen_t addrlen
= sizeof(struct sockaddr_storage
);
293 struct accept_args a
;
295 a
.addr
= (struct sockaddr
*)&addr
;
296 a
.addrlen
= &addrlen
;
297 prepare_accept(&a
, self
, argc
, argv
);
298 return my_accept(&a
, 1);
304 * server = Kgio::TCPServer.new('0.0.0.0', 80)
305 * server.kgio_accept -> Kgio::Socket or nil
306 * server.kgio_tryaccept -> Kgio::Socket or nil
307 * server.kgio_tryaccept(klass = MySocket) -> MySocket or nil
309 * Initiates a blocking accept and returns a generic Kgio::Socket
310 * object with the kgio_addr attribute set to the IP address of
311 * the client on success.
313 * On Ruby implementations using native threads, this can use a blocking
314 * accept(2) (or accept4(2)) system call to avoid thundering herds.
316 * An optional +klass+ argument may be specified to override the
317 * Kgio::Socket-class on a successful return value.
319 * An optional +flags+ argument may also be specifed to override the
320 * value of +Kgio.accept_cloexec+ and +Kgio.accept_nonblock+. +flags+
321 * is a bitmask that may contain any combination of:
323 * - Fcntl::FD_CLOEXEC - close-on-exec flag
324 * - IO::NONBLOCK - non-blocking flag
326 static VALUE
tcp_accept(int argc
, VALUE
*argv
, VALUE self
)
328 struct sockaddr_storage addr
;
329 socklen_t addrlen
= sizeof(struct sockaddr_storage
);
330 struct accept_args a
;
332 a
.addr
= (struct sockaddr
*)&addr
;
333 a
.addrlen
= &addrlen
;
334 prepare_accept(&a
, self
, argc
, argv
);
335 return my_accept(&a
, 0);
341 * server = Kgio::UNIXServer.new("/path/to/unix/socket")
342 * server.kgio_tryaccept -> Kgio::Socket or nil
343 * server.kgio_tryaccept(klass = MySocket) -> MySocket or nil
344 * server.kgio_tryaccept(nil, flags) -> Kgio::Socket or nil
346 * Initiates a non-blocking accept and returns a generic Kgio::Socket
347 * object with the kgio_addr attribute set (to the value of
348 * Kgio::LOCALHOST) on success.
350 * An optional +klass+ argument may be specified to override the
351 * Kgio::Socket-class on a successful return value.
353 * An optional +flags+ argument may also be specifed to override the
354 * value of +Kgio.accept_cloexec+ and +Kgio.accept_nonblock+. +flags+
355 * is a bitmask that may contain any combination of:
357 * - Fcntl::FD_CLOEXEC - close-on-exec flag
358 * - IO::NONBLOCK - non-blocking flag
360 static VALUE
unix_tryaccept(int argc
, VALUE
*argv
, VALUE self
)
362 struct accept_args a
;
366 prepare_accept(&a
, self
, argc
, argv
);
367 return my_accept(&a
, 1);
373 * server = Kgio::UNIXServer.new("/path/to/unix/socket")
374 * server.kgio_accept -> Kgio::Socket or nil
375 * server.kgio_accept(klass = MySocket) -> MySocket or nil
376 * server.kgio_accept(nil, flags) -> Kgio::Socket or nil
378 * Initiates a blocking accept and returns a generic Kgio::Socket
379 * object with the kgio_addr attribute set (to the value of
380 * Kgio::LOCALHOST) on success.
382 * On Ruby implementations using native threads, this can use a blocking
383 * accept(2) (or accept4(2)) system call to avoid thundering herds.
385 * An optional +klass+ argument may be specified to override the
386 * Kgio::Socket-class on a successful return value.
388 * An optional +flags+ argument may also be specifed to override the
389 * value of +Kgio.accept_cloexec+ and +Kgio.accept_nonblock+. +flags+
390 * is a bitmask that may contain any combination of:
392 * - Fcntl::FD_CLOEXEC - close-on-exec flag
393 * - IO::NONBLOCK - non-blocking flag
395 static VALUE
unix_accept(int argc
, VALUE
*argv
, VALUE self
)
397 struct accept_args a
;
401 prepare_accept(&a
, self
, argc
, argv
);
402 return my_accept(&a
, 0);
408 * Kgio.accept_cloexec? -> true or false
410 * Returns true if newly accepted Kgio::Sockets are created with the
411 * FD_CLOEXEC file descriptor flag, false if not.
413 static VALUE
get_cloexec(VALUE mod
)
415 return (accept4_flags
& SOCK_CLOEXEC
) == SOCK_CLOEXEC
? Qtrue
: Qfalse
;
422 * Kgio.accept_nonblock? -> true or false
424 * Returns true if newly accepted Kgio::Sockets are created with the
425 * O_NONBLOCK file status flag, false if not.
427 static VALUE
get_nonblock(VALUE mod
)
429 return (accept4_flags
& SOCK_NONBLOCK
)==SOCK_NONBLOCK
? Qtrue
: Qfalse
;
435 * Kgio.accept_cloexec = true
436 * Kgio.accept_cloexec = false
438 * Sets whether or not Kgio::Socket objects created by
439 * TCPServer#kgio_accept,
440 * TCPServer#kgio_tryaccept,
441 * UNIXServer#kgio_accept,
442 * and UNIXServer#kgio_tryaccept
443 * default to being created with the FD_CLOEXEC file descriptor flag.
445 * This is on by default, as there is little reason to deal to enable
446 * it for client sockets on a socket server.
448 static VALUE
set_cloexec(VALUE mod
, VALUE boolean
)
450 switch (TYPE(boolean
)) {
452 accept4_flags
|= SOCK_CLOEXEC
;
455 accept4_flags
&= ~SOCK_CLOEXEC
;
458 rb_raise(rb_eTypeError
, "not true or false");
465 * Kgio.accept_nonblock = true
466 * Kgio.accept_nonblock = false
468 * Sets whether or not Kgio::Socket objects created by
469 * TCPServer#kgio_accept,
470 * TCPServer#kgio_tryaccept,
471 * UNIXServer#kgio_accept,
472 * and UNIXServer#kgio_tryaccept
473 * are created with the O_NONBLOCK file status flag.
475 * This defaults to +false+ for GNU/Linux where MSG_DONTWAIT is
476 * available (and on newer GNU/Linux, accept4() may also set
477 * the non-blocking flag. This defaults to +true+ on non-GNU/Linux
480 static VALUE
set_nonblock(VALUE mod
, VALUE boolean
)
482 switch (TYPE(boolean
)) {
484 accept4_flags
|= SOCK_NONBLOCK
;
487 accept4_flags
&= ~SOCK_NONBLOCK
;
490 rb_raise(rb_eTypeError
, "not true or false");
494 void init_kgio_accept(void)
496 VALUE cUNIXServer
, cTCPServer
;
497 VALUE mKgio
= rb_define_module("Kgio");
499 localhost
= rb_const_get(mKgio
, rb_intern("LOCALHOST"));
500 cKgio_Socket
= rb_const_get(mKgio
, rb_intern("Socket"));
501 cClientSocket
= cKgio_Socket
;
502 mSocketMethods
= rb_const_get(mKgio
, rb_intern("SocketMethods"));
504 rb_define_method(mSocketMethods
, "kgio_addr!", addr_bang
, 0);
506 rb_define_singleton_method(mKgio
, "accept_cloexec?", get_cloexec
, 0);
507 rb_define_singleton_method(mKgio
, "accept_cloexec=", set_cloexec
, 1);
508 rb_define_singleton_method(mKgio
, "accept_nonblock?", get_nonblock
, 0);
509 rb_define_singleton_method(mKgio
, "accept_nonblock=", set_nonblock
, 1);
510 rb_define_singleton_method(mKgio
, "accept_class=", set_accepted
, 1);
511 rb_define_singleton_method(mKgio
, "accept_class", get_accepted
, 0);
514 * Document-class: Kgio::UNIXServer
516 * Kgio::UNIXServer should be used in place of the plain UNIXServer
517 * when kgio_accept and kgio_tryaccept methods are needed.
519 cUNIXServer
= rb_const_get(rb_cObject
, rb_intern("UNIXServer"));
520 cUNIXServer
= rb_define_class_under(mKgio
, "UNIXServer", cUNIXServer
);
521 rb_define_method(cUNIXServer
, "kgio_tryaccept", unix_tryaccept
, -1);
522 rb_define_method(cUNIXServer
, "kgio_accept", unix_accept
, -1);
525 * Document-class: Kgio::TCPServer
527 * Kgio::TCPServer should be used in place of the plain TCPServer
528 * when kgio_accept and kgio_tryaccept methods are needed.
530 cTCPServer
= rb_const_get(rb_cObject
, rb_intern("TCPServer"));
531 cTCPServer
= rb_define_class_under(mKgio
, "TCPServer", cTCPServer
);
533 rb_define_method(cTCPServer
, "kgio_tryaccept", tcp_tryaccept
, -1);
534 rb_define_method(cTCPServer
, "kgio_accept", tcp_accept
, -1);
536 iv_kgio_addr
= rb_intern("@kgio_addr");