PageRenderTime 34ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/windows/native/java/net/DualStackPlainDatagramSocketImpl.c

https://github.com/ikeji/openjdk7-jdk
C | 496 lines | 316 code | 55 blank | 125 comment | 91 complexity | 36fac4b19e458453327bfce1db80e13c MD5 | raw file
  1. /*
  2. * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
  3. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4. *
  5. * This code is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License version 2 only, as
  7. * published by the Free Software Foundation. Oracle designates this
  8. * particular file as subject to the "Classpath" exception as provided
  9. * by Oracle in the LICENSE file that accompanied this code.
  10. *
  11. * This code is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14. * version 2 for more details (a copy is included in the LICENSE file that
  15. * accompanied this code).
  16. *
  17. * You should have received a copy of the GNU General Public License version
  18. * 2 along with this work; if not, write to the Free Software Foundation,
  19. * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20. *
  21. * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22. * or visit www.oracle.com if you need additional information or have any
  23. * questions.
  24. */
  25. #include <windows.h>
  26. #include <winsock2.h>
  27. #include "jni.h"
  28. #include "net_util.h"
  29. #include "java_net_DualStackPlainDatagramSocketImpl.h"
  30. /*
  31. * This function "purges" all outstanding ICMP port unreachable packets
  32. * outstanding on a socket and returns JNI_TRUE if any ICMP messages
  33. * have been purged. The rational for purging is to emulate normal BSD
  34. * behaviour whereby receiving a "connection reset" status resets the
  35. * socket.
  36. */
  37. static jboolean purgeOutstandingICMP(JNIEnv *env, jint fd)
  38. {
  39. jboolean got_icmp = JNI_FALSE;
  40. char buf[1];
  41. fd_set tbl;
  42. struct timeval t = { 0, 0 };
  43. struct sockaddr_in rmtaddr;
  44. int addrlen = sizeof(rmtaddr);
  45. /*
  46. * Peek at the queue to see if there is an ICMP port unreachable. If there
  47. * is then receive it.
  48. */
  49. FD_ZERO(&tbl);
  50. FD_SET(fd, &tbl);
  51. while(1) {
  52. if (select(/*ignored*/fd+1, &tbl, 0, 0, &t) <= 0) {
  53. break;
  54. }
  55. if (recvfrom(fd, buf, 1, MSG_PEEK,
  56. (struct sockaddr *)&rmtaddr, &addrlen) != JVM_IO_ERR) {
  57. break;
  58. }
  59. if (WSAGetLastError() != WSAECONNRESET) {
  60. /* some other error - we don't care here */
  61. break;
  62. }
  63. recvfrom(fd, buf, 1, 0, (struct sockaddr *)&rmtaddr, &addrlen);
  64. got_icmp = JNI_TRUE;
  65. }
  66. return got_icmp;
  67. }
  68. /*
  69. * Class: java_net_DualStackPlainDatagramSocketImpl
  70. * Method: socketCreate
  71. * Signature: (Z)I
  72. */
  73. JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketCreate
  74. (JNIEnv *env, jclass clazz, jboolean v6Only /*unused*/) {
  75. int fd, rv, opt=0, t=TRUE;
  76. DWORD x1, x2; /* ignored result codes */
  77. fd = (int) socket(AF_INET6, SOCK_DGRAM, 0);
  78. if (fd == INVALID_SOCKET) {
  79. NET_ThrowNew(env, WSAGetLastError(), "Socket creation failed");
  80. return -1;
  81. }
  82. rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, sizeof(opt));
  83. if (rv == SOCKET_ERROR) {
  84. NET_ThrowNew(env, WSAGetLastError(), "Socket creation failed");
  85. return -1;
  86. }
  87. SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
  88. NET_SetSockOpt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
  89. /* SIO_UDP_CONNRESET fixes a "bug" introduced in Windows 2000, which
  90. * returns connection reset errors on unconnected UDP sockets (as well
  91. * as connected sockets). The solution is to only enable this feature
  92. * when the socket is connected.
  93. */
  94. t = FALSE;
  95. WSAIoctl(fd ,SIO_UDP_CONNRESET ,&t ,sizeof(t) ,&x1 ,sizeof(x1) ,&x2 ,0 ,0);
  96. return fd;
  97. }
  98. /*
  99. * Class: java_net_DualStackPlainDatagramSocketImpl
  100. * Method: socketBind
  101. * Signature: (ILjava/net/InetAddress;I)V
  102. */
  103. JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketBind
  104. (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
  105. SOCKETADDRESS sa;
  106. int rv;
  107. int sa_len = sizeof(sa);
  108. if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa,
  109. &sa_len, JNI_TRUE) != 0) {
  110. return;
  111. }
  112. rv = bind(fd, (struct sockaddr *)&sa, sa_len);
  113. if (rv == SOCKET_ERROR) {
  114. if (WSAGetLastError() == WSAEACCES) {
  115. WSASetLastError(WSAEADDRINUSE);
  116. }
  117. NET_ThrowNew(env, WSAGetLastError(), "Cannot bind");
  118. }
  119. }
  120. /*
  121. * Class: java_net_DualStackPlainDatagramSocketImpl
  122. * Method: socketConnect
  123. * Signature: (ILjava/net/InetAddress;I)V
  124. */
  125. JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketConnect
  126. (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
  127. SOCKETADDRESS sa;
  128. int rv;
  129. int sa_len = sizeof(sa);
  130. DWORD x1, x2; /* ignored result codes */
  131. int t = TRUE;
  132. if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa,
  133. &sa_len, JNI_TRUE) != 0) {
  134. return;
  135. }
  136. rv = connect(fd, (struct sockaddr *)&sa, sa_len);
  137. if (rv == SOCKET_ERROR) {
  138. NET_ThrowNew(env, WSAGetLastError(), "connect");
  139. return;
  140. }
  141. /* see comment in socketCreate */
  142. WSAIoctl(fd, SIO_UDP_CONNRESET, &t, sizeof(t), &x1, sizeof(x1), &x2, 0, 0);
  143. }
  144. /*
  145. * Class: java_net_DualStackPlainDatagramSocketImpl
  146. * Method: socketDisconnect
  147. * Signature: (I)V
  148. */
  149. JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketDisconnect
  150. (JNIEnv *env, jclass clazz, jint fd ) {
  151. SOCKETADDRESS sa;
  152. int sa_len = sizeof(sa);
  153. DWORD x1, x2; /* ignored result codes */
  154. int t = FALSE;
  155. memset(&sa, 0, sa_len);
  156. connect(fd, (struct sockaddr *)&sa, sa_len);
  157. /* see comment in socketCreate */
  158. WSAIoctl(fd, SIO_UDP_CONNRESET, &t, sizeof(t), &x1, sizeof(x1), &x2, 0, 0);
  159. }
  160. /*
  161. * Class: java_net_DualStackPlainDatagramSocketImpl
  162. * Method: socketClose
  163. * Signature: (I)V
  164. */
  165. JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketClose
  166. (JNIEnv *env, jclass clazz , jint fd) {
  167. NET_SocketClose(fd);
  168. }
  169. /*
  170. * Class: java_net_DualStackPlainDatagramSocketImpl
  171. * Method: socketLocalPort
  172. * Signature: (I)I
  173. */
  174. JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketLocalPort
  175. (JNIEnv *env, jclass clazz, jint fd) {
  176. SOCKETADDRESS sa;
  177. int len = sizeof(sa);
  178. if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) {
  179. NET_ThrowNew(env, WSAGetLastError(), "JVM_GetSockName");
  180. return -1;
  181. }
  182. return (int) ntohs((u_short)GET_PORT(&sa));
  183. }
  184. /*
  185. * Class: java_net_DualStackPlainDatagramSocketImpl
  186. * Method: socketLocalAddress
  187. * Signature: (I)Ljava/lang/Object;
  188. */
  189. JNIEXPORT jobject JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketLocalAddress
  190. (JNIEnv *env , jclass clazz, jint fd) {
  191. SOCKETADDRESS sa;
  192. int len = sizeof(sa);
  193. jobject iaObj;
  194. int port;
  195. if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) {
  196. NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name");
  197. return NULL;
  198. }
  199. iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
  200. return iaObj;
  201. }
  202. /*
  203. * Class: java_net_DualStackPlainDatagramSocketImpl
  204. * Method: socketReceiveOrPeekData
  205. * Signature: (ILjava/net/DatagramPacket;IZZ)I
  206. */
  207. JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketReceiveOrPeekData
  208. (JNIEnv *env, jclass clazz, jint fd, jobject dpObj,
  209. jint timeout, jboolean connected, jboolean peek) {
  210. SOCKETADDRESS sa;
  211. int sa_len = sizeof(sa);
  212. int port, rv, flags=0;
  213. char BUF[MAX_BUFFER_LEN];
  214. char *fullPacket;
  215. BOOL retry;
  216. jlong prevTime = 0;
  217. jint packetBufferOffset, packetBufferLen;
  218. jbyteArray packetBuffer;
  219. /* if we are only peeking. Called from peekData */
  220. if (peek) {
  221. flags = MSG_PEEK;
  222. }
  223. packetBuffer = (*env)->GetObjectField(env, dpObj, dp_bufID);
  224. packetBufferOffset = (*env)->GetIntField(env, dpObj, dp_offsetID);
  225. packetBufferLen = (*env)->GetIntField(env, dpObj, dp_bufLengthID);
  226. if (packetBufferLen > MAX_BUFFER_LEN) {
  227. /* Note: the buffer needn't be greater than 65,536 (0xFFFF)
  228. * the max size of an IP packet. Anything bigger is truncated anyway.
  229. */
  230. if (packetBufferLen > MAX_PACKET_LEN) {
  231. packetBufferLen = MAX_PACKET_LEN;
  232. }
  233. fullPacket = (char *)malloc(packetBufferLen);
  234. if (!fullPacket) {
  235. JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
  236. return -1;
  237. }
  238. } else {
  239. fullPacket = &(BUF[0]);
  240. }
  241. do {
  242. retry = FALSE;
  243. if (timeout) {
  244. if (prevTime == 0) {
  245. prevTime = JVM_CurrentTimeMillis(env, 0);
  246. }
  247. rv = NET_Timeout(fd, timeout);
  248. if (rv <= 0) {
  249. if (rv == 0) {
  250. JNU_ThrowByName(env,JNU_JAVANETPKG "SocketTimeoutException",
  251. "Receive timed out");
  252. } else if (rv == JVM_IO_ERR) {
  253. JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
  254. "Socket closed");
  255. } else if (rv == JVM_IO_INTR) {
  256. JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
  257. "operation interrupted");
  258. }
  259. if (packetBufferLen > MAX_BUFFER_LEN) {
  260. free(fullPacket);
  261. }
  262. return -1;
  263. }
  264. }
  265. /* receive the packet */
  266. rv = recvfrom(fd, fullPacket, packetBufferLen, flags,
  267. (struct sockaddr *)&sa, &sa_len);
  268. if (rv == SOCKET_ERROR && (WSAGetLastError() == WSAECONNRESET)) {
  269. /* An icmp port unreachable - we must receive this as Windows
  270. * does not reset the state of the socket until this has been
  271. * received.
  272. */
  273. purgeOutstandingICMP(env, fd);
  274. if (connected) {
  275. JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
  276. "ICMP Port Unreachable");
  277. if (packetBufferLen > MAX_BUFFER_LEN)
  278. free(fullPacket);
  279. return -1;
  280. } else if (timeout) {
  281. /* Adjust timeout */
  282. jlong newTime = JVM_CurrentTimeMillis(env, 0);
  283. timeout -= (jint)(newTime - prevTime);
  284. if (timeout <= 0) {
  285. JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
  286. "Receive timed out");
  287. if (packetBufferLen > MAX_BUFFER_LEN)
  288. free(fullPacket);
  289. return -1;
  290. }
  291. prevTime = newTime;
  292. }
  293. retry = TRUE;
  294. }
  295. } while (retry);
  296. port = (int) ntohs ((u_short) GET_PORT((SOCKETADDRESS *)&sa));
  297. /* truncate the data if the packet's length is too small */
  298. if (rv > packetBufferLen) {
  299. rv = packetBufferLen;
  300. }
  301. if (rv < 0) {
  302. if (WSAGetLastError() == WSAEMSGSIZE) {
  303. /* it is because the buffer is too small. It's UDP, it's
  304. * unreliable, it's all good. discard the rest of the
  305. * data..
  306. */
  307. rv = packetBufferLen;
  308. } else {
  309. /* failure */
  310. (*env)->SetIntField(env, dpObj, dp_lengthID, 0);
  311. }
  312. }
  313. if (rv == -1) {
  314. JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
  315. } else if (rv == -2) {
  316. JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
  317. "operation interrupted");
  318. } else if (rv < 0) {
  319. NET_ThrowCurrent(env, "Datagram receive failed");
  320. } else {
  321. jobject packetAddress;
  322. /*
  323. * Check if there is an InetAddress already associated with this
  324. * packet. If so, we check if it is the same source address. We
  325. * can't update any existing InetAddress because it is immutable
  326. */
  327. packetAddress = (*env)->GetObjectField(env, dpObj, dp_addressID);
  328. if (packetAddress != NULL) {
  329. if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&sa,
  330. packetAddress)) {
  331. /* force a new InetAddress to be created */
  332. packetAddress = NULL;
  333. }
  334. }
  335. if (packetAddress == NULL) {
  336. packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa,
  337. &port);
  338. /* stuff the new Inetaddress into the packet */
  339. (*env)->SetObjectField(env, dpObj, dp_addressID, packetAddress);
  340. }
  341. /* populate the packet */
  342. (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, rv,
  343. (jbyte *)fullPacket);
  344. (*env)->SetIntField(env, dpObj, dp_portID, port);
  345. (*env)->SetIntField(env, dpObj, dp_lengthID, rv);
  346. }
  347. if (packetBufferLen > MAX_BUFFER_LEN) {
  348. free(fullPacket);
  349. }
  350. return port;
  351. }
  352. /*
  353. * Class: java_net_DualStackPlainDatagramSocketImpl
  354. * Method: socketSend
  355. * Signature: (I[BIILjava/net/InetAddress;IZ)V
  356. */
  357. JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketSend
  358. (JNIEnv *env, jclass clazz, jint fd, jbyteArray data, jint offset, jint length,
  359. jobject iaObj, jint port, jboolean connected) {
  360. SOCKETADDRESS sa;
  361. int sa_len = sizeof(sa);
  362. SOCKETADDRESS *sap = &sa;
  363. char BUF[MAX_BUFFER_LEN];
  364. char *fullPacket;
  365. int rv;
  366. if (connected) {
  367. sap = 0; /* arg to JVM_Sendto () null in this case */
  368. sa_len = 0;
  369. } else {
  370. if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa,
  371. &sa_len, JNI_TRUE) != 0) {
  372. return;
  373. }
  374. }
  375. if (length > MAX_BUFFER_LEN) {
  376. /* Note: the buffer needn't be greater than 65,536 (0xFFFF)
  377. * the max size of an IP packet. Anything bigger is truncated anyway.
  378. */
  379. if (length > MAX_PACKET_LEN) {
  380. length = MAX_PACKET_LEN;
  381. }
  382. fullPacket = (char *)malloc(length);
  383. if (!fullPacket) {
  384. JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
  385. return;
  386. }
  387. } else {
  388. fullPacket = &(BUF[0]);
  389. }
  390. (*env)->GetByteArrayRegion(env, data, offset, length,
  391. (jbyte *)fullPacket);
  392. rv = sendto(fd, fullPacket, length, 0, (struct sockaddr *)sap, sa_len);
  393. if (rv == SOCKET_ERROR) {
  394. if (rv == JVM_IO_ERR) {
  395. NET_ThrowNew(env, WSAGetLastError(), "Datagram send failed");
  396. } else if (rv == JVM_IO_INTR) {
  397. JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
  398. "operation interrupted");
  399. }
  400. }
  401. if (length > MAX_BUFFER_LEN) {
  402. free(fullPacket);
  403. }
  404. }
  405. /*
  406. * Class: java_net_DualStackPlainDatagramSocketImpl
  407. * Method: socketSetIntOption
  408. * Signature: (III)V
  409. */
  410. JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketSetIntOption
  411. (JNIEnv *env, jclass clazz, jint fd , jint cmd, jint value) {
  412. int level, opt;
  413. if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
  414. JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
  415. "Invalid option");
  416. return;
  417. }
  418. if (NET_SetSockOpt(fd, level, opt, (char *)&value, sizeof(value)) < 0) {
  419. NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
  420. }
  421. }
  422. /*
  423. * Class: java_net_DualStackPlainDatagramSocketImpl
  424. * Method: socketGetIntOption
  425. * Signature: (II)I
  426. */
  427. JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketGetIntOption
  428. (JNIEnv *env, jclass clazz, jint fd, jint cmd) {
  429. int level, opt, result=0;
  430. int result_len = sizeof(result);
  431. if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
  432. JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
  433. "Invalid option");
  434. return -1;
  435. }
  436. if (NET_GetSockOpt(fd, level, opt, (void *)&result, &result_len) < 0) {
  437. NET_ThrowNew(env, WSAGetLastError(), "getsockopt");
  438. return -1;
  439. }
  440. return result;
  441. }