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 105static 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 */ 128static 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 152JNIEXPORT void JNICALL 153Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz) 154{ 155 initInetAddressIDs(env); 156} 157 158JNIEXPORT jboolean JNICALL 159Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl) 160{ 161 return (ipv6_available()) ? JNI_TRUE : JNI_FALSE; 162} 163 164JNIEXPORT jboolean JNICALL 165Java_sun_nio_ch_Net_isReusePortAvailable0(JNIEnv* env, jclass c1) 166{ 167 return (reuseport_available()) ? JNI_TRUE : JNI_FALSE; 168} 169 170JNIEXPORT jint JNICALL 171Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) { 172 return -1; 173} 174 175JNIEXPORT jboolean JNICALL 176Java_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 186JNIEXPORT jboolean JNICALL 187Java_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 196JNIEXPORT jint JNICALL 197Java_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 /* Disable IPV6_V6ONLY to ensure dual-socket support */ 215 if (domain == AF_INET6) { 216 int arg = 0; 217 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, 218 sizeof(int)) < 0) { 219 JNU_ThrowByNameWithLastError(env, 220 JNU_JAVANETPKG "SocketException", 221 "Unable to set IPV6_V6ONLY"); 222 close(fd); 223 return -1; 224 } 225 } 226#endif 227 228 if (reuse) { 229 int arg = 1; 230 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, 231 sizeof(arg)) < 0) { 232 JNU_ThrowByNameWithLastError(env, 233 JNU_JAVANETPKG "SocketException", 234 "Unable to set SO_REUSEADDR"); 235 close(fd); 236 return -1; 237 } 238 } 239 240#if defined(__linux__) 241 if (type == SOCK_DGRAM) { 242 int arg = 0; 243 int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP; 244 if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) && 245 (errno != ENOPROTOOPT)) { 246 JNU_ThrowByNameWithLastError(env, 247 JNU_JAVANETPKG "SocketException", 248 "Unable to set IP_MULTICAST_ALL"); 249 close(fd); 250 return -1; 251 } 252 } 253#endif 254 255#if defined(__linux__) && defined(AF_INET6) 256 /* By default, Linux uses the route default */ 257 if (domain == AF_INET6 && type == SOCK_DGRAM) { 258 int arg = 1; 259 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg, 260 sizeof(arg)) < 0) { 261 JNU_ThrowByNameWithLastError(env, 262 JNU_JAVANETPKG "SocketException", 263 "Unable to set IPV6_MULTICAST_HOPS"); 264 close(fd); 265 return -1; 266 } 267 } 268#endif 269 return fd; 270} 271 272JNIEXPORT void JNICALL 273Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6, 274 jboolean useExclBind, jobject iao, int port) 275{ 276 SOCKETADDRESS sa; 277 int sa_len = 0; 278 int rv = 0; 279 280 if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, 281 preferIPv6) != 0) { 282 return; 283 } 284 285 rv = NET_Bind(fdval(env, fdo), &sa, sa_len); 286 if (rv != 0) { 287 handleSocketError(env, errno); 288 } 289} 290 291JNIEXPORT void JNICALL 292Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog) 293{ 294 if (listen(fdval(env, fdo), backlog) < 0) 295 handleSocketError(env, errno); 296} 297 298JNIEXPORT jint JNICALL 299Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, 300 jobject fdo, jobject iao, jint port) 301{ 302 SOCKETADDRESS sa; 303 int sa_len = 0; 304 int rv; 305 306 if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, 307 preferIPv6) != 0) { 308 return IOS_THROWN; 309 } 310 311 rv = connect(fdval(env, fdo), &sa.sa, sa_len); 312 if (rv != 0) { 313 if (errno == EINPROGRESS) { 314 return IOS_UNAVAILABLE; 315 } else if (errno == EINTR) { 316 return IOS_INTERRUPTED; 317 } 318 return handleSocketError(env, errno); 319 } 320 return 1; 321} 322 323JNIEXPORT jint JNICALL 324Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo) 325{ 326 SOCKETADDRESS sa; 327 socklen_t sa_len = sizeof(SOCKETADDRESS); 328 if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) { 329#ifdef _ALLBSD_SOURCE 330 /* 331 * XXXBSD: 332 * ECONNRESET is specific to the BSDs. We can not return an error, 333 * as the calling Java code with raise a java.lang.Error given the expectation 334 * that getsockname() will never fail. According to the Single UNIX Specification, 335 * it shouldn't fail. As such, we just fill in generic Linux-compatible values. 336 */ 337 if (errno == ECONNRESET) { 338 bzero(&sa.sa4, sizeof(sa)); 339 sa.sa4.sin_len = sizeof(struct sockaddr_in); 340 sa.sa4.sin_family = AF_INET; 341 sa.sa4.sin_port = htonl(0); 342 sa.sa4.sin_addr.s_addr = INADDR_ANY; 343 } else { 344 handleSocketError(env, errno); 345 return -1; 346 } 347#else /* _ALLBSD_SOURCE */ 348 handleSocketError(env, errno); 349 return -1; 350#endif /* _ALLBSD_SOURCE */ 351 } 352 return NET_GetPortFromSockaddr(&sa); 353} 354 355JNIEXPORT jobject JNICALL 356Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo) 357{ 358 SOCKETADDRESS sa; 359 socklen_t sa_len = sizeof(SOCKETADDRESS); 360 int port; 361 if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) { 362#ifdef _ALLBSD_SOURCE 363 /* 364 * XXXBSD: 365 * ECONNRESET is specific to the BSDs. We can not return an error, 366 * as the calling Java code with raise a java.lang.Error with the expectation 367 * that getsockname() will never fail. According to the Single UNIX Specification, 368 * it shouldn't fail. As such, we just fill in generic Linux-compatible values. 369 */ 370 if (errno == ECONNRESET) { 371 bzero(&sa.sa4, sizeof(sa)); 372 sa.sa4.sin_len = sizeof(struct sockaddr_in); 373 sa.sa4.sin_family = AF_INET; 374 sa.sa4.sin_port = htonl(0); 375 sa.sa4.sin_addr.s_addr = INADDR_ANY; 376 } else { 377 handleSocketError(env, errno); 378 return NULL; 379 } 380#else /* _ALLBSD_SOURCE */ 381 handleSocketError(env, errno); 382 return NULL; 383#endif /* _ALLBSD_SOURCE */ 384 } 385 return NET_SockaddrToInetAddress(env, &sa, &port); 386} 387 388JNIEXPORT jint JNICALL 389Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 390 jboolean mayNeedConversion, jint level, jint opt) 391{ 392 int result; 393 struct linger linger; 394 u_char carg; 395 void *arg; 396 socklen_t arglen; 397 int n; 398 399 /* Option value is an int except for a few specific cases */ 400 401 arg = (void *)&result; 402 arglen = sizeof(result); 403 404 if (level == IPPROTO_IP && 405 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { 406 arg = (void*)&carg; 407 arglen = sizeof(carg); 408 } 409 410 if (level == SOL_SOCKET && opt == SO_LINGER) { 411 arg = (void *)&linger; 412 arglen = sizeof(linger); 413 } 414 415 if (mayNeedConversion) { 416 n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, (int*)&arglen); 417 } else { 418 n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen); 419 } 420 if (n < 0) { 421 JNU_ThrowByNameWithLastError(env, 422 JNU_JAVANETPKG "SocketException", 423 "sun.nio.ch.Net.getIntOption"); 424 return -1; 425 } 426 427 if (level == IPPROTO_IP && 428 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) 429 { 430 return (jint)carg; 431 } 432 433 if (level == SOL_SOCKET && opt == SO_LINGER) 434 return linger.l_onoff ? (jint)linger.l_linger : (jint)-1; 435 436 return (jint)result; 437} 438 439JNIEXPORT void JNICALL 440Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 441 jboolean mayNeedConversion, jint level, 442 jint opt, jint arg, jboolean isIPv6) 443{ 444 int result; 445 struct linger linger; 446 u_char carg; 447 void *parg; 448 socklen_t arglen; 449 int n; 450 451 /* Option value is an int except for a few specific cases */ 452 453 parg = (void*)&arg; 454 arglen = sizeof(arg); 455 456 if (level == IPPROTO_IP && 457 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { 458 parg = (void*)&carg; 459 arglen = sizeof(carg); 460 carg = (u_char)arg; 461 } 462 463 if (level == SOL_SOCKET && opt == SO_LINGER) { 464 parg = (void *)&linger; 465 arglen = sizeof(linger); 466 if (arg >= 0) { 467 linger.l_onoff = 1; 468 linger.l_linger = arg; 469 } else { 470 linger.l_onoff = 0; 471 linger.l_linger = 0; 472 } 473 } 474 475 if (mayNeedConversion) { 476 n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen); 477 } else { 478 n = setsockopt(fdval(env, fdo), level, opt, parg, arglen); 479 } 480 if (n < 0) { 481 JNU_ThrowByNameWithLastError(env, 482 JNU_JAVANETPKG "SocketException", 483 "sun.nio.ch.Net.setIntOption"); 484 } 485#ifdef __linux__ 486 if (level == IPPROTO_IPV6 && opt == IPV6_TCLASS && isIPv6) { 487 // set the V4 option also 488 setsockopt(fdval(env, fdo), IPPROTO_IP, IP_TOS, parg, arglen); 489 } 490#endif 491} 492 493JNIEXPORT jint JNICALL 494Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo, 495 jint group, jint interf, jint source) 496{ 497 struct ip_mreq mreq; 498 struct ip_mreq_source mreq_source; 499 int opt, n, optlen; 500 void* optval; 501 502 if (source == 0) { 503 mreq.imr_multiaddr.s_addr = htonl(group); 504 mreq.imr_interface.s_addr = htonl(interf); 505 opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; 506 optval = (void*)&mreq; 507 optlen = sizeof(mreq); 508 } else { 509 510#ifdef _AIX 511 /* check AIX for support of source filtering */ 512 if (isSourceFilterSupported() != JNI_TRUE){ 513 return IOS_UNAVAILABLE; 514 } 515#endif 516 517 mreq_source.imr_multiaddr.s_addr = htonl(group); 518 mreq_source.imr_sourceaddr.s_addr = htonl(source); 519 mreq_source.imr_interface.s_addr = htonl(interf); 520 opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP; 521 optval = (void*)&mreq_source; 522 optlen = sizeof(mreq_source); 523 } 524 525 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen); 526 if (n < 0) { 527 if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) 528 return IOS_UNAVAILABLE; 529 handleSocketError(env, errno); 530 } 531 return 0; 532} 533 534JNIEXPORT jint JNICALL 535Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo, 536 jint group, jint interf, jint source) 537{ 538#ifdef __APPLE__ 539 /* no IPv4 exclude-mode filtering for now */ 540 return IOS_UNAVAILABLE; 541#else 542 struct ip_mreq_source mreq_source; 543 int n; 544 int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE; 545 546#ifdef _AIX 547 /* check AIX for support of source filtering */ 548 if (isSourceFilterSupported() != JNI_TRUE){ 549 return IOS_UNAVAILABLE; 550 } 551#endif 552 553 mreq_source.imr_multiaddr.s_addr = htonl(group); 554 mreq_source.imr_sourceaddr.s_addr = htonl(source); 555 mreq_source.imr_interface.s_addr = htonl(interf); 556 557 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, 558 (void*)&mreq_source, sizeof(mreq_source)); 559 if (n < 0) { 560 if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) 561 return IOS_UNAVAILABLE; 562 handleSocketError(env, errno); 563 } 564 return 0; 565#endif 566} 567 568JNIEXPORT jint JNICALL 569Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo, 570 jbyteArray group, jint index, jbyteArray source) 571{ 572#ifdef AF_INET6 573 struct ipv6_mreq mreq6; 574 struct group_source_req req; 575 int opt, n, optlen; 576 void* optval; 577 578 if (source == NULL) { 579 COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr)); 580 mreq6.ipv6mr_interface = (int)index; 581 opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP; 582 optval = (void*)&mreq6; 583 optlen = sizeof(mreq6); 584 } else { 585#ifdef __APPLE__ 586 /* no IPv6 include-mode filtering for now */ 587 return IOS_UNAVAILABLE; 588#else 589 initGroupSourceReq(env, group, index, source, &req); 590 opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP; 591 optval = (void*)&req; 592 optlen = sizeof(req); 593#endif 594 } 595 596 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen); 597 if (n < 0) { 598 if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) 599 return IOS_UNAVAILABLE; 600 handleSocketError(env, errno); 601 } 602 return 0; 603#else 604 JNU_ThrowInternalError(env, "Should not get here"); 605 return IOS_THROWN; 606#endif /* AF_INET6 */ 607} 608 609JNIEXPORT jint JNICALL 610Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo, 611 jbyteArray group, jint index, jbyteArray source) 612{ 613#ifdef AF_INET6 614 #ifdef __APPLE__ 615 /* no IPv6 exclude-mode filtering for now */ 616 return IOS_UNAVAILABLE; 617 #else 618 struct group_source_req req; 619 int n; 620 int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE; 621 622 initGroupSourceReq(env, group, index, source, &req); 623 624 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, 625 (void*)&req, sizeof(req)); 626 if (n < 0) { 627 if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) 628 return IOS_UNAVAILABLE; 629 handleSocketError(env, errno); 630 } 631 return 0; 632 #endif 633#else 634 JNU_ThrowInternalError(env, "Should not get here"); 635 return IOS_THROWN; 636#endif 637} 638 639JNIEXPORT void JNICALL 640Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf) 641{ 642 struct in_addr in; 643 socklen_t arglen = sizeof(struct in_addr); 644 int n; 645 646 in.s_addr = htonl(interf); 647 648 n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, 649 (void*)&(in.s_addr), arglen); 650 if (n < 0) { 651 handleSocketError(env, errno); 652 } 653} 654 655JNIEXPORT jint JNICALL 656Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo) 657{ 658 struct in_addr in; 659 socklen_t arglen = sizeof(struct in_addr); 660 int n; 661 662 n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen); 663 if (n < 0) { 664 handleSocketError(env, errno); 665 return -1; 666 } 667 return ntohl(in.s_addr); 668} 669 670JNIEXPORT void JNICALL 671Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index) 672{ 673 int value = (jint)index; 674 socklen_t arglen = sizeof(value); 675 int n; 676 677 n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, 678 (void*)&(index), arglen); 679 if (n < 0) { 680 handleSocketError(env, errno); 681 } 682} 683 684JNIEXPORT jint JNICALL 685Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo) 686{ 687 int index; 688 socklen_t arglen = sizeof(index); 689 int n; 690 691 n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen); 692 if (n < 0) { 693 handleSocketError(env, errno); 694 return -1; 695 } 696 return (jint)index; 697} 698 699JNIEXPORT void JNICALL 700Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) 701{ 702 int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD : 703 (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR; 704 if ((shutdown(fdval(env, fdo), how) < 0) && (errno != ENOTCONN)) 705 handleSocketError(env, errno); 706} 707 708JNIEXPORT jint JNICALL 709Java_sun_nio_ch_Net_poll(JNIEnv* env, jclass this, jobject fdo, jint events, jlong timeout) 710{ 711 struct pollfd pfd; 712 int rv; 713 pfd.fd = fdval(env, fdo); 714 pfd.events = events; 715 if (timeout < -1) { 716 timeout = -1; 717 } else if (timeout > INT_MAX) { 718 timeout = INT_MAX; 719 } 720 rv = poll(&pfd, 1, (int)timeout); 721 722 if (rv >= 0) { 723 return pfd.revents; 724 } else if (errno == EINTR) { 725 return IOS_INTERRUPTED; 726 } else { 727 handleSocketError(env, errno); 728 return IOS_THROWN; 729 } 730} 731 732JNIEXPORT jshort JNICALL 733Java_sun_nio_ch_Net_pollinValue(JNIEnv *env, jclass this) 734{ 735 return (jshort)POLLIN; 736} 737 738JNIEXPORT jshort JNICALL 739Java_sun_nio_ch_Net_polloutValue(JNIEnv *env, jclass this) 740{ 741 return (jshort)POLLOUT; 742} 743 744JNIEXPORT jshort JNICALL 745Java_sun_nio_ch_Net_pollerrValue(JNIEnv *env, jclass this) 746{ 747 return (jshort)POLLERR; 748} 749 750JNIEXPORT jshort JNICALL 751Java_sun_nio_ch_Net_pollhupValue(JNIEnv *env, jclass this) 752{ 753 return (jshort)POLLHUP; 754} 755 756JNIEXPORT jshort JNICALL 757Java_sun_nio_ch_Net_pollnvalValue(JNIEnv *env, jclass this) 758{ 759 return (jshort)POLLNVAL; 760} 761 762JNIEXPORT jshort JNICALL 763Java_sun_nio_ch_Net_pollconnValue(JNIEnv *env, jclass this) 764{ 765 return (jshort)POLLOUT; 766} 767 768 769/* Declared in nio_util.h */ 770 771jint 772handleSocketError(JNIEnv *env, jint errorValue) 773{ 774 char *xn; 775 switch (errorValue) { 776 case EINPROGRESS: /* Non-blocking connect */ 777 return 0; 778#ifdef EPROTO 779 case EPROTO: 780 xn = JNU_JAVANETPKG "ProtocolException"; 781 break; 782#endif 783 case ECONNREFUSED: 784 xn = JNU_JAVANETPKG "ConnectException"; 785 break; 786 case ETIMEDOUT: 787 xn = JNU_JAVANETPKG "ConnectException"; 788 break; 789 case EHOSTUNREACH: 790 xn = JNU_JAVANETPKG "NoRouteToHostException"; 791 break; 792 case EADDRINUSE: /* Fall through */ 793 case EADDRNOTAVAIL: 794 xn = JNU_JAVANETPKG "BindException"; 795 break; 796 default: 797 xn = JNU_JAVANETPKG "SocketException"; 798 break; 799 } 800 errno = errorValue; 801 JNU_ThrowByNameWithLastError(env, xn, "NioSocketError"); 802 return IOS_THROWN; 803} 804