1. /*
  2. * @(#)PlainDatagramSocketImpl.java 1.39 03/12/19
  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.FileDescriptor;
  9. import java.io.IOException;
  10. import java.io.InterruptedIOException;
  11. import java.util.Enumeration;
  12. /**
  13. * Concrete datagram and multicast socket implementation base class.
  14. * Note: This is not a public class, so that applets cannot call
  15. * into the implementation directly and hence cannot bypass the
  16. * security checks present in the DatagramSocket and MulticastSocket
  17. * classes.
  18. *
  19. * @author Pavani Diwanji
  20. */
  21. class PlainDatagramSocketImpl extends DatagramSocketImpl
  22. {
  23. /* timeout value for receive() */
  24. private int timeout = 0;
  25. private int trafficClass = 0;
  26. private boolean connected = false;
  27. private InetAddress connectedAddress = null;
  28. private int connectedPort = -1;
  29. /* cached socket options */
  30. private int multicastInterface = 0;
  31. private boolean loopbackMode = true;
  32. private int ttl = -1;
  33. /* Used for IPv6 on Windows only */
  34. private FileDescriptor fd1;
  35. private int fduse=-1; /* saved between peek() and receive() calls */
  36. /* saved between successive calls to receive, if data is detected
  37. * on both sockets at same time. To ensure that one socket is not
  38. * starved, they rotate using this field
  39. */
  40. private int lastfd=-1;
  41. /*
  42. * Needed for ipv6 on windows because we need to know
  43. * if the socket was bound to ::0 or 0.0.0.0, when a caller
  44. * asks for it. In this case, both sockets are used, but we
  45. * don't know whether the caller requested ::0 or 0.0.0.0
  46. * and need to remember it here.
  47. */
  48. private InetAddress anyLocalBoundAddr=null;
  49. /**
  50. * Load net library into runtime.
  51. */
  52. static {
  53. java.security.AccessController.doPrivileged(
  54. new sun.security.action.LoadLibraryAction("net"));
  55. init();
  56. }
  57. /**
  58. * Creates a datagram socket
  59. */
  60. protected synchronized void create() throws SocketException {
  61. fd = new FileDescriptor();
  62. fd1 = new FileDescriptor();
  63. datagramSocketCreate();
  64. }
  65. /**
  66. * Binds a datagram socket to a local port.
  67. */
  68. protected synchronized void bind(int lport, InetAddress laddr)
  69. throws SocketException {
  70. bind0(lport, laddr);
  71. if (laddr.isAnyLocalAddress()) {
  72. anyLocalBoundAddr = laddr;
  73. }
  74. }
  75. protected synchronized native void bind0(int lport, InetAddress laddr)
  76. throws SocketException;
  77. /**
  78. * Sends a datagram packet. The packet contains the data and the
  79. * destination address to send the packet to.
  80. * @param packet to be sent.
  81. */
  82. protected native void send(DatagramPacket p) throws IOException;
  83. /**
  84. * Connects a datagram socket to a remote destination. This associates the remote
  85. * address with the local socket so that datagrams may only be sent to this destination
  86. * and received from this destination.
  87. * @param address the remote InetAddress to connect to
  88. * @param port the remote port number
  89. */
  90. protected void connect(InetAddress address, int port) throws SocketException {
  91. connect0(address, port);
  92. connectedAddress = address;
  93. connectedPort = port;
  94. connected = true;
  95. }
  96. /**
  97. * Disconnects a previously connected socket. Does nothing if the socket was
  98. * not connected already.
  99. */
  100. protected void disconnect() {
  101. disconnect0(connectedAddress.family);
  102. connected = false;
  103. connectedAddress = null;
  104. connectedPort = -1;
  105. }
  106. /**
  107. * Peek at the packet to see who it is from.
  108. * @param return the address which the packet came from.
  109. */
  110. protected synchronized native int peek(InetAddress i) throws IOException;
  111. protected synchronized native int peekData(DatagramPacket p) throws IOException;
  112. /**
  113. * Receive the datagram packet.
  114. * @param Packet Received.
  115. */
  116. protected synchronized void receive(DatagramPacket p)
  117. throws IOException {
  118. try {
  119. receive0(p);
  120. } finally {
  121. fduse = -1;
  122. }
  123. }
  124. protected synchronized native void receive0(DatagramPacket p)
  125. throws IOException;
  126. /**
  127. * Set the TTL (time-to-live) option.
  128. * @param TTL to be set.
  129. */
  130. protected native void setTimeToLive(int ttl) throws IOException;
  131. /**
  132. * Get the TTL (time-to-live) option.
  133. */
  134. protected native int getTimeToLive() throws IOException;
  135. /**
  136. * Set the TTL (time-to-live) option.
  137. * @param TTL to be set.
  138. */
  139. protected native void setTTL(byte ttl) throws IOException;
  140. /**
  141. * Get the TTL (time-to-live) option.
  142. */
  143. protected native byte getTTL() throws IOException;
  144. /**
  145. * Join the multicast group.
  146. * @param multicast address to join.
  147. */
  148. protected void join(InetAddress inetaddr) throws IOException {
  149. join(inetaddr, null);
  150. }
  151. /**
  152. * Leave the multicast group.
  153. * @param multicast address to leave.
  154. */
  155. protected void leave(InetAddress inetaddr) throws IOException {
  156. leave(inetaddr, null);
  157. }
  158. /**
  159. * Join the multicast group.
  160. * @param multicast address to join.
  161. * @param netIf specifies the local interface to receive multicast
  162. * datagram packets
  163. * @throws IllegalArgumentException if mcastaddr is null or is a
  164. * SocketAddress subclass not supported by this socket
  165. * @since 1.4
  166. */
  167. protected void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)
  168. throws IOException {
  169. if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
  170. throw new IllegalArgumentException("Unsupported address type");
  171. join(((InetSocketAddress)mcastaddr).getAddress(), netIf);
  172. }
  173. private native void join(InetAddress inetaddr, NetworkInterface netIf)
  174. throws IOException;
  175. /**
  176. * Leave the multicast group.
  177. * @param multicast address to leave.
  178. * @param netIf specified the local interface to leave the group at
  179. * @throws IllegalArgumentException if mcastaddr is null or is a
  180. * SocketAddress subclass not supported by this socket
  181. * @since 1.4
  182. */
  183. protected void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)
  184. throws IOException {
  185. if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
  186. throw new IllegalArgumentException("Unsupported address type");
  187. leave(((InetSocketAddress)mcastaddr).getAddress(), netIf);
  188. }
  189. private native void leave(InetAddress inetaddr, NetworkInterface netIf)
  190. throws IOException;
  191. /**
  192. * Close the socket.
  193. */
  194. protected void close() {
  195. if (fd != null || fd1 != null) {
  196. datagramSocketClose();
  197. fd = null;
  198. fd1 = null;
  199. }
  200. }
  201. protected void finalize() {
  202. close();
  203. }
  204. /**
  205. * set a value - since we only support (setting) binary options
  206. * here, o must be a Boolean
  207. */
  208. public void setOption(int optID, Object o) throws SocketException {
  209. if (fd == null && fd1 == null) {
  210. throw new SocketException("Socket Closed");
  211. }
  212. switch (optID) {
  213. /* check type safety b4 going native. These should never
  214. * fail, since only java.Socket* has access to
  215. * PlainSocketImpl.setOption().
  216. */
  217. case SO_TIMEOUT:
  218. if (o == null || !(o instanceof Integer)) {
  219. throw new SocketException("bad argument for SO_TIMEOUT");
  220. }
  221. int tmp = ((Integer) o).intValue();
  222. if (tmp < 0)
  223. throw new IllegalArgumentException("timeout < 0");
  224. timeout = tmp;
  225. return;
  226. case IP_TOS:
  227. if (o == null || !(o instanceof Integer)) {
  228. throw new SocketException("bad argument for IP_TOS");
  229. }
  230. trafficClass = ((Integer)o).intValue();
  231. break;
  232. case SO_REUSEADDR:
  233. if (o == null || !(o instanceof Boolean)) {
  234. throw new SocketException("bad argument for SO_REUSEADDR");
  235. }
  236. break;
  237. case SO_BROADCAST:
  238. if (o == null || !(o instanceof Boolean)) {
  239. throw new SocketException("bad argument for SO_BROADCAST");
  240. }
  241. break;
  242. case SO_BINDADDR:
  243. throw new SocketException("Cannot re-bind Socket");
  244. case SO_RCVBUF:
  245. case SO_SNDBUF:
  246. if (o == null || !(o instanceof Integer) ||
  247. ((Integer)o).intValue() < 0) {
  248. throw new SocketException("bad argument for SO_SNDBUF or " +
  249. "SO_RCVBUF");
  250. }
  251. break;
  252. case IP_MULTICAST_IF:
  253. if (o == null || !(o instanceof InetAddress))
  254. throw new SocketException("bad argument for IP_MULTICAST_IF");
  255. break;
  256. case IP_MULTICAST_IF2:
  257. if (o == null || !(o instanceof NetworkInterface))
  258. throw new SocketException("bad argument for IP_MULTICAST_IF2");
  259. break;
  260. case IP_MULTICAST_LOOP:
  261. if (o == null || !(o instanceof Boolean))
  262. throw new SocketException("bad argument for IP_MULTICAST_LOOP");
  263. break;
  264. default:
  265. throw new SocketException("invalid option: " + optID);
  266. }
  267. socketSetOption(optID, o);
  268. }
  269. /*
  270. * get option's state - set or not
  271. */
  272. public Object getOption(int optID) throws SocketException {
  273. if (fd == null && fd1 == null) {
  274. throw new SocketException("Socket Closed");
  275. }
  276. Object result;
  277. switch (optID) {
  278. case SO_TIMEOUT:
  279. result = new Integer(timeout);
  280. break;
  281. case IP_TOS:
  282. result = socketGetOption(optID);
  283. if ( ((Integer)result).intValue() == -1) {
  284. result = new Integer(trafficClass);
  285. }
  286. break;
  287. case SO_BINDADDR:
  288. if (fd != null && fd1 != null) {
  289. return anyLocalBoundAddr;
  290. }
  291. /* fall through */
  292. case IP_MULTICAST_IF:
  293. case IP_MULTICAST_IF2:
  294. case SO_RCVBUF:
  295. case SO_SNDBUF:
  296. case IP_MULTICAST_LOOP:
  297. case SO_REUSEADDR:
  298. case SO_BROADCAST:
  299. result = socketGetOption(optID);
  300. break;
  301. default:
  302. throw new SocketException("invalid option: " + optID);
  303. }
  304. return result;
  305. }
  306. private native void datagramSocketCreate() throws SocketException;
  307. private native void datagramSocketClose();
  308. private native void socketSetOption(int opt, Object val)
  309. throws SocketException;
  310. private native Object socketGetOption(int opt) throws SocketException;
  311. private native void connect0(InetAddress address, int port) throws SocketException;
  312. private native void disconnect0(int family);
  313. /**
  314. * Perform class load-time initializations.
  315. */
  316. private native static void init();
  317. }