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