PageRenderTime 106ms CodeModel.GetById 15ms app.highlight 85ms RepoModel.GetById 2ms app.codeStats 0ms

/IronPython_Main/External.LCA_RESTRICTED/Languages/Ruby/redist-libs/ruby/1.9.1/socket.rb

#
Ruby | 755 lines | 400 code | 36 blank | 319 comment | 93 complexity | dc1a0673385e6647fbd8ff92dce775e8 MD5 | raw file
  1require 'socket.so'
  2
  3class Addrinfo
  4  # creates an Addrinfo object from the arguments.
  5  #
  6  # The arguments are interpreted as similar to self.
  7  #
  8  #   Addrinfo.tcp("0.0.0.0", 4649).family_addrinfo("www.ruby-lang.org", 80)
  9  #   #=> #<Addrinfo: 221.186.184.68:80 TCP (www.ruby-lang.org:80)>
 10  #
 11  #   Addrinfo.unix("/tmp/sock").family_addrinfo("/tmp/sock2")
 12  #   #=> #<Addrinfo: /tmp/sock2 SOCK_STREAM>
 13  #
 14  def family_addrinfo(*args)
 15    if args.empty?
 16      raise ArgumentError, "no address specified"
 17    elsif Addrinfo === args.first
 18      raise ArgumentError, "too many arguments" if args.length != 1
 19    elsif self.ip?
 20      raise ArgumentError, "IP address needs host and port but #{args.length} arguments given" if args.length != 2
 21      host, port = args
 22      Addrinfo.getaddrinfo(host, port, self.pfamily, self.socktype, self.protocol)[0]
 23    elsif self.unix?
 24      raise ArgumentError, "UNIX socket needs single path argument but #{args.length} arguments given" if args.length != 1
 25      path, = args
 26      Addrinfo.unix(path)
 27    else
 28      raise ArgumentError, "unexpected family"
 29    end
 30  end
 31
 32  def connect_internal(local_addrinfo)
 33    sock = Socket.new(self.pfamily, self.socktype, self.protocol)
 34    begin
 35      sock.ipv6only! if self.ipv6?
 36      sock.bind local_addrinfo if local_addrinfo
 37      sock.connect(self)
 38      if block_given?
 39        yield sock
 40      else
 41        sock
 42      end
 43    ensure
 44      sock.close if !sock.closed? && (block_given? || $!)
 45    end
 46  end
 47  private :connect_internal
 48
 49  # creates a socket connected to the address of self.
 50  #
 51  # If one or more arguments given as _local_addr_args_,
 52  # it is used as the local address of the socket.
 53  # _local_addr_args_ is given for family_addrinfo to obtain actual address.
 54  #
 55  # If no arguments given, the local address of the socket is not bound.
 56  #
 57  # If a block is given, it is called with the socket and the value of the block is returned.
 58  # The socket is returned otherwise.
 59  #
 60  #   Addrinfo.tcp("www.ruby-lang.org", 80).connect_from("0.0.0.0", 4649) {|s|
 61  #     s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
 62  #     puts s.read
 63  #   }
 64  #
 65  #   # Addrinfo object can be taken for the argument.
 66  #   Addrinfo.tcp("www.ruby-lang.org", 80).connect_from(Addrinfo.tcp("0.0.0.0", 4649)) {|s|
 67  #     s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
 68  #     puts s.read
 69  #   }
 70  #
 71  def connect_from(*local_addr_args, &block)
 72    connect_internal(family_addrinfo(*local_addr_args), &block)
 73  end
 74
 75  # creates a socket connected to the address of self.
 76  #
 77  # If a block is given, it is called with the socket and the value of the block is returned.
 78  # The socket is returned otherwise.
 79  #
 80  #   Addrinfo.tcp("www.ruby-lang.org", 80).connect {|s|
 81  #     s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
 82  #     puts s.read
 83  #   }
 84  #
 85  def connect(&block)
 86    connect_internal(nil, &block)
 87  end
 88
 89  # creates a socket connected to _remote_addr_args_ and bound to self.
 90  #
 91  # If a block is given, it is called with the socket and the value of the block is returned.
 92  # The socket is returned otherwise.
 93  #
 94  #   Addrinfo.tcp("0.0.0.0", 4649).connect_to("www.ruby-lang.org", 80) {|s|
 95  #     s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
 96  #     puts s.read
 97  #   }
 98  #
 99  def connect_to(*remote_addr_args, &block)
