PageRenderTime 46ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/test/jruby/test_socket.rb

http://github.com/jruby/jruby
Ruby | 689 lines | 491 code | 125 blank | 73 comment | 42 complexity | 9b19ad8977f069a64e6e2e710ffe5c66 MD5 | raw file
Possible License(s): GPL-3.0, BSD-3-Clause, GPL-2.0, JSON, LGPL-2.1
  1. require 'test/unit'
  2. require 'test/jruby/test_helper'
  3. require 'socket'
  4. require 'thread'
  5. require 'ipaddr'
  6. class SocketTest < Test::Unit::TestCase
  7. include TestHelper
  8. # Disabled for now. See https://github.com/jruby/jruby/issues/620
  9. #
  10. # # Should this work on windows? JRUBY-6665
  11. # if !WINDOWS
  12. # def test_multicast_send_and_receive
  13. # multicast_addr = "225.4.5.6"
  14. # port = 6789
  15. # multicast_msg = "Hello from automated JRuby test suite"
  16. #
  17. # assert_nothing_raised do
  18. # socket = UDPSocket.new
  19. # ip = IPAddr.new(multicast_addr).hton + IPAddr.new("0.0.0.0").hton
  20. # socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ip)
  21. # socket.bind(Socket::INADDR_ANY, port)
  22. # socket.send(multicast_msg, 0, multicast_addr, port)
  23. # msg, info = socket.recvfrom(1024)
  24. # assert_equal(multicast_msg, msg)
  25. # assert_equal(multicast_msg.size, msg.size)
  26. # assert_equal(port, info[1])
  27. # socket.close
  28. # end
  29. # end
  30. # end
  31. def test_tcp_socket_allows_nil_for_hostname
  32. assert_nothing_raised do
  33. server = TCPServer.new(nil, 7789)
  34. t = Thread.new do
  35. s = server.accept
  36. s.close
  37. end
  38. client = TCPSocket.new(nil, 7789)
  39. client.write ""
  40. t.join
  41. end
  42. end
  43. #JRUBY-3827
  44. def test_nil_hostname_and_passive_returns_inaddr_any
  45. assert_nothing_raised do
  46. addrs = Socket::getaddrinfo(nil, 7789, Socket::AF_UNSPEC, Socket::SOCK_STREAM, 0, Socket::AI_PASSIVE)
  47. assert_not_equal(0, addrs.size)
  48. assert_equal("0.0.0.0", addrs[0][2])
  49. assert_equal("0.0.0.0", addrs[0][3])
  50. end
  51. end
  52. def test_nil_hostname_and_no_flags_returns_localhost
  53. assert_nothing_raised do
  54. addrs = Socket::getaddrinfo(nil, 7789, Socket::AF_UNSPEC, Socket::SOCK_STREAM, 0)
  55. assert_not_equal(0, addrs.size)
  56. # FIXME, behaves differently on Windows, both JRuby and MRI.
  57. # JRuby returns "127.0.0.1", "127.0.0.1"
  58. # MRI returns "<actual_hostname>", "127.0.0.1"
  59. unless WINDOWS
  60. #assert_equal("localhost", addrs[0][2])
  61. assert_equal("127.0.0.1", addrs[0][3])
  62. end
  63. end
  64. end
  65. def test_getifaddrs
  66. begin
  67. list = Socket.getifaddrs
  68. rescue NotImplementedError
  69. return
  70. end
  71. list.each {|ifaddr|
  72. assert_instance_of(Socket::Ifaddr, ifaddr)
  73. }
  74. end
  75. def test_getifaddrs_packet_interfaces
  76. begin
  77. list = Socket.getifaddrs
  78. rescue NotImplementedError
  79. return
  80. end
  81. ifnames = list.collect(&:name).uniq
  82. ifnames.each do |ifname|
  83. packet_interfaces = list.select { |ifaddr| ifaddr.name == ifname && ifaddr.addr.afamily == Socket::AF_UNSPEC } # TODO: (gf) Socket::AF_PACKET when available
  84. assert_equal(1, packet_interfaces.count) # one for each interface
  85. end
  86. end
  87. def test_basic_socket_reverse_lookup
  88. assert_nothing_raised do
  89. reverse = BasicSocket.do_not_reverse_lookup
  90. BasicSocket.do_not_reverse_lookup = !reverse
  91. assert_equal(reverse, !BasicSocket.do_not_reverse_lookup)
  92. BasicSocket.do_not_reverse_lookup = reverse
  93. end
  94. end
  95. #JRUBY-2147
  96. def test_tcp_close_read
  97. socket = TCPServer.new(nil, 9999)
  98. socket.close_read
  99. assert(!socket.closed?)
  100. socket.close
  101. end
  102. #JRUBY-2146
  103. def test_tcp_close_write
  104. socket = TCPServer.new(nil, 8888)
  105. socket.close_write
  106. assert(!socket.closed?)
  107. socket.close
  108. end
  109. def test_tcp_close_read_then_write_should_close_socket
  110. socket = TCPServer.new(nil, 7777)
  111. socket.close_write
  112. assert(!socket.closed?)
  113. socket.close_read
  114. assert(socket.closed?)
  115. end
  116. # JRUBY-2874
  117. def test_raises_socket_error_on_out_of_range_port
  118. port = -2**16
  119. assert_raises(SocketError) { TCPSocket.new('localhost', port) }
  120. # SocketError(<getaddrinfo: Servname not supported for ai_socktype>)
  121. port = -2**8
  122. assert_raises(SocketError) { TCPSocket.new('localhost', port) }
  123. # SocketError(<getaddrinfo: Servname not supported for ai_socktype>)
  124. port = -2
  125. assert_raises(SocketError) { TCPSocket.new('localhost', port) }
  126. # SocketError(<getaddrinfo: Servname not supported for ai_socktype>)
  127. port = -1
  128. assert_raises(SocketError) { TCPSocket.new('localhost', port) }
  129. # SocketError(<getaddrinfo: Servname not supported for ai_socktype>)
  130. error = defined?(JRUBY_VERSION) ? SocketError : Errno::ECONNREFUSED
  131. [ 2**16, 2**16 + 1, 2**17, 2**30 - 1 ].each do |p|
  132. assert_raises(error) { TCPSocket.new('localhost', p) }
  133. end
  134. end
  135. # JRUBY-4299
  136. def test_tcp_socket_reuse_addr
  137. socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
  138. socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
  139. assert_not_equal 0, socket.getsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR).unpack('i')[0]
  140. ensure
  141. socket.close
  142. end
  143. # JRUBY-4299
  144. def test_udp_socket_reuse_addr
  145. socket = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0)
  146. socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
  147. assert_not_equal 0, socket.getsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR).unpack('i')[0]
  148. ensure
  149. socket.close
  150. end
  151. # JRUBY-4868
  152. def test_getservbyname
  153. assert_equal(21, Socket.getservbyname('ftp'))
  154. assert_equal(21, Socket.getservbyname('21'))
  155. assert_equal(21, Socket.getservbyname(' 21'))
  156. end
  157. def test_ipv4_socket
  158. socket = Socket.new(:INET, :STREAM)
  159. server_socket = ServerSocket.new(:INET, :STREAM)
  160. addr = Addrinfo.tcp('0.0.0.0', 3030)
  161. addr1 = Addrinfo.tcp('0.0.0.0', 3031)
  162. assert_not_equal(socket.bind(addr), nil)
  163. assert_not_equal(server_socket.bind(addr1), nil)
  164. assert_not_equal(server_socket.listen(128), nil)
  165. end
  166. def test_udp_socket_bind
  167. begin
  168. UDPSocket.new.bind nil, 42
  169. rescue Errno::EACCES => e
  170. # Permission denied - bind(2) for nil port 42
  171. assert_equal 'Permission denied - bind(2) for nil port 42', e.message
  172. else; fail 'not raised'
  173. end
  174. #begin
  175. # UDPSocket.new.bind nil, nil
  176. #rescue SocketError
  177. # # getaddrinfo: Name or service not known
  178. #else; fail 'not raised'
  179. #end
  180. begin
  181. socket = UDPSocket.new
  182. socket.bind 0, 42
  183. rescue Errno::EACCES
  184. # Permission denied - bind(2) for 0 port 42
  185. else; fail 'not raised'
  186. end
  187. begin
  188. UDPSocket.new.bind "127.0.0.1", 191
  189. rescue Errno::EACCES
  190. # Permission denied - bind(2) for "127.0.0.1" port 191
  191. else; fail 'not raised'
  192. end
  193. end
  194. def test_tcp_socket_errors
  195. begin
  196. TCPSocket.new('0.0.0.0', 42)
  197. rescue Errno::ECONNREFUSED => e
  198. # Connection refused - connect(2) for "0.0.0.0" port 42
  199. assert_equal 'Connection refused - connect(2) for "0.0.0.0" port 42', e.message
  200. else; fail 'not raised'
  201. end
  202. server = TCPServer.new('127.0.0.1', 10022)
  203. Thread.new { server.accept }
  204. socket = TCPSocket.new('127.0.0.1', 10022)
  205. begin
  206. socket.read_nonblock 100
  207. rescue IO::EAGAINWaitReadable
  208. # Resource temporarily unavailable - read would block
  209. else; fail 'not raised'
  210. ensure
  211. server.close rescue nil
  212. socket.close rescue nil
  213. end
  214. end
  215. def test_connect_nonblock_no_exception
  216. serv = ServerSocket.new(:INET, :STREAM)
  217. serv.bind(Socket.sockaddr_in(0, "127.0.0.1"), 5)
  218. c = Socket.new(:INET, :STREAM)
  219. servaddr = serv.getsockname
  220. rv = c.connect_nonblock(servaddr, exception: false)
  221. case rv
  222. when 0
  223. # some OSes return immediately on non-blocking local connect()
  224. else
  225. assert_equal :wait_writable, rv
  226. end
  227. assert_equal([ [], [c], [] ], IO.select(nil, [c], nil, 60))
  228. assert_equal(0, c.connect_nonblock(servaddr, exception: false),
  229. 'there should be no EISCONN error')
  230. ensure
  231. serv.close if serv
  232. c.close if c
  233. end
  234. end
  235. class UNIXSocketTests < Test::Unit::TestCase
  236. include TestHelper
  237. # this is intentional, otherwise test run fails on windows
  238. def test_dummy; end
  239. if defined?(UNIXSocket) && !WINDOWS
  240. def test_unix_socket_path
  241. path = "/tmp/sample"
  242. File.unlink(path) if File.exist?(path)
  243. server = UNIXServer.open(path)
  244. assert_equal path, server.path
  245. cli = UNIXSocket.open(path)
  246. assert_equal "", cli.path
  247. cli.close
  248. server.close
  249. File.unlink(path) if File.exist?(path)
  250. end
  251. def test_unix_socket_addr
  252. path = "/tmp/sample"
  253. File.unlink(path) if File.exist?(path)
  254. server = UNIXServer.open(path)
  255. assert_equal ["AF_UNIX", path], server.addr
  256. cli = UNIXSocket.open(path)
  257. assert_equal ["AF_UNIX", ""], cli.addr
  258. cli.close
  259. server.close
  260. File.unlink(path) if File.exist?(path)
  261. end
  262. def test_unix_socket_peeraddr_raises_enotconn
  263. path = "/tmp/sample"
  264. File.unlink(path) if File.exist?(path)
  265. server = UNIXServer.open(path)
  266. assert_raises(Errno::ENOTCONN) do
  267. server.peeraddr
  268. end
  269. File.unlink(path) if File.exist?(path)
  270. end
  271. def test_unix_socket_peeraddr
  272. path = "/tmp/sample"
  273. File.unlink(path) if File.exist?(path)
  274. server = UNIXServer.open(path)
  275. cli = UNIXSocket.open(path)
  276. ssrv = server.accept
  277. assert_equal ["AF_UNIX", ""], ssrv.peeraddr
  278. # TODO doesn't work as expected :
  279. pend "UNIXSocket#peeraddr #{cli.peeraddr.inspect} does not include path: #{path.inspect}"
  280. assert_equal ["AF_UNIX", path], cli.peeraddr
  281. ssrv.close
  282. cli.close
  283. server.close
  284. File.unlink(path) if File.exist?(path)
  285. end
  286. def test_unix_socket_raises_exception_on_too_long_path
  287. assert_raises(ArgumentError) do
  288. # on some platforms, 103 is invalid length (MacOS)
  289. # on others, 108 (Linux), we'll take the biggest one
  290. UNIXSocket.new("a" * 108)
  291. end
  292. end
  293. def test_unix_socket_raises_exception_on_path_that_cant_exist
  294. path = "a"
  295. File.unlink(path) if File.exist?(path)
  296. assert_raises(Errno::ENOENT) do
  297. UNIXSocket.new(path)
  298. end
  299. end
  300. def test_can_create_socket_server
  301. path = "/tmp/sample"
  302. File.unlink(path) if File.exist?(path)
  303. sock = UNIXServer.open(path)
  304. assert File.exist?(path)
  305. sock.close
  306. File.unlink(path) if File.exist?(path)
  307. end
  308. def test_can_create_socket_server_and_accept_nonblocking
  309. path = "/tmp/sample"
  310. File.unlink(path) if File.exist?(path)
  311. sock = UNIXServer.open(path)
  312. assert File.exist?(path)
  313. begin
  314. sock.accept_nonblock
  315. assert false, "failed to raise EAGAIN"
  316. rescue Errno::EAGAIN => e
  317. assert IO::WaitReadable === e
  318. end
  319. cli = UNIXSocket.open(path)
  320. sock.accept_nonblock.close
  321. cli.close
  322. sock.close
  323. File.unlink(path) if File.exist?(path)
  324. end
  325. def test_can_create_socket_server_and_relisten
  326. path = "/tmp/sample"
  327. File.unlink(path) if File.exist?(path)
  328. sock = UNIXServer.open(path)
  329. assert File.exist?(path)
  330. sock.listen(1)
  331. assert File.exist?(path)
  332. sock.close
  333. File.unlink(path) if File.exist?(path)
  334. end
  335. # JRUBY-5708
  336. def test_can_create_socket_server_and_blocking_select_blocks_on_it
  337. require 'timeout'
  338. path = "/tmp/sample"
  339. File.unlink(path) if File.exist?(path)
  340. sock = UNIXServer.open(path)
  341. assert File.exist?(path)
  342. assert_raises(Timeout::Error) do
  343. Timeout::timeout(0.1) do
  344. IO.select [sock], nil, nil, 1
  345. end
  346. end
  347. sock.close
  348. File.unlink(path) if File.exist?(path)
  349. end
  350. def test_can_create_socket_server_and_client_connected_to_it
  351. path = "/tmp/sample"
  352. File.unlink(path) if File.exist?(path)
  353. sock = UNIXServer.open(path)
  354. assert File.exist?(path)
  355. cli = UNIXSocket.open(path)
  356. cli.close
  357. sock.close
  358. File.unlink(path) if File.exist?(path)
  359. end
  360. def test_can_create_socket_server_and_client_connected_to_it_and_send_from_client_to_server
  361. path = "/tmp/sample"
  362. File.unlink(path) if File.exist?(path)
  363. sock = UNIXServer.open(path)
  364. assert File.exist?(path)
  365. cli = UNIXSocket.open(path)
  366. servsock = sock.accept
  367. cli.send("hello",0)
  368. assert_equal "hello", servsock.recv(5)
  369. servsock.close
  370. cli.close
  371. sock.close
  372. File.unlink(path) if File.exist?(path)
  373. end
  374. def test_can_create_socket_server_and_client_connected_to_it_and_send_from_server_to_client
  375. path = "/tmp/sample"
  376. File.unlink(path) if File.exist?(path)
  377. sock = UNIXServer.open(path)
  378. assert File.exist?(path)
  379. cli = UNIXSocket.open(path)
  380. servsock = sock.accept
  381. servsock.send("hello",0)
  382. assert_equal "hello", cli.recv(5)
  383. servsock.close
  384. cli.close
  385. sock.close
  386. File.unlink(path) if File.exist?(path)
  387. end
  388. def test_can_create_socket_server_and_client_connected_to_it_and_send_from_client_to_server_using_recvfrom
  389. path = "/tmp/sample"
  390. File.unlink(path) if File.exist?(path)
  391. sock = UNIXServer.open(path)
  392. assert File.exist?(path)
  393. cli = UNIXSocket.open(path)
  394. servsock = sock.accept
  395. cli.send("hello",0)
  396. assert_equal ["hello", ["AF_UNIX", ""]], servsock.recvfrom(5)
  397. servsock.close
  398. cli.close
  399. sock.close
  400. File.unlink(path) if File.exist?(path)
  401. end
  402. def test_can_create_socket_server_and_client_connected_to_it_and_send_from_server_to_client_using_recvfrom
  403. path = "/tmp/sample"
  404. File.unlink(path) if File.exist?(path)
  405. sock = UNIXServer.open(path)
  406. assert File.exist?(path)
  407. cli = UNIXSocket.open(path)
  408. servsock = sock.accept
  409. servsock.send("hello",0)
  410. data = cli.recvfrom(5)
  411. assert_equal "hello", data[0]
  412. assert_equal "AF_UNIX", data[1][0]
  413. servsock.close
  414. cli.close
  415. sock.close
  416. File.unlink(path) if File.exist?(path)
  417. end
  418. def test_can_create_socketpair_and_send_from_one_to_the_other
  419. sock1, sock2 = UNIXSocket.socketpair
  420. sock1.send("hello", 0)
  421. assert_equal "hello", sock2.recv(5)
  422. sock1.close
  423. sock2.close
  424. end
  425. def test_can_create_socketpair_and_can_send_from_the_other
  426. sock1, sock2 = UNIXSocket.socketpair
  427. sock2.send("hello", 0)
  428. assert_equal "hello", sock1.recv(5)
  429. sock2.close
  430. sock1.close
  431. end
  432. def test_can_create_socketpair_and_can_send_from_the_other_with_recvfrom
  433. sock1, sock2 = UNIXSocket.socketpair
  434. sock2.send("hello", 0)
  435. assert_equal ["hello", ["AF_UNIX", ""]], sock1.recvfrom(5)
  436. sock2.close
  437. sock1.close
  438. end
  439. def test_can_read_and_get_minus_one
  440. sock1, sock2 = UNIXSocket.socketpair
  441. sock2.send("hello", 0)
  442. assert_equal "hell", sock1.recv(4)
  443. assert_equal "", sock1.recv(0)
  444. assert_equal "o", sock1.recv(1)
  445. sock2.close
  446. sock1.close
  447. assert_raises(IOError) do
  448. sock1.recv(1)
  449. end
  450. end
  451. def test_recv_nonblock
  452. s1, s2 = UNIXSocket.pair(Socket::SOCK_DGRAM)
  453. begin
  454. s1.recv_nonblock(1)
  455. assert false
  456. rescue => e
  457. assert(IO::EAGAINWaitReadable === e)
  458. assert(IO::WaitReadable === e)
  459. end
  460. # TODO '' does not get through as expected :
  461. #s2.send('', 0)
  462. #assert_equal '', s1.recv_nonblock(10, nil)
  463. begin
  464. s1.recv_nonblock(10, nil)
  465. assert false
  466. rescue IO::EAGAINWaitReadable
  467. end
  468. s2.send('a', 0)
  469. s1.recv_nonblock(5, nil, str = '')
  470. assert_equal 'a', str
  471. assert_raise(IO::EAGAINWaitReadable) { s1.recv_nonblock(5, nil, str) }
  472. assert_equal :wait_readable, s1.recv_nonblock(5, exception: false)
  473. end
  474. end
  475. end
  476. class ServerTest < Test::Unit::TestCase
  477. include TestHelper
  478. def test_server_close_interrupts_pending_accepts
  479. # unfortunately this test is going to not be 100% reliable
  480. # since it involves thread interaction and it's impossible to
  481. # do things like wait until the other thread blocks
  482. port = 41258
  483. server = TCPServer.new('localhost', port)
  484. queue = Queue.new
  485. thread = Thread.new do
  486. server.accept
  487. end
  488. # wait until the thread is sleeping (ready to accept)
  489. Thread.pass while thread.alive? && thread.status != "sleep"
  490. # close the server
  491. server.close
  492. # propagate the thread's termination error, checking it for IOError
  493. # NOTE: 1.8 raises IOError, 1.9 EBADF, so this isn't consistent. I'm
  494. # changing it to Exception so we can at least test the interrupt.
  495. assert_raise(IOError) {thread.value}
  496. end
  497. # JRUBY-2874
  498. def test_raises_socket_error_on_out_of_range_port
  499. [-2**16, -2**8, -2, -1, 2**16, 2**16 + 1, 2**17, 2**30 - 1].each do |p|
  500. assert_raises(SocketError) do
  501. TCPServer.new('localhost', p)
  502. end
  503. end
  504. end
  505. # JRUBY-4299
  506. def test_server_reuse_addr
  507. socket = TCPServer.new("127.0.0.1", 7777)
  508. socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
  509. assert_not_equal 0, socket.getsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR).unpack('i')[0]
  510. ensure
  511. socket.close
  512. end
  513. # JRUBY-5111
  514. def test_server_methods_with_closed_socket
  515. socket = TCPServer.new("127.0.0.1", 7777)
  516. socket.close
  517. assert_raises(IOError) { socket.addr }
  518. assert_raises(IOError) { socket.getsockname }
  519. end
  520. # JRUBY-5876
  521. def test_syswrite_raises_epipe
  522. t = Thread.new do
  523. server = TCPServer.new("127.0.0.1", 1234)
  524. while sock = server.accept
  525. sock.close
  526. end
  527. end
  528. Thread.pass while t.alive? and t.status != 'sleep'
  529. sock = TCPSocket.new("127.0.0.1", 1234)
  530. sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
  531. delay = 0.1
  532. tries = 0
  533. loop do
  534. sock.syswrite("2")
  535. end
  536. rescue Errno::EPIPE, Errno::ECONNRESET
  537. # ok
  538. rescue => ex
  539. # FIXME: make Windows behave the same?
  540. raise ex if !WINDOWS
  541. ensure
  542. t.kill rescue nil
  543. server.close rescue nil
  544. sock.close rescue nil
  545. end
  546. # jruby/jruby#1637
  547. def test_read_zero_never_blocks
  548. require 'timeout'
  549. assert_nothing_raised do
  550. server = TCPServer.new(nil, 12345)
  551. t = Thread.new do
  552. s = server.accept
  553. end
  554. client = TCPSocket.new(nil, 12345)
  555. Timeout.timeout(1) do
  556. assert_equal "", client.read(0)
  557. end
  558. t.join
  559. end
  560. ensure
  561. server.close rescue nil
  562. client.close rescue nil
  563. end if RUBY_VERSION >= '1.9'
  564. end