1 /*
   2  * Copyright (c) 1995, 2020, 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.IOException;
  29 import java.nio.channels.DatagramChannel;
  30 import java.nio.channels.MulticastChannel;
  31 import java.util.Collections;
  32 import java.util.Enumeration;
  33 import java.util.Set;
  34 
  35 /**
  36  * The multicast datagram socket class is useful for sending
  37  * and receiving IP multicast packets. A MulticastSocket is
  38  * a (UDP) DatagramSocket, with additional capabilities for
  39  * joining "groups" of other multicast hosts on the internet.
  40  * <P>
  41  * A multicast group is specified by a class D IP address
  42  * and by a standard UDP port number. Class D IP addresses
  43  * are in the range {@code 224.0.0.0} to {@code 239.255.255.255},
  44  * inclusive. The address 224.0.0.0 is reserved and should not be used.
  45  * <P>
  46  * One would join a multicast group by first creating a MulticastSocket
  47  * with the desired port, then invoking the
  48  * <CODE>joinGroup(InetAddress groupAddr)</CODE>
  49  * method:
  50  * <PRE>
  51  * // join a Multicast group and send the group salutations
  52  * ...
  53  * String msg = "Hello";
  54  * InetAddress mcastaddr = InetAddress.getByName("228.5.6.7");
  55  * InetSocketAddress group = new InetSocketAddress(mcastaddr, port);
  56  * NetworkInterface netIf = NetworkInterface.getByName("bge0");
  57  * MulticastSocket s = new MulticastSocket(6789);
  58  *
  59  * s.joinGroup(group, netIf);
  60  * byte[] msgBytes = msg.getBytes(StandardCharsets.UTF_8);
  61  * DatagramPacket hi = new DatagramPacket(msgBytes, msgBytes.length,
  62  *                                        group, 6789);
  63  * s.send(hi);
  64  * // get their responses!
  65  * byte[] buf = new byte[1000];
  66  * DatagramPacket recv = new DatagramPacket(buf, buf.length);
  67  * s.receive(recv);
  68  * ...
  69  * // OK, I'm done talking - leave the group...
  70  * s.leaveGroup(group, netIf);
  71  * </PRE>
  72  *
  73  * When one sends a message to a multicast group, <B>all</B> subscribing
  74  * recipients to that host and port receive the message (within the
  75  * time-to-live range of the packet, see below). The socket needn't
  76  * be a member of the multicast group to send messages to it.
  77  * <P>
  78  * When a socket subscribes to a multicast group/port, it receives
  79  * datagrams sent by other hosts to the group/port, as do all other
  80  * members of the group and port.  A socket relinquishes membership
  81  * in a group by the leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)
  82  * method.
  83  * <B>Multiple MulticastSockets</B> may subscribe to a multicast group
  84  * and port concurrently, and they will all receive group datagrams.
  85  *
  86  * <p> The {@code DatagramSocket} and {@code MulticastSocket}
  87  * classes define convenience methods to set and get several
  88  * socket options. Like {@code DatagramSocket} this class also
  89  * supports the {@link #setOption(SocketOption, Object) setOption}
  90  * and {@link #getOption(SocketOption) getOption} methods to set
  91  * and query socket options.
  92  * In addition to the socket options supported by
  93  * <a href="DatagramSocket.html#SocketOptions">{@code DatagramSocket}</a>, a
  94  * {@code MulticastSocket} supports the following socket options:
  95  * <blockquote>
  96  * <a id="MulticastOptions"></a>
  97  * <table class="striped">
  98  * <caption style="display:none">Socket options</caption>
  99  * <thead>
 100  *   <tr>
 101  *     <th scope="col">Option Name</th>
 102  *     <th scope="col">Description</th>
 103  *   </tr>
 104  * </thead>
 105  * <tbody>
 106  *   <tr>
 107  *     <th scope="row"> {@link java.net.StandardSocketOptions#IP_MULTICAST_IF IP_MULTICAST_IF} </th>
 108  *     <td> The network interface for Internet Protocol (IP) multicast datagrams </td>
 109  *   </tr>
 110  *   <tr>
 111  *     <th scope="row"> {@link java.net.StandardSocketOptions#IP_MULTICAST_TTL
 112  *       IP_MULTICAST_TTL} </th>
 113  *     <td> The <em>time-to-live</em> for Internet Protocol (IP) multicast
 114  *       datagrams </td>
 115  *   </tr>
 116  *   <tr>
 117  *     <th scope="row"> {@link java.net.StandardSocketOptions#IP_MULTICAST_LOOP
 118  *       IP_MULTICAST_LOOP} </th>
 119  *     <td> Loopback for Internet Protocol (IP) multicast datagrams </td>
 120  *   </tr>
 121  * </tbody>
 122  * </table>
 123  * </blockquote>
 124  * Additional (implementation specific) options may also be supported.
 125  *
 126  * @apiNote {@link DatagramChannel} implements the {@link MulticastChannel} interface
 127  *          and provides an alternative API for sending and receiving multicast datagrams.
 128  *          The {@link MulticastChannel} API supports both {@linkplain
 129  *          MulticastChannel#join(InetAddress, NetworkInterface) any-source} and
 130  *          {@linkplain MulticastChannel#join(InetAddress, NetworkInterface, InetAddress)
 131  *          source-specific} multicast.
 132  *
 133  * @author Pavani Diwanji
 134  * @since 1.1
 135  */
 136 public class MulticastSocket extends DatagramSocket {
 137 
 138     /**
 139      * Used on some platforms to record if an outgoing interface
 140      * has been set for this socket.
 141      */
 142     private boolean interfaceSet;
 143 
 144     /**
 145      * Create a multicast socket.
 146      *
 147      * <p>
 148      * If there is a security manager, its {@code checkListen} method is first
 149      * called with 0 as its argument to ensure the operation is allowed. This
 150      * could result in a SecurityException.
 151      * <p>
 152      * When the socket is created the
 153      * {@link DatagramSocket#setReuseAddress(boolean)} method is called to
 154      * enable the SO_REUSEADDR socket option.
 155      *
 156      * @throws    IOException if an I/O exception occurs while creating the
 157      * MulticastSocket
 158      * @throws    SecurityException if a security manager exists and its
 159      * {@code checkListen} method doesn't allow the operation.
 160      * @see SecurityManager#checkListen
 161      * @see java.net.DatagramSocket#setReuseAddress(boolean)
 162      * @see java.net.DatagramSocketImpl#setOption(SocketOption, Object)
 163      */
 164     public MulticastSocket() throws IOException {
 165         this(new InetSocketAddress(0));
 166     }
 167 
 168     /**
 169      * Create a multicast socket and bind it to a specific port.
 170      *
 171      * <p>If there is a security manager,
 172      * its {@code checkListen} method is first called
 173      * with the {@code port} argument
 174      * as its argument to ensure the operation is allowed.
 175      * This could result in a SecurityException.
 176      * <p>
 177      * When the socket is created the
 178      * {@link DatagramSocket#setReuseAddress(boolean)} method is
 179      * called to enable the SO_REUSEADDR socket option.
 180      *
 181      * @param     port port to use
 182      * @throws    IOException if an I/O exception occurs
 183      *            while creating the MulticastSocket
 184      * @throws    SecurityException  if a security manager exists and its
 185      *            {@code checkListen} method doesn't allow the operation.
 186      * @see       SecurityManager#checkListen
 187      * @see       java.net.DatagramSocket#setReuseAddress(boolean)
 188      */
 189     public MulticastSocket(int port) throws IOException {
 190         this(new InetSocketAddress(port));
 191     }
 192 
 193     /**
 194      * Create a MulticastSocket bound to the specified socket address.
 195      * <p>
 196      * Or, if the address is {@code null}, create an unbound socket.
 197      *
 198      * <p>If there is a security manager,
 199      * its {@code checkListen} method is first called
 200      * with the SocketAddress port as its argument to ensure the operation is allowed.
 201      * This could result in a SecurityException.
 202      * <p>
 203      * When the socket is created the
 204      * {@link DatagramSocket#setReuseAddress(boolean)} method is
 205      * called to enable the SO_REUSEADDR socket option.
 206      *
 207      * @param    bindaddr Socket address to bind to, or {@code null} for
 208      *           an unbound socket.
 209      * @throws   IOException if an I/O exception occurs
 210      *           while creating the MulticastSocket
 211      * @throws   SecurityException  if a security manager exists and its
 212      *           {@code checkListen} method doesn't allow the operation.
 213      * @see      SecurityManager#checkListen
 214      * @see      java.net.DatagramSocket#setReuseAddress(boolean)
 215      *
 216      * @since 1.4
 217      */
 218     public MulticastSocket(SocketAddress bindaddr) throws IOException {
 219         super((SocketAddress) null);
 220 
 221         // No further initialization when this is a DatagramChannel socket adaptor
 222         if (this instanceof sun.nio.ch.DatagramSocketAdaptor)
 223             return;
 224 
 225         // Enable SO_REUSEADDR before binding
 226         setReuseAddress(true);
 227 
 228         if (bindaddr != null) {
 229             try {
 230                 bind(bindaddr);
 231             } finally {
 232                 if (!isBound()) {
 233                     close();
 234                 }
 235             }
 236         }
 237     }
 238 
 239     /**
 240      * The lock on the socket's TTL. This is for set/getTTL and
 241      * send(packet,ttl).
 242      */
 243     private Object ttlLock = new Object();
 244 
 245     /**
 246      * The lock on the socket's interface - used by setInterface
 247      * and getInterface
 248      */
 249     private Object infLock = new Object();
 250 
 251     /**
 252      * The "last" interface set by setInterface on this MulticastSocket
 253      */
 254     private InetAddress infAddress = null;
 255 
 256 
 257     /**
 258      * Set the default time-to-live for multicast packets sent out
 259      * on this {@code MulticastSocket} in order to control the
 260      * scope of the multicasts.
 261      *
 262      * <p>The ttl is an <b>unsigned</b> 8-bit quantity, and so <B>must</B> be
 263      * in the range {@code 0 <= ttl <= 0xFF }.
 264      *
 265      * @param      ttl the time-to-live
 266      * @throws     IOException if an I/O exception occurs
 267      *             while setting the default time-to-live value
 268      * @deprecated use the setTimeToLive method instead, which uses
 269      *             <b>int</b> instead of <b>byte</b> as the type for ttl.
 270      * @see #getTTL()
 271      */
 272     @Deprecated
 273     public void setTTL(byte ttl) throws IOException {
 274         if (isClosed())
 275             throw new SocketException("Socket is closed");
 276         getImpl().setTTL(ttl);
 277     }
 278 
 279     /**
 280      * Set the default time-to-live for multicast packets sent out
 281      * on this {@code MulticastSocket} in order to control the
 282      * scope of the multicasts.
 283      *
 284      * <P> The ttl <B>must</B> be in the range {@code  0 <= ttl <=
 285      * 255} or an {@code IllegalArgumentException} will be thrown.
 286      * Multicast packets sent with a TTL of {@code 0} are not transmitted
 287      * on the network but may be delivered locally.
 288      *
 289      * @param  ttl
 290      *         the time-to-live
 291      *
 292      * @throws  IOException
 293      *          if an I/O exception occurs while setting the
 294      *          default time-to-live value
 295      *
 296      * @see #getTimeToLive()
 297      * @since 1.2
 298      */
 299     public void setTimeToLive(int ttl) throws IOException {
 300         if (ttl < 0 || ttl > 255) {
 301             throw new IllegalArgumentException("ttl out of range");
 302         }
 303         if (isClosed())
 304             throw new SocketException("Socket is closed");
 305         getImpl().setTimeToLive(ttl);
 306     }
 307 
 308     /**
 309      * Get the default time-to-live for multicast packets sent out on
 310      * the socket.
 311      *
 312      * @throws    IOException if an I/O exception occurs
 313      * while getting the default time-to-live value
 314      * @return the default time-to-live value
 315      * @deprecated use the getTimeToLive method instead, which returns
 316      * an <b>int</b> instead of a <b>byte</b>.
 317      * @see #setTTL(byte)
 318      */
 319     @Deprecated
 320     public byte getTTL() throws IOException {
 321         if (isClosed())
 322             throw new SocketException("Socket is closed");
 323         return getImpl().getTTL();
 324     }
 325 
 326     /**
 327      * Get the default time-to-live for multicast packets sent out on
 328      * the socket.
 329      * @throws    IOException if an I/O exception occurs while
 330      * getting the default time-to-live value
 331      * @return the default time-to-live value
 332      * @see #setTimeToLive(int)
 333      * @since 1.2
 334      */
 335     public int getTimeToLive() throws IOException {
 336         if (isClosed())
 337             throw new SocketException("Socket is closed");
 338         return getImpl().getTimeToLive();
 339     }
 340 
 341     /**
 342      * Joins a multicast group. Its behavior may be affected by
 343      * {@code setInterface} or {@code setNetworkInterface}.
 344      *
 345      * <p>If there is a security manager, this method first
 346      * calls its {@code checkMulticast} method with the
 347      * {@code mcastaddr} argument as its argument.
 348      *
 349      * @param      mcastaddr is the multicast address to join
 350      * @throws     IOException if there is an error joining,
 351      *             or when the address is not a multicast address,
 352      *             or the platform does not support multicasting
 353      * @throws     SecurityException if a security manager exists and its
 354      *             {@code checkMulticast} method doesn't allow the join.
 355      * @deprecated This method does not accept the network interface on
 356      *             which to join the multicast group. Use
 357      *             {@link #joinGroup(SocketAddress, NetworkInterface)} instead.
 358      * @see        SecurityManager#checkMulticast(InetAddress)
 359      */
 360     @Deprecated(since="14")
 361     public void joinGroup(InetAddress mcastaddr) throws IOException {
 362         if (isClosed()) {
 363             throw new SocketException("Socket is closed");
 364         }
 365 
 366         checkAddress(mcastaddr, "joinGroup");
 367         SecurityManager security = System.getSecurityManager();
 368         if (security != null) {
 369             security.checkMulticast(mcastaddr);
 370         }
 371 
 372         if (!mcastaddr.isMulticastAddress()) {
 373             throw new SocketException("Not a multicast address");
 374         }
 375 
 376         /**
 377          * required for some platforms where it's not possible to join
 378          * a group without setting the interface first.
 379          */
 380         NetworkInterface defaultInterface = NetworkInterface.getDefault();
 381 
 382         if (!interfaceSet && defaultInterface != null) {
 383             setNetworkInterface(defaultInterface);
 384         }
 385 
 386         getImpl().join(mcastaddr);
 387     }
 388 
 389     /**
 390      * Leave a multicast group. Its behavior may be affected by
 391      * {@code setInterface} or {@code setNetworkInterface}.
 392      *
 393      * <p>If there is a security manager, this method first
 394      * calls its {@code checkMulticast} method with the
 395      * {@code mcastaddr} argument as its argument.
 396      *
 397      * @param      mcastaddr is the multicast address to leave
 398      * @throws     IOException if there is an error leaving
 399      *             or when the address is not a multicast address.
 400      * @throws     SecurityException if a security manager exists and its
 401      *             {@code checkMulticast} method doesn't allow the operation.
 402      * @deprecated This method does not accept the network interface on which
 403      *             to leave the multicast group. Use
 404      *             {@link #leaveGroup(SocketAddress, NetworkInterface)} instead.
 405      * @see        SecurityManager#checkMulticast(InetAddress)
 406      */
 407     @Deprecated(since="14")
 408     public void leaveGroup(InetAddress mcastaddr) throws IOException {
 409         if (isClosed()) {
 410             throw new SocketException("Socket is closed");
 411         }
 412 
 413         checkAddress(mcastaddr, "leaveGroup");
 414         SecurityManager security = System.getSecurityManager();
 415         if (security != null) {
 416             security.checkMulticast(mcastaddr);
 417         }
 418 
 419         if (!mcastaddr.isMulticastAddress()) {
 420             throw new SocketException("Not a multicast address");
 421         }
 422 
 423         getImpl().leave(mcastaddr);
 424     }
 425 
 426     /**
 427      * Joins the specified multicast group at the specified interface.
 428      *
 429      * <p>If there is a security manager, this method first
 430      * calls its {@code checkMulticast} method
 431      * with the {@code mcastaddr} argument
 432      * as its argument.
 433      *
 434      * @param  mcastaddr is the multicast address to join
 435      * @param  netIf specifies the local interface to receive multicast
 436      *         datagram packets, or {@code null} to defer to the interface set by
 437      *         {@link MulticastSocket#setInterface(InetAddress)} or
 438      *         {@link MulticastSocket#setNetworkInterface(NetworkInterface)}.
 439      *         If {@code null}, and no interface has been set, the behaviour is
 440      *         unspecified: any interface may be selected or the operation may fail
 441      *         with a {@code SocketException}.
 442      * @throws IOException if there is an error joining, or when the address
 443      *         is not a multicast address, or the platform does not support
 444      *         multicasting
 445      * @throws SecurityException if a security manager exists and its
 446      *         {@code checkMulticast} method doesn't allow the join.
 447      * @throws IllegalArgumentException if mcastaddr is {@code null} or is a
 448      *         SocketAddress subclass not supported by this socket
 449      * @see    SecurityManager#checkMulticast(InetAddress)
 450      * @see    DatagramChannel#join(InetAddress, NetworkInterface)
 451      * @since  1.4
 452      */
 453     public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)
 454         throws IOException {
 455         if (isClosed())
 456             throw new SocketException("Socket is closed");
 457 
 458         if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
 459             throw new IllegalArgumentException("Unsupported address type");
 460 
 461         if (oldImpl)
 462             throw new UnsupportedOperationException();
 463 
 464         checkAddress(((InetSocketAddress)mcastaddr).getAddress(), "joinGroup");
 465         SecurityManager security = System.getSecurityManager();
 466         if (security != null) {
 467             security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress());
 468         }
 469 
 470         if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) {
 471             throw new SocketException("Not a multicast address");
 472         }
 473 
 474         getImpl().joinGroup(mcastaddr, netIf);
 475     }
 476 
 477     /**
 478      * Leave a multicast group on a specified local interface.
 479      *
 480      * <p>If there is a security manager, this method first
 481      * calls its {@code checkMulticast} method with the
 482      * {@code mcastaddr} argument as its argument.
 483      *
 484      * @param  mcastaddr is the multicast address to leave
 485      * @param  netIf specifies the local interface or {@code null} to defer
 486      *         to the interface set by
 487      *         {@link MulticastSocket#setInterface(InetAddress)} or
 488      *         {@link MulticastSocket#setNetworkInterface(NetworkInterface)}.
 489      *         If {@code null}, and no interface has been set, the behaviour
 490      *         is unspecified: any interface may be selected or the operation
 491      *         may fail with a {@code SocketException}.
 492      * @throws IOException if there is an error leaving or when the address
 493      *         is not a multicast address.
 494      * @throws SecurityException if a security manager exists and its
 495      *         {@code checkMulticast} method doesn't allow the operation.
 496      * @throws IllegalArgumentException if mcastaddr is {@code null} or is a
 497      *         SocketAddress subclass not supported by this socket.
 498      * @see    SecurityManager#checkMulticast(InetAddress)
 499      * @since  1.4
 500      */
 501     public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)
 502         throws IOException {
 503         if (isClosed())
 504             throw new SocketException("Socket is closed");
 505 
 506         if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
 507             throw new IllegalArgumentException("Unsupported address type");
 508 
 509         if (oldImpl)
 510             throw new UnsupportedOperationException();
 511 
 512         checkAddress(((InetSocketAddress)mcastaddr).getAddress(), "leaveGroup");
 513         SecurityManager security = System.getSecurityManager();
 514         if (security != null) {
 515             security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress());
 516         }
 517 
 518         if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) {
 519             throw new SocketException("Not a multicast address");
 520         }
 521 
 522         getImpl().leaveGroup(mcastaddr, netIf);
 523      }
 524 
 525     /**
 526      * Set the multicast network interface used by methods
 527      * whose behavior would be affected by the value of the
 528      * network interface. Useful for multihomed hosts.
 529      *
 530      * @param      inf the InetAddress
 531      * @throws     SocketException if there is an error in
 532      *             the underlying protocol, such as a TCP error.
 533      * @deprecated The InetAddress may not uniquely identify
 534      *             the network interface. Use
 535      *             {@link #setNetworkInterface(NetworkInterface)} instead.
 536      * @see        #getInterface()
 537      */
 538     @Deprecated(since="14")
 539     public void setInterface(InetAddress inf) throws SocketException {
 540         if (isClosed()) {
 541             throw new SocketException("Socket is closed");
 542         }
 543         checkAddress(inf, "setInterface");
 544         synchronized (infLock) {
 545             getImpl().setOption(SocketOptions.IP_MULTICAST_IF, inf);
 546             infAddress = inf;
 547             interfaceSet = true;
 548         }
 549     }
 550 
 551     /**
 552      * Retrieve the address of the network interface used for
 553      * multicast packets.
 554      *
 555      * @return     An {@code InetAddress} representing the address
 556      *             of the network interface used for multicast packets,
 557      *             or if no interface has been set, an {@code InetAddress}
 558      *             representing any local address.
 559      * @throws     SocketException if there is an error in the
 560      *             underlying protocol, such as a TCP error.
 561      * @deprecated The network interface may not be uniquely identified by
 562      *             the InetAddress returned.
 563      *             Use {@link #getNetworkInterface()} instead.
 564      * @see        #setInterface(java.net.InetAddress)
 565      */
 566     @Deprecated(since="14")
 567     public InetAddress getInterface() throws SocketException {
 568         if (isClosed()) {
 569             throw new SocketException("Socket is closed");
 570         }
 571         synchronized (infLock) {
 572             InetAddress ia =
 573                 (InetAddress)getImpl().getOption(SocketOptions.IP_MULTICAST_IF);
 574 
 575             /**
 576              * No previous setInterface or interface can be
 577              * set using setNetworkInterface
 578              */
 579             if (infAddress == null) {
 580                 return ia;
 581             }
 582 
 583             /**
 584              * Same interface set with setInterface?
 585              */
 586             if (ia.equals(infAddress)) {
 587                 return ia;
 588             }
 589 
 590             /**
 591              * Different InetAddress from what we set with setInterface
 592              * so enumerate the current interface to see if the
 593              * address set by setInterface is bound to this interface.
 594              */
 595             try {
 596                 NetworkInterface ni = NetworkInterface.getByInetAddress(ia);
 597                 Enumeration<InetAddress> addrs = ni.getInetAddresses();
 598                 while (addrs.hasMoreElements()) {
 599                     InetAddress addr = addrs.nextElement();
 600                     if (addr.equals(infAddress)) {
 601                         return infAddress;
 602                     }
 603                 }
 604 
 605                 /**
 606                  * No match so reset infAddress to indicate that the
 607                  * interface has changed via means
 608                  */
 609                 infAddress = null;
 610                 return ia;
 611             } catch (Exception e) {
 612                 return ia;
 613             }
 614         }
 615     }
 616 
 617     /**
 618      * Specify the network interface for outgoing multicast datagrams
 619      * sent on this socket.
 620      *
 621      * @param netIf the interface
 622      * @throws    SocketException if there is an error in
 623      * the underlying protocol, such as a TCP error.
 624      * @see #getNetworkInterface()
 625      * @since 1.4
 626      */
 627     public void setNetworkInterface(NetworkInterface netIf)
 628         throws SocketException {
 629 
 630         synchronized (infLock) {
 631             getImpl().setOption(SocketOptions.IP_MULTICAST_IF2, netIf);
 632             infAddress = null;
 633             interfaceSet = true;
 634         }
 635     }
 636 
 637     /**
 638      * Get the multicast network interface set.
 639      *
 640      * @throws SocketException if there is an error in
 641      *         the underlying protocol, such as a TCP error.
 642      * @return The multicast {@code NetworkInterface} currently set. A placeholder
 643      *         NetworkInterface is returned when there is no interface set; it has
 644      *         a single InetAddress to represent any local address.
 645      * @see    #setNetworkInterface(NetworkInterface)
 646      * @since  1.4
 647      */
 648     public NetworkInterface getNetworkInterface() throws SocketException {
 649         NetworkInterface ni
 650             = (NetworkInterface)getImpl().getOption(SocketOptions.IP_MULTICAST_IF2);
 651         if (ni == null) {
 652             InetAddress[] addrs = new InetAddress[1];
 653             addrs[0] = InetAddress.anyLocalAddress();
 654             return new NetworkInterface(addrs[0].getHostName(), 0, addrs);
 655         } else {
 656             return ni;
 657         }
 658     }
 659 
 660     /**
 661      * Disable/Enable local loopback of multicast datagrams.
 662      * The option is used by the platform's networking code as a hint
 663      * for setting whether multicast data will be looped back to
 664      * the local socket.
 665      *
 666      * <p>Because this option is a hint, applications that want to
 667      * verify what loopback mode is set to should call
 668      * {@link #getLoopbackMode()}
 669      * @param      disable {@code true} to disable the LoopbackMode
 670      * @throws     SocketException if an error occurs while setting the value
 671      * @since      1.4
 672      * @deprecated Use {@link #setOption(SocketOption, Object)} with
 673      *             {@link java.net.StandardSocketOptions#IP_MULTICAST_LOOP}
 674      *             instead. The loopback mode is enabled by default,
 675      *             {@code MulticastSocket.setOption(StandardSocketOptions.IP_MULTICAST_LOOP, false)}
 676      *             disables it.
 677      * @see        #getLoopbackMode
 678      */
 679     @Deprecated(since="14")
 680     public void setLoopbackMode(boolean disable) throws SocketException {
 681         getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP, Boolean.valueOf(disable));
 682     }
 683 
 684     /**
 685      * Get the setting for local loopback of multicast datagrams.
 686      *
 687      * @throws     SocketException if an error occurs while getting the value
 688      * @return     true if the LoopbackMode has been disabled
 689      * @since      1.4
 690      * @deprecated Use {@link #getOption(SocketOption)} with
 691      *             {@link java.net.StandardSocketOptions#IP_MULTICAST_LOOP}
 692      *             instead.
 693      * @see        #setLoopbackMode
 694      */
 695     @Deprecated(since="14")
 696     public boolean getLoopbackMode() throws SocketException {
 697         return ((Boolean)getImpl().getOption(SocketOptions.IP_MULTICAST_LOOP)).booleanValue();
 698     }
 699 
 700     /**
 701      * Sends a datagram packet to the destination, with a TTL (time-
 702      * to-live) other than the default for the socket.  This method
 703      * need only be used in instances where a particular TTL is desired;
 704      * otherwise it is preferable to set a TTL once on the socket, and
 705      * use that default TTL for all packets.  This method does <B>not
 706      * </B> alter the default TTL for the socket. Its behavior may be
 707      * affected by {@code setInterface}.
 708      *
 709      * <p>If there is a security manager, this method first performs some
 710      * security checks. First, if {@code p.getAddress().isMulticastAddress()}
 711      * is true, this method calls the
 712      * security manager's {@code checkMulticast} method
 713      * with {@code p.getAddress()} and {@code ttl} as its arguments.
 714      * If the evaluation of that expression is false,
 715      * this method instead calls the security manager's
 716      * {@code checkConnect} method with arguments
 717      * {@code p.getAddress().getHostAddress()} and
 718      * {@code p.getPort()}. Each call to a security manager method
 719      * could result in a SecurityException if the operation is not allowed.
 720      *
 721      * @param p is the packet to be sent. The packet should contain
 722      * the destination multicast ip address and the data to be sent.
 723      * One does not need to be the member of the group to send
 724      * packets to a destination multicast address.
 725      * @param ttl optional time to live for multicast packet.
 726      * default ttl is 1.
 727      *
 728      * @throws     IOException is raised if an error occurs i.e
 729      *             error while setting ttl.
 730      * @throws     SecurityException  if a security manager exists and its
 731      *             {@code checkMulticast} or {@code checkConnect}
 732      *             method doesn't allow the send.
 733      * @throws     PortUnreachableException may be thrown if the socket is connected
 734      *             to a currently unreachable destination. Note, there is no
 735      *             guarantee that the exception will be thrown.
 736      * @throws     IllegalArgumentException if the socket is connected,
 737      *             and connected address and packet address differ, or
 738      *             if the socket is not connected and the packet address
 739      *             is not set or if its port is out of range.
 740      *
 741      *
 742      * @deprecated Use the following code or its equivalent instead:
 743      *  ......
 744      *  int ttl = mcastSocket.getTimeToLive();
 745      *  mcastSocket.setTimeToLive(newttl);
 746      *  mcastSocket.send(p);
 747      *  mcastSocket.setTimeToLive(ttl);
 748      *  ......
 749      *
 750      * @see DatagramSocket#send
 751      * @see DatagramSocket#receive
 752      * @see SecurityManager#checkMulticast(java.net.InetAddress, byte)
 753      * @see SecurityManager#checkConnect
 754      */
 755     @Deprecated
 756     public void send(DatagramPacket p, byte ttl)
 757         throws IOException {
 758             if (isClosed())
 759                 throw new SocketException("Socket is closed");
 760             synchronized(ttlLock) {
 761                 synchronized(p) {
 762                     InetAddress packetAddress = p.getAddress();
 763                     int packetPort = p.getPort();
 764                     checkAddress(packetAddress, "send");
 765                     if (connectState == ST_NOT_CONNECTED) {
 766                         if (packetAddress == null) {
 767                             throw new IllegalArgumentException("Address not set");
 768                         }
 769                         if (packetPort < 0 || packetPort > 0xFFFF)
 770                             throw new IllegalArgumentException("port out of range:" + packetPort);
 771                         // Security manager makes sure that the multicast address
 772                         // is allowed one and that the ttl used is less
 773                         // than the allowed maxttl.
 774                         SecurityManager security = System.getSecurityManager();
 775                         if (security != null) {
 776                             if (packetAddress.isMulticastAddress()) {
 777                                 security.checkMulticast(packetAddress, ttl);
 778                             } else {
 779                                 security.checkConnect(packetAddress.getHostAddress(),
 780                                         packetPort);
 781                             }
 782                         }
 783                     } else {
 784                         // we're connected
 785                         if (packetAddress == null) {
 786                             p.setAddress(connectedAddress);
 787                             p.setPort(connectedPort);
 788                         } else if ((!packetAddress.equals(connectedAddress)) ||
 789                                 packetPort != connectedPort) {
 790                             throw new IllegalArgumentException("connected address and packet address" +
 791                                                         " differ");
 792                         }
 793                     }
 794                     byte dttl = getTTL();
 795                     try {
 796                         if (ttl != dttl) {
 797                             // set the ttl
 798                             getImpl().setTTL(ttl);
 799                         }
 800                         // call the datagram method to send
 801                         getImpl().send(p);
 802                     } finally {
 803                         // set it back to default
 804                         if (ttl != dttl) {
 805                             getImpl().setTTL(dttl);
 806                         }
 807                     }
 808                 } // synch p
 809             }  //synch ttl
 810     } //method
 811 
 812     private static Set<SocketOption<?>> options;
 813     private static boolean optionsSet = false;
 814 
 815     @Override
 816     public Set<SocketOption<?>> supportedOptions() {
 817         synchronized (MulticastSocket.class) {
 818             if (optionsSet) {
 819                 return options;
 820             }
 821             try {
 822                 DatagramSocketImpl impl = getImpl();
 823                 options = Collections.unmodifiableSet(impl.supportedOptions());
 824             } catch (SocketException ex) {
 825                 options = Collections.emptySet();
 826             }
 827             optionsSet = true;
 828             return options;
 829         }
 830     }
 831 }