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