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