1 /* 2 * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 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; 64 65 /* number of threads using the FileDescriptor */ 66 protected int fdUseCount = 0; 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 } 156 } else { 157 fd = new FileDescriptor(); 158 socketCreate(true); 159 SocketCleanable.register(fd); 160 } 161 } 162 163 /** 164 * Creates a socket and connects it to the specified port on 165 * the specified host. 166 * @param host the specified host 167 * @param port the specified port 168 */ 169 protected void connect(String host, int port) 170 throws UnknownHostException, IOException 171 { 172 boolean connected = false; 173 try { 174 InetAddress address = InetAddress.getByName(host); 175 this.port = port; 176 this.address = address; 177 178 connectToAddress(address, port, timeout); 179 connected = true; 180 } finally { 181 if (!connected) { 182 try { 183 close(); 184 } catch (IOException ioe) { 185 /* Do nothing. If connect threw an exception then 186 it will be passed up the call stack */ 187 } 188 } 189 isConnected = connected; 190 } 191 } 192 193 /** 194 * Creates a socket and connects it to the specified address on 195 * the specified port. 196 * @param address the address 197 * @param port the specified port 198 */ 199 protected void connect(InetAddress address, int port) throws IOException { 200 this.port = port; 201 this.address = address; 202 203 try { 204 connectToAddress(address, port, timeout); 205 isConnected = true; 206 return; 207 } catch (IOException e) { 208 // everything failed 209 close(); 210 throw e; 211 } 212 } 213 214 /** 215 * Creates a socket and connects it to the specified address on 216 * the specified port. 217 * @param address the address 218 * @param timeout the timeout value in milliseconds, or zero for no timeout. 219 * @throws IOException if connection fails 220 * @throws IllegalArgumentException if address is null or is a 221 * SocketAddress subclass not supported by this socket 222 * @since 1.4 223 */ 224 protected void connect(SocketAddress address, int timeout) 225 throws IOException { 226 boolean connected = false; 227 try { 228 if (address == null || !(address instanceof InetSocketAddress)) 229 throw new IllegalArgumentException("unsupported address type"); 230 InetSocketAddress addr = (InetSocketAddress) address; 231 if (addr.isUnresolved()) 232 throw new UnknownHostException(addr.getHostName()); 233 this.port = addr.getPort(); 234 this.address = addr.getAddress(); 235 236 connectToAddress(this.address, port, timeout); 237 connected = true; 238 } finally { 239 if (!connected) { 240 try { 241 close(); 242 } catch (IOException ioe) { 243 /* Do nothing. If connect threw an exception then 244 it will be passed up the call stack */ 245 } 246 } 247 isConnected = connected; 248 } 249 } 250 251 private void connectToAddress(InetAddress address, int port, int timeout) throws IOException { 252 if (address.isAnyLocalAddress()) { 253 doConnect(InetAddress.getLocalHost(), port, timeout); 254 } else { 255 doConnect(address, port, timeout); 256 } 257 } 258 259 public void setOption(int opt, Object val) throws SocketException { 260 if (isClosedOrPending()) { 261 throw new SocketException("Socket Closed"); 262 } 263 boolean on = true; 264 switch (opt) { 265 /* check type safety b4 going native. These should never 266 * fail, since only java.Socket* has access to 267 * PlainSocketImpl.setOption(). 268 */ 269 case SO_LINGER: 270 if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean))) 271 throw new SocketException("Bad parameter for option"); 272 if (val instanceof Boolean) { 273 /* true only if disabling - enabling should be Integer */ 274 on = false; 275 } 276 break; 277 case SO_TIMEOUT: 278 if (val == null || (!(val instanceof Integer))) 279 throw new SocketException("Bad parameter for SO_TIMEOUT"); 280 int tmp = ((Integer) val).intValue(); 281 if (tmp < 0) 282 throw new IllegalArgumentException("timeout < 0"); 283 timeout = tmp; 284 break; 285 case IP_TOS: 286 if (val == null || !(val instanceof Integer)) { 287 throw new SocketException("bad argument for IP_TOS"); 288 } 289 trafficClass = ((Integer)val).intValue(); 290 break; 291 case SO_BINDADDR: 292 throw new SocketException("Cannot re-bind socket"); 293 case TCP_NODELAY: 294 if (val == null || !(val instanceof Boolean)) 295 throw new SocketException("bad parameter for TCP_NODELAY"); 296 on = ((Boolean)val).booleanValue(); 297 break; 298 case SO_SNDBUF: 299 case SO_RCVBUF: 300 if (val == null || !(val instanceof Integer) || 301 !(((Integer)val).intValue() > 0)) { 302 throw new SocketException("bad parameter for SO_SNDBUF " + 303 "or SO_RCVBUF"); 304 } 305 break; 306 case SO_KEEPALIVE: 307 if (val == null || !(val instanceof Boolean)) 308 throw new SocketException("bad parameter for SO_KEEPALIVE"); 309 on = ((Boolean)val).booleanValue(); 310 break; 311 case SO_OOBINLINE: 312 if (val == null || !(val instanceof Boolean)) 313 throw new SocketException("bad parameter for SO_OOBINLINE"); 314 on = ((Boolean)val).booleanValue(); 315 break; 316 case SO_REUSEADDR: 317 if (val == null || !(val instanceof Boolean)) 318 throw new SocketException("bad parameter for SO_REUSEADDR"); 319 on = ((Boolean)val).booleanValue(); 320 break; 321 case SO_REUSEPORT: 322 if (val == null || !(val instanceof Boolean)) 323 throw new SocketException("bad parameter for SO_REUSEPORT"); 324 if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) 325 throw new UnsupportedOperationException("unsupported option"); 326 on = ((Boolean)val).booleanValue(); 327 break; 328 default: 329 throw new SocketException("unrecognized TCP option: " + opt); 330 } 331 socketSetOption(opt, on, val); 332 } 333 public Object getOption(int opt) throws SocketException { 334 if (isClosedOrPending()) { 335 throw new SocketException("Socket Closed"); 336 } 337 if (opt == SO_TIMEOUT) { 338 return timeout; 339 } 340 int ret = 0; 341 /* 342 * The native socketGetOption() knows about 3 options. 343 * The 32 bit value it returns will be interpreted according 344 * to what we're asking. A return of -1 means it understands 345 * the option but its turned off. It will raise a SocketException 346 * if "opt" isn't one it understands. 347 */ 348 349 switch (opt) { 350 case TCP_NODELAY: 351 ret = socketGetOption(opt, null); 352 return Boolean.valueOf(ret != -1); 353 case SO_OOBINLINE: 354 ret = socketGetOption(opt, null); 355 return Boolean.valueOf(ret != -1); 356 case SO_LINGER: 357 ret = socketGetOption(opt, null); 358 return (ret == -1) ? Boolean.FALSE: (Object)(ret); 359 case SO_REUSEADDR: 360 ret = socketGetOption(opt, null); 361 return Boolean.valueOf(ret != -1); 362 case SO_BINDADDR: 363 InetAddressContainer in = new InetAddressContainer(); 364 ret = socketGetOption(opt, in); 365 return in.addr; 366 case SO_SNDBUF: 367 case SO_RCVBUF: 368 ret = socketGetOption(opt, null); 369 return ret; 370 case IP_TOS: 371 try { 372 ret = socketGetOption(opt, null); 373 if (ret == -1) { // ipv6 tos 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 */ 414 synchronized (fdLock) { 415 if (closePending) { 416 throw new SocketException ("Socket closed"); 417 } 418 } 419 } finally { 420 releaseFD(); 421 } 422 } catch (IOException e) { 423 close(); 424 throw SocketExceptions.of(e, new InetSocketAddress(address, port)); 425 } 426 } 427 428 /** 429 * Binds the socket to the specified address of the specified local port. 430 * @param address the address 431 * @param lport the port 432 */ 433 protected synchronized void bind(InetAddress address, int lport) 434 throws IOException 435 { 436 synchronized (fdLock) { 437 if (!closePending && !isBound) { 438 NetHooks.beforeTcpBind(fd, address, lport); 439 } 440 } 441 socketBind(address, lport); 442 isBound = true; 443 } 444 445 /** 446 * Listens, for a specified amount of time, for connections. 447 * @param count the amount of time to listen for connections 448 */ 449 protected synchronized void listen(int count) throws IOException { 450 socketListen(count); 451 } 452 453 /** 454 * Accepts connections. 455 * @param si the socket impl 456 */ 457 protected void accept(SocketImpl si) throws IOException { 458 si.fd = new FileDescriptor(); 459 acquireFD(); 460 try { 461 socketAccept(si); 462 } finally { 463 releaseFD(); 464 } 465 SocketCleanable.register(si.fd); 466 } 467 468 /** 469 * Gets an InputStream for this socket. 470 */ 471 protected synchronized InputStream getInputStream() throws IOException { 472 synchronized (fdLock) { 473 if (isClosedOrPending()) 474 throw new IOException("Socket Closed"); 475 if (shut_rd) 476 throw new IOException("Socket input is shutdown"); 477 if (socketInputStream == null) { 478 PrivilegedExceptionAction<SocketInputStream> pa = () -> new SocketInputStream(this); 479 try { 480 socketInputStream = AccessController.doPrivileged(pa); 481 } catch (PrivilegedActionException e) { 482 throw (IOException) e.getCause(); 483 } 484 } 485 } 486 return socketInputStream; 487 } 488 489 void setInputStream(SocketInputStream in) { 490 socketInputStream = in; 491 } 492 493 /** 494 * Gets an OutputStream for this socket. 495 */ 496 protected synchronized OutputStream getOutputStream() throws IOException { 497 synchronized (fdLock) { 498 if (isClosedOrPending()) 499 throw new IOException("Socket Closed"); 500 if (shut_wr) 501 throw new IOException("Socket output is shutdown"); 502 if (socketOutputStream == null) { 503 PrivilegedExceptionAction<SocketOutputStream> pa = () -> new SocketOutputStream(this); 504 try { 505 socketOutputStream = AccessController.doPrivileged(pa); 506 } catch (PrivilegedActionException e) { 507 throw (IOException) e.getCause(); 508 } 509 } 510 } 511 return socketOutputStream; 512 } 513 514 void setFileDescriptor(FileDescriptor fd) { 515 this.fd = fd; 516 } 517 518 void setAddress(InetAddress address) { 519 this.address = address; 520 } 521 522 void setPort(int port) { 523 this.port = port; 524 } 525 526 void setLocalPort(int localport) { 527 this.localport = localport; 528 } 529 530 /** 531 * Returns the number of bytes that can be read without blocking. 532 */ 533 protected synchronized int available() throws IOException { 534 if (isClosedOrPending()) { 535 throw new IOException("Stream closed."); 536 } 537 538 /* 539 * If connection has been reset or shut down for input, then return 0 540 * to indicate there are no buffered bytes. 541 */ 542 if (isConnectionReset() || shut_rd) { 543 return 0; 544 } 545 546 /* 547 * If no bytes available and we were previously notified 548 * of a connection reset then we move to the reset state. 549 * 550 * If are notified of a connection reset then check 551 * again if there are bytes buffered on the socket. 552 */ 553 int n = 0; 554 try { 555 n = socketAvailable(); 556 } catch (ConnectionResetException exc1) { 557 setConnectionReset(); 558 } 559 return n; 560 } 561 562 /** 563 * Closes the socket. 564 */ 565 protected void close() throws IOException { 566 synchronized(fdLock) { 567 if (fd != null) { 568 if (!stream) { 569 ResourceManager.afterUdpClose(); 570 } 571 if (fdUseCount == 0) { 572 if (closePending) { 573 return; 574 } 575 closePending = true; 576 /* 577 * We close the FileDescriptor in two-steps - first the 578 * "pre-close" which closes the socket but doesn't 579 * release the underlying file descriptor. This operation 580 * may be lengthy due to untransmitted data and a long 581 * linger interval. Once the pre-close is done we do the 582 * actual socket to release the fd. 583 */ 584 try { 585 socketPreClose(); 586 } finally { 587 socketClose(); 588 } 589 fd = null; 590 return; 591 } else { 592 /* 593 * If a thread has acquired the fd and a close 594 * isn't pending then use a deferred close. 595 * Also decrement fdUseCount to signal the last 596 * thread that releases the fd to close it. 597 */ 598 if (!closePending) { 599 closePending = true; 600 fdUseCount--; 601 socketPreClose(); 602 } 603 } 604 } 605 } 606 } 607 608 void reset() { 609 throw new InternalError("should not get here"); 610 } 611 612 /** 613 * Shutdown read-half of the socket connection; 614 */ 615 protected void shutdownInput() throws IOException { 616 if (fd != null) { 617 socketShutdown(SHUT_RD); 618 if (socketInputStream != null) { 619 socketInputStream.setEOF(true); 620 } 621 shut_rd = true; 622 } 623 } 624 625 /** 626 * Shutdown write-half of the socket connection; 627 */ 628 protected void shutdownOutput() throws IOException { 629 if (fd != null) { 630 socketShutdown(SHUT_WR); 631 shut_wr = true; 632 } 633 } 634 635 protected boolean supportsUrgentData () { 636 return true; 637 } 638 639 protected void sendUrgentData (int data) throws IOException { 640 if (fd == null) { 641 throw new IOException("Socket Closed"); 642 } 643 socketSendUrgentData (data); 644 } 645 646 /* 647 * "Acquires" and returns the FileDescriptor for this impl 648 * 649 * A corresponding releaseFD is required to "release" the 650 * FileDescriptor. 651 */ 652 FileDescriptor acquireFD() { 653 synchronized (fdLock) { 654 fdUseCount++; 655 return fd; 656 } 657 } 658 659 /* 660 * "Release" the FileDescriptor for this impl. 661 * 662 * If the use count goes to -1 then the socket is closed. 663 */ 664 void releaseFD() { 665 synchronized (fdLock) { 666 fdUseCount--; 667 if (fdUseCount == -1) { 668 if (fd != null) { 669 try { 670 socketClose(); 671 } catch (IOException e) { 672 } finally { 673 fd = null; 674 } 675 } 676 } 677 } 678 } 679 680 boolean isConnectionReset() { 681 return connectionReset; 682 } 683 684 void setConnectionReset() { 685 connectionReset = true; 686 } 687 688 /* 689 * Return true if already closed or close is pending 690 */ 691 public boolean isClosedOrPending() { 692 /* 693 * Lock on fdLock to ensure that we wait if a 694 * close is in progress. 695 */ 696 synchronized (fdLock) { 697 if (closePending || (fd == null)) { 698 return true; 699 } else { 700 return false; 701 } 702 } 703 } 704 705 /* 706 * Return the current value of SO_TIMEOUT 707 */ 708 public int getTimeout() { 709 return timeout; 710 } 711 712 /* 713 * "Pre-close" a socket by dup'ing the file descriptor - this enables 714 * the socket to be closed without releasing the file descriptor. 715 */ 716 private void socketPreClose() throws IOException { 717 socketClose0(true); 718 } 719 720 /* 721 * Close the socket (and release the file descriptor). 722 */ 723 protected void socketClose() throws IOException { 724 SocketCleanable.unregister(fd); 725 socketClose0(false); 726 } 727 728 abstract void socketCreate(boolean stream) throws IOException; 729 abstract void socketConnect(InetAddress address, int port, int timeout) 730 throws IOException; 731 abstract void socketBind(InetAddress address, int port) 732 throws IOException; 733 abstract void socketListen(int count) 734 throws IOException; 735 abstract void socketAccept(SocketImpl s) 736 throws IOException; 737 abstract int socketAvailable() 738 throws IOException; 739 abstract void socketClose0(boolean useDeferredClose) 740 throws IOException; 741 abstract void socketShutdown(int howto) 742 throws IOException; 743 abstract void socketSetOption(int cmd, boolean on, Object value) 744 throws SocketException; 745 abstract int socketGetOption(int opt, Object iaContainerObj) throws SocketException; 746 abstract void socketSendUrgentData(int data) 747 throws IOException; 748 749 public static final int SHUT_RD = 0; 750 public static final int SHUT_WR = 1; 751 752 private static native boolean isReusePortAvailable0(); 753 }