1 /* MulticastSocket.java -- Class for using multicast sockets
2    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2007
3    Free Software Foundation, Inc.
4 
5 This file is part of GNU Classpath.
6 
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11 
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING.  If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21 
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library.  Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
26 
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module.  An independent module is a module which is not derived from
34 or based on this library.  If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so.  If you do not wish to do so, delete this
37 exception statement from your version. */
38 
39 package java.net;
40 
41 import java.io.IOException;
42 import java.util.Enumeration;
43 
44 
45 /**
46  * Written using on-line Java Platform 1.2 API Specification, as well
47  * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
48  * Status:  Believed complete and correct.
49  */
50 /**
51  * This class models a multicast UDP socket.  A multicast address is a
52  * class D internet address (one whose most significant bits are 1110).
53  * A multicast group consists of a multicast address and a well known
54  * port number.  All members of the group listening on that address and
55  * port will receive all the broadcasts to the group.
56  * <p>
57  * Please note that applets are not allowed to use multicast sockets
58  *
59  * Written using on-line Java Platform 1.2 API Specification, as well
60  * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
61  * Status:  Believed complete and correct.
62  *
63  * @author Warren Levy (warrenl@cygnus.com)
64  * @author Aaron M. Renn (arenn@urbanophile.com) (Documentation comments)
65  * @since 1.1
66  * @date May 18, 1999.
67  */
68 public class MulticastSocket extends DatagramSocket
69 {
70   /**
71    * Create a MulticastSocket that this not bound to any address
72    *
73    * @exception IOException If an error occurs
74    * @exception SecurityException If a security manager exists and its
75    * checkListen method doesn't allow the operation
76    */
MulticastSocket()77   public MulticastSocket() throws IOException
78   {
79     this(new InetSocketAddress(0));
80   }
81 
82   /**
83    * Create a multicast socket bound to the specified port
84    *
85    * @param port The port to bind to
86    *
87    * @exception IOException If an error occurs
88    * @exception SecurityException If a security manager exists and its
89    * checkListen method doesn't allow the operation
90    */
MulticastSocket(int port)91   public MulticastSocket(int port) throws IOException
92   {
93     this(new InetSocketAddress(port));
94   }
95 
96   /**
97    * Create a multicast socket bound to the specified SocketAddress.
98    *
99    * @param address The SocketAddress the multicast socket will be bound to
100    *
101    * @exception IOException If an error occurs
102    * @exception SecurityException If a security manager exists and its
103    * checkListen method doesn't allow the operation
104    *
105    * @since 1.4
106    */
MulticastSocket(SocketAddress address)107   public MulticastSocket(SocketAddress address) throws IOException
108   {
109     super((SocketAddress) null);
110     setReuseAddress(true);
111     if (address != null)
112       bind(address);
113   }
114 
115   /**
116    * Returns the interface being used for multicast packets
117    *
118    * @return The multicast interface
119    *
120    * @exception SocketException If an error occurs
121    */
getInterface()122   public InetAddress getInterface() throws SocketException
123   {
124     if (isClosed())
125       throw new SocketException("socket is closed");
126 
127     return (InetAddress) getImpl().getOption(SocketOptions.IP_MULTICAST_IF);
128   }
129 
130   /**
131    * Returns the current value of the "Time to Live" option.  This is the
132    * number of hops a packet can make before it "expires".   This method id
133    * deprecated.  Use <code>getTimeToLive</code> instead.
134    *
135    * @return The TTL value
136    *
137    * @exception IOException If an error occurs
138    *
139    * @deprecated 1.2 Replaced by getTimeToLive()
140    *
141    * @see MulticastSocket#getTimeToLive()
142    */
getTTL()143   public byte getTTL() throws IOException
144   {
145     if (isClosed())
146       throw new SocketException("socket is closed");
147 
148     // Use getTTL here rather than getTimeToLive in case we're using an impl
149     // other than the default PlainDatagramSocketImpl and it doesn't have
150     // getTimeToLive yet.
151     return getImpl().getTTL();
152   }
153 
154   /**
155    * Returns the current value of the "Time to Live" option.  This is the
156    * number of hops a packet can make before it "expires".
157    *
158    * @return The TTL value
159    *
160    * @exception IOException If an error occurs
161    *
162    * @since 1.2
163    */
getTimeToLive()164   public int getTimeToLive() throws IOException
165   {
166     if (isClosed())
167       throw new SocketException("socket is closed");
168 
169     return getImpl().getTimeToLive();
170   }
171 
172   /**
173    * Sets the interface to use for sending multicast packets.
174    *
175    * @param addr The new interface to use.
176    *
177    * @exception SocketException If an error occurs.
178    *
179    * @since 1.4
180    */
setInterface(InetAddress addr)181   public void setInterface(InetAddress addr) throws SocketException
182   {
183     if (isClosed())
184       throw new SocketException("socket is closed");
185 
186     getImpl().setOption(SocketOptions.IP_MULTICAST_IF, addr);
187   }
188 
189   /**
190    * Sets the local network interface used to send multicast messages
191    *
192    * @param netIf The local network interface used to send multicast messages
193    *
194    * @exception SocketException If an error occurs
195    *
196    * @see MulticastSocket#getNetworkInterface()
197    *
198    * @since 1.4
199    */
setNetworkInterface(NetworkInterface netIf)200   public void setNetworkInterface(NetworkInterface netIf)
201     throws SocketException
202   {
203     if (isClosed())
204       throw new SocketException("socket is closed");
205 
206     InetAddress address;
207     if (netIf != null)
208       out:
209       {
210         Enumeration e = netIf.getInetAddresses();
211         if (getLocalAddress() instanceof Inet4Address)
212           {
213             // Search for a IPv4 address.
214             while (e.hasMoreElements())
215               {
216                 address = (InetAddress) e.nextElement();
217                 if (address instanceof Inet4Address)
218                   break out;
219               }
220             throw new SocketException("interface " + netIf.getName() + " has no IPv6 address");
221           }
222         else if (getLocalAddress() instanceof Inet6Address)
223           {
224             // Search for a IPv6 address.
225             while (e.hasMoreElements())
226               {
227                 address = (InetAddress) e.nextElement();
228                 if (address instanceof Inet6Address)
229                   break out;
230               }
231             throw new SocketException("interface " + netIf.getName() + " has no IPv6 address");
232           }
233         else
234           throw new SocketException("interface " + netIf.getName() + " has no suitable IP address");
235       }
236     else
237       address = InetAddress.ANY_IF;
238 
239 
240     getImpl().setOption(SocketOptions.IP_MULTICAST_IF, address);
241   }
242 
243   /**
244    * Gets the local network interface which is used to send multicast messages
245    *
246    * @return The local network interface to send multicast messages
247    *
248    * @exception SocketException If an error occurs
249    *
250    * @see MulticastSocket#setNetworkInterface(NetworkInterface netIf)
251    *
252    * @since 1.4
253    */
getNetworkInterface()254   public NetworkInterface getNetworkInterface() throws SocketException
255   {
256     if (isClosed())
257       throw new SocketException("socket is closed");
258 
259     InetAddress address =
260       (InetAddress) getImpl().getOption(SocketOptions.IP_MULTICAST_IF);
261 
262     if (address.isAnyLocalAddress())
263       return NetworkInterface.createAnyInterface();
264 
265     NetworkInterface netIf = NetworkInterface.getByInetAddress(address);
266 
267     return netIf;
268   }
269 
270   /**
271    * Disable/Enable local loopback of multicast packets.  The option is used by
272    * the platform's networking code as a hint for setting whether multicast
273    * data will be looped back to the local socket.
274    *
275    * Because this option is a hint, applications that want to verify what
276    * loopback mode is set to should call #getLoopbackMode
277    *
278    * @param disable True to disable loopback mode
279    *
280    * @exception SocketException If an error occurs
281    *
282    * @since 1.4
283    */
setLoopbackMode(boolean disable)284   public void setLoopbackMode(boolean disable) throws SocketException
285   {
286     if (isClosed())
287       throw new SocketException("socket is closed");
288 
289     getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP,
290                         Boolean.valueOf(disable));
291   }
292 
293   /**
294    * Checks if local loopback mode is enabled
295    *
296    * @return true if loopback mode is enabled, false otherwise
297    *
298    * @exception SocketException If an error occurs
299    *
300    * @since 1.4
301    */
getLoopbackMode()302   public boolean getLoopbackMode() throws SocketException
303   {
304     if (isClosed())
305       throw new SocketException("socket is closed");
306 
307     Object buf = getImpl().getOption(SocketOptions.IP_MULTICAST_LOOP);
308 
309     if (buf instanceof Boolean)
310       return ((Boolean) buf).booleanValue();
311 
312     throw new SocketException("unexpected type");
313   }
314 
315   /**
316    * Sets the "Time to Live" value for a socket.  The value must be between
317    * 1 and 255.
318    *
319    * @param ttl The new TTL value
320    *
321    * @exception IOException If an error occurs
322    *
323    * @deprecated 1.2 Replaced by <code>setTimeToLive</code>
324    *
325    * @see MulticastSocket#setTimeToLive(int ttl)
326    */
setTTL(byte ttl)327   public void setTTL(byte ttl) throws IOException
328   {
329     if (isClosed())
330       throw new SocketException("socket is closed");
331 
332     // Use setTTL here rather than setTimeToLive in case we're using an impl
333     // other than the default PlainDatagramSocketImpl and it doesn't have
334     // setTimeToLive yet.
335     getImpl().setTTL(ttl);
336   }
337 
338   /**
339    * Sets the "Time to Live" value for a socket.  The value must be between
340    * 0 and 255, inclusive.
341    *
342    * @param ttl The new TTL value
343    *
344    * @exception IOException If an error occurs
345    *
346    * @since 1.2
347    */
setTimeToLive(int ttl)348   public void setTimeToLive(int ttl) throws IOException
349   {
350     if (isClosed())
351       throw new SocketException("socket is closed");
352 
353     if (ttl < 0 || ttl > 255)
354       throw new IllegalArgumentException("Invalid ttl: " + ttl);
355 
356     getImpl().setTimeToLive(ttl);
357   }
358 
359   /**
360    * Joins the specified multicast group.
361    *
362    * @param mcastaddr The address of the group to join
363    *
364    * @exception IOException If an error occurs
365    * @exception SecurityException If a security manager exists and its
366    * checkMulticast method doesn't allow the operation
367    */
joinGroup(InetAddress mcastaddr)368   public void joinGroup(InetAddress mcastaddr) throws IOException
369   {
370     if (isClosed())
371       throw new SocketException("socket is closed");
372 
373     if (! mcastaddr.isMulticastAddress())
374       throw new IOException("Not a Multicast address");
375 
376     SecurityManager s = System.getSecurityManager();
377     if (s != null)
378       s.checkMulticast(mcastaddr);
379 
380     getImpl().join(mcastaddr);
381   }
382 
383   /**
384    * Leaves the specified multicast group
385    *
386    * @param mcastaddr The address of the group to leave
387    *
388    * @exception IOException If an error occurs
389    * @exception SecurityException If a security manager exists and its
390    * checkMulticast method doesn't allow the operation
391    */
leaveGroup(InetAddress mcastaddr)392   public void leaveGroup(InetAddress mcastaddr) throws IOException
393   {
394     if (isClosed())
395       throw new SocketException("socket is closed");
396 
397     if (! mcastaddr.isMulticastAddress())
398       throw new IOException("Not a Multicast address");
399 
400     SecurityManager s = System.getSecurityManager();
401     if (s != null)
402       s.checkMulticast(mcastaddr);
403 
404     getImpl().leave(mcastaddr);
405   }
406 
407   /**
408    * Joins the specified mulitcast group on a specified interface.
409    *
410    * @param mcastaddr The multicast address to join
411    * @param netIf The local network interface to receive the multicast
412    * messages on or null to defer the interface set by #setInterface or
413    * #setNetworkInterface
414    *
415    * @exception IOException If an error occurs
416    * @exception IllegalArgumentException If address type is not supported
417    * @exception SecurityException If a security manager exists and its
418    * checkMulticast method doesn't allow the operation
419    *
420    * @see MulticastSocket#setInterface(InetAddress addr)
421    * @see MulticastSocket#setNetworkInterface(NetworkInterface netIf)
422    *
423    * @since 1.4
424    */
joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)425   public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)
426     throws IOException
427   {
428     if (isClosed())
429       throw new SocketException("socket is closed");
430 
431     if (! (mcastaddr instanceof InetSocketAddress))
432       throw new IllegalArgumentException("SocketAddress type not supported");
433 
434     InetSocketAddress tmp = (InetSocketAddress) mcastaddr;
435 
436     if (! tmp.getAddress().isMulticastAddress())
437       throw new IOException("Not a Multicast address");
438 
439     SecurityManager s = System.getSecurityManager();
440     if (s != null)
441       s.checkMulticast(tmp.getAddress());
442 
443     getImpl().joinGroup(mcastaddr, netIf);
444   }
445 
446   /**
447    * Leaves the specified mulitcast group on a specified interface.
448    *
449    * @param mcastaddr The multicast address to leave
450    * @param netIf The local networki interface or null to defer to the
451    * interface set by setInterface or setNetworkInterface
452    *
453    * @exception IOException If an error occurs
454    * @exception IllegalArgumentException If address type is not supported
455    * @exception SecurityException If a security manager exists and its
456    * checkMulticast method doesn't allow the operation
457    *
458    * @see MulticastSocket#setInterface(InetAddress addr)
459    * @see MulticastSocket#setNetworkInterface(NetworkInterface netIf)
460    *
461    * @since 1.4
462    */
leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)463   public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)
464     throws IOException
465   {
466     if (isClosed())
467       throw new SocketException("socket is closed");
468 
469     InetSocketAddress tmp = (InetSocketAddress) mcastaddr;
470 
471     if (! tmp.getAddress().isMulticastAddress())
472       throw new IOException("Not a Multicast address");
473 
474     SecurityManager s = System.getSecurityManager();
475     if (s != null)
476       s.checkMulticast(tmp.getAddress());
477 
478     getImpl().leaveGroup(mcastaddr, netIf);
479   }
480 
481   /**
482    * Sends a packet of data to a multicast address with a TTL that is
483    * different from the default TTL on this socket.  The default TTL for
484    * the socket is not changed.
485    *
486    * @param packet The packet of data to send
487    * @param ttl The TTL for this packet
488    *
489    * @exception IOException If an error occurs
490    * @exception SecurityException If a security manager exists and its
491    * checkConnect or checkMulticast method doesn't allow the operation
492    *
493    * @deprecated
494    */
send(DatagramPacket packet, byte ttl)495   public synchronized void send(DatagramPacket packet, byte ttl)
496     throws IOException
497   {
498     if (isClosed())
499       throw new SocketException("socket is closed");
500 
501     SecurityManager s = System.getSecurityManager();
502     if (s != null)
503       {
504         InetAddress addr = packet.getAddress();
505         if (addr.isMulticastAddress())
506           s.checkPermission(new SocketPermission(addr.getHostName()
507                                                  + packet.getPort(),
508                                                  "accept,connect"));
509         else
510           s.checkConnect(addr.getHostAddress(), packet.getPort());
511       }
512 
513     int oldttl = getImpl().getTimeToLive();
514     getImpl().setTimeToLive(((int) ttl) & 0xFF);
515     getImpl().send(packet);
516     getImpl().setTimeToLive(oldttl);
517   }
518 }
519