
Building the allocation map takes time, which scales with the size of the disc being presented. By building that map in the space between bind() and accept(), we leave the process in a useless state after the only good signal we have for "we are ready" and the state where it is actually ready. This was breaking migrations of large files.
160 lines
3.1 KiB
Ruby
160 lines
3.1 KiB
Ruby
# encoding: utf-8
|
|
|
|
require 'socket'
|
|
require "timeout"
|
|
require 'flexnbd/constants'
|
|
|
|
module FlexNBD
|
|
class FakeSource
|
|
|
|
def initialize( addr, port, err_msg, source_addr=nil, source_port=0 )
|
|
timing_out( 10, err_msg ) {
|
|
@sock = wait_for_server_socket( addr, port, source_addr, source_port )
|
|
}
|
|
end
|
|
|
|
|
|
def wait_for_server_socket(addr, port, saddr = nil, sport = 0)
|
|
sock = nil
|
|
|
|
loop do
|
|
sock = try_get_server_socket( addr, port, saddr, sport )
|
|
break if sock
|
|
sleep 0.1
|
|
end
|
|
|
|
sock
|
|
end
|
|
|
|
def try_get_server_socket(addr, port, saddr = nil, sport = 0)
|
|
if saddr
|
|
TCPSocket.new( addr, port, saddr, sport ) rescue nil
|
|
else
|
|
TCPSocket.new( addr, port ) rescue nil
|
|
end
|
|
end
|
|
|
|
|
|
|
|
|
|
def close
|
|
@sock.close
|
|
end
|
|
|
|
|
|
def read_hello()
|
|
timing_out( FlexNBD::MS_HELLO_TIME_SECS,
|
|
"Timed out waiting for hello." ) do
|
|
fail "No hello." unless (hello = @sock.read( 152 )) &&
|
|
hello.length==152
|
|
|
|
magic_s = hello[0..7]
|
|
ignore_s= hello[8..15]
|
|
size_s = hello[16..23]
|
|
|
|
size_h, size_l = size_s.unpack("NN")
|
|
size = (size_h << 32) + size_l
|
|
|
|
return { :magic => magic_s, :size => size }
|
|
end
|
|
end
|
|
|
|
|
|
def send_request( type, handle="myhandle", from=0, len=0 )
|
|
fail "Bad handle" unless handle.length == 8
|
|
|
|
@sock.write( "\x25\x60\x95\x13" )
|
|
@sock.write( [type].pack( 'N' ) )
|
|
@sock.write( handle )
|
|
@sock.write( "\x0"*4 )
|
|
@sock.write( [from].pack( 'N' ) )
|
|
@sock.write( [len ].pack( 'N' ) )
|
|
end
|
|
|
|
|
|
def write_write_request( from, len, handle="myhandle" )
|
|
send_request( 1, handle, from, len )
|
|
end
|
|
|
|
|
|
def write_entrust_request( handle="myhandle" )
|
|
send_request( 65536, handle )
|
|
end
|
|
|
|
def write_disconnect_request( handle="myhandle" )
|
|
send_request( 2, handle )
|
|
end
|
|
|
|
def write_read_request( from, len, handle="myhandle" )
|
|
send_request( 0, "myhandle", from, len )
|
|
end
|
|
|
|
|
|
def write_data( data )
|
|
@sock.write( data )
|
|
end
|
|
|
|
|
|
# Handy utility
|
|
def read( from, len )
|
|
timing_out( 2, "Timed out reading" ) do
|
|
send_request( 0, "myhandle", from, len )
|
|
read_raw( len )
|
|
end
|
|
end
|
|
|
|
def read_raw( len )
|
|
@sock.read( len )
|
|
end
|
|
|
|
def send_mirror
|
|
read_hello()
|
|
write( 0, "12345678" )
|
|
read_response()
|
|
write_disconnect_request()
|
|
close()
|
|
end
|
|
|
|
|
|
def write( from, data )
|
|
write_write_request( from, data.length )
|
|
write_data( data )
|
|
end
|
|
|
|
|
|
def read_response
|
|
magic = @sock.read(4)
|
|
error_s = @sock.read(4)
|
|
handle = @sock.read(8)
|
|
|
|
{
|
|
:magic => magic,
|
|
:error => error_s.unpack("N").first,
|
|
:handle => handle
|
|
}
|
|
end
|
|
|
|
|
|
def ensure_disconnected
|
|
Timeout.timeout( 2 ) do
|
|
@sock.read(1)
|
|
end
|
|
end
|
|
|
|
|
|
def timing_out( time, msg )
|
|
begin
|
|
Timeout.timeout( time ) do
|
|
yield
|
|
end
|
|
rescue Timeout::Error
|
|
$stderr.puts msg
|
|
exit 1
|
|
end
|
|
end
|
|
|
|
|
|
end # class FakeSource
|
|
end # module FlexNBD
|
|
|