1 /* MulticastSocket.java -- Class for using multicast sockets 2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2007 3 Free Software Foundation, Inc. 4 5 This file is part of GNU Classpath. 6 7 GNU Classpath is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2, or (at your option) 10 any later version. 11 12 GNU Classpath is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with GNU Classpath; see the file COPYING. If not, write to the 19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20 02110-1301 USA. 21 22 Linking this library statically or dynamically with other modules is 23 making a combined work based on this library. Thus, the terms and 24 conditions of the GNU General Public License cover the whole 25 combination. 26 27 As a special exception, the copyright holders of this library give you 28 permission to link this library with independent modules to produce an 29 executable, regardless of the license terms of these independent 30 modules, and to copy and distribute the resulting executable under 31 terms of your choice, provided that you also meet, for each linked 32 independent module, the terms and conditions of the license of that 33 module. An independent module is a module which is not derived from 34 or based on this library. If you modify this library, you may extend 35 this exception to your version of the library, but you are not 36 obligated to do so. If you do not wish to do so, delete this 37 exception statement from your version. */ 38 39 package java.net; 40 41 import java.io.IOException; 42 import java.util.Enumeration; 43 44 45 /** 46 * Written using on-line Java Platform 1.2 API Specification, as well 47 * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). 48 * Status: Believed complete and correct. 49 */ 50 /** 51 * This class models a multicast UDP socket. A multicast address is a 52 * class D internet address (one whose most significant bits are 1110). 53 * A multicast group consists of a multicast address and a well known 54 * port number. All members of the group listening on that address and 55 * port will receive all the broadcasts to the group. 56 * <p> 57 * Please note that applets are not allowed to use multicast sockets 58 * 59 * Written using on-line Java Platform 1.2 API Specification, as well 60 * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). 61 * Status: Believed complete and correct. 62 * 63 * @author Warren Levy (warrenl@cygnus.com) 64 * @author Aaron M. Renn (arenn@urbanophile.com) (Documentation comments) 65 * @since 1.1 66 * @date May 18, 1999. 67 */ 68 public class MulticastSocket extends DatagramSocket 69 { 70 /** 71 * Create a MulticastSocket that this not bound to any address 72 * 73 * @exception IOException If an error occurs 74 * @exception SecurityException If a security manager exists and its 75 * checkListen method doesn't allow the operation 76 */ MulticastSocket()77 public MulticastSocket() throws IOException 78 { 79 this(new InetSocketAddress(0)); 80 } 81 82 /** 83 * Create a multicast socket bound to the specified port 84 * 85 * @param port The port to bind to 86 * 87 * @exception IOException If an error occurs 88 * @exception SecurityException If a security manager exists and its 89 * checkListen method doesn't allow the operation 90 */ MulticastSocket(int port)91 public MulticastSocket(int port) throws IOException 92 { 93 this(new InetSocketAddress(port)); 94 } 95 96 /** 97 * Create a multicast socket bound to the specified SocketAddress. 98 * 99 * @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 */ MulticastSocket(SocketAddress address)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 */ getInterface()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 */ getTTL()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 */ getTimeToLive()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 */ setInterface(InetAddress addr)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 */ setNetworkInterface(NetworkInterface netIf)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 */ getNetworkInterface()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 */ setLoopbackMode(boolean disable)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 */ getLoopbackMode()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 */ setTTL(byte ttl)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 */ setTimeToLive(int ttl)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 */ joinGroup(InetAddress mcastaddr)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 */ leaveGroup(InetAddress mcastaddr)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 */ joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)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 */ leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)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 */ send(DatagramPacket packet, byte ttl)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 } 519