For reporting TCP ListenStats, users of older Linux kernels need to ensure that the the “inet_diag“ and “tcp_diag“ kernel modules are loaded as they do not autoload correctly. The inet_diag facilities of Raindrops is useful for periodic snapshot reporting of listen queue sizes.
Instead of snapshotting, Raindrops::Aggregate::LastDataRecv may be used to aggregate statistics from all accepted sockets as they arrive based on the last_data_recv field in Raindrops::TCP_Info
The standard proc path for active UNIX domain sockets, feel free to call String#replace on this if your /proc is mounted in a non-standard location for whatever reason
If specified, addr may be a string or array of strings representing listen addresses to filter for. Returns a hash with given addresses as keys and ListenStats objects as the values or a hash of all addresses.
addrs = %w(0.0.0.0:80 127.0.0.1:8080)
If addr is nil or not specified, all (IPv4) addresses are returned. If sock is specified, it should be a Raindrops::InetDiagSock object.
static VALUE tcp_listener_stats(int argc, VALUE *argv, VALUE self) { VALUE *ary; long i; VALUE rv = rb_hash_new(); struct nogvl_args args; VALUE addrs, sock; rb_scan_args(argc, argv, "02", &addrs, &sock); /* * allocating page_size instead of OP_LEN since we'll reuse the * buffer for recvmsg() later, we already checked for * OPLEN <= page_size at initialization */ args.iov[2].iov_len = OPLEN; args.iov[2].iov_base = alloca(page_size); args.table = NULL; if (NIL_P(sock)) sock = rb_funcall(cIDSock, id_new, 0); args.fd = my_fileno(sock); switch (TYPE(addrs)) { case T_STRING: rb_hash_aset(rv, addrs, tcp_stats(&args, addrs)); return rv; case T_ARRAY: ary = RARRAY_PTR(addrs); i = RARRAY_LEN(addrs); if (i == 1) { rb_hash_aset(rv, *ary, tcp_stats(&args, *ary)); return rv; } for (; --i >= 0; ary++) { union any_addr check; parse_addr(&check, *ary); rb_hash_aset(rv, *ary, Qtrue); } /* fall through */ case T_NIL: args.table = st_init_strtable(); gen_bytecode_all(&args.iov[2]); break; default: rb_raise(rb_eArgError, "addr must be an array of strings, a string, or nil"); } nl_errcheck(rb_thread_io_blocking_region(diag, &args, args.fd)); st_foreach(args.table, NIL_P(addrs) ? st_to_hash : st_AND_hash, rv); st_free_table(args.table); /* let GC deal with corner cases */ if (argc < 2) rb_io_close(sock); return rv; }
Get ListenStats from an array of paths
Socket state mapping from integer => symbol, based on socket_state enum from include/linux/net.h in the Linux kernel:
typedef enum { SS_FREE = 0, /* not allocated */ SS_UNCONNECTED, /* unconnected to any socket */ SS_CONNECTING, /* in process of connecting */ SS_CONNECTED, /* connected to socket */ SS_DISCONNECTING /* in process of disconnecting */ } socket_state;
SS_CONNECTING maps to ListenStats#queued
SS_CONNECTED maps to ListenStats#active
This method may be significantly slower than its tcp_listener_stats counterpart due to the latter being able to use inet_diag via netlink. This parses /proc/net/unix as there is no other (known) way to expose Unix domain socket statistics over netlink.
# File lib/raindrops/linux.rb, line 37 37: def unix_listener_stats(paths = nil) 38: rv = Hash.new { |h,k| h[k.freeze] = Raindrops::ListenStats.new(0, 0) } 39: if nil == paths 40: paths = [ '[^\n]+' ] 41: else 42: paths = paths.map do |path| 43: path = path.dup 44: path.force_encoding(Encoding::BINARY) if defined?(Encoding) 45: rv[path] 46: Regexp.escape(path) 47: end 48: end 49: paths = /^\w+: \d+ \d+ 00000000 \d+ (\d+)\s+\d+ (#{paths.join('|')})$/ 50: 51: # no point in pread since we can't stat for size on this file 52: File.read(*PROC_NET_UNIX_ARGS).scan(paths) do |s| 53: path = s[1] 54: case s[0].to_i 55: when 2 then rv[path].queued += 1 56: when 3 then rv[path].active += 1 57: end 58: end 59: 60: rv 61: end
Get ListenStats from an array of paths
Socket state mapping from integer => symbol, based on socket_state enum from include/linux/net.h in the Linux kernel:
typedef enum { SS_FREE = 0, /* not allocated */ SS_UNCONNECTED, /* unconnected to any socket */ SS_CONNECTING, /* in process of connecting */ SS_CONNECTED, /* connected to socket */ SS_DISCONNECTING /* in process of disconnecting */ } socket_state;
SS_CONNECTING maps to ListenStats#queued
SS_CONNECTED maps to ListenStats#active
This method may be significantly slower than its tcp_listener_stats counterpart due to the latter being able to use inet_diag via netlink. This parses /proc/net/unix as there is no other (known) way to expose Unix domain socket statistics over netlink.
# File lib/raindrops/linux.rb, line 37 37: def unix_listener_stats(paths = nil) 38: rv = Hash.new { |h,k| h[k.freeze] = Raindrops::ListenStats.new(0, 0) } 39: if nil == paths 40: paths = [ '[^\n]+' ] 41: else 42: paths = paths.map do |path| 43: path = path.dup 44: path.force_encoding(Encoding::BINARY) if defined?(Encoding) 45: rv[path] 46: Regexp.escape(path) 47: end 48: end 49: paths = /^\w+: \d+ \d+ 00000000 \d+ (\d+)\s+\d+ (#{paths.join('|')})$/ 50: 51: # no point in pread since we can't stat for size on this file 52: File.read(*PROC_NET_UNIX_ARGS).scan(paths) do |s| 53: path = s[1] 54: case s[0].to_i 55: when 2 then rv[path].queued += 1 56: when 3 then rv[path].active += 1 57: end 58: end 59: 60: rv 61: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.