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 */ 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 */ 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 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 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 */ 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 */ 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 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 */ 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 */ 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 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 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 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 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 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 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 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 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 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 */ 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 }