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; |
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. |