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