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