Net.c 23.9 KB
Newer Older
D
duke 已提交
1
/*
2
 * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
D
duke 已提交
3 4 5 6
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
7
 * published by the Free Software Foundation.  Oracle designates this
D
duke 已提交
8
 * particular file as subject to the "Classpath" exception as provided
9
 * by Oracle in the LICENSE file that accompanied this code.
D
duke 已提交
10 11 12 13 14 15 16 17 18 19 20
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
21 22 23
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
D
duke 已提交
24 25
 */

26
#include <sys/poll.h>
D
duke 已提交
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <netinet/tcp.h>

#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "jlong.h"
#include "sun_nio_ch_Net.h"
#include "net_util.h"
#include "net_util_md.h"
#include "nio_util.h"
#include "nio.h"
42
#include "sun_nio_ch_PollArrayWrapper.h"
D
duke 已提交
43

44 45 46
#ifdef _AIX
#include <sys/utsname.h>
#endif
47 48 49 50 51 52 53 54 55 56 57

/**
 * IP_MULTICAST_ALL supported since 2.6.31 but may not be available at
 * build time.
 */
#ifdef __linux__
  #ifndef IP_MULTICAST_ALL
  #define IP_MULTICAST_ALL    49
  #endif
#endif

58
#if defined(_ALLBSD_SOURCE) || defined(_AIX)
59 60 61

#ifndef IP_BLOCK_SOURCE

62 63 64 65 66 67 68 69 70
#if defined(_AIX)

#define IP_BLOCK_SOURCE                 58   /* Block data from a given source to a given group */
#define IP_UNBLOCK_SOURCE               59   /* Unblock data from a given source to a given group */
#define IP_ADD_SOURCE_MEMBERSHIP        60   /* Join a source-specific group */
#define IP_DROP_SOURCE_MEMBERSHIP       61   /* Leave a source-specific group */

#else

71 72 73 74 75
#define IP_ADD_SOURCE_MEMBERSHIP        70   /* join a source-specific group */
#define IP_DROP_SOURCE_MEMBERSHIP       71   /* drop a single source */
#define IP_BLOCK_SOURCE                 72   /* block a source */
#define IP_UNBLOCK_SOURCE               73   /* unblock a source */

76 77
#endif /* _AIX */

78 79 80 81
#endif  /* IP_BLOCK_SOURCE */

#ifndef MCAST_BLOCK_SOURCE

82 83 84 85 86 87 88 89 90
#if defined(_AIX)

#define MCAST_BLOCK_SOURCE              64
#define MCAST_UNBLOCK_SOURCE            65
#define MCAST_JOIN_SOURCE_GROUP         66
#define MCAST_LEAVE_SOURCE_GROUP        67

#else

91 92 93 94 95
#define MCAST_JOIN_SOURCE_GROUP         82   /* join a source-specific group */
#define MCAST_LEAVE_SOURCE_GROUP        83   /* leave a single source */
#define MCAST_BLOCK_SOURCE              84   /* block a source */
#define MCAST_UNBLOCK_SOURCE            85   /* unblock a source */

96 97
#endif /* _AIX */

98 99 100 101 102 103 104 105 106
#endif /* MCAST_BLOCK_SOURCE */

#ifndef IPV6_ADD_MEMBERSHIP

#define IPV6_ADD_MEMBERSHIP     IPV6_JOIN_GROUP
#define IPV6_DROP_MEMBERSHIP    IPV6_LEAVE_GROUP

#endif /* IPV6_ADD_MEMBERSHIP */

107 108 109 110 111 112 113 114 115 116
#if defined(_AIX)

struct my_ip_mreq_source {
        struct in_addr  imr_multiaddr;
        struct in_addr  imr_sourceaddr;
        struct in_addr  imr_interface;
};

#else

117 118 119 120 121 122
struct my_ip_mreq_source {
        struct in_addr  imr_multiaddr;
        struct in_addr  imr_interface;
        struct in_addr  imr_sourceaddr;
};

123 124
#endif /* _AIX */

125 126 127 128 129 130
struct my_group_source_req {
        uint32_t                gsr_interface;  /* interface index */
        struct sockaddr_storage gsr_group;      /* group address */
        struct sockaddr_storage gsr_source;     /* source address */
};

131 132 133 134 135 136
#else   /* _ALLBSD_SOURCE */

#define my_ip_mreq_source         ip_mreq_source
#define my_group_source_req       group_source_req

