001 /* MulticastSocket.java -- Class for using multicast sockets 002 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2007 003 Free Software Foundation, Inc. 004 005 This file is part of GNU Classpath. 006 007 GNU Classpath is free software; you can redistribute it and/or modify 008 it under the terms of the GNU General Public License as published by 009 the Free Software Foundation; either version 2, or (at your option) 010 any later version. 011 012 GNU Classpath is distributed in the hope that it will be useful, but 013 WITHOUT ANY WARRANTY; without even the implied warranty of 014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 General Public License for more details. 016 017 You should have received a copy of the GNU General Public License 018 along with GNU Classpath; see the file COPYING. If not, write to the 019 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 020 02110-1301 USA. 021 022 Linking this library statically or dynamically with other modules is 023 making a combined work based on this library. Thus, the terms and 024 conditions of the GNU General Public License cover the whole 025 combination. 026 027 As a special exception, the copyright holders of this library give you 028 permission to link this library with independent modules to produce an 029 executable, regardless of the license terms of these independent 030 modules, and to copy and distribute the resulting executable under 031 terms of your choice, provided that you also meet, for each linked 032 independent module, the terms and conditions of the license of that 033 module. An independent module is a module which is not derived from 034 or based on this library. If you modify this library, you may extend 035 this exception to your version of the library, but you are not 036 obligated to do so. If you do not wish to do so, delete this 037 exception statement from your version. */ 038 039 package java.net; 040 041 import java.io.IOException; 042 import 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 */ 068 public 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 // FIXME: libgcj doesn't have createAnyInterface. 263 // if (address.isAnyLocalAddress()) 264 // return NetworkInterface.createAnyInterface(); 265 266 NetworkInterface netIf = NetworkInterface.getByInetAddress(address); 267 268 return netIf; 269 } 270 271 /** 272 * Disable/Enable local loopback of multicast packets. The option is used by 273 * the platform's networking code as a hint for setting whether multicast 274 * data will be looped back to the local socket. 275 * 276 * Because this option is a hint, applications that want to verify what 277 * loopback mode is set to should call #getLoopbackMode 278 * 279 * @param disable True to disable loopback mode 280 * 281 * @exception SocketException If an error occurs 282 * 283 * @since 1.4 284 */ 285 public void setLoopbackMode(boolean disable) throws SocketException 286 { 287 if (isClosed()) 288 throw new SocketException("socket is closed"); 289 290 getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP, 291 Boolean.valueOf(disable)); 292 } 293 294 /** 295 * Checks if local loopback mode is enabled 296 * 297 * @return true if loopback mode is enabled, false otherwise 298 * 299 * @exception SocketException If an error occurs 300 * 301 * @since 1.4 302 */ 303 public boolean getLoopbackMode() throws SocketException 304 { 305 if (isClosed()) 306 throw new SocketException("socket is closed"); 307 308 Object buf = getImpl().getOption(SocketOptions.IP_MULTICAST_LOOP); 309 310 if (buf instanceof Boolean) 311 return ((Boolean) buf).booleanValue(); 312 313 throw new SocketException("unexpected type"); 314 } 315 316 /** 317 * Sets the "Time to Live" value for a socket. The value must be between 318 * 1 and 255. 319 * 320 * @param ttl The new TTL value 321 * 322 * @exception IOException If an error occurs 323 * 324 * @deprecated 1.2 Replaced by <code>setTimeToLive</code> 325 * 326 * @see MulticastSocket#setTimeToLive(int ttl) 327 */ 328 public void setTTL(byte ttl) throws IOException 329 { 330 if (isClosed()) 331 throw new SocketException("socket is closed"); 332 333 // Use setTTL here rather than setTimeToLive in case we're using an impl 334 // other than the default PlainDatagramSocketImpl and it doesn't have 335 // setTimeToLive yet. 336 getImpl().setTTL(ttl); 337 } 338 339 /** 340 * Sets the "Time to Live" value for a socket. The value must be between 341 * 0 and 255, inclusive. 342 * 343 * @param ttl The new TTL value 344 * 345 * @exception IOException If an error occurs 346 * 347 * @since 1.2 348 */ 349 public void setTimeToLive(int ttl) throws IOException 350 { 351 if (isClosed()) 352 throw new SocketException("socket is closed"); 353 354 if (ttl < 0 || ttl > 255) 355 throw new IllegalArgumentException("Invalid ttl: " + ttl); 356 357 getImpl().setTimeToLive(ttl); 358 } 359 360 /** 361 * Joins the specified multicast group. 362 * 363 * @param mcastaddr The address of the group to join 364 * 365 * @exception IOException If an error occurs 366 * @exception SecurityException If a security manager exists and its 367 * checkMulticast method doesn't allow the operation 368 */ 369 public void joinGroup(InetAddress mcastaddr) throws IOException 370 { 371 if (isClosed()) 372 throw new SocketException("socket is closed"); 373 374 if (! mcastaddr.isMulticastAddress()) 375 throw new IOException("Not a Multicast address"); 376 377 SecurityManager s = System.getSecurityManager(); 378 if (s != null) 379 s.checkMulticast(mcastaddr); 380 381 getImpl().join(mcastaddr); 382 } 383 384 /** 385 * Leaves the specified multicast group 386 * 387 * @param mcastaddr The address of the group to leave 388 * 389 * @exception IOException If an error occurs 390 * @exception SecurityException If a security manager exists and its 391 * checkMulticast method doesn't allow the operation 392 */ 393 public void leaveGroup(InetAddress mcastaddr) throws IOException 394 { 395 if (isClosed()) 396 throw new SocketException("socket is closed"); 397 398 if (! mcastaddr.isMulticastAddress()) 399 throw new IOException("Not a Multicast address"); 400 401 SecurityManager s = System.getSecurityManager(); 402 if (s != null) 403 s.checkMulticast(mcastaddr); 404 405 getImpl().leave(mcastaddr); 406 } 407 408 /** 409 * Joins the specified mulitcast group on a specified interface. 410 * 411 * @param mcastaddr The multicast address to join 412 * @param netIf The local network interface to receive the multicast 413 * messages on or null to defer the interface set by #setInterface or 414 * #setNetworkInterface 415 * 416 * @exception IOException If an error occurs 417 * @exception IllegalArgumentException If address type is not supported 418 * @exception SecurityException If a security manager exists and its 419 * checkMulticast method doesn't allow the operation 420 * 421 * @see MulticastSocket#setInterface(InetAddress addr) 422 * @see MulticastSocket#setNetworkInterface(NetworkInterface netIf) 423 * 424 * @since 1.4 425 */ 426 public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) 427 throws IOException 428 { 429 if (isClosed()) 430 throw new SocketException("socket is closed"); 431 432 if (! (mcastaddr instanceof InetSocketAddress)) 433 throw new IllegalArgumentException("SocketAddress type not supported"); 434 435 InetSocketAddress tmp = (InetSocketAddress) mcastaddr; 436 437 if (! tmp.getAddress().isMulticastAddress()) 438 throw new IOException("Not a Multicast address"); 439 440 SecurityManager s = System.getSecurityManager(); 441 if (s != null) 442 s.checkMulticast(tmp.getAddress()); 443 444 getImpl().joinGroup(mcastaddr, netIf); 445 } 446 447 /** 448 * Leaves the specified mulitcast group on a specified interface. 449 * 450 * @param mcastaddr The multicast address to leave 451 * @param netIf The local networki interface or null to defer to the 452 * interface set by setInterface or setNetworkInterface 453 * 454 * @exception IOException If an error occurs 455 * @exception IllegalArgumentException If address type is not supported 456 * @exception SecurityException If a security manager exists and its 457 * checkMulticast method doesn't allow the operation 458 * 459 * @see MulticastSocket#setInterface(InetAddress addr) 460 * @see MulticastSocket#setNetworkInterface(NetworkInterface netIf) 461 * 462 * @since 1.4 463 */ 464 public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) 465 throws IOException 466 { 467 if (isClosed()) 468 throw new SocketException("socket is closed"); 469 470 InetSocketAddress tmp = (InetSocketAddress) mcastaddr; 471 472 if (! tmp.getAddress().isMulticastAddress()) 473 throw new IOException("Not a Multicast address"); 474 475 SecurityManager s = System.getSecurityManager(); 476 if (s != null) 477 s.checkMulticast(tmp.getAddress()); 478 479 getImpl().leaveGroup(mcastaddr, netIf); 480 } 481 482 /** 483 * Sends a packet of data to a multicast address with a TTL that is 484 * different from the default TTL on this socket. The default TTL for 485 * the socket is not changed. 486 * 487 * @param packet The packet of data to send 488 * @param ttl The TTL for this packet 489 * 490 * @exception IOException If an error occurs 491 * @exception SecurityException If a security manager exists and its 492 * checkConnect or checkMulticast method doesn't allow the operation 493 * 494 * @deprecated 495 */ 496 public synchronized void send(DatagramPacket packet, byte ttl) 497 throws IOException 498 { 499 if (isClosed()) 500 throw new SocketException("socket is closed"); 501 502 SecurityManager s = System.getSecurityManager(); 503 if (s != null) 504 { 505 InetAddress addr = packet.getAddress(); 506 if (addr.isMulticastAddress()) 507 s.checkPermission(new SocketPermission(addr.getHostName() 508 + packet.getPort(), 509 "accept,connect")); 510 else 511 s.checkConnect(addr.getHostAddress(), packet.getPort()); 512 } 513 514 int oldttl = getImpl().getTimeToLive(); 515 getImpl().setTimeToLive(((int) ttl) & 0xFF); 516 getImpl().send(packet); 517 getImpl().setTimeToLive(oldttl); 518 } 519 }