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