Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Making TCPSocket.new "Happy"!

Making TCPSocket.new "Happy"!

More Decks by Misaki Shioi(塩井美咲/しおい)

Other Decks in Programming

Transcript

  1. "OBEWFOUVSFPG)BQQZ&ZFCBMMT 5IF3VCZTPDLFUMJCSBSZQSPWJEFTNFUIPETGPSSFUVSOJOH BDMJFOUTPDLFUDPOOFDUFEUPBTQFDJ fi FETFSWFSWJB5$1  0OFJT4PDLFUUDQ JNQMFNFOUFEJO3VCZ  BOEUIFPUIFSJT5$14PDLFUOFX

    JNQMFNFOUFEJO$ SFUVSOTBDMJFOUTPDLFU 4FSWFS $POOFDUJPOFTUBCMJTIFE 4PDLFUUDQ 5$14PDLFUOFX TPDLFU"OFOEQPJOUGPSDPNNVOJDBUJPOCFUXFFOIPTUTPWFSBOFUXPSL
  2. *GUIFEFTUJOBUJPOTFSWFSIBECPUI*1WBOE*1WBEESFTTFT  UIFTFNFUIPETQSFWJPVTMZQSPDFTTFETFRVFOUJBMMZ 'PSFYBNQMF 3FTPMWF*1WBEESFTTFT fi STU UIFO*1WBEESFTTFT "GUFSCPUIXFSFSFTPMWFE BUUFNQUDPOOFDUJOHUPUIF*1WBEESFTTFT

    fi STU BOEGBMMCBDLUPUIF*1WBEESFTTFTPOMZJGUIFZGBJMFE *1W *1W FH $POOFDUJPOGBJMFEXJUI*1W "OBEWFOUVSFPG)BQQZ&ZFCBMMT 4FSWFS 4PDLFUUDQ 5$14PDLFUOFX 4UBSUBDPOOFDUJPOBUUFNQUUP*1W 4UBSUBDPOOFDUJPOBUUFNQUUP*1W $POOFDUJPOFTUBCMJTIFEXJUI*1W
  3. )BQQZ&ZFCBMMT7FSTJPO )&W JTBOBMHPSJUINEFTJHOFEUP PWFSDPNFUIJTJTTVFBOEBDIJFWFNPSFF ff i DJFOUDPOOFDUJPOT 8JUI)&W IPTUOBNFSFTPMVUJPOBOEDPOOFDUJPOBUUFNQUT 

    XIJDIXFSFQSFWJPVTMZQFSGPSNFEPOFBUBUJNF TFRVFOUJBMMZ  BSFOPXQFSGPSNFENVMUJQMFBUPODF JOQBSBMMFM *1W *1W 4FSWFS $POOFDUJPOFTUBCMJTIFEXJUIFBSMJFS "OBEWFOUVSFPG)BQQZ&ZFCBMMT FH 4UBSUBDPOOFDUJPOBUUFNQUUP*1W 4UBSUBDPOOFDUJPOBUUFNQUUP*1W 4PDLFUUDQ 5$14PDLFUOFX
  4. def self.tcp(host, port, ...) # ... state = :start loop

    do case state when :start then Start hostname resolution when :v4w then Wait for 50ms for IPv6 name resolution when :v6c, :v4c, :v46c then Start a new connection attempt when :v46w then Wait for the connection state to be confirmed and name resolution to complete when :success then Return the successfully connected socket when :failure then Raise an exception when :timeout then Raise a timeout exception end end end 5IFJNQMFNFOUBUJPOPG4PDLFUUDQ )FSFJTBCSJFGPWFSWJFXPG4PDLFUUDQXJUI)&W JNQMFNFOUBUJPO
  5. 5IFTUBUFUSBOTJUJPO def self.tcp(host, port, ...) # ... state = :start

    loop do case state when :start then Start hostname resolution when :v4w then Wait for 50ms for IPv6 name resolution when :v6c, :v4c, :v46c then Start a new connection attempt when :v46w then Wait for the connection state to be confirmed and name resolution to complete when :success then Return the successfully connected socket when :failure then Raise an exception when :timeout then Raise a timeout exception end end end WD GBJMVSF TVDDFTT TUBSU WX UJNFPVU WX WD WD 5IFTUBUFUSBOTJUJPOEJBHSBNJTSFQSFTFOUFE CZDBMMJOHBDBTFTUBUFNFOUJOTJEF,FSOFMMPPQ
  6. def self.tcp(host, port, ...) # ... state = :start loop

    do case state when :start then Start hostname resolution when :v4w then Wait for 50ms for IPv6 name resolution when :v6c, :v4c, :v46c then Start a new connection attempt when :v46w then Wait for the connection state to be confirmed and name resolution to complete when :success then Return the successfully connected socket when :failure then Raise an exception when :timeout then Raise a timeout exception end end end 5IFDVSSFOUTUBUFJTTUPSFEJOBWBSJBCMFTUBUF TUBUF"WBSJBCMFUPTUPSFUIFDVSSFOUTUBUF 5IFDVSSFOUTUBUF 5IFTUBUFUSBOTJUJPO
  7. def self.tcp(host, port, ...) # ... state = :start loop

    do case state when :start then Start hostname resolution when :v4w then Wait for 50ms for IPv6 name resolution when :v6c, :v4c, :v46c then Start a new connection attempt when :v46w then Wait for the connection state to be confirmed and name resolution to complete when :success then Return the successfully connected socket when :failure then Raise an exception when :timeout then Raise a timeout exception end end end 5IFQSPDFTTPQFSBUFTBTGPMMPXT &YFDVUFUIFQSFEF fi OFEQSPDFTTJOHGPSUIFDVSSFOUTUBUF  ➡︎ 4FUUIFOFYUTUBUF ➡︎ 1SPDFFEUPUIFOFYUMPPQJUFSBUJPO 5IFBDUJPOTQFSGPSNFEGPSFBDITUBUF TUBUF"WBSJBCMFUPTUPSFUIFDVSSFOUTUBUF 5IFDVSSFOUTUBUF 5IFTUBUFUSBOTJUJPO
  8. 5IFTUBUFUSBOTJUJPO def self.tcp(host, port, ...) # ... state = :start

    loop do case state when :start then Start hostname resolution when :v4w then Wait for 50ms for IPv6 name resolution when :v6c, :v4c, :v46c then Start a new connection attempt when :v46w then Wait for the connection state to be confirmed and name resolution to complete when :success then Return the successfully connected socket when :failure then Raise an exception when :timeout then Raise a timeout exception end end end "UUIFTUBSUPGUIFNFUIPE UIFWBSJBCMFTUBUFJT JOJUJBMJ[FEXJUIUIFJOJUJBMTUBUFTUBSU TUBSUBTBJOJUJBMTUBUF
  9. 5IFTUBUFTUBSU def self.tcp(host, port, ...) # ... state = :start

    loop do case state when :start then Start hostname resolution when :v4w then Wait for 50ms for IPv6 name resolution when :v6c, :v4c, :v46c then Start a new connection attempt when :v46w then Wait for the connection state to be confirmed and name resolution to complete when :success then Return the successfully connected socket when :failure then Raise an exception when :timeout then Raise a timeout exception end end end WD GBJMVSF TVDDFTT TUBSU WX UJNFPVU WX WD WD *OUIF fi STUJUFSBUJPOPGUIFMPPQ  UIFQSPDFTTPGTUBSUJTFYFDVUFE
  10. case state when :start # ... TUBSU'JSTU DSFBUFBOPCKFDUXJUI BQBJSPGQJQF SFUVSOWBMVFPG*0QJQF

     BOEBRVFVF SFUVSOWBMVFPG2VFVFOFX  hostname_resolution_queue = HostnameResolutionQueue.new(resolving_family_names.size) 4UBSUIPTUOBNFSFTPMVUJPO def initialize(size) # ... @rpipe, @wpipe = IO.pipe @queue = Queue.new @mutex = Mutex.new end 5IFTUBUFTUBSU
  11. case state when :start # ... hostname_resolution_threads.concat( resolving_family_names.map { |family|

    thread_args = [family, *hostname_resolution_args] thread = Thread.new(*thread_args) { |*thread_args| hostname_resolution(*thread_args) } Thread.pass thread } ) # ... TUBSU4QBXOBUISFBEGPSFBDIBEESFTTGBNJMZ #ZDBMMJOHUIFOBNFSFTPMVUJPONFUIPEJOFBDIDIJME UISFBE *1WBOE*1WOBNFSFTPMVUJPOTUBSUJOQBSBMMFM 5IFOBNFSFTPMVUJPONFUIPE 4QBXOBUISFBE 4UBSUIPTUOBNFSFTPMVUJPO hostname_resolution_queue = HostnameResolutionQueue.new(resolving_family_names.size) hostname_resolution_waiting = hostname_resolution_queue.waiting_pipe hostname_resolution_args = [host, port, hostname_resolution_queue] 5IFTUBUFTUBSU
  12. case state when :start # ... hostname_resolution_threads.concat( resolving_family_names.map { |family|

    thread_args = [family, *hostname_resolution_args] thread = Thread.new(*thread_args) { |*thread_args| hostname_resolution(*thread_args) } Thread.pass thread } ) # ... 4UBSUIPTUOBNFSFTPMVUJPO hostname_resolution_queue = HostnameResolutionQueue.new(resolving_family_names.size) hostname_resolution_waiting = hostname_resolution_queue.waiting_pipe hostname_resolution_args = [host, port, hostname_resolution_queue] TUBSU1BTTUIFPCKFDUDSFBUFEFBSMJFSUIBUIPMETUIFQJQF BOEUIFRVFVF BMPOHXJUIPUIFSFMFNFOUTOFDFTTBSZGPS OBNFSFTPMVUJPOUPUIFNFUIPE BTBSHVNFOUT  5IFTUBUFTUBSU
  13. def self.hostname_resolution(family, host, port, hostname_resolution_queue) begin resolved_addrinfos = Addrinfo.getaddrinfo(host, port,

    ADDRESS_FAMILIES[family], :STREAM) hostname_resolution_queue.add_resolved(family, resolved_addrinfos) rescue => e # ... end end TUBSU)FSFJTUIFJNQMFNFOUBUJPOPG UIFOBNFSFTPMVUJPONFUIPE 5IFTUBUFTUBSU
  14. def self.hostname_resolution(family, host, port, hostname_resolution_queue) begin resolved_addrinfos = Addrinfo.getaddrinfo(host, port,

    ADDRESS_FAMILIES[family], :STREAM) hostname_resolution_queue.add_resolved(family, resolved_addrinfos) rescue => e # ... end end TUBSU$BMM"EESJOGPHFUBEESJOGPXIJDIQFSGPSNT IPTUOBNFSFTPMVUJPO 'PSIPTUOBNFSFTPMVUJPO 5IFTUBUFTUBSU
  15. def self.hostname_resolution(family, host, port, hostname_resolution_queue) begin resolved_addrinfos = Addrinfo.getaddrinfo(host, port,

    ADDRESS_FAMILIES[family], :STREAM) hostname_resolution_queue.add_resolved(family, resolved_addrinfos) rescue => e # ... end end TUBSU0ODFIPTUOBNFSFTPMVUJPOJTDPNQMFUF  QVTIUIFPCUBJOFEBEESFTTFTJOUPUIFRVFVFTIBSFE CFUXFFOUIFDIJMEUISFBETBOEUIFNBJOUISFBE def add_resolved(family, resolved_addrinfos) @mutex.synchronize do @queue.push [family, resolved_addrinfos] @wpipe.putc HOSTNAME_RESOLUTION_QUEUE_UPDATED end end 5IFTUBUFTUBSU
  16. def self.hostname_resolution(family, host, port, hostname_resolution_queue) begin resolved_addrinfos = Addrinfo.getaddrinfo(host, port,

    ADDRESS_FAMILIES[family], :STREAM) hostname_resolution_queue.add_resolved(family, resolved_addrinfos) rescue => e # ... end end TUBSU"OEJUJTOFDFTTBSZUPOPUJGZUIFNBJOUISFBE UIBUOBNFSFTPMVUJPOIBTDPNQMFUFEJOUIFDIJMEUISFBE def add_resolved(family, resolved_addrinfos) @mutex.synchronize do @queue.push [family, resolved_addrinfos] @wpipe.putc HOSTNAME_RESOLUTION_QUEUE_UPDATED end end 5IFTUBUFTUBSU
  17. def self.hostname_resolution(family, host, port, hostname_resolution_queue) begin resolved_addrinfos = Addrinfo.getaddrinfo(host, port,

    ADDRESS_FAMILIES[family], :STREAM) hostname_resolution_queue.add_resolved(family, resolved_addrinfos) rescue => e # ... end end TUBSU5PEPUIJT XSJUFUIFOPUJ fi DBUJPOUPUIFXSJUFFOE PGBQJQFUIBUJTBMTPTIBSFEXJUIUIFNBJOUISFBE def add_resolved(family, resolved_addrinfos) @mutex.synchronize do @queue.push [family, resolved_addrinfos] @wpipe.putc HOSTNAME_RESOLUTION_QUEUE_UPDATED end end 5IFTUBUFTUBSU
  18. case state when :start # Create child threads and call

    Socket.hostname_resolution hostname_resolved, _, = IO.select( # ... (hostname_resolution_waiting, nil, nil, nil) TUBSU*OUIFNBJOUISFBE *0TFMFDUJTDBMMFE BGUFSTQBXOJOHUIFDIJMEUISFBET 4UBSUIPTUOBNFSFTPMVUJPO 5IFTUBUFTUBSU
  19. case state when :start # Create child threads and call

    Socket.hostname_resolution hostname_resolved, _, = IO.select( # ... (hostname_resolution_waiting, nil, nil, nil) TUBSU5IFSFBEFOEPGUIFQJQFTIBSFEXJUI UIFDIJMEUISFBEJTQBTTFEBTBOBSHVNFOUUP*0TFMFDU 4UBSUIPTUOBNFSFTPMVUJPO 5IFTUBUFTUBSU 5IFSFBEFOEPGUIFQJQF
  20. case state when :start # Create child threads and call

    Socket.hostname_resolution hostname_resolved, _, = IO.select( # ... (hostname_resolution_waiting, nil, nil, nil) TUBSU8IFOFJUIFSUIF*1WPS*1WOBNFSFTPMVUJPO DPNQMFUFTJOUIFDIJMEUISFBE BOPUJ fi DBUJPOJTTFOU UISPVHIUIJTQJQF6OUJMUIBUOPUJ fi DBUJPOBSSJWFT  *0TFMFDUXJMMCMPDLJOEF fi OJUFMZ #MPDLQSPDFTTJOH 4UBSUIPTUOBNFSFTPMVUJPO 5IFTUBUFTUBSU 5IFOPUJ fi DBUJPOGSPNUIFDIJMEUISFBEBSSJWFTIFSF
  21. case state when :start # Create child threads and call

    Socket.hostname_resolution hostname_resolved, _, = IO.select( # ... family_name, res = hostname_resolution_queue.get # ... state = case family_name when :ipv6 then :v6c when :ipv4 then :v4w end selectable_addrinfos.add(family_name, res) # ... next TUBSU8IFOBOPUJ fi DBUJPOBSSJWFTUISPVHIUIFQJQF BOE*0TFMFDUVOCMPDLT UIFOSFUSJFWFUIFSFTPMWFE BEESFTTFT (FUUIFSFTVMUPGUIFIPTUOBNFSFTPMVUJPO 4UBSUIPTUOBNFSFTPMVUJPO 5IFTUBUFTUBSU (hostname_resolution_waiting, nil, nil, nil)
  22. case state when :start # Create child threads and call

    Socket.hostname_resolution hostname_resolved, _, = IO.select( # ... family_name, res = hostname_resolution_queue.get # ... state = case family_name when :ipv6 then :v6c when :ipv4 then :v4w end selectable_addrinfos.add(family_name, res) # ... next TUBSU*GUIFSFTPMWFEBEESFTTFTBSF*1W  USBOTJUJPOUPWX*GJUJT*1W USBOTJUJPOUPWD %FUFSNJOFUIFOFYUTUBUF (POFYU 4UBSUIPTUOBNFSFTPMVUJPO 5IFTUBUFTUBSU (hostname_resolution_waiting, nil, nil, nil)
  23. 5IFTUBUFWX def self.tcp(host, port, ...) # ... state = :start

    loop do case state when :start then Start hostname resolution when :v4w then Wait for 50ms for IPv6 name resolution when :v6c, :v4c, :v46c then Start a new connection attempt when :v46w then Wait for the connection state to be confirmed and name resolution to complete when :success then Return the successfully connected socket when :failure then Raise an exception when :timeout then Raise a timeout exception end end end WD GBJMVSF TVDDFTT TUBSU WX UJNFPVU WX WD WD WXJTTUBUFGPS3FTPMVUJPO%FMBZ  XIJDIXBJUTVQUPNTGPSPOMZ*1WOBNFSFTPMVUJPO
  24. case state when :v4w ipv6_resolved, _, = IO.select( # ...

    WX1BTTUIFSFBEFOEPGUIFQJQFUP*0TFMFDU UPCMPDLUIFQSPDFTT (hostname_resolution_waiting, nil, nil, RESOLUTION_DELAY) 8BJUGPSNTGPS*1WOBNFSFTPMVUJPO 5IFTUBUFWX 5IFSFBEFOEPGUIFQJQF #MPDLQSPDFTTJOH
  25. case state when :v4w ipv6_resolved, _, = IO.select( # ...

    WX1BTTNTBT3FTPMVUJPO%FMBZUPUIFUJNFPVU BSHVNFOU*0TFMFDUXJMMVOCMPDLFJUIFSXIFOUIF*1W OBNFSFTPMVUJPODPNQMFUFTPSXIFOUIFNTUJNFPVU FMBQTFT (hostname_resolution_waiting, nil, nil, RESOLUTION_DELAY) 8BJUGPSNTGPS*1WOBNFSFTPMVUJPO 5IFTUBUFWX #MPDLQSPDFTTJOH NTGPS3FTPMVUJPO%FMBZ 5IFSFBEFOEPGUIFQJQF
  26. case state when :v4w ipv6_resolved, _, = IO.select( if ipv6_resolved

    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 WX"GUFS*0TFMFDUVOCMPDLTBOEJG*1WJTSFTPMWFE XJUIJONT USBOTJUJPOUPWD *GOPU USBOTJUJPOUPWD (hostname_resolution_waiting, nil, nil, RESOLUTION_DELAY) Exception (POFYU %FUFSNJOFUIFOFYUTUBUF 5IFTUBUFWX 8BJUGPSNTGPS*1WOBNFSFTPMVUJPO
  27. 5IFTUBUFWDWDWD def self.tcp(host, port, ...) # ... state = :start

    loop do case state when :start then Start hostname resolution when :v4w then Wait for 50ms for IPv6 name resolution when :v6c, :v4c, :v46c then Start a new connection attempt when :v46w then Wait for the connection state to be confirmed and name resolution to complete when :success then Return the successfully connected socket when :failure then Raise an exception when :timeout then Raise a timeout exception end end end WD GBJMVSF TVDDFTT TUBSU WX UJNFPVU WX WD WD WD WD BOEWDBSFUIFTUBUF UPTUBSUBOFXDPOOFDUJPOBUUFNQU
  28. case state when :v6c, :v4c, v46c # ... addrinfo =

    selectable_addrinfos.get # ... socket = Socket.new( # ... result = socket.connect_nonblock(addrinfo, exception: false) # ... (addrinfo.pfamily, addrinfo.socktype, addrinfo.protocol) WDWDWD3FUSJFWFPOFPGBWBJMBCMFBEESFTTFT GPSUIFDPOOFDUJPOBOETUBSUBOPOCMPDLJOHDPOOFDUJPO 4UBSUBOFXDPOOFDUJPOBUUFNQU 3FUSJFWFBOBWBJMBCMFBEESFTT 4UBSUBDPOOFDUJPOBUUFNQU 5IFTUBUFWDWDWD
  29. case state when :v6c, :v4c, v46c # ... addrinfo =

    selectable_addrinfos.get # ... socket = Socket.new( # ... result = socket.connect_nonblock(addrinfo, exception: false) # ... connecting_sockets.add(socket, addrinfo) state = :v46w # ... next (addrinfo.pfamily, addrinfo.socktype, addrinfo.protocol) WDWDWD5IFOTUPSFUIFTPDLFUVTFEGPS UIFDPOOFDUJPOBUUFNQU BOEUSBOTJUJPOUPWX (POFYU 4FUUIFOFYUTUBUF 4UPSFUIFTPDLFU 4UBSUBOFXDPOOFDUJPOBUUFNQU 5IFTUBUFWDWDWD
  30. def self.tcp(host, port, ...) # ... state = :start loop

    do case state when :start then Start hostname resolution when :v4w then Wait for 50ms for IPv6 name resolution when :v6c, :v4c, :v46c then Start a new connection attempt when :v46w then Wait for the connection state to be confirmed and name resolution to complete when :success then Return the successfully connected socket when :failure then Raise an exception when :timeout then Raise a timeout exception end end end WD GBJMVSF TVDDFTT TUBSU WX UJNFPVU WX WD WD *OWX UIFQSPDFTTXBJUTGPSUIFDPOOFDUJPOUPCF FTUBCMJTIFE0S JGUIFPUIFSBEESFTTGBNJMZJTTUJMMSFTPMWJOH BUUIJTQPJOU JUBMTPXBJUTGPSUIBUSFTPMVUJPOUPDPNQMFUF 5IFTUBUFWX
  31. case state when :v46w # ... hostname_resolved, connectable_sockets, = IO.select(

    # ... (hostname_resolution_waiting, connecting_sockets.all, nil, remaining) WX5IFQSPDFTTJOHJTCMPDLFEXJUI*0TFMFDUBHBJO 5IJT*0TFMFDUNPOJUPSTCPUIUIFSFBEFOEPGUIFQJQF BOEBMMUIFTPDLFUTDVSSFOUMZBUUFNQUJOHUPDPOOFDU 8BJUGPSUIFDPOOFDUJPOTUBUFUPCFDPO fi SNFEBOEOBNFSFTPMVUJPOUPDPNQMFUF 5IFTUBUFWX 5IFTPDLFUTBUUFNQUJOHUPDPOOFDU 5IFSFBEFOEPGUIFQJQF #MPDLQSPDFTTJOH
  32. case state when :v46w # ... hostname_resolved, connectable_sockets, = IO.select(

    # ... (hostname_resolution_waiting, connecting_sockets.all, nil, remaining) 8BJUGPSUIFDPOOFDUJPOTUBUFUPCFDPO fi SNFEBOEOBNFSFTPMVUJPOUPDPNQMFUF #MPDLQSPDFTTJOH WX5IFUJNFPVUBSHVNFOUJTTFUUPNT 5IJTSFQSFTFOUT$POOFDUJPO"UUFNQU%FMBZŠ UIFXBJUJOHUJNFCFUXFFOTUBSUJOHUIFQSFWJPVT DPOOFDUJPOBUUFNQUBOETUBSUJOHUIFOFYUPOF NTGPS$POOFDUJPO"UUFNQU%FMBZ 5IFTPDLFUTBUUFNQUJOHUPDPOOFDU 5IFSFBEFOEPGUIFQJQF 5IFTUBUFWX
  33. 5IFTUBUFWX case state when :v46w # ... hostname_resolved, connectable_sockets, =

    IO.select( # ... (hostname_resolution_waiting, connecting_sockets.all, nil, remaining) 8BJUGPSUIFDPOOFDUJPOTUBUFUPCFDPO fi SNFEBOEOBNFSFTPMVUJPOUPDPNQMFUF #MPDLQSPDFTTJOH NTGPS$POOFDUJPO"UUFNQU%FMBZ 5IFTPDLFUTBUUFNQUJOHUPDPOOFDU 5IFSFBEFOEPGUIFQJQF WX*0TFMFDUVOCMPDLTXIFOFJUIFSBOBNFSFTPMVUJPO DPNQMFUJPOOPUJ fi DBUJPOBSSJWFTPOUIFSFBEFOEPGUIFQJQF  BOZPGUIFTPDLFUTDVSSFOUMZBUUFNQUJOHUPDPOOFDUCFDPNF XSJUBCMF PSUIFNTUJNFPVUFMBQTFT
  34. case state when :v46w # ... hostname_resolved, connectable_sockets, = IO.select(

    # ... if connectable_sockets&.any? # ... elsif hostname_resolved&.any? # ... else # ... end # ... next (hostname_resolution_waiting, connecting_sockets.all, nil, remaining) WX0ODF*0TFMFDUVOCMPDLT UIFOFYUTUBUFJT EFUFSNJOFECBTFEPOUIFSFBTPOJUXBTVOCMPDLFE (POFYU %FUFSNJOFUIFOFYUTUBUF 5IFJNQMFNFOUBUJPOPG4PDLFUUDQ WX 8BJUGPSUIFDPOOFDUJPOTUBUFUPCFDPO fi SNFEBOEOBNFSFTPMVUJPOUPDPNQMFUF *GUIF$POOFDUJPO"UUFNQU%FMBZUJNFTPVU
  35. 5IFJNQMFNFOUBUJPOPG4PDLFUUDQ def self.tcp(host, port, ...) # ... state = :start

    loop do case state when :start then Start hostname resolution when :v4w then Wait for 50ms for IPv6 name resolution when :v6c, :v4c, :v46c then Start a new connection attempt when :v46w then Wait for the connection state to be confirmed and name resolution to complete when :success then Return the successfully connected socket when :failure then Raise an exception when :timeout then Raise a timeout exception end end end WD GBJMVSF TVDDFTT TUBSU WX UJNFPVU WX WD WD &WFOUVBMMZ POFPGUIFUFSNJOBMTUBUFT TVDDFTT GBJMVSF  PSUJNFPVU JTSFBDIFE5IFO4PDLFUUDQ fi OJTIFTCZ FJUIFSSFUVSOJOHUIFDPOOFDUFETPDLFUPSSBJTJOH BOFYDFQUJPO EFQFOEJOHPOUIFTJUVBUJPO
  36. def self.tcp(host, port, ...) # ... state = :start loop

    do case state when :start then Start hostname resolution when :v4w then Wait for 50ms for IPv6 name resolution when :v6c, :v4c, :v46c then Start a new connection attempt when :v46w then Wait for the connection state to be confirmed and name resolution to complete when :success then Return the successfully connected socket when :failure then Raise an exception when :timeout then Raise a timeout exception end end end WD GBJMVSF TVDDFTT TUBSU WX UJNFPVU WX WD WD 5IFJNQMFNFOUBUJPOPG4PDLFUUDQXJUI)&W JTOPXDPNQMFUF 5IFJNQMFNFOUBUJPOPG4PDLFUUDQ
  37. "OFYBNQMFTPGUIFFYDFTTJWFMZBTUBUFUSBOTJUJPOMJLFJNQM case state when :start # ... hostname_resolved, _, =

    IO.select( # ... family_name, res = hostname_resolution_queue.get # ... state = case family_name when :ipv6 then :v6c when :ipv4 then :v4w end selectable_addrinfos.add(family_name, res) # ... next (hostname_resolution_waiting, nil, nil, remaining) -FUTSFWJFXTUBSUBHBJO GPDVTJOHPOXIBUIBQQFOT BGUFS*0TFMFDUVOCMPDLTŠUIBUJT BGUFSFJUIFSUIF*1W PS*1WSFTPMVUJPODPNQMFUFT 4UBSUIPTUOBNFSFTPMVUJPO
  38. case state when :start # ... hostname_resolved, _, = IO.select(

    # ... family_name, res = hostname_resolution_queue.get # ... state = case family_name when :ipv6 then :v6c when :ipv4 then :v4w end selectable_addrinfos.add(family_name, res) # ... next (hostname_resolution_waiting, nil, nil, remaining) 5IFOFYUTUBUFJTEFUFSNJOFECBTFEPOXIFUIFS UIFBEESFTTSFUSJFWFGSPNUIFRVFVFJT*1WPS*1W 4UBSUIPTUOBNFSFTPMVUJPO (FUUIFSFTVMU "OFYBNQMFTPGUIFFYDFTTJWFMZBTUBUFUSBOTJUJPOMJLFJNQM %FUFSNJOFUIFOFYUTUBUF
  39. case state when :start # ... hostname_resolved, _, = IO.select(

    # ... family_name, res = hostname_resolution_queue.get # ... state = case family_name when :ipv6 then :v6c when :ipv4 then :v4w end selectable_addrinfos.add(family_name, res) # ... next (hostname_resolution_waiting, nil, nil, remaining) 8IBUIBQQFOTJGCPUI*1WBOE*1WIBWF BMSFBEZDPNQMFUFEOBNFSFTPMVUJPOBUUIJTQPJOU 4UBSUIPTUOBNFSFTPMVUJPO "OFYBNQMFTPGUIFFYDFTTJWFMZBTUBUFUSBOTJUJPOMJLFJNQM
  40. case state when :start # ... hostname_resolved, _, = IO.select(

    # ... family_name, res = hostname_resolution_queue.get # ... state = case family_name when :ipv6 then :v6c when :ipv4 then :v4w end selectable_addrinfos.add(family_name, res) # ... next 4UBSUIPTUOBNFSFTPMVUJPO *1W *OUIJTDBTF UIFRVFVFIBT CPUI*1WBOE*1WBEESFTTFT (hostname_resolution_waiting, nil, nil, remaining) "OFYBNQMFTPGUIFFYDFTTJWFMZBTUBUFUSBOTJUJPOMJLFJNQM *1W 5IFRVFVF
  41. case state when :start # ... hostname_resolved, _, = IO.select(

    # ... family_name, res = hostname_resolution_queue.get # ... state = case family_name when :ipv6 then :v6c when :ipv4 then :v4w end selectable_addrinfos.add(family_name, res) # ... next 4UBSUIPTUOBNFSFTPMVUJPO 'PSFYBNQMF  JGUIF*1WBEESFTTFTBSFSFUSJFWFEGSPNUIFRVFVF  (hostname_resolution_waiting, nil, nil, remaining) "OFYBNQMFTPGUIFFYDFTTJWFMZBTUBUFUSBOTJUJPOMJLFJNQM *1W *1W 5IFRVFVF 3FUSJFWF*1WBEESFTTPOMZ
  42. case state when :start # ... hostname_resolved, _, = IO.select(

    # ... family_name, res = hostname_resolution_queue.get # ... state = case family_name when :ipv6 then :v6c when :ipv4 then :v4w end selectable_addrinfos.add(family_name, res) # ... next 4UBSUIPTUOBNFSFTPMVUJPO %FUFSNJOFUIBU*1WXBTSFTPMWFE fi STU  BOEUIFQSPDFTTUSBOTJUJPOTUPWX UPXBJUGPS*1WOBNFSFTPMVUJPO (hostname_resolution_waiting, nil, nil, remaining) %FUFSNJOFUIFOFYUTUBUFBTWX "OFYBNQMFTPGUIFFYDFTTJWFMZBTUBUFUSBOTJUJPOMJLFJNQM 3FUSJFWF*1WBEESFTTPOMZ
  43. case state when :v4w ipv6_resolved, _, = IO.select( if ipv6_resolved

    family_name, res = hostname_resolution_queue.get # ... state = :v46c else state = :v4c end next *OWX *0TFMFDUJTDBMMFEUPXBJUGPS*1WOBNF SFTPMVUJPO FWFOUIPVHI*1WIBTBMSFBEZCFFOSFTPMWFE   "OVOOFDFTTBSZ*0TFMFDUDBMMJTPDDVSSJOH &WFOUIPVHI*1WIBTBMSFBEZCFFOJOUIFRVFVF (hostname_resolution_waiting, nil, nil, RESOLUTION_DELAY) "OFYBNQMFTPGUIFFYDFTTJWFMZBTUBUFUSBOTJUJPOMJLFJNQM 8BJUGPSNTGPS*1WOBNFSFTPMVUJPO *1W 3FUSJFWF*1WBEESFTT 5IFRVFVF
  44. 5IFPWFSWJFXPGUIFJNQSPWFEWFSTJPOPG4PDLFUUDQ def self.tcp(host, port, ...) <Initialization of the timeout variables>

    <Start hostname resolution in child threads> loop do if <The condition to start a connection> then <Start a connection> timeout = <Calculate the timeout value> IO.select(<name resolution>, <connections>, nil, <timeout>) if <Sockets are confirmed connected> then <Verify the connection> if <A name resolution is complete> then <Save the resolved IP addresses> if <The next loop cannot proceed> then <Raise an exception> end end -FUTSFWJFXUIFDIBOHFT
  45. def self.tcp(host, port, ...) <Initialization of the timeout variables> <Start

    hostname resolution in child threads> loop do # Processes in this loop end end 5IFPWFSWJFXPGUIFJNQSPWFEWFSTJPOPG4PDLFUUDQ 'JSTU UIFJOJUJBMJ[BUJPOPGWBSJBCMFTGPSNBOBHJOH UJNFPVUT TVDIBT3FTPMVUJPO%FMBZBOE $POOFDUJPO"UUFNQU%FMBZ BSFOFXMZBEEFE "EEFE
  46. *OJUJBMJ[BUJPOPGUIFUJNFPVUWBSJBCMFT def self.tcp(host, port, ...) # Other initialization processes resolution_delay_expires_at

    = nil connection_attempt_delay_expires_at = nil <Start hostname resolution in child threads> loop do # Processes in this loop end end SFTPMVUJPO@EFMBZ@FYQJSFT@BUJTBWBSJBCMFUIBUTUPSFT UIFEFBEMJOFGPSXBJUJOHPO*1WOBNFSFTPMVUJPO BTQBSUPGUIF3FTPMVUJPO%FMBZ *OJUJBMJ[BUJPOPGUIFUJNFPVUWBSJBCMFT
  47. *OJUJBMJ[BUJPOPGUIFUJNFPVUWBSJBCMFT def self.tcp(host, port, ...) # Other initialization processes resolution_delay_expires_at

    = nil connection_attempt_delay_expires_at = nil <Start hostname resolution in child threads> loop do # Processes in this loop end end DPOOFDUJPO@BUUFNQU@EFMBZ@FYQJSFT@BUJTBWBSJBCMF UIBUTUPSFTUIFUJNFBUXIJDIUIFOFYUDPOOFDUJPO BUUFNQUDBOCFHJOBGUFSUIFQSFWJPVTPOFIBTTUBSUFE  BTQBSUPG$POOFDUJPO"UUFNQU%FMBZ *OJUJBMJ[BUJPOPGUIFUJNFPVUWBSJBCMFT
  48. *OJUJBMJ[BUJPOPGUIFUJNFPVUWBSJBCMFT def self.tcp(host, port, ...) # Other initialization processes resolution_delay_expires_at

    = nil connection_attempt_delay_expires_at = nil <Start hostname resolution in child threads> loop do # Processes in this loop end end 5IFTFWBSJBCMFTBSFJOJUJBMMZTFUUPOJM 5IFWBMVFTXJMMCFTFUMBUFS XIFOXBJUJOHCFDPNFT OFDFTTBSZ *OJUJBMJ[FXJUIOJM
  49. def self.tcp(host, port, ...) # Other initialization processes resolution_delay_expires_at =

    nil connection_attempt_delay_expires_at = nil <Start hostname resolution in child threads> loop do # Processes in this loop end end 4UBSUIPTUOBNFSFTPMVUJPOJODIJMEUISFBET /FYU UIFNFUIPEGPSOBNFSFTPMVUJPOJTDBMMFE 5IFJNQMFNFOUBUJPOBOEJOWPDBUJPOPGUIJTNFUIPEBSF NPTUMZUIFTBNFBTQSFWJPVTJNQMFNFOUBUJPO &YFDVUFUIFOBNFSFTPMVUJPONFUIPE
  50. def self.tcp(host, port, ...) # Other initialization processes resolution_delay_expires_at =

    nil connection_attempt_delay_expires_at = nil <Start hostname resolution in child threads> loop do # Processes in this loop end end 4UBSUBMPPQ 4UBSUBMPPQ
  51. loop do if <The condition to start a connection> then

    <Start a connection> timeout = <Calculate the timeout value> IO.select(<name resolution>, <connections>, nil, <timeout>) if <Sockets are confirmed connected> then <Verify the connection> if <A name resolution is complete> then <Save the resolved IP addresses> if <The next loop cannot proceed> then <Raise an exception> end 5IFPWFSWJFXPGUIFQSPDFTTFTJOUIJTMPPQ 5IFDBTFTUBUFNFOUJOUIFQSFWJPVTJNQMFNFOUBUJPO  XIJDIEJSFDUFEQSPDFTTJOHCBTFEPOUIFDVSSFOUTUBUF  IBTCFFOSFQMBDFEXJUIJGTUBUFNFOUTJOTJEFUIFMPPQ 3FQMBDFDBTFXJUIJGT
  52. loop do if <The condition to start a connection> then

    <Start a connection> timeout = <Calculate the timeout value> IO.select(<name resolution>, <connections>, nil, <timeout>) if <Sockets are confirmed connected> then <Verify the connection> if <A name resolution is complete> then <Save the resolved IP addresses> if <The next loop cannot proceed> then <Raise an exception> end 5IFPWFSWJFXPGUIFQSPDFTTFTJOUIJTMPPQ 0OFBDIMPPQJUFSBUJPO DPOEJUJPOTBSFDIFDLFEBOE UIFOFDFTTBSZQSPDFTTJOHJTQFSGPSNFE 3FQMBDFDBTFXJUIJGT
  53. loop do if <The condition to start a connection> then

    <Start a connection> timeout = <Calculate the timeout value> IO.select(<name resolution>, <connections>, nil, <timeout>) if <Sockets are confirmed connected> then <Verify the connection> if <A name resolution is complete> then <Save the resolved IP addresses> if <The next loop cannot proceed> then <Raise an exception> end 5IF fi STUDPOEJUJPO 5IF fi STUDPOEJUJPODIFDLT XIFUIFSBOFXDPOOFDUJPOBUUFNQUDBOCFTUBSUFE 5IFSFRVJSFNFOUTGPSTUBSUJOHBOBUUFNQUBSF
  54. if resolution_store.any_addrinfos? && !resolution_delay_expires_at && !connection_attempt_delay_expires_at # ... end 5IFDPOEJUJPOUPTUBSUBDPOOFDUJPO

    "UMFBTUPOFBEESFTTGBNJMZIBTDPNQMFUFEOBNF SFTPMVUJPO BOEUIFSFBSFBWBJMBCMFDBOEJEBUF BEESFTTFTUPDPOOFDUUP 5IFDPOEJUJPOUPTUBSUBDPOOFDUJPO
  55. if resolution_store.any_addrinfos? && !resolution_delay_expires_at && !connection_attempt_delay_expires_at # ... end SFTPMVUJPO@EFMBZ@FYQJSFT@BUJTOJM

     NFBOJOHJUJTOPUEVSJOH3FTPMVUJPO%FMBZ 5IFDPOEJUJPOUPTUBSUBDPOOFDUJPO 5IFDPOEJUJPOUPTUBSUBDPOOFDUJPO
  56. if resolution_store.any_addrinfos? && !resolution_delay_expires_at && !connection_attempt_delay_expires_at # ... end DPOOFDUJPO@BUUFNQU@EFMBZ@FYQJSFT@BUJTOJM

     NFBOJOHJUJTOPUEVSJOH$POOFDUJPO"UUFNQU%FMBZ 5IFDPOEJUJPOUPTUBSUBDPOOFDUJPO 5IFDPOEJUJPOUPTUBSUBDPOOFDUJPO
  57. if resolution_store.any_addrinfos? && !resolution_delay_expires_at && !connection_attempt_delay_expires_at while (addrinfo = resolution_store.get_addrinfo)

    # ... socket = Socket.new(addrinfo.pfamily, addrinfo.socktype, addrinfo.protocol) socket.bind(local_addrinfo) if local_addrinfo result = socket.connect_nonblock(addrinfo, exception: false) if result == :wait_writable # ... # ... connecting_sockets[socket] = addrinfo # ... end end end *GBMMUIFTFDPOEJUJPOTBSFNFU  POFEFTUJOBUJPOBEESFTTJT3FUSJFWF  BOETUBSUBDPOOFDUJPOBUUFNQUJOOPOCMPDLJOHNPEF 3FUSJFWFBOBEESFTT 4UBSUBOPOCMPDLJOHDPOOFDU 5IFDPOEJUJPOUPTUBSUBDPOOFDUJPO
  58. if resolution_store.any_addrinfos? && !resolution_delay_expires_at && !connection_attempt_delay_expires_at while (addrinfo = resolution_store.get_addrinfo)

    # ... socket = Socket.new(addrinfo.pfamily, addrinfo.socktype, addrinfo.protocol) socket.bind(local_addrinfo) if local_addrinfo result = socket.connect_nonblock(addrinfo, exception: false) if result == :wait_writable connection_attempt_delay_expires_at = now + CONNECTION_ATTEMPT_DELAY # ... end end end DPOOFDUJPO@BUUFNQU@EFMBZ@FYQJSFT@BUJTTFUUP UIFDVSSFOUUJNF NT5IJTSFQSFTFOUTUIFUJNFBU XIJDIUIFOFYUDPOOFDUJPOBUUFNQUDBOCFHJO 5IFDVSSFOUUJNF NT 5IFDPOEJUJPOUPTUBSUBDPOOFDUJPO
  59. if resolution_store.any_addrinfos? && !resolution_delay_expires_at && !connection_attempt_delay_expires_at while (addrinfo = resolution_store.get_addrinfo)

    # ... socket = Socket.new(addrinfo.pfamily, addrinfo.socktype, addrinfo.protocol) socket.bind(local_addrinfo) if local_addrinfo result = socket.connect_nonblock(addrinfo, exception: false) if result == :wait_writable connection_attempt_delay_expires_at = now + CONNECTION_ATTEMPT_DELAY # ... connecting_sockets[socket] = addrinfo # ... end end end 5IFOTUPSFUIFTPDLFUVTFEGPSUIFDPOOFDUJPOBUUFNQU  FYJUUIJTJGTUBUFNFOU 4UPSFUIFTPDLFU 5IFDPOEJUJPOUPTUBSUBDPOOFDUJPO
  60. loop do if <The condition to start a connection> then

    <Start a connection> timeout = <Calculate the timeout value> IO.select(<name resolution>, <connections>, nil, <timeout>) if <Sockets are confirmed connected> then <Verify the connection> if <A name resolution is complete> then <Save the resolved IP addresses> if <The next loop cannot proceed> then <Raise an exception> end "GUFSUIF fi STUDPOEJUJPO 5IFOFYUTUFQJTUPDBMM*0TFMFDU
  61. loop do if <The condition to start a connection> then

    <Start a connection> timeout = <Calculate the timeout value> IO.select(<name resolution>, <connections>, nil, <timeout>) if <Sockets are confirmed connected> then <Verify the connection> if <A name resolution is complete> then <Save the resolved IP addresses> if <The next loop cannot proceed> then <Raise an exception> end $BMM*0TFMFDUUPXBJU *OUIFQSFWJPVTJNQMFNFOUBUJPO *0TFMFDUXBTDBMMFEJO UISFFEJ ff FSFOUTUBUFTŠTUBSU WX BOEWXŠUPXBJU GPSFJUIFSBDPOOFDUJPOPSOBNFSFTPMVUJPOUPDPNQMFUF
  62. loop do if <The condition to start a connection> then

    <Start a connection> timeout = <Calculate the timeout value> IO.select(<name resolution>, <connections>, nil, <timeout>) if <Sockets are confirmed connected> then <Verify the connection> if <A name resolution is complete> then <Save the resolved IP addresses> if <The next loop cannot proceed> then <Raise an exception> end $BMM*0TFMFDUUPXBJU *OUIFOFXJNQMFNFOUBUJPO JUJTDPOTPMJEBUFEJOUP BTJOHMFMPDBUJPO XIFSFJUXBJUTGPSFJUIFSBDPOOFDUJPO PSOBNFSFTPMVUJPOUPDPNQMFUF
  63. loop do if <The condition to start a connection> then

    <Start a connection> timeout = <Calculate the timeout value> IO.select(<name resolution>, <connections>, nil, <timeout>) if <Sockets are confirmed connected> then <Verify the connection> if <A name resolution is complete> then <Save the resolved IP addresses> if <The next loop cannot proceed> then <Raise an exception> end 5PTVQQPSUUIJT MPHJDIBTCFFOBEEFEUPDBMDVMBUF UIFBQQSPQSJBUFUJNFPVUWBMVFUPQBTTUP*0TFMFDU  CBTFEPOUIFDVSSFOUTJUVBUJPO $BMM*0TFMFDUUPXBJU
  64. ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [user_specified_resolv_timeout_at, user_specified_connect_timeout_at].compact.max

    end BOE3FTPMVUJPO%FMBZJTJOQSPHSFTT  SFTPMVUJPO@EFMBZ@FYQJSFT@BUXJMMIBWFBWBMVF  BOEUIBUWBMVFJTSFUVSOFE $BMDVMBUFUIFUJNFPVUWBMVF
  65. $BMDVMBUFUIFUJNFPVUWBMVF ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [user_specified_resolv_timeout_at,

    user_specified_connect_timeout_at].compact.max end *G3FTPMVUJPO%FMBZJTOPUJOQSPHSFTT UIFWBMVFTFU DPOOFDUJPO@BUUFNQU@EFMBZ@FYQJSFT@BUJTSFUVSOFE JOTUFBE
  66. $BMDVMBUFUIFUJNFPVUWBMVF ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [user_specified_resolv_timeout_at,

    user_specified_connect_timeout_at].compact.max end *GUIFSFBSFOPBWBJMBCMFDBOEJEBUFBEESFTTFT  5IJTNFBOTFJUIFSOPOBNFSFTPMVUJPOIBTCFFO DPNQMFUFEZFU PSDPOOFDUJPOBUUFNQUTIBWFBMSFBEZ CFFOTUBSUFEGPSBMMSFTPMWFEBEESFTTFTBUUIJTQPJOU
  67. $BMDVMBUFUIFUJNFPVUWBMVF ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [user_specified_resolv_timeout_at,

    user_specified_connect_timeout_at].compact.max end *OUIJTDBTF JGTPNFVTFSTQFDJ fi FEUJNFPVUWBMVFT BSFQSPWJEFEBTBOBSHVNFOUUP4PDLFUUDQ  UIFMBSHFSWBMVFJTVTFE
  68. ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [user_specified_resolv_timeout_at, user_specified_connect_timeout_at].compact.max

    end *GOPVTFSTQFDJ fi FEUJNFPVUJTHJWFO  BXPSLBSPVOEJTBQQMJFEUPSFUVSOBWBMVFUIBU F ff FDUJWFMZXBJUTJOEF fi OJUFMZ EFUBJMTPNJUUFEIFSF  $BMDVMBUFUIFUJNFPVUWBMVF
  69. ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [user_specified_resolv_timeout_at, user_specified_connect_timeout_at].compact.max

    end hostname_resolved, writable_sockets, except_sockets = IO.select( hostname_resolution_notifier, connecting_sockets.keys, is_windows_environment ? connecting_sockets.keys : nil, second_to_timeout(current_clock_time, ends_at), ) $BMM*0TFMFDUXJUIUIFUJNFPVUWBMVFDBMDVMBUFEGSPN UIFSFUVSOWBMVFPGUIJTMPHJD $BMM*0TFMFDUXJUIUIFUJNFPVUWBMVF "DUVBMUJNFPVUWBMVF
  70. ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at || connection_attempt_delay_expires_at else [user_specified_resolv_timeout_at, user_specified_connect_timeout_at].compact.max

    end hostname_resolved, writable_sockets, except_sockets = IO.select( hostname_resolution_notifier, connecting_sockets.keys, is_windows_environment ? connecting_sockets.keys : nil, second_to_timeout(current_clock_time, ends_at), ) "TWXJOUIFQSFWJPVTJNQMFNFOUBUJPO  UIFBSHVNFOUTPUIFSUIBOUIFUJNFPVUBSF ɾ5IFQJQFXBJUJOHGPSOBNFSFTPMVUJPOOPUJ fi DBUJPOT ɾ5IFTPDLFUTDVSSFOUMZBUUFNQUJOHUPDPOOFDU $BMM*0TFMFDUXJUIUIFUJNFPVUWBMVF 5IFQJQFXBJUJOHGPSOBNFSFTPMVUJPOOPUJ fi DBUJPO 5IFTPDLFUTBUUFNQUJOHUPDPOOFDU
  71. "GUFS*0TFMFDU hostname_resolved, writable_sockets, except_sockets = IO.select( hostname_resolution_notifier, connecting_sockets.keys, is_windows_environment ?

    connecting_sockets.keys : nil, second_to_timeout(current_clock_time, ends_at), ) now = current_clock_time if expired?(now, resolution_delay_expires_at) resolution_delay_expires_at = nil end if expired?(now, connection_attempt_delay_expires_at) connection_attempt_delay_expires_at = nil end 0ODF*0TFMFDUVOCMPDLT UIF fi STUTUFQJTUP DIFDLUIFWBMVFTPGUIFUJNFPVUWBSJBCMFT SFTPMVUJPO@EFMBZ@FYQJSFT@BUJTQBTU  DPOOFDUJPO@BUUFNQU@EFMBZ@FYQJSFT@BUJTQBTU 
  72. hostname_resolved, writable_sockets, except_sockets = IO.select( hostname_resolution_notifier, connecting_sockets.keys, is_windows_environment ? connecting_sockets.keys

    : nil, second_to_timeout(current_clock_time, ends_at), ) now = current_clock_time if expired?(now, resolution_delay_expires_at) resolution_delay_expires_at = nil end if expired?(now, connection_attempt_delay_expires_at) connection_attempt_delay_expires_at = nil end 3FTFU "GUFS*0TFMFDU *GBOZTUPSFEUJNFIBTBMSFBEZQBTTFEBUUIJTQPJOU  JUJTSFTFUUPOJM 3FTFU
  73. loop do if <The condition to start a connection> then

    <Start a connection> timeout = <Calculate the timeout value> IO.select(<name resolution>, <connections>, nil, <timeout>) if <Sockets are confirmed connected> then <Verify the connection> if <A name resolution is complete> then <Save the resolved IP addresses> if <The next loop cannot proceed> then <Raise an exception> end $IFDLUIFSFTVMUPG*0TFMFDU /FYU CBTFEPOUIFSFTVMUPG*0TFMFDU DIFDLXIFUIFS ɾ0OFPSNPSFXSJUBCMFTPDLFUTBSFBWBJMBCMF ɾ"OBNFSFTPMVUJPOOPUJ fi DBUJPOIBTBSSJWFEPOUIFQJQF $IFDLUIFSFTVMU
  74. 0OFPSNPSFXSJUBCMFTPDLFUTBSFBWBJMBCMF if writable_sockets&.any? while (writable_socket = writable_sockets.pop) is_connected = is_windows_environment

    || ( sockopt = writable_socket.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR) sockopt.int.zero? ) if is_connected connecting_sockets.delete writable_socket return writable_socket else # ... end end end *GUIFSFBSFXSJUBCMFTPDLFUT DIFDLUIFJSDPOOFDUJPO TUBUVT*GUIFDPOOFDUJPOJTTVDDFTTGVM  SFUVSOUIFTPDLFUBOEFYJU4PDLFUUDQ *TUIFDPOOFDUJPOTVDDFTTGVM  3FUVSOUIFTVDDFTTGVMMZDPOOFDUFETPDLFU $IFDLUIFDPOOFDUJPOTUBUVT
  75. if hostname_resolved&.any? while (family_and_result = hostname_resolution_result.get) family_name, result = family_and_result

    if result.is_a? Exception # ... else resolution_store.add_resolved(family_name, result) end end # ... end *GBOBNFSFTPMVUJPOOPUJ fi DBUJPOIBTBSSJWFEPO UIFQJQF SFUSJFWFUIFSFTPMWFEBEESFTTFT BOETUPSFUIFN "OBNFSFTPMVUJPOOPUJ fi DBUJPOIBTBSSJWFE 0CUBJOSFTPMWFEBEESFTTFT 4UPSFUIFPCUBJOFEBEESFTTFT
  76. if hostname_resolved&.any? while (family_and_result = hostname_resolution_result.get) # ... end if

    resolution_store.resolved?(:ipv4) if resolution_store.resolved?(:ipv6) hostname_resolution_notifier = nil resolution_delay_expires_at = nil user_specified_resolv_timeout_at = nil elsif resolution_store.resolved_successfully?(:ipv4) resolution_delay_expires_at = now + RESOLUTION_DELAY end end end *GPOMZ*1WJTSFTPMWFEBOE*1WJTTUJMMVOSFTPMWFE TFU SFTPMVUJPO@EFMBZ@FYQJSFT@BUUPUIFDVSSFOUUJNF  NTUPXBJUGPS*1WSFTPMVUJPOJOUIFOFYUMPPQ "OBNFSFTPMVUJPOOPUJ fi DBUJPOIBTBSSJWFE 4FUSFTPMVUJPO@EFMBZ@FYQJSFT@BU *1WIBTCFFOSFTPMWFE *1WIBTOPUCFFOSFTPMWFE
  77. loop do if <The condition to start a connection> then

    <Start a connection> timeout = <Calculate the timeout value> IO.select(<name resolution>, <connections>, nil, <timeout>) if <Sockets are confirmed connected> then <Verify the connection> if <A name resolution is complete> then <Save the resolved IP addresses> if <The next loop cannot proceed> then <Raise an exception> end "UUIFFOEPGUIFMPPQ "UUIFFOEPGUIFMPPQ UIFSFJTBDIFDLUPEFUFSNJOF XIFUIFSUIFOFYUMPPQJUFSBUJPODBOQSPDFFE
  78. loop do # ... if resolution_store.empty_addrinfos? if connecting_sockets.empty? && resolution_store.resolved_all_families?

    raise last_error end if (expired?(now, user_specified_resolv_timeout_at) || ...) && (expired?(now, user_specified_connect_timeout_at) || ...) raise Errno::ETIMEDOUT, 'user specified timeout' end end end ɾ*GUIFSFBSFOPBWBJMBCMFBEESFTTDBOEJEBUFT ɾ"OEUIFSFBSFOPTPDLFUTDVSSFOUMZDPOOFDUJOH ɾ"OEBMMOBNFSFTPMVUJPOTIBWFDPNQMFUFE UIFOOPGVSUIFSQSPDFTTJOHDBOCFQFSGPSNFE  TPBOFYDFQUJPOJTSBJTFE 8IFUIFSUIFOFYUMPPQJUFSBUJPODBOQSPDFFE 3BJTFBOFYDFQUJPO
  79. loop do # ... if resolution_store.empty_addrinfos? if connecting_sockets.empty? && resolution_store.resolved_all_families?

    raise last_error end if (expired?(now, user_specified_resolv_timeout_at) || ...) && (expired?(now, user_specified_connect_timeout_at) || ...) raise Errno::ETIMEDOUT, 'user specified timeout' end end end *GUIFVTFSTQFDJ fi FEUJNFPVUTIBWFCFFOFYDFFEFE  SBJTFBUJNFPVUFYDFQUJPO 8IFUIFSUIFOFYUMPPQJUFSBUJPODBOQSPDFFE 3BJTFBUJNFPVUFYDFQUJPO
  80. loop do # ... if resolution_store.empty_addrinfos? if connecting_sockets.empty? && resolution_store.resolved_all_families?

    raise last_error end if (expired?(now, user_specified_resolv_timeout_at) || ...) && (expired?(now, user_specified_connect_timeout_at) || ...) raise Errno::ETIMEDOUT, 'user specified timeout' end end end 0UIFSXJTF TJODFUIFSFBSFTUJMMFYFDVUBCMFQSPDFTTFT SFNBJOJOH QSPDFFEUPUIFOFYUMPPQJUFSBUJPO 8IFUIFSUIFOFYUMPPQJUFSBUJPODBOQSPDFFE 5PCFDPOUJOVFE ⬇︎
  81. def self.tcp(host, port, ...) <Initialization of the timeout variables> <Start

    hostname resolution in child threads> loop do if <The condition to start a connection> then <Start a connection> timeout = <Calculate the timeout value> IO.select(<name resolution>, <connections>, nil, <timeout>) if <Sockets are confirmed connected> then <Verify the connection> if <A name resolution is complete> then <Save the resolved IP addresses> if <The next loop cannot proceed> then <Raise an exception> end end 5IJTSFQFBUTVOUJM4PDLFUUDQSFUVSOTBTVDDFTTGVMMZ DPOOFDUFETPDLFU 8IFUIFSUIFOFYUMPPQJUFSBUJPODBOQSPDFFE
  82. def self.tcp(host, port, ...) <Initialization of the timeout variables> <Start

    hostname resolution in child threads> loop do if <The condition to start a connection> then <Start a connection> timeout = <Calculate the timeout value> IO.select(<name resolution>, <connections>, nil, <timeout>) if <Sockets are confirmed connected> then <Verify the connection> if <A name resolution is complete> then <Save the resolved IP addresses> if <The next loop cannot proceed> then <Raise an exception> end end 5IFJNQSPWFEWFSTJPOPG4PDLFUUDQ 5IFJNQSPWFEWFSTJPOPG4PDLFUUDQJTOPXDPNQMFUF
  83. *OUFSSVQUJCMFHFUBEESJOGP*NQMFNFOUBUJPO BTPG3VCZ FH5IFDBMMTUBDLPG"EESJOGPHFUBEESJOGP "EESJOGPHFUBEESJOGP  ➡︎ BEESJOGP@T@HFUBEESJOGP ɹ ➡︎ BEESJOGP@MJTU@OFX

    ɹ ➡︎ DBMM@HFUBEESJOGP ɹɹ ➡︎ STPDL@HFUBEESJOGP ɹɹ ➡︎ SC@HFUBEESJOGP -FUTTFFIPXUIFTFNFUIPETNBLFUIF OBNFSFTPMVUJPOJOUFSSVQUJCMFJO3VCZ *OBOFOWJSPONFOUXIFSFUIFQUISFBEMJCSBSZJTBWBJMBCMF
  84. FH5IFDBMMTUBDLPG"EESJOGPHFUBEESJOGP "EESJOGPHFUBEESJOGP  ➡︎ BEESJOGP@T@HFUBEESJOGP ɹ ➡︎ BEESJOGP@MJTU@OFX ɹ ➡︎

    DBMM@HFUBEESJOGP ɹɹ ➡︎ STPDL@HFUBEESJOGP ɹɹ ➡︎ SC@HFUBEESJOGP *OUFSSVQUJCMFHFUBEESJOGP*NQMFNFOUBUJPO BTPG3VCZ Attention! *OBOFOWJSPONFOUXIFSFUIFQUISFBEMJCSBSZJTBWBJMBCMF
  85. static int rb_getaddrinfo(...) { // ... pthread_t th; if (do_pthread_create(&th,

    do_getaddrinfo, arg) != 0) { free_getaddrinfo_arg(arg); return EAI_AGAIN; } pthread_detach(th); // ... } *OUFSSVQUJCMFHFUBEESJOGP*NQMFNFOUBUJPO BTPG3VCZ IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUSBEESJOGPD BOEEFUBDIJU 4QBXOBOFXDIJMEUISFBE *OBOFOWJSPONFOUXIFSFUIFQUISFBEMJCSBSZJTBWBJMBCMF *OTJEFSC@HFUBEESJOGP  BOFXDIJMEUISFBEJTTQBXOFEBOEEFUBDIFE GSPNUIFNBJOUISFBE
  86. static int rb_getaddrinfo(...) { // ... pthread_t th; if (do_pthread_create(&th,

    do_getaddrinfo, arg) != 0) { free_getaddrinfo_arg(arg); return EAI_AGAIN; } pthread_detach(th); // ... } *OUFSSVQUJCMFHFUBEESJOGP*NQMFNFOUBUJPO BTPG3VCZ static void *do_getaddrinfo(void *ptr) { // ... int err, gai_errno; err = getaddrinfo(...); // ... } $BMMHFUBEESJOGP   IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUSBEESJOGPD *OBOFOWJSPONFOUXIFSFUIFQUISFBEMJCSBSZJTBWBJMBCMF *OUIFEFUBDIFEDIJMEUISFBE HFUBEESJOGP  JTDBMMFE
  87. static int rb_getaddrinfo(...) { // ... pthread_t th; if (do_pthread_create(&th,

    do_getaddrinfo, arg) != 0) { free_getaddrinfo_arg(arg); return EAI_AGAIN; } pthread_detach(th); // ... } *OUFSSVQUJCMFHFUBEESJOGP*NQMFNFOUBUJPO BTPG3VCZ static void *do_getaddrinfo(void *ptr) { // ... arg->done = 1; rb_native_cond_signal(&arg->cond); // ... } 4JHOBMUPUIFNBJOUISFBE IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUSBEESJOGPD *OBOFOWJSPONFOUXIFSFUIFQUISFBEMJCSBSZJTBWBJMBCMF 0ODFOBNFSFTPMVUJPOXJUIHFUBEESJOGP  JTDPNQMFUF  OPUJGZJUUPUIFNBJOUISFBEVTJOHBDPOEJUJPOWBSJBCMF
  88. static int rb_getaddrinfo(...) { // ... pthread_t th; if (do_pthread_create(&th,

    do_getaddrinfo, arg) != 0) { free_getaddrinfo_arg(arg); return EAI_AGAIN; } pthread_detach(th); rb_thread_call_without_gvl2(wait_getaddrinfo, arg, cancel_getaddrinfo, arg); // ... } *OUFSSVQUJCMFHFUBEESJOGP*NQMFNFOUBUJPO BTPG3VCZ IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUSBEESJOGPD *OBOFOWJSPONFOUXIFSFUIFQUISFBEMJCSBSZJTBWBJMBCMF *OUIFNBJOUISFBE JUXBJUTVOUJMBOPUJ fi DBUJPOBSSJWFT POUIFDPOEJUJPOWBSJBCMF 8BJUGPSOPUJ fi DBUJPOUPUIFDPOEJUJPOWBSJBCMF
  89. static int rb_getaddrinfo(...) { // ... pthread_t th; if (do_pthread_create(&th,

    do_getaddrinfo, arg) != 0) { free_getaddrinfo_arg(arg); return EAI_AGAIN; } pthread_detach(th); rb_thread_call_without_gvl2(wait_getaddrinfo, arg, cancel_getaddrinfo, arg); // ... } *OUFSSVQUJCMFHFUBEESJOGP*NQMFNFOUBUJPO BTPG3VCZ IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUSBEESJOGPD *OBOFOWJSPONFOUXIFSFUIFQUISFBEMJCSBSZJTBWBJMBCMF %FUFDUTBDPNQMFUJPOPGOBNFSFTPMVUJPO %FUFDUTBOJOUFSSVQUJPO 5IJTDPOEJUJPOWBSJBCMFJTOPUJ fi FEOPUPOMZ XIFOOBNFSFTPMVUJPODPNQMFUFTJOBDIJMEUISFBE  CVUBMTPXIFOUIFNFUIPEJTJOUFSSVQUFE
  90. static int rb_getaddrinfo(...) { // ... pthread_t th; if (do_pthread_create(&th,

    do_getaddrinfo, arg) != 0) { free_getaddrinfo_arg(arg); return EAI_AGAIN; } pthread_detach(th); rb_thread_call_without_gvl2(wait_getaddrinfo, arg, cancel_getaddrinfo, arg); // ... } *OUFSSVQUJCMFHFUBEESJOGP*NQMFNFOUBUJPO BTPG3VCZ IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUSBEESJOGPD *OBOFOWJSPONFOUXIFSFUIFQUISFBEMJCSBSZJTBWBJMBCMF 5PCFDPOUJOVFE ⬇︎ 0ODFUIFOPUJ fi DBUJPOBSSJWFT UIFXBJUJTMJGUFE  BOEUIFTVCTFRVFOUQSPDFTTJOHJTDBSSJFEPVU CBTFEPOUIFSFBTPOUIBUUSJHHFSFEUIFOPUJ fi DBUJPO
  91. static int rb_getaddrinfo(...) { // ... pthread_t th; if (do_pthread_create(&th,

    do_getaddrinfo, arg) != 0) { free_getaddrinfo_arg(arg); return EAI_AGAIN; } pthread_detach(th); rb_thread_call_without_gvl2(wait_getaddrinfo, arg, cancel_getaddrinfo, arg); // ... } *OUFSSVQUJCMFHFUBEESJOGP*NQMFNFOUBUJPO BTPG3VCZ IUUQTHJUIVCDPNSVCZSVCZCMPCSVCZ@@FYUTPDLFUSBEESJOGPD *OBOFOWJSPONFOUXIFSFUIFQUISFBEMJCSBSZJTBWBJMBCMF 5PCFDPOUJOVFE ⬇︎ 8JUIUIBUJONJOE MFUTHFUCBDLUPUIFNBJOUPQJD
  92. 5$14PDLFUOFX  ➡︎ UDQ@JOJU  ➡︎ STPDL@JOJU@JOFUTPDL  ➡︎ JOJU@JOFUTPDL@JOUFSOBM

     ➡︎ STPDL@BEESJOGPɹ  ➡︎ STPDL@HFUBEESJOGP  ➡︎ SC@HFUBEESJOGP  ➡︎  5IFDBMMTUBDLPG5$14PDLFUOFX 3VCZ *OUFSSVQUJCMFOBNFSFTPMVUJPO *O5$14PDLFUOFX  SC@BEESJOGPJTBMTPVTFEGPSOBNFSFTPMVUJPO 4UBSUOBNFSFTPMVUJPO
  93. 5$14PDLFUOFX  ➡︎ UDQ@JOJU  ➡︎ STPDL@JOJU@JOFUTPDL  ➡︎ JOJU@JOFUTPDL@JOUFSOBM

     ➡︎ STPDL@BEESJOGPɹ  ➡︎ STPDL@HFUBEESJOGP  ➡︎ SC@HFUBEESJOGP  ➡︎  5IFDBMMTUBDLPG5$14PDLFUOFX 3VCZ 5IFQSPCMFNJTUIBUSC@HFUBEESJOGPJTOPUEFTJHOFE GPS)&W Not for HEv2 ...
  94. 4QFDJ fi DBUJPO%J ff FSFODF 5IFOVNCFSPGDIJMEUISFBETTQBXOFE SC@HFUBEESJOGP $SFBUFDIJMEUISFBE 'VODUJPOGPS5$14PDLFUOFX $SFBUFrDIJMEUISFBET

    POFGPSFBDIBEESFTTGBNJMZ SC@HFUBEESJOGPWT5$14PDLFUOFXXJUI)&W SC@HFUBEESJOGP 4QBXODIJMEUISFBE  EPFTOPUTQFDJGZ BOBEESFTTGBNJMZEVSJOH OBNFSFTPMVUJPO 5$14PDLFUOFXGPS)&W 4QBXOrDIJMEUISFBET  POFGPSFBDIBEESFTTGBNJMZ
  95. 4QFDJ fi DBUJPO%J ff FSFODF %FUFDUJOHOBNFSFTPMVUJPODPNQMFUJPO 5$14PDLFUOFXGPS)&W 6TJOHBQJQFBOETFMFDU  

    #FDBVTFJUOFFETUPXBJUOPU POMZGPSOBNFSFTPMVUJPOCVU BMTPGPSTPDLFUTBUUFNQUJOH UPDPOOFDU SC@HFUBEESJOGP 6TJOHBDPOEJUJPOWBSJBCMF SC@HFUBEESJOGPWT5$14PDLFUOFXXJUI)&W
  96. <#FGPSF>5IF5$14PDLFUOFXJNQMFNFOUBUJPO 5$14PDLFUOFX  ➡︎ UDQ@JOJU  ➡︎ STPDL@JOJU@JOFUTPDL  ➡︎

    JOJU@JOFUTPDL@JOUFSOBM  ➡︎ STPDL@BEESJOGPɹ  ➡︎ STPDL@HFUBEESJOGP  ➡︎ SC@HFUBEESJOGP  ➡︎  )FSFJTUIFDBMMTUBDLPG5$14PDLFUOFX CFGPSFUIFDIBOHF
  97. 5$14PDLFUOFX  ➡︎ UDQ@JOJU  ➡︎ STPDL@JOJU@JOFUTPDL  ➡︎ JOJU@GBTU@GBMMCBDL@JOFUTPDL@JOUFSOBM

     ➡︎ SBEESJOGP@QUISFBE@DSFBUF  ➡︎ EP@GBTU@GBMMCBDL@HFUBEESJOGPɹ  ➡︎ SC@UISFBE@DBMM@XJUIPVU@HWM  ➡︎ XBJU@GBTU@GBMMCBDLDBODFM@GBTU@GBMMCBDL  ➡︎  "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM )FSFJTUIFDBMMTUBDLPG5$14PDLFUOFX BGUFSUIFDIBOHF <"GUFS>5IF5$14PDLFUOFXJNQMFNFOUBUJPO
  98. 5$14PDLFUOFX  ➡︎ UDQ@JOJU  ➡︎ STPDL@JOJU@JOFUTPDL  ➡︎ JOJU@GBTU@GBMMCBDL@JOFUTPDL@JOUFSOBM

     ➡︎ SBEESJOGP@QUISFBE@DSFBUF  ➡︎ EP@GBTU@GBMMCBDL@HFUBEESJOGPɹ  ➡︎ SC@UISFBE@DBMM@XJUIPVU@HWM  ➡︎ XBJU@GBTU@GBMMCBDLDBODFM@GBTU@GBMMCBDL  ➡︎  <"GUFS>5IF5$14PDLFUOFXJNQMFNFOUBUJPO "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM Attention!
  99. *OUIFNBJOUISFBE static VALUE init_fast_fallback_inetsock_internal(VALUE v) { // ... if (raddrinfo_pthread_create(...,

    do_fast_fallback_getaddrinfo, ...) != 0) { rsock_raise_resolution_error("getaddrinfo(3)", EAI_AGAIN); } pthread_detach(threads[i]); // ... } *OTJEFJOJU@GBTU@GBMMCBDL@JOFUTPDL@JOUFSOBM  BOFXUISFBEJTDSFBUFEBOEEFUBDIFE GPSFBDIBEESFTTGBNJMZ "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM BOEEFUBDIJU $SFBUFBOFXUISFBE
  100. *OUIFNBJOUISFBE static VALUE init_fast_fallback_inetsock_internal(VALUE v) { // ... if (raddrinfo_pthread_create(...,

    do_fast_fallback_getaddrinfo, ...) != 0) { // ... } pthread_detach(threads[i]); // ... } *OTJEFFBDIPGUIFEFUBDIFEDIJMEUISFBET HFUBEESJOGP  JTDBMMFE $BMMJOUIFUISFBE "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM void *do_fast_fallback_getaddrinfo(void *ptr) { // ... int err, gai_errno; err = getaddrinfo(...); // ... } $BMMHFUBEESJOGP  
  101. *OUIFNBJOUISFBE static VALUE init_fast_fallback_inetsock_internal(VALUE v) { // ... if (raddrinfo_pthread_create(...,

    do_fast_fallback_getaddrinfo, ...) != 0) { // ... } pthread_detach(threads[i]); // ... } 0ODFOBNFSFTPMVUJPOJTDPNQMFUF  BOPUJ fi DBUJPOJTTFOUUPUIFQJQFTIBSFEXJUI UIFNBJOUISFBE $BMMJOUIFUISFBE "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM void *do_fast_fallback_getaddrinfo(void *ptr) { // ... write(shared->notify, &notification, strlen(&notification)); // ... } 8SJUFUIFOPUJGZUPUIFQJQF
  102. *OUIFNBJOUISFBE static VALUE init_fast_fallback_inetsock_internal(VALUE v) { // ... if (raddrinfo_pthread_create(...,

    do_fast_fallback_getaddrinfo, ...) != 0) { rsock_raise_resolution_error("getaddrinfo(3)", EAI_AGAIN); } pthread_detach(threads[i]); // ... rb_thread_call_without_gvl2( wait_fast_fallback, &wait_arg, cancel_fast_fallback, arg->getaddrinfo_shared ); // ... } .FBOXIJMF JOUIFNBJOUISFBE DBMMBGVODUJPOUPXBJU GPSCPUIOBNFSFTPMVUJPOPSBDPOOFDUJPOUPDPNQMFUF 8BJUGPSCPUIDPOOFDUJPODPNQMFUJPO BOEOBNFSFTPMVUJPO 5PCFDPOUJOVFE ⬇︎ "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM
  103. 8BJUJOHGPSCPUIDPOOFDUJPOBOEOBNFSFTPMVUJPO static void * wait_fast_fallback(void *ptr) { struct wait_fast_fallback_arg *arg

    = (struct wait_fast_fallback_arg *)ptr; int status; status = select(arg->nfds, arg->readfds, arg->writefds, NULL, arg->delay); arg->status = status; if (errno == EINTR) *arg->cancelled = true; return 0; } *OUIFXBJUJOHGVODUJPO DBMMTFMFDU  UPNPOJUPSCPUI UIFQJQFXBJUJOHGPSOBNFSFTPMVUJPOOPUJ fi DBUJPOBOE UIFTPDLFUTDVSSFOUMZBUUFNQUJOHUPDPOOFDU "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM
  104. static void * wait_fast_fallback(void *ptr) { struct wait_fast_fallback_arg *arg =

    (struct wait_fast_fallback_arg *)ptr; int status; status = select(arg->nfds, arg->readfds, arg->writefds, NULL, arg->delay); arg->status = status; if (errno == EINTR) *arg->cancelled = true; return 0; } TFMFDU  VOCMPDLTXIFOFJUIFSBOBNFSFTPMVUJPO DPNQMFUJPOOPUJ fi DBUJPOBSSJWFTPOUIFQJQF BOZPGUIF TPDLFUTDVSSFOUMZBUUFNQUJOHUPDPOOFDUCFDPNF XSJUBCMF PSUIFXBJUUJNFFYDFFETUIFUJNFPVU "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM 8BJUJOHGPSCPUIDPOOFDUJPOBOEOBNFSFTPMVUJPO *ODMVEFTUIFQJQF *ODMVEFTUIFTPDLFUTBUUFNQUJOHUPDPOOFDU
  105. static void * wait_fast_fallback(void *ptr) { struct wait_fast_fallback_arg *arg =

    (struct wait_fast_fallback_arg *)ptr; int status; status = select(arg->nfds, arg->readfds, arg->writefds, NULL, arg->delay); arg->status = status; if (errno == EINTR) *arg->cancelled = true; return 0; } *OTIPSU UIJTTFMFDU  QFSGPSNTUIFTBNFSPMFBTUIF *0TFMFDUJOUIF4PDLFUUDQJNQMFNFOUBUJPO "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM 8BJUJOHGPSCPUIDPOOFDUJPOBOEOBNFSFTPMVUJPO
  106. 5$14PDLFUOFX  ➡︎ UDQ@JOJU  ➡︎ STPDL@JOJU@JOFUTPDL  ➡︎ JOJU@GBTU@GBMMCBDL@JOFUTPDL@JOUFSOBM

     ➡︎ SBEESJOGP@QUISFBE@DSFBUF  ➡︎ EP@GBTU@GBMMCBDL@HFUBEESJOGPɹ  ➡︎ SC@UISFBE@DBMM@XJUIPVU@HWM  ➡︎ XBJU@GBTU@GBMMCBDLDBODFM@GBTU@GBMMCBDL  ➡︎  $BMM4UBDLPG5$14PDLFUOFXXJUI)&W "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM "OBNFSFTPMVUJPOGVODUJPO JOUIFDIJMEUISFBE 4QBXOBOFXDIJMEUISFBE 8BJUJOUIFNBJOUISFBE 5IJTJNQMFNFOUBUJPOBMTPSFRVJSFTUIFQUISFBEMJCSBSZ 5$14PDLFUOFXXJUI)&WJTPOMZJOFOWJSPONFOUT XIFSFQUISFBEJTBWBJMBCMFBOECFIBWFTBTJUBMXBZT IBTPOQMBUGPSNTMJLF8JOEPXT
  107. 5FTU/FU)551@W@@DIVOLFEUFTU@UJNFPVU@EVSJOH@)551@TFTTJPO@XSJUF def test_timeout_during_HTTP_session_write th = nil TCPServer.open('localhost', 0) {|server| port

    = server.addr[1] conn = Net::HTTP.new('localhost', port) conn.write_timeout = EnvUtil.apply_timeout_scale(0.01) conn.open_timeout = EnvUtil.apply_timeout_scale(0.1) th = Thread.new do assert_raise(Net::WriteTimeout) do assert_warning(/Content-Type did not set/) do conn.post('/', "a"*50_000_000) end end end assert th.join(EnvUtil.apply_timeout_scale(10)) } # ... end UFTUOFUIUUQUFTU@IUUQSC "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM 5IF8JOEPXTTQFDJ fi DQBSUTBSFPNJUUFE
  108. 5FTU/FU)551@W@@DIVOLFEUFTU@UJNFPVU@EVSJOH@)551@TFTTJPO@XSJUF def test_timeout_during_HTTP_session_write th = nil TCPServer.open('localhost', 0) {|server| port

    = server.addr[1] conn = Net::HTTP.new('localhost', port) conn.write_timeout = EnvUtil.apply_timeout_scale(0.01) conn.open_timeout = EnvUtil.apply_timeout_scale(0.1) th = Thread.new do assert_raise(Net::WriteTimeout) do assert_warning(/Content-Type did not set/) do conn.post('/', "a"*50_000_000) end end end assert th.join(EnvUtil.apply_timeout_scale(10)) } # ... end *OUIJTUFTU BTFSWFSJT fi STUTUBSUFEPOMPDBMIPTU 4UBSUB5$1TFSWFS UFTUOFUIUUQUFTU@IUUQSC "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM 5IF8JOEPXTTQFDJ fi DQBSUTBSFPNJUUFE
  109. 5FTU/FU)551@W@@DIVOLFEUFTU@UJNFPVU@EVSJOH@)551@TFTTJPO@XSJUF def test_timeout_during_HTTP_session_write th = nil TCPServer.open('localhost', 0) {|server| port

    = server.addr[1] conn = Net::HTTP.new('localhost', port) conn.write_timeout = EnvUtil.apply_timeout_scale(0.01) conn.open_timeout = EnvUtil.apply_timeout_scale(0.1) th = Thread.new do assert_raise(Net::WriteTimeout) do assert_warning(/Content-Type did not set/) do conn.post('/', "a"*50_000_000) end end end assert th.join(EnvUtil.apply_timeout_scale(10)) } # ... end 5IFO UIFDMJFOUTUJNFPVUWBMVFTBSFTFU BXSJUFUJNFPVUPGNT BOEBDPOOFDUUJNFPVUPGNT XSJUFUJNFPVUNT DPOOFDUUJNFPVUNT UFTUOFUIUUQUFTU@IUUQSC "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM 5IF8JOEPXTTQFDJ fi DQBSUTBSFPNJUUFE
  110. 5FTU/FU)551@W@@DIVOLFEUFTU@UJNFPVU@EVSJOH@)551@TFTTJPO@XSJUF def test_timeout_during_HTTP_session_write th = nil TCPServer.open('localhost', 0) {|server| port

    = server.addr[1] conn = Net::HTTP.new('localhost', port) conn.write_timeout = EnvUtil.apply_timeout_scale(0.01) conn.open_timeout = EnvUtil.apply_timeout_scale(0.1) th = Thread.new do assert_raise(Net::WriteTimeout) do assert_warning(/Content-Type did not set/) do conn.post('/', "a"*50_000_000) end end end assert th.join(EnvUtil.apply_timeout_scale(10)) } # ... end 5IFDMJFOUUIFOTUBSUTBDPOOFDUJPOUPUIFTFSWFS 4UBSUBOFXDPOOFDUJPO UFTUOFUIUUQUFTU@IUUQSC "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM 5IF8JOEPXTTQFDJ fi DQBSUTBSFPNJUUFE
  111. def test_timeout_during_HTTP_session_write th = nil TCPServer.open('localhost', 0) {|server| port =

    server.addr[1] conn = Net::HTTP.new('localhost', port) conn.write_timeout = EnvUtil.apply_timeout_scale(0.01) conn.open_timeout = EnvUtil.apply_timeout_scale(0.1) th = Thread.new do assert_raise(Net::WriteTimeout) do assert_warning(/Content-Type did not set/) do conn.post('/', "a"*50_000_000) end end end assert th.join(EnvUtil.apply_timeout_scale(10)) } # ... end 5FTU/FU)551@W@@DIVOLFEUFTU@UJNFPVU@EVSJOH@)551@TFTTJPO@XSJUF 4FOEBWFSZMPOHTUSJOH *GUIFDPOOFDUJPOJTTVDDFTTGVM  JUBUUFNQUTUPTFOEBWFSZMPOHTUSJOH BTBSFRVFTUNFTTBHFUPUIFTFSWFS UFTUOFUIUUQUFTU@IUUQSC "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM 5IF8JOEPXTTQFDJ fi DQBSUTBSFPNJUUFE
  112. 5FTU/FU)551@W@@DIVOLFEUFTU@UJNFPVU@EVSJOH@)551@TFTTJPO@XSJUF def test_timeout_during_HTTP_session_write th = nil TCPServer.open('localhost', 0) {|server| port

    = server.addr[1] conn = Net::HTTP.new('localhost', port) conn.write_timeout = EnvUtil.apply_timeout_scale(0.01) conn.open_timeout = EnvUtil.apply_timeout_scale(0.1) th = Thread.new do assert_raise(Net::WriteTimeout) do assert_warning(/Content-Type did not set/) do conn.post('/', "a"*50_000_000) end end end assert th.join(EnvUtil.apply_timeout_scale(10)) } # ... end 5IFFYQFDUBUJPOJTUIBUEVSJOHUIFTFOE NTXJMM QBTTBOE/FU8SJUF5JNFPVUBTBXSJUFUJNFPVU XJMMCFSBJTFE UFTUOFUIUUQUFTU@IUUQSC "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM 5IF8JOEPXTTQFDJ fi DQBSUTBSFPNJUUFE
  113. /PU/FU8SJUF5JNFPVU CVU/FU0QFO5JNFPVU *OUIFGBJMJOHUFTU  /FU0QFO5JNFPVUPDDVSTXIFSF/FU8SJUF5JNFPVUJTFYQFDUFE 5IJTJOEJDBUFTUIBUUIFUJNFPVUJTIBQQFOJOHEVSJOHUIFDPOOFDUJPO BUUFNQU CFGPSFUIFXSJUFFWFOCFHJOT > 1)

    Failure: > TestNetHTTP_v1_2_chunked#test_timeout_during_HTTP_session_write > [/.../ruby/test/net/http/test_http.rb:572]: > [Net::WriteTimeout] exception expected, > not #<Net::OpenTimeout: Failed to open TCP connection to ...>.
  114. /FU)551DPOOFDU def connect # ... s = Timeout.timeout(@open_timeout, Net::OpenTimeout) {

    begin TCPSocket.open(conn_addr, conn_port, @local_host, @local_port) rescue => e # ... end } # ... end private :connect MJCOFUIUUQSC "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM -FUTUBLFBMPPLBU/FU)551 5IFNFUIPESFTQPOTJCMFGPSBUUFNQUJOH B5$1DPOOFDUJPOJT/FU)551DPOOFDU 5$14PDLFUPQFO BOBMJBTGPS5$14PDLFUOFXTUBSUTBDPOOFDUJPO
  115. /FU)551DPOOFDU def connect # ... s = Timeout.timeout(@open_timeout, Net::OpenTimeout) {

    begin TCPSocket.open(conn_addr, conn_port, @local_host, @local_port) rescue => e # ... end } # ... end private :connect )FSF UJNFPVUHFNJTVTFEUPNBOBHFUIFDPOOFDUJPO UJNFPVU*GUIFUJNFUBLFOGPSUIFDPOOFDUJPOBUUFNQU FYDFFETUIFTQFDJ fi FEUJNFPVUWBMVF  /FU0QFO5JNFPVUJTSBJTFE .BOBHFUJNFPVU /FU0QFO5JNFPVUXJUIDPOOFDUUJNFPVU MJCOFUIUUQSC "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM
  116. /FU)551DPOOFDU def connect # ... s = Timeout.timeout(@open_timeout, Net::OpenTimeout) {

    begin TCPSocket.open(conn_addr, conn_port, @local_host, @local_port) rescue => e # ... end } # ... end private :connect 5IJTDPEFBOEUIFUFTUXFSFXPSLJOHBTFYQFDUFE CFGPSF)&WXBTJOUSPEVDFE4PXIBU`THPJOHPOOPX def test_timeout_during_HTTP_session_write th = nil TCPServer.open('localhost', 0) {|server| # ... conn.open_timeout = EnvUtil.apply_timeout_scale(0.1) # ... } # ... end UFTUOFUIUUQUFTU@IUUQSC MJCOFUIUUQSC "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM
  117. def test_timeout_during_HTTP_session_write th = nil TCPServer.open('localhost', 0) {|server| port =

    server.addr[1] conn = Net::HTTP.new('localhost', port) conn.write_timeout = EnvUtil.apply_timeout_scale(0.01) conn.open_timeout = EnvUtil.apply_timeout_scale(0.1) th = Thread.new do assert_raise(Net::WriteTimeout) do assert_warning(/Content-Type did not set/) do conn.post('/', "a"*50_000_000) end end end assert th.join(EnvUtil.apply_timeout_scale(10)) } # ... end "OTXFSJOHUIFRVFTUJPO8IZJTUIFUFTUGBJMJOH -FU`TUBLFMPPLBUUIFUFTUDPEFBHBJO 5IFTFSWFSJTTUBSUFECZQBTTJOHMPDBMIPTU UP5$14FSWFSOFX 4UBSUB5$1TFSWFS XJUIIPTUOBNFMPDBMIPTU UFTUOFUIUUQUFTU@IUUQSC "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM 5IF8JOEPXTTQFDJ fi DQBSUTBSFPNJUUFE
  118. def test_timeout_during_HTTP_session_write th = nil TCPServer.open('localhost', 0) {|server| port =

    server.addr[1] conn = Net::HTTP.new('localhost', port) conn.write_timeout = EnvUtil.apply_timeout_scale(0.01) conn.open_timeout = EnvUtil.apply_timeout_scale(0.1) th = Thread.new do assert_raise(Net::WriteTimeout) do assert_warning(/Content-Type did not set/) do conn.post('/', "a"*50_000_000) end end end assert th.join(EnvUtil.apply_timeout_scale(10)) } # ... end *OUIFCBDLHSPVOE UIFTFSWFSSFTPMWFTUIFIPTUOBNF MPDBMIPTUBOECJOETJUTMJTUFOJOHTPDLFU UPPOFPGUIFSFTPMWFEBEESFTTFT CJOE 0OFPGUIFSFTPMWFEBEESFTTFT "MJTUFOJOHTPDLFU 4FSWFS "OTXFSJOHUIFRVFTUJPO8IZJTUIFUFTUGBJMJOH UFTUOFUIUUQUFTU@IUUQSC "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM 5IF8JOEPXTTQFDJ fi DQBSUTBSFPNJUUFE
  119. def test_timeout_during_HTTP_session_write th = nil TCPServer.open('localhost', 0) {|server| port =

    server.addr[1] conn = Net::HTTP.new('localhost', port) conn.write_timeout = EnvUtil.apply_timeout_scale(0.01) conn.open_timeout = EnvUtil.apply_timeout_scale(0.1) th = Thread.new do assert_raise(Net::WriteTimeout) do assert_warning(/Content-Type did not set/) do conn.post('/', "a"*50_000_000) end end end assert th.join(EnvUtil.apply_timeout_scale(10)) } # ... end 0OBEVBMTUBDLIPTU UIFTFSWFSCJOETUP FJUIFS *1W PS *1W  EFQFOEJOHPOXIJDIPOFJTSFTPMWFE fi STU  "MJTUFOJOHTPDLFU 4FSWFS  PS 8IJDIFWFSSFTPMWFT fi STU CJOE 8IFUIFS*1WPS*1WHFUTSFTPMWFE fi STU EFQFOETPOUIF04BOEOFUXPSLTFUUJOHT "OTXFSJOHUIFRVFTUJPO8IZJTUIFUFTUGBJMJOH UFTUOFUIUUQUFTU@IUUQSC "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM 5IF8JOEPXTTQFDJ fi DQBSUTBSFPNJUUFE
  120. def test_timeout_during_HTTP_session_write th = nil TCPServer.open('localhost', 0) {|server| port =

    server.addr[1] conn = Net::HTTP.new('localhost', port) conn.write_timeout = EnvUtil.apply_timeout_scale(0.01) conn.open_timeout = EnvUtil.apply_timeout_scale(0.1) th = Thread.new do assert_raise(Net::WriteTimeout) do assert_warning(/Content-Type did not set/) do conn.post('/', "a"*50_000_000) end end end assert th.join(EnvUtil.apply_timeout_scale(10)) } # ... end *OUIFFOWJSPONFOUXIFSFUIFUFTUXBTGBJMJOH  UIFTFSWFSFOEFEVQCJOEJOHUP *1W   "MJTUFOJOHTPDLFU 4FSWFS *OUIFFOWJSPONFOU XIFSFUIFUFTUXBTGBJMJOH CJOE "OTXFSJOHUIFRVFTUJPO8IZJTUIFUFTUGBJMJOH UFTUOFUIUUQUFTU@IUUQSC "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM 5IF8JOEPXTTQFDJ fi DQBSUTBSFPNJUUFE
  121. def test_timeout_during_HTTP_session_write th = nil TCPServer.open('localhost', 0) {|server| port =

    server.addr[1] conn = Net::HTTP.new('localhost', port) conn.write_timeout = EnvUtil.apply_timeout_scale(0.01) conn.open_timeout = EnvUtil.apply_timeout_scale(0.1) th = Thread.new do assert_raise(Net::WriteTimeout) do assert_warning(/Content-Type did not set/) do conn.post('/', "a"*50_000_000) end end end assert th.join(EnvUtil.apply_timeout_scale(10)) } # ... end UFTUOFUIUUQUFTU@IUUQSC "TPG13IUUQTHJUIVCDPNSVCZSVCZQVMM 5IJTNFBOTUIBUXIJMFXBJUJOHGPSUIFNT $POOFDUJPO"UUFNQU%FMBZ UIFNT DPOOFDUUJNFPVUXBTCFJOHUSJHHFSFE DPOOFDUUJNFPVUNT "OTXFSJOHUIFRVFTUJPO8IZJTUIFUFTUGBJMJOH 5IFNTUJNFPVUFYQJSFTEVSJOHUIFNTXBJU 5IF8JOEPXTTQFDJ fi DQBSUTBSFPNJUUFE
  122. 3FTPMWJOHUIFUJNFPVUJTTVF if (status > 0) { /* check for connection

    */ if (in_progress_fds(arg->connection_attempt_fds_size)) { for (/* If there are sockets with a confirmed connection state */) { // Check for connection } if (connected_fd >= 0) break; if (!in_progress_fds(arg->connection_attempt_fds_size)) { if (/* No address candidates available and finished name resolution */) { // Raise an error and exit } connection_attempt_delay_expires_at = NULL; user_specified_connect_timeout_at = NULL; } } // ... FYUTPDLFUJQTPDLFUD 4P *SFTFUDPOOFDUJPO@BUUFNQU@EFMBZ@BUXIFOBMM QSFWJPVTDPOOFDUJPOBUUFNQUTIBWFGBJMFE BMMPXJOHUIF OFYUDPOOFDUJPOUPTUBSUXJUIPVUXBJUJOHNT 3FTFUDPOOFDUJPO@BUUFNQU@EFMBZ@FYQJSFT@BU 5IFSFJTOPTVDDFTTGVMMZDPOOFDUFETPDLFU  BOEOPTPDLFUDVSSFOUMZBUUFNQUJOHUPDPOOFDU
  123. "OJTTVFSFQPSUFECZ!KIBXUIPSO require "socket" open_fds = [] loop do file =

    open(__FILE__) open_fds << file break if file.fileno >= 1010 end TCPServer.open("localhost", 0) do |server| port = server.addr[1] sockets = [] 50.times do |i| socket = TCPSocket.open("localhost", port) p socket sockets << socket end end IUUQTCVHTSVCZMBOHPSHJTTVFT 3FQSPEVDUJPODPEFCZ!KIBXUIPSO
  124. "OJTTVFSFQPSUFECZ!KIBXUIPSO require "socket" open_fds = [] loop do file =

    open(__FILE__) open_fds << file break if file.fileno >= 1010 end TCPServer.open("localhost", 0) do |server| port = server.addr[1] sockets = [] 50.times do |i| socket = TCPSocket.open("localhost", port) p socket sockets << socket end end IUUQTCVHTSVCZMBOHPSHJTTVFT 3FQSPEVDUJPODPEFCZ!KIBXUIPSO 0QFOFOPVHI fi MFTJOBEWBODFTPUIBU UIFUPUBMOVNCFSPGGETDPNFTDMPTF UPUIFTZTUFN`T'%@4&54*;&MJNJU
  125. "OJTTVFSFQPSUFECZ!KIBXUIPSO require "socket" open_fds = [] loop do file =

    open(__FILE__) open_fds << file break if file.fileno >= 1010 end TCPServer.open("localhost", 0) do |server| port = server.addr[1] sockets = [] 50.times do |i| socket = TCPSocket.open("localhost", port) p socket sockets << socket end end IUUQTCVHTSVCZMBOHPSHJTTVFT 3FQSPEVDUJPODPEFCZ!KIBXUIPSO 4UBSUBTFSWFS
  126. "OJTTVFSFQPSUFECZ!KIBXUIPSO require "socket" open_fds = [] loop do file =

    open(__FILE__) open_fds << file break if file.fileno >= 1010 end TCPServer.open("localhost", 0) do |server| port = server.addr[1] sockets = [] 50.times do |i| socket = TCPSocket.open("localhost", port) p socket sockets << socket end end IUUQTCVHTSVCZMBOHPSHJTTVFT 3FQSPEVDUJPODPEFCZ!KIBXUIPSO 4UBSUTFWFSBMOFXDPOOFDUJPOTUP UIFTFSWFSVTJOH5$14PDLFUPQFO 5$14PDLFUOFX
  127. "OJTTVFSFQPSUFECZ!KIBXUIPSO require "socket" open_fds = [] loop do file =

    open(__FILE__) open_fds << file break if file.fileno >= 1010 end TCPServer.open("localhost", 0) do |server| port = server.addr[1] sockets = [] 50.times do |i| socket = TCPSocket.open("localhost", port) p socket sockets << socket end end IUUQTCVHTSVCZMBOHPSHJTTVFT 3FQSPEVDUJPODPEFCZ!KIBXUIPSO 8IFOUIFUPUBMOVNCFSPG BMSFBEZPQFOFE fi MFT UIFTPDLFUT PQFOFECZ5$14PDLFUOFX SFBDIFTFYDFFET'%@4&54*;& 4UBSUTFWFSBMOFXDPOOFDUJPOTUP UIFTFSWFSVTJOH5$14PDLFUPQFO 5$14PDLFUOFX
  128. "OJTTVFSFQPSUFECZ!KIBXUIPSO $ ulimit -n 2048 $ ruby test.rb #<TCPSocket:fd 1015,

    AF_INET6, ::1, 40622> #<TCPSocket:fd 1014, AF_INET6, ::1, 40628> #<TCPSocket:fd 1016, AF_INET6, ::1, 40630> ... ================================================================= ==3180778==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ae35aadc580 at pc 0x7ae35b1b7449 bp 0x7fffc9af1af0 sp 0x7fffc9af1ae8 READ of size 8 at 0x7ae35aadc580 thread T0 #0 0x7ae35b1b7448 in init_fast_fallback_inetsock_internal /.../ruby/ext/socket/ipsocket.c:912:17 #1 0x60462ff14879 in rb_ensure /.../ruby/eval.c:1053:18 #2 0x7ae35b1b41b9 in rsock_init_inetsock /.../ruby/ext/socket/ipsocket.c:1315:20 #3 0x7ae35b1bae9a in tcp_init /.../ruby/ext/socket/tcpsocket.c:91:12 ... IUUQTCVHTSVCZMBOHPSHJTTVFT A segmentation fault occurs!!
  129. "GVODUJPOPGUIFDBVTFPGUIFQSPCMFN static void * wait_fast_fallback(void *ptr) { struct wait_fast_fallback_arg *arg

    = (struct wait_fast_fallback_arg *)ptr; int status; status = select(arg->nfds, arg->readfds, arg->writefds, NULL, arg->delay); arg->status = status; if (errno == EINTR) *arg->cancelled = true; return 0; } 5IFDBVTFPGUIJTJTTVFXBT UIFGVODUJPOQSFWJPVTMZJOUSPEVDFE
  130. "GVODUJPOPGUIFDBVTFPGUIFQSPCMFN static void * wait_fast_fallback(void *ptr) { struct wait_fast_fallback_arg *arg

    = (struct wait_fast_fallback_arg *)ptr; int status; status = select(arg->nfds, arg->readfds, arg->writefds, NULL, arg->delay); arg->status = status; if (errno == EINTR) *arg->cancelled = true; return 0; } *OTJEFUIJTGVODUJPO DBMMTFMFDU  XBJUGPSFJUIFS OBNFSFTPMVUJPOPSBDPOOFDUJPOUPDPNQMFUF CZ NPOJUPSJOHCPUIUIFQJQFXBJUJOHGPSOBNFSFTPMVUJPO OPUJ fi DBUJPOTBOEUIFTPDLFUTBUUFNQUJOHUPDPOOFDU 5IFQJQFXBJUJOHGPSOBNFSFTPMVUJPOOPUJ fi DBUJPOT 5IFTPDLFUTXBJUJOHUPDPOOFDU
  131. static void * wait_fast_fallback(void *ptr) { struct wait_fast_fallback_arg *arg =

    (struct wait_fast_fallback_arg *)ptr; int status; status = select(arg->nfds, arg->readfds, arg->writefds, NULL, arg->delay); arg->status = status; if (errno == EINTR) *arg->cancelled = true; return 0; } "GVODUJPOPGUIFDBVTFPGUIFQSPCMFN *OBTFOTF TFMFDU  JTUIFNPTUJNQPSUBOUTZTUFNDBMM XIFOJUDPNFTUPJNQMFNFOUJOHUIF)&WTQFDJ fi DBUJPO 5IFNPTUJNQPSUBOUTZTUFNDBMMGPS)&W
  132. static void * wait_fast_fallback(void *ptr) { struct wait_fast_fallback_arg *arg =

    (struct wait_fast_fallback_arg *)ptr; int status; status = select(arg->nfds, arg->readfds, arg->writefds, NULL, arg->delay); arg->status = status; if (errno == EINTR) *arg->cancelled = true; return 0; } "GVODUJPOPGUIFDBVTFPGUIFQSPCMFN 5IFQSPCMFNJTUIBUTFMFDU  DBOOPUNPOJUPS GETOVNCFSHSFBUFSUIBO'%@4&54*;& /PUTVQQPSUFECFZPOE'%@4&54*;&
  133. TFMFDU  Š-JOVYNBOVBMQBHF IUUQTNBOPSHMJOVYNBOQBHFTNBOTFMFDUIUNM 5IJTMJNJUBUJPOJTBDUVBMMZEPDVNFOUFEJOUIFNBOVBM GPSTFMFDU  'PSFYBNQMF IFSF`TUIFSFMFWBOUTFDUJPO GSPNUIFNBOPG-JOVY

    DESCRIPTION WARNING: select() can monitor only fi le descriptors numbers that are less than FD_SETSIZE (1024)—an unreasonably low limit for many modern applications—and this limitation will not change. All modern applications should instead use poll(2) or epoll(7), which do not su ff er this limitation.
  134. TFMFDU  Š-JOVYNBOVBMQBHF IUUQTNBOPSHMJOVYNBOQBHFTNBOTFMFDUIUNM DESCRIPTION WARNING: select() can monitor only

    fi le descriptors numbers that are less than FD_SETSIZE (1024)—an unreasonably low limit for many modern applications—and this limitation will not change. All modern applications should instead use poll(2) or epoll(7), which do not su ff er this limitation.
  135. TFMFDU  Š-JOVYNBOVBMQBHF IUUQTNBOPSHMJOVYNBOQBHFTNBOTFMFDUIUNM NOTES The following header also provides

    the fd_set type: <sys/time.h>. An fd_set is a fi xed size bu ff er. Executing FD_CLR() or FD_SET() with a value of fd that is negative or is equal to or larger than FD_SETSIZE will result in unde fi ned behavior. Moreover, POSIX requires fd to be a valid fi le descriptor. '%@$-3 BOE'%@4&5 BSFNBDSPT UIBUBSFFYFDVUFECFGPSFDBMMJOHTFMFDU 
  136. TFMFDU  Š-JOVYNBOVBMQBHF IUUQTNBOPSHMJOVYNBOQBHFTNBOTFMFDUIUNM NOTES The following header also provides

    the fd_set type: <sys/time.h>. An fd_set is a fi xed size bu ff er. Executing FD_CLR() or FD_SET() with a value of fd that is negative or is equal to or larger than FD_SETSIZE will result in unde fi ned behavior. Moreover, POSIX requires fd to be a valid fi le descriptor. 5IJTJTBQSPCMFN
  137. TFMFDU  Š-JOVYNBOVBMQBHF IUUQTNBOPSHMJOVYNBOQBHFTNBOTFMFDUIUNM 5IFNBOPG-JOVYSFDPNNFOETVTJOH FJUIFSQPMM  PSFQPMM  GPSUIJTQVSQPTF

    DESCRIPTION WARNING: select() can monitor only fi le descriptors numbers that are less than FD_SETSIZE (1024)—an unreasonably low limit for many modern applications—and this limitation will not change. All modern applications should instead use poll(2) or epoll(7), which do not su ff er this limitation.
  138. TFMFDU  Š-JOVYNBOVBMQBHF DESCRIPTION WARNING: select() can monitor only fi

    le descriptors numbers that are less than FD_SETSIZE (1024)—an unreasonably low limit for many modern applications—and this limitation will not change. All modern applications should instead use poll(2) or epoll(7), which do not su ff er this limitation. IUUQTNBOPSHMJOVYNBOQBHFTNBOTFMFDUIUNM FQPMM  JTBO"1*TQFDJ fi DUP-JOVYFOWJSPONFOUT 4JODF5$14PDLFUOFXXJUI)&WJTJOUFOEFEUPXPSLPO BMMFOWJSPONFOUTXIFSFQUISFBETBSFBWBJMBCMF DIPPTJOH QPMM  JTUIFNPSFSFBTPOBCMFPQUJPOJOUIJTDBTF
  139. 4PMWJOHUIFTFMFDU  QSPCMFN *MPPLFEJOUPXIFUIFS TFMFDU  DPVMECFSFQMBDFEXJUIQPMM  CZFYBNJOJOH UIFEJ

    ff FSFODFTCFUXFFOUIFTFTZTUFNDBMMT "TBSFTVMU *GPVOEUIBUUIFJSEJ ff FSFODFTBSFBTGPMMPXT
  140. 5IFEJ ff FSFODFTCFUXFFOTFMFDU  BOEQPMM  'VODUJPOTJHOBUVSFT int poll( struct

    pollfd *fds, nfds_t nfds, int timeout ); int select( int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *utimeout );
  141. 5IFEJ ff FSFODFTCFUXFFOTFMFDU  BOEQPMM  5ZQFTPGUBSHFUTUIFZDBONPOJUPS int poll( struct

    pollfd *fds, nfds_t nfds, int timeout ); int select( int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *utimeout ); +VTUTPNFGE@TFUT struct pollfd { int fd; short events; short revents:
 };
  142. 5IFEJ ff FSFODFTCFUXFFOTFMFDU  BOEQPMM  5ZQFTPGFWFOUTUIFZDBONPOJUPS ɾPOLLIN ɾPOLLOUT ɾPOLLERR

    ɾPOLLHUP ɾPOLNVAL ɾreadfds ɾwritefds ɾexceptfds int poll( struct pollfd *fds, nfds_t nfds, int timeout ); int select( int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *utimeout );
  143. 5IFEJ ff FSFODFTCFUXFFOTFMFDU  BOEQPMM  )PXUPTQFDJGZUIFGETUPNPOJUPS int fd; fd_set

    set; FD_ZERO(&set); FD_SET(fd, &set); int fd; struct pollfd fds[1]; fds[0].fd = fd; fds[0].events = POLLIN | POLLOUT; int poll( struct pollfd *fds, nfds_t nfds, int timeout ); int select( int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *utimeout );
  144. 5IFEJ ff FSFODFTCFUXFFOTFMFDU  BOEQPMM  5JNFPVUSFTPMVUJPO NJMMJTFDPOET struct timeval

    { time_t tv_sec; suseconds_t tv_usec
 }; int poll( struct pollfd *fds, nfds_t nfds, int timeout ); int select( int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *utimeout );
  145. 5IFEJ ff FSFODFTCFUXFFOTFMFDU  BOEQPMM  $PODMVTJPO 1SFUUZNVDIFWFSZUIJOHJTEJ ff FSFOU

    ➡︎ 4JHOJ fi DBOUBNPVOUPGDPEFXJMMOFFEUPCFSFXSJUUFO ɹ5IFQSPCMFNJT JU`TBMSFBEZ%FDFNCFSUI ɹ -FTTUIBOEBZTMFGUVOUJMUIFSFMFBTFPG3VCZ  *`EMJLFUPIBWFUIFDIBOHFTNFSHFEBOEUIFOMFU3VCZ$* SVOGPSBEFDFOUBNPVOUPGUJNFUPNPOJUPSUIFSFTVMUT
  146. class Socket # ... def self.tcp(...) # ... hostname_resolved, writable_sockets,

    except_sockets = IO.select( hostname_resolution_notifier, connecting_sockets.keys, is_windows_environment ? connecting_sockets.keys : nil, second_to_timeout(current_clock_time, ends_at), ) # ... end # ... end *O4PDLFUUDQ *0TFMFDUJTVTFEUPXBJUGPS OBNFSFTPMVUJPOBOEDPOOFDUJPODPNQMFUJPO 4PIPXJTJUIBOEMFEJO4PDLFUUDQ )PXJTJUIBOEMFEJO4PDLFUUDQ
  147. void Init_IO(void) { // ... rb_cIO = rb_define_class("IO", rb_cObject); //

    ... rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1); // ... } 5IFJOUFSOBMJNQMFNFOUBUJPOPG*0TFMFDU JPD *GPVOEUIBU*0TFMFDUJTJNQMFNFOUFEJOUFSOBMMZ JO3VCZBTSC@G@TFMFDU %F fi OFSC@G@TFMFDUBT*0TFMFDU %F fi OF*0DMBTT
  148. $BMM4UBDLPG*0TFMFDU *0TFMFDU  ➡︎ SC@G@TFMFDU  ➡︎ SC@FOTVSF  ➡︎

    TFMFDU@DBMM  ➡︎ TFMFDU@JOUFSOBM  ➡︎ SC@UISFBE@GE@TFMFDU  ➡︎ TFMFDU@FOE 5IFJOUFSOBMJNQMFNFOUBUJPOPG*0TFMFDU 5IJTGVODUJPODBMMTSC@UISFBE@GE@TFMFDU  BOJOUFSOBM3VCZGVODUJPO
  149. int rb_thread_fd_select(int max, rb_fdset_t * read, rb_fdset_t * write, rb_fdset_t

    * except, struct timeval *timeout) { // ... BLOCKING_REGION(set->th, { struct timeval tv; if (!RUBY_VM_INTERRUPTED(set->th->ec)) { result = native_fd_select(set->max, set->rset, set->wset, set->eset, rb_hrtime2timeval(&tv, to), set->th); if (result < 0) lerrno = errno; } }, ubf_select, set->th, TRUE); // ... } SC@UISFBE@GE@TFMFDUUIFODBMMTOBUJWF@GE@TFMFDU 5IFJOUFSOBMJNQMFNFOUBUJPOPG*0TFMFDU
  150. 5IFJOUFSOBMJNQMFNFOUBUJPOPG*0TFMFDU ɾUISFBE@QUISFBED 5IFEF fi OJUJPOPGOBUJWF@GE@TFMFDUEJ ff FST EFQFOEJOHPOXIFUIFSUIFFOWJSPONFOUTVQQPSUT QUISFBETPSJTSVOOJOHPO8JOEPXT static

    int native_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout, rb_thread_t *th) static int native_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout, rb_thread_t *th) ɾUISFBE@XJOD
  151. 5IFJOUFSOBMJNQMFNFOUBUJPOPG*0TFMFDU static int native_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t

    *exceptfds, struct timeval *timeout, rb_thread_t *th) { return rb_fd_select(n, readfds, writefds, exceptfds, timeout); } UISFBE@QUISFBED *OFOWJSPONFOUTXJUIQUISFBET  JUJOUFSOBMMZDBMMTSC@GE@TFMFDU
  152. ɾJODMVEFSVCZJOUFSOBMJOUFSOTFMFDUMBSHFTJ[FI 5IFJOUFSOBMJNQMFNFOUBUJPOPG*0TFMFDU SC@GE@TFMFDUBMTPIBTEJ ff FSFOUEF fi OJUJPOTEFQFOEJOH PO04'PSDFSUBJOWFSTJPOTPG04 JUJTEF fi

    OFEJO MBSHFTJ[FIGPSPUIFST JUJTEF fi OFEJOQPTJYI int rb_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout) #define rb_fd_select select ɾJODMVEFSVCZJOUFSOBMJOUFSOTFMFDUQPTJYI
  153. 5BSHFU04WFSTJPOTGPSMBSHFTJ[FI /** * ... * * - Linux 2.2.12 (?)

    * * - NetBSD 1.2 (src/sys/kern/sys_generic.c:1.25) * ... * - FreeBSD 2.2 (src/sys/kern/sys_generic.c:1.19) * * - OpenBSD 2.0 (src/sys/kern/sys_generic.c:1.4) * ... * - Solaris 8 has `select_large_fdset` * * - Mac OS X 10.7 (Lion) * ... */ )FSFBSFUIFMJTUPG04WFSTJPOT XIFSFUIFMBSHFTJ[FIEF fi OJUJPOJTVTFE JODMVEFSVCZJOUFSOBMJOUFSOTFMFDUMBSHFTJ[FI
  154. /** * ... * * - Linux 2.2.12 (?) *

    * - NetBSD 1.2 (src/sys/kern/sys_generic.c:1.25) * ... * - FreeBSD 2.2 (src/sys/kern/sys_generic.c:1.19) * * - OpenBSD 2.0 (src/sys/kern/sys_generic.c:1.4) * ... * - Solaris 8 has `select_large_fdset` * * - Mac OS X 10.7 (Lion) * ... */ 'PSNPTUNPEFSO DPNNPOMZVTFE04WFSTJPOT  UIFEF fi OJUJPOJOMBSHFTJ[FIJTUIFPOFUIBUHFUTVTFE 5BSHFU04WFSTJPOTGPSMBSHFTJ[FI JODMVEFSVCZJOUFSOBMJOUFSOTFMFDUMBSHFTJ[FI
  155. /** * ... * * Several Unix platforms support file

    descriptors bigger than FD_SETSIZE in * `select(2)` system call. * * ... (The target OS versions) ... * * When `fd_set` is not big enough to hold big file descriptors, it should be * allocated dynamically. Note that this assumes `fd_set` is structured as * bitmap. * * `rb_fd_init` allocates the memory. * `rb_fd_term` frees the memory. * `rb_fd_set` may re-allocate bitmap. * * So `rb_fd_set` doesn't reject file descriptors bigger than `FD_SETSIZE`. */ 8IBUMBSHFTJ[FIUFMMT )FSF`TXIBU`TXSJUUFOJOMBSHFTJ[FI JODMVEFSVCZJOUFSOBMJOUFSOTFMFDUMBSHFTJ[FI
  156. /** * ... * * Several Unix platforms support file

    descriptors bigger than FD_SETSIZE in * `select(2)` system call. * * ... (The target OS versions) ... * * When `fd_set` is not big enough to hold big file descriptors, it should be * allocated dynamically. Note that this assumes `fd_set` is structured as * bitmap. * * `rb_fd_init` allocates the memory. * `rb_fd_term` frees the memory. * `rb_fd_set` may re-allocate bitmap. * * So `rb_fd_set` doesn't reject file descriptors bigger than `FD_SETSIZE`. */ 8IBUMBSHFTJ[FIUFMMT JODMVEFSVCZJOUFSOBMJOUFSOTFMFDUMBSHFTJ[FI
  157. /** * ... * * Several Unix platforms support file

    descriptors bigger than FD_SETSIZE in * `select(2)` system call. * * ... (The target OS versions) ... * * When `fd_set` is not big enough to hold big file descriptors, it should be * allocated dynamically. Note that this assumes `fd_set` is structured as * bitmap. * * `rb_fd_init` allocates the memory. * `rb_fd_term` frees the memory. * `rb_fd_set` may re-allocate bitmap. * * So `rb_fd_set` doesn't reject file descriptors bigger than `FD_SETSIZE`. */ JODMVEFSVCZJOUFSOBMJOUFSOTFMFDUMBSHFTJ[FI 8IBUMBSHFTJ[FIUFMMT  GE@TFUTUPSFTUIF fi MFEFTDSJQUPSTUPCFNPOJUPSFE
  158. 5IFJNQMFNFOUBUJPOPGSC@GE@TFMFDU int rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds,

    struct timeval *timeout) { fd_set *r = NULL, *w = NULL, *e = NULL; if (readfds) { rb_fd_resize(n - 1, readfds); r = rb_fd_ptr(readfds); } if (writefds) { rb_fd_resize(n - 1, writefds); w = rb_fd_ptr(writefds); } if (exceptfds) { rb_fd_resize(n - 1, exceptfds); e = rb_fd_ptr(exceptfds); } return select(n, r, w, e, timeout); } UISFBED
  159. int rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct

    timeval *timeout) { fd_set *r = NULL, *w = NULL, *e = NULL; if (readfds) { rb_fd_resize(n - 1, readfds); r = rb_fd_ptr(readfds); } if (writefds) { rb_fd_resize(n - 1, writefds); w = rb_fd_ptr(writefds); } if (exceptfds) { rb_fd_resize(n - 1, exceptfds); e = rb_fd_ptr(exceptfds); } return select(n, r, w, e, timeout); } 5IJTGVODUJPONBLFTVTFPGUIFTUSVDUSC@GETFU@U 5IFJNQMFNFOUBUJPOPGSC@GE@TFMFDU TUSVDUSC@GETFU@UTBSFVTFE UISFBED
  160. TUSVDUSC@GETFU@U /** * The data structure which wraps the fd_set

    bitmap used by select(2). This * allows Ruby to use FD sets larger than that allowed by historic limitations * on modern platforms. */ typedef struct { int maxfd; /**< Maximum allowed number of FDs. */ fd_set *fdset; /**< File descriptors buffer */ } rb_fdset_t; JODMVEFSVCZJOUFSOBMJOUFSOTFMFDUMBSHFTJ[FI
  161. /** * The data structure which wraps the fd_set bitmap

    used by select(2). This * allows Ruby to use FD sets larger than that allowed by historic limitations * on modern platforms. */ typedef struct { int maxfd; /**< Maximum allowed number of FDs. */ fd_set *fdset; /**< File descriptors buffer */ } rb_fdset_t; TUSVDUSC@GETFU@U TUSVDUSC@GETFU@UXSBQTUIFGE@TFU UPCFQBTTFEUPTFMFDU   5IFGE@TFUUPCFQBTTFEUPTFMFDU   JODMVEFSVCZJOUFSOBMJOUFSOTFMFDUMBSHFTJ[FI
  162. /** * The data structure which wraps the fd_set bitmap

    used by select(2). This * allows Ruby to use FD sets larger than that allowed by historic limitations * on modern platforms. */ typedef struct { int maxfd; /**< Maximum allowed number of FDs. */ fd_set *fdset; /**< File descriptors buffer */ } rb_fdset_t; "OEJUIBTBDPNNFOU JODMVEFSVCZJOUFSOBMJOUFSOTFMFDUMBSHFTJ[FI TUSVDUSC@GETFU@U
  163. 5IFJNQMFNFOUBUJPOPGSC@GE@TFMFDU int rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds,

    struct timeval *timeout) { fd_set *r = NULL, *w = NULL, *e = NULL; if (readfds) { rb_fd_resize(n - 1, readfds); r = rb_fd_ptr(readfds); } if (writefds) { rb_fd_resize(n - 1, writefds); w = rb_fd_ptr(writefds); } if (exceptfds) { rb_fd_resize(n - 1, exceptfds); e = rb_fd_ptr(exceptfds); } return select(n, r, w, e, timeout); } SC@GE@TFMFDUEZOBNJDBMMZBMMPDBUFTPSFYQBOETUIF CJUNBQSFHJPOTGPSUIFNPOJUPSFEGE@TFU BDDPSEJOHUPUIFNBYJNVNGEOVNCFS UISFBED
  164. 5IFJNQMFNFOUBUJPOPGSC@GE@TFMFDU int rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds,

    struct timeval *timeout) { fd_set *r = NULL, *w = NULL, *e = NULL; if (readfds) { rb_fd_resize(n - 1, readfds); r = rb_fd_ptr(readfds); } if (writefds) { rb_fd_resize(n - 1, writefds); w = rb_fd_ptr(writefds); } if (exceptfds) { rb_fd_resize(n - 1, exceptfds); e = rb_fd_ptr(exceptfds); } return select(n, r, w, e, timeout); } BOEQBTTFTQPJOUFSTUPUIFTFSFHJPOTUPTFMFDU   UIFSFCZFOBCMJOHTVQQPSUGPS fi MFEFTDSJQUPST UIBUFYDFFE'%@4&54*;& $BMMTFMFDU  XJUIUIFQPJOUFST UISFBED
  165. $BMM4UBDLPG*0TFMFDU *0TFMFDU  ➡︎ SC@G@TFMFDU  ➡︎ SC@FOTVSF  ➡︎

    TFMFDU@DBMM  ➡︎ TFMFDU@JOUFSOBM  ➡︎ SC@UISFBE@GE@TFMFDU  ➡︎ OBUJWF@GE@TFMFDU  ➡︎ SC@GE@TFMFDU  ➡︎ TFMFDU@FOE 4P EPFTO`UUIBUNFBO5$14PDLFUOFXDPVMEKVTUDBMM SC@GE@TFMFDUJOTUFBEPGDBMMJOHTFMFDU  EJSFDUMZ This seems like a good fit!
  166. 5IFPVUDPNFPGJOUSPEVDJOH)&W require "rubydns" RubyDNS.run_server([[:udp, "0.0.0.0", 53], [:udp, "::", 53]]) do

    match("example.com", Resolv::DNS::Resource::IN::A) do |tx| tx.respond!("127.0.0.1") end match("example.com", Resolv::DNS::Resource::IN::AAAA) do |tx| sleep Float::INFINITY tx.respond!("::1") end otherwise do |query| tx.fail!(:NXDomain) end end *QSFQBSFEB%/4TFSWFSUIBUOFWFSSFUVSOTBOZ*1W BEESFTTFT CVUSFTQPOETJNNFEJBUFMZXJUIBO*1W BEESFTT /FWFSSFUVSOTBO*1WBEESFTT 3FUVSOTBO*1WBEESFTTJNNFEJBUFMZ
  167. $ time ruby -rsocket -e " > p TCPSocket.new('example.com', 4567,

    fast_fallback: false) > " 5IFPVUDPNFPGJOUSPEVDJOH)&W 8JUIUIJT%/4TFSWFSQSPDFTTSVOOJOH   fi STUSVO5$14PDLFUOFXXJUI)&WEJTBCMFE *OUIJTDBTF 3VCZPO6CVOUV
  168. $ time ruby -rsocket -e " > p TCPSocket.new('example.com', 4567,

    fast_fallback: false) > " #<TCPSocket:fd 5, AF_INET, 127.0.0.1, 48004> 0.06s user 0.01s system 0% cpu 15.086 total 5IFPVUDPNFPGJOUSPEVDJOH)&W JUUBLFTBCPVUTFDPOETGPSUIFNFUIPEUPDPNQMFUF 3VCZPO6CVOUV
  169. $ time ruby -rsocket -e " > p TCPSocket.new('example.com', 4567,

    fast_fallback: false) > " #<TCPSocket:fd 5, AF_INET, 127.0.0.1, 48004> 0.06s user 0.01s system 0% cpu 15.086 total $ time ruby -rsocket -e " > p TCPSocket.new('example.com', 4567, fast_fallback: true) > " 5IFPVUDPNFPGJOUSPEVDJOH)&W 0OUIFPUIFSIBOE XIFO)&WJTFOBCMFE 3VCZPO6CVOUV
  170. $ time ruby -rsocket -e " > p TCPSocket.new('example.com', 4567,

    fast_fallback: false) > " #<TCPSocket:fd 5, AF_INET, 127.0.0.1, 48004> 0.06s user 0.01s system 0% cpu 15.086 total $ time ruby -rsocket -e " > p TCPSocket.new('example.com', 4567, fast_fallback: true) > " #<TCPSocket:fd 7, AF_INET, 127.0.0.1, 54768> 0.05s user 0.01s system 52% cpu 0.114 total 5IFPVUDPNFPGJOUSPEVDJOH)&W UIFSFTVMUJTSFUVSOFEJOBCPVUTFDPOET *OBXPSTUDBTFTDFOBSJPMJLFUIJT FOBCMJOH)&W NBLFTUIFDPOOFDUJPOSPVHIMZUJNFTGBTUFS 132.3x faster! 3VCZPO6CVOUV
  171. *NQBDUPOQFSGPSNBODF require "socket" require "benchmark" hostname = "www.ruby-lang.org" port =

    80 Benchmark.bmbm do |x| x.report("fast_fallback: false") do 100.times { TCPSocket.new(hostname, port, fast_fallback: false).close } end x.report("fast_fallback: true") do 100.times { TCPSocket.new(hostname, port, fast_fallback: true).close } end end 0OUIFPUIFSIBOE  SFHBSEJOHUIFJNQBDUPOQFSGPSNBODF  SVOBCFODINBSLPWFSFYFDVUJPOT
  172. *NQBDUPOQFSGPSNBODF $ time ruby benchmark.rb Rehearsal -------------------------------------------------------- fast_fallback: false 0.014033

    0.078984 0.093017 ( 1.413951) fast_fallback: true 0.017588 0.097045 0.114633 ( 1.460664) ----------------------------------------------- total: 0.207650sec user system total real fast_fallback: false 0.018392 0.110852 0.129244 ( 1.466014) fast_fallback: true 0.020891 0.124054 0.144945 ( 1.473816) 'PSFYBNQMF XIFODPOOFDUJOHUPSVCZMBOHPSH  UIFBWFSBHFFYFDVUJPOUJNFXBTTFDPOET XJUI)&WEJTBCMFE BOETFDPOETXJUIJUFOBCMFE 3VCZPO6CVOUV