|  | /* MulticastSocket.java -- Class for using multicast sockets | 
|  | Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2007 | 
|  | Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of GNU Classpath. | 
|  |  | 
|  | GNU Classpath is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 2, or (at your option) | 
|  | any later version. | 
|  |  | 
|  | GNU Classpath 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 for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with GNU Classpath; see the file COPYING.  If not, write to the | 
|  | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | 
|  | 02110-1301 USA. | 
|  |  | 
|  | Linking this library statically or dynamically with other modules is | 
|  | making a combined work based on this library.  Thus, the terms and | 
|  | conditions of the GNU General Public License cover the whole | 
|  | combination. | 
|  |  | 
|  | As a special exception, the copyright holders of this library give you | 
|  | permission to link this library with independent modules to produce an | 
|  | executable, regardless of the license terms of these independent | 
|  | modules, and to copy and distribute the resulting executable under | 
|  | terms of your choice, provided that you also meet, for each linked | 
|  | independent module, the terms and conditions of the license of that | 
|  | module.  An independent module is a module which is not derived from | 
|  | or based on this library.  If you modify this library, you may extend | 
|  | this exception to your version of the library, but you are not | 
|  | obligated to do so.  If you do not wish to do so, delete this | 
|  | exception statement from your version. */ | 
|  |  | 
|  | package java.net; | 
|  |  | 
|  | import java.io.IOException; | 
|  | import java.util.Enumeration; | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Written using on-line Java Platform 1.2 API Specification, as well | 
|  | * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). | 
|  | * Status:  Believed complete and correct. | 
|  | */ | 
|  | /** | 
|  | * This class models a multicast UDP socket.  A multicast address is a | 
|  | * class D internet address (one whose most significant bits are 1110). | 
|  | * A multicast group consists of a multicast address and a well known | 
|  | * port number.  All members of the group listening on that address and | 
|  | * port will receive all the broadcasts to the group. | 
|  | * <p> | 
|  | * Please note that applets are not allowed to use multicast sockets | 
|  | * | 
|  | * Written using on-line Java Platform 1.2 API Specification, as well | 
|  | * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). | 
|  | * Status:  Believed complete and correct. | 
|  | * | 
|  | * @author Warren Levy (warrenl@cygnus.com) | 
|  | * @author Aaron M. Renn (arenn@urbanophile.com) (Documentation comments) | 
|  | * @since 1.1 | 
|  | * @date May 18, 1999. | 
|  | */ | 
|  | public class MulticastSocket extends DatagramSocket | 
|  | { | 
|  | /** | 
|  | * Create a MulticastSocket that this not bound to any address | 
|  | * | 
|  | * @exception IOException If an error occurs | 
|  | * @exception SecurityException If a security manager exists and its | 
|  | * checkListen method doesn't allow the operation | 
|  | */ | 
|  | public MulticastSocket() throws IOException | 
|  | { | 
|  | this(new InetSocketAddress(0)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Create a multicast socket bound to the specified port | 
|  | * | 
|  | * @param port The port to bind to | 
|  | * | 
|  | * @exception IOException If an error occurs | 
|  | * @exception SecurityException If a security manager exists and its | 
|  | * checkListen method doesn't allow the operation | 
|  | */ | 
|  | public MulticastSocket(int port) throws IOException | 
|  | { | 
|  | this(new InetSocketAddress(port)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Create a multicast socket bound to the specified SocketAddress. | 
|  | * | 
|  | * @param address The SocketAddress the multicast socket will be bound to | 
|  | * | 
|  | * @exception IOException If an error occurs | 
|  | * @exception SecurityException If a security manager exists and its | 
|  | * checkListen method doesn't allow the operation | 
|  | * | 
|  | * @since 1.4 | 
|  | */ | 
|  | public MulticastSocket(SocketAddress address) throws IOException | 
|  | { | 
|  | super((SocketAddress) null); | 
|  | setReuseAddress(true); | 
|  | if (address != null) | 
|  | bind(address); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the interface being used for multicast packets | 
|  | * | 
|  | * @return The multicast interface | 
|  | * | 
|  | * @exception SocketException If an error occurs | 
|  | */ | 
|  | public InetAddress getInterface() throws SocketException | 
|  | { | 
|  | if (isClosed()) | 
|  | throw new SocketException("socket is closed"); | 
|  |  | 
|  | return (InetAddress) getImpl().getOption(SocketOptions.IP_MULTICAST_IF); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the current value of the "Time to Live" option.  This is the | 
|  | * number of hops a packet can make before it "expires".   This method id | 
|  | * deprecated.  Use <code>getTimeToLive</code> instead. | 
|  | * | 
|  | * @return The TTL value | 
|  | * | 
|  | * @exception IOException If an error occurs | 
|  | * | 
|  | * @deprecated 1.2 Replaced by getTimeToLive() | 
|  | * | 
|  | * @see MulticastSocket#getTimeToLive() | 
|  | */ | 
|  | public byte getTTL() throws IOException | 
|  | { | 
|  | if (isClosed()) | 
|  | throw new SocketException("socket is closed"); | 
|  |  | 
|  | // Use getTTL here rather than getTimeToLive in case we're using an impl | 
|  | // other than the default PlainDatagramSocketImpl and it doesn't have | 
|  | // getTimeToLive yet. | 
|  | return getImpl().getTTL(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the current value of the "Time to Live" option.  This is the | 
|  | * number of hops a packet can make before it "expires". | 
|  | * | 
|  | * @return The TTL value | 
|  | * | 
|  | * @exception IOException If an error occurs | 
|  | * | 
|  | * @since 1.2 | 
|  | */ | 
|  | public int getTimeToLive() throws IOException | 
|  | { | 
|  | if (isClosed()) | 
|  | throw new SocketException("socket is closed"); | 
|  |  | 
|  | return getImpl().getTimeToLive(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the interface to use for sending multicast packets. | 
|  | * | 
|  | * @param addr The new interface to use. | 
|  | * | 
|  | * @exception SocketException If an error occurs. | 
|  | * | 
|  | * @since 1.4 | 
|  | */ | 
|  | public void setInterface(InetAddress addr) throws SocketException | 
|  | { | 
|  | if (isClosed()) | 
|  | throw new SocketException("socket is closed"); | 
|  |  | 
|  | getImpl().setOption(SocketOptions.IP_MULTICAST_IF, addr); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the local network interface used to send multicast messages | 
|  | * | 
|  | * @param netIf The local network interface used to send multicast messages | 
|  | * | 
|  | * @exception SocketException If an error occurs | 
|  | * | 
|  | * @see MulticastSocket#getNetworkInterface() | 
|  | * | 
|  | * @since 1.4 | 
|  | */ | 
|  | public void setNetworkInterface(NetworkInterface netIf) | 
|  | throws SocketException | 
|  | { | 
|  | if (isClosed()) | 
|  | throw new SocketException("socket is closed"); | 
|  |  | 
|  | InetAddress address; | 
|  | if (netIf != null) | 
|  | out: | 
|  | { | 
|  | Enumeration e = netIf.getInetAddresses(); | 
|  | if (getLocalAddress() instanceof Inet4Address) | 
|  | { | 
|  | // Search for a IPv4 address. | 
|  | while (e.hasMoreElements()) | 
|  | { | 
|  | address = (InetAddress) e.nextElement(); | 
|  | if (address instanceof Inet4Address) | 
|  | break out; | 
|  | } | 
|  | throw new SocketException("interface " + netIf.getName() + " has no IPv6 address"); | 
|  | } | 
|  | else if (getLocalAddress() instanceof Inet6Address) | 
|  | { | 
|  | // Search for a IPv6 address. | 
|  | while (e.hasMoreElements()) | 
|  | { | 
|  | address = (InetAddress) e.nextElement(); | 
|  | if (address instanceof Inet6Address) | 
|  | break out; | 
|  | } | 
|  | throw new SocketException("interface " + netIf.getName() + " has no IPv6 address"); | 
|  | } | 
|  | else | 
|  | throw new SocketException("interface " + netIf.getName() + " has no suitable IP address"); | 
|  | } | 
|  | else | 
|  | address = InetAddress.ANY_IF; | 
|  |  | 
|  |  | 
|  | getImpl().setOption(SocketOptions.IP_MULTICAST_IF, address); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets the local network interface which is used to send multicast messages | 
|  | * | 
|  | * @return The local network interface to send multicast messages | 
|  | * | 
|  | * @exception SocketException If an error occurs | 
|  | * | 
|  | * @see MulticastSocket#setNetworkInterface(NetworkInterface netIf) | 
|  | * | 
|  | * @since 1.4 | 
|  | */ | 
|  | public NetworkInterface getNetworkInterface() throws SocketException | 
|  | { | 
|  | if (isClosed()) | 
|  | throw new SocketException("socket is closed"); | 
|  |  | 
|  | InetAddress address = | 
|  | (InetAddress) getImpl().getOption(SocketOptions.IP_MULTICAST_IF); | 
|  |  | 
|  | if (address.isAnyLocalAddress()) | 
|  | return NetworkInterface.createAnyInterface(); | 
|  |  | 
|  | NetworkInterface netIf = NetworkInterface.getByInetAddress(address); | 
|  |  | 
|  | return netIf; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Disable/Enable local loopback of multicast packets.  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. | 
|  | * | 
|  | * Because this option is a hint, applications that want to verify what | 
|  | * loopback mode is set to should call #getLoopbackMode | 
|  | * | 
|  | * @param disable True to disable loopback mode | 
|  | * | 
|  | * @exception SocketException If an error occurs | 
|  | * | 
|  | * @since 1.4 | 
|  | */ | 
|  | public void setLoopbackMode(boolean disable) throws SocketException | 
|  | { | 
|  | if (isClosed()) | 
|  | throw new SocketException("socket is closed"); | 
|  |  | 
|  | getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP, | 
|  | Boolean.valueOf(disable)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Checks if local loopback mode is enabled | 
|  | * | 
|  | * @return true if loopback mode is enabled, false otherwise | 
|  | * | 
|  | * @exception SocketException If an error occurs | 
|  | * | 
|  | * @since 1.4 | 
|  | */ | 
|  | public boolean getLoopbackMode() throws SocketException | 
|  | { | 
|  | if (isClosed()) | 
|  | throw new SocketException("socket is closed"); | 
|  |  | 
|  | Object buf = getImpl().getOption(SocketOptions.IP_MULTICAST_LOOP); | 
|  |  | 
|  | if (buf instanceof Boolean) | 
|  | return ((Boolean) buf).booleanValue(); | 
|  |  | 
|  | throw new SocketException("unexpected type"); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the "Time to Live" value for a socket.  The value must be between | 
|  | * 1 and 255. | 
|  | * | 
|  | * @param ttl The new TTL value | 
|  | * | 
|  | * @exception IOException If an error occurs | 
|  | * | 
|  | * @deprecated 1.2 Replaced by <code>setTimeToLive</code> | 
|  | * | 
|  | * @see MulticastSocket#setTimeToLive(int ttl) | 
|  | */ | 
|  | public void setTTL(byte ttl) throws IOException | 
|  | { | 
|  | if (isClosed()) | 
|  | throw new SocketException("socket is closed"); | 
|  |  | 
|  | // Use setTTL here rather than setTimeToLive in case we're using an impl | 
|  | // other than the default PlainDatagramSocketImpl and it doesn't have | 
|  | // setTimeToLive yet. | 
|  | getImpl().setTTL(ttl); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the "Time to Live" value for a socket.  The value must be between | 
|  | * 0 and 255, inclusive. | 
|  | * | 
|  | * @param ttl The new TTL value | 
|  | * | 
|  | * @exception IOException If an error occurs | 
|  | * | 
|  | * @since 1.2 | 
|  | */ | 
|  | public void setTimeToLive(int ttl) throws IOException | 
|  | { | 
|  | if (isClosed()) | 
|  | throw new SocketException("socket is closed"); | 
|  |  | 
|  | if (ttl < 0 || ttl > 255) | 
|  | throw new IllegalArgumentException("Invalid ttl: " + ttl); | 
|  |  | 
|  | getImpl().setTimeToLive(ttl); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Joins the specified multicast group. | 
|  | * | 
|  | * @param mcastaddr The address of the group to join | 
|  | * | 
|  | * @exception IOException If an error occurs | 
|  | * @exception SecurityException If a security manager exists and its | 
|  | * checkMulticast method doesn't allow the operation | 
|  | */ | 
|  | public void joinGroup(InetAddress mcastaddr) throws IOException | 
|  | { | 
|  | if (isClosed()) | 
|  | throw new SocketException("socket is closed"); | 
|  |  | 
|  | if (! mcastaddr.isMulticastAddress()) | 
|  | throw new IOException("Not a Multicast address"); | 
|  |  | 
|  | SecurityManager s = System.getSecurityManager(); | 
|  | if (s != null) | 
|  | s.checkMulticast(mcastaddr); | 
|  |  | 
|  | getImpl().join(mcastaddr); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Leaves the specified multicast group | 
|  | * | 
|  | * @param mcastaddr The address of the group to leave | 
|  | * | 
|  | * @exception IOException If an error occurs | 
|  | * @exception SecurityException If a security manager exists and its | 
|  | * checkMulticast method doesn't allow the operation | 
|  | */ | 
|  | public void leaveGroup(InetAddress mcastaddr) throws IOException | 
|  | { | 
|  | if (isClosed()) | 
|  | throw new SocketException("socket is closed"); | 
|  |  | 
|  | if (! mcastaddr.isMulticastAddress()) | 
|  | throw new IOException("Not a Multicast address"); | 
|  |  | 
|  | SecurityManager s = System.getSecurityManager(); | 
|  | if (s != null) | 
|  | s.checkMulticast(mcastaddr); | 
|  |  | 
|  | getImpl().leave(mcastaddr); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Joins the specified mulitcast group on a specified interface. | 
|  | * | 
|  | * @param mcastaddr The multicast address to join | 
|  | * @param netIf The local network interface to receive the multicast | 
|  | * messages on or null to defer the interface set by #setInterface or | 
|  | * #setNetworkInterface | 
|  | * | 
|  | * @exception IOException If an error occurs | 
|  | * @exception IllegalArgumentException If address type is not supported | 
|  | * @exception SecurityException If a security manager exists and its | 
|  | * checkMulticast method doesn't allow the operation | 
|  | * | 
|  | * @see MulticastSocket#setInterface(InetAddress addr) | 
|  | * @see MulticastSocket#setNetworkInterface(NetworkInterface netIf) | 
|  | * | 
|  | * @since 1.4 | 
|  | */ | 
|  | public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) | 
|  | throws IOException | 
|  | { | 
|  | if (isClosed()) | 
|  | throw new SocketException("socket is closed"); | 
|  |  | 
|  | if (! (mcastaddr instanceof InetSocketAddress)) | 
|  | throw new IllegalArgumentException("SocketAddress type not supported"); | 
|  |  | 
|  | InetSocketAddress tmp = (InetSocketAddress) mcastaddr; | 
|  |  | 
|  | if (! tmp.getAddress().isMulticastAddress()) | 
|  | throw new IOException("Not a Multicast address"); | 
|  |  | 
|  | SecurityManager s = System.getSecurityManager(); | 
|  | if (s != null) | 
|  | s.checkMulticast(tmp.getAddress()); | 
|  |  | 
|  | getImpl().joinGroup(mcastaddr, netIf); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Leaves the specified mulitcast group on a specified interface. | 
|  | * | 
|  | * @param mcastaddr The multicast address to leave | 
|  | * @param netIf The local networki interface or null to defer to the | 
|  | * interface set by setInterface or setNetworkInterface | 
|  | * | 
|  | * @exception IOException If an error occurs | 
|  | * @exception IllegalArgumentException If address type is not supported | 
|  | * @exception SecurityException If a security manager exists and its | 
|  | * checkMulticast method doesn't allow the operation | 
|  | * | 
|  | * @see MulticastSocket#setInterface(InetAddress addr) | 
|  | * @see MulticastSocket#setNetworkInterface(NetworkInterface netIf) | 
|  | * | 
|  | * @since 1.4 | 
|  | */ | 
|  | public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) | 
|  | throws IOException | 
|  | { | 
|  | if (isClosed()) | 
|  | throw new SocketException("socket is closed"); | 
|  |  | 
|  | InetSocketAddress tmp = (InetSocketAddress) mcastaddr; | 
|  |  | 
|  | if (! tmp.getAddress().isMulticastAddress()) | 
|  | throw new IOException("Not a Multicast address"); | 
|  |  | 
|  | SecurityManager s = System.getSecurityManager(); | 
|  | if (s != null) | 
|  | s.checkMulticast(tmp.getAddress()); | 
|  |  | 
|  | getImpl().leaveGroup(mcastaddr, netIf); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sends a packet of data to a multicast address with a TTL that is | 
|  | * different from the default TTL on this socket.  The default TTL for | 
|  | * the socket is not changed. | 
|  | * | 
|  | * @param packet The packet of data to send | 
|  | * @param ttl The TTL for this packet | 
|  | * | 
|  | * @exception IOException If an error occurs | 
|  | * @exception SecurityException If a security manager exists and its | 
|  | * checkConnect or checkMulticast method doesn't allow the operation | 
|  | * | 
|  | * @deprecated | 
|  | */ | 
|  | public synchronized void send(DatagramPacket packet, byte ttl) | 
|  | throws IOException | 
|  | { | 
|  | if (isClosed()) | 
|  | throw new SocketException("socket is closed"); | 
|  |  | 
|  | SecurityManager s = System.getSecurityManager(); | 
|  | if (s != null) | 
|  | { | 
|  | InetAddress addr = packet.getAddress(); | 
|  | if (addr.isMulticastAddress()) | 
|  | s.checkPermission(new SocketPermission(addr.getHostName() | 
|  | + packet.getPort(), | 
|  | "accept,connect")); | 
|  | else | 
|  | s.checkConnect(addr.getHostAddress(), packet.getPort()); | 
|  | } | 
|  |  | 
|  | int oldttl = getImpl().getTimeToLive(); | 
|  | getImpl().setTimeToLive(((int) ttl) & 0xFF); | 
|  | getImpl().send(packet); | 
|  | getImpl().setTimeToLive(oldttl); | 
|  | } | 
|  | } |