class Girl::ResolvdWorker
Public Class Methods
new( resolvd_port, nameserver )
click to toggle source
initialize
# File lib/girl/resolvd_worker.rb, line 7 def initialize( resolvd_port, nameserver ) @custom = Girl::ResolvCustom.new @nameserver_addr = Socket.sockaddr_in( 53, nameserver ) @reads = [] @roles = {} # sock => :dotr / :resolvd / :dst @dst_infos = ConcurrentHash.new # dst => { :resolvd, :src_addr, :created_at, :closing } new_a_pipe new_resolvds( resolvd_port ) end
Public Instance Methods
looping()
click to toggle source
looping
# File lib/girl/resolvd_worker.rb, line 21 def looping puts "#{ Time.new } looping" loop_check_state loop do rs, _ = IO.select( @reads ) rs.each do | sock | role = @roles[ sock ] case role when :dotr then read_dotr( sock ) when :resolvd then read_resolvd( sock ) when :dst then read_dst( sock ) else puts "#{ Time.new } read unknown role #{ role }" close_sock( sock ) end end end rescue Interrupt => e puts e.class quit! end
quit!()
click to toggle source
quit!
# File lib/girl/resolvd_worker.rb, line 52 def quit! # puts "debug exit" exit end
Private Instance Methods
add_read( sock, role = nil )
click to toggle source
add read
# File lib/girl/resolvd_worker.rb, line 62 def add_read( sock, role = nil ) return if sock.nil? || sock.closed? || @reads.include?( sock ) @reads << sock if role then @roles[ sock ] = role end end
close_dst( dst )
click to toggle source
close dst
# File lib/girl/resolvd_worker.rb, line 74 def close_dst( dst ) # puts "debug close dst" close_sock( dst ) @dst_infos.delete( dst ) end
close_sock( sock )
click to toggle source
close sock
# File lib/girl/resolvd_worker.rb, line 83 def close_sock( sock ) return if sock.nil? || sock.closed? sock.close @reads.delete( sock ) @roles.delete( sock ) end
loop_check_state()
click to toggle source
loop check state
# File lib/girl/resolvd_worker.rb, line 93 def loop_check_state Thread.new do loop do sleep CHECK_STATE_INTERVAL now = Time.new @dst_infos.select{ | dst, info | !dst.closed? && ( now - info[ :created_at ] >= EXPIRE_NEW ) }.values.each do | dst_info | puts "#{ Time.new } expire dst" dst_info[ :closing ] = true next_tick end end end end
new_a_dst( resolvd, src_addr, data )
click to toggle source
new a dst
# File lib/girl/resolvd_worker.rb, line 111 def new_a_dst( resolvd, src_addr, data ) dst = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 ) dst.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 ) # puts "debug new a dst" @dst_infos[ dst ] = { resolvd: resolvd, src_addr: src_addr, created_at: Time.new, closing: false } add_read( dst, :dst ) send_data( dst, @nameserver_addr, data ) end
new_a_pipe()
click to toggle source
new a pipe
# File lib/girl/resolvd_worker.rb, line 130 def new_a_pipe dotr, dotw = IO.pipe @dotw = dotw add_read( dotr, :dotr ) end
new_resolvds( begin_port )
click to toggle source
new resolvds
# File lib/girl/resolvd_worker.rb, line 139 def new_resolvds( begin_port ) 10.times do | i | resolvd_port = begin_port + i resolvd = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 ) resolvd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 ) resolvd.bind( Socket.sockaddr_in( resolvd_port, '0.0.0.0' ) ) puts "#{ Time.new } resolvd bind on #{ resolvd_port }" add_read( resolvd, :resolvd ) end end
next_tick()
click to toggle source
next tick
# File lib/girl/resolvd_worker.rb, line 154 def next_tick @dotw.write( '.' ) end
read_dotr( dotr )
click to toggle source
read dotr
# File lib/girl/resolvd_worker.rb, line 172 def read_dotr( dotr ) dotr.read_nonblock( READ_SIZE ) @dst_infos.select{ | _, info | info[ :closing ] }.keys.each{ | dst | close_dst( dst ) } end
read_dst( dst )
click to toggle source
read dst
# File lib/girl/resolvd_worker.rb, line 190 def read_dst( dst ) if dst.closed? then puts "#{ Time.new } read dst but dst closed?" return end begin data, addrinfo, rflags, *controls = dst.recvmsg rescue Exception => e puts "#{ Time.new } dst recvmsg #{ e.class }" close_dst( dst ) return end # puts "debug dst recvmsg #{ addrinfo.ip_unpack.inspect } #{ data.inspect }" dst_info = @dst_infos[ dst ] data = @custom.encode( data ) send_data( dst_info[ :resolvd ], dst_info[ :src_addr ], data ) close_dst( dst ) end
read_resolvd( resolvd )
click to toggle source
read resolvd
# File lib/girl/resolvd_worker.rb, line 180 def read_resolvd( resolvd ) data, addrinfo, rflags, *controls = resolvd.recvmsg # puts "debug resolvd recvmsg #{ addrinfo.ip_unpack.inspect } #{ data.inspect }" data = @custom.decode( data ) new_a_dst( resolvd, addrinfo, data ) end
send_data( sock, to_addr, data )
click to toggle source
send data
# File lib/girl/resolvd_worker.rb, line 161 def send_data( sock, to_addr, data ) begin sock.sendmsg_nonblock( data, 0, to_addr ) rescue Exception => e puts "#{ Time.new } sendmsg #{ e.class } #{ to_addr.inspect }" end end