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.IOException;
  29 import java.io.InputStream;
  30 import java.io.OutputStream;
  31 import java.io.FileDescriptor;
  32 import java.util.Set;
  33 
  34 import sun.net.PlatformSocketImpl;
  35 
  36 /**
  37  * The abstract class {@code SocketImpl} is a common superclass
  38  * of all classes that actually implement sockets. It is used to
  39  * create both client and server sockets.
  40  * <p>
  41  * A "plain" socket implements these methods exactly as
  42  * described, without attempting to go through a firewall or proxy.
  43  *
  44  * @author  unascribed
  45  * @since   1.0
  46  */
  47 public abstract class SocketImpl implements SocketOptions {
  48 
  49     /**
  50      * Creates an instance of platform's SocketImpl
  51      */
  52     @SuppressWarnings("unchecked")
  53     static <S extends SocketImpl & PlatformSocketImpl> S createPlatformSocketImpl(boolean server) {
  54         return (S) new PlainSocketImpl(server);
  55     }
  56 
  57     /**
  58      * The file descriptor object for this socket.
  59      */
  60     protected FileDescriptor fd;
  61 
  62     /**
  63      * The IP address of the remote end of this socket.
  64      */
  65     protected InetAddress address;
  66 
  67     /**
  68      * The port number on the remote host to which this socket is connected.
  69      */
  70     protected int port;
  71 
  72     /**
  73      * The local port number to which this socket is connected.
  74      */
  75     protected int localport;
  76 
  77     /**
  78      * Whether this is a server or not.
  79      */
  80     final boolean isServer;
  81 
  82 
  83     SocketImpl(boolean isServer) {
  84         this.isServer = isServer;
  85     }
  86 
  87     /**
  88      * Initialize a new instance of this class
  89      */
  90     public SocketImpl() {
  91         this.isServer = false;
  92     }
  93 
  94     /**
  95      * Creates either a stream or a datagram socket.
  96      *
  97      * @param      stream   if {@code true}, create a stream socket;
  98      *                      otherwise, create a datagram socket.
  99      * @exception  IOException  if an I/O error occurs while creating the
 100      *               socket.
 101      */
 102     protected abstract void create(boolean stream) throws IOException;
 103 
 104     /**
 105      * Connects this socket to the specified port on the named host.
 106      *
 107      * @param      host   the name of the remote host.
 108      * @param      port   the port number.
 109      * @exception  IOException  if an I/O error occurs when connecting to the
 110      *               remote host.
 111      */
 112     protected abstract void connect(String host, int port) throws IOException;
 113 
 114     /**
 115      * Connects this socket to the specified port number on the specified host.
 116      *
 117      * @param      address   the IP address of the remote host.
 118      * @param      port      the port number.
 119      * @exception  IOException  if an I/O error occurs when attempting a
 120      *               connection.
 121      */
 122     protected abstract void connect(InetAddress address, int port) throws IOException;
 123 
 124     /**
 125      * Connects this socket to the specified port number on the specified host.
 126      * A timeout of zero is interpreted as an infinite timeout. The connection
 127      * will then block until established or an error occurs.
 128      *
 129      * @param      address   the Socket address of the remote host.
 130      * @param     timeout  the timeout value, in milliseconds, or zero for no timeout.
 131      * @exception  IOException  if an I/O error occurs when attempting a
 132      *               connection.
 133      * @since 1.4
 134      */
 135     protected abstract void connect(SocketAddress address, int timeout) throws IOException;
 136 
 137     /**
 138      * Binds this socket to the specified local IP address and port number.
 139      *
 140      * @param      host   an IP address that belongs to a local interface.
 141      * @param      port   the port number.
 142      * @exception  IOException  if an I/O error occurs when binding this socket.
 143      */
 144     protected abstract void bind(InetAddress host, int port) throws IOException;
 145 
 146     /**
 147      * Sets the maximum queue length for incoming connection indications
 148      * (a request to connect) to the {@code count} argument. If a
 149      * connection indication arrives when the queue is full, the
 150      * connection is refused.
 151      *
 152      * @param      backlog   the maximum length of the queue.
 153      * @exception  IOException  if an I/O error occurs when creating the queue.
 154      */
 155     protected abstract void listen(int backlog) throws IOException;
 156 
 157     /**
 158      * Accepts a connection.
 159      *
 160      * @param      s   the accepted connection.
 161      * @exception  IOException  if an I/O error occurs when accepting the
 162      *               connection.
 163      */
 164     protected abstract void accept(SocketImpl s) throws IOException;
 165 
 166     /**
 167      * Returns an input stream for this socket.
 168      *
 169      * @return     a stream for reading from this socket.
 170      * @exception  IOException  if an I/O error occurs when creating the
 171      *               input stream.
 172     */
 173     protected abstract InputStream getInputStream() throws IOException;
 174 
 175     /**
 176      * Returns an output stream for this socket.
 177      *
 178      * @return     an output stream for writing to this socket.
 179      * @exception  IOException  if an I/O error occurs when creating the
 180      *               output stream.
 181      */
 182     protected abstract OutputStream getOutputStream() throws IOException;
 183 
 184     /**
 185      * Returns the number of bytes that can be read from this socket
 186      * without blocking.
 187      *
 188      * @return     the number of bytes that can be read from this socket
 189      *             without blocking.
 190      * @exception  IOException  if an I/O error occurs when determining the
 191      *               number of bytes available.
 192      */
 193     protected abstract int available() throws IOException;
 194 
 195     /**
 196      * Closes this socket.
 197      *
 198      * @exception  IOException  if an I/O error occurs when closing this socket.
 199      */
 200     protected abstract void close() throws IOException;
 201 
 202     /**
 203      * Closes this socket, ignoring any IOException that is thrown by close.
 204      */
 205     void closeQuietly() {
 206         try {
 207             close();
 208         } catch (IOException ignore) { }
 209     }
 210 
 211     /**
 212      * Places the input stream for this socket at "end of stream".
 213      * Any data sent to this socket is acknowledged and then
 214      * silently discarded.
 215      *
 216      * If you read from a socket input stream after invoking this method on the
 217      * socket, the stream's {@code available} method will return 0, and its
 218      * {@code read} methods will return {@code -1} (end of stream).
 219      *
 220      * @exception IOException if an I/O error occurs when shutting down this
 221      * socket.
 222      * @see java.net.Socket#shutdownOutput()
 223      * @see java.net.Socket#close()
 224      * @see java.net.Socket#setSoLinger(boolean, int)
 225      * @since 1.3
 226      */
 227     protected void shutdownInput() throws IOException {
 228       throw new IOException("Method not implemented!");
 229     }
 230 
 231     /**
 232      * Disables the output stream for this socket.
 233      * For a TCP socket, any previously written data will be sent
 234      * followed by TCP's normal connection termination sequence.
 235      *
 236      * If you write to a socket output stream after invoking
 237      * shutdownOutput() on the socket, the stream will throw
 238      * an IOException.
 239      *
 240      * @exception IOException if an I/O error occurs when shutting down this
 241      * socket.
 242      * @see java.net.Socket#shutdownInput()
 243      * @see java.net.Socket#close()
 244      * @see java.net.Socket#setSoLinger(boolean, int)
 245      * @since 1.3
 246      */
 247     protected void shutdownOutput() throws IOException {
 248       throw new IOException("Method not implemented!");
 249     }
 250 
 251     /**
 252      * Returns the value of this socket's {@code fd} field.
 253      *
 254      * @return  the value of this socket's {@code fd} field.
 255      * @see     java.net.SocketImpl#fd
 256      */
 257     protected FileDescriptor getFileDescriptor() {
 258         return fd;
 259     }
 260 
 261     /**
 262      * Returns the value of this socket's {@code address} field.
 263      *
 264      * @return  the value of this socket's {@code address} field.
 265      * @see     java.net.SocketImpl#address
 266      */
 267     protected InetAddress getInetAddress() {
 268         return address;
 269     }
 270 
 271     /**
 272      * Returns the value of this socket's {@code port} field.
 273      *
 274      * @return  the value of this socket's {@code port} field.
 275      * @see     java.net.SocketImpl#port
 276      */
 277     protected int getPort() {
 278         return port;
 279     }
 280 
 281     /**
 282      * Returns whether or not this SocketImpl supports sending
 283      * urgent data. By default, false is returned
 284      * unless the method is overridden in a sub-class
 285      *
 286      * @return  true if urgent data supported
 287      * @see     java.net.SocketImpl#address
 288      * @since 1.4
 289      */
 290     protected boolean supportsUrgentData () {
 291         return false; // must be overridden in sub-class
 292     }
 293 
 294     /**
 295      * Send one byte of urgent data on the socket.
 296      * The byte to be sent is the low eight bits of the parameter
 297      * @param data The byte of data to send
 298      * @exception IOException if there is an error
 299      *  sending the data.
 300      * @since 1.4
 301      */
 302     protected abstract void sendUrgentData (int data) throws IOException;
 303 
 304     /**
 305      * Returns the value of this socket's {@code localport} field.
 306      *
 307      * @return  the value of this socket's {@code localport} field.
 308      * @see     java.net.SocketImpl#localport
 309      */
 310     protected int getLocalPort() {
 311         return localport;
 312     }
 313 
 314     /**
 315      * Returns the address and port of this socket as a {@code String}.
 316      *
 317      * @return  a string representation of this socket.
 318      */
 319     public String toString() {
 320         return "Socket[addr=" + getInetAddress() +
 321             ",port=" + getPort() + ",localport=" + getLocalPort()  + "]";
 322     }
 323 
 324     void reset() {
 325         fd = null;
 326         address = null;
 327         port = 0;
 328         localport = 0;
 329     }
 330 
 331     /**
 332      * Sets performance preferences for this socket.
 333      *
 334      * <p> Sockets use the TCP/IP protocol by default.  Some implementations
 335      * may offer alternative protocols which have different performance
 336      * characteristics than TCP/IP.  This method allows the application to
 337      * express its own preferences as to how these tradeoffs should be made
 338      * when the implementation chooses from the available protocols.
 339      *
 340      * <p> Performance preferences are described by three integers
 341      * whose values indicate the relative importance of short connection time,
 342      * low latency, and high bandwidth.  The absolute values of the integers
 343      * are irrelevant; in order to choose a protocol the values are simply
 344      * compared, with larger values indicating stronger preferences. Negative
 345      * values represent a lower priority than positive values. If the
 346      * application prefers short connection time over both low latency and high
 347      * bandwidth, for example, then it could invoke this method with the values
 348      * {@code (1, 0, 0)}.  If the application prefers high bandwidth above low
 349      * latency, and low latency above short connection time, then it could
 350      * invoke this method with the values {@code (0, 1, 2)}.
 351      *
 352      * By default, this method does nothing, unless it is overridden in
 353      * a sub-class.
 354      *
 355      * @param  connectionTime
 356      *         An {@code int} expressing the relative importance of a short
 357      *         connection time
 358      *
 359      * @param  latency
 360      *         An {@code int} expressing the relative importance of low
 361      *         latency
 362      *
 363      * @param  bandwidth
 364      *         An {@code int} expressing the relative importance of high
 365      *         bandwidth
 366      *
 367      * @since 1.5
 368      */
 369     protected void setPerformancePreferences(int connectionTime,
 370                                           int latency,
 371                                           int bandwidth)
 372     {
 373         /* Not implemented yet */
 374     }
 375 
 376     /**
 377      * Called to set a socket option.
 378      *
 379      * @param <T> The type of the socket option value
 380      * @param name The socket option
 381      *
 382      * @param value The value of the socket option. A value of {@code null}
 383      *              may be valid for some options.
 384      *
 385      * @throws UnsupportedOperationException if the SocketImpl does not
 386      *         support the option
 387      *
 388      * @throws IOException if an I/O error occurs, or if the socket is closed.
 389      *
 390      * @since 9
 391      */
 392     protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
 393         if (name == StandardSocketOptions.SO_KEEPALIVE && !isServer) {
 394             setOption(SocketOptions.SO_KEEPALIVE, value);
 395         } else if (name == StandardSocketOptions.SO_SNDBUF && !isServer) {
 396             setOption(SocketOptions.SO_SNDBUF, value);
 397         } else if (name == StandardSocketOptions.SO_RCVBUF) {
 398             setOption(SocketOptions.SO_RCVBUF, value);
 399         } else if (name == StandardSocketOptions.SO_REUSEADDR) {
 400             setOption(SocketOptions.SO_REUSEADDR, value);
 401         } else if (name == StandardSocketOptions.SO_REUSEPORT &&
 402             supportedOptions().contains(name)) {
 403             setOption(SocketOptions.SO_REUSEPORT, value);
 404         } else if (name == StandardSocketOptions.SO_LINGER && !isServer) {
 405             setOption(SocketOptions.SO_LINGER, value);
 406         } else if (name == StandardSocketOptions.IP_TOS) {
 407             setOption(SocketOptions.IP_TOS, value);
 408         } else if (name == StandardSocketOptions.TCP_NODELAY && !isServer) {
 409             setOption(SocketOptions.TCP_NODELAY, value);
 410         } else {
 411             throw new UnsupportedOperationException("unsupported option");
 412         }
 413     }
 414 
 415     /**
 416      * Called to get a socket option.
 417      *
 418      * @param <T> The type of the socket option value
 419      * @param name The socket option
 420      *
 421      * @return the value of the named option
 422      *
 423      * @throws UnsupportedOperationException if the SocketImpl does not
 424      *         support the option.
 425      *
 426      * @throws IOException if an I/O error occurs, or if the socket is closed.
 427      *
 428      * @since 9
 429      */
 430     @SuppressWarnings("unchecked")
 431     protected <T> T getOption(SocketOption<T> name) throws IOException {
 432         if (name == StandardSocketOptions.SO_KEEPALIVE && !isServer) {
 433             return (T)getOption(SocketOptions.SO_KEEPALIVE);
 434         } else if (name == StandardSocketOptions.SO_SNDBUF && !isServer) {
 435             return (T)getOption(SocketOptions.SO_SNDBUF);
 436         } else if (name == StandardSocketOptions.SO_RCVBUF) {
 437             return (T)getOption(SocketOptions.SO_RCVBUF);
 438         } else if (name == StandardSocketOptions.SO_REUSEADDR) {
 439             return (T)getOption(SocketOptions.SO_REUSEADDR);
 440         } else if (name == StandardSocketOptions.SO_REUSEPORT &&
 441             supportedOptions().contains(name)) {
 442             return (T)getOption(SocketOptions.SO_REUSEPORT);
 443         } else if (name == StandardSocketOptions.SO_LINGER && !isServer) {
 444             return (T)getOption(SocketOptions.SO_LINGER);
 445         } else if (name == StandardSocketOptions.IP_TOS) {
 446             return (T)getOption(SocketOptions.IP_TOS);
 447         } else if (name == StandardSocketOptions.TCP_NODELAY && !isServer) {
 448             return (T)getOption(SocketOptions.TCP_NODELAY);
 449         } else {
 450             throw new UnsupportedOperationException("unsupported option");
 451         }
 452     }
 453 
 454     /**
 455      * Attempts to copy socket options from this SocketImpl to a target SocketImpl.
 456      * At this time, only the SO_TIMEOUT make sense to copy.
 457      */
 458     void copyOptionsTo(SocketImpl target) {
 459         try {
 460             Object timeout = getOption(SocketOptions.SO_TIMEOUT);
 461             if (timeout instanceof Integer) {
 462                 target.setOption(SocketOptions.SO_TIMEOUT, timeout);
 463             }
 464         } catch (IOException ignore) { }
 465     }
 466 
 467     private static final Set<SocketOption<?>> socketOptions;
 468 
 469     private static final Set<SocketOption<?>> serverSocketOptions;
 470 
 471     static {
 472         socketOptions = Set.of(StandardSocketOptions.SO_KEEPALIVE,
 473                                StandardSocketOptions.SO_SNDBUF,
 474                                StandardSocketOptions.SO_RCVBUF,
 475                                StandardSocketOptions.SO_REUSEADDR,
 476                                StandardSocketOptions.SO_LINGER,
 477                                StandardSocketOptions.IP_TOS,
 478                                StandardSocketOptions.TCP_NODELAY);
 479 
 480         serverSocketOptions = Set.of(StandardSocketOptions.SO_RCVBUF,
 481                                      StandardSocketOptions.SO_REUSEADDR,
 482                                      StandardSocketOptions.IP_TOS);
 483     }
 484 
 485     /**
 486      * Returns a set of SocketOptions supported by this impl
 487      * and by this impl's socket (Socket or ServerSocket)
 488      *
 489      * @return a Set of SocketOptions
 490      *
 491      * @since 9
 492      */
 493     protected Set<SocketOption<?>> supportedOptions() {
 494         if (!isServer) {
 495             return socketOptions;
 496         } else {
 497             return serverSocketOptions;
 498         }
 499     }
 500 }