#endif
137

138 139 140 141 142 143 144 145

#define COPY_INET6_ADDRESS(env, source, target) \
    (*env)->GetByteArrayRegion(env, source, 0, 16, target)

/*
 * Copy IPv6 group, interface index, and IPv6 source address
 * into group_source_req structure.
 */
C
chegar 已提交
146
#ifdef AF_INET6
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
static void initGroupSourceReq(JNIEnv* env, jbyteArray group, jint index,
                               jbyteArray source, struct my_group_source_req* req)
{
    struct sockaddr_in6* sin6;

    req->gsr_interface = (uint32_t)index;

    sin6 = (struct sockaddr_in6*)&(req->gsr_group);
    sin6->sin6_family = AF_INET6;
    COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr));

    sin6 = (struct sockaddr_in6*)&(req->gsr_source);
    sin6->sin6_family = AF_INET6;
    COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr));
}
C
chegar 已提交
162
#endif
163

164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
#ifdef _AIX

/*
 * Checks whether or not "socket extensions for multicast source filters" is supported.
 * Returns JNI_TRUE if it is supported, JNI_FALSE otherwise
 */
static jboolean isSourceFilterSupported(){
    static jboolean alreadyChecked = JNI_FALSE;
    static jboolean result = JNI_TRUE;
    if (alreadyChecked != JNI_TRUE){
        struct utsname uts;
        memset(&uts, 0, sizeof(uts));
        strcpy(uts.sysname, "?");
        const int utsRes = uname(&uts);
        int major = -1;
        int minor = -1;
        major = atoi(uts.version);
        minor = atoi(uts.release);
        if (strcmp(uts.sysname, "AIX") == 0) {
            if (major < 6 || (major == 6 && minor < 1)) {// unsupported on aix < 6.1
                result = JNI_FALSE;
            }
        }
        alreadyChecked = JNI_TRUE;
    }
    return result;
}

#endif  /* _AIX */

D
duke 已提交
194 195 196 197 198 199
JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz)
{
    /* Here because Windows native code does need to init IDs */
}

200 201 202 203 204 205
JNIEXPORT jboolean JNICALL
Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl)
{
    return (ipv6_available()) ? JNI_TRUE : JNI_FALSE;
}

206 207 208 209 210
JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) {
    return -1;
}

211 212 213
JNIEXPORT jboolean JNICALL
Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl)
{
214
#if defined(MACOSX) || defined(_AIX)
215 216 217
    /* for now IPv6 sockets cannot join IPv4 multicast groups */
    return JNI_FALSE;
#else
218
    return JNI_TRUE;
219
#endif
220 221 222 223 224 225 226 227 228 229 230 231
}

JNIEXPORT jboolean JNICALL
Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl)
{
#ifdef __solaris__
    return JNI_TRUE;
#else
    return JNI_FALSE;
#endif
}

D
duke 已提交
232
JNIEXPORT int JNICALL
233
Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
234
                            jboolean stream, jboolean reuse, jboolean ignored)
D
duke 已提交
235 236
{
    int fd;
237
    int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
C
chegar 已提交
238
#ifdef AF_INET6
239
    int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET;
C
chegar 已提交
240 241 242
#else
    int domain = AF_INET;
#endif
D
duke 已提交
243

244
    fd = socket(domain, type, 0);
D
duke 已提交
245 246 247
    if (fd < 0) {
        return handleSocketError(env, errno);
    }
248 249 250 251 252 253 254 255 256

#ifdef AF_INET6
    /* Disable IPV6_V6ONLY to ensure dual-socket support */
    if (domain == AF_INET6) {
        int arg = 0;
        if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
                       sizeof(int)) < 0) {
            JNU_ThrowByNameWithLastError(env,
                                         JNU_JAVANETPKG "SocketException",
257
                                         "Unable to set IPV6_V6ONLY");
258 259 260 261 262 263
            close(fd);
            return -1;
        }
    }
#endif

D
duke 已提交
264 265
    if (reuse) {
        int arg = 1;
266 267 268 269
        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
                       sizeof(arg)) < 0) {
            JNU_ThrowByNameWithLastError(env,
                                         JNU_JAVANETPKG "SocketException",
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
                                         "Unable to set SO_REUSEADDR");
            close(fd);
            return -1;
        }
    }

