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

/test/socket/test_socket.rb

https://github.com/tmiller/ruby
Ruby | 461 lines | 423 code | 31 blank | 7 comment | 30 complexity | 28004b860934ad7631d3243679db8880 MD5 | raw file
  1. begin
  2. require "socket"
  3. require "tmpdir"
  4. require "test/unit"
  5. rescue LoadError
  6. end
  7. class TestSocket < Test::Unit::TestCase
  8. def test_socket_new
  9. s = Socket.new(:INET, :STREAM)
  10. assert_kind_of(Socket, s)
  11. end
  12. def test_unpack_sockaddr
  13. sockaddr_in = Socket.sockaddr_in(80, "")
  14. assert_raise(ArgumentError) { Socket.unpack_sockaddr_un(sockaddr_in) }
  15. sockaddr_un = Socket.sockaddr_un("/testdir/s")
  16. assert_raise(ArgumentError) { Socket.unpack_sockaddr_in(sockaddr_un) }
  17. assert_raise(ArgumentError) { Socket.unpack_sockaddr_in("") }
  18. assert_raise(ArgumentError) { Socket.unpack_sockaddr_un("") }
  19. end if Socket.respond_to?(:sockaddr_un)
  20. def test_sysaccept
  21. serv = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
  22. serv.bind(Socket.sockaddr_in(0, "127.0.0.1"))
  23. serv.listen 5
  24. c = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
  25. c.connect(serv.getsockname)
  26. fd, peeraddr = serv.sysaccept
  27. assert_equal(c.getsockname, peeraddr.to_sockaddr)
  28. ensure
  29. serv.close if serv
  30. c.close if c
  31. IO.for_fd(fd).close if fd
  32. end
  33. def test_initialize
  34. Socket.open(Socket::AF_INET, Socket::SOCK_STREAM, 0) {|s|
  35. s.bind(Socket.sockaddr_in(0, "127.0.0.1"))
  36. addr = s.getsockname
  37. assert_nothing_raised { Socket.unpack_sockaddr_in(addr) }
  38. assert_raise(ArgumentError, NoMethodError) { Socket.unpack_sockaddr_un(addr) }
  39. }
  40. Socket.open("AF_INET", "SOCK_STREAM", 0) {|s|
  41. s.bind(Socket.sockaddr_in(0, "127.0.0.1"))
  42. addr = s.getsockname
  43. assert_nothing_raised { Socket.unpack_sockaddr_in(addr) }
  44. assert_raise(ArgumentError, NoMethodError) { Socket.unpack_sockaddr_un(addr) }
  45. }
  46. Socket.open(:AF_INET, :SOCK_STREAM, 0) {|s|
  47. s.bind(Socket.sockaddr_in(0, "127.0.0.1"))
  48. addr = s.getsockname
  49. assert_nothing_raised { Socket.unpack_sockaddr_in(addr) }
  50. assert_raise(ArgumentError, NoMethodError) { Socket.unpack_sockaddr_un(addr) }
  51. }
  52. end
  53. def test_getaddrinfo
  54. # This should not send a DNS query because AF_UNIX.
  55. assert_raise(SocketError) { Socket.getaddrinfo("www.kame.net", 80, "AF_UNIX") }
  56. end
  57. def test_getaddrinfo_raises_no_errors_on_port_argument_of_0 # [ruby-core:29427]
  58. assert_nothing_raised('[ruby-core:29427]'){ Socket.getaddrinfo('localhost', 0, Socket::AF_INET, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME) }
  59. assert_nothing_raised('[ruby-core:29427]'){ Socket.getaddrinfo('localhost', '0', Socket::AF_INET, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME) }
  60. assert_nothing_raised('[ruby-core:29427]'){ Socket.getaddrinfo('localhost', '00', Socket::AF_INET, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME) }
  61. assert_raise(SocketError, '[ruby-core:29427]'){ Socket.getaddrinfo(nil, nil, Socket::AF_INET, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME) }
  62. assert_nothing_raised('[ruby-core:29427]'){ TCPServer.open('localhost', 0) {} }
  63. end
  64. def test_getnameinfo
  65. assert_raise(SocketError) { Socket.getnameinfo(["AF_UNIX", 80, "0.0.0.0"]) }
  66. end
  67. def test_ip_address_list
  68. begin
  69. list = Socket.ip_address_list
  70. rescue NotImplementedError
  71. return
  72. end
  73. list.each {|ai|
  74. assert_instance_of(Addrinfo, ai)
  75. assert(ai.ip?)
  76. }
  77. end
  78. def test_tcp
  79. TCPServer.open(0) {|serv|
  80. addr = serv.connect_address
  81. addr.connect {|s1|
  82. s2 = serv.accept
  83. begin
  84. assert_equal(s2.remote_address.ip_unpack, s1.local_address.ip_unpack)
  85. ensure
  86. s2.close
  87. end
  88. }
  89. }
  90. end
  91. def random_port
  92. # IANA suggests dynamic port for 49152 to 65535
  93. # http://www.iana.org/assignments/port-numbers
  94. 49152 + rand(65535-49152+1)
  95. end
  96. def errors_addrinuse
  97. [Errno::EADDRINUSE]
  98. end
  99. def test_tcp_server_sockets
  100. port = random_port
  101. begin
  102. sockets = Socket.tcp_server_sockets(port)
  103. rescue *errors_addrinuse
  104. return # not test failure
  105. end
  106. begin
  107. sockets.each {|s|
  108. assert_equal(port, s.local_address.ip_port)
  109. }
  110. ensure
  111. sockets.each {|s|
  112. s.close
  113. }
  114. end
  115. end
  116. def test_tcp_server_sockets_port0
  117. sockets = Socket.tcp_server_sockets(0)
  118. ports = sockets.map {|s| s.local_address.ip_port }
  119. the_port = ports.first
  120. ports.each {|port|
  121. assert_equal(the_port, port)
  122. }
  123. ensure
  124. if sockets
  125. sockets.each {|s|
  126. s.close
  127. }
  128. end
  129. end
  130. if defined? UNIXSocket
  131. def test_unix
  132. Dir.mktmpdir {|tmpdir|
  133. path = "#{tmpdir}/sock"
  134. UNIXServer.open(path) {|serv|
  135. Socket.unix(path) {|s1|
  136. s2 = serv.accept
  137. begin
  138. s2raddr = s2.remote_address
  139. s1laddr = s1.local_address
  140. assert(s2raddr.to_sockaddr.empty? ||
  141. s1laddr.to_sockaddr.empty? ||
  142. s2raddr.unix_path == s1laddr.unix_path)
  143. ensure
  144. s2.close
  145. end
  146. }
  147. }
  148. }
  149. end
  150. def test_unix_server_socket
  151. Dir.mktmpdir {|tmpdir|
  152. path = "#{tmpdir}/sock"
  153. 2.times {
  154. serv = Socket.unix_server_socket(path)
  155. begin
  156. assert_kind_of(Socket, serv)
  157. assert(File.socket?(path))
  158. assert_equal(path, serv.local_address.unix_path)
  159. ensure
  160. serv.close
  161. end
  162. }
  163. }
  164. end
  165. def test_accept_loop_with_unix
  166. Dir.mktmpdir {|tmpdir|
  167. tcp_servers = []
  168. clients = []
  169. accepted = []
  170. begin
  171. tcp_servers = Socket.tcp_server_sockets(0)
  172. unix_server = Socket.unix_server_socket("#{tmpdir}/sock")
  173. tcp_servers.each {|s|
  174. addr = s.connect_address
  175. assert_nothing_raised("connect to #{addr.inspect}") {
  176. clients << addr.connect
  177. }
  178. }
  179. addr = unix_server.connect_address
  180. assert_nothing_raised("connect to #{addr.inspect}") {
  181. clients << addr.connect
  182. }
  183. Socket.accept_loop(tcp_servers, unix_server) {|s|
  184. accepted << s
  185. break if clients.length == accepted.length
  186. }
  187. assert_equal(clients.length, accepted.length)
  188. ensure
  189. tcp_servers.each {|s| s.close if !s.closed? }
  190. unix_server.close if unix_server && !unix_server.closed?
  191. clients.each {|s| s.close if !s.closed? }
  192. accepted.each {|s| s.close if !s.closed? }
  193. end
  194. }
  195. end
  196. end
  197. def test_accept_loop
  198. servers = []
  199. begin
  200. servers = Socket.tcp_server_sockets(0)
  201. port = servers[0].local_address.ip_port
  202. Socket.tcp("localhost", port) {|s1|
  203. Socket.accept_loop(servers) {|s2, client_ai|
  204. begin
  205. assert_equal(s1.local_address.ip_unpack, client_ai.ip_unpack)
  206. ensure
  207. s2.close
  208. end
  209. break
  210. }
  211. }
  212. ensure
  213. servers.each {|s| s.close if !s.closed? }
  214. end
  215. end
  216. def test_accept_loop_multi_port
  217. servers = []
  218. begin
  219. servers = Socket.tcp_server_sockets(0)
  220. port = servers[0].local_address.ip_port
  221. servers2 = Socket.tcp_server_sockets(0)
  222. servers.concat servers2
  223. port2 = servers2[0].local_address.ip_port
  224. Socket.tcp("localhost", port) {|s1|
  225. Socket.accept_loop(servers) {|s2, client_ai|
  226. begin
  227. assert_equal(s1.local_address.ip_unpack, client_ai.ip_unpack)
  228. ensure
  229. s2.close
  230. end
  231. break
  232. }
  233. }
  234. Socket.tcp("localhost", port2) {|s1|
  235. Socket.accept_loop(servers) {|s2, client_ai|
  236. begin
  237. assert_equal(s1.local_address.ip_unpack, client_ai.ip_unpack)
  238. ensure
  239. s2.close
  240. end
  241. break
  242. }
  243. }
  244. ensure
  245. servers.each {|s| s.close if !s.closed? }
  246. end
  247. end
  248. def test_udp_server
  249. begin
  250. ip_addrs = Socket.ip_address_list
  251. rescue NotImplementedError
  252. skip "Socket.ip_address_list not implemented"
  253. end
  254. Socket.udp_server_sockets(0) {|sockets|
  255. famlies = {}
  256. sockets.each {|s| famlies[s.local_address.afamily] = true }
  257. ip_addrs.reject! {|ai| !famlies[ai.afamily] }
  258. skipped = false
  259. begin
  260. port = sockets.first.local_address.ip_port
  261. th = Thread.new {
  262. Socket.udp_server_loop_on(sockets) {|msg, msg_src|
  263. break if msg == "exit"
  264. rmsg = Marshal.dump([msg, msg_src.remote_address, msg_src.local_address])
  265. msg_src.reply rmsg
  266. }
  267. }
  268. ip_addrs.each {|ai|
  269. Addrinfo.udp(ai.ip_address, port).connect {|s|
  270. msg1 = "<<<#{ai.inspect}>>>"
  271. s.sendmsg msg1
  272. unless IO.select([s], nil, nil, 10)
  273. raise "no response from #{ai.inspect}"
  274. end
  275. msg2, addr = s.recvmsg
  276. msg2, remote_address, local_address = Marshal.load(msg2)
  277. assert_equal(msg1, msg2)
  278. assert_equal(ai.ip_address, addr.ip_address)
  279. }
  280. }
  281. rescue NotImplementedError, Errno::ENOSYS
  282. skipped = true
  283. skip "need sendmsg and recvmsg"
  284. ensure
  285. if th
  286. if skipped
  287. Thread.kill th unless th.join(10)
  288. else
  289. Addrinfo.udp("127.0.0.1", port).connect {|s| s.sendmsg "exit" }
  290. unless th.join(10)
  291. Thread.kill th
  292. th.join(10)
  293. raise "thread killed"
  294. end
  295. end
  296. end
  297. end
  298. }
  299. end
  300. def test_linger
  301. opt = Socket::Option.linger(true, 0)
  302. assert_equal([true, 0], opt.linger)
  303. Addrinfo.tcp("127.0.0.1", 0).listen {|serv|
  304. serv.local_address.connect {|s1|
  305. s2, _ = serv.accept
  306. begin
  307. s1.setsockopt(opt)
  308. s1.close
  309. assert_raise(Errno::ECONNRESET) { s2.read }
  310. ensure
  311. s2.close
  312. end
  313. }
  314. }
  315. end
  316. def test_timestamp
  317. return if /linux|freebsd|netbsd|openbsd|solaris|darwin/ !~ RUBY_PLATFORM
  318. return if !defined?(Socket::AncillaryData)
  319. t1 = Time.now.strftime("%Y-%m-%d")
  320. stamp = nil
  321. Addrinfo.udp("127.0.0.1", 0).bind {|s1|
  322. Addrinfo.udp("127.0.0.1", 0).bind {|s2|
  323. s1.setsockopt(:SOCKET, :TIMESTAMP, true)
  324. s2.send "a", 0, s1.local_address
  325. msg, addr, rflags, stamp = s1.recvmsg
  326. assert_equal("a", msg)
  327. assert(stamp.cmsg_is?(:SOCKET, :TIMESTAMP))
  328. }
  329. }
  330. t2 = Time.now.strftime("%Y-%m-%d")
  331. pat = Regexp.union([t1, t2].uniq)
  332. assert_match(pat, stamp.inspect)
  333. t = stamp.timestamp
  334. assert_match(pat, t.strftime("%Y-%m-%d"))
  335. pat = /\.#{"%06d" % t.usec}/
  336. assert_match(pat, stamp.inspect)
  337. end
  338. def test_timestampns
  339. return if /linux/ !~ RUBY_PLATFORM || !defined?(Socket::SO_TIMESTAMPNS)
  340. t1 = Time.now.strftime("%Y-%m-%d")
  341. stamp = nil
  342. Addrinfo.udp("127.0.0.1", 0).bind {|s1|
  343. Addrinfo.udp("127.0.0.1", 0).bind {|s2|
  344. begin
  345. s1.setsockopt(:SOCKET, :TIMESTAMPNS, true)
  346. rescue Errno::ENOPROTOOPT
  347. # SO_TIMESTAMPNS is available since Linux 2.6.22
  348. return
  349. end
  350. s2.send "a", 0, s1.local_address
  351. msg, addr, rflags, stamp = s1.recvmsg
  352. assert_equal("a", msg)
  353. assert(stamp.cmsg_is?(:SOCKET, :TIMESTAMPNS))
  354. }
  355. }
  356. t2 = Time.now.strftime("%Y-%m-%d")
  357. pat = Regexp.union([t1, t2].uniq)
  358. assert_match(pat, stamp.inspect)
  359. t = stamp.timestamp
  360. assert_match(pat, t.strftime("%Y-%m-%d"))
  361. pat = /\.#{"%09d" % t.nsec}/
  362. assert_match(pat, stamp.inspect)
  363. end
  364. def test_bintime
  365. return if /freebsd/ !~ RUBY_PLATFORM
  366. t1 = Time.now.strftime("%Y-%m-%d")
  367. stamp = nil
  368. Addrinfo.udp("127.0.0.1", 0).bind {|s1|
  369. Addrinfo.udp("127.0.0.1", 0).bind {|s2|
  370. s1.setsockopt(:SOCKET, :BINTIME, true)
  371. s2.send "a", 0, s1.local_address
  372. msg, addr, rflags, stamp = s1.recvmsg
  373. assert_equal("a", msg)
  374. assert(stamp.cmsg_is?(:SOCKET, :BINTIME))
  375. }
  376. }
  377. t2 = Time.now.strftime("%Y-%m-%d")
  378. pat = Regexp.union([t1, t2].uniq)
  379. assert_match(pat, stamp.inspect)
  380. t = stamp.timestamp
  381. assert_match(pat, t.strftime("%Y-%m-%d"))
  382. assert_equal(stamp.data[-8,8].unpack("Q")[0], t.subsec * 2**64)
  383. end
  384. def test_closed_read
  385. require 'timeout'
  386. require 'socket'
  387. bug4390 = '[ruby-core:35203]'
  388. server = TCPServer.new("localhost", 0)
  389. serv_thread = Thread.new {server.accept}
  390. begin sleep(0.1) end until serv_thread.stop?
  391. sock = TCPSocket.new("localhost", server.addr[1])
  392. client_thread = Thread.new do
  393. sock.readline
  394. end
  395. begin sleep(0.1) end until client_thread.stop?
  396. Timeout.timeout(1) do
  397. sock.close
  398. sock = nil
  399. assert_raise(IOError, bug4390) {client_thread.join}
  400. end
  401. ensure
  402. server.close
  403. end
  404. def test_connect_timeout
  405. host = "127.0.0.1"
  406. server = TCPServer.new(host, 0)
  407. port = server.addr[1]
  408. serv_thread = Thread.new {server.accept}
  409. sock = Socket.tcp(host, port, :connect_timeout => 30)
  410. accepted = serv_thread.value
  411. assert_kind_of TCPSocket, accepted
  412. assert_equal sock, IO.select(nil, [ sock ])[1][0], "not writable"
  413. sock.close
  414. # some platforms may not timeout when the listener queue overflows,
  415. # but we know Linux does with the default listen backlog of SOMAXCONN for
  416. # TCPServer.
  417. assert_raises(Errno::ETIMEDOUT) do
  418. (Socket::SOMAXCONN*2).times do |i|
  419. sock = Socket.tcp(host, port, :connect_timeout => 0)
  420. assert_equal sock, IO.select(nil, [ sock ])[1][0],
  421. "not writable (#{i})"
  422. sock.close
  423. end
  424. end if RUBY_PLATFORM =~ /linux/
  425. ensure
  426. server.close
  427. accepted.close if accepted
  428. sock.close if sock && ! sock.closed?
  429. end
  430. end if defined?(Socket)