about summary refs log tree commit homepage
path: root/ext/kgio/autopush.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/kgio/autopush.c')
-rw-r--r--ext/kgio/autopush.c247
1 files changed, 0 insertions, 247 deletions
diff --git a/ext/kgio/autopush.c b/ext/kgio/autopush.c
deleted file mode 100644
index 74576e8..0000000
--- a/ext/kgio/autopush.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * We use a very basic strategy to use TCP_CORK semantics optimally
- * in most TCP servers:  On corked sockets, we will uncork on recv()
- * if there was a previous send().  Otherwise we do not fiddle
- * with TCP_CORK at all.
- *
- * Under Linux, we can rely on TCP_CORK being inherited in an
- * accept()-ed client socket so we can avoid syscalls for each
- * accept()-ed client if we know the accept() socket corks.
- *
- * This module does NOTHING for client TCP sockets, we only deal
- * with accept()-ed sockets right now.
- */
-
-#include "kgio.h"
-#include "my_fileno.h"
-#include <netinet/tcp.h>
-
-/*
- * As of FreeBSD 4.5, TCP_NOPUSH == TCP_CORK
- * ref: http://dotat.at/writing/nopush.html
- * We won't care for older FreeBSD since nobody runs Ruby on them...
- */
-#ifdef TCP_CORK
-#  define KGIO_NOPUSH TCP_CORK
-#elif defined(TCP_NOPUSH)
-#  define KGIO_NOPUSH TCP_NOPUSH
-#endif
-
-#ifdef KGIO_NOPUSH
-static ID id_autopush_state;
-static int enabled = 1;
-
-enum autopush_state {
-        AUTOPUSH_STATE_ACCEPTOR_IGNORE = -1,
-        AUTOPUSH_STATE_IGNORE = 0,
-        AUTOPUSH_STATE_WRITER = 1,
-        AUTOPUSH_STATE_WRITTEN = 2,
-        AUTOPUSH_STATE_ACCEPTOR = 3
-};
-
-#if defined(R_CAST) && \
-    defined(HAVE_TYPE_STRUCT_RFILE) && \
-    defined(HAVE_TYPE_STRUCT_ROBJECT) && \
-    ((SIZEOF_STRUCT_RFILE + SIZEOF_INT) <= (SIZEOF_STRUCT_ROBJECT))
-
-struct AutopushSocket {
-        struct RFile rfile;
-        enum autopush_state autopush_state;
-};
-
-static enum autopush_state state_get(VALUE io)
-{
-        return ((struct AutopushSocket *)(io))->autopush_state;
-}
-
-static void state_set(VALUE io, enum autopush_state state)
-{
-        ((struct AutopushSocket *)(io))->autopush_state = state;
-}
-#else
-static enum autopush_state state_get(VALUE io)
-{
-        VALUE val;
-
-        if (rb_ivar_defined(io, id_autopush_state) == Qfalse)
-                return AUTOPUSH_STATE_IGNORE;
-        val = rb_ivar_get(io, id_autopush_state);
-
-        return (enum autopush_state)NUM2INT(val);
-}
-
-static void state_set(VALUE io, enum autopush_state state)
-{
-        rb_ivar_set(io, id_autopush_state, INT2NUM(state));
-}
-#endif /* IVAR fallback */
-
-static enum autopush_state detect_acceptor_state(VALUE io);
-static void push_pending_data(VALUE io);
-
-/*
- * call-seq:
- *        Kgio.autopush? -> true or false
- *
- * Returns whether or not autopush is enabled.
- *
- * Only available on systems with TCP_CORK (Linux) or
- * TCP_NOPUSH (FreeBSD, and maybe other *BSDs).
- */
-static VALUE s_get_autopush(VALUE self)
-{
-        return enabled ? Qtrue : Qfalse;
-}
-
-/*
- * call-seq:
- *        Kgio.autopush = true
- *        Kgio.autopush = false
- *
- * Enables or disables autopush for sockets created with kgio_accept
- * and kgio_tryaccept methods.  Autopush relies on TCP_CORK/TCP_NOPUSH
- * being enabled on the listen socket.
- *
- * Only available on systems with TCP_CORK (Linux) or
- * TCP_NOPUSH (FreeBSD, and maybe other *BSDs).
- */
-static VALUE s_set_autopush(VALUE self, VALUE val)
-{
-        enabled = RTEST(val);
-
-        return val;
-}
-
-/*
- * call-seq:
- *
- *        io.kgio_autopush?  -> true or false
- *
- * Returns the current autopush state of the Kgio::SocketMethods-enabled
- * socket.
- *
- * Only available on systems with TCP_CORK (Linux) or
- * TCP_NOPUSH (FreeBSD, and maybe other *BSDs).
- */
-static VALUE autopush_get(VALUE io)
-{
-        return state_get(io) <= 0 ? Qfalse : Qtrue;
-}
-
-/*
- * call-seq:
- *
- *        io.kgio_autopush = true
- *        io.kgio_autopush = false
- *
- * Enables or disables autopush on any given Kgio::SocketMethods-capable
- * IO object.  This does NOT enable or disable TCP_NOPUSH/TCP_CORK right
- * away, that must be done with IO.setsockopt
- *
- * Only available on systems with TCP_CORK (Linux) or
- * TCP_NOPUSH (FreeBSD, and maybe other *BSDs).
- */
-static VALUE autopush_set(VALUE io, VALUE vbool)
-{
-        if (RTEST(vbool))
-                state_set(io, AUTOPUSH_STATE_WRITER);
-        else
-                state_set(io, AUTOPUSH_STATE_IGNORE);
-        return vbool;
-}
-
-void init_kgio_autopush(void)
-{
-        VALUE mKgio = rb_define_module("Kgio");
-        VALUE tmp;
-
-        rb_define_singleton_method(mKgio, "autopush?", s_get_autopush, 0);
-        rb_define_singleton_method(mKgio, "autopush=", s_set_autopush, 1);
-
-        tmp = rb_define_module_under(mKgio, "SocketMethods");
-        rb_define_method(tmp, "kgio_autopush=", autopush_set, 1);
-        rb_define_method(tmp, "kgio_autopush?", autopush_get, 0);
-
-        id_autopush_state = rb_intern("@kgio_autopush_state");
-}
-
-/*
- * called after a successful write, just mark that we've put something
- * in the skb and will need to uncork on the next write.
- */
-void kgio_autopush_send(VALUE io)
-{
-        if (state_get(io) == AUTOPUSH_STATE_WRITER)
-                state_set(io, AUTOPUSH_STATE_WRITTEN);
-}
-
-/* called on successful accept() */
-void kgio_autopush_accept(VALUE accept_io, VALUE client_io)
-{
-        enum autopush_state acceptor_state;
-
-        if (!enabled)
-                return;
-        acceptor_state = state_get(accept_io);
-        if (acceptor_state == AUTOPUSH_STATE_IGNORE)
-                acceptor_state = detect_acceptor_state(accept_io);
-        if (acceptor_state == AUTOPUSH_STATE_ACCEPTOR)
-                state_set(client_io, AUTOPUSH_STATE_WRITER);
-        else
-                state_set(client_io, AUTOPUSH_STATE_IGNORE);
-}
-
-void kgio_autopush_recv(VALUE io)
-{
-        if (enabled && (state_get(io) == AUTOPUSH_STATE_WRITTEN)) {
-                push_pending_data(io);
-                state_set(io, AUTOPUSH_STATE_WRITER);
-        }
-}
-
-static enum autopush_state detect_acceptor_state(VALUE io)
-{
-        int corked = 0;
-        int fd = my_fileno(io);
-        socklen_t optlen = sizeof(int);
-        enum autopush_state state;
-
-        if (getsockopt(fd, IPPROTO_TCP, KGIO_NOPUSH, &corked, &optlen) != 0) {
-                if (errno != EOPNOTSUPP)
-                        rb_sys_fail("getsockopt(TCP_CORK/TCP_NOPUSH)");
-                errno = 0;
-                state = AUTOPUSH_STATE_ACCEPTOR_IGNORE;
-        } else if (corked) {
-                state = AUTOPUSH_STATE_ACCEPTOR;
-        } else {
-                state = AUTOPUSH_STATE_ACCEPTOR_IGNORE;
-        }
-        state_set(io, state);
-
-        return state;
-}
-
-/*
- * checks to see if we've written anything since the last recv()
- * If we have, uncork the socket and immediately recork it.
- */
-static void push_pending_data(VALUE io)
-{
-        int optval = 0;
-        const socklen_t optlen = sizeof(int);
-        const int fd = my_fileno(io);
-
-        if (setsockopt(fd, IPPROTO_TCP, KGIO_NOPUSH, &optval, optlen) != 0)
-                rb_sys_fail("setsockopt(TCP_CORK/TCP_NOPUSH, 0)");
-        /* immediately recork */
-        optval = 1;
-        if (setsockopt(fd, IPPROTO_TCP, KGIO_NOPUSH, &optval, optlen) != 0)
-                rb_sys_fail("setsockopt(TCP_CORK/TCP_NOPUSH, 1)");
-}
-#else /* !KGIO_NOPUSH */
-void kgio_autopush_recv(VALUE io){}
-void kgio_autopush_send(VALUE io){}
-void init_kgio_autopush(void)
-{
-}
-#endif /* ! KGIO_NOPUSH */