1. /*
  2. * @(#)MulticastSocket.java 1.32 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.net;
  8. import java.io.IOException;
  9. import java.io.InterruptedIOException;
  10. /**
  11. * The multicast datagram socket class is useful for sending
  12. * and receiving IP multicast packets. A MulticastSocket is
  13. * a (UDP) DatagramSocket, with additional capabilities for
  14. * joining "groups" of other multicast hosts on the internet.
  15. * <P>
  16. * A multicast group is specified by a class D IP address, those
  17. * in the range <CODE>224.0.0.1</CODE> to <CODE>239.255.255.255</CODE>,
  18. * inclusive, and by a standard UDP port number. One would join a
  19. * multicast group by first creating a MulticastSocket with the desired
  20. * port, then invoking the <CODE>joinGroup(InetAddress groupAddr)</CODE>
  21. * method:
  22. * <PRE>
  23. * // join a Multicast group and send the group salutations
  24. * ...
  25. * byte[] msg = {'H', 'e', 'l', 'l', 'o'};
  26. * InetAddress group = InetAddress.getByName("228.5.6.7");
  27. * MulticastSocket s = new MulticastSocket(6789);
  28. * s.joinGroup(group);
  29. * DatagramPacket hi = new DatagramPacket(msg, msg.length,
  30. * group, 6789);
  31. * s.send(hi);
  32. * // get their responses!
  33. * byte[] buf = new byte[1000];
  34. * DatagramPacket recv = new DatagramPacket(buf, buf.length);
  35. * s.receive(recv);
  36. * ...
  37. * // OK, I'm done talking - leave the group...
  38. * s.leaveGroup(group);
  39. * </PRE>
  40. *
  41. * When one sends a message to a multicast group, <B>all</B> subscribing
  42. * recipients to that host and port receive the message (within the
  43. * time-to-live range of the packet, see below). The socket needn't
  44. * be a member of the multicast group to send messages to it.
  45. * <P>
  46. * When a socket subscribes to a multicast group/port, it receives
  47. * datagrams sent by other hosts to the group/port, as do all other
  48. * members of the group and port. A socket relinquishes membership
  49. * in a group by the leaveGroup(InetAddress addr) method. <B>
  50. * Multiple MulticastSocket's</B> may subscribe to a multicast group
  51. * and port concurrently, and they will all receive group datagrams.
  52. * <P>
  53. * Currently applets are not allowed to use multicast sockets.
  54. *
  55. * @author Pavani Diwanji
  56. * @since JDK1.1
  57. */
  58. public
  59. class MulticastSocket extends DatagramSocket {
  60. /**
  61. * Create a multicast socket.
  62. *
  63. * <p>If there is a security manager,
  64. * its <code>checkListen</code> method is first called
  65. * with 0 as its argument to ensure the operation is allowed.
  66. * This could result in a SecurityException.
  67. *
  68. * @exception SecurityException if a security manager exists and its
  69. * <code>checkListen</code> method doesn't allow the operation.
  70. * @see SecurityManager#checkListen
  71. */
  72. public MulticastSocket() throws IOException {
  73. super();
  74. }
  75. /**
  76. * Create a multicast socket and bind it to a specific port.
  77. *
  78. * <p>If there is a security manager,
  79. * its <code>checkListen</code> method is first called
  80. * with the <code>port</code> argument
  81. * as its argument to ensure the operation is allowed.
  82. * This could result in a SecurityException.
  83. *
  84. * @param port port to use
  85. * @exception SecurityException if a security manager exists and its
  86. * <code>checkListen</code> method doesn't allow the operation.
  87. * @see SecurityManager#checkListen
  88. */
  89. public MulticastSocket(int port) throws IOException {
  90. super(port);
  91. }
  92. /* do the work of creating a vanilla multicast socket. It is
  93. * important that the signature of this method not change,
  94. * even though it is package-private, since it is overrides a
  95. * method from DatagramSocket, which must not set SO_REUSEADDR.
  96. */
  97. void create(int port, InetAddress ignore) throws SocketException {
  98. SecurityManager security = System.getSecurityManager();
  99. if (security != null) {
  100. security.checkListen(port);
  101. }
  102. try {
  103. this.impl = (DatagramSocketImpl) implClass.newInstance();
  104. } catch (Exception e) {
  105. throw new SocketException("can't instantiate DatagramSocketImpl" + e.toString());
  106. }
  107. impl.create();
  108. impl.setOption(SocketOptions.SO_REUSEADDR, new Integer(-1));
  109. impl.bind(port, InetAddress.anyLocalAddress);
  110. }
  111. /**
  112. * The lock on the socket's TTL. This is for set/getTTL and
  113. * send(packet,ttl).
  114. */
  115. private Object ttlLock = new Object();
  116. /**
  117. * Set the default time-to-live for multicast packets sent out
  118. * on this socket. The TTL sets the IP time-to-live for
  119. * <code>DatagramPackets</code> sent to a MulticastGroup, which
  120. * specifies how many "hops" that the packet will be forwarded
  121. * on the network before it expires.
  122. *
  123. * <p>The ttl is an <b>unsigned</b> 8-bit quantity, and so <B>must</B> be
  124. * in the range <code> 0 <= ttl <= 0xFF </code>.
  125. *
  126. * @param ttl the time-to-live
  127. *
  128. * @deprecated use the setTimeToLive method instead, which uses
  129. * <b>int</b> instead of <b>byte</b> as the type for ttl.
  130. */
  131. public void setTTL(byte ttl) throws IOException {
  132. impl.setTTL(ttl);
  133. }
  134. /**
  135. * Set the default time-to-live for multicast packets sent out
  136. * on this socket. The TTL sets the IP time-to-live for
  137. * <code>DatagramPackets</code> sent to a MulticastGroup, which
  138. * specifies how many "hops" that the packet will be forwarded
  139. * on the network before it expires.
  140. *
  141. * <P> The ttl <B>must</B> be in the range <code> 0 <= ttl <=
  142. * 255</code> or an IllegalArgumentException will be thrown.
  143. *
  144. * @param ttl the time-to-live
  145. */
  146. public void setTimeToLive(int ttl) throws IOException {
  147. if (ttl < 0 || ttl > 255) {
  148. throw new IllegalArgumentException("ttl out of range");
  149. }
  150. impl.setTimeToLive(ttl);
  151. }
  152. /**
  153. * Get the default time-to-live for multicast packets sent out on
  154. * the socket.
  155. *
  156. * @deprecated use the getTimeToLive method instead, which returns
  157. * an <b>int</b> instead of a <b>byte</b>.
  158. */
  159. public byte getTTL() throws IOException {
  160. return impl.getTTL();
  161. }
  162. /**
  163. * Get the default time-to-live for multicast packets sent out on
  164. * the socket.
  165. */
  166. public int getTimeToLive() throws IOException {
  167. return impl.getTimeToLive();
  168. }
  169. /**
  170. * Joins a multicast group.Its behavior may be affected
  171. * by <code>setInterface</code>.
  172. *
  173. * <p>If there is a security manager, this method first
  174. * calls its <code>checkMulticast</code> method
  175. * with the <code>mcastaddr</code> argument
  176. * as its argument.
  177. *
  178. * @param mcastaddr is the multicast address to join
  179. *
  180. * @exception IOException if there is an error joining
  181. * or when the address is not a multicast address.
  182. * @exception SecurityException if a security manager exists and its
  183. * <code>checkMulticast</code> method doesn't allow the join.
  184. *
  185. * @see SecurityManager#checkMulticast(InetAddress)
  186. */
  187. public void joinGroup(InetAddress mcastaddr) throws IOException {
  188. SecurityManager security = System.getSecurityManager();
  189. if (security != null) {
  190. security.checkMulticast(mcastaddr);
  191. }
  192. impl.join(mcastaddr);
  193. }
  194. /**
  195. * Leave a multicast group. Its behavior may be affected
  196. * by <code>setInterface</code>.
  197. *
  198. * <p>If there is a security manager, this method first
  199. * calls its <code>checkMulticast</code> method
  200. * with the <code>mcastaddr</code> argument
  201. * as its argument.
  202. *
  203. * @param mcastaddr is the multicast address to leave
  204. * @exception IOException if there is an error leaving
  205. * or when the address is not a multicast address.
  206. * @exception SecurityException if a security manager exists and its
  207. * <code>checkMulticast</code> method doesn't allow the operation.
  208. *
  209. * @see SecurityManager#checkMulticast(InetAddress)
  210. */
  211. public void leaveGroup(InetAddress mcastaddr) throws IOException {
  212. SecurityManager security = System.getSecurityManager();
  213. if (security != null) {
  214. security.checkMulticast(mcastaddr);
  215. }
  216. impl.leave(mcastaddr);
  217. }
  218. /**
  219. * Set the multicast network interface used by methods
  220. * whose behavior would be affected by the value of the
  221. * network interface. Useful for multihomed hosts.
  222. */
  223. public void setInterface(InetAddress inf) throws SocketException {
  224. impl.setOption(SocketOptions.IP_MULTICAST_IF, inf);
  225. }
  226. /**
  227. * Retrieve the address of the network interface used for
  228. * multicast packets.
  229. */
  230. public InetAddress getInterface() throws SocketException {
  231. return (InetAddress) impl.getOption(SocketOptions.IP_MULTICAST_IF);
  232. }
  233. /**
  234. * Sends a datagram packet to the destination, with a TTL (time-
  235. * to-live) other than the default for the socket. This method
  236. * need only be used in instances where a particular TTL is desired;
  237. * otherwise it is preferable to set a TTL once on the socket, and
  238. * use that default TTL for all packets. This method does <B>not
  239. * </B> alter the default TTL for the socket. Its behavior may be
  240. * affected by <code>setInterface</code>.
  241. *
  242. * <p>If there is a security manager, this method first performs some
  243. * security checks. First, if <code>p.getAddress().isMulticastAddress()</code>
  244. * is true, this method calls the
  245. * security manager's <code>checkMulticast</code> method
  246. * with <code>p.getAddress()</code> and <code>ttl</code> as its arguments.
  247. * If the evaluation of that expression is false,
  248. * this method instead calls the security manager's
  249. * <code>checkConnect</code> method with arguments
  250. * <code>p.getAddress().getHostAddress()</code> and
  251. * <code>p.getPort()</code>. Each call to a security manager method
  252. * could result in a SecurityException if the operation is not allowed.
  253. *
  254. * @param p is the packet to be sent. The packet should contain
  255. * the destination multicast ip address and the data to be sent.
  256. * One does not need to be the member of the group to send
  257. * packets to a destination multicast address.
  258. * @param ttl optional time to live for multicast packet.
  259. * default ttl is 1.
  260. *
  261. * @exception IOException is raised if an error occurs i.e
  262. * error while setting ttl.
  263. * @exception SecurityException if a security manager exists and its
  264. * <code>checkMulticast</code> or <code>checkConnect</code>
  265. * method doesn't allow the send.
  266. *
  267. * @see DatagramSocket#send
  268. * @see DatagramSocket#receive
  269. * @see SecurityManager#checkMulticast(java.net.InetAddress, byte)
  270. * @see SecurityManager#checkConnect
  271. */
  272. public void send(DatagramPacket p, byte ttl)
  273. throws IOException {
  274. synchronized(ttlLock) {
  275. synchronized(p) {
  276. if (!connected) {
  277. // Security manager makes sure that the multicast address
  278. // is allowed one and that the ttl used is less
  279. // than the allowed maxttl.
  280. SecurityManager security = System.getSecurityManager();
  281. if (security != null) {
  282. if (p.getAddress().isMulticastAddress()) {
  283. security.checkMulticast(p.getAddress(), ttl);
  284. } else {
  285. security.checkConnect(p.getAddress().getHostAddress(),
  286. p.getPort());
  287. }
  288. }
  289. } else {
  290. // we're connected
  291. InetAddress packetAddress = null;
  292. packetAddress = p.getAddress();
  293. if (packetAddress == null) {
  294. p.setAddress(connectedAddress);
  295. p.setPort(connectedPort);
  296. } else if ((!packetAddress.equals(connectedAddress)) ||
  297. p.getPort() != connectedPort) {
  298. throw new SecurityException("connected address and packet address" +
  299. " differ");
  300. }
  301. }
  302. byte dttl = getTTL();
  303. try {
  304. if (ttl != dttl) {
  305. // set the ttl
  306. impl.setTTL(ttl);
  307. }
  308. // call the datagram method to send
  309. impl.send(p);
  310. } finally {
  311. // set it back to default
  312. if (ttl != dttl) {
  313. impl.setTTL(dttl);
  314. }
  315. }
  316. } // synch p
  317. } //synch ttl
  318. } //method
  319. }