100    remote_addrinfo = family_addrinfo(*remote_addr_args)
101    remote_addrinfo.send(:connect_internal, self, &block)
102  end
103
104  # creates a socket bound to self.
105  #
106  # If a block is given, it is called with the socket and the value of the block is returned.
107  # The socket is returned otherwise.
108  #
109  #   Addrinfo.udp("0.0.0.0", 9981).bind {|s|
110  #     s.local_address.connect {|s| s.send "hello", 0 }
111  #     p s.recv(10) #=> "hello"
112  #   }
113  #
114  def bind
115    sock = Socket.new(self.pfamily, self.socktype, self.protocol)
116    begin
117      sock.ipv6only! if self.ipv6?
118      sock.setsockopt(:SOCKET, :REUSEADDR, 1)
119      sock.bind(self)
120      if block_given?
121        yield sock
122      else
123        sock
124      end
125    ensure
126      sock.close if !sock.closed? && (block_given? || $!)
127    end
128  end
129
130  # creates a listening socket bound to self.
131  def listen(backlog=5)
132    sock = Socket.new(self.pfamily, self.socktype, self.protocol)
133    begin
134      sock.ipv6only! if self.ipv6?
135      sock.setsockopt(:SOCKET, :REUSEADDR, 1)
136      sock.bind(self)
137      sock.listen(backlog)
138      if block_given?
139        yield sock
140      else
141        sock
142      end
143    ensure
144      sock.close if !sock.closed? && (block_given? || $!)
145    end
146  end
147
148  # iterates over the list of Addrinfo objects obtained by Addrinfo.getaddrinfo.
149  #
150  #   Addrinfo.foreach(nil, 80) {|x| p x }
151  #   #=> #<Addrinfo: 127.0.0.1:80 TCP (:80)>
152  #   #   #<Addrinfo: 127.0.0.1:80 UDP (:80)>
153  #   #   #<Addrinfo: [::1]:80 TCP (:80)>
154  #   #   #<Addrinfo: [::1]:80 UDP (:80)>
155  #
156  def self.foreach(nodename, service, family=nil, socktype=nil, protocol=nil, flags=nil, &block)
157    Addrinfo.getaddrinfo(nodename, service, family, socktype, protocol, flags).each(&block)
158  end
159end
160
161class BasicSocket < IO
162  # Returns an address of the socket suitable for connect in the local machine.
163  #
164  # This method returns _self_.local_address, except following condition.
165  #
166  # - IPv4 unspecified address (0.0.0.0) is replaced by IPv4 loopback address (127.0.0.1).
167  # - IPv6 unspecified address (::) is replaced by IPv6 loopback address (::1).
168  #
169  # If the local address is not suitable for connect, SocketError is raised.
170  # IPv4 and IPv6 address which port is 0 is not suitable for connect.
171  # Unix domain socket which has no path is not suitable for connect.
172  #
173  #   Addrinfo.tcp("0.0.0.0", 0).listen {|serv|
174  #     p serv.connect_address #=> #<Addrinfo: 127.0.0.1:53660 TCP>
175  #     serv.connect_address.connect {|c|
176  #       s, _ = serv.accept
177  #       p [c, s] #=> [#<Socket:fd 4>, #<Socket:fd 6>]
178  #     }
179  #   }
180  #
181  def connect_address
182    addr = local_address
183    afamily = addr.afamily
184    if afamily == Socket::AF_INET
185      raise SocketError, "unbound IPv4 socket" if addr.ip_port == 0
186      if addr.ip_address == "0.0.0.0"
187        addr = Addrinfo.new(["AF_INET", addr.ip_port, nil, "127.0.0.1"], addr.pfamily, addr.socktype, addr.protocol)
188      end
189    elsif defined?(Socket::AF_INET6) && afamily == Socket::AF_INET6
190      raise SocketError, "unbound IPv6 socket" if addr.ip_port == 0
191      if addr.ip_address == "::"
192        addr = Addrinfo.new(["AF_INET6", addr.ip_port, nil, "::1"], addr.pfamily, addr.socktype, addr.protocol)
193      elsif addr.ip_address == "0.0.0.0" # MacOS X 10.4 returns "a.b.c.d" for IPv4-mapped IPv6 address.
194        addr = Addrinfo.new(["AF_INET6", addr.ip_port, nil, "::1"], addr.pfamily, addr.socktype, addr.protocol)
195      elsif addr.ip_address == "::ffff:0.0.0.0" # MacOS X 10.6 returns "::ffff:a.b.c.d" for IPv4-mapped IPv6 address.
196        addr = Addrinfo.new(["AF_INET6", addr.ip_port, nil, "::1"], addr.pfamily, addr.socktype, addr.protocol)
197      end
198    elsif defined?(Socket::AF_UNIX) && afamily == Socket::AF_UNIX
199      raise SocketError, "unbound Unix socket" if addr.unix_path == ""
200    end
201    addr
202  end
203end
204
205class Socket < BasicSocket
206  # enable the socket option IPV6_V6ONLY if IPV6_V6ONLY is available.
207  def ipv6only!
208    if defined? Socket::IPV6_V6ONLY
209      self.setsockopt(:IPV6, :V6ONLY, 1)
210    end
211  end
212
213  # creates a new socket object connected to host:port using TCP/IP.
214  #
215  # If local_host:local_port is given,
216  # the socket is bound to it.
217  #
218  # If a block is given, the block is called with the socket.
219  # The value of the block is returned.
220  # The socket is closed when this method returns.
221  #
222  # If no block is given, the socket is returned.
223  #
224  #   Socket.tcp("www.ruby-lang.org", 80) {|sock|
225  #     sock.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
226  #     sock.close_write
227  #     puts sock.read
228  #   }
229  #
230  def self.tcp(host, port, local_host=nil, local_port=nil) # :yield: socket
231    last_error = nil
232    ret = nil
233
234    local_addr_list = nil
235    if local_host != nil || local_port != nil
236      local_addr_list = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, nil)
237    end
238
239    Addrinfo.foreach(host, port, nil, :STREAM) {|ai|
240      if local_addr_list
241        local_addr = local_addr_list.find {|local_ai| local_ai.afamily == ai.afamily }
242        next if !local_addr
243      else
244        local_addr = nil
245      end
246      begin
247        sock = local_addr ? ai.connect_from(local_addr) : ai.connect
248      rescue SystemCallError
249        last_error = $!
250        next
251      end
252      ret = sock
253      break
254    }
255    if !ret
256      if last_error
257        raise last_error
258      else
259        raise SocketError, "no appropriate local address"
260      end
261    end
262    if block_given?
263      begin
264        yield ret
265      ensure
266        ret.close if !ret.closed?
267      end
268    else
269      ret
270    end
271  end
272
273  # :stopdoc:
274  def self.ip_sockets_port0(ai_list, reuseaddr)
275    begin
276      sockets = []
277      port = nil
278      ai_list.each {|ai|
279        begin
280          s = Socket.new(ai.pfamily, ai.socktype, ai.protocol)
281        rescue SystemCallError
282          next
283        end
284        sockets << s
285        s.ipv6only! if ai.ipv6?
286        if reuseaddr
287          s.setsockopt(:SOCKET, :REUSEADDR, 1)
288        end
289        if !port
290          s.bind(ai)
291          port = s.local_address.ip_port
292        else
293          s.bind(ai.family_addrinfo(ai.ip_address, port))
294        end
295      }
296    rescue Errno::EADDRINUSE
297      sockets.each {|s|
298        s.close
299      }
300      retry
301    end
302    sockets
303  ensure
304    sockets.each {|s| s.close if !s.closed? } if $!
305  end
306  class << self
307    private :ip_sockets_port0
308  end
309
310  def self.tcp_server_sockets_port0(host)
311    ai_list = Addrinfo.getaddrinfo(host, 0, nil, :STREAM, nil, Socket::AI_PASSIVE)
312    sockets = ip_sockets_port0(ai_list, true)
313    sockets.each {|s|
314      s.listen(5)
315    }
316    sockets
317  ensure
318    sockets.each {|s| s.close if !s.closed? } if $! && sockets
319  end
320  class << self
321    private :tcp_server_sockets_port0
322  end
323  # :startdoc:
324
325  # creates TCP/IP server sockets for _host_ and _port_.
326  # _host_ is optional.
327  #
328  # If no block given,
329  # it returns an array of listening sockets.
330  #
331  # If a block is given, the block is called with the sockets.
332  # The value of the block is returned.
333  # The socket is closed when this method returns.
334  #
335  # If _port_ is 0, actual port number is choosen dynamically.
336  # However all sockets in the result has same port number.
337  #
338  #   # tcp_server_sockets returns two sockets.
339  #   sockets = Socket.tcp_server_sockets(1296)
340  #   p sockets #=> [#<Socket:fd 3>, #<Socket:fd 4>]
341  #
342  #   # The sockets contains IPv6 and IPv4 sockets.
343  #   sockets.each {|s| p s.local_address }
344  #   #=> #<Addrinfo: [::]:1296 TCP>
345  #   #   #<Addrinfo: 0.0.0.0:1296 TCP>
346  #
347  #   # IPv6 and IPv4 socket has same port number, 53114, even if it is choosen dynamically.
348  #   sockets = Socket.tcp_server_sockets(0)
349  #   sockets.each {|s| p s.local_address }
350  #   #=> #<Addrinfo: [::]:53114 TCP>
351  #   #   #<Addrinfo: 0.0.0.0:53114 TCP>
352  #
353  #   # The block is called with the sockets.
354  #   Socket.tcp_server_sockets(0) {|sockets|
355  #     p sockets #=> [#<Socket:fd 3>, #<Socket:fd 4>]
356  #   }
357  #
358  def self.tcp_server_sockets(host=nil, port)
359    if port == 0
360      sockets = tcp_server_sockets_port0(host)
361    else
362      begin
363        last_error = nil
364        sockets = []
365        Addrinfo.foreach(host, port, nil, :STREAM, nil, Socket::AI_PASSIVE) {|ai|
366          begin
367            s = ai.listen
368          rescue SystemCallError
369            last_error = $!
370            next
371          end
372          sockets << s
373        }
374        if sockets.empty?
375          raise last_error
376        end
377      ensure
378        sockets.each {|s| s.close if !s.closed? } if $!
379      end
380    end
381    if block_given?
382      begin
383        yield sockets
384      ensure
385        sockets.each {|s| s.close if !s.closed? }
386      end
387    else
388      sockets
389    end
390  end
391
392  # yield socket and client address for each a connection accepted via given sockets.
393  #
394  # The arguments are a list of sockets.
395  # The individual argument should be a socket or an array of sockets.
396  #
397  # This method yields the block sequentially.
398  # It means that the next connection is not accepted until the block returns.
399  # So concurrent mechanism, thread for example, should be used to service multiple clients at a time.
400  #
401  def self.accept_loop(*sockets) # :yield: socket, client_addrinfo
402    sockets.flatten!(1)
403    if sockets.empty?
404      raise ArgumentError, "no sockets"
405    end
406    loop {
407      readable, _, _ = IO.select(sockets)
408      readable.each {|r|
409        begin
410          sock, addr = r.accept_nonblock
411        rescue IO::WaitReadable
412          next
413        end
414        yield sock, addr
415      }
416    }
417  end
418
419  # creates a TCP/IP server on _port_ and calls the block for each connection accepted.
420  # The block is called with a socket and a client_address as an Addrinfo object.
421  #
422  # If _host_ is specified, it is used with _port_ to determine the server addresses.
423  #
424  # The socket is *not* closed when the block returns.
425  # So application should close it explicitly.
426  #
427  # This method calls the block sequentially.
428  # It means that the next connection is not accepted until the block returns.
429  # So concurrent mechanism, thread for example, should be used to service multiple clients at a time.
430  #
431  # Note that Addrinfo.getaddrinfo is used to determine the server socket addresses.
432  # When Addrinfo.getaddrinfo returns two or more addresses,
433  # IPv4 and IPv6 address for example,
434  # all of them are used.
435  # Socket.tcp_server_loop succeeds if one socket can be used at least.
436  #
437  #   # Sequential echo server.
438  #   # It services only one client at a time.
439  #   Socket.tcp_server_loop(16807) {|sock, client_addrinfo|
440  #     begin
441  #       IO.copy_stream(sock, sock)
442  #     ensure
443  #       sock.close
444  #     end
445  #   }
446  #
447  #   # Threaded echo server
448  #   # It services multiple clients at a time.
449  #   # Note that it may accept connections too much.
450  #   Socket.tcp_server_loop(16807) {|sock, client_addrinfo|
451  #     Thread.new {
452  #       begin
453  #         IO.copy_stream(sock, sock)
454  #       ensure
455  #         sock.close
456  #       end
457  #     }
458  #   }
459  #
460  def self.tcp_server_loop(host=nil, port, &b) # :yield: socket, client_addrinfo
461    tcp_server_sockets(host, port) {|sockets|
462      accept_loop(sockets, &b)
463    }
464  end
465
466  # :call-seq:
467  #   Socket.udp_server_sockets([host, ] port)
468  #
469  # Creates UDP/IP sockets for a UDP server.
470  #
471  # If no block given, it returns an array of sockets.
472  #
473  # If a block is given, the block is called with the sockets.
474  # The value of the block is returned.
475  # The sockets are closed when this method returns.
476  #
477  # If _port_ is zero, some port is choosen.
478  # But the choosen port is used for the all sockets.
479  #
480  #   # UDP/IP echo server
481  #   Socket.udp_server_sockets(0) {|sockets|
482  #     p sockets.first.local_address.ip_port     #=> 32963
483  #     Socket.udp_server_loop_on(sockets) {|msg, msg_src|
484  #       msg_src.reply msg
485  #     }
486  #   }
487  #
488  def self.udp_server_sockets(host=nil, port)
489    last_error = nil
490    sockets = []
491
492    ipv6_recvpktinfo = nil
493    if defined? Socket::AncillaryData
494      if defined? Socket::IPV6_RECVPKTINFO # RFC 3542
495        ipv6_recvpktinfo = Socket::IPV6_RECVPKTINFO
496      elsif defined? Socket::IPV6_PKTINFO # RFC 2292
497        ipv6_recvpktinfo = Socket::IPV6_PKTINFO
498      end
499    end
500
501    local_addrs = Socket.ip_address_list
502
503    ip_list = []
504    Addrinfo.foreach(host, port, nil, :DGRAM, nil, Socket::AI_PASSIVE) {|ai|
505      if ai.ipv4? && ai.ip_address == "0.0.0.0"
506        local_addrs.each {|a|
507          next if !a.ipv4?
508          ip_list << Addrinfo.new(a.to_sockaddr, :INET, :DGRAM, 0);
509        }
510      elsif ai.ipv6? && ai.ip_address == "::" && !ipv6_recvpktinfo
511        local_addrs.each {|a|
512          next if !a.ipv6?
513          ip_list << Addrinfo.new(a.to_sockaddr, :INET6, :DGRAM, 0);
514        }
515      else
516        ip_list << ai
517      end
518    }
519
520    if port == 0
521      sockets = ip_sockets_port0(ip_list, false)
522    else
523      ip_list.each {|ip|
524        ai = Addrinfo.udp(ip.ip_address, port)
525        begin
526          s = ai.bind
527        rescue SystemCallError
528          last_error = $!
529          next
530        end
531        sockets << s
532      }
533      if sockets.empty?
534        raise last_error
535      end
536    end
537
538    pktinfo_sockets = {}
539    sockets.each {|s|
540      ai = s.local_address
541      if ipv6_recvpktinfo && ai.ipv6? && ai.ip_address == "::"
542        s.setsockopt(:IPV6, ipv6_recvpktinfo, 1)
543        pktinfo_sockets[s] = true
544      end
545    }
546
547    if block_given?
548      begin
549        yield sockets
550      ensure
551        sockets.each {|s| s.close if !s.closed? } if sockets
552      end
553    else
554      sockets
555    end
556  end
557
558  # :call-seq:
559  #   Socket.udp_server_recv(sockets) {|msg, msg_src| ... }
560  #
561  # Receive UDP/IP packets from the given _sockets_.
562  # For each packet received, the block is called.
563  #
564  # The block receives _msg_ and _msg_src_.
565  # _msg_ is a string which is the payload of the received packet.
566  # _msg_src_ is a Socket::UDPSource object which is used for reply.
567  #
568  # Socket.udp_server_loop can be implemented using this method as follows.
569  #
570  #   udp_server_sockets(host, port) {|sockets|
571  #     loop {
572  #       readable, _, _ = IO.select(sockets)
573  #       udp_server_recv(readable) {|msg, msg_src| ... }
574  #     }
575  #   }
576  #
577  def self.udp_server_recv(sockets)
578    sockets.each {|r|
579      begin
580        msg, sender_addrinfo, rflags, *controls = r.recvmsg_nonblock
581      rescue IO::WaitReadable
582        next
583      end
584      ai = r.local_address
585      if ai.ipv6? and pktinfo = controls.find {|c| c.cmsg_is?(:IPV6, :PKTINFO) }
586        ai = Addrinfo.udp(pktinfo.ipv6_pktinfo_addr.ip_address, ai.ip_port)
587        yield msg, UDPSource.new(sender_addrinfo, ai) {|reply_msg|
588          r.sendmsg reply_msg, 0, sender_addrinfo, pktinfo
589        }
590      else
591        yield msg, UDPSource.new(sender_addrinfo, ai) {|reply_msg|
592          r.send reply_msg, 0, sender_addrinfo
593        }
594      end
595    }
596  end
597
598  # :call-seq:
599  #   Socket.udp_server_loop_on(sockets) {|msg, msg_src| ... }
600  #
601  # Run UDP/IP server loop on the given sockets.
602  #
603  # The return value of Socket.udp_server_sockets is appropriate for the argument.
604  #
605  # It calls the block for each message received.
606  #
607  def self.udp_server_loop_on(sockets, &b) # :yield: msg, msg_src
608    loop {
609      readable, _, _ = IO.select(sockets)
610      udp_server_recv(readable, &b)
611    }
612  end
613
614  # :call-seq:
615  #   Socket.udp_server_loop(port) {|msg, msg_src| ... }
616  #   Socket.udp_server_loop(host, port) {|msg, msg_src| ... }
617  #
618  # creates a UDP/IP server on _port_ and calls the block for each message arrived.
619  # The block is called with the message and its source information.
620  #
621  # This method allocates sockets internally using _port_.
622  # If _host_ is specified, it is used conjunction with _port_ to determine the server addresses.
623  #
624  # The _msg_ is a string.
625  #
626  # The _msg_src_ is a Socket::UDPSource object.
627  # It is used for reply.
628  #
629  #   # UDP/IP echo server.
630  #   Socket.udp_server_loop(9261) {|msg, msg_src|
631  #     msg_src.reply msg
632  #   }
633  #
634  def self.udp_server_loop(host=nil, port, &b) # :yield: message, message_source
635    udp_server_sockets(host, port) {|sockets|
636      udp_server_loop_on(sockets, &b)
637    }
638  end
639
640  # UDP/IP address information used by Socket.udp_server_loop.
641  class UDPSource
642    def initialize(remote_address, local_address, &reply_proc)
643      @remote_address = remote_address
644      @local_address = local_address
645      @reply_proc = reply_proc
646    end
647    attr_reader :remote_address, :local_address
648
649    def inspect
650      "\#<#{self.class}: #{@remote_address.inspect_sockaddr} to #{@local_address.inspect_sockaddr}>"
651    end
652
653    def reply(msg)
654      @reply_proc.call msg
655    end
656  end
657
658  # creates a new socket connected to path using UNIX socket socket.
659  #
660  # If a block is given, the block is called with the socket.
661  # The value of the block is returned.
662  # The socket is closed when this method returns.
663  #
664  # If no block is given, the socket is returned.
665  #
666  #   # talk to /tmp/sock socket.
667  #   Socket.unix("/tmp/sock") {|sock|
668  #     t = Thread.new { IO.copy_stream(sock, STDOUT) }
669  #     IO.copy_stream(STDIN, sock)
670  #     t.join
671  #   }
672  #
673  def self.unix(path) # :yield: socket
674    addr = Addrinfo.unix(path)
675    sock = addr.connect
676    if block_given?
677      begin
678        yield sock
679      ensure
680        sock.close if !sock.closed?
681      end
682    else
683      sock
684    end
685  end
686
687  # creates a UNIX server socket on _path_
688  #
689  # If no block given, it returns a listening socket.
690  #
691  # If a block is given, it is called with the socket and the block value is returned.
692  # When the block exits, the socket is closed and the socket file is removed.
693  #
694  #   socket = Socket.unix_server_socket("/tmp/s")
695  #   p socket                  #=> #<Socket:fd 3>
696  #   p socket.local_address    #=> #<Addrinfo: /tmp/s SOCK_STREAM>
697  #
698  #   Socket.unix_server_socket("/tmp/sock") {|s|
699  #     p s                     #=> #<Socket:fd 3>
700  #     p s.local_address       #=> # #<Addrinfo: /tmp/sock SOCK_STREAM>
701  #   }
702  #
703  def self.unix_server_socket(path)
704    begin
705      st = File.lstat(path)
706    rescue Errno::ENOENT
707    end
708    if st && st.socket? && st.owned?
709      File.unlink path
710    end
711    s = Addrinfo.unix(path).listen
712    if block_given?
713      begin
714        yield s
715      ensure
716        s.close if !s.closed?
717        File.unlink path
718      end
719    else
720      s
721    end
722  end
723
724  # creates a UNIX socket server on _path_.
725  # It calls the block for each socket accepted.
726  #
727  # If _host_ is specified, it is used with _port_ to determine the server ports.
728  #
729  # The socket is *not* closed when the block returns.
730  # So application should close it.
731  #
732  # This method deletes the socket file pointed by _path_ at first if
733  # the file is a socket file and it is owned by the user of the application.
734  # This is safe only if the directory of _path_ is not changed by a malicious user.
735  # So don't use /tmp/malicious-users-directory/socket.
736  # Note that /tmp/socket and /tmp/your-private-directory/socket is safe assuming that /tmp has sticky bit.
737  #
738  #   # Sequential echo server.
739  #   # It services only one client at a time.
740  #   Socket.unix_server_loop("/tmp/sock") {|sock, client_addrinfo|
741  #     begin
742  #       IO.copy_stream(sock, sock)
743  #     ensure
744  #       sock.close
745  #     end
746  #   }
747  #
748  def self.unix_server_loop(path, &b) # :yield: socket, client_addrinfo
749    unix_server_socket(path) {|serv|
750      accept_loop(serv, &b)
751    }
752  end
753
754end
755