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