| Class | Dsadmin::Admind::SocketListener |
| In: |
lib/dsadmin/admind/socket_listener.rb
|
| Parent: | Object |
This class sets up TCP servers on the IPs/ports configured in the configfile, spawns a thread for each incoming connection and hands the requests off to the RequestProcessor.
Also handles ACL checking (by host/IP) for incoming connections.
# File lib/dsadmin/admind/socket_listener.rb, line 74
74: def initialize
75: @in_shutdown = false
76: @running = false
77: @gc_counter = 0
78: end
Shut down the system. Multiple startup/shutdown cycles for the same SocketListener are fine.
# File lib/dsadmin/admind/socket_listener.rb, line 55
55: def shutdown
56: return if @in_shutdown
57: return unless @running
58: @in_shutdown = true # don't accept any new frontend connections
59: @running = false
60:
61: log.notice("Shutting down ...")
62:
63: @servers.each { |server| server.close rescue nil }
64: @listener_threads.each { |thread| thread.join }
65: @connection_handlers.each { |handler| handler.shutdown }
66:
67: @in_shutdown = false
68: end
Start the system. Multiple startup/shutdown cycles for the same SocketListener are fine.
# File lib/dsadmin/admind/socket_listener.rb, line 39
39: def startup
40: requireTrue(! @in_shutdown)
41: return if @running
42:
43: @servers = []
44: @net_acls = nil
45: @connection_handlers = []
46: @connection_handlers.extend(MonitorMixin)
47:
48: start_listeners
49:
50: @running = true
51: end
Check if remote_host or remote_port are in the given accept_list
# File lib/dsadmin/admind/socket_listener.rb, line 185
185: def check_acl(accept_list, remote_host, remote_ip)
186: #@log.debug "Checking incoming connection from #{remote_host}(#{remote_ip}"
187: accept_list.each { |entry|
188: if((entry.kind_of?(String) && (entry == remote_host)) ||
189: (entry.kind_of?(IPAddr) && entry.include?(remote_ip))
190: )
191: return true
192: end
193: }
194:
195: return false
196: end
Create a ConnectionHandler for the given connection and hand processing over to it
# File lib/dsadmin/admind/socket_listener.rb, line 136
136: def dispatch(connection)
137: handler = ConnectionHandler.new
138: handler.handle(connection)
139: @connection_handlers.synchronize { @connection_handlers << handler }
140: end
Remove leftover ConnectionHandler objects
# File lib/dsadmin/admind/socket_listener.rb, line 144
144: def garbage_collect
145: if(@gc_counter < 100)
146: @gc_counter += 1
147: return
148: end
149:
150: @gc_counter = 0
151:
152: @connnection_handlers.synchronize {
153: @connection_handlers.delete_if { |handler|
154: ! handler.active?
155: }
156: }
157: end
# File lib/dsadmin/admind/socket_listener.rb, line 114
114: def listen(server)
115: while ((! @in_shutdown) && (conn = server.accept))
116: rhost = conn.peeraddr[2]
117: rip = IPAddr.new(conn.peeraddr[3])
118: rport = conn.peeraddr[1]
119:
120: if(check_acl(net_acls, rhost, rip))
121: log.notice("Accepting connection from #{rhost}(#{rip}):#{rport}")
122: dispatch(conn)
123: else
124: log.warning("Rejecting connection attempt from #{rhost}(#{rip}):#{rport}")
125: session.shutdown
126: end
127:
128: garbage_collect
129: end
130:
131: server.close
132: end
# File lib/dsadmin/admind/socket_listener.rb, line 95
95: def listener_thread(ip, port)
96: # We create the TCPServer outside of the thread to make sure that all servers are
97: # really listening before we return from startup() (which is typically followed by a
98: # drop_privileges in AdminDaemon)
99: server = TCPServer.new(ip, port)
100: @servers << server
101: log.notice "Now listening on '#{server.addr[2]}':#{server.addr[1]} ('#{server.addr[3]}':#{server.addr[1]})"
102:
103: spawnThread do
104: begin
105: listen(server)
106: rescue IOError
107: # ignore -- this is caused by the forced
108: # close() on shutdown
109: end
110: end
111: end
Get the list of hosts/ports (or port ranges/patterns) that are allowed to connect (configfile:/admind/net/accept-from). Caches the information.
# File lib/dsadmin/admind/socket_listener.rb, line 162
162: def net_acls
163: return @net_acls if @net_acls
164:
165: csect = cfg.net_config.get('accept_from', Array, false) || []
166:
167: accept = Array.new
168:
169: csect.each do |entry|
170: host = entry
171:
172: begin
173: ip = IPAddr.new(host)
174: accept << ip # Valid IP adress w/ optional mask
175: rescue ArgumentError
176: accept << host # Hostname
177: end
178: end
179:
180: @net_acls = accept
181: end
# File lib/dsadmin/admind/socket_listener.rb, line 81
81: def start_listeners
82: csect= cfg.net_config.get('listen', Array)
83:
84: @listener_threads = Array.new
85:
86: csect.each { |lsect|
87: lhost = lsect.host
88: lport = lsect.port.to_i
89:
90: @listener_threads << listener_thread(lhost, lport)
91: }
92: end