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