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