raindrops 0.17.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b07afc95a2e2b6d5f116be36ceab5bfe45b58bef
4
- data.tar.gz: 5c8e436802a87b95de68fda59b5e0947d58a4ad5
3
+ metadata.gz: b8dbbea0d1ec6311fe4433caa527f1ca5483f63b
4
+ data.tar.gz: e89d864999d618bc1c93df83569d7326924dfa74
5
5
  SHA512:
6
- metadata.gz: fd1415d86ff4e2a641eec851906498b551318d0a66cdc52d8cfafe5d46826ede496c0e44b9b6a768ea95db0537f03b5387ce4fda09a8e97af2a8f9ab7ce741d0
7
- data.tar.gz: f0960929656a511b43df2340bf07cbd072cd2fabbe8858c35112450bc790c6cfa406114329b93dd954a6d7c9e6f3ebee75a703bd6cf29f8198b0342fb9c292fd
6
+ metadata.gz: fe837f974b975b0582c9a86d041acd823dc78b83aaffc2d35bb721d6da2544a6771fbf53d3ea8a2db6240b0ef05d463bd9572e85375f3600227f08fd44fb6cdd
7
+ data.tar.gz: 9b380c94a516fbb9df57773f19722314a5c294810ed7f0e4b3027e7a3581c6aefcb0c6f5d5326c4400024e55cf856350e396e37934c781042098297239baafb4
data/.document CHANGED
@@ -4,4 +4,4 @@ NEWS
4
4
  lib
5
5
  ext/raindrops/raindrops.c
6
6
  ext/raindrops/linux_inet_diag.c
7
- ext/raindrops/linux_tcp_info.c
7
+ ext/raindrops/tcp_info.c
@@ -3,7 +3,6 @@ cgit_url: https://bogomips.org/raindrops.git
3
3
  git_url: git://bogomips.org/raindrops.git
4
4
  rdoc_url: https://bogomips.org/raindrops/
5
5
  public_email: raindrops-public@bogomips.org
6
- private_email: raindrops@bogomips.org
7
6
  ml_url:
8
7
  - https://bogomips.org/raindrops-public/
9
8
  - http://ou63pmih66umazou.onion/raindrops-public
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v0.17.0
4
+ DEF_VER=v0.18.0
5
5
 
6
6
  LF='
7
7
  '
data/README CHANGED
@@ -58,7 +58,8 @@ If you use RubyGems:
58
58
 
59
59
  See Raindrops::Middleware and Raindrops::LastDataRecv documentation for
60
60
  use Rack servers. The entire library is fully-documented and we are
61
- responsive on the mailing list (mailto:raindrops-public@bogomips.org) if
61
+ responsive on the publically archived mailing list
62
+ (mailto:raindrops-public@bogomips.org) if
62
63
  you have any questions or comments.
63
64
 
64
65
  == Development
@@ -88,9 +89,13 @@ raindrops is licensed under the LGPL-2.1+
88
89
  == Contact
89
90
 
90
91
  All feedback (bug reports, user/development discussion, patches, pull
91
- requests) go to the mailing list: mailto:raindrops-public@bogomips.org
92
+ requests) go to the publically archived mailing list:
93
+ mailto:raindrops-public@bogomips.org
92
94
 
93
95
  Mailing list archives are available over HTTPS and NNTP:
94
96
 
95
97
  * https://bogomips.org/raindrops-public/
96
98
  * nntp://news.public-inbox.org/inbox.comp.lang.ruby.raindrops
99
+
100
+ Since archives are public, scrub sensitive information and
101
+ use anonymity tools such as Tor or Mixmaster if you deem necessary.
data/TODO CHANGED
@@ -1,2 +1,3 @@
1
+ * fix IPv6 inet_diag reporting for Raindrops::Middleware
1
2
  * pure Ruby version for non-forking servers (patches welcome!)
2
3
  * unix_diag and udp_diag support
@@ -1,4 +1,5 @@
1
1
  require 'mkmf'
2
+ require 'shellwords'
2
3
 
3
4
  dir_config('atomic_ops')
4
5
  have_func('mmap', 'sys/mman.h') or abort 'mmap() not found'
@@ -6,9 +7,110 @@
6
7
 
7
8
  $CPPFLAGS += " -D_GNU_SOURCE "
8
9
  have_func('mremap', 'sys/mman.h')
9
- have_header('linux/tcp.h')
10
+ headers = %w(sys/types.h netdb.h string.h sys/socket.h netinet/in.h)
11
+ if have_header('linux/tcp.h')
12
+ headers << 'linux/tcp.h'
13
+ else
14
+ %w(netinet/tcp.h netinet/tcp_fsm.h).each { |h|
15
+ have_header(h, headers) and headers << h
16
+ }
17
+ end
10
18
 
11
19
  $CPPFLAGS += " -D_BSD_SOURCE "
