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