1 /*
   2  * Copyright (c) 1995, 2016, 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 /**
  35  * The abstract class {@code SocketImpl} is a common superclass
  36  * of all classes that actually implement sockets. It is used to
  37  * create both client and server sockets.
  38  * <p>
  39  * A "plain" socket implements these methods exactly as
  40  * described, without attempting to go through a firewall or proxy.
  41  *
  42  * @author  unascribed
  43  * @since   1.0
  44  */
  45 public abstract class SocketImpl implements SocketOptions {
  46     /**
  47      * The actual Socket object.
  48      */
  49     Socket socket = null;
  50     ServerSocket serverSocket = null;
  51 
  52     /**
  53      * The file descriptor object for this socket.
  54      */
  55     protected FileDescriptor fd;
  56 
  57     /**
  58      * The IP address of the remote end of this socket.
  59      */
  60     protected InetAddress address;
  61 
  62     /**
  63      * The port number on the remote host to which this socket is connected.
  64      */
  65     protected int port;
  66 
  67     /**
  68      * The local port number to which this socket is connected.
  69      */
  70     protected int localport;
  71 
  72     /**
  73      * Creates either a stream or a datagram socket.
  74      *
  75      * @param      stream   if {@code true}, create a stream socket;
  76      *                      otherwise, create a datagram socket.
  77      * @exception  IOException  if an I/O error occurs while creating the
  78      *               socket.
  79      */
  80     protected abstract void create(boolean stream) throws IOException;
  81 
  82     /**
  83      * Connects this socket to the specified port on the named host.
  84      *
  85      * @param      host   the name of the remote host.
  86      * @param      port   the port number.
  87      * @exception  IOException  if an I/O error occurs when connecting to the
  88      *               remote host.
  89      */
  90     protected abstract void connect(String host, int port) throws IOException;
  91 
  92     /**
  93      * Connects this socket to the specified port number on the specified host.
  94      *
  95      * @param      address   the IP address of the remote host.
  96      * @param      port      the port number.
  97      * @exception  IOException  if an I/O error occurs when attempting a
  98      *               connection.
  99      */
 100     protected abstract void connect(InetAddress address, int port) throws IOException;
 101 
 102     /**
 103      * Connects this socket to the specified port number on the specified host.
 104      * A timeout of zero is interpreted as an infinite timeout. The connection
 105      * will then block until established or an error occurs.
 106      *
 107      * @param      address   the Socket address of the remote host.
 108      * @param     timeout  the timeout value, in milliseconds, or zero for no timeout.
 109      * @exception  IOException  if an I/O error occurs when attempting a
 110      *               connection.
 111      * @since 1.4
 112      */
 113     protected abstract void connect(SocketAddress address, int timeout) throws IOException;
 114 
 115     /**
 116      * Binds this socket to the specified local IP address and port number.
 117      *
 118      * @param      host   an IP address that belongs to a local interface.
 119      * @param      port   the port number.
 120      * @exception  IOException  if an I/O error occurs when binding this socket.
 121      */
 122     protected abstract void bind(InetAddress host, int port) throws IOException;
 123 
 124     /**
 125      * Sets the maximum queue length for incoming connection indications
 126      * (a request to connect) to the {@code count} argument. If a
 127      * connection indication arrives when the queue is full, the
 128      * connection is refused.
 129      *
 130      * @param      backlog   the maximum length of the queue.
 131      * @exception  IOException  if an I/O error occurs when creating the queue.
 132      */
 133     protected abstract void listen(int backlog) throws IOException;
 134 
 135     /**
 136      * Accepts a connection.
 137      *
 138      * @param      s   the accepted connection.
 139      * @exception  IOException  if an I/O error occurs when accepting the
 140      *               connection.
 141      */
 142     protected abstract void accept(SocketImpl s) throws IOException;
 143 
 144     /**
 145      * Returns an input stream for this socket.
 146      *
 147      * @return     a stream for reading from this socket.
 148      * @exception  IOException  if an I/O error occurs when creating the
 149      *               input stream.
 150     */
 151     protected abstract InputStream getInputStream() throws IOException;
 152 
 153     /**
 154      * Returns an output stream for this socket.
 155      *
 156      * @return     an output stream for writing to this socket.
 157      * @exception  IOException  if an I/O error occurs when creating the
 158      *               output stream.
 159      */
 160     protected abstract OutputStream getOutputStream() throws IOException;
 161 
 162     /**
 163      * Returns the number of bytes that can be read from this socket
 164      * without blocking.
 165      *
 166      * @return     the number of bytes that can be read from this socket
 167      *             without blocking.
 168      * @exception  IOException  if an I/O error occurs when determining the
 169      *               number of bytes available.
 170      */
 171     protected abstract int available() throws IOException;
 172 
 173     /**
 174      * Closes this socket.
 175      *
 176      * @exception  IOException  if an I/O error occurs when closing this socket.
 177      */
 178     protected abstract void close() throws IOException;
 179 
 180     /**
 181      * Places the input stream for this socket at "end of stream".
 182      * Any data sent to this socket is acknowledged and then
 183      * silently discarded.
 184      *
 185      * If you read from a socket input stream after invoking this method on the
 186      * socket, the stream's {@code available} method will return 0, and its
 187      * {@code read} methods will return {@code -1} (end of stream).
 188      *
 189      * @exception IOException if an I/O error occurs when shutting down this
 190      * socket.
 191      * @see java.net.Socket#shutdownOutput()
 192      * @see java.net.Socket#close()
 193      * @see java.net.Socket#setSoLinger(boolean, int)
 194      * @since 1.3
 195      */
 196     protected void shutdownInput() throws IOException {
 197       throw new IOException("Method not implemented!");
 198     }
 199 
 200     /**
 201      * Disables the output stream for this socket.
 202      * For a TCP socket, any previously written data will be sent
 203      * followed by TCP's normal connection termination sequence.
 204      *
 205      * If you write to a socket output stream after invoking
 206      * shutdownOutput() on the socket, the stream will throw
 207      * an IOException.
 208      *
 209      * @exception IOException if an I/O error occurs when shutting down this
 210      * socket.
 211      * @see java.net.Socket#shutdownInput()
 212      * @see java.net.Socket#close()
 213      * @see java.net.Socket#setSoLinger(boolean, int)
 214      * @since 1.3
 215      */
 216     protected void shutdownOutput() throws IOException {
 217       throw new IOException("Method not implemented!");
 218     }
 219 
 220     /**
 221      * Returns the value of this socket's {@code fd} field.
 222      *
 223      * @return  the value of this socket's {@code fd} field.
 224      * @see     java.net.SocketImpl#fd
 225      */
 226     protected FileDescriptor getFileDescriptor() {
 227         return fd;
 228     }
 229 
 230     /**
 231      * Sets the value of this socket's {@code fd} field.
 232      *
 233      * @param fd the value of the fd
 234      */
 235     protected void setFileDescriptor(FileDescriptor fd) {
 236         this.fd = fd;
 237     }
 238 
 239     /**
 240      * Returns the value of this socket's {@code address} field.
 241      *
 242      * @return  the value of this socket's {@code address} field.
 243      * @see     java.net.SocketImpl#address
 244      */
 245     protected InetAddress getInetAddress() {
 246         return address;
 247     }
 248 
 249     /**
 250      * Sets the value of this socket's {@code address} field.
 251      *
 252      * @param address the value of the address
 253      */
 254     protected void setAddress(InetAddress address) {
 255         this.address = address;
 256     }
 257 
 258     /**
 259      * Returns the value of this socket's {@code port} field.
 260      *
 261      * @return  the value of this socket's {@code port} field.
 262      * @see     java.net.SocketImpl#port
 263      */
 264     protected int getPort() {
 265         return port;
 266     }
 267 
 268     /**
 269      * Returns whether or not this SocketImpl supports sending
 270      * urgent data. By default, false is returned
 271      * unless the method is overridden in a sub-class
 272      *
 273      * @return  true if urgent data supported
 274      * @see     java.net.SocketImpl#address
 275      * @since 1.4
 276      */
 277     protected boolean supportsUrgentData () {
 278         return false; // must be overridden in sub-class
 279     }
 280 
 281     /**
 282      * Send one byte of urgent data on the socket.
 283      * The byte to be sent is the low eight bits of the parameter
 284      * @param data The byte of data to send
 285      * @exception IOException if there is an error
 286      *  sending the data.
 287      * @since 1.4
 288      */
 289     protected abstract void sendUrgentData (int data) throws IOException;
 290 
 291     /**
 292      * Returns the value of this socket's {@code localport} field.
 293      *
 294      * @return  the value of this socket's {@code localport} field.
 295      * @see     java.net.SocketImpl#localport
 296      */
 297     protected int getLocalPort() {
 298         return localport;
 299     }
 300 
 301     void setSocket(Socket soc) {
 302         this.socket = soc;
 303     }
 304 
 305     Socket getSocket() {
 306         return socket;
 307     }
 308 
 309     void setServerSocket(ServerSocket soc) {
 310         this.serverSocket = soc;
 311     }
 312 
 313     ServerSocket getServerSocket() {
 314         return serverSocket;
 315     }
 316 
 317     /**
 318      * Returns the address and port of this socket as a {@code String}.
 319      *
 320      * @return  a string representation of this socket.
 321      */
 322     public String toString() {
 323         return "Socket[addr=" + getInetAddress() +
 324             ",port=" + getPort() + ",localport=" + getLocalPort()  + "]";
 325     }
 326 
 327     void reset() throws IOException {
 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 &&
 396                 (getSocket() != null)) {
 397             setOption(SocketOptions.SO_KEEPALIVE, value);
 398         } else if (name == StandardSocketOptions.SO_SNDBUF &&
 399                 (getSocket() != null)) {
 400             setOption(SocketOptions.SO_SNDBUF, value);
 401         } else if (name == StandardSocketOptions.SO_RCVBUF) {
 402             setOption(SocketOptions.SO_RCVBUF, value);
 403         } else if (name == StandardSocketOptions.SO_REUSEADDR) {
 404             setOption(SocketOptions.SO_REUSEADDR, value);
 405         } else if (name == StandardSocketOptions.SO_REUSEPORT &&
 406             supportedOptions().contains(name)) {
 407             setOption(SocketOptions.SO_REUSEPORT, value);
 408         } else if (name == StandardSocketOptions.SO_LINGER &&
 409                 (getSocket() != null)) {
 410             setOption(SocketOptions.SO_LINGER, value);
 411         } else if (name == StandardSocketOptions.IP_TOS) {
 412             setOption(SocketOptions.IP_TOS, value);
 413         } else if (name == StandardSocketOptions.TCP_NODELAY &&
 414                 (getSocket() != null)) {
 415             setOption(SocketOptions.TCP_NODELAY, value);
 416         } else {
 417             throw new UnsupportedOperationException("unsupported option");
 418         }
 419     }
 420 
 421     /**
 422      * Called to get a socket option.
 423      *
 424      * @param <T> The type of the socket option value
 425      * @param name The socket option
 426      *
 427      * @return the value of the named option
 428      *
 429      * @throws UnsupportedOperationException if the SocketImpl does not
 430      *         support the option.
 431      *
 432      * @throws IOException if an I/O error occurs, or if the socket is closed.
 433      *
 434      * @since 9
 435      */
 436     @SuppressWarnings("unchecked")
 437     protected <T> T getOption(SocketOption<T> name) throws IOException {
 438         if (name == StandardSocketOptions.SO_KEEPALIVE &&
 439                 (getSocket() != null)) {
 440             return (T)getOption(SocketOptions.SO_KEEPALIVE);
 441         } else if (name == StandardSocketOptions.SO_SNDBUF &&
 442                 (getSocket() != null)) {
 443             return (T)getOption(SocketOptions.SO_SNDBUF);
 444         } else if (name == StandardSocketOptions.SO_RCVBUF) {
 445             return (T)getOption(SocketOptions.SO_RCVBUF);
 446         } else if (name == StandardSocketOptions.SO_REUSEADDR) {
 447             return (T)getOption(SocketOptions.SO_REUSEADDR);
 448         } else if (name == StandardSocketOptions.SO_REUSEPORT &&
 449             supportedOptions().contains(name)) {
 450             return (T)getOption(SocketOptions.SO_REUSEPORT);
 451         } else if (name == StandardSocketOptions.SO_LINGER &&
 452                 (getSocket() != null)) {
 453             return (T)getOption(SocketOptions.SO_LINGER);
 454         } else if (name == StandardSocketOptions.IP_TOS) {
 455             return (T)getOption(SocketOptions.IP_TOS);
 456         } else if (name == StandardSocketOptions.TCP_NODELAY &&
 457                 (getSocket() != null)) {
 458             return (T)getOption(SocketOptions.TCP_NODELAY);
 459         } else {
 460             throw new UnsupportedOperationException("unsupported option");
 461         }
 462     }
 463 
 464     private static final Set<SocketOption<?>> socketOptions;
 465 
 466     private static final Set<SocketOption<?>> serverSocketOptions;
 467 
 468     static {
 469         socketOptions = Set.of(StandardSocketOptions.SO_KEEPALIVE,
 470                                StandardSocketOptions.SO_SNDBUF,
 471                                StandardSocketOptions.SO_RCVBUF,
 472                                StandardSocketOptions.SO_REUSEADDR,
 473                                StandardSocketOptions.SO_LINGER,
 474                                StandardSocketOptions.IP_TOS,
 475                                StandardSocketOptions.TCP_NODELAY);
 476 
 477         serverSocketOptions = Set.of(StandardSocketOptions.SO_RCVBUF,
 478                                      StandardSocketOptions.SO_REUSEADDR,
 479                                      StandardSocketOptions.IP_TOS);
 480     }
 481 
 482     /**
 483      * Returns a set of SocketOptions supported by this impl
 484      * and by this impl's socket (Socket or ServerSocket)
 485      *
 486      * @return a Set of SocketOptions
 487      *
 488      * @since 9
 489      */
 490     protected Set<SocketOption<?>> supportedOptions() {
 491         if (getSocket() != null) {
 492             return socketOptions;
 493         } else {
 494             return serverSocketOptions;
 495         }
 496     }
 497 }