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