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