Skip to content

Commit

Permalink
Merge pull request ManageIQ#16490 from skateman/websocket-webmks
Browse files Browse the repository at this point in the history
Allow proxying WebMKS consoles using the WebsocketWorker
(cherry picked from commit 6421e3d)

https://bugzilla.redhat.com/show_bug.cgi?id=1523404
  • Loading branch information
martinpovolny authored and d-m-u committed Jun 6, 2018
1 parent 06fb156 commit 276946b
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 27 deletions.
32 changes: 13 additions & 19 deletions lib/websocket_proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,23 @@ def initialize(env, console, logger)
@ws = env['rack.hijack'].call
# Set up the socket client for the proxy
@sock = TCPSocket.open(@console.host_name, @console.port)
init_ssl if @console.ssl
adapter = case @console.protocol
when 'vnc'
WebsocketSocket
when 'spice'
@console.ssl ? WebsocketSSLSocket : WebsocketSocket
when 'webmks'
WebsocketWebmks
end
@right = adapter.new(@sock, @console)
rescue => ex
@logger.error(ex)
@error = true
end

@driver.on(:open) { @console.update(:opened => true) }

@driver.on(:message) do |msg|
@ssl ? @ssl.syswrite(msg.data.pack('C*')) : @sock.write(msg.data.pack('C*'))
end
@driver.on(:message) { |msg| @right.issue(msg.data.pack('C*')) }

@driver.on(:close) { cleanup }
end
Expand All @@ -44,8 +50,9 @@ def transmit(sockets, is_ws)
data = @ws.recv_nonblock(64.kilobytes)
@driver.parse(data)
else
data = @ssl ? @ssl.sysread(64.kilobytes) : @sock.recv_nonblock(64.kilobytes)
@driver.binary(data)
@right.fetch(64.kilobytes) do |data|
@driver.binary(data)
end
end
end

Expand All @@ -69,17 +76,4 @@ def write(string)
def vm_id
@console ? @console.vm_id : 'unknown'
end

private

def init_ssl
context = OpenSSL::SSL::SSLContext.new
context.cert = OpenSSL::X509::Certificate.new(File.open('certs/server.cer'))
context.key = OpenSSL::PKey::RSA.new(File.open('certs/server.cer.key'))
context.ssl_version = :SSLv23
context.verify_depth = OpenSSL::SSL::VERIFY_NONE
@ssl = OpenSSL::SSL::SSLSocket.new(@sock, context)
@ssl.sync_close = true
@ssl.connect
end
end
14 changes: 14 additions & 0 deletions lib/websocket_right.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class WebsocketRight
def initialize(socket, model)
@sock = socket
@model = model
end

def fetch(*)
raise NotImplementedError, 'This should be defined in a subclass'
end

def issue(*)
raise NotImplementedError, 'This should be defined in a subclass'
end
end
9 changes: 9 additions & 0 deletions lib/websocket_socket.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class WebsocketSocket < WebsocketRight
def fetch(length)
yield(@sock.recv_nonblock(length))
end

def issue(data)
@sock.write(data)
end
end
22 changes: 22 additions & 0 deletions lib/websocket_ssl_socket.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class WebsocketSSLSocket < WebsocketRight
def initialize(socket, model)
super(socket, model)

context = OpenSSL::SSL::SSLContext.new
context.cert = OpenSSL::X509::Certificate.new(File.open('certs/server.cer'))
context.key = OpenSSL::PKey::RSA.new(File.open('certs/server.cer.key'))
context.ssl_version = :SSLv23
context.verify_depth = OpenSSL::SSL::VERIFY_NONE
@ssl = OpenSSL::SSL::SSLSocket.new(@sock, context)
@ssl.sync_close = true
@ssl.connect
end

def fetch(length)
yield(@ssl.sysread(length))
end

def issue(data)
@ssl.syswrite(data)
end
end
30 changes: 30 additions & 0 deletions lib/websocket_webmks.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
class WebsocketWebmks < WebsocketSSLSocket
attr_accessor :url

def initialize(socket, model)
super(socket, model)
@url = URI::Generic.build(:scheme => 'wss',
:host => @model.host_name,
:port => @model.port,
:path => "/ticket/#{@model.secret}").to_s
@driver = WebSocket::Driver.client(self, :protocols => ['binary'])
@driver.on(:close) { socket.close unless socket.closed? }
@driver.start
end

def fetch(length)
# WebSocket::Driver requires an event handler that should be registered only once
@driver.on(:message) { |msg| yield(msg.data) } if @driver.listeners(:message).length.zero?

data = @ssl.sysread(length)
@driver.parse(data)
end

def issue(data)
@driver.binary(data)
end

def write(data)
@ssl.syswrite(data)
end
end
16 changes: 8 additions & 8 deletions spec/lib/websocket_proxy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,18 @@
let(:ws) { double }
let(:sock) { double }

before do
subject.instance_variable_set(:@driver, driver)
subject.instance_variable_set(:@ws, ws)
subject.instance_variable_set(:@sock, sock)
right = subject.instance_variable_get(:@right)
right.instance_variable_set(:@sock, sock)
end

context 'websocket to socket' do
let(:is_ws) { true }

it 'reads from the websocket and parses the result' do
subject.instance_variable_set(:@driver, driver)
subject.instance_variable_set(:@ws, ws)
subject.instance_variable_set(:@sock, sock)

expect(ws).to receive(:recv_nonblock).and_return(123)
expect(driver).to receive(:parse).with(123)

Expand All @@ -64,10 +68,6 @@
let(:is_ws) { false }

it 'reads from the socket and sends the result to the driver' do
subject.instance_variable_set(:@driver, driver)
subject.instance_variable_set(:@ws, ws)
subject.instance_variable_set(:@sock, sock)

expect(sock).to receive(:recv_nonblock).and_return(123)
expect(driver).to receive(:binary).with(123)

Expand Down

0 comments on commit 276946b

Please sign in to comment.