raindrops 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.document +1 -1
- data/.olddoc.yml +0 -1
- data/GIT-VERSION-GEN +1 -1
- data/README +7 -2
- data/TODO +1 -0
- data/ext/raindrops/extconf.rb +104 -1
- data/ext/raindrops/linux_inet_diag.c +39 -47
- data/ext/raindrops/raindrops.c +28 -7
- data/ext/raindrops/tcp_info.c +246 -0
- data/lib/raindrops/aggregate/pmq.rb +17 -11
- data/raindrops.gemspec +11 -15
- data/test/test_aggregate_pmq.rb +1 -1
- data/test/test_inet_diag_socket.rb +1 -1
- data/test/test_last_data_recv_unicorn.rb +1 -1
- data/test/{test_linux_tcp_info.rb → test_tcp_info.rb} +30 -10
- data/test/test_watcher.rb +6 -1
- metadata +9 -53
- data/ext/raindrops/linux_tcp_info.c +0 -173
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b8dbbea0d1ec6311fe4433caa527f1ca5483f63b
|
4
|
+
data.tar.gz: e89d864999d618bc1c93df83569d7326924dfa74
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe837f974b975b0582c9a86d041acd823dc78b83aaffc2d35bb721d6da2544a6771fbf53d3ea8a2db6240b0ef05d463bd9572e85375f3600227f08fd44fb6cdd
|
7
|
+
data.tar.gz: 9b380c94a516fbb9df57773f19722314a5c294810ed7f0e4b3027e7a3581c6aefcb0c6f5d5326c4400024e55cf856350e396e37934c781042098297239baafb4
|
data/.document
CHANGED
data/.olddoc.yml
CHANGED
@@ -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
|
data/GIT-VERSION-GEN
CHANGED
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
|
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:
|
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
data/ext/raindrops/extconf.rb
CHANGED
@@ -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
|
-
|
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
|
239
|
+
socklen_t hostlen;
|
240
240
|
socklen_t portlen = (socklen_t)sizeof("65535");
|
241
|
-
|
242
|
-
|
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 (
|
244
|
+
switch (r->idiag_family) {
|
247
245
|
case AF_INET: {
|
248
|
-
|
249
|
-
|
250
|
-
|
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
|
-
|
261
|
-
|
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
|
-
|
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 (
|
277
|
-
bug_warn_nogvl("BUG:
|
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
|
-
|
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
|
-
|
287
|
-
|
269
|
+
host[hostlen] = ':';
|
270
|
+
port = host + hostlen + 1;
|
288
271
|
break;
|
289
272
|
case AF_INET6:
|
290
|
-
key[
|
291
|
-
|
292
|
-
|
293
|
-
|
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
|
-
|
306
|
-
addr_any(
|
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
|
-
|
323
|
-
|
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 =
|
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
|
-
|
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",
|
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"));
|
data/ext/raindrops/raindrops.c
CHANGED
@@ -38,7 +38,7 @@ struct raindrops {
|
|
38
38
|
};
|
39
39
|
|
40
40
|
/* called by GC */
|
41
|
-
static void
|
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 =
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
data/raindrops.gemspec
CHANGED
@@ -1,30 +1,26 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
-
|
3
|
-
|
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 =
|
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 =
|
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 =
|
20
|
-
s.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
|
data/test/test_aggregate_pmq.rb
CHANGED
@@ -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
|
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
|
@@ -5,15 +5,15 @@
|
|
5
5
|
require 'socket'
|
6
6
|
require 'pp'
|
7
7
|
$stderr.sync = $stdout.sync = true
|
8
|
-
class
|
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
|
-
|
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
|
-
|
33
|
-
|
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
|
-
|
50
|
-
|
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
|
-
|
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
|
data/test/test_watcher.rb
CHANGED
@@ -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.
|
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:
|
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/
|
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:
|
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.
|
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) */
|