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