1 /* 2 * Copyright (c) 2001, 2019, 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 26 #include <windows.h> 27 #include <winsock2.h> 28 29 #include "jni.h" 30 #include "jni_util.h" 31 #include "jvm.h" 32 #include "jlong.h" 33 #include "nio.h" 34 #include "nio_util.h" 35 #include "net_util.h" 36 37 #include "sun_nio_ch_Net.h" 38 #include "sun_nio_ch_PollArrayWrapper.h" 39 40 /** 41 * Definitions to allow for building with older SDK include files. 42 */ 43 44 #ifndef MCAST_BLOCK_SOURCE 45 46 #define MCAST_BLOCK_SOURCE 43 47 #define MCAST_UNBLOCK_SOURCE 44 48 #define MCAST_JOIN_SOURCE_GROUP 45 49 #define MCAST_LEAVE_SOURCE_GROUP 46 50 51 #endif /* MCAST_BLOCK_SOURCE */ 52 53 struct my_ip_mreq_source { 54 IN_ADDR imr_multiaddr; 55 IN_ADDR imr_sourceaddr; 56 IN_ADDR imr_interface; 57 }; 58 59 struct my_group_source_req { 60 ULONG gsr_interface; 61 SOCKADDR_STORAGE gsr_group; 62 SOCKADDR_STORAGE gsr_source; 63 }; 64 65 /** 66 * Copy IPv6 address as jbytearray to target 67 */ 68 #define COPY_INET6_ADDRESS(env, source, target) \ 69 (*env)->GetByteArrayRegion(env, source, 0, 16, target) 70 71 /** 72 * Enable or disable receipt of WSAECONNRESET errors. 73 */ 74 static void setConnectionReset(SOCKET s, BOOL enable) { 75 DWORD bytesReturned = 0; 76 WSAIoctl(s, SIO_UDP_CONNRESET, &enable, sizeof(enable), 77 NULL, 0, &bytesReturned, NULL, NULL); 78 } 79 80 jint handleSocketError(JNIEnv *env, int errorValue) 81 { 82 NET_ThrowNew(env, errorValue, NULL); 83 return IOS_THROWN; 84 } 85 86 static jclass isa_class; /* java.net.InetSocketAddress */ 87 static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */ 88 89 JNIEXPORT void JNICALL 90 Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz) 91 { 92 jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress"); 93 CHECK_NULL(cls); 94 isa_class = (*env)->NewGlobalRef(env, cls); 95 if (isa_class == NULL) { 96 JNU_ThrowOutOfMemoryError(env, NULL); 97 return; 98 } 99 isa_ctorID = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/net/InetAddress;I)V"); 100 CHECK_NULL(isa_ctorID); 101 102 initInetAddressIDs(env); 103 } 104 105 JNIEXPORT jboolean JNICALL 106 Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl) 107 { 108 /* 109 * Return true if IPv6 is configured 110 */ 111 return ipv6_available() ? JNI_TRUE : JNI_FALSE; 112 } 113 114 JNIEXPORT jboolean JNICALL 115 Java_sun_nio_ch_Net_isReusePortAvailable0(JNIEnv* env, jclass c1) 116 { 117 // SO_REUSEPORT is not supported on Windows 118 return JNI_FALSE; 119 } 120 121 JNIEXPORT jint JNICALL 122 Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) { 123 return 1; 124 } 125 126 JNIEXPORT jboolean JNICALL 127 Java_sun_nio_ch_Net_shouldSetBothIPv4AndIPv6Options0(JNIEnv* env, jclass cl) 128 { 129 /* Set both IPv4 and IPv6 socket options when setting multicast options */ 130 return JNI_TRUE; 131 } 132 133 JNIEXPORT jboolean JNICALL 134 Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl) 135 { 136 /* IPv6 sockets can join IPv4 multicast groups */ 137 return JNI_TRUE; 138 } 139 140 JNIEXPORT jboolean JNICALL 141 Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl) 142 { 143 /* IPV6_ADD_MEMBERSHIP cannot be used to join IPv4 multicast groups */ 144 return JNI_FALSE; 145 } 146 147 JNIEXPORT jboolean JNICALL 148 Java_sun_nio_ch_Net_canUseIPv6OptionsWithIPv4LocalAddress0(JNIEnv* env, jclass cl) 149 { 150 /* IPV6_XXX socket options cannot be used on IPv6 sockets bound to IPv4 address */ 151 return JNI_FALSE; 152 } 153 154 JNIEXPORT jint JNICALL 155 Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, 156 jboolean stream, jboolean reuse, jboolean fastLoopback) 157 { 158 SOCKET s; 159 int domain = (preferIPv6) ? AF_INET6 : AF_INET; 160 161 s = socket(domain, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); 162 if (s != INVALID_SOCKET) { 163 SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0); 164 165 /* IPV6_V6ONLY is true by default */ 166 if (domain == AF_INET6) { 167 int opt = 0; 168 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 169 (const char *)&opt, sizeof(opt)); 170 } 171 172 /* Disable WSAECONNRESET errors for initially unconnected UDP sockets */ 173 if (!stream) { 174 setConnectionReset(s, FALSE); 175 } 176 177 } else { 178 NET_ThrowNew(env, WSAGetLastError(), "socket"); 179 } 180 181 if (stream && fastLoopback) { 182 static int loopback_available = 1; 183 if (loopback_available) { 184 int rv = NET_EnableFastTcpLoopback((jint)s); 185 if (rv) { 186 if (rv == WSAEOPNOTSUPP) { 187 loopback_available = 0; 188 } else { 189 NET_ThrowNew(env, rv, "fastLoopback"); 190 } 191 } 192 } 193 } 194 195 return (jint)s; 196 } 197 198 JNIEXPORT void JNICALL 199 Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6, 200 jboolean isExclBind, jobject iao, jint port) 201 { 202 SOCKETADDRESS sa; 203 int rv; 204 int sa_len = 0; 205 206 if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) { 207 return; 208 } 209 210 rv = NET_WinBind(fdval(env, fdo), &sa, sa_len, isExclBind); 211 if (rv == SOCKET_ERROR) 212 NET_ThrowNew(env, WSAGetLastError(), "bind"); 213 } 214 215 JNIEXPORT void JNICALL 216 Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog) 217 { 218 if (listen(fdval(env,fdo), backlog) == SOCKET_ERROR) { 219 NET_ThrowNew(env, WSAGetLastError(), "listen"); 220 } 221 } 222 223 JNIEXPORT jint JNICALL 224 Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, jobject fdo, 225 jobject iao, jint port) 226 { 227 SOCKETADDRESS sa; 228 int rv; 229 int so_rv; 230 int sa_len = 0; 231 SOCKET s = (SOCKET)fdval(env, fdo); 232 int type = 0, optlen = sizeof(type); 233 234 if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) { 235 return IOS_THROWN; 236 } 237 238 so_rv = getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&type, &optlen); 239 240 /** 241 * Windows has a very long socket connect timeout of 2 seconds. 242 * If it's the loopback adapter we can shorten the wait interval. 243 */ 244 if (so_rv == 0 && type == SOCK_STREAM && IS_LOOPBACK_ADDRESS(&sa)) { 245 NET_EnableFastTcpLoopbackConnect((jint)s); 246 } 247 248 rv = connect(s, &sa.sa, sa_len); 249 if (rv != 0) { 250 int err = WSAGetLastError(); 251 if (err == WSAEINPROGRESS || err == WSAEWOULDBLOCK) { 252 return IOS_UNAVAILABLE; 253 } 254 NET_ThrowNew(env, err, "connect"); 255 return IOS_THROWN; 256 } else { 257 /* Enable WSAECONNRESET errors when a UDP socket is connected */ 258 if (so_rv == 0 && type == SOCK_DGRAM) { 259 setConnectionReset(s, TRUE); 260 } 261 } 262 return 1; 263 } 264 265 JNIEXPORT jint JNICALL 266 Java_sun_nio_ch_Net_accept(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo, 267 jobjectArray isaa) 268 { 269 jint fd = fdval(env,fdo); 270 jint newfd; 271 SOCKETADDRESS sa; 272 int addrlen = sizeof(sa); 273 jobject remote_ia; 274 jint remote_port = 0; 275 jobject isa; 276 277 memset((char *)&sa, 0, sizeof(sa)); 278 newfd = (jint) accept(fd, &sa.sa, &addrlen); 279 if (newfd == INVALID_SOCKET) { 280 int theErr = (jint)WSAGetLastError(); 281 if (theErr == WSAEWOULDBLOCK) { 282 return IOS_UNAVAILABLE; 283 } 284 JNU_ThrowIOExceptionWithLastError(env, "Accept failed"); 285 return IOS_THROWN; 286 } 287 288 SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0); 289 setfdval(env, newfdo, newfd); 290 291 remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port); 292 CHECK_NULL_RETURN(remote_ia, IOS_THROWN); 293 294 isa = (*env)->NewObject(env, isa_class, isa_ctorID, remote_ia, remote_port); 295 CHECK_NULL_RETURN(isa, IOS_THROWN); 296 (*env)->SetObjectArrayElement(env, isaa, 0, isa); 297 298 return 1; 299 } 300 301 JNIEXPORT jint JNICALL 302 Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo) 303 { 304 SOCKETADDRESS sa; 305 int sa_len = sizeof(sa); 306 307 if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) == SOCKET_ERROR) { 308 int error = WSAGetLastError(); 309 if (error == WSAEINVAL) { 310 return 0; 311 } 312 NET_ThrowNew(env, error, "getsockname"); 313 return IOS_THROWN; 314 } 315 return NET_GetPortFromSockaddr(&sa); 316 } 317 318 JNIEXPORT jobject JNICALL 319 Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo) 320 { 321 SOCKETADDRESS sa; 322 int sa_len = sizeof(sa); 323 int port; 324 325 if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) == SOCKET_ERROR) { 326 NET_ThrowNew(env, WSAGetLastError(), "getsockname"); 327 return NULL; 328 } 329 return NET_SockaddrToInetAddress(env, &sa, &port); 330 } 331 332 JNIEXPORT jint JNICALL 333 Java_sun_nio_ch_Net_remotePort(JNIEnv *env, jclass clazz, jobject fdo) 334 { 335 SOCKETADDRESS sa; 336 int sa_len = sizeof(sa); 337 338 if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) == SOCKET_ERROR) { 339 int error = WSAGetLastError(); 340 if (error == WSAEINVAL) { 341 return 0; 342 } 343 NET_ThrowNew(env, error, "getsockname"); 344 return IOS_THROWN; 345 } 346 return NET_GetPortFromSockaddr(&sa); 347 } 348 349 JNIEXPORT jobject JNICALL 350 Java_sun_nio_ch_Net_remoteInetAddress(JNIEnv *env, jclass clazz, jobject fdo) 351 { 352 SOCKETADDRESS sa; 353 int sa_len = sizeof(sa); 354 int port; 355 356 if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) == SOCKET_ERROR) { 357 NET_ThrowNew(env, WSAGetLastError(), "getsockname"); 358 return NULL; 359 } 360 return NET_SockaddrToInetAddress(env, &sa, &port); 361 } 362 363 JNIEXPORT jint JNICALL 364 Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 365 jboolean mayNeedConversion, jint level, jint opt) 366 { 367 int result = 0; 368 struct linger linger; 369 char *arg; 370 int arglen, n; 371 372 if (level == SOL_SOCKET && opt == SO_LINGER) { 373 arg = (char *)&linger; 374 arglen = sizeof(linger); 375 } else { 376 arg = (char *)&result; 377 arglen = sizeof(result); 378 } 379 380 /** 381 * HACK: IP_TOS is deprecated on Windows and querying the option 382 * returns a protocol error. NET_GetSockOpt handles this and uses 383 * a fallback mechanism. Same applies to IPV6_TCLASS 384 */ 385 if ((level == IPPROTO_IP && opt == IP_TOS) || (level == IPPROTO_IPV6 && opt == IPV6_TCLASS)) { 386 mayNeedConversion = JNI_TRUE; 387 } 388 389 if (mayNeedConversion) { 390 n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, &arglen); 391 } else { 392 n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen); 393 } 394 if (n == SOCKET_ERROR) { 395 handleSocketError(env, WSAGetLastError()); 396 return IOS_THROWN; 397 } 398 399 if (level == SOL_SOCKET && opt == SO_LINGER) 400 return linger.l_onoff ? linger.l_linger : -1; 401 else 402 return result; 403 } 404 405 JNIEXPORT void JNICALL 406 Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 407 jboolean mayNeedConversion, jint level, jint opt, jint arg, jboolean ipv6) 408 { 409 struct linger linger; 410 char *parg; 411 int arglen, n; 412 413 if (level == SOL_SOCKET && opt == SO_LINGER) { 414 parg = (char *)&linger; 415 arglen = sizeof(linger); 416 if (arg >= 0) { 417 linger.l_onoff = 1; 418 linger.l_linger = (unsigned short)arg; 419 } else { 420 linger.l_onoff = 0; 421 linger.l_linger = 0; 422 } 423 } else { 424 parg = (char *)&arg; 425 arglen = sizeof(arg); 426 } 427 428 if (level == IPPROTO_IPV6 && opt == IPV6_TCLASS) { 429 /* No op */ 430 return; 431 } 432 433 if (mayNeedConversion) { 434 n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen); 435 } else { 436 n = setsockopt(fdval(env, fdo), level, opt, parg, arglen); 437 } 438 if (n == SOCKET_ERROR) 439 handleSocketError(env, WSAGetLastError()); 440 } 441 442 JNIEXPORT jint JNICALL 443 Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo, 444 jint group, jint interf, jint source) 445 { 446 struct ip_mreq mreq; 447 struct my_ip_mreq_source mreq_source; 448 int opt, n, optlen; 449 void* optval; 450 451 if (source == 0) { 452 mreq.imr_multiaddr.s_addr = htonl(group); 453 mreq.imr_interface.s_addr = htonl(interf); 454 opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; 455 optval = (void*)&mreq; 456 optlen = sizeof(mreq); 457 } else { 458 mreq_source.imr_multiaddr.s_addr = htonl(group); 459 mreq_source.imr_sourceaddr.s_addr = htonl(source); 460 mreq_source.imr_interface.s_addr = htonl(interf); 461 opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP; 462 optval = (void*)&mreq_source; 463 optlen = sizeof(mreq_source); 464 } 465 466 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen); 467 if (n == SOCKET_ERROR) { 468 if (join && (WSAGetLastError() == WSAENOPROTOOPT)) 469 return IOS_UNAVAILABLE; 470 handleSocketError(env, WSAGetLastError()); 471 } 472 return 0; 473 } 474 475 JNIEXPORT jint JNICALL 476 Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo, 477 jint group, jint interf, jint source) 478 { 479 struct my_ip_mreq_source mreq_source; 480 int n; 481 int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE; 482 483 mreq_source.imr_multiaddr.s_addr = htonl(group); 484 mreq_source.imr_sourceaddr.s_addr = htonl(source); 485 mreq_source.imr_interface.s_addr = htonl(interf); 486 487 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, 488 (void*)&mreq_source, sizeof(mreq_source)); 489 if (n == SOCKET_ERROR) { 490 if (block && (WSAGetLastError() == WSAENOPROTOOPT)) 491 return IOS_UNAVAILABLE; 492 handleSocketError(env, WSAGetLastError()); 493 } 494 return 0; 495 } 496 497 /** 498 * Call setsockopt with a IPPROTO_IPV6 level socket option 499 * and a group_source_req structure as the option value. The 500 * given IPv6 group, interface index, and IPv6 source address 501 * are copied into the structure. 502 */ 503 static int setGroupSourceReqOption(JNIEnv* env, 504 jobject fdo, 505 int opt, 506 jbyteArray group, 507 jint index, 508 jbyteArray source) 509 { 510 struct my_group_source_req req; 511 struct sockaddr_in6* sin6; 512 513 req.gsr_interface = (ULONG)index; 514 515 sin6 = (struct sockaddr_in6*)&(req.gsr_group); 516 sin6->sin6_family = AF_INET6; 517 COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr)); 518 519 sin6 = (struct sockaddr_in6*)&(req.gsr_source); 520 sin6->sin6_family = AF_INET6; 521 COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr)); 522 523 return setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, (void*)&req, sizeof(req)); 524 } 525 526 JNIEXPORT jint JNICALL 527 Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo, 528 jbyteArray group, jint index, jbyteArray source) 529 { 530 struct ipv6_mreq mreq6; 531 int n; 532 533 if (source == NULL) { 534 int opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP; 535 COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr)); 536 mreq6.ipv6mr_interface = (int)index; 537 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, 538 (void*)&mreq6, sizeof(mreq6)); 539 } else { 540 int opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP; 541 n = setGroupSourceReqOption(env, fdo, opt, group, index, source); 542 } 543 544 if (n == SOCKET_ERROR) { 545 handleSocketError(env, WSAGetLastError()); 546 } 547 return 0; 548 } 549 550 JNIEXPORT jint JNICALL 551 Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo, 552 jbyteArray group, jint index, jbyteArray source) 553 { 554 int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE; 555 int n = setGroupSourceReqOption(env, fdo, opt, group, index, source); 556 if (n == SOCKET_ERROR) { 557 handleSocketError(env, WSAGetLastError()); 558 } 559 return 0; 560 } 561 562 JNIEXPORT void JNICALL 563 Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf) 564 { 565 struct in_addr in; 566 int arglen = sizeof(struct in_addr); 567 int n; 568 569 in.s_addr = htonl(interf); 570 571 n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, 572 (void*)&(in.s_addr), arglen); 573 if (n == SOCKET_ERROR) { 574 handleSocketError(env, WSAGetLastError()); 575 } 576 } 577 578 JNIEXPORT jint JNICALL 579 Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo) 580 { 581 struct in_addr in; 582 int arglen = sizeof(struct in_addr); 583 int n; 584 585 n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen); 586 if (n == SOCKET_ERROR) { 587 handleSocketError(env, WSAGetLastError()); 588 return IOS_THROWN; 589 } 590 return ntohl(in.s_addr); 591 } 592 593 JNIEXPORT void JNICALL 594 Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index) 595 { 596 DWORD value = (jint)index; 597 int arglen = sizeof(value); 598 int n; 599 600 n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, 601 (void*)&(index), arglen); 602 if (n == SOCKET_ERROR) { 603 handleSocketError(env, WSAGetLastError()); 604 } 605 } 606 607 JNIEXPORT jint JNICALL 608 Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo) 609 { 610 DWORD index; 611 int arglen = sizeof(index); 612 int n; 613 614 n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen); 615 if (n == SOCKET_ERROR) { 616 handleSocketError(env, WSAGetLastError()); 617 return -1; 618 } 619 return (jint)index; 620 } 621 622 JNIEXPORT void JNICALL 623 Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) { 624 int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SD_RECEIVE : 625 (jhow == sun_nio_ch_Net_SHUT_WR) ? SD_SEND : SD_BOTH; 626 if (shutdown(fdval(env, fdo), how) == SOCKET_ERROR) { 627 NET_ThrowNew(env, WSAGetLastError(), "shutdown"); 628 } 629 } 630 631 JNIEXPORT jint JNICALL 632 Java_sun_nio_ch_Net_available(JNIEnv *env, jclass cl, jobject fdo) 633 { 634 int count = 0; 635 if (NET_SocketAvailable(fdval(env, fdo), &count) != 0) { 636 handleSocketError(env, WSAGetLastError()); 637 return IOS_THROWN; 638 } 639 return (jint) count; 640 } 641 642 JNIEXPORT jint JNICALL 643 Java_sun_nio_ch_Net_poll(JNIEnv* env, jclass this, jobject fdo, jint events, jlong timeout) 644 { 645 int rv; 646 int revents = 0; 647 struct timeval t; 648 fd_set rd, wr, ex; 649 jint fd = fdval(env, fdo); 650 651 FD_ZERO(&rd); 652 FD_ZERO(&wr); 653 FD_ZERO(&ex); 654 if (events & POLLIN) { 655 FD_SET(fd, &rd); 656 } 657 if (events & POLLOUT || 658 events & POLLCONN) { 659 FD_SET(fd, &wr); 660 } 661 FD_SET(fd, &ex); 662 663 if (timeout >= 0) { 664 t.tv_sec = (long)(timeout / 1000); 665 t.tv_usec = (timeout % 1000) * 1000; 666 } 667 668 rv = select(fd+1, &rd, &wr, &ex, (timeout >= 0) ? &t : NULL); 669 670 /* save last winsock error */ 671 if (rv == SOCKET_ERROR) { 672 handleSocketError(env, WSAGetLastError()); 673 return IOS_THROWN; 674 } else if (rv >= 0) { 675 rv = 0; 676 if (FD_ISSET(fd, &rd)) { 677 rv |= POLLIN; 678 } 679 if (FD_ISSET(fd, &wr)) { 680 rv |= POLLOUT; 681 } 682 if (FD_ISSET(fd, &ex)) { 683 rv |= POLLERR; 684 } 685 } 686 return rv; 687 } 688 689 JNIEXPORT jboolean JNICALL 690 Java_sun_nio_ch_Net_pollConnect(JNIEnv* env, jclass this, jobject fdo, jlong timeout) 691 { 692 int optError = 0; 693 int result; 694 int n = sizeof(int); 695 jint fd = fdval(env, fdo); 696 fd_set wr, ex; 697 struct timeval t; 698 699 FD_ZERO(&wr); 700 FD_ZERO(&ex); 701 FD_SET((u_int)fd, &wr); 702 FD_SET((u_int)fd, &ex); 703 704 if (timeout >= 0) { 705 t.tv_sec = (long)(timeout / 1000); 706 t.tv_usec = (timeout % 1000) * 1000; 707 } 708 709 result = select(fd+1, 0, &wr, &ex, (timeout >= 0) ? &t : NULL); 710 711 if (result == SOCKET_ERROR) { 712 handleSocketError(env, WSAGetLastError()); 713 return JNI_FALSE; 714 } else if (result == 0) { 715 return JNI_FALSE; 716 } else { 717 // connection established if writable and no error to check 718 if (FD_ISSET(fd, &wr) && !FD_ISSET(fd, &ex)) { 719 return JNI_TRUE; 720 } 721 result = getsockopt((SOCKET)fd, 722 SOL_SOCKET, 723 SO_ERROR, 724 (char *)&optError, 725 &n); 726 if (result == SOCKET_ERROR) { 727 int lastError = WSAGetLastError(); 728 if (lastError != WSAEINPROGRESS) { 729 NET_ThrowNew(env, lastError, "getsockopt"); 730 } 731 } else if (optError != NO_ERROR) { 732 handleSocketError(env, optError); 733 } 734 return JNI_FALSE; 735 } 736 } 737 738 JNIEXPORT jshort JNICALL 739 Java_sun_nio_ch_Net_pollinValue(JNIEnv *env, jclass this) 740 { 741 return (jshort)POLLIN; 742 } 743 744 JNIEXPORT jshort JNICALL 745 Java_sun_nio_ch_Net_polloutValue(JNIEnv *env, jclass this) 746 { 747 return (jshort)POLLOUT; 748 } 749 750 JNIEXPORT jshort JNICALL 751 Java_sun_nio_ch_Net_pollerrValue(JNIEnv *env, jclass this) 752 { 753 return (jshort)POLLERR; 754 } 755 756 JNIEXPORT jshort JNICALL 757 Java_sun_nio_ch_Net_pollhupValue(JNIEnv *env, jclass this) 758 { 759 return (jshort)POLLHUP; 760 } 761 762 JNIEXPORT jshort JNICALL 763 Java_sun_nio_ch_Net_pollnvalValue(JNIEnv *env, jclass this) 764 { 765 return (jshort)POLLNVAL; 766 } 767 768 JNIEXPORT jshort JNICALL 769 Java_sun_nio_ch_Net_pollconnValue(JNIEnv *env, jclass this) 770 { 771 return (jshort)POLLCONN; 772 } 773 774 JNIEXPORT jint JNICALL 775 Java_sun_nio_ch_Net_sendOOB(JNIEnv* env, jclass this, jobject fdo, jbyte b) 776 { 777 int n = send(fdval(env, fdo), (const char*)&b, 1, MSG_OOB); 778 if (n == SOCKET_ERROR) { 779 if (WSAGetLastError() == WSAEWOULDBLOCK) { 780 return IOS_UNAVAILABLE; 781 } else { 782 JNU_ThrowIOExceptionWithLastError(env, "send failed"); 783 return IOS_THROWN; 784 } 785 } else { 786 return n; 787 } 788 }