raindrops 0.17.0 → 0.19.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: b07afc95a2e2b6d5f116be36ceab5bfe45b58bef
4
- data.tar.gz: 5c8e436802a87b95de68fda59b5e0947d58a4ad5
2
+ SHA256:
3
+ metadata.gz: 0c5318918bfd5808ecc840404c67ed59f80019c6a705ef434b10ae92da78ba06
4
+ data.tar.gz: 1f25061c601aab07e3eb041cc9c2fd005438a1527994e0696b5eafc8dc148650
5
5
  SHA512:
6
- metadata.gz: fd1415d86ff4e2a641eec851906498b551318d0a66cdc52d8cfafe5d46826ede496c0e44b9b6a768ea95db0537f03b5387ce4fda09a8e97af2a8f9ab7ce741d0
7
- data.tar.gz: f0960929656a511b43df2340bf07cbd072cd2fabbe8858c35112450bc790c6cfa406114329b93dd954a6d7c9e6f3ebee75a703bd6cf29f8198b0342fb9c292fd
6
+ metadata.gz: df8be08761d8444a8599da3a5885efc806df935820753f5b000f27ab408171438b0f6ff4650810b5096e648904f5993bbc2a1303b9571df213201919b4b7f565
7
+ data.tar.gz: 250b7236881f06fdd684b22f4844cacb7a0d2ca43703220fe3f0f4ebc49e51faf2015864ef6776edc0d66c7dfd2762e08145548a5dd06b55c2193e989f21a3fd
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
data/.olddoc.yml CHANGED
@@ -1,15 +1,13 @@
1
1
  ---
2
- cgit_url: https://bogomips.org/raindrops.git
3
- git_url: git://bogomips.org/raindrops.git
4
- rdoc_url: https://bogomips.org/raindrops/
5
- public_email: raindrops-public@bogomips.org
6
- private_email: raindrops@bogomips.org
2
+ cgit_url: https://yhbt.net/raindrops.git/
3
+ rdoc_url: https://yhbt.net/raindrops/
4
+ public_email: raindrops-public@yhbt.net
7
5
  ml_url:
8
- - https://bogomips.org/raindrops-public/
6
+ - https://yhbt.net/raindrops-public/
9
7
  - http://ou63pmih66umazou.onion/raindrops-public
10
8
  nntp_url:
11
9
  - nntp://news.public-inbox.org/inbox.comp.lang.ruby.raindrops
12
10
  - nntp://ou63pmih66umazou.onion/inbox.comp.lang.ruby.raindrops
13
11
  source_code:
14
- - git clone git://bogomips.org/raindrops.git
15
- - git clone https://bogomips.org/raindrops.git
12
+ - git clone https://yhbt.net/raindrops.git
13
+ - torsocks git clone http://ou63pmih66umazou.onion/raindrops.git
data/GIT-VERSION-GEN CHANGED
@@ -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.19.1
5
5
 
6
6
  LF='
7
7
  '
data/GNUmakefile CHANGED
@@ -1,4 +1,4 @@
1
1
  all::
2
- RSYNC_DEST := bogomips.org:/srv/bogomips/raindrops
2
+ RSYNC_DEST := yhbt.net:/srv/yhbt/raindrops
3
3
  rfpackage := raindrops
4
4
  include pkg.mk
data/README CHANGED
@@ -58,20 +58,21 @@ 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@yhbt.net) if
62
63
  you have any questions or comments.
63
64
 
64
65
  == Development
65
66
 
66
67
  You can get the latest source via git from the following locations:
67
68
 
68
- git://bogomips.org/raindrops.git
69
+ git://yhbt.net/raindrops.git
69
70
  git://repo.or.cz/raindrops.git (mirror)
70
71
 
71
72
  You may browse the code from the web and download the latest snapshot
72
73
  tarballs here:
73
74
 
74
- * https://bogomips.org/raindrops.git
75
+ * https://yhbt.net/raindrops.git
75
76
  * http://repo.or.cz/w/raindrops.git (gitweb)
76
77
 
77
78
  Inline patches (from "git format-patch") to the mailing list are
@@ -88,9 +89,14 @@ 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@yhbt.net
92
94
 
93
95
  Mailing list archives are available over HTTPS and NNTP:
94
96
 
