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