From db192979f096d0153ad14e530e1e2e193289c7e0 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 22 Feb 2011 19:24:54 -0800 Subject: linux: add support for TCP_INFO reporting This returns a Raindrops::TCP_Info object that wraps a tcp_info struct. --- ext/raindrops/linux_tcp_info.c | 114 +++++++++++++++++++++++++++++++++++++++++ ext/raindrops/my_fileno.h | 36 +++++++++++++ ext/raindrops/raindrops.c | 2 + 3 files changed, 152 insertions(+) create mode 100644 ext/raindrops/linux_tcp_info.c create mode 100644 ext/raindrops/my_fileno.h (limited to 'ext') 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 +#include +#include +#include +#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 +#ifdef HAVE_RUBY_IO_H +# include +#else +# include +# include +#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 } -- cgit v1.2.3-24-ge0c7