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