mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	 8794dec6a5
			
		
	
	
		8794dec6a5
		
	
	
	
	
		
			
			* ext/socket/unixsocket.c (rsock_init_unixsock): check NUL bytes. https://hackerone.com/reports/302997 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62991 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
			
				
	
	
		
			711 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			711 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # frozen_string_literal: true
 | |
| 
 | |
| begin
 | |
|   require "socket"
 | |
| rescue LoadError
 | |
| end
 | |
| 
 | |
| require "test/unit"
 | |
| require "tempfile"
 | |
| require "timeout"
 | |
| require "tmpdir"
 | |
| require "io/nonblock"
 | |
| 
 | |
| class TestSocket_UNIXSocket < Test::Unit::TestCase
 | |
|   def test_fd_passing
 | |
|     r1, w = IO.pipe
 | |
|     s1, s2 = UNIXSocket.pair
 | |
|     begin
 | |
|       s1.send_io(nil)
 | |
|     rescue NotImplementedError
 | |
|       assert_raise(NotImplementedError) { s2.recv_io }
 | |
|     rescue TypeError
 | |
|       s1.send_io(r1)
 | |
|       r2 = s2.recv_io
 | |
|       assert_equal(r1.stat.ino, r2.stat.ino)
 | |
|       assert_not_equal(r1.fileno, r2.fileno)
 | |
|       assert(r2.close_on_exec?)
 | |
|       w.syswrite "a"
 | |
|       assert_equal("a", r2.sysread(10))
 | |
|     ensure
 | |
|       s1.close
 | |
|       s2.close
 | |
|       w.close
 | |
|       r1.close
 | |
|       r2.close if r2 && !r2.closed?
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_fd_passing_class_mode
 | |
|     UNIXSocket.pair do |s1, s2|
 | |
|       s1.send_io(s1.fileno)
 | |
|       r = s2.recv_io(nil)
 | |
|       assert_kind_of Integer, r, 'recv_io with klass=nil returns integer FD'
 | |
|       assert_not_equal s1.fileno, r
 | |
|       r = IO.for_fd(r)
 | |
|       assert_equal s1.stat.ino, r.stat.ino
 | |
|       r.close
 | |
| 
 | |
|       s1.send_io(s1)
 | |
|       # klass = UNIXSocket FIXME: [ruby-core:71860] [Bug #11778]
 | |
|       klass = IO
 | |
|       r = s2.recv_io(klass, 'r+')
 | |
|       assert_instance_of klass, r, 'recv_io with proper klass'
 | |
|       assert_not_equal s1.fileno, r.fileno
 | |
|       r.close
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_fd_passing_n
 | |
|     io_ary = []
 | |
|     return if !defined?(Socket::SCM_RIGHTS)
 | |
|     io_ary.concat IO.pipe
 | |
|     io_ary.concat IO.pipe
 | |
|     io_ary.concat IO.pipe
 | |
|     send_io_ary = []
 | |
|     io_ary.each {|io|
 | |
|       send_io_ary << io
 | |
|       UNIXSocket.pair {|s1, s2|
 | |
|         begin
 | |
|           ret = s1.sendmsg("\0", 0, nil, [Socket::SOL_SOCKET, Socket::SCM_RIGHTS,
 | |
|                                           send_io_ary.map {|io2| io2.fileno }.pack("i!*")])
 | |
|         rescue NotImplementedError
 | |
|           return
 | |
|         end
 | |
|         assert_equal(1, ret)
 | |
|         ret = s2.recvmsg(:scm_rights=>true)
 | |
|         _, _, _, *ctls = ret
 | |
|         recv_io_ary = []
 | |
|         begin
 | |
|           ctls.each {|ctl|
 | |
|             next if ctl.level != Socket::SOL_SOCKET || ctl.type != Socket::SCM_RIGHTS
 | |
|             recv_io_ary.concat ctl.unix_rights
 | |
|           }
 | |
|           assert_equal(send_io_ary.length, recv_io_ary.length)
 | |
|           send_io_ary.length.times {|i|
 | |
|             assert_not_equal(send_io_ary[i].fileno, recv_io_ary[i].fileno)
 | |
|             assert(File.identical?(send_io_ary[i], recv_io_ary[i]))
 | |
|             assert(recv_io_ary[i].close_on_exec?)
 | |
|           }
 | |
|         ensure
 | |
|           recv_io_ary.each {|io2| io2.close if !io2.closed? }
 | |
|         end
 | |
|       }
 | |
|     }
 | |
