class Addrinfo # # call-seq: # Addrinfo.new(sockaddr, family=Socket::PF_UNSPEC, socktype=0, protocol=0) -> addrinfo # # Creates a new Addrinfo object from socket address information. # sockaddr can be a packed sockaddr string or an array representation. # # Addrinfo.new(Socket.sockaddr_in(80, "127.0.0.1")) # Addrinfo.new(["AF_INET", 80, "localhost", "127.0.0.1"]) # Addrinfo.new(["AF_UNIX", "/tmp/socket"]) # def initialize(sockaddr, family=Socket::PF_UNSPEC, socktype=0, protocol=0) @hostname = nil if sockaddr.is_a? Array sary = sockaddr if sary[0] == 'AF_INET' || sary[0] == 'AF_INET6' @sockaddr = Socket.sockaddr_in(sary[1], sary[3]) @hostname = sary[2] elsif sary[0] == 'AF_UNIX' @sockaddr = Socket.sockaddr_un(sary[1]) end else @sockaddr = sockaddr.dup end if family == Socket::PF_UNSPEC or family == nil @family = Socket._sockaddr_family(@sockaddr) else @family = family end @socktype = socktype @protocol = protocol end # # call-seq: # Addrinfo.foreach(nodename, service, family=nil, socktype=nil, protocol=nil, flags=0) { |addrinfo| block } -> array # # Iterates over all address information for the given nodename and service. # Returns an array of Addrinfo objects. # # Addrinfo.foreach("www.example.com", "http") { |ai| puts ai.ip_address } # Addrinfo.foreach("localhost", 80) { |ai| puts ai.inspect } # def self.foreach(nodename, service, family=nil, socktype=nil, protocol=nil, flags=0, &block) a = self.getaddrinfo(nodename, service, family, socktype, protocol, flags) a.each {|ai| block.call(ai) } a end # # call-seq: # Addrinfo.ip(host) -> addrinfo # # Creates an Addrinfo object for the given host with port 0. # Useful for creating address info without specifying a port. # # Addrinfo.ip("127.0.0.1") #=> # # Addrinfo.ip("::1") #=> # # def self.ip(host) Addrinfo.new(Socket.sockaddr_in(0, host)) end # # call-seq: # Addrinfo.tcp(host, port) -> addrinfo # # Creates an Addrinfo object for TCP connection to the given host and port. # # Addrinfo.tcp("localhost", 80) #=> # # Addrinfo.tcp("www.example.com", 443) #=> # # def self.tcp(host, port) Addrinfo.getaddrinfo(host, port, nil, Socket::SOCK_STREAM, Socket::IPPROTO_TCP)[0] end # # call-seq: # Addrinfo.udp(host, port) -> addrinfo # # Creates an Addrinfo object for UDP connection to the given host and port. # # Addrinfo.udp("localhost", 53) #=> # # Addrinfo.udp("8.8.8.8", 53) #=> # # def self.udp(host, port) Addrinfo.getaddrinfo(host, port, nil, Socket::SOCK_DGRAM, Socket::IPPROTO_UDP)[0] end # # call-seq: # Addrinfo.unix(path, socktype=Socket::SOCK_STREAM) -> addrinfo # # Creates an Addrinfo object for Unix domain socket at the given path. # # Addrinfo.unix("/tmp/socket") #=> # # Addrinfo.unix("/var/run/daemon.sock", Socket::SOCK_DGRAM) #=> # # def self.unix(path, socktype=Socket::SOCK_STREAM) Addrinfo.new(Socket.sockaddr_un(path), Socket::AF_UNIX, socktype) end # # call-seq: # addrinfo.afamily -> integer # # Returns the address family of the socket address. # # Addrinfo.tcp("localhost", 80).afamily #=> 2 (AF_INET) # Addrinfo.unix("/tmp/sock").afamily #=> 1 (AF_UNIX) # # # call-seq: # addrinfo.afamily -> integer # # Returns the address family of the socket address. # # Addrinfo.tcp("localhost", 80).afamily #=> 2 (AF_INET) # Addrinfo.unix("/tmp/sock").afamily #=> 1 (AF_UNIX) # def afamily @family end #def bind #def canonname #def connect #def connect_from #def connect_to #def family_addrinfo(host, port=nil) #def getnameinfo(flags=0) # Socket.getnameinfo #end # # call-seq: # addrinfo.inspect -> string # # Returns a string representation of the Addrinfo object. # # Addrinfo.tcp("localhost", 80).inspect #=> "#" # Addrinfo.unix("/tmp/sock").inspect #=> "#" # def inspect if ipv4? or ipv6? if @protocol == Socket::IPPROTO_TCP or (@socktype == Socket::SOCK_STREAM and @protocol == 0) proto = 'TCP' elsif @protocol == Socket::IPPROTO_UDP or (@socktype == Socket::SOCK_DGRAM and @protocol == 0) proto = 'UDP' else proto = '???' end else proto = "SOCK_STREAM" end "#" end # # call-seq: # addrinfo.inspect_sockaddr -> string # # Returns a string representation of the socket address portion. # # Addrinfo.tcp("localhost", 80).inspect_sockaddr #=> "127.0.0.1:80" # Addrinfo.unix("/tmp/sock").inspect_sockaddr #=> "/tmp/sock" # def inspect_sockaddr if ipv4? a, p = ip_unpack "#{a}:#{p}" elsif ipv6? a, p = ip_unpack "[#{a}]:#{p}" elsif unix? unix_path else '???' end end # # call-seq: # addrinfo.ip? -> true or false # # Returns true if the address is an IP address (IPv4 or IPv6). # # Addrinfo.tcp("localhost", 80).ip? #=> true # Addrinfo.unix("/tmp/sock").ip? #=> false # def ip? ipv4? or ipv6? end # # call-seq: # addrinfo.ip_address -> string # # Returns the IP address as a string. Raises an exception if not an IP address. # # Addrinfo.tcp("localhost", 80).ip_address #=> "127.0.0.1" # Addrinfo.udp("::1", 53).ip_address #=> "::1" # def ip_address ip_unpack[0] end # # call-seq: # addrinfo.ip_port -> integer # # Returns the port number. Raises an exception if not an IP address. # # Addrinfo.tcp("localhost", 80).ip_port #=> 80 # Addrinfo.udp("127.0.0.1", 53).ip_port #=> 53 # def ip_port ip_unpack[1] end # # call-seq: # addrinfo.ip_unpack -> [ip_address, port] # # Returns an array containing the IP address and port number. # # Addrinfo.tcp("localhost", 80).ip_unpack #=> ["127.0.0.1", 80] # Addrinfo.udp("::1", 53).ip_unpack #=> ["::1", 53] # def ip_unpack h, p = getnameinfo(Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV) [ h, p.to_i ] end # # call-seq: # addrinfo.ipv4? -> true or false # # Returns true if the address is an IPv4 address. # # Addrinfo.tcp("127.0.0.1", 80).ipv4? #=> true # Addrinfo.tcp("::1", 80).ipv4? #=> false # def ipv4? @family == Socket::AF_INET end #def ipv4_loopback? #def ipv4_multicast? #def ipv4_private? # # call-seq: # addrinfo.ipv6? -> true or false # # Returns true if the address is an IPv6 address. # # Addrinfo.tcp("::1", 80).ipv6? #=> true # Addrinfo.tcp("127.0.0.1", 80).ipv6? #=> false # def ipv6? @family == Socket::AF_INET6 end #def ipv6_loopback? #def ipv6_mc_global? #def ipv6_mc_linklocal? #def ipv6_mc_nodelocal? #def ipv6_mc_orilocal? #def ipv6_mc_sitelocal? #def ipv6_multicast? #def ipv6_to_ipv4 #def ipv6_unspecified #def ipv6_v4compat? #def ipv6_v4mapped? #def listen(backlog=5) # # call-seq: # addrinfo.pfamily -> integer # # Returns the protocol family (same as afamily). # # Addrinfo.tcp("localhost", 80).pfamily #=> 2 (PF_INET) # Addrinfo.unix("/tmp/sock").pfamily #=> 1 (PF_UNIX) # def pfamily @family end # # call-seq: # addrinfo.protocol -> integer # # Returns the protocol number. # # Addrinfo.tcp("localhost", 80).protocol #=> 6 (IPPROTO_TCP) # Addrinfo.udp("localhost", 53).protocol #=> 17 (IPPROTO_UDP) # attr_reader :protocol # # call-seq: # addrinfo.socktype -> integer # # Returns the socket type. # # Addrinfo.tcp("localhost", 80).socktype #=> 1 (SOCK_STREAM) # Addrinfo.udp("localhost", 53).socktype #=> 2 (SOCK_DGRAM) # attr_reader :socktype # # call-seq: # addrinfo._to_array -> array # # Internal method that returns the address information as an array. # Used internally by socket operations. # def _to_array case @family when Socket::AF_INET s = "AF_INET" when Socket::AF_INET6 s = "AF_INET6" when Socket::AF_UNIX s = "AF_UNIX" else s = "(unknown AF)" end addr, port = self.getnameinfo(Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV) [ s, port.to_i, addr, addr ] end # # call-seq: # addrinfo.to_sockaddr -> string # # Returns the socket address as a packed string. # # ai = Addrinfo.tcp("localhost", 80) # ai.to_sockaddr #=> packed sockaddr string # def to_sockaddr @sockaddr end alias to_s to_sockaddr # # call-seq: # addrinfo.unix? -> true or false # # Returns true if the address is a Unix domain socket address. # # Addrinfo.unix("/tmp/sock").unix? #=> true # Addrinfo.tcp("localhost", 80).unix? #=> false # def unix? @family == Socket::AF_UNIX end end class BasicSocket < IO @@do_not_reverse_lookup = true # # call-seq: # BasicSocket.do_not_reverse_lookup -> true or false # # Returns the current setting for reverse DNS lookups. # # BasicSocket.do_not_reverse_lookup #=> false # def self.do_not_reverse_lookup @@do_not_reverse_lookup end # # call-seq: # BasicSocket.do_not_reverse_lookup = boolean -> boolean # # Sets whether to perform reverse DNS lookups. # # BasicSocket.do_not_reverse_lookup = true # def self.do_not_reverse_lookup=(val) @@do_not_reverse_lookup = val ? true : false end # # call-seq: # BasicSocket.new(*args) -> basicsocket # # Creates a new BasicSocket object. This is typically called by subclasses. # def initialize(*args) super(*args) self._is_socket = true @do_not_reverse_lookup = @@do_not_reverse_lookup end # # call-seq: # BasicSocket.for_fd(fd) -> basicsocket # # Creates a BasicSocket object from an existing file descriptor. # # sock = BasicSocket.for_fd(3) # def self.for_fd(fd) super(fd, "r+") end #def connect_address # # call-seq: # basicsocket.local_address -> addrinfo # # Returns an Addrinfo object for the local address of the socket. # # sock.local_address #=> # # def local_address Addrinfo.new self.getsockname end # # call-seq: # basicsocket.recv_nonblock(maxlen, flags=0) -> string # # Receives data from the socket without blocking. May raise an exception # if no data is available. # # data = sock.recv_nonblock(1024) # def recv_nonblock(maxlen, flags=0) begin _setnonblock(true) recv(maxlen, flags) ensure _setnonblock(false) end end # # call-seq: # basicsocket.remote_address -> addrinfo # # Returns an Addrinfo object for the remote address of the socket. # # sock.remote_address #=> # # def remote_address Addrinfo.new self.getpeername end attr_accessor :do_not_reverse_lookup end class IPSocket < BasicSocket # # call-seq: # IPSocket.getaddress(host) -> string # # Returns the IP address of the given hostname as a string. # # IPSocket.getaddress("localhost") #=> "127.0.0.1" # IPSocket.getaddress("www.ruby-lang.org") #=> "150.95.145.38" # def self.getaddress(host) Addrinfo.ip(host).ip_address end # # call-seq: # ipsocket.addr -> [family, port, hostname, ip_address] # # Returns the local address information as an array. # # sock.addr #=> ["AF_INET", 12345, "localhost", "127.0.0.1"] # def addr Addrinfo.new(self.getsockname)._to_array end # # call-seq: # ipsocket.peeraddr -> [family, port, hostname, ip_address] # # Returns the remote address information as an array. # # sock.peeraddr #=> ["AF_INET", 80, "example.com", "93.184.216.34"] # def peeraddr Addrinfo.new(self.getpeername)._to_array end # # call-seq: # ipsocket.recvfrom(maxlen, flags=0) -> [data, addrinfo] # # Receives data and sender information from the IP socket. # # data, addr = sock.recvfrom(1024) # data, addr = sock.recvfrom(512, 0) # def recvfrom(maxlen, flags=0) msg, sa = _recvfrom(maxlen, flags) [ msg, Addrinfo.new(sa)._to_array ] end end class TCPSocket < IPSocket # # call-seq: # TCPSocket.new(host, service, local_host=nil, local_service=nil) -> tcpsocket # # Creates a new TCP socket connected to the given host and service. # Optionally binds to local_host and local_service first. # # sock = TCPSocket.new("localhost", 80) # sock = TCPSocket.new("www.example.com", "http") # sock = TCPSocket.new("remote", 80, "127.0.0.1", 12345) # def initialize(host, service, local_host=nil, local_service=nil) if @init_with_fd super(host, service) else s = nil e = SocketError Addrinfo.foreach(host, service) {|ai| begin s = Socket._socket(ai.afamily, Socket::SOCK_STREAM, 0) if local_host or local_service local_host ||= (ai.afamily == Socket::AF_INET) ? "0.0.0.0" : "::" local_service ||= "0" bi = Addrinfo.getaddrinfo(local_host, local_service, ai.afamily, ai.socktype)[0] Socket._bind(s, bi.to_sockaddr) end Socket._connect(s, ai.to_sockaddr) super(s, "r+") return rescue => e0 e = e0 end } raise e end end #def self.gethostbyname(host) end class TCPServer < TCPSocket # # call-seq: # TCPServer.new(host=nil, service) -> tcpserver # # Creates a new TCP server socket bound to the given host and service. # If host is nil, binds to all available interfaces. # # server = TCPServer.new("localhost", 8080) # server = TCPServer.new(nil, 3000) # binds to all interfaces # server = TCPServer.new("0.0.0.0", "http") # def initialize(host=nil, service) ai = Addrinfo.getaddrinfo(host, service, nil, nil, nil, Socket::AI_PASSIVE)[0] @init_with_fd = true super(Socket._socket(ai.afamily, Socket::SOCK_STREAM, 0), "r+") if Socket.const_defined?(:SO_REUSEADDR) self.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true) end Socket._bind(self.fileno, ai.to_sockaddr) listen(5) self end # # call-seq: # tcpserver.accept -> tcpsocket # # Accepts an incoming connection and returns a new TCPSocket. # # server = TCPServer.new(8080) # client = server.accept # def accept fd = self.sysaccept begin s = TCPSocket._allocate s.instance_eval{ @init_with_fd = true } s.__send__(:initialize, fd, "r+") s rescue => e IO._sysclose(fd) rescue nil raise e end end # # call-seq: # tcpserver.accept_nonblock -> unixsocket # # Accepts an incoming connection without blocking. May raise an exception # if no connection is available. # # client = server.accept_nonblock # def accept_nonblock begin self._setnonblock(true) self.accept ensure self._setnonblock(false) end end # # call-seq: # unixserver.listen(backlog) -> 0 # # Sets the socket to listen for incoming connections with the given backlog. # # server.listen(5) # server.listen(128) # def listen(backlog) Socket._listen(self.fileno, backlog) 0 end # # call-seq: # tcpserver.sysaccept -> integer # # Accepts an incoming connection and returns the file descriptor. # # fd = server.sysaccept # def sysaccept Socket._accept(self.fileno) end end class UDPSocket < IPSocket # # call-seq: # UDPSocket.new(af=Socket::AF_INET) -> udpsocket # # Creates a new UDP socket for the given address family. # # sock = UDPSocket.new # sock = UDPSocket.new(Socket::AF_INET6) # def initialize(af=Socket::AF_INET) super(Socket._socket(af, Socket::SOCK_DGRAM, 0), "r+") @af = af self end # # call-seq: # ipsocket.bind(host, port) -> 0 # # Binds the socket to the given host and port. # # sock.bind("127.0.0.1", 8080) # sock.bind("0.0.0.0", 3000) # def bind(host, port) Socket._bind(self.fileno, _sockaddr_in(port, host)) 0 end # # call-seq: # ipsocket.connect(host, port) -> 0 # # Connects the socket to the given host and port. # # sock.connect("127.0.0.1", 80) # sock.connect("www.example.com", 443) # def connect(host, port) Socket._connect(self.fileno, _sockaddr_in(port, host)) 0 end # # call-seq: # udpsocket.recvfrom_nonblock(maxlen, flags=0) -> [data, addrinfo] # # Receives data and sender information without blocking. # May raise an exception if no data is available. # # data, addr = sock.recvfrom_nonblock(1024) # def recvfrom_nonblock(*args) begin self._setnonblock(true) self.recvfrom(*args) ensure self._setnonblock(false) end end # # call-seq: # ipsocket.send(mesg, flags, host=nil, port=nil) -> integer # # Sends data through the socket. Returns the number of bytes sent. # # sock.send("Hello", 0) # sock.send("Data", 0, "127.0.0.1", 8080) # def send(mesg, flags, host=nil, port=nil) if port super(mesg, flags, _sockaddr_in(port, host)) elsif host super(mesg, flags, host) else super(mesg, flags) end end # # call-seq: # udpsocket._sockaddr_in(port, host) -> string # # Internal method to create a sockaddr_in structure for the given port and host. # Uses the socket's address family. # def _sockaddr_in(port, host) ai = Addrinfo.getaddrinfo(host, port, @af, Socket::SOCK_DGRAM)[0] ai.to_sockaddr end end class Socket < BasicSocket # # call-seq: # Socket.new(domain, type, protocol=0) -> socket # # Creates a new socket with the given domain, type, and protocol. # # sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) # sock = Socket.new(Socket::AF_UNIX, Socket::SOCK_DGRAM) # def initialize(domain, type, protocol=0) super(Socket._socket(domain, type, protocol), "r+") end #def self.accept_loop # # call-seq: # Socket.getaddrinfo(nodename, servname, family=nil, socktype=nil, protocol=nil, flags=0) -> array # # Returns an array of Addrinfo objects for the given nodename and servname. # # Addrinfo.getaddrinfo("localhost", "http") # Addrinfo.getaddrinfo("www.example.com", 80, Socket::AF_INET) # def self.getaddrinfo(nodename, servname, family=nil, socktype=nil, protocol=nil, flags=0) Addrinfo.getaddrinfo(nodename, servname, family, socktype, protocol, flags).map {|ai| ary = ai._to_array ary[2] = nodename ary[4] = ai.afamily ary[5] = ai.socktype ary[6] = ai.protocol ary } end #def self.getnameinfo #def self.ip_address_list # # call-seq: # Socket.open(domain, type, protocol=0) -> socket # # Creates a new socket. Alias for Socket.new. # # sock = Socket.open(Socket::AF_INET, Socket::SOCK_STREAM) # def self.open(*args) new(args) end # # call-seq: # Socket.sockaddr_in(port, host) -> string # # Returns a packed sockaddr_in structure for the given port and host. # # Socket.sockaddr_in(80, "127.0.0.1") # Socket.sockaddr_in(443, "localhost") # def self.sockaddr_in(port, host) ai = Addrinfo.getaddrinfo(host, port, nil, Socket::SOCK_DGRAM)[0] ai.to_sockaddr end #def self.tcp #def self.tcp_server_loop #def self.tcp_server_sockets #def self.udp_server_loop #def self.udp_server_loop_on #def self.udp_server_recv #def self.udp_server_sockets #def self.unix(path) #def self.unix_server_loop #def self.unix_server_socket # # call-seq: # Socket.unpack_sockaddr_in(sockaddr) -> [port, ip_address] # # Unpacks a packed sockaddr_in structure and returns port and IP address. # # port, addr = Socket.unpack_sockaddr_in(sockaddr) # def self.unpack_sockaddr_in(sa) Addrinfo.new(sa).ip_unpack.reverse end # # call-seq: # Socket.unpack_sockaddr_un(sockaddr) -> path # # Unpacks a packed sockaddr_un structure and returns the Unix socket path. # # path = Socket.unpack_sockaddr_un(sockaddr) # def self.unpack_sockaddr_un(sa) Addrinfo.new(sa).unix_path end class << self alias pack_sockaddr_in sockaddr_in alias pack_sockaddr_un sockaddr_un alias pair socketpair end def accept fd, addr = self.sysaccept [ Socket.for_fd(fd), addr ] end def accept_nonblock begin self._setnonblock(true) self.accept ensure self._setnonblock(false) end end # # call-seq: # socket.bind(sockaddr) -> 0 # # Binds the socket to the given socket address. # # sock.bind(Socket.sockaddr_in(8080, "127.0.0.1")) # sock.bind(addrinfo) # def bind(sockaddr) sockaddr = sockaddr.to_sockaddr if sockaddr.is_a? Addrinfo Socket._bind(self.fileno, sockaddr) 0 end # # call-seq: # socket.connect(sockaddr) -> 0 # # Connects the socket to the given socket address. # # sock.connect(Socket.sockaddr_in(80, "127.0.0.1")) # sock.connect(addrinfo) # def connect(sockaddr) sockaddr = sockaddr.to_sockaddr if sockaddr.is_a? Addrinfo Socket._connect(self.fileno, sockaddr) 0 end # # call-seq: # socket.connect_nonblock(sockaddr) -> 0 # # Connects the socket to the given address without blocking. # May raise an exception if the connection cannot be completed immediately. # # sock.connect_nonblock(sockaddr) # def connect_nonblock(sockaddr) begin self._setnonblock(true) self.connect(sockaddr) ensure self._setnonblock(false) end end #def ipv6only! def listen(backlog) Socket._listen(self.fileno, backlog) 0 end def recvfrom(maxlen, flags=0) msg, sa = _recvfrom(maxlen, flags) socktype = self.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE).int [ msg, Addrinfo.new(sa, Socket::PF_UNSPEC, socktype) ] end def recvfrom_nonblock(*args) begin self._setnonblock(true) self._recvfrom(*args) ensure self._setnonblock(false) end end def sysaccept Socket._accept2(self.fileno) end end class UNIXSocket < BasicSocket # # call-seq: # UNIXSocket.new(path) -> unixsocket # UNIXSocket.new(path) { |sock| block } -> obj # # Creates a new Unix domain socket connected to the given path. # If a block is given, yields the socket and closes it when done. # # sock = UNIXSocket.new("/tmp/socket") # UNIXSocket.new("/tmp/socket") { |s| s.write("data") } # def initialize(path, &block) if self.is_a? UNIXServer super(path, "r") else super(Socket._socket(Socket::AF_UNIX, Socket::SOCK_STREAM, 0), "r+") Socket._connect(self.fileno, Socket.sockaddr_un(path)) if block_given? begin yield self ensure begin self.close unless self.closed? rescue StandardError end end end end end class << self # # call-seq: # UNIXSocket.socketpair(type=Socket::SOCK_STREAM, protocol=0) -> [socket1, socket2] # # Creates a pair of connected Unix domain sockets. # # sock1, sock2 = UNIXSocket.socketpair # sock1, sock2 = UNIXSocket.socketpair(Socket::SOCK_DGRAM) # def socketpair(type=Socket::SOCK_STREAM, protocol=0) a = Socket.socketpair(Socket::AF_UNIX, type, protocol) [ UNIXSocket.for_fd(a[0]), UNIXSocket.for_fd(a[1]) ] end alias pair socketpair end # # call-seq: # unixsocket.addr -> [family, path] # # Returns the local address information as an array. # # sock.addr #=> ["AF_UNIX", "/tmp/socket"] # def addr [ "AF_UNIX", path ] end # # call-seq: # unixsocket.path -> string # # Returns the path of the Unix domain socket. # # sock.path #=> "/tmp/socket" # def path Addrinfo.new(self.getsockname).unix_path end # # call-seq: # unixsocket.peeraddr -> [family, path] # # Returns the remote address information as an array. # # sock.peeraddr #=> ["AF_UNIX", "/tmp/peer_socket"] # def peeraddr [ "AF_UNIX", Addrinfo.new(self.getpeername).unix_path ] end #def recv_io def recvfrom(maxlen, flags=0) msg, sa = _recvfrom(maxlen, flags) path = (sa.size > 0) ? Addrinfo.new(sa).unix_path : "" [ msg, [ "AF_UNIX", path ] ] end #def send_io end class UNIXServer < UNIXSocket # # call-seq: # UNIXServer.new(path) -> unixserver # # Creates a new Unix domain server socket bound to the given path. # # server = UNIXServer.new("/tmp/server_socket") # def initialize(path) fd = Socket._socket(Socket::AF_UNIX, Socket::SOCK_STREAM, 0) begin super(fd) Socket._bind(fd, Socket.pack_sockaddr_un(path)) self.listen(5) rescue => e IO._sysclose(fd) rescue nil raise e end if block_given? begin yield self ensure self.close rescue nil unless self.closed? end end end # # call-seq: # unixserver.accept -> unixsocket # # Accepts an incoming connection and returns a new UNIXSocket. # # server = UNIXServer.new("/tmp/server") # client = server.accept # def accept fd = self.sysaccept begin sock = UNIXSocket.for_fd(fd) rescue IO._sysclose(fd) rescue nil end sock end # # call-seq: # unixserver.accept_nonblock -> unixsocket # # Accepts an incoming connection without blocking. May raise an exception # if no connection is available. # # client = server.accept_nonblock # def accept_nonblock begin self._setnonblock(true) self.accept ensure self._setnonblock(false) end end # # call-seq: # unixserver.listen(backlog) -> 0 # # Sets the socket to listen for incoming connections with the given backlog. # # server.listen(5) # server.listen(128) # def listen(backlog) Socket._listen(self.fileno, backlog) 0 end # # call-seq: # unixserver.sysaccept -> integer # # Accepts an incoming connection and returns the file descriptor. # # fd = server.sysaccept # def sysaccept Socket._accept(self.fileno) end end class SocketError < StandardError; end