1 /* 2 * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.net; 27 28 import java.io.IOException; 29 import java.util.Enumeration; 30 31 /** 32 * The multicast datagram socket class is useful for sending 33 * and receiving IP multicast packets. A MulticastSocket is 34 * a (UDP) DatagramSocket, with additional capabilities for 35 * joining "groups" of other multicast hosts on the internet. 36 * <P> 37 * A multicast group is specified by a class D IP address 38 * and by a standard UDP port number. Class D IP addresses 39 * are in the range <CODE>224.0.0.0</CODE> to <CODE>239.255.255.255</CODE>, 40 * inclusive. The address 224.0.0.0 is reserved and should not be used. 41 * <P> 42 * One would join a multicast group by first creating a MulticastSocket 43 * with the desired port, then invoking the 44 * <CODE>joinGroup(InetAddress groupAddr)</CODE> 45 * method: 46 * <PRE> 47 * // join a Multicast group and send the group salutations 48 * ... 49 * String msg = "Hello"; 50 * InetAddress group = InetAddress.getByName("228.5.6.7"); 51 * MulticastSocket s = new MulticastSocket(6789); 52 * s.joinGroup(group); 53 * DatagramPacket hi = new DatagramPacket(msg.getBytes(), msg.length(), 54 * group, 6789); 55 * s.send(hi); 56 * // get their responses! 57 * byte[] buf = new byte[1000]; 58 * DatagramPacket recv = new DatagramPacket(buf, buf.length); 59 * s.receive(recv); 60 * ... 61 * // OK, I'm done talking - leave the group... 62 * s.leaveGroup(group); 63 * </PRE> 64 * 65 * When one sends a message to a multicast group, <B>all</B> subscribing 66 * recipients to that host and port receive the message (within the 67 * time-to-live range of the packet, see below). The socket needn't 68 * be a member of the multicast group to send messages to it. 69 * <P> 70 * When a socket subscribes to a multicast group/port, it receives 71 * datagrams sent by other hosts to the group/port, as do all other 72 * members of the group and port. A socket relinquishes membership 73 * in a group by the leaveGroup(InetAddress addr) method. <B> 74 * Multiple MulticastSocket's</B> may subscribe to a multicast group 75 * and port concurrently, and they will all receive group datagrams. 76 * <P> 77 * Currently applets are not allowed to use multicast sockets. 78 * 79 * @author Pavani Diwanji 80 * @since JDK1.1 81 */ 82 public 83 class MulticastSocket extends DatagramSocket { 84 /** 85 * Create a multicast socket. 86 * 87 * <p>If there is a security manager, 88 * its <code>checkListen</code> method is first called 89 * with 0 as its argument to ensure the operation is allowed. 90 * This could result in a SecurityException. 91 * <p> 92 * When the socket is created the 93 * {@link DatagramSocket#setReuseAddress(boolean)} method is 94 * called to enable the SO_REUSEADDR socket option. 95 * 96 * @exception IOException if an I/O exception occurs 97 * while creating the MulticastSocket 98 * @exception SecurityException if a security manager exists and its 99 * <code>checkListen</code> method doesn't allow the operation. 100 * @see SecurityManager#checkListen 101 * @see java.net.DatagramSocket#setReuseAddress(boolean) 102 */ 103 public MulticastSocket() throws IOException { 104 this(new InetSocketAddress(0)); 105 } 106 107 /** 108 * Create a multicast socket and bind it to a specific port. 109 * 110 * <p>If there is a security manager, 111 * its <code>checkListen</code> method is first called 112 * with the <code>port</code> argument 113 * as its argument to ensure the operation is allowed. 114 * This could result in a SecurityException. 115 * <p> 116 * When the socket is created the 117 * {@link DatagramSocket#setReuseAddress(boolean)} method is 118 * called to enable the SO_REUSEADDR socket option. 119 * 120 * @param port port to use 121 * @exception IOException if an I/O exception occurs 122 * while creating the MulticastSocket 123 * @exception SecurityException if a security manager exists and its 124 * <code>checkListen</code> method doesn't allow the operation. 125 * @see SecurityManager#checkListen 126 * @see java.net.DatagramSocket#setReuseAddress(boolean) 127 */ 128 public MulticastSocket(int port) throws IOException { 129 this(new InetSocketAddress(port)); 130 } 131 132 /** 133 * Create a MulticastSocket bound to the specified socket address. 134 * <p> 135 * Or, if the address is <code>null</code>, create an unbound socket. 136 * <p> 137 * <p>If there is a security manager, 138 * its <code>checkListen</code> method is first called 139 * with the SocketAddress port as its argument to ensure the operation is allowed. 140 * This could result in a SecurityException. 141 * <p> 142 * When the socket is created the 143 * {@link DatagramSocket#setReuseAddress(boolean)} method is 144 * called to enable the SO_REUSEADDR socket option. 145 * 146 * @param bindaddr Socket address to bind to, or <code>null</code> for 147 * an unbound socket. 148 * @exception IOException if an I/O exception occurs 149 * while creating the MulticastSocket 150 * @exception SecurityException if a security manager exists and its 151 * <code>checkListen</code> method doesn't allow the operation. 152 * @see SecurityManager#checkListen 153 * @see java.net.DatagramSocket#setReuseAddress(boolean) 154 * 155 * @since 1.4 156 */ 157 public MulticastSocket(SocketAddress bindaddr) throws IOException { 158 super((SocketAddress) null); 159 160 // Enable SO_REUSEADDR before binding 161 setReuseAddress(true); 162 163 if (bindaddr != null) { 164 bind(bindaddr); 165 } 166 } 167 168 /** 169 * The lock on the socket's TTL. This is for set/getTTL and 170 * send(packet,ttl). 171 */ 172 private Object ttlLock = new Object(); 173 174 /** 175 * The lock on the socket's interface - used by setInterface 176 * and getInterface 177 */ 178 private Object infLock = new Object(); 179 180 /** 181 * The "last" interface set by setInterface on this MulticastSocket 182 */ 183 private InetAddress infAddress = null; 184 185 186 /** 187 * Set the default time-to-live for multicast packets sent out 188 * on this <code>MulticastSocket</code> in order to control the 189 * scope of the multicasts. 190 * 191 * <p>The ttl is an <b>unsigned</b> 8-bit quantity, and so <B>must</B> be 192 * in the range <code> 0 <= ttl <= 0xFF </code>. 193 * 194 * @param ttl the time-to-live 195 * @exception IOException if an I/O exception occurs 196 * while setting the default time-to-live value 197 * @deprecated use the setTimeToLive method instead, which uses 198 * <b>int</b> instead of <b>byte</b> as the type for ttl. 199 * @see #getTTL() 200 */ 201 @Deprecated 202 public void setTTL(byte ttl) throws IOException { 203 if (isClosed()) 204 throw new SocketException("Socket is closed"); 205 getImpl().setTTL(ttl); 206 } 207 208 /** 209 * Set the default time-to-live for multicast packets sent out 210 * on this {@code MulticastSocket} in order to control the 211 * scope of the multicasts. 212 * 213 * <P> The ttl <B>must</B> be in the range {@code 0 <= ttl <= 214 * 255} or an {@code IllegalArgumentException} will be thrown. 215 * 216 * @param ttl 217 * the time-to-live 218 * 219 * @throws IOException 220 * if an I/O exception occurs while setting the 221 * default time-to-live value 222 * 223 * @see #getTimeToLive() 224 */ 225 public void setTimeToLive(int ttl) throws IOException { 226 if (ttl < 0 || ttl > 255) { 227 throw new IllegalArgumentException("ttl out of range"); 228 } 229 if (isClosed()) 230 throw new SocketException("Socket is closed"); 231 getImpl().setTimeToLive(ttl); 232 } 233 234 /** 235 * Get the default time-to-live for multicast packets sent out on 236 * the socket. 237 * 238 * @exception IOException if an I/O exception occurs 239 * while getting the default time-to-live value 240 * @return the default time-to-live value 241 * @deprecated use the getTimeToLive method instead, which returns 242 * an <b>int</b> instead of a <b>byte</b>. 243 * @see #setTTL(byte) 244 */ 245 @Deprecated 246 public byte getTTL() throws IOException { 247 if (isClosed()) 248 throw new SocketException("Socket is closed"); 249 return getImpl().getTTL(); 250 } 251 252 /** 253 * Get the default time-to-live for multicast packets sent out on 254 * the socket. 255 * @exception IOException if an I/O exception occurs while 256 * getting the default time-to-live value 257 * @return the default time-to-live value 258 * @see #setTimeToLive(int) 259 */ 260 public int getTimeToLive() throws IOException { 261 if (isClosed()) 262 throw new SocketException("Socket is closed"); 263 return getImpl().getTimeToLive(); 264 } 265 266 /** 267 * Joins a multicast group. Its behavior may be affected by 268 * <code>setInterface</code> or <code>setNetworkInterface</code>. 269 * 270 * <p>If there is a security manager, this method first 271 * calls its <code>checkMulticast</code> method 272 * with the <code>mcastaddr</code> argument 273 * as its argument. 274 * 275 * @param mcastaddr is the multicast address to join 276 * 277 * @exception IOException if there is an error joining 278 * or when the address is not a multicast address. 279 * @exception SecurityException if a security manager exists and its 280 * <code>checkMulticast</code> method doesn't allow the join. 281 * 282 * @see SecurityManager#checkMulticast(InetAddress) 283 */ 284 public void joinGroup(InetAddress mcastaddr) throws IOException { 285 if (isClosed()) { 286 throw new SocketException("Socket is closed"); 287 } 288 289 checkAddress(mcastaddr, "joinGroup"); 290 SecurityManager security = System.getSecurityManager(); 291 if (security != null) { 292 security.checkMulticast(mcastaddr); 293 } 294 295 if (!mcastaddr.isMulticastAddress()) { 296 throw new SocketException("Not a multicast address"); 297 } 298 299 getImpl().join(mcastaddr); 300 } 301 302 /** 303 * Leave a multicast group. Its behavior may be affected by 304 * <code>setInterface</code> or <code>setNetworkInterface</code>. 305 * 306 * <p>If there is a security manager, this method first 307 * calls its <code>checkMulticast</code> method 308 * with the <code>mcastaddr</code> argument 309 * as its argument. 310 * 311 * @param mcastaddr is the multicast address to leave 312 * @exception IOException if there is an error leaving 313 * or when the address is not a multicast address. 314 * @exception SecurityException if a security manager exists and its 315 * <code>checkMulticast</code> method doesn't allow the operation. 316 * 317 * @see SecurityManager#checkMulticast(InetAddress) 318 */ 319 public void leaveGroup(InetAddress mcastaddr) throws IOException { 320 if (isClosed()) { 321 throw new SocketException("Socket is closed"); 322 } 323 324 checkAddress(mcastaddr, "leaveGroup"); 325 SecurityManager security = System.getSecurityManager(); 326 if (security != null) { 327 security.checkMulticast(mcastaddr); 328 } 329 330 if (!mcastaddr.isMulticastAddress()) { 331 throw new SocketException("Not a multicast address"); 332 } 333 334 getImpl().leave(mcastaddr); 335 } 336 337 /** 338 * Joins the specified multicast group at the specified interface. 339 * 340 * <p>If there is a security manager, this method first 341 * calls its <code>checkMulticast</code> method 342 * with the <code>mcastaddr</code> argument 343 * as its argument. 344 * 345 * @param mcastaddr is the multicast address to join 346 * @param netIf specifies the local interface to receive multicast 347 * datagram packets, or <i>null</i> to defer to the interface set by 348 * {@link MulticastSocket#setInterface(InetAddress)} or 349 * {@link MulticastSocket#setNetworkInterface(NetworkInterface)} 350 * 351 * @exception IOException if there is an error joining 352 * or when the address is not a multicast address. 353 * @exception SecurityException if a security manager exists and its 354 * <code>checkMulticast</code> method doesn't allow the join. 355 * @throws IllegalArgumentException if mcastaddr is null or is a 356 * SocketAddress subclass not supported by this socket 357 * 358 * @see SecurityManager#checkMulticast(InetAddress) 359 * @since 1.4 360 */ 361 public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) 362 throws IOException { 363 if (isClosed()) 364 throw new SocketException("Socket is closed"); 365 366 if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress)) 367 throw new IllegalArgumentException("Unsupported address type"); 368 369 if (oldImpl) 370 throw new UnsupportedOperationException(); 371 372 checkAddress(((InetSocketAddress)mcastaddr).getAddress(), "joinGroup"); 373 SecurityManager security = System.getSecurityManager(); 374 if (security != null) { 375 security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress()); 376 } 377 378 if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) { 379 throw new SocketException("Not a multicast address"); 380 } 381 382 getImpl().joinGroup(mcastaddr, netIf); 383 } 384 385 /** 386 * Leave a multicast group on a specified local interface. 387 * 388 * <p>If there is a security manager, this method first 389 * calls its <code>checkMulticast</code> method 390 * with the <code>mcastaddr</code> argument 391 * as its argument. 392 * 393 * @param mcastaddr is the multicast address to leave 394 * @param netIf specifies the local interface or <i>null</i> to defer 395 * to the interface set by 396 * {@link MulticastSocket#setInterface(InetAddress)} or 397 * {@link MulticastSocket#setNetworkInterface(NetworkInterface)} 398 * @exception IOException if there is an error leaving 399 * or when the address is not a multicast address. 400 * @exception SecurityException if a security manager exists and its 401 * <code>checkMulticast</code> method doesn't allow the operation. 402 * @throws IllegalArgumentException if mcastaddr is null or is a 403 * SocketAddress subclass not supported by this socket 404 * 405 * @see SecurityManager#checkMulticast(InetAddress) 406 * @since 1.4 407 */ 408 public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) 409 throws IOException { 410 if (isClosed()) 411 throw new SocketException("Socket is closed"); 412 413 if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress)) 414 throw new IllegalArgumentException("Unsupported address type"); 415 416 if (oldImpl) 417 throw new UnsupportedOperationException(); 418 419 checkAddress(((InetSocketAddress)mcastaddr).getAddress(), "leaveGroup"); 420 SecurityManager security = System.getSecurityManager(); 421 if (security != null) { 422 security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress()); 423 } 424 425 if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) { 426 throw new SocketException("Not a multicast address"); 427 } 428 429 getImpl().leaveGroup(mcastaddr, netIf); 430 } 431 432 /** 433 * Set the multicast network interface used by methods 434 * whose behavior would be affected by the value of the 435 * network interface. Useful for multihomed hosts. 436 * @param inf the InetAddress 437 * @exception SocketException if there is an error in 438 * the underlying protocol, such as a TCP error. 439 * @see #getInterface() 440 */ 441 public void setInterface(InetAddress inf) throws SocketException { 442 if (isClosed()) { 443 throw new SocketException("Socket is closed"); 444 } 445 checkAddress(inf, "setInterface"); 446 synchronized (infLock) { 447 getImpl().setOption(SocketOptions.IP_MULTICAST_IF, inf); 448 infAddress = inf; 449 } 450 } 451 452 /** 453 * Retrieve the address of the network interface used for 454 * multicast packets. 455 * 456 * @return An <code>InetAddress</code> representing 457 * the address of the network interface used for 458 * multicast packets. 459 * 460 * @exception SocketException if there is an error in 461 * the underlying protocol, such as a TCP error. 462 * 463 * @see #setInterface(java.net.InetAddress) 464 */ 465 public InetAddress getInterface() throws SocketException { 466 if (isClosed()) { 467 throw new SocketException("Socket is closed"); 468 } 469 synchronized (infLock) { 470 InetAddress ia = 471 (InetAddress)getImpl().getOption(SocketOptions.IP_MULTICAST_IF); 472 473 /** 474 * No previous setInterface or interface can be 475 * set using setNetworkInterface 476 */ 477 if (infAddress == null) { 478 return ia; 479 } 480 481 /** 482 * Same interface set with setInterface? 483 */ 484 if (ia.equals(infAddress)) { 485 return ia; 486 } 487 488 /** 489 * Different InetAddress from what we set with setInterface 490 * so enumerate the current interface to see if the 491 * address set by setInterface is bound to this interface. 492 */ 493 try { 494 NetworkInterface ni = NetworkInterface.getByInetAddress(ia); 495 Enumeration<InetAddress> addrs = ni.getInetAddresses(); 496 while (addrs.hasMoreElements()) { 497 InetAddress addr = addrs.nextElement(); 498 if (addr.equals(infAddress)) { 499 return infAddress; 500 } 501 } 502 503 /** 504 * No match so reset infAddress to indicate that the 505 * interface has changed via means 506 */ 507 infAddress = null; 508 return ia; 509 } catch (Exception e) { 510 return ia; 511 } 512 } 513 } 514 515 /** 516 * Specify the network interface for outgoing multicast datagrams 517 * sent on this socket. 518 * 519 * @param netIf the interface 520 * @exception SocketException if there is an error in 521 * the underlying protocol, such as a TCP error. 522 * @see #getNetworkInterface() 523 * @since 1.4 524 */ 525 public void setNetworkInterface(NetworkInterface netIf) 526 throws SocketException { 527 528 synchronized (infLock) { 529 getImpl().setOption(SocketOptions.IP_MULTICAST_IF2, netIf); 530 infAddress = null; 531 } 532 } 533 534 /** 535 * Get the multicast network interface set. 536 * 537 * @exception SocketException if there is an error in 538 * the underlying protocol, such as a TCP error. 539 * @return the multicast <code>NetworkInterface</code> currently set 540 * @see #setNetworkInterface(NetworkInterface) 541 * @since 1.4 542 */ 543 public NetworkInterface getNetworkInterface() throws SocketException { 544 NetworkInterface ni 545 = (NetworkInterface)getImpl().getOption(SocketOptions.IP_MULTICAST_IF2); 546 if ((ni.getIndex() == 0) || (ni.getIndex() == -1)) { 547 InetAddress[] addrs = new InetAddress[1]; 548 addrs[0] = InetAddress.anyLocalAddress(); 549 return new NetworkInterface(addrs[0].getHostName(), 0, addrs); 550 } else { 551 return ni; 552 } 553 } 554 555 /** 556 * Disable/Enable local loopback of multicast datagrams 557 * The option is used by the platform's networking code as a hint 558 * for setting whether multicast data will be looped back to 559 * the local socket. 560 * 561 * <p>Because this option is a hint, applications that want to 562 * verify what loopback mode is set to should call 563 * {@link #getLoopbackMode()} 564 * @param disable <code>true</code> to disable the LoopbackMode 565 * @throws SocketException if an error occurs while setting the value 566 * @since 1.4 567 * @see #getLoopbackMode 568 */ 569 public void setLoopbackMode(boolean disable) throws SocketException { 570 getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP, Boolean.valueOf(disable)); 571 } 572 573 /** 574 * Get the setting for local loopback of multicast datagrams. 575 * 576 * @throws SocketException if an error occurs while getting the value 577 * @return true if the LoopbackMode has been disabled 578 * @since 1.4 579 * @see #setLoopbackMode 580 */ 581 public boolean getLoopbackMode() throws SocketException { 582 return ((Boolean)getImpl().getOption(SocketOptions.IP_MULTICAST_LOOP)).booleanValue(); 583 } 584 585 /** 586 * Sends a datagram packet to the destination, with a TTL (time- 587 * to-live) other than the default for the socket. This method 588 * need only be used in instances where a particular TTL is desired; 589 * otherwise it is preferable to set a TTL once on the socket, and 590 * use that default TTL for all packets. This method does <B>not 591 * </B> alter the default TTL for the socket. Its behavior may be 592 * affected by <code>setInterface</code>. 593 * 594 * <p>If there is a security manager, this method first performs some 595 * security checks. First, if <code>p.getAddress().isMulticastAddress()</code> 596 * is true, this method calls the 597 * security manager's <code>checkMulticast</code> method 598 * with <code>p.getAddress()</code> and <code>ttl</code> as its arguments. 599 * If the evaluation of that expression is false, 600 * this method instead calls the security manager's 601 * <code>checkConnect</code> method with arguments 602 * <code>p.getAddress().getHostAddress()</code> and 603 * <code>p.getPort()</code>. Each call to a security manager method 604 * could result in a SecurityException if the operation is not allowed. 605 * 606 * @param p is the packet to be sent. The packet should contain 607 * the destination multicast ip address and the data to be sent. 608 * One does not need to be the member of the group to send 609 * packets to a destination multicast address. 610 * @param ttl optional time to live for multicast packet. 611 * default ttl is 1. 612 * 613 * @exception IOException is raised if an error occurs i.e 614 * error while setting ttl. 615 * @exception SecurityException if a security manager exists and its 616 * <code>checkMulticast</code> or <code>checkConnect</code> 617 * method doesn't allow the send. 618 * 619 * @deprecated Use the following code or its equivalent instead: 620 * ...... 621 * int ttl = mcastSocket.getTimeToLive(); 622 * mcastSocket.setTimeToLive(newttl); 623 * mcastSocket.send(p); 624 * mcastSocket.setTimeToLive(ttl); 625 * ...... 626 * 627 * @see DatagramSocket#send 628 * @see DatagramSocket#receive 629 * @see SecurityManager#checkMulticast(java.net.InetAddress, byte) 630 * @see SecurityManager#checkConnect 631 */ 632 @Deprecated 633 public void send(DatagramPacket p, byte ttl) 634 throws IOException { 635 if (isClosed()) 636 throw new SocketException("Socket is closed"); 637 checkAddress(p.getAddress(), "send"); 638 synchronized(ttlLock) { 639 synchronized(p) { 640 if (connectState == ST_NOT_CONNECTED) { 641 // Security manager makes sure that the multicast address 642 // is allowed one and that the ttl used is less 643 // than the allowed maxttl. 644 SecurityManager security = System.getSecurityManager(); 645 if (security != null) { 646 if (p.getAddress().isMulticastAddress()) { 647 security.checkMulticast(p.getAddress(), ttl); 648 } else { 649 security.checkConnect(p.getAddress().getHostAddress(), 650 p.getPort()); 651 } 652 } 653 } else { 654 // we're connected 655 InetAddress packetAddress = null; 656 packetAddress = p.getAddress(); 657 if (packetAddress == null) { 658 p.setAddress(connectedAddress); 659 p.setPort(connectedPort); 660 } else if ((!packetAddress.equals(connectedAddress)) || 661 p.getPort() != connectedPort) { 662 throw new SecurityException("connected address and packet address" + 663 " differ"); 664 } 665 } 666 byte dttl = getTTL(); 667 try { 668 if (ttl != dttl) { 669 // set the ttl 670 getImpl().setTTL(ttl); 671 } 672 // call the datagram method to send 673 getImpl().send(p); 674 } finally { 675 // set it back to default 676 if (ttl != dttl) { 677 getImpl().setTTL(dttl); 678 } 679 } 680 } // synch p 681 } //synch ttl 682 } //method 683 }