18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.net; 27 28 import java.io.FileDescriptor; 29 import java.io.IOException; 30 import java.io.InputStream; 31 import java.io.OutputStream; 32 33 import java.security.AccessController; 34 import java.security.PrivilegedActionException; 35 import java.security.PrivilegedExceptionAction; 36 import java.util.Collections; 37 import java.util.HashSet; 38 import java.util.Set; 39 40 import sun.net.ConnectionResetException; 41 import sun.net.NetHooks; 42 import sun.net.PlatformSocketImpl; 43 import sun.net.ResourceManager; 44 import sun.net.util.SocketExceptions; 45 46 /** 47 * Default Socket Implementation. This implementation does 48 * not implement any security checks. 49 * Note this class should <b>NOT</b> be public. 50 * 51 * @author Steven B. Byrne 52 */ 53 abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSocketImpl { 54 /* instance variable for SO_TIMEOUT */ 55 int timeout; // timeout in millisec 56 // traffic class 57 private int trafficClass; 58 59 private boolean shut_rd = false; 60 private boolean shut_wr = false; 61 62 private SocketInputStream socketInputStream = null; 63 private SocketOutputStream socketOutputStream = null; 67 68 /* lock when increment/decrementing fdUseCount */ 69 protected final Object fdLock = new Object(); 70 71 /* indicates a close is pending on the file descriptor */ 72 protected boolean closePending = false; 73 74 /* indicates connection reset state */ 75 private volatile boolean connectionReset; 76 77 /* indicates whether impl is bound */ 78 boolean isBound; 79 80 /* indicates whether impl is connected */ 81 volatile boolean isConnected; 82 83 /* whether this Socket is a stream (TCP) socket or not (UDP) 84 */ 85 protected boolean stream; 86 87 /** 88 * Load net library into runtime. 89 */ 90 static { 91 java.security.AccessController.doPrivileged( 92 new java.security.PrivilegedAction<>() { 93 public Void run() { 94 System.loadLibrary("net"); 95 return null; 96 } 97 }); 98 } 99 100 private static volatile boolean checkedReusePort; 101 private static volatile boolean isReusePortAvailable; 102 103 /** 104 * Tells whether SO_REUSEPORT is supported. 105 */ 106 static boolean isReusePortAvailable() { 107 if (!checkedReusePort) { 108 isReusePortAvailable = isReusePortAvailable0(); 109 checkedReusePort = true; 110 } 111 return isReusePortAvailable; 112 } 113 114 AbstractPlainSocketImpl(boolean isServer) { 115 super(isServer); 116 } 117 118 /** 119 * Returns a set of SocketOptions supported by this impl and by this impl's 120 * socket (Socket or ServerSocket) 121 * 122 * @return a Set of SocketOptions 123 */ 124 @Override 125 protected Set<SocketOption<?>> supportedOptions() { 126 Set<SocketOption<?>> options; 127 if (isReusePortAvailable()) { 128 options = new HashSet<>(); 129 options.addAll(super.supportedOptions()); 130 options.add(StandardSocketOptions.SO_REUSEPORT); 131 options = Collections.unmodifiableSet(options); 132 } else { 133 options = super.supportedOptions(); 134 } 135 return options; 136 } 137 138 /** 139 * Creates a socket with a boolean that specifies whether this 140 * is a stream socket (true) or an unconnected UDP socket (false). 141 */ 142 protected synchronized void create(boolean stream) throws IOException { 143 this.stream = stream; 144 if (!stream) { 145 ResourceManager.beforeUdpCreate(); 146 // only create the fd after we know we will be able to create the socket 147 fd = new FileDescriptor(); 148 try { 149 socketCreate(false); 150 SocketCleanable.register(fd); 151 } catch (IOException ioe) { 152 ResourceManager.afterUdpClose(); 153 fd = null; 154 throw ioe; 155 } 374 return trafficClass; 375 } else { 376 return ret; 377 } 378 } catch (SocketException se) { 379 // TODO - should make better effort to read TOS or TCLASS 380 return trafficClass; // ipv6 tos 381 } 382 case SO_KEEPALIVE: 383 ret = socketGetOption(opt, null); 384 return Boolean.valueOf(ret != -1); 385 case SO_REUSEPORT: 386 if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { 387 throw new UnsupportedOperationException("unsupported option"); 388 } 389 ret = socketGetOption(opt, null); 390 return Boolean.valueOf(ret != -1); 391 // should never get here 392 default: 393 return null; 394 } 395 } 396 397 /** 398 * The workhorse of the connection operation. Tries several times to 399 * establish a connection to the given <host, port>. If unsuccessful, 400 * throws an IOException indicating what went wrong. 401 */ 402 403 synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException { 404 synchronized (fdLock) { 405 if (!closePending && !isBound) { 406 NetHooks.beforeTcpConnect(fd, address, port); 407 } 408 } 409 try { 410 acquireFD(); 411 try { 412 socketConnect(address, port, timeout); 413 /* socket may have been closed during poll/select */ | 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.net; 27 28 import java.io.FileDescriptor; 29 import java.io.IOException; 30 import java.io.InputStream; 31 import java.io.OutputStream; 32 33 import java.security.AccessController; 34 import java.security.PrivilegedActionException; 35 import java.security.PrivilegedExceptionAction; 36 import java.util.Collections; 37 import java.util.HashSet; 38 import java.util.Objects; 39 import java.util.Set; 40 41 import sun.net.ConnectionResetException; 42 import sun.net.NetHooks; 43 import sun.net.PlatformSocketImpl; 44 import sun.net.ResourceManager; 45 import sun.net.ext.ExtendedSocketOptions; 46 import sun.net.util.SocketExceptions; 47 48 /** 49 * Default Socket Implementation. This implementation does 50 * not implement any security checks. 51 * Note this class should <b>NOT</b> be public. 52 * 53 * @author Steven B. Byrne 54 */ 55 abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSocketImpl { 56 /* instance variable for SO_TIMEOUT */ 57 int timeout; // timeout in millisec 58 // traffic class 59 private int trafficClass; 60 61 private boolean shut_rd = false; 62 private boolean shut_wr = false; 63 64 private SocketInputStream socketInputStream = null; 65 private SocketOutputStream socketOutputStream = null; 69 70 /* lock when increment/decrementing fdUseCount */ 71 protected final Object fdLock = new Object(); 72 73 /* indicates a close is pending on the file descriptor */ 74 protected boolean closePending = false; 75 76 /* indicates connection reset state */ 77 private volatile boolean connectionReset; 78 79 /* indicates whether impl is bound */ 80 boolean isBound; 81 82 /* indicates whether impl is connected */ 83 volatile boolean isConnected; 84 85 /* whether this Socket is a stream (TCP) socket or not (UDP) 86 */ 87 protected boolean stream; 88 89 /* whether this is a server or not */ 90 final boolean isServer; 91 92 /** 93 * Load net library into runtime. 94 */ 95 static { 96 java.security.AccessController.doPrivileged( 97 new java.security.PrivilegedAction<>() { 98 public Void run() { 99 System.loadLibrary("net"); 100 return null; 101 } 102 }); 103 } 104 105 private static volatile boolean checkedReusePort; 106 private static volatile boolean isReusePortAvailable; 107 108 /** 109 * Tells whether SO_REUSEPORT is supported. 110 */ 111 static boolean isReusePortAvailable() { 112 if (!checkedReusePort) { 113 isReusePortAvailable = isReusePortAvailable0(); 114 checkedReusePort = true; 115 } 116 return isReusePortAvailable; 117 } 118 119 AbstractPlainSocketImpl(boolean isServer) { 120 this.isServer = isServer; 121 } 122 123 /** 124 * Creates a socket with a boolean that specifies whether this 125 * is a stream socket (true) or an unconnected UDP socket (false). 126 */ 127 protected synchronized void create(boolean stream) throws IOException { 128 this.stream = stream; 129 if (!stream) { 130 ResourceManager.beforeUdpCreate(); 131 // only create the fd after we know we will be able to create the socket 132 fd = new FileDescriptor(); 133 try { 134 socketCreate(false); 135 SocketCleanable.register(fd); 136 } catch (IOException ioe) { 137 ResourceManager.afterUdpClose(); 138 fd = null; 139 throw ioe; 140 } 359 return trafficClass; 360 } else { 361 return ret; 362 } 363 } catch (SocketException se) { 364 // TODO - should make better effort to read TOS or TCLASS 365 return trafficClass; // ipv6 tos 366 } 367 case SO_KEEPALIVE: 368 ret = socketGetOption(opt, null); 369 return Boolean.valueOf(ret != -1); 370 case SO_REUSEPORT: 371 if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { 372 throw new UnsupportedOperationException("unsupported option"); 373 } 374 ret = socketGetOption(opt, null); 375 return Boolean.valueOf(ret != -1); 376 // should never get here 377 default: 378 return null; 379 } 380 } 381 382 static final ExtendedSocketOptions extendedOptions = 383 ExtendedSocketOptions.getInstance(); 384 385 private static final Set<SocketOption<?>> clientSocketOptions = clientSocketOptions(); 386 private static final Set<SocketOption<?>> serverSocketOptions = serverSocketOptions(); 387 388 private static Set<SocketOption<?>> clientSocketOptions() { 389 HashSet<SocketOption<?>> options = new HashSet<>(); 390 options.add(StandardSocketOptions.SO_KEEPALIVE); 391 options.add(StandardSocketOptions.SO_SNDBUF); 392 options.add(StandardSocketOptions.SO_RCVBUF); 393 options.add(StandardSocketOptions.SO_REUSEADDR); 394 options.add(StandardSocketOptions.SO_LINGER); 395 options.add(StandardSocketOptions.IP_TOS); 396 options.add(StandardSocketOptions.TCP_NODELAY); 397 if (isReusePortAvailable()) 398 options.add(StandardSocketOptions.SO_REUSEPORT); 399 options.addAll(ExtendedSocketOptions.clientSocketOptions()); 400 return Collections.unmodifiableSet(options); 401 } 402 403 private static Set<SocketOption<?>> serverSocketOptions() { 404 HashSet<SocketOption<?>> options = new HashSet<>(); 405 options.add(StandardSocketOptions.SO_RCVBUF); 406 options.add(StandardSocketOptions.SO_REUSEADDR); 407 options.add(StandardSocketOptions.IP_TOS); 408 if (isReusePortAvailable()) 409 options.add(StandardSocketOptions.SO_REUSEPORT); 410 options.addAll(ExtendedSocketOptions.serverSocketOptions()); 411 return Collections.unmodifiableSet(options); 412 } 413 414 @Override 415 protected Set<SocketOption<?>> supportedOptions() { 416 if (isServer) 417 return serverSocketOptions; 418 else 419 return clientSocketOptions; 420 } 421 422 @Override 423 protected <T> void setOption(SocketOption<T> name, T value) throws IOException { 424 Objects.requireNonNull(name); 425 if (!supportedOptions().contains(name)) 426 throw new UnsupportedOperationException("'" + name + "' not supported"); 427 428 if (!name.type().isInstance(value)) 429 throw new IllegalArgumentException("Invalid value '" + value + "'"); 430 431 if (isClosedOrPending()) 432 throw new SocketException("Socket closed"); 433 434 if (name == StandardSocketOptions.SO_KEEPALIVE) { 435 setOption(SocketOptions.SO_KEEPALIVE, value); 436 } else if (name == StandardSocketOptions.SO_SNDBUF) { 437 if (((Integer)value).intValue() < 0) 438 throw new IllegalArgumentException("Invalid send buffer size:" + value); 439 setOption(SocketOptions.SO_SNDBUF, value); 440 } else if (name == StandardSocketOptions.SO_RCVBUF) { 441 if (((Integer)value).intValue() < 0) 442 throw new IllegalArgumentException("Invalid recv buffer size:" + value); 443 setOption(SocketOptions.SO_RCVBUF, value); 444 } else if (name == StandardSocketOptions.SO_REUSEADDR) { 445 setOption(SocketOptions.SO_REUSEADDR, value); 446 } else if (name == StandardSocketOptions.SO_REUSEPORT) { 447 setOption(SocketOptions.SO_REUSEPORT, value); 448 } else if (name == StandardSocketOptions.SO_LINGER ) { 449 setOption(SocketOptions.SO_LINGER, value); 450 } else if (name == StandardSocketOptions.IP_TOS) { 451 int i = ((Integer)value).intValue(); 452 if (i < 0 || i > 255) 453 throw new IllegalArgumentException("Invalid IP_TOS value: " + value); 454 setOption(SocketOptions.IP_TOS, value); 455 } else if (name == StandardSocketOptions.TCP_NODELAY) { 456 setOption(SocketOptions.TCP_NODELAY, value); 457 } else if (extendedOptions.isOptionSupported(name)) { 458 extendedOptions.setOption(fd, name, value); 459 } else { 460 throw new AssertionError("unknown option: " + name); 461 } 462 } 463 464 @Override 465 @SuppressWarnings("unchecked") 466 protected <T> T getOption(SocketOption<T> name) throws IOException { 467 Objects.requireNonNull(name); 468 if (!supportedOptions().contains(name)) 469 throw new UnsupportedOperationException("'" + name + "' not supported"); 470 471 if (isClosedOrPending()) 472 throw new SocketException("Socket closed"); 473 474 if (name == StandardSocketOptions.SO_KEEPALIVE) { 475 return (T)getOption(SocketOptions.SO_KEEPALIVE); 476 } else if (name == StandardSocketOptions.SO_SNDBUF) { 477 return (T)getOption(SocketOptions.SO_SNDBUF); 478 } else if (name == StandardSocketOptions.SO_RCVBUF) { 479 return (T)getOption(SocketOptions.SO_RCVBUF); 480 } else if (name == StandardSocketOptions.SO_REUSEADDR) { 481 return (T)getOption(SocketOptions.SO_REUSEADDR); 482 } else if (name == StandardSocketOptions.SO_REUSEPORT) { 483 return (T)getOption(SocketOptions.SO_REUSEPORT); 484 } else if (name == StandardSocketOptions.SO_LINGER) { 485 return (T)getOption(SocketOptions.SO_LINGER); 486 } else if (name == StandardSocketOptions.IP_TOS) { 487 return (T)getOption(SocketOptions.IP_TOS); 488 } else if (name == StandardSocketOptions.TCP_NODELAY) { 489 return (T)getOption(SocketOptions.TCP_NODELAY); 490 } else if (extendedOptions.isOptionSupported(name)) { 491 return (T) extendedOptions.getOption(fd, name); 492 } else { 493 throw new AssertionError("unknown option: " + name); 494 } 495 } 496 497 /** 498 * The workhorse of the connection operation. Tries several times to 499 * establish a connection to the given <host, port>. If unsuccessful, 500 * throws an IOException indicating what went wrong. 501 */ 502 503 synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException { 504 synchronized (fdLock) { 505 if (!closePending && !isBound) { 506 NetHooks.beforeTcpConnect(fd, address, port); 507 } 508 } 509 try { 510 acquireFD(); 511 try { 512 socketConnect(address, port, timeout); 513 /* socket may have been closed during poll/select */ |