doc: fully RDoc all methods and classes
[kgio.git] / ext / kgio / accept.c
blob902145c4077366fa1d720850a533051be139c18f
1 #include "kgio.h"
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;
13 #else /* ! linux */
14 static int accept4_flags = SOCK_CLOEXEC | SOCK_NONBLOCK;
15 #endif /* ! linux */
17 struct accept_args {
18 int fd;
19 struct sockaddr *addr;
20 socklen_t *addrlen;
24 * Sets the default class for newly accepted sockets. This is
25 * legacy behavior, kgio_accept and kgio_tryaccept now take optional
26 * class arguments to override this value.
28 static VALUE set_accepted(VALUE klass, VALUE aclass)
30 VALUE tmp;
32 if (NIL_P(aclass))
33 aclass = cKgio_Socket;
35 tmp = rb_funcall(aclass, rb_intern("included_modules"), 0, 0);
36 tmp = rb_funcall(tmp, rb_intern("include?"), 1, mSocketMethods);
38 if (tmp != Qtrue)
39 rb_raise(rb_eTypeError,
40 "class must include Kgio::SocketMethods");
42 cClientSocket = aclass;
44 return aclass;
48 * Returns the default class for newly accepted sockets when kgio_accept
49 * or kgio_tryaccept are not passed arguments
51 static VALUE get_accepted(VALUE klass)
53 return cClientSocket;
56 static VALUE xaccept(void *ptr)
58 struct accept_args *a = ptr;
59 int rv;
61 rv = accept_fn(a->fd, a->addr, a->addrlen, accept4_flags);
62 if (rv == -1 && errno == ENOSYS && accept_fn != my_accept4) {
63 accept_fn = my_accept4;
64 rv = accept_fn(a->fd, a->addr, a->addrlen, accept4_flags);
67 return (VALUE)rv;
70 #ifdef HAVE_RB_THREAD_BLOCKING_REGION
71 # include <time.h>
73 * Try to use a (real) blocking accept() since that can prevent
74 * thundering herds under Linux:
75 * http://www.citi.umich.edu/projects/linux-scalability/reports/accept.html
77 * So we periodically disable non-blocking, but not too frequently
78 * because other processes may set non-blocking (especially during
79 * a process upgrade) with Rainbows! concurrency model changes.
81 static int thread_accept(struct accept_args *a, int force_nonblock)
83 if (force_nonblock)
84 set_nonblocking(a->fd);
85 return (int)rb_thread_blocking_region(xaccept, a, RUBY_UBF_IO, 0);
88 static void set_blocking_or_block(int fd)
90 static time_t last_set_blocking;
91 time_t now = time(NULL);
93 if (last_set_blocking == 0) {
94 last_set_blocking = now;
95 (void)rb_io_wait_readable(fd);
96 } else if ((now - last_set_blocking) <= 5) {
97 (void)rb_io_wait_readable(fd);
98 } else {
99 int flags = fcntl(fd, F_GETFL);
100 if (flags == -1)
101 rb_sys_fail("fcntl(F_GETFL)");
102 if (flags & O_NONBLOCK) {
103 flags = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
104 if (flags == -1)
105 rb_sys_fail("fcntl(F_SETFL)");
107 last_set_blocking = now;
110 #else /* ! HAVE_RB_THREAD_BLOCKING_REGION */
111 # include <rubysig.h>
112 static int thread_accept(struct accept_args *a, int force_nonblock)
114 int rv;
116 /* always use non-blocking accept() under 1.8 for green threads */
117 set_nonblocking(a->fd);
118 TRAP_BEG;
119 rv = (int)xaccept(a);
120 TRAP_END;
121 return rv;
123 #define set_blocking_or_block(fd) (void)rb_io_wait_readable(fd)
124 #endif /* ! HAVE_RB_THREAD_BLOCKING_REGION */
126 static VALUE acceptor(int argc, const VALUE *argv)
128 if (argc == 0)
129 return cClientSocket; /* default, legacy behavior */
130 else if (argc == 1)
131 return argv[0];
133 rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc);
136 #if defined(__linux__)
137 # define post_accept kgio_autopush_accept
138 #else
139 # define post_accept(a,b) for(;0;)
140 #endif
142 static VALUE
143 my_accept(VALUE accept_io, VALUE klass,
144 struct sockaddr *addr, socklen_t *addrlen, int nonblock)
146 int client;
147 VALUE client_io;
148 struct accept_args a;
150 a.fd = my_fileno(accept_io);
151 a.addr = addr;
152 a.addrlen = addrlen;
153 retry:
154 client = thread_accept(&a, nonblock);
155 if (client == -1) {
156 switch (errno) {
157 case EAGAIN:
158 if (nonblock)
159 return Qnil;
160 set_blocking_or_block(a.fd);
161 #ifdef ECONNABORTED
162 case ECONNABORTED:
163 #endif /* ECONNABORTED */
164 #ifdef EPROTO
165 case EPROTO:
166 #endif /* EPROTO */
167 case EINTR:
168 goto retry;
169 case ENOMEM:
170 case EMFILE:
171 case ENFILE:
172 #ifdef ENOBUFS
173 case ENOBUFS:
174 #endif /* ENOBUFS */
175 errno = 0;
176 rb_gc();
177 client = thread_accept(&a, nonblock);
179 if (client == -1) {
180 if (errno == EINTR)
181 goto retry;
182 rb_sys_fail("accept");
185 client_io = sock_for_fd(klass, client);
186 post_accept(accept_io, client_io);
187 return client_io;
190 static VALUE in_addr_set(VALUE io, struct sockaddr_storage *addr, socklen_t len)
192 VALUE host;
193 int host_len, rc;
194 char *host_ptr;
196 switch (addr->ss_family) {
197 case AF_INET:
198 host_len = (long)INET_ADDRSTRLEN;
199 break;
200 case AF_INET6:
201 host_len = (long)INET6_ADDRSTRLEN;
202 break;
203 default:
204 rb_raise(rb_eRuntimeError, "unsupported address family");
206 host = rb_str_new(NULL, host_len);
207 host_ptr = RSTRING_PTR(host);
208 rc = getnameinfo((struct sockaddr *)addr, len,
209 host_ptr, host_len, NULL, 0, NI_NUMERICHOST);
210 if (rc != 0)
211 rb_raise(rb_eRuntimeError, "getnameinfo: %s", gai_strerror(rc));
212 rb_str_set_len(host, strlen(host_ptr));
213 return rb_ivar_set(io, iv_kgio_addr, host);
217 * call-seq:
219 * io.kgio_addr! => refreshes the given sock address
221 static VALUE addr_bang(VALUE io)
223 int fd = my_fileno(io);
224 struct sockaddr_storage addr;
225 socklen_t len = sizeof(struct sockaddr_storage);
227 if (getpeername(fd, (struct sockaddr *)&addr, &len) != 0)
228 rb_sys_fail("getpeername");
230 if (addr.ss_family == AF_UNIX)
231 return rb_ivar_set(io, iv_kgio_addr, localhost);
233 return in_addr_set(io, &addr, len);
237 * call-seq:
239 * server = Kgio::TCPServer.new('0.0.0.0', 80)
240 * server.kgio_tryaccept -> Kgio::Socket or nil
242 * Initiates a non-blocking accept and returns a generic Kgio::Socket
243 * object with the kgio_addr attribute set to the IP address of the
244 * connected client on success.
246 * Returns nil on EAGAIN, and raises on other errors.
248 * An optional class argument may be specified to override the
249 * Kgio::Socket-class return value:
251 * server.kgio_tryaccept(MySocket) -> MySocket
253 static VALUE tcp_tryaccept(int argc, VALUE *argv, VALUE io)
255 struct sockaddr_storage addr;
256 socklen_t addrlen = sizeof(struct sockaddr_storage);
257 VALUE klass = acceptor(argc, argv);
258 VALUE rv = my_accept(io, klass, (struct sockaddr *)&addr, &addrlen, 1);
260 if (!NIL_P(rv))
261 in_addr_set(rv, &addr, addrlen);
262 return rv;
266 * call-seq:
268 * server = Kgio::TCPServer.new('0.0.0.0', 80)
269 * server.kgio_accept -> Kgio::Socket or nil
271 * Initiates a blocking accept and returns a generic Kgio::Socket
272 * object with the kgio_addr attribute set to the IP address of
273 * the client on success.
275 * On Ruby implementations using native threads, this can use a blocking
276 * accept(2) (or accept4(2)) system call to avoid thundering herds.
278 * An optional class argument may be specified to override the
279 * Kgio::Socket-class return value:
281 * server.kgio_accept(MySocket) -> MySocket
283 static VALUE tcp_accept(int argc, VALUE *argv, VALUE io)
285 struct sockaddr_storage addr;
286 socklen_t addrlen = sizeof(struct sockaddr_storage);
287 VALUE klass = acceptor(argc, argv);
288 VALUE rv = my_accept(io, klass, (struct sockaddr *)&addr, &addrlen, 0);
290 in_addr_set(rv, &addr, addrlen);
291 return rv;
295 * call-seq:
297 * server = Kgio::UNIXServer.new("/path/to/unix/socket")
298 * server.kgio_tryaccept -> Kgio::Socket or nil
300 * Initiates a non-blocking accept and returns a generic Kgio::Socket
301 * object with the kgio_addr attribute set (to the value of
302 * Kgio::LOCALHOST) on success.
304 * Returns nil on EAGAIN, and raises on other errors.
306 * An optional class argument may be specified to override the
307 * Kgio::Socket-class return value:
309 * server.kgio_tryaccept(MySocket) -> MySocket
311 static VALUE unix_tryaccept(int argc, VALUE *argv, VALUE io)
313 VALUE klass = acceptor(argc, argv);
314 VALUE rv = my_accept(io, klass, NULL, NULL, 1);
316 if (!NIL_P(rv))
317 rb_ivar_set(rv, iv_kgio_addr, localhost);
318 return rv;
322 * call-seq:
324 * server = Kgio::UNIXServer.new("/path/to/unix/socket")
325 * server.kgio_accept -> Kgio::Socket or nil
327 * Initiates a blocking accept and returns a generic Kgio::Socket
328 * object with the kgio_addr attribute set (to the value of
329 * Kgio::LOCALHOST) on success.
331 * On Ruby implementations using native threads, this can use a blocking
332 * accept(2) (or accept4(2)) system call to avoid thundering herds.
334 * An optional class argument may be specified to override the
335 * Kgio::Socket-class return value:
337 * server.kgio_accept(MySocket) -> MySocket
339 static VALUE unix_accept(int argc, VALUE *argv, VALUE io)
341 VALUE klass = acceptor(argc, argv);
342 VALUE rv = my_accept(io, klass, NULL, NULL, 0);
344 rb_ivar_set(rv, iv_kgio_addr, localhost);
345 return rv;
349 * call-seq:
351 * Kgio.accept_cloexec? -> true or false
353 * Returns true if newly accepted Kgio::Sockets are created with the
354 * FD_CLOEXEC file descriptor flag, false if not.
356 static VALUE get_cloexec(VALUE mod)
358 return (accept4_flags & SOCK_CLOEXEC) == SOCK_CLOEXEC ? Qtrue : Qfalse;
363 * call-seq:
365 * Kgio.accept_nonblock? -> true or false
367 * Returns true if newly accepted Kgio::Sockets are created with the
368 * O_NONBLOCK file status flag, false if not.
370 static VALUE get_nonblock(VALUE mod)
372 return (accept4_flags & SOCK_NONBLOCK)==SOCK_NONBLOCK ? Qtrue : Qfalse;
376 * call-seq:
378 * Kgio.accept_cloexec = true
379 * Kgio.accept_cloexec = false
381 * Sets whether or not Kgio::Socket objects created by
382 * TCPServer#kgio_accept,
383 * TCPServer#kgio_tryaccept,
384 * UNIXServer#kgio_accept,
385 * and UNIXServer#kgio_tryaccept
386 * are created with the FD_CLOEXEC file descriptor flag.
388 * This is on by default, as there is little reason to deal to enable
389 * it for client sockets on a socket server.
391 static VALUE set_cloexec(VALUE mod, VALUE boolean)
393 switch (TYPE(boolean)) {
394 case T_TRUE:
395 accept4_flags |= SOCK_CLOEXEC;
396 return boolean;
397 case T_FALSE:
398 accept4_flags &= ~SOCK_CLOEXEC;
399 return boolean;
401 rb_raise(rb_eTypeError, "not true or false");
402 return Qnil;
406 * call-seq:
408 * Kgio.accept_nonblock = true
409 * Kgio.accept_nonblock = false
411 * Sets whether or not Kgio::Socket objects created by
412 * TCPServer#kgio_accept,
413 * TCPServer#kgio_tryaccept,
414 * UNIXServer#kgio_accept,
415 * and UNIXServer#kgio_tryaccept
416 * are created with the O_NONBLOCK file status flag.
418 * This defaults to +false+ for GNU/Linux where MSG_DONTWAIT is
419 * available (and on newer GNU/Linux, accept4() may also set
420 * the non-blocking flag. This defaults to +true+ on non-GNU/Linux
421 * systems.
423 static VALUE set_nonblock(VALUE mod, VALUE boolean)
425 switch (TYPE(boolean)) {
426 case T_TRUE:
427 accept4_flags |= SOCK_NONBLOCK;
428 return boolean;
429 case T_FALSE:
430 accept4_flags &= ~SOCK_NONBLOCK;
431 return boolean;
433 rb_raise(rb_eTypeError, "not true or false");
434 return Qnil;
437 void init_kgio_accept(void)
439 VALUE cUNIXServer, cTCPServer;
440 VALUE mKgio = rb_define_module("Kgio");
442 localhost = rb_const_get(mKgio, rb_intern("LOCALHOST"));
443 cKgio_Socket = rb_const_get(mKgio, rb_intern("Socket"));
444 cClientSocket = cKgio_Socket;
445 mSocketMethods = rb_const_get(mKgio, rb_intern("SocketMethods"));
447 rb_define_method(mSocketMethods, "kgio_addr!", addr_bang, 0);
449 rb_define_singleton_method(mKgio, "accept_cloexec?", get_cloexec, 0);
450 rb_define_singleton_method(mKgio, "accept_cloexec=", set_cloexec, 1);
451 rb_define_singleton_method(mKgio, "accept_nonblock?", get_nonblock, 0);
452 rb_define_singleton_method(mKgio, "accept_nonblock=", set_nonblock, 1);
453 rb_define_singleton_method(mKgio, "accept_class=", set_accepted, 1);
454 rb_define_singleton_method(mKgio, "accept_class", get_accepted, 0);
457 * Document-class: Kgio::UNIXServer
459 * Kgio::UNIXServer should be used in place of the plain UNIXServer
460 * when kgio_accept and kgio_tryaccept methods are needed.
462 cUNIXServer = rb_const_get(rb_cObject, rb_intern("UNIXServer"));
463 cUNIXServer = rb_define_class_under(mKgio, "UNIXServer", cUNIXServer);
464 rb_define_method(cUNIXServer, "kgio_tryaccept", unix_tryaccept, -1);
465 rb_define_method(cUNIXServer, "kgio_accept", unix_accept, -1);
468 * Document-class: Kgio::TCPServer
470 * Kgio::TCPServer should be used in place of the plain TCPServer
471 * when kgio_accept and kgio_tryaccept methods are needed.
473 cTCPServer = rb_const_get(rb_cObject, rb_intern("TCPServer"));
474 cTCPServer = rb_define_class_under(mKgio, "TCPServer", cTCPServer);
476 rb_define_method(cTCPServer, "kgio_tryaccept", tcp_tryaccept, -1);
477 rb_define_method(cTCPServer, "kgio_accept", tcp_accept, -1);
478 init_sock_for_fd();
479 iv_kgio_addr = rb_intern("@kgio_addr");