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