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