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