1 /*
2 * Copyright (c) 1997, 2019, 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: send0
419 * Signature: (Ljava/net/DatagramPacket;)V
420 */
421 JNIEXPORT void JNICALL
Java_java_net_TwoStacksPlainDatagramSocketImpl_send0(JNIEnv * env,jobject this,jobject packet)422 Java_java_net_TwoStacksPlainDatagramSocketImpl_send0
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 && fd1 >= 0) {
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 && fd1 >= 0) {
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 if (isAdapterIpv6Enabled(env, index) != 0) {
1512 if (setsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1513 (const char*)&index, sizeof(index)) < 0) {
1514 if (errno == EINVAL && index > 0) {
1515 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1516 "IPV6_MULTICAST_IF failed (interface has IPv4 "
1517 "address only?)");
1518 } else {
1519 JNU_ThrowByNameWithMessageAndLastError
1520 (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1521 }
1522 return;
1523 }
1524 }
1525 if (fd >= 0) {
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 }
1538 return;
1539 } else {
1540 struct in_addr in;
1541
1542 if (getInet4AddrFromIf (env, value, &in) < 0) {
1543 if ((*env)->ExceptionOccurred(env)) {
1544 return;
1545 }
1546 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1547 "no InetAddress instances of requested type");
1548 return;
1549 }
1550
1551 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1552 (const char*)&in, sizeof(in)) < 0) {
1553 JNU_ThrowByNameWithMessageAndLastError
1554 (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1555 }
1556 return;
1557 }
1558 }
1559 }
1560
1561 /*
1562 * Class: java_net_TwoStacksPlainDatagramSocketImpl
1563 * Method: socketNativeSetOption
1564 * Signature: (ILjava/lang/Object;)V
1565 */
1566 JNIEXPORT void JNICALL
Java_java_net_TwoStacksPlainDatagramSocketImpl_socketNativeSetOption(JNIEnv * env,jobject this,jint opt,jobject value)1567 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketNativeSetOption
1568 (JNIEnv *env,jobject this, jint opt,jobject value)
1569 {
1570 int fd = -1, fd1 = -1;
1571 int levelv4 = 0, levelv6 = 0, optnamev4 = 0, optnamev6 = 0, optlen = 0;
1572 union {
1573 int i;
1574 char c;
1575 } optval = { 0 };
1576 int ipv6_supported = ipv6_available();
1577 fd = getFD(env, this);
1578
1579 if (ipv6_supported) {
1580 fd1 = getFD1(env, this);
1581 }
1582 if (fd < 0 && fd1 < 0) {
1583 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
1584 return;
1585 }
1586
1587 if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
1588 (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1589
1590 setMulticastInterface(env, this, fd, fd1, opt, value);
1591 return;
1592 }
1593
1594 /*
1595 * Map the Java level socket option to the platform specific
1596 * level(s) and option name(s).
1597 */
1598 if (fd1 != -1) {
1599 if (NET_MapSocketOptionV6(opt, &levelv6, &optnamev6)) {
1600 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
1601 return;
1602 }
1603 }
1604 if (fd != -1) {
1605 if (NET_MapSocketOption(opt, &levelv4, &optnamev4)) {
1606 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
1607 return;
1608 }
1609 }
1610
1611 switch (opt) {
1612 case java_net_SocketOptions_SO_SNDBUF :
1613 case java_net_SocketOptions_SO_RCVBUF :
1614 case java_net_SocketOptions_IP_TOS :
1615 {
1616 jclass cls;
1617 jfieldID fid;
1618
1619 cls = (*env)->FindClass(env, "java/lang/Integer");
1620 CHECK_NULL(cls);
1621 fid = (*env)->GetFieldID(env, cls, "value", "I");
1622 CHECK_NULL(fid);
1623
1624 optval.i = (*env)->GetIntField(env, value, fid);
1625 optlen = sizeof(optval.i);
1626 }
1627 break;
1628
1629 case java_net_SocketOptions_SO_REUSEADDR:
1630 case java_net_SocketOptions_SO_BROADCAST:
1631 case java_net_SocketOptions_IP_MULTICAST_LOOP:
1632 {
1633 jclass cls;
1634 jfieldID fid;
1635 jboolean on;
1636
1637 cls = (*env)->FindClass(env, "java/lang/Boolean");
1638 CHECK_NULL(cls);
1639 fid = (*env)->GetFieldID(env, cls, "value", "Z");
1640 CHECK_NULL(fid);
1641
1642 on = (*env)->GetBooleanField(env, value, fid);
1643 optval.i = (on ? 1 : 0);
1644 /*
1645 * setLoopbackMode (true) disables IP_MULTICAST_LOOP rather
1646 * than enabling it.
1647 */
1648 if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) {
1649 optval.i = !optval.i;
1650 }
1651 optlen = sizeof(optval.i);
1652 }
1653 break;
1654
1655 default :
1656 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1657 "Socket option not supported by PlainDatagramSocketImp");
1658 return;
1659
1660 }
1661
1662 if (fd1 != -1) {
1663 if (NET_SetSockOpt(fd1, levelv6, optnamev6, (void *)&optval, optlen) < 0) {
1664 NET_ThrowCurrent(env, "setsockopt IPv6");
1665 return;
1666 }
1667 }
1668 if (fd != -1) {
1669 if (NET_SetSockOpt(fd, levelv4, optnamev4, (void *)&optval, optlen) < 0) {
1670 NET_ThrowCurrent(env, "setsockopt");
1671 return;
1672 }
1673 }
1674 }
1675
1676 /*
1677 *
1678 * called by getMulticastInterface to retrieve a NetworkInterface
1679 * configured for IPv4.
1680 * The ipv4Mode parameter, is a closet boolean, which allows for a NULL return,
1681 * or forces the creation of a NetworkInterface object with null data.
1682 * It relates to its calling context in getMulticastInterface.
1683 * ipv4Mode == 1, the context is IPV4 processing only.
1684 * ipv4Mode == 0, the context is IPV6 processing
1685 *
1686 */
getIPv4NetworkInterface(JNIEnv * env,jobject this,int fd,jint opt,int ipv4Mode)1687 static jobject getIPv4NetworkInterface (JNIEnv *env, jobject this, int fd, jint opt, int ipv4Mode) {
1688 static jclass inet4_class;
1689 static jmethodID inet4_ctrID;
1690
1691 static jclass ni_class; static jmethodID ni_ctrID;
1692 static jfieldID ni_indexID;
1693 static jfieldID ni_addrsID;
1694
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 return NULL;
1753 }
1754
1755 /*
1756 * Return the multicast interface:
1757 *
1758 * SocketOptions.IP_MULTICAST_IF
1759 * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
1760 * Create InetAddress
1761 * IP_MULTICAST_IF returns struct ip_mreqn on 2.2
1762 * kernel but struct in_addr on 2.4 kernel
1763 * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF or
1764 * obtain from impl is Linux 2.2 kernel
1765 * If index == 0 return InetAddress representing
1766 * anyLocalAddress.
1767 * If index > 0 query NetworkInterface by index
1768 * and returns addrs[0]
1769 *
1770 * SocketOptions.IP_MULTICAST_IF2
1771 * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
1772 * Query NetworkInterface by IP address and
1773 * return the NetworkInterface that the address
1774 * is bound too.
1775 * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
1776 * (except Linux .2 kernel)
1777 * Query NetworkInterface by index and
1778 * return NetworkInterface.
1779 */
getMulticastInterface(JNIEnv * env,jobject this,int fd,int fd1,jint opt)1780 jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint opt) {
1781 jboolean isIPV4 = !ipv6_available() || fd1 == -1;
1782
1783 /*
1784 * IPv4 implementation
1785 */
1786 if (isIPV4) {
1787 jobject netObject = NULL; // return is either an addr or a netif
1788 netObject = getIPv4NetworkInterface(env, this, fd, opt, 1);
1789 return netObject;
1790 }
1791
1792 /*
1793 * IPv6 implementation
1794 */
1795 if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
1796 (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1797
1798 static jclass ni_class;
1799 static jmethodID ni_ctrID;
1800 static jfieldID ni_indexID;
1801 static jfieldID ni_addrsID;
1802 static jclass ia_class;
1803 static jmethodID ia_anyLocalAddressID;
1804
1805 int index;
1806 int len = sizeof(index);
1807
1808 jobjectArray addrArray;
1809 jobject addr;
1810 jobject ni;
1811
1812 {
1813 if (getsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1814 (char*)&index, &len) < 0) {
1815 JNU_ThrowByNameWithMessageAndLastError
1816 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
1817 return NULL;
1818 }
1819 }
1820
1821 if (ni_class == NULL) {
1822 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1823 CHECK_NULL_RETURN(c, NULL);
1824 ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1825 CHECK_NULL_RETURN(ni_ctrID, NULL);
1826 ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1827 CHECK_NULL_RETURN(ni_indexID, NULL);
1828 ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1829 "[Ljava/net/InetAddress;");
1830 CHECK_NULL_RETURN(ni_addrsID, NULL);
1831
1832 ia_class = (*env)->FindClass(env, "java/net/InetAddress");
1833 CHECK_NULL_RETURN(ia_class, NULL);
1834 ia_class = (*env)->NewGlobalRef(env, ia_class);
1835 CHECK_NULL_RETURN(ia_class, NULL);
1836 ia_anyLocalAddressID = (*env)->GetStaticMethodID(env,
1837 ia_class,
1838 "anyLocalAddress",
1839 "()Ljava/net/InetAddress;");
1840 CHECK_NULL_RETURN(ia_anyLocalAddressID, NULL);
1841 ni_class = (*env)->NewGlobalRef(env, c);
1842 CHECK_NULL_RETURN(ni_class, NULL);
1843 }
1844
1845 /*
1846 * If multicast to a specific interface then return the
1847 * interface (for IF2) or the any address on that interface
1848 * (for IF).
1849 */
1850 if (index > 0) {
1851 ni = Java_java_net_NetworkInterface_getByIndex0(env, ni_class,
1852 index);
1853 if (ni == NULL) {
1854 char errmsg[255];
1855 sprintf(errmsg,
1856 "IPV6_MULTICAST_IF returned index to unrecognized interface: %d",
1857 index);
1858 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg);
1859 return NULL;
1860 }
1861
1862 /*
1863 * For IP_MULTICAST_IF2 return the NetworkInterface
1864 */
1865 if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1866 return ni;
1867 }
1868
1869 /*
1870 * For IP_MULTICAST_IF return addrs[0]
1871 */
1872 addrArray = (*env)->GetObjectField(env, ni, ni_addrsID);
1873 if ((*env)->GetArrayLength(env, addrArray) < 1) {
1874 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1875 "IPV6_MULTICAST_IF returned interface without IP bindings");
1876 return NULL;
1877 }
1878
1879 addr = (*env)->GetObjectArrayElement(env, addrArray, 0);
1880 return addr;
1881 } else if (index == 0 && fd >= 0) {
1882 // falling back to treat interface as configured for IPv4
1883 jobject netObject = NULL;
1884 netObject = getIPv4NetworkInterface(env, this, fd, opt, 0);
1885 if (netObject != NULL) {
1886 return netObject;
1887 }
1888 }
1889 }
1890 return NULL;
1891 }
1892
1893
1894 /*
1895 * Returns relevant info as a jint.
1896 *
1897 * Class: java_net_TwoStacksPlainDatagramSocketImpl
1898 * Method: socketGetOption
1899 * Signature: (I)Ljava/lang/Object;
1900 */
1901 JNIEXPORT jobject JNICALL
Java_java_net_TwoStacksPlainDatagramSocketImpl_socketGetOption(JNIEnv * env,jobject this,jint opt)1902 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketGetOption
1903 (JNIEnv *env, jobject this, jint opt)
1904 {
1905 int fd = -1, fd1 = -1;
1906 int level, optname, optlen;
1907 union {
1908 int i;
1909 } optval = {0};
1910 int ipv6_supported = ipv6_available();
1911
1912 fd = getFD(env, this);
1913 if (ipv6_supported) {
1914 fd1 = getFD1(env, this);
1915 }
1916
1917 if (fd < 0 && fd1 < 0) {
1918 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1919 "Socket closed");
1920 return NULL;
1921 }
1922
1923 /*
1924 * Handle IP_MULTICAST_IF separately
1925 */
1926 if (opt == java_net_SocketOptions_IP_MULTICAST_IF ||
1927 opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1928 return getMulticastInterface(env, this, fd, fd1, opt);
1929 }
1930
1931 /*
1932 * Map the Java level socket option to the platform specific
1933 * level and option name.
1934 */
1935 if (NET_MapSocketOption(opt, &level, &optname)) {
1936 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
1937 return NULL;
1938 }
1939
1940 if (fd == -1) {
1941 if (NET_MapSocketOptionV6(opt, &level, &optname)) {
1942 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
1943 return NULL;
1944 }
1945 fd = fd1; /* must be IPv6 only */
1946 }
1947
1948 optlen = sizeof(optval.i);
1949 if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
1950 char tmpbuf[255];
1951 int size = 0;
1952 char errmsg[255 + 31];
1953 getErrorString(errno, tmpbuf, sizeof(tmpbuf));
1954 sprintf(errmsg, "error getting socket option: %s", tmpbuf);
1955 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg);
1956 return NULL;
1957 }
1958
1959 switch (opt) {
1960 case java_net_SocketOptions_SO_BROADCAST:
1961 case java_net_SocketOptions_SO_REUSEADDR:
1962 return createBoolean(env, optval.i);
1963
1964 case java_net_SocketOptions_IP_MULTICAST_LOOP:
1965 /* getLoopbackMode() returns true if IP_MULTICAST_LOOP is disabled */
1966 return createBoolean(env, !optval.i);
1967
1968 case java_net_SocketOptions_SO_SNDBUF:
1969 case java_net_SocketOptions_SO_RCVBUF:
1970 case java_net_SocketOptions_IP_TOS:
1971 return createInteger(env, optval.i);
1972
1973 default :
1974 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1975 "Socket option not supported by TwoStacksPlainDatagramSocketImpl");
1976 return NULL;
1977
1978 }
1979 }
1980
1981 /*
1982 * Returns local address of the socket.
1983 *
1984 * Class: java_net_TwoStacksPlainDatagramSocketImpl
1985 * Method: socketLocalAddress
1986 * Signature: (I)Ljava/lang/Object;
1987 */
1988 JNIEXPORT jobject JNICALL
Java_java_net_TwoStacksPlainDatagramSocketImpl_socketLocalAddress(JNIEnv * env,jobject this,jint family)1989 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketLocalAddress
1990 (JNIEnv *env, jobject this, jint family)
1991 {
1992 int fd = -1, fd1 = -1;
1993 SOCKETADDRESS sa;
1994 int len = 0;
1995 int port;
1996 jobject iaObj;
1997 int ipv6_supported = ipv6_available();
1998
1999 fd = getFD(env, this);
2000 if (ipv6_supported) {
2001 fd1 = getFD1(env, this);
2002 }
2003
2004 if (fd < 0 && fd1 < 0) {
2005 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2006 "Socket closed");
2007 return NULL;
2008 }
2009
2010 /* find out local IP address */
2011
2012 len = sizeof(struct sockaddr_in);
2013
2014 /* family==-1 when socket is not connected */
2015 if ((family == java_net_InetAddress_IPv6) || (family == -1 && fd == -1)) {
2016 fd = fd1; /* must be IPv6 only */
2017 len = sizeof(struct sockaddr_in6);
2018 }
2019
2020 if (fd == -1) {
2021 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2022 "Socket closed");
2023 return NULL;
2024 }
2025
2026 if (getsockname(fd, &sa.sa, &len) == -1) {
2027 JNU_ThrowByNameWithMessageAndLastError
2028 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
2029 return NULL;
2030 }
2031 iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
2032
2033 return iaObj;
2034 }
2035
2036 /*
2037 * Class: java_net_TwoStacksPlainDatagramSocketImpl
2038 * Method: setTimeToLive
2039 * Signature: (I)V
2040 */
2041 JNIEXPORT void JNICALL
Java_java_net_TwoStacksPlainDatagramSocketImpl_setTimeToLive(JNIEnv * env,jobject this,jint ttl)2042 Java_java_net_TwoStacksPlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this,
2043 jint ttl) {
2044
2045 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2046 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2047 int fd = -1, fd1 = -1;
2048 int ittl = (int)ttl;
2049
2050 if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
2051 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2052 "Socket closed");
2053 return;
2054 } else {
2055 if (!IS_NULL(fdObj)) {
2056 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
2057 }
2058 if (!IS_NULL(fd1Obj)) {
2059 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2060 }
2061 }
2062
2063 /* setsockopt to be correct ttl */
2064 if (fd >= 0) {
2065 if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
2066 sizeof (ittl)) < 0) {
2067 NET_ThrowCurrent(env, "set IP_MULTICAST_TTL failed");
2068 return;
2069 }
2070 }
2071
2072 if (fd1 >= 0) {
2073 if (NET_SetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&ittl,
2074 sizeof(ittl)) <0) {
2075 NET_ThrowCurrent(env, "set IPV6_MULTICAST_HOPS failed");
2076 }
2077 }
2078 }
2079
2080 /*
2081 * Class: java_net_TwoStacksPlainDatagramSocketImpl
2082 * Method: setTTL
2083 * Signature: (B)V
2084 */
2085 JNIEXPORT void JNICALL
Java_java_net_TwoStacksPlainDatagramSocketImpl_setTTL(JNIEnv * env,jobject this,jbyte ttl)2086 Java_java_net_TwoStacksPlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this,
2087 jbyte ttl) {
2088 Java_java_net_TwoStacksPlainDatagramSocketImpl_setTimeToLive(env, this,
2089 (jint)ttl & 0xFF);
2090 }
2091
2092 /*
2093 * Class: java_net_TwoStacksPlainDatagramSocketImpl
2094 * Method: getTimeToLive
2095 * Signature: ()I
2096 */
2097 JNIEXPORT jint JNICALL
Java_java_net_TwoStacksPlainDatagramSocketImpl_getTimeToLive(JNIEnv * env,jobject this)2098 Java_java_net_TwoStacksPlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) {
2099 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2100 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2101 int fd = -1, fd1 = -1;
2102 int ttl = 0;
2103 int len = sizeof(ttl);
2104
2105 if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
2106 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2107 "Socket closed");
2108 return -1;
2109 } else {
2110 if (!IS_NULL(fdObj)) {
2111 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
2112 }
2113 if (!IS_NULL(fd1Obj)) {
2114 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2115 }
2116 }
2117
2118 /* getsockopt of ttl */
2119 if (fd >= 0) {
2120 if (NET_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, &len) < 0) {
2121 NET_ThrowCurrent(env, "get IP_MULTICAST_TTL failed");
2122 return -1;
2123 }
2124 return (jint)ttl;
2125 }
2126 if (fd1 >= 0) {
2127 if (NET_GetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char*)&ttl, &len) < 0) {
2128 NET_ThrowCurrent(env, "get IP_MULTICAST_TTL failed");
2129 return -1;
2130 }
2131 return (jint)ttl;
2132 }
2133 return -1;
2134 }
2135
2136 /*
2137 * Class: java_net_TwoStacksPlainDatagramSocketImpl
2138 * Method: getTTL
2139 * Signature: ()B
2140 */
2141 JNIEXPORT jbyte JNICALL
Java_java_net_TwoStacksPlainDatagramSocketImpl_getTTL(JNIEnv * env,jobject this)2142 Java_java_net_TwoStacksPlainDatagramSocketImpl_getTTL(JNIEnv *env, jobject this) {
2143 int result = Java_java_net_TwoStacksPlainDatagramSocketImpl_getTimeToLive(env, this);
2144
2145 return (jbyte)result;
2146 }
2147
2148 /* join/leave the named group on the named interface, or if no interface specified
2149 * then the interface set with setInterfac(), or the default interface otherwise */
2150
mcast_join_leave(JNIEnv * env,jobject this,jobject iaObj,jobject niObj,jboolean join)2151 static void mcast_join_leave(JNIEnv *env, jobject this,
2152 jobject iaObj, jobject niObj,
2153 jboolean join)
2154 {
2155 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2156 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2157 jint fd = -1, fd1 = -1;
2158
2159 SOCKETADDRESS name;
2160 struct ip_mreq mname;
2161 struct ipv6_mreq mname6;
2162
2163 struct in_addr in;
2164 DWORD ifindex = 0;
2165
2166 int len, family;
2167 int ipv6_supported = ipv6_available();
2168 int cmd;
2169
2170 memset((char *)&in, 0, sizeof(in));
2171 memset((char *)&name, 0, sizeof(name));
2172
2173 if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
2174 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2175 "Socket closed");
2176 return;
2177 }
2178 if (!IS_NULL(fdObj)) {
2179 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
2180 }
2181 if (ipv6_supported && !IS_NULL(fd1Obj)) {
2182 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2183 }
2184
2185 if (IS_NULL(iaObj)) {
2186 JNU_ThrowNullPointerException(env, "address");
2187 return;
2188 }
2189
2190 if (NET_InetAddressToSockaddr(env, iaObj, 0, &name, &len, JNI_FALSE) != 0) {
2191 return;
2192 }
2193
2194 /* Set the multicast group address in the ip_mreq field
2195 * eventually this check should be done by the security manager
2196 */
2197 family = name.sa.sa_family;
2198
2199 if (family == AF_INET) {
2200 int address = name.sa4.sin_addr.s_addr;
2201 if (!IN_MULTICAST(ntohl(address))) {
2202 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "not in multicast");
2203 return;
2204 }
2205 mname.imr_multiaddr.s_addr = address;
2206 if (fd < 0) {
2207 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Can't join an IPv4 group on an IPv6 only socket");
2208 return;
2209 }
2210 if (IS_NULL(niObj)) {
2211 len = sizeof(in);
2212 if (NET_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
2213 (char *)&in, &len) < 0) {
2214 NET_ThrowCurrent(env, "get IP_MULTICAST_IF failed");
2215 return;
2216 }
2217 mname.imr_interface.s_addr = in.s_addr;
2218 } else {
2219 if (getInet4AddrFromIf (env, niObj, &mname.imr_interface) != 0) {
2220 NET_ThrowCurrent(env, "no Inet4Address associated with interface");
2221 return;
2222 }
2223 }
2224
2225 cmd = join ? IP_ADD_MEMBERSHIP: IP_DROP_MEMBERSHIP;
2226
2227 /* Join the multicast group */
2228 if (NET_SetSockOpt(fd, IPPROTO_IP, cmd, (char *) &mname, sizeof (mname)) < 0) {
2229 if (WSAGetLastError() == WSAENOBUFS) {
2230 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2231 "IP_ADD_MEMBERSHIP failed (out of hardware filters?)");
2232 } else {
2233 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException","error setting options");
2234 }
2235 }
2236 } else /* AF_INET6 */ {
2237 if (ipv6_supported) {
2238 struct in6_addr *address;
2239 address = &name.sa6.sin6_addr;
2240 if (!IN6_IS_ADDR_MULTICAST(address)) {
2241 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "not in6 multicast");
2242 return;
2243 }
2244 mname6.ipv6mr_multiaddr = *address;
2245 } else {
2246 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "IPv6 not supported");
2247 return;
2248 }
2249 if (fd1 < 0) {
2250 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Can't join an IPv6 group on a IPv4 socket");
2251 return;
2252 }
2253 if (IS_NULL(niObj)) {
2254 len = sizeof (ifindex);
2255 if (NET_GetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, &len) < 0) {
2256 NET_ThrowCurrent(env, "get IPV6_MULTICAST_IF failed");
2257 return;
2258 }
2259 } else {
2260 ifindex = getIndexFromIf (env, niObj);
2261 if (ifindex == -1) {
2262 if ((*env)->ExceptionOccurred(env)) {
2263 return;
2264 }
2265 NET_ThrowCurrent(env, "get ifindex failed");
2266 return;
2267 }
2268 }
2269 mname6.ipv6mr_interface = ifindex;
2270 cmd = join ? IPV6_ADD_MEMBERSHIP: IPV6_DROP_MEMBERSHIP;
2271
2272 /* Join the multicast group */
2273 if (NET_SetSockOpt(fd1, IPPROTO_IPV6, cmd, (char *) &mname6, sizeof (mname6)) < 0) {
2274 if (WSAGetLastError() == WSAENOBUFS) {
2275 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2276 "IP_ADD_MEMBERSHIP failed (out of hardware filters?)");
2277 } else {
2278 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException","error setting options");
2279 }
2280 }
2281 }
2282
2283 return;
2284 }
2285
2286 /*
2287 * Class: java_net_TwoStacksPlainDatagramSocketImpl
2288 * Method: join
2289 * Signature: (Ljava/net/InetAddress;)V
2290 */
2291 JNIEXPORT void JNICALL
Java_java_net_TwoStacksPlainDatagramSocketImpl_join(JNIEnv * env,jobject this,jobject iaObj,jobject niObj)2292 Java_java_net_TwoStacksPlainDatagramSocketImpl_join(JNIEnv *env, jobject this,
2293 jobject iaObj, jobject niObj)
2294 {
2295 mcast_join_leave (env, this, iaObj, niObj, JNI_TRUE);
2296 }
2297
2298 /*
2299 * Class: java_net_TwoStacksPlainDatagramSocketImpl
2300 * Method: leave
2301 * Signature: (Ljava/net/InetAddress;)V
2302 */
2303 JNIEXPORT void JNICALL
Java_java_net_TwoStacksPlainDatagramSocketImpl_leave(JNIEnv * env,jobject this,jobject iaObj,jobject niObj)2304 Java_java_net_TwoStacksPlainDatagramSocketImpl_leave(JNIEnv *env, jobject this,
2305 jobject iaObj, jobject niObj)
2306 {
2307 mcast_join_leave (env, this, iaObj, niObj, JNI_FALSE);
2308 }
2309
2310 /*
2311 * Class: java_net_TwoStacksPlainDatagramSocketImpl
2312 * Method: dataAvailable
2313 * Signature: ()I
2314 */
Java_java_net_TwoStacksPlainDatagramSocketImpl_dataAvailable(JNIEnv * env,jobject this)2315 JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainDatagramSocketImpl_dataAvailable
2316 (JNIEnv *env, jobject this) {
2317 SOCKET fd;
2318 SOCKET fd1;
2319 int rv = -1, rv1 = -1;
2320 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2321 jobject fd1Obj;
2322
2323 if (!IS_NULL(fdObj)) {
2324 int retval = 0;
2325 fd = (SOCKET)(*env)->GetIntField(env, fdObj, IO_fd_fdID);
2326 rv = ioctlsocket(fd, FIONREAD, &retval);
2327 if (retval > 0) {
2328 return retval;
2329 }
2330 }
2331
2332 fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2333 if (!IS_NULL(fd1Obj)) {
2334 int retval = 0;
2335 fd1 = (SOCKET)(*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2336 rv1 = ioctlsocket(fd1, FIONREAD, &retval);
2337 if (retval > 0) {
2338 return retval;
2339 }
2340 }
2341
2342 if (rv < 0 && rv1 < 0) {
2343 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2344 "Socket closed");
2345 return -1;
2346 }
2347
2348 return 0;
2349 }
2350