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