| 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