ruby/ext/socket/sockssocket.c
Misaki Shioi 4c270200db
[Feature #120782] Introduction of Happy Eyeballs Version 2 (RFC8305) in TCPSocket.new (#11653)
* 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>
2024-11-12 10:06:48 +09:00

75 lines
1.7 KiB
C

/************************************************
sockssocket.c -
created at: Thu Mar 31 12:21:29 JST 1994
Copyright (C) 1993-2007 Yukihiro Matsumoto
************************************************/
#include "rubysocket.h"
#ifdef SOCKS
/*
* call-seq:
* SOCKSSocket.new(host, port) => socket
*
* Opens a SOCKS connection to +host+ via the SOCKS server.
*
* The SOCKS server configuration varies by implementation
*
* When using the Dante libsocks/libsocksd implementation it is configured as SOCKS_SERVER env var.
*
* See: https://manpages.debian.org/testing/dante-client/socksify.1.en.html for full env variable support.
*
*/
static VALUE
socks_init(VALUE sock, VALUE host, VALUE port)
{
static int init = 0;
if (init == 0) {
SOCKSinit("ruby");
init = 1;
}
return rsock_init_inetsock(sock, host, port, Qnil, Qnil, INET_SOCKS, Qnil, Qnil, Qfalse, Qnil);
}
#ifdef SOCKS5
/*
* Closes the SOCKS connection.
*
*/
static VALUE
socks_s_close(VALUE sock)
{
rb_io_t *fptr;
GetOpenFile(sock, fptr);
shutdown(fptr->fd, SHUT_RDWR);
return rb_io_close(sock);
}
#endif
#endif
void
rsock_init_sockssocket(void)
{
#ifdef SOCKS
/*
* Document-class: SOCKSSocket < TCPSocket
*
* SOCKS is an Internet protocol that routes packets between a client and
* a server through a proxy server. SOCKS5, if supported, additionally
* provides authentication so only authorized users may access a server.
*/
rb_cSOCKSSocket = rb_define_class("SOCKSSocket", rb_cTCPSocket);
rb_define_method(rb_cSOCKSSocket, "initialize", socks_init, 2);
#ifdef SOCKS5
rb_define_method(rb_cSOCKSSocket, "close", socks_s_close, 0);
#endif
#endif
}