95
- * https://bogomips.org/raindrops-public/
97
+ * https://yhbt.net/raindrops-public/
98
+ * http://ou63pmih66umazou.onion/raindrops-public/
96
99
  * nntp://news.public-inbox.org/inbox.comp.lang.ruby.raindrops
100
+
101
+ Since archives are public, scrub sensitive information and
102
+ 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
@@ -15,7 +15,6 @@
15
15
  usage = "Usage: #$0 [-d DELAY] [-t QUEUED_THRESHOLD] ADDR..."
16
16
  ARGV.size > 0 or abort usage
17
17
  delay = false
18
- all = false
19
18
  queued_thresh = -1
20
19
  # "normal" exits when driven on the command-line
21
20
  trap(:INT) { exit 130 }
@@ -25,7 +24,7 @@
25
24
  opts.banner = usage
26
25
  opts.on('-d', '--delay=DELAY', Float) { |n| delay = n }
27
26
  opts.on('-t', '--queued-threshold=INT', Integer) { |n| queued_thresh = n }
28
- opts.on('-a', '--all') { all = true }
27
+ opts.on('-a', '--all') { } # noop
29
28
  opts.parse! ARGV
30
29
  end
31
30
 
@@ -1,5 +1,5 @@
1
1
  # This is a snippet of the config that powers
2
- # https://raindrops-demo.bogomips.org/
2
+ # https://yhbt.net/raindrops-demo/
3
3
  # This may be used with the packaged zbatery.conf.rb
4
4
  #
5
5
  # zbatery -c zbatery.conf.ru watcher_demo.ru -E none
@@ -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,10 +7,112 @@
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")
115
+ have_func('rb_thread_call_without_gvl')
13
116
  have_func('rb_thread_blocking_region')
14
117
  have_func('rb_thread_io_blocking_region')
15
118
 
@@ -40,7 +143,7 @@
40
143
  $defs.push(format("-DHAVE_GCC_ATOMIC_BUILTINS"))
41
144
  true
42
145
  else
43
- prev_cflags = $CFLAGS
146
+ $CFLAGS = prev_cflags
44
147
  false
45
148
  end
46
149
  end
@@ -53,4 +156,5 @@
53
156
 
54
157
  apt-get install libatomic-ops-dev
55
158
  SRC
159
+ create_header # generate extconf.h to avoid excessively long command-line
56
160
  create_makefile('raindrops_ext')
@@ -1,46 +1,24 @@
1
1
  #include <ruby.h>
2
2
  #include <stdarg.h>
3
- #ifdef HAVE_RUBY_ST_H
4
- # include <ruby/st.h>
5
- #else
6
- # include <st.h>
7
- #endif
3
+ #include <ruby/st.h>
8
4
  #include "my_fileno.h"
9
5
  #ifdef __linux__
10
6
 
11
- /* Ruby 1.8.6+ macros (for compatibility with Ruby 1.9) */
12
- #ifndef RSTRING_LEN
13
- # define RSTRING_LEN(s) (RSTRING(s)->len)
14
- #endif
15
-
16
- /* partial emulation of the 1.9 rb_thread_blocking_region under 1.8 */
17
- #if !defined(HAVE_RB_THREAD_BLOCKING_REGION) && \
18
- !defined(HAVE_RB_THREAD_IO_BLOCKING_REGION)
19
- # include <rubysig.h>
20
- # define RUBY_UBF_IO ((rb_unblock_function_t *)-1)
21
- typedef void rb_unblock_function_t(void *);
22
- typedef VALUE rb_blocking_function_t(void *);
23
- static VALUE
24
- rb_thread_blocking_region(
25
- rb_blocking_function_t *func, void *data1,
26
- rb_unblock_function_t *ubf, void *data2)
27
- {
28
- VALUE rv;
29
-
30
- TRAP_BEG;
31
- rv = func(data1);
32
- TRAP_END;
33
-
34
- return rv;
35
- }
36
- #endif /* ! HAVE_RB_THREAD_BLOCKING_REGION */
37
-
38
7
  #ifdef HAVE_RB_THREAD_IO_BLOCKING_REGION
8
+ /* Ruby 1.9.3 and 2.0.0 */
39
9
  VALUE rb_thread_io_blocking_region(rb_blocking_function_t *, void *, int);
