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 = ∈
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