1 /* 2 * Copyright (c) 2001, 2017, 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 #include "jni.h" 29 #include "jni_util.h" 30 #include "jvm.h" 31 #include "jlong.h" 32 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 81 JNIEXPORT void JNICALL 82 Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz) 83 { 84 initInetAddressIDs(env); 85 } 86 87 JNIEXPORT jboolean JNICALL 88 Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl) 89 { 90 /* 91 * Return true if IPv6 is configured 92 */ 93 return ipv6_available() ? JNI_TRUE : JNI_FALSE; 94 } 95 96 JNIEXPORT jboolean JNICALL 97 Java_sun_nio_ch_Net_isReusePortAvailable0(JNIEnv* env, jclass c1) 98 { 99 // SO_REUSEPORT is not supported on Windows 100 return JNI_FALSE; 101 } 102 103 JNIEXPORT jint JNICALL 104 Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) { 105 return 1; 106 } 107 108 109 JNIEXPORT jboolean JNICALL 110 Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl) 111 { 112 return JNI_FALSE; 113 } 114 115 JNIEXPORT jboolean JNICALL 116 Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl) 117 { 118 return JNI_FALSE; 119 } 120 121 JNIEXPORT jint JNICALL 122 Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, 123 jboolean stream, jboolean reuse, jboolean fastLoopback) 124 { 125 SOCKET s; 126 int domain = (preferIPv6) ? AF_INET6 : AF_INET; 127 128 s = socket(domain, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); 129 if (s != INVALID_SOCKET) { 130 SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0); 131 132 /* IPV6_V6ONLY is true by default */ 133 if (domain == AF_INET6) { 134 int opt = 0; 135 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 136 (const char *)&opt, sizeof(opt)); 137 } 138 139 /* Disable WSAECONNRESET errors for initially unconnected UDP sockets */ 140 if (!stream) { 141 setConnectionReset(s, FALSE); 142 } 143 144 } else { 145 NET_ThrowNew(env, WSAGetLastError(), "socket"); 146 } 147 148 if (stream && fastLoopback) { 149 static int loopback_available = 1; 150 if (loopback_available) { 151 int rv = NET_EnableFastTcpLoopback((jint)s); 152 if (rv) { 153 if (rv == WSAEOPNOTSUPP) { 154 loopback_available = 0; 155 } else { 156 NET_ThrowNew(env, rv, "fastLoopback"); 157 } 158 } 159 } 160 } 161 162 return (jint)s; 163 } 164 165 JNIEXPORT void JNICALL 166 Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6, 167 jboolean isExclBind, jobject iao, jint port) 168 { 169 SOCKETADDRESS sa; 170 int rv; 171 int sa_len = 0; 172 173 if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) { 174 return; 175 } 176 177 rv = NET_WinBind(fdval(env, fdo), &sa, sa_len, isExclBind); 178 if (rv == SOCKET_ERROR) 179 NET_ThrowNew(env, WSAGetLastError(), "bind"); 180 } 181 182 JNIEXPORT void JNICALL 183 Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog) 184 { 185 if (listen(fdval(env,fdo), backlog) == SOCKET_ERROR) { 186 NET_ThrowNew(env, WSAGetLastError(), "listen"); 187 } 188 } 189 190 191 JNIEXPORT jint JNICALL 192 Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, jobject fdo, 193 jobject iao, jint port) 194 { 195 SOCKETADDRESS sa; 196 int rv; 197 int so_rv; 198 int sa_len = 0; 199 SOCKET s = (SOCKET)fdval(env, fdo); 200 int type = 0, optlen = sizeof(type); 201 202 if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) { 203 return IOS_THROWN; 204 } 205 206 so_rv = getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&type, &optlen); 207 208 /** 209 * Windows has a very long socket connect timeout of 2 seconds. 210 * If it's the loopback adapter we can shorten the wait interval. 211 */ 212 if (so_rv == 0 && type == SOCK_STREAM && IS_LOOPBACK_ADDRESS(&sa)) { 213 NET_EnableFastTcpLoopbackConnect((jint)s); 214 } 215 216 rv = connect(s, &sa.sa, sa_len); 217 if (rv != 0) { 218 int err = WSAGetLastError(); 219 if (err == WSAEINPROGRESS || err == WSAEWOULDBLOCK) { 220 return IOS_UNAVAILABLE; 221 } 222 NET_ThrowNew(env, err, "connect"); 223 return IOS_THROWN; 224 } else { 225 /* Enable WSAECONNRESET errors when a UDP socket is connected */ 226 if (so_rv == 0 && type == SOCK_DGRAM) { 227 setConnectionReset(s, TRUE); 228 } 229 } 230 return 1; 231 } 232 233 JNIEXPORT jint JNICALL 234 Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo) 235 { 236 SOCKETADDRESS sa; 237 int sa_len = sizeof(sa); 238 239 if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) { 240 int error = WSAGetLastError(); 241 if (error == WSAEINVAL) { 242 return 0; 243 } 244 NET_ThrowNew(env, error, "getsockname"); 245 return IOS_THROWN; 246 } 247 return NET_GetPortFromSockaddr(&sa); 248 } 249 250 JNIEXPORT jobject JNICALL 251 Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo) 252 { 253 SOCKETADDRESS sa; 254 int sa_len = sizeof(sa); 255 int port; 256 257 if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) { 258 NET_ThrowNew(env, WSAGetLastError(), "getsockname"); 259 return NULL; 260 } 261 return NET_SockaddrToInetAddress(env, &sa, &port); 262 } 263 264 JNIEXPORT jint JNICALL 265 Java_sun_nio_ch_Net_remotePort(JNIEnv *env, jclass clazz, jobject fdo) 266 { 267 SOCKETADDRESS sa; 268 int sa_len = sizeof(sa); 269 270 if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) { 271 int error = WSAGetLastError(); 272 if (error == WSAEINVAL) { 273 return 0; 274 } 275 NET_ThrowNew(env, error, "getsockname"); 276 return IOS_THROWN; 277 } 278 return NET_GetPortFromSockaddr(&sa); 279 } 280 281 JNIEXPORT jobject JNICALL 282 Java_sun_nio_ch_Net_remoteInetAddress(JNIEnv *env, jclass clazz, jobject fdo) 283 { 284 SOCKETADDRESS sa; 285 int sa_len = sizeof(sa); 286 int port; 287 288 if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) { 289 NET_ThrowNew(env, WSAGetLastError(), "getsockname"); 290 return NULL; 291 } 292 return NET_SockaddrToInetAddress(env, &sa, &port); 293 } 294 295 JNIEXPORT jint JNICALL 296 Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 297 jboolean mayNeedConversion, jint level, jint opt) 298 { 299 int result = 0; 300 struct linger linger; 301 char *arg; 302 int arglen, n; 303 304 if (level == SOL_SOCKET && opt == SO_LINGER) { 305 arg = (char *)&linger; 306 arglen = sizeof(linger); 307 } else { 308 arg = (char *)&result; 309 arglen = sizeof(result); 310 } 311 312 /** 313 * HACK: IP_TOS is deprecated on Windows and querying the option 314 * returns a protocol error. NET_GetSockOpt handles this and uses 315 * a fallback mechanism. Same applies to IPV6_TCLASS 316 */ 317 if ((level == IPPROTO_IP && opt == IP_TOS) || (level == IPPROTO_IPV6 && opt == IPV6_TCLASS)) { 318 mayNeedConversion = JNI_TRUE; 319 } 320 321 if (mayNeedConversion) { 322 n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, &arglen); 323 } else { 324 n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen); 325 } 326 if (n < 0) { 327 handleSocketError(env, WSAGetLastError()); 328 return IOS_THROWN; 329 } 330 331 if (level == SOL_SOCKET && opt == SO_LINGER) 332 return linger.l_onoff ? linger.l_linger : -1; 333 else 334 return result; 335 } 336 337 JNIEXPORT void JNICALL 338 Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 339 jboolean mayNeedConversion, jint level, jint opt, jint arg, jboolean ipv6) 340 { 341 struct linger linger; 342 char *parg; 343 int arglen, n; 344 345 if (level == SOL_SOCKET && opt == SO_LINGER) { 346 parg = (char *)&linger; 347 arglen = sizeof(linger); 348 if (arg >= 0) { 349 linger.l_onoff = 1; 350 linger.l_linger = (unsigned short)arg; 351 } else { 352 linger.l_onoff = 0; 353 linger.l_linger = 0; 354 } 355 } else { 356 parg = (char *)&arg; 357 arglen = sizeof(arg); 358 } 359 360 if (level == IPPROTO_IPV6 && opt == IPV6_TCLASS) { 361 /* No op */ 362 return; 363 } 364 365 if (mayNeedConversion) { 366 n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen); 367 } else { 368 n = setsockopt(fdval(env, fdo), level, opt, parg, arglen); 369 } 370 if (n < 0) 371 handleSocketError(env, WSAGetLastError()); 372 } 373 374 JNIEXPORT jint JNICALL 375 Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo, 376 jint group, jint interf, jint source) 377 { 378 struct ip_mreq mreq; 379 struct my_ip_mreq_source mreq_source; 380 int opt, n, optlen; 381 void* optval; 382 383 if (source == 0) { 384 mreq.imr_multiaddr.s_addr = htonl(group); 385 mreq.imr_interface.s_addr = htonl(interf); 386 opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; 387 optval = (void*)&mreq; 388 optlen = sizeof(mreq); 389 } else { 390 mreq_source.imr_multiaddr.s_addr = htonl(group); 391 mreq_source.imr_sourceaddr.s_addr = htonl(source); 392 mreq_source.imr_interface.s_addr = htonl(interf); 393 opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP; 394 optval = (void*)&mreq_source; 395 optlen = sizeof(mreq_source); 396 } 397 398 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen); 399 if (n < 0) { 400 if (join && (WSAGetLastError() == WSAENOPROTOOPT)) 401 return IOS_UNAVAILABLE; 402 handleSocketError(env, WSAGetLastError()); 403 } 404 return 0; 405 } 406 407 JNIEXPORT jint JNICALL 408 Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo, 409 jint group, jint interf, jint source) 410 { 411 struct my_ip_mreq_source mreq_source; 412 int n; 413 int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE; 414 415 mreq_source.imr_multiaddr.s_addr = htonl(group); 416 mreq_source.imr_sourceaddr.s_addr = htonl(source); 417 mreq_source.imr_interface.s_addr = htonl(interf); 418 419 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, 420 (void*)&mreq_source, sizeof(mreq_source)); 421 if (n < 0) { 422 if (block && (WSAGetLastError() == WSAENOPROTOOPT)) 423 return IOS_UNAVAILABLE; 424 handleSocketError(env, WSAGetLastError()); 425 } 426 return 0; 427 } 428 429 /** 430 * Call setsockopt with a IPPROTO_IPV6 level socket option 431 * and a group_source_req structure as the option value. The 432 * given IPv6 group, interface index, and IPv6 source address 433 * are copied into the structure. 434 */ 435 static int setGroupSourceReqOption(JNIEnv* env, 436 jobject fdo, 437 int opt, 438 jbyteArray group, 439 jint index, 440 jbyteArray source) 441 { 442 struct my_group_source_req req; 443 struct sockaddr_in6* sin6; 444 445 req.gsr_interface = (ULONG)index; 446 447 sin6 = (struct sockaddr_in6*)&(req.gsr_group); 448 sin6->sin6_family = AF_INET6; 449 COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr)); 450 451 sin6 = (struct sockaddr_in6*)&(req.gsr_source); 452 sin6->sin6_family = AF_INET6; 453 COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr)); 454 455 return setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, (void*)&req, sizeof(req)); 456 } 457 458 JNIEXPORT jint JNICALL 459 Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo, 460 jbyteArray group, jint index, jbyteArray source) 461 { 462 struct ipv6_mreq mreq6; 463 int n; 464 465 if (source == NULL) { 466 int opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP; 467 COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr)); 468 mreq6.ipv6mr_interface = (int)index; 469 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, 470 (void*)&mreq6, sizeof(mreq6)); 471 } else { 472 int opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP; 473 n = setGroupSourceReqOption(env, fdo, opt, group, index, source); 474 } 475 476 if (n < 0) { 477 handleSocketError(env, errno); 478 } 479 return 0; 480 } 481 482 JNIEXPORT jint JNICALL 483 Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo, 484 jbyteArray group, jint index, jbyteArray source) 485 { 486 int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE; 487 int n = setGroupSourceReqOption(env, fdo, opt, group, index, source); 488 if (n < 0) { 489 handleSocketError(env, errno); 490 } 491 return 0; 492 } 493 494 JNIEXPORT void JNICALL 495 Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf) 496 { 497 struct in_addr in; 498 int arglen = sizeof(struct in_addr); 499 int n; 500 501 in.s_addr = htonl(interf); 502 503 n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, 504 (void*)&(in.s_addr), arglen); 505 if (n < 0) { 506 handleSocketError(env, WSAGetLastError()); 507 } 508 } 509 510 JNIEXPORT jint JNICALL 511 Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo) 512 { 513 struct in_addr in; 514 int arglen = sizeof(struct in_addr); 515 int n; 516 517 n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen); 518 if (n < 0) { 519 handleSocketError(env, WSAGetLastError()); 520 return IOS_THROWN; 521 } 522 return ntohl(in.s_addr); 523 } 524 525 JNIEXPORT void JNICALL 526 Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index) 527 { 528 int value = (jint)index; 529 int arglen = sizeof(value); 530 int n; 531 532 n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, 533 (void*)&(index), arglen); 534 if (n < 0) { 535 handleSocketError(env, errno); 536 } 537 } 538 539 JNIEXPORT jint JNICALL 540 Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo) 541 { 542 int index; 543 int arglen = sizeof(index); 544 int n; 545 546 n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen); 547 if (n < 0) { 548 handleSocketError(env, errno); 549 return -1; 550 } 551 return (jint)index; 552 } 553 554 JNIEXPORT void JNICALL 555 Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) { 556 int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SD_RECEIVE : 557 (jhow == sun_nio_ch_Net_SHUT_WR) ? SD_SEND : SD_BOTH; 558 if (shutdown(fdval(env, fdo), how) == SOCKET_ERROR) { 559 NET_ThrowNew(env, WSAGetLastError(), "shutdown"); 560 } 561 } 562 563 JNIEXPORT jint JNICALL 564 Java_sun_nio_ch_Net_poll(JNIEnv* env, jclass this, jobject fdo, jint events, jlong timeout) 565 { 566 int rv; 567 int revents = 0; 568 struct timeval t; 569 int lastError = 0; 570 fd_set rd, wr, ex; 571 jint fd = fdval(env, fdo); 572 573 t.tv_sec = (long)(timeout / 1000); 574 t.tv_usec = (timeout % 1000) * 1000; 575 576 FD_ZERO(&rd); 577 FD_ZERO(&wr); 578 FD_ZERO(&ex); 579 if (events & POLLIN) { 580 FD_SET(fd, &rd); 581 } 582 if (events & POLLOUT || 583 events & POLLCONN) { 584 FD_SET(fd, &wr); 585 } 586 FD_SET(fd, &ex); 587 588 rv = select(fd+1, &rd, &wr, &ex, &t); 589 590 /* save last winsock error */ 591 if (rv == SOCKET_ERROR) { 592 handleSocketError(env, lastError); 593 return IOS_THROWN; 594 } else if (rv >= 0) { 595 rv = 0; 596 if (FD_ISSET(fd, &rd)) { 597 rv |= POLLIN; 598 } 599 if (FD_ISSET(fd, &wr)) { 600 rv |= POLLOUT; 601 } 602 if (FD_ISSET(fd, &ex)) { 603 rv |= POLLERR; 604 } 605 } 606 return rv; 607 } 608 609 JNIEXPORT jshort JNICALL 610 Java_sun_nio_ch_Net_pollinValue(JNIEnv *env, jclass this) 611 { 612 return (jshort)POLLIN; 613 } 614 615 JNIEXPORT jshort JNICALL 616 Java_sun_nio_ch_Net_polloutValue(JNIEnv *env, jclass this) 617 { 618 return (jshort)POLLOUT; 619 } 620 621 JNIEXPORT jshort JNICALL 622 Java_sun_nio_ch_Net_pollerrValue(JNIEnv *env, jclass this) 623 { 624 return (jshort)POLLERR; 625 } 626 627 JNIEXPORT jshort JNICALL 628 Java_sun_nio_ch_Net_pollhupValue(JNIEnv *env, jclass this) 629 { 630 return (jshort)POLLHUP; 631 } 632 633 JNIEXPORT jshort JNICALL 634 Java_sun_nio_ch_Net_pollnvalValue(JNIEnv *env, jclass this) 635 { 636 return (jshort)POLLNVAL; 637 } 638 639 JNIEXPORT jshort JNICALL 640 Java_sun_nio_ch_Net_pollconnValue(JNIEnv *env, jclass this) 641 { 642 return (jshort)POLLCONN; 643 }