1 /* 2 * Copyright (c) 1995, 2019, 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.Collections; 30 import java.util.Enumeration; 31 import java.util.Set; 32 import java.net.PortUnreachableException; 33 34 /** 35 * The multicast datagram socket class is useful for sending 36 * and receiving IP multicast packets. A MulticastSocket is 37 * a (UDP) DatagramSocket, with additional capabilities for 38 * joining "groups" of other multicast hosts on the internet. 39 * <P> 40 * A multicast group is specified by a class D IP address 41 * and by a standard UDP port number. Class D IP addresses 42 * are in the range <CODE>224.0.0.0</CODE> to <CODE>239.255.255.255</CODE>, 43 * inclusive. The address 224.0.0.0 is reserved and should not be used. 44 * <P> 45 * One would join a multicast group by first creating a MulticastSocket 46 * with the desired port, then invoking the 47 * <CODE>joinGroup(InetAddress groupAddr)</CODE> 48 * method: 49 * <PRE> 50 * // join a Multicast group and send the group salutations 51 * ... 52 * String msg = "Hello"; 53 * InetAddress group = InetAddress.getByName("228.5.6.7"); 54 * MulticastSocket s = new MulticastSocket(6789); 55 * s.joinGroup(group); 56 * byte[] msgBytes = msg.getBytes(StandardCharsets.UTF_8); 57 * DatagramPacket hi = new DatagramPacket(msgBytes, msgBytes.length, 58 * group, 6789); 59 * s.send(hi); 60 * // get their responses! 61 * byte[] buf = new byte[1000]; 62 * DatagramPacket recv = new DatagramPacket(buf, buf.length); 63 * s.receive(recv); 64 * ... 65 * // OK, I'm done talking - leave the group... 66 * s.leaveGroup(group); 67 * </PRE> 68 * 69 * When one sends a message to a multicast group, <B>all</B> subscribing 70 * recipients to that host and port receive the message (within the 71 * time-to-live range of the packet, see below). The socket needn't 72 * be a member of the multicast group to send messages to it. 73 * <P> 74 * When a socket subscribes to a multicast group/port, it receives 75 * datagrams sent by other hosts to the group/port, as do all other 76 * members of the group and port. A socket relinquishes membership 77 * in a group by the leaveGroup(InetAddress addr) method. <B> 78 * Multiple MulticastSocket's</B> may subscribe to a multicast group 79 * and port concurrently, and they will all receive group datagrams. 80 * <P> 81 * 82 * <p> The {@code DatagramSocket} and {@code MulticastSocket} classes offer 83 * some convenience methods (such as {@link DatagramSocket#setReuseAddress(boolean) 84 * setReuseAddress}) to get and set some commonly used options. However, socket 85 * options can be more generally configured using the 86 * {@link #setOption(SocketOption, Object) setOption} method. 87 * In addition to the socket options supported by 88 * <a href="DatagramSocket.html#SocketOptions">{@code DatagramSocket}</a>, a 89 * {@code MulticastSocket} supports the following socket options: 90 * <blockquote> 91 * <a id="MulticastOptions"></a> 92 * <table class="striped"> 93 * <caption style="display:none">Socket options</caption> 94 * <thead> 95 * <tr> 96 * <th scope="col">Option Name</th> 97 * <th scope="col">Description</th> 98 * </tr> 99 * </thead> 100 * <tbody> 101 * <tr> 102 * <th scope="row"> {@link java.net.StandardSocketOptions#IP_MULTICAST_IF IP_MULTICAST_IF} </th> 103 * <td> The network interface for Internet Protocol (IP) multicast datagrams </td> 104 * </tr> 105 * <tr> 106 * <th scope="row"> {@link java.net.StandardSocketOptions#IP_MULTICAST_TTL 107 * IP_MULTICAST_TTL} </th> 108 * <td> The <em>time-to-live</em> for Internet Protocol (IP) multicast 109 * datagrams </td> 110 * </tr> 111 * <tr> 112 * <th scope="row"> {@link java.net.StandardSocketOptions#IP_MULTICAST_LOOP 113 * IP_MULTICAST_LOOP} </th> 114 * <td> Loopback for Internet Protocol (IP) multicast datagrams </td> 115 * </tr> 116 * </tbody> 117 * </table> 118 * </blockquote> 119 * Additional (implementation specific) options may also be supported. 120 * 121 * @author Pavani Diwanji 122 * @since 1.1 123 */ 124 public class MulticastSocket extends DatagramSocket { 125 126 /** 127 * Used on some platforms to record if an outgoing interface 128 * has been set for this socket. 129 */ 130 private boolean interfaceSet; 131 132 /** 133 * Create a multicast socket. 134 * 135 * <p> 136 * If there is a security manager, its {@code checkListen} method is first 137 * called with 0 as its argument to ensure the operation is allowed. This 138 * could result in a SecurityException. 139 * <p> 140 * When the socket is created the 141 * {@link DatagramSocket#setReuseAddress(boolean)} method is called to 142 * enable the SO_REUSEADDR socket option. 143 * 144 * @throws IOException if an I/O exception occurs while creating the 145 * MulticastSocket 146 * @throws SecurityException if a security manager exists and its 147 * {@code checkListen} method doesn't allow the operation. 148 * @see SecurityManager#checkListen 149 * @see java.net.DatagramSocket#setReuseAddress(boolean) 150 * @see java.net.DatagramSocketImpl#setOption(SocketOption, Object) 151 */ 152 public MulticastSocket() throws IOException { 153 this(new InetSocketAddress(0)); 154 } 155 156 /** 157 * Create a multicast socket and bind it to a specific port. 158 * 159 * <p>If there is a security manager, 160 * its {@code checkListen} method is first called 161 * with the {@code port} argument 162 * as its argument to ensure the operation is allowed. 163 * This could result in a SecurityException. 164 * <p> 165 * When the socket is created the 166 * {@link DatagramSocket#setReuseAddress(boolean)} method is 167 * called to enable the SO_REUSEADDR socket option. 168 * 169 * @param port port to use 170 * @throws IOException if an I/O exception occurs 171 * while creating the MulticastSocket 172 * @throws SecurityException if a security manager exists and its 173 * {@code checkListen} method doesn't allow the operation. 174 * @see SecurityManager#checkListen 175 * @see java.net.DatagramSocket#setReuseAddress(boolean) 176 */ 177 public MulticastSocket(int port) throws IOException { 178 this(new InetSocketAddress(port)); 179 } 180 181 /** 182 * Create a MulticastSocket bound to the specified socket address. 183 * <p> 184 * Or, if the address is {@code null}, create an unbound socket. 185 * 186 * <p>If there is a security manager, 187 * its {@code checkListen} method is first called 188 * with the SocketAddress port as its argument to ensure the operation is allowed. 189 * This could result in a SecurityException. 190 * <p> 191 * When the socket is created the 192 * {@link DatagramSocket#setReuseAddress(boolean)} method is 193 * called to enable the SO_REUSEADDR socket option. 194 * 195 * @param bindaddr Socket address to bind to, or {@code null} for 196 * an unbound socket. 197 * @throws IOException if an I/O exception occurs 198 * while creating the MulticastSocket 199 * @throws SecurityException if a security manager exists and its 200 * {@code checkListen} method doesn't allow the operation. 201 * @see SecurityManager#checkListen 202 * @see java.net.DatagramSocket#setReuseAddress(boolean) 203 * 204 * @since 1.4 205 */ 206 public MulticastSocket(SocketAddress bindaddr) throws IOException { 207 super((SocketAddress) null); 208 209 // Enable SO_REUSEADDR before binding 210 setReuseAddress(true); 211 212 if (bindaddr != null) { 213 try { 214 bind(bindaddr); 215 } finally { 216 if (!isBound()) { 217 close(); 218 } 219 } 220 } 221 } 222 223 /** 224 * The lock on the socket's TTL. This is for set/getTTL and 225 * send(packet,ttl). 226 */ 227 private Object ttlLock = new Object(); 228 229 /** 230 * The lock on the socket's interface - used by setInterface 231 * and getInterface 232 */ 233 private Object infLock = new Object(); 234 235 /** 236 * The "last" interface set by setInterface on this MulticastSocket 237 */ 238 private InetAddress infAddress = null; 239 240 241 /** 242 * Set the default time-to-live for multicast packets sent out 243 * on this {@code MulticastSocket} in order to control the 244 * scope of the multicasts. 245 * 246 * <p>The ttl is an <b>unsigned</b> 8-bit quantity, and so <B>must</B> be 247 * in the range {@code 0 <= ttl <= 0xFF }. 248 * 249 * @param ttl the time-to-live 250 * @throws IOException if an I/O exception occurs 251 * while setting the default time-to-live value 252 * @deprecated use the setTimeToLive method instead, which uses 253 * <b>int</b> instead of <b>byte</b> as the type for ttl. 254 * @see #getTTL() 255 */ 256 @Deprecated 257 public void setTTL(byte ttl) throws IOException { 258 if (isClosed()) 259 throw new SocketException("Socket is closed"); 260 getImpl().setTTL(ttl); 261 } 262 263 /** 264 * Set the default time-to-live for multicast packets sent out 265 * on this {@code MulticastSocket} in order to control the 266 * scope of the multicasts. 267 * 268 * <P> The ttl <B>must</B> be in the range {@code 0 <= ttl <= 269 * 255} or an {@code IllegalArgumentException} will be thrown. 270 * Multicast packets sent with a TTL of {@code 0} are not transmitted 271 * on the network but may be delivered locally. 272 * 273 * @param ttl 274 * the time-to-live 275 * 276 * @throws IOException 277 * if an I/O exception occurs while setting the 278 * default time-to-live value 279 * 280 * @see #getTimeToLive() 281 */ 282 public void setTimeToLive(int ttl) throws IOException { 283 if (ttl < 0 || ttl > 255) { 284 throw new IllegalArgumentException("ttl out of range"); 285 } 286 if (isClosed()) 287 throw new SocketException("Socket is closed"); 288 getImpl().setTimeToLive(ttl); 289 } 290 291 /** 292 * Get the default time-to-live for multicast packets sent out on 293 * the socket. 294 * 295 * @throws IOException if an I/O exception occurs 296 * while getting the default time-to-live value 297 * @return the default time-to-live value 298 * @deprecated use the getTimeToLive method instead, which returns 299 * an <b>int</b> instead of a <b>byte</b>. 300 * @see #setTTL(byte) 301 */ 302 @Deprecated 303 public byte getTTL() throws IOException { 304 if (isClosed()) 305 throw new SocketException("Socket is closed"); 306 return getImpl().getTTL(); 307 } 308 309 /** 310 * Get the default time-to-live for multicast packets sent out on 311 * the socket. 312 * @throws IOException if an I/O exception occurs while 313 * getting the default time-to-live value 314 * @return the default time-to-live value 315 * @see #setTimeToLive(int) 316 */ 317 public int getTimeToLive() throws IOException { 318 if (isClosed()) 319 throw new SocketException("Socket is closed"); 320 return getImpl().getTimeToLive(); 321 } 322 323 /** 324 * Joins a multicast group. Its behavior may be affected by 325 * {@code setInterface} or {@code setNetworkInterface}. 326 * 327 * <p>If there is a security manager, this method first 328 * calls its {@code checkMulticast} method 329 * with the {@code mcastaddr} argument 330 * as its argument. 331 * 332 * @param mcastaddr is the multicast address to join 333 * 334 * @throws IOException if there is an error joining, or when the address 335 * is not a multicast address, or the platform does not support 336 * multicasting 337 * @throws SecurityException if a security manager exists and its 338 * {@code checkMulticast} method doesn't allow the join. 339 * 340 * @see SecurityManager#checkMulticast(InetAddress) 341 */ 342 public void joinGroup(InetAddress mcastaddr) throws IOException { 343 if (isClosed()) { 344 throw new SocketException("Socket is closed"); 345 } 346 347 checkAddress(mcastaddr, "joinGroup"); 348 SecurityManager security = System.getSecurityManager(); 349 if (security != null) { 350 security.checkMulticast(mcastaddr); 351 } 352 353 if (!mcastaddr.isMulticastAddress()) { 354 throw new SocketException("Not a multicast address"); 355 } 356 357 /** 358 * required for some platforms where it's not possible to join 359 * a group without setting the interface first. 360 */ 361 NetworkInterface defaultInterface = NetworkInterface.getDefault(); 362 363 if (!interfaceSet && defaultInterface != null) { 364 setNetworkInterface(defaultInterface); 365 } 366 367 getImpl().join(mcastaddr); 368 } 369 370 /** 371 * Leave a multicast group. Its behavior may be affected by 372 * {@code setInterface} or {@code setNetworkInterface}. 373 * 374 * <p>If there is a security manager, this method first 375 * calls its {@code checkMulticast} method 376 * with the {@code mcastaddr} argument 377 * as its argument. 378 * 379 * @param mcastaddr is the multicast address to leave 380 * @throws IOException if there is an error leaving 381 * or when the address is not a multicast address. 382 * @throws SecurityException if a security manager exists and its 383 * {@code checkMulticast} method doesn't allow the operation. 384 * 385 * @see SecurityManager#checkMulticast(InetAddress) 386 */ 387 public void leaveGroup(InetAddress mcastaddr) throws IOException { 388 if (isClosed()) { 389 throw new SocketException("Socket is closed"); 390 } 391 392 checkAddress(mcastaddr, "leaveGroup"); 393 SecurityManager security = System.getSecurityManager(); 394 if (security != null) { 395 security.checkMulticast(mcastaddr); 396 } 397 398 if (!mcastaddr.isMulticastAddress()) { 399 throw new SocketException("Not a multicast address"); 400 } 401 402 getImpl().leave(mcastaddr); 403 } 404 405 /** 406 * Joins the specified multicast group at the specified interface. 407 * 408 * <p>If there is a security manager, this method first 409 * calls its {@code checkMulticast} method 410 * with the {@code mcastaddr} argument 411 * as its argument. 412 * 413 * @param mcastaddr is the multicast address to join 414 * @param netIf specifies the local interface to receive multicast 415 * datagram packets, or <i>null</i> to defer to the interface set by 416 * {@link MulticastSocket#setInterface(InetAddress)} or 417 * {@link MulticastSocket#setNetworkInterface(NetworkInterface)} 418 * 419 * @throws IOException if there is an error joining, or when the address 420 * is not a multicast address, or the platform does not support 421 * multicasting 422 * @throws SecurityException if a security manager exists and its 423 * {@code checkMulticast} method doesn't allow the join. 424 * @throws IllegalArgumentException if mcastaddr is null or is a 425 * SocketAddress subclass not supported by this socket 426 * 427 * @see SecurityManager#checkMulticast(InetAddress) 428 * @since 1.4 429 */ 430 public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) 431 throws IOException { 432 if (isClosed()) 433 throw new SocketException("Socket is closed"); 434 435 if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress)) 436 throw new IllegalArgumentException("Unsupported address type"); 437 438 if (oldImpl) 439 throw new UnsupportedOperationException(); 440 441 checkAddress(((InetSocketAddress)mcastaddr).getAddress(), "joinGroup"); 442 SecurityManager security = System.getSecurityManager(); 443 if (security != null) { 444 security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress()); 445 } 446 447 if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) { 448 throw new SocketException("Not a multicast address"); 449 } 450 451 getImpl().joinGroup(mcastaddr, netIf); 452 } 453 454 /** 455 * Leave a multicast group on a specified local interface. 456 * 457 * <p>If there is a security manager, this method first 458 * calls its {@code checkMulticast} method 459 * with the {@code mcastaddr} argument 460 * as its argument. 461 * 462 * @param mcastaddr is the multicast address to leave 463 * @param netIf specifies the local interface or <i>null</i> to defer 464 * to the interface set by 465 * {@link MulticastSocket#setInterface(InetAddress)} or 466 * {@link MulticastSocket#setNetworkInterface(NetworkInterface)} 467 * @throws IOException if there is an error leaving 468 * or when the address is not a multicast address. 469 * @throws SecurityException if a security manager exists and its 470 * {@code checkMulticast} method doesn't allow the operation. 471 * @throws IllegalArgumentException if mcastaddr is null or is a 472 * SocketAddress subclass not supported by this socket 473 * 474 * @see SecurityManager#checkMulticast(InetAddress) 475 * @since 1.4 476 */ 477 public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) 478 throws IOException { 479 if (isClosed()) 480 throw new SocketException("Socket is closed"); 481 482 if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress)) 483 throw new IllegalArgumentException("Unsupported address type"); 484 485 if (oldImpl) 486 throw new UnsupportedOperationException(); 487 488 checkAddress(((InetSocketAddress)mcastaddr).getAddress(), "leaveGroup"); 489 SecurityManager security = System.getSecurityManager(); 490 if (security != null) { 491 security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress()); 492 } 493 494 if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) { 495 throw new SocketException("Not a multicast address"); 496 } 497 498 getImpl().leaveGroup(mcastaddr, netIf); 499 } 500 501 /** 502 * Set the multicast network interface used by methods 503 * whose behavior would be affected by the value of the 504 * network interface. Useful for multihomed hosts. 505 * @param inf the InetAddress 506 * @throws SocketException if there is an error in 507 * the underlying protocol, such as a TCP error. 508 * @see #getInterface() 509 */ 510 public void setInterface(InetAddress inf) throws SocketException { 511 if (isClosed()) { 512 throw new SocketException("Socket is closed"); 513 } 514 checkAddress(inf, "setInterface"); 515 synchronized (infLock) { 516 getImpl().setOption(SocketOptions.IP_MULTICAST_IF, inf); 517 infAddress = inf; 518 interfaceSet = true; 519 } 520 } 521 522 /** 523 * Retrieve the address of the network interface used for 524 * multicast packets. 525 * 526 * @return An {@code InetAddress} representing 527 * the address of the network interface used for 528 * multicast packets. 529 * 530 * @throws SocketException if there is an error in 531 * the underlying protocol, such as a TCP error. 532 * 533 * @see #setInterface(java.net.InetAddress) 534 */ 535 public InetAddress getInterface() throws SocketException { 536 if (isClosed()) { 537 throw new SocketException("Socket is closed"); 538 } 539 synchronized (infLock) { 540 InetAddress ia = 541 (InetAddress)getImpl().getOption(SocketOptions.IP_MULTICAST_IF); 542 543 /** 544 * No previous setInterface or interface can be 545 * set using setNetworkInterface 546 */ 547 if (infAddress == null) { 548 return ia; 549 } 550 551 /** 552 * Same interface set with setInterface? 553 */ 554 if (ia.equals(infAddress)) { 555 return ia; 556 } 557 558 /** 559 * Different InetAddress from what we set with setInterface 560 * so enumerate the current interface to see if the 561 * address set by setInterface is bound to this interface. 562 */ 563 try { 564 NetworkInterface ni = NetworkInterface.getByInetAddress(ia); 565 Enumeration<InetAddress> addrs = ni.getInetAddresses(); 566 while (addrs.hasMoreElements()) { 567 InetAddress addr = addrs.nextElement(); 568 if (addr.equals(infAddress)) { 569 return infAddress; 570 } 571 } 572 573 /** 574 * No match so reset infAddress to indicate that the 575 * interface has changed via means 576 */ 577 infAddress = null; 578 return ia; 579 } catch (Exception e) { 580 return ia; 581 } 582 } 583 } 584 585 /** 586 * Specify the network interface for outgoing multicast datagrams 587 * sent on this socket. 588 * 589 * @param netIf the interface 590 * @throws SocketException if there is an error in 591 * the underlying protocol, such as a TCP error. 592 * @see #getNetworkInterface() 593 * @since 1.4 594 */ 595 public void setNetworkInterface(NetworkInterface netIf) 596 throws SocketException { 597 598 synchronized (infLock) { 599 getImpl().setOption(SocketOptions.IP_MULTICAST_IF2, netIf); 600 infAddress = null; 601 interfaceSet = true; 602 } 603 } 604 605 /** 606 * Get the multicast network interface set. 607 * 608 * @throws SocketException if there is an error in 609 * the underlying protocol, such as a TCP error. 610 * @return the multicast {@code NetworkInterface} currently set 611 * @see #setNetworkInterface(NetworkInterface) 612 * @since 1.4 613 */ 614 public NetworkInterface getNetworkInterface() throws SocketException { 615 NetworkInterface ni 616 = (NetworkInterface)getImpl().getOption(SocketOptions.IP_MULTICAST_IF2); 617 if (ni == null) { 618 InetAddress[] addrs = new InetAddress[1]; 619 addrs[0] = InetAddress.anyLocalAddress(); 620 return new NetworkInterface(addrs[0].getHostName(), 0, addrs); 621 } else { 622 return ni; 623 } 624 } 625 626 /** 627 * Disable/Enable local loopback of multicast datagrams 628 * The option is used by the platform's networking code as a hint 629 * for setting whether multicast data will be looped back to 630 * the local socket. 631 * 632 * <p>Because this option is a hint, applications that want to 633 * verify what loopback mode is set to should call 634 * {@link #getLoopbackMode()} 635 * @param disable {@code true} to disable the LoopbackMode 636 * @throws SocketException if an error occurs while setting the value 637 * @since 1.4 638 * @see #getLoopbackMode 639 */ 640 public void setLoopbackMode(boolean disable) throws SocketException { 641 getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP, Boolean.valueOf(disable)); 642 } 643 644 /** 645 * Get the setting for local loopback of multicast datagrams. 646 * 647 * @throws SocketException if an error occurs while getting the value 648 * @return true if the LoopbackMode has been disabled 649 * @since 1.4 650 * @see #setLoopbackMode 651 */ 652 public boolean getLoopbackMode() throws SocketException { 653 return ((Boolean)getImpl().getOption(SocketOptions.IP_MULTICAST_LOOP)).booleanValue(); 654 } 655 656 /** 657 * Sends a datagram packet to the destination, with a TTL (time- 658 * to-live) other than the default for the socket. This method 659 * need only be used in instances where a particular TTL is desired; 660 * otherwise it is preferable to set a TTL once on the socket, and 661 * use that default TTL for all packets. This method does <B>not 662 * </B> alter the default TTL for the socket. Its behavior may be 663 * affected by {@code setInterface}. 664 * 665 * <p>If there is a security manager, this method first performs some 666 * security checks. First, if {@code p.getAddress().isMulticastAddress()} 667 * is true, this method calls the 668 * security manager's {@code checkMulticast} method 669 * with {@code p.getAddress()} and {@code ttl} as its arguments. 670 * If the evaluation of that expression is false, 671 * this method instead calls the security manager's 672 * {@code checkConnect} method with arguments 673 * {@code p.getAddress().getHostAddress()} and 674 * {@code p.getPort()}. Each call to a security manager method 675 * could result in a SecurityException if the operation is not allowed. 676 * 677 * @param p is the packet to be sent. The packet should contain 678 * the destination multicast ip address and the data to be sent. 679 * One does not need to be the member of the group to send 680 * packets to a destination multicast address. 681 * @param ttl optional time to live for multicast packet. 682 * default ttl is 1. 683 * 684 * @throws IOException is raised if an error occurs i.e 685 * error while setting ttl. 686 * @throws SecurityException if a security manager exists and its 687 * {@code checkMulticast} or {@code checkConnect} 688 * method doesn't allow the send. 689 * @throws PortUnreachableException may be thrown if the socket is connected 690 * to a currently unreachable destination. Note, there is no 691 * guarantee that the exception will be thrown. 692 * @throws IllegalArgumentException if the socket is connected, 693 * and connected address and packet address differ, or 694 * if the socket is not connected and the packet address 695 * is not set. 696 * 697 * 698 * @deprecated Use the following code or its equivalent instead: 699 * ...... 700 * int ttl = mcastSocket.getTimeToLive(); 701 * mcastSocket.setTimeToLive(newttl); 702 * mcastSocket.send(p); 703 * mcastSocket.setTimeToLive(ttl); 704 * ...... 705 * 706 * @see DatagramSocket#send 707 * @see DatagramSocket#receive 708 * @see SecurityManager#checkMulticast(java.net.InetAddress, byte) 709 * @see SecurityManager#checkConnect 710 */ 711 @Deprecated 712 public void send(DatagramPacket p, byte ttl) 713 throws IOException { 714 if (isClosed()) 715 throw new SocketException("Socket is closed"); 716 synchronized(ttlLock) { 717 synchronized(p) { 718 InetAddress packetAddress = p.getAddress(); 719 checkAddress(packetAddress, "send"); 720 if (connectState == ST_NOT_CONNECTED) { 721 if (packetAddress == null) { 722 throw new IllegalArgumentException("Address not set"); 723 } 724 // Security manager makes sure that the multicast address 725 // is allowed one and that the ttl used is less 726 // than the allowed maxttl. 727 SecurityManager security = System.getSecurityManager(); 728 if (security != null) { 729 if (packetAddress.isMulticastAddress()) { 730 security.checkMulticast(packetAddress, ttl); 731 } else { 732 security.checkConnect(packetAddress.getHostAddress(), 733 p.getPort()); 734 } 735 } 736 } else { 737 // we're connected 738 if (packetAddress == null) { 739 p.setAddress(connectedAddress); 740 p.setPort(connectedPort); 741 } else if ((!packetAddress.equals(connectedAddress)) || 742 p.getPort() != connectedPort) { 743 throw new IllegalArgumentException("connected address and packet address" + 744 " differ"); 745 } 746 } 747 byte dttl = getTTL(); 748 try { 749 if (ttl != dttl) { 750 // set the ttl 751 getImpl().setTTL(ttl); 752 } 753 // call the datagram method to send 754 getImpl().send(p); 755 } finally { 756 // set it back to default 757 if (ttl != dttl) { 758 getImpl().setTTL(dttl); 759 } 760 } 761 } // synch p 762 } //synch ttl 763 } //method 764 765 private static Set<SocketOption<?>> options; 766 private static boolean optionsSet = false; 767 768 @Override 769 public Set<SocketOption<?>> supportedOptions() { 770 synchronized (MulticastSocket.class) { 771 if (optionsSet) { 772 return options; 773 } 774 try { 775 DatagramSocketImpl impl = getImpl(); 776 options = Collections.unmodifiableSet(impl.supportedOptions()); 777 } catch (SocketException ex) { 778 options = Collections.emptySet(); 779 } 780 optionsSet = true; 781 return options; 782 } 783 } 784 }