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