|   ensure
 | |
|     io_ary.each {|io| io.close if !io.closed? }
 | |
|   end
 | |
| 
 | |
|   def test_fd_passing_n2
 | |
|     io_ary = []
 | |
|     return if !defined?(Socket::SCM_RIGHTS)
 | |
|     return if !defined?(Socket::AncillaryData)
 | |
|     io_ary.concat IO.pipe
 | |
|     io_ary.concat IO.pipe
 | |
|     io_ary.concat IO.pipe
 | |
|     send_io_ary = []
 | |
|     io_ary.each {|io|
 | |
|       send_io_ary << io
 | |
|       UNIXSocket.pair {|s1, s2|
 | |
|         begin
 | |
|           ancdata = Socket::AncillaryData.unix_rights(*send_io_ary)
 | |
|           ret = s1.sendmsg("\0", 0, nil, ancdata)
 | |
|         rescue NotImplementedError
 | |
|           return
 | |
|         end
 | |
|         assert_equal(1, ret)
 | |
|         ret = s2.recvmsg(:scm_rights=>true)
 | |
|         _, _, _, *ctls = ret
 | |
|         recv_io_ary = []
 | |
|         begin
 | |
|           ctls.each {|ctl|
 | |
|             next if ctl.level != Socket::SOL_SOCKET || ctl.type != Socket::SCM_RIGHTS
 | |
|             recv_io_ary.concat ctl.unix_rights
 | |
|           }
 | |
|           assert_equal(send_io_ary.length, recv_io_ary.length)
 | |
|           send_io_ary.length.times {|i|
 | |
|             assert_not_equal(send_io_ary[i].fileno, recv_io_ary[i].fileno)
 | |
|             assert(File.identical?(send_io_ary[i], recv_io_ary[i]))
 | |
|             assert(recv_io_ary[i].close_on_exec?)
 | |
|           }
 | |
|         ensure
 | |
|           recv_io_ary.each {|io2| io2.close if !io2.closed? }
 | |
|         end
 | |
|       }
 | |
|     }
 | |
|   ensure
 | |
|     io_ary.each {|io| io.close if !io.closed? }
 | |
|   end
 | |
| 
 | |
|   def test_fd_passing_race_condition
 | |
|     r1, w = IO.pipe
 | |
|     s1, s2 = UNIXSocket.pair
 | |
|     s1.nonblock = s2.nonblock = true
 | |
|     lock = Thread::Mutex.new
 | |
|     nr = 0
 | |
|     x = 2
 | |
|     y = 1000
 | |
|     begin
 | |
|       s1.send_io(nil)
 | |
|     rescue NotImplementedError
 | |
|       assert_raise(NotImplementedError) { s2.recv_io }
 | |
|     rescue TypeError
 | |
|       thrs = x.times.map do
 | |
|         Thread.new do
 | |
|           y.times do
 | |
|             s2.recv_io.close
 | |
|             lock.synchronize { nr += 1 }
 | |
|           end
 | |
|           true
 | |
|         end
 | |
|       end
 | |
|       (x * y).times { s1.send_io r1 }
 | |
|       assert_equal([true]*x, thrs.map { |t| t.value })
 | |
|       assert_equal x * y, nr
 | |
|     ensure
 | |
|       s1.close
 | |
|       s2.close
 | |
|       w.close
 | |
|       r1.close
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_sendmsg
 | |
|     return if !defined?(Socket::SCM_RIGHTS)
 | |