10
+ # define rd_fd_region(fn,data,fd) \
11
+ rb_thread_io_blocking_region((fn),(data),(fd))
12
+ #elif defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) && \
13
+ defined(HAVE_RUBY_THREAD_H) && HAVE_RUBY_THREAD_H
14
+ /* in case Ruby 2.0+ ever drops rb_thread_io_blocking_region: */
15
+ # include <ruby/thread.h>
16
+ # define COMPAT_FN (void *(*)(void *))
17
+ # define rd_fd_region(fn,data,fd) \
18
+ rb_thread_call_without_gvl(COMPAT_FN(fn),(data),RUBY_UBF_IO,NULL)
40
19
  #else
41
- # define rb_thread_io_blocking_region(fn,data,fd) \
42
- rb_thread_blocking_region((fn),(data),RUBY_UBF_IO,0)
43
- #endif /* HAVE_RB_THREAD_IO_BLOCKING_REGION */
20
+ # error Ruby <= 1.8 not supported
21
+ #endif
44
22
 
45
23
  #include <assert.h>
46
24
  #include <errno.h>
@@ -227,86 +205,76 @@ static void bug_warn_nogvl(const char *fmt, ...)
227
205
  va_end(ap);
228
206
 
229
207
  fprintf(stderr, "Please report how you produced this at "\
230
- "raindrops-public@bogomips.org\n");
208
+ "raindrops-public@yhbt.net\n");
231
209
  fflush(stderr);
232
210
  }
233
211
 
234
212
  static struct listen_stats *stats_for(st_table *table, struct inet_diag_msg *r)
235
213
  {
236
- char *key, *port, *old_key;
214
+ char *host, *key, *port, *old_key;
237
215
  size_t alloca_len;
238
216
  struct listen_stats *stats;
239
- socklen_t keylen;
217
+ socklen_t hostlen;
240
218
  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;
219
+ int n;
220
+ const void *src = r->id.idiag_src;
245
221
 
246
- switch ((sa.ss.ss_family = r->idiag_family)) {
222
+ switch (r->idiag_family) {
247
223
  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);
224
+ hostlen = INET_ADDRSTRLEN;
225
+ alloca_len = hostlen + portlen;
226
+ host = key = alloca(alloca_len);
257
227
  break;
258
228
  }
259
229
  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;
230
+ hostlen = INET6_ADDRSTRLEN;
231
+ alloca_len = 1 + hostlen + 1 + portlen;
265
232
  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);
233
+ host = key + 1;
271
234
  break;
272
235
  }
273
236
  default:
274
237
  assert(0 && "unsupported address family, could that be IPv7?!");
275
238
  }