#if defined(__linux__)
    if (type == SOCK_DGRAM) {
        int arg = 0;
        int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP;
        if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) &&
            (errno != ENOPROTOOPT)) {
            JNU_ThrowByNameWithLastError(env,
                                         JNU_JAVANETPKG "SocketException",
                                         "Unable to set IP_MULTICAST_ALL");
285 286 287 288
            close(fd);
            return -1;
        }
    }
289 290
#endif

C
chegar 已提交
291
#if defined(__linux__) && defined(AF_INET6)
292 293 294 295 296
    /* By default, Linux uses the route default */
    if (domain == AF_INET6 && type == SOCK_DGRAM) {
        int arg = 1;
        if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg,
                       sizeof(arg)) < 0) {
D
duke 已提交
297 298
            JNU_ThrowByNameWithLastError(env,
                                         JNU_JAVANETPKG "SocketException",
299
                                         "Unable to set IPV6_MULTICAST_HOPS");
300 301
            close(fd);
            return -1;
D
duke 已提交
302 303
        }
    }
304
#endif
D
duke 已提交
305 306 307 308
    return fd;
}

JNIEXPORT void JNICALL
309 310
Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6,
                          jboolean useExclBind, jobject iao, int port)
D
duke 已提交
311 312 313 314 315
{
    SOCKADDR sa;
    int sa_len = SOCKADDR_LEN;
    int rv = 0;

316
    if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) {
D
duke 已提交
317 318 319 320 321 322 323 324 325
      return;
    }

    rv = NET_Bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
    if (rv != 0) {
        handleSocketError(env, errno);
    }
}

326 327 328 329 330 331 332
JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog)
{
    if (listen(fdval(env, fdo), backlog) < 0)
        handleSocketError(env, errno);
}

D
duke 已提交
333
JNIEXPORT jint JNICALL
334 335
Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6,
                             jobject fdo, jobject iao, jint port)
D
duke 已提交
336 337 338 339 340
{
    SOCKADDR sa;
    int sa_len = SOCKADDR_LEN;
    int rv;

341 342 343
    if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa,
                                  &sa_len, preferIPv6) != 0)
    {
D
duke 已提交
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
      return IOS_THROWN;
    }

    rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
    if (rv != 0) {
        if (errno == EINPROGRESS) {
            return IOS_UNAVAILABLE;
        } else if (errno == EINTR) {
            return IOS_INTERRUPTED;
        }
        return handleSocketError(env, errno);
    }
    return 1;
}

JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo)
{
    SOCKADDR sa;
A
alanb 已提交
363
    socklen_t sa_len = SOCKADDR_LEN;
D
duke 已提交
364
    if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
#ifdef _ALLBSD_SOURCE
        /*
         * XXXBSD:
         * ECONNRESET is specific to the BSDs. We can not return an error,
         * as the calling Java code with raise a java.lang.Error given the expectation
         * that getsockname() will never fail. According to the Single UNIX Specification,
         * it shouldn't fail. As such, we just fill in generic Linux-compatible values.
         */
        if (errno == ECONNRESET) {
            struct sockaddr_in *sin;
            sin = (struct sockaddr_in *) &sa;
            bzero(sin, sizeof(*sin));
            sin->sin_len  = sizeof(struct sockaddr_in);
            sin->sin_family = AF_INET;
            sin->sin_port = htonl(0);
            sin->sin_addr.s_addr = INADDR_ANY;
        } else {
            handleSocketError(env, errno);
            return -1;
        }
#else /* _ALLBSD_SOURCE */
D
duke 已提交
386 387
        handleSocketError(env, errno);
        return -1;
388
#endif /* _ALLBSD_SOURCE */
D
duke 已提交
389 390 391 392 393 394 395 396
    }
    return NET_GetPortFromSockaddr((struct sockaddr *)&sa);
}

JNIEXPORT jobject JNICALL
Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo)
{
    SOCKADDR sa;
A
alanb 已提交
397
    socklen_t sa_len = SOCKADDR_LEN;
D
duke 已提交
398 399
    int port;
    if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
#ifdef _ALLBSD_SOURCE
        /*
         * XXXBSD:
         * ECONNRESET is specific to the BSDs. We can not return an error,
         * as the calling Java code with raise a java.lang.Error with the expectation
         * that getsockname() will never fail. According to the Single UNIX Specification,
         * it shouldn't fail. As such, we just fill in generic Linux-compatible values.
         */
        if (errno == ECONNRESET) {
            struct sockaddr_in *sin;
            sin = (struct sockaddr_in *) &sa;
            bzero(sin, sizeof(*sin));
            sin->sin_len  = sizeof(struct sockaddr_in);
            sin->sin_family = AF_INET;
            sin->sin_port = htonl(0);
            sin->sin_addr.s_addr = INADDR_ANY;
        } else {
            handleSocketError(env, errno);
            return NULL;
        }
#else /* _ALLBSD_SOURCE */
D
duke 已提交
421 422
        handleSocketError(env, errno);
        return NULL;
423
#endif /* _ALLBSD_SOURCE */
D
duke 已提交
424 425 426 427 428
    }
    return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
}

