Socket::AF_INET].map { |family| # ... } # Do "obtaining an address", "starting a connection attempt", # and "waiting for connections" # ... end end 5IFOFYUQBSUJTDPOOFDUJPOQSPDFTTJOH 5IFQSPDFTTPGPCUBJOJOHBOBEESFTT TUBSUJOHB DPOOFDUJPOBUUFNQUBOEXBJUJOHGPSDPOOFDUJPOTJT SFQFBUFEFWFSZNT *NQMFNFOUBUJPOPG4PDLFUUDQXJUI)&W
Socket::AF_INET].map { |family| # ... } loop do # Do "obtaining an address", "starting a connection # and "waiting for connections" end # ... end end 6TF,FSOFMMPPQUPSFQFBUUIFTFTUFQT *NQMFNFOUBUJPOPG4PDLFUUDQXJUI)&W n attempt",
do cond.wait(mutex) while resolved_addresses.empty? address = resolved_addresses.shift end socket = Socket.new(...) # ... end # ... end end 6QPO fi STUFOUFSJOHUIFMPPQ UIFMJTUPGSFTPMWFE*1 BEESFTTFTJTFNQUZ8BJUVOUJMBOZDIJMEUISFBEBEET BEESFTTFT UIFOCSFBLUIFXBJUBOEPCUBJOPOFPGUIFN 8BJUGPSBEESFTTFT 0CUBJOBOBEESFTT *NQMFNFOUBUJPOPG4PDLFUUDQXJUI)&W
do cond.wait(mutex) while resolved_addresses.empty? address = resolved_addresses.shift end socket = sockets.push(Socket.new(...)).last socket.connect_nonblock(address, exception: false) # ... end # ... end end 5IFOTUBSUBDPOOFDUJPOBUUFNQU UPUIFPCUBJOFEBEESFTT *NQMFNFOUBUJPOPG4PDLFUUDQXJUI)&W 4UBSUBDPOOFDUJPOBUUFNQU
do mutex.synchronize do cond.wait(mutex) while resolved_addresses.empty? address = resolved_addresses.shift end socket = sockets.push(Socket.new(...)).last socket.connect_nonblock(address, exception: false) _, writable_sockets, = IO.select(nil, sockets, nil, 0.25) connected = pick_connected_socket(writable_sockets, sockets) break connected if connected end do_cleanup connected end end 4PDLFUUDQXJUI)&WTVQQPSUFEJTOPXDPNQMFUF *NQMFNFOUBUJPOPG4PDLFUUDQXJUI)&W
when :start # ... end end ensure # ... end *OUIJTJNQMFNFOUBUJPO VTF,FSOFMMPPQBOEDBTFTUBUFNFOUTUPQFSGPSN BQQSPQSJBUFBDUJPOTGPSFBDITUBUF *NQMFNFOUBUJPOPG4PDLFUUDQXJUI)&W ,FSOFMMPPQ DBTFTUBUFNFOUT
do case state when :start # ... end end ensure # ... end 'JSTU TFUDVSSFOUTUBUFUPTUBSUBTBOJOJUJBMTUBUF CFGPSFTUBSUJOHUIFMPPQ *NQMFNFOUBUJPOPG4PDLFUUDQXJUI)&W *OJUJBMJ[FTUBUF
if res.is_a? Exception # ... else state = case family_name when :ipv6 then :v6c when :ipv4 then <resolution completed?> ? :v4c : :v4w end selectable_addrinfos.add(family_name, res) # ... end # ... next # ... 0ODFOBNFSFTPMVUJPOJT fi OJTIFE BEEUIFPCUBJOFE BEESFTTFTUPUIFMJTUPGSFTPMWFE*1BEESFTTFT *NQMFNFOUBUJPOPG4PDLFUUDQXJUI)&WTUBSU "EEUIFPCUBJOFEBEESFTTFT 5IFMJTUPGSFTPMWFE*1BEESFTTFT
if res.is_a? Exception # ... else state = case family_name when :ipv6 then :v6c when :ipv4 then < end selectable_addrinfos.add(family_name, res) # ... end # ... next # ... %FUFSNJOFUIFOFYUTUBUFCBTFEPOUIFPCUBJOFE BEESFTT BOEUIFOFOUFSUIFOFYUMPPQ *NQMFNFOUBUJPOPG4PDLFUUDQXJUI)&WTUBSU %FUFSNJOFUIFOFYUTUBUF ⬅︎ All name resolutions are finished?> ? :v4c : :v4w
family_name, res = hostname_resolution_queue.get selectable_addrinfos.add(family_name, res) unless res.is_a? E state = :v46c else state = :v4c end next # ... %FUFSNJOFUIFOFYUCBTFEPOXIFUIFSUIFOBNF SFTPMVUJPOXBT fi OJTIFEXJUIJOUIFBMMPUUFEUJNF BOEUIFOFOUFSUIFOFYUMPPQ *NQMFNFOUBUJPOPG4PDLFUUDQXJUI)&WWX Exception (hostname_resolution_waiting, nil, nil, RESOLUTION_DELAY) %FUFSNJOFUIFOFYUTUBUF ⬅︎
selectable_addrinfos.get # ... 1FSUIF3'$ BEESFTTFTTIPVMECFTPSUFECFGPSF DPOOFDUJOH5IJTJNQMFNFOUBUJPOTJNQMJ fi FTUIFQSPDFTT CZBMUFSOBUJOHCFUXFFO*1WBOE*1WBEESFTTFT *NQMFNFOUBUJPOPG4PDLFUUDQXJUI)&WWDWDWD precedences = case @last_family when :ipv4, nil then [:ipv6, :ipv4] when :ipv6 then [:ipv4, :ipv6] end precedences.each do |family_name| addrinfo = @addrinfo_dict[family_name]&.shift next unless addrinfo @last_family = family_name return addrinfo end 0CUBJOBOBEESFTT GSPNBEJ ff FSFOUBEESFTTGBNJMZ UIBOQSFWJPVTMZTFMFDUFE QSJPSJUJ[JOH*1WJOJUJBMMZ
when 0 connected_socket = socket state = :success when Socket connected_socket = result state = :success when :wait_writable connecting_sockets.add(socket, addrinfo) state = :v46w end # ... next "GUFSTUBSUJOHUIFDPOOFDUJPOBUUFNQU EFUFSNJOFUIF OFYUTUBUFCBTFEPOXIFUIFSUIFDPOOFDUJPOXBTNBEF JNNFEJBUFMZ BOEUIFOFOUFSUIFOFYUMPPQ *NQMFNFOUBUJPOPG4PDLFUUDQXJUI)&WWDWDWD %FUFSNJOFUIFOFYUTUBUF ⬅︎
when 0 connected_socket = socket state = :success when Socket connected_socket = result state = :success when :wait_writable connecting_sockets.add(socket, addrinfo) state = :v46w end # ... next *GUIFDPOOFDUJPODBOUCFFTUBCMJTIFEJNNFEJBUFMZ BEEUIFTPDLFUVTFEGPSUIFBUUFNQUUPUIFMJTUPG DPOOFDUJOHTPDLFUTCFGPSFEFUFSNJOJOHUIFOFYUTUBUF *NQMFNFOUBUJPOPG4PDLFUUDQXJUI)&WWDWDWD "EEUIFTPDLFUVTFE 5IFMJTUPGDPOOFDUJOHTPDLFUT
:success # ... when :failure raise last_error when :timeout # ... end end 5IFTUBUFTJOUSPEVDFEIFSFBGUFSBMMSFQSFTFOUUIF DPNQMFUJPOPGTUBUFUSBOTJUJPOT GBJMVSFXIJDIJTSFBDIFEJGBMMOBNFSFTPMVUJPOTPS BMMDPOOFDUJPOBUUFNQUTGBJM SBJTFBOFYDFQUJPO XJUIUIFMBTUDBQUVSFEFSSPS 3BJTFBOFYDFQUJPO
:success # ... when :failure raise last_error when :timeout raise Errno::ETIMEDOUT, "user specified timeout" end end *GBVTFSTQFDJ fi FEUJNFPVUPDDVST SFBDIUJNFPVU BOESBJTFBOFYDFQUJPOJOEJDBUJOHJU 3BJTFBOFYDFQUJPO
do # ... end # ... ensure # ... hostname_resolution_threads.each do |thread| thread&.exit end hostname_resolution_queue&.close_all connecting_sockets.each do |connecting_socket| connecting_socket.close unless connecting_socket.closed? end end "GUFSCSFBLJOHPVUPGUIFMPPQ DMFBOVQUISFBET QJQFT BOEPUIFSTPDLFUTJOFBDIDPOOFDUJPOBUUFNQUT $MFBOVQ
do # ... end if block_given? begin yield ret ensure ret.close end else ret end ensure # ... end SFUVSOUIFDPOOFDUFETPDLFUBOEUIFNFUIPEFYJUT &YFDVUFCMPDLXJUIUIFDPOOFDUFETPDLFU 3FUVSOUIFDPOOFDUFETPDLFU