Class | PolicyServer |
In: |
flashpolicyd.rb
|
Parent: | Object |
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 172 172: def initialize(port, host, xml, logger, timeout=10, debug=false) 173: @logger = logger 174: @connections = [] 175: @@connMutex = Mutex.new 176: @@clientsMutex = Mutex.new 177: @@bogusclients = 0 178: @@totalclients = 0 179: @timeout = timeout 180: @@starttime = Time.new 181: @xml = xml 182: @port = port 183: @host = host 184: 185: if debug 186: @logger.level = Logger::DEBUG 187: debug("Starting in DEBUG mode") 188: else 189: @logger.level = Logger::INFO 190: end 191: end
Logs a message passed to it and increment the bogus client counter inside a mutex
# File flashpolicyd.rb, line 235 235: def bogusclient(msg, client) 236: addr = client.addr 237: 238: warn("Client #{addr[2]} #{msg}") 239: 240: @@clientsMutex.synchronize { 241: @@bogusclients += 1 242: } 243: end
Log a msg at level DEBUG
# File flashpolicyd.rb, line 141 141: def debug(msg) 142: log(Logger::DEBUG, msg) 143: end
Walks the list of active connections and dump them to the logger at INFO level
# File flashpolicyd.rb, line 205 205: def dumpconnections 206: if (@connections.size == 0) 207: info("No active connections to dump") 208: else 209: connections = @connections 210: 211: info("Dumping current #{connections.size} connections:") 212: 213: connections.each{ |c| 214: addr = c.addr 215: info("#{c.thread.object_id} started at #{c.timecreated} currently in #{c.thread.status} status serving #{addr[2]} [#{addr[3]}]") 216: } 217: end 218: end
Dump the current thread list
# File flashpolicyd.rb, line 221 221: def dumpthreads 222: Thread.list.each {|t| 223: info("Thread: #{t.id} status #{t.status}") 224: } 225: end
Log a msg at level ERROR
# File flashpolicyd.rb, line 151 151: def error(msg) 152: log(Logger::ERROR, msg) 153: end
Log a msg at level FATAL
# File flashpolicyd.rb, line 146 146: def fatal(msg) 147: log(Logger::FATAL, msg) 148: end
Log a msg at level INFO
# File flashpolicyd.rb, line 131 131: def info(msg) 132: log(Logger::INFO, msg) 133: end
Generic logging method that takes a severity constant from the Logger class such as Logger::DEBUG
# File flashpolicyd.rb, line 126 126: def log(severity, msg) 127: @logger.add(severity) { "#{Thread.current.object_id}: #{msg}" } 128: end
Prints some basic stats about the server so far, bogus client are ones that timeout or otherwise cause problems
# File flashpolicyd.rb, line 228 228: def printstats 229: u = sec2dhms(Time.new - @@starttime) 230: 231: 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.") 232: 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 250 250: def serve(connection) 251: client = connection.client 252: 253: # Flash clients send a null terminate request 254: $/ = "\000" 255: 256: # run this in a timeout block, clients will have --timeout seconds to complete the transaction or go away 257: begin 258: timeout(@timeout.to_i) do 259: loop do 260: request = client.gets 261: 262: if request =~ /policy-file-request/ 263: client.puts(@xml) 264: 265: debug("Sent xml data to client") 266: break 267: end 268: end 269: end 270: rescue Timeout::Error 271: bogusclient("connection timed out after #{@timeout} seconds", connection) 272: rescue Errno::ENOTCONN => e 273: warn("Unexpected disconnection while handling request") 274: rescue Errno::ECONNRESET => e 275: warn("Connection reset by peer") 276: rescue Exception => e 277: bogusclient("Unexpected #{e.class} exception: #{e}", connection) 278: end 279: end
Starts the main loop of the server and handles connections, logic is more or less:
# File flashpolicyd.rb, line 291 291: def start 292: begin 293: # Disable reverse lookups, makes it all slow down 294: BasicSocket::do_not_reverse_lookup=true 295: server = TCPServer.new(@host, @port) 296: rescue Exception => e 297: fatal("Can't open server: #{e.class} #{e}") 298: exit 299: end 300: 301: begin 302: @serverThread = Thread.new { 303: while (session = server.accept) 304: Thread.new(session) do |client| 305: begin 306: debug("Handling new connection from #{client.peeraddr[2]}, #{Thread.list.size} total threads ") 307: 308: @@clientsMutex.synchronize { 309: @@totalclients += 1 310: } 311: 312: connection = OpenStruct.new 313: connection.client = client 314: connection.timecreated = Time.new 315: connection.thread = Thread.current 316: connection.addr = client.peeraddr 317: 318: @@connMutex.synchronize { 319: @connections << connection 320: debug("Pushed connection thread to @connections, now #{@connections.size} connections") 321: } 322: 323: debug("Calling serve on connection") 324: serve(connection) 325: 326: client.close 327: 328: @@connMutex.synchronize { 329: @connections.delete(connection) 330: debug("Removed connection from @connections, now #{@connections.size} connections") 331: } 332: 333: rescue Errno::ENOTCONN => e 334: warn("Unexpected disconnection while handling request") 335: rescue Errno::ECONNRESET => e 336: warn("Connection reset by peer") 337: rescue Exception => e 338: error("Unexpected #{e.class} exception while handling client connection: #{e}") 339: error("Unexpected #{e.class} exception while handling client connection: #{e.backtrace.join("\n")}") 340: client.close 341: end # block around main logic 342: end # while 343: end # around Thread.new for client connections 344: } # @serverThread 345: rescue Exception => e 346: fatal("Got #{e.class} exception in main listening thread: #{e}") 347: end 348: end
If the logger instanse is in DEBUG mode, put it into INFO and vica versa
# File flashpolicyd.rb, line 194 194: def toggledebug 195: if (@logger.debug?) 196: @logger.level = Logger::INFO 197: info("Set logging level to INFO") 198: else 199: @logger.level = Logger::DEBUG 200: info("Set logging level to DEBUG") 201: end 202: end