From 2b82d4c4c4dc7bf573d7acf42f113c335ba3bb2c Mon Sep 17 00:00:00 2001 From: Matt Miller Date: Mon, 22 Aug 2005 02:36:09 +0000 Subject: [PATCH] fixed up the ol' http server git-svn-id: file:///home/svn/incoming/trunk@2843 4d416f70-5f16-0410-b530-b9f4589650da --- lib/rex/io/stream_server.rb | 125 +++++++++++++++++++++++++++++++++++ lib/rex/proto/http/server.rb | 94 ++++++-------------------- lib/rex/socket/parameters.rb | 2 +- 3 files changed, 146 insertions(+), 75 deletions(-) diff --git a/lib/rex/io/stream_server.rb b/lib/rex/io/stream_server.rb index 85ba006e15..b71eabf56a 100644 --- a/lib/rex/io/stream_server.rb +++ b/lib/rex/io/stream_server.rb @@ -40,6 +40,131 @@ module StreamServer super end + ## + # + # Default server monitoring and client management implementation follows + # below. + # + ## + + def on_client_connect(client) + if (on_client_connect_proc) + on_client_connect_proc.call(client) + end + end + + def on_client_data(client) + if (on_client_data_proc) + on_client_data_proc.call(client) + end + end + + def on_client_close(client) + if (on_client_close_proc) + on_client_close_proc.call(client) + end + end + + # + # Start monitoring the listener socket for connections and keep track of + # all client connections. + # + def start + self.clients = [] + self.clifds = [] + self.fd2cli = {} + + self.listener_thread = Thread.new { + monitor_listener + } + self.clients_thread = Thread.new { + monitor_clients + } + end + + # + # Terminates the listener monitoring threads and closes all active clients. + # + def stop + self.listener_thread.kill + self.clients_thread.kill + + self.clients.each { |cli| + close_client(cli) + } + end + + # + # Closes a client connection. + # + def close_client(client) + if (client) + fd2cli.delete(client.sock) + clifds.delete(client.sock) + clients.delete(client) + + client.close + end + end + + # + # Callback procedures. + # + attr_accessor :on_client_connect_proc + attr_accessor :on_client_data_proc + attr_accessor :on_client_close_proc + +protected + + attr_accessor :clients, :clifds, :fd2cli + attr_accessor :listener_thread, :clients_thread + + # + # Monitors the listener socket for new connections + # + def monitor_listener + begin + sd = Rex::ThreadSafe.select([ poll_fd ]) + + # Accept the new client connection + if (sd[0].length > 0) + cli = accept + + next if (!cli) + + # Insert it into some lists + self.clients << cli + self.clifds << cli.sock + self.fd2cli[cli.sock] = cli + + on_client_connect(cli) + end + rescue + elog("Error in stream server listener monitor: #{$!}") + end while true + + end + + # + # Monitors clients for data. + # + def monitor_clients + begin + if (clients.length == 0) + Rex::ThreadSafe::sleep(0.2) + next + end + + sd = Rex::ThreadSafe.select(clifds) + + sd[0].each { |fd| + on_client_data(self.fd2cli[fd]) + } + rescue + elog("Error in stream server client monitor: #{$!}") + end while true + end + end end diff --git a/lib/rex/proto/http/server.rb b/lib/rex/proto/http/server.rb index 92bf86e97c..dd5dbcb433 100644 --- a/lib/rex/proto/http/server.rb +++ b/lib/rex/proto/http/server.rb @@ -78,9 +78,6 @@ class Server self.listen_port = port self.listen_host = listen_host self.listener = nil - self.clients = [] - self.clifds = [] - self.fd2cli = {} self.resources = {} end @@ -91,40 +88,31 @@ class Server self.listener = Rex::Socket::TcpServer.create( 'LocalHost' => self.listen_host, 'LocalPort' => self.listen_port) + + # Register callbacks + self.listener.on_client_connect_proc = Proc.new { |cli| + on_client_connect(cli) + } + self.listener.on_client_data_proc = Proc.new { |cli| + on_client_data(cli) + } - self.listener_thread = Thread.new { - monitor_listener - } - self.clients_thread = Thread.new { - monitor_clients - } + self.listener.start end # # Terminates the monitor thread and turns off the listener. # def stop - self.listener_thread.kill - self.clients_thread.kill - - self.clients.each { |cli| - close_client(cli) - } - + self.listener.stop self.listener.close end # - # Closes the supplied client connection and removes it from the internal - # hashes and lists. + # Closes the supplied client, if valid. # def close_client(cli) - if (cli) - self.fd2cli.delete(cli.sock) - self.clifds.delete(cli.sock) - self.clients.delete(cli) - cli.close - end + listener.close_client(cli) end # @@ -153,7 +141,7 @@ class Server end # - # Adds Server headers and stuff + # Adds Server headers and stuff. # def add_response_headers(resp) resp['Server'] = DefaultServer @@ -163,63 +151,21 @@ class Server protected - attr_accessor :listener - attr_accessor :listener_thread, :clients_thread - attr_accessor :clients, :clifds, :fd2cli - attr_accessor :resources + attr_accessor :listener, :resources # - # Monitors the listener for new connections + # Extends new clients with the ServerClient module and initializes them. # - def monitor_listener - begin - sd = Rex::ThreadSafe.select([ listener.sock ]) + def on_client_connect(cli) + cli.extend(ServerClient) - # Accept the new client connection - if (sd[0].length > 0) - cli = listener.accept - - next if (!cli) - - cli.extend(ServerClient) - - # Initialize the server client extension - cli.init_cli(self) - - # Insert it into some lists - self.clients << cli - self.clifds << cli.sock - self.fd2cli[cli.sock] = cli - end - rescue - elog("Exception caught in HTTP server listener monitor: #{$!}") - end while true + cli.init_cli(self) end # - # Monitors client connections for data + # Processes data coming in from a client. # - def monitor_clients - begin - if (clients.length == 0) - Rex::ThreadSafe::sleep(0.2) - next - end - - sd = Rex::ThreadSafe.select(clifds) - - sd[0].each { |fd| - process_client(self.fd2cli[fd]) - } - rescue - elog("Exception caught in HTTP server clients monitor: #{$!}") - end while true - end - - # - # Processes data coming in from a client - # - def process_client(cli) + def on_client_data(cli) begin case cli.request.parse(cli.get) when Packet::ParseCode::Completed diff --git a/lib/rex/socket/parameters.rb b/lib/rex/socket/parameters.rb index 724d10e3a6..eaf8ede1ca 100644 --- a/lib/rex/socket/parameters.rb +++ b/lib/rex/socket/parameters.rb @@ -80,7 +80,7 @@ class Rex::Socket::Parameters self.server = hash['Server'] || false # The communication subsystem to use to create the socket - self.comm = hash['Comm'] || Rex::Socket::Comm::Local; + self.comm = hash['Comm'] || Rex::Socket::Comm::Local # The number of connection retries to make (client only) self.retries = hash['Retries'] || 0