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