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 static jclass isa_class; /* java.net.InetSocketAddress */ 150 static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */ 151 static jclass usa_class; /* java.net.UnixSocketAddress */ 152 static jmethodID usa_ctor; /* UnixSocketAddress() */ 153 static jmethodID usa_ctorBytes; /* UnixSocketAddress(byte[]) */ 154 155 JNIEXPORT void JNICALL 156 Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz) 157 { 158 jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress"); 159 CHECK_NULL(cls); 160 isa_class = (*env)->NewGlobalRef(env, cls); 161 if (isa_class == NULL) { 162 JNU_ThrowOutOfMemoryError(env, NULL); 163 return; 164 } 165 isa_ctorID = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/net/InetAddress;I)V"); 166 CHECK_NULL(isa_ctorID); 167 168 cls = (*env)->FindClass(env, "java/net/UnixSocketAddress"); 169 CHECK_NULL(cls); 170 usa_class = (*env)->NewGlobalRef(env, cls); 171 if (usa_class == NULL) { 172 JNU_ThrowOutOfMemoryError(env, NULL); 173 return; 174 } 175 usa_ctor = (*env)->GetMethodID(env, cls, "<init>", "()V"); 176 CHECK_NULL(usa_ctor); 177 usa_ctorBytes = (*env)->GetMethodID(env, cls, "<init>", "([B)V"); 178 CHECK_NULL(usa_ctorBytes); 179 180 initInetAddressIDs(env); 181 } 182 183 JNIEXPORT jboolean JNICALL 184 Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl) 185 { 186 return (ipv6_available()) ? JNI_TRUE : JNI_FALSE; 187 } 188 189 JNIEXPORT jboolean JNICALL 190 Java_sun_nio_ch_Net_isReusePortAvailable0(JNIEnv* env, jclass c1) 191 { 192 return (reuseport_available()) ? JNI_TRUE : JNI_FALSE; 193 } 194 195 JNIEXPORT jint JNICALL 196 Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) { 197 return -1; 198 } 199 200 JNIEXPORT jboolean JNICALL 201 Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl) 202 { 203 #if defined(__APPLE__) || defined(_AIX) 204 /* for now IPv6 sockets cannot join IPv4 multicast groups */ 205 return JNI_FALSE; 206 #else 207 return JNI_TRUE; 208 #endif 209 } 210 211 JNIEXPORT jboolean JNICALL 212 Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl) 213 { 214 #ifdef __solaris__ 215 return JNI_TRUE; 216 #else 217 return JNI_FALSE; 218 #endif 219 } 220 221 JNIEXPORT jint JNICALL 222 Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, 223 jboolean stream, jboolean reuse, jboolean ignored) 224 { 225 int fd; 226 int type = (stream ? SOCK_STREAM : SOCK_DGRAM); 227 int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; 228 229 fd = socket(domain, type, 0); 230 if (fd < 0) { 231 return handleSocketError(env, errno); 232 } 233 234 /* 235 * If IPv4 is available, disable IPV6_V6ONLY to ensure dual-socket support. 236 */ 237 if (domain == AF_INET6 && ipv4_available()) { 238 int arg = 0; 239 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, 240 sizeof(int)) < 0) { 241 JNU_ThrowByNameWithLastError(env, 242 JNU_JAVANETPKG "SocketException", 243 "Unable to set IPV6_V6ONLY"); 244 close(fd); 245 return -1; 246 } 247 } 248 249 if (reuse) { 250 int arg = 1; 251 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, 252 sizeof(arg)) < 0) { 253 JNU_ThrowByNameWithLastError(env, 254 JNU_JAVANETPKG "SocketException", 255 "Unable to set SO_REUSEADDR"); 256 close(fd); 257 return -1; 258 } 259 } 260 261 #if defined(__linux__) 262 if (type == SOCK_DGRAM) { 263 int arg = 0; 264 int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP; 265 if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) && 266 (errno != ENOPROTOOPT)) { 267 JNU_ThrowByNameWithLastError(env, 268 JNU_JAVANETPKG "SocketException", 269 "Unable to set IP_MULTICAST_ALL"); 270 close(fd); 271 return -1; 272 } 273 } 274 275 /* By default, Linux uses the route default */ 276 if (domain == AF_INET6 && type == SOCK_DGRAM) { 277 int arg = 1; 278 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg, 279 sizeof(arg)) < 0) { 280 JNU_ThrowByNameWithLastError(env, 281 JNU_JAVANETPKG "SocketException", 282 "Unable to set IPV6_MULTICAST_HOPS"); 283 close(fd); 284 return -1; 285 } 286 } 287 #endif 288 return fd; 289 } 290 291 JNIEXPORT jint JNICALL 292 Java_sun_nio_ch_Net_socket1 (JNIEnv *env, jclass clazz, jboolean stream) 293 { 294 int type = (stream ? SOCK_STREAM : SOCK_DGRAM); 295 int fd = socket(AF_UNIX, type, 0); 296 if (fd < 0) { 297 return handleSocketError(env, errno); 298 } 299 return fd; 300 } 301 302 JNIEXPORT void JNICALL 303 Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6, 304 jboolean useExclBind, jobject iao, int port) 305 { 306 SOCKETADDRESS sa; 307 int sa_len = 0; 308 int rv = 0; 309 310 if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, 311 preferIPv6) != 0) { 312 return; 313 } 314 315 rv = NET_Bind(fdval(env, fdo), &sa, sa_len); 316 if (rv != 0) { 317 handleSocketError(env, errno); 318 } 319 } 320 321 JNIEXPORT void JNICALL 322 Java_sun_nio_ch_Net_bind1(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray uao) 323 { 324 SOCKETADDRESS sa; 325 memset(&sa, 0x00, sizeof (sa)); 326 sa.sau.sun_family = AF_UNIX; 327 size_t uao_len = (* env) -> GetArrayLength(env, uao); 328 size_t sa_len = sizeof (sa.sau.sun_path); 329 if (uao_len > sa_len) { 330 // TODO: throw propper exception 331 return; 332 } 333 (* env) -> GetByteArrayRegion(env, uao, 0, uao_len, (jbyte *) sa.sau.sun_path); 334 int rv = bind(fdval(env, fdo), &sa.sa, sa_len); 335 if (rv != 0) { 336 handleSocketError(env, errno); 337 } 338 } 339 340 JNIEXPORT void JNICALL 341 Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog) 342 { 343 if (listen(fdval(env, fdo), backlog) < 0) 344 handleSocketError(env, errno); 345 } 346 347 JNIEXPORT jint JNICALL 348 Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, 349 jobject fdo, jobject iao, jint port) 350 { 351 SOCKETADDRESS sa; 352 int sa_len = 0; 353 int rv; 354 355 if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) { 356 return IOS_THROWN; 357 } 358 359 rv = connect(fdval(env, fdo), &sa.sa, sa_len); 360 if (rv != 0) { 361 if (errno == EINPROGRESS) { 362 return IOS_UNAVAILABLE; 363 } else if (errno == EINTR) { 364 return IOS_INTERRUPTED; 365 } 366 return handleSocketError(env, errno); 367 } 368 return 1; 369 } 370 371 JNIEXPORT jint JNICALL 372 Java_sun_nio_ch_Net_connect1(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray uao) 373 { 374 SOCKETADDRESS sa; 375 memset(&sa, 0x00, sizeof (sa)); 376 sa.sau.sun_family = AF_UNIX; 377 size_t uao_len = (* env) -> GetArrayLength(env, uao); 378 size_t sa_len = sizeof (sa.sau.sun_path); 379 if (uao_len > sa_len) { 380 // TODO: throw propper exception 381 return IOS_UNAVAILABLE; 382 } 383 (* env) -> GetByteArrayRegion(env, uao, 0, uao_len, (jbyte *) sa.sau.sun_path); 384 385 // TODO: refactoring, common method 386 int rv = connect(fdval(env, fdo), &sa.sa, sa_len); 387 if (rv != 0) { 388 if (errno == EINPROGRESS) { 389 return IOS_UNAVAILABLE; 390 } else if (errno == EINTR) { 391 return IOS_INTERRUPTED; 392 } 393 return handleSocketError(env, errno); 394 } 395 return 1; 396 } 397 398 JNIEXPORT jint JNICALL 399 Java_sun_nio_ch_Net_accept(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo, 400 jobjectArray isaa) 401 { 402 jint fd = fdval(env, fdo); 403 jint newfd; 404 SOCKETADDRESS sa; 405 socklen_t sa_len = sizeof(SOCKETADDRESS); 406 jobject remote_ia; 407 jint remote_port = 0; 408 jobject isa; 409 410 /* accept connection but ignore ECONNABORTED */ 411 for (;;) { 412 newfd = accept(fd, &sa.sa, &sa_len); 413 if (newfd >= 0) { 414 break; 415 } 416 if (errno != ECONNABORTED) { 417 break; 418 } 419 /* ECONNABORTED => restart accept */ 420 } 421 422 if (newfd < 0) { 423 if (errno == EAGAIN || errno == EWOULDBLOCK) 424 return IOS_UNAVAILABLE; 425 if (errno == EINTR) 426 return IOS_INTERRUPTED; 427 JNU_ThrowIOExceptionWithLastError(env, "Accept failed"); 428 return IOS_THROWN; 429 } 430 431 setfdval(env, newfdo, newfd); 432 433 if (sa.sa.sa_family == AF_INET || sa.sa.sa_family == AF_INET6) { 434 remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port); 435 CHECK_NULL_RETURN(remote_ia, IOS_THROWN); 436 437 isa = (*env)->NewObject(env, isa_class, isa_ctorID, remote_ia, remote_port); 438 CHECK_NULL_RETURN(isa, IOS_THROWN); 439 (*env)->SetObjectArrayElement(env, isaa, 0, isa); 440 441 return 1; 442 } else if (sa.sa.sa_family == AF_UNIX) { 443 isa = (*env)->NewObject(env, usa_class, usa_ctor); 444 CHECK_NULL_RETURN(isa, IOS_THROWN); 445 (*env)->SetObjectArrayElement(env, isaa, 0, isa); 446 return 1; 447 } else { 448 return -6; // UNSUPPORTED_CASE 449 } 450 } 451 452 JNIEXPORT jint JNICALL 453 Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo) 454 { 455 SOCKETADDRESS sa; 456 socklen_t sa_len = sizeof(SOCKETADDRESS); 457 if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) { 458 #ifdef _ALLBSD_SOURCE 459 /* 460 * XXXBSD: 461 * ECONNRESET is specific to the BSDs. We can not return an error, 462 * as the calling Java code with raise a java.lang.Error given the expectation 463 * that getsockname() will never fail. According to the Single UNIX Specification, 464 * it shouldn't fail. As such, we just fill in generic Linux-compatible values. 465 */ 466 if (errno == ECONNRESET) { 467 bzero(&sa.sa4, sizeof(sa)); 468 sa.sa4.sin_len = sizeof(struct sockaddr_in); 469 sa.sa4.sin_family = AF_INET; 470 sa.sa4.sin_port = htonl(0); 471 sa.sa4.sin_addr.s_addr = INADDR_ANY; 472 } else { 473 handleSocketError(env, errno); 474 return -1; 475 } 476 #else /* _ALLBSD_SOURCE */ 477 handleSocketError(env, errno); 478 return -1; 479 #endif /* _ALLBSD_SOURCE */ 480 } 481 return NET_GetPortFromSockaddr(&sa); 482 } 483 484 JNIEXPORT jobject JNICALL 485 Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo) 486 { 487 SOCKETADDRESS sa; 488 socklen_t sa_len = sizeof(SOCKETADDRESS); 489 int port; 490 if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) { 491 #ifdef _ALLBSD_SOURCE 492 /* 493 * XXXBSD: 494 * ECONNRESET is specific to the BSDs. We can not return an error, 495 * as the calling Java code with raise a java.lang.Error with the expectation 496 * that getsockname() will never fail. According to the Single UNIX Specification, 497 * it shouldn't fail. As such, we just fill in generic Linux-compatible values. 498 */ 499 if (errno == ECONNRESET) { 500 bzero(&sa.sa4, sizeof(sa)); 501 sa.sa4.sin_len = sizeof(struct sockaddr_in); 502 sa.sa4.sin_family = AF_INET; 503 sa.sa4.sin_port = htonl(0); 504 sa.sa4.sin_addr.s_addr = INADDR_ANY; 505 } else { 506 handleSocketError(env, errno); 507 return NULL; 508 } 509 #else /* _ALLBSD_SOURCE */ 510 handleSocketError(env, errno); 511 return NULL; 512 #endif /* _ALLBSD_SOURCE */ 513 } 514 return NET_SockaddrToInetAddress(env, &sa, &port); 515 } 516 517 JNIEXPORT jobject JNICALL 518 Java_sun_nio_ch_Net_localSocketAddress(JNIEnv *env, jclass clazz, jobject fdo) 519 { 520 SOCKETADDRESS sa; 521 socklen_t sa_len = sizeof (SOCKETADDRESS); 522 memset(&sa, 0x00, sa_len); 523 if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) != 0) { 524 return NULL; // TODO: exception? 525 } 526 527 if (sa.sa.sa_family == AF_UNIX) { 528 jbyteArray addr = (*env)->NewByteArray(env, sizeof(sa.sau.sun_path)); 529 (*env)->SetByteArrayRegion(env, addr, 0, sizeof(sa.sau.sun_path), (jbyte *) sa.sau.sun_path); 530 return (*env)->NewObject(env, usa_class, usa_ctorBytes, addr); 531 } else if (sa.sa.sa_family == AF_INET || sa.sa.sa_family == AF_INET6) { 532 jobject address = Java_sun_nio_ch_Net_localInetAddress(env, clazz, fdo); 533 jint port = Java_sun_nio_ch_Net_localPort(env, clazz, fdo); 534 return (*env)->NewObject(env, isa_class, isa_ctorID, address, port); 535 } else { 536 return NULL; // TODO: exception? 537 } 538 } 539 540 JNIEXPORT jint JNICALL 541 Java_sun_nio_ch_Net_remotePort(JNIEnv *env, jclass clazz, jobject fdo) 542 { 543 SOCKETADDRESS sa; 544 socklen_t sa_len = sizeof(sa); 545 546 if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) { 547 handleSocketError(env, errno); 548 return IOS_THROWN; 549 } 550 return NET_GetPortFromSockaddr(&sa); 551 } 552 553 JNIEXPORT jobject JNICALL 554 Java_sun_nio_ch_Net_remoteInetAddress(JNIEnv *env, jclass clazz, jobject fdo) 555 { 556 SOCKETADDRESS sa; 557 socklen_t sa_len = sizeof(sa); 558 int port; 559 560 if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) { 561 handleSocketError(env, errno); 562 return NULL; 563 } 564 return NET_SockaddrToInetAddress(env, &sa, &port); 565 } 566 567 JNIEXPORT jint JNICALL 568 Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 569 jboolean mayNeedConversion, jint level, jint opt) 570 { 571 int result; 572 struct linger linger; 573 u_char carg; 574 void *arg; 575 socklen_t arglen; 576 int n; 577 578 /* Option value is an int except for a few specific cases */ 579 580 arg = (void *)&result; 581 arglen = sizeof(result); 582 583 if (level == IPPROTO_IP && 584 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { 585 arg = (void*)&carg; 586 arglen = sizeof(carg); 587 } 588 589 if (level == SOL_SOCKET && opt == SO_LINGER) { 590 arg = (void *)&linger; 591 arglen = sizeof(linger); 592 } 593 594 if (mayNeedConversion) { 595 n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, (int*)&arglen); 596 } else { 597 n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen); 598 } 599 if (n < 0) { 600 JNU_ThrowByNameWithLastError(env, 601 JNU_JAVANETPKG "SocketException", 602 "sun.nio.ch.Net.getIntOption"); 603 return -1; 604 } 605 606 if (level == IPPROTO_IP && 607 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) 608 { 609 return (jint)carg; 610 } 611 612 if (level == SOL_SOCKET && opt == SO_LINGER) 613 return linger.l_onoff ? (jint)linger.l_linger : (jint)-1; 614 615 return (jint)result; 616 } 617 618 JNIEXPORT void JNICALL 619 Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 620 jboolean mayNeedConversion, jint level, 621 jint opt, jint arg, jboolean isIPv6) 622 { 623 int result; 624 struct linger linger; 625 u_char carg; 626 void *parg; 627 socklen_t arglen; 628 int n; 629 630 /* Option value is an int except for a few specific cases */ 631 632 parg = (void*)&arg; 633 arglen = sizeof(arg); 634 635 if (level == IPPROTO_IP && 636 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { 637 parg = (void*)&carg; 638 arglen = sizeof(carg); 639 carg = (u_char)arg; 640 } 641 642 if (level == SOL_SOCKET && opt == SO_LINGER) { 643 parg = (void *)&linger; 644 arglen = sizeof(linger); 645 if (arg >= 0) { 646 linger.l_onoff = 1; 647 linger.l_linger = arg; 648 } else { 649 linger.l_onoff = 0; 650 linger.l_linger = 0; 651 } 652 } 653 654 if (mayNeedConversion) { 655 n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen); 656 } else { 657 n = setsockopt(fdval(env, fdo), level, opt, parg, arglen); 658 } 659 if (n < 0) { 660 JNU_ThrowByNameWithLastError(env, 661 JNU_JAVANETPKG "SocketException", 662 "sun.nio.ch.Net.setIntOption"); 663 } 664 #ifdef __linux__ 665 if (level == IPPROTO_IPV6 && opt == IPV6_TCLASS && isIPv6) { 666 // set the V4 option also 667 setsockopt(fdval(env, fdo), IPPROTO_IP, IP_TOS, parg, arglen); 668 } 669 #endif 670 } 671 672 JNIEXPORT jint JNICALL 673 Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo, 674 jint group, jint interf, jint source) 675 { 676 struct ip_mreq mreq; 677 struct ip_mreq_source mreq_source; 678 int opt, n, optlen; 679 void* optval; 680 681 if (source == 0) { 682 mreq.imr_multiaddr.s_addr = htonl(group); 683 mreq.imr_interface.s_addr = htonl(interf); 684 opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; 685 optval = (void*)&mreq; 686 optlen = sizeof(mreq); 687 } else { 688 689 #ifdef _AIX 690 /* check AIX for support of source filtering */ 691 if (isSourceFilterSupported() != JNI_TRUE){ 692 return IOS_UNAVAILABLE; 693 } 694 #endif 695 696 mreq_source.imr_multiaddr.s_addr = htonl(group); 697 mreq_source.imr_sourceaddr.s_addr = htonl(source); 698 mreq_source.imr_interface.s_addr = htonl(interf); 699 opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP; 700 optval = (void*)&mreq_source; 701 optlen = sizeof(mreq_source); 702 } 703 704 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen); 705 if (n < 0) { 706 if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) 707 return IOS_UNAVAILABLE; 708 handleSocketError(env, errno); 709 } 710 return 0; 711 } 712 713 JNIEXPORT jint JNICALL 714 Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo, 715 jint group, jint interf, jint source) 716 { 717 #ifdef __APPLE__ 718 /* no IPv4 exclude-mode filtering for now */ 719 return IOS_UNAVAILABLE; 720 #else 721 struct ip_mreq_source mreq_source; 722 int n; 723 int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE; 724 725 #ifdef _AIX 726 /* check AIX for support of source filtering */ 727 if (isSourceFilterSupported() != JNI_TRUE){ 728 return IOS_UNAVAILABLE; 729 } 730 #endif 731 732 mreq_source.imr_multiaddr.s_addr = htonl(group); 733 mreq_source.imr_sourceaddr.s_addr = htonl(source); 734 mreq_source.imr_interface.s_addr = htonl(interf); 735 736 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, 737 (void*)&mreq_source, sizeof(mreq_source)); 738 if (n < 0) { 739 if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) 740 return IOS_UNAVAILABLE; 741 handleSocketError(env, errno); 742 } 743 return 0; 744 #endif 745 } 746 747 JNIEXPORT jint JNICALL 748 Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo, 749 jbyteArray group, jint index, jbyteArray source) 750 { 751 struct ipv6_mreq mreq6; 752 struct group_source_req req; 753 int opt, n, optlen; 754 void* optval; 755 756 if (source == NULL) { 757 COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr)); 758 mreq6.ipv6mr_interface = (int)index; 759 opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP; 760 optval = (void*)&mreq6; 761 optlen = sizeof(mreq6); 762 } else { 763 #ifdef __APPLE__ 764 /* no IPv6 include-mode filtering for now */ 765 return IOS_UNAVAILABLE; 766 #else 767 initGroupSourceReq(env, group, index, source, &req); 768 opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP; 769 optval = (void*)&req; 770 optlen = sizeof(req); 771 #endif 772 } 773 774 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen); 775 if (n < 0) { 776 if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) 777 return IOS_UNAVAILABLE; 778 handleSocketError(env, errno); 779 } 780 return 0; 781 } 782 783 JNIEXPORT jint JNICALL 784 Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo, 785 jbyteArray group, jint index, jbyteArray source) 786 { 787 #ifdef __APPLE__ 788 /* no IPv6 exclude-mode filtering for now */ 789 return IOS_UNAVAILABLE; 790 #else 791 struct group_source_req req; 792 int n; 793 int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE; 794 795 initGroupSourceReq(env, group, index, source, &req); 796 797 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, 798 (void*)&req, sizeof(req)); 799 if (n < 0) { 800 if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) 801 return IOS_UNAVAILABLE; 802 handleSocketError(env, errno); 803 } 804 return 0; 805 #endif 806 } 807 808 JNIEXPORT void JNICALL 809 Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf) 810 { 811 struct in_addr in; 812 socklen_t arglen = sizeof(struct in_addr); 813 int n; 814 815 in.s_addr = htonl(interf); 816 817 n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, 818 (void*)&(in.s_addr), arglen); 819 if (n < 0) { 820 handleSocketError(env, errno); 821 } 822 } 823 824 JNIEXPORT jint JNICALL 825 Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo) 826 { 827 struct in_addr in; 828 socklen_t arglen = sizeof(struct in_addr); 829 int n; 830 831 n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen); 832 if (n < 0) { 833 handleSocketError(env, errno); 834 return -1; 835 } 836 return ntohl(in.s_addr); 837 } 838 839 JNIEXPORT void JNICALL 840 Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index) 841 { 842 int value = (jint)index; 843 socklen_t arglen = sizeof(value); 844 int n; 845 846 n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, 847 (void*)&(index), arglen); 848 if (n < 0) { 849 handleSocketError(env, errno); 850 } 851 } 852 853 JNIEXPORT jint JNICALL 854 Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo) 855 { 856 int index; 857 socklen_t arglen = sizeof(index); 858 int n; 859 860 n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen); 861 if (n < 0) { 862 handleSocketError(env, errno); 863 return -1; 864 } 865 return (jint)index; 866 } 867 868 JNIEXPORT void JNICALL 869 Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) 870 { 871 int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD : 872 (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR; 873 if ((shutdown(fdval(env, fdo), how) < 0) && (errno != ENOTCONN)) 874 handleSocketError(env, errno); 875 } 876 877 JNIEXPORT jint JNICALL 878 Java_sun_nio_ch_Net_available(JNIEnv *env, jclass cl, jobject fdo) 879 { 880 int count = 0; 881 if (NET_SocketAvailable(fdval(env, fdo), &count) != 0) { 882 handleSocketError(env, errno); 883 return IOS_THROWN; 884 } 885 return (jint) count; 886 } 887 888 JNIEXPORT jint JNICALL 889 Java_sun_nio_ch_Net_poll(JNIEnv* env, jclass this, jobject fdo, jint events, jlong timeout) 890 { 891 struct pollfd pfd; 892 int rv; 893 pfd.fd = fdval(env, fdo); 894 pfd.events = events; 895 if (timeout < -1) { 896 timeout = -1; 897 } else if (timeout > INT_MAX) { 898 timeout = INT_MAX; 899 } 900 rv = poll(&pfd, 1, (int)timeout); 901 902 if (rv >= 0) { 903 return pfd.revents; 904 } else if (errno == EINTR) { 905 // interrupted, no events to return 906 return 0; 907 } else { 908 handleSocketError(env, errno); 909 return IOS_THROWN; 910 } 911 } 912 913 JNIEXPORT jboolean JNICALL 914 Java_sun_nio_ch_Net_pollConnect(JNIEnv *env, jobject this, jobject fdo, jlong timeout) 915 { 916 jint fd = fdval(env, fdo); 917 struct pollfd poller; 918 int result; 919 920 poller.fd = fd; 921 poller.events = POLLOUT; 922 poller.revents = 0; 923 if (timeout < -1) { 924 timeout = -1; 925 } else if (timeout > INT_MAX) { 926 timeout = INT_MAX; 927 } 928 929 result = poll(&poller, 1, (int)timeout); 930 931 if (result > 0) { 932 int error = 0; 933 socklen_t n = sizeof(int); 934 errno = 0; 935 result = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &n); 936 if (result < 0) { 937 handleSocketError(env, errno); 938 return JNI_FALSE; 939 } else if (error) { 940 handleSocketError(env, error); 941 return JNI_FALSE; 942 } else if ((poller.revents & POLLHUP) != 0) { 943 handleSocketError(env, ENOTCONN); 944 return JNI_FALSE; 945 } 946 // connected 947 return JNI_TRUE; 948 } else if (result == 0 || errno == EINTR) { 949 return JNI_FALSE; 950 } else { 951 JNU_ThrowIOExceptionWithLastError(env, "poll failed"); 952 return JNI_FALSE; 953 } 954 } 955 956 JNIEXPORT jshort JNICALL 957 Java_sun_nio_ch_Net_pollinValue(JNIEnv *env, jclass this) 958 { 959 return (jshort)POLLIN; 960 } 961 962 JNIEXPORT jshort JNICALL 963 Java_sun_nio_ch_Net_polloutValue(JNIEnv *env, jclass this) 964 { 965 return (jshort)POLLOUT; 966 } 967 968 JNIEXPORT jshort JNICALL 969 Java_sun_nio_ch_Net_pollerrValue(JNIEnv *env, jclass this) 970 { 971 return (jshort)POLLERR; 972 } 973 974 JNIEXPORT jshort JNICALL 975 Java_sun_nio_ch_Net_pollhupValue(JNIEnv *env, jclass this) 976 { 977 return (jshort)POLLHUP; 978 } 979 980 JNIEXPORT jshort JNICALL 981 Java_sun_nio_ch_Net_pollnvalValue(JNIEnv *env, jclass this) 982 { 983 return (jshort)POLLNVAL; 984 } 985 986 JNIEXPORT jshort JNICALL 987 Java_sun_nio_ch_Net_pollconnValue(JNIEnv *env, jclass this) 988 { 989 return (jshort)POLLOUT; 990 } 991 992 JNIEXPORT jint JNICALL 993 Java_sun_nio_ch_Net_sendOOB(JNIEnv* env, jclass this, jobject fdo, jbyte b) 994 { 995 int n = send(fdval(env, fdo), (const void*)&b, 1, MSG_OOB); 996 return convertReturnVal(env, n, JNI_FALSE); 997 } 998 999 /* Declared in nio_util.h */ 1000 1001 jint handleSocketError(JNIEnv *env, jint errorValue) 1002 { 1003 char *xn; 1004 switch (errorValue) { 1005 case EINPROGRESS: /* Non-blocking connect */ 1006 return 0; 1007 #ifdef EPROTO 1008 case EPROTO: 1009 xn = JNU_JAVANETPKG "ProtocolException"; 1010 break; 1011 #endif 1012 case ECONNREFUSED: 1013 case ETIMEDOUT: 1014 case ENOTCONN: 1015 xn = JNU_JAVANETPKG "ConnectException"; 1016 break; 1017 1018 case EHOSTUNREACH: 1019 xn = JNU_JAVANETPKG "NoRouteToHostException"; 1020 break; 1021 case EADDRINUSE: /* Fall through */ 1022 case EADDRNOTAVAIL: 1023 case EACCES: 1024 xn = JNU_JAVANETPKG "BindException"; 1025 break; 1026 default: 1027 xn = JNU_JAVANETPKG "SocketException"; 1028 break; 1029 } 1030 errno = errorValue; 1031 JNU_ThrowByNameWithLastError(env, xn, "NioSocketError"); 1032 return IOS_THROWN; 1033 }