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