Initializes the server
port |
The port to listen on, if the port is < 1024 server must run as roo |
host |
The host to listen on, use 0.0.0.0 for all addresses |
xml |
The XML to serve to clients |
logger |
An instanse of the Ruby Standard Logger class |
timeout |
How long does client have to complete the whole process before the socket closes and the thread terminates |
debug |
Set to true to enable DEBUG level logging from startup |
# File flashpolicyd.rb, line 195 def initialize(port, host, xml, logger, timeout=10, debug=false) @logger = logger @connections = [] @@connMutex = Mutex.new @@clientsMutex = Mutex.new @@bogusclients = 0 @@totalclients = 0 @timeout = timeout @@starttime = Time.new @xml = xml @port = port @host = host if debug @logger.level = Logger::DEBUG debug("Starting in DEBUG mode") else @logger.level = Logger::INFO end end
Logs a message passed to it and increment the bogus client counter inside a mutex
# File flashpolicyd.rb, line 258 def bogusclient(msg, client) addr = client.addr warn("Client #{addr[2]} #{msg}") @@clientsMutex.synchronize { @@bogusclients += 1 } end
Log a msg at level DEBUG
# File flashpolicyd.rb, line 164 def debug(msg) log(Logger::DEBUG, msg) end
Walks the list of active connections and dump them to the logger at INFO level
# File flashpolicyd.rb, line 228 def dumpconnections if (@connections.size == 0) info("No active connections to dump") else connections = @connections info("Dumping current #{connections.size} connections:") connections.each{ |c| addr = c.addr info("#{c.thread.object_id} started at #{c.timecreated} currently in #{c.thread.status} status serving #{addr[2]} [#{addr[3]}]") } end end
Dump the current thread list
# File flashpolicyd.rb, line 244 def dumpthreads Thread.list.each {|t| info("Thread: #{t.id} status #{t.status}") } end
Log a msg at level ERROR
# File flashpolicyd.rb, line 174 def error(msg) log(Logger::ERROR, msg) end
Log a msg at level FATAL
# File flashpolicyd.rb, line 169 def fatal(msg) log(Logger::FATAL, msg) end
Log a msg at level INFO
# File flashpolicyd.rb, line 154 def info(msg) log(Logger::INFO, msg) end
Generic logging method that takes a severity constant from the Logger class such as Logger::DEBUG
# File flashpolicyd.rb, line 149 def log(severity, msg) @logger.add(severity) { "#{Thread.current.object_id}: #{msg}" } end
Prints some basic stats about the server so far, bogus client are ones that timeout or otherwise cause problems
# File flashpolicyd.rb, line 251 def printstats u = sec2dhms(Time.new - @@starttime) info("Had #{@@totalclients} clients and #{@@bogusclients} bogus clients. Uptime #{u[0]} days #{u[1]} hours #{u[2]} min. #{@connections.size} connection(s) in use now.") end
The main logic of client handling, waits for @timeout seconds to receive a null terminated request containing "policy-file-request" and sends back the data, else marks the client as bogus and close the connection.
Any exception caught during this should mark a client as bogus
# File flashpolicyd.rb, line 273 def serve(connection) client = connection.client # Flash clients send a null terminate request $/ = "\0000" # run this in a timeout block, clients will have --timeout seconds to complete the transaction or go away begin timeout(@timeout.to_i) do loop do request = client.gets if request =~ /policy-file-request/ client.puts(@xml) debug("Sent xml data to client") break end end end rescue Timeout::Error bogusclient("connection timed out after #{@timeout} seconds", connection) rescue Errno::ENOTCONN => e warn("Unexpected disconnection while handling request") rescue Errno::ECONNRESET => e warn("Connection reset by peer") rescue Exception => e bogusclient("Unexpected #{e.class} exception: #{e}", connection) end end
Starts the main loop of the server and handles connections, logic is more or less:
Opens the port for listening
Create a new thread so the connection handling happens seperate from the main loop
Create a loop to accept new sessions from the socket, each new sesison gets a new thread
Increment the totalclient variable for stats handling
Create a OpenStruct structure with detail about the current connection and put it in the @connections array
Pass the connection to the serve method for handling
Once handling completes, remove the connection from the active list and close the socket
# File flashpolicyd.rb, line 314 def start begin # Disable reverse lookups, makes it all slow down BasicSocket::do_not_reverse_lookup=true server = TCPServer.new(@host, @port) rescue Exception => e fatal("Can't open server: #{e.class} #{e}") exit end begin @serverThread = Thread.new { while (session = server.accept) Thread.new(session) do |client| begin debug("Handling new connection from #{client.peeraddr[2]}, #{Thread.list.size} total threads ") @@clientsMutex.synchronize { @@totalclients += 1 } connection = OpenStruct.new connection.client = client connection.timecreated = Time.new connection.thread = Thread.current connection.addr = client.peeraddr @@connMutex.synchronize { @connections << connection debug("Pushed connection thread to @connections, now #{@connections.size} connections") } debug("Calling serve on connection") serve(connection) client.close @@connMutex.synchronize { @connections.delete(connection) debug("Removed connection from @connections, now #{@connections.size} connections") } rescue Errno::ENOTCONN => e warn("Unexpected disconnection while handling request") rescue Errno::ECONNRESET => e warn("Connection reset by peer") rescue Exception => e error("Unexpected #{e.class} exception while handling client connection: #{e}") error("Unexpected #{e.class} exception while handling client connection: #{e.backtrace.join("\n")}") client.close end # block around main logic end # while end # around Thread.new for client connections } # @serverThread rescue Exception => e fatal("Got #{e.class} exception in main listening thread: #{e}") end end
If the logger instanse is in DEBUG mode, put it into INFO and vica versa
# File flashpolicyd.rb, line 217 def toggledebug if (@logger.debug?) @logger.level = Logger::INFO info("Set logging level to INFO") else @logger.level = Logger::DEBUG info("Set logging level to DEBUG") end end
Generated with the Darkfish Rdoc Generator 2.