SocketImpl.java revision dd828f42a5c83b4270d4fbf6fce2da1878f1e84a
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.InterruptedIOException;
24import java.io.OutputStream;
25
26import org.apache.harmony.luni.platform.INetworkSystem;
27import org.apache.harmony.luni.platform.Platform;
28import org.apache.harmony.luni.util.Msg;
29
30/**
31 * This class is the base of all streaming socket implementation classes.
32 * Streaming sockets are wrapped by two classes, {@code ServerSocket} and
33 * {@code Socket} at the server and client end of a connection. At the server,
34 * there are two types of sockets engaged in communication, the {@code
35 * ServerSocket} on a well known port (referred to as listener) used to
36 * establish a connection and the resulting {@code Socket} (referred to as
37 * host).
38 *
39 * @since Android 1.0
40 */
41public abstract class SocketImpl implements SocketOptions {
42
43    /**
44     * The remote address this socket is connected to.
45     *
46     * @since Android 1.0
47     */
48    protected InetAddress address;
49
50    /**
51     * The remote port this socket is connected to.
52     *
53     * @since Android 1.0
54     */
55    protected int port;
56
57    /**
58     * The file descriptor of this socket.
59     *
60     * @since Android 1.0
61     */
62    protected FileDescriptor fd;
63
64    /**
65     * The local port this socket is connected to.
66     *
67     * @since Android 1.0
68     */
69    protected int localport;
70
71    INetworkSystem netImpl;
72
73    // BEGIN android-removed
74    // int receiveTimeout;
75    // END android-removed
76
77    boolean streaming = true;
78
79    boolean shutdownInput;
80
81    /**
82     * Creates a new connection-oriented socket implementation.
83     *
84     * @see SocketImplFactory
85     * @since Android 1.0
86     */
87    public SocketImpl() {
88        this.netImpl = Platform.getNetworkSystem();
89    }
90
91    /**
92     * Waits for an incoming request and blocks until the connection is opened
93     * on the given socket.
94     *
95     * @param newSocket
96     *            the socket to accept connections on.
97     * @throws IOException
98     *             if an error occurs while accepting a new connection.
99     * @since Android 1.0
100     */
101    protected abstract void accept(SocketImpl newSocket) throws IOException;
102
103    /**
104     * Returns the available number of bytes which are readable from this socket
105     * without blocking.
106     *
107     * @return the number of bytes that may be read without blocking.
108     * @throws IOException
109     *             if an error occurs while reading the number of bytes.
110     * @since Android 1.0
111     */
112    protected abstract int available() throws IOException;
113
114    /**
115     * Binds this socket to the specified local host address and port number.
116     *
117     * @param address
118     *            the local machine address to bind this socket to.
119     * @param port
120     *            the port on the local machine to bind this socket to.
121     * @throws IOException
122     *             if an error occurs while binding this socket.
123     * @since Android 1.0
124     */
125    protected abstract void bind(InetAddress address, int port)
126            throws IOException;
127
128    /**
129     * Closes this socket. This makes later access invalid.
130     *
131     * @throws IOException
132     *             if an error occurs while closing this socket.
133     * @since Android 1.0
134     */
135    protected abstract void close() throws IOException;
136
137    /**
138     * Connects this socket to the specified remote host and port number.
139     *
140     * @param host
141     *            the remote host this socket has to be connected to.
142     * @param port
143     *            the remote port on which this socket has to be connected.
144     * @throws IOException
145     *             if an error occurs while connecting to the remote host.
146     * @since Android 1.0
147     */
148    protected abstract void connect(String host, int port) throws IOException;
149
150    /**
151     * Connects this socket to the specified remote host address and port
152     * number.
153     *
154     * @param address
155     *            the remote host address this socket has to be connected to.
156     * @param port
157     *            the remote port on which this socket has to be connected.
158     * @throws IOException
159     *             if an error occurs while connecting to the remote host.
160     * @since Android 1.0
161     */
162    protected abstract void connect(InetAddress address, int port)
163            throws IOException;
164
165    /**
166     * Creates a new unconnected socket. The argument {@code isStreaming}
167     * defines whether the new socket is a streaming or a datagram socket.
168     *
169     * @param isStreaming
170     *            defines whether the type of the new socket is streaming or
171     *            datagram.
172     * @throws IOException
173     *             if an error occurs while creating the socket.
174     * @since Android 1.0
175     */
176    protected abstract void create(boolean isStreaming) throws IOException;
177
178    /**
179     * Gets the file descriptor of this socket.
180     *
181     * @return the file descriptor of this socket.
182     * @since Android 1.0
183     */
184    protected FileDescriptor getFileDescriptor() {
185        return fd;
186    }
187
188    /**
189     * Gets the remote address this socket is connected to.
190     *
191     * @return the remote address of this socket.
192     * @since Android 1.0
193     */
194    protected InetAddress getInetAddress() {
195        return address;
196    }
197
198    /**
199     * Gets the input stream of this socket.
200     *
201     * @return the input stream of this socket.
202     * @throws IOException
203     *             if an error occurs while accessing the input stream.
204     * @since Android 1.0
205     */
206    protected abstract InputStream getInputStream() throws IOException;
207
208    /**
209     * Gets the local port number of this socket. The field is initialized to
210     * {@code -1} and upon demand will go to the IP stack to get the bound
211     * value. See the class comment for the context of the local port.
212     *
213     * @return the local port number this socket is bound to.
214     * @since Android 1.0
215     */
216    protected int getLocalPort() {
217        return localport;
218    }
219
220    /**
221     * Gets the value of the given socket option.
222     *
223     * @param optID
224     *            the socket option to retrieve.
225     * @return the option value.
226     * @throws SocketException
227     *             if an error occurs while accessing the option.
228     * @since Android 1.0
229     */
230    public abstract Object getOption(int optID) throws SocketException;
231
232    /**
233     * Gets the output stream of this socket.
234     *
235     * @return the output stream of this socket.
236     * @throws IOException
237     *             if an error occurs while accessing the output stream.
238     * @since Android 1.0
239     */
240    protected abstract OutputStream getOutputStream() throws IOException;
241
242    /**
243     * Gets the remote port number of this socket. This value is not meaningful
244     * when this instance is wrapped by a {@code ServerSocket}.
245     *
246     * @return the remote port this socket is connected to.
247     * @since Android 1.0
248     */
249    protected int getPort() {
250        return port;
251    }
252
253    /**
254     * Listens for connection requests on this streaming socket. Incoming
255     * connection requests are queued up to the limit specified by {@code
256     * backlog}. Additional requests are rejected. The method {@code listen()}
257     * may only be invoked on streaming sockets.
258     *
259     * @param backlog
260     *            the maximum number of outstanding connection requests.
261     * @throws IOException
262     *             if an error occurs while listening.
263     * @since Android 1.0
264     */
265    protected abstract void listen(int backlog) throws IOException;
266
267    /**
268     * In the IP stack, read at most {@code count} bytes off the socket
269     * into the {@code buffer}, at the {@code offset}. If the timeout
270     * is zero, block indefinitely waiting for data, otherwise wait the
271     * specified period (in milliseconds).
272     *
273     * @param buffer
274     *            the buffer to read into
275     * @param offset
276     *            the offset into the buffer
277     * @param count
278     *            the max number of bytes to read
279     * @return int the actual number of bytes read
280     * @exception IOException
281     *                thrown if an error occurs while reading
282     */
283    int read(byte[] buffer, int offset, int count) throws IOException {
284        if (shutdownInput) {
285            return -1;
286        }
287        try {
288            // BEGIN android-added
289            int receiveTimeout = (Integer)getOption(SocketOptions.SO_TIMEOUT);
290            // END android-added
291            int read = this.netImpl.receiveStream(fd, buffer, offset, count,
292                    receiveTimeout);
293            if (read == -1) {
294                shutdownInput = true;
295            }
296            return read;
297        } catch (InterruptedIOException e) {
298            throw new SocketTimeoutException(e.getMessage());
299        }
300    }
301
302    /**
303     * Sets the value for the specified socket option.
304     *
305     * @param optID
306     *            the socket option to be set.
307     * @param val
308     *            the option value.
309     * @throws SocketException
310     *             if an error occurs while setting the option.
311     * @since Android 1.0
312     */
313    public abstract void setOption(int optID, Object val)
314            throws SocketException;
315
316    /**
317     * Returns a string containing a concise, human-readable description of the
318     * socket.
319     *
320     * @return the textual representation of this socket.
321     * @since Android 1.0
322     */
323    @SuppressWarnings("nls")
324    @Override
325    public String toString() {
326        return new StringBuffer(100).append("Socket[addr=").append(
327                getInetAddress()).append(",port=").append(port).append(
328                ",localport=").append(getLocalPort()).append("]").toString();
329    }
330
331    /**
332     * In the IP stack, write at most {@code count} bytes on the socket
333     * from the {@code buffer}, from the {@code offset}.
334     *
335     * @param buffer
336     *            the buffer to read into
337     * @param offset
338     *            the offset into the buffer
339     * @param count
340     *            the number of bytes to write
341     * @return int the actual number of bytes written
342     * @exception IOException
343     *                thrown if an error occurs while writing
344     */
345    int write(byte[] buffer, int offset, int count) throws IOException {
346        if (!streaming) {
347            // BEGIN android-changed
348            // copied from newer harmony version
349            return this.netImpl
350                    .sendDatagram2(fd, buffer, offset, count, port, address);
351            // END android-changed
352        }
353        return this.netImpl.sendStream(fd, buffer, offset, count);
354    }
355
356    /**
357     * Closes the input channel of this socket.
358     * <p>
359     * This default implementation always throws an {@link IOException} to
360     * indicate that the subclass should have overridden this method.
361     * </p>
362     *
363     * @throws IOException
364     *             always because this method should be overridden.
365     * @since Android 1.0
366     */
367    protected void shutdownInput() throws IOException {
368        // KA025=Method has not been implemented
369        throw new IOException(Msg.getString("KA025"));//$NON-NLS-1$
370    }
371
372    /**
373     * Closes the output channel of this socket.
374     * <p>
375     * This default implementation always throws an {@link IOException} to
376     * indicate that the subclass should have overridden this method.
377     * </p>
378     *
379     * @throws IOException
380     *             always because this method should be overridden.
381     * @since Android 1.0
382     */
383    protected void shutdownOutput() throws IOException {
384        // KA025=Method has not been implemented
385        throw new IOException(Msg.getString("KA025"));//$NON-NLS-1$
386    }
387
388    /**
389     * Connects this socket to the remote host address and port number specified
390     * by the {@code SocketAddress} object with the given timeout. This method
391     * will block indefinitely if the timeout is set to zero.
392     *
393     * @param remoteAddr
394     *            the remote host address and port number to connect to.
395     * @param timeout
396     *            the timeout value in milliseconds.
397     * @throws IOException
398     *             if an error occurs while connecting.
399     * @since Android 1.0
400     */
401    protected abstract void connect(SocketAddress remoteAddr, int timeout)
402            throws IOException;
403
404    /**
405     * Returns whether the socket supports urgent data or not. Subclasses should
406     * override this method.
407     *
408     * @return {@code false} because subclasses must override this method.
409     * @since Android 1.0
410     */
411    protected boolean supportsUrgentData() {
412        return false;
413    }
414
415    /**
416     * Sends the single byte of urgent data on the socket.
417     *
418     * @param value
419     *            the byte of urgent data.
420     * @throws IOException
421     *             if an error occurs sending urgent data.
422     * @since Android 1.0
423     */
424    protected abstract void sendUrgentData(int value) throws IOException;
425
426    /**
427     * Sets performance preference for connection time, latency and bandwidth.
428     * Does nothing by default.
429     *
430     * @param connectionTime
431     *            the importance of connect time.
432     * @param latency
433     *            the importance of latency.
434     * @param bandwidth
435     *            the importance of bandwidth.
436     * @since Android 1.0
437     */
438    protected void setPerformancePreferences(int connectionTime, int latency,
439            int bandwidth) {
440        // Our socket implementation only provide one protocol: TCP/IP, so
441        // we do nothing for this method
442    }
443}
444