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