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