DatagramSocketImpl.java revision 13532:859397229dc4
1/*
2 * Copyright (c) 1996, 2015, 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.FileDescriptor;
29import java.io.IOException;
30import java.io.InterruptedIOException;
31import java.util.Set;
32import java.util.HashSet;
33
34/**
35 * Abstract datagram and multicast socket implementation base class.
36 * @author Pavani Diwanji
37 * @since  1.1
38 */
39
40public abstract class DatagramSocketImpl implements SocketOptions {
41
42    /**
43     * The local port number.
44     */
45    protected int localPort;
46
47    /**
48     * The file descriptor object.
49     */
50    protected FileDescriptor fd;
51
52    /**
53     * The DatagramSocket or MulticastSocket
54     * that owns this impl
55     */
56    DatagramSocket socket;
57
58    void setDatagramSocket(DatagramSocket socket) {
59        this.socket = socket;
60    }
61
62    DatagramSocket getDatagramSocket() {
63        return socket;
64    }
65
66    int dataAvailable() {
67        // default impl returns zero, which disables the calling
68        // functionality
69        return 0;
70    }
71
72    /**
73     * Creates a datagram socket.
74     * @exception SocketException if there is an error in the
75     * underlying protocol, such as a TCP error.
76     */
77    protected abstract void create() throws SocketException;
78
79    /**
80     * Binds a datagram socket to a local port and address.
81     * @param lport the local port
82     * @param laddr the local address
83     * @exception SocketException if there is an error in the
84     * underlying protocol, such as a TCP error.
85     */
86    protected abstract void bind(int lport, InetAddress laddr) throws SocketException;
87
88    /**
89     * Sends a datagram packet. The packet contains the data and the
90     * destination address to send the packet to.
91     * @param p the packet to be sent.
92     * @exception IOException if an I/O exception occurs while sending the
93     * datagram packet.
94     * @exception  PortUnreachableException may be thrown if the socket is connected
95     * to a currently unreachable destination. Note, there is no guarantee that
96     * the exception will be thrown.
97     */
98    protected abstract void send(DatagramPacket p) throws IOException;
99
100    /**
101     * Connects a datagram socket to a remote destination. This associates the remote
102     * address with the local socket so that datagrams may only be sent to this destination
103     * and received from this destination. This may be overridden to call a native
104     * system connect.
105     *
106     * <p>If the remote destination to which the socket is connected does not
107     * exist, or is otherwise unreachable, and if an ICMP destination unreachable
108     * packet has been received for that address, then a subsequent call to
109     * send or receive may throw a PortUnreachableException.
110     * Note, there is no guarantee that the exception will be thrown.
111     * @param address the remote InetAddress to connect to
112     * @param port the remote port number
113     * @exception   SocketException may be thrown if the socket cannot be
114     * connected to the remote destination
115     * @since 1.4
116     */
117    protected void connect(InetAddress address, int port) throws SocketException {}
118
119    /**
120     * Disconnects a datagram socket from its remote destination.
121     * @since 1.4
122     */
123    protected void disconnect() {}
124
125    /**
126     * Peek at the packet to see who it is from. Updates the specified {@code InetAddress}
127     * to the address which the packet came from.
128     * @param i an InetAddress object
129     * @return the port number which the packet came from.
130     * @exception IOException if an I/O exception occurs
131     * @exception  PortUnreachableException may be thrown if the socket is connected
132     *       to a currently unreachable destination. Note, there is no guarantee that the
133     *       exception will be thrown.
134     */
135    protected abstract int peek(InetAddress i) throws IOException;
136
137    /**
138     * Peek at the packet to see who it is from. The data is copied into the specified
139     * {@code DatagramPacket}. The data is returned,
140     * but not consumed, so that a subsequent peekData/receive operation
141     * will see the same data.
142     * @param p the Packet Received.
143     * @return the port number which the packet came from.
144     * @exception IOException if an I/O exception occurs
145     * @exception  PortUnreachableException may be thrown if the socket is connected
146     *       to a currently unreachable destination. Note, there is no guarantee that the
147     *       exception will be thrown.
148     * @since 1.4
149     */
150    protected abstract int peekData(DatagramPacket p) throws IOException;
151    /**
152     * Receive the datagram packet.
153     * @param p the Packet Received.
154     * @exception IOException if an I/O exception occurs
155     * while receiving the datagram packet.
156     * @exception  PortUnreachableException may be thrown if the socket is connected
157     *       to a currently unreachable destination. Note, there is no guarantee that the
158     *       exception will be thrown.
159     */
160    protected abstract void receive(DatagramPacket p) throws IOException;
161
162    /**
163     * Set the TTL (time-to-live) option.
164     * @param ttl a byte specifying the TTL value
165     *
166     * @deprecated use setTimeToLive instead.
167     * @exception IOException if an I/O exception occurs while setting
168     * the time-to-live option.
169     * @see #getTTL()
170     */
171    @Deprecated
172    protected abstract void setTTL(byte ttl) throws IOException;
173
174    /**
175     * Retrieve the TTL (time-to-live) option.
176     *
177     * @exception IOException if an I/O exception occurs
178     * while retrieving the time-to-live option
179     * @deprecated use getTimeToLive instead.
180     * @return a byte representing the TTL value
181     * @see #setTTL(byte)
182     */
183    @Deprecated
184    protected abstract byte getTTL() throws IOException;
185
186    /**
187     * Set the TTL (time-to-live) option.
188     * @param ttl an {@code int} specifying the time-to-live value
189     * @exception IOException if an I/O exception occurs
190     * while setting the time-to-live option.
191     * @see #getTimeToLive()
192     */
193    protected abstract void setTimeToLive(int ttl) throws IOException;
194
195    /**
196     * Retrieve the TTL (time-to-live) option.
197     * @exception IOException if an I/O exception occurs
198     * while retrieving the time-to-live option
199     * @return an {@code int} representing the time-to-live value
200     * @see #setTimeToLive(int)
201     */
202    protected abstract int getTimeToLive() throws IOException;
203
204    /**
205     * Join the multicast group.
206     * @param inetaddr multicast address to join.
207     * @exception IOException if an I/O exception occurs
208     * while joining the multicast group.
209     */
210    protected abstract void join(InetAddress inetaddr) throws IOException;
211
212    /**
213     * Leave the multicast group.
214     * @param inetaddr multicast address to leave.
215     * @exception IOException if an I/O exception occurs
216     * while leaving the multicast group.
217     */
218    protected abstract void leave(InetAddress inetaddr) throws IOException;
219
220    /**
221     * Join the multicast group.
222     * @param mcastaddr address to join.
223     * @param netIf specifies the local interface to receive multicast
224     *        datagram packets
225     * @throws IOException if an I/O exception occurs while joining
226     * the multicast group
227     * @since 1.4
228     */
229    protected abstract void joinGroup(SocketAddress mcastaddr,
230                                      NetworkInterface netIf)
231        throws IOException;
232
233    /**
234     * Leave the multicast group.
235     * @param mcastaddr address to leave.
236     * @param netIf specified the local interface to leave the group at
237     * @throws IOException if an I/O exception occurs while leaving
238     * the multicast group
239     * @since 1.4
240     */
241    protected abstract void leaveGroup(SocketAddress mcastaddr,
242                                       NetworkInterface netIf)
243        throws IOException;
244
245    /**
246     * Close the socket.
247     */
248    protected abstract void close();
249
250    /**
251     * Gets the local port.
252     * @return an {@code int} representing the local port value
253     */
254    protected int getLocalPort() {
255        return localPort;
256    }
257
258    /**
259     * Gets the datagram socket file descriptor.
260     * @return a {@code FileDescriptor} object representing the datagram socket
261     * file descriptor
262     */
263    protected FileDescriptor getFileDescriptor() {
264        return fd;
265    }
266
267    /**
268     * Called to set a socket option.
269     *
270     * @param <T> The type of the socket option value
271     * @param name The socket option
272     *
273     * @param value The value of the socket option. A value of {@code null}
274     *              may be valid for some options.
275     *
276     * @throws UnsupportedOperationException if the DatagramSocketImpl does not
277     *         support the option
278     *
279     * @throws NullPointerException if name is {@code null}
280     * @throws IOException if an I/O problem occurs while attempting to set the option
281     * @since 9
282     */
283    protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
284        if (name == StandardSocketOptions.SO_SNDBUF) {
285            setOption(SocketOptions.SO_SNDBUF, value);
286        } else if (name == StandardSocketOptions.SO_RCVBUF) {
287            setOption(SocketOptions.SO_RCVBUF, value);
288        } else if (name == StandardSocketOptions.SO_REUSEADDR) {
289            setOption(SocketOptions.SO_REUSEADDR, value);
290        } else if (name == StandardSocketOptions.IP_TOS) {
291            setOption(SocketOptions.IP_TOS, value);
292        } else if (name == StandardSocketOptions.IP_MULTICAST_IF &&
293            (getDatagramSocket() instanceof MulticastSocket)) {
294            setOption(SocketOptions.IP_MULTICAST_IF2, value);
295        } else if (name == StandardSocketOptions.IP_MULTICAST_TTL &&
296            (getDatagramSocket() instanceof MulticastSocket)) {
297            if (! (value instanceof Integer)) {
298                throw new IllegalArgumentException("not an integer");
299            }
300            setTimeToLive((Integer)value);
301        } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP &&
302            (getDatagramSocket() instanceof MulticastSocket)) {
303            setOption(SocketOptions.IP_MULTICAST_LOOP, value);
304        } else {
305            throw new UnsupportedOperationException("unsupported option");
306        }
307    }
308
309    /**
310     * Called to get a socket option.
311     *
312     * @return the socket option
313     * @param <T> The type of the socket option value
314     * @param name The socket option
315     *
316     * @throws UnsupportedOperationException if the DatagramSocketImpl does not
317     *         support the option
318     *
319     * @throws NullPointerException if name is {@code null}
320     * @throws IOException if an I/O problem occurs while attempting to set the option
321     *
322     * @since 9
323     */
324    @SuppressWarnings("unchecked")
325    protected <T> T getOption(SocketOption<T> name) throws IOException {
326        if (name == StandardSocketOptions.SO_SNDBUF) {
327            return (T) getOption(SocketOptions.SO_SNDBUF);
328        } else if (name == StandardSocketOptions.SO_RCVBUF) {
329            return (T) getOption(SocketOptions.SO_RCVBUF);
330        } else if (name == StandardSocketOptions.SO_REUSEADDR) {
331            return (T) getOption(SocketOptions.SO_REUSEADDR);
332        } else if (name == StandardSocketOptions.IP_TOS) {
333            return (T) getOption(SocketOptions.IP_TOS);
334        } else if (name == StandardSocketOptions.IP_MULTICAST_IF &&
335            (getDatagramSocket() instanceof MulticastSocket)) {
336            return (T) getOption(SocketOptions.IP_MULTICAST_IF2);
337        } else if (name == StandardSocketOptions.IP_MULTICAST_TTL &&
338            (getDatagramSocket() instanceof MulticastSocket)) {
339            Integer ttl = getTimeToLive();
340            return (T)ttl;
341        } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP &&
342            (getDatagramSocket() instanceof MulticastSocket)) {
343            return (T) getOption(SocketOptions.IP_MULTICAST_LOOP);
344        } else {
345            throw new UnsupportedOperationException("unsupported option");
346        }
347    }
348
349    private static final  Set<SocketOption<?>> dgSocketOptions =
350        new HashSet<>();
351
352    private static final  Set<SocketOption<?>> mcSocketOptions =
353        new HashSet<>();
354
355    static {
356        dgSocketOptions.add(StandardSocketOptions.SO_SNDBUF);
357        dgSocketOptions.add(StandardSocketOptions.SO_RCVBUF);
358        dgSocketOptions.add(StandardSocketOptions.SO_REUSEADDR);
359        dgSocketOptions.add(StandardSocketOptions.IP_TOS);
360
361        mcSocketOptions.add(StandardSocketOptions.SO_SNDBUF);
362        mcSocketOptions.add(StandardSocketOptions.SO_RCVBUF);
363        mcSocketOptions.add(StandardSocketOptions.SO_REUSEADDR);
364        mcSocketOptions.add(StandardSocketOptions.IP_TOS);
365        mcSocketOptions.add(StandardSocketOptions.IP_MULTICAST_IF);
366        mcSocketOptions.add(StandardSocketOptions.IP_MULTICAST_TTL);
367        mcSocketOptions.add(StandardSocketOptions.IP_MULTICAST_LOOP);
368    };
369
370    /**
371     * Returns a set of SocketOptions supported by this impl
372     * and by this impl's socket (DatagramSocket or MulticastSocket)
373     *
374     * @return a Set of SocketOptions
375     */
376    protected Set<SocketOption<?>> supportedOptions() {
377        if (getDatagramSocket() instanceof MulticastSocket) {
378            return mcSocketOptions;
379        } else {
380            return dgSocketOptions;
381        }
382    }
383}
384