SocketImpl.java revision 4eb8ca7f1e5de2d208c5fcee8b11a7e50200cf17
1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.net;
19
20import java.io.FileDescriptor;
21import java.io.IOException;
22import java.io.InputStream;
23import java.io.OutputStream;
24import org.apache.harmony.luni.platform.INetworkSystem;
25import org.apache.harmony.luni.platform.Platform;
26
27/**
28 * This class is the base of all streaming socket implementation classes.
29 * Streaming sockets are wrapped by two classes, {@code ServerSocket} and
30 * {@code Socket} at the server and client end of a connection. At the server,
31 * there are two types of sockets engaged in communication, the {@code
32 * ServerSocket} on a well known port (referred to as listener) used to
33 * establish a connection and the resulting {@code Socket} (referred to as
34 * host).
35 */
36public abstract class SocketImpl implements SocketOptions {
37
38    /**
39     * The remote address this socket is connected to.
40     */
41    protected InetAddress address;
42
43    /**
44     * The remote port this socket is connected to.
45     */
46    protected int port;
47
48    /**
49     * The file descriptor of this socket.
50     */
51    protected FileDescriptor fd;
52
53    /**
54     * The local port this socket is connected to.
55     */
56    protected int localport;
57
58    INetworkSystem netImpl = Platform.getNetworkSystem();
59
60    boolean streaming = true;
61
62    /**
63     * Waits for an incoming request and blocks until the connection is opened
64     * on the given socket.
65     *
66     * @param newSocket
67     *            the socket to accept connections on.
68     * @throws IOException
69     *             if an error occurs while accepting a new connection.
70     */
71    protected abstract void accept(SocketImpl newSocket) throws IOException;
72
73    /**
74     * Returns the available number of bytes which are readable from this socket
75     * without blocking.
76     *
77     * @return the number of bytes that may be read without blocking.
78     * @throws IOException
79     *             if an error occurs while reading the number of bytes.
80     */
81    protected abstract int available() throws IOException;
82
83    /**
84     * Binds this socket to the specified local host address and port number.
85     *
86     * @param address
87     *            the local machine address to bind this socket to.
88     * @param port
89     *            the port on the local machine to bind this socket to.
90     * @throws IOException
91     *             if an error occurs while binding this socket.
92     */
93    protected abstract void bind(InetAddress address, int port)
94            throws IOException;
95
96    /**
97     * Closes this socket. This makes later access invalid.
98     *
99     * @throws IOException
100     *             if an error occurs while closing this socket.
101     */
102    protected abstract void close() throws IOException;
103
104    /**
105     * Connects this socket to the specified remote host and port number.
106     *
107     * @param host
108     *            the remote host this socket has to be connected to.
109     * @param port
110     *            the remote port on which this socket has to be connected.
111     * @throws IOException
112     *             if an error occurs while connecting to the remote host.
113     */
114    protected abstract void connect(String host, int port) throws IOException;
115
116    /**
117     * Connects this socket to the specified remote host address and port
118     * number.
119     *
120     * @param address
121     *            the remote host address this socket has to be connected to.
122     * @param port
123     *            the remote port on which this socket has to be connected.
124     * @throws IOException
125     *             if an error occurs while connecting to the remote host.
126     */
127    protected abstract void connect(InetAddress address, int port)
128            throws IOException;
129
130    /**
131     * Creates a new unconnected socket. The argument {@code isStreaming}
132     * defines whether the new socket is a streaming or a datagram socket.
133     *
134     * @param isStreaming
135     *            defines whether the type of the new socket is streaming or
136     *            datagram.
137     * @throws IOException
138     *             if an error occurs while creating the socket.
139     */
140    protected abstract void create(boolean isStreaming) throws IOException;
141
142    /**
143     * Gets the file descriptor of this socket.
144     *
145     * @return the file descriptor of this socket.
146     */
147    protected FileDescriptor getFileDescriptor() {
148        return fd;
149    }
150
151    /**
152     * Gets the remote address this socket is connected to.
153     *
154     * @return the remote address of this socket.
155     */
156    protected InetAddress getInetAddress() {
157        return address;
158    }
159
160    /**
161     * Gets the input stream of this socket.
162     *
163     * @return the input stream of this socket.
164     * @throws IOException
165     *             if an error occurs while accessing the input stream.
166     */
167    protected abstract InputStream getInputStream() throws IOException;
168
169    /**
170     * Gets the local port number of this socket. The field is initialized to
171     * {@code -1} and upon demand will go to the IP stack to get the bound
172     * value. See the class comment for the context of the local port.
173     *
174     * @return the local port number this socket is bound to.
175     */
176    protected int getLocalPort() {
177        return localport;
178    }
179
180    /**
181     * Gets the output stream of this socket.
182     *
183     * @return the output stream of this socket.
184     * @throws IOException
185     *             if an error occurs while accessing the output stream.
186     */
187    protected abstract OutputStream getOutputStream() throws IOException;
188
189    /**
190     * Gets the remote port number of this socket. This value is not meaningful
191     * when this instance is wrapped by a {@code ServerSocket}.
192     *
193     * @return the remote port this socket is connected to.
194     */
195    protected int getPort() {
196        return port;
197    }
198
199    /**
200     * Listens for connection requests on this streaming socket. Incoming
201     * connection requests are queued up to the limit specified by {@code
202     * backlog}. Additional requests are rejected. The method {@code listen()}
203     * may only be invoked on streaming sockets.
204     *
205     * @param backlog
206     *            the maximum number of outstanding connection requests.
207     * @throws IOException
208     *             if an error occurs while listening.
209     */
210    protected abstract void listen(int backlog) throws IOException;
211
212    /**
213     * Returns a string containing a concise, human-readable description of the
214     * socket.
215     *
216     * @return the textual representation of this socket.
217     */
218    @SuppressWarnings("nls")
219    @Override
220    public String toString() {
221        return new StringBuilder(100).append("Socket[addr=").append(
222                getInetAddress()).append(",port=").append(port).append(
223                ",localport=").append(getLocalPort()).append("]").toString();
224    }
225
226    /**
227     * In the IP stack, write at most {@code count} bytes on the socket
228     * from the {@code buffer}, from the {@code offset}.
229     *
230     * @param buffer
231     *            the buffer to read into
232     * @param offset
233     *            the offset into the buffer
234     * @param count
235     *            the number of bytes to write
236     * @return int the actual number of bytes written
237     * @throws IOException
238     *                thrown if an error occurs while writing
239     */
240    int write(byte[] buffer, int offset, int count) throws IOException {
241        if (streaming) {
242            return this.netImpl.write(fd, buffer, offset, count);
243        } else {
244            return this.netImpl.send(fd, buffer, offset, count, port, address);
245        }
246    }
247
248    /**
249     * Closes the input channel of this socket.
250     * <p>
251     * This default implementation always throws an {@link IOException} to
252     * indicate that the subclass should have overridden this method.
253     *
254     * @throws IOException
255     *             always because this method should be overridden.
256     */
257    protected void shutdownInput() throws IOException {
258        throw new IOException("Method has not been implemented");
259    }
260
261    /**
262     * Closes the output channel of this socket.
263     * <p>
264     * This default implementation always throws an {@link IOException} to
265     * indicate that the subclass should have overridden this method.
266     *
267     * @throws IOException
268     *             always because this method should be overridden.
269     */
270    protected void shutdownOutput() throws IOException {
271        throw new IOException("Method has not been implemented");
272    }
273
274    /**
275     * Connects this socket to the remote host address and port number specified
276     * by the {@code SocketAddress} object with the given timeout. This method
277     * will block indefinitely if the timeout is set to zero.
278     *
279     * @param remoteAddr
280     *            the remote host address and port number to connect to.
281     * @param timeout
282     *            the timeout value in milliseconds.
283     * @throws IOException
284     *             if an error occurs while connecting.
285     */
286    protected abstract void connect(SocketAddress remoteAddr, int timeout)
287            throws IOException;
288
289    /**
290     * Returns whether the socket supports urgent data or not. Subclasses should
291     * override this method.
292     *
293     * @return {@code false} because subclasses must override this method.
294     */
295    protected boolean supportsUrgentData() {
296        return false;
297    }
298
299    /**
300     * Sends the single byte of urgent data on the socket.
301     *
302     * @param value
303     *            the byte of urgent data.
304     * @throws IOException
305     *             if an error occurs sending urgent data.
306     */
307    protected abstract void sendUrgentData(int value) throws IOException;
308
309    /**
310     * Sets performance preference for connection time, latency and bandwidth.
311     * Does nothing by default.
312     *
313     * @param connectionTime
314     *            the importance of connect time.
315     * @param latency
316     *            the importance of latency.
317     * @param bandwidth
318     *            the importance of bandwidth.
319     */
320    protected void setPerformancePreferences(int connectionTime, int latency,
321            int bandwidth) {
322        // Our socket implementation only provide one protocol: TCP/IP, so
323        // we do nothing for this method
324    }
325}
326