1/* 2 * Copyright (c) 2001, 2011, 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 33#include "jni.h" 34#include "jni_util.h" 35#include "jvm.h" 36#include "jlong.h" 37#include "sun_nio_ch_Net.h" 38#include "net_util.h" 39#include "net_util_md.h" 40#include "nio_util.h" 41#include "nio.h" 42#include "sun_nio_ch_PollArrayWrapper.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#include <nativehelper/JNIHelp.h> 59 60#define NATIVE_METHOD(className, functionName, signature) \ 61{ #functionName, signature, (void*)(Java_sun_nio_ch_ ## className ## _ ## functionName) } 62 63#if defined(_ALLBSD_SOURCE) || defined(_AIX) 64 65#ifndef IP_BLOCK_SOURCE 66 67#if defined(_AIX) 68 69#define IP_BLOCK_SOURCE 58 /* Block data from a given source to a given group */ 70#define IP_UNBLOCK_SOURCE 59 /* Unblock data from a given source to a given group */ 71#define IP_ADD_SOURCE_MEMBERSHIP 60 /* Join a source-specific group */ 72#define IP_DROP_SOURCE_MEMBERSHIP 61 /* Leave a source-specific group */ 73 74#else 75 76#define IP_ADD_SOURCE_MEMBERSHIP 70 /* join a source-specific group */ 77#define IP_DROP_SOURCE_MEMBERSHIP 71 /* drop a single source */ 78#define IP_BLOCK_SOURCE 72 /* block a source */ 79#define IP_UNBLOCK_SOURCE 73 /* unblock a source */ 80 81#endif /* _AIX */ 82 83#endif /* IP_BLOCK_SOURCE */ 84 85#ifndef MCAST_BLOCK_SOURCE 86 87#if defined(_AIX) 88 89#define MCAST_BLOCK_SOURCE 64 90#define MCAST_UNBLOCK_SOURCE 65 91#define MCAST_JOIN_SOURCE_GROUP 66 92#define MCAST_LEAVE_SOURCE_GROUP 67 93 94#else 95 96#define MCAST_JOIN_SOURCE_GROUP 82 /* join a source-specific group */ 97#define MCAST_LEAVE_SOURCE_GROUP 83 /* leave a single source */ 98#define MCAST_BLOCK_SOURCE 84 /* block a source */ 99#define MCAST_UNBLOCK_SOURCE 85 /* unblock a source */ 100 101#endif /* _AIX */ 102 103#endif /* MCAST_BLOCK_SOURCE */ 104 105#ifndef IPV6_ADD_MEMBERSHIP 106 107#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP 108#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP 109 110#endif /* IPV6_ADD_MEMBERSHIP */ 111 112#if defined(_AIX) 113 114struct my_ip_mreq_source { 115 struct in_addr imr_multiaddr; 116 struct in_addr imr_sourceaddr; 117 struct in_addr imr_interface; 118}; 119 120#else 121 122struct my_ip_mreq_source { 123 struct in_addr imr_multiaddr; 124 struct in_addr imr_interface; 125 struct in_addr imr_sourceaddr; 126}; 127 128#endif /* _AIX */ 129 130struct my_group_source_req { 131 uint32_t gsr_interface; /* interface index */ 132 struct sockaddr_storage gsr_group; /* group address */ 133 struct sockaddr_storage gsr_source; /* source address */ 134}; 135 136#else /* _ALLBSD_SOURCE */ 137 138#define my_ip_mreq_source ip_mreq_source 139#define my_group_source_req group_source_req 140 141#endif 142 143 144#define COPY_INET6_ADDRESS(env, source, target) \ 145 (*(env))->GetByteArrayRegion(env, source, 0, 16, target) 146 147/* 148 * Copy IPv6 group, interface index, and IPv6 source address 149 * into group_source_req structure. 150 */ 151#ifdef AF_INET6 152static void initGroupSourceReq(JNIEnv* env, jbyteArray group, jint index, 153 jbyteArray source, struct my_group_source_req* req) 154{ 155 struct sockaddr_in6* sin6; 156 157 req->gsr_interface = (uint32_t)index; 158 159 sin6 = (struct sockaddr_in6*)&(req->gsr_group); 160 sin6->sin6_family = AF_INET6; 161 COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr)); 162 163 sin6 = (struct sockaddr_in6*)&(req->gsr_source); 164 sin6->sin6_family = AF_INET6; 165 COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr)); 166} 167#endif 168 169#ifdef _AIX 170 171/* 172 * Checks whether or not "socket extensions for multicast source filters" is supported. 173 * Returns JNI_TRUE if it is supported, JNI_FALSE otherwise 174 */ 175static jboolean isSourceFilterSupported(){ 176 static jboolean alreadyChecked = JNI_FALSE; 177 static jboolean result = JNI_TRUE; 178 if (alreadyChecked != JNI_TRUE){ 179 struct utsname uts; 180 memset(&uts, 0, sizeof(uts)); 181 strcpy(uts.sysname, "?"); 182 const int utsRes = uname(&uts); 183 int major = -1; 184 int minor = -1; 185 major = atoi(uts.version); 186 minor = atoi(uts.release); 187 if (strcmp(uts.sysname, "AIX") == 0) { 188 if (major < 6 || (major == 6 && minor < 1)) {// unsupported on aix < 6.1 189 result = JNI_FALSE; 190 } 191 } 192 alreadyChecked = JNI_TRUE; 193 } 194 return result; 195} 196 197#endif /* _AIX */ 198 199JNIEXPORT jboolean JNICALL 200Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl) 201{ 202 return (ipv6_available()) ? JNI_TRUE : JNI_FALSE; 203} 204 205JNIEXPORT jint JNICALL 206Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) { 207 return -1; 208} 209 210JNIEXPORT jboolean JNICALL 211Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl) 212{ 213#if defined(MACOSX) || defined(_AIX) 214 /* for now IPv6 sockets cannot join IPv4 multicast groups */ 215 return JNI_FALSE; 216#else 217 return JNI_TRUE; 218#endif 219} 220 221JNIEXPORT jboolean JNICALL 222Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl) 223{ 224#ifdef __solaris__ 225 return JNI_TRUE; 226#else 227 return JNI_FALSE; 228#endif 229} 230 231JNIEXPORT int JNICALL 232Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, 233 jboolean stream, jboolean reuse, jboolean ignored) 234{ 235 int fd; 236 int type = (stream ? SOCK_STREAM : SOCK_DGRAM); 237#ifdef AF_INET6 238 int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; 239#else 240 int domain = AF_INET; 241#endif 242 243 fd = socket(domain, type, 0); 244 tagSocket(env, fd); 245 if (fd < 0) { 246 return handleSocketError(env, errno); 247 } 248 249#ifdef AF_INET6 250 /* Disable IPV6_V6ONLY to ensure dual-socket support */ 251 if (domain == AF_INET6) { 252 int arg = 0; 253 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, 254 sizeof(int)) < 0) { 255 JNU_ThrowByNameWithLastError(env, 256 JNU_JAVANETPKG "SocketException", 257 "Unable to set IPV6_V6ONLY"); 258 close(fd); 259 return -1; 260 } 261 } 262#endif 263 264 if (reuse) { 265 int arg = 1; 266 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, 267 sizeof(arg)) < 0) { 268 JNU_ThrowByNameWithLastError(env, 269 JNU_JAVANETPKG "SocketException", 270 "Unable to set SO_REUSEADDR"); 271 close(fd); 272 return -1; 273 } 274 } 275 276#if defined(__linux__) 277 if (type == SOCK_DGRAM) { 278 int arg = 0; 279 int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP; 280 if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) && 281 (errno != ENOPROTOOPT)) { 282 JNU_ThrowByNameWithLastError(env, 283 JNU_JAVANETPKG "SocketException", 284 "Unable to set IP_MULTICAST_ALL"); 285 close(fd); 286 return -1; 287 } 288 } 289#endif 290 291#if defined(__linux__) && defined(AF_INET6) 292 /* By default, Linux uses the route default */ 293 if (domain == AF_INET6 && type == SOCK_DGRAM) { 294 int arg = 1; 295 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg, 296 sizeof(arg)) < 0) { 297 JNU_ThrowByNameWithLastError(env, 298 JNU_JAVANETPKG "SocketException", 299 "Unable to set IPV6_MULTICAST_HOPS"); 300 close(fd); 301 return -1; 302 } 303 } 304#endif 305 return fd; 306} 307 308JNIEXPORT void JNICALL 309Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6, 310 jboolean useExclBind, jobject iao, int port) 311{ 312 SOCKADDR sa; 313 int sa_len = SOCKADDR_LEN; 314 int rv = 0; 315 316 if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) { 317 return; 318 } 319 320 rv = NET_Bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); 321 if (rv != 0) { 322 handleSocketError(env, errno); 323 } 324} 325 326JNIEXPORT void JNICALL 327Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog) 328{ 329 if (listen(fdval(env, fdo), backlog) < 0) 330 handleSocketError(env, errno); 331} 332 333JNIEXPORT jint JNICALL 334Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, 335 jobject fdo, jobject iao, jint port) 336{ 337 SOCKADDR sa; 338 int sa_len = SOCKADDR_LEN; 339 int rv; 340 341 if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa, 342 &sa_len, preferIPv6) != 0) 343 { 344 return IOS_THROWN; 345 } 346 347 rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); 348 if (rv != 0) { 349 if (errno == EINPROGRESS) { 350 return IOS_UNAVAILABLE; 351 } else if (errno == EINTR) { 352 return IOS_INTERRUPTED; 353 } 354 return handleSocketErrorWithDefault(env, errno, JNU_JAVANETPKG "ConnectException"); 355 } 356 return 1; 357} 358 359JNIEXPORT jint JNICALL 360Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo) 361{ 362 SOCKADDR sa; 363 socklen_t sa_len = SOCKADDR_LEN; 364 if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { 365#ifdef _ALLBSD_SOURCE 366 /* 367 * XXXBSD: 368 * ECONNRESET is specific to the BSDs. We can not return an error, 369 * as the calling Java code with raise a java.lang.Error given the expectation 370 * that getsockname() will never fail. According to the Single UNIX Specification, 371 * it shouldn't fail. As such, we just fill in generic Linux-compatible values. 372 */ 373 if (errno == ECONNRESET) { 374 struct sockaddr_in *sin; 375 sin = (struct sockaddr_in *) &sa; 376 bzero(sin, sizeof(*sin)); 377 sin->sin_len = sizeof(struct sockaddr_in); 378 sin->sin_family = AF_INET; 379 sin->sin_port = htonl(0); 380 sin->sin_addr.s_addr = INADDR_ANY; 381 } else { 382 handleSocketError(env, errno); 383 return -1; 384 } 385#else /* _ALLBSD_SOURCE */ 386 handleSocketError(env, errno); 387 return -1; 388#endif /* _ALLBSD_SOURCE */ 389 } 390 return NET_GetPortFromSockaddr((struct sockaddr *)&sa); 391} 392 393JNIEXPORT jobject JNICALL 394Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo) 395{ 396 SOCKADDR sa; 397 socklen_t sa_len = SOCKADDR_LEN; 398 int port; 399 if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { 400#ifdef _ALLBSD_SOURCE 401 /* 402 * XXXBSD: 403 * ECONNRESET is specific to the BSDs. We can not return an error, 404 * as the calling Java code with raise a java.lang.Error with the expectation 405 * that getsockname() will never fail. According to the Single UNIX Specification, 406 * it shouldn't fail. As such, we just fill in generic Linux-compatible values. 407 */ 408 if (errno == ECONNRESET) { 409 struct sockaddr_in *sin; 410 sin = (struct sockaddr_in *) &sa; 411 bzero(sin, sizeof(*sin)); 412 sin->sin_len = sizeof(struct sockaddr_in); 413 sin->sin_family = AF_INET; 414 sin->sin_port = htonl(0); 415 sin->sin_addr.s_addr = INADDR_ANY; 416 } else { 417 handleSocketError(env, errno); 418 return NULL; 419 } 420#else /* _ALLBSD_SOURCE */ 421 handleSocketError(env, errno); 422 return NULL; 423#endif /* _ALLBSD_SOURCE */ 424 } 425 return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); 426} 427 428JNIEXPORT jint JNICALL 429Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 430 jboolean mayNeedConversion, jint level, jint opt) 431{ 432 int result; 433 struct linger linger; 434 u_char carg; 435 void *arg; 436 socklen_t arglen; 437 int n; 438 439 /* Option value is an int except for a few specific cases */ 440 441 arg = (void *)&result; 442 arglen = sizeof(result); 443 444 if (level == IPPROTO_IP && 445 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { 446 arg = (void*)&carg; 447 arglen = sizeof(carg); 448 } 449 450 if (level == SOL_SOCKET && opt == SO_LINGER) { 451 arg = (void *)&linger; 452 arglen = sizeof(linger); 453 } 454 455 if (mayNeedConversion) { 456 n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, (int*)&arglen); 457 } else { 458 n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen); 459 } 460 if (n < 0) { 461 JNU_ThrowByNameWithLastError(env, 462 JNU_JAVANETPKG "SocketException", 463 "sun.nio.ch.Net.getIntOption"); 464 return -1; 465 } 466 467 if (level == IPPROTO_IP && 468 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) 469 { 470 return (jint)carg; 471 } 472 473 if (level == SOL_SOCKET && opt == SO_LINGER) 474 return linger.l_onoff ? (jint)linger.l_linger : (jint)-1; 475 476 return (jint)result; 477} 478 479JNIEXPORT void JNICALL 480Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 481 jboolean mayNeedConversion, jint level, 482 jint opt, jint arg, jboolean isIPv6) 483{ 484 int result; 485 struct linger linger; 486 u_char carg; 487 void *parg; 488 socklen_t arglen; 489 int n; 490 491 /* Option value is an int except for a few specific cases */ 492 493 parg = (void*)&arg; 494 arglen = sizeof(arg); 495 496 if (level == IPPROTO_IP && 497 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { 498 parg = (void*)&carg; 499 arglen = sizeof(carg); 500 carg = (u_char)arg; 501 } 502 503 if (level == SOL_SOCKET && opt == SO_LINGER) { 504 parg = (void *)&linger; 505 arglen = sizeof(linger); 506 if (arg >= 0) { 507 linger.l_onoff = 1; 508 linger.l_linger = arg; 509 } else { 510 linger.l_onoff = 0; 511 linger.l_linger = 0; 512 } 513 } 514 515 if (mayNeedConversion) { 516 n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen); 517 } else { 518 n = setsockopt(fdval(env, fdo), level, opt, parg, arglen); 519 } 520 if (n < 0) { 521 JNU_ThrowByNameWithLastError(env, 522 JNU_JAVANETPKG "SocketException", 523 "sun.nio.ch.Net.setIntOption"); 524 } 525#ifdef __linux__ 526 if (level == IPPROTO_IPV6 && opt == IPV6_TCLASS && isIPv6) { 527 // set the V4 option also 528 setsockopt(fdval(env, fdo), IPPROTO_IP, IP_TOS, parg, arglen); 529 } 530#endif 531} 532 533JNIEXPORT jint JNICALL 534Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo, 535 jint group, jint interf, jint source) 536{ 537 struct ip_mreq mreq; 538 struct my_ip_mreq_source mreq_source; 539 int opt, n, optlen; 540 void* optval; 541 542 if (source == 0) { 543 mreq.imr_multiaddr.s_addr = htonl(group); 544 mreq.imr_interface.s_addr = htonl(interf); 545 opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; 546 optval = (void*)&mreq; 547 optlen = sizeof(mreq); 548 } else { 549#ifdef MACOSX 550 /* no IPv4 include-mode filtering for now */ 551 return IOS_UNAVAILABLE; 552#else 553 554#ifdef _AIX 555 /* check AIX for support of source filtering */ 556 if (isSourceFilterSupported() != JNI_TRUE){ 557 return IOS_UNAVAILABLE; 558 } 559#endif 560 561 mreq_source.imr_multiaddr.s_addr = htonl(group); 562 mreq_source.imr_sourceaddr.s_addr = htonl(source); 563 mreq_source.imr_interface.s_addr = htonl(interf); 564 opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP; 565 optval = (void*)&mreq_source; 566 optlen = sizeof(mreq_source); 567#endif 568 } 569 570 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen); 571 if (n < 0) { 572 if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) 573 return IOS_UNAVAILABLE; 574 handleSocketError(env, errno); 575 } 576 return 0; 577} 578 579JNIEXPORT jint JNICALL 580Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo, 581 jint group, jint interf, jint source) 582{ 583#ifdef MACOSX 584 /* no IPv4 exclude-mode filtering for now */ 585 return IOS_UNAVAILABLE; 586#else 587 struct my_ip_mreq_source mreq_source; 588 int n; 589 int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE; 590 591#ifdef _AIX 592 /* check AIX for support of source filtering */ 593 if (isSourceFilterSupported() != JNI_TRUE){ 594 return IOS_UNAVAILABLE; 595 } 596#endif 597 mreq_source.imr_multiaddr.s_addr = htonl(group); 598 mreq_source.imr_sourceaddr.s_addr = htonl(source); 599 mreq_source.imr_interface.s_addr = htonl(interf); 600 601 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, 602 (void*)&mreq_source, sizeof(mreq_source)); 603 if (n < 0) { 604 if (block && (errno == ENOPROTOOPT)) 605 return IOS_UNAVAILABLE; 606 handleSocketError(env, errno); 607 } 608 return 0; 609#endif 610} 611 612JNIEXPORT jint JNICALL 613Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo, 614 jbyteArray group, jint index, jbyteArray source) 615{ 616#ifdef AF_INET6 617 struct ipv6_mreq mreq6; 618 struct my_group_source_req req; 619 int opt, n, optlen; 620 void* optval; 621 622 if (source == NULL) { 623 COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr)); 624 mreq6.ipv6mr_interface = (int)index; 625 opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP; 626 optval = (void*)&mreq6; 627 optlen = sizeof(mreq6); 628 } else { 629#ifdef MACOSX 630 /* no IPv6 include-mode filtering for now */ 631 return IOS_UNAVAILABLE; 632#else 633 initGroupSourceReq(env, group, index, source, &req); 634 opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP; 635 optval = (void*)&req; 636 optlen = sizeof(req); 637#endif 638 } 639 640 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen); 641 if (n < 0) { 642 if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) 643 return IOS_UNAVAILABLE; 644 handleSocketError(env, errno); 645 } 646 return 0; 647#else 648 JNU_ThrowInternalError(env, "Should not get here"); 649 return IOS_THROWN; 650#endif /* AF_INET6 */ 651} 652 653JNIEXPORT jint JNICALL 654Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo, 655 jbyteArray group, jint index, jbyteArray source) 656{ 657#ifdef AF_INET6 658 #ifdef MACOSX 659 /* no IPv6 exclude-mode filtering for now */ 660 return IOS_UNAVAILABLE; 661 #else 662 struct my_group_source_req req; 663 int n; 664 int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE; 665 666 initGroupSourceReq(env, group, index, source, &req); 667 668 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, 669 (void*)&req, sizeof(req)); 670 if (n < 0) { 671 if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) 672 return IOS_UNAVAILABLE; 673 handleSocketError(env, errno); 674 } 675 return 0; 676 #endif 677#else 678 JNU_ThrowInternalError(env, "Should not get here"); 679 return IOS_THROWN; 680#endif 681} 682 683JNIEXPORT void JNICALL 684Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf) 685{ 686 struct in_addr in; 687 socklen_t arglen = sizeof(struct in_addr); 688 int n; 689 690 in.s_addr = htonl(interf); 691 692 n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, 693 (void*)&(in.s_addr), arglen); 694 if (n < 0) { 695 handleSocketError(env, errno); 696 } 697} 698 699JNIEXPORT jint JNICALL 700Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo) 701{ 702 struct in_addr in; 703 socklen_t arglen = sizeof(struct in_addr); 704 int n; 705 706 n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen); 707 if (n < 0) { 708 handleSocketError(env, errno); 709 return -1; 710 } 711 return ntohl(in.s_addr); 712} 713 714JNIEXPORT void JNICALL 715Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index) 716{ 717 int value = (jint)index; 718 socklen_t arglen = sizeof(value); 719 int n; 720 721 n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, 722 (void*)&(index), arglen); 723 if (n < 0) { 724 handleSocketError(env, errno); 725 } 726} 727 728JNIEXPORT jint JNICALL 729Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo) 730{ 731 int index; 732 socklen_t arglen = sizeof(index); 733 int n; 734 735 n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen); 736 if (n < 0) { 737 handleSocketError(env, errno); 738 return -1; 739 } 740 return (jint)index; 741} 742 743JNIEXPORT void JNICALL 744Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) 745{ 746 int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD : 747 (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR; 748 if ((shutdown(fdval(env, fdo), how) < 0) && (errno != ENOTCONN)) 749 handleSocketError(env, errno); 750} 751 752JNIEXPORT jint JNICALL 753Java_sun_nio_ch_Net_poll(JNIEnv* env, jclass this, jobject fdo, jint events, jlong timeout) 754{ 755 struct pollfd pfd; 756 int rv; 757 pfd.fd = fdval(env, fdo); 758 pfd.events = events; 759 rv = poll(&pfd, 1, timeout); 760 761 if (rv >= 0) { 762 return pfd.revents; 763 } else if (errno == EINTR) { 764 return IOS_INTERRUPTED; 765 } else { 766 handleSocketError(env, errno); 767 return IOS_THROWN; 768 } 769} 770 771JNIEXPORT jshort JNICALL 772Java_sun_nio_ch_Net_pollinValue(JNIEnv *env, jclass this) 773{ 774 return (jshort)POLLIN; 775} 776 777JNIEXPORT jshort JNICALL 778Java_sun_nio_ch_Net_polloutValue(JNIEnv *env, jclass this) 779{ 780 return (jshort)POLLOUT; 781} 782 783JNIEXPORT jshort JNICALL 784Java_sun_nio_ch_Net_pollerrValue(JNIEnv *env, jclass this) 785{ 786 return (jshort)POLLERR; 787} 788 789JNIEXPORT jshort JNICALL 790Java_sun_nio_ch_Net_pollhupValue(JNIEnv *env, jclass this) 791{ 792 return (jshort)POLLHUP; 793} 794 795JNIEXPORT jshort JNICALL 796Java_sun_nio_ch_Net_pollnvalValue(JNIEnv *env, jclass this) 797{ 798 return (jshort)POLLNVAL; 799} 800 801JNIEXPORT jshort JNICALL 802Java_sun_nio_ch_Net_pollconnValue(JNIEnv *env, jclass this) 803{ 804 return (jshort)POLLOUT; 805} 806 807 808/* Declared in nio_util.h */ 809 810jint 811handleSocketErrorWithDefault(JNIEnv *env, jint errorValue, const char *defaultException) 812{ 813 const char *xn; 814 switch (errorValue) { 815 case EINPROGRESS: /* Non-blocking connect */ 816 return 0; 817#ifdef EPROTO 818 case EPROTO: 819 xn = JNU_JAVANETPKG "ProtocolException"; 820 break; 821#endif 822 case ECONNREFUSED: 823 xn = JNU_JAVANETPKG "ConnectException"; 824 break; 825 case ETIMEDOUT: 826 xn = JNU_JAVANETPKG "ConnectException"; 827 break; 828 case EHOSTUNREACH: 829 xn = JNU_JAVANETPKG "NoRouteToHostException"; 830 break; 831 case EADDRINUSE: /* Fall through */ 832 case EADDRNOTAVAIL: 833 xn = JNU_JAVANETPKG "BindException"; 834 break; 835 default: 836 xn = defaultException; 837 break; 838 } 839 errno = errorValue; 840 JNU_ThrowByNameWithLastError(env, xn, "NioSocketError"); 841 return IOS_THROWN; 842} 843 844/* Declared in nio_util.h */ 845 846jint 847handleSocketError(JNIEnv *env, jint errorValue) { 848 return handleSocketErrorWithDefault(env, errorValue, 849 JNU_JAVANETPKG "SocketException"); 850} 851 852 853static JNINativeMethod gMethods[] = { 854 NATIVE_METHOD(Net, isIPv6Available0, "()Z"), 855 NATIVE_METHOD(Net, isExclusiveBindAvailable, "()I"), 856 NATIVE_METHOD(Net, canIPv6SocketJoinIPv4Group0, "()Z"), 857 NATIVE_METHOD(Net, canJoin6WithIPv4Group0, "()Z"), 858 NATIVE_METHOD(Net, socket0, "(ZZZZ)I"), 859 NATIVE_METHOD(Net, bind0, "(Ljava/io/FileDescriptor;ZZLjava/net/InetAddress;I)V"), 860 NATIVE_METHOD(Net, listen, "(Ljava/io/FileDescriptor;I)V"), 861 NATIVE_METHOD(Net, connect0, "(ZLjava/io/FileDescriptor;Ljava/net/InetAddress;I)I"), 862 NATIVE_METHOD(Net, shutdown, "(Ljava/io/FileDescriptor;I)V"), 863 NATIVE_METHOD(Net, localPort, "(Ljava/io/FileDescriptor;)I"), 864 NATIVE_METHOD(Net, localInetAddress, "(Ljava/io/FileDescriptor;)Ljava/net/InetAddress;"), 865 NATIVE_METHOD(Net, getIntOption0, "(Ljava/io/FileDescriptor;ZII)I"), 866 NATIVE_METHOD(Net, setIntOption0, "(Ljava/io/FileDescriptor;ZIIIZ)V"), 867 NATIVE_METHOD(Net, joinOrDrop4, "(ZLjava/io/FileDescriptor;III)I"), 868 NATIVE_METHOD(Net, blockOrUnblock4, "(ZLjava/io/FileDescriptor;III)I"), 869 NATIVE_METHOD(Net, joinOrDrop6, "(ZLjava/io/FileDescriptor;[BI[B)I"), 870 NATIVE_METHOD(Net, blockOrUnblock6, "(ZLjava/io/FileDescriptor;[BI[B)I"), 871 NATIVE_METHOD(Net, setInterface4, "(Ljava/io/FileDescriptor;I)V"), 872 NATIVE_METHOD(Net, getInterface4, "(Ljava/io/FileDescriptor;)I"), 873 NATIVE_METHOD(Net, setInterface6, "(Ljava/io/FileDescriptor;I)V"), 874 NATIVE_METHOD(Net, getInterface6, "(Ljava/io/FileDescriptor;)I"), 875 NATIVE_METHOD(Net, poll, "(Ljava/io/FileDescriptor;IJ)I"), 876 NATIVE_METHOD(Net, pollinValue, "()S"), 877 NATIVE_METHOD(Net, polloutValue, "()S"), 878 NATIVE_METHOD(Net, pollhupValue, "()S"), 879 NATIVE_METHOD(Net, pollerrValue, "()S"), 880 NATIVE_METHOD(Net, pollnvalValue, "()S"), 881 NATIVE_METHOD(Net, pollconnValue, "()S"), 882}; 883 884void register_sun_nio_ch_Net(JNIEnv* env) { 885 jniRegisterNativeMethods(env, "sun/nio/ch/Net", gMethods, NELEM(gMethods)); 886} 887