* [Feature #21347] Add `open_timeout` as an overall timeout option for `TCPSocket.new`
With this change, `TCPSocket.new` now accepts the `open_timeout` option.
This option raises an exception if the specified number of seconds has elapsed since the start of the method call,
even if the operation is still in the middle of name resolution or connection attempts.
The addition of this option follows the same intent as the previously merged change to `Socket.tcp`.
[Feature #21347](https://bugs.ruby-lang.org/issues/21347)
https://github.com/ruby/ruby/pull/13368
* Tidy up: Extract rsock_raise_user_specified_timeout()
* Added a note to the documentation of `Socket.tcp`
* Fix `rsock_init_inetsock` for `FAST_FALLBACK_INIT_INETSOCK_IMPL`
* Introduction of Happy Eyeballs Version 2 (RFC8305) in TCPSocket.new
This is an implementation of Happy Eyeballs version 2 (RFC 8305) in `TCPSocket.new`.
See https://github.com/ruby/ruby/pull/11653
1. Background
Prior to this implementation, I implemented Happy Eyeballs Version 2 (HEv2) for `Socket.tcp` in https://github.com/ruby/ruby/pull/9374.
HEv2 is an algorithm defined in [RFC 8305](https://datatracker.ietf.org/doc/html/rfc8305), aimed at improving network connectivity.
For more details on the specific cases that HEv2 helps, please refer to https://bugs.ruby-lang.org/issues/20108.
2. Proposal & Outcome
This proposal implements the same HEv2 algorithm in `TCPSocket.new`.
Since `TCPSocket.new` is used more widely than `Socket.tcp`, this change is expected to broaden the impact of HEv2's benefits.
Like `Socket.tcp`, I have also added `fast_fallback` keyword argument to `TCPSocket.new`.
This option is set to true by default, enabling the HEv2 functionality.
However, users can explicitly set it to false to disable HEv2 and use the previous behavior of `TCPSocket.new`.
It should be noted that HEv2 is enabled only in environments where pthreads are available.
This specification follows the approach taken in https://bugs.ruby-lang.org/issues/19965 , where name resolution can be interrupted.
(In environments where pthreads are not available, the `fast_fallback` option is ignored.)
3. Performance
Below is the benchmark of 100 requests to `www.ruby-lang.org` with the fast_fallback option set to true and false, respectively.
While there is a slight performance degradation when HEv2 is enabled, the degradation is smaller compared to that seen in `Socket.tcp`.
```
~/s/build ❯❯❯ ../install/bin/ruby ../ruby/test.rb
Rehearsal --------------------------------------------------------
fast_fallback: true 0.017588 0.097045 0.114633 ( 1.460664)
fast_fallback: false 0.014033 0.078984 0.093017 ( 1.413951)
----------------------------------------------- total: 0.207650sec
user system total real
fast_fallback: true 0.020891 0.124054 0.144945 ( 1.473816)
fast_fallback: false 0.018392 0.110852 0.129244 ( 1.466014)
```
* Update debug prints
Co-authored-by: Nobuyoshi Nakada <nobu.nakada@gmail.com>
* Remove debug prints
* misc
* Disable HEv2 in Win
* Raise resolution error with hostname resolution
* Fix to handle errors
* Remove warnings
* Errors that do not need to be handled
* misc
* Improve doc
* Fix bug on cancellation
* Avoid EAI_ADDRFAMILY for resolving IPv6
* Follow upstream
* misc
* Refactor connection_attempt_fds management
- Introduced allocate_connection_attempt_fds and reallocate_connection_attempt_fds for improved memory allocation of connection_attempt_fds
- Added remove_connection_attempt_fd to resize connection_attempt_fds dynamically.
- Simplified the in_progress_fds function to only check the size of connection_attempt_fds.
* Rename do_pthread_create to raddrinfo_pthread_create to avoid conflicting
---------
Co-authored-by: Nobuyoshi Nakada <nobu.nakada@gmail.com>
This is analogous to functionality found in IO#read_nonblock and
IO#wait_nonblock. Raising exceptions for common failures on
non-blocking servers is expensive and makes $DEBUG too noisy.
Benchmark results:
user system total real
default 2.790000 0.870000 3.660000 ( 3.671597)
exception: false 1.120000 0.800000 1.920000 ( 1.922032)
exception: false (cached arg) 0.820000 0.770000 1.590000 ( 1.589267)
--------------------- benchmark script ------------------------
require 'socket'
require 'benchmark'
require 'tmpdir'
nr = 1000000
Dir.mktmpdir('nb_bench') do |path|
sock_path = "#{path}/test.sock"
s = UNIXServer.new(sock_path)
Benchmark.bmbm do |x|
x.report("default") do
nr.times do
begin
s.accept_nonblock
rescue IO::WaitReadable
end
end
end
x.report("exception: false") do
nr.times do
begin
s.accept_nonblock(exception: false)
rescue IO::WaitReadable
abort "should not raise"
end
end
end
x.report("exception: false (cached arg)") do
arg = { exception: false }
nr.times do
begin
s.accept_nonblock(arg)
rescue IO::WaitReadable
abort "should not raise"
end
end
end
end
end
* ext/socket/init.c (rsock_s_accept_nonblock):
support exception: false
[ruby-core:66385] [Feature #10532]
* ext/socket/init.c (rsock_init_socket_init): define new symbols
* ext/socket/rubysocket.h: adjust prototype
* ext/socket/socket.c (sock_accept_nonblock): support exception: false
* ext/openssl/ossl_ssl.c (ossl_ssl_accept_nonblock): ditto
* ext/socket/socket.c (Init_socket): adjust accept_nonblock definition
* ext/openssl/ossl_ssl.c (Init_ossl_ssl): ditto
* ext/socket/tcpserver.c (rsock_init_tcpserver): ditto
* ext/socket/unixserver.c (rsock_init_unixserver): ditto
* ext/socket/tcpserver.c (tcp_accept_nonblock): adjust
rsock_s_accept_nonblock call
* ext/socket/unixserver.c (unix_accept_nonblock): ditto
* ext/openssl/ossl_ssl.c (ossl_start_ssl): support no_exception
* ext/openssl/ossl_ssl.c (ossl_ssl_connect): adjust ossl_start_ssl call
* ext/openssl/ossl_ssl.c (ossl_ssl_connect_nonblock): ditto
* ext/openssl/ossl_ssl.c (ossl_ssl_accept): ditto
* test/socket/test_nonblock.rb (test_accept_nonblock): test for
"exception :false"
* test/socket/test_tcp.rb (test_accept_nonblock): new test
* test/socket/test_unix.rb (test_accept_nonblock): ditto
* test/openssl/test_pair.rb (test_accept_nonblock_no_exception): ditto
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49948 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
mandatory arguments right after the number of optional arguments
only if the number of leading mandatory arguments is not omitted.
* ext/socket/tcpserver.c (tcp_svr_init): Make use of it.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22603 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* ext/socket/rubysocket.h: common header.
* ext/socket/basicsocket.c: new file for BasicSocket.
* ext/socket/ipsocket.c: new file for IPSocket.
* ext/socket/tcpsocket.c: new file for TCPSocket.
* ext/socket/tcpserver.c: new file for TCPServer.
* ext/socket/sockssocket.c: new file for SOCKSSocket.
* ext/socket/udpsocket.c: new file for UDPSocket.
* ext/socket/unixsocket.c: new file for UNIXSocket.
* ext/socket/unixserver.c: new file for UNIXServer.
* ext/socket/socket.c: now for Socket.
* ext/socket/raddrinfo.c: new file for AddrInfo and name resolution.
* ext/socket/constants.c: new file for constants.
* ext/socket/init.c: new file for utilities.
* ext/socket/mkconstants.rb: export *_to_int.
* ext/socket/extconf.rb: add new object files.
* ext/socket/depend: add dependencies for new files.
* ext/.document: add new files.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@21619 b2dd03c8-39d4-4d8f-98ff-823fe69b080e