1 # -*- encoding: binary -*-
2 # frozen_string_literal: false
4 # For reporting TCP ListenStats, users of older \Linux kernels need to ensure
5 # that the the "inet_diag" and "tcp_diag" kernel modules are loaded as they do
6 # not autoload correctly. The inet_diag facilities of \Raindrops is useful
7 # for periodic snapshot reporting of listen queue sizes.
9 # Instead of snapshotting, Raindrops::Aggregate::LastDataRecv may be used
10 # to aggregate statistics from +all+ accepted sockets as they arrive
11 # based on the +last_data_recv+ field in Raindrops::TCP_Info
13 module Raindrops::Linux
15 # The standard proc path for active UNIX domain sockets, feel free to call
16 # String#replace on this if your /proc is mounted in a non-standard location
18 PROC_NET_UNIX_ARGS = [ '/proc/net/unix', { encoding: "binary" }]
20 # Get ListenStats from an array of +paths+
22 # Socket state mapping from integer => symbol, based on socket_state
23 # enum from include/linux/net.h in the \Linux kernel:
25 # SS_FREE = 0, /* not allocated */
26 # SS_UNCONNECTED, /* unconnected to any socket */
27 # SS_CONNECTING, /* in process of connecting */
28 # SS_CONNECTED, /* connected to socket */
29 # SS_DISCONNECTING /* in process of disconnecting */
31 # * SS_CONNECTING maps to ListenStats#queued
32 # * SS_CONNECTED maps to ListenStats#active
34 # This method may be significantly slower than its tcp_listener_stats
35 # counterpart due to the latter being able to use inet_diag via netlink.
36 # This parses /proc/net/unix as there is no other (known) way
37 # to expose Unix domain socket statistics over netlink.
38 def unix_listener_stats(paths = nil)
39 rv = Hash.new { |h,k| h[k.freeze] = Raindrops::ListenStats.new(0, 0) }
43 paths = paths.map do |path|
45 path.force_encoding(Encoding::BINARY)
46 if File.symlink?(path)
48 path = File.readlink(link)
49 path.force_encoding(Encoding::BINARY)
50 rv[link] = rv[path] # vivify ListenerStats
52 rv[path] # vivify ListenerStats
57 paths = /^\w+: \d+ \d+ (\d+) \d+ (\d+)\s+\d+ (#{paths.join('|')})$/n
59 # no point in pread since we can't stat for size on this file
60 File.read(PROC_NET_UNIX_ARGS[0], encoding: 'binary').scan(paths) do |s|
63 when "00000000" # client sockets
65 when 2 then rv[path].queued += 1
66 when 3 then rv[path].active += 1
69 # listeners, vivify empty stats
76 module_function :unix_listener_stats
78 end # Raindrops::Linux