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 
  56     void setDatagramSocket(DatagramSocket socket) {
  57         this.socket = socket;
  58     }
  59 
  60     DatagramSocket getDatagramSocket() {
  61         return socket;
  62     }
  63 
  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      */
  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      */
  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      */
  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      */
 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      */
 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      */
 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      */
 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      */
 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
 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
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 239     protected abstract void leaveGroup(SocketAddress mcastaddr,
 240                                        NetworkInterface netIf)
 241         throws IOException;
 242 
 243     /**
 244      * Close the socket.
 245      */
 246     protected abstract void close();
 247 
 248     /**
 249      * Gets the local port.
 250      * @return an {@code int} representing the local port value
 251      */
 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      */
 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      */
 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")
 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      */
 380     protected Set<SocketOption<?>> supportedOptions() {
 381         if (getDatagramSocket() instanceof MulticastSocket) {
 382             return mcSocketOptions;
 383         } else {
 384             return dgSocketOptions;
 385         }
 386     }
 387 }