1. /*
  2. * @(#)MulticastSocket.java 1.71 04/05/18
  3. *
  4. * Copyright 2004 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(boolean)} 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(boolean)} 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(boolean)} 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. @Deprecated
  173. public void setTTL(byte ttl) throws IOException {
  174. if (isClosed())
  175. throw new SocketException("Socket is closed");
  176. getImpl().setTTL(ttl);
  177. }
  178. /**
  179. * Set the default time-to-live for multicast packets sent out
  180. * on this <code>MulticastSocket</code> in order to control the
  181. * scope of the multicasts.
  182. *
  183. * <P> The ttl <B>must</B> be in the range <code> 0 <= ttl <=
  184. * 255</code> or an IllegalArgumentException will be thrown.
  185. * @exception IOException if an I/O exception occurs
  186. * while setting the default time-to-live value
  187. * @param ttl the time-to-live
  188. * @see #getTimeToLive()
  189. */
  190. public void setTimeToLive(int ttl) throws IOException {
  191. if (ttl < 0 || ttl > 255) {
  192. throw new IllegalArgumentException("ttl out of range");
  193. }
  194. if (isClosed())
  195. throw new SocketException("Socket is closed");
  196. getImpl().setTimeToLive(ttl);
  197. }
  198. /**
  199. * Get the default time-to-live for multicast packets sent out on
  200. * the socket.
  201. *
  202. * @exception IOException if an I/O exception occurs
  203. * while getting the default time-to-live value
  204. * @return the default time-to-live value
  205. * @deprecated use the getTimeToLive method instead, which returns
  206. * an <b>int</b> instead of a <b>byte</b>.
  207. * @see #setTTL(byte)
  208. */
  209. @Deprecated
  210. public byte getTTL() throws IOException {
  211. if (isClosed())
  212. throw new SocketException("Socket is closed");
  213. return getImpl().getTTL();
  214. }
  215. /**
  216. * Get the default time-to-live for multicast packets sent out on
  217. * the socket.
  218. * @exception IOException if an I/O exception occurs while
  219. * getting the default time-to-live value
  220. * @return the default time-to-live value
  221. * @see #setTimeToLive(int)
  222. */
  223. public int getTimeToLive() throws IOException {
  224. if (isClosed())
  225. throw new SocketException("Socket is closed");
  226. return getImpl().getTimeToLive();
  227. }
  228. /**
  229. * Joins a multicast group. Its behavior may be affected by
  230. * <code>setInterface</code> or <code>setNetworkInterface</code>.
  231. *
  232. * <p>If there is a security manager, this method first
  233. * calls its <code>checkMulticast</code> method
  234. * with the <code>mcastaddr</code> argument
  235. * as its argument.
  236. *
  237. * @param mcastaddr is the multicast address to join
  238. *
  239. * @exception IOException if there is an error joining
  240. * or when the address is not a multicast address.
  241. * @exception SecurityException if a security manager exists and its
  242. * <code>checkMulticast</code> method doesn't allow the join.
  243. *
  244. * @see SecurityManager#checkMulticast(InetAddress)
  245. */
  246. public void joinGroup(InetAddress mcastaddr) throws IOException {
  247. if (isClosed()) {
  248. throw new SocketException("Socket is closed");
  249. }
  250. SecurityManager security = System.getSecurityManager();
  251. if (security != null) {
  252. security.checkMulticast(mcastaddr);
  253. }
  254. if (!mcastaddr.isMulticastAddress()) {
  255. throw new SocketException("Not a multicast address");
  256. }
  257. getImpl().join(mcastaddr);
  258. }
  259. /**
  260. * Leave a multicast group. Its behavior may be affected by
  261. * <code>setInterface</code> or <code>setNetworkInterface</code>.
  262. *
  263. * <p>If there is a security manager, this method first
  264. * calls its <code>checkMulticast</code> method
  265. * with the <code>mcastaddr</code> argument
  266. * as its argument.
  267. *
  268. * @param mcastaddr is the multicast address to leave
  269. * @exception IOException if there is an error leaving
  270. * or when the address is not a multicast address.
  271. * @exception SecurityException if a security manager exists and its
  272. * <code>checkMulticast</code> method doesn't allow the operation.
  273. *
  274. * @see SecurityManager#checkMulticast(InetAddress)
  275. */
  276. public void leaveGroup(InetAddress mcastaddr) throws IOException {
  277. if (isClosed()) {
  278. throw new SocketException("Socket is closed");
  279. }
  280. SecurityManager security = System.getSecurityManager();
  281. if (security != null) {
  282. security.checkMulticast(mcastaddr);
  283. }
  284. if (!mcastaddr.isMulticastAddress()) {
  285. throw new SocketException("Not a multicast address");
  286. }
  287. getImpl().leave(mcastaddr);
  288. }
  289. /**
  290. * Joins the specified multicast group at the specified interface.
  291. *
  292. * <p>If there is a security manager, this method first
  293. * calls its <code>checkMulticast</code> method
  294. * with the <code>mcastaddr</code> argument
  295. * as its argument.
  296. *
  297. * @param mcastaddr is the multicast address to join
  298. * @param netIf specifies the local interface to receive multicast
  299. * datagram packets, or <i>null</i> to defer to the interface set by
  300. * {@link MulticastSocket#setInterface(InetAddress)} or
  301. * {@link MulticastSocket#setNetworkInterface(NetworkInterface)}
  302. *
  303. * @exception IOException if there is an error joining
  304. * or when the address is not a multicast address.
  305. * @exception SecurityException if a security manager exists and its
  306. * <code>checkMulticast</code> method doesn't allow the join.
  307. * @throws IllegalArgumentException if mcastaddr is null or is a
  308. * SocketAddress subclass not supported by this socket
  309. *
  310. * @see SecurityManager#checkMulticast(InetAddress)
  311. * @since 1.4
  312. */
  313. public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)
  314. throws IOException {
  315. if (isClosed())
  316. throw new SocketException("Socket is closed");
  317. if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
  318. throw new IllegalArgumentException("Unsupported address type");
  319. if (oldImpl)
  320. throw new UnsupportedOperationException();
  321. SecurityManager security = System.getSecurityManager();
  322. if (security != null) {
  323. security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress());
  324. }
  325. if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) {
  326. throw new SocketException("Not a multicast address");
  327. }
  328. getImpl().joinGroup(mcastaddr, netIf);
  329. }
  330. /**
  331. * Leave a multicast group on a specified local interface.
  332. *
  333. * <p>If there is a security manager, this method first
  334. * calls its <code>checkMulticast</code> method
  335. * with the <code>mcastaddr</code> argument
  336. * as its argument.
  337. *
  338. * @param mcastaddr is the multicast address to leave
  339. * @param netIf specifies the local interface or <i>null</i> to defer
  340. * to the interface set by
  341. * {@link MulticastSocket#setInterface(InetAddress)} or
  342. * {@link MulticastSocket#setNetworkInterface(NetworkInterface)}
  343. * @exception IOException if there is an error leaving
  344. * or when the address is not a multicast address.
  345. * @exception SecurityException if a security manager exists and its
  346. * <code>checkMulticast</code> method doesn't allow the operation.
  347. * @throws IllegalArgumentException if mcastaddr is null or is a
  348. * SocketAddress subclass not supported by this socket
  349. *
  350. * @see SecurityManager#checkMulticast(InetAddress)
  351. * @since 1.4
  352. */
  353. public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)
  354. throws IOException {
  355. if (isClosed())
  356. throw new SocketException("Socket is closed");
  357. if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
  358. throw new IllegalArgumentException("Unsupported address type");
  359. if (oldImpl)
  360. throw new UnsupportedOperationException();
  361. SecurityManager security = System.getSecurityManager();
  362. if (security != null) {
  363. security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress());
  364. }
  365. if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) {
  366. throw new SocketException("Not a multicast address");
  367. }
  368. getImpl().leaveGroup(mcastaddr, netIf);
  369. }
  370. /**
  371. * Set the multicast network interface used by methods
  372. * whose behavior would be affected by the value of the
  373. * network interface. Useful for multihomed hosts.
  374. * @param inf the InetAddress
  375. * @exception SocketException if there is an error in
  376. * the underlying protocol, such as a TCP error.
  377. * @see #getInterface()
  378. */
  379. public void setInterface(InetAddress inf) throws SocketException {
  380. if (isClosed()) {
  381. throw new SocketException("Socket is closed");
  382. }
  383. synchronized (infLock) {
  384. getImpl().setOption(SocketOptions.IP_MULTICAST_IF, inf);
  385. infAddress = inf;
  386. }
  387. }
  388. /**
  389. * Retrieve the address of the network interface used for
  390. * multicast packets.
  391. *
  392. * @return An <code>InetAddress</code> representing
  393. * the address of the network interface used for
  394. * multicast packets.
  395. *
  396. * @exception SocketException if there is an error in
  397. * the underlying protocol, such as a TCP error.
  398. *
  399. * @see #setInterface(java.net.InetAddress)
  400. */
  401. public InetAddress getInterface() throws SocketException {
  402. if (isClosed()) {
  403. throw new SocketException("Socket is closed");
  404. }
  405. synchronized (infLock) {
  406. InetAddress ia =
  407. (InetAddress)getImpl().getOption(SocketOptions.IP_MULTICAST_IF);
  408. /**
  409. * No previous setInterface or interface can be
  410. * set using setNetworkInterface
  411. */
  412. if (infAddress == null) {
  413. return ia;
  414. }
  415. /**
  416. * Same interface set with setInterface?
  417. */
  418. if (ia.equals(infAddress)) {
  419. return ia;
  420. }
  421. /**
  422. * Different InetAddress from what we set with setInterface
  423. * so enumerate the current interface to see if the
  424. * address set by setInterface is bound to this interface.
  425. */
  426. try {
  427. NetworkInterface ni = NetworkInterface.getByInetAddress(ia);
  428. Enumeration addrs = ni.getInetAddresses();
  429. while (addrs.hasMoreElements()) {
  430. InetAddress addr = (InetAddress)(addrs.nextElement());
  431. if (addr.equals(infAddress)) {
  432. return infAddress;
  433. }
  434. }
  435. /**
  436. * No match so reset infAddress to indicate that the
  437. * interface has changed via means
  438. */
  439. infAddress = null;
  440. return ia;
  441. } catch (Exception e) {
  442. return ia;
  443. }
  444. }
  445. }
  446. /**
  447. * Specify the network interface for outgoing multicast datagrams
  448. * sent on this socket.
  449. *
  450. * @param netIf the interface
  451. * @exception SocketException if there is an error in
  452. * the underlying protocol, such as a TCP error.
  453. * @see #getNetworkInterface()
  454. * @since 1.4
  455. */
  456. public void setNetworkInterface(NetworkInterface netIf)
  457. throws SocketException {
  458. synchronized (infLock) {
  459. getImpl().setOption(SocketOptions.IP_MULTICAST_IF2, netIf);
  460. infAddress = null;
  461. }
  462. }
  463. /**
  464. * Get the multicast network interface set.
  465. *
  466. * @exception SocketException if there is an error in
  467. * the underlying protocol, such as a TCP error.
  468. * @return the multicast <code>NetworkInterface</code> currently set
  469. * @see #setNetworkInterface(NetworkInterface)
  470. * @since 1.4
  471. */
  472. public NetworkInterface getNetworkInterface() throws SocketException {
  473. NetworkInterface ni
  474. = (NetworkInterface)getImpl().getOption(SocketOptions.IP_MULTICAST_IF2);
  475. if (ni.getIndex() == 0) {
  476. InetAddress[] addrs = new InetAddress[1];
  477. addrs[0] = InetAddress.anyLocalAddress();
  478. return new NetworkInterface(addrs[0].getHostName(), 0, addrs);
  479. } else {
  480. return ni;
  481. }
  482. }
  483. /**
  484. * Disable/Enable local loopback of multicast datagrams
  485. * The option is used by the platform's networking code as a hint
  486. * for setting whether multicast data will be looped back to
  487. * the local socket.
  488. *
  489. * <p>Because this option is a hint, applications that want to
  490. * verify what loopback mode is set to should call
  491. * {@link #getLoopbackMode()}
  492. * @param disable <code>true</code> to disable the LoopbackMode
  493. * @throws SocketException if an error occurs while setting the value
  494. * @since 1.4
  495. * @see #getLoopbackMode
  496. */
  497. public void setLoopbackMode(boolean disable) throws SocketException {
  498. getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP, Boolean.valueOf(disable));
  499. }
  500. /**
  501. * Get the setting for local loopback of multicast datagrams.
  502. *
  503. * @throws SocketException if an error occurs while getting the value
  504. * @return true if the LoopbackMode has been disabled
  505. * @since 1.4
  506. * @see #setLoopbackMode
  507. */
  508. public boolean getLoopbackMode() throws SocketException {
  509. return ((Boolean)getImpl().getOption(SocketOptions.IP_MULTICAST_LOOP)).booleanValue();
  510. }
  511. /**
  512. * Sends a datagram packet to the destination, with a TTL (time-
  513. * to-live) other than the default for the socket. This method
  514. * need only be used in instances where a particular TTL is desired;
  515. * otherwise it is preferable to set a TTL once on the socket, and
  516. * use that default TTL for all packets. This method does <B>not
  517. * </B> alter the default TTL for the socket. Its behavior may be
  518. * affected by <code>setInterface</code>.
  519. *
  520. * <p>If there is a security manager, this method first performs some
  521. * security checks. First, if <code>p.getAddress().isMulticastAddress()</code>
  522. * is true, this method calls the
  523. * security manager's <code>checkMulticast</code> method
  524. * with <code>p.getAddress()</code> and <code>ttl</code> as its arguments.
  525. * If the evaluation of that expression is false,
  526. * this method instead calls the security manager's
  527. * <code>checkConnect</code> method with arguments
  528. * <code>p.getAddress().getHostAddress()</code> and
  529. * <code>p.getPort()</code>. Each call to a security manager method
  530. * could result in a SecurityException if the operation is not allowed.
  531. *
  532. * @param p is the packet to be sent. The packet should contain
  533. * the destination multicast ip address and the data to be sent.
  534. * One does not need to be the member of the group to send
  535. * packets to a destination multicast address.
  536. * @param ttl optional time to live for multicast packet.
  537. * default ttl is 1.
  538. *
  539. * @exception IOException is raised if an error occurs i.e
  540. * error while setting ttl.
  541. * @exception SecurityException if a security manager exists and its
  542. * <code>checkMulticast</code> or <code>checkConnect</code>
  543. * method doesn't allow the send.
  544. *
  545. * @deprecated Use the following code or its equivalent instead:
  546. * ......
  547. * int ttl = mcastSocket.getTimeToLive();
  548. * mcastSocket.setTimeToLive(newttl);
  549. * mcastSocket.send(p);
  550. * mcastSocket.setTimeToLive(ttl);
  551. * ......
  552. *
  553. * @see DatagramSocket#send
  554. * @see DatagramSocket#receive
  555. * @see SecurityManager#checkMulticast(java.net.InetAddress, byte)
  556. * @see SecurityManager#checkConnect
  557. */
  558. @Deprecated
  559. public void send(DatagramPacket p, byte ttl)
  560. throws IOException {
  561. if (isClosed())
  562. throw new SocketException("Socket is closed");
  563. synchronized(ttlLock) {
  564. synchronized(p) {
  565. if (connectState == ST_NOT_CONNECTED) {
  566. // Security manager makes sure that the multicast address
  567. // is allowed one and that the ttl used is less
  568. // than the allowed maxttl.
  569. SecurityManager security = System.getSecurityManager();
  570. if (security != null) {
  571. if (p.getAddress().isMulticastAddress()) {
  572. security.checkMulticast(p.getAddress(), ttl);
  573. } else {
  574. security.checkConnect(p.getAddress().getHostAddress(),
  575. p.getPort());
  576. }
  577. }
  578. } else {
  579. // we're connected
  580. InetAddress packetAddress = null;
  581. packetAddress = p.getAddress();
  582. if (packetAddress == null) {
  583. p.setAddress(connectedAddress);
  584. p.setPort(connectedPort);
  585. } else if ((!packetAddress.equals(connectedAddress)) ||
  586. p.getPort() != connectedPort) {
  587. throw new SecurityException("connected address and packet address" +
  588. " differ");
  589. }
  590. }
  591. byte dttl = getTTL();
  592. try {
  593. if (ttl != dttl) {
  594. // set the ttl
  595. getImpl().setTTL(ttl);
  596. }
  597. // call the datagram method to send
  598. getImpl().send(p);
  599. } finally {
  600. // set it back to default
  601. if (ttl != dttl) {
  602. getImpl().setTTL(dttl);
  603. }
  604. }
  605. } // synch p
  606. } //synch ttl
  607. } //method
  608. }