8231260: (dc) DatagramChannel::disconnect changes the port of the local address to 0 (lnx)

DatagramChannel::disconnect will attempt to rebind to the original port if the local port switches back to 0 after the association is disolved by the system.

Reviewed-by: alanb, chegar, fweimer
This commit is contained in:
Daniel Fuchs 2019-10-09 17:38:58 +01:00
parent fddd963cec
commit a690af3832
3 changed files with 134 additions and 3 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -328,6 +328,10 @@ public abstract class DatagramChannel
* <p> If this channel's socket is not connected, or if the channel is
* closed, then invoking this method has no effect. </p>
*
* @apiNote If this method throws an IOException, the channel's socket
* may be left in an unspecified state. It is strongly recommended that
* the channel be closed when disconnect fails.
*
* @return This datagram channel
*
* @throws IOException

View file

@ -875,6 +875,11 @@ class DatagramChannelImpl
if (state == ST_CONNECTED)
throw new AlreadyConnectedException();
// ensure that the socket is bound
if (localAddress == null) {
bindInternal(null);
}
int n = Net.connect(family,
fd,
isa.getAddress(),
@ -932,8 +937,21 @@ class DatagramChannelImpl
remoteAddress = null;
state = ST_UNCONNECTED;
// refresh local address
localAddress = Net.localAddress(fd);
// check whether rebind is needed
InetSocketAddress isa = Net.localAddress(fd);
if (isa.getPort() == 0) {
// On Linux, if bound to ephemeral port,
// disconnect does not preserve that port.
// In this case, try to rebind to the previous port.
int port = localAddress.getPort();
localAddress = isa; // in case Net.bind fails
Net.bind(family, fd, isa.getAddress(), port);
isa = Net.localAddress(fd); // refresh address
assert isa.getPort() == port;
}
// refresh localAddress
localAddress = isa;
}
} finally {
writeLock.unlock();