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.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; 66 67 /* number of threads using the FileDescriptor */ 68 protected int fdUseCount = 0; 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 } 141 } else { 142 fd = new FileDescriptor(); 143 socketCreate(true); 144 SocketCleanable.register(fd); 145 } 146 } 147 148 /** 149 * Creates a socket and connects it to the specified port on 150 * the specified host. 151 * @param host the specified host 152 * @param port the specified port 153 */ 154 protected void connect(String host, int port) 155 throws UnknownHostException, IOException 156 { 157 boolean connected = false; 158 try { 159 InetAddress address = InetAddress.getByName(host); 160 this.port = port; 161 this.address = address; 162 163 connectToAddress(address, port, timeout); 164 connected = true; 165 } finally { 166 if (!connected) { 167 try { 168 close(); 169 } catch (IOException ioe) { 170 /* Do nothing. If connect threw an exception then 171 it will be passed up the call stack */ 172 } 173 } 174 isConnected = connected; 175 } 176 } 177 178 /** 179 * Creates a socket and connects it to the specified address on 180 * the specified port. 181 * @param address the address 182 * @param port the specified port 183 */ 184 protected void connect(InetAddress address, int port) throws IOException { 185 this.port = port; 186 this.address = address; 187 188 try { 189 connectToAddress(address, port, timeout); 190 isConnected = true; 191 return; 192 } catch (IOException e) { 193 // everything failed 194 close(); 195 throw e; 196 } 197 } 198 199 /** 200 * Creates a socket and connects it to the specified address on 201 * the specified port. 202 * @param address the address 203 * @param timeout the timeout value in milliseconds, or zero for no timeout. 204 * @throws IOException if connection fails 205 * @throws IllegalArgumentException if address is null or is a 206 * SocketAddress subclass not supported by this socket 207 * @since 1.4 208 */ 209 protected void connect(SocketAddress address, int timeout) 210 throws IOException { 211 boolean connected = false; 212 try { 213 if (address == null || !(address instanceof InetSocketAddress)) 214 throw new IllegalArgumentException("unsupported address type"); 215 InetSocketAddress addr = (InetSocketAddress) address; 216 if (addr.isUnresolved()) 217 throw new UnknownHostException(addr.getHostName()); 218 this.port = addr.getPort(); 219 this.address = addr.getAddress(); 220 221 connectToAddress(this.address, port, timeout); 222 connected = true; 223 } finally { 224 if (!connected) { 225 try { 226 close(); 227 } catch (IOException ioe) { 228 /* Do nothing. If connect threw an exception then 229 it will be passed up the call stack */ 230 } 231 } 232 isConnected = connected; 233 } 234 } 235 236 private void connectToAddress(InetAddress address, int port, int timeout) throws IOException { 237 if (address.isAnyLocalAddress()) { 238 doConnect(InetAddress.getLocalHost(), port, timeout); 239 } else { 240 doConnect(address, port, timeout); 241 } 242 } 243 244 public void setOption(int opt, Object val) throws SocketException { 245 if (isClosedOrPending()) { 246 throw new SocketException("Socket Closed"); 247 } 248 boolean on = true; 249 switch (opt) { 250 /* check type safety b4 going native. These should never 251 * fail, since only java.Socket* has access to 252 * PlainSocketImpl.setOption(). 253 */ 254 case SO_LINGER: 255 if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean))) 256 throw new SocketException("Bad parameter for option"); 257 if (val instanceof Boolean) { 258 /* true only if disabling - enabling should be Integer */ 259 on = false; 260 } 261 break; 262 case SO_TIMEOUT: 263 if (val == null || (!(val instanceof Integer))) 264 throw new SocketException("Bad parameter for SO_TIMEOUT"); 265 int tmp = ((Integer) val).intValue(); 266 if (tmp < 0) 267 throw new IllegalArgumentException("timeout < 0"); 268 timeout = tmp; 269 break; 270 case IP_TOS: 271 if (val == null || !(val instanceof Integer)) { 272 throw new SocketException("bad argument for IP_TOS"); 273 } 274 trafficClass = ((Integer)val).intValue(); 275 break; 276 case SO_BINDADDR: 277 throw new SocketException("Cannot re-bind socket"); 278 case TCP_NODELAY: 279 if (val == null || !(val instanceof Boolean)) 280 throw new SocketException("bad parameter for TCP_NODELAY"); 281 on = ((Boolean)val).booleanValue(); 282 break; 283 case SO_SNDBUF: 284 case SO_RCVBUF: 285 if (val == null || !(val instanceof Integer) || 286 !(((Integer)val).intValue() > 0)) { 287 throw new SocketException("bad parameter for SO_SNDBUF " + 288 "or SO_RCVBUF"); 289 } 290 break; 291 case SO_KEEPALIVE: 292 if (val == null || !(val instanceof Boolean)) 293 throw new SocketException("bad parameter for SO_KEEPALIVE"); 294 on = ((Boolean)val).booleanValue(); 295 break; 296 case SO_OOBINLINE: 297 if (val == null || !(val instanceof Boolean)) 298 throw new SocketException("bad parameter for SO_OOBINLINE"); 299 on = ((Boolean)val).booleanValue(); 300 break; 301 case SO_REUSEADDR: 302 if (val == null || !(val instanceof Boolean)) 303 throw new SocketException("bad parameter for SO_REUSEADDR"); 304 on = ((Boolean)val).booleanValue(); 305 break; 306 case SO_REUSEPORT: 307 if (val == null || !(val instanceof Boolean)) 308 throw new SocketException("bad parameter for SO_REUSEPORT"); 309 if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) 310 throw new UnsupportedOperationException("unsupported option"); 311 on = ((Boolean)val).booleanValue(); 312 break; 313 default: 314 throw new SocketException("unrecognized TCP option: " + opt); 315 } 316 socketSetOption(opt, on, val); 317 } 318 public Object getOption(int opt) throws SocketException { 319 if (isClosedOrPending()) { 320 throw new SocketException("Socket Closed"); 321 } 322 if (opt == SO_TIMEOUT) { 323 return timeout; 324 } 325 int ret = 0; 326 /* 327 * The native socketGetOption() knows about 3 options. 328 * The 32 bit value it returns will be interpreted according 329 * to what we're asking. A return of -1 means it understands 330 * the option but its turned off. It will raise a SocketException 331 * if "opt" isn't one it understands. 332 */ 333 334 switch (opt) { 335 case TCP_NODELAY: 336 ret = socketGetOption(opt, null); 337 return Boolean.valueOf(ret != -1); 338 case SO_OOBINLINE: 339 ret = socketGetOption(opt, null); 340 return Boolean.valueOf(ret != -1); 341 case SO_LINGER: 342 ret = socketGetOption(opt, null); 343 return (ret == -1) ? Boolean.FALSE: (Object)(ret); 344 case SO_REUSEADDR: 345 ret = socketGetOption(opt, null); 346 return Boolean.valueOf(ret != -1); 347 case SO_BINDADDR: 348 InetAddressContainer in = new InetAddressContainer(); 349 ret = socketGetOption(opt, in); 350 return in.addr; 351 case SO_SNDBUF: 352 case SO_RCVBUF: 353 ret = socketGetOption(opt, null); 354 return ret; 355 case IP_TOS: 356 try { 357 ret = socketGetOption(opt, null); 358 if (ret == -1) { // ipv6 tos 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 if (((Integer)value).intValue() < 0) 450 setOption(SocketOptions.SO_LINGER, false); 451 else 452 setOption(SocketOptions.SO_LINGER, value); 453 } else if (name == StandardSocketOptions.IP_TOS) { 454 int i = ((Integer)value).intValue(); 455 if (i < 0 || i > 255) 456 throw new IllegalArgumentException("Invalid IP_TOS value: " + value); 457 setOption(SocketOptions.IP_TOS, value); 458 } else if (name == StandardSocketOptions.TCP_NODELAY) { 459 setOption(SocketOptions.TCP_NODELAY, value); 460 } else if (extendedOptions.isOptionSupported(name)) { 461 extendedOptions.setOption(fd, name, value); 462 } else { 463 throw new AssertionError("unknown option: " + name); 464 } 465 } 466 467 @Override 468 @SuppressWarnings("unchecked") 469 protected <T> T getOption(SocketOption<T> name) throws IOException { 470 Objects.requireNonNull(name); 471 if (!supportedOptions().contains(name)) 472 throw new UnsupportedOperationException("'" + name + "' not supported"); 473 474 if (isClosedOrPending()) 475 throw new SocketException("Socket closed"); 476 477 if (name == StandardSocketOptions.SO_KEEPALIVE) { 478 return (T)getOption(SocketOptions.SO_KEEPALIVE); 479 } else if (name == StandardSocketOptions.SO_SNDBUF) { 480 return (T)getOption(SocketOptions.SO_SNDBUF); 481 } else if (name == StandardSocketOptions.SO_RCVBUF) { 482 return (T)getOption(SocketOptions.SO_RCVBUF); 483 } else if (name == StandardSocketOptions.SO_REUSEADDR) { 484 return (T)getOption(SocketOptions.SO_REUSEADDR); 485 } else if (name == StandardSocketOptions.SO_REUSEPORT) { 486 return (T)getOption(SocketOptions.SO_REUSEPORT); 487 } else if (name == StandardSocketOptions.SO_LINGER) { 488 Object value = getOption(SocketOptions.SO_LINGER); 489 if (value instanceof Boolean) { 490 assert ((Boolean)value).booleanValue() == false; 491 value = -1; 492 } 493 return (T)value; 494 } else if (name == StandardSocketOptions.IP_TOS) { 495 return (T)getOption(SocketOptions.IP_TOS); 496 } else if (name == StandardSocketOptions.TCP_NODELAY) { 497 return (T)getOption(SocketOptions.TCP_NODELAY); 498 } else if (extendedOptions.isOptionSupported(name)) { 499 return (T) extendedOptions.getOption(fd, name); 500 } else { 501 throw new AssertionError("unknown option: " + name); 502 } 503 } 504 505 /** 506 * The workhorse of the connection operation. Tries several times to 507 * establish a connection to the given <host, port>. If unsuccessful, 508 * throws an IOException indicating what went wrong. 509 */ 510 511 synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException { 512 synchronized (fdLock) { 513 if (!closePending && !isBound) { 514 NetHooks.beforeTcpConnect(fd, address, port); 515 } 516 } 517 try { 518 acquireFD(); 519 try { 520 socketConnect(address, port, timeout); 521 /* socket may have been closed during poll/select */ 522 synchronized (fdLock) { 523 if (closePending) { 524 throw new SocketException ("Socket closed"); 525 } 526 } 527 } finally { 528 releaseFD(); 529 } 530 } catch (IOException e) { 531 close(); 532 throw SocketExceptions.of(e, new InetSocketAddress(address, port)); 533 } 534 } 535 536 /** 537 * Binds the socket to the specified address of the specified local port. 538 * @param address the address 539 * @param lport the port 540 */ 541 protected synchronized void bind(InetAddress address, int lport) 542 throws IOException 543 { 544 synchronized (fdLock) { 545 if (!closePending && !isBound) { 546 NetHooks.beforeTcpBind(fd, address, lport); 547 } 548 } 549 socketBind(address, lport); 550 isBound = true; 551 } 552 553 /** 554 * Listens, for a specified amount of time, for connections. 555 * @param count the amount of time to listen for connections 556 */ 557 protected synchronized void listen(int count) throws IOException { 558 socketListen(count); 559 } 560 561 /** 562 * Accepts connections. 563 * @param si the socket impl 564 */ 565 protected void accept(SocketImpl si) throws IOException { 566 si.fd = new FileDescriptor(); 567 acquireFD(); 568 try { 569 socketAccept(si); 570 } finally { 571 releaseFD(); 572 } 573 SocketCleanable.register(si.fd); 574 } 575 576 /** 577 * Gets an InputStream for this socket. 578 */ 579 protected synchronized InputStream getInputStream() throws IOException { 580 synchronized (fdLock) { 581 if (isClosedOrPending()) 582 throw new IOException("Socket Closed"); 583 if (shut_rd) 584 throw new IOException("Socket input is shutdown"); 585 if (socketInputStream == null) { 586 PrivilegedExceptionAction<SocketInputStream> pa = () -> new SocketInputStream(this); 587 try { 588 socketInputStream = AccessController.doPrivileged(pa); 589 } catch (PrivilegedActionException e) { 590 throw (IOException) e.getCause(); 591 } 592 } 593 } 594 return socketInputStream; 595 } 596 597 void setInputStream(SocketInputStream in) { 598 socketInputStream = in; 599 } 600 601 /** 602 * Gets an OutputStream for this socket. 603 */ 604 protected synchronized OutputStream getOutputStream() throws IOException { 605 synchronized (fdLock) { 606 if (isClosedOrPending()) 607 throw new IOException("Socket Closed"); 608 if (shut_wr) 609 throw new IOException("Socket output is shutdown"); 610 if (socketOutputStream == null) { 611 PrivilegedExceptionAction<SocketOutputStream> pa = () -> new SocketOutputStream(this); 612 try { 613 socketOutputStream = AccessController.doPrivileged(pa); 614 } catch (PrivilegedActionException e) { 615 throw (IOException) e.getCause(); 616 } 617 } 618 } 619 return socketOutputStream; 620 } 621 622 void setFileDescriptor(FileDescriptor fd) { 623 this.fd = fd; 624 } 625 626 void setAddress(InetAddress address) { 627 this.address = address; 628 } 629 630 void setPort(int port) { 631 this.port = port; 632 } 633 634 void setLocalPort(int localport) { 635 this.localport = localport; 636 } 637 638 /** 639 * Returns the number of bytes that can be read without blocking. 640 */ 641 protected synchronized int available() throws IOException { 642 if (isClosedOrPending()) { 643 throw new IOException("Stream closed."); 644 } 645 646 /* 647 * If connection has been reset or shut down for input, then return 0 648 * to indicate there are no buffered bytes. 649 */ 650 if (isConnectionReset() || shut_rd) { 651 return 0; 652 } 653 654 /* 655 * If no bytes available and we were previously notified 656 * of a connection reset then we move to the reset state. 657 * 658 * If are notified of a connection reset then check 659 * again if there are bytes buffered on the socket. 660 */ 661 int n = 0; 662 try { 663 n = socketAvailable(); 664 } catch (ConnectionResetException exc1) { 665 setConnectionReset(); 666 } 667 return n; 668 } 669 670 /** 671 * Closes the socket. 672 */ 673 protected void close() throws IOException { 674 synchronized(fdLock) { 675 if (fd != null) { 676 if (!stream) { 677 ResourceManager.afterUdpClose(); 678 } 679 if (fdUseCount == 0) { 680 if (closePending) { 681 return; 682 } 683 closePending = true; 684 /* 685 * We close the FileDescriptor in two-steps - first the 686 * "pre-close" which closes the socket but doesn't 687 * release the underlying file descriptor. This operation 688 * may be lengthy due to untransmitted data and a long 689 * linger interval. Once the pre-close is done we do the 690 * actual socket to release the fd. 691 */ 692 try { 693 socketPreClose(); 694 } finally { 695 socketClose(); 696 } 697 fd = null; 698 return; 699 } else { 700 /* 701 * If a thread has acquired the fd and a close 702 * isn't pending then use a deferred close. 703 * Also decrement fdUseCount to signal the last 704 * thread that releases the fd to close it. 705 */ 706 if (!closePending) { 707 closePending = true; 708 fdUseCount--; 709 socketPreClose(); 710 } 711 } 712 } 713 } 714 } 715 716 void reset() { 717 throw new InternalError("should not get here"); 718 } 719 720 /** 721 * Shutdown read-half of the socket connection; 722 */ 723 protected void shutdownInput() throws IOException { 724 if (fd != null) { 725 socketShutdown(SHUT_RD); 726 if (socketInputStream != null) { 727 socketInputStream.setEOF(true); 728 } 729 shut_rd = true; 730 } 731 } 732 733 /** 734 * Shutdown write-half of the socket connection; 735 */ 736 protected void shutdownOutput() throws IOException { 737 if (fd != null) { 738 socketShutdown(SHUT_WR); 739 shut_wr = true; 740 } 741 } 742 743 protected boolean supportsUrgentData () { 744 return true; 745 } 746 747 protected void sendUrgentData (int data) throws IOException { 748 if (fd == null) { 749 throw new IOException("Socket Closed"); 750 } 751 socketSendUrgentData (data); 752 } 753 754 /* 755 * "Acquires" and returns the FileDescriptor for this impl 756 * 757 * A corresponding releaseFD is required to "release" the 758 * FileDescriptor. 759 */ 760 FileDescriptor acquireFD() { 761 synchronized (fdLock) { 762 fdUseCount++; 763 return fd; 764 } 765 } 766 767 /* 768 * "Release" the FileDescriptor for this impl. 769 * 770 * If the use count goes to -1 then the socket is closed. 771 */ 772 void releaseFD() { 773 synchronized (fdLock) { 774 fdUseCount--; 775 if (fdUseCount == -1) { 776 if (fd != null) { 777 try { 778 socketClose(); 779 } catch (IOException e) { 780 } finally { 781 fd = null; 782 } 783 } 784 } 785 } 786 } 787 788 boolean isConnectionReset() { 789 return connectionReset; 790 } 791 792 void setConnectionReset() { 793 connectionReset = true; 794 } 795 796 /* 797 * Return true if already closed or close is pending 798 */ 799 public boolean isClosedOrPending() { 800 /* 801 * Lock on fdLock to ensure that we wait if a 802 * close is in progress. 803 */ 804 synchronized (fdLock) { 805 if (closePending || (fd == null)) { 806 return true; 807 } else { 808 return false; 809 } 810 } 811 } 812 813 /* 814 * Return the current value of SO_TIMEOUT 815 */ 816 public int getTimeout() { 817 return timeout; 818 } 819 820 /* 821 * "Pre-close" a socket by dup'ing the file descriptor - this enables 822 * the socket to be closed without releasing the file descriptor. 823 */ 824 private void socketPreClose() throws IOException { 825 socketClose0(true); 826 } 827 828 /* 829 * Close the socket (and release the file descriptor). 830 */ 831 protected void socketClose() throws IOException { 832 SocketCleanable.unregister(fd); 833 socketClose0(false); 834 } 835 836 abstract void socketCreate(boolean stream) throws IOException; 837 abstract void socketConnect(InetAddress address, int port, int timeout) 838 throws IOException; 839 abstract void socketBind(InetAddress address, int port) 840 throws IOException; 841 abstract void socketListen(int count) 842 throws IOException; 843 abstract void socketAccept(SocketImpl s) 844 throws IOException; 845 abstract int socketAvailable() 846 throws IOException; 847 abstract void socketClose0(boolean useDeferredClose) 848 throws IOException; 849 abstract void socketShutdown(int howto) 850 throws IOException; 851 abstract void socketSetOption(int cmd, boolean on, Object value) 852 throws SocketException; 853 abstract int socketGetOption(int opt, Object iaContainerObj) throws SocketException; 854 abstract void socketSendUrgentData(int data) 855 throws IOException; 856 857 public static final int SHUT_RD = 0; 858 public static final int SHUT_WR = 1; 859 860 private static native boolean isReusePortAvailable0(); 861 }