resolve symlinks to Unix domain sockets
[raindrops.git] / lib / raindrops / linux.rb
bloba1982538d16d984f6e5e9ce6acb45d33d66eeb33
1 # -*- encoding: binary -*-
3 # For reporting TCP ListenStats, users of older \Linux kernels need to ensure
4 # that the the "inet_diag" and "tcp_diag" kernel modules are loaded as they do
5 # not autoload correctly.  The inet_diag facilities of \Raindrops is useful
6 # for periodic snapshot reporting of listen queue sizes.
8 # Instead of snapshotting, Raindrops::Aggregate::LastDataRecv may be used
9 # to aggregate statistics from +all+ accepted sockets as they arrive
10 # based on the +last_data_recv+ field in Raindrops::TCP_Info
11 require 'pathname'
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
17   # for whatever reason
18   PROC_NET_UNIX_ARGS = %w(/proc/net/unix)
19   defined?(::Encoding) and PROC_NET_UNIX_ARGS.push({ :encoding => "binary" })
21   # Get ListenStats from an array of +paths+
22   #
23   # Socket state mapping from integer => symbol, based on socket_state
24   # enum from include/linux/net.h in the \Linux kernel:
25   #     typedef enum {
26   #             SS_FREE = 0,              /* not allocated                */
27   #             SS_UNCONNECTED,           /* unconnected to any socket    */
28   #             SS_CONNECTING,            /* in process of connecting     */
29   #             SS_CONNECTED,             /* connected to socket          */
30   #             SS_DISCONNECTING          /* in process of disconnecting  */
31   #     } socket_state;
32   # * SS_CONNECTING maps to ListenStats#queued
33   # * SS_CONNECTED maps to ListenStats#active
34   #
35   # This method may be significantly slower than its tcp_listener_stats
36   # counterpart due to the latter being able to use inet_diag via netlink.
37   # This parses /proc/net/unix as there is no other (known) way
38   # to expose Unix domain socket statistics over netlink.
39   def unix_listener_stats(paths = nil)
40     rv = Hash.new { |h,k| h[k.freeze] = Raindrops::ListenStats.new(0, 0) }
41     if nil == paths
42       paths = [ '[^\n]+' ]
43     else
44       paths = paths.map do |path|
45         path = path.dup
46         path = Pathname.new(path).realpath.to_s
47         path.force_encoding(Encoding::BINARY) if defined?(Encoding)
48         rv[path]
49         Regexp.escape(path)
50       end
51     end
52     paths = /^\w+: \d+ \d+ 00000000 \d+ (\d+)\s+\d+ (#{paths.join('|')})$/n
54     # no point in pread since we can't stat for size on this file
55     File.read(*PROC_NET_UNIX_ARGS).scan(paths) do |s|
56       path = s[-1]
57       case s[0].to_i
58       when 2 then rv[path].queued += 1
59       when 3 then rv[path].active += 1
60       end
61     end
63     rv
64   end
65   module_function :unix_listener_stats
67 end # Raindrops::Linux