[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 https://github.com/dart-lang/sdk/issues/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 <kustermann@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
This commit is contained in:
committed by
Commit Queue
parent
fecf1b0750
commit
931ec382d4
@@ -81,6 +81,10 @@ intptr_t Socket::CreateBindConnect(const RawAddr& addr,
|
||||
return fd;
|
||||
}
|
||||
|
||||
int optval = 1;
|
||||
VOID_NO_RETRY_EXPECTED(
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
|
||||
|
||||
intptr_t result = TEMP_FAILURE_RETRY(
|
||||
bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
|
||||
if (result != 0) {
|
||||
|
||||
@@ -86,6 +86,10 @@ intptr_t Socket::CreateBindConnect(const RawAddr& addr,
|
||||
return fd;
|
||||
}
|
||||
|
||||
int optval = 1;
|
||||
VOID_NO_RETRY_EXPECTED(
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
|
||||
|
||||
intptr_t result = TEMP_FAILURE_RETRY(
|
||||
bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
|
||||
if (result != 0) {
|
||||
|
||||
@@ -8,46 +8,40 @@ import "dart:io";
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
Future testCustomPortIPv4() {
|
||||
String clientAddress = "127.0.0.1";
|
||||
String host = "127.0.0.1";
|
||||
int customLocalPort = 50988;
|
||||
String serverAddress = clientAddress;
|
||||
int port = 50989;
|
||||
String customAddress = host;
|
||||
|
||||
return testCustomPort(serverAddress, port, clientAddress, customLocalPort);
|
||||
return testCustomPort(host, customAddress, customLocalPort);
|
||||
}
|
||||
|
||||
Future testCustomPortIPv6() {
|
||||
String clientAddress = "::1";
|
||||
int customLocalPort = 50988;
|
||||
String serverAddress = clientAddress;
|
||||
int port = 50989;
|
||||
String host = "::1";
|
||||
int customLocalPort = 50989;
|
||||
String customAddress = host;
|
||||
|
||||
return testCustomPort(serverAddress, port, clientAddress, customLocalPort);
|
||||
return testCustomPort(host, customAddress, customLocalPort);
|
||||
}
|
||||
|
||||
Future testCustomPortIPv4NoSourceAddress() {
|
||||
String expectedClientAddress = "127.0.0.1";
|
||||
int customLocalPort = 50988;
|
||||
String serverAddress = expectedClientAddress;
|
||||
int port = 50989;
|
||||
String host = "127.0.0.1";
|
||||
int customLocalPort = 50990;
|
||||
String expectedClientAddress = host;
|
||||
|
||||
return testCustomPort(
|
||||
serverAddress,
|
||||
port,
|
||||
return testCustomPortNoSourceAddress(
|
||||
host,
|
||||
expectedClientAddress,
|
||||
customLocalPort,
|
||||
);
|
||||
}
|
||||
|
||||
Future testCustomPortIPv6NoSourceAddress() {
|
||||
String expectedClientAddress = "::1";
|
||||
int customLocalPort = 50988;
|
||||
String serverAddress = expectedClientAddress;
|
||||
int port = 50989;
|
||||
String host = "::1";
|
||||
int customLocalPort = 50991;
|
||||
String expectedClientAddress = host;
|
||||
|
||||
return testCustomPort(
|
||||
serverAddress,
|
||||
port,
|
||||
return testCustomPortNoSourceAddress(
|
||||
host,
|
||||
expectedClientAddress,
|
||||
customLocalPort,
|
||||
);
|
||||
@@ -56,134 +50,118 @@ Future testCustomPortIPv6NoSourceAddress() {
|
||||
Future testNoCustomPortIPv4() {
|
||||
String host = "127.0.0.1";
|
||||
String clientAddress = host;
|
||||
int serverPort = 39998;
|
||||
|
||||
return testNoCustomPortNoSourceAddress(host, serverPort, clientAddress);
|
||||
return testNoCustomPort(host, clientAddress);
|
||||
}
|
||||
|
||||
Future testNoCustomPortIPv6() {
|
||||
String host = "::1";
|
||||
String clientAddress = host;
|
||||
int serverPort = 39998;
|
||||
|
||||
return testNoCustomPortNoSourceAddress(host, serverPort, clientAddress);
|
||||
return testNoCustomPort(host, clientAddress);
|
||||
}
|
||||
|
||||
Future testNoCustomPortNoSourceAddressIPv4() {
|
||||
String host = "127.0.0.1";
|
||||
String expectedAddress = host;
|
||||
int serverPort = 39998;
|
||||
|
||||
return testNoCustomPortNoSourceAddress(host, serverPort, expectedAddress);
|
||||
return testNoCustomPortNoSourceAddress(host, expectedAddress);
|
||||
}
|
||||
|
||||
Future testNoCustomPortNoSourceAddressIPv6() {
|
||||
String host = "::1";
|
||||
String expectedAddress = host;
|
||||
int serverPort = 39998;
|
||||
|
||||
return testNoCustomPortNoSourceAddress(host, serverPort, expectedAddress);
|
||||
return testNoCustomPortNoSourceAddress(host, expectedAddress);
|
||||
}
|
||||
|
||||
// Core functionality
|
||||
Future testCustomPort(
|
||||
String host,
|
||||
int port,
|
||||
String sourceAddress,
|
||||
int sourcePort,
|
||||
) async {
|
||||
var server = await ServerSocket.bind(host, port);
|
||||
server.listen((client) {
|
||||
Expect.equals(server.port, port);
|
||||
|
||||
Future testCustomPort(String host, String sourceAddress, int sourcePort) async {
|
||||
final serverTestDone = Completer();
|
||||
final server = await ServerSocket.bind(host, 0);
|
||||
server.listen((Socket client) async {
|
||||
Expect.equals(client.remotePort, sourcePort);
|
||||
Expect.equals(client.address.address, sourceAddress);
|
||||
client.destroy();
|
||||
await (client.close(), client.drain()).wait;
|
||||
serverTestDone.complete();
|
||||
});
|
||||
|
||||
Socket s = await Socket.connect(
|
||||
final client = await Socket.connect(
|
||||
host,
|
||||
port,
|
||||
server.port,
|
||||
sourceAddress: sourceAddress,
|
||||
sourcePort: sourcePort,
|
||||
);
|
||||
s.destroy();
|
||||
await (client.close(), client.drain()).wait;
|
||||
await serverTestDone.future;
|
||||
await server.close();
|
||||
}
|
||||
|
||||
Future testCustomPortNoSourceAddress(
|
||||
String host,
|
||||
int port,
|
||||
String expectedAddress,
|
||||
int sourcePort,
|
||||
) async {
|
||||
Completer completer = new Completer();
|
||||
var server = await ServerSocket.bind(host, port);
|
||||
|
||||
server.listen((client) {
|
||||
Expect.equals(server.port, port);
|
||||
final serverTestDone = Completer();
|
||||
final server = await ServerSocket.bind(host, 0);
|
||||
server.listen((Socket client) async {
|
||||
Expect.equals(client.remotePort, sourcePort);
|
||||
Expect.equals(client.address.address, expectedAddress);
|
||||
client.destroy();
|
||||
completer.complete();
|
||||
await (client.close(), client.drain()).wait;
|
||||
serverTestDone.complete();
|
||||
});
|
||||
|
||||
Socket s = await Socket.connect(host, port, sourcePort: sourcePort);
|
||||
s.destroy();
|
||||
final client = await Socket.connect(
|
||||
host,
|
||||
server.port,
|
||||
sourcePort: sourcePort,
|
||||
);
|
||||
await (client.close(), client.drain()).wait;
|
||||
await serverTestDone.future;
|
||||
await server.close();
|
||||
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
Future testNoCustomPort(String host, int port, String sourceAddress) async {
|
||||
Completer serverCompleter = new Completer();
|
||||
Completer clientCompleter = new Completer();
|
||||
var server = await ServerSocket.bind(host, port);
|
||||
Socket.connect(host, port, sourceAddress: sourceAddress).then((
|
||||
clientSocket,
|
||||
) async {
|
||||
server.listen((client) async {
|
||||
Expect.equals(server.port, port);
|
||||
Expect.equals(client.remotePort, clientSocket.port);
|
||||
Expect.equals(client.address.address, sourceAddress);
|
||||
|
||||
client.destroy();
|
||||
clientCompleter.complete();
|
||||
});
|
||||
|
||||
clientSocket.destroy();
|
||||
await server.close();
|
||||
serverCompleter.complete();
|
||||
Future testNoCustomPort(String host, String sourceAddress) async {
|
||||
final serverTestDone = Completer();
|
||||
final server = await ServerSocket.bind(host, 0);
|
||||
server.listen((Socket client) async {
|
||||
Expect.equals(client.address.address, sourceAddress);
|
||||
await (client.close(), client.drain()).wait;
|
||||
serverTestDone.complete();
|
||||
});
|
||||
|
||||
await serverCompleter.future;
|
||||
await clientCompleter.future;
|
||||
final client = await Socket.connect(
|
||||
host,
|
||||
server.port,
|
||||
sourceAddress: sourceAddress,
|
||||
);
|
||||
await (client.close(), client.drain()).wait;
|
||||
await serverTestDone.future;
|
||||
await server.close();
|
||||
}
|
||||
|
||||
Future testNoCustomPortNoSourceAddress(
|
||||
String host,
|
||||
int port,
|
||||
String expectedAddress,
|
||||
) async {
|
||||
Completer completer = new Completer();
|
||||
var server = await ServerSocket.bind(host, port);
|
||||
Socket.connect(host, port).then((clientSocket) {
|
||||
server.listen((client) async {
|
||||
Expect.equals(server.port, port);
|
||||
Expect.equals(client.remotePort, clientSocket.port);
|
||||
Expect.equals(client.address.address, expectedAddress);
|
||||
clientSocket.destroy();
|
||||
client.destroy();
|
||||
await server.close();
|
||||
completer.complete();
|
||||
});
|
||||
final serverTestDone = Completer();
|
||||
final server = await ServerSocket.bind(host, 0);
|
||||
server.listen((Socket client) async {
|
||||
Expect.equals(client.address.address, expectedAddress);
|
||||
await (client.close(), client.drain()).wait;
|
||||
serverTestDone.complete();
|
||||
});
|
||||
return completer.future;
|
||||
final client = await Socket.connect(host, server.port);
|
||||
await (client.close(), client.drain()).wait;
|
||||
await serverTestDone.future;
|
||||
await server.close();
|
||||
}
|
||||
|
||||
Future main() async {
|
||||
await testCustomPortIPv4();
|
||||
await testCustomPortIPv6();
|
||||
|
||||
await testCustomPortIPv4NoSourceAddress();
|
||||
await testCustomPortIPv6NoSourceAddress();
|
||||
|
||||
await testNoCustomPortIPv4();
|
||||
await testNoCustomPortIPv6();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user