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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
|
# frozen_string_literal: true
begin
require "socket"
require "test/unit"
require "io/nonblock"
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|
begin
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)
rescue Minitest::Assertion
s.close
if /aix/ =~ RUBY_PLATFORM
skip "Known bug in getsockopt(2) on AIX"
end
raise $!
end
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('localhost', 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(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
def test_read_write_nonblock
socks do |sserv, ssock, csock|
set_nb = true
buf = String.new
if ssock.respond_to?(:nonblock?)
assert_predicate(ssock, :nonblock?)
assert_predicate(csock, :nonblock?)
csock.nonblock = ssock.nonblock = false
# Linux may use MSG_DONTWAIT to avoid setting O_NONBLOCK
if RUBY_PLATFORM.match?(/linux/) && Socket.const_defined?(:MSG_DONTWAIT)
set_nb = false
end
end
assert_equal :wait_readable, ssock.read_nonblock(1, buf, exception: false)
assert_equal 5, csock.write_nonblock('hello')
IO.select([ssock])
assert_same buf, ssock.read_nonblock(5, buf, exception: false)
assert_equal 'hello', buf
buf = '*' * 16384
n = 0
case w = csock.write_nonblock(buf, exception: false)
when Integer
n += w
when :wait_writable
break
end while true
assert_equal :wait_writable, w
assert_raise(IO::WaitWritable) { loop { csock.write_nonblock(buf) } }
assert_operator n, :>, 0
assert_not_predicate(csock, :nonblock?, '[Feature #13362]') unless set_nb
csock.close
case r = ssock.read_nonblock(16384, buf, exception: false)
when String
next
when nil
break
when :wait_readable
IO.select([ssock], nil, nil, 10) or
flunk 'socket did not become readable'
else
flunk "unexpected read_nonblock return: #{r.inspect}"
end while true
assert_raise(EOFError) { ssock.read_nonblock(1) }
assert_not_predicate(ssock, :nonblock?) unless set_nb
end
end
def test_read_nonblock_mix_buffered
socks do |sserv, ssock, csock|
ssock.write("hello\nworld\n")
assert_equal "hello\n", csock.gets
IO.select([csock], nil, nil, 10) or
flunk 'socket did not become readable'
assert_equal "world\n", csock.read_nonblock(8)
end
end
def test_write_nonblock_buffered
socks do |sserv, ssock, csock|
ssock.sync = false
ssock.write("h")
assert_equal :wait_readable, csock.read_nonblock(1, exception: false)
assert_equal 4, ssock.write_nonblock("ello")
ssock.close
assert_equal "hello", csock.read(5)
end
end
end if defined?(BasicSocket)
|