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) != 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_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, "JVM_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 JVM_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 switch (sendto(fd, fullPacket, packetBufferLen, 0, 761 (struct sockaddr *)addrp, addrlen)) { 762 case JVM_IO_ERR: 763 NET_ThrowCurrent(env, "Datagram send failed"); 764 break; 765 766 case JVM_IO_INTR: 767 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 768 "operation interrupted"); 769 } 770 771 if (packetBufferLen > MAX_BUFFER_LEN) { 772 free(fullPacket); 773 } 774 } 775 776 /* 777 * check which socket was last serviced when there was data on both sockets. 778 * Only call this if sure that there is data on both sockets. 779 */ 780 static int checkLastFD (JNIEnv *env, jobject this, int fd, int fd1) { 781 int nextfd, lastfd = (*env)->GetIntField(env, this, pdsi_lastfdID); 782 if (lastfd == -1) { 783 /* arbitrary. Choose fd */ 784 (*env)->SetIntField(env, this, pdsi_lastfdID, fd); 785 return fd; 786 } else { 787 if (lastfd == fd) { 788 nextfd = fd1; 789 } else { 790 nextfd = fd; 791 } 792 (*env)->SetIntField(env, this, pdsi_lastfdID, nextfd); 793 return nextfd; 794 } 795 } 796 797 /* 798 * Class: java_net_TwoStacksPlainDatagramSocketImpl 799 * Method: peek 800 * Signature: (Ljava/net/InetAddress;)I 801 */ 802 JNIEXPORT jint JNICALL 803 Java_java_net_TwoStacksPlainDatagramSocketImpl_peek(JNIEnv *env, jobject this, 804 jobject addressObj) { 805 806 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 807 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID); 808 jint fd; 809 810 /* The address and family fields of addressObj */ 811 jint address, family; 812 813 int n; 814 struct sockaddr_in remote_addr; 815 jint remote_addrsize = sizeof (remote_addr); 816 char buf[1]; 817 BOOL retry; 818 jlong prevTime = 0; 819 820 if (IS_NULL(fdObj)) { 821 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 822 return -1; 823 } else { 824 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 825 if (fd < 0) { 826 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 827 "socket closed"); 828 return -1; 829 } 830 } 831 if (IS_NULL(addressObj)) { 832 JNU_ThrowNullPointerException(env, "Null address in peek()"); 833 } else { 834 address = getInetAddress_addr(env, addressObj); 835 /* We only handle IPv4 for now. Will support IPv6 once its in the os */ 836 family = AF_INET; 837 } 838 839 do { 840 retry = FALSE; 841 842 /* 843 * If a timeout has been specified then we select on the socket 844 * waiting for a read event or a timeout. 845 */ 846 if (timeout) { 847 int ret; 848 prevTime = JVM_CurrentTimeMillis(env, 0); 849 ret = NET_Timeout (fd, timeout); 850 if (ret == 0) { 851 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 852 "Peek timed out"); 853 return ret; 854 } else if (ret == JVM_IO_ERR) { 855 NET_ThrowCurrent(env, "timeout in datagram socket peek"); 856 return ret; 857 } else if (ret == JVM_IO_INTR) { 858 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 859 "operation interrupted"); 860 return ret; 861 } 862 } 863 864 /* now try the peek */ 865 n = recvfrom(fd, buf, 1, MSG_PEEK, 866 (struct sockaddr *)&remote_addr, &remote_addrsize); 867 868 if (n == JVM_IO_ERR) { 869 if (WSAGetLastError() == WSAECONNRESET) { 870 jboolean connected; 871 872 /* 873 * An icmp port unreachable - we must receive this as Windows 874 * does not reset the state of the socket until this has been 875 * received. 876 */ 877 purgeOutstandingICMP(env, this, fd); 878 879 connected = (*env)->GetBooleanField(env, this, pdsi_connected); 880 if (connected) { 881 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 882 "ICMP Port Unreachable"); 883 return 0; 884 } 885 886 /* 887 * If a timeout was specified then we need to adjust it because 888 * we may have used up some of the timeout befor the icmp port 889 * unreachable arrived. 890 */ 891 if (timeout) { 892 jlong newTime = JVM_CurrentTimeMillis(env, 0); 893 timeout -= (jint)(newTime - prevTime); 894 if (timeout <= 0) { 895 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 896 "Receive timed out"); 897 return 0; 898 } 899 prevTime = newTime; 900 } 901 902 /* Need to retry the recv */ 903 retry = TRUE; 904 } 905 } 906 } while (retry); 907 908 if (n == JVM_IO_ERR && WSAGetLastError() != WSAEMSGSIZE) { 909 NET_ThrowCurrent(env, "Datagram peek failed"); 910 return 0; 911 } 912 if (n == JVM_IO_INTR) { 913 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 0); 914 return 0; 915 } 916 setInetAddress_addr(env, addressObj, ntohl(remote_addr.sin_addr.s_addr)); 917 setInetAddress_family(env, addressObj, IPv4); 918 919 /* return port */ 920 return ntohs(remote_addr.sin_port); 921 } 922 923 JNIEXPORT jint JNICALL 924 Java_java_net_TwoStacksPlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this, 925 jobject packet) { 926 927 char BUF[MAX_BUFFER_LEN]; 928 char *fullPacket; 929 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 930 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID); 931 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID); 932 933 jbyteArray packetBuffer; 934 jint packetBufferOffset, packetBufferLen; 935 936 int fd, fd1, fduse, nsockets=0, errorCode; 937 int port; 938 939 int checkBoth = 0; 940 int n; 941 SOCKETADDRESS remote_addr; 942 jint remote_addrsize=sizeof(remote_addr); 943 BOOL retry; 944 jlong prevTime = 0; 945 946 if (!IS_NULL(fdObj)) { 947 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 948 if (fd < 0) { 949 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 950 "socket closed"); 951 return -1; 952 } 953 nsockets = 1; 954 } 955 956 if (!IS_NULL(fd1Obj)) { 957 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID); 958 if (fd1 < 0) { 959 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 960 "socket closed"); 961 return -1; 962 } 963 nsockets ++; 964 } 965 966 switch (nsockets) { 967 case 0: 968 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 969 "socket closed"); 970 return -1; 971 case 1: 972 if (!IS_NULL(fdObj)) { 973 fduse = fd; 974 } else { 975 fduse = fd1; 976 } 977 break; 978 case 2: 979 checkBoth = TRUE; 980 break; 981 } 982 983 if (IS_NULL(packet)) { 984 JNU_ThrowNullPointerException(env, "packet"); 985 return -1; 986 } 987 988 packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID); 989 990 if (IS_NULL(packetBuffer)) { 991 JNU_ThrowNullPointerException(env, "packet buffer"); 992 return -1; 993 } 994 995 packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID); 996 packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID); 997 998 if (packetBufferLen > MAX_BUFFER_LEN) { 999 1000 /* When JNI-ifying the JDK's IO routines, we turned 1001 * read's and write's of byte arrays of size greater 1002 * than 2048 bytes into several operations of size 2048. 1003 * This saves a malloc()/memcpy()/free() for big 1004 * buffers. This is OK for file IO and TCP, but that 1005 * strategy violates the semantics of a datagram protocol. 1006 * (one big send) != (several smaller sends). So here 1007 * we *must* alloc the buffer. Note it needn't be bigger 1008 * than 65,536 (0xFFFF) the max size of an IP packet. 1009 * anything bigger is truncated anyway. 1010 */ 1011 fullPacket = (char *)malloc(packetBufferLen); 1012 if (!fullPacket) { 1013 JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); 1014 return -1; 1015 } 1016 } else { 1017 fullPacket = &(BUF[0]); 1018 } 1019 1020 do { 1021 int ret; 1022 retry = FALSE; 1023 1024 /* 1025 * If a timeout has been specified then we select on the socket 1026 * waiting for a read event or a timeout. 1027 */ 1028 if (checkBoth) { 1029 int t = timeout == 0 ? -1: timeout; 1030 prevTime = JVM_CurrentTimeMillis(env, 0); 1031 ret = NET_Timeout2 (fd, fd1, t, &fduse); 1032 /* all subsequent calls to recv() or select() will use the same fd 1033 * for this call to peek() */ 1034 if (ret <= 0) { 1035 if (ret == 0) { 1036 JNU_ThrowByName(env,JNU_JAVANETPKG "SocketTimeoutException", 1037 "Peek timed out"); 1038 } else if (ret == JVM_IO_ERR) { 1039 NET_ThrowCurrent(env, "timeout in datagram socket peek"); 1040 } else if (ret == JVM_IO_INTR) { 1041 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 1042 "operation interrupted"); 1043 } 1044 if (packetBufferLen > MAX_BUFFER_LEN) { 1045 free(fullPacket); 1046 } 1047 return -1; 1048 } 1049 if (ret == 2) { 1050 fduse = checkLastFD (env, this, fd, fd1); 1051 } 1052 checkBoth = FALSE; 1053 } else if (timeout) { 1054 if (prevTime == 0) { 1055 prevTime = JVM_CurrentTimeMillis(env, 0); 1056 } 1057 ret = NET_Timeout (fduse, timeout); 1058 if (ret <= 0) { 1059 if (ret == 0) { 1060 JNU_ThrowByName(env,JNU_JAVANETPKG "SocketTimeoutException", 1061 "Receive timed out"); 1062 } else if (ret == JVM_IO_ERR) { 1063 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1064 "Socket closed"); 1065 } else if (ret == JVM_IO_INTR) { 1066 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 1067 "operation interrupted"); 1068 } 1069 if (packetBufferLen > MAX_BUFFER_LEN) { 1070 free(fullPacket); 1071 } 1072 return -1; 1073 } 1074 } 1075 1076 /* receive the packet */ 1077 n = recvfrom(fduse, fullPacket, packetBufferLen, MSG_PEEK, 1078 (struct sockaddr *)&remote_addr, &remote_addrsize); 1079 port = (int) ntohs ((u_short) GET_PORT((SOCKETADDRESS *)&remote_addr)); 1080 if (n == JVM_IO_ERR) { 1081 if (WSAGetLastError() == WSAECONNRESET) { 1082 jboolean connected; 1083 1084 /* 1085 * An icmp port unreachable - we must receive this as Windows 1086 * does not reset the state of the socket until this has been 1087 * received. 1088 */ 1089 purgeOutstandingICMP(env, this, fduse); 1090 1091 connected = (*env)->GetBooleanField(env, this, pdsi_connected); 1092 if (connected) { 1093 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 1094 "ICMP Port Unreachable"); 1095 1096 if (packetBufferLen > MAX_BUFFER_LEN) { 1097 free(fullPacket); 1098 } 1099 return -1; 1100 } 1101 1102 /* 1103 * If a timeout was specified then we need to adjust it because 1104 * we may have used up some of the timeout befor the icmp port 1105 * unreachable arrived. 1106 */ 1107 if (timeout) { 1108 jlong newTime = JVM_CurrentTimeMillis(env, 0); 1109 timeout -= (jint)(newTime - prevTime); 1110 if (timeout <= 0) { 1111 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 1112 "Receive timed out"); 1113 if (packetBufferLen > MAX_BUFFER_LEN) { 1114 free(fullPacket); 1115 } 1116 return -1; 1117 } 1118 prevTime = newTime; 1119 } 1120 retry = TRUE; 1121 } 1122 } 1123 } while (retry); 1124 1125 /* truncate the data if the packet's length is too small */ 1126 if (n > packetBufferLen) { 1127 n = packetBufferLen; 1128 } 1129 if (n < 0) { 1130 errorCode = WSAGetLastError(); 1131 /* check to see if it's because the buffer was too small */ 1132 if (errorCode == WSAEMSGSIZE) { 1133 /* it is because the buffer is too small. It's UDP, it's 1134 * unreliable, it's all good. discard the rest of the 1135 * data.. 1136 */ 1137 n = packetBufferLen; 1138 } else { 1139 /* failure */ 1140 (*env)->SetIntField(env, packet, dp_lengthID, 0); 1141 } 1142 } 1143 if (n == -1) { 1144 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed"); 1145 } else if (n == -2) { 1146 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 1147 "operation interrupted"); 1148 } else if (n < 0) { 1149 NET_ThrowCurrent(env, "Datagram receive failed"); 1150 } else { 1151 jobject packetAddress; 1152 1153 /* 1154 * Check if there is an InetAddress already associated with this 1155 * packet. If so we check if it is the same source address. We 1156 * can't update any existing InetAddress because it is immutable 1157 */ 1158 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID); 1159 if (packetAddress != NULL) { 1160 if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *) 1161 &remote_addr, packetAddress)) { 1162 /* force a new InetAddress to be created */ 1163 packetAddress = NULL; 1164 } 1165 } 1166 if (packetAddress == NULL) { 1167 packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *) 1168 &remote_addr, &port); 1169 /* stuff the new Inetaddress in the packet */ 1170 (*env)->SetObjectField(env, packet, dp_addressID, packetAddress); 1171 } 1172 1173 /* populate the packet */ 1174 (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n, 1175 (jbyte *)fullPacket); 1176 (*env)->SetIntField(env, packet, dp_portID, port); 1177 (*env)->SetIntField(env, packet, dp_lengthID, n); 1178 } 1179 1180 /* make sure receive() picks up the right fd */ 1181 (*env)->SetIntField(env, this, pdsi_fduseID, fduse); 1182 1183 if (packetBufferLen > MAX_BUFFER_LEN) { 1184 free(fullPacket); 1185 } 1186 return port; 1187 } 1188 1189 /* 1190 * Class: java_net_TwoStacksPlainDatagramSocketImpl 1191 * Method: receive 1192 * Signature: (Ljava/net/DatagramPacket;)V 1193 */ 1194 JNIEXPORT void JNICALL 1195 Java_java_net_TwoStacksPlainDatagramSocketImpl_receive0(JNIEnv *env, jobject this, 1196 jobject packet) { 1197 1198 char BUF[MAX_BUFFER_LEN]; 1199 char *fullPacket; 1200 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 1201 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID); 1202 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID); 1203 jbyteArray packetBuffer; 1204 jint packetBufferOffset, packetBufferLen; 1205 int ipv6_supported = ipv6_available(); 1206 1207 /* as a result of the changes for ipv6, peek() or peekData() 1208 * must be called prior to receive() so that fduse can be set. 1209 */ 1210 int fd, fd1, fduse, errorCode; 1211 1212 int n, nsockets=0; 1213 SOCKETADDRESS remote_addr; 1214 jint remote_addrsize=sizeof(remote_addr); 1215 BOOL retry; 1216 jlong prevTime = 0, selectTime=0; 1217 jboolean connected; 1218 1219 if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { 1220 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1221 "Socket closed"); 1222 return; 1223 } 1224 1225 if (!IS_NULL(fdObj)) { 1226 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 1227 nsockets ++; 1228 } 1229 if (!IS_NULL(fd1Obj)) { 1230 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID); 1231 nsockets ++; 1232 } 1233 1234 if (nsockets == 2) { /* need to choose one of them */ 1235 /* was fduse set in peek? */ 1236 fduse = (*env)->GetIntField(env, this, pdsi_fduseID); 1237 if (fduse == -1) { 1238 /* not set in peek(), must select on both sockets */ 1239 int ret, t = (timeout == 0) ? -1: timeout; 1240 ret = NET_Timeout2 (fd, fd1, t, &fduse); 1241 if (ret == 2) { 1242 fduse = checkLastFD (env, this, fd, fd1); 1243 } else if (ret <= 0) { 1244 if (ret == 0) { 1245 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 1246 "Receive timed out"); 1247 } else if (ret == JVM_IO_ERR) { 1248 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1249 "Socket closed"); 1250 } else if (ret == JVM_IO_INTR) { 1251 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 1252 "operation interrupted"); 1253 } 1254 return; 1255 } 1256 } 1257 } else if (!ipv6_supported) { 1258 fduse = fd; 1259 } else if (IS_NULL(fdObj)) { 1260 /* ipv6 supported: and this socket bound to an IPV6 only address */ 1261 fduse = fd1; 1262 } else { 1263 /* ipv6 supported: and this socket bound to an IPV4 only address */ 1264 fduse = fd; 1265 } 1266 1267 if (IS_NULL(packet)) { 1268 JNU_ThrowNullPointerException(env, "packet"); 1269 return; 1270 } 1271 1272 packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID); 1273 1274 if (IS_NULL(packetBuffer)) { 1275 JNU_ThrowNullPointerException(env, "packet buffer"); 1276 return; 1277 } 1278 1279 packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID); 1280 packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID); 1281 1282 if (packetBufferLen > MAX_BUFFER_LEN) { 1283 1284 /* When JNI-ifying the JDK's IO routines, we turned 1285 * read's and write's of byte arrays of size greater 1286 * than 2048 bytes into several operations of size 2048. 1287 * This saves a malloc()/memcpy()/free() for big 1288 * buffers. This is OK for file IO and TCP, but that 1289 * strategy violates the semantics of a datagram protocol. 1290 * (one big send) != (several smaller sends). So here 1291 * we *must* alloc the buffer. Note it needn't be bigger 1292 * than 65,536 (0xFFFF) the max size of an IP packet. 1293 * anything bigger is truncated anyway. 1294 */ 1295 fullPacket = (char *)malloc(packetBufferLen); 1296 if (!fullPacket) { 1297 JNU_ThrowOutOfMemoryError(env, "Receive buf native heap allocation failed"); 1298 return; 1299 } 1300 } else { 1301 fullPacket = &(BUF[0]); 1302 } 1303 1304 1305 1306 /* 1307 * If this Windows edition supports ICMP port unreachable and if we 1308 * are not connected then we need to know if a timeout has been specified 1309 * and if so we need to pick up the current time. These are required in 1310 * order to implement the semantics of timeout, viz :- 1311 * timeout set to t1 but ICMP port unreachable arrives in t2 where 1312 * t2 < t1. In this case we must discard the ICMP packets and then 1313 * wait for the next packet up to a maximum of t1 minus t2. 1314 */ 1315 connected = (*env)->GetBooleanField(env, this, pdsi_connected); 1316 if (supportPortUnreachable() && !connected && timeout &&!ipv6_supported) { 1317 prevTime = JVM_CurrentTimeMillis(env, 0); 1318 } 1319 1320 if (timeout && nsockets == 1) { 1321 int ret; 1322 ret = NET_Timeout(fduse, timeout); 1323 if (ret <= 0) { 1324 if (ret == 0) { 1325 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 1326 "Receive timed out"); 1327 } else if (ret == JVM_IO_ERR) { 1328 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1329 "Socket closed"); 1330 } else if (ret == JVM_IO_INTR) { 1331 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 1332 "operation interrupted"); 1333 } 1334 if (packetBufferLen > MAX_BUFFER_LEN) { 1335 free(fullPacket); 1336 } 1337 return; 1338 } 1339 } 1340 1341 /* 1342 * Loop only if we discarding ICMP port unreachable packets 1343 */ 1344 do { 1345 retry = FALSE; 1346 1347 /* receive the packet */ 1348 n = recvfrom(fduse, fullPacket, packetBufferLen, 0, 1349 (struct sockaddr *)&remote_addr, &remote_addrsize); 1350 1351 if (n == JVM_IO_ERR) { 1352 if (WSAGetLastError() == WSAECONNRESET) { 1353 /* 1354 * An icmp port unreachable has been received - consume any other 1355 * outstanding packets. 1356 */ 1357 purgeOutstandingICMP(env, this, fduse); 1358 1359 /* 1360 * If connected throw a PortUnreachableException 1361 */ 1362 1363 if (connected) { 1364 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 1365 "ICMP Port Unreachable"); 1366 1367 if (packetBufferLen > MAX_BUFFER_LEN) { 1368 free(fullPacket); 1369 } 1370 1371 return; 1372 } 1373 1374 /* 1375 * If a timeout was specified then we need to adjust it because 1376 * we may have used up some of the timeout before the icmp port 1377 * unreachable arrived. 1378 */ 1379 if (timeout) { 1380 int ret; 1381 jlong newTime = JVM_CurrentTimeMillis(env, 0); 1382 timeout -= (jint)(newTime - prevTime); 1383 prevTime = newTime; 1384 1385 if (timeout <= 0) { 1386 ret = 0; 1387 } else { 1388 ret = NET_Timeout(fduse, timeout); 1389 } 1390 1391 if (ret <= 0) { 1392 if (ret == 0) { 1393 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 1394 "Receive timed out"); 1395 } else if (ret == JVM_IO_ERR) { 1396 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1397 "Socket closed"); 1398 } else if (ret == JVM_IO_INTR) { 1399 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 1400 "operation interrupted"); 1401 } 1402 if (packetBufferLen > MAX_BUFFER_LEN) { 1403 free(fullPacket); 1404 } 1405 return; 1406 } 1407 } 1408 1409 /* 1410 * An ICMP port unreachable was received but we are 1411 * not connected so ignore it. 1412 */ 1413 retry = TRUE; 1414 } 1415 } 1416 } while (retry); 1417 1418 /* truncate the data if the packet's length is too small */ 1419 if (n > packetBufferLen) { 1420 n = packetBufferLen; 1421 } 1422 if (n < 0) { 1423 errorCode = WSAGetLastError(); 1424 /* check to see if it's because the buffer was too small */ 1425 if (errorCode == WSAEMSGSIZE) { 1426 /* it is because the buffer is too small. It's UDP, it's 1427 * unreliable, it's all good. discard the rest of the 1428 * data.. 1429 */ 1430 n = packetBufferLen; 1431 } else { 1432 /* failure */ 1433 (*env)->SetIntField(env, packet, dp_lengthID, 0); 1434 } 1435 } 1436 if (n == -1) { 1437 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed"); 1438 } else if (n == -2) { 1439 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 1440 "operation interrupted"); 1441 } else if (n < 0) { 1442 NET_ThrowCurrent(env, "Datagram receive failed"); 1443 } else { 1444 int port; 1445 jobject packetAddress; 1446 1447 /* 1448 * Check if there is an InetAddress already associated with this 1449 * packet. If so we check if it is the same source address. We 1450 * can't update any existing InetAddress because it is immutable 1451 */ 1452 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID); 1453 1454 if (packetAddress != NULL) { 1455 if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) { 1456 /* force a new InetAddress to be created */ 1457 packetAddress = NULL; 1458 } 1459 } 1460 if (packetAddress == NULL) { 1461 packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port); 1462 /* stuff the new Inetaddress in the packet */ 1463 (*env)->SetObjectField(env, packet, dp_addressID, packetAddress); 1464 } else { 1465 /* only get the new port number */ 1466 port = NET_GetPortFromSockaddr((struct sockaddr *)&remote_addr); 1467 } 1468 /* populate the packet */ 1469 (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n, 1470 (jbyte *)fullPacket); 1471 (*env)->SetIntField(env, packet, dp_portID, port); 1472 (*env)->SetIntField(env, packet, dp_lengthID, n); 1473 } 1474 if (packetBufferLen > MAX_BUFFER_LEN) { 1475 free(fullPacket); 1476 } 1477 } 1478 1479 /* 1480 * Class: java_net_TwoStacksPlainDatagramSocketImpl 1481 * Method: datagramSocketCreate 1482 * Signature: ()V 1483 */ 1484 JNIEXPORT void JNICALL 1485 Java_java_net_TwoStacksPlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env, 1486 jobject this) { 1487 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 1488 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID); 1489 1490 int fd, fd1; 1491 int t = TRUE; 1492 DWORD x1, x2; /* ignored result codes */ 1493 int ipv6_supported = ipv6_available(); 1494 1495 int arg = -1; 1496 1497 if (IS_NULL(fdObj) || (ipv6_supported && IS_NULL(fd1Obj))) { 1498 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 1499 return; 1500 } else { 1501 fd = (int) socket (AF_INET, SOCK_DGRAM, 0); 1502 } 1503 if (fd == JVM_IO_ERR) { 1504 NET_ThrowCurrent(env, "Socket creation failed"); 1505 return; 1506 } 1507 SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE); 1508 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd); 1509 NET_SetSockOpt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL)); 1510 1511 if (ipv6_supported) { 1512 /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which 1513 * returns connection reset errors un connected UDP sockets (as well 1514 * as connected sockets. The solution is to only enable this feature 1515 * when the socket is connected 1516 */ 1517 t = FALSE; 1518 WSAIoctl(fd,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0); 1519 t = TRUE; 1520 fd1 = socket (AF_INET6, SOCK_DGRAM, 0); 1521 if (fd1 == JVM_IO_ERR) { 1522 NET_ThrowCurrent(env, "Socket creation failed"); 1523 return; 1524 } 1525 NET_SetSockOpt(fd1, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL)); 1526 t = FALSE; 1527 WSAIoctl(fd1,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0); 1528 (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1); 1529 SetHandleInformation((HANDLE)(UINT_PTR)fd1, HANDLE_FLAG_INHERIT, FALSE); 1530 } else { 1531 /* drop the second fd */ 1532 (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL); 1533 } 1534 } 1535 1536 /* 1537 * Class: java_net_TwoStacksPlainDatagramSocketImpl 1538 * Method: datagramSocketClose 1539 * Signature: ()V 1540 */ 1541 JNIEXPORT void JNICALL 1542 Java_java_net_TwoStacksPlainDatagramSocketImpl_datagramSocketClose(JNIEnv *env, 1543 jobject this) { 1544 /* 1545 * REMIND: PUT A LOCK AROUND THIS CODE 1546 */ 1547 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 1548 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID); 1549 int ipv6_supported = ipv6_available(); 1550 int fd=-1, fd1=-1; 1551 1552 if (IS_NULL(fdObj) && (!ipv6_supported || IS_NULL(fd1Obj))) { 1553 return; 1554 } 1555 1556 if (!IS_NULL(fdObj)) { 1557 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 1558 if (fd != -1) { 1559 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1); 1560 NET_SocketClose(fd); 1561 } 1562 } 1563 1564 if (ipv6_supported && fd1Obj != NULL) { 1565 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID); 1566 if (fd1 == -1) { 1567 return; 1568 } 1569 (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, -1); 1570 NET_SocketClose(fd1); 1571 } 1572 } 1573 1574 /* 1575 * check the addresses attached to the NetworkInterface object 1576 * and return the first one (of the requested family Ipv4 or Ipv6) 1577 * in *iaddr 1578 */ 1579 1580 static int getInetAddrFromIf (JNIEnv *env, int family, jobject nif, jobject *iaddr) 1581 { 1582 jobjectArray addrArray; 1583 static jfieldID ni_addrsID=0; 1584 jsize len; 1585 jobject addr; 1586 int i; 1587 1588 if (ni_addrsID == NULL ) { 1589 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface"); 1590 CHECK_NULL_RETURN (c, -1); 1591 ni_addrsID = (*env)->GetFieldID(env, c, "addrs", 1592 "[Ljava/net/InetAddress;"); 1593 CHECK_NULL_RETURN (ni_addrsID, -1); 1594 } 1595 1596 addrArray = (*env)->GetObjectField(env, nif, ni_addrsID); 1597 len = (*env)->GetArrayLength(env, addrArray); 1598 1599 /* 1600 * Check that there is at least one address bound to this 1601 * interface. 1602 */ 1603 if (len < 1) { 1604 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1605 "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface"); 1606 return -1; 1607 } 1608 for (i=0; i<len; i++) { 1609 int fam; 1610 addr = (*env)->GetObjectArrayElement(env, addrArray, i); 1611 fam = getInetAddress_family(env, addr); 1612 if (fam == family) { 1613 *iaddr = addr; 1614 return 0; 1615 } 1616 } 1617 return -1; 1618 } 1619 1620 static int getInet4AddrFromIf (JNIEnv *env, jobject nif, struct in_addr *iaddr) 1621 { 1622 jobject addr; 1623 1624 int ret = getInetAddrFromIf (env, IPv4, nif, &addr); 1625 if (ret == -1) { 1626 return -1; 1627 } 1628 1629 iaddr->s_addr = htonl(getInetAddress_addr(env, addr)); 1630 return 0; 1631 } 1632 1633 /* Get the multicasting index from the interface */ 1634 1635 static int getIndexFromIf (JNIEnv *env, jobject nif) { 1636 static jfieldID ni_indexID; 1637 1638 if (ni_indexID == NULL) { 1639 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface"); 1640 CHECK_NULL_RETURN(c, -1); 1641 ni_indexID = (*env)->GetFieldID(env, c, "index", "I"); 1642 CHECK_NULL_RETURN(ni_indexID, -1); 1643 } 1644 1645 return (*env)->GetIntField(env, nif, ni_indexID); 1646 } 1647 1648 static int isAdapterIpv6Enabled(JNIEnv *env, int index) { 1649 extern int getAllInterfacesAndAddresses (JNIEnv *env, netif **netifPP); 1650 netif *ifList, *curr; 1651 int ipv6Enabled = 0; 1652 if (getAllInterfacesAndAddresses (env, &ifList) < 0) { 1653 return ipv6Enabled; 1654 } 1655 1656 /* search by index */ 1657 curr = ifList; 1658 while (curr != NULL) { 1659 if (index == curr->index) { 1660 break; 1661 } 1662 curr = curr->next; 1663 } 1664 1665 /* if found ipv6Index != 0 then interface is configured with IPV6 */ 1666 if ((curr != NULL) && (curr->ipv6Index !=0)) { 1667 ipv6Enabled = 1; 1668 } 1669 1670 /* release the interface list */ 1671 free_netif(ifList); 1672 1673 return ipv6Enabled; 1674 } 1675 1676 /* 1677 * Sets the multicast interface. 1678 * 1679 * SocketOptions.IP_MULTICAST_IF (argument is an InetAddress) :- 1680 * IPv4: set outgoing multicast interface using 1681 * IPPROTO_IP/IP_MULTICAST_IF 1682 * 1683 * IPv6: Get the interface to which the 1684 * InetAddress is bound 1685 * and do same as SockOptions.IF_MULTICAST_IF2 1686 * 1687 * SockOptions.IF_MULTICAST_IF2 (argument is a NetworkInterface ) :- 1688 * For each stack: 1689 * IPv4: Obtain IP address bound to network interface 1690 * (NetworkInterface.addres[0]) 1691 * set outgoing multicast interface using 1692 * IPPROTO_IP/IP_MULTICAST_IF 1693 * 1694 * IPv6: Obtain NetworkInterface.index 1695 * Set outgoing multicast interface using 1696 * IPPROTO_IPV6/IPV6_MULTICAST_IF 1697 * 1698 */ 1699 static void setMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, 1700 jint opt, jobject value) 1701 { 1702 int ipv6_supported = ipv6_available(); 1703 1704 if (opt == java_net_SocketOptions_IP_MULTICAST_IF) { 1705 /* 1706 * value is an InetAddress. 1707 * On IPv4 system use IP_MULTICAST_IF socket option 1708 * On IPv6 system get the NetworkInterface that this IP 1709 * address is bound to and use the IPV6_MULTICAST_IF 1710 * option instead of IP_MULTICAST_IF 1711 */ 1712 if (ipv6_supported) { 1713 static jclass ni_class; 1714 if (ni_class == NULL) { 1715 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface"); 1716 CHECK_NULL(c); 1717 ni_class = (*env)->NewGlobalRef(env, c); 1718 CHECK_NULL(ni_class); 1719 } 1720 1721 value = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, value); 1722 if (value == NULL) { 1723 if (!(*env)->ExceptionOccurred(env)) { 1724 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1725 "bad argument for IP_MULTICAST_IF" 1726 ": address not bound to any interface"); 1727 } 1728 return; 1729 } 1730 opt = java_net_SocketOptions_IP_MULTICAST_IF2; 1731 } else { 1732 struct in_addr in; 1733 1734 in.s_addr = htonl(getInetAddress_addr(env, value)); 1735 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, 1736 (const char*)&in, sizeof(in)) < 0) { 1737 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1738 "Error setting socket option"); 1739 } 1740 return; 1741 } 1742 } 1743 1744 if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) { 1745 /* 1746 * value is a NetworkInterface. 1747 * On IPv6 system get the index of the interface and use the 1748 * IPV6_MULTICAST_IF socket option 1749 * On IPv4 system extract addr[0] and use the IP_MULTICAST_IF 1750 * option. For IPv6 both must be done. 1751 */ 1752 if (ipv6_supported) { 1753 static jfieldID ni_indexID; 1754 struct in_addr in; 1755 int index; 1756 1757 if (ni_indexID == NULL) { 1758 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface"); 1759 CHECK_NULL(c); 1760 ni_indexID = (*env)->GetFieldID(env, c, "index", "I"); 1761 CHECK_NULL(ni_indexID); 1762 } 1763 index = (*env)->GetIntField(env, value, ni_indexID); 1764 1765 if ( isAdapterIpv6Enabled(env, index) != 0 ) { 1766 if (setsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF, 1767 (const char*)&index, sizeof(index)) < 0) { 1768 if (errno == EINVAL && index > 0) { 1769 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1770 "IPV6_MULTICAST_IF failed (interface has IPv4 " 1771 "address only?)"); 1772 } else { 1773 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1774 "Error setting socket option"); 1775 } 1776 return; 1777 } 1778 } 1779 /* If there are any IPv4 addresses on this interface then 1780 * repeat the operation on the IPv4 fd */ 1781 1782 if (getInet4AddrFromIf (env, value, &in) < 0) { 1783 return; 1784 } 1785 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, 1786 (const char*)&in, sizeof(in)) < 0) { 1787 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1788 "Error setting socket option"); 1789 } 1790 return; 1791 } else { 1792 struct in_addr in; 1793 1794 if (getInet4AddrFromIf (env, value, &in) < 0) { 1795 if ((*env)->ExceptionOccurred(env)) { 1796 return; 1797 } 1798 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1799 "no InetAddress instances of requested type"); 1800 return; 1801 } 1802 1803 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, 1804 (const char*)&in, sizeof(in)) < 0) { 1805 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1806 "Error setting socket option"); 1807 } 1808 return; 1809 } 1810 } 1811 } 1812 1813 /* 1814 * Class: java_net_TwoStacksPlainDatagramSocketImpl 1815 * Method: socketNativeSetOption 1816 * Signature: (ILjava/lang/Object;)V 1817 */ 1818 JNIEXPORT void JNICALL 1819 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketNativeSetOption(JNIEnv *env,jobject this, 1820 jint opt,jobject value) { 1821 1822 int fd=-1, fd1=-1; 1823 int levelv4, levelv6, optnamev4, optnamev6, optlen; 1824 union { 1825 int i; 1826 char c; 1827 } optval; 1828 int ipv6_supported = ipv6_available(); 1829 fd = getFD(env, this); 1830 1831 if (ipv6_supported) { 1832 fd1 = getFD1(env, this); 1833 } 1834 if (fd < 0 && fd1 < 0) { 1835 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed"); 1836 return; 1837 } 1838 1839 if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) || 1840 (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) { 1841 1842 setMulticastInterface(env, this, fd, fd1, opt, value); 1843 return; 1844 } 1845 1846 /* 1847 * Map the Java level socket option to the platform specific 1848 * level(s) and option name(s). 1849 */ 1850 if (fd1 != -1) { 1851 if (NET_MapSocketOptionV6(opt, &levelv6, &optnamev6)) { 1852 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option"); 1853 return; 1854 } 1855 } 1856 if (fd != -1) { 1857 if (NET_MapSocketOption(opt, &levelv4, &optnamev4)) { 1858 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option"); 1859 return; 1860 } 1861 } 1862 1863 switch (opt) { 1864 case java_net_SocketOptions_SO_SNDBUF : 1865 case java_net_SocketOptions_SO_RCVBUF : 1866 case java_net_SocketOptions_IP_TOS : 1867 { 1868 jclass cls; 1869 jfieldID fid; 1870 1871 cls = (*env)->FindClass(env, "java/lang/Integer"); 1872 CHECK_NULL(cls); 1873 fid = (*env)->GetFieldID(env, cls, "value", "I"); 1874 CHECK_NULL(fid); 1875 1876 optval.i = (*env)->GetIntField(env, value, fid); 1877 optlen = sizeof(optval.i); 1878 } 1879 break; 1880 1881 case java_net_SocketOptions_SO_REUSEADDR: 1882 case java_net_SocketOptions_SO_BROADCAST: 1883 case java_net_SocketOptions_IP_MULTICAST_LOOP: 1884 { 1885 jclass cls; 1886 jfieldID fid; 1887 jboolean on; 1888 1889 cls = (*env)->FindClass(env, "java/lang/Boolean"); 1890 CHECK_NULL(cls); 1891 fid = (*env)->GetFieldID(env, cls, "value", "Z"); 1892 CHECK_NULL(fid); 1893 1894 on = (*env)->GetBooleanField(env, value, fid); 1895 optval.i = (on ? 1 : 0); 1896 /* 1897 * setLoopbackMode (true) disables IP_MULTICAST_LOOP rather 1898 * than enabling it. 1899 */ 1900 if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) { 1901 optval.i = !optval.i; 1902 } 1903 optlen = sizeof(optval.i); 1904 } 1905 break; 1906 1907 default : 1908 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1909 "Socket option not supported by PlainDatagramSocketImp"); 1910 break; 1911 1912 } 1913 1914 if (fd1 != -1) { 1915 if (NET_SetSockOpt(fd1, levelv6, optnamev6, (void *)&optval, optlen) < 0) { 1916 NET_ThrowCurrent(env, "setsockopt IPv6"); 1917 return; 1918 } 1919 } 1920 if (fd != -1) { 1921 if (NET_SetSockOpt(fd, levelv4, optnamev4, (void *)&optval, optlen) < 0) { 1922 NET_ThrowCurrent(env, "setsockopt"); 1923 return; 1924 } 1925 } 1926 } 1927 1928 /* 1929 * 1930 * called by getMulticastInterface to retrieve a NetworkInterface 1931 * configured for IPv4. 1932 * The ipv4Mode parameter, is a closet boolean, which allows for a NULL return, 1933 * or forces the creation of a NetworkInterface object with null data. 1934 * It relates to its calling context in getMulticastInterface. 1935 * ipv4Mode == 1, the context is IPV4 processing only. 1936 * ipv4Mode == 0, the context is IPV6 processing 1937 * 1938 */ 1939 static jobject getIPv4NetworkInterface (JNIEnv *env, jobject this, int fd, jint opt, int ipv4Mode) { 1940 static jclass inet4_class; 1941 static jmethodID inet4_ctrID; 1942 1943 static jclass ni_class; static jmethodID ni_ctrID; 1944 static jfieldID ni_indexID; 1945 static jfieldID ni_addrsID; 1946 1947 jobjectArray addrArray; 1948 jobject addr; 1949 jobject ni; 1950 1951 struct in_addr in; 1952 struct in_addr *inP = ∈ 1953 int len = sizeof(struct in_addr); 1954 if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, 1955 (char *)inP, &len) < 0) { 1956 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1957 "Error getting socket option"); 1958 return NULL; 1959 } 1960 1961 /* 1962 * Construct and populate an Inet4Address 1963 */ 1964 if (inet4_class == NULL) { 1965 jclass c = (*env)->FindClass(env, "java/net/Inet4Address"); 1966 CHECK_NULL_RETURN(c, NULL); 1967 inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V"); 1968 CHECK_NULL_RETURN(inet4_ctrID, NULL); 1969 inet4_class = (*env)->NewGlobalRef(env, c); 1970 CHECK_NULL_RETURN(inet4_class, NULL); 1971 } 1972 addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0); 1973 CHECK_NULL_RETURN(addr, NULL); 1974 1975 setInetAddress_addr(env, addr, ntohl(in.s_addr)); 1976 1977 /* 1978 * For IP_MULTICAST_IF return InetAddress 1979 */ 1980 if (opt == java_net_SocketOptions_IP_MULTICAST_IF) { 1981 return addr; 1982 } 1983 1984 /* 1985 * For IP_MULTICAST_IF2 we get the NetworkInterface for 1986 * this address and return it 1987 */ 1988 if (ni_class == NULL) { 1989 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface"); 1990 CHECK_NULL_RETURN(c, NULL); 1991 ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V"); 1992 CHECK_NULL_RETURN(ni_ctrID, NULL); 1993 ni_indexID = (*env)->GetFieldID(env, c, "index", "I"); 1994 CHECK_NULL_RETURN(ni_indexID, NULL); 1995 ni_addrsID = (*env)->GetFieldID(env, c, "addrs", 1996 "[Ljava/net/InetAddress;"); 1997 CHECK_NULL_RETURN(ni_addrsID, NULL); 1998 ni_class = (*env)->NewGlobalRef(env, c); 1999 CHECK_NULL_RETURN(ni_class, NULL); 2000 } 2001 ni = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, addr); 2002 if (ni) { 2003 return ni; 2004 } 2005 if (ipv4Mode) { 2006 ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0); 2007 CHECK_NULL_RETURN(ni, NULL); 2008 2009 (*env)->SetIntField(env, ni, ni_indexID, -1); 2010 addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL); 2011 CHECK_NULL_RETURN(addrArray, NULL); 2012 (*env)->SetObjectArrayElement(env, addrArray, 0, addr); 2013 (*env)->SetObjectField(env, ni, ni_addrsID, addrArray); 2014 } else { 2015 ni = NULL; 2016 } 2017 return ni; 2018 } 2019 2020 /* 2021 * Return the multicast interface: 2022 * 2023 * SocketOptions.IP_MULTICAST_IF 2024 * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF 2025 * Create InetAddress 2026 * IP_MULTICAST_IF returns struct ip_mreqn on 2.2 2027 * kernel but struct in_addr on 2.4 kernel 2028 * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF or 2029 * obtain from impl is Linux 2.2 kernel 2030 * If index == 0 return InetAddress representing 2031 * anyLocalAddress. 2032 * If index > 0 query NetworkInterface by index 2033 * and returns addrs[0] 2034 * 2035 * SocketOptions.IP_MULTICAST_IF2 2036 * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF 2037 * Query NetworkInterface by IP address and 2038 * return the NetworkInterface that the address 2039 * is bound too. 2040 * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF 2041 * (except Linux .2 kernel) 2042 * Query NetworkInterface by index and 2043 * return NetworkInterface. 2044 */ 2045 jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint opt) { 2046 jboolean isIPV4 = !ipv6_available() || fd1 == -1; 2047 2048 /* 2049 * IPv4 implementation 2050 */ 2051 if (isIPV4) { 2052 jobject netObject = NULL; // return is either an addr or a netif 2053 netObject = getIPv4NetworkInterface(env, this, fd, opt, 1); 2054 return netObject; 2055 } 2056 2057 /* 2058 * IPv6 implementation 2059 */ 2060 if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) || 2061 (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) { 2062 2063 static jclass ni_class; 2064 static jmethodID ni_ctrID; 2065 static jfieldID ni_indexID; 2066 static jfieldID ni_addrsID; 2067 static jclass ia_class; 2068 static jmethodID ia_anyLocalAddressID; 2069 2070 int index; 2071 int len = sizeof(index); 2072 2073 jobjectArray addrArray; 2074 jobject addr; 2075 jobject ni; 2076 2077 { 2078 if (getsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF, 2079 (char*)&index, &len) < 0) { 2080 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 2081 "Error getting socket option"); 2082 return NULL; 2083 } 2084 } 2085 2086 if (ni_class == NULL) { 2087 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface"); 2088 CHECK_NULL_RETURN(c, NULL); 2089 ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V"); 2090 CHECK_NULL_RETURN(ni_ctrID, NULL); 2091 ni_indexID = (*env)->GetFieldID(env, c, "index", "I"); 2092 CHECK_NULL_RETURN(ni_indexID, NULL); 2093 ni_addrsID = (*env)->GetFieldID(env, c, "addrs", 2094 "[Ljava/net/InetAddress;"); 2095 CHECK_NULL_RETURN(ni_addrsID, NULL); 2096 2097 ia_class = (*env)->FindClass(env, "java/net/InetAddress"); 2098 CHECK_NULL_RETURN(ia_class, NULL); 2099 ia_class = (*env)->NewGlobalRef(env, ia_class); 2100 CHECK_NULL_RETURN(ia_class, NULL); 2101 ia_anyLocalAddressID = (*env)->GetStaticMethodID(env, 2102 ia_class, 2103 "anyLocalAddress", 2104 "()Ljava/net/InetAddress;"); 2105 CHECK_NULL_RETURN(ia_anyLocalAddressID, NULL); 2106 ni_class = (*env)->NewGlobalRef(env, c); 2107 CHECK_NULL_RETURN(ni_class, NULL); 2108 } 2109 2110 /* 2111 * If multicast to a specific interface then return the 2112 * interface (for IF2) or the any address on that interface 2113 * (for IF). 2114 */ 2115 if (index > 0) { 2116 ni = Java_java_net_NetworkInterface_getByIndex0(env, ni_class, 2117 index); 2118 if (ni == NULL) { 2119 char errmsg[255]; 2120 sprintf(errmsg, 2121 "IPV6_MULTICAST_IF returned index to unrecognized interface: %d", 2122 index); 2123 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg); 2124 return NULL; 2125 } 2126 2127 /* 2128 * For IP_MULTICAST_IF2 return the NetworkInterface 2129 */ 2130 if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) { 2131 return ni; 2132 } 2133 2134 /* 2135 * For IP_MULTICAST_IF return addrs[0] 2136 */ 2137 addrArray = (*env)->GetObjectField(env, ni, ni_addrsID); 2138 if ((*env)->GetArrayLength(env, addrArray) < 1) { 2139 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 2140 "IPV6_MULTICAST_IF returned interface without IP bindings"); 2141 return NULL; 2142 } 2143 2144 addr = (*env)->GetObjectArrayElement(env, addrArray, 0); 2145 return addr; 2146 } else if (index == 0) { // index == 0 typically means IPv6 not configured on the interfaces 2147 // falling back to treat interface as configured for IPv4 2148 jobject netObject = NULL; 2149 netObject = getIPv4NetworkInterface(env, this, fd, opt, 0); 2150 if (netObject != NULL) { 2151 return netObject; 2152 } 2153 } 2154 2155 /* 2156 * Multicast to any address - return anyLocalAddress 2157 * or a NetworkInterface with addrs[0] set to anyLocalAddress 2158 */ 2159 2160 addr = (*env)->CallStaticObjectMethod(env, ia_class, ia_anyLocalAddressID, 2161 NULL); 2162 if (opt == java_net_SocketOptions_IP_MULTICAST_IF) { 2163 return addr; 2164 } 2165 2166 ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0); 2167 CHECK_NULL_RETURN(ni, NULL); 2168 (*env)->SetIntField(env, ni, ni_indexID, -1); 2169 addrArray = (*env)->NewObjectArray(env, 1, ia_class, NULL); 2170 CHECK_NULL_RETURN(addrArray, NULL); 2171 (*env)->SetObjectArrayElement(env, addrArray, 0, addr); 2172 (*env)->SetObjectField(env, ni, ni_addrsID, addrArray); 2173 return ni; 2174 } 2175 return NULL; 2176 } 2177 2178 2179 /* 2180 * Returns relevant info as a jint. 2181 * 2182 * Class: java_net_TwoStacksPlainDatagramSocketImpl 2183 * Method: socketGetOption 2184 * Signature: (I)Ljava/lang/Object; 2185 */ 2186 JNIEXPORT jobject JNICALL 2187 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketGetOption(JNIEnv *env, jobject this, 2188 jint opt) { 2189 2190 int fd=-1, fd1=-1; 2191 int level, optname, optlen; 2192 union { 2193 int i; 2194 } optval; 2195 int ipv6_supported = ipv6_available(); 2196 2197 fd = getFD(env, this); 2198 if (ipv6_supported) { 2199 fd1 = getFD1(env, this); 2200 } 2201 2202 if (fd < 0 && fd1 < 0) { 2203 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 2204 "Socket closed"); 2205 return NULL; 2206 } 2207 2208 /* 2209 * Handle IP_MULTICAST_IF separately 2210 */ 2211 if (opt == java_net_SocketOptions_IP_MULTICAST_IF || 2212 opt == java_net_SocketOptions_IP_MULTICAST_IF2) { 2213 return getMulticastInterface(env, this, fd, fd1, opt); 2214 } 2215 2216 /* 2217 * Map the Java level socket option to the platform specific 2218 * level and option name. 2219 */ 2220 if (NET_MapSocketOption(opt, &level, &optname)) { 2221 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option"); 2222 return NULL; 2223 } 2224 2225 if (fd == -1) { 2226 if (NET_MapSocketOptionV6(opt, &level, &optname)) { 2227 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option"); 2228 return NULL; 2229 } 2230 fd = fd1; /* must be IPv6 only */ 2231 } 2232 2233 optlen = sizeof(optval.i); 2234 if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) { 2235 char errmsg[255]; 2236 sprintf(errmsg, "error getting socket option: %s\n", strerror(errno)); 2237 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg); 2238 return NULL; 2239 } 2240 2241 switch (opt) { 2242 case java_net_SocketOptions_SO_BROADCAST: 2243 case java_net_SocketOptions_SO_REUSEADDR: 2244 return createBoolean(env, optval.i); 2245 2246 case java_net_SocketOptions_IP_MULTICAST_LOOP: 2247 /* getLoopbackMode() returns true if IP_MULTICAST_LOOP is disabled */ 2248 return createBoolean(env, !optval.i); 2249 2250 case java_net_SocketOptions_SO_SNDBUF: 2251 case java_net_SocketOptions_SO_RCVBUF: 2252 case java_net_SocketOptions_IP_TOS: 2253 return createInteger(env, optval.i); 2254 2255 default : 2256 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 2257 "Socket option not supported by TwoStacksPlainDatagramSocketImpl"); 2258 return NULL; 2259 2260 } 2261 } 2262 2263 /* 2264 * Returns local address of the socket. 2265 * 2266 * Class: java_net_TwoStacksPlainDatagramSocketImpl 2267 * Method: socketLocalAddress 2268 * Signature: (I)Ljava/lang/Object; 2269 */ 2270 JNIEXPORT jobject JNICALL 2271 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketLocalAddress(JNIEnv *env, jobject this, 2272 jint family) { 2273 2274 int fd=-1, fd1=-1; 2275 SOCKETADDRESS him; 2276 int len = 0; 2277 int port; 2278 jobject iaObj; 2279 int ipv6_supported = ipv6_available(); 2280 2281 fd = getFD(env, this); 2282 if (ipv6_supported) { 2283 fd1 = getFD1(env, this); 2284 } 2285 2286 if (fd < 0 && fd1 < 0) { 2287 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 2288 "Socket closed"); 2289 return NULL; 2290 } 2291 2292 /* find out local IP address */ 2293 2294 len = sizeof (struct sockaddr_in); 2295 2296 /* family==-1 when socket is not connected */ 2297 if ((family == IPv6) || (family == -1 && fd == -1)) { 2298 fd = fd1; /* must be IPv6 only */ 2299 len = sizeof (struct SOCKADDR_IN6); 2300 } 2301 2302 if (fd == -1) { 2303 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 2304 "Socket closed"); 2305 return NULL; 2306 } 2307 2308 if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) { 2309 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 2310 "Error getting socket name"); 2311 return NULL; 2312 } 2313 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port); 2314 2315 return iaObj; 2316 } 2317 2318 /* 2319 * Class: java_net_TwoStacksPlainDatagramSocketImpl 2320 * Method: setTimeToLive 2321 * Signature: (I)V 2322 */ 2323 JNIEXPORT void JNICALL 2324 Java_java_net_TwoStacksPlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this, 2325 jint ttl) { 2326 2327 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 2328 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID); 2329 int fd = -1, fd1 = -1; 2330 int ittl = (int)ttl; 2331 2332 if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { 2333 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 2334 "Socket closed"); 2335 return; 2336 } else { 2337 if (!IS_NULL(fdObj)) { 2338 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 2339 } 2340 if (!IS_NULL(fd1Obj)) { 2341 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID); 2342 } 2343 } 2344 2345 /* setsockopt to be correct ttl */ 2346 if (fd >= 0) { 2347 if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl, 2348 sizeof (ittl)) < 0) { 2349 NET_ThrowCurrent(env, "set IP_MULTICAST_TTL failed"); 2350 } 2351 } 2352 2353 if (fd1 >= 0) { 2354 if (NET_SetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&ittl, 2355 sizeof(ittl)) <0) { 2356 NET_ThrowCurrent(env, "set IPV6_MULTICAST_HOPS failed"); 2357 } 2358 } 2359 } 2360 2361 /* 2362 * Class: java_net_TwoStacksPlainDatagramSocketImpl 2363 * Method: setTTL 2364 * Signature: (B)V 2365 */ 2366 JNIEXPORT void JNICALL 2367 Java_java_net_TwoStacksPlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this, 2368 jbyte ttl) { 2369 Java_java_net_TwoStacksPlainDatagramSocketImpl_setTimeToLive(env, this, 2370 (jint)ttl & 0xFF); 2371 } 2372 2373 /* 2374 * Class: java_net_TwoStacksPlainDatagramSocketImpl 2375 * Method: getTimeToLive 2376 * Signature: ()I 2377 */ 2378 JNIEXPORT jint JNICALL 2379 Java_java_net_TwoStacksPlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) { 2380 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 2381 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID); 2382 int fd = -1, fd1 = -1; 2383 int ttl = 0; 2384 int len = sizeof(ttl); 2385 2386 if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { 2387 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 2388 "Socket closed"); 2389 return -1; 2390 } else { 2391 if (!IS_NULL(fdObj)) { 2392 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 2393 } 2394 if (!IS_NULL(fd1Obj)) { 2395 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID); 2396 } 2397 } 2398 2399 /* getsockopt of ttl */ 2400 if (fd >= 0) { 2401 if (NET_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, &len) < 0) { 2402 NET_ThrowCurrent(env, "get IP_MULTICAST_TTL failed"); 2403 return -1; 2404 } 2405 return (jint)ttl; 2406 } 2407 if (fd1 >= 0) { 2408 if (NET_GetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char*)&ttl, &len) < 0) { 2409 NET_ThrowCurrent(env, "get IP_MULTICAST_TTL failed"); 2410 return -1; 2411 } 2412 return (jint)ttl; 2413 } 2414 return -1; 2415 } 2416 2417 /* 2418 * Class: java_net_TwoStacksPlainDatagramSocketImpl 2419 * Method: getTTL 2420 * Signature: ()B 2421 */ 2422 JNIEXPORT jbyte JNICALL 2423 Java_java_net_TwoStacksPlainDatagramSocketImpl_getTTL(JNIEnv *env, jobject this) { 2424 int result = Java_java_net_TwoStacksPlainDatagramSocketImpl_getTimeToLive(env, this); 2425 2426 return (jbyte)result; 2427 } 2428 2429 /* join/leave the named group on the named interface, or if no interface specified 2430 * then the interface set with setInterfac(), or the default interface otherwise */ 2431 2432 static void mcast_join_leave(JNIEnv *env, jobject this, 2433 jobject iaObj, jobject niObj, 2434 jboolean join) 2435 { 2436 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 2437 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID); 2438 jint fd = -1, fd1 = -1; 2439 2440 SOCKETADDRESS name; 2441 struct ip_mreq mname; 2442 struct ipv6_mreq mname6; 2443 2444 struct in_addr in; 2445 DWORD ifindex; 2446 2447 int len, family; 2448 int ipv6_supported = ipv6_available(); 2449 int cmd ; 2450 2451 if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { 2452 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 2453 "Socket closed"); 2454 return; 2455 } 2456 if (!IS_NULL(fdObj)) { 2457 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 2458 } 2459 if (ipv6_supported && !IS_NULL(fd1Obj)) { 2460 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID); 2461 } 2462 2463 if (IS_NULL(iaObj)) { 2464 JNU_ThrowNullPointerException(env, "address"); 2465 return; 2466 } 2467 2468 if (NET_InetAddressToSockaddr(env, iaObj, 0, (struct sockaddr *)&name, &len, JNI_FALSE) != 0) { 2469 return; 2470 } 2471 2472 /* Set the multicast group address in the ip_mreq field 2473 * eventually this check should be done by the security manager 2474 */ 2475 family = name.him.sa_family; 2476 2477 if (family == AF_INET) { 2478 int address = name.him4.sin_addr.s_addr; 2479 if (!IN_MULTICAST(ntohl(address))) { 2480 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "not in multicast"); 2481 return; 2482 } 2483 mname.imr_multiaddr.s_addr = address; 2484 if (fd < 0) { 2485 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Can't join an IPv4 group on an IPv6 only socket"); 2486 return; 2487 } 2488 if (IS_NULL(niObj)) { 2489 len = sizeof (in); 2490 if (NET_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF, 2491 (char *)&in, &len) < 0) { 2492 NET_ThrowCurrent(env, "get IP_MULTICAST_IF failed"); 2493 return; 2494 } 2495 mname.imr_interface.s_addr = in.s_addr; 2496 } else { 2497 if (getInet4AddrFromIf (env, niObj, &mname.imr_interface) != 0) { 2498 NET_ThrowCurrent(env, "no Inet4Address associated with interface"); 2499 return; 2500 } 2501 } 2502 2503 cmd = join ? IP_ADD_MEMBERSHIP: IP_DROP_MEMBERSHIP; 2504 2505 /* Join the multicast group */ 2506 if (NET_SetSockOpt(fd, IPPROTO_IP, cmd, (char *) &mname, sizeof (mname)) < 0) { 2507 if (WSAGetLastError() == WSAENOBUFS) { 2508 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 2509 "IP_ADD_MEMBERSHIP failed (out of hardware filters?)"); 2510 } else { 2511 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException","error setting options"); 2512 } 2513 } 2514 } else /* AF_INET6 */ { 2515 if (ipv6_supported) { 2516 struct in6_addr *address; 2517 address = &name.him6.sin6_addr; 2518 if (!IN6_IS_ADDR_MULTICAST(address)) { 2519 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "not in6 multicast"); 2520 return; 2521 } 2522 mname6.ipv6mr_multiaddr = *address; 2523 } else { 2524 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "IPv6 not supported"); 2525 return; 2526 } 2527 if (fd1 < 0) { 2528 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Can't join an IPv6 group on a IPv4 socket"); 2529 return; 2530 } 2531 if (IS_NULL(niObj)) { 2532 len = sizeof (ifindex); 2533 if (NET_GetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, &len) < 0) { 2534 NET_ThrowCurrent(env, "get IPV6_MULTICAST_IF failed"); 2535 return; 2536 } 2537 } else { 2538 ifindex = getIndexFromIf (env, niObj); 2539 if (ifindex == -1) { 2540 NET_ThrowCurrent(env, "get ifindex failed"); 2541 return; 2542 } 2543 } 2544 mname6.ipv6mr_interface = ifindex; 2545 cmd = join ? IPV6_ADD_MEMBERSHIP: IPV6_DROP_MEMBERSHIP; 2546 2547 /* Join the multicast group */ 2548 if (NET_SetSockOpt(fd1, IPPROTO_IPV6, cmd, (char *) &mname6, sizeof (mname6)) < 0) { 2549 if (WSAGetLastError() == WSAENOBUFS) { 2550 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 2551 "IP_ADD_MEMBERSHIP failed (out of hardware filters?)"); 2552 } else { 2553 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException","error setting options"); 2554 } 2555 } 2556 } 2557 2558 return; 2559 } 2560 2561 /* 2562 * Class: java_net_TwoStacksPlainDatagramSocketImpl 2563 * Method: join 2564 * Signature: (Ljava/net/InetAddress;)V 2565 */ 2566 JNIEXPORT void JNICALL 2567 Java_java_net_TwoStacksPlainDatagramSocketImpl_join(JNIEnv *env, jobject this, 2568 jobject iaObj, jobject niObj) 2569 { 2570 mcast_join_leave (env, this, iaObj, niObj, JNI_TRUE); 2571 } 2572 2573 /* 2574 * Class: java_net_TwoStacksPlainDatagramSocketImpl 2575 * Method: leave 2576 * Signature: (Ljava/net/InetAddress;)V 2577 */ 2578 JNIEXPORT void JNICALL 2579 Java_java_net_TwoStacksPlainDatagramSocketImpl_leave(JNIEnv *env, jobject this, 2580 jobject iaObj, jobject niObj) 2581 { 2582 mcast_join_leave (env, this, iaObj, niObj, JNI_FALSE); 2583 }