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