src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java
changeset 59146 455612b3161a
parent 59000 612c58965775
child 59329 289000934908
equal deleted inserted replaced
59145:ea044aedc2b6 59146:455612b3161a
    29 import java.io.IOException;
    29 import java.io.IOException;
    30 import java.io.UncheckedIOException;
    30 import java.io.UncheckedIOException;
    31 import java.lang.invoke.MethodHandles;
    31 import java.lang.invoke.MethodHandles;
    32 import java.lang.invoke.VarHandle;
    32 import java.lang.invoke.VarHandle;
    33 import java.lang.ref.Cleaner.Cleanable;
    33 import java.lang.ref.Cleaner.Cleanable;
       
    34 import java.lang.reflect.Method;
    34 import java.net.DatagramSocket;
    35 import java.net.DatagramSocket;
    35 import java.net.Inet4Address;
    36 import java.net.Inet4Address;
    36 import java.net.Inet6Address;
    37 import java.net.Inet6Address;
    37 import java.net.InetAddress;
    38 import java.net.InetAddress;
    38 import java.net.InetSocketAddress;
    39 import java.net.InetSocketAddress;
    52 import java.nio.channels.DatagramChannel;
    53 import java.nio.channels.DatagramChannel;
    53 import java.nio.channels.IllegalBlockingModeException;
    54 import java.nio.channels.IllegalBlockingModeException;
    54 import java.nio.channels.MembershipKey;
    55 import java.nio.channels.MembershipKey;
    55 import java.nio.channels.NotYetConnectedException;
    56 import java.nio.channels.NotYetConnectedException;
    56 import java.nio.channels.SelectionKey;
    57 import java.nio.channels.SelectionKey;
       
    58 import java.nio.channels.spi.AbstractSelectableChannel;
    57 import java.nio.channels.spi.SelectorProvider;
    59 import java.nio.channels.spi.SelectorProvider;
       
    60 import java.security.AccessController;
       
    61 import java.security.PrivilegedExceptionAction;
    58 import java.util.Collections;
    62 import java.util.Collections;
       
    63 import java.util.HashMap;
    59 import java.util.HashSet;
    64 import java.util.HashSet;
       
    65 import java.util.Map;
    60 import java.util.Objects;
    66 import java.util.Objects;
    61 import java.util.Set;
    67 import java.util.Set;
    62 import java.util.concurrent.locks.ReentrantLock;
    68 import java.util.concurrent.locks.ReentrantLock;
       
    69 import java.util.function.Consumer;
    63 
    70 
    64 import jdk.internal.ref.CleanerFactory;
    71 import jdk.internal.ref.CleanerFactory;
    65 import sun.net.ResourceManager;
    72 import sun.net.ResourceManager;
    66 import sun.net.ext.ExtendedSocketOptions;
    73 import sun.net.ext.ExtendedSocketOptions;
    67 import sun.net.util.IPAddressUtil;
    74 import sun.net.util.IPAddressUtil;
   111 
   118 
   112     // IDs of native threads doing reads and writes, for signalling
   119     // IDs of native threads doing reads and writes, for signalling
   113     private long readerThread;
   120     private long readerThread;
   114     private long writerThread;
   121     private long writerThread;
   115 
   122 
   116     // Binding and remote address (when connected)
   123     // Local and remote (connected) address
   117     private InetSocketAddress localAddress;
   124     private InetSocketAddress localAddress;
   118     private InetSocketAddress remoteAddress;
   125     private InetSocketAddress remoteAddress;
       
   126 
       
   127     // Local address prior to connecting
       
   128     private InetSocketAddress initialLocalAddress;
   119 
   129 
   120     // Socket adaptor, created lazily
   130     // Socket adaptor, created lazily
   121     private static final VarHandle SOCKET;
   131     private static final VarHandle SOCKET;
   122     static {
   132     static {
   123         try {
   133         try {
  1101                     // ensure that the socket is bound
  1111                     // ensure that the socket is bound
  1102                     if (localAddress == null) {
  1112                     if (localAddress == null) {
  1103                         bindInternal(null);
  1113                         bindInternal(null);
  1104                     }
  1114                     }
  1105 
  1115 
       
  1116                     // capture local address before connect
       
  1117                     initialLocalAddress = localAddress;
       
  1118 
  1106                     int n = Net.connect(family,
  1119                     int n = Net.connect(family,
  1107                                         fd,
  1120                                         fd,
  1108                                         isa.getAddress(),
  1121                                         isa.getAddress(),
  1109                                         isa.getPort());
  1122                                         isa.getPort());
  1110                     if (n <= 0)
  1123                     if (n <= 0)
  1158 
  1171 
  1159                     // no longer connected
  1172                     // no longer connected
  1160                     remoteAddress = null;
  1173                     remoteAddress = null;
  1161                     state = ST_UNCONNECTED;
  1174                     state = ST_UNCONNECTED;
  1162 
  1175 
  1163                     // check whether rebind is needed
  1176                     // refresh localAddress, should be same as it was prior to connect
  1164                     InetSocketAddress isa = Net.localAddress(fd);
  1177                     localAddress = Net.localAddress(fd);
  1165                     if (isa.getPort() == 0) {
  1178                     try {
  1166                         // On Linux, if bound to ephemeral port,
  1179                         if (!localAddress.equals(initialLocalAddress)) {
  1167                         // disconnect does not preserve that port.
  1180                             // Workaround connect(2) issues on Linux and macOS
  1168                         // In this case, try to rebind to the previous port.
  1181                             repairSocket(initialLocalAddress);
  1169                         int port = localAddress.getPort();
  1182                             assert (localAddress != null)
  1170                         localAddress = isa; // in case Net.bind fails
  1183                                     && localAddress.equals(Net.localAddress(fd))
  1171                         Net.bind(family, fd, isa.getAddress(), port);
  1184                                     && localAddress.equals(initialLocalAddress);
  1172                         isa = Net.localAddress(fd); // refresh address
  1185                         }
  1173                         assert isa.getPort() == port;
  1186                     } finally {
       
  1187                         initialLocalAddress = null;
  1174                     }
  1188                     }
  1175 
       
  1176                     // refresh localAddress
       
  1177                     localAddress = isa;
       
  1178                 }
  1189                 }
  1179             } finally {
  1190             } finally {
  1180                 writeLock.unlock();
  1191                 writeLock.unlock();
  1181             }
  1192             }
  1182         } finally {
  1193         } finally {
  1183             readLock.unlock();
  1194             readLock.unlock();
  1184         }
  1195         }
  1185         return this;
  1196         return this;
       
  1197     }
       
  1198 
       
  1199     /**
       
  1200      * "Repair" the channel's socket after a disconnect that didn't restore the
       
  1201      * local address.
       
  1202      *
       
  1203      * On Linux, connect(2) dissolves the association but changes the local port
       
  1204      * to 0 when it was initially bound to an ephemeral port. The workaround here
       
  1205      * is to rebind to the original port.
       
  1206      *
       
  1207      * On macOS, connect(2) dissolves the association but rebinds the socket to
       
  1208      * the wildcard address when it was initially bound to a specific address.
       
  1209      * The workaround here is to re-create the socket.
       
  1210      */
       
  1211     private void repairSocket(InetSocketAddress target)
       
  1212         throws IOException
       
  1213     {
       
  1214         assert Thread.holdsLock(stateLock);
       
  1215 
       
  1216         // Linux: try to bind the socket to the original address/port
       
  1217         if (localAddress.getPort() == 0) {
       
  1218             assert localAddress.getAddress().equals(target.getAddress());
       
  1219             Net.bind(family, fd, target.getAddress(), target.getPort());
       
  1220             localAddress = Net.localAddress(fd);
       
  1221             return;
       
  1222         }
       
  1223 
       
  1224         // capture the value of all existing socket options
       
  1225         Map<SocketOption<?>, Object> map = new HashMap<>();
       
  1226         for (SocketOption<?> option : supportedOptions()) {
       
  1227             Object value = getOption(option);
       
  1228             if (value != null) {
       
  1229                 map.put(option, value);
       
  1230             }
       
  1231         }
       
  1232 
       
  1233         // macOS: re-create the socket.
       
  1234         FileDescriptor newfd = Net.socket(family, false);
       
  1235         try {
       
  1236             // copy the socket options that are protocol family agnostic
       
  1237             for (Map.Entry<SocketOption<?>, Object> e : map.entrySet()) {
       
  1238                 SocketOption<?> option = e.getKey();
       
  1239                 if (SocketOptionRegistry.findOption(option, Net.UNSPEC) != null) {
       
  1240                     Object value = e.getValue();
       
  1241                     try {
       
  1242                         Net.setSocketOption(newfd, Net.UNSPEC, option, value);
       
  1243                     } catch (IOException ignore) { }
       
  1244                 }
       
  1245             }
       
  1246 
       
  1247             // copy the blocking mode
       
  1248             if (!isBlocking()) {
       
  1249                 IOUtil.configureBlocking(newfd, false);
       
  1250             }
       
  1251 
       
  1252             // dup this channel's socket to the new socket. If this succeeds then
       
  1253             // fd will reference the new socket. If it fails then it will still
       
  1254             // reference the old socket.
       
  1255             nd.dup(newfd, fd);
       
  1256         } finally {
       
  1257             // release the file descriptor
       
  1258             nd.close(newfd);
       
  1259         }
       
  1260 
       
  1261         // bind to the original local address
       
  1262         try {
       
  1263             Net.bind(family, fd, target.getAddress(), target.getPort());
       
  1264         } catch (IOException ioe) {
       
  1265             // bind failed, socket is left unbound
       
  1266             localAddress = null;
       
  1267             throw ioe;
       
  1268         }
       
  1269 
       
  1270         // restore local address
       
  1271         localAddress = Net.localAddress(fd);
       
  1272 
       
  1273         // restore all socket options (including those set in first pass)
       
  1274         for (Map.Entry<SocketOption<?>, Object> e : map.entrySet()) {
       
  1275             @SuppressWarnings("unchecked")
       
  1276             SocketOption<Object> option = (SocketOption<Object>) e.getKey();
       
  1277             Object value = e.getValue();
       
  1278             try {
       
  1279                 setOption(option, value);
       
  1280             } catch (IOException ignore) { }
       
  1281         }
       
  1282 
       
  1283         // restore multicast group membership
       
  1284         MembershipRegistry registry = this.registry;
       
  1285         if (registry != null) {
       
  1286             registry.forEach(k -> {
       
  1287                 if (k instanceof MembershipKeyImpl.Type6) {
       
  1288                     MembershipKeyImpl.Type6 key6 = (MembershipKeyImpl.Type6) k;
       
  1289                     Net.join6(fd, key6.groupAddress(), key6.index(), key6.source());
       
  1290                 } else {
       
  1291                     MembershipKeyImpl.Type4 key4 = (MembershipKeyImpl.Type4) k;
       
  1292                     Net.join4(fd, key4.groupAddress(), key4.interfaceAddress(), key4.source());
       
  1293                 }
       
  1294             });
       
  1295         }
       
  1296 
       
  1297         // reset registration in all Selectors that this channel is registered with
       
  1298         AbstractSelectableChannels.forEach(this, SelectionKeyImpl::reset);
       
  1299     }
       
  1300 
       
  1301     /**
       
  1302      * Defines static methods to access AbstractSelectableChannel non-public members.
       
  1303      */
       
  1304     private static class AbstractSelectableChannels {
       
  1305         private static final Method FOREACH;
       
  1306         static {
       
  1307             try {
       
  1308                 PrivilegedExceptionAction<Method> pae = () -> {
       
  1309                     Method m = AbstractSelectableChannel.class.getDeclaredMethod("forEach", Consumer.class);
       
  1310                     m.setAccessible(true);
       
  1311                     return m;
       
  1312                 };
       
  1313                 FOREACH = AccessController.doPrivileged(pae);
       
  1314             } catch (Exception e) {
       
  1315                 throw new InternalError(e);
       
  1316             }
       
  1317         }
       
  1318         static void forEach(AbstractSelectableChannel ch, Consumer<SelectionKeyImpl> action) {
       
  1319             try {
       
  1320                 FOREACH.invoke(ch, action);
       
  1321             } catch (Exception e) {
       
  1322                 throw new InternalError(e);
       
  1323             }
       
  1324         }
  1186     }
  1325     }
  1187 
  1326 
  1188     /**
  1327     /**
  1189      * Joins channel's socket to the given group/interface and
  1328      * Joins channel's socket to the given group/interface and
  1190      * optional source address.
  1329      * optional source address.