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 setFileDescriptor(FileDescriptor fd) {
 498         this.fd = fd;
 499     }
 500 
 501     void setAddress(InetAddress address) {
 502         this.address = address;
 503     }
 504 
 505     void setPort(int port) {
 506         this.port = port;
 507     }
 508 
 509     void setLocalPort(int localport) {
 510         this.localport = localport;
 511     }
 512 
 513     /**
 514      * Returns the number of bytes that can be read without blocking.
 515      */
 516     protected synchronized int available() throws IOException {
 517         if (isClosedOrPending()) {
 518             throw new IOException("Stream closed.");
 519         }
 520 
 521         /*
 522          * If connection has been reset or shut down for input, then return 0
 523          * to indicate there are no buffered bytes.
 524          */
 525         if (isConnectionReset() || shut_rd) {
 526             return 0;
 527         }
 528 
 529         /*
 530          * If no bytes available and we were previously notified
 531          * of a connection reset then we move to the reset state.
 532          *
 533          * If are notified of a connection reset then check
 534          * again if there are bytes buffered on the socket.
 535          */
 536         int n = 0;
 537         try {
 538             n = socketAvailable();
 539         } catch (ConnectionResetException exc1) {
 540             setConnectionReset();
 541         }
 542         return n;
 543     }
 544 
 545     /**
 546      * Closes the socket.
 547      */
 548     protected void close() throws IOException {
 549         synchronized(fdLock) {
 550             if (fd != null) {
 551                 if (!stream) {
 552                     ResourceManager.afterUdpClose();
 553                 }
 554                 if (fdUseCount == 0) {
 555                     if (closePending) {
 556                         return;
 557                     }
 558                     closePending = true;
 559                     /*
 560                      * We close the FileDescriptor in two-steps - first the
 561                      * "pre-close" which closes the socket but doesn't
 562                      * release the underlying file descriptor. This operation
 563                      * may be lengthy due to untransmitted data and a long
 564                      * linger interval. Once the pre-close is done we do the
 565                      * actual socket to release the fd.
 566                      */
 567                     try {
 568                         socketPreClose();
 569                     } finally {
 570                         socketClose();
 571                     }
 572                     fd = null;
 573                     return;
 574                 } else {
 575                     /*
 576                      * If a thread has acquired the fd and a close
 577                      * isn't pending then use a deferred close.
 578                      * Also decrement fdUseCount to signal the last
 579                      * thread that releases the fd to close it.
 580                      */
 581                     if (!closePending) {
 582                         closePending = true;
 583                         fdUseCount--;
 584                         socketPreClose();
 585                     }
 586                 }
 587             }
 588         }
 589     }
 590 
 591     void reset() throws IOException {
 592         if (fd != null) {
 593             socketClose();
 594         }
 595         fd = null;
 596         super.reset();
 597     }
 598 
 599 
 600     /**
 601      * Shutdown read-half of the socket connection;
 602      */
 603     protected void shutdownInput() throws IOException {
 604       if (fd != null) {
 605           socketShutdown(SHUT_RD);
 606           if (socketInputStream != null) {
 607               socketInputStream.setEOF(true);
 608           }
 609           shut_rd = true;
 610       }
 611     }
 612 
 613     /**
 614      * Shutdown write-half of the socket connection;
 615      */
 616     protected void shutdownOutput() throws IOException {
 617       if (fd != null) {
 618           socketShutdown(SHUT_WR);
 619           shut_wr = true;
 620       }
 621     }
 622 
 623     protected boolean supportsUrgentData () {
 624         return true;
 625     }
 626 
 627     protected void sendUrgentData (int data) throws IOException {
 628         if (fd == null) {
 629             throw new IOException("Socket Closed");
 630         }
 631         socketSendUrgentData (data);
 632     }
 633 
 634     /*
 635      * "Acquires" and returns the FileDescriptor for this impl
 636      *
 637      * A corresponding releaseFD is required to "release" the
 638      * FileDescriptor.
 639      */
 640     FileDescriptor acquireFD() {
 641         synchronized (fdLock) {
 642             fdUseCount++;
 643             return fd;
 644         }
 645     }
 646 
 647     /*
 648      * "Release" the FileDescriptor for this impl.
 649      *
 650      * If the use count goes to -1 then the socket is closed.
 651      */
 652     void releaseFD() {
 653         synchronized (fdLock) {
 654             fdUseCount--;
 655             if (fdUseCount == -1) {
 656                 if (fd != null) {
 657                     try {
 658                         socketClose();
 659                     } catch (IOException e) {
 660                     } finally {
 661                         fd = null;
 662                     }
 663                 }
 664             }
 665         }
 666     }
 667 
 668     boolean isConnectionReset() {
 669         return connectionReset;
 670     }
 671 
 672     void setConnectionReset() {
 673         connectionReset = true;
 674     }
 675 
 676     /*
 677      * Return true if already closed or close is pending
 678      */
 679     public boolean isClosedOrPending() {
 680         /*
 681          * Lock on fdLock to ensure that we wait if a
 682          * close is in progress.
 683          */
 684         synchronized (fdLock) {
 685             if (closePending || (fd == null)) {
 686                 return true;
 687             } else {
 688                 return false;
 689             }
 690         }
 691     }
 692 
 693     /*
 694      * Return the current value of SO_TIMEOUT
 695      */
 696     public int getTimeout() {
 697         return timeout;
 698     }
 699 
 700     /*
 701      * "Pre-close" a socket by dup'ing the file descriptor - this enables
 702      * the socket to be closed without releasing the file descriptor.
 703      */
 704     private void socketPreClose() throws IOException {
 705         socketClose0(true);
 706     }
 707 
 708     /*
 709      * Close the socket (and release the file descriptor).
 710      */
 711     protected void socketClose() throws IOException {
 712         SocketCleanable.unregister(fd);
 713         socketClose0(false);
 714     }
 715 
 716     abstract void socketCreate(boolean isServer) throws IOException;
 717     abstract void socketConnect(InetAddress address, int port, int timeout)
 718         throws IOException;
 719     abstract void socketBind(InetAddress address, int port)
 720         throws IOException;
 721     abstract void socketListen(int count)
 722         throws IOException;
 723     abstract void socketAccept(SocketImpl s)
 724         throws IOException;
 725     abstract int socketAvailable()
 726         throws IOException;
 727     abstract void socketClose0(boolean useDeferredClose)
 728         throws IOException;
 729     abstract void socketShutdown(int howto)
 730         throws IOException;
 731     abstract void socketSetOption(int cmd, boolean on, Object value)
 732         throws SocketException;
 733     abstract int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
 734     abstract void socketSendUrgentData(int data)
 735         throws IOException;
 736 
 737     public static final int SHUT_RD = 0;
 738     public static final int SHUT_WR = 1;
 739 
 740     private static native boolean isReusePortAvailable0();
 741 }