001/* MulticastSocket.java -- Class for using multicast sockets 002 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2007 003 Free Software Foundation, Inc. 004 005This file is part of GNU Classpath. 006 007GNU Classpath is free software; you can redistribute it and/or modify 008it under the terms of the GNU General Public License as published by 009the Free Software Foundation; either version 2, or (at your option) 010any later version. 011 012GNU Classpath is distributed in the hope that it will be useful, but 013WITHOUT ANY WARRANTY; without even the implied warranty of 014MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015General Public License for more details. 016 017You should have received a copy of the GNU General Public License 018along with GNU Classpath; see the file COPYING. If not, write to the 019Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02002110-1301 USA. 021 022Linking this library statically or dynamically with other modules is 023making a combined work based on this library. Thus, the terms and 024conditions of the GNU General Public License cover the whole 025combination. 026 027As a special exception, the copyright holders of this library give you 028permission to link this library with independent modules to produce an 029executable, regardless of the license terms of these independent 030modules, and to copy and distribute the resulting executable under 031terms of your choice, provided that you also meet, for each linked 032independent module, the terms and conditions of the license of that 033module. An independent module is a module which is not derived from 034or based on this library. If you modify this library, you may extend 035this exception to your version of the library, but you are not 036obligated to do so. If you do not wish to do so, delete this 037exception statement from your version. */ 038 039package java.net; 040 041import java.io.IOException; 042import java.util.Enumeration; 043 044 045/** 046 * Written using on-line Java Platform 1.2 API Specification, as well 047 * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). 048 * Status: Believed complete and correct. 049 */ 050/** 051 * This class models a multicast UDP socket. A multicast address is a 052 * class D internet address (one whose most significant bits are 1110). 053 * A multicast group consists of a multicast address and a well known 054 * port number. All members of the group listening on that address and 055 * port will receive all the broadcasts to the group. 056 * <p> 057 * Please note that applets are not allowed to use multicast sockets 058 * 059 * Written using on-line Java Platform 1.2 API Specification, as well 060 * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). 061 * Status: Believed complete and correct. 062 * 063 * @author Warren Levy (warrenl@cygnus.com) 064 * @author Aaron M. Renn (arenn@urbanophile.com) (Documentation comments) 065 * @since 1.1 066 * @date May 18, 1999. 067 */ 068public class MulticastSocket extends DatagramSocket 069{ 070 /** 071 * Create a MulticastSocket that this not bound to any address 072 * 073 * @exception IOException If an error occurs 074 * @exception SecurityException If a security manager exists and its 075 * checkListen method doesn't allow the operation 076 */ 077 public MulticastSocket() throws IOException 078 { 079 this(new InetSocketAddress(0)); 080 } 081 082 /** 083 * Create a multicast socket bound to the specified port 084 * 085 * @param port The port to bind to 086 * 087 * @exception IOException If an error occurs 088 * @exception SecurityException If a security manager exists and its 089 * checkListen method doesn't allow the operation 090 */ 091 public MulticastSocket(int port) throws IOException 092 { 093 this(new InetSocketAddress(port)); 094 } 095 096 /** 097 * Create a multicast socket bound to the specified SocketAddress. 098 * 099 * @param address The SocketAddress the multicast socket will be bound to 100 * 101 * @exception IOException If an error occurs 102 * @exception SecurityException If a security manager exists and its 103 * checkListen method doesn't allow the operation 104 * 105 * @since 1.4 106 */ 107 public MulticastSocket(SocketAddress address) throws IOException 108 { 109 super((SocketAddress) null); 110 setReuseAddress(true); 111 if (address != null) 112 bind(address); 113 } 114 115 /** 116 * Returns the interface being used for multicast packets 117 * 118 * @return The multicast interface 119 * 120 * @exception SocketException If an error occurs 121 */ 122 public InetAddress getInterface() throws SocketException 123 { 124 if (isClosed()) 125 throw new SocketException("socket is closed"); 126 127 return (InetAddress) getImpl().getOption(SocketOptions.IP_MULTICAST_IF); 128 } 129 130 /** 131 * Returns the current value of the "Time to Live" option. This is the 132 * number of hops a packet can make before it "expires". This method id 133 * deprecated. Use <code>getTimeToLive</code> instead. 134 * 135 * @return The TTL value 136 * 137 * @exception IOException If an error occurs 138 * 139 * @deprecated 1.2 Replaced by getTimeToLive() 140 * 141 * @see MulticastSocket#getTimeToLive() 142 */ 143 public byte getTTL() throws IOException 144 { 145 if (isClosed()) 146 throw new SocketException("socket is closed"); 147 148 // Use getTTL here rather than getTimeToLive in case we're using an impl 149 // other than the default PlainDatagramSocketImpl and it doesn't have 150 // getTimeToLive yet. 151 return getImpl().getTTL(); 152 } 153 154 /** 155 * Returns the current value of the "Time to Live" option. This is the 156 * number of hops a packet can make before it "expires". 157 * 158 * @return The TTL value 159 * 160 * @exception IOException If an error occurs 161 * 162 * @since 1.2 163 */ 164 public int getTimeToLive() throws IOException 165 { 166 if (isClosed()) 167 throw new SocketException("socket is closed"); 168 169 return getImpl().getTimeToLive(); 170 } 171 172 /** 173 * Sets the interface to use for sending multicast packets. 174 * 175 * @param addr The new interface to use. 176 * 177 * @exception SocketException If an error occurs. 178 * 179 * @since 1.4 180 */ 181 public void setInterface(InetAddress addr) throws SocketException 182 { 183 if (isClosed()) 184 throw new SocketException("socket is closed"); 185 186 getImpl().setOption(SocketOptions.IP_MULTICAST_IF, addr); 187 } 188 189 /** 190 * Sets the local network interface used to send multicast messages 191 * 192 * @param netIf The local network interface used to send multicast messages 193 * 194 * @exception SocketException If an error occurs 195 * 196 * @see MulticastSocket#getNetworkInterface() 197 * 198 * @since 1.4 199 */ 200 public void setNetworkInterface(NetworkInterface netIf) 201 throws SocketException 202 { 203 if (isClosed()) 204 throw new SocketException("socket is closed"); 205 206 InetAddress address; 207 if (netIf != null) 208 out: 209 { 210 Enumeration e = netIf.getInetAddresses(); 211 if (getLocalAddress() instanceof Inet4Address) 212 { 213 // Search for a IPv4 address. 214 while (e.hasMoreElements()) 215 { 216 address = (InetAddress) e.nextElement(); 217 if (address instanceof Inet4Address) 218 break out; 219 } 220 throw new SocketException("interface " + netIf.getName() + " has no IPv6 address"); 221 } 222 else if (getLocalAddress() instanceof Inet6Address) 223 { 224 // Search for a IPv6 address. 225 while (e.hasMoreElements()) 226 { 227 address = (InetAddress) e.nextElement(); 228 if (address instanceof Inet6Address) 229 break out; 230 } 231 throw new SocketException("interface " + netIf.getName() + " has no IPv6 address"); 232 } 233 else 234 throw new SocketException("interface " + netIf.getName() + " has no suitable IP address"); 235 } 236 else 237 address = InetAddress.ANY_IF; 238 239 240 getImpl().setOption(SocketOptions.IP_MULTICAST_IF, address); 241 } 242 243 /** 244 * Gets the local network interface which is used to send multicast messages 245 * 246 * @return The local network interface to send multicast messages 247 * 248 * @exception SocketException If an error occurs 249 * 250 * @see MulticastSocket#setNetworkInterface(NetworkInterface netIf) 251 * 252 * @since 1.4 253 */ 254 public NetworkInterface getNetworkInterface() throws SocketException 255 { 256 if (isClosed()) 257 throw new SocketException("socket is closed"); 258 259 InetAddress address = 260 (InetAddress) getImpl().getOption(SocketOptions.IP_MULTICAST_IF); 261 262 if (address.isAnyLocalAddress()) 263 return NetworkInterface.createAnyInterface(); 264 265 NetworkInterface netIf = NetworkInterface.getByInetAddress(address); 266 267 return netIf; 268 } 269 270 /** 271 * Disable/Enable local loopback of multicast packets. The option is used by 272 * the platform's networking code as a hint for setting whether multicast 273 * data will be looped back to the local socket. 274 * 275 * Because this option is a hint, applications that want to verify what 276 * loopback mode is set to should call #getLoopbackMode 277 * 278 * @param disable True to disable loopback mode 279 * 280 * @exception SocketException If an error occurs 281 * 282 * @since 1.4 283 */ 284 public void setLoopbackMode(boolean disable) throws SocketException 285 { 286 if (isClosed()) 287 throw new SocketException("socket is closed"); 288 289 getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP, 290 Boolean.valueOf(disable)); 291 } 292 293 /** 294 * Checks if local loopback mode is enabled 295 * 296 * @return true if loopback mode is enabled, false otherwise 297 * 298 * @exception SocketException If an error occurs 299 * 300 * @since 1.4 301 */ 302 public boolean getLoopbackMode() throws SocketException 303 { 304 if (isClosed()) 305 throw new SocketException("socket is closed"); 306 307 Object buf = getImpl().getOption(SocketOptions.IP_MULTICAST_LOOP); 308 309 if (buf instanceof Boolean) 310 return ((Boolean) buf).booleanValue(); 311 312 throw new SocketException("unexpected type"); 313 } 314 315 /** 316 * Sets the "Time to Live" value for a socket. The value must be between 317 * 1 and 255. 318 * 319 * @param ttl The new TTL value 320 * 321 * @exception IOException If an error occurs 322 * 323 * @deprecated 1.2 Replaced by <code>setTimeToLive</code> 324 * 325 * @see MulticastSocket#setTimeToLive(int ttl) 326 */ 327 public void setTTL(byte ttl) throws IOException 328 { 329 if (isClosed()) 330 throw new SocketException("socket is closed"); 331 332 // Use setTTL here rather than setTimeToLive in case we're using an impl 333 // other than the default PlainDatagramSocketImpl and it doesn't have 334 // setTimeToLive yet. 335 getImpl().setTTL(ttl); 336 } 337 338 /** 339 * Sets the "Time to Live" value for a socket. The value must be between 340 * 0 and 255, inclusive. 341 * 342 * @param ttl The new TTL value 343 * 344 * @exception IOException If an error occurs 345 * 346 * @since 1.2 347 */ 348 public void setTimeToLive(int ttl) throws IOException 349 { 350 if (isClosed()) 351 throw new SocketException("socket is closed"); 352 353 if (ttl < 0 || ttl > 255) 354 throw new IllegalArgumentException("Invalid ttl: " + ttl); 355 356 getImpl().setTimeToLive(ttl); 357 } 358 359 /** 360 * Joins the specified multicast group. 361 * 362 * @param mcastaddr The address of the group to join 363 * 364 * @exception IOException If an error occurs 365 * @exception SecurityException If a security manager exists and its 366 * checkMulticast method doesn't allow the operation 367 */ 368 public void joinGroup(InetAddress mcastaddr) throws IOException 369 { 370 if (isClosed()) 371 throw new SocketException("socket is closed"); 372 373 if (! mcastaddr.isMulticastAddress()) 374 throw new IOException("Not a Multicast address"); 375 376 SecurityManager s = System.getSecurityManager(); 377 if (s != null) 378 s.checkMulticast(mcastaddr); 379 380 getImpl().join(mcastaddr); 381 } 382 383 /** 384 * Leaves the specified multicast group 385 * 386 * @param mcastaddr The address of the group to leave 387 * 388 * @exception IOException If an error occurs 389 * @exception SecurityException If a security manager exists and its 390 * checkMulticast method doesn't allow the operation 391 */ 392 public void leaveGroup(InetAddress mcastaddr) throws IOException 393 { 394 if (isClosed()) 395 throw new SocketException("socket is closed"); 396 397 if (! mcastaddr.isMulticastAddress()) 398 throw new IOException("Not a Multicast address"); 399 400 SecurityManager s = System.getSecurityManager(); 401 if (s != null) 402 s.checkMulticast(mcastaddr); 403 404 getImpl().leave(mcastaddr); 405 } 406 407 /** 408 * Joins the specified mulitcast group on a specified interface. 409 * 410 * @param mcastaddr The multicast address to join 411 * @param netIf The local network interface to receive the multicast 412 * messages on or null to defer the interface set by #setInterface or 413 * #setNetworkInterface 414 * 415 * @exception IOException If an error occurs 416 * @exception IllegalArgumentException If address type is not supported 417 * @exception SecurityException If a security manager exists and its 418 * checkMulticast method doesn't allow the operation 419 * 420 * @see MulticastSocket#setInterface(InetAddress addr) 421 * @see MulticastSocket#setNetworkInterface(NetworkInterface netIf) 422 * 423 * @since 1.4 424 */ 425 public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) 426 throws IOException 427 { 428 if (isClosed()) 429 throw new SocketException("socket is closed"); 430 431 if (! (mcastaddr instanceof InetSocketAddress)) 432 throw new IllegalArgumentException("SocketAddress type not supported"); 433 434 InetSocketAddress tmp = (InetSocketAddress) mcastaddr; 435 436 if (! tmp.getAddress().isMulticastAddress()) 437 throw new IOException("Not a Multicast address"); 438 439 SecurityManager s = System.getSecurityManager(); 440 if (s != null) 441 s.checkMulticast(tmp.getAddress()); 442 443 getImpl().joinGroup(mcastaddr, netIf); 444 } 445 446 /** 447 * Leaves the specified mulitcast group on a specified interface. 448 * 449 * @param mcastaddr The multicast address to leave 450 * @param netIf The local networki interface or null to defer to the 451 * interface set by setInterface or setNetworkInterface 452 * 453 * @exception IOException If an error occurs 454 * @exception IllegalArgumentException If address type is not supported 455 * @exception SecurityException If a security manager exists and its 456 * checkMulticast method doesn't allow the operation 457 * 458 * @see MulticastSocket#setInterface(InetAddress addr) 459 * @see MulticastSocket#setNetworkInterface(NetworkInterface netIf) 460 * 461 * @since 1.4 462 */ 463 public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) 464 throws IOException 465 { 466 if (isClosed()) 467 throw new SocketException("socket is closed"); 468 469 InetSocketAddress tmp = (InetSocketAddress) mcastaddr; 470 471 if (! tmp.getAddress().isMulticastAddress()) 472 throw new IOException("Not a Multicast address"); 473 474 SecurityManager s = System.getSecurityManager(); 475 if (s != null) 476 s.checkMulticast(tmp.getAddress()); 477 478 getImpl().leaveGroup(mcastaddr, netIf); 479 } 480 481 /** 482 * Sends a packet of data to a multicast address with a TTL that is 483 * different from the default TTL on this socket. The default TTL for 484 * the socket is not changed. 485 * 486 * @param packet The packet of data to send 487 * @param ttl The TTL for this packet 488 * 489 * @exception IOException If an error occurs 490 * @exception SecurityException If a security manager exists and its 491 * checkConnect or checkMulticast method doesn't allow the operation 492 * 493 * @deprecated 494 */ 495 public synchronized void send(DatagramPacket packet, byte ttl) 496 throws IOException 497 { 498 if (isClosed()) 499 throw new SocketException("socket is closed"); 500 501 SecurityManager s = System.getSecurityManager(); 502 if (s != null) 503 { 504 InetAddress addr = packet.getAddress(); 505 if (addr.isMulticastAddress()) 506 s.checkPermission(new SocketPermission(addr.getHostName() 507 + packet.getPort(), 508 "accept,connect")); 509 else 510 s.checkConnect(addr.getHostAddress(), packet.getPort()); 511 } 512 513 int oldttl = getImpl().getTimeToLive(); 514 getImpl().setTimeToLive(((int) ttl) & 0xFF); 515 getImpl().send(packet); 516 getImpl().setTimeToLive(oldttl); 517 } 518}