Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (c) 1997, 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 <errno.h>
     27 #include <netinet/in.h>
     28 #include <stdlib.h>
     29 #include <string.h>
     30 #include <sys/types.h>
     31 #include <sys/socket.h>
     32 
     33 #ifdef __solaris__
     34 #include <fcntl.h>
     35 #endif
     36 #ifdef __linux__
     37 #include <unistd.h>
     38 //#include <sys/sysctl.h>
     39 #include <sys/utsname.h>
     40 #include <netinet/ip.h>
     41 
     42 #define IPV6_MULTICAST_IF 17
     43 #ifndef SO_BSDCOMPAT
     44 #define SO_BSDCOMPAT  14
     45 #endif
     46 #endif
     47 
     48 #ifndef IPTOS_TOS_MASK
     49 #define IPTOS_TOS_MASK 0x1e
     50 #endif
     51 #ifndef IPTOS_PREC_MASK
     52 #define IPTOS_PREC_MASK 0xe0
     53 #endif
     54 
     55 #include "jvm.h"
     56 #include "jni_util.h"
     57 #include "net_util.h"
     58 
     59 #include "java_net_SocketOptions.h"
     60 #include "java_net_PlainDatagramSocketImpl.h"
     61 #include "JNIHelp.h"
     62 
     63 #define NATIVE_METHOD(className, functionName, signature) \
     64 { #functionName, signature, (void*)(className ## _ ## functionName) }
     65 /************************************************************************
     66  * PlainDatagramSocketImpl
     67  */
     68 
     69 static jfieldID IO_fd_fdID;
     70 
     71 static jfieldID pdsi_fdID;
     72 static jfieldID pdsi_timeoutID;
     73 static jfieldID pdsi_trafficClassID;
     74 static jfieldID pdsi_localPortID;
     75 static jfieldID pdsi_connected;
     76 static jfieldID pdsi_connectedAddress;
     77 static jfieldID pdsi_connectedPort;
     78 
     79 #if defined(__linux__) && defined(AF_INET6)
     80 static jfieldID pdsi_multicastInterfaceID;
     81 static jfieldID pdsi_loopbackID;
     82 static jfieldID pdsi_ttlID;
     83 #endif
     84 
     85 extern void setDefaultScopeID(JNIEnv *env, struct sockaddr *him);
     86 extern int getDefaultScopeID(JNIEnv *env);
     87 
     88 /*
     89  * Returns a java.lang.Integer based on 'i'
     90  */
     91 static jobject createInteger(JNIEnv *env, int i) {
     92     static jclass i_class;
     93     static jmethodID i_ctrID;
     94 
     95     if (i_class == NULL) {
     96         jclass c = (*env)->FindClass(env, "java/lang/Integer");
     97         CHECK_NULL_RETURN(c, NULL);
     98         i_ctrID = (*env)->GetMethodID(env, c, "<init>", "(I)V");
     99         CHECK_NULL_RETURN(i_ctrID, NULL);
    100         i_class = (*env)->NewGlobalRef(env, c);
    101         CHECK_NULL_RETURN(i_class, NULL);
    102     }
    103 
    104     return ( (*env)->NewObject(env, i_class, i_ctrID, i) );
    105 }
    106 
    107 /*
    108  * Returns a java.lang.Boolean based on 'b'
    109  */
    110 static jobject createBoolean(JNIEnv *env, int b) {
    111     static jclass b_class;
    112     static jmethodID b_ctrID;
    113 
    114     if (b_class == NULL) {
    115         jclass c = (*env)->FindClass(env, "java/lang/Boolean");
    116         CHECK_NULL_RETURN(c, NULL);
    117         b_ctrID = (*env)->GetMethodID(env, c, "<init>", "(Z)V");
    118         CHECK_NULL_RETURN(b_ctrID, NULL);
    119         b_class = (*env)->NewGlobalRef(env, c);
    120         CHECK_NULL_RETURN(b_class, NULL);
    121     }
    122 
    123     return( (*env)->NewObject(env, b_class, b_ctrID, (jboolean)(b!=0)) );
    124 }
    125 
    126 
    127 /*
    128  * Returns the fd for a PlainDatagramSocketImpl or -1
    129  * if closed.
    130  */
    131 static int getFD(JNIEnv *env, jobject this) {
    132     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
    133     if (fdObj == NULL) {
    134         return -1;
    135     }
    136     return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
    137 }
    138 
    139 
    140 /*
    141  * Class:     java_net_PlainDatagramSocketImpl
    142  * Method:    init
    143  * Signature: ()V
    144  */
    145 JNIEXPORT void JNICALL
    146 PlainDatagramSocketImpl_init(JNIEnv *env, jclass cls) {
    147 
    148 #ifdef __linux__
    149     struct utsname sysinfo;
    150 #endif
    151     pdsi_fdID = (*env)->GetFieldID(env, cls, "fd",
    152                                    "Ljava/io/FileDescriptor;");
    153     CHECK_NULL(pdsi_fdID);
    154     pdsi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
    155     CHECK_NULL(pdsi_timeoutID);
    156     pdsi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
    157     CHECK_NULL(pdsi_trafficClassID);
    158     pdsi_localPortID = (*env)->GetFieldID(env, cls, "localPort", "I");
    159     CHECK_NULL(pdsi_localPortID);
    160     pdsi_connected = (*env)->GetFieldID(env, cls, "connected", "Z");
    161     CHECK_NULL(pdsi_connected);
    162     pdsi_connectedAddress = (*env)->GetFieldID(env, cls, "connectedAddress",
    163                                                "Ljava/net/InetAddress;");
    164     CHECK_NULL(pdsi_connectedAddress);
    165     pdsi_connectedPort = (*env)->GetFieldID(env, cls, "connectedPort", "I");
    166     CHECK_NULL(pdsi_connectedPort);
    167 
    168     IO_fd_fdID = NET_GetFileDescriptorID(env);
    169     CHECK_NULL(IO_fd_fdID);
    170 
    171 #ifdef __linux__
    172 #ifdef AF_INET6
    173     pdsi_multicastInterfaceID = (*env)->GetFieldID(env, cls, "multicastInterface", "I");
    174     CHECK_NULL(pdsi_multicastInterfaceID);
    175     pdsi_loopbackID = (*env)->GetFieldID(env, cls, "loopbackMode", "Z");
    176     CHECK_NULL(pdsi_loopbackID);
    177     pdsi_ttlID = (*env)->GetFieldID(env, cls, "ttl", "I");
    178     CHECK_NULL(pdsi_ttlID);
    179 #endif
    180 
    181 #endif
    182 
    183 }
    184 
    185 /*
    186  * Class:     java_net_PlainDatagramSocketImpl
    187  * Method:    bind
    188  * Signature: (ILjava/net/InetAddress;)V
    189  */
    190 JNIEXPORT void JNICALL
    191 PlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this,
    192                                            jint localport, jobject iaObj) {
    193     /* fdObj is the FileDescriptor field on this */
    194     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
    195     /* fd is an int field on fdObj */
    196     int fd;
    197     int len = 0;
    198     SOCKADDR him;
    199 
    200     if (IS_NULL(fdObj)) {
    201         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
    202                         "Socket closed");
    203         return;
    204     } else {
    205         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
    206     }
    207 
    208     if (IS_NULL(iaObj)) {
    209         JNU_ThrowNullPointerException(env, "iaObj is null.");
    210         return;
    211     }
    212 
    213     /* bind */
    214     if (NET_InetAddressToSockaddr(env, iaObj, localport, (struct sockaddr *)&him, &len, JNI_TRUE) != 0) {
    215       return;
    216     }
    217     setDefaultScopeID(env, (struct sockaddr *)&him);
    218 
    219     if (NET_Bind(fd, (struct sockaddr *)&him, len) < 0)  {
    220         if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||
    221             errno == EPERM || errno == EACCES) {
    222             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException",
    223                             "Bind failed");
    224         } else {
    225             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
    226                             "Bind failed");
    227         }
    228         return;
    229     }
    230 
    231     /* intialize the local port */
    232     if (localport == 0) {
    233         /* Now that we're a connected socket, let's extract the port number
    234          * that the system chose for us and store it in the Socket object.
    235          */
    236         if (JVM_GetSockName(fd, (struct sockaddr *)&him, &len) == -1) {
    237             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
    238                             "Error getting socket name");
    239             return;
    240         }
    241 
    242         localport = NET_GetPortFromSockaddr((struct sockaddr *)&him);
    243 
    244         (*env)->SetIntField(env, this, pdsi_localPortID, localport);
    245     } else {
    246         (*env)->SetIntField(env, this, pdsi_localPortID, localport);
    247     }
    248 }
    249 
    250 /*
    251  * Class:     java_net_PlainDatagramSocketImpl
    252  * Method:    connect0
    253  * Signature: (Ljava/net/InetAddress;I)V
    254  */
    255 JNIEXPORT void JNICALL
    256 PlainDatagramSocketImpl_connect0(JNIEnv *env, jobject this,
    257                                                jobject address, jint port) {
    258     /* The object's field */
    259     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
    260     /* The fdObj'fd */
    261     jint fd;
    262     /* The packetAddress address, family and port */
    263     SOCKADDR rmtaddr;
    264     int len = 0;
    265 
    266     if (IS_NULL(fdObj)) {
    267         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
    268                         "Socket closed");
    269         return;
    270     }
    271     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
    272 
    273     if (IS_NULL(address)) {
    274         JNU_ThrowNullPointerException(env, "address");
    275         return;
    276     }
    277 
    278     if (NET_InetAddressToSockaddr(env, address, port, (struct sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) {
    279       return;
    280     }
    281 
    282     setDefaultScopeID(env, (struct sockaddr *)&rmtaddr);
    283     {
    284         if (JVM_Connect(fd, (struct sockaddr *)&rmtaddr, len) == -1) {
    285             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
    286                             "Connect failed");
    287             return;
    288         }
    289     }
    290 }
    291 
    292 /*
    293  * Class:     java_net_PlainDatagramSocketImpl
    294  * Method:    disconnect0
    295  * Signature: ()V
    296  */
    297 JNIEXPORT void JNICALL
    298 PlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jint family) {
    299     /* The object's field */
    300     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
    301     /* The fdObj'fd */
    302     jint fd;
    303 
    304 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
    305     SOCKADDR addr;
    306     int len;
    307 #endif
    308 
    309     if (IS_NULL(fdObj)) {
    310         return;
    311     }
    312     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
    313 
    314 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
    315         memset(&addr, 0, sizeof(addr));
    316 #ifdef AF_INET6
    317         if (ipv6_available()) {
    318             struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)&addr;
    319             him6->sin6_family = AF_UNSPEC;
    320             len = sizeof(struct sockaddr_in6);
    321         } else
    322 #endif
    323         {
    324             struct sockaddr_in *him4 = (struct sockaddr_in*)&addr;
    325             him4->sin_family = AF_UNSPEC;
    326             len = sizeof(struct sockaddr_in);
    327         }
    328         JVM_Connect(fd, (struct sockaddr *)&addr, len);
    329 
    330 #ifdef __linux__
    331         // After disconnecting a UDP socket, Linux kernel will set
    332         // local port to zero if the port number comes from implicit
    333         // bind. Successive send/recv on the same socket will fail.
    334         // So bind again with former port number here.
    335         int localPort = 0;
    336         if (JVM_GetSockName(fd, (struct sockaddr *)&addr, &len) == -1) {
    337             return;
    338         }
    339         localPort = NET_GetPortFromSockaddr((struct sockaddr *)&addr);
    340         if (localPort == 0) {
    341             localPort = (*env)->GetIntField(env, this, pdsi_localPortID);
    342 #ifdef AF_INET6
    343             if (((struct sockaddr*)&addr)->sa_family == AF_INET6) {
    344                 ((struct sockaddr_in6*)&addr)->sin6_port = htons(localPort);
    345             } else
    346 #endif /* AF_INET6 */
    347             {
    348                 ((struct sockaddr_in*)&addr)->sin_port = htons(localPort);
    349             }
    350             NET_Bind(fd, (struct sockaddr *)&addr, len);
    351         }
    352 #endif
    353 #else
    354     JVM_Connect(fd, 0, 0);
    355 #endif
    356 }
    357 
    358 /*
    359  * Class:     java_net_PlainDatagramSocketImpl
    360  * Method:    send
    361  * Signature: (Ljava/net/DatagramPacket;)V
    362  */
    363 JNIEXPORT void JNICALL
    364 PlainDatagramSocketImpl_send(JNIEnv *env, jobject this,
    365                                            jobject packet) {
    366 
    367     char BUF[MAX_BUFFER_LEN];
    368     char *fullPacket = NULL;
    369     int ret, mallocedPacket = JNI_FALSE;
    370     /* The object's field */
    371     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
    372     jint trafficClass = (*env)->GetIntField(env, this, pdsi_trafficClassID);
    373 
    374     jbyteArray packetBuffer;
    375     jobject packetAddress;
    376     jint packetBufferOffset, packetBufferLen, packetPort;
    377     jboolean connected;
    378 
    379     /* The fdObj'fd */
    380     jint fd;
    381 
    382     SOCKADDR rmtaddr, *rmtaddrP=&rmtaddr;
    383     int len;
    384 
    385     if (IS_NULL(fdObj)) {
    386         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
    387                         "Socket closed");
    388         return;
    389     }
    390     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
    391 
    392     if (IS_NULL(packet)) {
    393         JNU_ThrowNullPointerException(env, "packet");
    394         return;
    395     }
    396 
    397     connected = (*env)->GetBooleanField(env, this, pdsi_connected);
    398 
    399     packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
    400     packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
    401     if (IS_NULL(packetBuffer) || IS_NULL(packetAddress)) {
    402         JNU_ThrowNullPointerException(env, "null buffer || null address");
    403         return;
    404     }
    405 
    406     packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
    407     packetBufferLen = (*env)->GetIntField(env, packet, dp_lengthID);
    408 
    409     if (connected) {
    410         /* arg to NET_Sendto () null in this case */
    411         len = 0;
    412         rmtaddrP = 0;
    413     } else {
    414         packetPort = (*env)->GetIntField(env, packet, dp_portID);
    415         if (NET_InetAddressToSockaddr(env, packetAddress, packetPort, (struct sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) {
    416           return;
    417         }
    418     }
    419     setDefaultScopeID(env, (struct sockaddr *)&rmtaddr);
    420 
    421     if (packetBufferLen > MAX_BUFFER_LEN) {
    422         /* When JNI-ifying the JDK's IO routines, we turned
    423          * read's and write's of byte arrays of size greater
    424          * than 2048 bytes into several operations of size 2048.
    425          * This saves a malloc()/memcpy()/free() for big
    426          * buffers.  This is OK for file IO and TCP, but that
    427          * strategy violates the semantics of a datagram protocol.
    428          * (one big send) != (several smaller sends).  So here
    429          * we *must* alloc the buffer.  Note it needn't be bigger
    430          * than 65,536 (0xFFFF) the max size of an IP packet.
    431          * Anything bigger should be truncated anyway.
    432          *
    433          * We may want to use a smarter allocation scheme at some
    434          * point.
    435          */
    436         if (packetBufferLen > MAX_PACKET_LEN) {
    437             packetBufferLen = MAX_PACKET_LEN;
    438         }
    439         fullPacket = (char *)malloc(packetBufferLen);
    440 
    441         if (!fullPacket) {
    442             JNU_ThrowOutOfMemoryError(env, "Send buffer native heap allocation failed");
    443             return;
    444         } else {
    445             mallocedPacket = JNI_TRUE;
    446         }
    447     } else {
    448         fullPacket = &(BUF[0]);
    449     }
    450 
    451     (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset, packetBufferLen,
    452                                (jbyte *)fullPacket);
    453 #ifdef AF_INET6
    454     if (trafficClass != 0 && ipv6_available()) {
    455         NET_SetTrafficClass((struct sockaddr *)&rmtaddr, trafficClass);
    456     }
    457 #endif /* AF_INET6 */
    458 
    459 
    460     /*
    461      * Send the datagram.
    462      *
    463      * If we are connected it's possible that sendto will return
    464      * ECONNREFUSED indicating that an ICMP port unreachable has
    465      * received.
    466      */
    467     ret = NET_SendTo(fd, fullPacket, packetBufferLen, 0,
    468                      (struct sockaddr *)rmtaddrP, len);
    469 
    470     if (ret < 0) {
    471         switch (ret) {
    472             case JVM_IO_ERR :
    473                 if (errno == ECONNREFUSED) {
    474                     JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
    475                             "ICMP Port Unreachable");
    476                 } else {
    477                     NET_ThrowByNameWithLastError(env, "java/io/IOException", "sendto failed");
    478                 }
    479                 break;
    480 
    481             case JVM_IO_INTR:
    482                 JNU_ThrowByName(env, "java/io/InterruptedIOException",
    483                                 "operation interrupted");
    484                 break;
    485         }
    486     }
    487 
    488     if (mallocedPacket) {
    489         free(fullPacket);
    490     }
    491     return;
    492 }
    493 
    494 /*
    495  * Class:     java_net_PlainDatagramSocketImpl
    496  * Method:    peek
    497  * Signature: (Ljava/net/InetAddress;)I
    498  */
    499 JNIEXPORT jint JNICALL
    500 PlainDatagramSocketImpl_peek(JNIEnv *env, jobject this,
    501                                            jobject addressObj) {
    502 
    503     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
    504     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
    505     jint fd;
    506     ssize_t n;
    507     SOCKADDR remote_addr;
    508     int len;
    509     char buf[1];
    510     jint family;
    511     jobject iaObj;
    512     int port;
    513     if (IS_NULL(fdObj)) {
    514         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
    515         return -1;
    516     } else {
    517         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
    518     }
    519     if (IS_NULL(addressObj)) {
    520         JNU_ThrowNullPointerException(env, "Null address in peek()");
    521     }
    522     if (timeout) {
    523         int ret = NET_Timeout(fd, timeout);
    524         if (ret == 0) {
    525             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
    526                             "Peek timed out");
    527             return ret;
    528         } else if (ret == JVM_IO_ERR) {
    529             if (errno == EBADF) {
    530                  JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
    531             } else {
    532                  NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");
    533             }
    534             return ret;
    535         } else if (ret == JVM_IO_INTR) {
    536             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
    537                             "operation interrupted");
    538             return ret; /* WARNING: SHOULD WE REALLY RETURN -2??? */
    539         }
    540     }
    541 
    542     len = SOCKADDR_LEN;
    543     n = NET_RecvFrom(fd, buf, 1, MSG_PEEK,
    544                      (struct sockaddr *)&remote_addr, &len);
    545 
    546     if (n == JVM_IO_ERR) {
    547 
    548 #ifdef __solaris__
    549         if (errno == ECONNREFUSED) {
    550             int orig_errno = errno;
    551             (void) recv(fd, buf, 1, 0);
    552             errno = orig_errno;
    553         }
    554 #endif
    555         if (errno == ECONNREFUSED) {
    556             JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
    557                             "ICMP Port Unreachable");
    558         } else {
    559             if (errno == EBADF) {
    560                  JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
    561             } else {
    562                  NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");
    563             }
    564         }
    565         return 0;
    566     } else if (n == JVM_IO_INTR) {
    567         JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
    568         return 0;
    569     }
    570 
    571     iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
    572 #ifdef AF_INET6
    573     family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
    574 #else
    575     family = AF_INET;
    576 #endif
    577     if (family == AF_INET) { /* this api can't handle IPV6 addresses */
    578         int address = getInetAddress_addr(env, iaObj);
    579         setInetAddress_addr(env, addressObj, address);
    580     }
    581     return port;
    582 }
    583 
    584 JNIEXPORT jint JNICALL
    585 PlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this,
    586                                            jobject packet) {
    587 
    588     char BUF[MAX_BUFFER_LEN];
    589     char *fullPacket = NULL;
    590     int mallocedPacket = JNI_FALSE;
    591     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
    592     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
    593 
    594     jbyteArray packetBuffer;
    595     jint packetBufferOffset, packetBufferLen;
    596 
    597     int fd;
    598 
    599     int n;
    600     SOCKADDR remote_addr;
    601     int len;
    602     int port;
    603 
    604     if (IS_NULL(fdObj)) {
    605         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
    606                         "Socket closed");
    607         return -1;
    608     }
    609 
    610     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
    611 
    612     if (IS_NULL(packet)) {
    613         JNU_ThrowNullPointerException(env, "packet");
    614         return -1;
    615     }
    616 
    617     packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
    618     if (IS_NULL(packetBuffer)) {
    619         JNU_ThrowNullPointerException(env, "packet buffer");
    620         return -1;
    621     }
    622     packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
    623     packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
    624     if (timeout) {
    625         int ret = NET_Timeout(fd, timeout);
    626         if (ret == 0) {
    627             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
    628                             "Receive timed out");
    629             return -1;
    630         } else if (ret == JVM_IO_ERR) {
    631 #ifdef __linux__
    632             if (errno == EBADF) {
    633                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
    634             } else {
    635                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
    636             }
    637 #else
    638             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
    639 #endif
    640             return -1;
    641         } else if (ret == JVM_IO_INTR) {
    642             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
    643                             "operation interrupted");
    644             return -1;
    645         }
    646     }
    647 
    648     if (packetBufferLen > MAX_BUFFER_LEN) {
    649 
    650         /* When JNI-ifying the JDK's IO routines, we turned
    651          * read's and write's of byte arrays of size greater
    652          * than 2048 bytes into several operations of size 2048.
    653          * This saves a malloc()/memcpy()/free() for big
    654          * buffers.  This is OK for file IO and TCP, but that
    655          * strategy violates the semantics of a datagram protocol.
    656          * (one big send) != (several smaller sends).  So here
    657          * we *must* alloc the buffer.  Note it needn't be bigger
    658          * than 65,536 (0xFFFF) the max size of an IP packet.
    659          * anything bigger is truncated anyway.
    660          *
    661          * We may want to use a smarter allocation scheme at some
    662          * point.
    663          */
    664         if (packetBufferLen > MAX_PACKET_LEN) {
    665             packetBufferLen = MAX_PACKET_LEN;
    666         }
    667         fullPacket = (char *)malloc(packetBufferLen);
    668 
    669         if (!fullPacket) {
    670             JNU_ThrowOutOfMemoryError(env, "Peek buffer native heap allocation failed");
    671             return -1;
    672         } else {
    673             mallocedPacket = JNI_TRUE;
    674         }
    675     } else {
    676         fullPacket = &(BUF[0]);
    677     }
    678 
    679     len = SOCKADDR_LEN;
    680     n = NET_RecvFrom(fd, fullPacket, packetBufferLen, MSG_PEEK,
    681                      (struct sockaddr *)&remote_addr, &len);
    682     /* truncate the data if the packet's length is too small */
    683     if (n > packetBufferLen) {
    684         n = packetBufferLen;
    685     }
    686     if (n == JVM_IO_ERR) {
    687 
    688 #ifdef __solaris__
    689         if (errno == ECONNREFUSED) {
    690             int orig_errno = errno;
    691             (void) recv(fd, fullPacket, 1, 0);
    692             errno = orig_errno;
    693         }
    694 #endif
    695         (*env)->SetIntField(env, packet, dp_offsetID, 0);
    696         (*env)->SetIntField(env, packet, dp_lengthID, 0);
    697         if (errno == ECONNREFUSED) {
    698             JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
    699                             "ICMP Port Unreachable");
    700         } else {
    701             if (errno == EBADF) {
    702                  JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
    703             } else {
    704                  NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
    705             }
    706         }
    707     } else if (n == JVM_IO_INTR) {
    708         (*env)->SetIntField(env, packet, dp_offsetID, 0);
    709         (*env)->SetIntField(env, packet, dp_lengthID, 0);
    710         JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
    711                         "operation interrupted");
    712     } else {
    713         /*
    714          * success - fill in received address...
    715          *
    716          * REMIND: Fill in an int on the packet, and create inetadd
    717          * object in Java, as a performance improvement. Also
    718          * construct the inetadd object lazily.
    719          */
    720 
    721         jobject packetAddress;
    722 
    723         /*
    724          * Check if there is an InetAddress already associated with this
    725          * packet. If so we check if it is the same source address. We
    726          * can't update any existing InetAddress because it is immutable
    727          */
    728         packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
    729         if (packetAddress != NULL) {
    730             if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) {
    731                 /* force a new InetAddress to be created */
    732                 packetAddress = NULL;
    733             }
    734         }
    735         if (packetAddress == NULL) {
    736             packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
    737             /* stuff the new Inetaddress in the packet */
    738             (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
    739         } else {
    740             /* only get the new port number */
    741             port = NET_GetPortFromSockaddr((struct sockaddr *)&remote_addr);
    742         }
    743         /* and fill in the data, remote address/port and such */
    744         (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,
    745                                    (jbyte *)fullPacket);
    746         (*env)->SetIntField(env, packet, dp_portID, port);
    747         (*env)->SetIntField(env, packet, dp_lengthID, n);
    748     }
    749 
    750     if (mallocedPacket) {
    751         free(fullPacket);
    752     }
    753     return port;
    754 }
    755 
    756 /*
    757  * Class:     java_net_PlainDatagramSocketImpl
    758  * Method:    receive
    759  * Signature: (Ljava/net/DatagramPacket;)V
    760  */
    761 JNIEXPORT void JNICALL
    762 PlainDatagramSocketImpl_receive0(JNIEnv *env, jobject this,
    763                                               jobject packet) {
    764 
    765     char BUF[MAX_BUFFER_LEN];
    766     char *fullPacket = NULL;
    767     int mallocedPacket = JNI_FALSE;
    768     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
    769     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
    770 
    771     jbyteArray packetBuffer;
    772     jint packetBufferOffset, packetBufferLen;
    773 
    774     int fd;
    775 
    776     int n;
    777     SOCKADDR remote_addr;
    778     int len;
    779     jboolean retry;
    780 #ifdef __linux__
    781     jboolean connected = JNI_FALSE;
    782     jobject connectedAddress = NULL;
    783     jint connectedPort = 0;
    784     jlong prevTime = 0;
    785 #endif
    786 
    787     if (IS_NULL(fdObj)) {
    788         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
    789                         "Socket closed");
    790         return;
    791     }
    792 
    793     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
    794 
    795     if (IS_NULL(packet)) {
    796         JNU_ThrowNullPointerException(env, "packet");
    797         return;
    798     }
    799 
    800     packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
    801     if (IS_NULL(packetBuffer)) {
    802         JNU_ThrowNullPointerException(env, "packet buffer");
    803         return;
    804     }
    805     packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
    806     packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
    807 
    808     if (packetBufferLen > MAX_BUFFER_LEN) {
    809 
    810         /* When JNI-ifying the JDK's IO routines, we turned
    811          * read's and write's of byte arrays of size greater
    812          * than 2048 bytes into several operations of size 2048.
    813          * This saves a malloc()/memcpy()/free() for big
    814          * buffers.  This is OK for file IO and TCP, but that
    815          * strategy violates the semantics of a datagram protocol.
    816          * (one big send) != (several smaller sends).  So here
    817          * we *must* alloc the buffer.  Note it needn't be bigger
    818          * than 65,536 (0xFFFF) the max size of an IP packet.
    819          * anything bigger is truncated anyway.
    820          *
    821          * We may want to use a smarter allocation scheme at some
    822          * point.
    823          */
    824         if (packetBufferLen > MAX_PACKET_LEN) {
    825             packetBufferLen = MAX_PACKET_LEN;
    826         }
    827         fullPacket = (char *)malloc(packetBufferLen);
    828 
    829         if (!fullPacket) {
    830             JNU_ThrowOutOfMemoryError(env, "Receive buffer native heap allocation failed");
    831             return;
    832         } else {
    833             mallocedPacket = JNI_TRUE;
    834         }
    835     } else {
    836         fullPacket = &(BUF[0]);
    837     }
    838 
    839 
    840     do {
    841         retry = JNI_FALSE;
    842 
    843         if (timeout) {
    844             int ret = NET_Timeout(fd, timeout);
    845             if (ret <= 0) {
    846                 if (ret == 0) {
    847                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
    848                                     "Receive timed out");
    849                 } else if (ret == JVM_IO_ERR) {
    850 #ifdef __linux__
    851                     if (errno == EBADF) {
    852                          JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
    853                      } else {
    854                          NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
    855                      }
    856 #else
    857                      JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
    858 #endif
    859                 } else if (ret == JVM_IO_INTR) {
    860                     JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
    861                                     "operation interrupted");
    862                 }
    863 
    864                 if (mallocedPacket) {
    865                     free(fullPacket);
    866                 }
    867 
    868                 return;
    869             }
    870         }
    871 
    872         /*
    873          * Security Note: For Linux 2.2 with connected datagrams ensure that
    874          * you receive into the stack/heap allocated buffer - do not attempt
    875          * to receive directly into DatagramPacket's byte array.
    876          * (ie: if the virtual machine support pinning don't use
    877          * GetByteArrayElements or a JNI critical section and receive
    878          * directly into the byte array)
    879          */
    880         len = SOCKADDR_LEN;
    881         n = NET_RecvFrom(fd, fullPacket, packetBufferLen, 0,
    882                          (struct sockaddr *)&remote_addr, &len);
    883         /* truncate the data if the packet's length is too small */
    884         if (n > packetBufferLen) {
    885             n = packetBufferLen;
    886         }
    887         if (n == JVM_IO_ERR) {
    888             (*env)->SetIntField(env, packet, dp_offsetID, 0);
    889             (*env)->SetIntField(env, packet, dp_lengthID, 0);
    890             if (errno == ECONNREFUSED) {
    891                 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
    892                                 "ICMP Port Unreachable");
    893             } else {
    894                 if (errno == EBADF) {
    895                      JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
    896                  } else {
    897                      NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
    898                  }
    899             }
    900         } else if (n == JVM_IO_INTR) {
    901             (*env)->SetIntField(env, packet, dp_offsetID, 0);
    902             (*env)->SetIntField(env, packet, dp_lengthID, 0);
    903             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
    904                             "operation interrupted");
    905         } else {
    906             int port;
    907             jobject packetAddress;
    908 
    909             /*
    910              * If we are connected then we know that the datagram that we have
    911              * received is from the address that we are connected too. However
    912              * on Linux with 2.2 kernel we have to simulate this behaviour by
    913              * discarding any datagrams that aren't from the connected address.
    914              */
    915 
    916             /*
    917              * success - fill in received address...
    918              *
    919              * REMIND: Fill in an int on the packet, and create inetadd
    920              * object in Java, as a performance improvement. Also
    921              * construct the inetadd object lazily.
    922              */
    923 
    924             /*
    925              * Check if there is an InetAddress already associated with this
    926              * packet. If so we check if it is the same source address. We
    927              * can't update any existing InetAddress because it is immutable
    928              */
    929             packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
    930             if (packetAddress != NULL) {
    931                 if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) {
    932                     /* force a new InetAddress to be created */
    933                     packetAddress = NULL;
    934                 }
    935             }
    936             if (packetAddress == NULL) {
    937                 packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
    938                 /* stuff the new Inetaddress in the packet */
    939                 (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
    940             } else {
    941                 /* only get the new port number */
    942                 port = NET_GetPortFromSockaddr((struct sockaddr *)&remote_addr);
    943             }
    944             /* and fill in the data, remote address/port and such */
    945             (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,
    946                                        (jbyte *)fullPacket);
    947             (*env)->SetIntField(env, packet, dp_portID, port);
    948             (*env)->SetIntField(env, packet, dp_lengthID, n);
    949         }
    950 
    951     } while (retry);
    952 
    953     if (mallocedPacket) {
    954         free(fullPacket);
    955     }
    956 }
    957 
    958 /*
    959  * Class:     java_net_PlainDatagramSocketImpl
    960  * Method:    datagramSocketCreate
    961  * Signature: ()V
    962  */
    963 JNIEXPORT void JNICALL
    964 PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
    965                                                            jobject this) {
    966     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
    967     int arg, fd, t = 1;
    968 #ifdef AF_INET6
    969     int domain = ipv6_available() ? AF_INET6 : AF_INET;
    970 #else
    971     int domain = AF_INET;
    972 #endif
    973 
    974     if (IS_NULL(fdObj)) {
    975         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
    976                         "Socket closed");
    977         return;
    978     }
    979 
    980     if ((fd = JVM_Socket(domain, SOCK_DGRAM, 0)) == JVM_IO_ERR) {
    981         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
    982                        "Error creating socket");
    983         return;
    984     }
    985     tagSocket(env, fd);
    986 
    987 #ifdef AF_INET6
    988     /* Disable IPV6_V6ONLY to ensure dual-socket support */
    989     if (domain == AF_INET6) {
    990         arg = 0;
    991         if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
    992                        sizeof(int)) < 0) {
    993             NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
    994             untagSocket(env, fd);
    995             close(fd);
    996             return;
    997         }
    998     }
    999 #endif /* AF_INET6 */
   1000 
   1001 #ifdef __APPLE__
   1002     arg = 65507;
   1003     if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_SNDBUF,
   1004                        (char *)&arg, sizeof(arg)) < 0) {
   1005         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
   1006                         strerror(errno));
   1007         return;
   1008     }
   1009     if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_RCVBUF,
   1010                        (char *)&arg, sizeof(arg)) < 0) {
   1011         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
   1012                         strerror(errno));
   1013         return;
   1014     }
   1015 #endif /* __APPLE__ */
   1016 
   1017      setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*) &t, sizeof(int));
   1018 
   1019 #ifdef __linux__
   1020 #ifdef AF_INET6
   1021     /*
   1022      * On Linux for IPv6 sockets we must set the hop limit
   1023      * to 1 to be compatible with default ttl of 1 for IPv4 sockets.
   1024      */
   1025     if (domain == AF_INET6) {
   1026         int ttl = 1;
   1027         setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&ttl,
   1028                    sizeof(ttl));
   1029     }
   1030 #endif
   1031 
   1032 #endif /* __linux__ */
   1033 
   1034     (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
   1035 }
   1036 
   1037 /*
   1038  * Class:     java_net_PlainDatagramSocketImpl
   1039  * Method:    datagramSocketClose
   1040  * Signature: ()V
   1041  */
   1042 JNIEXPORT void JNICALL
   1043 PlainDatagramSocketImpl_datagramSocketClose(JNIEnv *env,
   1044                                                           jobject this) {
   1045     /*
   1046      * REMIND: PUT A LOCK AROUND THIS CODE
   1047      */
   1048     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
   1049     int fd;
   1050 
   1051     if (IS_NULL(fdObj)) {
   1052         return;
   1053     }
   1054     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
   1055     if (fd == -1) {
   1056         return;
   1057     }
   1058     (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
   1059     untagSocket(env, fd);
   1060     NET_SocketClose(fd);
   1061 }
   1062 
   1063 
   1064 /*
   1065  * Set outgoing multicast interface designated by a NetworkInterface index.
   1066  * Throw exception if failed.
   1067  *
   1068  * Android changed: return 0 on success, negative on failure.
   1069  * Android changed: Interface index (not NetworkInterface) as the parameter
   1070  */
   1071 static int mcast_set_if_by_if_v4(JNIEnv *env, jobject this, int fd, jint ifindex) {
   1072     struct ip_mreqn req;
   1073     memset(&req, 0, sizeof(req));
   1074     req.imr_ifindex = ifindex;
   1075 
   1076     if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
   1077                        (const char*)&req, sizeof(req)) < 0) {
   1078         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
   1079                        "Error setting socket option");
   1080         return -1;
   1081     }
   1082 
   1083     return 0;
   1084 }
   1085 
   1086 /*
   1087  * Set outgoing multicast interface designated by a NetworkInterface.
   1088  * Throw exception if failed.
   1089  * Android changed: Interface index (not NetworkInterface) as the parameter
   1090  */
   1091 static void mcast_set_if_by_if_v6(JNIEnv *env, jobject this, int fd, jint ifindex) {
   1092     if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
   1093                        (const char*)&ifindex, sizeof(ifindex)) < 0) {
   1094         if (errno == EINVAL && ifindex > 0) {
   1095             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
   1096                 "IPV6_MULTICAST_IF failed (interface has IPv4 "
   1097                 "address only?)");
   1098         } else {
   1099             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
   1100                            "Error setting socket option");
   1101         }
   1102         return;
   1103     }
   1104 }
   1105 
   1106 /*
   1107  * Set outgoing multicast interface designated by an InetAddress.
   1108  * Throw exception if failed.
   1109  *
   1110  * Android-changed : Return type, return 0 on success, negative on failure.
   1111  */
   1112 static int mcast_set_if_by_addr_v4(JNIEnv *env, jobject this, int fd, jobject value) {
   1113     struct in_addr in;
   1114 
   1115     in.s_addr = htonl( getInetAddress_addr(env, value) );
   1116 
   1117     if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
   1118                        (const char*)&in, sizeof(in)) < 0) {
   1119         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
   1120                          "Error setting socket option");
   1121         return -1;
   1122     }
   1123 
   1124     return 0;
   1125 }
   1126 
   1127 /*
   1128  * Set outgoing multicast interface designated by an InetAddress.
   1129  * Throw exception if failed.
   1130  */
   1131 static void mcast_set_if_by_addr_v6(JNIEnv *env, jobject this, int fd, jobject value) {
   1132     static jclass ni_class;
   1133     static jmethodID ni_getByInetAddress;
   1134     static jmethodID ni_getIndex;
   1135     if (ni_class == NULL) {
   1136         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
   1137         CHECK_NULL(c);
   1138         ni_class = (*env)->NewGlobalRef(env, c);
   1139         CHECK_NULL(ni_class);
   1140         ni_getByInetAddress = (*env)->GetStaticMethodID(
   1141             env, ni_class, "getByInetAddress", "(Ljava/net/InetAddress;)Ljava/net/NetworkInterface;");
   1142         CHECK_NULL(ni_getByInetAddress);
   1143         ni_getIndex = (*env)->GetMethodID(
   1144             env, ni_class, "getIndex", "()I");
   1145         CHECK_NULL(ni_getIndex);
   1146     }
   1147 
   1148     /*
   1149      * Get the NetworkInterface by inetAddress
   1150      */
   1151     jobject ni_value = (*env)->CallStaticObjectMethod(
   1152         env, ni_class, ni_getByInetAddress, value);
   1153     if (ni_value == NULL) {
   1154         if (!(*env)->ExceptionOccurred(env)) {
   1155             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
   1156                  "bad argument for IP_MULTICAST_IF"
   1157                  ": address not bound to any interface");
   1158         }
   1159         return;
   1160     }
   1161 
   1162     /*
   1163      * Get the NetworkInterface index
   1164      */
   1165     jint ifindex = (*env)->CallIntMethod(env, ni_value, ni_getIndex);
   1166     if ((*env)->ExceptionOccurred(env)) {
   1167         return;
   1168     }
   1169 
   1170     mcast_set_if_by_if_v6(env, this, fd, ifindex);
   1171 }
   1172 
   1173 /*
   1174  * Sets the multicast interface.
   1175  *
   1176  * SocketOptions.IP_MULTICAST_IF :-
   1177  *      value is a InetAddress
   1178  *      IPv4:   set outgoing multicast interface using
   1179  *              IPPROTO_IP/IP_MULTICAST_IF
   1180  *      IPv6:   Get the index of the interface to which the
   1181  *              InetAddress is bound
   1182  *              Set outgoing multicast interface using
   1183  *              IPPROTO_IPV6/IPV6_MULTICAST_IF
   1184  *              On Linux 2.2 record interface index as can't
   1185  *              query the multicast interface.
   1186  *
   1187  * SockOptions.IF_MULTICAST_IF2 :-
   1188  *      value is a NetworkInterface
   1189  *      IPv4:   Obtain IP address bound to network interface
   1190  *              (NetworkInterface.addres[0])
   1191  *              set outgoing multicast interface using
   1192  *              IPPROTO_IP/IP_MULTICAST_IF
   1193  *      IPv6:   Obtain NetworkInterface.index
   1194  *              Set outgoing multicast interface using
   1195  *              IPPROTO_IPV6/IPV6_MULTICAST_IF
   1196  *              On Linux 2.2 record interface index as can't
   1197  *              query the multicast interface.
   1198  *
   1199  */
   1200 static void setMulticastInterface(JNIEnv *env, jobject this, int fd,
   1201                                   jint opt, jobject value)
   1202 {
   1203     if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
   1204         /*
   1205          * value is an InetAddress.
   1206          */
   1207         // Android-changed: Return early if mcast_set_if_by_addr_v4 threw.
   1208         // We don't want to call into the IPV6 code with a pending exception.
   1209         if (mcast_set_if_by_addr_v4(env, this, fd, value)) {
   1210             return;
   1211         }
   1212         if (ipv6_available()) {
   1213             mcast_set_if_by_addr_v6(env, this, fd, value);
   1214         }
   1215     }
   1216 
   1217     if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
   1218       /*
   1219          * value is a Integer (Android-changed, openJdk uses NetworkInterface)
   1220          */
   1221         static jfieldID integer_valueID;
   1222         if (integer_valueID == NULL) {
   1223             jclass c = (*env)->FindClass(env, "java/lang/Integer");
   1224             CHECK_NULL(c);
   1225             integer_valueID = (*env)->GetFieldID(env, c, "value", "I");
   1226             CHECK_NULL(integer_valueID);
   1227         }
   1228         int index = (*env)->GetIntField(env, value, integer_valueID);
   1229 
   1230         // Android-changed: Return early if mcast_set_if_by_addr_v4 threw.
   1231         // We don't want to call into the IPV6 code with a pending exception.
   1232         if (mcast_set_if_by_if_v4(env, this, fd, index)) {
   1233             return;
   1234         }
   1235         if (ipv6_available()) {
   1236             mcast_set_if_by_if_v6(env, this, fd, index);
   1237         }
   1238     }
   1239 }
   1240 
   1241 /*
   1242  * Enable/disable local loopback of multicast datagrams.
   1243  */
   1244 static void mcast_set_loop_v4(JNIEnv *env, jobject this, int fd, jobject value) {
   1245     jclass cls;
   1246     jfieldID fid;
   1247     jboolean on;
   1248     char loopback;
   1249 
   1250     cls = (*env)->FindClass(env, "java/lang/Boolean");
   1251     CHECK_NULL(cls);
   1252     fid =  (*env)->GetFieldID(env, cls, "value", "Z");
   1253     CHECK_NULL(fid);
   1254 
   1255     on = (*env)->GetBooleanField(env, value, fid);
   1256     loopback = (!on ? 1 : 0);
   1257 
   1258     if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&loopback, sizeof(char)) < 0) {
   1259         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
   1260         return;
   1261     }
   1262 }
   1263 
   1264 /*
   1265  * Enable/disable local loopback of multicast datagrams.
   1266  */
   1267 #ifdef AF_INET6
   1268 static void mcast_set_loop_v6(JNIEnv *env, jobject this, int fd, jobject value) {
   1269     jclass cls;
   1270     jfieldID fid;
   1271     jboolean on;
   1272     int loopback;
   1273 
   1274     cls = (*env)->FindClass(env, "java/lang/Boolean");
   1275     CHECK_NULL(cls);
   1276     fid =  (*env)->GetFieldID(env, cls, "value", "Z");
   1277     CHECK_NULL(fid);
   1278 
   1279     on = (*env)->GetBooleanField(env, value, fid);
   1280     loopback = (!on ? 1 : 0);
   1281 
   1282     if (NET_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&loopback, sizeof(int)) < 0) {
   1283         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
   1284         return;
   1285     }
   1286 
   1287 }
   1288 #endif  /* AF_INET6 */
   1289 
   1290 /*
   1291  * Sets the multicast loopback mode.
   1292  */
   1293 static void setMulticastLoopbackMode(JNIEnv *env, jobject this, int fd,
   1294                                   jint opt, jobject value) {
   1295 #ifdef AF_INET6
   1296 #ifdef __linux__
   1297     mcast_set_loop_v4(env, this, fd, value);
   1298     if (ipv6_available()) {
   1299         mcast_set_loop_v6(env, this, fd, value);
   1300     }
   1301 #else  /* __linux__ not defined */
   1302     if (ipv6_available()) {
   1303         mcast_set_loop_v6(env, this, fd, value);
   1304     } else {
   1305         mcast_set_loop_v4(env, this, fd, value);
   1306     }
   1307 #endif  /* __linux__ */
   1308 #else
   1309     mcast_set_loop_v4(env, this, fd, value);
   1310 #endif  /* AF_INET6 */
   1311 }
   1312 
   1313 /*
   1314  * Class:     java_net_PlainDatagramSocketImpl
   1315  * Method:    socketSetOption
   1316  * Signature: (ILjava/lang/Object;)V
   1317  */
   1318 JNIEXPORT void JNICALL
   1319 PlainDatagramSocketImpl_socketSetOption(JNIEnv *env,
   1320                                                       jobject this,
   1321                                                       jint opt,
   1322                                                       jobject value) {
   1323     int fd;
   1324     int level, optname, optlen;
   1325     union {
   1326         int i;
   1327         char c;
   1328     } optval;
   1329 
   1330     /*
   1331      * Check that socket hasn't been closed
   1332      */
   1333     fd = getFD(env, this);
   1334     if (fd < 0) {
   1335         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
   1336                         "Socket closed");
   1337         return;
   1338     }
   1339 
   1340     /*
   1341      * Check argument has been provided
   1342      */
   1343     if (IS_NULL(value)) {
   1344         JNU_ThrowNullPointerException(env, "value argument");
   1345         return;
   1346     }
   1347 
   1348     /*
   1349      * Setting the multicast interface handled seperately
   1350      */
   1351     if (opt == java_net_SocketOptions_IP_MULTICAST_IF ||
   1352         opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
   1353 
   1354         setMulticastInterface(env, this, fd, opt, value);
   1355         return;
   1356     }
   1357 
   1358     /*
   1359      * Setting the multicast loopback mode handled separately
   1360      */
   1361     if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) {
   1362         setMulticastLoopbackMode(env, this, fd, opt, value);
   1363         return;
   1364     }
   1365 
   1366     /*
   1367      * Map the Java level socket option to the platform specific
   1368      * level and option name.
   1369      */
   1370     if (NET_MapSocketOption(opt, &level, &optname)) {
   1371         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
   1372         return;
   1373     }
   1374 
   1375     switch (opt) {
   1376         case java_net_SocketOptions_SO_SNDBUF :
   1377         case java_net_SocketOptions_SO_RCVBUF :
   1378         case java_net_SocketOptions_IP_TOS :
   1379             {
   1380                 jclass cls;
   1381                 jfieldID fid;
   1382 
   1383                 cls = (*env)->FindClass(env, "java/lang/Integer");
   1384                 CHECK_NULL(cls);
   1385                 fid =  (*env)->GetFieldID(env, cls, "value", "I");
   1386                 CHECK_NULL(fid);
   1387 
   1388                 optval.i = (*env)->GetIntField(env, value, fid);
   1389                 optlen = sizeof(optval.i);
   1390                 break;
   1391             }
   1392 
   1393         case java_net_SocketOptions_SO_REUSEADDR:
   1394         case java_net_SocketOptions_SO_BROADCAST:
   1395             {
   1396                 jclass cls;
   1397                 jfieldID fid;
   1398                 jboolean on;
   1399 
   1400                 cls = (*env)->FindClass(env, "java/lang/Boolean");
   1401                 CHECK_NULL(cls);
   1402                 fid =  (*env)->GetFieldID(env, cls, "value", "Z");
   1403                 CHECK_NULL(fid);
   1404 
   1405                 on = (*env)->GetBooleanField(env, value, fid);
   1406 
   1407                 /* SO_REUSEADDR or SO_BROADCAST */
   1408                 optval.i = (on ? 1 : 0);
   1409                 optlen = sizeof(optval.i);
   1410 
   1411                 break;
   1412             }
   1413 
   1414         default :
   1415             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
   1416                 "Socket option not supported by PlainDatagramSocketImp");
   1417             break;
   1418 
   1419     }
   1420 
   1421     if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {
   1422         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
   1423         return;
   1424     }
   1425 }
   1426 
   1427 
   1428 /*
   1429  * Return the multicast interface:
   1430  *
   1431  * SocketOptions.IP_MULTICAST_IF
   1432  *      IPv4:   Query IPPROTO_IP/IP_MULTICAST_IF
   1433  *              Create InetAddress
   1434  *              IP_MULTICAST_IF returns struct ip_mreqn on 2.2
   1435  *              kernel but struct in_addr on 2.4 kernel
   1436  *      IPv6:   Query IPPROTO_IPV6 / IPV6_MULTICAST_IF or
   1437  *              obtain from impl is Linux 2.2 kernel
   1438  *              If index == 0 return InetAddress representing
   1439  *              anyLocalAddress.
   1440  *              If index > 0 query NetworkInterface by index
   1441  *              and returns addrs[0]
   1442  *
   1443  * SocketOptions.IP_MULTICAST_IF2
   1444  *      IPv4:   Query IPPROTO_IP/IP_MULTICAST_IF
   1445  *              Query NetworkInterface by IP address and
   1446  *              return the NetworkInterface that the address
   1447  *              is bound too.
   1448  *      IPv6:   Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
   1449  *              (except Linux .2 kernel)
   1450  *              Query NetworkInterface by index and
   1451  *              return NetworkInterface.
   1452  */
   1453 jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, jint opt) {
   1454     if ((opt == java_net_SocketOptions_IP_MULTICAST_IF2) ||
   1455         (opt == java_net_SocketOptions_IP_MULTICAST_IF)) {
   1456         int index;
   1457         int len = sizeof(index);
   1458 
   1459         {
   1460             if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
   1461                                (char*)&index, &len) < 0) {
   1462                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
   1463                                "Error getting socket option");
   1464                 return NULL;
   1465             }
   1466         }
   1467 
   1468         jobject ifindex = createInteger(env, index);
   1469         CHECK_NULL_RETURN(ifindex, NULL);
   1470         return ifindex;
   1471     }
   1472     return NULL;
   1473 }
   1474 
   1475 
   1476 
   1477 /*
   1478  * Returns relevant info as a jint.
   1479  *
   1480  * Class:     java_net_PlainDatagramSocketImpl
   1481  * Method:    socketGetOption
   1482  * Signature: (I)Ljava/lang/Object;
   1483  */
   1484 JNIEXPORT jobject JNICALL
   1485 PlainDatagramSocketImpl_socketGetOption(JNIEnv *env, jobject this,
   1486                                                       jint opt) {
   1487     int fd;
   1488     int level, optname, optlen;
   1489     union {
   1490         int i;
   1491         char c;
   1492     } optval;
   1493 
   1494     fd = getFD(env, this);
   1495     if (fd < 0) {
   1496         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
   1497                         "socket closed");
   1498         return NULL;
   1499     }
   1500 
   1501     /*
   1502      * Handle IP_MULTICAST_IF seperately
   1503      */
   1504     if (opt == java_net_SocketOptions_IP_MULTICAST_IF ||
   1505         opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
   1506         return getMulticastInterface(env, this, fd, opt);
   1507 
   1508     }
   1509 
   1510     /*
   1511      * SO_BINDADDR implemented using getsockname
   1512      */
   1513     if (opt == java_net_SocketOptions_SO_BINDADDR) {
   1514         /* find out local IP address */
   1515         SOCKADDR him;
   1516         socklen_t len = 0;
   1517         int port;
   1518         jobject iaObj;
   1519 
   1520         len = SOCKADDR_LEN;
   1521 
   1522         if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) {
   1523             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
   1524                            "Error getting socket name");
   1525             return NULL;
   1526         }
   1527         iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
   1528 
   1529         return iaObj;
   1530     }
   1531 
   1532     /*
   1533      * Map the Java level socket option to the platform specific
   1534      * level and option name.
   1535      */
   1536     if (NET_MapSocketOption(opt, &level, &optname)) {
   1537         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
   1538         return NULL;
   1539     }
   1540 
   1541     if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP &&
   1542         level == IPPROTO_IP) {
   1543         optlen = sizeof(optval.c);
   1544     } else {
   1545         optlen = sizeof(optval.i);
   1546     }
   1547 
   1548     if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
   1549         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
   1550                          "Error getting socket option");
   1551         return NULL;
   1552     }
   1553 
   1554     switch (opt) {
   1555         case java_net_SocketOptions_IP_MULTICAST_LOOP:
   1556             /* getLoopbackMode() returns true if IP_MULTICAST_LOOP disabled */
   1557             if (level == IPPROTO_IP) {
   1558                 return createBoolean(env, (int)!optval.c);
   1559             } else {
   1560                 return createBoolean(env, !optval.i);
   1561             }
   1562 
   1563         case java_net_SocketOptions_SO_BROADCAST:
   1564         case java_net_SocketOptions_SO_REUSEADDR:
   1565             return createBoolean(env, optval.i);
   1566 
   1567         case java_net_SocketOptions_SO_SNDBUF:
   1568         case java_net_SocketOptions_SO_RCVBUF:
   1569         case java_net_SocketOptions_IP_TOS:
   1570             return createInteger(env, optval.i);
   1571 
   1572     }
   1573 
   1574     /* should never rearch here */
   1575     return NULL;
   1576 }
   1577 
   1578 /*
   1579  * Multicast-related calls
   1580  */
   1581 
   1582 JNIEXPORT void JNICALL
   1583 PlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this,
   1584                                              jbyte ttl) {
   1585     jint ittl = ttl;
   1586     if (ittl < 0) {
   1587         ittl += 0x100;
   1588     }
   1589     PlainDatagramSocketImpl_setTimeToLive(env, this, ittl);
   1590 }
   1591 
   1592 /*
   1593  * Set TTL for a socket. Throw exception if failed.
   1594  */
   1595 static void setTTL(JNIEnv *env, int fd, jint ttl) {
   1596     char ittl = (char)ttl;
   1597     if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
   1598                        sizeof(ittl)) < 0) {
   1599         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
   1600                        "Error setting socket option");
   1601     }
   1602 }
   1603 
   1604 /*
   1605  * Set hops limit for a socket. Throw exception if failed.
   1606  */
   1607 #ifdef AF_INET6
   1608 static void setHopLimit(JNIEnv *env, int fd, jint ttl) {
   1609     int ittl = (int)ttl;
   1610     if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
   1611                        (char*)&ittl, sizeof(ittl)) < 0) {
   1612         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
   1613                        "Error setting socket option");
   1614     }
   1615 }
   1616 #endif
   1617 
   1618 /*
   1619  * Class:     java_net_PlainDatagramSocketImpl
   1620  * Method:    setTTL
   1621  * Signature: (B)V
   1622  */
   1623 JNIEXPORT void JNICALL
   1624 PlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this,
   1625                                                     jint ttl) {
   1626 
   1627     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
   1628     int fd;
   1629     /* it is important to cast this to a char, otherwise setsockopt gets confused */
   1630 
   1631     if (IS_NULL(fdObj)) {
   1632         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
   1633                         "Socket closed");
   1634         return;
   1635     } else {
   1636         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
   1637     }
   1638     /* setsockopt to be correct ttl */
   1639 #ifdef AF_INET6
   1640 #ifdef __linux__
   1641     setTTL(env, fd, ttl);
   1642     if (ipv6_available()) {
   1643         setHopLimit(env, fd, ttl);
   1644     }
   1645 #else  /*  __linux__ not defined */
   1646     if (ipv6_available()) {
   1647         setHopLimit(env, fd, ttl);
   1648     } else {
   1649         setTTL(env, fd, ttl);
   1650     }
   1651 #endif  /* __linux__ */
   1652 #else
   1653     setTTL(env, fd, ttl);
   1654 #endif  /* AF_INET6 */
   1655 }
   1656 
   1657 /*
   1658  * Class:     java_net_PlainDatagramSocketImpl
   1659  * Method:    getTTL
   1660  * Signature: ()B
   1661  */
   1662 JNIEXPORT jbyte JNICALL
   1663 PlainDatagramSocketImpl_getTTL(JNIEnv *env, jobject this) {
   1664     return (jbyte)PlainDatagramSocketImpl_getTimeToLive(env, this);
   1665 }
   1666 
   1667 
   1668 /*
   1669  * Class:     java_net_PlainDatagramSocketImpl
   1670  * Method:    getTTL
   1671  * Signature: ()B
   1672  */
   1673 JNIEXPORT jint JNICALL
   1674 PlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) {
   1675 
   1676     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
   1677     jint fd = -1;
   1678 
   1679     if (IS_NULL(fdObj)) {
   1680         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
   1681                         "Socket closed");
   1682         return -1;
   1683     } else {
   1684         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
   1685     }
   1686     /* getsockopt of ttl */
   1687 #ifdef AF_INET6
   1688     if (ipv6_available()) {
   1689         int ttl = 0;
   1690         int len = sizeof(ttl);
   1691 
   1692         if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
   1693                                (char*)&ttl, &len) < 0) {
   1694                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
   1695                                "Error getting socket option");
   1696                 return -1;
   1697             }
   1698         return (jint)ttl;
   1699     } else
   1700 #endif /* AF_INET6 */
   1701         {
   1702             u_char ttl = 0;
   1703             int len = sizeof(ttl);
   1704             if (JVM_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
   1705                                (char*)&ttl, &len) < 0) {
   1706                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
   1707                                "Error getting socket option");
   1708                 return -1;
   1709             }
   1710             return (jint)ttl;
   1711         }
   1712 }
   1713 
   1714 
   1715 /*
   1716  * mcast_join_leave: Join or leave a multicast group.
   1717  *
   1718  * For IPv4 sockets use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option
   1719  * to join/leave multicast group.
   1720  *
   1721  * For IPv6 sockets use IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP socket option
   1722  * to join/leave multicast group. If multicast group is an IPv4 address then
   1723  * an IPv4-mapped address is used.
   1724  *
   1725  * On Linux with IPv6 if we wish to join/leave an IPv4 multicast group then
   1726  * we must use the IPv4 socket options. This is because the IPv6 socket options
   1727  * don't support IPv4-mapped addresses. This is true as per 2.2.19 and 2.4.7
   1728  * kernel releases. In the future it's possible that IP_ADD_MEMBERSHIP
   1729  * will be updated to return ENOPROTOOPT if uses with an IPv6 socket (Solaris
   1730  * already does this). Thus to cater for this we first try with the IPv4
   1731  * socket options and if they fail we use the IPv6 socket options. This
   1732  * seems a reasonable failsafe solution.
   1733  */
   1734 static void mcast_join_leave(JNIEnv *env, jobject this,
   1735                              jobject iaObj, jobject niObj,
   1736                              jboolean join) {
   1737 
   1738     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
   1739     jint fd;
   1740     jint ipv6_join_leave;
   1741 
   1742     if (IS_NULL(fdObj)) {
   1743         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
   1744                         "Socket closed");
   1745         return;
   1746     } else {
   1747         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
   1748     }
   1749     if (IS_NULL(iaObj)) {
   1750         JNU_ThrowNullPointerException(env, "iaObj");
   1751         return;
   1752     }
   1753 
   1754     /*
   1755      * Get java/net/NetworkInterface#index field.
   1756      */
   1757     static jfieldID ni_indexID;
   1758 
   1759     if (ni_indexID == NULL) {
   1760       jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
   1761       CHECK_NULL(c);
   1762       ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
   1763       CHECK_NULL(ni_indexID);
   1764     }
   1765 
   1766     /*
   1767      * Determine if this is an IPv4 or IPv6 join/leave.
   1768      */
   1769     ipv6_join_leave = ipv6_available();
   1770 
   1771     if (getInetAddress_family(env, iaObj) == IPv4) {
   1772         ipv6_join_leave = JNI_FALSE;
   1773     }
   1774 
   1775     /*
   1776      * For IPv4 join use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option
   1777      *
   1778      * On Linux if IPv4 or IPv6 use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP
   1779      */
   1780     if (!ipv6_join_leave) {
   1781         struct ip_mreqn mname;
   1782         int mname_len;
   1783 
   1784         /*
   1785          * joinGroup(InetAddress, NetworkInterface) implementation :-
   1786          *
   1787          * Linux/IPv6:  use ip_mreqn structure populated with multicast
   1788          *              address and interface index.
   1789          *
   1790          */
   1791         if (niObj != NULL) {
   1792             mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj));
   1793             mname.imr_address.s_addr = 0;
   1794             mname.imr_ifindex =  (*env)->GetIntField(env, niObj, ni_indexID);
   1795             mname_len = sizeof(struct ip_mreqn);
   1796         }
   1797 
   1798 
   1799         /*
   1800          * joinGroup(InetAddress) implementation :-
   1801          *
   1802          * Linux/IPv6:  use ip_mreqn structure populated with multicast
   1803          *              address and interface index. index obtained
   1804          *              from cached value or IPV6_MULTICAST_IF.
   1805          *
   1806          * IPv4:        use ip_mreq structure populated with multicast
   1807          *              address and local address obtained from
   1808          *              IP_MULTICAST_IF. On Linux IP_MULTICAST_IF
   1809          *              returns different structure depending on
   1810          *              kernel.
   1811          */
   1812 
   1813         if (niObj == NULL) {
   1814             int index;
   1815             int len = sizeof(index);
   1816 
   1817             if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
   1818                                (char*)&index, &len) < 0) {
   1819                 NET_ThrowCurrent(env, "getsockopt IPV6_MULTICAST_IF failed");
   1820                 return;
   1821             }
   1822 
   1823             mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj));
   1824             mname.imr_address.s_addr = 0 ;
   1825             mname.imr_ifindex = index;
   1826             mname_len = sizeof(struct ip_mreqn);
   1827         }
   1828 
   1829 
   1830         /*
   1831          * Join the multicast group.
   1832          */
   1833         if (JVM_SetSockOpt(fd, IPPROTO_IP, (join ? IP_ADD_MEMBERSHIP:IP_DROP_MEMBERSHIP),
   1834                            (char *) &mname, mname_len) < 0) {
   1835 
   1836             /*
   1837              * If IP_ADD_MEMBERSHIP returns ENOPROTOOPT on Linux and we've got
   1838              * IPv6 enabled then it's possible that the kernel has been fixed
   1839              * so we switch to IPV6_ADD_MEMBERSHIP socket option.
   1840              * As of 2.4.7 kernel IPV6_ADD_MEMERSHIP can't handle IPv4-mapped
   1841              * addresses so we have to use IP_ADD_MEMERSHIP for IPv4 multicast
   1842              * groups. However if the socket is an IPv6 socket then then setsockopt
   1843              * should reurn ENOPROTOOPT. We assume this will be fixed in Linux
   1844              * at some stage.
   1845              */
   1846             if (errno == ENOPROTOOPT) {
   1847                 if (ipv6_available()) {
   1848                     ipv6_join_leave = JNI_TRUE;
   1849                     errno = 0;
   1850                 } else  {
   1851                     errno = ENOPROTOOPT;    /* errno can be changed by ipv6_available */
   1852                 }
   1853             }
   1854             if (errno) {
   1855                 if (join) {
   1856                     NET_ThrowCurrent(env, "setsockopt IP_ADD_MEMBERSHIP failed");
   1857                 } else {
   1858                     if (errno == ENOENT)
   1859                         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
   1860                             "Not a member of the multicast group");
   1861                     else
   1862                         NET_ThrowCurrent(env, "setsockopt IP_DROP_MEMBERSHIP failed");
   1863                 }
   1864             }
   1865         }
   1866 
   1867         /*
   1868          * If we haven't switched to IPv6 socket option then we're done.
   1869          */
   1870         if (!ipv6_join_leave) {
   1871             return;
   1872         }
   1873     }
   1874 
   1875 
   1876     /*
   1877      * IPv6 join. If it's an IPv4 multicast group then we use an IPv4-mapped
   1878      * address.
   1879      */
   1880     {
   1881         struct ipv6_mreq mname6;
   1882 
   1883         jbyteArray ipaddress;
   1884         jbyte caddr[16];
   1885         jint family;
   1886         jint address;
   1887         family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
   1888         if (family == AF_INET) { /* will convert to IPv4-mapped address */
   1889             memset((char *) caddr, 0, 16);
   1890             address = getInetAddress_addr(env, iaObj);
   1891 
   1892             caddr[10] = 0xff;
   1893             caddr[11] = 0xff;
   1894 
   1895             caddr[12] = ((address >> 24) & 0xff);
   1896             caddr[13] = ((address >> 16) & 0xff);
   1897             caddr[14] = ((address >> 8) & 0xff);
   1898             caddr[15] = (address & 0xff);
   1899         } else {
   1900             ipaddress = (*env)->GetObjectField(env, iaObj, ia6_ipaddressID);
   1901             (*env)->GetByteArrayRegion(env, ipaddress, 0, 16, caddr);
   1902         }
   1903 
   1904         memcpy((void *)&(mname6.ipv6mr_multiaddr), caddr, sizeof(struct in6_addr));
   1905         if (IS_NULL(niObj)) {
   1906             int index;
   1907             int len = sizeof(index);
   1908 
   1909             {
   1910                 if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
   1911                                  (char*)&index, &len) < 0) {
   1912                     NET_ThrowCurrent(env, "getsockopt IPV6_MULTICAST_IF failed");
   1913                     return;
   1914                 }
   1915             }
   1916 
   1917             mname6.ipv6mr_interface = index;
   1918         } else {
   1919             jint idx = (*env)->GetIntField(env, niObj, ni_indexID);
   1920             mname6.ipv6mr_interface = idx;
   1921         }
   1922 
   1923 #define ADD_MEMBERSHIP          IPV6_ADD_MEMBERSHIP
   1924 #define DRP_MEMBERSHIP          IPV6_DROP_MEMBERSHIP
   1925 #define S_ADD_MEMBERSHIP        "IPV6_ADD_MEMBERSHIP"
   1926 #define S_DRP_MEMBERSHIP        "IPV6_DROP_MEMBERSHIP"
   1927 
   1928         /* Join the multicast group */
   1929         if (JVM_SetSockOpt(fd, IPPROTO_IPV6, (join ? ADD_MEMBERSHIP : DRP_MEMBERSHIP),
   1930                            (char *) &mname6, sizeof (mname6)) < 0) {
   1931 
   1932             if (join) {
   1933                 NET_ThrowCurrent(env, "setsockopt " S_ADD_MEMBERSHIP " failed");
   1934             } else {
   1935                 if (errno == ENOENT) {
   1936                    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
   1937                         "Not a member of the multicast group");
   1938                 } else {
   1939                     NET_ThrowCurrent(env, "setsockopt " S_DRP_MEMBERSHIP " failed");
   1940                 }
   1941             }
   1942         }
   1943     }
   1944 }
   1945 
   1946 /*
   1947  * Class:     java_net_PlainDatagramSocketImpl
   1948  * Method:    join
   1949  * Signature: (Ljava/net/InetAddress;)V
   1950  */
   1951 JNIEXPORT void JNICALL
   1952 PlainDatagramSocketImpl_join(JNIEnv *env, jobject this,
   1953                                            jobject iaObj, jobject niObj)
   1954 {
   1955     mcast_join_leave(env, this, iaObj, niObj, JNI_TRUE);
   1956 }
   1957 
   1958 /*
   1959  * Class:     java_net_PlainDatagramSocketImpl
   1960  * Method:    leave
   1961  * Signature: (Ljava/net/InetAddress;)V
   1962  */
   1963 JNIEXPORT void JNICALL
   1964 PlainDatagramSocketImpl_leave(JNIEnv *env, jobject this,
   1965                                             jobject iaObj, jobject niObj)
   1966 {
   1967     mcast_join_leave(env, this, iaObj, niObj, JNI_FALSE);
   1968 }
   1969 
   1970 static JNINativeMethod gMethods[] = {
   1971   NATIVE_METHOD(PlainDatagramSocketImpl, leave, "(Ljava/net/InetAddress;Ljava/net/NetworkInterface;)V"),
   1972   NATIVE_METHOD(PlainDatagramSocketImpl, join, "(Ljava/net/InetAddress;Ljava/net/NetworkInterface;)V"),
   1973   NATIVE_METHOD(PlainDatagramSocketImpl, getTimeToLive, "()I"),
   1974   NATIVE_METHOD(PlainDatagramSocketImpl, getTTL, "()B"),
   1975   NATIVE_METHOD(PlainDatagramSocketImpl, setTimeToLive, "(I)V"),
   1976   NATIVE_METHOD(PlainDatagramSocketImpl, setTTL, "(B)V"),
   1977   NATIVE_METHOD(PlainDatagramSocketImpl, socketGetOption, "(I)Ljava/lang/Object;"),
   1978   NATIVE_METHOD(PlainDatagramSocketImpl, socketSetOption, "(ILjava/lang/Object;)V"),
   1979   NATIVE_METHOD(PlainDatagramSocketImpl, datagramSocketClose, "()V"),
   1980   NATIVE_METHOD(PlainDatagramSocketImpl, datagramSocketCreate, "()V"),
   1981   NATIVE_METHOD(PlainDatagramSocketImpl, receive0, "(Ljava/net/DatagramPacket;)V"),
   1982   NATIVE_METHOD(PlainDatagramSocketImpl, peekData, "(Ljava/net/DatagramPacket;)I"),
   1983   NATIVE_METHOD(PlainDatagramSocketImpl, peek, "(Ljava/net/InetAddress;)I"),
   1984   NATIVE_METHOD(PlainDatagramSocketImpl, send, "(Ljava/net/DatagramPacket;)V"),
   1985   NATIVE_METHOD(PlainDatagramSocketImpl, disconnect0, "(I)V"),
   1986   NATIVE_METHOD(PlainDatagramSocketImpl, connect0, "(Ljava/net/InetAddress;I)V"),
   1987   NATIVE_METHOD(PlainDatagramSocketImpl, bind0, "(ILjava/net/InetAddress;)V"),
   1988   NATIVE_METHOD(PlainDatagramSocketImpl, init, "()V"),
   1989 };
   1990 
   1991 void register_java_net_PlainDatagramSocketImpl(JNIEnv* env) {
   1992   jniRegisterNativeMethods(env, "java/net/PlainDatagramSocketImpl", gMethods, NELEM(gMethods));
   1993 }
   1994