# frozen_string_literal: true
# creates an Addrinfo object from the arguments.
# The arguments are interpreted as similar to self.
# Addrinfo.tcp("0.0.0.0", 4649).family_addrinfo("www.ruby-lang.org", 80)
# #=> #<Addrinfo: 221.186.184.68:80 TCP (www.ruby-lang.org:80)>
# Addrinfo.unix("/tmp/sock").family_addrinfo("/tmp/sock2")
# #=> #<Addrinfo: /tmp/sock2 SOCK_STREAM>
def family_addrinfo(*args)
raise ArgumentError, "no address specified"
elsif Addrinfo === args.first
raise ArgumentError, "too many arguments" if args.length != 1
if (self.pfamily != addrinfo.pfamily) ||
(self.socktype != addrinfo.socktype)
raise ArgumentError, "Addrinfo type mismatch"
raise ArgumentError, "IP address needs host and port but #{args.length} arguments given" if args.length != 2
Addrinfo.getaddrinfo(host, port, self.pfamily, self.socktype, self.protocol)[0]
raise ArgumentError, "UNIX socket needs single path argument but #{args.length} arguments given" if args.length != 1
raise ArgumentError, "unexpected family"
# creates a new Socket connected to the address of +local_addrinfo+.
# If _local_addrinfo_ is nil, the address of the socket is not bound.
# The _timeout_ specify the seconds for timeout.
# Errno::ETIMEDOUT is raised when timeout occur.
# If a block is given the created socket is yielded for each address.
def connect_internal(local_addrinfo, timeout=nil) # :yields: socket
sock = Socket.new(self.pfamily, self.socktype, self.protocol)
sock.ipv6only! if self.ipv6?
sock.bind local_addrinfo if local_addrinfo
case sock.connect_nonblock(self, exception: false)
when 0 # success or EISCONN, other errors raise
sock.wait_writable(timeout) or
raise Errno::ETIMEDOUT, 'user specified timeout'
protected :connect_internal
# addrinfo.connect_from([local_addr_args], [opts]) {|socket| ... }
# addrinfo.connect_from([local_addr_args], [opts])
# creates a socket connected to the address of self.
# If one or more arguments given as _local_addr_args_,
# it is used as the local address of the socket.
# _local_addr_args_ is given for family_addrinfo to obtain actual address.
# If _local_addr_args_ is not given, the local address of the socket is not bound.
# The optional last argument _opts_ is options represented by a hash.
# _opts_ may have following options:
# [:timeout] specify the timeout in seconds.
# If a block is given, it is called with the socket and the value of the block is returned.
# The socket is returned otherwise.
# Addrinfo.tcp("www.ruby-lang.org", 80).connect_from("0.0.0.0", 4649) {|s|
# s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
# # Addrinfo object can be taken for the argument.
# Addrinfo.tcp("www.ruby-lang.org", 80).connect_from(Addrinfo.tcp("0.0.0.0", 4649)) {|s|
# s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
def connect_from(*args, timeout: nil, &block)
connect_internal(family_addrinfo(*args), timeout, &block)
# addrinfo.connect([opts]) {|socket| ... }
# addrinfo.connect([opts])
# creates a socket connected to the address of self.
# The optional argument _opts_ is options represented by a hash.
# _opts_ may have following options:
# [:timeout] specify the timeout in seconds.
# If a block is given, it is called with the socket and the value of the block is returned.
# The socket is returned otherwise.
# Addrinfo.tcp("www.ruby-lang.org", 80).connect {|s|
# s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
def connect(timeout: nil, &block)
connect_internal(nil, timeout, &block)
# addrinfo.connect_to([remote_addr_args], [opts]) {|socket| ... }
# addrinfo.connect_to([remote_addr_args], [opts])
# creates a socket connected to _remote_addr_args_ and bound to self.
# The optional last argument _opts_ is options represented by a hash.
# _opts_ may have following options:
# [:timeout] specify the timeout in seconds.
# If a block is given, it is called with the socket and the value of the block is returned.
# The socket is returned otherwise.
# Addrinfo.tcp("0.0.0.0", 4649).connect_to("www.ruby-lang.org", 80) {|s|
# s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
def connect_to(*args, timeout: nil, &block)
remote_addrinfo = family_addrinfo(*args)
remote_addrinfo.connect_internal(self, timeout, &block)
# creates a socket bound to self.
# If a block is given, it is called with the socket and the value of the block is returned.
# The socket is returned otherwise.
# Addrinfo.udp("0.0.0.0", 9981).bind {|s|
# s.local_address.connect {|s| s.send "hello", 0 }
# p s.recv(10) #=> "hello"
sock = Socket.new(self.pfamily, self.socktype, self.protocol)
sock.ipv6only! if self.ipv6?
sock.setsockopt(:SOCKET, :REUSEADDR, 1)
# creates a listening socket bound to self.
def listen(backlog=Socket::SOMAXCONN)
sock = Socket.new(self.pfamily, self.socktype, self.protocol)
sock.ipv6only! if self.ipv6?
sock.setsockopt(:SOCKET, :REUSEADDR, 1)
# iterates over the list of Addrinfo objects obtained by Addrinfo.getaddrinfo.
# Addrinfo.foreach(nil, 80) {|x| p x }
# #=> #<Addrinfo: 127.0.0.1:80 TCP (:80)>
# # #<Addrinfo: 127.0.0.1:80 UDP (:80)>
# # #<Addrinfo: [::1]:80 TCP (:80)>
# # #<Addrinfo: [::1]:80 UDP (:80)>
def self.foreach(nodename, service, family=nil, socktype=nil, protocol=nil, flags=nil, timeout: nil, &block)
Addrinfo.getaddrinfo(nodename, service, family, socktype, protocol, flags, timeout: timeout).each(&block)
# Returns an address of the socket suitable for connect in the local machine.
# This method returns _self_.local_address, except following condition.
# - IPv4 unspecified address (0.0.0.0) is replaced by IPv4 loopback address (127.0.0.1).
# - IPv6 unspecified address (::) is replaced by IPv6 loopback address (::1).
# If the local address is not suitable for connect, SocketError is raised.
# IPv4 and IPv6 address which port is 0 is not suitable for connect.
# Unix domain socket which has no path is not suitable for connect.
# Addrinfo.tcp("0.0.0.0", 0).listen {|serv|
# p serv.connect_address #=> #<Addrinfo: 127.0.0.1:53660 TCP>
# serv.connect_address.connect {|c|
# p [c, s] #=> [#<Socket:fd 4>, #<Socket:fd 6>]
if afamily == Socket::AF_INET
raise SocketError, "unbound IPv4 socket" if addr.ip_port == 0
if addr.ip_address == "0.0.0.0"
addr = Addrinfo.new(["AF_INET", addr.ip_port, nil, "127.0.0.1"], addr.pfamily, addr.socktype, addr.protocol)
elsif defined?(Socket::AF_INET6) && afamily == Socket::AF_INET6
raise SocketError, "unbound IPv6 socket" if addr.ip_port == 0
if addr.ip_address == "::"
addr = Addrinfo.new(["AF_INET6", addr.ip_port, nil, "::1"], addr.pfamily, addr.socktype, addr.protocol)
elsif addr.ip_address == "0.0.0.0" # MacOS X 10.4 returns "a.b.c.d" for IPv4-mapped IPv6 address.
addr = Addrinfo.new(["AF_INET6", addr.ip_port, nil, "::1"], addr.pfamily, addr.socktype, addr.protocol)
elsif addr.ip_address == "::ffff:0.0.0.0" # MacOS X 10.6 returns "::ffff:a.b.c.d" for IPv4-mapped IPv6 address.
addr = Addrinfo.new(["AF_INET6", addr.ip_port, nil, "::1"], addr.pfamily, addr.socktype, addr.protocol)
elsif defined?(Socket::AF_UNIX) && afamily == Socket::AF_UNIX
raise SocketError, "unbound Unix socket" if addr.unix_path == ""
# basicsocket.sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
# sendmsg sends a message using sendmsg(2) system call in blocking manner.
# _mesg_ is a string to send.
# _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_OOB.
# _dest_sockaddr_ is a destination socket address for connection-less socket.
# It should be a sockaddr such as a result of Socket.sockaddr_in.
# An Addrinfo object can be used too.
# _controls_ is a list of ancillary data.
# The element of _controls_ should be Socket::AncillaryData or
# The 3-element array should contains cmsg_level, cmsg_type and data.
# The return value, _numbytes_sent_ is an integer which is the number of bytes sent.
# sendmsg can be used to implement send_io as follows:
# # use Socket::AncillaryData.
# ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, io.fileno)
# sock.sendmsg("a", 0, nil, ancdata)
# ancdata = [:SOCKET, :RIGHTS, [io.fileno].pack("i!")]
# sock.sendmsg("\0", 0, nil, ancdata)
def sendmsg(mesg, flags = 0, dest_sockaddr = nil, *controls)
__sendmsg(mesg, flags, dest_sockaddr, controls)
# basicsocket.sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls, opts={}) => numbytes_sent
# sendmsg_nonblock sends a message using sendmsg(2) system call in non-blocking manner.
# It is similar to BasicSocket#sendmsg
# but the non-blocking flag is set before the system call
# and it doesn't retry the system call.
# By specifying a keyword argument _exception_ to +false+, you can indicate
# that sendmsg_nonblock should not raise an IO::WaitWritable exception, but
# return the symbol +:wait_writable+ instead.
def sendmsg_nonblock(mesg, flags = 0, dest_sockaddr = nil, *controls,
__sendmsg_nonblock(mesg, flags, dest_sockaddr, controls, exception)
# basicsocket.recv_nonblock(maxlen [, flags [, buf [, options ]]]) => mesg
# Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
# O_NONBLOCK is set for the underlying file descriptor.
# _flags_ is zero or more of the +MSG_+ options.
# The result, _mesg_, is the data received.
# When recvfrom(2) returns 0, Socket#recv_nonblock returns
# an empty string as data.
# The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
# * +maxlen+ - the number of bytes to receive from the socket
# * +flags+ - zero or more of the +MSG_+ options
# * +buf+ - destination String buffer
# * +options+ - keyword hash, supporting `exception: false`
# serv = TCPServer.new("127.0.0.1", 0)
# af, port, host, addr = serv.addr
# c = TCPSocket.new(addr, port)
# begin # emulate blocking recv.
# p s.recv_nonblock(10) #=> "aaa"
# rescue IO::WaitReadable
# Refer to Socket#recvfrom for the exceptions that may be thrown if the call
# to _recv_nonblock_ fails.
# BasicSocket#recv_nonblock may raise any error corresponding to recvfrom(2) failure,
# including Errno::EWOULDBLOCK.
# If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
# it is extended by IO::WaitReadable.
# So IO::WaitReadable can be used to rescue the exceptions for retrying recv_nonblock.
# By specifying a keyword argument _exception_ to +false+, you can indicate
# that recv_nonblock should not raise an IO::WaitReadable exception, but
# return the symbol +:wait_readable+ instead.
def recv_nonblock(len, flag = 0, str = nil, exception: true)
__recv_nonblock(len, flag, str, exception)
# basicsocket.recvmsg(maxmesglen=nil, flags=0, maxcontrollen=nil, opts={}) => [mesg, sender_addrinfo, rflags, *controls]
# recvmsg receives a message using recvmsg(2) system call in blocking manner.
# _maxmesglen_ is the maximum length of mesg to receive.
# _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_PEEK.
# _maxcontrollen_ is the maximum length of controls (ancillary data) to receive.
# Currently :scm_rights=>bool is the only option.
# :scm_rights option specifies that application expects SCM_RIGHTS control message.
# If the value is nil or false, application don't expects SCM_RIGHTS control message.
# In this case, recvmsg closes the passed file descriptors immediately.
# This is the default behavior.
# If :scm_rights value is neither nil nor false, application expects SCM_RIGHTS control message.
# In this case, recvmsg creates IO objects for each file descriptors for
# Socket::AncillaryData#unix_rights method.
# The return value is 4-elements array.
# _mesg_ is a string of the received message.
# _sender_addrinfo_ is a sender socket address for connection-less socket.
# It is an Addrinfo object.
# For connection-oriented socket such as TCP, sender_addrinfo is platform dependent.
# _rflags_ is a flags on the received message which is bitwise OR of MSG_* constants such as Socket::MSG_TRUNC.
# It will be nil if the system uses 4.3BSD style old recvmsg system call.
# _controls_ is ancillary data which is an array of Socket::AncillaryData objects such as:
# #<Socket::AncillaryData: AF_UNIX SOCKET RIGHTS 7>
# _maxmesglen_ and _maxcontrollen_ can be nil.
# In that case, the buffer will be grown until the message is not truncated.
# Internally, MSG_PEEK is used.
# Buffer full and MSG_CTRUNC are checked for truncation.
# recvmsg can be used to implement recv_io as follows:
# mesg, sender_sockaddr, rflags, *controls = sock.recvmsg(:scm_rights=>true)
# controls.each {|ancdata|
# if ancdata.cmsg_is?(:SOCKET, :RIGHTS)
# return ancdata.unix_rights[0]
def recvmsg(dlen = nil, flags = 0, clen = nil, scm_rights: false)
__recvmsg(dlen, flags, clen, scm_rights)
# basicsocket.recvmsg_nonblock(maxdatalen=nil, flags=0, maxcontrollen=nil, opts={}) => [data, sender_addrinfo, rflags, *controls]
# recvmsg receives a message using recvmsg(2) system call in non-blocking manner.
# It is similar to BasicSocket#recvmsg
# but non-blocking flag is set before the system call
# and it doesn't retry the system call.
# By specifying a keyword argument _exception_ to +false+, you can indicate
# that recvmsg_nonblock should not raise an IO::WaitReadable exception, but
# return the symbol +:wait_readable+ instead.
def recvmsg_nonblock(dlen = nil, flags = 0, clen = nil,
scm_rights: false, exception: true)
__recvmsg_nonblock(dlen, flags, clen, scm_rights, exception)
# Linux-specific optimizations to avoid fcntl for IO#read_nonblock
# and IO#write_nonblock using MSG_DONTWAIT
# Do other platforms support MSG_DONTWAIT reliably?
if RUBY_PLATFORM =~ /linux/ && Socket.const_defined?(:MSG_DONTWAIT)
def read_nonblock(len, str = nil, exception: true) # :nodoc:
__read_nonblock(len, str, exception)
def write_nonblock(buf, exception: true) # :nodoc:
__write_nonblock(buf, exception)
class Socket < BasicSocket
# enable the socket option IPV6_V6ONLY if IPV6_V6ONLY is available.
if defined? Socket::IPV6_V6ONLY
self.setsockopt(:IPV6, :V6ONLY, 1)
# socket.recvfrom_nonblock(maxlen[, flags[, outbuf[, opts]]]) => [mesg, sender_addrinfo]
# Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
# O_NONBLOCK is set for the underlying file descriptor.
# _flags_ is zero or more of the +MSG_+ options.
# The first element of the results, _mesg_, is the data received.
# The second element, _sender_addrinfo_, contains protocol-specific address
# information of the sender.
# When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns
# an empty string as data.
# The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
# * +maxlen+ - the maximum number of bytes to receive from the socket
# * +flags+ - zero or more of the +MSG_+ options
# * +outbuf+ - destination String buffer
# * +opts+ - keyword hash, supporting `exception: false`
# # In one file, start this first
# include Socket::Constants
# socket = Socket.new(AF_INET, SOCK_STREAM, 0)
# sockaddr = Socket.sockaddr_in(2200, 'localhost')
# client, client_addrinfo = socket.accept
# begin # emulate blocking recvfrom
# pair = client.recvfrom_nonblock(20)
# rescue IO::WaitReadable