PageRenderTime 65ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

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