Class: Dalli::Socket::TCP
- Inherits:
-
TCPSocket
- Object
- TCPSocket
- Dalli::Socket::TCP
- Includes:
- InstanceMethods
- Defined in:
- lib/dalli/socket.rb
Overview
A standard TCP socket between the Dalli client and the Memcached server.
Constant Summary collapse
- TIMEVAL_PACK_FORMATS =
Pack formats for struct timeval across architectures. Uses fixed-size formats for JRuby compatibility (JRuby doesn’t support _ modifier on q).
-
ll: 8 bytes (32-bit time_t, 32-bit suseconds_t)
-
qq: 16 bytes (64-bit time_t, 64-bit suseconds_t or padded 32-bit)
-
%w[ll qq].freeze
- TIMEVAL_TEST_VALUES =
[0, 0].freeze
Constants included from InstanceMethods
InstanceMethods::FILTERED_OUT_OPTIONS, InstanceMethods::WAIT_RCS
Instance Attribute Summary collapse
-
#options ⇒ Object
options - supports enhanced logging in the case of a timeout.
Class Method Summary collapse
- .configure_socket_buffers(sock, options) ⇒ Object
- .configure_tcp_options(sock, options) ⇒ Object
- .configure_timeout(sock, options) ⇒ Object
- .create_socket_with_timeout(host, port, options) ⇒ Object
- .init_socket_options(sock, options) ⇒ Object
- .open(host, port, options = {}) ⇒ Object
- .pack_timeval(sock, seconds, microseconds) ⇒ Object
-
.supports_connect_timeout? ⇒ Boolean
Detect and cache whether TCPSocket supports the connect_timeout: keyword argument.
-
.timeval_pack_format(sock) ⇒ Object
Detect and cache the correct pack format for struct timeval on this platform.
- .wrapping_ssl_socket(tcp_socket, host, ssl_context) ⇒ Object
Methods included from InstanceMethods
#append_to_buffer?, #logged_options, #nonblock_timed_out?, #read_available, #readfull
Instance Attribute Details
#options ⇒ Object
options - supports enhanced logging in the case of a timeout
91 92 93 |
# File 'lib/dalli/socket.rb', line 91 def @options end |
Class Method Details
.configure_socket_buffers(sock, options) ⇒ Object
141 142 143 144 |
# File 'lib/dalli/socket.rb', line 141 def self.configure_socket_buffers(sock, ) sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_RCVBUF, [:rcvbuf]) if [:rcvbuf] sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_SNDBUF, [:sndbuf]) if [:sndbuf] end |
.configure_tcp_options(sock, options) ⇒ Object
136 137 138 139 |
# File 'lib/dalli/socket.rb', line 136 def self.(sock, ) sock.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, true) sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_KEEPALIVE, true) if [:keepalive] end |
.configure_timeout(sock, options) ⇒ Object
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/dalli/socket.rb', line 146 def self.configure_timeout(sock, ) return unless [:socket_timeout] if sock.respond_to?(:timeout=) # Ruby 3.2+ has IO#timeout for reliable cross-platform timeout handling sock.timeout = [:socket_timeout] else # Ruby 3.1 fallback using socket options # struct timeval has architecture-dependent sizes (time_t, suseconds_t) seconds, fractional = [:socket_timeout].divmod(1) microseconds = (fractional * 1_000_000).to_i timeval = pack_timeval(sock, seconds, microseconds) sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_RCVTIMEO, timeval) sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_SNDTIMEO, timeval) end end |
.create_socket_with_timeout(host, port, options) ⇒ Object
118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/dalli/socket.rb', line 118 def self.create_socket_with_timeout(host, port, ) if supports_connect_timeout? sock = new(host, port, connect_timeout: [:socket_timeout]) yield(sock) else Timeout.timeout([:socket_timeout]) do sock = new(host, port) yield(sock) end end end |
.init_socket_options(sock, options) ⇒ Object
130 131 132 133 134 |
# File 'lib/dalli/socket.rb', line 130 def self.(sock, ) (sock, ) configure_socket_buffers(sock, ) configure_timeout(sock, ) end |
.open(host, port, options = {}) ⇒ Object
99 100 101 102 103 104 105 106 |
# File 'lib/dalli/socket.rb', line 99 def self.open(host, port, = {}) create_socket_with_timeout(host, port, ) do |sock| sock. = { host: host, port: port }.merge() (sock, ) [:ssl_context] ? wrapping_ssl_socket(sock, host, [:ssl_context]) : sock end end |
.pack_timeval(sock, seconds, microseconds) ⇒ Object
180 181 182 |
# File 'lib/dalli/socket.rb', line 180 def self.pack_timeval(sock, seconds, microseconds) [seconds, microseconds].pack(timeval_pack_format(sock)) end |
.supports_connect_timeout? ⇒ Boolean
Detect and cache whether TCPSocket supports the connect_timeout: keyword argument. Returns false if TCPSocket#initialize has been monkey-patched by gems like socksify or resolv-replace, which don’t support keyword arguments.
111 112 113 114 115 116 |
# File 'lib/dalli/socket.rb', line 111 def self.supports_connect_timeout? return @supports_connect_timeout if defined?(@supports_connect_timeout) @supports_connect_timeout = RUBY_VERSION >= '3.0' && ::TCPSocket.instance_method(:initialize).parameters == TCPSOCKET_NATIVE_PARAMETERS end |
.timeval_pack_format(sock) ⇒ Object
Detect and cache the correct pack format for struct timeval on this platform. Different architectures have different sizes for time_t and suseconds_t.
173 174 175 176 177 178 |
# File 'lib/dalli/socket.rb', line 173 def self.timeval_pack_format(sock) @timeval_pack_format ||= begin expected_size = sock.getsockopt(::Socket::SOL_SOCKET, ::Socket::SO_RCVTIMEO).data.bytesize TIMEVAL_PACK_FORMATS.find { |fmt| TIMEVAL_TEST_VALUES.pack(fmt).bytesize == expected_size } || 'll' end end |
.wrapping_ssl_socket(tcp_socket, host, ssl_context) ⇒ Object
184 185 186 187 188 189 190 |
# File 'lib/dalli/socket.rb', line 184 def self.wrapping_ssl_socket(tcp_socket, host, ssl_context) ssl_socket = Dalli::Socket::SSLSocket.new(tcp_socket, ssl_context) ssl_socket.hostname = host ssl_socket.sync_close = true ssl_socket.connect ssl_socket end |