blob: 83a18c3a3d0d06108393efc0d329fd687ba08ec1 [file] [log] [blame]
Rahul Ravikumar05336002019-10-14 15:04:32 -07001/*
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
26package java.net;
27
28import java.io.IOException;
29import 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 */
84public
85class 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 */
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 */
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 */
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
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 */
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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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
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}