annotate src/windows/native/java/net/DualStackPlainDatagramSocketImpl.c @ 7940:b5bef1f71de6

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