| /* | 
 |  * Copyright (c) 1995, 2007, Oracle and/or its affiliates. All rights reserved. | 
 |  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
 |  * | 
 |  * This code is free software; you can redistribute it and/or modify it | 
 |  * under the terms of the GNU General Public License version 2 only, as | 
 |  * published by the Free Software Foundation.  Oracle designates this | 
 |  * particular file as subject to the "Classpath" exception as provided | 
 |  * by Oracle in the LICENSE file that accompanied this code. | 
 |  * | 
 |  * This code is distributed in the hope that it will be useful, but WITHOUT | 
 |  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
 |  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
 |  * version 2 for more details (a copy is included in the LICENSE file that | 
 |  * accompanied this code). | 
 |  * | 
 |  * You should have received a copy of the GNU General Public License version | 
 |  * 2 along with this work; if not, write to the Free Software Foundation, | 
 |  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
 |  * | 
 |  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
 |  * or visit www.oracle.com if you need additional information or have any | 
 |  * questions. | 
 |  */ | 
 |  | 
 | package java.net; | 
 |  | 
 | import java.io.IOException; | 
 | import java.io.InterruptedIOException; | 
 | import java.util.Enumeration; | 
 |  | 
 | /** | 
 |  * The multicast datagram socket class is useful for sending | 
 |  * and receiving IP multicast packets.  A MulticastSocket is | 
 |  * a (UDP) DatagramSocket, with additional capabilities for | 
 |  * joining "groups" of other multicast hosts on the internet. | 
 |  * <P> | 
 |  * A multicast group is specified by a class D IP address | 
 |  * and by a standard UDP port number. Class D IP addresses | 
 |  * are in the range <CODE>224.0.0.0</CODE> to <CODE>239.255.255.255</CODE>, | 
 |  * inclusive. The address 224.0.0.0 is reserved and should not be used. | 
 |  * <P> | 
 |  * One would join a multicast group by first creating a MulticastSocket | 
 |  * with the desired port, then invoking the | 
 |  * <CODE>joinGroup(InetAddress groupAddr)</CODE> | 
 |  * method: | 
 |  * <PRE> | 
 |  * // join a Multicast group and send the group salutations | 
 |  * ... | 
 |  * String msg = "Hello"; | 
 |  * InetAddress group = InetAddress.getByName("228.5.6.7"); | 
 |  * MulticastSocket s = new MulticastSocket(6789); | 
 |  * s.joinGroup(group); | 
 |  * DatagramPacket hi = new DatagramPacket(msg.getBytes(), msg.length(), | 
 |  *                             group, 6789); | 
 |  * s.send(hi); | 
 |  * // get their responses! | 
 |  * byte[] buf = new byte[1000]; | 
 |  * DatagramPacket recv = new DatagramPacket(buf, buf.length); | 
 |  * s.receive(recv); | 
 |  * ... | 
 |  * // OK, I'm done talking - leave the group... | 
 |  * s.leaveGroup(group); | 
 |  * </PRE> | 
 |  * | 
 |  * When one sends a message to a multicast group, <B>all</B> subscribing | 
 |  * recipients to that host and port receive the message (within the | 
 |  * time-to-live range of the packet, see below).  The socket needn't | 
 |  * be a member of the multicast group to send messages to it. | 
 |  * <P> | 
 |  * When a socket subscribes to a multicast group/port, it receives | 
 |  * datagrams sent by other hosts to the group/port, as do all other | 
 |  * members of the group and port.  A socket relinquishes membership | 
 |  * in a group by the leaveGroup(InetAddress addr) method.  <B> | 
 |  * Multiple MulticastSocket's</B> may subscribe to a multicast group | 
 |  * and port concurrently, and they will all receive group datagrams. | 
 |  * <P> | 
 |  * Currently applets are not allowed to use multicast sockets. | 
 |  * | 
 |  * @author Pavani Diwanji | 
 |  * @since  JDK1.1 | 
 |  */ | 
 | public | 
 | class MulticastSocket extends DatagramSocket { | 
 |  | 
 |     /** | 
 |      * Used on some platforms to record if an outgoing interface | 
 |      * has been set for this socket. | 
 |      */ | 
 |     private boolean interfaceSet; | 
 |  | 
 |     /** | 
 |      * Create a multicast socket. | 
 |      * | 
 |      * <p>If there is a security manager, | 
 |      * its <code>checkListen</code> method is first called | 
 |      * with 0 as its argument to ensure the operation is allowed. | 
 |      * This could result in a SecurityException. | 
 |      * <p> | 
 |      * When the socket is created the | 
 |      * {@link DatagramSocket#setReuseAddress(boolean)} method is | 
 |      * called to enable the SO_REUSEADDR socket option. | 
 |      * | 
 |      * @exception IOException if an I/O exception occurs | 
 |      * while creating the MulticastSocket | 
 |      * @exception  SecurityException  if a security manager exists and its | 
 |      *             <code>checkListen</code> method doesn't allow the operation. | 
 |      * @see SecurityManager#checkListen | 
 |      * @see java.net.DatagramSocket#setReuseAddress(boolean) | 
 |      */ | 
 |     public MulticastSocket() throws IOException { | 
 |         this(new InetSocketAddress(0)); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Create a multicast socket and bind it to a specific port. | 
 |      * | 
 |      * <p>If there is a security manager, | 
 |      * its <code>checkListen</code> method is first called | 
 |      * with the <code>port</code> argument | 
 |      * as its argument to ensure the operation is allowed. | 
 |      * This could result in a SecurityException. | 
 |      * <p> | 
 |      * When the socket is created the | 
 |      * {@link DatagramSocket#setReuseAddress(boolean)} method is | 
 |      * called to enable the SO_REUSEADDR socket option. | 
 |      * | 
 |      * @param port port to use | 
 |      * @exception IOException if an I/O exception occurs | 
 |      * while creating the MulticastSocket | 
 |      * @exception  SecurityException  if a security manager exists and its | 
 |      *             <code>checkListen</code> method doesn't allow the operation. | 
 |      * @see SecurityManager#checkListen | 
 |      * @see java.net.DatagramSocket#setReuseAddress(boolean) | 
 |      */ | 
 |     public MulticastSocket(int port) throws IOException { | 
 |         this(new InetSocketAddress(port)); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Create a MulticastSocket bound to the specified socket address. | 
 |      * <p> | 
 |      * Or, if the address is <code>null</code>, create an unbound socket. | 
 |      * <p> | 
 |      * <p>If there is a security manager, | 
 |      * its <code>checkListen</code> method is first called | 
 |      * with the SocketAddress port as its argument to ensure the operation is allowed. | 
 |      * This could result in a SecurityException. | 
 |      * <p> | 
 |      * When the socket is created the | 
 |      * {@link DatagramSocket#setReuseAddress(boolean)} method is | 
 |      * called to enable the SO_REUSEADDR socket option. | 
 |      * | 
 |      * @param bindaddr Socket address to bind to, or <code>null</code> for | 
 |      *                 an unbound socket. | 
 |      * @exception IOException if an I/O exception occurs | 
 |      * while creating the MulticastSocket | 
 |      * @exception  SecurityException  if a security manager exists and its | 
 |      *             <code>checkListen</code> method doesn't allow the operation. | 
 |      * @see SecurityManager#checkListen | 
 |      * @see java.net.DatagramSocket#setReuseAddress(boolean) | 
 |      * | 
 |      * @since 1.4 | 
 |      */ | 
 |     public MulticastSocket(SocketAddress bindaddr) throws IOException { | 
 |         super((SocketAddress) null); | 
 |  | 
 |         // Enable SO_REUSEADDR before binding | 
 |         setReuseAddress(true); | 
 |  | 
 |         if (bindaddr != null) { | 
 |             bind(bindaddr); | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * The lock on the socket's TTL. This is for set/getTTL and | 
 |      * send(packet,ttl). | 
 |      */ | 
 |     private Object ttlLock = new Object(); | 
 |  | 
 |     /** | 
 |      * The lock on the socket's interface - used by setInterface | 
 |      * and getInterface | 
 |      */ | 
 |     private Object infLock = new Object(); | 
 |  | 
 |     /** | 
 |      * The "last" interface set by setInterface on this MulticastSocket | 
 |      */ | 
 |     private InetAddress infAddress = null; | 
 |  | 
 |  | 
 |     /** | 
 |      * Set the default time-to-live for multicast packets sent out | 
 |      * on this <code>MulticastSocket</code> in order to control the | 
 |      * scope of the multicasts. | 
 |      * | 
 |      * <p>The ttl is an <b>unsigned</b> 8-bit quantity, and so <B>must</B> be | 
 |      * in the range <code> 0 <= ttl <= 0xFF </code>. | 
 |      * | 
 |      * @param ttl the time-to-live | 
 |      * @exception IOException if an I/O exception occurs | 
 |      * while setting the default time-to-live value | 
 |      * @deprecated use the setTimeToLive method instead, which uses | 
 |      * <b>int</b> instead of <b>byte</b> as the type for ttl. | 
 |      * @see #getTTL() | 
 |      */ | 
 |     @Deprecated | 
 |     public void setTTL(byte ttl) throws IOException { | 
 |         if (isClosed()) | 
 |             throw new SocketException("Socket is closed"); | 
 |         getImpl().setTTL(ttl); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Set the default time-to-live for multicast packets sent out | 
 |      * on this {@code MulticastSocket} in order to control the | 
 |      * scope of the multicasts. | 
 |      * | 
 |      * <P> The ttl <B>must</B> be in the range {@code  0 <= ttl <= | 
 |      * 255} or an {@code IllegalArgumentException} will be thrown. | 
 |      * Multicast packets sent with a TTL of {@code 0} are not transmitted | 
 |      * on the network but may be delivered locally. | 
 |      * | 
 |      * @param  ttl | 
 |      *         the time-to-live | 
 |      * | 
 |      * @throws  IOException | 
 |      *          if an I/O exception occurs while setting the | 
 |      *          default time-to-live value | 
 |      * | 
 |      * @see #getTimeToLive() | 
 |      */ | 
 |     public void setTimeToLive(int ttl) throws IOException { | 
 |         if (ttl < 0 || ttl > 255) { | 
 |             throw new IllegalArgumentException("ttl out of range"); | 
 |         } | 
 |         if (isClosed()) | 
 |             throw new SocketException("Socket is closed"); | 
 |         getImpl().setTimeToLive(ttl); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Get the default time-to-live for multicast packets sent out on | 
 |      * the socket. | 
 |      * | 
 |      * @exception IOException if an I/O exception occurs | 
 |      * while getting the default time-to-live value | 
 |      * @return the default time-to-live value | 
 |      * @deprecated use the getTimeToLive method instead, which returns | 
 |      * an <b>int</b> instead of a <b>byte</b>. | 
 |      * @see #setTTL(byte) | 
 |      */ | 
 |     @Deprecated | 
 |     public byte getTTL() throws IOException { | 
 |         if (isClosed()) | 
 |             throw new SocketException("Socket is closed"); | 
 |         return getImpl().getTTL(); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Get the default time-to-live for multicast packets sent out on | 
 |      * the socket. | 
 |      * @exception IOException if an I/O exception occurs while | 
 |      * getting the default time-to-live value | 
 |      * @return the default time-to-live value | 
 |      * @see #setTimeToLive(int) | 
 |      */ | 
 |     public int getTimeToLive() throws IOException { | 
 |         if (isClosed()) | 
 |             throw new SocketException("Socket is closed"); | 
 |         return getImpl().getTimeToLive(); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Joins a multicast group. Its behavior may be affected by | 
 |      * <code>setInterface</code> or <code>setNetworkInterface</code>. | 
 |      * | 
 |      * <p>If there is a security manager, this method first | 
 |      * calls its <code>checkMulticast</code> method | 
 |      * with the <code>mcastaddr</code> argument | 
 |      * as its argument. | 
 |      * | 
 |      * @param mcastaddr is the multicast address to join | 
 |      * | 
 |      * @exception IOException if there is an error joining | 
 |      * or when the address is not a multicast address. | 
 |      * @exception  SecurityException  if a security manager exists and its | 
 |      * <code>checkMulticast</code> method doesn't allow the join. | 
 |      * | 
 |      * @see SecurityManager#checkMulticast(InetAddress) | 
 |      */ | 
 |     public void joinGroup(InetAddress mcastaddr) throws IOException { | 
 |         if (isClosed()) { | 
 |             throw new SocketException("Socket is closed"); | 
 |         } | 
 |  | 
 |         checkAddress(mcastaddr, "joinGroup"); | 
 |         SecurityManager security = System.getSecurityManager(); | 
 |         if (security != null) { | 
 |             security.checkMulticast(mcastaddr); | 
 |         } | 
 |  | 
 |         if (!mcastaddr.isMulticastAddress()) { | 
 |             throw new SocketException("Not a multicast address"); | 
 |         } | 
 |  | 
 |         /** | 
 |          * required for some platforms where it's not possible to join | 
 |          * a group without setting the interface first. | 
 |          */ | 
 |         NetworkInterface defaultInterface = NetworkInterface.getDefault(); | 
 |  | 
 |         if (!interfaceSet && defaultInterface != null) { | 
 |             setNetworkInterface(defaultInterface); | 
 |         } | 
 |  | 
 |         getImpl().join(mcastaddr); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Leave a multicast group. Its behavior may be affected by | 
 |      * <code>setInterface</code> or <code>setNetworkInterface</code>. | 
 |      * | 
 |      * <p>If there is a security manager, this method first | 
 |      * calls its <code>checkMulticast</code> method | 
 |      * with the <code>mcastaddr</code> argument | 
 |      * as its argument. | 
 |      * | 
 |      * @param mcastaddr is the multicast address to leave | 
 |      * @exception IOException if there is an error leaving | 
 |      * or when the address is not a multicast address. | 
 |      * @exception  SecurityException  if a security manager exists and its | 
 |      * <code>checkMulticast</code> method doesn't allow the operation. | 
 |      * | 
 |      * @see SecurityManager#checkMulticast(InetAddress) | 
 |      */ | 
 |     public void leaveGroup(InetAddress mcastaddr) throws IOException { | 
 |         if (isClosed()) { | 
 |             throw new SocketException("Socket is closed"); | 
 |         } | 
 |  | 
 |         checkAddress(mcastaddr, "leaveGroup"); | 
 |         SecurityManager security = System.getSecurityManager(); | 
 |         if (security != null) { | 
 |             security.checkMulticast(mcastaddr); | 
 |         } | 
 |  | 
 |         if (!mcastaddr.isMulticastAddress()) { | 
 |             throw new SocketException("Not a multicast address"); | 
 |         } | 
 |  | 
 |         getImpl().leave(mcastaddr); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Joins the specified multicast group at the specified interface. | 
 |      * | 
 |      * <p>If there is a security manager, this method first | 
 |      * calls its <code>checkMulticast</code> method | 
 |      * with the <code>mcastaddr</code> argument | 
 |      * as its argument. | 
 |      * | 
 |      * @param mcastaddr is the multicast address to join | 
 |      * @param netIf specifies the local interface to receive multicast | 
 |      *        datagram packets, or <i>null</i> to defer to the interface set by | 
 |      *       {@link MulticastSocket#setInterface(InetAddress)} or | 
 |      *       {@link MulticastSocket#setNetworkInterface(NetworkInterface)} | 
 |      * | 
 |      * @exception IOException if there is an error joining | 
 |      * or when the address is not a multicast address. | 
 |      * @exception  SecurityException  if a security manager exists and its | 
 |      * <code>checkMulticast</code> method doesn't allow the join. | 
 |      * @throws  IllegalArgumentException if mcastaddr is null or is a | 
 |      *          SocketAddress subclass not supported by this socket | 
 |      * | 
 |      * @see SecurityManager#checkMulticast(InetAddress) | 
 |      * @since 1.4 | 
 |      */ | 
 |     public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) | 
 |         throws IOException { | 
 |         if (isClosed()) | 
 |             throw new SocketException("Socket is closed"); | 
 |  | 
 |         if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress)) | 
 |             throw new IllegalArgumentException("Unsupported address type"); | 
 |  | 
 |         if (oldImpl) | 
 |             throw new UnsupportedOperationException(); | 
 |  | 
 |         checkAddress(((InetSocketAddress)mcastaddr).getAddress(), "joinGroup"); | 
 |         SecurityManager security = System.getSecurityManager(); | 
 |         if (security != null) { | 
 |             security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress()); | 
 |         } | 
 |  | 
 |         if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) { | 
 |             throw new SocketException("Not a multicast address"); | 
 |         } | 
 |  | 
 |         getImpl().joinGroup(mcastaddr, netIf); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Leave a multicast group on a specified local interface. | 
 |      * | 
 |      * <p>If there is a security manager, this method first | 
 |      * calls its <code>checkMulticast</code> method | 
 |      * with the <code>mcastaddr</code> argument | 
 |      * as its argument. | 
 |      * | 
 |      * @param mcastaddr is the multicast address to leave | 
 |      * @param netIf specifies the local interface or <i>null</i> to defer | 
 |      *             to the interface set by | 
 |      *             {@link MulticastSocket#setInterface(InetAddress)} or | 
 |      *             {@link MulticastSocket#setNetworkInterface(NetworkInterface)} | 
 |      * @exception IOException if there is an error leaving | 
 |      * or when the address is not a multicast address. | 
 |      * @exception  SecurityException  if a security manager exists and its | 
 |      * <code>checkMulticast</code> method doesn't allow the operation. | 
 |      * @throws  IllegalArgumentException if mcastaddr is null or is a | 
 |      *          SocketAddress subclass not supported by this socket | 
 |      * | 
 |      * @see SecurityManager#checkMulticast(InetAddress) | 
 |      * @since 1.4 | 
 |      */ | 
 |     public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) | 
 |         throws IOException { | 
 |         if (isClosed()) | 
 |             throw new SocketException("Socket is closed"); | 
 |  | 
 |         if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress)) | 
 |             throw new IllegalArgumentException("Unsupported address type"); | 
 |  | 
 |         if (oldImpl) | 
 |             throw new UnsupportedOperationException(); | 
 |  | 
 |         checkAddress(((InetSocketAddress)mcastaddr).getAddress(), "leaveGroup"); | 
 |         SecurityManager security = System.getSecurityManager(); | 
 |         if (security != null) { | 
 |             security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress()); | 
 |         } | 
 |  | 
 |         if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) { | 
 |             throw new SocketException("Not a multicast address"); | 
 |         } | 
 |  | 
 |         getImpl().leaveGroup(mcastaddr, netIf); | 
 |      } | 
 |  | 
 |     /** | 
 |      * Set the multicast network interface used by methods | 
 |      * whose behavior would be affected by the value of the | 
 |      * network interface. Useful for multihomed hosts. | 
 |      * @param inf the InetAddress | 
 |      * @exception SocketException if there is an error in | 
 |      * the underlying protocol, such as a TCP error. | 
 |      * @see #getInterface() | 
 |      */ | 
 |     public void setInterface(InetAddress inf) throws SocketException { | 
 |         if (isClosed()) { | 
 |             throw new SocketException("Socket is closed"); | 
 |         } | 
 |         checkAddress(inf, "setInterface"); | 
 |         synchronized (infLock) { | 
 |             getImpl().setOption(SocketOptions.IP_MULTICAST_IF, inf); | 
 |             infAddress = inf; | 
 |             interfaceSet = true; | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Retrieve the address of the network interface used for | 
 |      * multicast packets. | 
 |      * | 
 |      * @return An <code>InetAddress</code> representing | 
 |      *  the address of the network interface used for | 
 |      *  multicast packets. | 
 |      * | 
 |      * @exception SocketException if there is an error in | 
 |      * the underlying protocol, such as a TCP error. | 
 |      * | 
 |      * @see #setInterface(java.net.InetAddress) | 
 |      */ | 
 |     public InetAddress getInterface() throws SocketException { | 
 |         if (isClosed()) { | 
 |             throw new SocketException("Socket is closed"); | 
 |         } | 
 |         synchronized (infLock) { | 
 |             InetAddress ia = | 
 |                 (InetAddress)getImpl().getOption(SocketOptions.IP_MULTICAST_IF); | 
 |  | 
 |             /** | 
 |              * No previous setInterface or interface can be | 
 |              * set using setNetworkInterface | 
 |              */ | 
 |             if (infAddress == null) { | 
 |                 return ia; | 
 |             } | 
 |  | 
 |             /** | 
 |              * Same interface set with setInterface? | 
 |              */ | 
 |             if (ia.equals(infAddress)) { | 
 |                 return ia; | 
 |             } | 
 |  | 
 |             /** | 
 |              * Different InetAddress from what we set with setInterface | 
 |              * so enumerate the current interface to see if the | 
 |              * address set by setInterface is bound to this interface. | 
 |              */ | 
 |             try { | 
 |                 NetworkInterface ni = NetworkInterface.getByInetAddress(ia); | 
 |                 Enumeration addrs = ni.getInetAddresses(); | 
 |                 while (addrs.hasMoreElements()) { | 
 |                     InetAddress addr = (InetAddress)(addrs.nextElement()); | 
 |                     if (addr.equals(infAddress)) { | 
 |                         return infAddress; | 
 |                     } | 
 |                 } | 
 |  | 
 |                 /** | 
 |                  * No match so reset infAddress to indicate that the | 
 |                  * interface has changed via means | 
 |                  */ | 
 |                 infAddress = null; | 
 |                 return ia; | 
 |             } catch (Exception e) { | 
 |                 return ia; | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Specify the network interface for outgoing multicast datagrams | 
 |      * sent on this socket. | 
 |      * | 
 |      * @param netIf the interface | 
 |      * @exception SocketException if there is an error in | 
 |      * the underlying protocol, such as a TCP error. | 
 |      * @see #getNetworkInterface() | 
 |      * @since 1.4 | 
 |      */ | 
 |     public void setNetworkInterface(NetworkInterface netIf) | 
 |         throws SocketException { | 
 |  | 
 |         synchronized (infLock) { | 
 |             getImpl().setOption(SocketOptions.IP_MULTICAST_IF2, netIf); | 
 |             infAddress = null; | 
 |             interfaceSet = true; | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Get the multicast network interface set. | 
 |      * | 
 |      * @exception SocketException if there is an error in | 
 |      * the underlying protocol, such as a TCP error. | 
 |      * @return the multicast <code>NetworkInterface</code> currently set | 
 |      * @see #setNetworkInterface(NetworkInterface) | 
 |      * @since 1.4 | 
 |      */ | 
 |     public NetworkInterface getNetworkInterface() throws SocketException { | 
 |         Integer niIndex | 
 |             = (Integer)getImpl().getOption(SocketOptions.IP_MULTICAST_IF2); | 
 |         if (niIndex == 0) { | 
 |             InetAddress[] addrs = new InetAddress[1]; | 
 |             addrs[0] = InetAddress.anyLocalAddress(); | 
 |             return new NetworkInterface(addrs[0].getHostName(), 0, addrs); | 
 |         } else { | 
 |             return NetworkInterface.getByIndex(niIndex); | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Disable/Enable local loopback of multicast datagrams | 
 |      * The option is used by the platform's networking code as a hint | 
 |      * for setting whether multicast data will be looped back to | 
 |      * the local socket. | 
 |      * | 
 |      * <p>Because this option is a hint, applications that want to | 
 |      * verify what loopback mode is set to should call | 
 |      * {@link #getLoopbackMode()} | 
 |      * @param disable <code>true</code> to disable the LoopbackMode | 
 |      * @throws SocketException if an error occurs while setting the value | 
 |      * @since 1.4 | 
 |      * @see #getLoopbackMode | 
 |      */ | 
 |     public void setLoopbackMode(boolean disable) throws SocketException { | 
 |         getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP, Boolean.valueOf(disable)); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Get the setting for local loopback of multicast datagrams. | 
 |      * | 
 |      * @throws SocketException  if an error occurs while getting the value | 
 |      * @return true if the LoopbackMode has been disabled | 
 |      * @since 1.4 | 
 |      * @see #setLoopbackMode | 
 |      */ | 
 |     public boolean getLoopbackMode() throws SocketException { | 
 |         return ((Boolean)getImpl().getOption(SocketOptions.IP_MULTICAST_LOOP)).booleanValue(); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Sends a datagram packet to the destination, with a TTL (time- | 
 |      * to-live) other than the default for the socket.  This method | 
 |      * need only be used in instances where a particular TTL is desired; | 
 |      * otherwise it is preferable to set a TTL once on the socket, and | 
 |      * use that default TTL for all packets.  This method does <B>not | 
 |      * </B> alter the default TTL for the socket. Its behavior may be | 
 |      * affected by <code>setInterface</code>. | 
 |      * | 
 |      * <p>If there is a security manager, this method first performs some | 
 |      * security checks. First, if <code>p.getAddress().isMulticastAddress()</code> | 
 |      * is true, this method calls the | 
 |      * security manager's <code>checkMulticast</code> method | 
 |      * with <code>p.getAddress()</code> and <code>ttl</code> as its arguments. | 
 |      * If the evaluation of that expression is false, | 
 |      * this method instead calls the security manager's | 
 |      * <code>checkConnect</code> method with arguments | 
 |      * <code>p.getAddress().getHostAddress()</code> and | 
 |      * <code>p.getPort()</code>. Each call to a security manager method | 
 |      * could result in a SecurityException if the operation is not allowed. | 
 |      * | 
 |      * @param p is the packet to be sent. The packet should contain | 
 |      * the destination multicast ip address and the data to be sent. | 
 |      * One does not need to be the member of the group to send | 
 |      * packets to a destination multicast address. | 
 |      * @param ttl optional time to live for multicast packet. | 
 |      * default ttl is 1. | 
 |      * | 
 |      * @exception IOException is raised if an error occurs i.e | 
 |      * error while setting ttl. | 
 |      * @exception  SecurityException  if a security manager exists and its | 
 |      *             <code>checkMulticast</code> or <code>checkConnect</code> | 
 |      *             method doesn't allow the send. | 
 |      * | 
 |      * @deprecated Use the following code or its equivalent instead: | 
 |      *  ...... | 
 |      *  int ttl = mcastSocket.getTimeToLive(); | 
 |      *  mcastSocket.setTimeToLive(newttl); | 
 |      *  mcastSocket.send(p); | 
 |      *  mcastSocket.setTimeToLive(ttl); | 
 |      *  ...... | 
 |      * | 
 |      * @see DatagramSocket#send | 
 |      * @see DatagramSocket#receive | 
 |      * @see SecurityManager#checkMulticast(java.net.InetAddress, byte) | 
 |      * @see SecurityManager#checkConnect | 
 |      */ | 
 |     @Deprecated | 
 |     public void send(DatagramPacket p, byte ttl) | 
 |         throws IOException { | 
 |             if (isClosed()) | 
 |                 throw new SocketException("Socket is closed"); | 
 |             checkAddress(p.getAddress(), "send"); | 
 |             synchronized(ttlLock) { | 
 |                 synchronized(p) { | 
 |                     if (connectState == ST_NOT_CONNECTED) { | 
 |                         // Security manager makes sure that the multicast address | 
 |                         // is allowed one and that the ttl used is less | 
 |                         // than the allowed maxttl. | 
 |                         SecurityManager security = System.getSecurityManager(); | 
 |                         if (security != null) { | 
 |                             if (p.getAddress().isMulticastAddress()) { | 
 |                                 security.checkMulticast(p.getAddress(), ttl); | 
 |                             } else { | 
 |                                 security.checkConnect(p.getAddress().getHostAddress(), | 
 |                                                       p.getPort()); | 
 |                             } | 
 |                         } | 
 |                     } else { | 
 |                         // we're connected | 
 |                         InetAddress packetAddress = null; | 
 |                         packetAddress = p.getAddress(); | 
 |                         if (packetAddress == null) { | 
 |                             p.setAddress(connectedAddress); | 
 |                             p.setPort(connectedPort); | 
 |                         } else if ((!packetAddress.equals(connectedAddress)) || | 
 |                                    p.getPort() != connectedPort) { | 
 |                             throw new SecurityException("connected address and packet address" + | 
 |                                                         " differ"); | 
 |                         } | 
 |                     } | 
 |                     byte dttl = getTTL(); | 
 |                     try { | 
 |                         if (ttl != dttl) { | 
 |                             // set the ttl | 
 |                             getImpl().setTTL(ttl); | 
 |                         } | 
 |                         // call the datagram method to send | 
 |                         getImpl().send(p); | 
 |                     } finally { | 
 |                         // set it back to default | 
 |                         if (ttl != dttl) { | 
 |                             getImpl().setTTL(dttl); | 
 |                         } | 
 |                     } | 
 |                 } // synch p | 
 |             }  //synch ttl | 
 |     } //method | 
 | } |