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