Grammar and stream of consciousness cleanup for Channel and Scheduler rdoc
[rbx.git] / lib / socket.rb
blobfca89203c937437438db3d10d838be68e6fc5574
1 require 'fcntl'
3 class SocketError < StandardError
4 end
6 class BasicSocket < IO
7   def self.do_not_reverse_lookup=(setting)
8     @no_reverse_lookup = setting
9   end
11   def self.do_not_reverse_lookup
12     @no_reverse_lookup ? true : false
13   end
15   def getsockopt(level, optname)
16     Socket::Foreign.getsockopt descriptor, level, optname
17   end
19   def setsockopt(level, optname, optval)
20     optval = 1 if optval == true
21     optval = 0 if optval == false
23     error = 0
25     case optval
26     when Fixnum then
27       MemoryPointer.new :socklen_t do |val|
28         val.write_int optval
29         error = Socket::Foreign.setsockopt(descriptor, level, optname, val,
30                                            val.size)
31       end
32     when String then
33       MemoryPointer.new optval.size do |val|
34         val.write_string optval
35         error = Socket::Foreign.setsockopt(descriptor, level, optname, val,
36                                            optval.size)
37       end
38     else
39       raise "socket option should be a String, a Fixnum, true, or false"
40     end
42     Errno.handle "Unable to set socket option" unless error == 0
44     return 0
45   end
47   def getsockname()
48     return Socket::Foreign.getsockname(descriptor)
49   end
51   def send(msg, flags, *rest)
52     if ((rest.size != 2) && (rest.size != 0))
53       raise ArgumentError, '#send takes 0 or 2 arguments, passed #{rest.size}'
54     end
55     
56     connect(*rest) if rest.size == 2
57     bytes = msg.length
58     bytes_sent = 0
59     MemoryPointer.new :char, bytes + 1 do |buffer|
60       buffer.write_string msg
61       bytes_sent = Socket::Foreign.send(descriptor, buffer, bytes, flags)
62       Errno.handle 'send(2)' if bytes_sent < 0
63     end
64     return bytes_sent
65   end
67   def recv(bytes_to_read, flags = 0)
68     bytes_to_read = Type.coerce_to bytes_to_read, Fixnum, :to_int
69     buffer = MemoryPointer.new :char, bytes_to_read + 1
70     # Wait until we have something to read, so we don't block other threads
71     IO.select([self])
72     bytes_read = Socket::Foreign.recv(descriptor, buffer, bytes_to_read, flags)
73     Errno.handle 'recv(2)' if bytes_read < 0
74     message = buffer.read_string(bytes_read)
75     buffer.free
76     return message
77   end
78 end
80 class Socket < BasicSocket
82   module Constants
83     FFI.config_hash("socket").each do |name, value|
84       const_set name, value
85     end
87     families = FFI.config_hash('socket').select { |name,| name =~ /^AF_/ }
88     families = families.map { |name, value| [value, name] }
90     AF_TO_FAMILY = Hash[*families.flatten]
91   end
93   module Foreign
94     class AddrInfo < FFI::Struct
95       config("rbx.platform.addrinfo", :ai_flags, :ai_family, :ai_socktype,
96              :ai_protocol, :ai_addrlen, :ai_addr, :ai_canonname, :ai_next)
97     end
99     attach_function "accept", :accept, [:int, :pointer, :pointer], :int
100     attach_function "bind", :_bind, [:int, :pointer, :socklen_t], :int
101     attach_function "close", :close, [:int], :int
102     attach_function "connect", :_connect, [:int, :pointer, :socklen_t], :int
103     attach_function "listen", :listen, [:int, :int], :int
104     attach_function "socket", :socket, [:int, :int, :int], :int
105     attach_function "send", :send, [:int, :pointer, :int, :int], :int
106     attach_function "recv", :recv, [:int, :pointer, :int, :int], :int
107     attach_function "recvfrom", :recvfrom, [:int, :pointer, :size_t, :int,
108                     :pointer, :pointer], :int
110     attach_function "getsockopt", :_getsockopt,
111                     [:int, :int, :int, :pointer, :pointer], :int
112     attach_function "setsockopt", :setsockopt,
113                     [:int, :int, :int, :pointer, :socklen_t], :int
115     attach_function "gai_strerror", :gai_strerror, [:int], :string
117     attach_function "getaddrinfo", :_getaddrinfo,
118                     [:string, :string, :pointer, :pointer], :int
119     attach_function "freeaddrinfo", :freeaddrinfo, [:pointer], :void
120     attach_function "getpeername", :_getpeername,
121                     [:int, :pointer, :pointer], :int
122     attach_function "getsockname", :_getsockname,
123                     [:int, :pointer, :pointer], :int
125     attach_function "socketpair", :socketpair,
126                     [:int, :int, :int, :pointer], :int
128     attach_function "gethostname", :gethostname, [:pointer, :size_t], :int
129     attach_function "getservbyname", :getservbyname,
130                     [:pointer, :pointer], :pointer
132     attach_function "htons", :htons, [:u_int16_t], :u_int16_t
133     attach_function "ntohs", :ntohs, [:u_int16_t], :u_int16_t
135     attach_function "getnameinfo", :_getnameinfo,
136                     [:pointer, :socklen_t, :pointer, :socklen_t,
137                      :pointer, :socklen_t, :int], :int
139     def self.bind(descriptor, sockaddr)
140       MemoryPointer.new :char, sockaddr.length do |sockaddr_p|
141         sockaddr_p.write_string sockaddr, sockaddr.length
143         _bind descriptor, sockaddr_p, sockaddr.length
144       end
145     end
147     def self.connect(descriptor, sockaddr)
148       err = 0
149       MemoryPointer.new :char, sockaddr.length do |sockaddr_p|
150         sockaddr_p.write_string sockaddr, sockaddr.length
152         err = _connect descriptor, sockaddr_p, sockaddr.length
153       end
155       getsockopt(descriptor, Socket::SOL_SOCKET, Socket::SO_ERROR) if err < 0
156       err
157     end
159     def self.getsockopt(descriptor, level, optname)
160       MemoryPointer.new 256 do |val| # HACK magic number
161         MemoryPointer.new :socklen_t do |length|
162           length.write_int 256 # HACK magic number
164           err = Socket::Foreign._getsockopt descriptor, level, optname, val, length
166           Errno.handle "Unable to get socket option" unless err == 0
168           return val.read_string(length.read_int)
169         end
170       end
171     end
173     def self.getaddrinfo(host, service = nil, family = 0, socktype = 0,  protocol = 0, flags = 0)
174       hints = Socket::Foreign::AddrInfo.new
175       hints[:ai_family] = family
176       hints[:ai_socktype] = socktype
177       hints[:ai_protocol] = protocol
178       hints[:ai_flags] = flags
179       host = "" if host.nil?
181       if host.empty?
182         if (flags & Socket::AI_PASSIVE == 1) # Passive socket
183           family == Socket::AF_INET6 ? (host = "::") : (host = "0.0.0.0") # IPv6 or IPv4
184         else
185           family == Socket::AF_INET6 ? (host = "::1") : (host = "127.0.0.1")
186         end
187       end
189       res_p = MemoryPointer.new :pointer
191       err = _getaddrinfo host, service, hints.pointer, res_p
193       raise SocketError, Socket::Foreign.gai_strerror(err) unless err == 0
195       ptr = res_p.read_pointer
197       return [] unless ptr
199       res = Socket::Foreign::AddrInfo.new ptr
201       addrinfos = []
203       loop do
204         addrinfo = []
205         addrinfo << res[:ai_flags]
206         addrinfo << res[:ai_family]
207         addrinfo << res[:ai_socktype]
208         addrinfo << res[:ai_protocol]
209         addrinfo << res[:ai_addr].read_string(res[:ai_addrlen])
210         addrinfo << res[:ai_canonname]
212         addrinfos << addrinfo
214         break unless res[:ai_next]
216         res = Socket::Foreign::AddrInfo.new res[:ai_next]
217       end
219       return addrinfos
220     ensure
221       hints.free if hints
223       if res_p then
224         ptr = res_p.read_pointer
226         # Be sure to feed a legit pointer to freeaddrinfo
227         if ptr and !ptr.null?
228           Socket::Foreign.freeaddrinfo ptr
229         end
230         res_p.free
231       end
232     end
234     def self.getaddress(host)
235       addrinfos = Socket::Foreign.getaddrinfo(host)
236       Socket::Foreign.unpack_sockaddr_in(addrinfos.first[4], false).first
237     end
239     def self.getnameinfo(sockaddr,
240                          reverse_lookup = !BasicSocket.do_not_reverse_lookup)
241       name_info = []
242       value = nil
244       MemoryPointer.new :char, sockaddr.length do |sockaddr_p|
245         MemoryPointer.new :char, Socket::Constants::NI_MAXHOST do |node|
246           MemoryPointer.new :char, Socket::Constants::NI_MAXSERV do |service|
247             sockaddr_p.write_string sockaddr, sockaddr.length
249             if reverse_lookup then
250               err = _getnameinfo(sockaddr_p, sockaddr.length,
251                                  node, Socket::Constants::NI_MAXHOST, nil, 0, 0)
253               unless err == 0 then
254                 raise SocketError, Socket::Foreign.gai_strerror(err)
255               end
257               name_info[2] = node.read_string
258             end
260             err = _getnameinfo(sockaddr_p, sockaddr.length,
261                                node, Socket::Constants::NI_MAXHOST,
262                                service, Socket::Constants::NI_MAXSERV,
263                                Socket::Constants::NI_NUMERICHOST |
264                                  Socket::Constants::NI_NUMERICSERV)
266             unless err == 0 then
267               raise SocketError, Socket::Foreign.gai_strerror(err)
268             end
270             sa_family = SockAddr_In.new(sockaddr)[:sin_family]
272             name_info[0] = Socket::Constants::AF_TO_FAMILY[sa_family]
273             name_info[1] = Integer service.read_string
274             name_info[3] = node.read_string
275           end
276         end
277       end
279       name_info[2] = name_info[3] if name_info[2].nil?
280       name_info
281     end
283     def self.getpeername(descriptor)
284       MemoryPointer.new :char, 128 do |sockaddr_storage_p|
285         MemoryPointer.new :socklen_t do |len_p|
286           len_p.write_int 128
288           err = _getpeername descriptor, sockaddr_storage_p, len_p
290           Errno.handle 'getpeername(2)' unless err == 0
292           sockaddr_storage_p.read_string len_p.read_int
293         end
294       end
295     end
297     def self.getsockname(descriptor)
298       MemoryPointer.new :char, 128 do |sockaddr_storage_p|
299         MemoryPointer.new :socklen_t do |len_p|
300           len_p.write_int 128
302           err = _getsockname descriptor, sockaddr_storage_p, len_p
304           Errno.handle 'getsockname(2)' unless err == 0
306           sockaddr_storage_p.read_string len_p.read_int
307         end
308       end
309     end
311     def self.pack_sockaddr_in(name, port, type, flags)
312       hints = Socket::Foreign::AddrInfo.new
313       hints[:ai_family] = Socket::AF_INET
314       hints[:ai_socktype] = type
315       hints[:ai_flags] = flags
317       res_p = MemoryPointer.new :pointer
319       err = _getaddrinfo name, port, hints.pointer, res_p
321       raise SocketError, Socket::Foreign.gai_strerror(err) unless err == 0
323       return [] if res_p.read_pointer.null?
325       res = Socket::Foreign::AddrInfo.new res_p.read_pointer
327       return res[:ai_addr].read_string(res[:ai_addrlen])
329     ensure
330       hints.free if hints
332       if res_p then
333         ptr = res_p.read_pointer
335         freeaddrinfo ptr if ptr and not ptr.null?
337         res_p.free
338       end
339     end
341     def self.unpack_sockaddr_in(sockaddr, reverse_lookup)
342       family, port, host, ip = getnameinfo sockaddr, reverse_lookup
343       # On some systems this doesn't fail for families other than AF_INET(6)
344       # so we raise manually here.
345       raise ArgumentError, 'not an AF_INET/AF_INET6 sockaddr' unless family =~ /AF_INET/
346       return host, ip, port
347     end
348   end
350   module ListenAndAccept
351     def listen(backlog)
352       backlog = Type.coerce_to backlog, Fixnum, :to_int
354       err = Socket::Foreign.listen descriptor, backlog
356       Errno.handle 'listen(2)' unless err == 0
358       err
359     end
361     def accept
362       return if closed?
363       wait_til_readable
365       fd = nil
366       sockaddr = nil
368       MemoryPointer.new 1024 do |sockaddr_p| # HACK from MRI
369         MemoryPointer.new :int do |size_p|
370           fd = Socket::Foreign.accept descriptor, sockaddr_p, size_p
371         end
372       end
374       Errno.handle 'accept(2)' if fd < 0
376       socket = self.class.superclass.allocate
377       socket.__send__ :from_descriptor, fd
378     end
379   end
381   include Socket::ListenAndAccept
382   include Socket::Constants
384   class SockAddr_In < FFI::Struct
385     config("rbx.platform.sockaddr_in", :sin_family, :sin_port, :sin_addr, :sin_zero)
387     def initialize(sockaddrin)
388       @p = MemoryPointer.new sockaddrin.size
389       @p.write_string(sockaddrin)
390       super(@p)
391     end
393     def to_s
394       @p.read_string(@p.size)
395     end
397   end
399   class SockAddr_Un < FFI::Struct
400     config("rbx.platform.sockaddr_un", :sun_family, :sun_path)
402     def initialize(filename = nil)
403       maxfnsize = self.size - ( FFI.config("sockaddr_un.sun_family.size") + 1 )
405       if(filename && filename.length > maxfnsize )
406         raise ArgumentError, "too long unix socket path (max: #{fnsize}bytes)"
407       end
408       @p = MemoryPointer.new self.size
409       if filename
410         @p.write_string( [Socket::AF_UNIX].pack("s") + filename )
411       end
412       super(@p)
413     end
415     def to_s
416       @p.read_string(self.size)
417     end
418   end if (FFI.config("sockaddr_un.sun_family.offset") && Socket.const_defined?(:AF_UNIX))
420   def self.getaddrinfo(host, service = nil, family = nil, socktype = nil,
421                        protocol = nil, flags = nil)
422     host = '' if host.nil?
423     service = service.to_s if service
425     family ||= 0
426     socktype ||= 0
427     protocol ||= 0
428     flags ||= 0
430     addrinfos = Socket::Foreign.getaddrinfo(host, service, family, socktype,
431                                             protocol, flags)
433     addrinfos.map do |ai|
434       addrinfo = []
435       addrinfo << Socket::Constants::AF_TO_FAMILY[ai[1]]
437       sockaddr = Socket::Foreign::unpack_sockaddr_in ai[4], true
439       addrinfo << sockaddr.pop # port
440       addrinfo.concat sockaddr # hosts
441       addrinfo << ai[1]
442       addrinfo << ai[2]
443       addrinfo << ai[3]
444       addrinfo
445     end
446   end
448   def self.gethostname
449     MemoryPointer.new :char, 1024 do |mp|  #magic number 1024 comes from MRI
450       Socket::Foreign.gethostname(mp, 1024) # same here
451       return mp.read_string
452     end
453   end
455   class Servent < FFI::Struct
456     config("rbx.platform.servent", :s_name, :s_aliases, :s_port, :s_proto)
458     def initialize(data)
459       @p = MemoryPointer.new data.size
460       @p.write_string(data)
461       super(@p)
462     end
464     def to_s
465       @p.read_string(size)
466     end
468   end
470   def self.getservbyname(service, proto='tcp')
471     MemoryPointer.new :char, service.length + 1 do |svc|
472       MemoryPointer.new :char, proto.length + 1 do |prot|
473         svc.write_string(service + "\0")
474         prot.write_string(proto + "\0")
475         fn = Socket::Foreign.getservbyname(svc, prot)
477         raise SocketError, "no such service #{service}/#{proto}" if fn.nil?
479         s = Servent.new(fn.read_string(Servent.size))
480         return Socket::Foreign.ntohs(s[:s_port])
481       end
482     end
483   end
485   def self.pack_sockaddr_in(port, host, type = Socket::SOCK_DGRAM, flags = 0)
486     host = "0.0.0.0" if host.empty?
487     Socket::Foreign.pack_sockaddr_in host.to_s, port.to_s, type, flags
488   end
490   def self.unpack_sockaddr_in(sockaddr)
491     host, address, port = Socket::Foreign.unpack_sockaddr_in sockaddr, false
493     return [port, address]
494   rescue SocketError => e
495     if e.message =~ /ai_family not supported/ then # HACK platform specific?
496       raise ArgumentError, 'not an AF_INET/AF_INET6 sockaddr'
497     else
498       raise e
499     end
500   end
502   def self.socketpair(domain, type, protocol)
503     MemoryPointer.new :int, 2 do |mp|
504       Socket::Foreign.socketpair(domain, type, protocol, mp)
505       fd0, fd1 = mp.read_array_of_int(2)
507       [ from_descriptor(fd0), from_descriptor(fd1) ]
508     end
509   end
511   class << self
512     alias_method :sockaddr_in, :pack_sockaddr_in
513     alias_method :pair, :socketpair
514   end
516   # Only define these methods if we support unix sockets
517   if self.const_defined?(:SockAddr_Un)
518     def self.pack_sockaddr_un(file)
519       SockAddr_Un.new(file).to_s
520     end
522     def self.unpack_sockaddr_un(addr)
524       if addr.length > FFI.config("sockaddr_un.sizeof")
525         raise TypeError, "too long sockaddr_un - #{addr.length} longer than #{FFI.config("sockaddr_un.sizeof")}"
526       end
528       struct = SockAddr_Un.new
529       struct.pointer.write_string(addr)
531       struct[:sun_path]
532     end
534     class << self
535       alias_method :sockaddr_un, :pack_sockaddr_un
536     end
537   end
539   def initialize(family, socket_type, protocol)
540     descriptor = Socket::Foreign.socket family, socket_type, protocol
542     Errno.handle 'socket(2)' if descriptor < 0
544     setup descriptor
545   end
547   def self.from_descriptor(fixnum)
548     sock = allocate()
549     sock.from_descriptor(fixnum)
550     return sock
551   end
553   def from_descriptor(fixnum)
554     setup(fixnum)
555     return self
556   end
558   def bind(server_sockaddr)
559     err = Socket::Foreign.bind(descriptor, server_sockaddr)
560     Errno.handle 'bind(2)' unless err == 0
561   end
564 class UNIXSocket < BasicSocket
565   attr_accessor :path
567   def initialize(path)
568     @path = path
569     unix_setup
570   end
571   private :initialize
573   def unix_setup(server = false)
574     syscall = 'socket(2)'
575     status = nil
576     sock = Socket::Foreign.socket Socket::Constants::AF_UNIX, Socket::Constants::SOCK_STREAM, 0
578     # TODO - Do we need to sync = true here?
579     setup sock, 'rw'
581     Errno.handle syscall if descriptor < 0
583     sockaddr = Socket.pack_sockaddr_un(@path)
585     if server then
586       syscall = 'bind(2)'
587       status = Socket::Foreign.bind descriptor, sockaddr
588     else
589       syscall = 'connect(2)'
590       status = Socket::Foreign.connect descriptor, sockaddr
591     end
593     if status < 0 then
594       Socket::Foreign.close descriptor
595       Errno.handle syscall
596     end
598     if server then
599       syscall = 'listen(2)'
600       status = Socket::Foreign.listen descriptor, 5
601       Errno.handle syscall if status < 0
602     end
604     return sock
605   end
606   private :unix_setup
608   def addr
609     sockaddr = Socket::Foreign.getsockname descriptor
610     _, sock_path = sockaddr.unpack('SZ*')
611     ["AF_UNIX", sock_path]
612   end
614   def peeraddr
615     sockaddr = Socket::Foreign.getpeername descriptor
616     _, sock_path = sockaddr.unpack('SZ*')
617     ["AF_UNIX", sock_path]
618   end
620   def from_descriptor(descriptor)
621     setup descriptor
623     self
624   end
625   private :from_descriptor
629 class UNIXServer < UNIXSocket
631   include Socket::ListenAndAccept
633   def initialize(path)
634     @path = path
635     unix_setup(true)
636   end
637   private :initialize
640 class IPSocket < BasicSocket
642   def self.getaddress(host)
643     Socket::Foreign.getaddress host
644   end
646   def addr
647     sockaddr = Socket::Foreign.getsockname descriptor
649     Socket::Foreign.getnameinfo sockaddr
650   end
652   def peeraddr
653     sockaddr = Socket::Foreign.getpeername descriptor
655     Socket::Foreign.getnameinfo sockaddr
656   end
658   def recvfrom(maxlen, flags = 0)
659     maxlen = Type.coerce_to maxlen, Fixnum, :to_int
660     mesg = nil
661     sender_sockaddr = nil
663     MemoryPointer.new(:char, maxlen + 1) do |buffer_p|
664       MemoryPointer.new :char, 128 do |sockaddr_storage_p|
665         MemoryPointer.new :socklen_t do |len_p|
666           len_p.write_int 128
667           bytes_read = Socket::Foreign.recvfrom(descriptor, buffer_p, maxlen,
668             flags, sockaddr_storage_p, len_p)
669           Errno.handle 'recvfrom(2)' if bytes_read < 0
671           mesg = buffer_p.read_string
672           sockaddr = sockaddr_storage_p.read_string(len_p.read_int)
673                                         sockaddr = Socket::Foreign.unpack_sockaddr_in(sockaddr, false)
674           sender_sockaddr = [ "AF_INET", sockaddr[2], sockaddr[0], sockaddr[1] ]
675         end
676       end
677     end
679     return [mesg, sender_sockaddr]
680   end
682   def recvfrom_nonblock(maxlen, flags = 0)
683     # Set socket to non-blocking, if we can
684     # Todo: Ensure this works in Windows!  If not, I claim that's Fcntl's fault.
685     fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
687     # Wait until we have something to read
688     IO.select([self])
689     return recvfrom(maxlen, flags)
690   end
693 class UDPSocket < IPSocket
694   def initialize(*args)
695     socktype = Socket::AF_INET
696     raise ArgumentError, 'too many arguments' if args.size > 1
697     socktype = args[0] if args.size == 1
698     status = Socket::Foreign.socket socktype, Socket::SOCK_DGRAM,
699       Socket::IPPROTO_UDP
700     Errno.handle 'socket(2)' if status < 0
701     setup status
702   end
704   def bind(host, port)
705     @host = host.to_s if host
706     @port = port.to_s if port
708     addrinfos = Socket::Foreign.getaddrinfo(@host,
709                                            @port,
710                                            Socket::AF_UNSPEC,
711                                            Socket::SOCK_DGRAM, 0,
712                                            Socket::AI_PASSIVE)
714     status = -1
716     addrinfos.each do |addrinfo|
717       flags, family, socket_type, protocol, sockaddr, canonname = addrinfo
719       status = Socket::Foreign.bind descriptor, sockaddr
720       syscall = 'bind(2)'
722       break if status >= 0
723     end
724     if status < 0
725       Errno.handle syscall
726       Socket::Foreign.close descriptor
727     end
728     status
729   end
731   def connect(host, port)
732     sockaddr = Socket.pack_sockaddr_in(port, host)
733     syscall = 'connect(2)'
734     status = Socket::Foreign.connect descriptor, sockaddr
736     if status < 0 then
737       Socket::Foreign.close descriptor
738       Errno.handle syscall
739     end
740     return 0
741   end
743   def inspect
744     "#<#{self.class}:0x#{object_id.to_s(16)} #{@host}:#{@port}>"
745   end
749 class TCPSocket < IPSocket
751   def self.gethostbyname(hostname)
752     addrinfos = Socket.getaddrinfo(hostname)
754     hostname     = addrinfos.first[2]
755     family       = addrinfos.first[4]
756     addresses    = []
757     alternatives = []
758     addrinfos.each do |a|
759       alternatives << a[2] unless a[2] == hostname
760       addresses    << a[3] if a[4] == family
761     end
763     [hostname, alternatives.uniq, family] + addresses.uniq
764   end
766   def initialize(host, port)
767     @host = host
768     @port = port
770     tcp_setup @host, @port
771   end
772   private :initialize
774   def tcp_setup(remote_host, remote_service, local_host = nil,
775                 local_service = nil, server = false)
776     status = nil
777     syscall = nil
778     remote_host    = remote_host.to_s    if remote_host
779     remote_service = remote_service.to_s if remote_service
781     flags = server ? Socket::AI_PASSIVE : 0
782     @remote_addrinfo = Socket::Foreign.getaddrinfo(remote_host,
783                                                    remote_service,
784                                                    Socket::AF_UNSPEC,
785                                                    Socket::SOCK_STREAM, 0,
786                                                    flags)
788     if server == false and (local_host or local_service) then
789       @local_addrinfo = Socket::Foreign.getaddrinfo(local_host,
790                                                     local_service,
791                                                     Socket::AF_UNSPEC,
792                                                     Socket::SOCK_STREAM, 0, 0)
793     end
795     @remote_addrinfo.each do |addrinfo|
796       flags, family, socket_type, protocol, sockaddr, canonname = addrinfo
798       status = Socket::Foreign.socket family, socket_type, protocol
799       syscall = 'socket(2)'
800       setup status
802       next if descriptor < 0
804       if server then
805         status = 1
807         begin
808           setsockopt(Socket::Constants::SOL_SOCKET,
809                      Socket::Constants::SO_REUSEADDR, true)
810         rescue SystemCallError
811         end
813         status = Socket::Foreign.bind descriptor, sockaddr
814         syscall = 'bind(2)'
815       else
816         if @local_addrinfo then
817           status = bind descriptor, @local_addrinfo.first[4]
818           syscall = 'bind(2)'
819         end
821         if status >= 0 then
822           status = Socket::Foreign.connect descriptor, sockaddr
823           syscall = 'connect(2)'
824         end
825       end
827       break if status >= 0
828     end
830     if status < 0
831       Errno.handle syscall
832       Socket::Foreign.close descriptor
833     end
835     if server then
836       err = Socket::Foreign.listen descriptor, 5
837       Errno.handle syscall unless err == 0
838     end
840     setup descriptor
841   end
842   private :tcp_setup
844   def from_descriptor(descriptor)
845     setup descriptor
847     self
848   end
849   private :from_descriptor
853 class TCPServer < TCPSocket
855   include Socket::ListenAndAccept
857   def initialize(host, port = nil)
858     if Fixnum === host and port.nil? then
859       port = host
860       host = nil
861     end
863     port = StringValue port unless port.__kind_of__ Fixnum
865     @host = host
866     @port = port
868     tcp_setup @host, @port, nil, nil, true
869   end