1 /*
   2  * Copyright (c) 1997, 2018, 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 #include <malloc.h>
  26 
  27 #include "net_util.h"
  28 #include "NetworkInterface.h"
  29 
  30 #include "java_net_TwoStacksPlainDatagramSocketImpl.h"
  31 #include "java_net_SocketOptions.h"
  32 #include "java_net_NetworkInterface.h"
  33 #include "java_net_InetAddress.h"
  34 
  35 #ifndef IPTOS_TOS_MASK
  36 #define IPTOS_TOS_MASK 0x1e
  37 #endif
  38 #ifndef IPTOS_PREC_MASK
  39 #define IPTOS_PREC_MASK 0xe0
  40 #endif
  41 
  42 
  43 #define IN_CLASSD(i)    (((long)(i) & 0xf0000000) == 0xe0000000)
  44 #define IN_MULTICAST(i) IN_CLASSD(i)
  45 
  46 extern int getAllInterfacesAndAddresses(JNIEnv *env, netif **netifPP);
  47 
  48 /************************************************************************
  49  * TwoStacksPlainDatagramSocketImpl
  50  */
  51 
  52 static jfieldID IO_fd_fdID;
  53 static jfieldID pdsi_trafficClassID;
  54 jfieldID pdsi_fdID;
  55 jfieldID pdsi_fd1ID;
  56 jfieldID pdsi_fduseID;
  57 jfieldID pdsi_lastfdID;
  58 jfieldID pdsi_timeoutID;
  59 
  60 jfieldID pdsi_localPortID;
  61 jfieldID pdsi_connected;
  62 
  63 static jclass ia4_clazz;
  64 static jmethodID ia4_ctor;
  65 
  66 /*
  67  * Notes about UDP/IPV6 on Windows (XP and 2003 server):
  68  *
  69  * fd always points to the IPv4 fd, and fd1 points to the IPv6 fd.
  70  * Both fds are used when we bind to a wild-card address. When a specific
  71  * address is used, only one of them is used.
  72  */
  73 
  74 /*
  75  * Returns a java.lang.Integer based on 'i'
  76  */
  77 jobject createInteger(JNIEnv *env, int i) {
  78     static jclass i_class = NULL;
  79     static jmethodID i_ctrID;
  80     static jfieldID i_valueID;
  81 
  82     if (i_class == NULL) {
  83         jclass c = (*env)->FindClass(env, "java/lang/Integer");
  84         CHECK_NULL_RETURN(c, NULL);
  85         i_ctrID = (*env)->GetMethodID(env, c, "<init>", "(I)V");
  86         CHECK_NULL_RETURN(i_ctrID, NULL);
  87         i_class = (*env)->NewGlobalRef(env, c);
  88         CHECK_NULL_RETURN(i_class, NULL);
  89     }
  90 
  91     return (*env)->NewObject(env, i_class, i_ctrID, i);
  92 }
  93 
  94 /*
  95  * Returns a java.lang.Boolean based on 'b'
  96  */
  97 jobject createBoolean(JNIEnv *env, int b) {
  98     static jclass b_class = NULL;
  99     static jmethodID b_ctrID;
 100     static jfieldID b_valueID;
 101 
 102     if (b_class == NULL) {
 103         jclass c = (*env)->FindClass(env, "java/lang/Boolean");
 104         CHECK_NULL_RETURN(c, NULL);
 105         b_ctrID = (*env)->GetMethodID(env, c, "<init>", "(Z)V");
 106         CHECK_NULL_RETURN(b_ctrID, NULL);
 107         b_class = (*env)->NewGlobalRef(env, c);
 108         CHECK_NULL_RETURN(b_class, NULL);
 109     }
 110 
 111     return (*env)->NewObject(env, b_class, b_ctrID, (jboolean)(b!=0));
 112 }
 113 
 114 static int getFD(JNIEnv *env, jobject this) {
 115     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 116 
 117     if (fdObj == NULL) {
 118         return -1;
 119     }
 120     return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 121 }
 122 
 123 static int getFD1(JNIEnv *env, jobject this) {
 124     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 125 
 126     if (fdObj == NULL) {
 127         return -1;
 128     }
 129     return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 130 }
 131 
 132 /*
 133  * This function "purges" all outstanding ICMP port unreachable packets
 134  * outstanding on a socket and returns JNI_TRUE if any ICMP messages
 135  * have been purged. The rational for purging is to emulate normal BSD
 136  * behaviour whereby receiving a "connection reset" status resets the
 137  * socket.
 138  */
 139 static jboolean purgeOutstandingICMP(JNIEnv *env, jobject this, jint fd)
 140 {
 141     jboolean got_icmp = JNI_FALSE;
 142     char buf[1];
 143     fd_set tbl;
 144     struct timeval t = { 0, 0 };
 145     SOCKETADDRESS rmtaddr;
 146     int addrlen = sizeof(SOCKETADDRESS);
 147 
 148     memset((char *)&rmtaddr, 0, sizeof(rmtaddr));
 149 
 150     /*
 151      * Peek at the queue to see if there is an ICMP port unreachable. If there
 152      * is then receive it.
 153      */
 154     FD_ZERO(&tbl);
 155     FD_SET(fd, &tbl);
 156     while(1) {
 157         if (select(/*ignored*/fd+1, &tbl, 0, 0, &t) <= 0) {
 158             break;
 159         }
 160         if (recvfrom(fd, buf, 1, MSG_PEEK, &rmtaddr.sa, &addrlen) != SOCKET_ERROR) {
 161             break;
 162         }
 163         if (WSAGetLastError() != WSAECONNRESET) {
 164             /* some other error - we don't care here */
 165             break;
 166         }
 167 
 168         recvfrom(fd, buf, 1, 0, &rmtaddr.sa, &addrlen);
 169         got_icmp = JNI_TRUE;
 170     }
 171 
 172     return got_icmp;
 173 }
 174 
 175 
 176 /*
 177  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
 178  * Method:    init
 179  * Signature: ()V
 180  */
 181 JNIEXPORT void JNICALL
 182 Java_java_net_TwoStacksPlainDatagramSocketImpl_init(JNIEnv *env, jclass cls) {
 183     /* get fieldIDs */
 184     pdsi_fdID = (*env)->GetFieldID(env, cls, "fd", "Ljava/io/FileDescriptor;");
 185     CHECK_NULL(pdsi_fdID);
 186     pdsi_fd1ID = (*env)->GetFieldID(env, cls, "fd1", "Ljava/io/FileDescriptor;");
 187     CHECK_NULL(pdsi_fd1ID);
 188     pdsi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
 189     CHECK_NULL(pdsi_timeoutID);
 190     pdsi_fduseID = (*env)->GetFieldID(env, cls, "fduse", "I");
 191     CHECK_NULL(pdsi_fduseID);
 192     pdsi_lastfdID = (*env)->GetFieldID(env, cls, "lastfd", "I");
 193     CHECK_NULL(pdsi_lastfdID);
 194     pdsi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
 195     CHECK_NULL(pdsi_trafficClassID);
 196     pdsi_localPortID = (*env)->GetFieldID(env, cls, "localPort", "I");
 197     CHECK_NULL(pdsi_localPortID);
 198     pdsi_connected = (*env)->GetFieldID(env, cls, "connected", "Z");
 199     CHECK_NULL(pdsi_connected);
 200 
 201     cls = (*env)->FindClass(env, "java/io/FileDescriptor");
 202     CHECK_NULL(cls);
 203     IO_fd_fdID = NET_GetFileDescriptorID(env);
 204     CHECK_NULL(IO_fd_fdID);
 205 
 206     ia4_clazz = (*env)->FindClass(env, "java/net/Inet4Address");
 207     CHECK_NULL(ia4_clazz);
 208     ia4_clazz = (*env)->NewGlobalRef(env, ia4_clazz);
 209     CHECK_NULL(ia4_clazz);
 210     ia4_ctor = (*env)->GetMethodID(env, ia4_clazz, "<init>", "()V");
 211     CHECK_NULL(ia4_ctor);
 212 }
 213 
 214 JNIEXPORT void JNICALL
 215 Java_java_net_TwoStacksPlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this,
 216                                            jint port, jobject addressObj,
 217                                            jboolean exclBind) {
 218     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 219     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 220     int ipv6_supported = ipv6_available();
 221     int fd, fd1 = -1, lcladdrlen = 0;
 222     jint family;
 223     SOCKETADDRESS lcladdr;
 224 
 225     family = getInetAddress_family(env, addressObj);
 226     JNU_CHECK_EXCEPTION(env);
 227     if (family == java_net_InetAddress_IPv6 && !ipv6_supported) {
 228         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 229                         "Protocol family not supported");
 230         return;
 231     }
 232     if (IS_NULL(fdObj) || (ipv6_supported && IS_NULL(fd1Obj))) {
 233         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
 234         return;
 235     } else {
 236         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 237         if (ipv6_supported) {
 238             fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 239         }
 240     }
 241 
 242     if (IS_NULL(addressObj)) {
 243         JNU_ThrowNullPointerException(env, "argument address");
 244         return;
 245     }
 246 
 247     if (NET_InetAddressToSockaddr(env, addressObj, port, &lcladdr,
 248                                   &lcladdrlen, JNI_FALSE) != 0) {
 249         return;
 250     }
 251 
 252     if (ipv6_supported) {
 253         struct ipv6bind v6bind;
 254         v6bind.addr = &lcladdr;
 255         v6bind.ipv4_fd = fd;
 256         v6bind.ipv6_fd = fd1;
 257         if (NET_BindV6(&v6bind, exclBind) != -1) {
 258             /* check if the fds have changed */
 259             if (v6bind.ipv4_fd != fd) {
 260                 fd = v6bind.ipv4_fd;
 261                 if (fd == -1) {
 262                     /* socket is closed. */
 263                     (*env)->SetObjectField(env, this, pdsi_fdID, NULL);
 264                 } else {
 265                     /* socket was re-created */
 266                     (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
 267                 }
 268             }
 269             if (v6bind.ipv6_fd != fd1) {
 270                 fd1 = v6bind.ipv6_fd;
 271                 if (fd1 == -1) {
 272                     /* socket is closed. */
 273                     (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL);
 274                 } else {
 275                     /* socket was re-created */
 276                     (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
 277                 }
 278             }
 279         } else {
 280             /* NET_BindV6() closes both sockets upon a failure */
 281             (*env)->SetObjectField(env, this, pdsi_fdID, NULL);
 282             (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL);
 283             NET_ThrowCurrent (env, "Cannot bind");
 284             return;
 285         }
 286     } else {
 287         if (NET_WinBind(fd, &lcladdr, lcladdrlen, exclBind) == -1) {
 288             if (WSAGetLastError() == WSAEACCES) {
 289                 WSASetLastError(WSAEADDRINUSE);
 290             }
 291             (*env)->SetObjectField(env, this, pdsi_fdID, NULL);
 292             NET_ThrowCurrent(env, "Cannot bind");
 293             closesocket(fd);
 294             return;
 295         }
 296     }
 297 
 298     if (port == 0) {
 299         if (getsockname(fd == -1 ? fd1 : fd, &lcladdr.sa, &lcladdrlen) == -1) {
 300             NET_ThrowCurrent(env, "getsockname");
 301             return;
 302         }
 303         port = ntohs((u_short)GET_PORT(&lcladdr));
 304     }
 305     (*env)->SetIntField(env, this, pdsi_localPortID, port);
 306 }
 307 
 308 
 309 /*
 310  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
 311  * Method:    connect0
 312  * Signature: (Ljava/net/InetAddress;I)V
 313  */
 314 
 315 JNIEXPORT void JNICALL
 316 Java_java_net_TwoStacksPlainDatagramSocketImpl_connect0
 317   (JNIEnv *env, jobject this, jobject address, jint port)
 318 {
 319     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 320     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 321     jint fd = -1, fd1 = -1, fdc, family;
 322     SOCKETADDRESS rmtaddr;
 323     int rmtaddrlen = 0;
 324     DWORD x1, x2; /* ignored result codes */
 325     int res, t;
 326 
 327     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
 328         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 329                         "Socket closed");
 330         return;
 331     }
 332 
 333     if (!IS_NULL(fdObj)) {
 334         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 335     }
 336 
 337     if (!IS_NULL(fd1Obj)) {
 338         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 339     }
 340 
 341     if (IS_NULL(address)) {
 342         JNU_ThrowNullPointerException(env, "address");
 343         return;
 344     }
 345 
 346     family = getInetAddress_family(env, address);
 347     JNU_CHECK_EXCEPTION(env);
 348     if (family == java_net_InetAddress_IPv6 && !ipv6_available()) {
 349         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 350                         "Protocol family not supported");
 351         return;
 352     }
 353 
 354     fdc = family == java_net_InetAddress_IPv4 ? fd : fd1;
 355 
 356     /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which
 357      * returns connection reset errors on connected UDP sockets (as well
 358      * as connected sockets). The solution is to only enable this feature
 359      * when the socket is connected
 360      */
 361     t = TRUE;
 362     res = WSAIoctl(fdc, SIO_UDP_CONNRESET, &t, sizeof(t), &x1, sizeof(x1), &x2, 0, 0);
 363 
 364     if (NET_InetAddressToSockaddr(env, address, port, &rmtaddr,
 365                                   &rmtaddrlen, JNI_FALSE) != 0) {
 366         return;
 367     }
 368 
 369     if (connect(fdc, &rmtaddr.sa, rmtaddrlen) == -1) {
 370         NET_ThrowCurrent(env, "connect");
 371         return;
 372     }
 373 }
 374 
 375 /*
 376  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
 377  * Method:    disconnect0
 378  * Signature: ()V
 379  */
 380 
 381 JNIEXPORT void JNICALL
 382 Java_java_net_TwoStacksPlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jint family) {
 383     /* The object's field */
 384     jobject fdObj;
 385     /* The fdObj'fd */
 386     jint fd, len;
 387     SOCKETADDRESS addr;
 388     DWORD x1 = 0, x2 = 0; /* ignored result codes */
 389     int t;
 390 
 391     if (family == java_net_InetAddress_IPv4) {
 392         fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 393         len = sizeof(struct sockaddr_in);
 394     } else {
 395         fdObj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 396         len = sizeof(struct sockaddr_in6);
 397     }
 398 
 399     if (IS_NULL(fdObj)) {
 400         /* disconnect doesn't throw any exceptions */
 401         return;
 402     }
 403     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 404 
 405     memset((char *)&addr, 0, len);
 406     connect(fd, &addr.sa, len);
 407 
 408     /*
 409      * use SIO_UDP_CONNRESET
 410      * to disable ICMP port unreachable handling here.
 411      */
 412     t = FALSE;
 413     WSAIoctl(fd, SIO_UDP_CONNRESET, &t, sizeof(t), &x1, sizeof(x1), &x2, 0, 0);
 414 }
 415 
 416 /*
 417  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
 418  * Method:    send
 419  * Signature: (Ljava/net/DatagramPacket;)V
 420  */
 421 JNIEXPORT void JNICALL
 422 Java_java_net_TwoStacksPlainDatagramSocketImpl_send
 423   (JNIEnv *env, jobject this, jobject packet)
 424 {
 425     char BUF[MAX_BUFFER_LEN];
 426     char *fullPacket;
 427     jobject fdObj;
 428     jint fd;
 429 
 430     jobject iaObj;
 431     jint family;
 432 
 433     jint packetBufferOffset, packetBufferLen, packetPort;
 434     jbyteArray packetBuffer;
 435     jboolean connected;
 436 
 437     SOCKETADDRESS rmtaddr;
 438     struct sockaddr *addrp = 0;
 439     int addrlen = 0;
 440 
 441     if (IS_NULL(packet)) {
 442         JNU_ThrowNullPointerException(env, "null packet");
 443         return;
 444     }
 445 
 446     iaObj = (*env)->GetObjectField(env, packet, dp_addressID);
 447 
 448     packetPort = (*env)->GetIntField(env, packet, dp_portID);
 449     packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
 450     packetBuffer = (jbyteArray)(*env)->GetObjectField(env, packet, dp_bufID);
 451     connected = (*env)->GetBooleanField(env, this, pdsi_connected);
 452 
 453     if (IS_NULL(iaObj) || IS_NULL(packetBuffer)) {
 454         JNU_ThrowNullPointerException(env, "null address || null buffer");
 455         return;
 456     }
 457 
 458     family = getInetAddress_family(env, iaObj);
 459     JNU_CHECK_EXCEPTION(env);
 460     if (family == java_net_InetAddress_IPv4) {
 461         fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 462     } else {
 463         if (!ipv6_available()) {
 464             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 465                         "Protocol not allowed");
 466             return;
 467         }
 468         fdObj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 469     }
 470 
 471     if (IS_NULL(fdObj)) {
 472         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 473                         "Socket closed");
 474         return;
 475     }
 476     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 477 
 478     packetBufferLen = (*env)->GetIntField(env, packet, dp_lengthID);
 479     /* Note: the buffer needn't be greater than 65,536 (0xFFFF)...
 480      * the maximum size of an IP packet. Anything bigger is truncated anyway.
 481      */
 482     if (packetBufferLen > MAX_PACKET_LEN) {
 483         packetBufferLen = MAX_PACKET_LEN;
 484     }
 485 
 486     // sockaddr arg to sendto() is null if already connected
 487     if (!connected) {
 488         if (NET_InetAddressToSockaddr(env, iaObj, packetPort, &rmtaddr,
 489                                       &addrlen, JNI_FALSE) != 0) {
 490             return;
 491         }
 492         addrp = &rmtaddr.sa;
 493     }
 494 
 495     if (packetBufferLen > MAX_BUFFER_LEN) {
 496         /* When JNI-ifying the JDK's IO routines, we turned
 497          * reads and writes of byte arrays of size greater
 498          * than 2048 bytes into several operations of size 2048.
 499          * This saves a malloc()/memcpy()/free() for big
 500          * buffers.  This is OK for file IO and TCP, but that
 501          * strategy violates the semantics of a datagram protocol.
 502          * (one big send) != (several smaller sends).  So here
 503          * we *must* alloc the buffer.  Note it needn't be bigger
 504          * than 65,536 (0xFFFF) the max size of an IP packet.
 505          * anything bigger is truncated anyway.
 506          */
 507         fullPacket = (char *)malloc(packetBufferLen);
 508         if (!fullPacket) {
 509             JNU_ThrowOutOfMemoryError(env, "Send buf native heap allocation failed");
 510             return;
 511         }
 512     } else {
 513         fullPacket = &(BUF[0]);
 514     }
 515 
 516     (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset,
 517                                packetBufferLen, (jbyte *)fullPacket);
 518     if (sendto(fd, fullPacket, packetBufferLen, 0, addrp,
 519                addrlen) == SOCKET_ERROR)
 520     {
 521         NET_ThrowCurrent(env, "Datagram send failed");
 522     }
 523 
 524     if (packetBufferLen > MAX_BUFFER_LEN) {
 525         free(fullPacket);
 526     }
 527 }
 528 
 529 /*
 530  * check which socket was last serviced when there was data on both sockets.
 531  * Only call this if sure that there is data on both sockets.
 532  */
 533 static int checkLastFD (JNIEnv *env, jobject this, int fd, int fd1) {
 534     int nextfd, lastfd = (*env)->GetIntField(env, this, pdsi_lastfdID);
 535     if (lastfd == -1) {
 536         /* arbitrary. Choose fd */
 537         (*env)->SetIntField(env, this, pdsi_lastfdID, fd);
 538         return fd;
 539     } else {
 540         if (lastfd == fd) {
 541             nextfd = fd1;
 542         } else {
 543             nextfd = fd;
 544         }
 545         (*env)->SetIntField(env, this, pdsi_lastfdID, nextfd);
 546         return nextfd;
 547     }
 548 }
 549 
 550 /*
 551  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
 552  * Method:    peek
 553  * Signature: (Ljava/net/InetAddress;)I
 554  */
 555 JNIEXPORT jint JNICALL
 556 Java_java_net_TwoStacksPlainDatagramSocketImpl_peek(JNIEnv *env, jobject this,
 557                                            jobject addressObj) {
 558 
 559     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 560     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
 561     jint fd;
 562 
 563     /* The address and family fields of addressObj */
 564     jint address, family;
 565 
 566     int n;
 567     SOCKETADDRESS remote_addr;
 568     jint remote_addrsize = sizeof(SOCKETADDRESS);
 569     char buf[1];
 570     BOOL retry;
 571     jlong prevTime = 0;
 572 
 573     if (IS_NULL(fdObj)) {
 574         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 575         return -1;
 576     } else {
 577         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 578         if (fd < 0) {
 579            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 580                            "socket closed");
 581            return -1;
 582         }
 583     }
 584     if (IS_NULL(addressObj)) {
 585         JNU_ThrowNullPointerException(env, "Null address in peek()");
 586         return -1;
 587     } else {
 588         address = getInetAddress_addr(env, addressObj);
 589         JNU_CHECK_EXCEPTION_RETURN(env, -1);
 590         /* We only handle IPv4 for now. Will support IPv6 once its in the os */
 591         family = AF_INET;
 592     }
 593 
 594     do {
 595         retry = FALSE;
 596 
 597         /*
 598          * If a timeout has been specified then we select on the socket
 599          * waiting for a read event or a timeout.
 600          */
 601         if (timeout) {
 602             int ret;
 603             prevTime = JVM_CurrentTimeMillis(env, 0);
 604             ret = NET_Timeout (fd, timeout);
 605             if (ret == 0) {
 606                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 607                                 "Peek timed out");
 608                 return ret;
 609             } else if (ret == -1) {
 610                 NET_ThrowCurrent(env, "timeout in datagram socket peek");
 611                 return ret;
 612             }
 613         }
 614 
 615         /* now try the peek */
 616         n = recvfrom(fd, buf, 1, MSG_PEEK, &remote_addr.sa, &remote_addrsize);
 617 
 618         if (n == SOCKET_ERROR) {
 619             if (WSAGetLastError() == WSAECONNRESET) {
 620                 jboolean connected;
 621 
 622                 /*
 623                  * An icmp port unreachable - we must receive this as Windows
 624                  * does not reset the state of the socket until this has been
 625                  * received.
 626                  */
 627                 purgeOutstandingICMP(env, this, fd);
 628 
 629                 connected =  (*env)->GetBooleanField(env, this, pdsi_connected);
 630                 if (connected) {
 631                     JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 632                                        "ICMP Port Unreachable");
 633                     return 0;
 634                 }
 635 
 636                 /*
 637                  * If a timeout was specified then we need to adjust it because
 638                  * we may have used up some of the timeout befor the icmp port
 639                  * unreachable arrived.
 640                  */
 641                 if (timeout) {
 642                     jlong newTime = JVM_CurrentTimeMillis(env, 0);
 643                     timeout -= (jint)(newTime - prevTime);
 644                     if (timeout <= 0) {
 645                         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 646                                 "Receive timed out");
 647                         return 0;
 648                     }
 649                     prevTime = newTime;
 650                 }
 651 
 652                 /* Need to retry the recv */
 653                 retry = TRUE;
 654             }
 655         }
 656     } while (retry);
 657 
 658     if (n == SOCKET_ERROR && WSAGetLastError() != WSAEMSGSIZE) {
 659         NET_ThrowCurrent(env, "Datagram peek failed");
 660         return 0;
 661     }
 662     setInetAddress_addr(env, addressObj, ntohl(remote_addr.sa4.sin_addr.s_addr));
 663     JNU_CHECK_EXCEPTION_RETURN(env, -1);
 664     setInetAddress_family(env, addressObj, java_net_InetAddress_IPv4);
 665     JNU_CHECK_EXCEPTION_RETURN(env, -1);
 666 
 667     /* return port */
 668     return ntohs(remote_addr.sa4.sin_port);
 669 }
 670 
 671 JNIEXPORT jint JNICALL
 672 Java_java_net_TwoStacksPlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this,
 673                                            jobject packet) {
 674 
 675      char BUF[MAX_BUFFER_LEN];
 676     char *fullPacket;
 677     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 678     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 679     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
 680 
 681     jbyteArray packetBuffer;
 682     jint packetBufferOffset, packetBufferLen;
 683 
 684     int fd = -1, fd1 = -1, fduse, nsockets = 0, errorCode;
 685     int port;
 686 
 687     int checkBoth = 0;
 688     int n;
 689     SOCKETADDRESS remote_addr;
 690     jint remote_addrsize = sizeof(SOCKETADDRESS);
 691     BOOL retry;
 692     jlong prevTime = 0;
 693 
 694     if (!IS_NULL(fdObj)) {
 695         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 696         if (fd < 0) {
 697            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 698                            "socket closed");
 699            return -1;
 700         }
 701         nsockets = 1;
 702     }
 703 
 704     if (!IS_NULL(fd1Obj)) {
 705         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 706         if (fd1 < 0) {
 707            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 708                            "socket closed");
 709            return -1;
 710         }
 711         nsockets ++;
 712     }
 713 
 714     switch (nsockets) {
 715       case 0:
 716         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 717                        "socket closed");
 718         return -1;
 719       case 1:
 720         if (!IS_NULL(fdObj)) {
 721            fduse = fd;
 722         } else {
 723            fduse = fd1;
 724         }
 725         break;
 726       case 2:
 727         checkBoth = TRUE;
 728         break;
 729     }
 730 
 731     if (IS_NULL(packet)) {
 732         JNU_ThrowNullPointerException(env, "packet");
 733         return -1;
 734     }
 735 
 736     packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
 737 
 738     if (IS_NULL(packetBuffer)) {
 739         JNU_ThrowNullPointerException(env, "packet buffer");
 740         return -1;
 741     }
 742 
 743     packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
 744     packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
 745 
 746     if (packetBufferLen > MAX_BUFFER_LEN) {
 747 
 748         /* When JNI-ifying the JDK's IO routines, we turned
 749          * read's and write's of byte arrays of size greater
 750          * than 2048 bytes into several operations of size 2048.
 751          * This saves a malloc()/memcpy()/free() for big
 752          * buffers.  This is OK for file IO and TCP, but that
 753          * strategy violates the semantics of a datagram protocol.
 754          * (one big send) != (several smaller sends).  So here
 755          * we *must* alloc the buffer.  Note it needn't be bigger
 756          * than 65,536 (0xFFFF) the max size of an IP packet.
 757          * anything bigger is truncated anyway.
 758          */
 759         fullPacket = (char *)malloc(packetBufferLen);
 760         if (!fullPacket) {
 761             JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
 762             return -1;
 763         }
 764     } else {
 765         fullPacket = &(BUF[0]);
 766     }
 767 
 768     do {
 769         int ret;
 770         retry = FALSE;
 771 
 772         /*
 773          * If a timeout has been specified then we select on the socket
 774          * waiting for a read event or a timeout.
 775          */
 776         if (checkBoth) {
 777             int t = timeout == 0 ? -1: timeout;
 778             prevTime = JVM_CurrentTimeMillis(env, 0);
 779             ret = NET_Timeout2 (fd, fd1, t, &fduse);
 780             /* all subsequent calls to recv() or select() will use the same fd
 781              * for this call to peek() */
 782             if (ret <= 0) {
 783                 if (ret == 0) {
 784                     JNU_ThrowByName(env,JNU_JAVANETPKG "SocketTimeoutException",
 785                                         "Peek timed out");
 786                 } else if (ret == -1) {
 787                     NET_ThrowCurrent(env, "timeout in datagram socket peek");
 788                 }
 789                 if (packetBufferLen > MAX_BUFFER_LEN) {
 790                     free(fullPacket);
 791                 }
 792                 return -1;
 793             }
 794             if (ret == 2) {
 795                 fduse = checkLastFD (env, this, fd, fd1);
 796             }
 797             checkBoth = FALSE;
 798         } else if (timeout) {
 799             if (prevTime == 0) {
 800                 prevTime = JVM_CurrentTimeMillis(env, 0);
 801             }
 802             ret = NET_Timeout (fduse, timeout);
 803             if (ret <= 0) {
 804                 if (ret == 0) {
 805                     JNU_ThrowByName(env,JNU_JAVANETPKG "SocketTimeoutException",
 806                                     "Receive timed out");
 807                 } else if (ret == -1) {
 808                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 809                                     "Socket closed");
 810                 }
 811                 if (packetBufferLen > MAX_BUFFER_LEN) {
 812                     free(fullPacket);
 813                 }
 814                 return -1;
 815             }
 816         }
 817 
 818         /* receive the packet */
 819         n = recvfrom(fduse, fullPacket, packetBufferLen, MSG_PEEK,
 820                      &remote_addr.sa, &remote_addrsize);
 821         port = (int) ntohs ((u_short) GET_PORT((SOCKETADDRESS *)&remote_addr));
 822         if (n == SOCKET_ERROR) {
 823             if (WSAGetLastError() == WSAECONNRESET) {
 824                 jboolean connected;
 825 
 826                 /*
 827                  * An icmp port unreachable - we must receive this as Windows
 828                  * does not reset the state of the socket until this has been
 829                  * received.
 830                  */
 831                 purgeOutstandingICMP(env, this, fduse);
 832 
 833                 connected = (*env)->GetBooleanField(env, this, pdsi_connected);
 834                 if (connected) {
 835                     JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 836                                        "ICMP Port Unreachable");
 837 
 838                     if (packetBufferLen > MAX_BUFFER_LEN) {
 839                         free(fullPacket);
 840                     }
 841                     return -1;
 842                 }
 843 
 844                 /*
 845                  * If a timeout was specified then we need to adjust it because
 846                  * we may have used up some of the timeout befor the icmp port
 847                  * unreachable arrived.
 848                  */
 849                 if (timeout) {
 850                     jlong newTime = JVM_CurrentTimeMillis(env, 0);
 851                     timeout -= (jint)(newTime - prevTime);
 852                     if (timeout <= 0) {
 853                         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 854                                 "Receive timed out");
 855                         if (packetBufferLen > MAX_BUFFER_LEN) {
 856                             free(fullPacket);
 857                         }
 858                         return -1;
 859                     }
 860                     prevTime = newTime;
 861                 }
 862                 retry = TRUE;
 863             }
 864         }
 865     } while (retry);
 866 
 867     /* truncate the data if the packet's length is too small */
 868     if (n > packetBufferLen) {
 869         n = packetBufferLen;
 870     }
 871     if (n < 0) {
 872         errorCode = WSAGetLastError();
 873         /* check to see if it's because the buffer was too small */
 874         if (errorCode == WSAEMSGSIZE) {
 875             /* it is because the buffer is too small. It's UDP, it's
 876              * unreliable, it's all good. discard the rest of the
 877              * data..
 878              */
 879             n = packetBufferLen;
 880         } else {
 881             /* failure */
 882             (*env)->SetIntField(env, packet, dp_lengthID, 0);
 883         }
 884     }
 885     if (n == -1) {
 886         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
 887         if (packetBufferLen > MAX_BUFFER_LEN) {
 888             free(fullPacket);
 889         }
 890         return -1;
 891     } else if (n == -2) {
 892         JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 893                         "operation interrupted");
 894         if (packetBufferLen > MAX_BUFFER_LEN) {
 895             free(fullPacket);
 896         }
 897         return -1;
 898     } else if (n < 0) {
 899         NET_ThrowCurrent(env, "Datagram receive failed");
 900         if (packetBufferLen > MAX_BUFFER_LEN) {
 901             free(fullPacket);
 902         }
 903         return -1;
 904     } else {
 905         jobject packetAddress;
 906 
 907         /*
 908          * Check if there is an InetAddress already associated with this
 909          * packet. If so we check if it is the same source address. We
 910          * can't update any existing InetAddress because it is immutable
 911          */
 912         packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
 913         if (packetAddress != NULL) {
 914             if (!NET_SockaddrEqualsInetAddress(env, &remote_addr,
 915                                                packetAddress)) {
 916                 /* force a new InetAddress to be created */
 917                 packetAddress = NULL;
 918             }
 919         }
 920         if (packetAddress == NULL) {
 921             packetAddress = NET_SockaddrToInetAddress(env, &remote_addr,
 922                                                       &port);
 923             /* stuff the new Inetaddress in the packet */
 924             (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
 925         }
 926 
 927         /* populate the packet */
 928         (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,
 929                                    (jbyte *)fullPacket);
 930         (*env)->SetIntField(env, packet, dp_portID, port);
 931         (*env)->SetIntField(env, packet, dp_lengthID, n);
 932     }
 933 
 934     /* make sure receive() picks up the right fd */
 935     (*env)->SetIntField(env, this, pdsi_fduseID, fduse);
 936 
 937     if (packetBufferLen > MAX_BUFFER_LEN) {
 938         free(fullPacket);
 939     }
 940     return port;
 941 }
 942 
 943 /*
 944  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
 945  * Method:    receive
 946  * Signature: (Ljava/net/DatagramPacket;)V
 947  */
 948 JNIEXPORT void JNICALL
 949 Java_java_net_TwoStacksPlainDatagramSocketImpl_receive0(JNIEnv *env, jobject this,
 950                                               jobject packet) {
 951 
 952     char BUF[MAX_BUFFER_LEN];
 953     char *fullPacket;
 954     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 955     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 956     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
 957     jbyteArray packetBuffer;
 958     jint packetBufferOffset, packetBufferLen;
 959     int ipv6_supported = ipv6_available();
 960 
 961     /* as a result of the changes for ipv6, peek() or peekData()
 962      * must be called prior to receive() so that fduse can be set.
 963      */
 964     int fd = -1, fd1 = -1, fduse, errorCode;
 965 
 966     int n, nsockets=0;
 967     SOCKETADDRESS remote_addr;
 968     jint remote_addrsize = sizeof(SOCKETADDRESS);
 969     BOOL retry;
 970     jlong prevTime = 0, selectTime=0;
 971     jboolean connected;
 972 
 973     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
 974         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 975                         "Socket closed");
 976         return;
 977     }
 978 
 979     if (!IS_NULL(fdObj)) {
 980         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 981         nsockets ++;
 982     }
 983     if (!IS_NULL(fd1Obj)) {
 984         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 985         nsockets ++;
 986     }
 987 
 988     if (nsockets == 2) { /* need to choose one of them */
 989         /* was fduse set in peek? */
 990         fduse = (*env)->GetIntField(env, this, pdsi_fduseID);
 991         if (fduse == -1) {
 992             /* not set in peek(), must select on both sockets */
 993             int ret, t = (timeout == 0) ? -1: timeout;
 994             ret = NET_Timeout2 (fd, fd1, t, &fduse);
 995             if (ret == 2) {
 996                 fduse = checkLastFD (env, this, fd, fd1);
 997             } else if (ret <= 0) {
 998                 if (ret == 0) {
 999                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1000                                     "Receive timed out");
1001                 } else if (ret == -1) {
1002                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1003                                     "Socket closed");
1004                 }
1005                 return;
1006             }
1007         }
1008     } else if (!ipv6_supported) {
1009         fduse = fd;
1010     } else if (IS_NULL(fdObj)) {
1011         /* ipv6 supported: and this socket bound to an IPV6 only address */
1012         fduse = fd1;
1013     } else {
1014         /* ipv6 supported: and this socket bound to an IPV4 only address */
1015         fduse = fd;
1016     }
1017 
1018     if (IS_NULL(packet)) {
1019         JNU_ThrowNullPointerException(env, "packet");
1020         return;
1021     }
1022 
1023     packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
1024 
1025     if (IS_NULL(packetBuffer)) {
1026         JNU_ThrowNullPointerException(env, "packet buffer");
1027         return;
1028     }
1029 
1030     packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
1031     packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
1032 
1033     if (packetBufferLen > MAX_BUFFER_LEN) {
1034 
1035         /* When JNI-ifying the JDK's IO routines, we turned
1036          * read's and write's of byte arrays of size greater
1037          * than 2048 bytes into several operations of size 2048.
1038          * This saves a malloc()/memcpy()/free() for big
1039          * buffers.  This is OK for file IO and TCP, but that
1040          * strategy violates the semantics of a datagram protocol.
1041          * (one big send) != (several smaller sends).  So here
1042          * we *must* alloc the buffer.  Note it needn't be bigger
1043          * than 65,536 (0xFFFF) the max size of an IP packet.
1044          * anything bigger is truncated anyway.
1045          */
1046         fullPacket = (char *)malloc(packetBufferLen);
1047         if (!fullPacket) {
1048             JNU_ThrowOutOfMemoryError(env, "Receive buf native heap allocation failed");
1049             return;
1050         }
1051     } else {
1052         fullPacket = &(BUF[0]);
1053     }
1054 
1055 
1056 
1057     /*
1058      * If we are not connected then we need to know if a timeout has been
1059      * specified and if so we need to pick up the current time. These are
1060      * required in order to implement the semantics of timeout, viz :-
1061      * timeout set to t1 but ICMP port unreachable arrives in t2 where
1062      * t2 < t1. In this case we must discard the ICMP packets and then
1063      * wait for the next packet up to a maximum of t1 minus t2.
1064      */
1065     connected = (*env)->GetBooleanField(env, this, pdsi_connected);
1066     if (!connected && timeout && !ipv6_supported) {
1067         prevTime = JVM_CurrentTimeMillis(env, 0);
1068     }
1069 
1070     if (timeout && nsockets == 1) {
1071         int ret;
1072         ret = NET_Timeout(fduse, timeout);
1073         if (ret <= 0) {
1074             if (ret == 0) {
1075                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1076                                 "Receive timed out");
1077             } else if (ret == -1) {
1078                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1079                                 "Socket closed");
1080             }
1081             if (packetBufferLen > MAX_BUFFER_LEN) {
1082                 free(fullPacket);
1083             }
1084             return;
1085         }
1086     }
1087 
1088     /*
1089      * Loop only if we discarding ICMP port unreachable packets
1090      */
1091     do {
1092         retry = FALSE;
1093 
1094         /* receive the packet */
1095         n = recvfrom(fduse, fullPacket, packetBufferLen, 0, &remote_addr.sa,
1096                      &remote_addrsize);
1097 
1098         if (n == SOCKET_ERROR) {
1099             if (WSAGetLastError() == WSAECONNRESET) {
1100                 /*
1101                  * An icmp port unreachable has been received - consume any other
1102                  * outstanding packets.
1103                  */
1104                 purgeOutstandingICMP(env, this, fduse);
1105 
1106                 /*
1107                  * If connected throw a PortUnreachableException
1108                  */
1109 
1110                 if (connected) {
1111                     JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
1112                                        "ICMP Port Unreachable");
1113 
1114                     if (packetBufferLen > MAX_BUFFER_LEN) {
1115                         free(fullPacket);
1116                     }
1117 
1118                     return;
1119                 }
1120 
1121                 /*
1122                  * If a timeout was specified then we need to adjust it because
1123                  * we may have used up some of the timeout before the icmp port
1124                  * unreachable arrived.
1125                  */
1126                 if (timeout) {
1127                     int ret;
1128                     jlong newTime = JVM_CurrentTimeMillis(env, 0);
1129                     timeout -= (jint)(newTime - prevTime);
1130                     prevTime = newTime;
1131 
1132                     if (timeout <= 0) {
1133                         ret = 0;
1134                     } else {
1135                         ret = NET_Timeout(fduse, timeout);
1136                     }
1137 
1138                     if (ret <= 0) {
1139                         if (ret == 0) {
1140                             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1141                                             "Receive timed out");
1142                         } else if (ret == -1) {
1143                             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1144                                             "Socket closed");
1145                         }
1146                         if (packetBufferLen > MAX_BUFFER_LEN) {
1147                             free(fullPacket);
1148                         }
1149                         return;
1150                     }
1151                 }
1152 
1153                 /*
1154                  * An ICMP port unreachable was received but we are
1155                  * not connected so ignore it.
1156                  */
1157                 retry = TRUE;
1158             }
1159         }
1160     } while (retry);
1161 
1162     /* truncate the data if the packet's length is too small */
1163     if (n > packetBufferLen) {
1164         n = packetBufferLen;
1165     }
1166     if (n < 0) {
1167         errorCode = WSAGetLastError();
1168         /* check to see if it's because the buffer was too small */
1169         if (errorCode == WSAEMSGSIZE) {
1170             /* it is because the buffer is too small. It's UDP, it's
1171              * unreliable, it's all good. discard the rest of the
1172              * data..
1173              */
1174             n = packetBufferLen;
1175         } else {
1176             /* failure */
1177             (*env)->SetIntField(env, packet, dp_lengthID, 0);
1178         }
1179     }
1180     if (n == -1) {
1181         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
1182     } else if (n == -2) {
1183         JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1184                         "operation interrupted");
1185     } else if (n < 0) {
1186         NET_ThrowCurrent(env, "Datagram receive failed");
1187     } else {
1188         int port = 0;
1189         jobject packetAddress;
1190 
1191         /*
1192          * Check if there is an InetAddress already associated with this
1193          * packet. If so we check if it is the same source address. We
1194          * can't update any existing InetAddress because it is immutable
1195          */
1196         packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
1197         if (packetAddress != NULL) {
1198             if (!NET_SockaddrEqualsInetAddress(env, &remote_addr,
1199                                                packetAddress)) {
1200                 /* force a new InetAddress to be created */
1201                 packetAddress = NULL;
1202             }
1203         }
1204         if (packetAddress == NULL) {
1205             packetAddress = NET_SockaddrToInetAddress(env, &remote_addr,
1206                                                       &port);
1207             /* stuff the new Inetaddress in the packet */
1208             (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
1209         } else {
1210             /* only get the new port number */
1211             port = NET_GetPortFromSockaddr(&remote_addr);
1212         }
1213         /* populate the packet */
1214         (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,
1215                                    (jbyte *)fullPacket);
1216         (*env)->SetIntField(env, packet, dp_portID, port);
1217         (*env)->SetIntField(env, packet, dp_lengthID, n);
1218     }
1219     if (packetBufferLen > MAX_BUFFER_LEN) {
1220         free(fullPacket);
1221     }
1222 }
1223 
1224 /*
1225  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
1226  * Method:    datagramSocketCreate
1227  * Signature: ()V
1228  */
1229 JNIEXPORT void JNICALL
1230 Java_java_net_TwoStacksPlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
1231                                                            jobject this) {
1232     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1233     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
1234 
1235     int fd, fd1;
1236     int t = TRUE;
1237     DWORD x1, x2; /* ignored result codes */
1238     int ipv6_supported = ipv6_available();
1239 
1240     int arg = -1;
1241 
1242     if (IS_NULL(fdObj) || (ipv6_supported && IS_NULL(fd1Obj))) {
1243         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
1244         return;
1245     } else {
1246         fd =  (int) socket (AF_INET, SOCK_DGRAM, 0);
1247     }
1248     if (fd == SOCKET_ERROR) {
1249         NET_ThrowCurrent(env, "Socket creation failed");
1250         return;
1251     }
1252     SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
1253     (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
1254     NET_SetSockOpt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
1255 
1256     if (ipv6_supported) {
1257         /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which
1258          * returns connection reset errors un connected UDP sockets (as well
1259          * as connected sockets. The solution is to only enable this feature
1260          * when the socket is connected
1261          */
1262         t = FALSE;
1263         WSAIoctl(fd,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
1264         t = TRUE;
1265         fd1 = socket (AF_INET6, SOCK_DGRAM, 0);
1266         if (fd1 == SOCKET_ERROR) {
1267             NET_ThrowCurrent(env, "Socket creation failed");
1268             return;
1269         }
1270         NET_SetSockOpt(fd1, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
1271         t = FALSE;
1272         WSAIoctl(fd1,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
1273         (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
1274         SetHandleInformation((HANDLE)(UINT_PTR)fd1, HANDLE_FLAG_INHERIT, FALSE);
1275     } else {
1276         /* drop the second fd */
1277         (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL);
1278     }
1279 }
1280 
1281 /*
1282  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
1283  * Method:    datagramSocketClose
1284  * Signature: ()V
1285  */
1286 JNIEXPORT void JNICALL
1287 Java_java_net_TwoStacksPlainDatagramSocketImpl_datagramSocketClose(JNIEnv *env,
1288                                                           jobject this) {
1289     /*
1290      * REMIND: PUT A LOCK AROUND THIS CODE
1291      */
1292     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1293     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
1294     int ipv6_supported = ipv6_available();
1295     int fd = -1, fd1 = -1;
1296 
1297     if (IS_NULL(fdObj) && (!ipv6_supported || IS_NULL(fd1Obj))) {
1298         return;
1299     }
1300 
1301     if (!IS_NULL(fdObj)) {
1302         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1303         if (fd != -1) {
1304             (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
1305             NET_SocketClose(fd);
1306         }
1307     }
1308 
1309     if (ipv6_supported && fd1Obj != NULL) {
1310         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
1311         if (fd1 == -1) {
1312             return;
1313         }
1314         (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, -1);
1315         NET_SocketClose(fd1);
1316     }
1317 }
1318 
1319 /*
1320  * check the addresses attached to the NetworkInterface object
1321  * and return the first one (of the requested family Ipv4 or Ipv6)
1322  * in *iaddr
1323  */
1324 
1325 static int getInetAddrFromIf (JNIEnv *env, int family, jobject nif, jobject *iaddr)
1326 {
1327     jobjectArray addrArray;
1328     static jfieldID ni_addrsID=0;
1329     jsize len;
1330     jobject addr;
1331     int i;
1332 
1333     if (ni_addrsID == NULL ) {
1334         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1335         CHECK_NULL_RETURN (c, -1);
1336         ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1337                                         "[Ljava/net/InetAddress;");
1338         CHECK_NULL_RETURN (ni_addrsID, -1);
1339     }
1340 
1341     addrArray = (*env)->GetObjectField(env, nif, ni_addrsID);
1342     len = (*env)->GetArrayLength(env, addrArray);
1343 
1344     /*
1345      * Check that there is at least one address bound to this
1346      * interface.
1347      */
1348     if (len < 1) {
1349         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1350             "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface");
1351         return -1;
1352     }
1353     for (i=0; i<len; i++) {
1354         int fam;
1355         addr = (*env)->GetObjectArrayElement(env, addrArray, i);
1356         fam = getInetAddress_family(env, addr);
1357         JNU_CHECK_EXCEPTION_RETURN(env, -1);
1358         if (fam == family) {
1359             *iaddr = addr;
1360             return 0;
1361         }
1362     }
1363     return -1;
1364 }
1365 
1366 static int getInet4AddrFromIf (JNIEnv *env, jobject nif, struct in_addr *iaddr)
1367 {
1368     jobject addr;
1369 
1370     int ret = getInetAddrFromIf(env, java_net_InetAddress_IPv4, nif, &addr);
1371     if (ret == -1) {
1372         return -1;
1373     }
1374 
1375     iaddr->s_addr = htonl(getInetAddress_addr(env, addr));
1376     JNU_CHECK_EXCEPTION_RETURN(env, -1);
1377     return 0;
1378 }
1379 
1380 /* Get the multicasting index from the interface */
1381 
1382 static int getIndexFromIf (JNIEnv *env, jobject nif) {
1383     static jfieldID ni_indexID = NULL;
1384 
1385     if (ni_indexID == NULL) {
1386         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1387         CHECK_NULL_RETURN(c, -1);
1388         ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1389         CHECK_NULL_RETURN(ni_indexID, -1);
1390     }
1391 
1392     return (*env)->GetIntField(env, nif, ni_indexID);
1393 }
1394 
1395 static int isAdapterIpv6Enabled(JNIEnv *env, int index) {
1396   netif *ifList, *curr;
1397   int ipv6Enabled = 0;
1398   if (getAllInterfacesAndAddresses(env, &ifList) < 0) {
1399       return ipv6Enabled;
1400   }
1401 
1402   /* search by index */
1403   curr = ifList;
1404   while (curr != NULL) {
1405       if (index == curr->index) {
1406           break;
1407       }
1408       curr = curr->next;
1409   }
1410 
1411   /* if found ipv6Index != 0 then interface is configured with IPV6 */
1412   if ((curr != NULL) && (curr->ipv6Index !=0)) {
1413       ipv6Enabled = 1;
1414   }
1415 
1416   /* release the interface list */
1417   free_netif(ifList);
1418 
1419   return ipv6Enabled;
1420 }
1421 
1422 /*
1423  * Sets the multicast interface.
1424  *
1425  * SocketOptions.IP_MULTICAST_IF (argument is an InetAddress) :-
1426  *      IPv4:   set outgoing multicast interface using
1427  *              IPPROTO_IP/IP_MULTICAST_IF
1428  *
1429  *      IPv6:   Get the interface to which the
1430  *              InetAddress is bound
1431  *              and do same as SockOptions.IF_MULTICAST_IF2
1432  *
1433  * SockOptions.IF_MULTICAST_IF2 (argument is a NetworkInterface ) :-
1434  *      For each stack:
1435  *      IPv4:   Obtain IP address bound to network interface
1436  *              (NetworkInterface.addres[0])
1437  *              set outgoing multicast interface using
1438  *              IPPROTO_IP/IP_MULTICAST_IF
1439  *
1440  *      IPv6:   Obtain NetworkInterface.index
1441  *              Set outgoing multicast interface using
1442  *              IPPROTO_IPV6/IPV6_MULTICAST_IF
1443  *
1444  */
1445 static void setMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1,
1446                                   jint opt, jobject value)
1447 {
1448     int ipv6_supported = ipv6_available();
1449 
1450     if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1451         /*
1452          * value is an InetAddress.
1453          * On IPv4 system use IP_MULTICAST_IF socket option
1454          * On IPv6 system get the NetworkInterface that this IP
1455          * address is bound to and use the IPV6_MULTICAST_IF
1456          * option instead of IP_MULTICAST_IF
1457          */
1458         if (ipv6_supported) {
1459             static jclass ni_class = NULL;
1460             if (ni_class == NULL) {
1461                 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1462                 CHECK_NULL(c);
1463                 ni_class = (*env)->NewGlobalRef(env, c);
1464                 CHECK_NULL(ni_class);
1465             }
1466 
1467             value = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, value);
1468             if (value == NULL) {
1469                 if (!(*env)->ExceptionOccurred(env)) {
1470                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1471                          "bad argument for IP_MULTICAST_IF"
1472                          ": address not bound to any interface");
1473                 }
1474                 return;
1475             }
1476             opt = java_net_SocketOptions_IP_MULTICAST_IF2;
1477         } else {
1478             struct in_addr in;
1479 
1480             in.s_addr = htonl(getInetAddress_addr(env, value));
1481             JNU_CHECK_EXCEPTION(env);
1482             if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1483                                (const char*)&in, sizeof(in)) < 0) {
1484                 JNU_ThrowByNameWithMessageAndLastError
1485                     (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1486             }
1487             return;
1488         }
1489     }
1490 
1491     if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1492         /*
1493          * value is a NetworkInterface.
1494          * On IPv6 system get the index of the interface and use the
1495          * IPV6_MULTICAST_IF socket option
1496          * On IPv4 system extract addr[0] and use the IP_MULTICAST_IF
1497          * option. For IPv6 both must be done.
1498          */
1499         if (ipv6_supported) {
1500             static jfieldID ni_indexID = NULL;
1501             struct in_addr in;
1502             int index;
1503 
1504             if (ni_indexID == NULL) {
1505                 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1506                 CHECK_NULL(c);
1507                 ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1508                 CHECK_NULL(ni_indexID);
1509             }
1510             index = (*env)->GetIntField(env, value, ni_indexID);
1511 
1512             if (isAdapterIpv6Enabled(env, index) != 0) {
1513                 if (setsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1514                                (const char*)&index, sizeof(index)) < 0) {
1515                     if (errno == EINVAL && index > 0) {
1516                         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1517                             "IPV6_MULTICAST_IF failed (interface has IPv4 "
1518                             "address only?)");
1519                     } else {
1520                         JNU_ThrowByNameWithMessageAndLastError
1521                             (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1522                     }
1523                     return;
1524                 }
1525             }
1526             /* If there are any IPv4 addresses on this interface then
1527              * repeat the operation on the IPv4 fd */
1528 
1529             if (getInet4AddrFromIf(env, value, &in) < 0) {
1530                 return;
1531             }
1532             if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1533                                (const char*)&in, sizeof(in)) < 0) {
1534                 JNU_ThrowByNameWithMessageAndLastError
1535                     (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1536             }
1537             return;
1538         } else {
1539             struct in_addr in;
1540 
1541             if (getInet4AddrFromIf (env, value, &in) < 0) {
1542                 if ((*env)->ExceptionOccurred(env)) {
1543                     return;
1544                 }
1545                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1546                         "no InetAddress instances of requested type");
1547                 return;
1548             }
1549 
1550             if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1551                                (const char*)&in, sizeof(in)) < 0) {
1552                 JNU_ThrowByNameWithMessageAndLastError
1553                     (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1554             }
1555             return;
1556         }
1557     }
1558 }
1559 
1560 /*
1561  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
1562  * Method:    socketNativeSetOption
1563  * Signature: (ILjava/lang/Object;)V
1564  */
1565 JNIEXPORT void JNICALL
1566 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketNativeSetOption
1567   (JNIEnv *env,jobject this, jint opt,jobject value)
1568 {
1569     int fd = -1, fd1 = -1;
1570     int levelv4 = 0, levelv6 = 0, optnamev4 = 0, optnamev6 = 0, optlen = 0;
1571     union {
1572         int i;
1573         char c;
1574     } optval = { 0 };
1575     int ipv6_supported = ipv6_available();
1576     fd = getFD(env, this);
1577 
1578     if (ipv6_supported) {
1579         fd1 = getFD1(env, this);
1580     }
1581     if (fd < 0 && fd1 < 0) {
1582         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
1583         return;
1584     }
1585 
1586     if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
1587         (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1588 
1589         setMulticastInterface(env, this, fd, fd1, opt, value);
1590         return;
1591     }
1592 
1593     /*
1594      * Map the Java level socket option to the platform specific
1595      * level(s) and option name(s).
1596      */
1597     if (fd1 != -1) {
1598         if (NET_MapSocketOptionV6(opt, &levelv6, &optnamev6)) {
1599             JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
1600             return;
1601         }
1602     }
1603     if (fd != -1) {
1604         if (NET_MapSocketOption(opt, &levelv4, &optnamev4)) {
1605             JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
1606             return;
1607         }
1608     }
1609 
1610     switch (opt) {
1611         case java_net_SocketOptions_SO_SNDBUF :
1612         case java_net_SocketOptions_SO_RCVBUF :
1613         case java_net_SocketOptions_IP_TOS :
1614             {
1615                 jclass cls;
1616                 jfieldID fid;
1617 
1618                 cls = (*env)->FindClass(env, "java/lang/Integer");
1619                 CHECK_NULL(cls);
1620                 fid =  (*env)->GetFieldID(env, cls, "value", "I");
1621                 CHECK_NULL(fid);
1622 
1623                 optval.i = (*env)->GetIntField(env, value, fid);
1624                 optlen = sizeof(optval.i);
1625             }
1626             break;
1627 
1628         case java_net_SocketOptions_SO_REUSEADDR:
1629         case java_net_SocketOptions_SO_BROADCAST:
1630         case java_net_SocketOptions_IP_MULTICAST_LOOP:
1631             {
1632                 jclass cls;
1633                 jfieldID fid;
1634                 jboolean on;
1635 
1636                 cls = (*env)->FindClass(env, "java/lang/Boolean");
1637                 CHECK_NULL(cls);
1638                 fid =  (*env)->GetFieldID(env, cls, "value", "Z");
1639                 CHECK_NULL(fid);
1640 
1641                 on = (*env)->GetBooleanField(env, value, fid);
1642                 optval.i = (on ? 1 : 0);
1643                 /*
1644                  * setLoopbackMode (true) disables IP_MULTICAST_LOOP rather
1645                  * than enabling it.
1646                  */
1647                 if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) {
1648                     optval.i = !optval.i;
1649                 }
1650                 optlen = sizeof(optval.i);
1651             }
1652             break;
1653 
1654         default :
1655             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1656                 "Socket option not supported by PlainDatagramSocketImp");
1657             return;
1658 
1659     }
1660 
1661     if (fd1 != -1) {
1662         if (NET_SetSockOpt(fd1, levelv6, optnamev6, (void *)&optval, optlen) < 0) {
1663             NET_ThrowCurrent(env, "setsockopt IPv6");
1664             return;
1665         }
1666     }
1667     if (fd != -1) {
1668         if (NET_SetSockOpt(fd, levelv4, optnamev4, (void *)&optval, optlen) < 0) {
1669             NET_ThrowCurrent(env, "setsockopt");
1670             return;
1671         }
1672     }
1673 }
1674 
1675 /*
1676  *
1677  * called by getMulticastInterface to retrieve a NetworkInterface
1678  * configured for IPv4.
1679  * The ipv4Mode parameter, is a closet boolean, which allows for a NULL return,
1680  * or forces the creation of a NetworkInterface object with null data.
1681  * It relates to its calling context in getMulticastInterface.
1682  * ipv4Mode == 1, the context is IPV4 processing only.
1683  * ipv4Mode == 0, the context is IPV6 processing
1684  *
1685  */
1686 static jobject getIPv4NetworkInterface (JNIEnv *env, jobject this, int fd, jint opt, int ipv4Mode) {
1687         static jclass inet4_class;
1688         static jmethodID inet4_ctrID;
1689 
1690         static jclass ni_class; static jmethodID ni_ctrID;
1691         static jfieldID ni_indexID;
1692         static jfieldID ni_addrsID;
1693 
1694         jobjectArray addrArray;
1695         jobject addr;
1696         jobject ni;
1697 
1698         struct in_addr in;
1699         struct in_addr *inP = &in;
1700         int len = sizeof(struct in_addr);
1701         if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1702                            (char *)inP, &len) < 0) {
1703             JNU_ThrowByNameWithMessageAndLastError
1704                 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
1705             return NULL;
1706         }
1707 
1708         /*
1709          * Construct and populate an Inet4Address
1710          */
1711         if (inet4_class == NULL) {
1712             jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
1713             CHECK_NULL_RETURN(c, NULL);
1714             inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1715             CHECK_NULL_RETURN(inet4_ctrID, NULL);
1716             inet4_class = (*env)->NewGlobalRef(env, c);
1717             CHECK_NULL_RETURN(inet4_class, NULL);
1718         }
1719         addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0);
1720         CHECK_NULL_RETURN(addr, NULL);
1721 
1722         setInetAddress_addr(env, addr, ntohl(in.s_addr));
1723         JNU_CHECK_EXCEPTION_RETURN(env, NULL);
1724         /*
1725          * For IP_MULTICAST_IF return InetAddress
1726          */
1727         if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1728             return addr;
1729         }
1730 
1731         /*
1732          * For IP_MULTICAST_IF2 we get the NetworkInterface for
1733          * this address and return it
1734          */
1735         if (ni_class == NULL) {
1736             jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1737             CHECK_NULL_RETURN(c, NULL);
1738             ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1739             CHECK_NULL_RETURN(ni_ctrID, NULL);
1740             ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1741             CHECK_NULL_RETURN(ni_indexID, NULL);
1742             ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1743                                             "[Ljava/net/InetAddress;");
1744             CHECK_NULL_RETURN(ni_addrsID, NULL);
1745             ni_class = (*env)->NewGlobalRef(env, c);
1746             CHECK_NULL_RETURN(ni_class, NULL);
1747         }
1748         ni = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, addr);
1749         if (ni) {
1750             return ni;
1751         }
1752         if (ipv4Mode) {
1753             ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
1754             CHECK_NULL_RETURN(ni, NULL);
1755 
1756             (*env)->SetIntField(env, ni, ni_indexID, -1);
1757             addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL);
1758             CHECK_NULL_RETURN(addrArray, NULL);
1759             (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
1760             (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
1761         } else {
1762             ni = NULL;
1763         }
1764         return ni;
1765 }
1766 
1767 /*
1768  * Return the multicast interface:
1769  *
1770  * SocketOptions.IP_MULTICAST_IF
1771  *      IPv4:   Query IPPROTO_IP/IP_MULTICAST_IF
1772  *              Create InetAddress
1773  *              IP_MULTICAST_IF returns struct ip_mreqn on 2.2
1774  *              kernel but struct in_addr on 2.4 kernel
1775  *      IPv6:   Query IPPROTO_IPV6 / IPV6_MULTICAST_IF or
1776  *              obtain from impl is Linux 2.2 kernel
1777  *              If index == 0 return InetAddress representing
1778  *              anyLocalAddress.
1779  *              If index > 0 query NetworkInterface by index
1780  *              and returns addrs[0]
1781  *
1782  * SocketOptions.IP_MULTICAST_IF2
1783  *      IPv4:   Query IPPROTO_IP/IP_MULTICAST_IF
1784  *              Query NetworkInterface by IP address and
1785  *              return the NetworkInterface that the address
1786  *              is bound too.
1787  *      IPv6:   Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
1788  *              (except Linux .2 kernel)
1789  *              Query NetworkInterface by index and
1790  *              return NetworkInterface.
1791  */
1792 jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint opt) {
1793     jboolean isIPV4 = !ipv6_available() || fd1 == -1;
1794 
1795     /*
1796      * IPv4 implementation
1797      */
1798     if (isIPV4) {
1799         jobject netObject = NULL; // return is either an addr or a netif
1800         netObject = getIPv4NetworkInterface(env, this, fd, opt, 1);
1801         return netObject;
1802     }
1803 
1804     /*
1805      * IPv6 implementation
1806      */
1807     if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
1808         (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1809 
1810         static jclass ni_class;
1811         static jmethodID ni_ctrID;
1812         static jfieldID ni_indexID;
1813         static jfieldID ni_addrsID;
1814         static jclass ia_class;
1815         static jmethodID ia_anyLocalAddressID;
1816 
1817         int index;
1818         int len = sizeof(index);
1819 
1820         jobjectArray addrArray;
1821         jobject addr;
1822         jobject ni;
1823 
1824         {
1825             if (getsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1826                                (char*)&index, &len) < 0) {
1827                 JNU_ThrowByNameWithMessageAndLastError
1828                     (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
1829                 return NULL;
1830             }
1831         }
1832 
1833         if (ni_class == NULL) {
1834             jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1835             CHECK_NULL_RETURN(c, NULL);
1836             ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1837             CHECK_NULL_RETURN(ni_ctrID, NULL);
1838             ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1839             CHECK_NULL_RETURN(ni_indexID, NULL);
1840             ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1841                                             "[Ljava/net/InetAddress;");
1842             CHECK_NULL_RETURN(ni_addrsID, NULL);
1843 
1844             ia_class = (*env)->FindClass(env, "java/net/InetAddress");
1845             CHECK_NULL_RETURN(ia_class, NULL);
1846             ia_class = (*env)->NewGlobalRef(env, ia_class);
1847             CHECK_NULL_RETURN(ia_class, NULL);
1848             ia_anyLocalAddressID = (*env)->GetStaticMethodID(env,
1849                                                              ia_class,
1850                                                              "anyLocalAddress",
1851                                                              "()Ljava/net/InetAddress;");
1852             CHECK_NULL_RETURN(ia_anyLocalAddressID, NULL);
1853             ni_class = (*env)->NewGlobalRef(env, c);
1854             CHECK_NULL_RETURN(ni_class, NULL);
1855         }
1856 
1857         /*
1858          * If multicast to a specific interface then return the
1859          * interface (for IF2) or the any address on that interface
1860          * (for IF).
1861          */
1862         if (index > 0) {
1863             ni = Java_java_net_NetworkInterface_getByIndex0(env, ni_class,
1864                                                                    index);
1865             if (ni == NULL) {
1866                 char errmsg[255];
1867                 sprintf(errmsg,
1868                         "IPV6_MULTICAST_IF returned index to unrecognized interface: %d",
1869                         index);
1870                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg);
1871                 return NULL;
1872             }
1873 
1874             /*
1875              * For IP_MULTICAST_IF2 return the NetworkInterface
1876              */
1877             if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1878                 return ni;
1879             }
1880 
1881             /*
1882              * For IP_MULTICAST_IF return addrs[0]
1883              */
1884             addrArray = (*env)->GetObjectField(env, ni, ni_addrsID);
1885             if ((*env)->GetArrayLength(env, addrArray) < 1) {
1886                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1887                     "IPV6_MULTICAST_IF returned interface without IP bindings");
1888                 return NULL;
1889             }
1890 
1891             addr = (*env)->GetObjectArrayElement(env, addrArray, 0);
1892             return addr;
1893         } else if (index == 0) { // index == 0 typically means IPv6 not configured on the interfaces
1894             // falling back to treat interface as configured for IPv4
1895             jobject netObject = NULL;
1896             netObject = getIPv4NetworkInterface(env, this, fd, opt, 0);
1897             if (netObject != NULL) {
1898                 return netObject;
1899             }
1900         }
1901 
1902         /*
1903          * Multicast to any address - return anyLocalAddress
1904          * or a NetworkInterface with addrs[0] set to anyLocalAddress
1905          */
1906 
1907         addr = (*env)->CallStaticObjectMethod(env, ia_class, ia_anyLocalAddressID,
1908                                               NULL);
1909         if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1910             return addr;
1911         }
1912 
1913         ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
1914         CHECK_NULL_RETURN(ni, NULL);
1915         (*env)->SetIntField(env, ni, ni_indexID, -1);
1916         addrArray = (*env)->NewObjectArray(env, 1, ia_class, NULL);
1917         CHECK_NULL_RETURN(addrArray, NULL);
1918         (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
1919         (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
1920         return ni;
1921     }
1922     return NULL;
1923 }
1924 
1925 
1926 /*
1927  * Returns relevant info as a jint.
1928  *
1929  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
1930  * Method:    socketGetOption
1931  * Signature: (I)Ljava/lang/Object;
1932  */
1933 JNIEXPORT jobject JNICALL
1934 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketGetOption
1935   (JNIEnv *env, jobject this, jint opt)
1936 {
1937     int fd = -1, fd1 = -1;
1938     int level, optname, optlen;
1939     union {
1940         int i;
1941     } optval = {0};
1942     int ipv6_supported = ipv6_available();
1943 
1944     fd = getFD(env, this);
1945     if (ipv6_supported) {
1946         fd1 = getFD1(env, this);
1947     }
1948 
1949     if (fd < 0 && fd1 < 0) {
1950         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1951                         "Socket closed");
1952         return NULL;
1953     }
1954 
1955     /*
1956      * Handle IP_MULTICAST_IF separately
1957      */
1958     if (opt == java_net_SocketOptions_IP_MULTICAST_IF ||
1959         opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1960         return getMulticastInterface(env, this, fd, fd1, opt);
1961     }
1962 
1963     /*
1964      * Map the Java level socket option to the platform specific
1965      * level and option name.
1966      */
1967     if (NET_MapSocketOption(opt, &level, &optname)) {
1968         JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
1969         return NULL;
1970     }
1971 
1972     if (fd == -1) {
1973         if (NET_MapSocketOptionV6(opt, &level, &optname)) {
1974             JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
1975             return NULL;
1976         }
1977         fd = fd1; /* must be IPv6 only */
1978     }
1979 
1980     optlen = sizeof(optval.i);
1981     if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
1982         char tmpbuf[255];
1983         int size = 0;
1984         char errmsg[255 + 31];
1985         getErrorString(errno, tmpbuf, sizeof(tmpbuf));
1986         sprintf(errmsg, "error getting socket option: %s", tmpbuf);
1987         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg);
1988         return NULL;
1989     }
1990 
1991     switch (opt) {
1992         case java_net_SocketOptions_SO_BROADCAST:
1993         case java_net_SocketOptions_SO_REUSEADDR:
1994             return createBoolean(env, optval.i);
1995 
1996         case java_net_SocketOptions_IP_MULTICAST_LOOP:
1997             /* getLoopbackMode() returns true if IP_MULTICAST_LOOP is disabled */
1998             return createBoolean(env, !optval.i);
1999 
2000         case java_net_SocketOptions_SO_SNDBUF:
2001         case java_net_SocketOptions_SO_RCVBUF:
2002         case java_net_SocketOptions_IP_TOS:
2003             return createInteger(env, optval.i);
2004 
2005         default :
2006             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2007                 "Socket option not supported by TwoStacksPlainDatagramSocketImpl");
2008             return NULL;
2009 
2010     }
2011 }
2012 
2013 /*
2014  * Returns local address of the socket.
2015  *
2016  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2017  * Method:    socketLocalAddress
2018  * Signature: (I)Ljava/lang/Object;
2019  */
2020 JNIEXPORT jobject JNICALL
2021 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketLocalAddress
2022   (JNIEnv *env, jobject this, jint family)
2023 {
2024     int fd = -1, fd1 = -1;
2025     SOCKETADDRESS sa;
2026     int len = 0;
2027     int port;
2028     jobject iaObj;
2029     int ipv6_supported = ipv6_available();
2030 
2031     fd = getFD(env, this);
2032     if (ipv6_supported) {
2033         fd1 = getFD1(env, this);
2034     }
2035 
2036     if (fd < 0 && fd1 < 0) {
2037         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2038                         "Socket closed");
2039         return NULL;
2040     }
2041 
2042     /* find out local IP address */
2043 
2044     len = sizeof(struct sockaddr_in);
2045 
2046     /* family==-1 when socket is not connected */
2047     if ((family == java_net_InetAddress_IPv6) || (family == -1 && fd == -1)) {
2048         fd = fd1; /* must be IPv6 only */
2049         len = sizeof(struct sockaddr_in6);
2050     }
2051 
2052     if (fd == -1) {
2053         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2054                         "Socket closed");
2055         return NULL;
2056     }
2057 
2058     if (getsockname(fd, &sa.sa, &len) == -1) {
2059         JNU_ThrowByNameWithMessageAndLastError
2060             (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
2061         return NULL;
2062     }
2063     iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
2064 
2065     return iaObj;
2066 }
2067 
2068 /*
2069  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2070  * Method:    setTimeToLive
2071  * Signature: (I)V
2072  */
2073 JNIEXPORT void JNICALL
2074 Java_java_net_TwoStacksPlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this,
2075                                                     jint ttl) {
2076 
2077     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2078     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2079     int fd = -1, fd1 = -1;
2080     int ittl = (int)ttl;
2081 
2082     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
2083         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2084                         "Socket closed");
2085         return;
2086     } else {
2087       if (!IS_NULL(fdObj)) {
2088         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
2089       }
2090       if (!IS_NULL(fd1Obj)) {
2091         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2092       }
2093     }
2094 
2095     /* setsockopt to be correct ttl */
2096     if (fd >= 0) {
2097       if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
2098                          sizeof (ittl)) < 0) {
2099         NET_ThrowCurrent(env, "set IP_MULTICAST_TTL failed");
2100         return;
2101       }
2102     }
2103 
2104     if (fd1 >= 0) {
2105       if (NET_SetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&ittl,
2106                          sizeof(ittl)) <0) {
2107         NET_ThrowCurrent(env, "set IPV6_MULTICAST_HOPS failed");
2108       }
2109     }
2110 }
2111 
2112 /*
2113  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2114  * Method:    setTTL
2115  * Signature: (B)V
2116  */
2117 JNIEXPORT void JNICALL
2118 Java_java_net_TwoStacksPlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this,
2119                                              jbyte ttl) {
2120     Java_java_net_TwoStacksPlainDatagramSocketImpl_setTimeToLive(env, this,
2121                                                         (jint)ttl & 0xFF);
2122 }
2123 
2124 /*
2125  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2126  * Method:    getTimeToLive
2127  * Signature: ()I
2128  */
2129 JNIEXPORT jint JNICALL
2130 Java_java_net_TwoStacksPlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) {
2131     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2132     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2133     int fd = -1, fd1 = -1;
2134     int ttl = 0;
2135     int len = sizeof(ttl);
2136 
2137     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
2138         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2139                         "Socket closed");
2140         return -1;
2141     } else {
2142       if (!IS_NULL(fdObj)) {
2143         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
2144       }
2145       if (!IS_NULL(fd1Obj)) {
2146         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2147       }
2148     }
2149 
2150     /* getsockopt of ttl */
2151     if (fd >= 0) {
2152       if (NET_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, &len) < 0) {
2153         NET_ThrowCurrent(env, "get IP_MULTICAST_TTL failed");
2154         return -1;
2155       }
2156       return (jint)ttl;
2157     }
2158     if (fd1 >= 0) {
2159       if (NET_GetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char*)&ttl, &len) < 0) {
2160         NET_ThrowCurrent(env, "get IP_MULTICAST_TTL failed");
2161         return -1;
2162       }
2163       return (jint)ttl;
2164     }
2165     return -1;
2166 }
2167 
2168 /*
2169  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2170  * Method:    getTTL
2171  * Signature: ()B
2172  */
2173 JNIEXPORT jbyte JNICALL
2174 Java_java_net_TwoStacksPlainDatagramSocketImpl_getTTL(JNIEnv *env, jobject this) {
2175     int result = Java_java_net_TwoStacksPlainDatagramSocketImpl_getTimeToLive(env, this);
2176 
2177     return (jbyte)result;
2178 }
2179 
2180 /* join/leave the named group on the named interface, or if no interface specified
2181  * then the interface set with setInterfac(), or the default interface otherwise */
2182 
2183 static void mcast_join_leave(JNIEnv *env, jobject this,
2184                              jobject iaObj, jobject niObj,
2185                              jboolean join)
2186 {
2187     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2188     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2189     jint fd = -1, fd1 = -1;
2190 
2191     SOCKETADDRESS name;
2192     struct ip_mreq mname;
2193     struct ipv6_mreq mname6;
2194 
2195     struct in_addr in;
2196     DWORD ifindex = 0;
2197 
2198     int len, family;
2199     int ipv6_supported = ipv6_available();
2200     int cmd;
2201 
2202     memset((char *)&in, 0, sizeof(in));
2203     memset((char *)&name, 0, sizeof(name));
2204 
2205     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
2206         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2207                         "Socket closed");
2208         return;
2209     }
2210     if (!IS_NULL(fdObj)) {
2211         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
2212     }
2213     if (ipv6_supported && !IS_NULL(fd1Obj)) {
2214         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2215     }
2216 
2217     if (IS_NULL(iaObj)) {
2218         JNU_ThrowNullPointerException(env, "address");
2219         return;
2220     }
2221 
2222     if (NET_InetAddressToSockaddr(env, iaObj, 0, &name, &len, JNI_FALSE) != 0) {
2223       return;
2224     }
2225 
2226     /* Set the multicast group address in the ip_mreq field
2227      * eventually this check should be done by the security manager
2228      */
2229     family = name.sa.sa_family;
2230 
2231     if (family == AF_INET) {
2232         int address = name.sa4.sin_addr.s_addr;
2233         if (!IN_MULTICAST(ntohl(address))) {
2234             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "not in multicast");
2235             return;
2236         }
2237         mname.imr_multiaddr.s_addr = address;
2238         if (fd < 0) {
2239           JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Can't join an IPv4 group on an IPv6 only socket");
2240           return;
2241         }
2242         if (IS_NULL(niObj)) {
2243             len = sizeof(in);
2244             if (NET_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
2245                            (char *)&in, &len) < 0) {
2246                 NET_ThrowCurrent(env, "get IP_MULTICAST_IF failed");
2247                 return;
2248             }
2249             mname.imr_interface.s_addr = in.s_addr;
2250         } else {
2251             if (getInet4AddrFromIf (env, niObj, &mname.imr_interface) != 0) {
2252                 NET_ThrowCurrent(env, "no Inet4Address associated with interface");
2253                 return;
2254             }
2255         }
2256 
2257         cmd = join ? IP_ADD_MEMBERSHIP: IP_DROP_MEMBERSHIP;
2258 
2259         /* Join the multicast group */
2260         if (NET_SetSockOpt(fd, IPPROTO_IP, cmd, (char *) &mname, sizeof (mname)) < 0) {
2261             if (WSAGetLastError() == WSAENOBUFS) {
2262                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2263                     "IP_ADD_MEMBERSHIP failed (out of hardware filters?)");
2264             } else {
2265                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException","error setting options");
2266             }
2267         }
2268     } else /* AF_INET6 */ {
2269         if (ipv6_supported) {
2270             struct in6_addr *address;
2271             address = &name.sa6.sin6_addr;
2272             if (!IN6_IS_ADDR_MULTICAST(address)) {
2273                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "not in6 multicast");
2274                 return;
2275             }
2276             mname6.ipv6mr_multiaddr = *address;
2277         } else {
2278             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "IPv6 not supported");
2279             return;
2280         }
2281         if (fd1 < 0) {
2282           JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Can't join an IPv6 group on a IPv4 socket");
2283           return;
2284         }
2285         if (IS_NULL(niObj)) {
2286             len = sizeof (ifindex);
2287             if (NET_GetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, &len) < 0) {
2288                 NET_ThrowCurrent(env, "get IPV6_MULTICAST_IF failed");
2289                 return;
2290             }
2291         } else {
2292             ifindex = getIndexFromIf (env, niObj);
2293             if (ifindex == -1) {
2294                 if ((*env)->ExceptionOccurred(env)) {
2295                     return;
2296                 }
2297                 NET_ThrowCurrent(env, "get ifindex failed");
2298                 return;
2299             }
2300         }
2301         mname6.ipv6mr_interface = ifindex;
2302         cmd = join ? IPV6_ADD_MEMBERSHIP: IPV6_DROP_MEMBERSHIP;
2303 
2304         /* Join the multicast group */
2305         if (NET_SetSockOpt(fd1, IPPROTO_IPV6, cmd, (char *) &mname6, sizeof (mname6)) < 0) {
2306             if (WSAGetLastError() == WSAENOBUFS) {
2307                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2308                     "IP_ADD_MEMBERSHIP failed (out of hardware filters?)");
2309             } else {
2310                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException","error setting options");
2311             }
2312         }
2313     }
2314 
2315     return;
2316 }
2317 
2318 /*
2319  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2320  * Method:    join
2321  * Signature: (Ljava/net/InetAddress;)V
2322  */
2323 JNIEXPORT void JNICALL
2324 Java_java_net_TwoStacksPlainDatagramSocketImpl_join(JNIEnv *env, jobject this,
2325                                            jobject iaObj, jobject niObj)
2326 {
2327     mcast_join_leave (env, this, iaObj, niObj, JNI_TRUE);
2328 }
2329 
2330 /*
2331  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2332  * Method:    leave
2333  * Signature: (Ljava/net/InetAddress;)V
2334  */
2335 JNIEXPORT void JNICALL
2336 Java_java_net_TwoStacksPlainDatagramSocketImpl_leave(JNIEnv *env, jobject this,
2337                                             jobject iaObj, jobject niObj)
2338 {
2339     mcast_join_leave (env, this, iaObj, niObj, JNI_FALSE);
2340 }
2341 
2342 /*
2343  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2344  * Method:    dataAvailable
2345  * Signature: ()I
2346  */
2347 JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainDatagramSocketImpl_dataAvailable
2348 (JNIEnv *env, jobject this) {
2349     SOCKET fd;
2350     SOCKET fd1;
2351     int  rv = -1, rv1 = -1;
2352     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2353     jobject fd1Obj;
2354 
2355     if (!IS_NULL(fdObj)) {
2356         int retval = 0;
2357         fd = (SOCKET)(*env)->GetIntField(env, fdObj, IO_fd_fdID);
2358         rv = ioctlsocket(fd, FIONREAD, &retval);
2359         if (retval > 0) {
2360             return retval;
2361         }
2362     }
2363 
2364     fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2365     if (!IS_NULL(fd1Obj)) {
2366         int retval = 0;
2367         fd1 = (SOCKET)(*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2368         rv1 = ioctlsocket(fd1, FIONREAD, &retval);
2369         if (retval > 0) {
2370             return retval;
2371         }
2372     }
2373 
2374     if (rv < 0 && rv1 < 0) {
2375         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2376                         "Socket closed");
2377         return -1;
2378     }
2379 
2380     return 0;
2381 }