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
-
#clients ⇒ Hash
Current sessions.
-
#handler ⇒ Handler
Session handler.
-
#host ⇒ String
Host the sockets bind to.
-
#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:
- :host => host to bind to (default: 127.0.0.1)
- :port => dispatcher port (default: 69)
- :logger => logger instance
307 308 309 310 311 312 313 314 315 316 |
# File 'lib/tftp/tftp.rb', line 307 def initialize(handler, opts = {}) @handler = handler @host = opts[:host] || '127.0.0.1' @port = opts[:port] || 69 @logger = opts[:logger] @clients = Hash.new @run = false end |
Instance Attribute Details
#clients ⇒ Hash
Current sessions
294 295 296 |
# File 'lib/tftp/tftp.rb', line 294 def clients @clients end |
#handler ⇒ Handler
Session handler
294 295 296 |
# File 'lib/tftp/tftp.rb', line 294 def handler @handler end |
#host ⇒ String
Host the sockets bind to
294 295 296 |
# File 'lib/tftp/tftp.rb', line 294 def host @host end |
#port ⇒ Integer
Session dispatcher port
294 295 296 |
# File 'lib/tftp/tftp.rb', line 294 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.
375 376 377 378 379 |
# File 'lib/tftp/tftp.rb', line 375 def get_tid tid = 1024 + rand(64512) tid = 1024 + rand(64512) while @clients.has_key? tid tid end |
#log(level, msg) ⇒ Object (private)
381 382 383 |
# File 'lib/tftp/tftp.rb', line 381 def log(level, msg) @logger.send(level, msg) if @logger end |
#run! ⇒ Object
Run the main server loop.
This is obviously blocking.
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 351 352 353 354 355 356 357 358 |
# File 'lib/tftp/tftp.rb', line 321 def run! log :info, "UDP server loop at #{@host}:#{@port}" @run = true Socket.udp_server_loop(@host, @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(@host, 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.
363 364 365 366 367 |
# File 'lib/tftp/tftp.rb', line 363 def stop log :info, 'Stopping UDP server loop' @run = false UDPSocket.new.send('break', 0, @host, @port) end |