Module: Yahns::OpenSSLClient

Defined in:
lib/yahns/openssl_client.rb

Overview

this is to be included into a Kgio::Socket-derived class this requires Ruby 2.1 and later for “exception: false”

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(cls) ⇒ Object

:nodoc:



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/yahns/openssl_client.rb', line 9

def self.included(cls)
  # Forward these methods to OpenSSL::SSL::SSLSocket so hijackers
  # can rely on stdlib methods instead of ugly kgio stuff that
  # we hope to phase out.
  # This is a bit weird, since OpenSSL::SSL::SSLSocket wraps
  # our actual socket, too, so we must take care to not blindly
  # use method_missing and cause infinite recursion
  %w(sync= read write readpartial write_nonblock read_nonblock
     print printf puts gets readlines readline getc
     readchar ungetc eof eof? << flush
     sysread syswrite).map!(&:to_sym).each do |m|
    cls.__send__(:define_method, m) { |*a| @ssl.__send__(m, *a) }
  end

  # block captures, ugh, but nobody really uses them
  %w(each each_line each_byte).map!(&:to_sym).each do |m|
    cls.__send__(:define_method, m) { |*a, &b| @ssl.__send__(m, *a, &b) }
  end
end

Instance Method Details

#accept_nonblock(ssl) ⇒ Object



130
131
132
# File 'lib/yahns/openssl_client.rb', line 130

def accept_nonblock(ssl)
  ssl.accept_nonblock(exception: false)
end

#closeObject



124
125
126
127
# File 'lib/yahns/openssl_client.rb', line 124

def close
  @ssl.close # flushes SSLSocket
  super # IO#close
end

#kgio_syssend(buf, flags) ⇒ Object



74
75
76
# File 'lib/yahns/openssl_client.rb', line 74

def kgio_syssend(buf, flags)
  kgio_trywrite(buf)
end

#kgio_tryread(len, buf) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/yahns/openssl_client.rb', line 78

def kgio_tryread(len, buf)
  if @need_accept
    # most protocols require read before write, so we start the negotiation
    # process here:
    case rv = accept_nonblock(@ssl)
    when :wait_readable, :wait_writable, nil
      return rv
    end
    @need_accept = false
  end
  @ssl.read_nonblock(len, buf, exception: false)
end

#kgio_trywrite(buf) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/yahns/openssl_client.rb', line 40

def kgio_trywrite(buf)
  len = buf.bytesize
  return if len == 0

  case @ssl_blocked
  when nil # likely
    buf = @ssl_blocked = buf.dup
  when Exception
    raise @ssl_blocked
  when String
    if @ssl_blocked != buf
      pfx = object_id
      warn("#{pfx} BUG: ssl_blocked != buf\n" \
           "#{pfx} ssl_blocked=#{@ssl_blocked.inspect}\n" \
           "#{pfx} buf=#{buf.inspect}\n")
      raise 'BUG: ssl_blocked} != buf'
    end
  end

  case rv = @ssl.write_nonblock(buf, exception: false)
  when :wait_readable, :wait_writable
    rv # do not clear ssl_blocked
  when Integer
    @ssl_blocked = len == rv ? nil : buf.byteslice(rv, len - rv)
  end
rescue SystemCallError => e # ECONNRESET/EPIPE
  e.set_backtrace([])
  raise(@ssl_blocked = e)
end

#kgio_trywritev(buf) ⇒ Object



70
71
72
# File 'lib/yahns/openssl_client.rb', line 70

def kgio_trywritev(buf)
  kgio_trywrite(buf.join)
end

#shutdownObject

we never call this with a how=SHUT_* arg



118
119
120
# File 'lib/yahns/openssl_client.rb', line 118

def shutdown # we never call this with a how=SHUT_* arg
  @ssl.sysclose
end

#syncObject

this is special, called during IO initialization in Ruby



30
31
32
# File 'lib/yahns/openssl_client.rb', line 30

def sync
  defined?(@ssl) ? @ssl.sync : super
end

#trysendio(io, offset, count) ⇒ Object Also known as: trysendfile



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/yahns/openssl_client.rb', line 91

def trysendio(io, offset, count)
  return 0 if count == 0

  case buf = @ssl_blocked
  when nil
    buf = do_pread(io, count, offset) or return # nil for EOF
    buf = @ssl_blocked = buf.dup
  when Exception
    raise buf
  # when String # just use it as-is
  end

  # call write_nonblock directly since kgio_trywrite allocates
  # an unnecessary string
  len = buf.size
  case rv = @ssl.write_nonblock(buf, exception: false)
  when :wait_readable, :wait_writable
    return rv # do not clear ssl_blocked
  when Integer
    @ssl_blocked = len == rv ? nil : buf.byteslice(rv, len - rv)
  end
  rv
rescue SystemCallError => e # ECONNRESET/EPIPE
  e.set_backtrace([])
  raise(@ssl_blocked = e)
end

#yahns_init_ssl(ssl_ctx) ⇒ Object



34
35
36
37
38
# File 'lib/yahns/openssl_client.rb', line 34

def yahns_init_ssl(ssl_ctx)
  @need_accept = true
  @ssl = OpenSSL::SSL::SSLSocket.new(self, ssl_ctx)
  @ssl_blocked = nil
end