Skip to content

Commit 931ec38

Browse files
mkustermannCommit Queue
authored andcommitted
[io/gardening] Fix client address binding & fix standalone/io/socket_local_port_test
Various changes to the stanalone/io/socket_local_port_test: * Make server ports ephemeral: The test is testing client-side binding of address & port, the server part can use ephemeral ports. => This eliminates the issue of another process using the hard-coded port * Close sockets normally instead of using `Socket.destroy()` * Make dead code alive: There were test in the tests that were not invoked by `main()`. * Align the individual test helper functions. * ... Then we change the dart:io implementation of `Socket::CreateBindConnect` to set the `SO_REUSEADDR` socket option. We do this already for the server side in `Socket::CreateBindListen`, now we do it also for the client side. => This will ensure that one can bind the client side socket to specific address/source despite there being an old closed socket that's now in `TIME_WAIT` state. => This is the same reason we also do it in `Socket::CreateBindListen`. Fuchsia doesn't implement `Socket::CreateBindConnect` and on Windows the socket option seemingly has different semantics (we also don't use `SO_REUSEADDR` on windows for the server socket, but another option). Issue #51477 TEST=standalone/io/socket_local_port_test Change-Id: I7d07becad0cd98c3a9b973ef2f9037730d3f8b19 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/436902 Commit-Queue: Martin Kustermann <[email protected]> Reviewed-by: Slava Egorov <[email protected]>
1 parent fecf1b0 commit 931ec38

File tree

3 files changed

+80
-94
lines changed

3 files changed

+80
-94
lines changed

runtime/bin/socket_linux.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ intptr_t Socket::CreateBindConnect(const RawAddr& addr,
8181
return fd;
8282
}
8383

84+
int optval = 1;
85+
VOID_NO_RETRY_EXPECTED(
86+
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
87+
8488
intptr_t result = TEMP_FAILURE_RETRY(
8589
bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
8690
if (result != 0) {

runtime/bin/socket_macos.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ intptr_t Socket::CreateBindConnect(const RawAddr& addr,
8686
return fd;
8787
}
8888

89+
int optval = 1;
90+
VOID_NO_RETRY_EXPECTED(
91+
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
92+
8993
intptr_t result = TEMP_FAILURE_RETRY(
9094
bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
9195
if (result != 0) {

tests/standalone/io/socket_local_port_test.dart

Lines changed: 72 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -8,46 +8,40 @@ import "dart:io";
88
import "package:expect/expect.dart";
99

1010
Future testCustomPortIPv4() {
11-
String clientAddress = "127.0.0.1";
11+
String host = "127.0.0.1";
1212
int customLocalPort = 50988;
13-
String serverAddress = clientAddress;
14-
int port = 50989;
13+
String customAddress = host;
1514

16-
return testCustomPort(serverAddress, port, clientAddress, customLocalPort);
15+
return testCustomPort(host, customAddress, customLocalPort);
1716
}
1817

1918
Future testCustomPortIPv6() {
20-
String clientAddress = "::1";
21-
int customLocalPort = 50988;
22-
String serverAddress = clientAddress;
23-
int port = 50989;
19+
String host = "::1";
20+
int customLocalPort = 50989;
21+
String customAddress = host;
2422

25-
return testCustomPort(serverAddress, port, clientAddress, customLocalPort);
23+
return testCustomPort(host, customAddress, customLocalPort);
2624
}
2725

2826
Future testCustomPortIPv4NoSourceAddress() {
29-
String expectedClientAddress = "127.0.0.1";
30-
int customLocalPort = 50988;
31-
String serverAddress = expectedClientAddress;
32-
int port = 50989;
27+
String host = "127.0.0.1";
28+
int customLocalPort = 50990;
29+
String expectedClientAddress = host;
3330

34-
return testCustomPort(
35-
serverAddress,
36-
port,
31+
return testCustomPortNoSourceAddress(
32+
host,
3733
expectedClientAddress,
3834
customLocalPort,
3935
);
4036
}
4137

4238
Future testCustomPortIPv6NoSourceAddress() {
43-
String expectedClientAddress = "::1";
44-
int customLocalPort = 50988;
45-
String serverAddress = expectedClientAddress;
46-
int port = 50989;
39+
String host = "::1";
40+
int customLocalPort = 50991;
41+
String expectedClientAddress = host;
4742

48-
return testCustomPort(
49-
serverAddress,
50-
port,
43+
return testCustomPortNoSourceAddress(
44+
host,
5145
expectedClientAddress,
5246
customLocalPort,
5347
);
@@ -56,134 +50,118 @@ Future testCustomPortIPv6NoSourceAddress() {
5650
Future testNoCustomPortIPv4() {
5751
String host = "127.0.0.1";
5852
String clientAddress = host;
59-
int serverPort = 39998;
6053

61-
return testNoCustomPortNoSourceAddress(host, serverPort, clientAddress);
54+
return testNoCustomPort(host, clientAddress);
6255
}
6356

6457
Future testNoCustomPortIPv6() {
6558
String host = "::1";
6659
String clientAddress = host;
67-
int serverPort = 39998;
6860

69-
return testNoCustomPortNoSourceAddress(host, serverPort, clientAddress);
61+
return testNoCustomPort(host, clientAddress);
7062
}
7163

7264
Future testNoCustomPortNoSourceAddressIPv4() {
7365
String host = "127.0.0.1";
7466
String expectedAddress = host;
75-
int serverPort = 39998;
7667

77-
return testNoCustomPortNoSourceAddress(host, serverPort, expectedAddress);
68+
return testNoCustomPortNoSourceAddress(host, expectedAddress);
7869
}
7970

8071
Future testNoCustomPortNoSourceAddressIPv6() {
8172
String host = "::1";
8273
String expectedAddress = host;
83-
int serverPort = 39998;
8474

85-
return testNoCustomPortNoSourceAddress(host, serverPort, expectedAddress);
75+
return testNoCustomPortNoSourceAddress(host, expectedAddress);
8676
}
8777

8878
// Core functionality
89-
Future testCustomPort(
90-
String host,
91-
int port,
92-
String sourceAddress,
93-
int sourcePort,
94-
) async {
95-
var server = await ServerSocket.bind(host, port);
96-
server.listen((client) {
97-
Expect.equals(server.port, port);
79+
80+
Future testCustomPort(String host, String sourceAddress, int sourcePort) async {
81+
final serverTestDone = Completer();
82+
final server = await ServerSocket.bind(host, 0);
83+
server.listen((Socket client) async {
9884
Expect.equals(client.remotePort, sourcePort);
9985
Expect.equals(client.address.address, sourceAddress);
100-
client.destroy();
86+
await (client.close(), client.drain()).wait;
87+
serverTestDone.complete();
10188
});
102-
103-
Socket s = await Socket.connect(
89+
final client = await Socket.connect(
10490
host,
105-
port,
91+
server.port,
10692
sourceAddress: sourceAddress,
10793
sourcePort: sourcePort,
10894
);
109-
s.destroy();
95+
await (client.close(), client.drain()).wait;
96+
await serverTestDone.future;
11097
await server.close();
11198
}
11299

113100
Future testCustomPortNoSourceAddress(
114101
String host,
115-
int port,
116102
String expectedAddress,
117103
int sourcePort,
118104
) async {
119-
Completer completer = new Completer();
120-
var server = await ServerSocket.bind(host, port);
121-
122-
server.listen((client) {
123-
Expect.equals(server.port, port);
105+
final serverTestDone = Completer();
106+
final server = await ServerSocket.bind(host, 0);
107+
server.listen((Socket client) async {
124108
Expect.equals(client.remotePort, sourcePort);
125109
Expect.equals(client.address.address, expectedAddress);
126-
client.destroy();
127-
completer.complete();
110+
await (client.close(), client.drain()).wait;
111+
serverTestDone.complete();
128112
});
129-
130-
Socket s = await Socket.connect(host, port, sourcePort: sourcePort);
131-
s.destroy();
113+
final client = await Socket.connect(
114+
host,
115+
server.port,
116+
sourcePort: sourcePort,
117+
);
118+
await (client.close(), client.drain()).wait;
119+
await serverTestDone.future;
132120
await server.close();
133-
134-
return completer.future;
135121
}
136122

137-
Future testNoCustomPort(String host, int port, String sourceAddress) async {
138-
Completer serverCompleter = new Completer();
139-
Completer clientCompleter = new Completer();
140-
var server = await ServerSocket.bind(host, port);
141-
Socket.connect(host, port, sourceAddress: sourceAddress).then((
142-
clientSocket,
143-
) async {
144-
server.listen((client) async {
145-
Expect.equals(server.port, port);
146-
Expect.equals(client.remotePort, clientSocket.port);
147-
Expect.equals(client.address.address, sourceAddress);
148-
149-
client.destroy();
150-
clientCompleter.complete();
151-
});
152-
153-
clientSocket.destroy();
154-
await server.close();
155-
serverCompleter.complete();
123+
Future testNoCustomPort(String host, String sourceAddress) async {
124+
final serverTestDone = Completer();
125+
final server = await ServerSocket.bind(host, 0);
126+
server.listen((Socket client) async {
127+
Expect.equals(client.address.address, sourceAddress);
128+
await (client.close(), client.drain()).wait;
129+
serverTestDone.complete();
156130
});
157-
158-
await serverCompleter.future;
159-
await clientCompleter.future;
131+
final client = await Socket.connect(
132+
host,
133+
server.port,
134+
sourceAddress: sourceAddress,
135+
);
136+
await (client.close(), client.drain()).wait;
137+
await serverTestDone.future;
138+
await server.close();
160139
}
161140

162141
Future testNoCustomPortNoSourceAddress(
163142
String host,
164-
int port,
165143
String expectedAddress,
166144
) async {
167-
Completer completer = new Completer();
168-
var server = await ServerSocket.bind(host, port);
169-
Socket.connect(host, port).then((clientSocket) {
170-
server.listen((client) async {
171-
Expect.equals(server.port, port);
172-
Expect.equals(client.remotePort, clientSocket.port);
173-
Expect.equals(client.address.address, expectedAddress);
174-
clientSocket.destroy();
175-
client.destroy();
176-
await server.close();
177-
completer.complete();
178-
});
145+
final serverTestDone = Completer();
146+
final server = await ServerSocket.bind(host, 0);
147+
server.listen((Socket client) async {
148+
Expect.equals(client.address.address, expectedAddress);
149+
await (client.close(), client.drain()).wait;
150+
serverTestDone.complete();
179151
});
180-
return completer.future;
152+
final client = await Socket.connect(host, server.port);
153+
await (client.close(), client.drain()).wait;
154+
await serverTestDone.future;
155+
await server.close();
181156
}
182157

183158
Future main() async {
184159
await testCustomPortIPv4();
185160
await testCustomPortIPv6();
186161

162+
await testCustomPortIPv4NoSourceAddress();
163+
await testCustomPortIPv6NoSourceAddress();
164+
187165
await testNoCustomPortIPv4();
188166
await testNoCustomPortIPv6();
189167

0 commit comments

Comments
 (0)