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