module Rex::IO::StreamServer
This mixin provides the framework and interface for implementing a streaming server that can listen for and accept stream client connections. Stream
servers extend this class and are required to implement the following methods:
accept fd
Attributes
This callback procedure can be set and will be called when a client disconnects from the server.
This callback procedure can be set and will be called when new clients connect.
This callback procedure can be set and will be called when clients have data to be processed.
Public Instance Methods
This method closes a client connection and cleans up the resources associated with it.
# File lib/rex/io/stream_server.rb, line 92 def close_client(client) if (client) clients.delete(client) begin client.close rescue IOError end end end
This callback is notified when a client connection has closed.
# File lib/rex/io/stream_server.rb, line 54 def on_client_close(client) if (on_client_close_proc) on_client_close_proc.call(client) end end
This callback is notified when a client connects.
# File lib/rex/io/stream_server.rb, line 35 def on_client_connect(client) if (on_client_connect_proc) on_client_connect_proc.call(client) end end
This callback is notified when a client connection has data that needs to be processed.
# File lib/rex/io/stream_server.rb, line 45 def on_client_data(client) if (on_client_data_proc) on_client_data_proc.call(client) end end
Start monitoring the listener socket for connections and keep track of all client connections.
# File lib/rex/io/stream_server.rb, line 64 def start self.clients = [] self.client_waiter = ::Queue.new self.listener_thread = Rex::ThreadFactory.spawn("StreamServerListener", false) { monitor_listener } self.clients_thread = Rex::ThreadFactory.spawn("StreamServerClientMonitor", false) { monitor_clients } end
Terminates the listener monitoring threads and closes all active clients.
# File lib/rex/io/stream_server.rb, line 79 def stop self.listener_thread.kill self.clients_thread.kill self.clients.each { |cli| close_client(cli) } end
This method waits on the server listener thread
# File lib/rex/io/stream_server.rb, line 106 def wait self.listener_thread.join if self.listener_thread end
Protected Instance Methods
This method monitors client connections for data and calls the on_client_data
routine when new data arrives.
# File lib/rex/io/stream_server.rb, line 178 def monitor_clients begin # Wait for a notify if our client list is empty if (clients.length == 0) self.client_waiter.pop next end sd = Rex::ThreadSafe.select(clients, nil, nil, nil) sd[0].each { |cfd| begin on_client_data(cfd) rescue ::EOFError, ::Errno::ECONNRESET, ::Errno::ENOTCONN, ::Errno::ECONNABORTED on_client_close(cfd) close_client(cfd) rescue ::Interrupt raise $! rescue ::Exception close_client(cfd) elog("Error in stream server client monitor: #{$!}") rlog(ExceptionCallStack) end } rescue ::Rex::StreamClosedError => e # Remove the closed stream from the list clients.delete(e.stream) rescue ::Interrupt raise $! rescue ::Exception elog("Error in stream server client monitor: #{$!}") rlog(ExceptionCallStack) end while true end
This method monitors the listener socket for new connections and calls the on_client_connect
callback routine.
# File lib/rex/io/stream_server.rb, line 142 def monitor_listener while true begin cli = accept if not cli elog("The accept() returned nil in stream server listener monitor: #{fd.inspect}") ::IO.select(nil, nil, nil, 0.10) next end # Append to the list of clients self.clients << cli # Initialize the connection processing on_client_connect(cli) # Notify the client monitor self.client_waiter.push(cli) # Skip exceptions caused by accept() [ SSL ] rescue ::EOFError, ::Errno::ECONNRESET, ::Errno::ENOTCONN, ::Errno::ECONNABORTED rescue ::Interrupt raise $! rescue ::Exception elog("Error in stream server server monitor: #{$!}") rlog(ExceptionCallStack) break end end end