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 /* whether this Socket is a stream (TCP) socket or not (UDP) 78 */ 79 protected boolean stream; 80 81 /** 82 * Load net library into runtime. 83 */ 84 static { 85 java.security.AccessController.doPrivileged( 86 new java.security.PrivilegedAction<>() { 87 public Void run() { 88 System.loadLibrary("net"); 89 return null; 90 } 91 }); 92 } 93 94 private static volatile boolean checkedReusePort; 95 private static volatile boolean isReusePortAvailable; 96 97 /** 98 * Tells whether SO_REUSEPORT is supported. 99 */ 100 static boolean isReusePortAvailable() { 101 if (!checkedReusePort) { 102 isReusePortAvailable = isReusePortAvailable0(); 103 checkedReusePort = true; 104 } 105 return isReusePortAvailable; 106 } 107 108 /** 109 * Returns a set of SocketOptions supported by this impl and by this impl's 110 * socket (Socket or ServerSocket) 111 * 112 * @return a Set of SocketOptions 113 */ 114 @Override 115 protected Set<SocketOption<?>> supportedOptions() { 116 Set<SocketOption<?>> options; 117 if (isReusePortAvailable()) { 118 options = new HashSet<>(); 119 options.addAll(super.supportedOptions()); 120 options.add(StandardSocketOptions.SO_REUSEPORT); 121 options = Collections.unmodifiableSet(options); 122 } else { 123 options = super.supportedOptions(); 124 } 125 return options; 126 } 127 128 /** 129 * Creates a socket with a boolean that specifies whether this 130 * is a stream socket (true) or an unconnected UDP socket (false). 131 */ 132 protected synchronized void create(boolean stream) throws IOException { 133 this.stream = stream; 134 if (!stream) { 135 ResourceManager.beforeUdpCreate(); 136 // only create the fd after we know we will be able to create the socket 137 fd = new FileDescriptor(); 138 try { 139 socketCreate(false); 140 SocketCleanable.register(fd); 141 } catch (IOException ioe) { 142 ResourceManager.afterUdpClose(); 143 fd = null; 144 throw ioe; 145 } 146 } else { 147 fd = new FileDescriptor(); 148 socketCreate(true); 149 SocketCleanable.register(fd); 150 } 151 if (socket != null) 152 socket.setCreated(); 153 if (serverSocket != null) 154 serverSocket.setCreated(); 155 } 156 157 /** 158 * Creates a socket and connects it to the specified port on 159 * the specified host. 160 * @param host the specified host 161 * @param port the specified port 162 */ 163 protected void connect(String host, int port) 164 throws UnknownHostException, IOException 165 { 166 boolean connected = false; 167 try { 168 InetAddress address = InetAddress.getByName(host); 169 this.port = port; 170 this.address = address; 171 172 connectToAddress(address, port, timeout); 173 connected = true; 174 } finally { 175 if (!connected) { 176 try { 177 close(); 178 } catch (IOException ioe) { 179 /* Do nothing. If connect threw an exception then 180 it will be passed up the call stack */ 181 } 182 } 183 } 184 } 185 186 /** 187 * Creates a socket and connects it to the specified address on 188 * the specified port. 189 * @param address the address 190 * @param port the specified port 191 */ 192 protected void connect(InetAddress address, int port) throws IOException { 193 this.port = port; 194 this.address = address; 195 196 try { 197 connectToAddress(address, port, timeout); 198 return; 199 } catch (IOException e) { 200 // everything failed 201 close(); 202 throw e; 203 } 204 } 205 206 /** 207 * Creates a socket and connects it to the specified address on 208 * the specified port. 209 * @param address the address 210 * @param timeout the timeout value in milliseconds, or zero for no timeout. 211 * @throws IOException if connection fails 212 * @throws IllegalArgumentException if address is null or is a 213 * SocketAddress subclass not supported by this socket 214 * @since 1.4 215 */ 216 protected void connect(SocketAddress address, int timeout) 217 throws IOException { 218 boolean connected = false; 219 try { 220 if (address == null || !(address instanceof InetSocketAddress)) 221 throw new IllegalArgumentException("unsupported address type"); 222 InetSocketAddress addr = (InetSocketAddress) address; 223 if (addr.isUnresolved()) 224 throw new UnknownHostException(addr.getHostName()); 225 this.port = addr.getPort(); 226 this.address = addr.getAddress(); 227 228 connectToAddress(this.address, port, timeout); 229 connected = true; 230 } finally { 231 if (!connected) { 232 try { 233 close(); 234 } catch (IOException ioe) { 235 /* Do nothing. If connect threw an exception then 236 it will be passed up the call stack */ 237 } 238 } 239 } 240 } 241 242 private void connectToAddress(InetAddress address, int port, int timeout) throws IOException { 243 if (address.isAnyLocalAddress()) { 244 doConnect(InetAddress.getLocalHost(), port, timeout); 245 } else { 246 doConnect(address, port, timeout); 247 } 248 } 249 250 public void setOption(int opt, Object val) throws SocketException { 251 if (isClosedOrPending()) { 252 throw new SocketException("Socket Closed"); 253 } 254 boolean on = true; 255 switch (opt) { 256 /* check type safety b4 going native. These should never 257 * fail, since only java.Socket* has access to 258 * PlainSocketImpl.setOption(). 259 */ 260 case SO_LINGER: 261 if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean))) 262 throw new SocketException("Bad parameter for option"); 263 if (val instanceof Boolean) { 264 /* true only if disabling - enabling should be Integer */ 265 on = false; 266 } 267 break; 268 case SO_TIMEOUT: 269 if (val == null || (!(val instanceof Integer))) 270 throw new SocketException("Bad parameter for SO_TIMEOUT"); 271 int tmp = ((Integer) val).intValue(); 272 if (tmp < 0) 273 throw new IllegalArgumentException("timeout < 0"); 274 timeout = tmp; 275 break; 276 case IP_TOS: 277 if (val == null || !(val instanceof Integer)) { 278 throw new SocketException("bad argument for IP_TOS"); 279 } 280 trafficClass = ((Integer)val).intValue(); 281 break; 282 case SO_BINDADDR: 283 throw new SocketException("Cannot re-bind socket"); 284 case TCP_NODELAY: 285 if (val == null || !(val instanceof Boolean)) 286 throw new SocketException("bad parameter for TCP_NODELAY"); 287 on = ((Boolean)val).booleanValue(); 288 break; 289 case SO_SNDBUF: 290 case SO_RCVBUF: 291 if (val == null || !(val instanceof Integer) || 292 !(((Integer)val).intValue() > 0)) { 293 throw new SocketException("bad parameter for SO_SNDBUF " + 294 "or SO_RCVBUF"); 295 } 296 break; 297 case SO_KEEPALIVE: 298 if (val == null || !(val instanceof Boolean)) 299 throw new SocketException("bad parameter for SO_KEEPALIVE"); 300 on = ((Boolean)val).booleanValue(); 301 break; 302 case SO_OOBINLINE: 303 if (val == null || !(val instanceof Boolean)) 304 throw new SocketException("bad parameter for SO_OOBINLINE"); 305 on = ((Boolean)val).booleanValue(); 306 break; 307 case SO_REUSEADDR: 308 if (val == null || !(val instanceof Boolean)) 309 throw new SocketException("bad parameter for SO_REUSEADDR"); 310 on = ((Boolean)val).booleanValue(); 311 break; 312 case SO_REUSEPORT: 313 if (val == null || !(val instanceof Boolean)) 314 throw new SocketException("bad parameter for SO_REUSEPORT"); 315 if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) 316 throw new UnsupportedOperationException("unsupported option"); 317 on = ((Boolean)val).booleanValue(); 318 break; 319 default: 320 throw new SocketException("unrecognized TCP option: " + opt); 321 } 322 socketSetOption(opt, on, val); 323 } 324 public Object getOption(int opt) throws SocketException { 325 if (isClosedOrPending()) { 326 throw new SocketException("Socket Closed"); 327 } 328 if (opt == SO_TIMEOUT) { 329 return timeout; 330 } 331 int ret = 0; 332 /* 333 * The native socketGetOption() knows about 3 options. 334 * The 32 bit value it returns will be interpreted according 335 * to what we're asking. A return of -1 means it understands 336 * the option but its turned off. It will raise a SocketException 337 * if "opt" isn't one it understands. 338 */ 339 340 switch (opt) { 341 case TCP_NODELAY: 342 ret = socketGetOption(opt, null); 343 return Boolean.valueOf(ret != -1); 344 case SO_OOBINLINE: 345 ret = socketGetOption(opt, null); 346 return Boolean.valueOf(ret != -1); 347 case SO_LINGER: 348 ret = socketGetOption(opt, null); 349 return (ret == -1) ? Boolean.FALSE: (Object)(ret); 350 case SO_REUSEADDR: 351 ret = socketGetOption(opt, null); 352 return Boolean.valueOf(ret != -1); 353 case SO_BINDADDR: 354 InetAddressContainer in = new InetAddressContainer(); 355 ret = socketGetOption(opt, in); 356 return in.addr; 357 case SO_SNDBUF: 358 case SO_RCVBUF: 359 ret = socketGetOption(opt, null); 360 return ret; 361 case IP_TOS: 362 try { 363 ret = socketGetOption(opt, null); 364 if (ret == -1) { // ipv6 tos 365 return trafficClass; 366 } else { 367 return ret; 368 } 369 } catch (SocketException se) { 370 // TODO - should make better effort to read TOS or TCLASS 371 return trafficClass; // ipv6 tos 372 } 373 case SO_KEEPALIVE: 374 ret = socketGetOption(opt, null); 375 return Boolean.valueOf(ret != -1); 376 case SO_REUSEPORT: 377 if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { 378 throw new UnsupportedOperationException("unsupported option"); 379 } 380 ret = socketGetOption(opt, null); 381 return Boolean.valueOf(ret != -1); 382 // should never get here 383 default: 384 return null; 385 } 386 } 387 388 /** 389 * The workhorse of the connection operation. Tries several times to 390 * establish a connection to the given <host, port>. If unsuccessful, 391 * throws an IOException indicating what went wrong. 392 */ 393 394 synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException { 395 synchronized (fdLock) { 396 if (!closePending && (socket == null || !socket.isBound())) { 397 NetHooks.beforeTcpConnect(fd, address, port); 398 } 399 } 400 try { 401 acquireFD(); 402 try { 403 socketConnect(address, port, timeout); 404 /* socket may have been closed during poll/select */ 405 synchronized (fdLock) { 406 if (closePending) { 407 throw new SocketException ("Socket closed"); 408 } 409 } 410 // If we have a ref. to the Socket, then sets the flags 411 // created, bound & connected to true. 412 // This is normally done in Socket.connect() but some 413 // subclasses of Socket may call impl.connect() directly! 414 if (socket != null) { 415 socket.setBound(); 416 socket.setConnected(); 417 } 418 } finally { 419 releaseFD(); 420 } 421 } catch (IOException e) { 422 close(); 423 throw SocketExceptions.of(e, new InetSocketAddress(address, port)); 424 } 425 } 426 427 /** 428 * Binds the socket to the specified address of the specified local port. 429 * @param address the address 430 * @param lport the port 431 */ 432 protected synchronized void bind(InetAddress address, int lport) 433 throws IOException 434 { 435 synchronized (fdLock) { 436 if (!closePending && (socket == null || !socket.isBound())) { 437 NetHooks.beforeTcpBind(fd, address, lport); 438 } 439 } 440 socketBind(address, lport); 441 if (socket != null) 442 socket.setBound(); 443 if (serverSocket != null) 444 serverSocket.setBound(); 445 } 446 447 /** 448 * Listens, for a specified amount of time, for connections. 449 * @param count the amount of time to listen for connections 450 */ 451 protected synchronized void listen(int count) throws IOException { 452 socketListen(count); 453 } 454 455 /** 456 * Accepts connections. 457 * @param si the socket impl 458 */ 459 protected void accept(SocketImpl si) throws IOException { 460 si.fd = new FileDescriptor(); 461 acquireFD(); 462 try { 463 socketAccept(si); 464 } finally { 465 releaseFD(); 466 } 467 SocketCleanable.register(si.fd); 468 } 469 470 /** 471 * Gets an InputStream for this socket. 472 */ 473 protected synchronized InputStream getInputStream() throws IOException { 474 synchronized (fdLock) { 475 if (isClosedOrPending()) 476 throw new IOException("Socket Closed"); 477 if (shut_rd) 478 throw new IOException("Socket input is shutdown"); 479 if (socketInputStream == null) { 480 PrivilegedExceptionAction<SocketInputStream> pa = () -> new SocketInputStream(this); 481 try { 482 socketInputStream = AccessController.doPrivileged(pa); 483 } catch (PrivilegedActionException e) { 484 throw (IOException) e.getCause(); 485 } 486 } 487 } 488 return socketInputStream; 489 } 490 491 void setInputStream(SocketInputStream in) { 492 socketInputStream = in; 493 } 494 495 /** 496 * Gets an OutputStream for this socket. 497 */ 498 protected synchronized OutputStream getOutputStream() throws IOException { 499 synchronized (fdLock) { 500 if (isClosedOrPending()) 501 throw new IOException("Socket Closed"); 502 if (shut_wr) 503 throw new IOException("Socket output is shutdown"); 504 if (socketOutputStream == null) { 505 PrivilegedExceptionAction<SocketOutputStream> pa = () -> new SocketOutputStream(this); 506 try { 507 socketOutputStream = AccessController.doPrivileged(pa); 508 } catch (PrivilegedActionException e) { 509 throw (IOException) e.getCause(); 510 } 511 } 512 } 513 return socketOutputStream; 514 } 515 516 void setFileDescriptor(FileDescriptor fd) { 517 this.fd = fd; 518 } 519 520 void setAddress(InetAddress address) { 521 this.address = address; 522 } 523 524 void setPort(int port) { 525 this.port = port; 526 } 527 528 void setLocalPort(int localport) { 529 this.localport = localport; 530 } 531 532 /** 533 * Returns the number of bytes that can be read without blocking. 534 */ 535 protected synchronized int available() throws IOException { 536 if (isClosedOrPending()) { 537 throw new IOException("Stream closed."); 538 } 539 540 /* 541 * If connection has been reset or shut down for input, then return 0 542 * to indicate there are no buffered bytes. 543 */ 544 if (isConnectionReset() || shut_rd) { 545 return 0; 546 } 547 548 /* 549 * If no bytes available and we were previously notified 550 * of a connection reset then we move to the reset state. 551 * 552 * If are notified of a connection reset then check 553 * again if there are bytes buffered on the socket. 554 */ 555 int n = 0; 556 try { 557 n = socketAvailable(); 558 } catch (ConnectionResetException exc1) { 559 setConnectionReset(); 560 } 561 return n; 562 } 563 564 /** 565 * Closes the socket. 566 */ 567 protected void close() throws IOException { 568 synchronized(fdLock) { 569 if (fd != null) { 570 if (!stream) { 571 ResourceManager.afterUdpClose(); 572 } 573 if (fdUseCount == 0) { 574 if (closePending) { 575 return; 576 } 577 closePending = true; 578 /* 579 * We close the FileDescriptor in two-steps - first the 580 * "pre-close" which closes the socket but doesn't 581 * release the underlying file descriptor. This operation 582 * may be lengthy due to untransmitted data and a long 583 * linger interval. Once the pre-close is done we do the 584 * actual socket to release the fd. 585 */ 586 try { 587 socketPreClose(); 588 } finally { 589 socketClose(); 590 } 591 fd = null; 592 return; 593 } else { 594 /* 595 * If a thread has acquired the fd and a close 596 * isn't pending then use a deferred close. 597 * Also decrement fdUseCount to signal the last 598 * thread that releases the fd to close it. 599 */ 600 if (!closePending) { 601 closePending = true; 602 fdUseCount--; 603 socketPreClose(); 604 } 605 } 606 } 607 } 608 } 609 610 void reset() { 611 throw new InternalError("should not get here"); 612 } 613 614 /** 615 * Shutdown read-half of the socket connection; 616 */ 617 protected void shutdownInput() throws IOException { 618 if (fd != null) { 619 socketShutdown(SHUT_RD); 620 if (socketInputStream != null) { 621 socketInputStream.setEOF(true); 622 } 623 shut_rd = true; 624 } 625 } 626 627 /** 628 * Shutdown write-half of the socket connection; 629 */ 630 protected void shutdownOutput() throws IOException { 631 if (fd != null) { 632 socketShutdown(SHUT_WR); 633 shut_wr = true; 634 } 635 } 636 637 protected boolean supportsUrgentData () { 638 return true; 639 } 640 641 protected void sendUrgentData (int data) throws IOException { 642 if (fd == null) { 643 throw new IOException("Socket Closed"); 644 } 645 socketSendUrgentData (data); 646 } 647 648 /* 649 * "Acquires" and returns the FileDescriptor for this impl 650 * 651 * A corresponding releaseFD is required to "release" the 652 * FileDescriptor. 653 */ 654 FileDescriptor acquireFD() { 655 synchronized (fdLock) { 656 fdUseCount++; 657 return fd; 658 } 659 } 660 661 /* 662 * "Release" the FileDescriptor for this impl. 663 * 664 * If the use count goes to -1 then the socket is closed. 665 */ 666 void releaseFD() { 667 synchronized (fdLock) { 668 fdUseCount--; 669 if (fdUseCount == -1) { 670 if (fd != null) { 671 try { 672 socketClose(); 673 } catch (IOException e) { 674 } finally { 675 fd = null; 676 } 677 } 678 } 679 } 680 } 681 682 boolean isConnectionReset() { 683 return connectionReset; 684 } 685 686 void setConnectionReset() { 687 connectionReset = true; 688 } 689 690 /* 691 * Return true if already closed or close is pending 692 */ 693 public boolean isClosedOrPending() { 694 /* 695 * Lock on fdLock to ensure that we wait if a 696 * close is in progress. 697 */ 698 synchronized (fdLock) { 699 if (closePending || (fd == null)) { 700 return true; 701 } else { 702 return false; 703 } 704 } 705 } 706 707 /* 708 * Return the current value of SO_TIMEOUT 709 */ 710 public int getTimeout() { 711 return timeout; 712 } 713 714 /* 715 * "Pre-close" a socket by dup'ing the file descriptor - this enables 716 * the socket to be closed without releasing the file descriptor. 717 */ 718 private void socketPreClose() throws IOException { 719 socketClose0(true); 720 } 721 722 /* 723 * Close the socket (and release the file descriptor). 724 */ 725 protected void socketClose() throws IOException { 726 SocketCleanable.unregister(fd); 727 socketClose0(false); 728 } 729 730 abstract void socketCreate(boolean isServer) throws IOException; 731 abstract void socketConnect(InetAddress address, int port, int timeout) 732 throws IOException; 733 abstract void socketBind(InetAddress address, int port) 734 throws IOException; 735 abstract void socketListen(int count) 736 throws IOException; 737 abstract void socketAccept(SocketImpl s) 738 throws IOException; 739 abstract int socketAvailable() 740 throws IOException; 741 abstract void socketClose0(boolean useDeferredClose) 742 throws IOException; 743 abstract void socketShutdown(int howto) 744 throws IOException; 745 abstract void socketSetOption(int cmd, boolean on, Object value) 746 throws SocketException; 747 abstract int socketGetOption(int opt, Object iaContainerObj) throws SocketException; 748 abstract void socketSendUrgentData(int data) 749 throws IOException; 750 751 public static final int SHUT_RD = 0; 752 public static final int SHUT_WR = 1; 753 754 private static native boolean isReusePortAvailable0(); 755 }