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