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