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