From: Eric Wong <e@80x24.org>
To: raindrops-public@bogomips.org
Subject: [PATCH 1/2] tcp_info: support this struct under FreeBSD
Date: Thu, 16 Mar 2017 03:16:51 +0000 [thread overview]
Message-ID: <20170316031652.17433-2-e@80x24.org> (raw)
In-Reply-To: <20170316031652.17433-1-e@80x24.org>
Of course these fields are not portable between Linux and FreeBSD,
but they should remain ABI-compatible for future versions of each OS.
Tested on FreeBSD 10.3-RELEASE i386
TCP state names will be another problem...
---
ext/raindrops/extconf.rb | 78 ++++++++++-
ext/raindrops/raindrops.c | 8 +-
ext/raindrops/{linux_tcp_info.c => tcp_info.c} | 159 +++++++++++-----------
test/{test_linux_tcp_info.rb => test_tcp_info.rb} | 37 +++--
4 files changed, 189 insertions(+), 93 deletions(-)
rename ext/raindrops/{linux_tcp_info.c => tcp_info.c} (51%)
rename test/{test_linux_tcp_info.rb => test_tcp_info.rb} (66%)
diff --git a/ext/raindrops/extconf.rb b/ext/raindrops/extconf.rb
index 79d212c..5273b74 100644
--- a/ext/raindrops/extconf.rb
+++ b/ext/raindrops/extconf.rb
@@ -1,4 +1,5 @@
require 'mkmf'
+require 'shellwords'
dir_config('atomic_ops')
have_func('mmap', 'sys/mman.h') or abort 'mmap() not found'
@@ -6,9 +7,83 @@
$CPPFLAGS += " -D_GNU_SOURCE "
have_func('mremap', 'sys/mman.h')
-have_header('linux/tcp.h')
+headers = %w(sys/types.h netdb.h string.h sys/socket.h netinet/in.h)
+if have_header('linux/tcp.h')
+ headers << 'linux/tcp.h'
+else
+ %w(netinet/tcp.h netinet/tcp_fsm.h).each { |h|
+ have_header(h, headers) and headers << h
+ }
+end
$CPPFLAGS += " -D_BSD_SOURCE "
+
+if have_type("struct tcp_info", headers)
+ %w(
+ tcpi_state
+ tcpi_ca_state
+ tcpi_retransmits
+ tcpi_probes
+ tcpi_backoff
+ tcpi_options
+ tcpi_snd_wscale
+ tcpi_rcv_wscale
+ tcpi_rto
+ tcpi_ato
+ tcpi_snd_mss
+ tcpi_rcv_mss
+ tcpi_unacked
+ tcpi_sacked
+ tcpi_lost
+ tcpi_retrans
+ tcpi_fackets
+ tcpi_last_data_sent
+ tcpi_last_ack_sent
+ tcpi_last_data_recv
+ tcpi_last_ack_recv
+ tcpi_pmtu
+ tcpi_rcv_ssthresh
+ tcpi_rtt
+ tcpi_rttvar
+ tcpi_snd_ssthresh
+ tcpi_snd_cwnd
+ tcpi_advmss
+ tcpi_reordering
+ tcpi_rcv_rtt
+ tcpi_rcv_space
+ tcpi_total_retrans
+ tcpi_snd_wnd
+ tcpi_snd_bwnd
+ tcpi_snd_nxt
+ tcpi_rcv_nxt
+ tcpi_toe_tid
+ tcpi_snd_rexmitpack
+ tcpi_rcv_ooopack
+ tcpi_snd_zerowin
+ ).each do |field|
+ cfunc = "tcp_info_#{field}"
+ if have_struct_member('struct tcp_info', field, headers)
+ func_body = <<EOF
+static VALUE #{cfunc}(VALUE self)
+{
+ struct tcp_info *info = DATA_PTR(self);
+ return UINT2NUM((uint32_t)info->#{field});
+}
+EOF
+ func_body.delete!("\n")
+ $defs << "-DCFUNC_#{cfunc}=#{Shellwords.shellescape(func_body)}"
+ else
+ func_body = "static inline void #{cfunc}(void) {}"
+ $defs << "-DCFUNC_#{cfunc}=#{Shellwords.shellescape(func_body)}"
+ cfunc = 'rb_f_notimplement'.freeze
+ end
+ rbmethod = %Q("#{field.sub(/\Atcpi_/, ''.freeze)}")
+ $defs << "-DDEFINE_METHOD_tcp_info_#{field}=" \
+ "#{Shellwords.shellescape(
+ %Q[rb_define_method(cTCP_Info,#{rbmethod},#{cfunc},0)])}"
+ end
+end
+
have_func("getpagesize", "unistd.h")
have_func('rb_thread_blocking_region')
have_func('rb_thread_io_blocking_region')
@@ -53,4 +128,5 @@
apt-get install libatomic-ops-dev
SRC
+create_header # generate extconf.h to avoid excessively long command-line
create_makefile('raindrops_ext')
diff --git a/ext/raindrops/raindrops.c b/ext/raindrops/raindrops.c
index 390b8b8..0ea3e32 100644
--- a/ext/raindrops/raindrops.c
+++ b/ext/raindrops/raindrops.c
@@ -336,7 +336,9 @@ static VALUE aref(VALUE self, VALUE index)
#ifdef __linux__
void Init_raindrops_linux_inet_diag(void);
-void Init_raindrops_linux_tcp_info(void);
+#endif
+#ifdef HAVE_TYPE_STRUCT_TCP_INFO
+void Init_raindrops_tcp_info(void);
#endif
#ifndef _SC_NPROCESSORS_CONF
@@ -441,6 +443,8 @@ void Init_raindrops_ext(void)
#ifdef __linux__
Init_raindrops_linux_inet_diag();
- Init_raindrops_linux_tcp_info();
+#endif
+#ifdef HAVE_TYPE_STRUCT_TCP_INFO
+ Init_raindrops_tcp_info();
#endif
}
diff --git a/ext/raindrops/linux_tcp_info.c b/ext/raindrops/tcp_info.c
similarity index 51%
rename from ext/raindrops/linux_tcp_info.c
rename to ext/raindrops/tcp_info.c
index 83001a5..dc615f7 100644
--- a/ext/raindrops/linux_tcp_info.c
+++ b/ext/raindrops/tcp_info.c
@@ -1,50 +1,53 @@
-#if defined(__linux__) && defined(HAVE_LINUX_TCP_H)
#include <ruby.h>
+#include "extconf.h"
#include <sys/socket.h>
#include <netinet/in.h>
-#include <linux/tcp.h>
-#ifdef TCP_INFO
-#include "my_fileno.h"
+#if defined(HAVE_LINUX_TCP_H)
+# include <linux/tcp.h>
+#else
+# if defined(HAVE_NETINET_TCP_H)
+# include <netinet/tcp.h>
+# endif
+# if defined(HAVE_NETINET_TCP_FSM_H)
+# include <netinet/tcp_fsm.h>
+# endif
+#endif
-#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); \
-}
+#ifdef HAVE_TYPE_STRUCT_TCP_INFO
+#include "my_fileno.h"
-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)
+CFUNC_tcp_info_tcpi_state
+CFUNC_tcp_info_tcpi_ca_state
+CFUNC_tcp_info_tcpi_retransmits
+CFUNC_tcp_info_tcpi_probes
+CFUNC_tcp_info_tcpi_backoff
+CFUNC_tcp_info_tcpi_options
+CFUNC_tcp_info_tcpi_snd_wscale
+CFUNC_tcp_info_tcpi_rcv_wscale
+CFUNC_tcp_info_tcpi_rto
+CFUNC_tcp_info_tcpi_ato
+CFUNC_tcp_info_tcpi_snd_mss
+CFUNC_tcp_info_tcpi_rcv_mss
+CFUNC_tcp_info_tcpi_unacked
+CFUNC_tcp_info_tcpi_sacked
+CFUNC_tcp_info_tcpi_lost
+CFUNC_tcp_info_tcpi_retrans
+CFUNC_tcp_info_tcpi_fackets
+CFUNC_tcp_info_tcpi_last_data_sent
+CFUNC_tcp_info_tcpi_last_ack_sent
+CFUNC_tcp_info_tcpi_last_data_recv
+CFUNC_tcp_info_tcpi_last_ack_recv
+CFUNC_tcp_info_tcpi_pmtu
+CFUNC_tcp_info_tcpi_rcv_ssthresh
+CFUNC_tcp_info_tcpi_rtt
+CFUNC_tcp_info_tcpi_rttvar
+CFUNC_tcp_info_tcpi_snd_ssthresh
+CFUNC_tcp_info_tcpi_snd_cwnd
+CFUNC_tcp_info_tcpi_advmss
+CFUNC_tcp_info_tcpi_reordering
+CFUNC_tcp_info_tcpi_rcv_rtt
+CFUNC_tcp_info_tcpi_rcv_space
+CFUNC_tcp_info_tcpi_total_retrans
static size_t tcpi_memsize(const void *ptr)
{
@@ -85,7 +88,7 @@ static VALUE init(VALUE self, VALUE io)
return self;
}
-void Init_raindrops_linux_tcp_info(void)
+void Init_raindrops_tcp_info(void)
{
VALUE cRaindrops = rb_define_class("Raindrops", rb_cObject);
VALUE cTCP_Info;
@@ -156,41 +159,37 @@ void Init_raindrops_linux_tcp_info(void)
*/
rb_define_method(cTCP_Info, "get!", 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);
+ DEFINE_METHOD_tcp_info_tcpi_state;
+ DEFINE_METHOD_tcp_info_tcpi_ca_state;
+ DEFINE_METHOD_tcp_info_tcpi_retransmits;
+ DEFINE_METHOD_tcp_info_tcpi_probes;
+ DEFINE_METHOD_tcp_info_tcpi_backoff;
+ DEFINE_METHOD_tcp_info_tcpi_options;
+ DEFINE_METHOD_tcp_info_tcpi_snd_wscale;
+ DEFINE_METHOD_tcp_info_tcpi_rcv_wscale;
+ DEFINE_METHOD_tcp_info_tcpi_rto;
+ DEFINE_METHOD_tcp_info_tcpi_ato;
+ DEFINE_METHOD_tcp_info_tcpi_snd_mss;
+ DEFINE_METHOD_tcp_info_tcpi_rcv_mss;
+ DEFINE_METHOD_tcp_info_tcpi_unacked;
+ DEFINE_METHOD_tcp_info_tcpi_sacked;
+ DEFINE_METHOD_tcp_info_tcpi_lost;
+ DEFINE_METHOD_tcp_info_tcpi_retrans;
+ DEFINE_METHOD_tcp_info_tcpi_fackets;
+ DEFINE_METHOD_tcp_info_tcpi_last_data_sent;
+ DEFINE_METHOD_tcp_info_tcpi_last_ack_sent;
+ DEFINE_METHOD_tcp_info_tcpi_last_data_recv;
+ DEFINE_METHOD_tcp_info_tcpi_last_ack_recv;
+ DEFINE_METHOD_tcp_info_tcpi_pmtu;
+ DEFINE_METHOD_tcp_info_tcpi_rcv_ssthresh;
+ DEFINE_METHOD_tcp_info_tcpi_rtt;
+ DEFINE_METHOD_tcp_info_tcpi_rttvar;
+ DEFINE_METHOD_tcp_info_tcpi_snd_ssthresh;
+ DEFINE_METHOD_tcp_info_tcpi_snd_cwnd;
+ DEFINE_METHOD_tcp_info_tcpi_advmss;
+ DEFINE_METHOD_tcp_info_tcpi_reordering;
+ DEFINE_METHOD_tcp_info_tcpi_rcv_rtt;
+ DEFINE_METHOD_tcp_info_tcpi_rcv_space;
+ DEFINE_METHOD_tcp_info_tcpi_total_retrans;
}
-#endif /* TCP_INFO */
-#endif /* defined(__linux__) && defined(HAVE_LINUX_TCP_H) */
+#endif /* HAVE_STRUCT_TCP_INFO */
diff --git a/test/test_linux_tcp_info.rb b/test/test_tcp_info.rb
similarity index 66%
rename from test/test_linux_tcp_info.rb
rename to test/test_tcp_info.rb
index c947211..15df087 100644
--- a/test/test_linux_tcp_info.rb
+++ b/test/test_tcp_info.rb
@@ -5,15 +5,15 @@
require 'socket'
require 'pp'
$stderr.sync = $stdout.sync = true
-class TestLinuxTCP_Info < Test::Unit::TestCase
+class TestTCP_Info < Test::Unit::TestCase
TEST_ADDR = ENV['UNICORN_TEST_ADDR'] || '127.0.0.1'
# Linux kernel commit 5ee3afba88f5a79d0bff07ddd87af45919259f91
TCP_INFO_useful_listenq = `uname -r`.strip >= '2.6.24'
-
- def test_tcp_server
+ def test_tcp_server_unacked
+ return if RUBY_PLATFORM !~ /linux/ # unacked not implemented on others...
s = TCPServer.new(TEST_ADDR, 0)
rv = Raindrops::TCP_Info.new s
c = TCPSocket.new TEST_ADDR, s.addr[1]
@@ -29,10 +29,8 @@ def test_tcp_server
tmp.get!(s)
assert_equal before, tmp.object_id
- ensure
- c.close if c
- a.close if a
- s.close
+ ensure
+ [ c, a, s ].compact.each(&:close)
end
def test_accessors
@@ -42,12 +40,14 @@ def test_accessors
assert tcp_info_methods.size >= 32
tcp_info_methods.each do |m|
next if m.to_sym == :get!
+ next if ! tmp.respond_to?(m)
val = tmp.__send__ m
assert_kind_of Integer, val
assert val >= 0
end
- ensure
- s.close
+ assert tmp.respond_to?(:state), 'every OS knows about TCP state, right?'
+ ensure
+ s.close
end
def test_tcp_server_delayed
@@ -65,4 +65,21 @@ def test_tcp_server_delayed
a.close if a
s.close
end
-end if RUBY_PLATFORM =~ /linux/
+
+ def test_tcp_server_state_closed
+ s = TCPServer.new(TEST_ADDR, 0)
+ c = TCPSocket.new(TEST_ADDR, s.addr[1])
+ i = Raindrops::TCP_Info.allocate
+ a = s.accept
+ i.get!(a)
+ state = i.state
+ c = c.close
+ sleep(0.01) # wait for kernel to update state
+ i.get!(a)
+ assert_not_equal state, i.state
+ ensure
+ s.close if s
+ c.close if c
+ a.close if a
+ end
+end if defined? Raindrops::TCP_Info
--
EW
next prev parent reply other threads:[~2017-03-16 3:16 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-03-16 3:16 [PATCH 0/2] support TCP_INFO under FreeBSD Eric Wong
2017-03-16 3:16 ` Eric Wong [this message]
2017-03-16 3:16 ` [PATCH 2/2] define Raindrops::TCP hash for TCP states Eric Wong
2017-03-21 2:55 ` [PATCH (ccc)] http_request: support proposed Raindrops::TCP states on Eric Wong
2017-03-21 7:50 ` Simon Eskildsen
2017-03-21 8:19 ` Eric Wong
2017-03-21 18:48 ` Jeremy Evans
2017-03-21 19:12 ` Eric Wong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://yhbt.net/raindrops/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170316031652.17433-2-e@80x24.org \
--to=e@80x24.org \
--cc=raindrops-public@bogomips.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://yhbt.net/raindrops.git/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).