class XRBP::WebSocket::Socket

Low level wrapper around TCPSocket operations, providing mechanisms to negotiate base websocket connection.

@private

Constants

DEFAULT_PORTS

Attributes

client[RW]
pipe_broken[R]
socket[R]

Public Class Methods

new(client) click to toggle source
# File lib/xrbp/websocket/socket.rb, line 32
def initialize(client)
  @client      = client
  @pipe_broken = false
end

Public Instance Methods

close() click to toggle source
# File lib/xrbp/websocket/socket.rb, line 75
def close
  socket.close if socket
end
connect() click to toggle source
# File lib/xrbp/websocket/socket.rb, line 37
def connect
  uri = URI.parse client.url
  host = uri.host
  port = uri.port || DEFAULT_PORTS[uri.scheme.intern]

  @socket = TCPSocket.new(host, port)
  socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)

  init_ssl_socket if ['https', 'wss'].include? uri.scheme
  nil
end
options() click to toggle source
# File lib/xrbp/websocket/socket.rb, line 28
def options
  client.options
end
read_next(dest) click to toggle source
# File lib/xrbp/websocket/socket.rb, line 105
def read_next(dest)
  begin
    read_sockets, _, _ = IO.select([socket], nil, nil, 0.1)

    if read_sockets && read_sockets[0]
      dest << socket.read_nonblock(1024)

      if socket.respond_to?(:pending) # SSLSocket
        dest << socket.read(socket.pending) while socket.pending > 0
      end
    end
  rescue IO::WaitReadable
    # No op

  rescue IO::WaitWritable
    IO.select(nil, [socket])
    retry
  end
end
write(data) click to toggle source
# File lib/xrbp/websocket/socket.rb, line 79
def write(data)
  socket.write data
end
write_nonblock(data) click to toggle source
# File lib/xrbp/websocket/socket.rb, line 83
def write_nonblock(data)
  begin
    socket.write_nonblock(data)

  rescue IO::WaitReadable
    IO.select([socket]) # OpenSSL needs to read internally
    retry

  rescue IO::WaitWritable, Errno::EINTR
    IO.select(nil, [socket])
    retry

  rescue Errno::EPIPE => e
    @pipe_broken = true
    raise

  rescue OpenSSL::SSL::SSLError => e
    @pipe_broken = true
    raise
  end
end

Private Instance Methods

init_ssl_socket() click to toggle source
# File lib/xrbp/websocket/socket.rb, line 51
def init_ssl_socket
  ssl_context = options[:ssl_context] || begin
    ctx = OpenSSL::SSL::SSLContext.new
    ctx.ssl_version = options[:ssl_version] || 'SSLv23'

    # use VERIFY_PEER for verification:
    ctx.verify_mode = options[:verify_mode] ||
                        OpenSSL::SSL::VERIFY_NONE

    cert_store = OpenSSL::X509::Store.new
    cert_store.set_default_paths
    ctx.cert_store = cert_store

    ctx
  end

  @socket = ::OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
  socket.connect
end