@@ -66,6 +66,8 @@ class Address
6666 # @param [ String ] seed The provided address.
6767 # @param [ Hash ] options The address options.
6868 #
69+ # @option options [ Float ] :connect_timeout Connect timeout.
70+ #
6971 # @since 2.0.0
7072 def initialize ( seed , options = { } )
7173 if seed . nil?
@@ -85,6 +87,9 @@ def initialize(seed, options = {})
8587 # @return [ Integer ] port The port.
8688 attr_reader :port
8789
90+ # @api private
91+ attr_reader :options
92+
8893 # Check equality of the address to another.
8994 #
9095 # @example Check address equality.
@@ -138,13 +143,30 @@ def inspect
138143 "#<Mongo::Address:0x#{ object_id } address=#{ to_s } >"
139144 end
140145
141- # Get a socket for the provided address, given the options.
146+ # Get a socket for the address stored in this object, given the options.
147+ #
148+ # If the address stored in this object looks like a Unix path, this method
149+ # returns a Unix domain socket for this path.
142150 #
143- # The address the socket connects to is determined by the algorithm described in the
144- # #intialize_resolver! documentation. Each time this method is called, #initialize_resolver!
145- # will be called, meaning that a new hostname lookup will occur. This is done so that any
146- # changes to which addresses the hostname resolves to will be picked up even if a socket has
147- # been connected to it before.
151+ # Otherwise, this method attempts to resolve the address stored in
152+ # this object to IPv4 and IPv6 addresses using +Socket#getaddrinfo+, then
153+ # connects to the resulting addresses and returns the socket of the first
154+ # successful connection. The order in which address families (IPv4/IPV6)
155+ # are tried is the same order in which the addresses are returned by
156+ # +getaddrinfo+, and is determined by the host system.
157+ #
158+ # Name resolution is performed on each +socket+ call. This is done so that
159+ # any changes to which addresses the host names used as seeds or in
160+ # server configuration resolve to are immediately noticed by the driver,
161+ # even if a socket has been connected to the affected host name/address
162+ # before. However, note that DNS TTL values may still affect when a change
163+ # to a host address is noticed by the driver.
164+ #
165+ # This method propagates any exceptions raised during DNS resolution and
166+ # subsequent connection attempts. In case of a host name resolving to
167+ # multiple IP addresses, the error raised by the last attempt is propagated
168+ # to the caller. This method does not map exceptions to Mongo::Error
169+ # subclasses, and may raise any subclass of Exception.
148170 #
149171 # @example Get a socket.
150172 # address.socket(5, :ssl => true)
@@ -155,11 +177,34 @@ def inspect
155177 #
156178 # @option options [ Float ] :connect_timeout Connect timeout.
157179 #
158- # @return [ Mongo::Socket::SSL, Mongo::Socket::TCP, Mongo::Socket::Unix ] The socket.
180+ # @return [ Mongo::Socket::SSL | Mongo::Socket::TCP | Mongo::Socket::Unix ]
181+ # The socket.
182+ #
183+ # @raise [ Exception ] If network connection failed.
159184 #
160185 # @since 2.0.0
161186 def socket ( socket_timeout , ssl_options = { } , options = { } )
162- create_resolver ( ssl_options ) . socket ( socket_timeout , ssl_options , options )
187+ if seed . downcase =~ Unix ::MATCH
188+ specific_address = Unix . new ( seed . downcase )
189+ return specific_address . socket ( socket_timeout , ssl_options , options )
190+ end
191+
192+ options = {
193+ connect_timeout : Server ::CONNECT_TIMEOUT ,
194+ } . update ( options )
195+
196+ family = ( host == LOCALHOST ) ? ::Socket ::AF_INET : ::Socket ::AF_UNSPEC
197+ error = nil
198+ ::Socket . getaddrinfo ( host , nil , family , ::Socket ::SOCK_STREAM ) . each do |info |
199+ begin
200+ specific_address = FAMILY_MAP [ info [ 4 ] ] . new ( info [ 3 ] , port , host )
201+ socket = specific_address . socket ( socket_timeout , ssl_options , options )
202+ return socket
203+ rescue IOError , SystemCallError , Error ::SocketTimeoutError , Error ::SocketError => e
204+ error = e
205+ end
206+ end
207+ raise error
163208 end
164209
165210 # Get the address as a string.
@@ -182,37 +227,8 @@ def to_s
182227 end
183228 end
184229
185- # @api private
186- def connect_timeout
187- @connect_timeout ||= @options [ :connect_timeout ] || Server ::CONNECT_TIMEOUT
188- end
189-
190230 private
191231
192- # To determine which address the socket will connect to, the driver will
193- # attempt to connect to each IP address returned by Socket::getaddrinfo in
194- # sequence. Once a successful connection is made, a resolver with that
195- # IP address specified is returned. If no successful connection is
196- # made, the error made by the last connection attempt is raised.
197- def create_resolver ( ssl_options )
198- return Unix . new ( seed . downcase ) if seed . downcase =~ Unix ::MATCH
199-
200- family = ( host == LOCALHOST ) ? ::Socket ::AF_INET : ::Socket ::AF_UNSPEC
201- error = nil
202- ::Socket . getaddrinfo ( host , nil , family , ::Socket ::SOCK_STREAM ) . each do |info |
203- begin
204- specific_address = FAMILY_MAP [ info [ 4 ] ] . new ( info [ 3 ] , port , host )
205- socket = specific_address . socket (
206- connect_timeout , ssl_options , connect_timeout : connect_timeout )
207- socket . close
208- return specific_address
209- rescue IOError , SystemCallError , Error ::SocketTimeoutError , Error ::SocketError => e
210- error = e
211- end
212- end
213- raise error
214- end
215-
216232 def parse_host_port
217233 address = seed . downcase
218234 case address
0 commit comments