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 +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) */
|