src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java
branchdatagramsocketimpl-branch
changeset 58678 9cf78a70fa4f
parent 55081 dd321e3596c0
child 58679 9c3209ff7550
--- a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java	Thu Oct 17 20:27:44 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java	Thu Oct 17 20:53:35 2019 +0100
@@ -57,6 +57,7 @@
 
 import sun.net.ResourceManager;
 import sun.net.ext.ExtendedSocketOptions;
+import sun.net.util.IPAddressUtil;
 
 /**
  * An implementation of DatagramChannels.
@@ -527,14 +528,16 @@
                 } else {
                     // not connected
                     SecurityManager sm = System.getSecurityManager();
+                    InetAddress ia = isa.getAddress();
                     if (sm != null) {
-                        InetAddress ia = isa.getAddress();
                         if (ia.isMulticastAddress()) {
                             sm.checkMulticast(ia);
                         } else {
                             sm.checkConnect(ia.getHostAddress(), isa.getPort());
                         }
                     }
+                    if (ia.isLinkLocalAddress())
+                        isa = IPAddressUtil.toScopedAddress(isa);
                     n = send(fd, src, isa);
                     if (blocking) {
                         while (IOStatus.okayToRetry(n) && isOpen()) {
@@ -872,6 +875,11 @@
                     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(),
@@ -929,8 +937,21 @@
                     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();