PageRenderTime 81ms CodeModel.GetById 14ms app.highlight 60ms RepoModel.GetById 1ms app.codeStats 1ms

/res/build-tools/ruby-standalone/212/usr/local/lib/ruby/2.1.0/socket.rb

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