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