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