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