summaryrefslogtreecommitdiff
path: root/test/socket/test_basicsocket.rb
blob: ac35f709558c6a7533bf2df48e001a7a30346011 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# frozen_string_literal: true

begin
  require "socket"
  require "test/unit"
rescue LoadError
end

class TestSocket_BasicSocket < Test::Unit::TestCase
  def inet_stream
    sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
    yield sock
  ensure
    assert(sock.closed?)
  end

  def test_getsockopt
    inet_stream do |s|
      n = s.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE)
      assert_equal([Socket::SOCK_STREAM].pack("i"), n.data)

      n = s.getsockopt("SOL_SOCKET", "SO_TYPE")
      assert_equal([Socket::SOCK_STREAM].pack("i"), n.data)

      n = s.getsockopt(:SOL_SOCKET, :SO_TYPE)
      assert_equal([Socket::SOCK_STREAM].pack("i"), n.data)

      n = s.getsockopt(:SOCKET, :TYPE)
      assert_equal([Socket::SOCK_STREAM].pack("i"), n.data)

      n = s.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR)
      assert_equal([0].pack("i"), n.data)

      val = Object.new
      class << val; self end.send(:define_method, :to_int) {
        s.close
        Socket::SO_TYPE
      }
      assert_raise(IOError) {
        n = s.getsockopt(Socket::SOL_SOCKET, val)
      }
    end
  end

  def test_setsockopt
    s = nil
    linger = [0, 0].pack("ii")

    val = Object.new
    class << val; self end.send(:define_method, :to_str) {
      s.close
      linger
    }
    inet_stream do |sock|
      s = sock
      assert_equal(0, s.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, linger))

      assert_raise(IOError, "[ruby-dev:25039]") {
        s.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, val)
      }
    end

    val = Object.new
    class << val; self end.send(:define_method, :to_int) {
      s.close
      Socket::SO_LINGER
    }
    inet_stream do |sock|
      s = sock
      assert_raise(IOError) {
        s.setsockopt(Socket::SOL_SOCKET, val, linger)
      }
    end
  end

  def test_listen
    s = nil
    log = Object.new
    class << log; self end.send(:define_method, :to_int) {
      s.close
      2
    }
    inet_stream do |sock|
      s = sock
      assert_raise(IOError) {
        s.listen(log)
      }
    end
  end

  def socks
    sserv = TCPServer.new(0)
    ssock = nil
    t = Thread.new { ssock = sserv.accept }
    csock = TCPSocket.new('localhost', sserv.addr[1])
    t.join
    yield sserv, ssock, csock
  ensure
    ssock.close rescue nil
    csock.close rescue nil
    sserv.close rescue nil
  end

  def test_close_read
    socks do |sserv, ssock, csock|

      # close_read makes subsequent reads raise IOError
      csock.close_read
      assert_raise(IOError) { csock.read(5) }

      # close_read ignores any error from shutting down half of still-open socket
      assert_nothing_raised { csock.close_read }

      # close_read raises if socket is not open
      assert_nothing_raised { csock.close }
      assert_raise(IOError) { csock.close_read }
    end
  end

  def test_close_write
    socks do |sserv, ssock, csock|

      # close_write makes subsequent writes raise IOError
      csock.close_write
      assert_raise(IOError) { csock.write(5) }

      # close_write ignores any error from shutting down half of still-open socket
      assert_nothing_raised { csock.close_write }

      # close_write raises if socket is not open
      assert_nothing_raised { csock.close }
      assert_raise(IOError) { csock.close_write }
    end
  end

  def test_for_fd
    assert_raise(ArgumentError, # [ruby-cvs:60402]
                 Errno::EBADF, '[ruby-core:72418] [Bug #11854]') do
      BasicSocket.for_fd(-1)
    end
    inet_stream do |sock|
      s = BasicSocket.for_fd(sock.fileno)
      assert_instance_of BasicSocket, s
      s.autoclose = false
      sock.close
    end
  end
end if defined?(BasicSocket)