276
- if (rc != 0) {
277
- bug_warn_nogvl("BUG: getnameinfo: %s\n", gai_strerror(rc));
278
- *key = 0;
239
+ if (!inet_ntop(r->idiag_family, src, host, hostlen)) {
240
+ bug_warn_nogvl("BUG: inet_ntop: %s\n", strerror(errno));
241
+ *key = '\0';
242
+ *host = '\0';
279
243
  }
280
-
281
- keylen = (socklen_t)strlen(key);
282
- portlen = (socklen_t)strlen(port);
283
-
284
- switch (sa.ss.ss_family) {
244
+ hostlen = (socklen_t)strlen(host);
245
+ switch (r->idiag_family) {
285
246
  case AF_INET:
286
- key[keylen] = ':';
287
- memmove(key + keylen + 1, port, portlen + 1);
247
+ host[hostlen] = ':';
248
+ port = host + hostlen + 1;
288
249
  break;
289
250
  case AF_INET6:
290
- key[keylen] = ']';
291
- key[keylen + 1] = ':';
292
- memmove(key + keylen + 2, port, portlen + 1);
293
- keylen++;
251
+ key[0] = '[';
252
+ host[hostlen] = ']';
253
+ host[hostlen + 1] = ':';
254
+ port = host + hostlen + 2;
294
255
  break;
295
256
  default:
296
257
  assert(0 && "unsupported address family, could that be IPv7?!");
297
258
  }
298
259
 
260
+ n = snprintf(port, portlen, "%u", ntohs(r->id.idiag_sport));
261
+ if (n <= 0) {
262
+ bug_warn_nogvl("BUG: snprintf port: %d\n", n);
263
+ *key = '\0';
264
+ }
265
+
299
266
  if (st_lookup(table, (st_data_t)key, (st_data_t *)&stats))
300
267
  return stats;
301
268
 
302
269
  old_key = key;
303
270
 
304
271
  if (r->idiag_state == TCP_ESTABLISHED) {
305
- int n = snprintf(key, alloca_len, "%s:%u",
306
- addr_any(sa.ss.ss_family),
272
+ n = snprintf(key, alloca_len, "%s:%u",
273
+ addr_any(r->idiag_family),
307
274
  ntohs(r->id.idiag_sport));
308
275
  if (n <= 0) {
309
276
  bug_warn_nogvl("BUG: snprintf: %d\n", n);
277
+ *key = '\0';
310
278
  }
311
279
  if (st_lookup(table, (st_data_t)key, (st_data_t *)&stats))
312
280
  return stats;
@@ -319,8 +287,9 @@ static struct listen_stats *stats_for(st_table *table, struct inet_diag_msg *r)
319
287
  memcpy(key, old_key, n + 1);
320
288
  }
321
289
  } else {
322
- key = xmalloc(keylen + 1 + portlen + 1);
323
- memcpy(key, old_key, keylen + 1 + portlen + 1);
290
+ size_t old_len = strlen(old_key) + 1;
291
+ key = xmalloc(old_len);
292
+ memcpy(key, old_key, old_len);
324
293
  }
325
294
  stats = xcalloc(1, sizeof(struct listen_stats));
326
295
  st_insert(table, (st_data_t)key, (st_data_t)stats);
@@ -617,7 +586,7 @@ static VALUE tcp_stats(struct nogvl_args *args, VALUE addr)
617
586
  gen_bytecode(&args->iov[2], &query_addr);
618
587
 
619
588
  memset(&args->stats, 0, sizeof(struct listen_stats));
620
- nl_errcheck(rb_thread_io_blocking_region(diag, args, args->fd));
589
+ nl_errcheck(rd_fd_region(diag, args, args->fd));
621
590
 
622
591
  return rb_listen_stats(&args->stats);
623
592
  }
@@ -694,7 +663,7 @@ static VALUE tcp_listener_stats(int argc, VALUE *argv, VALUE self)
694
663
  "addr must be an array of strings, a string, or nil");
695
664
  }
696
665
 
697
- nl_errcheck(rb_thread_io_blocking_region(diag, &args, args.fd));
666
+ nl_errcheck(rd_fd_region(diag, &args, args.fd));
698
667
 
699
668
  st_foreach(args.table, NIL_P(addrs) ? st_to_hash : st_AND_hash, rv);
700
669
  st_free_table(args.table);
@@ -709,11 +678,12 @@ static VALUE tcp_listener_stats(int argc, VALUE *argv, VALUE self)
709
678
 
710
679
  void Init_raindrops_linux_inet_diag(void)
711
680
  {
712
- VALUE cRaindrops = rb_const_get(rb_cObject, rb_intern("Raindrops"));
681
+ VALUE cRaindrops = rb_define_class("Raindrops", rb_cObject);
713
682
  VALUE mLinux = rb_define_module_under(cRaindrops, "Linux");
683
+ VALUE Socket;
714
684
 
715
685
  rb_require("socket");
716
- cIDSock = rb_const_get(rb_cObject, rb_intern("Socket"));
686
+ Socket = rb_const_get(rb_cObject, rb_intern("Socket"));
717
687
  id_new = rb_intern("new");
718
688
 
719
689
  /*
@@ -722,7 +692,7 @@ void Init_raindrops_linux_inet_diag(void)
722
692
  * This is a subclass of +Socket+ specifically for talking
723
693
  * to the inet_diag facility of Netlink.
724
694
  */
725
- cIDSock = rb_define_class_under(cRaindrops, "InetDiagSocket", cIDSock);
695
+ cIDSock = rb_define_class_under(cRaindrops, "InetDiagSocket", Socket);
726
696
  rb_define_singleton_method(cIDSock, "new", ids_s_new, 0);
727
697
 
728
698
  cListenStats = rb_const_get(cRaindrops, rb_intern("ListenStats"));