JNIEXPORT jint JNICALL
429 430
Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
                                  jboolean mayNeedConversion, jint level, jint opt)
D
duke 已提交
431 432 433
{
    int result;
    struct linger linger;
434
    u_char carg;
D
duke 已提交
435
    void *arg;
436 437
    socklen_t arglen;
    int n;
D
duke 已提交
438

439 440 441 442 443 444 445 446 447
    /* Option value is an int except for a few specific cases */

    arg = (void *)&result;
    arglen = sizeof(result);

    if (level == IPPROTO_IP &&
        (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
        arg = (void*)&carg;
        arglen = sizeof(carg);
D
duke 已提交
448 449
    }

450
    if (level == SOL_SOCKET && opt == SO_LINGER) {
D
duke 已提交
451 452 453 454
        arg = (void *)&linger;
        arglen = sizeof(linger);
    }

455
    if (mayNeedConversion) {
456
        n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, (int*)&arglen);
457 458 459 460
    } else {
        n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen);
    }
    if (n < 0) {
D
duke 已提交
461 462 463 464 465 466
        JNU_ThrowByNameWithLastError(env,
                                     JNU_JAVANETPKG "SocketException",
                                     "sun.nio.ch.Net.getIntOption");
        return -1;
    }

467 468 469 470 471 472 473 474 475 476
    if (level == IPPROTO_IP &&
        (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP))
    {
        return (jint)carg;
    }

    if (level == SOL_SOCKET && opt == SO_LINGER)
        return linger.l_onoff ? (jint)linger.l_linger : (jint)-1;

    return (jint)result;
D
duke 已提交
477 478 479
}

JNIEXPORT void JNICALL
480
Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
481 482
                                  jboolean mayNeedConversion, jint level,
                                  jint opt, jint arg, jboolean isIPv6)
D
duke 已提交
483 484 485
{
    int result;
    struct linger linger;
486
    u_char carg;
D
duke 已提交
487
    void *parg;
488 489
    socklen_t arglen;
    int n;
D
duke 已提交
490

491 492 493 494 495 496 497 498 499 500
    /* Option value is an int except for a few specific cases */

    parg = (void*)&arg;
    arglen = sizeof(arg);

    if (level == IPPROTO_IP &&
        (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
        parg = (void*)&carg;
        arglen = sizeof(carg);
        carg = (u_char)arg;
D
duke 已提交
501 502
    }

503
    if (level == SOL_SOCKET && opt == SO_LINGER) {
D
duke 已提交
504 505 506 507 508 509 510 511 512 513 514
        parg = (void *)&linger;
        arglen = sizeof(linger);
        if (arg >= 0) {
            linger.l_onoff = 1;
            linger.l_linger = arg;
        } else {
            linger.l_onoff = 0;
            linger.l_linger = 0;
        }
    }

515 516 517 518 519 520
    if (mayNeedConversion) {
        n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen);
    } else {
        n = setsockopt(fdval(env, fdo), level, opt, parg, arglen);
    }
    if (n < 0) {
D
duke 已提交
521 522 523 524
        JNU_ThrowByNameWithLastError(env,
                                     JNU_JAVANETPKG "SocketException",
                                     "sun.nio.ch.Net.setIntOption");
    }
525 526 527 528 529 530
#ifdef __linux__
    if (level == IPPROTO_IPV6 && opt == IPV6_TCLASS && isIPv6) {
        // set the V4 option also
        setsockopt(fdval(env, fdo), IPPROTO_IP, IP_TOS, parg, arglen);
    }
#endif
D
duke 已提交
531 532
}

