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