@@ -31,26 +31,27 @@ def socket_class=(socket_class)
3131 @socket_class = socket_class
3232 end
3333
34- def prepare_socket ( server )
34+ def prepare_socket ( server , timeout = nil )
3535 socket = server [ :socket ]
3636 encryption = server [ :encryption ]
3737
3838 @conn = socket
39- setup_encryption encryption if encryption
39+ setup_encryption ( encryption , timeout ) if encryption
4040 end
4141
4242 def open_connection ( server )
4343 hosts = server [ :hosts ]
4444 encryption = server [ :encryption ]
4545
46+ timeout = server [ :connect_timeout ] || DefaultConnectTimeout
4647 socket_opts = {
47- connect_timeout : server [ :connect_timeout ] || DefaultConnectTimeout ,
48+ connect_timeout : timeout ,
4849 }
4950
5051 errors = [ ]
5152 hosts . each do |host , port |
5253 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 )
5455 return
5556 rescue Net ::LDAP ::Error , SocketError , SystemCallError ,
5657 OpenSSL ::SSL ::SSLError => e
@@ -76,7 +77,7 @@ def close
7677 end
7778 end
7879
79- def self . wrap_with_ssl ( io , tls_options = { } )
80+ def self . wrap_with_ssl ( io , tls_options = { } , timeout = nil )
8081 raise Net ::LDAP ::NoOpenSSLError , "OpenSSL is unavailable" unless Net ::LDAP ::HasOpenSSL
8182
8283 ctx = OpenSSL ::SSL ::SSLContext . new
@@ -86,7 +87,22 @@ def self.wrap_with_ssl(io, tls_options = {})
8687 ctx . set_params ( tls_options ) unless tls_options . empty?
8788
8889 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
90106
91107 # Doesn't work:
92108 # conn.sync_close = true
@@ -123,11 +139,11 @@ def self.wrap_with_ssl(io, tls_options = {})
123139 # communications, as with simple_tls. Thanks for Kouhei Sutou for
124140 # generously contributing the :start_tls path.
125141 #++
126- def setup_encryption ( args )
142+ def setup_encryption ( args , timeout = nil )
127143 args [ :tls_options ] ||= { }
128144 case args [ :method ]
129145 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 )
131147 # additional branches requiring server validation and peer certs, etc.
132148 # go here.
133149 when :start_tls
@@ -144,7 +160,7 @@ def setup_encryption(args)
144160 end
145161
146162 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 )
148164 else
149165 raise Net ::LDAP ::StartTLSError , "start_tls failed: #{ pdu . result_code } "
150166 end
0 commit comments