533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo,
                                jint group, jint interf, jint source)
{
    struct ip_mreq mreq;
    struct my_ip_mreq_source mreq_source;
    int opt, n, optlen;
    void* optval;

    if (source == 0) {
        mreq.imr_multiaddr.s_addr = htonl(group);
        mreq.imr_interface.s_addr = htonl(interf);
        opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
        optval = (void*)&mreq;
        optlen = sizeof(mreq);
    } else {
549 550 551 552
#ifdef MACOSX
        /* no IPv4 include-mode filtering for now */
        return IOS_UNAVAILABLE;
#else
553 554 555 556 557 558 559 560

#ifdef _AIX
        /* check AIX for support of source filtering */
        if (isSourceFilterSupported() != JNI_TRUE){
            return IOS_UNAVAILABLE;
        }
#endif

561 562 563 564 565 566
        mreq_source.imr_multiaddr.s_addr = htonl(group);
        mreq_source.imr_sourceaddr.s_addr = htonl(source);
        mreq_source.imr_interface.s_addr = htonl(interf);
        opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP;
        optval = (void*)&mreq_source;
        optlen = sizeof(mreq_source);
567
#endif
568 569 570 571
    }

    n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen);
    if (n < 0) {
572
        if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))
573 574 575 576 577 578 579 580 581 582
            return IOS_UNAVAILABLE;
        handleSocketError(env, errno);
    }
    return 0;
}

JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo,
                                    jint group, jint interf, jint source)
{
583 584 585 586
#ifdef MACOSX
    /* no IPv4 exclude-mode filtering for now */
    return IOS_UNAVAILABLE;
#else
587 588 589 590
    struct my_ip_mreq_source mreq_source;
    int n;
    int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE;

591 592 593 594 595 596 597
#ifdef _AIX
    /* check AIX for support of source filtering */
    if (isSourceFilterSupported() != JNI_TRUE){
        return IOS_UNAVAILABLE;
    }
#endif

598 599 600 601 602 603 604
    mreq_source.imr_multiaddr.s_addr = htonl(group);
    mreq_source.imr_sourceaddr.s_addr = htonl(source);
    mreq_source.imr_interface.s_addr = htonl(interf);

    n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt,
                   (void*)&mreq_source, sizeof(mreq_source));
    if (n < 0) {
605
        if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))
606 607 608 609
            return IOS_UNAVAILABLE;
        handleSocketError(env, errno);
    }
    return 0;
610
#endif
611 612 613 614 615 616
}

JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo,
                                jbyteArray group, jint index, jbyteArray source)
{
C
chegar 已提交
617
#ifdef AF_INET6
618 619 620 621 622 623 624 625 626 627 628 629
    struct ipv6_mreq mreq6;
    struct my_group_source_req req;
    int opt, n, optlen;
    void* optval;

    if (source == NULL) {
        COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr));
        mreq6.ipv6mr_interface = (int)index;
        opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
        optval = (void*)&mreq6;
        optlen = sizeof(mreq6);
    } else {
630 631
#ifdef MACOSX
        /* no IPv6 include-mode filtering for now */
632 633 634 635 636 637 638 639 640 641 642
        return IOS_UNAVAILABLE;
#else
        initGroupSourceReq(env, group, index, source, &req);
        opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP;
        optval = (void*)&req;
        optlen = sizeof(req);
#endif
    }

    n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen);
    if (n < 0) {
643
        if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))
644 645 646 647
            return IOS_UNAVAILABLE;
        handleSocketError(env, errno);
    }
    return 0;
C
chegar 已提交
648 649 650 651
#else
    JNU_ThrowInternalError(env, "Should not get here");
    return IOS_THROWN;
#endif  /* AF_INET6 */
652 653 654 655 656 657
}

JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo,
                                    jbyteArray group, jint index, jbyteArray source)
{
C
chegar 已提交
658
#ifdef AF_INET6
659 660 661 662
  #ifdef MACOSX
    /* no IPv6 exclude-mode filtering for now */
    return IOS_UNAVAILABLE;
  #else
663 664 665 666 667 668 669 670 671
    struct my_group_source_req req;
    int n;
    int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE;

    initGroupSourceReq(env, group, index, source, &req);

    n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt,
        (void*)&req, sizeof(req));
    if (n < 0) {
672
        if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))
673 674 675 676
            return IOS_UNAVAILABLE;
        handleSocketError(env, errno);
    }
    return 0;
677
  #endif
C
chegar 已提交
678 679 680 681
#else
    JNU_ThrowInternalError(env, "Should not get here");
    return IOS_THROWN;
