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 
  26 package java.net;
  27 
  28 import java.io.FileDescriptor;
  29 import java.io.IOException;
  30 import java.io.InterruptedIOException;
  31 import java.util.Set;
  32 import java.util.HashSet;
  33 
  34 /**
  35  * Abstract datagram and multicast socket implementation base class.
  36  * @author Pavani Diwanji
  37  * @since  1.1
  38  */
  39 
  40 public 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 1.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 1.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 }