|     IO.pipe {|r1, w|
 | |
|       UNIXSocket.pair {|s1, s2|
 | |
|         begin
 | |
|           ret = s1.sendmsg("\0", 0, nil, [Socket::SOL_SOCKET, Socket::SCM_RIGHTS, [r1.fileno].pack("i!")])
 | |
|         rescue NotImplementedError
 | |
|           return
 | |
|         end
 | |
|         assert_equal(1, ret)
 | |
|         r2 = s2.recv_io
 | |
|         begin
 | |
|           assert(File.identical?(r1, r2))
 | |
|           assert(r2.close_on_exec?)
 | |
|         ensure
 | |
|           r2.close
 | |
|         end
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_sendmsg_ancillarydata_int
 | |
|     return if !defined?(Socket::SCM_RIGHTS)
 | |
|     return if !defined?(Socket::AncillaryData)
 | |
|     IO.pipe {|r1, w|
 | |
|       UNIXSocket.pair {|s1, s2|
 | |
|         begin
 | |
|           ad = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, r1.fileno)
 | |
|           ret = s1.sendmsg("\0", 0, nil, ad)
 | |
|         rescue NotImplementedError
 | |
|           return
 | |
|         end
 | |
|         assert_equal(1, ret)
 | |
|         r2 = s2.recv_io
 | |
|         begin
 | |
|           assert(File.identical?(r1, r2))
 | |
|         ensure
 | |
|           r2.close
 | |
|         end
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_sendmsg_ancillarydata_unix_rights
 | |
|     return if !defined?(Socket::SCM_RIGHTS)
 | |
|     return if !defined?(Socket::AncillaryData)
 | |
|     IO.pipe {|r1, w|
 | |
|       UNIXSocket.pair {|s1, s2|
 | |
|         begin
 | |
|           ad = Socket::AncillaryData.unix_rights(r1)
 | |
|           ret = s1.sendmsg("\0", 0, nil, ad)
 | |
|         rescue NotImplementedError
 | |
|           return
 | |
|         end
 | |
|         assert_equal(1, ret)
 | |
|         r2 = s2.recv_io
 | |
|         begin
 | |
|           assert(File.identical?(r1, r2))
 | |
|         ensure
 | |
|           r2.close
 | |
|         end
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_recvmsg
 | |
|     return if !defined?(Socket::SCM_RIGHTS)
 | |
|     return if !defined?(Socket::AncillaryData)
 | |
|     IO.pipe {|r1, w|
 | |
|       UNIXSocket.pair {|s1, s2|
 | |
|         s1.send_io(r1)
 | |
|         ret = s2.recvmsg(:scm_rights=>true)
 | |
|         data, srcaddr, flags, *ctls = ret
 | |
|         assert_equal("\0", data)
 | |
| 	if flags == nil
 | |
| 	  # struct msghdr is 4.3BSD style (msg_accrights field).
 | |
| 	  assert_instance_of(Array, ctls)
 | |
| 	  assert_equal(0, ctls.length)
 | |
| 	else
 | |
| 	  # struct msghdr is POSIX/4.4BSD style (msg_control field).
 | |
| 	  assert_equal(0, flags & (Socket::MSG_TRUNC|Socket::MSG_CTRUNC))
 | |
| 	  assert_instance_of(Addrinfo, srcaddr)
 | |
| 	  assert_instance_of(Array, ctls)
 | |
| 	  assert_equal(1, ctls.length)
 | |
|           ctl = ctls[0]
 | |
| 	  assert_instance_of(Socket::AncillaryData, ctl)
 | |
| 	  assert_equal(Socket::SOL_SOCKET, ctl.level)
 | |
| 	  assert_equal(Socket::SCM_RIGHTS, ctl.type)
 | |
| 	  assert_instance_of(String, ctl.data)
 | |
|           ios = ctl.unix_rights
 | |
|           assert_equal(1, ios.length)
 | |
| 	  r2 = ios[0]
 | |
| 	  begin
 | |
| 	    assert(File.identical?(r1, r2))
 | |
|             assert(r2.close_on_exec?)
 | |
| 	  ensure
 | |
| 	    r2.close
 | |
| 	  end
 | |
| 	end
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def bound_unix_socket(klass)
 | |
|     tmpfile = Tempfile.new("s")
 | |
|     path = tmpfile.path
 | |
|     tmpfile.close(true)
 | |
|     io = klass.new(path)
 | |
|     yield io, path
 | |
|   ensure
 | |
|     io.close
 | |
|     File.unlink path if path && File.socket?(path)
 | |
|   end
 | |
| 
 | |
|   def test_open_nul_byte
 | |
|     tmpfile = Tempfile.new("s")
 | |
|     path = tmpfile.path
 | |
|     tmpfile.close(true)
 | |
|     assert_raise(ArgumentError) {UNIXServer.open(path+"\0")}
 | |
|     assert_raise(ArgumentError) {UNIXSocket.open(path+"\0")}
 | |
|   ensure
 | |
|     File.unlink path if path && File.socket?(path)
 | |
|   end
 | |
| 
 | |
|   def test_addr
 | |
|     bound_unix_socket(UNIXServer) {|serv, path|
 | |
|       UNIXSocket.open(path) {|c|
 | |
|         s = serv.accept
 | |
|         begin
 | |
|           assert_equal(["AF_UNIX", path], c.peeraddr)
 | |
|           assert_equal(["AF_UNIX", ""], c.addr)
 | |
|           assert_equal(["AF_UNIX", ""], s.peeraddr)
 | |
|           assert_equal(["AF_UNIX", path], s.addr)
 | |
|           assert_equal(path, s.path)
 | |
|           assert_equal("", c.path)
 | |
|         ensure
 | |
|           s.close
 | |
|         end
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_cloexec
 | |
|     bound_unix_socket(UNIXServer) {|serv, path|
 | |
|       UNIXSocket.open(path) {|c|
 | |
|         s = serv.accept
 | |
|         begin
 | |
|           assert(serv.close_on_exec?)
 | |
|           assert(c.close_on_exec?)
 | |
|           assert(s.close_on_exec?)
 | |
|         ensure
 | |
|           s.close
 | |
|         end
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_noname_path
 | |
|     s1, s2 = UNIXSocket.pair
 | |
|     assert_equal("", s1.path)
 | |
|     assert_equal("", s2.path)
 | |
|   ensure
 | |
|     s1.close
 | |
|     s2.close
 | |
|   end
 | |
| 
 | |
|   def test_noname_addr
 | |
|     s1, s2 = UNIXSocket.pair
 | |
|     assert_equal(["AF_UNIX", ""], s1.addr)
 | |
|     assert_equal(["AF_UNIX", ""], s2.addr)
 | |
|   ensure
 | |
|     s1.close
 | |
|     s2.close
 | |
|   end
 | |
| 
 | |
|   def test_noname_peeraddr
 | |
|     s1, s2 = UNIXSocket.pair
 | |
|     assert_equal(["AF_UNIX", ""], s1.peeraddr)
 | |
|     assert_equal(["AF_UNIX", ""], s2.peeraddr)
 | |
|   ensure
 | |
|     s1.close
 | |
|     s2.close
 | |
|   end
 | |
| 
 | |
|   def test_noname_unpack_sockaddr_un
 | |
|     s1, s2 = UNIXSocket.pair
 | |
|     n = nil
 | |
|     assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getsockname) != ""
 | |
|     assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getsockname) != ""
 | |
|     assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s2.getsockname) != ""
 | |
|     assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getpeername) != ""
 | |
|     assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s2.getpeername) != ""
 | |
|   ensure
 | |
|     s1.close
 | |
|     s2.close
 | |
|   end
 | |
| 
 | |
|   def test_noname_recvfrom
 | |
|     s1, s2 = UNIXSocket.pair
 | |
|     s2.write("a")
 | |
|     assert_equal(["a", ["AF_UNIX", ""]], s1.recvfrom(10))
 | |
|   ensure
 | |
|     s1.close
 | |
|     s2.close
 | |
|   end
 | |
| 
 | |
|   def test_noname_recv_nonblock
 | |
|     s1, s2 = UNIXSocket.pair
 | |
|     s2.write("a")
 | |
|     IO.select [s1]
 | |
|     assert_equal("a", s1.recv_nonblock(10))
 | |
|   ensure
 | |
|     s1.close
 | |
|     s2.close
 | |
|   end
 | |
| 
 | |
|   def test_too_long_path
 | |
|     assert_raise(ArgumentError) { Socket.sockaddr_un("a" * 3000) }
 | |
|     assert_raise(ArgumentError) { UNIXServer.new("a" * 3000) }
 | |
|   end
 | |
| 
 | |
|   def test_abstract_namespace
 | |
|     return if /linux/ !~ RUBY_PLATFORM
 | |
|     addr = Socket.pack_sockaddr_un("\0foo")
 | |
|     assert_match(/\0foo\z/, addr)
 | |
|     assert_equal("\0foo", Socket.unpack_sockaddr_un(addr))
 | |
|   end
 | |
| 
 | |
|   def test_dgram_pair
 | |
|     s1, s2 = UNIXSocket.pair(Socket::SOCK_DGRAM)
 | |
|     begin
 | |
|       s1.recv_nonblock(10)
 | |
|       fail
 | |
|     rescue => e
 | |
|       assert(IO::EAGAINWaitReadable === e)
 | |
|       assert(IO::WaitReadable === e)
 | |
|     end
 | |
|     s2.send("", 0)
 | |
|     s2.send("haha", 0)
 | |
|     s2.send("", 0)
 | |
|     s2.send("", 0)
 | |
|     assert_equal("", s1.recv(10))
 | |
|     assert_equal("haha", s1.recv(10))
 | |
|     assert_equal("", s1.recv(10))
 | |
|     assert_equal("", s1.recv(10))
 | |
|     assert_raise(IO::EAGAINWaitReadable) { s1.recv_nonblock(10) }
 | |
| 
 | |
|     buf = "".dup
 | |
|     s2.send("BBBBBB", 0)
 | |
|     IO.select([s1])
 | |
|     rv = s1.recv(100, 0, buf)
 | |
|     assert_equal buf.object_id, rv.object_id
 | |
|     assert_equal "BBBBBB", rv
 | |
|   ensure
 | |
|     s1.close if s1
 | |
|     s2.close if s2
 | |
|   end
 | |
| 
 | |
|   def test_dgram_pair_sendrecvmsg_errno_set
 | |
|     s1, s2 = to_close = UNIXSocket.pair(Socket::SOCK_DGRAM)
 | |
|     pipe = IO.pipe
 | |
|     to_close.concat(pipe)
 | |
|     set_errno = lambda do
 | |
|       begin
 | |
|         pipe[0].read_nonblock(1)
 | |
|         fail
 | |
|       rescue => e
 | |
|         assert(IO::EAGAINWaitReadable === e)
 | |
|       end
 | |
|     end
 | |
|     Timeout.timeout(10) do
 | |
|       set_errno.call
 | |
|       assert_equal(2, s1.sendmsg("HI"))
 | |
|       set_errno.call
 | |
|       assert_equal("HI", s2.recvmsg[0])
 | |
|     end
 | |
|   ensure
 | |
|     to_close.each(&:close) if to_close
 | |
|   end
 | |
| 
 | |
|   def test_epipe # [ruby-dev:34619]
 | |
|     UNIXSocket.pair {|s1, s2|
 | |
|       s1.shutdown(Socket::SHUT_WR)
 | |
|       assert_raise(Errno::EPIPE) { s1.write "a" }
 | |
|       assert_equal(nil, s2.read(1))
 | |
|       s2.write "a"
 | |
|       assert_equal("a", s1.read(1))
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_socket_pair_with_block
 | |
|     pair = nil
 | |
|     ret = Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM, 0) {|s1, s2|
 | |
|       pair = [s1, s2]
 | |
|       :return_value
 | |
|     }
 | |
|     assert_equal(:return_value, ret)
 | |
|     assert_kind_of(Socket, pair[0])
 | |
|     assert_kind_of(Socket, pair[1])
 | |
|   end
 | |
| 
 | |
|   def test_unix_socket_pair_with_block
 | |
|     pair = nil
 | |
|     UNIXSocket.pair {|s1, s2|
 | |
|       pair = [s1, s2]
 | |
|     }
 | |
|     assert_kind_of(UNIXSocket, pair[0])
 | |
|     assert_kind_of(UNIXSocket, pair[1])
 | |
|   end
 | |
| 
 | |
|   def test_unix_socket_pair_close_on_exec
 | |
|     UNIXSocket.pair {|s1, s2|
 | |
|       assert(s1.close_on_exec?)
 | |
|       assert(s2.close_on_exec?)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_initialize
 | |
|     Dir.mktmpdir {|d|
 | |
|       Socket.open(Socket::AF_UNIX, Socket::SOCK_STREAM, 0) {|s|
 | |
| 	s.bind(Socket.pack_sockaddr_un("#{d}/s1"))
 | |
| 	addr = s.getsockname
 | |
| 	assert_nothing_raised { Socket.unpack_sockaddr_un(addr) }
 | |
| 	assert_raise(ArgumentError) { Socket.unpack_sockaddr_in(addr) }
 | |
|       }
 | |
|       Socket.open("AF_UNIX", "SOCK_STREAM", 0) {|s|
 | |
| 	s.bind(Socket.pack_sockaddr_un("#{d}/s2"))
 | |
| 	addr = s.getsockname
 | |
| 	assert_nothing_raised { Socket.unpack_sockaddr_un(addr) }
 | |
| 	assert_raise(ArgumentError) { Socket.unpack_sockaddr_in(addr) }
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_unix_server_socket
 | |
|     Dir.mktmpdir {|d|
 | |
|       path = "#{d}/sock"
 | |
|       s0 = nil
 | |
|       Socket.unix_server_socket(path) {|s|
 | |
|         assert_equal(path, s.local_address.unix_path)
 | |
|         assert(File.socket?(path))
 | |
|         s0 = s
 | |
|       }
 | |
|       assert(s0.closed?)
 | |
|       assert_raise(Errno::ENOENT) { File.stat path }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_getcred_ucred
 | |
|     return if /linux/ !~ RUBY_PLATFORM
 | |
|     Dir.mktmpdir {|d|
 | |
|       sockpath = "#{d}/sock"
 | |
|       Socket.unix_server_socket(sockpath) {|serv|
 | |
|         Socket.unix(sockpath) {|c|
 | |
|           s, = serv.accept
 | |
|           begin
 | |
|             cred = s.getsockopt(:SOCKET, :PEERCRED)
 | |
|             inspect = cred.inspect
 | |
|             assert_match(/ pid=#{$$} /, inspect)
 | |
|             assert_match(/ euid=#{Process.euid} /, inspect)
 | |
|             assert_match(/ egid=#{Process.egid} /, inspect)
 | |
|             assert_match(/ \(ucred\)/, inspect)
 | |
|           ensure
 | |
|             s.close
 | |
|           end
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_getcred_xucred
 | |
|     return if /freebsd|darwin/ !~ RUBY_PLATFORM
 | |
|     Dir.mktmpdir {|d|
 | |
|       sockpath = "#{d}/sock"
 | |
|       serv = Socket.unix_server_socket(sockpath)
 | |
|       Socket.unix(sockpath)
 | |
|       s, = serv.accept
 | |
|       cred = s.getsockopt(0, Socket::LOCAL_PEERCRED)
 | |
|       inspect = cred.inspect
 | |
|       assert_match(/ euid=#{Process.euid} /, inspect)
 | |
|       assert_match(/ \(xucred\)/, inspect)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_sendcred_ucred
 | |
|     return if /linux/ !~ RUBY_PLATFORM
 | |
|     Dir.mktmpdir {|d|
 | |
|       sockpath = "#{d}/sock"
 | |
|       Socket.unix_server_socket(sockpath) {|serv|
 | |
|         Socket.unix(sockpath) {|c|
 | |
|           s, = serv.accept
 | |
|           begin
 | |
|             s.setsockopt(:SOCKET, :PASSCRED, 1)
 | |
|             c.print "a"
 | |
|             msg, _, _, cred = s.recvmsg
 | |
|             inspect = cred.inspect
 | |
|             assert_equal("a", msg)
 | |
|             assert_match(/ pid=#{$$} /, inspect)
 | |
|             assert_match(/ uid=#{Process.uid} /, inspect)
 | |
|             assert_match(/ gid=#{Process.gid} /, inspect)
 | |
|             assert_match(/ \(ucred\)/, inspect)
 | |
|           ensure
 | |
|             s.close
 | |
|           end
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_sendcred_sockcred
 | |
|     return if /netbsd|freebsd/ !~ RUBY_PLATFORM
 | |
|     Dir.mktmpdir {|d|
 | |
|       sockpath = "#{d}/sock"
 | |
|       serv = Socket.unix_server_socket(sockpath)
 | |
|       c = Socket.unix(sockpath)
 | |
|       s, = serv.accept
 | |
|       s.setsockopt(0, Socket::LOCAL_CREDS, 1)
 | |
|       c.print "a"
 | |
|       msg, _, _, cred = s.recvmsg
 | |
|       assert_equal("a", msg)
 | |
|       inspect = cred.inspect
 | |
|       assert_match(/ uid=#{Process.uid} /, inspect)
 | |
|       assert_match(/ euid=#{Process.euid} /, inspect)
 | |
|       assert_match(/ gid=#{Process.gid} /, inspect)
 | |
|       assert_match(/ egid=#{Process.egid} /, inspect)
 | |
|       assert_match(/ \(sockcred\)/, inspect)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_sendcred_cmsgcred
 | |
|     return if /freebsd/ !~ RUBY_PLATFORM
 | |
|     Dir.mktmpdir {|d|
 | |
|       sockpath = "#{d}/sock"
 | |
|       serv = Socket.unix_server_socket(sockpath)
 | |
|       c = Socket.unix(sockpath)
 | |
|       s, = serv.accept
 | |
|       c.sendmsg("a", 0, nil, [:SOCKET, Socket::SCM_CREDS, ""])
 | |
|       msg, _, _, cred = s.recvmsg
 | |
|       assert_equal("a", msg)
 | |
|       inspect = cred.inspect
 | |
|       assert_match(/ pid=#{$$} /, inspect)
 | |
|       assert_match(/ uid=#{Process.uid} /, inspect)
 | |
|       assert_match(/ euid=#{Process.euid} /, inspect)
 | |
|       assert_match(/ gid=#{Process.gid} /, inspect)
 | |
|       assert_match(/ \(cmsgcred\)/, inspect)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_getpeereid
 | |
|     Dir.mktmpdir {|d|
 | |
|       path = "#{d}/sock"
 | |
|       Socket.unix_server_socket(path) {|serv|
 | |
|         Socket.unix(path) {|c|
 | |
|           s, = serv.accept
 | |
|           begin
 | |
|             assert_equal([Process.euid, Process.egid], c.getpeereid)
 | |
|             assert_equal([Process.euid, Process.egid], s.getpeereid)
 | |
|           rescue NotImplementedError
 | |
|           ensure
 | |
|             s.close
 | |
|           end
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_abstract_unix_server
 | |
|     return if /linux/ !~ RUBY_PLATFORM
 | |
|     name = "\0ruby-test_unix"
 | |
|     s0 = nil
 | |
|     UNIXServer.open(name) {|s|
 | |
|       assert_equal(name, s.local_address.unix_path)
 | |
|       s0 = s
 | |
|       UNIXSocket.open(name) {|c|
 | |
|         sock = s.accept
 | |
|         begin
 | |
|           assert_equal(name, c.remote_address.unix_path)
 | |
|         ensure
 | |
|           sock.close
 | |
|         end
 | |
|       }
 | |
|     }
 | |
|     assert(s0.closed?)
 | |
|   end
 | |
| 
 | |
|   def test_abstract_unix_socket_econnrefused
 | |
|     return if /linux/ !~ RUBY_PLATFORM
 | |
|     name = "\0ruby-test_unix"
 | |
|     assert_raise(Errno::ECONNREFUSED) do
 | |
|       UNIXSocket.open(name) {}
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_abstract_unix_server_socket
 | |
|     return if /linux/ !~ RUBY_PLATFORM
 | |
|     name = "\0ruby-test_unix"
 | |
|     s0 = nil
 | |
|     Socket.unix_server_socket(name) {|s|
 | |
|       assert_equal(name, s.local_address.unix_path)
 | |
|       s0 = s
 | |
|       Socket.unix(name) {|c|
 | |
|         sock, = s.accept
 | |
|         begin
 | |
|           assert_equal(name, c.remote_address.unix_path)
 | |
|         ensure
 | |
|           sock.close
 | |
|         end
 | |
|       }
 | |
|     }
 | |
|     assert(s0.closed?)
 | |
|   end
 | |
| 
 | |
|   def test_autobind
 | |
|     return if /linux/ !~ RUBY_PLATFORM
 | |
|     s0 = nil
 | |
|     Socket.unix_server_socket("") {|s|
 | |
|       name = s.local_address.unix_path
 | |
|       assert_match(/\A\0[0-9a-f]{5}\z/, name)
 | |
|       s0 = s
 | |
|       Socket.unix(name) {|c|
 | |
|         sock, = s.accept
 | |
|         begin
 | |
|           assert_equal(name, c.remote_address.unix_path)
 | |
|         ensure
 | |
|           sock.close
 | |
|         end
 | |
|       }
 | |
|     }
 | |
|     assert(s0.closed?)
 | |
|   end
 | |
| 
 | |
|   def test_accept_nonblock
 | |
|     bound_unix_socket(UNIXServer) {|serv, path|
 | |
|       assert_raise(IO::WaitReadable) { serv.accept_nonblock }
 | |
|       assert_raise(IO::WaitReadable) { serv.accept_nonblock(exception: true) }
 | |
|       assert_equal :wait_readable, serv.accept_nonblock(exception: false)
 | |
|     }
 | |
|   end
 | |
| end if defined?(UNIXSocket) && /cygwin/ !~ RUBY_PLATFORM
 |