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/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 42 /** 43 * Definitions for source-specific multicast to allow for building 44 * with older header files. 45 */ 46 47 #ifdef __solaris__ 48 49 #ifndef IP_BLOCK_SOURCE 50 51 #define IP_BLOCK_SOURCE 0x15 52 #define IP_UNBLOCK_SOURCE 0x16 53 #define IP_ADD_SOURCE_MEMBERSHIP 0x17 54 #define IP_DROP_SOURCE_MEMBERSHIP 0x18 55 56 #define MCAST_BLOCK_SOURCE 0x2b 57 #define MCAST_UNBLOCK_SOURCE 0x2c 58 #define MCAST_JOIN_SOURCE_GROUP 0x2d 59 #define MCAST_LEAVE_SOURCE_GROUP 0x2e 60 61 #endif /* IP_BLOCK_SOURCE */ 62 63 struct my_ip_mreq_source { 64 struct in_addr imr_multiaddr; 65 struct in_addr imr_sourceaddr; 66 struct in_addr imr_interface; 67 }; 68 69 /* 70 * Use #pragma pack() construct to force 32-bit alignment on amd64. 71 */ 72 #if defined(amd64) 73 #pragma pack(4) 74 #endif 75 76 struct my_group_source_req { 77 uint32_t gsr_interface; /* interface index */ 78 struct sockaddr_storage gsr_group; /* group address */ 79 struct sockaddr_storage gsr_source; /* source address */ 80 }; 81 82 #if defined(amd64) 83 #pragma pack() 84 #endif 85 86 #endif /* __solaris__ */ 87 88 89 #ifdef __linux__ 90 91 #ifndef IP_BLOCK_SOURCE 92 93 #define IP_BLOCK_SOURCE 38 94 #define IP_UNBLOCK_SOURCE 37 95 #define IP_ADD_SOURCE_MEMBERSHIP 39 96 #define IP_DROP_SOURCE_MEMBERSHIP 40 97 98 #define MCAST_BLOCK_SOURCE 43 99 #define MCAST_UNBLOCK_SOURCE 44 100 #define MCAST_JOIN_SOURCE_GROUP 42 101 #define MCAST_LEAVE_SOURCE_GROUP 45 102 103 #endif /* IP_BLOCK_SOURCE */ 104 105 struct my_ip_mreq_source { 106 struct in_addr imr_multiaddr; 107 struct in_addr imr_interface; 108 struct in_addr imr_sourceaddr; 109 }; 110 111 struct my_group_source_req { 112 uint32_t gsr_interface; /* interface index */ 113 struct sockaddr_storage gsr_group; /* group address */ 114 struct sockaddr_storage gsr_source; /* source address */ 115 }; 116 117 #endif /* __linux__ */ 118 119 #ifdef _ALLBSD_SOURCE 120 121 #ifndef IP_BLOCK_SOURCE 122 123 #define IP_ADD_SOURCE_MEMBERSHIP 70 /* join a source-specific group */ 124 #define IP_DROP_SOURCE_MEMBERSHIP 71 /* drop a single source */ 125 #define IP_BLOCK_SOURCE 72 /* block a source */ 126 #define IP_UNBLOCK_SOURCE 73 /* unblock a source */ 127 128 #endif /* IP_BLOCK_SOURCE */ 129 130 #ifndef MCAST_BLOCK_SOURCE 131 132 #define MCAST_JOIN_SOURCE_GROUP 82 /* join a source-specific group */ 133 #define MCAST_LEAVE_SOURCE_GROUP 83 /* leave a single source */ 134 #define MCAST_BLOCK_SOURCE 84 /* block a source */ 135 #define MCAST_UNBLOCK_SOURCE 85 /* unblock a source */ 136 137 #endif /* MCAST_BLOCK_SOURCE */ 138 139 #ifndef IPV6_ADD_MEMBERSHIP 140 141 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP 142 #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP 143 144 #endif /* IPV6_ADD_MEMBERSHIP */ 145 146 struct my_ip_mreq_source { 147 struct in_addr imr_multiaddr; 148 struct in_addr imr_interface; 149 struct in_addr imr_sourceaddr; 150 }; 151 152 struct my_group_source_req { 153 uint32_t gsr_interface; /* interface index */ 154 struct sockaddr_storage gsr_group; /* group address */ 155 struct sockaddr_storage gsr_source; /* source address */ 156 }; 157 158 #endif /* _ALLBSD_SOURCE */ 159 160 161 #define COPY_INET6_ADDRESS(env, source, target) \ 162 (*env)->GetByteArrayRegion(env, source, 0, 16, target) 163 164 /* 165 * Copy IPv6 group, interface index, and IPv6 source address 166 * into group_source_req structure. 167 */ 168 #ifdef AF_INET6 169 static void initGroupSourceReq(JNIEnv* env, jbyteArray group, jint index, 170 jbyteArray source, struct my_group_source_req* req) 171 { 172 struct sockaddr_in6* sin6; 173 174 req->gsr_interface = (uint32_t)index; 175 176 sin6 = (struct sockaddr_in6*)&(req->gsr_group); 177 sin6->sin6_family = AF_INET6; 178 COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr)); 179 180 sin6 = (struct sockaddr_in6*)&(req->gsr_source); 181 sin6->sin6_family = AF_INET6; 182 COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr)); 183 } 184 #endif 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 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 "sun.nio.ch.Net.setIntOption"); 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 "sun.nio.ch.Net.setIntOption"); 258 close(fd); 259 return -1; 260 } 261 } 262 #if defined(__linux__) && defined(AF_INET6) 263 /* By default, Linux uses the route default */ 264 if (domain == AF_INET6 && type == SOCK_DGRAM) { 265 int arg = 1; 266 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg, 267 sizeof(arg)) < 0) { 268 JNU_ThrowByNameWithLastError(env, 269 JNU_JAVANETPKG "SocketException", 270 "sun.nio.ch.Net.setIntOption"); 271 close(fd); 272 return -1; 273 } 274 } 275 #endif 276 return fd; 277 } 278 279 JNIEXPORT void JNICALL 280 Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jboolean preferIPv6, 281 jobject fdo, jobject iao, int port) 282 { 283 SOCKADDR sa; 284 int sa_len = SOCKADDR_LEN; 285 int rv = 0; 286 287 if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) { 288 return; 289 } 290 291 rv = NET_Bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); 292 if (rv != 0) { 293 handleSocketError(env, errno); 294 } 295 } 296 297 JNIEXPORT void JNICALL 298 Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog) 299 { 300 if (listen(fdval(env, fdo), backlog) < 0) 301 handleSocketError(env, errno); 302 } 303 304 JNIEXPORT jint JNICALL 305 Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, 306 jobject fdo, jobject iao, jint port) 307 { 308 SOCKADDR sa; 309 int sa_len = SOCKADDR_LEN; 310 int rv; 311 312 if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa, 313 &sa_len, preferIPv6) != 0) 314 { 315 return IOS_THROWN; 316 } 317 318 rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); 319 if (rv != 0) { 320 if (errno == EINPROGRESS) { 321 return IOS_UNAVAILABLE; 322 } else if (errno == EINTR) { 323 return IOS_INTERRUPTED; 324 } 325 return handleSocketError(env, errno); 326 } 327 return 1; 328 } 329 330 JNIEXPORT jint JNICALL 331 Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo) 332 { 333 SOCKADDR sa; 334 socklen_t sa_len = SOCKADDR_LEN; 335 if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { 336 #ifdef _ALLBSD_SOURCE 337 /* 338 * XXXBSD: 339 * ECONNRESET is specific to the BSDs. We can not return an error, 340 * as the calling Java code with raise a java.lang.Error given the expectation 341 * that getsockname() will never fail. According to the Single UNIX Specification, 342 * it shouldn't fail. As such, we just fill in generic Linux-compatible values. 343 */ 344 if (errno == ECONNRESET) { 345 struct sockaddr_in *sin; 346 sin = (struct sockaddr_in *) &sa; 347 bzero(sin, sizeof(*sin)); 348 sin->sin_len = sizeof(struct sockaddr_in); 349 sin->sin_family = AF_INET; 350 sin->sin_port = htonl(0); 351 sin->sin_addr.s_addr = INADDR_ANY; 352 } else { 353 handleSocketError(env, errno); 354 return -1; 355 } 356 #else /* _ALLBSD_SOURCE */ 357 handleSocketError(env, errno); 358 return -1; 359 #endif /* _ALLBSD_SOURCE */ 360 } 361 return NET_GetPortFromSockaddr((struct sockaddr *)&sa); 362 } 363 364 JNIEXPORT jobject JNICALL 365 Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo) 366 { 367 SOCKADDR sa; 368 socklen_t sa_len = SOCKADDR_LEN; 369 int port; 370 if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { 371 #ifdef _ALLBSD_SOURCE 372 /* 373 * XXXBSD: 374 * ECONNRESET is specific to the BSDs. We can not return an error, 375 * as the calling Java code with raise a java.lang.Error with the expectation 376 * that getsockname() will never fail. According to the Single UNIX Specification, 377 * it shouldn't fail. As such, we just fill in generic Linux-compatible values. 378 */ 379 if (errno == ECONNRESET) { 380 struct sockaddr_in *sin; 381 sin = (struct sockaddr_in *) &sa; 382 bzero(sin, sizeof(*sin)); 383 sin->sin_len = sizeof(struct sockaddr_in); 384 sin->sin_family = AF_INET; 385 sin->sin_port = htonl(0); 386 sin->sin_addr.s_addr = INADDR_ANY; 387 } else { 388 handleSocketError(env, errno); 389 return NULL; 390 } 391 #else /* _ALLBSD_SOURCE */ 392 handleSocketError(env, errno); 393 return NULL; 394 #endif /* _ALLBSD_SOURCE */ 395 } 396 return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); 397 } 398 399 JNIEXPORT jint JNICALL 400 Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 401 jboolean mayNeedConversion, jint level, jint opt) 402 { 403 int result; 404 struct linger linger; 405 u_char carg; 406 void *arg; 407 socklen_t arglen; 408 int n; 409 410 /* Option value is an int except for a few specific cases */ 411 412 arg = (void *)&result; 413 arglen = sizeof(result); 414 415 if (level == IPPROTO_IP && 416 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { 417 arg = (void*)&carg; 418 arglen = sizeof(carg); 419 } 420 421 if (level == SOL_SOCKET && opt == SO_LINGER) { 422 arg = (void *)&linger; 423 arglen = sizeof(linger); 424 } 425 426 if (mayNeedConversion) { 427 n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, (int*)&arglen); 428 } else { 429 n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen); 430 } 431 if (n < 0) { 432 JNU_ThrowByNameWithLastError(env, 433 JNU_JAVANETPKG "SocketException", 434 "sun.nio.ch.Net.getIntOption"); 435 return -1; 436 } 437 438 if (level == IPPROTO_IP && 439 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) 440 { 441 return (jint)carg; 442 } 443 444 if (level == SOL_SOCKET && opt == SO_LINGER) 445 return linger.l_onoff ? (jint)linger.l_linger : (jint)-1; 446 447 return (jint)result; 448 } 449 450 JNIEXPORT void JNICALL 451 Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 452 jboolean mayNeedConversion, jint level, jint opt, jint arg) 453 { 454 int result; 455 struct linger linger; 456 u_char carg; 457 void *parg; 458 socklen_t arglen; 459 int n; 460 461 /* Option value is an int except for a few specific cases */ 462 463 parg = (void*)&arg; 464 arglen = sizeof(arg); 465 466 if (level == IPPROTO_IP && 467 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { 468 parg = (void*)&carg; 469 arglen = sizeof(carg); 470 carg = (u_char)arg; 471 } 472 473 if (level == SOL_SOCKET && opt == SO_LINGER) { 474 parg = (void *)&linger; 475 arglen = sizeof(linger); 476 if (arg >= 0) { 477 linger.l_onoff = 1; 478 linger.l_linger = arg; 479 } else { 480 linger.l_onoff = 0; 481 linger.l_linger = 0; 482 } 483 } 484 485 if (mayNeedConversion) { 486 n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen); 487 } else { 488 n = setsockopt(fdval(env, fdo), level, opt, parg, arglen); 489 } 490 if (n < 0) { 491 JNU_ThrowByNameWithLastError(env, 492 JNU_JAVANETPKG "SocketException", 493 "sun.nio.ch.Net.setIntOption"); 494 } 495 } 496 497 JNIEXPORT jint JNICALL 498 Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo, 499 jint group, jint interf, jint source) 500 { 501 struct ip_mreq mreq; 502 struct my_ip_mreq_source mreq_source; 503 int opt, n, optlen; 504 void* optval; 505 506 if (source == 0) { 507 mreq.imr_multiaddr.s_addr = htonl(group); 508 mreq.imr_interface.s_addr = htonl(interf); 509 opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; 510 optval = (void*)&mreq; 511 optlen = sizeof(mreq); 512 } else { 513 #ifdef MACOSX 514 /* no IPv4 include-mode filtering for now */ 515 return IOS_UNAVAILABLE; 516 #else 517 mreq_source.imr_multiaddr.s_addr = htonl(group); 518 mreq_source.imr_sourceaddr.s_addr = htonl(source); 519 mreq_source.imr_interface.s_addr = htonl(interf); 520 opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP; 521 optval = (void*)&mreq_source; 522 optlen = sizeof(mreq_source); 523 #endif 524 } 525 526 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen); 527 if (n < 0) { 528 if (join && (errno == ENOPROTOOPT)) 529 return IOS_UNAVAILABLE; 530 handleSocketError(env, errno); 531 } 532 return 0; 533 } 534 535 JNIEXPORT jint JNICALL 536 Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo, 537 jint group, jint interf, jint source) 538 { 539 #ifdef MACOSX 540 /* no IPv4 exclude-mode filtering for now */ 541 return IOS_UNAVAILABLE; 542 #else 543 struct my_ip_mreq_source mreq_source; 544 int n; 545 int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE; 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 551 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, 552 (void*)&mreq_source, sizeof(mreq_source)); 553 if (n < 0) { 554 if (block && (errno == ENOPROTOOPT)) 555 return IOS_UNAVAILABLE; 556 handleSocketError(env, errno); 557 } 558 return 0; 559 #endif 560 } 561 562 JNIEXPORT jint JNICALL 563 Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo, 564 jbyteArray group, jint index, jbyteArray source) 565 { 566 #ifdef AF_INET6 567 struct ipv6_mreq mreq6; 568 struct my_group_source_req req; 569 int opt, n, optlen; 570 void* optval; 571 572 if (source == NULL) { 573 COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr)); 574 mreq6.ipv6mr_interface = (int)index; 575 opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP; 576 optval = (void*)&mreq6; 577 optlen = sizeof(mreq6); 578 } else { 579 #if defined (__linux__) || defined(MACOSX) 580 /* Include-mode filtering broken on Mac OS & Linux at least to 2.6.24 */ 581 return IOS_UNAVAILABLE; 582 #else 583 initGroupSourceReq(env, group, index, source, &req); 584 opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP; 585 optval = (void*)&req; 586 optlen = sizeof(req); 587 #endif 588 } 589 590 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen); 591 if (n < 0) { 592 if (join && (errno == ENOPROTOOPT)) 593 return IOS_UNAVAILABLE; 594 handleSocketError(env, errno); 595 } 596 return 0; 597 #else 598 JNU_ThrowInternalError(env, "Should not get here"); 599 return IOS_THROWN; 600 #endif /* AF_INET6 */ 601 } 602 603 JNIEXPORT jint JNICALL 604 Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo, 605 jbyteArray group, jint index, jbyteArray source) 606 { 607 #ifdef AF_INET6 608 #ifdef MACOSX 609 /* no IPv6 exclude-mode filtering for now */ 610 return IOS_UNAVAILABLE; 611 #else 612 struct my_group_source_req req; 613 int n; 614 int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE; 615 616 initGroupSourceReq(env, group, index, source, &req); 617 618 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, 619 (void*)&req, sizeof(req)); 620 if (n < 0) { 621 if (block && (errno == ENOPROTOOPT)) 622 return IOS_UNAVAILABLE; 623 handleSocketError(env, errno); 624 } 625 return 0; 626 #endif 627 #else 628 JNU_ThrowInternalError(env, "Should not get here"); 629 return IOS_THROWN; 630 #endif 631 } 632 633 JNIEXPORT void JNICALL 634 Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf) 635 { 636 struct in_addr in; 637 socklen_t arglen = sizeof(struct in_addr); 638 int n; 639 640 in.s_addr = htonl(interf); 641 642 n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, 643 (void*)&(in.s_addr), arglen); 644 if (n < 0) { 645 handleSocketError(env, errno); 646 } 647 } 648 649 JNIEXPORT jint JNICALL 650 Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo) 651 { 652 struct in_addr in; 653 socklen_t arglen = sizeof(struct in_addr); 654 int n; 655 656 n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen); 657 if (n < 0) { 658 handleSocketError(env, errno); 659 return -1; 660 } 661 return ntohl(in.s_addr); 662 } 663 664 JNIEXPORT void JNICALL 665 Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index) 666 { 667 int value = (jint)index; 668 socklen_t arglen = sizeof(value); 669 int n; 670 671 n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, 672 (void*)&(index), arglen); 673 if (n < 0) { 674 handleSocketError(env, errno); 675 } 676 } 677 678 JNIEXPORT jint JNICALL 679 Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo) 680 { 681 int index; 682 socklen_t arglen = sizeof(index); 683 int n; 684 685 n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen); 686 if (n < 0) { 687 handleSocketError(env, errno); 688 return -1; 689 } 690 return (jint)index; 691 } 692 693 JNIEXPORT void JNICALL 694 Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) 695 { 696 int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD : 697 (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR; 698 if ((shutdown(fdval(env, fdo), how) < 0) && (errno != ENOTCONN)) 699 handleSocketError(env, errno); 700 } 701 702 /* Declared in nio_util.h */ 703 704 jint 705 handleSocketError(JNIEnv *env, jint errorValue) 706 { 707 char *xn; 708 switch (errorValue) { 709 case EINPROGRESS: /* Non-blocking connect */ 710 return 0; 711 #ifdef EPROTO 712 case EPROTO: 713 xn = JNU_JAVANETPKG "ProtocolException"; 714 break; 715 #endif 716 case ECONNREFUSED: 717 xn = JNU_JAVANETPKG "ConnectException"; 718 break; 719 case ETIMEDOUT: 720 xn = JNU_JAVANETPKG "ConnectException"; 721 break; 722 case EHOSTUNREACH: 723 xn = JNU_JAVANETPKG "NoRouteToHostException"; 724 break; 725 case EADDRINUSE: /* Fall through */ 726 case EADDRNOTAVAIL: 727 xn = JNU_JAVANETPKG "BindException"; 728 break; 729 default: 730 xn = JNU_JAVANETPKG "SocketException"; 731 break; 732 } 733 errno = errorValue; 734 JNU_ThrowByNameWithLastError(env, xn, "NioSocketError"); 735 return IOS_THROWN; 736 }