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