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