PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/RubyPlugin/RubyPlugin/Lib/socket.rb

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