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