1 /* 2 * Copyright (c) 2001, 2020, 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 <poll.h> 27 #include <sys/types.h> 28 #include <sys/socket.h> 29 #include <string.h> 30 #include <netinet/in.h> 31 #include <netinet/tcp.h> 32 #include <limits.h> 33 34 #include "jni.h" 35 #include "jni_util.h" 36 #include "jvm.h" 37 #include "jlong.h" 38 #include "sun_nio_ch_Net.h" 39 #include "net_util.h" 40 #include "net_util_md.h" 41 #include "nio_util.h" 42 #include "nio.h" 43 44 #ifdef _AIX 45 #include <stdlib.h> 46 #include <sys/utsname.h> 47 #endif 48 49 /** 50 * IP_MULTICAST_ALL supported since 2.6.31 but may not be available at 51 * build time. 52 */ 53 #ifdef __linux__ 54 #ifndef IP_MULTICAST_ALL 55 #define IP_MULTICAST_ALL 49 56 #endif 57 #endif 58 59 /** 60 * IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP may not be defined on OSX and AIX 61 */ 62 #if defined(__APPLE__) || defined(_AIX) 63 #ifndef IPV6_ADD_MEMBERSHIP 64 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP 65 #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP 66 #endif 67 #endif 68 69 #define COPY_INET6_ADDRESS(env, source, target) \ 70 (*env)->GetByteArrayRegion(env, source, 0, 16, target) 71 72 /* 73 * Copy IPv6 group, interface index, and IPv6 source address 74 * into group_source_req structure. 75 */ 76 static void initGroupSourceReq(JNIEnv* env, jbyteArray group, jint index, 77 jbyteArray source, struct group_source_req *req) 78 { 79 struct sockaddr_in6* sin6; 80 81 req->gsr_interface = (uint32_t)index; 82 83 sin6 = (struct sockaddr_in6 *)&(req->gsr_group); 84 sin6->sin6_family = AF_INET6; 85 COPY_INET6_ADDRESS(env, group, (jbyte *)&(sin6->sin6_addr)); 86 87 sin6 = (struct sockaddr_in6 *)&(req->gsr_source); 88 sin6->sin6_family = AF_INET6; 89 COPY_INET6_ADDRESS(env, source, (jbyte *)&(sin6->sin6_addr)); 90 } 91 92 #ifdef _AIX 93 94 /* 95 * Checks whether or not "socket extensions for multicast source filters" is supported. 96 * Returns JNI_TRUE if it is supported, JNI_FALSE otherwise 97 */ 98 static jboolean isSourceFilterSupported(){ 99 static jboolean alreadyChecked = JNI_FALSE; 100 static jboolean result = JNI_TRUE; 101 if (alreadyChecked != JNI_TRUE){ 102 struct utsname uts; 103 memset(&uts, 0, sizeof(uts)); 104 strcpy(uts.sysname, "?"); 105 const int utsRes = uname(&uts); 106 int major = -1; 107 int minor = -1; 108 major = atoi(uts.version); 109 minor = atoi(uts.release); 110 if (strcmp(uts.sysname, "AIX") == 0) { 111 if (major < 6 || (major == 6 && minor < 1)) {// unsupported on aix < 6.1 112 result = JNI_FALSE; 113 } 114 } 115 alreadyChecked = JNI_TRUE; 116 } 117 return result; 118 } 119 120 #endif /* _AIX */ 121 122 static jclass isa_class; /* java.net.InetSocketAddress */ 123 static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */ 124 125 JNIEXPORT void JNICALL 126 Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz) 127 { 128 jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress"); 129 CHECK_NULL(cls); 130 isa_class = (*env)->NewGlobalRef(env, cls); 131 if (isa_class == NULL) { 132 JNU_ThrowOutOfMemoryError(env, NULL); 133 return; 134 } 135 isa_ctorID = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/net/InetAddress;I)V"); 136 CHECK_NULL(isa_ctorID); 137 138 initInetAddressIDs(env); 139 } 140 141 JNIEXPORT jboolean JNICALL 142 Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl) 143 { 144 return (ipv6_available()) ? JNI_TRUE : JNI_FALSE; 145 } 146 147 JNIEXPORT jboolean JNICALL 148 Java_sun_nio_ch_Net_isReusePortAvailable0(JNIEnv* env, jclass c1) 149 { 150 return (reuseport_available()) ? JNI_TRUE : JNI_FALSE; 151 } 152 153 JNIEXPORT jint JNICALL 154 Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) { 155 return -1; 156 } 157 158 JNIEXPORT jboolean JNICALL 159 Java_sun_nio_ch_Net_shouldSetBothIPv4AndIPv6Options0(JNIEnv* env, jclass cl) 160 { 161 #if defined(__linux__) 162 /* Set both IPv4 and IPv6 socket options when setting multicast options */ 163 return JNI_TRUE; 164 #else 165 /* Do not set both IPv4 and IPv6 socket options when setting multicast options */ 166 return JNI_FALSE; 167 #endif 168 } 169 170 JNIEXPORT jboolean JNICALL 171 Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl) 172 { 173 #if defined(__linux__) || defined(__APPLE__) 174 /* IPv6 sockets can join IPv4 multicast groups */ 175 return JNI_TRUE; 176 #else 177 /* IPv6 sockets cannot join IPv4 multicast groups */ 178 return JNI_FALSE; 179 #endif 180 } 181 182 JNIEXPORT jboolean JNICALL 183 Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl) 184 { 185 #if defined(__APPLE__) 186 /* IPV6_ADD_MEMBERSHIP can be used to join IPv4 multicast groups */ 187 return JNI_TRUE; 188 #else 189 /* IPV6_ADD_MEMBERSHIP cannot be used to join IPv4 multicast groups */ 190 return JNI_FALSE; 191 #endif 192 } 193 194 JNIEXPORT jboolean JNICALL 195 Java_sun_nio_ch_Net_canUseIPv6OptionsWithIPv4LocalAddress0(JNIEnv* env, jclass cl) 196 { 197 /* IPV6_XXX socket options can be used on IPv6 sockets bound to IPv4 address */ 198 return JNI_TRUE; 199 } 200 201 JNIEXPORT jint JNICALL 202 Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, 203 jboolean stream, jboolean reuse, jboolean ignored) 204 { 205 int fd; 206 int type = (stream ? SOCK_STREAM : SOCK_DGRAM); 207 int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; 208 209 fd = socket(domain, type, 0); 210 if (fd < 0) { 211 return handleSocketError(env, errno); 212 } 213 214 /* 215 * If IPv4 is available, disable IPV6_V6ONLY to ensure dual-socket support. 216 */ 217 if (domain == AF_INET6 && ipv4_available()) { 218 int arg = 0; 219 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, 220 sizeof(int)) < 0) { 221 JNU_ThrowByNameWithLastError(env, 222 JNU_JAVANETPKG "SocketException", 223 "Unable to set IPV6_V6ONLY"); 224 close(fd); 225 return -1; 226 } 227 } 228 229 if (reuse) { 230 int arg = 1; 231 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, 232 sizeof(arg)) < 0) { 233 JNU_ThrowByNameWithLastError(env, 234 JNU_JAVANETPKG "SocketException", 235 "Unable to set SO_REUSEADDR"); 236 close(fd); 237 return -1; 238 } 239 } 240 241 #if defined(__linux__) 242 if (type == SOCK_DGRAM) { 243 int arg = 0; 244 int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP; 245 if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) && 246 (errno != ENOPROTOOPT)) { 247 JNU_ThrowByNameWithLastError(env, 248 JNU_JAVANETPKG "SocketException", 249 "Unable to set IP_MULTICAST_ALL"); 250 close(fd); 251 return -1; 252 } 253 } 254 255 /* By default, Linux uses the route default */ 256 if (domain == AF_INET6 && type == SOCK_DGRAM) { 257 int arg = 1; 258 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg, 259 sizeof(arg)) < 0) { 260 JNU_ThrowByNameWithLastError(env, 261 JNU_JAVANETPKG "SocketException", 262 "Unable to set IPV6_MULTICAST_HOPS"); 263 close(fd); 264 return -1; 265 } 266 } 267 #endif 268 269 #ifdef __APPLE__ 270 /** 271 * Attempt to set SO_SNDBUF to a minimum size to allow sending large datagrams 272 * (net.inet.udp.maxdgram defaults to 9216). 273 */ 274 if (type == SOCK_DGRAM) { 275 int size; 276 socklen_t arglen = sizeof(size); 277 if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, &arglen) == 0) { 278 int minSize = (domain == AF_INET6) ? 65527 : 65507; 279 if (size < minSize) { 280 setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &minSize, sizeof(minSize)); 281 } 282 } 283 } 284 #endif 285 286 return fd; 287 } 288 289 JNIEXPORT void JNICALL 290 Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6, 291 jboolean useExclBind, jobject iao, int port) 292 { 293 SOCKETADDRESS sa; 294 int sa_len = 0; 295 int rv = 0; 296 297 if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, 298 preferIPv6) != 0) { 299 return; 300 } 301 302 rv = NET_Bind(fdval(env, fdo), &sa, sa_len); 303 if (rv != 0) { 304 handleSocketError(env, errno); 305 } 306 } 307 308 JNIEXPORT void JNICALL 309 Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog) 310 { 311 if (listen(fdval(env, fdo), backlog) < 0) 312 handleSocketError(env, errno); 313 } 314 315 JNIEXPORT jint JNICALL 316 Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, 317 jobject fdo, jobject iao, jint port) 318 { 319 SOCKETADDRESS sa; 320 int sa_len = 0; 321 int rv; 322 323 if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) { 324 return IOS_THROWN; 325 } 326 327 rv = connect(fdval(env, fdo), &sa.sa, sa_len); 328 if (rv != 0) { 329 if (errno == EINPROGRESS) { 330 return IOS_UNAVAILABLE; 331 } else if (errno == EINTR) { 332 return IOS_INTERRUPTED; 333 } 334 return handleSocketError(env, errno); 335 } 336 return 1; 337 } 338 339 JNIEXPORT jint JNICALL 340 Java_sun_nio_ch_Net_accept(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo, 341 jobjectArray isaa) 342 { 343 jint fd = fdval(env, fdo); 344 jint newfd; 345 SOCKETADDRESS sa; 346 socklen_t sa_len = sizeof(SOCKETADDRESS); 347 jobject remote_ia; 348 jint remote_port = 0; 349 jobject isa; 350 351 /* accept connection but ignore ECONNABORTED */ 352 for (;;) { 353 newfd = accept(fd, &sa.sa, &sa_len); 354 if (newfd >= 0) { 355 break; 356 } 357 if (errno != ECONNABORTED) { 358 break; 359 } 360 /* ECONNABORTED => restart accept */ 361 } 362 363 if (newfd < 0) { 364 if (errno == EAGAIN || errno == EWOULDBLOCK) 365 return IOS_UNAVAILABLE; 366 if (errno == EINTR) 367 return IOS_INTERRUPTED; 368 JNU_ThrowIOExceptionWithLastError(env, "Accept failed"); 369 return IOS_THROWN; 370 } 371 372 setfdval(env, newfdo, newfd); 373 374 remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port); 375 CHECK_NULL_RETURN(remote_ia, IOS_THROWN); 376 377 isa = (*env)->NewObject(env, isa_class, isa_ctorID, remote_ia, remote_port); 378 CHECK_NULL_RETURN(isa, IOS_THROWN); 379 (*env)->SetObjectArrayElement(env, isaa, 0, isa); 380 381 return 1; 382 } 383 384 JNIEXPORT jint JNICALL 385 Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo) 386 { 387 SOCKETADDRESS sa; 388 socklen_t sa_len = sizeof(SOCKETADDRESS); 389 if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) { 390 #ifdef _ALLBSD_SOURCE 391 /* 392 * XXXBSD: 393 * ECONNRESET is specific to the BSDs. We can not return an error, 394 * as the calling Java code with raise a java.lang.Error given the expectation 395 * that getsockname() will never fail. According to the Single UNIX Specification, 396 * it shouldn't fail. As such, we just fill in generic Linux-compatible values. 397 */ 398 if (errno == ECONNRESET) { 399 bzero(&sa.sa4, sizeof(sa)); 400 sa.sa4.sin_len = sizeof(struct sockaddr_in); 401 sa.sa4.sin_family = AF_INET; 402 sa.sa4.sin_port = htonl(0); 403 sa.sa4.sin_addr.s_addr = INADDR_ANY; 404 } else { 405 handleSocketError(env, errno); 406 return -1; 407 } 408 #else /* _ALLBSD_SOURCE */ 409 handleSocketError(env, errno); 410 return -1; 411 #endif /* _ALLBSD_SOURCE */ 412 } 413 return NET_GetPortFromSockaddr(&sa); 414 } 415 416 JNIEXPORT jobject JNICALL 417 Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo) 418 { 419 SOCKETADDRESS sa; 420 socklen_t sa_len = sizeof(SOCKETADDRESS); 421 int port; 422 if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) { 423 #ifdef _ALLBSD_SOURCE 424 /* 425 * XXXBSD: 426 * ECONNRESET is specific to the BSDs. We can not return an error, 427 * as the calling Java code with raise a java.lang.Error with the expectation 428 * that getsockname() will never fail. According to the Single UNIX Specification, 429 * it shouldn't fail. As such, we just fill in generic Linux-compatible values. 430 */ 431 if (errno == ECONNRESET) { 432 bzero(&sa.sa4, sizeof(sa)); 433 sa.sa4.sin_len = sizeof(struct sockaddr_in); 434 sa.sa4.sin_family = AF_INET; 435 sa.sa4.sin_port = htonl(0); 436 sa.sa4.sin_addr.s_addr = INADDR_ANY; 437 } else { 438 handleSocketError(env, errno); 439 return NULL; 440 } 441 #else /* _ALLBSD_SOURCE */ 442 handleSocketError(env, errno); 443 return NULL; 444 #endif /* _ALLBSD_SOURCE */ 445 } 446 return NET_SockaddrToInetAddress(env, &sa, &port); 447 } 448 449 JNIEXPORT jint JNICALL 450 Java_sun_nio_ch_Net_remotePort(JNIEnv *env, jclass clazz, jobject fdo) 451 { 452 SOCKETADDRESS sa; 453 socklen_t sa_len = sizeof(sa); 454 455 if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) { 456 handleSocketError(env, errno); 457 return IOS_THROWN; 458 } 459 return NET_GetPortFromSockaddr(&sa); 460 } 461 462 JNIEXPORT jobject JNICALL 463 Java_sun_nio_ch_Net_remoteInetAddress(JNIEnv *env, jclass clazz, jobject fdo) 464 { 465 SOCKETADDRESS sa; 466 socklen_t sa_len = sizeof(sa); 467 int port; 468 469 if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) { 470 handleSocketError(env, errno); 471 return NULL; 472 } 473 return NET_SockaddrToInetAddress(env, &sa, &port); 474 } 475 476 JNIEXPORT jint JNICALL 477 Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 478 jboolean mayNeedConversion, jint level, jint opt) 479 { 480 int result; 481 struct linger linger; 482 u_char carg; 483 void *arg; 484 socklen_t arglen; 485 int n; 486 487 /* Option value is an int except for a few specific cases */ 488 489 arg = (void *)&result; 490 arglen = sizeof(result); 491 492 if (level == IPPROTO_IP && 493 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { 494 arg = (void*)&carg; 495 arglen = sizeof(carg); 496 } 497 498 if (level == SOL_SOCKET && opt == SO_LINGER) { 499 arg = (void *)&linger; 500 arglen = sizeof(linger); 501 } 502 503 if (mayNeedConversion) { 504 n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, (int*)&arglen); 505 } else { 506 n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen); 507 } 508 if (n < 0) { 509 JNU_ThrowByNameWithLastError(env, 510 JNU_JAVANETPKG "SocketException", 511 "sun.nio.ch.Net.getIntOption"); 512 return -1; 513 } 514 515 if (level == IPPROTO_IP && 516 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) 517 { 518 return (jint)carg; 519 } 520 521 if (level == SOL_SOCKET && opt == SO_LINGER) 522 return linger.l_onoff ? (jint)linger.l_linger : (jint)-1; 523 524 return (jint)result; 525 } 526 527 JNIEXPORT void JNICALL 528 Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 529 jboolean mayNeedConversion, jint level, 530 jint opt, jint arg, jboolean isIPv6) 531 { 532 int result; 533 struct linger linger; 534 u_char carg; 535 void *parg; 536 socklen_t arglen; 537 int n; 538 539 /* Option value is an int except for a few specific cases */ 540 541 parg = (void*)&arg; 542 arglen = sizeof(arg); 543 544 if (level == IPPROTO_IP && 545 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { 546 parg = (void*)&carg; 547 arglen = sizeof(carg); 548 carg = (u_char)arg; 549 } 550 551 if (level == SOL_SOCKET && opt == SO_LINGER) { 552 parg = (void *)&linger; 553 arglen = sizeof(linger); 554 if (arg >= 0) { 555 linger.l_onoff = 1; 556 linger.l_linger = arg; 557 } else { 558 linger.l_onoff = 0; 559 linger.l_linger = 0; 560 } 561 } 562 563 if (mayNeedConversion) { 564 n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen); 565 } else { 566 n = setsockopt(fdval(env, fdo), level, opt, parg, arglen); 567 } 568 if (n < 0) { 569 JNU_ThrowByNameWithLastError(env, 570 JNU_JAVANETPKG "SocketException", 571 "sun.nio.ch.Net.setIntOption"); 572 } 573 } 574 575 JNIEXPORT jint JNICALL 576 Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo, 577 jint group, jint interf, jint source) 578 { 579 struct ip_mreq mreq; 580 struct ip_mreq_source mreq_source; 581 int opt, n, optlen; 582 void* optval; 583 584 if (source == 0) { 585 mreq.imr_multiaddr.s_addr = htonl(group); 586 mreq.imr_interface.s_addr = htonl(interf); 587 opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; 588 optval = (void*)&mreq; 589 optlen = sizeof(mreq); 590 } else { 591 592 #ifdef _AIX 593 /* check AIX for support of source filtering */ 594 if (isSourceFilterSupported() != JNI_TRUE){ 595 return IOS_UNAVAILABLE; 596 } 597 #endif 598 599 mreq_source.imr_multiaddr.s_addr = htonl(group); 600 mreq_source.imr_sourceaddr.s_addr = htonl(source); 601 mreq_source.imr_interface.s_addr = htonl(interf); 602 opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP; 603 optval = (void*)&mreq_source; 604 optlen = sizeof(mreq_source); 605 } 606 607 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen); 608 #ifdef __APPLE__ 609 // workaround macOS bug where IP_ADD_MEMBERSHIP fails intermittently 610 if (n < 0 && errno == ENOMEM) { 611 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen); 612 } 613 #endif 614 615 if (n < 0) { 616 if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) 617 return IOS_UNAVAILABLE; 618 handleSocketError(env, errno); 619 } 620 return 0; 621 } 622 623 JNIEXPORT jint JNICALL 624 Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo, 625 jint group, jint interf, jint source) 626 { 627 #ifdef __APPLE__ 628 /* no IPv4 exclude-mode filtering for now */ 629 return IOS_UNAVAILABLE; 630 #else 631 struct ip_mreq_source mreq_source; 632 int n; 633 int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE; 634 635 #ifdef _AIX 636 /* check AIX for support of source filtering */ 637 if (isSourceFilterSupported() != JNI_TRUE){ 638 return IOS_UNAVAILABLE; 639 } 640 #endif 641 642 mreq_source.imr_multiaddr.s_addr = htonl(group); 643 mreq_source.imr_sourceaddr.s_addr = htonl(source); 644 mreq_source.imr_interface.s_addr = htonl(interf); 645 646 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, 647 (void*)&mreq_source, sizeof(mreq_source)); 648 if (n < 0) { 649 if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) 650 return IOS_UNAVAILABLE; 651 handleSocketError(env, errno); 652 } 653 return 0; 654 #endif 655 } 656 657 JNIEXPORT jint JNICALL 658 Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo, 659 jbyteArray group, jint index, jbyteArray source) 660 { 661 struct ipv6_mreq mreq6; 662 struct group_source_req req; 663 int opt, n, optlen; 664 void* optval; 665 666 if (source == NULL) { 667 COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr)); 668 mreq6.ipv6mr_interface = (int)index; 669 opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP; 670 optval = (void*)&mreq6; 671 optlen = sizeof(mreq6); 672 } else { 673 #ifdef __APPLE__ 674 /* no IPv6 include-mode filtering for now */ 675 return IOS_UNAVAILABLE; 676 #else 677 initGroupSourceReq(env, group, index, source, &req); 678 opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP; 679 optval = (void*)&req; 680 optlen = sizeof(req); 681 #endif 682 } 683 684 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen); 685 #ifdef __APPLE__ 686 // workaround macOS bug where IPV6_ADD_MEMBERSHIP fails intermittently 687 if (n < 0 && errno == ENOMEM) { 688 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen); 689 } 690 #endif 691 692 if (n < 0) { 693 if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) 694 return IOS_UNAVAILABLE; 695 handleSocketError(env, errno); 696 } 697 return 0; 698 } 699 700 JNIEXPORT jint JNICALL 701 Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo, 702 jbyteArray group, jint index, jbyteArray source) 703 { 704 #ifdef __APPLE__ 705 /* no IPv6 exclude-mode filtering for now */ 706 return IOS_UNAVAILABLE; 707 #else 708 struct group_source_req req; 709 int n; 710 int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE; 711 712 initGroupSourceReq(env, group, index, source, &req); 713 714 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, 715 (void*)&req, sizeof(req)); 716 if (n < 0) { 717 if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) 718 return IOS_UNAVAILABLE; 719 handleSocketError(env, errno); 720 } 721 return 0; 722 #endif 723 } 724 725 JNIEXPORT void JNICALL 726 Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf) 727 { 728 struct in_addr in; 729 socklen_t arglen = sizeof(struct in_addr); 730 int n; 731 732 in.s_addr = htonl(interf); 733 734 n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, 735 (void*)&(in.s_addr), arglen); 736 if (n < 0) { 737 handleSocketError(env, errno); 738 } 739 } 740 741 JNIEXPORT jint JNICALL 742 Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo) 743 { 744 struct in_addr in; 745 socklen_t arglen = sizeof(struct in_addr); 746 int n; 747 748 n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen); 749 if (n < 0) { 750 handleSocketError(env, errno); 751 return -1; 752 } 753 return ntohl(in.s_addr); 754 } 755 756 JNIEXPORT void JNICALL 757 Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index) 758 { 759 int value = (jint)index; 760 socklen_t arglen = sizeof(value); 761 int n; 762 763 n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, 764 (void*)&(index), arglen); 765 if (n < 0) { 766 handleSocketError(env, errno); 767 } 768 } 769 770 JNIEXPORT jint JNICALL 771 Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo) 772 { 773 int index; 774 socklen_t arglen = sizeof(index); 775 int n; 776 777 n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen); 778 if (n < 0) { 779 handleSocketError(env, errno); 780 return -1; 781 } 782 return (jint)index; 783 } 784 785 JNIEXPORT void JNICALL 786 Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) 787 { 788 int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD : 789 (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR; 790 if ((shutdown(fdval(env, fdo), how) < 0) && (errno != ENOTCONN)) 791 handleSocketError(env, errno); 792 } 793 794 JNIEXPORT jint JNICALL 795 Java_sun_nio_ch_Net_available(JNIEnv *env, jclass cl, jobject fdo) 796 { 797 int count = 0; 798 if (NET_SocketAvailable(fdval(env, fdo), &count) != 0) { 799 handleSocketError(env, errno); 800 return IOS_THROWN; 801 } 802 return (jint) count; 803 } 804 805 JNIEXPORT jint JNICALL 806 Java_sun_nio_ch_Net_poll(JNIEnv* env, jclass this, jobject fdo, jint events, jlong timeout) 807 { 808 struct pollfd pfd; 809 int rv; 810 pfd.fd = fdval(env, fdo); 811 pfd.events = events; 812 if (timeout < -1) { 813 timeout = -1; 814 } else if (timeout > INT_MAX) { 815 timeout = INT_MAX; 816 } 817 rv = poll(&pfd, 1, (int)timeout); 818 819 if (rv >= 0) { 820 return pfd.revents; 821 } else if (errno == EINTR) { 822 // interrupted, no events to return 823 return 0; 824 } else { 825 handleSocketError(env, errno); 826 return IOS_THROWN; 827 } 828 } 829 830 JNIEXPORT jboolean JNICALL 831 Java_sun_nio_ch_Net_pollConnect(JNIEnv *env, jobject this, jobject fdo, jlong timeout) 832 { 833 jint fd = fdval(env, fdo); 834 struct pollfd poller; 835 int result; 836 837 poller.fd = fd; 838 poller.events = POLLOUT; 839 poller.revents = 0; 840 if (timeout < -1) { 841 timeout = -1; 842 } else if (timeout > INT_MAX) { 843 timeout = INT_MAX; 844 } 845 846 result = poll(&poller, 1, (int)timeout); 847 848 if (result > 0) { 849 int error = 0; 850 socklen_t n = sizeof(int); 851 errno = 0; 852 result = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &n); 853 if (result < 0) { 854 handleSocketError(env, errno); 855 return JNI_FALSE; 856 } else if (error) { 857 handleSocketError(env, error); 858 return JNI_FALSE; 859 } else if ((poller.revents & POLLHUP) != 0) { 860 handleSocketError(env, ENOTCONN); 861 return JNI_FALSE; 862 } 863 // connected 864 return JNI_TRUE; 865 } else if (result == 0 || errno == EINTR) { 866 return JNI_FALSE; 867 } else { 868 JNU_ThrowIOExceptionWithLastError(env, "poll failed"); 869 return JNI_FALSE; 870 } 871 } 872 873 JNIEXPORT jshort JNICALL 874 Java_sun_nio_ch_Net_pollinValue(JNIEnv *env, jclass this) 875 { 876 return (jshort)POLLIN; 877 } 878 879 JNIEXPORT jshort JNICALL 880 Java_sun_nio_ch_Net_polloutValue(JNIEnv *env, jclass this) 881 { 882 return (jshort)POLLOUT; 883 } 884 885 JNIEXPORT jshort JNICALL 886 Java_sun_nio_ch_Net_pollerrValue(JNIEnv *env, jclass this) 887 { 888 return (jshort)POLLERR; 889 } 890 891 JNIEXPORT jshort JNICALL 892 Java_sun_nio_ch_Net_pollhupValue(JNIEnv *env, jclass this) 893 { 894 return (jshort)POLLHUP; 895 } 896 897 JNIEXPORT jshort JNICALL 898 Java_sun_nio_ch_Net_pollnvalValue(JNIEnv *env, jclass this) 899 { 900 return (jshort)POLLNVAL; 901 } 902 903 JNIEXPORT jshort JNICALL 904 Java_sun_nio_ch_Net_pollconnValue(JNIEnv *env, jclass this) 905 { 906 return (jshort)POLLOUT; 907 } 908 909 JNIEXPORT jint JNICALL 910 Java_sun_nio_ch_Net_sendOOB(JNIEnv* env, jclass this, jobject fdo, jbyte b) 911 { 912 int n = send(fdval(env, fdo), (const void*)&b, 1, MSG_OOB); 913 return convertReturnVal(env, n, JNI_FALSE); 914 } 915 916 /* Declared in nio_util.h */ 917 918 jint handleSocketError(JNIEnv *env, jint errorValue) 919 { 920 char *xn; 921 switch (errorValue) { 922 case EINPROGRESS: /* Non-blocking connect */ 923 return 0; 924 #ifdef EPROTO 925 case EPROTO: 926 xn = JNU_JAVANETPKG "ProtocolException"; 927 break; 928 #endif 929 case ECONNREFUSED: 930 case ETIMEDOUT: 931 case ENOTCONN: 932 xn = JNU_JAVANETPKG "ConnectException"; 933 break; 934 935 case EHOSTUNREACH: 936 xn = JNU_JAVANETPKG "NoRouteToHostException"; 937 break; 938 case EADDRINUSE: /* Fall through */ 939 case EADDRNOTAVAIL: 940 case EACCES: 941 xn = JNU_JAVANETPKG "BindException"; 942 break; 943 default: 944 xn = JNU_JAVANETPKG "SocketException"; 945 break; 946 } 947 errno = errorValue; 948 JNU_ThrowByNameWithLastError(env, xn, "NioSocketError"); 949 return IOS_THROWN; 950 }