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
26package java.net;
27
28import java.io.IOException;
29import java.io.InputStream;
30import java.io.OutputStream;
31import java.io.FileDescriptor;
32import 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 */
45public 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     * Returns the value of this socket's {@code address} field.
232     *
233     * @return  the value of this socket's {@code address} field.
234     * @see     java.net.SocketImpl#address
235     */
236    protected InetAddress getInetAddress() {
237        return address;
238    }
239
240    /**
241     * Returns the value of this socket's {@code port} field.
242     *
243     * @return  the value of this socket's {@code port} field.
244     * @see     java.net.SocketImpl#port
245     */
246    protected int getPort() {
247        return port;
248    }
249
250    /**
251     * Returns whether or not this SocketImpl supports sending
252     * urgent data. By default, false is returned
253     * unless the method is overridden in a sub-class
254     *
255     * @return  true if urgent data supported
256     * @see     java.net.SocketImpl#address
257     * @since 1.4
258     */
259    protected boolean supportsUrgentData () {
260        return false; // must be overridden in sub-class
261    }
262
263    /**
264     * Send one byte of urgent data on the socket.
265     * The byte to be sent is the low eight bits of the parameter
266     * @param data The byte of data to send
267     * @exception IOException if there is an error
268     *  sending the data.
269     * @since 1.4
270     */
271    protected abstract void sendUrgentData (int data) throws IOException;
272
273    /**
274     * Returns the value of this socket's {@code localport} field.
275     *
276     * @return  the value of this socket's {@code localport} field.
277     * @see     java.net.SocketImpl#localport
278     */
279    protected int getLocalPort() {
280        return localport;
281    }
282
283    void setSocket(Socket soc) {
284        this.socket = soc;
285    }
286
287    Socket getSocket() {
288        return socket;
289    }
290
291    void setServerSocket(ServerSocket soc) {
292        this.serverSocket = soc;
293    }
294
295    ServerSocket getServerSocket() {
296        return serverSocket;
297    }
298
299    /**
300     * Returns the address and port of this socket as a {@code String}.
301     *
302     * @return  a string representation of this socket.
303     */
304    public String toString() {
305        return "Socket[addr=" + getInetAddress() +
306            ",port=" + getPort() + ",localport=" + getLocalPort()  + "]";
307    }
308
309    void reset() throws IOException {
310        address = null;
311        port = 0;
312        localport = 0;
313    }
314
315    /**
316     * Sets performance preferences for this socket.
317     *
318     * <p> Sockets use the TCP/IP protocol by default.  Some implementations
319     * may offer alternative protocols which have different performance
320     * characteristics than TCP/IP.  This method allows the application to
321     * express its own preferences as to how these tradeoffs should be made
322     * when the implementation chooses from the available protocols.
323     *
324     * <p> Performance preferences are described by three integers
325     * whose values indicate the relative importance of short connection time,
326     * low latency, and high bandwidth.  The absolute values of the integers
327     * are irrelevant; in order to choose a protocol the values are simply
328     * compared, with larger values indicating stronger preferences. Negative
329     * values represent a lower priority than positive values. If the
330     * application prefers short connection time over both low latency and high
331     * bandwidth, for example, then it could invoke this method with the values
332     * {@code (1, 0, 0)}.  If the application prefers high bandwidth above low
333     * latency, and low latency above short connection time, then it could
334     * invoke this method with the values {@code (0, 1, 2)}.
335     *
336     * By default, this method does nothing, unless it is overridden in a
337     * a sub-class.
338     *
339     * @param  connectionTime
340     *         An {@code int} expressing the relative importance of a short
341     *         connection time
342     *
343     * @param  latency
344     *         An {@code int} expressing the relative importance of low
345     *         latency
346     *
347     * @param  bandwidth
348     *         An {@code int} expressing the relative importance of high
349     *         bandwidth
350     *
351     * @since 1.5
352     */
353    protected void setPerformancePreferences(int connectionTime,
354                                          int latency,
355                                          int bandwidth)
356    {
357        /* Not implemented yet */
358    }
359
360    /**
361     * Called to set a socket option.
362     *
363     * @param <T> The type of the socket option value
364     * @param name The socket option
365     *
366     * @param value The value of the socket option. A value of {@code null}
367     *              may be valid for some options.
368     *
369     * @throws UnsupportedOperationException if the SocketImpl does not
370     *         support the option
371     *
372     * @throws IOException if an I/O error occurs, or if the socket is closed.
373     *
374     * @since 9
375     */
376    protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
377        if (name == StandardSocketOptions.SO_KEEPALIVE &&
378                (getSocket() != null)) {
379            setOption(SocketOptions.SO_KEEPALIVE, value);
380        } else if (name == StandardSocketOptions.SO_SNDBUF &&
381                (getSocket() != null)) {
382            setOption(SocketOptions.SO_SNDBUF, value);
383        } else if (name == StandardSocketOptions.SO_RCVBUF) {
384            setOption(SocketOptions.SO_RCVBUF, value);
385        } else if (name == StandardSocketOptions.SO_REUSEADDR) {
386            setOption(SocketOptions.SO_REUSEADDR, value);
387        } else if (name == StandardSocketOptions.SO_REUSEPORT &&
388            supportedOptions().contains(name)) {
389            setOption(SocketOptions.SO_REUSEPORT, value);
390        } else if (name == StandardSocketOptions.SO_LINGER &&
391                (getSocket() != null)) {
392            setOption(SocketOptions.SO_LINGER, value);
393        } else if (name == StandardSocketOptions.IP_TOS) {
394            setOption(SocketOptions.IP_TOS, value);
395        } else if (name == StandardSocketOptions.TCP_NODELAY &&
396                (getSocket() != null)) {
397            setOption(SocketOptions.TCP_NODELAY, value);
398        } else {
399            throw new UnsupportedOperationException("unsupported option");
400        }
401    }
402
403    /**
404     * Called to get a socket option.
405     *
406     * @param <T> The type of the socket option value
407     * @param name The socket option
408     *
409     * @return the value of the named option
410     *
411     * @throws UnsupportedOperationException if the SocketImpl does not
412     *         support the option.
413     *
414     * @throws IOException if an I/O error occurs, or if the socket is closed.
415     *
416     * @since 9
417     */
418    @SuppressWarnings("unchecked")
419    protected <T> T getOption(SocketOption<T> name) throws IOException {
420        if (name == StandardSocketOptions.SO_KEEPALIVE &&
421                (getSocket() != null)) {
422            return (T)getOption(SocketOptions.SO_KEEPALIVE);
423        } else if (name == StandardSocketOptions.SO_SNDBUF &&
424                (getSocket() != null)) {
425            return (T)getOption(SocketOptions.SO_SNDBUF);
426        } else if (name == StandardSocketOptions.SO_RCVBUF) {
427            return (T)getOption(SocketOptions.SO_RCVBUF);
428        } else if (name == StandardSocketOptions.SO_REUSEADDR) {
429            return (T)getOption(SocketOptions.SO_REUSEADDR);
430        } else if (name == StandardSocketOptions.SO_REUSEPORT &&
431            supportedOptions().contains(name)) {
432            return (T)getOption(SocketOptions.SO_REUSEPORT);
433        } else if (name == StandardSocketOptions.SO_LINGER &&
434                (getSocket() != null)) {
435            return (T)getOption(SocketOptions.SO_LINGER);
436        } else if (name == StandardSocketOptions.IP_TOS) {
437            return (T)getOption(SocketOptions.IP_TOS);
438        } else if (name == StandardSocketOptions.TCP_NODELAY &&
439                (getSocket() != null)) {
440            return (T)getOption(SocketOptions.TCP_NODELAY);
441        } else {
442            throw new UnsupportedOperationException("unsupported option");
443        }
444    }
445
446    private static final Set<SocketOption<?>> socketOptions;
447
448    private static final Set<SocketOption<?>> serverSocketOptions;
449
450    static {
451        socketOptions = Set.of(StandardSocketOptions.SO_KEEPALIVE,
452                               StandardSocketOptions.SO_SNDBUF,
453                               StandardSocketOptions.SO_RCVBUF,
454                               StandardSocketOptions.SO_REUSEADDR,
455                               StandardSocketOptions.SO_LINGER,
456                               StandardSocketOptions.IP_TOS,
457                               StandardSocketOptions.TCP_NODELAY);
458
459        serverSocketOptions = Set.of(StandardSocketOptions.SO_RCVBUF,
460                                     StandardSocketOptions.SO_REUSEADDR,
461                                     StandardSocketOptions.IP_TOS);
462    }
463
464    /**
465     * Returns a set of SocketOptions supported by this impl
466     * and by this impl's socket (Socket or ServerSocket)
467     *
468     * @return a Set of SocketOptions
469     *
470     * @since 9
471     */
472    protected Set<SocketOption<?>> supportedOptions() {
473        if (getSocket() != null) {
474            return socketOptions;
475        } else {
476            return serverSocketOptions;
477        }
478    }
479}
480