#endif
682 683 684 685 686 687
}

JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf)
{
    struct in_addr in;
688
    socklen_t arglen = sizeof(struct in_addr);
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
    int n;

    in.s_addr = htonl(interf);

    n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF,
                   (void*)&(in.s_addr), arglen);
    if (n < 0) {
        handleSocketError(env, errno);
    }
}

JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo)
{
    struct in_addr in;
704
    socklen_t arglen = sizeof(struct in_addr);
705 706 707 708 709 710 711 712 713 714 715 716 717 718
    int n;

    n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen);
    if (n < 0) {
        handleSocketError(env, errno);
        return -1;
    }
    return ntohl(in.s_addr);
}

JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index)
{
    int value = (jint)index;
719
    socklen_t arglen = sizeof(value);
720
    int n;
D
duke 已提交
721

722 723 724 725 726 727 728 729 730 731 732
    n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF,
                   (void*)&(index), arglen);
    if (n < 0) {
        handleSocketError(env, errno);
    }
}

JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo)
{
    int index;
733
    socklen_t arglen = sizeof(index);
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
    int n;

    n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen);
    if (n < 0) {
        handleSocketError(env, errno);
        return -1;
    }
    return (jint)index;
}

JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow)
{
    int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD :
        (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR;
749
    if ((shutdown(fdval(env, fdo), how) < 0) && (errno != ENOTCONN))
750 751
        handleSocketError(env, errno);
}
D
duke 已提交
752

753 754 755 756 757 758 759 760 761 762 763 764 765
JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_poll(JNIEnv* env, jclass this, jobject fdo, jint events, jlong timeout)
{
    struct pollfd pfd;
    int rv;
    pfd.fd = fdval(env, fdo);
    pfd.events = events;
    rv = poll(&pfd, 1, timeout);

    if (rv >= 0) {
        return pfd.revents;
    } else if (errno == EINTR) {
        return IOS_INTERRUPTED;
766
    } else {
767 768 769 770 771
        handleSocketError(env, errno);
        return IOS_THROWN;
    }
}

772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
JNIEXPORT jshort JNICALL
Java_sun_nio_ch_Net_pollinValue(JNIEnv *env, jclass this)
{
    return (jshort)POLLIN;
}

JNIEXPORT jshort JNICALL
Java_sun_nio_ch_Net_polloutValue(JNIEnv *env, jclass this)
{
    return (jshort)POLLOUT;
}

JNIEXPORT jshort JNICALL
Java_sun_nio_ch_Net_pollerrValue(JNIEnv *env, jclass this)
{
    return (jshort)POLLERR;
}

JNIEXPORT jshort JNICALL
Java_sun_nio_ch_Net_pollhupValue(JNIEnv *env, jclass this)
{
    return (jshort)POLLHUP;
}

JNIEXPORT jshort JNICALL
Java_sun_nio_ch_Net_pollnvalValue(JNIEnv *env, jclass this)
{
    return (jshort)POLLNVAL;
}

JNIEXPORT jshort JNICALL
Java_sun_nio_ch_Net_pollconnValue(JNIEnv *env, jclass this)
{
    return (jshort)POLLOUT;
}

808

D
duke 已提交
809 810 811 812 813 814 815 816 817
/* Declared in nio_util.h */

jint
handleSocketError(JNIEnv *env, jint errorValue)
{
    char *xn;
    switch (errorValue) {
        case EINPROGRESS:       /* Non-blocking connect */
            return 0;
818
#ifdef EPROTO
D
duke 已提交
819 820 821
        case EPROTO:
            xn = JNU_JAVANETPKG "ProtocolException";
            break;
822
#endif
D
duke 已提交
823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843
        case ECONNREFUSED:
            xn = JNU_JAVANETPKG "ConnectException";
            break;
        case ETIMEDOUT:
            xn = JNU_JAVANETPKG "ConnectException";
            break;
        case EHOSTUNREACH:
            xn = JNU_JAVANETPKG "NoRouteToHostException";
            break;
        case EADDRINUSE:  /* Fall through */
        case EADDRNOTAVAIL:
            xn = JNU_JAVANETPKG "BindException";
            break;
        default:
            xn = JNU_JAVANETPKG "SocketException";
            break;
    }
    errno = errorValue;
    JNU_ThrowByNameWithLastError(env, xn, "NioSocketError");
    return IOS_THROWN;
}