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