Class: TFTP::Server::Base
- Inherits:
-
Object
- Object
- TFTP::Server::Base
- Defined in:
- lib/tftp/tftp.rb
Overview
Basic server utilizing threads for handling sessions.
It lacks a mutex around access to @clients, in case you'd want to stress test it for 10K or something.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#address ⇒ String
Address to listen to.
-
#clients ⇒ Hash
Current sessions.
-
#handler ⇒ Handler
Session handler.
-
#port ⇒ Integer
Session dispatcher port.
Instance Method Summary collapse
-
#get_tid ⇒ Object
private
Get the server's TID.
-
#initialize(handler, opts = {}) ⇒ Base
constructor
Initialize the server.
- #log(level, msg) ⇒ Object private
-
#run! ⇒ Object
Run the main server loop.
-
#stop ⇒ Object
Stop the main server loop.
Constructor Details
#initialize(handler, opts = {}) ⇒ Base
Initialize the server.
Options:
- :address => address to listen to (default: '0.0.0.0')
- :port => dispatcher port (default: 69)
- :logger => logger instance
299 300 301 302 303 304 305 306 307 308 |
# File 'lib/tftp/tftp.rb', line 299 def initialize(handler, opts = {}) @handler = handler @address = opts[:address] || '0.0.0.0' @port = opts[:port] || 69 @logger = opts[:logger] @clients = Hash.new @run = false end |
Instance Attribute Details
#address ⇒ String
Address to listen to
286 287 288 |
# File 'lib/tftp/tftp.rb', line 286 def address @address end |
#clients ⇒ Hash
Current sessions
286 287 288 |
# File 'lib/tftp/tftp.rb', line 286 def clients @clients end |
#handler ⇒ Handler
Session handler
286 287 288 |
# File 'lib/tftp/tftp.rb', line 286 def handler @handler end |
#port ⇒ Integer
Session dispatcher port
286 287 288 |
# File 'lib/tftp/tftp.rb', line 286 def port @port end |
Instance Method Details
#get_tid ⇒ Object (private)
Get the server's TID.
The TID is basically a random port number we will use for a session. This actually tries to get a unique TID per session. It uses only ports 1024 - 65535 as not to require root.
367 368 369 370 371 |
# File 'lib/tftp/tftp.rb', line 367 def get_tid tid = 1024 + rand(64512) tid = 1024 + rand(64512) while @clients.has_key? tid tid end |
#log(level, msg) ⇒ Object (private)
373 374 375 |
# File 'lib/tftp/tftp.rb', line 373 def log(level, msg) @logger.send(level, msg) if @logger end |
#run! ⇒ Object
Run the main server loop.
This is obviously blocking.
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
# File 'lib/tftp/tftp.rb', line 313 def run! log :info, "UDP server loop at #{@address}:#{@port}" @run = true Socket.udp_server_loop(@address, @port) do |msg, src| break unless @run addr = src.remote_address tag = "[#{addr.ip_address}:#{addr.ip_port.to_s.ljust(5)}]" log :info, "#{tag} New initial packet received" begin pkt = Packet.parse(msg) rescue ParseError => e log :warn, "#{tag} Packet parse error: #{e.to_s}" next end log :debug, "#{tag} -> PKT: #{pkt.inspect}" tid = get_tid tag = "[#{addr.ip_address}:#{addr.ip_port.to_s.ljust(5)}:#{tid.to_s.ljust(5)}]" sock = addr.connect_from(@address, tid) @clients[tid] = tag unless pkt.is_a?(Packet::RRQ) || pkt.is_a?(Packet::WRQ) log :warn, "#{tag} Bad initial packet: #{pkt.class}" sock.send(Packet::ERROR.new(4, 'Illegal TFTP operation.').encode, 0) sock.close next end Thread.new do @handler.run!(tag, pkt, sock, src) @clients.delete(tid) log :info, "#{tag} Session ended" end end log :info, 'UDP server loop has stopped' end |
#stop ⇒ Object
Stop the main server loop.
This will allow the currently pending sessions to finish.
355 356 357 358 359 |
# File 'lib/tftp/tftp.rb', line 355 def stop log :info, 'Stopping UDP server loop' @run = false UDPSocket.new.send('break', 0, @address, @port) end |