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