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