1. /*
  2. * @(#)DatagramSocket.java 1.40 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.FileDescriptor;
  9. import java.io.IOException;
  10. import java.io.InterruptedIOException;
  11. /**
  12. * This class represents a socket for sending and receiving datagram packets.
  13. *
  14. * <p>A datagram socket is the sending or receiving point for a packet
  15. * delivery service. Each packet sent or received on a datagram socket
  16. * is individually addressed and routed. Multiple packets sent from
  17. * one machine to another may be routed differently, and may arrive in
  18. * any order.
  19. *
  20. * <p>UDP broadcasts sends and receives are always enabled on a
  21. * DatagramSocket.
  22. *
  23. * @author Pavani Diwanji
  24. * @version 1.37, 10/30/98
  25. * @see java.net.DatagramPacket
  26. * @since JDK1.0
  27. */
  28. public
  29. class DatagramSocket {
  30. /*
  31. * The implementation of this DatagramSocket.
  32. */
  33. DatagramSocketImpl impl;
  34. boolean connected = false;
  35. InetAddress connectedAddress = null;
  36. int connectedPort = -1;
  37. /*
  38. * The Class of DatagramSocketImpl we use for this runtime.
  39. */
  40. static Class implClass;
  41. static {
  42. String prefix = "";
  43. try {
  44. prefix = (String) java.security.AccessController.doPrivileged(
  45. new sun.security.action.GetPropertyAction("impl.prefix",
  46. "Plain"));
  47. implClass = Class.forName("java.net."+prefix+"DatagramSocketImpl");
  48. } catch (Exception e) {
  49. System.err.println("Can't find class: java.net." + prefix +
  50. "DatagramSocketImpl: check impl.prefix property");
  51. }
  52. if (implClass == null) {
  53. try {
  54. implClass = Class.forName("java.net.PlainDatagramSocketImpl");
  55. } catch (Exception e) {
  56. throw new Error("System property impl.prefix incorrect");
  57. }
  58. }
  59. }
  60. /**
  61. * Constructs a datagram socket and binds it to any available port
  62. * on the local host machine.
  63. *
  64. * <p>If there is a security manager,
  65. * its <code>checkListen</code> method is first called
  66. * with 0 as its argument to ensure the operation is allowed.
  67. * This could result in a SecurityException.
  68. *
  69. * @exception SocketException if the socket could not be opened,
  70. * or the socket could not bind to the specified local port.
  71. * @exception SecurityException if a security manager exists and its
  72. * <code>checkListen</code> method doesn't allow the operation.
  73. *
  74. * @see SecurityManager#checkListen
  75. */
  76. public DatagramSocket() throws SocketException {
  77. // create a datagram socket.
  78. create(0, null);
  79. }
  80. /**
  81. * Constructs a datagram socket and binds it to the specified port
  82. * on the local host machine.
  83. *
  84. * <p>If there is a security manager,
  85. * its <code>checkListen</code> method is first called
  86. * with the <code>port</code> argument
  87. * as its argument to ensure the operation is allowed.
  88. * This could result in a SecurityException.
  89. *
  90. * @param port port to use.
  91. * @exception SocketException if the socket could not be opened,
  92. * or the socket could not bind to the specified local port.
  93. * @exception SecurityException if a security manager exists and its
  94. * <code>checkListen</code> method doesn't allow the operation.
  95. *
  96. * @see SecurityManager#checkListen
  97. */
  98. public DatagramSocket(int port) throws SocketException {
  99. this(port, null);
  100. }
  101. /**
  102. * Creates a datagram socket, bound to the specified local
  103. * address. The local port must be between 0 and 65535 inclusive.
  104. *
  105. * <p>If there is a security manager,
  106. * its <code>checkListen</code> method is first called
  107. * with the <code>port</code> argument
  108. * as its argument to ensure the operation is allowed.
  109. * This could result in a SecurityException.
  110. *
  111. * @param port local port to use
  112. * @param laddr local address to bind
  113. *
  114. * @exception SocketException if the socket could not be opened,
  115. * or the socket could not bind to the specified local port.
  116. * @exception SecurityException if a security manager exists and its
  117. * <code>checkListen</code> method doesn't allow the operation.
  118. *
  119. * @see SecurityManager#checkListen
  120. * @since JDK1.1
  121. */
  122. public DatagramSocket(int port, InetAddress laddr) throws SocketException {
  123. if (port < 0 || port > 0xFFFF)
  124. throw new IllegalArgumentException("Port out of range:"+port);
  125. create(port, laddr);
  126. }
  127. /* do the work of creating a vanilla datagramsocket. It is
  128. * important that the signature of this method not change,
  129. * even though it is package-private since it is overridden by
  130. * MulticastSocket, which must set SO_REUSEADDR.
  131. */
  132. void create(int port, InetAddress laddr) throws SocketException {
  133. SecurityManager sec = System.getSecurityManager();
  134. if (sec != null) {
  135. sec.checkListen(port);
  136. }
  137. try {
  138. impl = (DatagramSocketImpl) implClass.newInstance();
  139. } catch (Exception e) {
  140. throw new SocketException("can't instantiate DatagramSocketImpl");
  141. }
  142. // creates a udp socket
  143. impl.create();
  144. // binds the udp socket to desired port + address
  145. if (laddr == null) {
  146. laddr = InetAddress.anyLocalAddress;
  147. }
  148. impl.bind(port, laddr);
  149. }
  150. /**
  151. * Connects the socket to a remote address for this socket. When a
  152. * socket is connected to a remote address, packets may only be
  153. * sent to or received from that address. By default a datagram
  154. * socket is not connected.
  155. *
  156. * <p>A caller's permission to send and receive datagrams to a
  157. * given host and port are checked at connect time. When a socket
  158. * is connected, receive and send <b>will not
  159. * perform any security checks</b> on incoming and outgoing
  160. * packets, other than matching the packet's and the socket's
  161. * address and port. On a send operation, if the packet's address
  162. * is set and the packet's address and the socket's address do not
  163. * match, an IllegalArgumentException will be thrown. A socket
  164. * connected to a multicast address may only be used to send packets.
  165. *
  166. * @param address the remote address for the socket
  167. *
  168. * @param port the remote port for the socket.
  169. *
  170. * @exception IllegalArgumentException if the address is invalid
  171. * or the port is out of range.
  172. *
  173. * @exception SecurityException if the caller is not allowed to
  174. * send datagrams to and receive datagrams from the address and port.
  175. *
  176. * @see #disconnect
  177. * @see #send
  178. * @see #receive
  179. */
  180. public void connect(InetAddress address, int port) {
  181. synchronized (this) {
  182. if (port < 0 || port > 0xFFFF) {
  183. throw new IllegalArgumentException("connect: " + port);
  184. }
  185. if (address == null) {
  186. throw new IllegalArgumentException("connect: null address");
  187. }
  188. SecurityManager security = System.getSecurityManager();
  189. if (security != null) {
  190. if (address.isMulticastAddress()) {
  191. security.checkMulticast(address);
  192. } else {
  193. security.checkConnect(address.getHostAddress(), port);
  194. security.checkAccept(address.getHostAddress(), port);
  195. }
  196. }
  197. connectedAddress = address;
  198. connectedPort = port;
  199. connected = true;
  200. }
  201. }
  202. /**
  203. * Disconnects the socket. This does nothing if the socket is not
  204. * connected.
  205. *
  206. * @see #connect
  207. */
  208. public void disconnect() {
  209. synchronized (this) {
  210. connectedAddress = null;
  211. connectedPort = -1;
  212. connected = false;
  213. }
  214. }
  215. /**
  216. * Returns the address to which this socket is connected. Returns null
  217. * if the socket is not connected.
  218. *
  219. * @return the address to which this socket is connected.
  220. */
  221. public InetAddress getInetAddress() {
  222. return connectedAddress;
  223. }
  224. /**
  225. * Returns the port for this socket. Returns -1 if the socket is not
  226. * connected.
  227. *
  228. * @return the port to which this socket is connected.
  229. */
  230. public int getPort() {
  231. return connectedPort;
  232. }
  233. /**
  234. * Sends a datagram packet from this socket. The
  235. * <code>DatagramPacket</code> includes information indicating the
  236. * data to be sent, its length, the IP address of the remote host,
  237. * and the port number on the remote host.
  238. *
  239. * <p>If there is a security manager, and the socket is not currently
  240. * connected to a remote address, this method first performs some
  241. * security checks. First, if <code>p.getAddress().isMulticastAddress()</code>
  242. * is true, this method calls the
  243. * security manager's <code>checkMulticast</code> method
  244. * with <code>p.getAddress()</code> as its argument.
  245. * If the evaluation of that expression is false,
  246. * this method instead calls the security manager's
  247. * <code>checkConnect</code> method with arguments
  248. * <code>p.getAddress().getHostAddress()</code> and
  249. * <code>p.getPort()</code>. Each call to a security manager method
  250. * could result in a SecurityException if the operation is not allowed.
  251. *
  252. * @param p the <code>DatagramPacket</code> to be sent.
  253. *
  254. * @exception IOException if an I/O error occurs.
  255. * @exception SecurityException if a security manager exists and its
  256. * <code>checkMulticast</code> or <code>checkConnect</code>
  257. * method doesn't allow the send.
  258. *
  259. * @see java.net.DatagramPacket
  260. * @see SecurityManager#checkMulticast(InetAddress)
  261. * @see SecurityManager#checkConnect
  262. */
  263. public void send(DatagramPacket p) throws IOException {
  264. InetAddress packetAddress = null;
  265. synchronized (p) {
  266. if (!connected) {
  267. // check the address is ok wiht the security manager on every send.
  268. SecurityManager security = System.getSecurityManager();
  269. // The reason you want to synchronize on datagram packet
  270. // is because you dont want an applet to change the address
  271. // while you are trying to send the packet for example
  272. // after the security check but before the send.
  273. if (security != null) {
  274. if (p.getAddress().isMulticastAddress()) {
  275. security.checkMulticast(p.getAddress());
  276. } else {
  277. security.checkConnect(p.getAddress().getHostAddress(),
  278. p.getPort());
  279. }
  280. }
  281. } else {
  282. // we're connected
  283. packetAddress = p.getAddress();
  284. if (packetAddress == null) {
  285. p.setAddress(connectedAddress);
  286. p.setPort(connectedPort);
  287. } else if ((!packetAddress.equals(connectedAddress)) ||
  288. p.getPort() != connectedPort) {
  289. throw new IllegalArgumentException("connected address " +
  290. "and packet address" +
  291. " differ");
  292. }
  293. }
  294. // call the method to send
  295. impl.send(p);
  296. }
  297. }
  298. /**
  299. * Receives a datagram packet from this socket. When this method
  300. * returns, the <code>DatagramPacket</code>'s buffer is filled with
  301. * the data received. The datagram packet also contains the sender's
  302. * IP address, and the port number on the sender's machine.
  303. * <p>
  304. * This method blocks until a datagram is received. The
  305. * <code>length</code> field of the datagram packet object contains
  306. * the length of the received message. If the message is longer than
  307. * the packet's length, the message is truncated.
  308. * <p>
  309. * If there is a security manager, a packet cannot be received if the
  310. * security manager's <code>checkAccept</code> method
  311. * does not allow it.
  312. *
  313. * @param p the <code>DatagramPacket</code> into which to place
  314. * the incoming data.
  315. * @exception IOException if an I/O error occurs.
  316. * @see java.net.DatagramPacket
  317. * @see java.net.DatagramSocket
  318. */
  319. public synchronized void receive(DatagramPacket p) throws IOException {
  320. // check the address is ok with the security manager before every recv.
  321. SecurityManager security = null;
  322. synchronized (p) {
  323. if (connected || ((security = System.getSecurityManager()) != null)) {
  324. while(true) {
  325. // peek at the packet to see who it is from.
  326. InetAddress peekAddress = new InetAddress();
  327. int peekPort = impl.peek(peekAddress);
  328. if (connected) {
  329. if (!connectedAddress.equals(peekAddress) ||
  330. (connectedPort != peekPort)) {
  331. // throw the packet away and silently continue
  332. DatagramPacket tmp = new DatagramPacket(new byte[1], 1);
  333. impl.receive(tmp);
  334. continue;
  335. } else {
  336. break;
  337. }
  338. } else if (security != null) {
  339. try {
  340. security.checkAccept(peekAddress.getHostAddress(),
  341. peekPort);
  342. // security check succeeded - so now break
  343. // and recv the packet.
  344. break;
  345. } catch (SecurityException se) {
  346. // Throw away the offending packet by consuming
  347. // it in a tmp buffer.
  348. DatagramPacket tmp = new DatagramPacket(new byte[1], 1);
  349. impl.receive(tmp);
  350. // silently discard the offending packet
  351. // and continue: unknown/malicious
  352. // entities on nets should not make
  353. // runtime throw security exception and
  354. // disrupt the applet by sending random
  355. // datagram packets.
  356. continue;
  357. }
  358. }
  359. } // end of while
  360. }
  361. // If the security check succeeds, or the datagram is
  362. // connected then receive the packet
  363. impl.receive(p);
  364. }
  365. }
  366. /**
  367. * Gets the local address to which the socket is bound.
  368. *
  369. * <p>If there is a security manager, its
  370. * <code>checkConnect</code> method is first called
  371. * with the host address and <code>-1</code>
  372. * as its arguments to see if the operation is allowed.
  373. *
  374. * @exception SecurityException if a security manager exists and its
  375. * <code>checkConnect</code> method doesn't allow the operation.
  376. *
  377. * @see SecurityManager#checkConnect
  378. *
  379. * @since 1.1
  380. */
  381. public InetAddress getLocalAddress() {
  382. InetAddress in = null;
  383. try {
  384. in = (InetAddress) impl.getOption(SocketOptions.SO_BINDADDR);
  385. SecurityManager s = System.getSecurityManager();
  386. if (s != null) {
  387. s.checkConnect(in.getHostAddress(), -1);
  388. }
  389. } catch (Exception e) {
  390. in = InetAddress.anyLocalAddress; // "0.0.0.0"
  391. }
  392. return in;
  393. }
  394. /**
  395. * Returns the port number on the local host to which this socket is bound.
  396. *
  397. * @return the port number on the local host to which this socket is bound.
  398. */
  399. public int getLocalPort() {
  400. return impl.getLocalPort();
  401. }
  402. /** Enable/disable SO_TIMEOUT with the specified timeout, in
  403. * milliseconds. With this option set to a non-zero timeout,
  404. * a call to receive() for this DatagramSocket
  405. * will block for only this amount of time. If the timeout expires,
  406. * a <B>java.io.InterruptedIOException</B> is raised, though the
  407. * ServerSocket is still valid. The option <B>must</B> be enabled
  408. * prior to entering the blocking operation to have effect. The
  409. * timeout must be > 0.
  410. * A timeout of zero is interpreted as an infinite timeout.
  411. *
  412. * @since JDK1.1
  413. */
  414. public synchronized void setSoTimeout(int timeout) throws SocketException {
  415. impl.setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
  416. }
  417. /**
  418. * Retrive setting for SO_TIMEOUT. 0 returns implies that the
  419. * option is disabled (i.e., timeout of infinity).
  420. *
  421. * @since JDK1.1
  422. */
  423. public synchronized int getSoTimeout() throws SocketException {
  424. Object o = impl.getOption(SocketOptions.SO_TIMEOUT);
  425. /* extra type safety */
  426. if (o instanceof Integer) {
  427. return ((Integer) o).intValue();
  428. } else {
  429. return 0;
  430. }
  431. }
  432. /**
  433. * Sets the SO_SNDBUF option to the specified value for this
  434. * DatagramSocket. The SO_SNDBUF option is used by the platform's
  435. * networking code as a hint for the size to use to allocate set
  436. * the underlying network I/O buffers.
  437. *
  438. * <p>Increasing buffer size can increase the performance of
  439. * network I/O for high-volume connection, while decreasing it can
  440. * help reduce the backlog of incoming data. For UDP, this sets
  441. * the maximum size of a packet that may be sent on this socket.
  442. *
  443. * <p>Because SO_SNDBUF is a hint, applications that want to
  444. * verify what size the buffers were set to should call
  445. * <href="#getSendBufferSize>getSendBufferSize</a>.
  446. *
  447. * @param size the size to which to set the send buffer
  448. * size. This value must be greater than 0.
  449. *
  450. * @exception IllegalArgumentException if the value is 0 or is
  451. * negative.
  452. */
  453. public synchronized void setSendBufferSize(int size)
  454. throws SocketException{
  455. if (!(size > 0)) {
  456. throw new IllegalArgumentException("negative send size");
  457. }
  458. impl.setOption(SocketOptions.SO_SNDBUF, new Integer(size));
  459. }
  460. /**
  461. * Get value of the SO_SNDBUF option for this socket, that is the
  462. * buffer size used by the platform for output on the this Socket.
  463. *
  464. * @see #setSendBufferSize
  465. */
  466. public synchronized int getSendBufferSize() throws SocketException {
  467. int result = 0;
  468. Object o = impl.getOption(SocketOptions.SO_SNDBUF);
  469. if (o instanceof Integer) {
  470. result = ((Integer)o).intValue();
  471. }
  472. return result;
  473. }
  474. /**
  475. * Sets the SO_RCVBUF option to the specified value for this
  476. * DatagramSocket. The SO_RCVBUF option is used by the platform's
  477. * networking code as a hint for the size to use to allocate set
  478. * the underlying network I/O buffers.
  479. *
  480. * <p>Increasing buffer size can increase the performance of
  481. * network I/O for high-volume connection, while decreasing it can
  482. * help reduce the backlog of incoming data. For UDP, this sets
  483. * the maximum size of a packet that may be sent on this socket.
  484. *
  485. * <p>Because SO_RCVBUF is a hint, applications that want to
  486. * verify what size the buffers were set to should call
  487. * <href="#getReceiveBufferSize>getReceiveBufferSize</a>.
  488. *
  489. * @param size the size to which to set the receive buffer
  490. * size. This value must be greater than 0.
  491. *
  492. * @exception IllegalArgumentException if the value is 0 or is
  493. * negative.
  494. */
  495. public synchronized void setReceiveBufferSize(int size)
  496. throws SocketException{
  497. if (size < 0) {
  498. throw new IllegalArgumentException("invalid receive size");
  499. }
  500. impl.setOption(SocketOptions.SO_RCVBUF, new Integer(size));
  501. }
  502. /**
  503. * Get value of the SO_RCVBUF option for this socket, that is the
  504. * buffer size used by the platform for input on the this Socket.
  505. *
  506. * @see #setReceiveBufferSize
  507. */
  508. public synchronized int getReceiveBufferSize()
  509. throws SocketException{
  510. int result = 0;
  511. Object o = impl.getOption(SocketOptions.SO_RCVBUF);
  512. if (o instanceof Integer) {
  513. result = ((Integer)o).intValue();
  514. }
  515. return result;
  516. }
  517. /**
  518. * Closes this datagram socket.
  519. */
  520. public void close() {
  521. impl.close();
  522. }
  523. }