20
+
21
+ if have_type("struct tcp_info", headers)
22
+ %w(
23
+ tcpi_state
24
+ tcpi_ca_state
25
+ tcpi_retransmits
26
+ tcpi_probes
27
+ tcpi_backoff
28
+ tcpi_options
29
+ tcpi_snd_wscale
30
+ tcpi_rcv_wscale
31
+ tcpi_rto
32
+ tcpi_ato
33
+ tcpi_snd_mss
34
+ tcpi_rcv_mss
35
+ tcpi_unacked
36
+ tcpi_sacked
37
+ tcpi_lost
38
+ tcpi_retrans
39
+ tcpi_fackets
40
+ tcpi_last_data_sent
41
+ tcpi_last_ack_sent
42
+ tcpi_last_data_recv
43
+ tcpi_last_ack_recv
44
+ tcpi_pmtu
45
+ tcpi_rcv_ssthresh
46
+ tcpi_rtt
47
+ tcpi_rttvar
48
+ tcpi_snd_ssthresh
49
+ tcpi_snd_cwnd
50
+ tcpi_advmss
51
+ tcpi_reordering
52
+ tcpi_rcv_rtt
53
+ tcpi_rcv_space
54
+ tcpi_total_retrans
55
+ tcpi_snd_wnd
56
+ tcpi_snd_bwnd
57
+ tcpi_snd_nxt
58
+ tcpi_rcv_nxt
59
+ tcpi_toe_tid
60
+ tcpi_snd_rexmitpack
61
+ tcpi_rcv_ooopack
62
+ tcpi_snd_zerowin
63
+ ).each do |field|
64
+ cfunc = "tcp_info_#{field}"
65
+ if have_struct_member('struct tcp_info', field, headers)
66
+ func_body = <<EOF
67
+ static VALUE #{cfunc}(VALUE self)
68
+ {
69
+ struct tcp_info *info = DATA_PTR(self);
70
+ return UINT2NUM((uint32_t)info->#{field});
71
+ }
72
+ EOF
73
+ func_body.delete!("\n")
74
+ $defs << "-DCFUNC_#{cfunc}=#{Shellwords.shellescape(func_body)}"
75
+ else
76
+ func_body = "static inline void #{cfunc}(void) {}"
77
+ $defs << "-DCFUNC_#{cfunc}=#{Shellwords.shellescape(func_body)}"
78
+ cfunc = 'rb_f_notimplement'.freeze
79
+ end
80
+ rbmethod = %Q("#{field.sub(/\Atcpi_/, ''.freeze)}")
81
+ $defs << "-DDEFINE_METHOD_tcp_info_#{field}=" \
82
+ "#{Shellwords.shellescape(
83
+ %Q[rb_define_method(cTCP_Info,#{rbmethod},#{cfunc},0)])}"
84
+ end
85
+ tcp_state_map = {
86
+ ESTABLISHED: %w(TCP_ESTABLISHED TCPS_ESTABLISHED),
87
+ SYN_SENT: %w(TCP_SYN_SENT TCPS_SYN_SENT),
88
+ SYN_RECV: %w(TCP_SYN_RECV TCPS_SYN_RECEIVED),
89
+ FIN_WAIT1: %w(TCP_FIN_WAIT1 TCPS_FIN_WAIT_1),
90
+ FIN_WAIT2: %w(TCP_FIN_WAIT2 TCPS_FIN_WAIT_2),
91
+ TIME_WAIT: %w(TCP_TIME_WAIT TCPS_TIME_WAIT),
92
+ CLOSE: %w(TCP_CLOSE TCPS_CLOSED),
93
+ CLOSE_WAIT: %w(TCP_CLOSE_WAIT TCPS_CLOSE_WAIT),
94
+ LAST_ACK: %w(TCP_LAST_ACK TCPS_LAST_ACK),
95
+ LISTEN: %w(TCP_LISTEN TCPS_LISTEN),
96
+ CLOSING: %w(TCP_CLOSING TCPS_CLOSING),
97
+ }
98
+ nstate = 0
99
+ tcp_state_map.each do |state, try|
100
+ try.each do |os_name|
101
+ have_const(os_name, headers) or next
102
+ tcp_state_map[state] = os_name
103
+ nstate += 1
104
+ end
105
+ end
106
+ if nstate == tcp_state_map.size
107
+ $defs << '-DRAINDROPS_TCP_STATES_ALL_KNOWN=1'
108
+ tcp_state_map.each do |state, name|
109
+ $defs << "-DRAINDROPS_TCP_#{state}=#{name}"
110
+ end
111
+ end
112
+ end
113
+
12
114
  have_func("getpagesize", "unistd.h")
13
115
  have_func('rb_thread_blocking_region')
14
116
  have_func('rb_thread_io_blocking_region')
@@ -53,4 +155,5 @@
53
155
 
54
156
  apt-get install libatomic-ops-dev
55
157
  SRC
158
+ create_header # generate extconf.h to avoid excessively long command-line
56
159
  create_makefile('raindrops_ext')
@@ -233,80 +233,70 @@ static void bug_warn_nogvl(const char *fmt, ...)
233
233
 
234
234
  static struct listen_stats *stats_for(st_table *table, struct inet_diag_msg *r)
235
235
  {
236
- char *key, *port, *old_key;
236
+ char *host, *key, *port, *old_key;
237
237
  size_t alloca_len;
238
238
  struct listen_stats *stats;
239
- socklen_t keylen;
239
+ socklen_t hostlen;
240
240
  socklen_t portlen = (socklen_t)sizeof("65535");
241
- union any_addr sa;
242
- socklen_t len = sizeof(struct sockaddr_storage);
243
- int rc;
244
- int flags = NI_NUMERICHOST | NI_NUMERICSERV;
241
+ int n;
242
+ const void *src = r->id.idiag_src;
245
243
 
246
- switch ((sa.ss.ss_family = r->idiag_family)) {
244
+ switch (r->idiag_family) {
247
245
  case AF_INET: {
248
- sa.in.sin_port = r->id.idiag_sport;
249
- sa.in.sin_addr.s_addr = r->id.idiag_src[0];
250
- keylen = INET_ADDRSTRLEN;
251
- alloca_len = keylen + 1 + portlen;
252
- key = alloca(alloca_len);
253
- key[keylen] = 0; /* will be ':' later */
254
- port = key + keylen + 1;
255
- rc = getnameinfo(&sa.sa, len,
256
- key, keylen, port, portlen, flags);
246
+ hostlen = INET_ADDRSTRLEN;
247
+ alloca_len = hostlen + portlen;
248
+ host = key = alloca(alloca_len);
257
249
  break;
258
250
  }
259
251
  case AF_INET6: {
260
- sa.in6.sin6_port = r->id.idiag_sport;
261
- memcpy(&sa.in6.sin6_addr, &r->id.idiag_src, sizeof(__be32[4]));
262
- keylen = INET6_ADDRSTRLEN;
263
- /* [ ] */
264
- alloca_len = 1 + keylen + 1 + 1 + portlen;
252
+ hostlen = INET6_ADDRSTRLEN;
253
+ alloca_len = 1 + hostlen + 1 + portlen;
265
254
  key = alloca(alloca_len);
266
- *key = '[';
267
- key[1 + keylen + 1] = 0; /* will be ':' later */
268
- port = 1 + key + keylen + 1 + 1;
269
- rc = getnameinfo(&sa.sa, len,
270
- key + 1, keylen, port, portlen, flags);
255
+ host = key + 1;
271
256
  break;
272
257
  }
273
258
  default:
274
259
  assert(0 && "unsupported address family, could that be IPv7?!");
275
260
  }
276
- if (rc != 0) {
277
- bug_warn_nogvl("BUG: getnameinfo: %s\n", gai_strerror(rc));
278
- *key = 0;
261
+ if (!inet_ntop(r->idiag_family, src, host, hostlen)) {
262
+ bug_warn_nogvl("BUG: inet_ntop: %s\n", strerror(errno));
263
+ *key = '\0';
264
+ *host = '\0';
279
265
  }
280
-
281
- keylen = (socklen_t)strlen(key);
282
- portlen = (socklen_t)strlen(port);
283
-
284
- switch (sa.ss.ss_family) {
266
+ hostlen = (socklen_t)strlen(host);
267
+ switch (r->idiag_family) {
285
268
  case AF_INET:
286
- key[keylen] = ':';
287
- memmove(key + keylen + 1, port, portlen + 1);
269
+ host[hostlen] = ':';
270
+ port = host + hostlen + 1;
288
271
  break;
289
272
  case AF_INET6:
290
- key[keylen] = ']';
291
- key[keylen + 1] = ':';
292
- memmove(key + keylen + 2, port, portlen + 1);
293
- keylen++;
273
+ key[0] = '[';
274
+ host[hostlen] = ']';
275
+ host[hostlen + 1] = ':';
276
+ port = host + hostlen + 2;
294
277
  break;
295
278
  default:
296
279
  assert(0 && "unsupported address family, could that be IPv7?!");
297
280
  }
298
281
 
282
+ n = snprintf(port, portlen, "%u", ntohs(r->id.idiag_sport));
283
+ if (n <= 0) {
284
+ bug_warn_nogvl("BUG: snprintf port: %d\n", n);
285
+ *key = '\0';
286
+ }
287
+
299
288
  if (st_lookup(table, (st_data_t)key, (st_data_t *)&stats))
300
289
  return stats;
301
290
 
302
291
  old_key = key;
303
292
 
304
293
  if (r->idiag_state == TCP_ESTABLISHED) {
305
- int n = snprintf(key, alloca_len, "%s:%u",
306
- addr_any(sa.ss.ss_family),
294
+ n = snprintf(key, alloca_len, "%s:%u",
295
+ addr_any(r->idiag_family),
307
296
  ntohs(r->id.idiag_sport));
308
297
  if (n <= 0) {
309
298
  bug_warn_nogvl("BUG: snprintf: %d\n", n);
299
+ *key = '\0';
310
300
  }
311
301
  if (st_lookup(table, (st_data_t)key, (st_data_t *)&stats))
312
302
  return stats;
@@ -319,8 +309,9 @@ static struct listen_stats *stats_for(st_table *table, struct inet_diag_msg *r)
319
309
  memcpy(key, old_key, n + 1);
320
310
  }
321
311
  } else {
322
- key = xmalloc(keylen + 1 + portlen + 1);
323
- memcpy(key, old_key, keylen + 1 + portlen + 1);
312
+ size_t old_len = strlen(old_key) + 1;
313
+ key = xmalloc(old_len);
314
+ memcpy(key, old_key, old_len);
324
315
  }
325
316
  stats = xcalloc(1, sizeof(struct listen_stats));
326
317
  st_insert(table, (st_data_t)key, (st_data_t)stats);
@@ -709,11 +700,12 @@ static VALUE tcp_listener_stats(int argc, VALUE *argv, VALUE self)
709
700
 
710
701
  void Init_raindrops_linux_inet_diag(void)
711
702
  {
712
- VALUE cRaindrops = rb_const_get(rb_cObject, rb_intern("Raindrops"));
703
+ VALUE cRaindrops = rb_define_class("Raindrops", rb_cObject);
713
704
  VALUE mLinux = rb_define_module_under(cRaindrops, "Linux");
705
+ VALUE Socket;
714
706
 
715
707
  rb_require("socket");
716
- cIDSock = rb_const_get(rb_cObject, rb_intern("Socket"));
708
+ Socket = rb_const_get(rb_cObject, rb_intern("Socket"));
717
709
  id_new = rb_intern("new");
718
710
 
719
711
  /*
@@ -722,7 +714,7 @@ void Init_raindrops_linux_inet_diag(void)
722
714
  * This is a subclass of +Socket+ specifically for talking
723
715
  * to the inet_diag facility of Netlink.
724
716
  */
725
- cIDSock = rb_define_class_under(cRaindrops, "InetDiagSocket", cIDSock);
717
+ cIDSock = rb_define_class_under(cRaindrops, "InetDiagSocket", Socket);
726
718
  rb_define_singleton_method(cIDSock, "new", ids_s_new, 0);
727
719
 
728
720
  cListenStats = rb_const_get(cRaindrops, rb_intern("ListenStats"));
@@ -38,7 +38,7 @@ struct raindrops {
38
38
  };
39
39
 
40
40
  /* called by GC */
41
- static void gcfree(void *ptr)
41
+ static void rd_free(void *ptr)
42
42
  {
43
43
  struct raindrops *r = ptr;
44
44
 
@@ -51,11 +51,24 @@ static void gcfree(void *ptr)
51
51
  xfree(ptr);
52
52
  }
53
53
 
54
+ static size_t rd_memsize(const void *ptr)
55
+ {
56
+ const struct raindrops *r = ptr;
57
+
58
+ return r->drops == MAP_FAILED ? 0 : raindrop_size * r->capa;
59
+ }
60
+
61
+ static const rb_data_type_t rd_type = {
62
+ "raindrops",
63
+ { NULL, rd_free, rd_memsize, /* reserved */ },
64
+ /* parent, data, [ flags ] */
65
+ };
66
+
54
67
  /* automatically called at creation (before initialize) */
55
68
  static VALUE alloc(VALUE klass)
56
69
  {
57
70
  struct raindrops *r;
58
- VALUE rv = Data_Make_Struct(klass, struct raindrops, NULL, gcfree, r);
71
+ VALUE rv = TypedData_Make_Struct(klass, struct raindrops, &rd_type, r);
59
72
 
60
73
  r->drops = MAP_FAILED;
61
74
  return rv;
@@ -65,7 +78,7 @@ static struct raindrops *get(VALUE self)
65
78
  {
66
79
  struct raindrops *r;
67
80
 
68
- Data_Get_Struct(self, struct raindrops, r);
81
+ TypedData_Get_Struct(self, struct raindrops, &rd_type, r);
69
82
 
70
83
  if (r->drops == MAP_FAILED)
71
84
  rb_raise(rb_eStandardError, "invalid or freed Raindrops");
@@ -104,7 +117,9 @@ retry:
104
117
  r->drops = mmap(NULL, tmp,
105
118
  PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
106
119
  if (r->drops == MAP_FAILED) {
107
- if ((errno == EAGAIN || errno == ENOMEM) && tries-- > 0) {
120
+ int err = errno;
121
+
122
+ if ((err == EAGAIN || err == ENOMEM) && tries-- > 0) {
108
123
  rb_gc();
109
124
  goto retry;
110
125
  }
@@ -140,7 +155,9 @@ static void resize(struct raindrops *r, size_t new_rd_size)
140
155
 
141
156
  rv = mremap(old_address, old_size, new_size, MREMAP_MAYMOVE);
142
157
  if (rv == MAP_FAILED) {
143
- if (errno == EAGAIN || errno == ENOMEM) {
158
+ int err = errno;
159
+
160
+ if (err == EAGAIN || err == ENOMEM) {
144
161
  rb_gc();
145
162
  rv = mremap(old_address, old_size, new_size, 0);
146
163
  }
@@ -323,7 +340,9 @@ static VALUE aref(VALUE self, VALUE index)
323
340
 
324
341
  #ifdef __linux__
325
342
  void Init_raindrops_linux_inet_diag(void);
326
- void Init_raindrops_linux_tcp_info(void);
343
+ #endif
344
+ #ifdef HAVE_TYPE_STRUCT_TCP_INFO
345
+ void Init_raindrops_tcp_info(void);
327
346
  #endif
328
347
 
329
348
  #ifndef _SC_NPROCESSORS_CONF
@@ -428,6 +447,8 @@ void Init_raindrops_ext(void)
428
447
 
429
448
  #ifdef __linux__
430
449
  Init_raindrops_linux_inet_diag();
431
- Init_raindrops_linux_tcp_info();
450
+ #endif
451
+ #ifdef HAVE_TYPE_STRUCT_TCP_INFO
452
+ Init_raindrops_tcp_info();
432
453
  #endif
433
454
  }
@@ -0,0 +1,246 @@
1
+ #include <ruby.h>
2
+ #include "extconf.h"
3
+ #include <sys/socket.h>
4
+ #include <netinet/in.h>
5
+ #if defined(HAVE_LINUX_TCP_H)
6
+ # include <linux/tcp.h>
7
+ #else
8
+ # if defined(HAVE_NETINET_TCP_H)
9
+ # include <netinet/tcp.h>
10
+ # endif
11
+ # if defined(HAVE_NETINET_TCP_FSM_H)
12
+ # include <netinet/tcp_fsm.h>
13
+ # endif
14
+ #endif
15
+
16
+ #ifdef HAVE_TYPE_STRUCT_TCP_INFO
17
+ #include "my_fileno.h"
18
+
19
+ CFUNC_tcp_info_tcpi_state
20
+ CFUNC_tcp_info_tcpi_ca_state
21
+ CFUNC_tcp_info_tcpi_retransmits
22
+ CFUNC_tcp_info_tcpi_probes
23
+ CFUNC_tcp_info_tcpi_backoff
24
+ CFUNC_tcp_info_tcpi_options
25
+ CFUNC_tcp_info_tcpi_snd_wscale
26
+ CFUNC_tcp_info_tcpi_rcv_wscale
27
+ CFUNC_tcp_info_tcpi_rto
28
+ CFUNC_tcp_info_tcpi_ato
29
+ CFUNC_tcp_info_tcpi_snd_mss
30
+ CFUNC_tcp_info_tcpi_rcv_mss
31
+ CFUNC_tcp_info_tcpi_unacked
32
+ CFUNC_tcp_info_tcpi_sacked
33
+ CFUNC_tcp_info_tcpi_lost
34
+ CFUNC_tcp_info_tcpi_retrans
35
+ CFUNC_tcp_info_tcpi_fackets
36
+ CFUNC_tcp_info_tcpi_last_data_sent
37
+ CFUNC_tcp_info_tcpi_last_ack_sent
38
+ CFUNC_tcp_info_tcpi_last_data_recv
39
+ CFUNC_tcp_info_tcpi_last_ack_recv
40
+ CFUNC_tcp_info_tcpi_pmtu
41
+ CFUNC_tcp_info_tcpi_rcv_ssthresh
42
+ CFUNC_tcp_info_tcpi_rtt
43
+ CFUNC_tcp_info_tcpi_rttvar
44
+ CFUNC_tcp_info_tcpi_snd_ssthresh
45
+ CFUNC_tcp_info_tcpi_snd_cwnd
46
+ CFUNC_tcp_info_tcpi_advmss
47
+ CFUNC_tcp_info_tcpi_reordering
48
+ CFUNC_tcp_info_tcpi_rcv_rtt
49
+ CFUNC_tcp_info_tcpi_rcv_space
50
+ CFUNC_tcp_info_tcpi_total_retrans
51
+
52
+ static size_t tcpi_memsize(const void *ptr)
53
+ {
54
+ return sizeof(struct tcp_info);
55
+ }
56
+
57
+ static const rb_data_type_t tcpi_type = {
58
+ "tcp_info",
59
+ { NULL, RUBY_TYPED_DEFAULT_FREE, tcpi_memsize, /* reserved */ },
60
+ /* parent, data, [ flags ] */
61
+ };
62
+
63
+ static VALUE alloc(VALUE klass)
64
+ {
65
+ struct tcp_info *info;
66
+
67
+ return TypedData_Make_Struct(klass, struct tcp_info, &tcpi_type, info);
68
+ }
69
+
70
+ /*
71
+ * call-seq:
72
+ *
73
+ * Raindrops::TCP_Info.new(tcp_socket) -> TCP_Info object
74
+ *
75
+ * Reads a TCP_Info object from any given +tcp_socket+. See the tcp(7)
76
+ * manpage and /usr/include/linux/tcp.h for more details.
77
+ */
78
+ static VALUE init(VALUE self, VALUE io)
79
+ {
80
+ int fd = my_fileno(io);
81
+ struct tcp_info *info = DATA_PTR(self);
82
+ socklen_t len = (socklen_t)sizeof(struct tcp_info);
83
+ int rc = getsockopt(fd, IPPROTO_TCP, TCP_INFO, info, &len);
84
+
85
+ if (rc != 0)
86
+ rb_sys_fail("getsockopt");
87
+
88
+ return self;
89
+ }
90
+
91
+ void Init_raindrops_tcp_info(void)
92
+ {
93
+ VALUE cRaindrops = rb_define_class("Raindrops", rb_cObject);
94
+ VALUE cTCP_Info;
95
+
96
+ /*
97
+ * Document-class: Raindrops::TCP_Info
98
+ *
99
+ * This is used to wrap "struct tcp_info" as described in tcp(7)
100
+ * and /usr/include/linux/tcp.h. The following readers methods
101
+ * are defined corresponding to the "tcpi_" fields in the
102
+ * tcp_info struct.
103
+ *
104
+ * As of raindrops 0.18.0+, this is supported on FreeBSD and OpenBSD
105
+ * systems as well as Linux, although not all fields exist or
106
+ * match the documentation, below.
107
+ *
108
+ * In particular, the +last_data_recv+ field is useful for measuring
109
+ * the amount of time a client spent in the listen queue before
110
+ * +accept()+, but only if +TCP_DEFER_ACCEPT+ is used with the
111
+ * listen socket (it is on by default in Unicorn).
112
+ *
113
+ * - state
114
+ * - ca_state
115
+ * - retransmits
116
+ * - probes
117
+ * - backoff
118
+ * - options
119
+ * - snd_wscale
120
+ * - rcv_wscale
121
+ * - rto
122
+ * - ato
123
+ * - snd_mss
124
+ * - rcv_mss
125
+ * - unacked
126
+ * - sacked
127
+ * - lost
128
+ * - retrans
129
+ * - fackets
130
+ * - last_data_sent
131
+ * - last_ack_sent
132
+ * - last_data_recv
133
+ * - last_ack_recv
134
+ * - pmtu
135
+ * - rcv_ssthresh
136
+ * - rtt
137
+ * - rttvar
138
+ * - snd_ssthresh
139
+ * - snd_cwnd
140
+ * - advmss
141
+ * - reordering
142
+ * - rcv_rtt
143
+ * - rcv_space
144
+ * - total_retrans
145
+ *
146
+ * https://kernel.org/doc/man-pages/online/pages/man7/tcp.7.html
147
+ */
148
+ cTCP_Info = rb_define_class_under(cRaindrops, "TCP_Info", rb_cObject);
149
+ rb_define_alloc_func(cTCP_Info, alloc);
150
+ rb_define_private_method(cTCP_Info, "initialize", init, 1);
151
+
152
+ /*
153
+ * Document-method: Raindrops::TCP_Info#get!
154
+ *
155
+ * call-seq:
156
+ *
157
+ * info = Raindrops::TCP_Info.new(tcp_socket)
158
+ * info.get!(tcp_socket)
159
+ *
160
+ * Update an existing TCP_Info objects with the latest stats
161
+ * from the given socket. This even allows sharing TCP_Info
162
+ * objects between different sockets to avoid garbage.
163
+ */
164
+ rb_define_method(cTCP_Info, "get!", init, 1);
165
+
166
+ DEFINE_METHOD_tcp_info_tcpi_state;
167
+ DEFINE_METHOD_tcp_info_tcpi_ca_state;
168
+ DEFINE_METHOD_tcp_info_tcpi_retransmits;
169
+ DEFINE_METHOD_tcp_info_tcpi_probes;
170
+ DEFINE_METHOD_tcp_info_tcpi_backoff;
171
+ DEFINE_METHOD_tcp_info_tcpi_options;
172
+ DEFINE_METHOD_tcp_info_tcpi_snd_wscale;
173
+ DEFINE_METHOD_tcp_info_tcpi_rcv_wscale;
174
+ DEFINE_METHOD_tcp_info_tcpi_rto;
175
+ DEFINE_METHOD_tcp_info_tcpi_ato;
176
+ DEFINE_METHOD_tcp_info_tcpi_snd_mss;
177
+ DEFINE_METHOD_tcp_info_tcpi_rcv_mss;
178
+ DEFINE_METHOD_tcp_info_tcpi_unacked;
179
+ DEFINE_METHOD_tcp_info_tcpi_sacked;
180
+ DEFINE_METHOD_tcp_info_tcpi_lost;
181
+ DEFINE_METHOD_tcp_info_tcpi_retrans;
182
+ DEFINE_METHOD_tcp_info_tcpi_fackets;
183
+ DEFINE_METHOD_tcp_info_tcpi_last_data_sent;
184
+ DEFINE_METHOD_tcp_info_tcpi_last_ack_sent;
185
+ DEFINE_METHOD_tcp_info_tcpi_last_data_recv;
186
+ DEFINE_METHOD_tcp_info_tcpi_last_ack_recv;
187
+ DEFINE_METHOD_tcp_info_tcpi_pmtu;
188
+ DEFINE_METHOD_tcp_info_tcpi_rcv_ssthresh;
189
+ DEFINE_METHOD_tcp_info_tcpi_rtt;
190
+ DEFINE_METHOD_tcp_info_tcpi_rttvar;
191
+ DEFINE_METHOD_tcp_info_tcpi_snd_ssthresh;
192
+ DEFINE_METHOD_tcp_info_tcpi_snd_cwnd;
193
+ DEFINE_METHOD_tcp_info_tcpi_advmss;
194
+ DEFINE_METHOD_tcp_info_tcpi_reordering;
195
+ DEFINE_METHOD_tcp_info_tcpi_rcv_rtt;
196
+ DEFINE_METHOD_tcp_info_tcpi_rcv_space;
197
+ DEFINE_METHOD_tcp_info_tcpi_total_retrans;
198
+
199
+ #ifdef RAINDROPS_TCP_STATES_ALL_KNOWN
200
+
201
+ /*
202
+ * Document-const: Raindrops::TCP
203
+ *
204
+ * This is a frozen hash storing the numeric values
205
+ * maps platform-independent symbol keys to
206
+ * platform-dependent numeric values. These states
207
+ * are all valid values for the Raindrops::TCP_Info#state field.
208
+ *
209
+ * The platform-independent names of the keys in this hash are:
210
+ *
211
+ * - :ESTABLISHED
212
+ * - :SYN_SENT
213
+ * - :SYN_RECV
214
+ * - :FIN_WAIT1
215
+ * - :FIN_WAIT2
216
+ * - :TIME_WAIT
217
+ * - :CLOSE
218
+ * - :CLOSE_WAIT
219
+ * - :LAST_ACK
220
+ * - :LISTEN
221
+ * - :CLOSING
222
+ *
223
+ * This is only supported on platforms where TCP_Info is supported,
224
+ * currently FreeBSD, OpenBSD, and Linux-based systems.
225
+ */
226
+ {
227
+ #define TCPSET(n,v) rb_hash_aset(tcp, ID2SYM(rb_intern(#n)), INT2NUM(v))
228
+ VALUE tcp = rb_hash_new();
229
+ TCPSET(ESTABLISHED, RAINDROPS_TCP_ESTABLISHED);
230
+ TCPSET(SYN_SENT, RAINDROPS_TCP_SYN_SENT);
231
+ TCPSET(SYN_RECV, RAINDROPS_TCP_SYN_RECV);
232
+ TCPSET(FIN_WAIT1, RAINDROPS_TCP_FIN_WAIT1);
233
+ TCPSET(FIN_WAIT2, RAINDROPS_TCP_FIN_WAIT2);
234
+ TCPSET(TIME_WAIT, RAINDROPS_TCP_TIME_WAIT);
235
+ TCPSET(CLOSE, RAINDROPS_TCP_CLOSE);
236
+ TCPSET(CLOSE_WAIT, RAINDROPS_TCP_CLOSE_WAIT);
237
+ TCPSET(LAST_ACK, RAINDROPS_TCP_LAST_ACK);
238
+ TCPSET(LISTEN, RAINDROPS_TCP_LISTEN);
239
+ TCPSET(CLOSING, RAINDROPS_TCP_CLOSING);
240
+ #undef TCPSET
241
+ OBJ_FREEZE(tcp);
242
+ rb_define_const(cRaindrops, "TCP", tcp);
243
+ }
244
+ #endif
245
+ }
246
+ #endif /* HAVE_STRUCT_TCP_INFO */
@@ -3,10 +3,10 @@
3
3
  require "aggregate"
4
4
  require "posix_mq"
5
5
  require "fcntl"
6
- require "io/extra"
7
6
  require "thread"
7
+ require "stringio"
8
8
 
9
- # \Aggregate + POSIX message queues support for Ruby 1.9 and \Linux
9
+ # \Aggregate + POSIX message queues support for Ruby 1.9+ and \Linux
10
10
  #
11
11
  # This class is duck-type compatible with \Aggregate and allows us to
12
12
  # aggregate and share statistics from multiple processes/threads aided
@@ -14,12 +14,11 @@
14
14
  # Raindrops::LastDataRecv Rack application, but can be used independently
15
15
  # on compatible Runtimes.
16
16
  #
17
- # Unlike the core of raindrops, this is only supported on Ruby 1.9 and
18
- # Linux 2.6. Using this class requires the following additional RubyGems
17
+ # Unlike the core of raindrops, this is only supported on Ruby 1.9+ and
18
+ # Linux 2.6+. Using this class requires the following additional RubyGems
19
19
  # or libraries:
20
20
  #
21
21
  # * aggregate (tested with 0.2.2)
22
- # * io-extra (tested with 1.2.3)
23
22
  # * posix_mq (tested with 1.0.0)
24
23
  #
25
24
  # == Design
@@ -39,9 +38,9 @@ class Raindrops::Aggregate::PMQ
39
38
  # :stopdoc:
40
39
  # These constants are for Linux. This is designed for aggregating
41
40
  # TCP_INFO.
42
- RDLOCK = [ Fcntl::F_RDLCK ].pack("s @256")
43
- WRLOCK = [ Fcntl::F_WRLCK ].pack("s @256")
44
- UNLOCK = [ Fcntl::F_UNLCK ].pack("s @256")
41
+ RDLOCK = [ Fcntl::F_RDLCK ].pack("s @256".freeze).freeze
42
+ WRLOCK = [ Fcntl::F_WRLCK ].pack("s @256".freeze).freeze
43
+ UNLOCK = [ Fcntl::F_UNLCK ].pack("s @256".freeze).freeze
45
44
  # :startdoc:
46
45
 
47
46
  # returns the number of dropped messages sent to a POSIX message
@@ -84,6 +83,7 @@ def initialize(params = {})
84
83
  @wr = File.open(t.path, "wb")
85
84
  @rd = File.open(t.path, "rb")
86
85
  end
86
+ @wr.sync = true
87
87
  @cached_aggregate = @aggregate
88
88
  flush_master
89
89
  @mq_send = if opts[:lossy]
@@ -151,7 +151,10 @@ def aggregate
151
151
  @cached_aggregate ||= begin
152
152
  flush
153
153
  Marshal.load(synchronize(@rd, RDLOCK) do |rd|
154
- IO.pread rd.fileno, rd.stat.size, 0
154
+ dst = StringIO.new
155
+ dst.binmode
156
+ IO.copy_stream(rd, dst, rd.size, 0)
157
+ dst.string
155
158
  end)
156
159
  end
157
160
  end
@@ -163,7 +166,8 @@ def flush_master
163
166
  dump = Marshal.dump @aggregate
164
167
  synchronize(@wr, WRLOCK) do |wr|
165
168
  wr.truncate 0
166
- IO.pwrite wr.fileno, dump, 0
169
+ wr.rewind
170
+ wr.write(dump)
167
171
  end
168
172
  end
169
173
 
@@ -185,10 +189,12 @@ def lock! io, type # :nodoc:
185
189
  def synchronize io, type # :nodoc:
186
190
  @mutex.synchronize do
187
191
  begin
192
+ type = type.dup
188
193
  lock! io, type
189
194
  yield io
190
195
  ensure
191
- lock! io, UNLOCK
196
+ lock! io, type.replace(UNLOCK)
197
+ type.clear
192
198
  end
193
199
  end
194
200
  end
@@ -1,30 +1,26 @@
1
1
  # -*- encoding: binary -*-
2
- ENV["VERSION"] or abort "VERSION= must be specified"
3
- manifest = File.readlines('.manifest').map! { |x| x.chomp! }
2
+ manifest = File.exist?('.manifest') ?
3
+ IO.readlines('.manifest').map!(&:chomp!) : `git ls-files`.split("\n")
4
4
  test_files = manifest.grep(%r{\Atest/test_.*\.rb\z})
5
- require 'olddoc'
6
- extend Olddoc::Gemspec
7
- name, summary, title = readme_metadata
8
5
 
9
6
  Gem::Specification.new do |s|
10
7
  s.name = %q{raindrops}
11
- s.version = ENV["VERSION"].dup
12
-
8
+ s.version = (ENV["VERSION"] ||= '0.18.0').dup
13
9
  s.authors = ["raindrops hackers"]
14
- s.description = readme_description
15
- s.email = %q{raindrops@bogomips.org}
10
+ s.description = File.read('README').split("\n\n")[1]
11
+ s.email = %q{raindrops-public@bogomips.org}
16
12
  s.extensions = %w(ext/raindrops/extconf.rb)
17
- s.extra_rdoc_files = extra_rdoc_files(manifest)
13
+ s.extra_rdoc_files = IO.readlines('.document').map!(&:chomp!).keep_if do |f|
14
+ File.exist?(f)
15
+ end
18
16
  s.files = manifest
19
- s.homepage = Olddoc.config['rdoc_url']
20
- s.summary = summary
17
+ s.homepage = 'https://bogomips.org/raindrops/'
18
+ s.summary = 'real-time stats for preforking Rack servers'
19
+ s.required_ruby_version = '>= 1.9.3'
21
20
  s.test_files = test_files
22
21
  s.add_development_dependency('aggregate', '~> 0.2')
23
22
  s.add_development_dependency('test-unit', '~> 3.0')
24
- s.add_development_dependency('io-extra', [ '~> 1.2', '>= 1.2.3'])
25
23
  s.add_development_dependency('posix_mq', '~> 2.0')
26
24
  s.add_development_dependency('rack', [ '>= 1.2', '< 3.0' ])
27
- s.add_development_dependency('olddoc', '~> 1.0')
28
-
29
25
  s.licenses = %w(LGPL-2.1+)
30
26
  end
@@ -3,7 +3,7 @@
3
3
  pmq = begin
4
4
  Raindrops::Aggregate::PMQ
5
5
  rescue LoadError => e
6
- warn "W: #{e} skipping test"
6
+ warn "W: #{e} skipping #{__FILE__}"
7
7
  false
8
8
  end
9
9
  if RUBY_VERSION.to_f < 1.9
@@ -8,7 +8,7 @@ class TestInetDiagSocket < Test::Unit::TestCase
8
8
  def test_new
9
9
  sock = Raindrops::InetDiagSocket.new
10
10
  assert_kind_of Socket, sock
11
- assert_kind_of Fixnum, sock.fileno
11
+ assert_kind_of Integer, sock.fileno
12
12
  flags = sock.fcntl(Fcntl::F_GETFD)
13
13
  assert_equal Fcntl::FD_CLOEXEC, flags & Fcntl::FD_CLOEXEC
14
14
  assert_nil sock.close
@@ -7,7 +7,7 @@
7
7
  pmq = begin
8
8
  Raindrops::Aggregate::PMQ
9
9
  rescue LoadError => e
10
- warn "W: #{e} skipping test"
10
+ warn "W: #{e} skipping #{__FILE__}"
11
11
  false
12
12
  end
13
13
  if RUBY_VERSION.to_f < 1.9
@@ -5,15 +5,15 @@
5
5
  require 'socket'
6
6
  require 'pp'
7
7
  $stderr.sync = $stdout.sync = true
8
- class TestLinuxTCP_Info < Test::Unit::TestCase
8
+ class TestTCP_Info < Test::Unit::TestCase
9
9
 
10
10
  TEST_ADDR = ENV['UNICORN_TEST_ADDR'] || '127.0.0.1'
11
11
 
12
12
  # Linux kernel commit 5ee3afba88f5a79d0bff07ddd87af45919259f91
13
13
  TCP_INFO_useful_listenq = `uname -r`.strip >= '2.6.24'
14
14
 
15
-
16
- def test_tcp_server
15
+ def test_tcp_server_unacked
16
+ return if RUBY_PLATFORM !~ /linux/ # unacked not implemented on others...
17
17
  s = TCPServer.new(TEST_ADDR, 0)
18
18
  rv = Raindrops::TCP_Info.new s
19
19
  c = TCPSocket.new TEST_ADDR, s.addr[1]
@@ -29,10 +29,8 @@ def test_tcp_server
29
29
  tmp.get!(s)
30
30
  assert_equal before, tmp.object_id
31
31
 
32
- ensure
33
- c.close if c
34
- a.close if a
35
- s.close
32
+ ensure
33
+ [ c, a, s ].compact.each(&:close)
36
34
  end
37
35
 
38
36
  def test_accessors
@@ -42,12 +40,14 @@ def test_accessors
42
40
  assert tcp_info_methods.size >= 32
43
41
  tcp_info_methods.each do |m|
44
42
  next if m.to_sym == :get!
43
+ next if ! tmp.respond_to?(m)
45
44
  val = tmp.__send__ m
46
45
  assert_kind_of Integer, val
47
46
  assert val >= 0
48
47
  end
49
- ensure
50
- s.close
48
+ assert tmp.respond_to?(:state), 'every OS knows about TCP state, right?'
49
+ ensure
50
+ s.close
51
51
  end
52
52
 
53
53
  def test_tcp_server_delayed
@@ -65,4 +65,24 @@ def test_tcp_server_delayed
65
65
  a.close if a
66
66
  s.close
67
67
  end
68
- end if RUBY_PLATFORM =~ /linux/
68
+
69
+ def test_tcp_server_state_closed
70
+ s = TCPServer.new(TEST_ADDR, 0)
71
+ c = TCPSocket.new(TEST_ADDR, s.addr[1])
72
+ i = Raindrops::TCP_Info.allocate
73
+ a = s.accept
74
+ i.get!(a)
75
+ state = i.state
76
+ if Raindrops.const_defined?(:TCP)
77
+ assert_equal state, Raindrops::TCP[:ESTABLISHED]
78
+ end
79
+ c = c.close
80
+ sleep(0.01) # wait for kernel to update state
81
+ i.get!(a)
82
+ assert_not_equal state, i.state
83
+ ensure
84
+ s.close if s
85
+ c.close if c
86
+ a.close if a
87
+ end
88
+ end if defined? Raindrops::TCP_Info
@@ -2,6 +2,11 @@
2
2
  require "test/unit"
3
3
  require "rack"
4
4
  require "raindrops"
5
+ begin
6
+ require 'aggregate'
7
+ rescue LoadError => e
8
+ warn "W: #{e} skipping #{__FILE__}"
9
+ end
5
10
 
6
11
  class TestWatcher < Test::Unit::TestCase
7
12
  TEST_ADDR = ENV['UNICORN_TEST_ADDR'] || '127.0.0.1'
@@ -178,4 +183,4 @@ def test_peaks
178
183
  assert_equal queued_before, headers["X-Last-Peak-At"], "should not change"
179
184
  assert_equal start, headers["X-First-Peak-At"]
180
185
  end
181
- end if RUBY_PLATFORM =~ /linux/
186
+ end if RUBY_PLATFORM =~ /linux/ && defined?(Aggregate)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: raindrops
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 0.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - raindrops hackers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-31 00:00:00.000000000 Z
11
+ date: 2017-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aggregate
@@ -38,26 +38,6 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '3.0'
41
- - !ruby/object:Gem::Dependency
42
- name: io-extra
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '1.2'
48
- - - ">="
49
- - !ruby/object:Gem::Version
50
- version: 1.2.3
51
- type: :development
52
- prerelease: false
53
- version_requirements: !ruby/object:Gem::Requirement
54
- requirements:
55
- - - "~>"
56
- - !ruby/object:Gem::Version
57
- version: '1.2'
58
- - - ">="
59
- - !ruby/object:Gem::Version
60
- version: 1.2.3
61
41
  - !ruby/object:Gem::Dependency
62
42
  name: posix_mq
63
43
  requirement: !ruby/object:Gem::Requirement
@@ -92,27 +72,13 @@ dependencies:
92
72
  - - "<"
93
73
  - !ruby/object:Gem::Version
94
74
  version: '3.0'
95
- - !ruby/object:Gem::Dependency
96
- name: olddoc
97
- requirement: !ruby/object:Gem::Requirement
98
- requirements:
99
- - - "~>"
100
- - !ruby/object:Gem::Version
101
- version: '1.0'
102
- type: :development
103
- prerelease: false
104
- version_requirements: !ruby/object:Gem::Requirement
105
- requirements:
106
- - - "~>"
107
- - !ruby/object:Gem::Version
108
- version: '1.0'
109
75
  description: |-
110
76
  raindrops is a real-time stats toolkit to show statistics for Rack HTTP
111
77
  servers. It is designed for preforking servers such as unicorn, but
112
78
  should support any Rack HTTP server on platforms supporting POSIX shared
113
79
  memory. It may also be used as a generic scoreboard for sharing atomic
114
80
  counters across multiple processes.
115
- email: raindrops@bogomips.org
81
+ email: raindrops-public@bogomips.org
116
82
  executables: []
117
83
  extensions:
118
84
  - ext/raindrops/extconf.rb
@@ -120,19 +86,9 @@ extra_rdoc_files:
120
86
  - README
121
87
  - LICENSE
122
88
  - NEWS
123
- - lib/raindrops.rb
124
- - lib/raindrops/aggregate.rb
125
- - lib/raindrops/aggregate/last_data_recv.rb
126
- - lib/raindrops/aggregate/pmq.rb
127
- - lib/raindrops/last_data_recv.rb
128
- - lib/raindrops/linux.rb
129
- - lib/raindrops/middleware.rb
130
- - lib/raindrops/middleware/proxy.rb
131
- - lib/raindrops/struct.rb
132
- - lib/raindrops/watcher.rb
133
89
  - ext/raindrops/raindrops.c
134
90
  - ext/raindrops/linux_inet_diag.c
135
- - ext/raindrops/linux_tcp_info.c
91
+ - ext/raindrops/tcp_info.c
136
92
  files:
137
93
  - ".document"
138
94
  - ".gitattributes"
@@ -158,10 +114,10 @@ files:
158
114
  - examples/zbatery.conf.rb
159
115
  - ext/raindrops/extconf.rb
160
116
  - ext/raindrops/linux_inet_diag.c
161
- - ext/raindrops/linux_tcp_info.c
162
117
  - ext/raindrops/my_fileno.h
163
118
  - ext/raindrops/raindrops.c
164
119
  - ext/raindrops/raindrops_atomic.h
120
+ - ext/raindrops/tcp_info.c
165
121
  - lib/raindrops.rb
166
122
  - lib/raindrops/aggregate.rb
167
123
  - lib/raindrops/aggregate/last_data_recv.rb
@@ -185,13 +141,13 @@ files:
185
141
  - test/test_linux_all_tcp_listen_stats_leak.rb
186
142
  - test/test_linux_ipv6.rb
187
143
  - test/test_linux_middleware.rb
188
- - test/test_linux_tcp_info.rb
189
144
  - test/test_middleware.rb
190
145
  - test/test_middleware_unicorn.rb
191
146
  - test/test_middleware_unicorn_ipv6.rb
192
147
  - test/test_raindrops.rb
193
148
  - test/test_raindrops_gc.rb
194
149
  - test/test_struct.rb
150
+ - test/test_tcp_info.rb
195
151
  - test/test_watcher.rb
196
152
  homepage: https://bogomips.org/raindrops/
197
153
  licenses:
@@ -205,7 +161,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
205
161
  requirements:
206
162
  - - ">="
207
163
  - !ruby/object:Gem::Version
208
- version: '0'
164
+ version: 1.9.3
209
165
  required_rubygems_version: !ruby/object:Gem::Requirement
210
166
  requirements:
211
167
  - - ">="
@@ -213,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
213
169
  version: '0'
214
170
  requirements: []
215
171
  rubyforge_project:
216
- rubygems_version: 2.6.6
172
+ rubygems_version: 2.6.10
217
173
  signing_key:
218
174
  specification_version: 4
219
175
  summary: real-time stats for preforking Rack servers
@@ -226,11 +182,11 @@ test_files:
226
182
  - test/test_linux_all_tcp_listen_stats_leak.rb
227
183
  - test/test_linux_ipv6.rb
228
184
  - test/test_linux_middleware.rb
229
- - test/test_linux_tcp_info.rb
230
185
  - test/test_middleware.rb
231
186
  - test/test_middleware_unicorn.rb
232
187
  - test/test_middleware_unicorn_ipv6.rb
233
188
  - test/test_raindrops.rb
234
189
  - test/test_raindrops_gc.rb
235
190
  - test/test_struct.rb
191
+ - test/test_tcp_info.rb
236
192
  - test/test_watcher.rb
@@ -1,173 +0,0 @@
1
- #if defined(__linux__) && defined(HAVE_LINUX_TCP_H)
2
- #include <ruby.h>
3
- #include <sys/socket.h>
4
- #include <netinet/in.h>
5
- #include <linux/tcp.h>
6
- #ifdef TCP_INFO
7
- #include "my_fileno.h"
8
-
9
- #define TCPI_ATTR_READER(x) \
10
- static VALUE tcp_info_##x(VALUE self) \
11
- { \
12
- struct tcp_info *info = DATA_PTR(self); \
13
- return UINT2NUM((uint32_t)info->tcpi_##x); \
14
- }
15
-
16
- TCPI_ATTR_READER(state)
17
- TCPI_ATTR_READER(ca_state)
18
- TCPI_ATTR_READER(retransmits)
19
- TCPI_ATTR_READER(probes)
20
- TCPI_ATTR_READER(backoff)
21
- TCPI_ATTR_READER(options)
22
- TCPI_ATTR_READER(snd_wscale)
23
- TCPI_ATTR_READER(rcv_wscale)
24
- TCPI_ATTR_READER(rto)
25
- TCPI_ATTR_READER(ato)
26
- TCPI_ATTR_READER(snd_mss)
27
- TCPI_ATTR_READER(rcv_mss)
28
- TCPI_ATTR_READER(unacked)
29
- TCPI_ATTR_READER(sacked)
30
- TCPI_ATTR_READER(lost)
31
- TCPI_ATTR_READER(retrans)
32
- TCPI_ATTR_READER(fackets)
33
- TCPI_ATTR_READER(last_data_sent)
34
- TCPI_ATTR_READER(last_ack_sent)
35
- TCPI_ATTR_READER(last_data_recv)
36
- TCPI_ATTR_READER(last_ack_recv)
37
- TCPI_ATTR_READER(pmtu)
38
- TCPI_ATTR_READER(rcv_ssthresh)
39
- TCPI_ATTR_READER(rtt)
40
- TCPI_ATTR_READER(rttvar)
41
- TCPI_ATTR_READER(snd_ssthresh)
42
- TCPI_ATTR_READER(snd_cwnd)
43
- TCPI_ATTR_READER(advmss)
44
- TCPI_ATTR_READER(reordering)
45
- TCPI_ATTR_READER(rcv_rtt)
46
- TCPI_ATTR_READER(rcv_space)
47
- TCPI_ATTR_READER(total_retrans)
48
-
49
- static VALUE alloc(VALUE klass)
50
- {
51
- struct tcp_info *info = xmalloc(sizeof(struct tcp_info));
52
-
53
- /* Data_Make_Struct has an extra memset 0 which is so wasteful */
54
- return Data_Wrap_Struct(klass, NULL, -1, info);
55
- }
56
-
57
- /*
58
- * call-seq:
59
- *
60
- * Raindrops::TCP_Info.new(tcp_socket) -> TCP_Info object
61
- *
62
- * Reads a TCP_Info object from any given +tcp_socket+. See the tcp(7)
63
- * manpage and /usr/include/linux/tcp.h for more details.
64
- */
65
- static VALUE init(VALUE self, VALUE io)
66
- {
67
- int fd = my_fileno(io);
68
- struct tcp_info *info = DATA_PTR(self);
69
- socklen_t len = (socklen_t)sizeof(struct tcp_info);
70
- int rc = getsockopt(fd, IPPROTO_TCP, TCP_INFO, info, &len);
71
-
72
- if (rc != 0)
73
- rb_sys_fail("getsockopt");
74
-
75
- return self;
76
- }
77
-
78
- void Init_raindrops_linux_tcp_info(void)
79
- {
80
- VALUE cRaindrops = rb_const_get(rb_cObject, rb_intern("Raindrops"));
81
- VALUE cTCP_Info;
82
-
83
- /*
84
- * Document-class: Raindrops::TCP_Info
85
- *
86
- * This is used to wrap "struct tcp_info" as described in tcp(7)
87
- * and /usr/include/linux/tcp.h. The following readers methods
88
- * are defined corresponding to the "tcpi_" fields in the
89
- * tcp_info struct.
90
- *
91
- * In particular, the +last_data_recv+ field is useful for measuring
92
- * the amount of time a client spent in the listen queue before
93
- * +accept()+, but only if +TCP_DEFER_ACCEPT+ is used with the
94
- * listen socket (it is on by default in Unicorn).
95
- *
96
- * - state
97
- * - ca_state
98
- * - retransmits
99
- * - probes
100
- * - backoff
101
- * - options
102
- * - snd_wscale
103
- * - rcv_wscale
104
- * - rto
105
- * - ato
106
- * - snd_mss
107
- * - rcv_mss
108
- * - unacked
109
- * - sacked
110
- * - lost
111
- * - retrans
112
- * - fackets
113
- * - last_data_sent
114
- * - last_ack_sent
115
- * - last_data_recv
116
- * - last_ack_recv
117
- * - pmtu
118
- * - rcv_ssthresh
119
- * - rtt
120
- * - rttvar
121
- * - snd_ssthresh
122
- * - snd_cwnd
123
- * - advmss
124
- * - reordering
125
- * - rcv_rtt
126
- * - rcv_space
127
- * - total_retrans
128
- *
129
- * https://kernel.org/doc/man-pages/online/pages/man7/tcp.7.html
130
- */
131
- cTCP_Info = rb_define_class_under(cRaindrops, "TCP_Info", rb_cObject);
132
- rb_define_alloc_func(cTCP_Info, alloc);
133
- rb_define_private_method(cTCP_Info, "initialize", init, 1);
134
- rb_define_method(cTCP_Info, "get!", init, 1);
135
-
136
- #define TCPI_DEFINE_METHOD(x) \
137
- rb_define_method(cTCP_Info, #x, tcp_info_##x, 0)
138
-
139
- TCPI_DEFINE_METHOD(state);
140
- TCPI_DEFINE_METHOD(ca_state);
141
- TCPI_DEFINE_METHOD(retransmits);
142
- TCPI_DEFINE_METHOD(probes);
143
- TCPI_DEFINE_METHOD(backoff);
144
- TCPI_DEFINE_METHOD(options);
145
- TCPI_DEFINE_METHOD(snd_wscale);
146
- TCPI_DEFINE_METHOD(rcv_wscale);
147
- TCPI_DEFINE_METHOD(rto);
148
- TCPI_DEFINE_METHOD(ato);
149
- TCPI_DEFINE_METHOD(snd_mss);
150
- TCPI_DEFINE_METHOD(rcv_mss);
151
- TCPI_DEFINE_METHOD(unacked);
152
- TCPI_DEFINE_METHOD(sacked);
153
- TCPI_DEFINE_METHOD(lost);
154
- TCPI_DEFINE_METHOD(retrans);
155
- TCPI_DEFINE_METHOD(fackets);
156
- TCPI_DEFINE_METHOD(last_data_sent);
157
- TCPI_DEFINE_METHOD(last_ack_sent);
158
- TCPI_DEFINE_METHOD(last_data_recv);
159
- TCPI_DEFINE_METHOD(last_ack_recv);
160
- TCPI_DEFINE_METHOD(pmtu);
161
- TCPI_DEFINE_METHOD(rcv_ssthresh);
162
- TCPI_DEFINE_METHOD(rtt);
163
- TCPI_DEFINE_METHOD(rttvar);
164
- TCPI_DEFINE_METHOD(snd_ssthresh);
165
- TCPI_DEFINE_METHOD(snd_cwnd);
166
- TCPI_DEFINE_METHOD(advmss);
167
- TCPI_DEFINE_METHOD(reordering);
168
- TCPI_DEFINE_METHOD(rcv_rtt);
169
- TCPI_DEFINE_METHOD(rcv_space);
170
- TCPI_DEFINE_METHOD(total_retrans);
171
- }
172
- #endif /* TCP_INFO */
173
- #endif /* defined(__linux__) && defined(HAVE_LINUX_TCP_H) */