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