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