about summary refs log tree commit homepage
path: root/ext
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2011-02-22 19:24:54 -0800
committerEric Wong <normalperson@yhbt.net>2011-02-23 13:14:27 -0800
commitdb192979f096d0153ad14e530e1e2e193289c7e0 (patch)
tree356c4a8bf64f30dd6c4886adc92f253bd4bf831d /ext
parentebc2093847705c382b4d83ed5120e44b9afad3c0 (diff)
downloadraindrops-db192979f096d0153ad14e530e1e2e193289c7e0.tar.gz
This returns a Raindrops::TCP_Info object
that wraps a tcp_info struct.
Diffstat (limited to 'ext')
-rw-r--r--ext/raindrops/linux_tcp_info.c114
-rw-r--r--ext/raindrops/my_fileno.h36
-rw-r--r--ext/raindrops/raindrops.c2
3 files changed, 152 insertions, 0 deletions
diff --git a/ext/raindrops/linux_tcp_info.c b/ext/raindrops/linux_tcp_info.c
new file mode 100644
index 0000000..8ca3585
--- /dev/null
+++ b/ext/raindrops/linux_tcp_info.c
@@ -0,0 +1,114 @@
+#include <ruby.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#ifdef TCP_INFO
+#include "my_fileno.h"
+
+#define TCPI_ATTR_READER(x) \
+static VALUE tcp_info_##x(VALUE self) \
+{ \
+        struct tcp_info *info = DATA_PTR(self); \
+        return UINT2NUM((uint32_t)info->tcpi_##x); \
+}
+
+TCPI_ATTR_READER(state)
+TCPI_ATTR_READER(ca_state)
+TCPI_ATTR_READER(retransmits)
+TCPI_ATTR_READER(probes)
+TCPI_ATTR_READER(backoff)
+TCPI_ATTR_READER(options)
+TCPI_ATTR_READER(snd_wscale)
+TCPI_ATTR_READER(rcv_wscale)
+TCPI_ATTR_READER(rto)
+TCPI_ATTR_READER(ato)
+TCPI_ATTR_READER(snd_mss)
+TCPI_ATTR_READER(rcv_mss)
+TCPI_ATTR_READER(unacked)
+TCPI_ATTR_READER(sacked)
+TCPI_ATTR_READER(lost)
+TCPI_ATTR_READER(retrans)
+TCPI_ATTR_READER(fackets)
+TCPI_ATTR_READER(last_data_sent)
+TCPI_ATTR_READER(last_ack_sent)
+TCPI_ATTR_READER(last_data_recv)
+TCPI_ATTR_READER(last_ack_recv)
+TCPI_ATTR_READER(pmtu)
+TCPI_ATTR_READER(rcv_ssthresh)
+TCPI_ATTR_READER(rtt)
+TCPI_ATTR_READER(rttvar)
+TCPI_ATTR_READER(snd_ssthresh)
+TCPI_ATTR_READER(snd_cwnd)
+TCPI_ATTR_READER(advmss)
+TCPI_ATTR_READER(reordering)
+TCPI_ATTR_READER(rcv_rtt)
+TCPI_ATTR_READER(rcv_space)
+TCPI_ATTR_READER(total_retrans)
+
+static VALUE alloc(VALUE klass)
+{
+        struct tcp_info *info = xmalloc(sizeof(struct tcp_info));
+
+        /* Data_Make_Struct has an extra memset 0 which is so wasteful */
+        return Data_Wrap_Struct(klass, NULL, -1, info);
+}
+
+static VALUE init(VALUE self, VALUE io)
+{
+        int fd = my_fileno(io);
+        struct tcp_info *info = DATA_PTR(self);
+        socklen_t len = (socklen_t)sizeof(struct tcp_info);
+        int rc = getsockopt(fd, IPPROTO_TCP, TCP_INFO, info, &len);
+
+        if (rc != 0)
+                rb_sys_fail("getsockopt");
+
+        return self;
+}
+
+void Init_raindrops_linux_tcp_info(void)
+{
+        VALUE cRaindrops = rb_const_get(rb_cObject, rb_intern("Raindrops"));
+        VALUE cTCP_Info;
+
+        cTCP_Info = rb_define_class_under(cRaindrops, "TCP_Info", rb_cObject);
+        rb_define_alloc_func(cTCP_Info, alloc);
+        rb_define_private_method(cTCP_Info, "initialize", init, 1);
+
+#define TCPI_DEFINE_METHOD(x) \
+        rb_define_method(cTCP_Info, #x, tcp_info_##x, 0)
+
+        TCPI_DEFINE_METHOD(state);
+        TCPI_DEFINE_METHOD(ca_state);
+        TCPI_DEFINE_METHOD(retransmits);
+        TCPI_DEFINE_METHOD(probes);
+        TCPI_DEFINE_METHOD(backoff);
+        TCPI_DEFINE_METHOD(options);
+        TCPI_DEFINE_METHOD(snd_wscale);
+        TCPI_DEFINE_METHOD(rcv_wscale);
+        TCPI_DEFINE_METHOD(rto);
+        TCPI_DEFINE_METHOD(ato);
+        TCPI_DEFINE_METHOD(snd_mss);
+        TCPI_DEFINE_METHOD(rcv_mss);
+        TCPI_DEFINE_METHOD(unacked);
+        TCPI_DEFINE_METHOD(sacked);
+        TCPI_DEFINE_METHOD(lost);
+        TCPI_DEFINE_METHOD(retrans);
+        TCPI_DEFINE_METHOD(fackets);
+        TCPI_DEFINE_METHOD(last_data_sent);
+        TCPI_DEFINE_METHOD(last_ack_sent);
+        TCPI_DEFINE_METHOD(last_data_recv);
+        TCPI_DEFINE_METHOD(last_ack_recv);
+        TCPI_DEFINE_METHOD(pmtu);
+        TCPI_DEFINE_METHOD(rcv_ssthresh);
+        TCPI_DEFINE_METHOD(rtt);
+        TCPI_DEFINE_METHOD(rttvar);
+        TCPI_DEFINE_METHOD(snd_ssthresh);
+        TCPI_DEFINE_METHOD(snd_cwnd);
+        TCPI_DEFINE_METHOD(advmss);
+        TCPI_DEFINE_METHOD(reordering);
+        TCPI_DEFINE_METHOD(rcv_rtt);
+        TCPI_DEFINE_METHOD(rcv_space);
+        TCPI_DEFINE_METHOD(total_retrans);
+}
+#endif /* TCP_INFO */
diff --git a/ext/raindrops/my_fileno.h b/ext/raindrops/my_fileno.h
new file mode 100644
index 0000000..bdf1a5f
--- /dev/null
+++ b/ext/raindrops/my_fileno.h
@@ -0,0 +1,36 @@
+#include <ruby.h>
+#ifdef HAVE_RUBY_IO_H
+#  include <ruby/io.h>
+#else
+#  include <stdio.h>
+#  include <rubyio.h>
+#endif
+
+#if ! HAVE_RB_IO_T
+#  define rb_io_t OpenFile
+#endif
+
+#ifdef GetReadFile
+#  define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
+#else
+#  if !HAVE_RB_IO_T || (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
+#    define FPTR_TO_FD(fptr) fileno(fptr->f)
+#  else
+#    define FPTR_TO_FD(fptr) fptr->fd
+#  endif
+#endif
+
+static int my_fileno(VALUE io)
+{
+        rb_io_t *fptr;
+        int fd;
+
+        if (TYPE(io) != T_FILE)
+                io = rb_convert_type(io, T_FILE, "IO", "to_io");
+        GetOpenFile(io, fptr);
+        fd = FPTR_TO_FD(fptr);
+
+        if (fd < 0)
+                rb_raise(rb_eIOError, "closed stream");
+        return fd;
+}
diff --git a/ext/raindrops/raindrops.c b/ext/raindrops/raindrops.c
index e43dc2c..599f39d 100644
--- a/ext/raindrops/raindrops.c
+++ b/ext/raindrops/raindrops.c
@@ -172,6 +172,7 @@ static VALUE aref(VALUE self, VALUE index)
 
 #ifdef __linux__
 void Init_raindrops_linux_inet_diag(void);
+void Init_raindrops_linux_tcp_info(void);
 #endif
 
 #ifndef _SC_NPROCESSORS_ONLN
@@ -215,5 +216,6 @@ void Init_raindrops_ext(void)
 
 #ifdef __linux__
         Init_raindrops_linux_inet_diag();
+        Init_raindrops_linux_tcp_info();
 #endif
 }