-
Notifications
You must be signed in to change notification settings - Fork 5.4k
/
Copy pathconnect_nonblock_spec.rb
149 lines (123 loc) · 4.2 KB
/
connect_nonblock_spec.rb
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
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe "Socket#connect_nonblock" do
before :each do
@hostname = "127.0.0.1"
@server = TCPServer.new(@hostname, 0) # started, but no accept
@addr = Socket.sockaddr_in(@server.addr[1], @hostname)
@socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
@thread = nil
end
after :each do
@socket.close
@server.close
@thread.join if @thread
end
platform_is_not :solaris do
it "connects the socket to the remote side" do
port = nil
accept = false
@thread = Thread.new do
server = TCPServer.new(@hostname, 0)
port = server.addr[1]
Thread.pass until accept
conn = server.accept
conn << "hello!"
conn.close
server.close
end
Thread.pass until port
addr = Socket.sockaddr_in(port, @hostname)
begin
@socket.connect_nonblock(addr)
rescue Errno::EINPROGRESS
end
accept = true
IO.select nil, [@socket]
begin
@socket.connect_nonblock(addr)
rescue Errno::EISCONN
# Not all OS's use this errno, so we trap and ignore it
end
@socket.read(6).should == "hello!"
end
end
platform_is_not :freebsd, :solaris, :aix do
it "raises Errno::EINPROGRESS when the connect would block" do
-> do
@socket.connect_nonblock(@addr)
end.should raise_error(Errno::EINPROGRESS)
end
it "raises Errno::EINPROGRESS with IO::WaitWritable mixed in when the connect would block" do
-> do
@socket.connect_nonblock(@addr)
end.should raise_error(IO::WaitWritable)
end
it "returns :wait_writable in exceptionless mode when the connect would block" do
@socket.connect_nonblock(@addr, exception: false).should == :wait_writable
end
end
end
describe 'Socket#connect_nonblock' do
SocketSpecs.each_ip_protocol do |family, ip_address|
describe 'using a DGRAM socket' do
before do
@server = Socket.new(family, :DGRAM)
@client = Socket.new(family, :DGRAM)
@sockaddr = Socket.sockaddr_in(0, ip_address)
@server.bind(@sockaddr)
end
after do
@client.close
@server.close
end
it 'returns 0 when successfully connected using a String' do
@client.connect_nonblock(@server.getsockname).should == 0
end
it 'returns 0 when successfully connected using an Addrinfo' do
@client.connect_nonblock(@server.connect_address).should == 0
end
it 'raises TypeError when passed an Integer' do
-> { @client.connect_nonblock(666) }.should raise_error(TypeError)
end
end
describe 'using a STREAM socket' do
before do
@server = Socket.new(family, :STREAM)
@client = Socket.new(family, :STREAM)
@sockaddr = Socket.sockaddr_in(0, ip_address)
end
after do
@client.close
@server.close
end
platform_is_not :windows do
it 'raises Errno::EISCONN when already connected' do
@server.listen(1)
@client.connect(@server.connect_address).should == 0
-> {
@client.connect_nonblock(@server.connect_address)
# A second call needed if non-blocking sockets become default
# XXX honestly I don't expect any real code to care about this spec
# as it's too implementation-dependent and checking for connect()
# errors is futile anyways because of TOCTOU
@client.connect_nonblock(@server.connect_address)
}.should raise_error(Errno::EISCONN)
end
it 'returns 0 when already connected in exceptionless mode' do
@server.listen(1)
@client.connect(@server.connect_address).should == 0
@client.connect_nonblock(@server.connect_address, exception: false).should == 0
end
end
platform_is_not :freebsd, :solaris do
it 'raises IO:EINPROGRESSWaitWritable when the connection would block' do
@server.bind(@sockaddr)
-> {
@client.connect_nonblock(@server.connect_address)
}.should raise_error(IO::EINPROGRESSWaitWritable)
end
end
end
end
end