@@ -31,26 +31,27 @@ def socket_class=(socket_class)
31
31
@socket_class = socket_class
32
32
end
33
33
34
- def prepare_socket ( server )
34
+ def prepare_socket ( server , timeout )
35
35
socket = server [ :socket ]
36
36
encryption = server [ :encryption ]
37
37
38
38
@conn = socket
39
- setup_encryption encryption if encryption
39
+ setup_encryption ( encryption , timeout ) if encryption
40
40
end
41
41
42
42
def open_connection ( server )
43
43
hosts = server [ :hosts ]
44
44
encryption = server [ :encryption ]
45
45
46
+ timeout = server [ :connect_timeout ] || DefaultConnectTimeout
46
47
socket_opts = {
47
- connect_timeout : server [ :connect_timeout ] || DefaultConnectTimeout ,
48
+ connect_timeout : timeout ,
48
49
}
49
50
50
51
errors = [ ]
51
52
hosts . each do |host , port |
52
53
begin
53
- prepare_socket ( server . merge ( socket : @socket_class . new ( host , port , socket_opts ) ) )
54
+ prepare_socket ( server . merge ( socket : @socket_class . new ( host , port , socket_opts ) ) , timeout )
54
55
return
55
56
rescue Net ::LDAP ::Error , SocketError , SystemCallError ,
56
57
OpenSSL ::SSL ::SSLError => e
@@ -76,7 +77,7 @@ def close
76
77
end
77
78
end
78
79
79
- def self . wrap_with_ssl ( io , tls_options = { } )
80
+ def self . wrap_with_ssl ( io , tls_options = { } , timeout = nil )
80
81
raise Net ::LDAP ::NoOpenSSLError , "OpenSSL is unavailable" unless Net ::LDAP ::HasOpenSSL
81
82
82
83
ctx = OpenSSL ::SSL ::SSLContext . new
@@ -86,7 +87,22 @@ def self.wrap_with_ssl(io, tls_options = {})
86
87
ctx . set_params ( tls_options ) unless tls_options . empty?
87
88
88
89
conn = OpenSSL ::SSL ::SSLSocket . new ( io , ctx )
89
- conn . connect
90
+
91
+ begin
92
+ conn . connect_nonblock
93
+ rescue IO ::WaitReadable
94
+ if IO . select ( [ conn ] , nil , nil , timeout )
95
+ retry
96
+ else
97
+ raise Net ::LDAP ::LdapError , "OpenSSL connection read timeout"
98
+ end
99
+ rescue IO ::WaitWritable
100
+ if IO . select ( nil , [ conn ] , nil , timeout )
101
+ retry
102
+ else
103
+ raise Net ::LDAP ::LdapError , "OpenSSL connection write timeout"
104
+ end
105
+ end
90
106
91
107
# Doesn't work:
92
108
# conn.sync_close = true
@@ -123,11 +139,11 @@ def self.wrap_with_ssl(io, tls_options = {})
123
139
# communications, as with simple_tls. Thanks for Kouhei Sutou for
124
140
# generously contributing the :start_tls path.
125
141
#++
126
- def setup_encryption ( args )
142
+ def setup_encryption ( args , timeout )
127
143
args [ :tls_options ] ||= { }
128
144
case args [ :method ]
129
145
when :simple_tls
130
- @conn = self . class . wrap_with_ssl ( @conn , args [ :tls_options ] )
146
+ @conn = self . class . wrap_with_ssl ( @conn , args [ :tls_options ] , timeout )
131
147
# additional branches requiring server validation and peer certs, etc.
132
148
# go here.
133
149
when :start_tls
@@ -144,7 +160,7 @@ def setup_encryption(args)
144
160
end
145
161
146
162
if pdu . result_code . zero?
147
- @conn = self . class . wrap_with_ssl ( @conn , args [ :tls_options ] )
163
+ @conn = self . class . wrap_with_ssl ( @conn , args [ :tls_options ] , timeout )
148
164
else
149
165
raise Net ::LDAP ::StartTLSError , "start_tls failed: #{ pdu . result_code } "
150
166
end
0 commit comments