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