Неблокирующее согласование сокетов SSL в Ruby. Возможный?

вступление

У меня есть клиент, который устанавливает многочисленные SSL-подключения к сторонней службе. В некоторых случаях сторонняя сторона перестает отвечать в процессе согласования сокета и ssl. Когда это происходит, моя текущая реализация "сидит" часами, прежде чем истечет время ожидания.

Чтобы бороться с этим, я пытаюсь реализовать следующий процесс:

require 'socket'
require 'openssl'

# variables

host = '....'
port = ...
p12  = #OpenSSL::PKCS12 object 

# set up socket

addr = Socket.getaddrinfo(host, nil)
sockaddr = Socket.pack_sockaddr_in(port, addr[0][3])

socket = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)

begin
  socket.connect_nonblock(sockaddr)
rescue IO::WaitWritable
  if IO.select(nil, [socket], nil, timeout)
    begin
      socket.connect_nonblock(sockaddr)
    rescue Errno::EISCONN
      puts "socket connected"
    rescue
      puts "socket error"
      socket.close
      raise
    end
  else
    socket.close
    raise "Connection timeout"
  end
end

# negotiate ssl

context      = OpenSSL::SSL::SSLContext.new
context.cert = p12.certificate
context.key  = p12.key

ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, context)
ssl_socket.sync_close = true

puts "ssl connecting"
ssl_socket.connect_nonblock
puts "ssl connected"

# cleanup

ssl_socket.close
puts "socket closed"

ssl_socket.connect_nonblock в конечном итоге будет заключен в структуру, аналогичную структуре socket.connect_nonblock.

Эта проблема

Проблема, с которой я сталкиваюсь, заключается в том, что ssl_socket.connect_nonblock при запуске вызывает следующее:

`connect_nonblock': read would block (OpenSSL::SSL::SSLError)

Вместо этого я ожидал, что он поднимет IO::WaitWritable, как это делает socket.connect_nonblock.

Я поискал в Интернете информацию об этой конкретной ошибке, но не нашел ничего особенно полезного. Насколько я понимаю, другие успешно использовали этот метод, поэтому я не уверен, что мне не хватает. Для полноты картины я обнаружил одинаковые результаты с рубином 2.2.0 и 1.9.3.

Любые предложения приветствуются!


person YWCA Hello    schedule 11.06.2015    source источник


Ответы (1)


У меня такая же проблема, я пробовал ниже, похоже, это подходит для моей ситуации.

ssl_socket = OpenSSL::SSL::SSLSocket.new socket, context
ssl_socket.sync = true

begin
  ssl_socket.connect_nonblock
rescue IO::WaitReadable
  if IO.select([ssl_socket], nil, nil, timeout)
    retry
  else
    # timeout
  end
rescue IO::WaitWritable
  if IO.select(nil, [ssl_socket], nil, timeout)
    retry
  else
    # timeout
  end
end
person aligo    schedule 24.09.2015