Module: Zerg::Support::SocketFactory
- Defined in:
- lib/zerg_support/socket_factory.rb
Class Method Summary collapse
-
.addr_infos(options) ⇒ Object
Retrieves possible IP addresses to connect to based on the given options.
-
.bind(socket, options) ⇒ Object
Binds a socket to an address based on the options.
-
.bind_host(options) ⇒ Object
The host from a host:port IP address, in a form suitable for bind().
-
.bind_port(options) ⇒ Object
The port from a host:port IP address, in a form suitable for bind().
-
.bind_socket_address(options) ⇒ Object
An address suitable for bind() based on the options.
-
.connect_host(options) ⇒ Object
The host from a host:port IP address, in a form suitable for connect().
-
.connect_port(options) ⇒ Object
The port from a host:port IP address, in a form suitable for connect().
-
.connect_with_addr_info(socket, addr_info) ⇒ Object
Connects a socket to an address obtained from getaddrinfo().
-
.host_from_address(address) ⇒ Object
The host from a host:port IP address.
-
.new_inbound_socket(options) ⇒ Object
New inbound socket based on the options.
-
.new_outbound_socket(options) ⇒ Object
New outbound socket based on the options.
-
.new_outbound_socket_with_addr_info(addr_info) ⇒ Object
New outbound socket based on an address obtained from getaddrinfo().
-
.outbound?(options) ⇒ Boolean
True for options requesting a connecting (as opposed to listening) socket.
-
.port_from_address(address) ⇒ Object
The port from a host:port IP address.
-
.set_options(socket, options) ⇒ Object
Sets socket flags (via setsockopt) based on the options.
-
.set_options_on_accept_sockets(socket, options) ⇒ Object
Hacks a socket’s accept method so that new sockets have the given flags set.
-
.socket(options) ⇒ Object
Kitchen-sink socket creation method.
-
.socket_type(options) ⇒ Object
The socket() type based on the options.
-
.split_address(address) ⇒ Object
Splits a host:port IP address into its components.
-
.sugar_socket_close(socket) ⇒ Object
Sugar-coat the socket’s close() call with a better way to close a socket.
-
.sugar_socket_listen(socket) ⇒ Object
Sugar-coat the socket’s listen() call with a default value for its argument.
-
.tcp?(options) ⇒ Boolean
True if the options indicate TCP should be used, false for UDP.
Class Method Details
.addr_infos(options) ⇒ Object
Retrieves possible IP addresses to connect to based on the given options.
The retrieval is done via setsockopt.
159 160 161 162 |
# File 'lib/zerg_support/socket_factory.rb', line 159 def self.addr_infos() Socket.getaddrinfo connect_host(), connect_port(), Socket::AF_INET, socket_type() end |
.bind(socket, options) ⇒ Object
Binds a socket to an address based on the options.
142 143 144 145 |
# File 'lib/zerg_support/socket_factory.rb', line 142 def self.bind(socket, ) socket.bind bind_socket_address() socket end |
.bind_host(options) ⇒ Object
The host from a host:port IP address, in a form suitable for bind().
41 42 43 |
# File 'lib/zerg_support/socket_factory.rb', line 41 def self.bind_host() host_from_address([:in_addr]) or [:in_host] or '0.0.0.0' end |
.bind_port(options) ⇒ Object
The port from a host:port IP address, in a form suitable for bind().
46 47 48 |
# File 'lib/zerg_support/socket_factory.rb', line 46 def self.bind_port() port_from_address([:in_addr]) or [:in_port] or 0 end |
.bind_socket_address(options) ⇒ Object
An address suitable for bind() based on the options.
51 52 53 |
# File 'lib/zerg_support/socket_factory.rb', line 51 def self.bind_socket_address() Socket::pack_sockaddr_in bind_port(), bind_host() end |
.connect_host(options) ⇒ Object
The host from a host:port IP address, in a form suitable for connect().
56 57 58 |
# File 'lib/zerg_support/socket_factory.rb', line 56 def self.connect_host() [:out_host] or host_from_address([:out_addr]) or 'localhost' end |
.connect_port(options) ⇒ Object
The port from a host:port IP address, in a form suitable for connect().
61 62 63 |
# File 'lib/zerg_support/socket_factory.rb', line 61 def self.connect_port() port_from_address([:out_addr]) or [:out_port] end |
.connect_with_addr_info(socket, addr_info) ⇒ Object
Connects a socket to an address obtained from getaddrinfo().
Returns the socket for success, or nil if the connection failed.
172 173 174 175 176 177 178 179 |
# File 'lib/zerg_support/socket_factory.rb', line 172 def self.connect_with_addr_info(socket, addr_info) begin socket.connect Socket.pack_sockaddr_in(addr_info[1], addr_info[3]) socket rescue nil end end |
.host_from_address(address) ⇒ Object
The host from a host:port IP address.
Empty string if the IP address does not contain a host (e.g. :3000)
24 25 26 |
# File 'lib/zerg_support/socket_factory.rb', line 24 def self.host_from_address(address) address and split_address(address)[0] end |
.new_inbound_socket(options) ⇒ Object
New inbound socket based on the options.
148 149 150 151 152 153 154 |
# File 'lib/zerg_support/socket_factory.rb', line 148 def self.new_inbound_socket() socket = Socket.new Socket::AF_INET, socket_type(), Socket::PF_UNSPEC socket, socket, sugar_socket_listen socket bind socket, end |
.new_outbound_socket(options) ⇒ Object
New outbound socket based on the options.
182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/zerg_support/socket_factory.rb', line 182 def self.new_outbound_socket() addr_infos = self.addr_infos addr_infos.each do |addr_info| socket = new_outbound_socket_with_addr_info addr_info socket, if connect_with_addr_info socket, addr_info sugar_socket_close socket return socket end socket.close rescue nil end nil end |
.new_outbound_socket_with_addr_info(addr_info) ⇒ Object
New outbound socket based on an address obtained from getaddrinfo().
165 166 167 |
# File 'lib/zerg_support/socket_factory.rb', line 165 def self.new_outbound_socket_with_addr_info(addr_info) Socket.new addr_info[4], addr_info[5], addr_info[6] end |
.outbound?(options) ⇒ Boolean
True for options requesting a connecting (as opposed to listening) socket.
36 37 38 |
# File 'lib/zerg_support/socket_factory.rb', line 36 def self.outbound?() [:out_port, :out_host, :out_addr].any? { |k| [k] } end |
.port_from_address(address) ⇒ Object
The port from a host:port IP address.
nil if the IP address does not contain a port (e.g. localhost)
31 32 33 |
# File 'lib/zerg_support/socket_factory.rb', line 31 def self.port_from_address(address) address and (port_string = split_address(address)[1]) and port_string.to_i end |
.set_options(socket, options) ⇒ Object
Sets socket flags (via setsockopt) based on the options.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/zerg_support/socket_factory.rb', line 76 def self.(socket, ) if [:no_delay] if tcp?() socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true end socket.sync = true end if [:reuse_addr] socket.setsockopt Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true end unless [:reverse_lookup] if socket.respond_to? :do_not_reverse_lookup socket.do_not_reverse_lookup = true else # work around until the patch below actually gets committed: # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/2346 BasicSocket.do_not_reverse_lookup = true end end if [:linger] socket.setsockopt Socket::SOL_SOCKET, Socket::SO_LINGER, [1, [:linger]].pack('ii') else # No lingering sockets. socket.setsockopt Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack('ii') end end |
.set_options_on_accept_sockets(socket, options) ⇒ Object
Hacks a socket’s accept method so that new sockets have the given flags set.
The flags are set in a similar manner to set_options.
110 111 112 113 114 115 116 117 118 119 |
# File 'lib/zerg_support/socket_factory.rb', line 110 def self.(socket, ) socket.instance_variable_set :@zerg_support_factory_options, def socket.accept(*args) sock, addr = super Zerg::Support::SocketFactory. sock, @zerg_support_factory_options Zerg::Support::SocketFactory.sugar_socket_close sock return sock, addr end end |
.socket(options) ⇒ Object
Kitchen-sink socket creation method. The following options are supported:
tcp:: forces the use of TCP (overrides the udp option)
udp:: selects UDP (the default is TCP)
out_port:: the port to connect an outgoing socket to
out_host:: the host to connect an outgoing socket to
out_addr:: the host:port address to connect an outgoing socket to; the
host and port override out_port and out_host, which can be used
in conjunction with out_addr to provide default values
in_port:: the port to bind a listening socket to
in_host:: the host to bind a listening socket to
in_addr:: the host:port address to bind a listening socket to; the host
and port override in_port and in_host, which can be used in
conjunction with in_addr to provide default values
no_delay:: disables Nagles' algorithm
reuse_addr:: allows binding other sockets to this socket's address
reverse_lookup:: enables reverse lookups on connections; this is the Ruby
default, but ZergSupport changes it for performance
213 214 215 216 217 218 219 |
# File 'lib/zerg_support/socket_factory.rb', line 213 def self.socket() if outbound? new_outbound_socket else new_inbound_socket end end |
.socket_type(options) ⇒ Object
The socket() type based on the options.
71 72 73 |
# File 'lib/zerg_support/socket_factory.rb', line 71 def self.socket_type() tcp?() ? Socket::SOCK_STREAM : Socket::SOCK_DGRAM end |
.split_address(address) ⇒ Object
Splits a host:port IP address into its components. IPv6 addresses welcome.
The port will be nil if the IP address doesn’t contain it.
10 11 12 13 14 15 16 17 18 19 |
# File 'lib/zerg_support/socket_factory.rb', line 10 def self.split_address(address) port_match = /(^|[^:])\:([^:].*)$/.match(address) if port_match port = port_match[2] host = address[0, address.length - port.length - 1] [(host.empty? ? nil : host), port] else [address, nil] end end |
.sugar_socket_close(socket) ⇒ Object
Sugar-coat the socket’s close() call with a better way to close a socket.
130 131 132 133 134 135 136 137 138 139 |
# File 'lib/zerg_support/socket_factory.rb', line 130 def self.sugar_socket_close(socket) def socket.close begin shutdown Socket::SHUT_WR loop { break if recv(65536).empty? } rescue SystemCallError end super end end |
.sugar_socket_listen(socket) ⇒ Object
Sugar-coat the socket’s listen() call with a default value for its argument.
122 123 124 125 126 127 |
# File 'lib/zerg_support/socket_factory.rb', line 122 def self.sugar_socket_listen(socket) def socket.listen(*args) args = [1000] if args.empty? super(*args) end end |
.tcp?(options) ⇒ Boolean
True if the options indicate TCP should be used, false for UDP.
66 67 68 |
# File 'lib/zerg_support/socket_factory.rb', line 66 def self.tcp?() [:tcp] or ![:udp] end |