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 }