1 /* 2 * Copyright (c) 1997, 2015, 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 <errno.h> 27 #include <netinet/in.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <sys/types.h> 31 #include <sys/socket.h> 32 33 #ifdef __solaris__ 34 #include <fcntl.h> 35 #include <unistd.h> 36 #include <stropts.h> 37 38 #ifndef BSD_COMP 39 #define BSD_COMP 40 #endif 41 #endif 42 #ifdef __linux__ 43 #include <unistd.h> 44 #include <sys/sysctl.h> 45 #include <sys/utsname.h> 46 #include <netinet/ip.h> 47 48 #define IPV6_MULTICAST_IF 17 49 #ifndef SO_BSDCOMPAT 50 #define SO_BSDCOMPAT 14 51 #endif 52 /** 53 * IP_MULTICAST_ALL has been supported since kernel version 2.6.31 54 * but we may be building on a machine that is older than that. 55 */ 56 #ifndef IP_MULTICAST_ALL 57 #define IP_MULTICAST_ALL 49 58 #endif 59 #endif // __linux__ 60 61 #include <sys/ioctl.h> 62 63 #ifndef IPTOS_TOS_MASK 64 #define IPTOS_TOS_MASK 0x1e 65 #endif 66 #ifndef IPTOS_PREC_MASK 67 #define IPTOS_PREC_MASK 0xe0 68 #endif 69 70 #include "jvm.h" 71 #include "jni_util.h" 72 #include "net_util.h" 73 74 #include "java_net_SocketOptions.h" 75 #include "java_net_PlainDatagramSocketImpl.h" 76 #include "java_net_NetworkInterface.h" 77 /************************************************************************ 78 * PlainDatagramSocketImpl 79 */ 80 81 static jfieldID IO_fd_fdID; 82 83 static jfieldID pdsi_fdID; 84 static jfieldID pdsi_timeoutID; 85 static jfieldID pdsi_trafficClassID; 86 static jfieldID pdsi_localPortID; 87 static jfieldID pdsi_connected; 88 static jfieldID pdsi_connectedAddress; 89 static jfieldID pdsi_connectedPort; 90 91 extern void setDefaultScopeID(JNIEnv *env, struct sockaddr *him); 92 extern int getDefaultScopeID(JNIEnv *env); 93 94 /* 95 * Returns a java.lang.Integer based on 'i' 96 */ 97 static jobject createInteger(JNIEnv *env, int i) { 98 static jclass i_class; 99 static jmethodID i_ctrID; 100 101 if (i_class == NULL) { 102 jclass c = (*env)->FindClass(env, "java/lang/Integer"); 103 CHECK_NULL_RETURN(c, NULL); 104 i_ctrID = (*env)->GetMethodID(env, c, "<init>", "(I)V"); 105 CHECK_NULL_RETURN(i_ctrID, NULL); 106 i_class = (*env)->NewGlobalRef(env, c); 107 CHECK_NULL_RETURN(i_class, NULL); 108 } 109 110 return ( (*env)->NewObject(env, i_class, i_ctrID, i) ); 111 } 112 113 /* 114 * Returns a java.lang.Boolean based on 'b' 115 */ 116 static jobject createBoolean(JNIEnv *env, int b) { 117 static jclass b_class; 118 static jmethodID b_ctrID; 119 120 if (b_class == NULL) { 121 jclass c = (*env)->FindClass(env, "java/lang/Boolean"); 122 CHECK_NULL_RETURN(c, NULL); 123 b_ctrID = (*env)->GetMethodID(env, c, "<init>", "(Z)V"); 124 CHECK_NULL_RETURN(b_ctrID, NULL); 125 b_class = (*env)->NewGlobalRef(env, c); 126 CHECK_NULL_RETURN(b_class, NULL); 127 } 128 129 return( (*env)->NewObject(env, b_class, b_ctrID, (jboolean)(b!=0)) ); 130 } 131 132 133 /* 134 * Returns the fd for a PlainDatagramSocketImpl or -1 135 * if closed. 136 */ 137 static int getFD(JNIEnv *env, jobject this) { 138 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 139 if (fdObj == NULL) { 140 return -1; 141 } 142 return (*env)->GetIntField(env, fdObj, IO_fd_fdID); 143 } 144 145 146 /* 147 * Class: java_net_PlainDatagramSocketImpl 148 * Method: init 149 * Signature: ()V 150 */ 151 JNIEXPORT void JNICALL 152 Java_java_net_PlainDatagramSocketImpl_init(JNIEnv *env, jclass cls) { 153 154 #ifdef __linux__ 155 struct utsname sysinfo; 156 #endif 157 pdsi_fdID = (*env)->GetFieldID(env, cls, "fd", 158 "Ljava/io/FileDescriptor;"); 159 CHECK_NULL(pdsi_fdID); 160 pdsi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I"); 161 CHECK_NULL(pdsi_timeoutID); 162 pdsi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I"); 163 CHECK_NULL(pdsi_trafficClassID); 164 pdsi_localPortID = (*env)->GetFieldID(env, cls, "localPort", "I"); 165 CHECK_NULL(pdsi_localPortID); 166 pdsi_connected = (*env)->GetFieldID(env, cls, "connected", "Z"); 167 CHECK_NULL(pdsi_connected); 168 pdsi_connectedAddress = (*env)->GetFieldID(env, cls, "connectedAddress", 169 "Ljava/net/InetAddress;"); 170 CHECK_NULL(pdsi_connectedAddress); 171 pdsi_connectedPort = (*env)->GetFieldID(env, cls, "connectedPort", "I"); 172 CHECK_NULL(pdsi_connectedPort); 173 174 IO_fd_fdID = NET_GetFileDescriptorID(env); 175 CHECK_NULL(IO_fd_fdID); 176 177 Java_java_net_InetAddress_init(env, 0); 178 Java_java_net_Inet4Address_init(env, 0); 179 Java_java_net_Inet6Address_init(env, 0); 180 Java_java_net_NetworkInterface_init(env, 0); 181 182 } 183 184 /* 185 * Class: java_net_PlainDatagramSocketImpl 186 * Method: bind 187 * Signature: (ILjava/net/InetAddress;)V 188 */ 189 JNIEXPORT void JNICALL 190 Java_java_net_PlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this, 191 jint localport, jobject iaObj) { 192 /* fdObj is the FileDescriptor field on this */ 193 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 194 /* fd is an int field on fdObj */ 195 int fd; 196 int len = 0; 197 SOCKADDR him; 198 199 if (IS_NULL(fdObj)) { 200 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 201 "Socket closed"); 202 return; 203 } else { 204 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 205 } 206 207 if (IS_NULL(iaObj)) { 208 JNU_ThrowNullPointerException(env, "iaObj is null."); 209 return; 210 } 211 212 /* bind */ 213 if (NET_InetAddressToSockaddr(env, iaObj, localport, (struct sockaddr *)&him, &len, JNI_TRUE) != 0) { 214 return; 215 } 216 setDefaultScopeID(env, (struct sockaddr *)&him); 217 218 if (NET_Bind(fd, (struct sockaddr *)&him, len) < 0) { 219 if (errno == EADDRINUSE || errno == EADDRNOTAVAIL || 220 errno == EPERM || errno == EACCES) { 221 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException", 222 "Bind failed"); 223 } else { 224 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 225 "Bind failed"); 226 } 227 return; 228 } 229 230 /* initialize the local port */ 231 if (localport == 0) { 232 /* Now that we're a connected socket, let's extract the port number 233 * that the system chose for us and store it in the Socket object. 234 */ 235 if (JVM_GetSockName(fd, (struct sockaddr *)&him, &len) == -1) { 236 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 237 "Error getting socket name"); 238 return; 239 } 240 241 localport = NET_GetPortFromSockaddr((struct sockaddr *)&him); 242 243 (*env)->SetIntField(env, this, pdsi_localPortID, localport); 244 } else { 245 (*env)->SetIntField(env, this, pdsi_localPortID, localport); 246 } 247 } 248 249 /* 250 * Class: java_net_PlainDatagramSocketImpl 251 * Method: connect0 252 * Signature: (Ljava/net/InetAddress;I)V 253 */ 254 JNIEXPORT void JNICALL 255 Java_java_net_PlainDatagramSocketImpl_connect0(JNIEnv *env, jobject this, 256 jobject address, jint port) { 257 /* The object's field */ 258 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 259 /* The fdObj'fd */ 260 jint fd; 261 /* The packetAddress address, family and port */ 262 SOCKADDR rmtaddr; 263 int len = 0; 264 265 if (IS_NULL(fdObj)) { 266 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 267 "Socket closed"); 268 return; 269 } 270 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 271 272 if (IS_NULL(address)) { 273 JNU_ThrowNullPointerException(env, "address"); 274 return; 275 } 276 277 if (NET_InetAddressToSockaddr(env, address, port, (struct sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) { 278 return; 279 } 280 281 setDefaultScopeID(env, (struct sockaddr *)&rmtaddr); 282 283 if (JVM_Connect(fd, (struct sockaddr *)&rmtaddr, len) == -1) { 284 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException", 285 "Connect failed"); 286 return; 287 } 288 289 } 290 291 /* 292 * Class: java_net_PlainDatagramSocketImpl 293 * Method: disconnect0 294 * Signature: ()V 295 */ 296 JNIEXPORT void JNICALL 297 Java_java_net_PlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jint family) { 298 /* The object's field */ 299 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 300 /* The fdObj'fd */ 301 jint fd; 302 303 #if defined(__linux__) || defined(_ALLBSD_SOURCE) 304 SOCKADDR addr; 305 int len; 306 #endif 307 308 if (IS_NULL(fdObj)) { 309 return; 310 } 311 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 312 313 #if defined(__linux__) || defined(_ALLBSD_SOURCE) 314 memset(&addr, 0, sizeof(addr)); 315 #ifdef AF_INET6 316 if (ipv6_available()) { 317 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)&addr; 318 him6->sin6_family = AF_UNSPEC; 319 len = sizeof(struct sockaddr_in6); 320 } else 321 #endif 322 { 323 struct sockaddr_in *him4 = (struct sockaddr_in*)&addr; 324 him4->sin_family = AF_UNSPEC; 325 len = sizeof(struct sockaddr_in); 326 } 327 JVM_Connect(fd, (struct sockaddr *)&addr, len); 328 329 #ifdef __linux__ 330 int localPort = 0; 331 if (JVM_GetSockName(fd, (struct sockaddr *)&addr, &len) == -1) 332 return; 333 334 localPort = NET_GetPortFromSockaddr((struct sockaddr *)&addr); 335 if (localPort == 0) { 336 localPort = (*env)->GetIntField(env, this, pdsi_localPortID); 337 #ifdef AF_INET6 338 if (((struct sockaddr*)&addr)->sa_family == AF_INET6) { 339 ((struct sockaddr_in6*)&addr)->sin6_port = htons(localPort); 340 } else 341 #endif /* AF_INET6 */ 342 { 343 ((struct sockaddr_in*)&addr)->sin_port = htons(localPort); 344 } 345 346 NET_Bind(fd, (struct sockaddr *)&addr, len); 347 } 348 349 #endif 350 #else 351 JVM_Connect(fd, 0, 0); 352 #endif 353 } 354 355 /* 356 * Class: java_net_PlainDatagramSocketImpl 357 * Method: send 358 * Signature: (Ljava/net/DatagramPacket;)V 359 */ 360 JNIEXPORT void JNICALL 361 Java_java_net_PlainDatagramSocketImpl_send(JNIEnv *env, jobject this, 362 jobject packet) { 363 364 char BUF[MAX_BUFFER_LEN]; 365 char *fullPacket = NULL; 366 int ret, mallocedPacket = JNI_FALSE; 367 /* The object's field */ 368 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 369 jint trafficClass = (*env)->GetIntField(env, this, pdsi_trafficClassID); 370 371 jbyteArray packetBuffer; 372 jobject packetAddress; 373 jint packetBufferOffset, packetBufferLen, packetPort; 374 jboolean connected; 375 376 /* The fdObj'fd */ 377 jint fd; 378 379 SOCKADDR rmtaddr, *rmtaddrP=&rmtaddr; 380 int len; 381 382 if (IS_NULL(fdObj)) { 383 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 384 "Socket closed"); 385 return; 386 } 387 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 388 389 if (IS_NULL(packet)) { 390 JNU_ThrowNullPointerException(env, "packet"); 391 return; 392 } 393 394 connected = (*env)->GetBooleanField(env, this, pdsi_connected); 395 396 packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID); 397 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID); 398 if (IS_NULL(packetBuffer) || IS_NULL(packetAddress)) { 399 JNU_ThrowNullPointerException(env, "null buffer || null address"); 400 return; 401 } 402 403 packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID); 404 packetBufferLen = (*env)->GetIntField(env, packet, dp_lengthID); 405 406 if (connected) { 407 /* arg to NET_Sendto () null in this case */ 408 len = 0; 409 rmtaddrP = 0; 410 } else { 411 packetPort = (*env)->GetIntField(env, packet, dp_portID); 412 if (NET_InetAddressToSockaddr(env, packetAddress, packetPort, (struct sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) { 413 return; 414 } 415 } 416 setDefaultScopeID(env, (struct sockaddr *)&rmtaddr); 417 418 if (packetBufferLen > MAX_BUFFER_LEN) { 419 /* When JNI-ifying the JDK's IO routines, we turned 420 * reads and writes of byte arrays of size greater 421 * than 2048 bytes into several operations of size 2048. 422 * This saves a malloc()/memcpy()/free() for big 423 * buffers. This is OK for file IO and TCP, but that 424 * strategy violates the semantics of a datagram protocol. 425 * (one big send) != (several smaller sends). So here 426 * we *must* allocate the buffer. Note it needn't be bigger 427 * than 65,536 (0xFFFF), the max size of an IP packet. 428 * Anything bigger should be truncated anyway. 429 * 430 * We may want to use a smarter allocation scheme at some 431 * point. 432 */ 433 if (packetBufferLen > MAX_PACKET_LEN) { 434 packetBufferLen = MAX_PACKET_LEN; 435 } 436 fullPacket = (char *)malloc(packetBufferLen); 437 438 if (!fullPacket) { 439 JNU_ThrowOutOfMemoryError(env, "Send buffer native heap allocation failed"); 440 return; 441 } else { 442 mallocedPacket = JNI_TRUE; 443 } 444 } else { 445 fullPacket = &(BUF[0]); 446 } 447 448 (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset, packetBufferLen, 449 (jbyte *)fullPacket); 450 #ifdef AF_INET6 451 if (trafficClass != 0 && ipv6_available()) { 452 NET_SetTrafficClass((struct sockaddr *)&rmtaddr, trafficClass); 453 } 454 #endif /* AF_INET6 */ 455 456 457 /* 458 * Send the datagram. 459 * 460 * If we are connected it's possible that sendto will return 461 * ECONNREFUSED indicating that an ICMP port unreachable has 462 * received. 463 */ 464 ret = NET_SendTo(fd, fullPacket, packetBufferLen, 0, 465 (struct sockaddr *)rmtaddrP, len); 466 467 if (ret < 0) { 468 switch (ret) { 469 case JVM_IO_ERR : 470 if (errno == ECONNREFUSED) { 471 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 472 "ICMP Port Unreachable"); 473 } else { 474 NET_ThrowByNameWithLastError(env, "java/io/IOException", "sendto failed"); 475 } 476 break; 477 478 case JVM_IO_INTR: 479 JNU_ThrowByName(env, "java/io/InterruptedIOException", 480 "operation interrupted"); 481 break; 482 } 483 } 484 485 if (mallocedPacket) { 486 free(fullPacket); 487 } 488 return; 489 } 490 491 /* 492 * Class: java_net_PlainDatagramSocketImpl 493 * Method: peek 494 * Signature: (Ljava/net/InetAddress;)I 495 */ 496 JNIEXPORT jint JNICALL 497 Java_java_net_PlainDatagramSocketImpl_peek(JNIEnv *env, jobject this, 498 jobject addressObj) { 499 500 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 501 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID); 502 jint fd; 503 ssize_t n; 504 SOCKADDR remote_addr; 505 int len; 506 char buf[1]; 507 jint family; 508 jobject iaObj; 509 int port; 510 if (IS_NULL(fdObj)) { 511 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 512 return -1; 513 } else { 514 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 515 } 516 if (IS_NULL(addressObj)) { 517 JNU_ThrowNullPointerException(env, "Null address in peek()"); 518 } 519 if (timeout) { 520 int ret = NET_Timeout(fd, timeout); 521 if (ret == 0) { 522 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 523 "Peek timed out"); 524 return ret; 525 } else if (ret == JVM_IO_ERR) { 526 if (errno == EBADF) { 527 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 528 } else if (errno == ENOMEM) { 529 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed"); 530 } else { 531 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed"); 532 } 533 return ret; 534 } else if (ret == JVM_IO_INTR) { 535 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 536 "operation interrupted"); 537 return ret; /* WARNING: SHOULD WE REALLY RETURN -2??? */ 538 } 539 } 540 541 len = SOCKADDR_LEN; 542 n = NET_RecvFrom(fd, buf, 1, MSG_PEEK, 543 (struct sockaddr *)&remote_addr, &len); 544 545 if (n == JVM_IO_ERR) { 546 547 #ifdef __solaris__ 548 if (errno == ECONNREFUSED) { 549 int orig_errno = errno; 550 (void) recv(fd, buf, 1, 0); 551 errno = orig_errno; 552 } 553 #endif 554 if (errno == ECONNREFUSED) { 555 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 556 "ICMP Port Unreachable"); 557 } else { 558 if (errno == EBADF) { 559 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 560 } else { 561 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed"); 562 } 563 } 564 return 0; 565 } else if (n == JVM_IO_INTR) { 566 JNU_ThrowByName(env, "java/io/InterruptedIOException", 0); 567 return 0; 568 } 569 570 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port); 571 #ifdef AF_INET6 572 family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6; 573 #else 574 family = AF_INET; 575 #endif 576 if (family == AF_INET) { /* this API can't handle IPV6 addresses */ 577 int address = getInetAddress_addr(env, iaObj); 578 setInetAddress_addr(env, addressObj, address); 579 } 580 return port; 581 } 582 583 JNIEXPORT jint JNICALL 584 Java_java_net_PlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this, 585 jobject packet) { 586 587 char BUF[MAX_BUFFER_LEN]; 588 char *fullPacket = NULL; 589 int mallocedPacket = JNI_FALSE; 590 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 591 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID); 592 593 jbyteArray packetBuffer; 594 jint packetBufferOffset, packetBufferLen; 595 596 int fd; 597 598 int n; 599 SOCKADDR remote_addr; 600 int len; 601 int port; 602 603 if (IS_NULL(fdObj)) { 604 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 605 "Socket closed"); 606 return -1; 607 } 608 609 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 610 611 if (IS_NULL(packet)) { 612 JNU_ThrowNullPointerException(env, "packet"); 613 return -1; 614 } 615 616 packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID); 617 if (IS_NULL(packetBuffer)) { 618 JNU_ThrowNullPointerException(env, "packet buffer"); 619 return -1; 620 } 621 packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID); 622 packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID); 623 if (timeout) { 624 int ret = NET_Timeout(fd, timeout); 625 if (ret == 0) { 626 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 627 "Receive timed out"); 628 return -1; 629 } else if (ret == JVM_IO_ERR) { 630 if (errno == ENOMEM) { 631 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed"); 632 #ifdef __linux__ 633 } else if (errno == EBADF) { 634 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 635 } else { 636 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed"); 637 #else 638 } else { 639 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 640 #endif 641 } 642 return -1; 643 } else if (ret == JVM_IO_INTR) { 644 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 645 "operation interrupted"); 646 return -1; 647 } 648 } 649 650 if (packetBufferLen > MAX_BUFFER_LEN) { 651 652 /* When JNI-ifying the JDK's IO routines, we turned 653 * reads and writes of byte arrays of size greater 654 * than 2048 bytes into several operations of size 2048. 655 * This saves a malloc()/memcpy()/free() for big 656 * buffers. This is OK for file IO and TCP, but that 657 * strategy violates the semantics of a datagram protocol. 658 * (one big send) != (several smaller sends). So here 659 * we *must* allocate the buffer. Note it needn't be bigger 660 * than 65,536 (0xFFFF), the max size of an IP packet. 661 * anything bigger is truncated anyway. 662 * 663 * We may want to use a smarter allocation scheme at some 664 * point. 665 */ 666 if (packetBufferLen > MAX_PACKET_LEN) { 667 packetBufferLen = MAX_PACKET_LEN; 668 } 669 fullPacket = (char *)malloc(packetBufferLen); 670 671 if (!fullPacket) { 672 JNU_ThrowOutOfMemoryError(env, "Peek buffer native heap allocation failed"); 673 return -1; 674 } else { 675 mallocedPacket = JNI_TRUE; 676 } 677 } else { 678 fullPacket = &(BUF[0]); 679 } 680 681 len = SOCKADDR_LEN; 682 n = NET_RecvFrom(fd, fullPacket, packetBufferLen, MSG_PEEK, 683 (struct sockaddr *)&remote_addr, &len); 684 /* truncate the data if the packet's length is too small */ 685 if (n > packetBufferLen) { 686 n = packetBufferLen; 687 } 688 if (n == JVM_IO_ERR) { 689 690 #ifdef __solaris__ 691 if (errno == ECONNREFUSED) { 692 int orig_errno = errno; 693 (void) recv(fd, fullPacket, 1, 0); 694 errno = orig_errno; 695 } 696 #endif 697 (*env)->SetIntField(env, packet, dp_offsetID, 0); 698 (*env)->SetIntField(env, packet, dp_lengthID, 0); 699 if (errno == ECONNREFUSED) { 700 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 701 "ICMP Port Unreachable"); 702 } else { 703 if (errno == EBADF) { 704 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 705 } else { 706 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed"); 707 } 708 } 709 } else if (n == JVM_IO_INTR) { 710 (*env)->SetIntField(env, packet, dp_offsetID, 0); 711 (*env)->SetIntField(env, packet, dp_lengthID, 0); 712 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 713 "operation interrupted"); 714 } else { 715 /* 716 * success - fill in received address... 717 * 718 * REMIND: Fill in an int on the packet, and create inetadd 719 * object in Java, as a performance improvement. Also 720 * construct the inetadd object lazily. 721 */ 722 723 jobject packetAddress; 724 725 /* 726 * Check if there is an InetAddress already associated with this 727 * packet. If so we check if it is the same source address. We 728 * can't update any existing InetAddress because it is immutable 729 */ 730 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID); 731 if (packetAddress != NULL) { 732 if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) { 733 /* force a new InetAddress to be created */ 734 packetAddress = NULL; 735 } 736 } 737 if (packetAddress == NULL) { 738 packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port); 739 /* stuff the new Inetaddress in the packet */ 740 (*env)->SetObjectField(env, packet, dp_addressID, packetAddress); 741 } else { 742 /* only get the new port number */ 743 port = NET_GetPortFromSockaddr((struct sockaddr *)&remote_addr); 744 } 745 /* and fill in the data, remote address/port and such */ 746 (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n, 747 (jbyte *)fullPacket); 748 (*env)->SetIntField(env, packet, dp_portID, port); 749 (*env)->SetIntField(env, packet, dp_lengthID, n); 750 } 751 752 if (mallocedPacket) { 753 free(fullPacket); 754 } 755 return port; 756 } 757 758 /* 759 * Class: java_net_PlainDatagramSocketImpl 760 * Method: receive 761 * Signature: (Ljava/net/DatagramPacket;)V 762 */ 763 JNIEXPORT void JNICALL 764 Java_java_net_PlainDatagramSocketImpl_receive0(JNIEnv *env, jobject this, 765 jobject packet) { 766 767 char BUF[MAX_BUFFER_LEN]; 768 char *fullPacket = NULL; 769 int mallocedPacket = JNI_FALSE; 770 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 771 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID); 772 773 jbyteArray packetBuffer; 774 jint packetBufferOffset, packetBufferLen; 775 776 int fd; 777 778 int n; 779 SOCKADDR remote_addr; 780 int len; 781 jboolean retry; 782 #ifdef __linux__ 783 jboolean connected = JNI_FALSE; 784 jobject connectedAddress = NULL; 785 jint connectedPort = 0; 786 jlong prevTime = 0; 787 #endif 788 789 if (IS_NULL(fdObj)) { 790 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 791 "Socket closed"); 792 return; 793 } 794 795 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 796 797 if (IS_NULL(packet)) { 798 JNU_ThrowNullPointerException(env, "packet"); 799 return; 800 } 801 802 packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID); 803 if (IS_NULL(packetBuffer)) { 804 JNU_ThrowNullPointerException(env, "packet buffer"); 805 return; 806 } 807 packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID); 808 packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID); 809 810 if (packetBufferLen > MAX_BUFFER_LEN) { 811 812 /* When JNI-ifying the JDK's IO routines, we turned 813 * reads and writes of byte arrays of size greater 814 * than 2048 bytes into several operations of size 2048. 815 * This saves a malloc()/memcpy()/free() for big 816 * buffers. This is OK for file IO and TCP, but that 817 * strategy violates the semantics of a datagram protocol. 818 * (one big send) != (several smaller sends). So here 819 * we *must* allocate the buffer. Note it needn't be bigger 820 * than 65,536 (0xFFFF) the max size of an IP packet, 821 * anything bigger is truncated anyway. 822 * 823 * We may want to use a smarter allocation scheme at some 824 * point. 825 */ 826 if (packetBufferLen > MAX_PACKET_LEN) { 827 packetBufferLen = MAX_PACKET_LEN; 828 } 829 fullPacket = (char *)malloc(packetBufferLen); 830 831 if (!fullPacket) { 832 JNU_ThrowOutOfMemoryError(env, "Receive buffer native heap allocation failed"); 833 return; 834 } else { 835 mallocedPacket = JNI_TRUE; 836 } 837 } else { 838 fullPacket = &(BUF[0]); 839 } 840 841 do { 842 retry = JNI_FALSE; 843 844 if (timeout) { 845 int ret = NET_Timeout(fd, timeout); 846 if (ret <= 0) { 847 if (ret == 0) { 848 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 849 "Receive timed out"); 850 } else if (ret == JVM_IO_ERR) { 851 if (errno == ENOMEM) { 852 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed"); 853 #ifdef __linux__ 854 } else if (errno == EBADF) { 855 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 856 } else { 857 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed"); 858 #else 859 } else { 860 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 861 #endif 862 } 863 } else if (ret == JVM_IO_INTR) { 864 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 865 "operation interrupted"); 866 } 867 868 if (mallocedPacket) { 869 free(fullPacket); 870 } 871 872 return; 873 } 874 } 875 876 len = SOCKADDR_LEN; 877 n = NET_RecvFrom(fd, fullPacket, packetBufferLen, 0, 878 (struct sockaddr *)&remote_addr, &len); 879 /* truncate the data if the packet's length is too small */ 880 if (n > packetBufferLen) { 881 n = packetBufferLen; 882 } 883 if (n == JVM_IO_ERR) { 884 (*env)->SetIntField(env, packet, dp_offsetID, 0); 885 (*env)->SetIntField(env, packet, dp_lengthID, 0); 886 if (errno == ECONNREFUSED) { 887 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException", 888 "ICMP Port Unreachable"); 889 } else { 890 if (errno == EBADF) { 891 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 892 } else { 893 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed"); 894 } 895 } 896 } else if (n == JVM_IO_INTR) { 897 (*env)->SetIntField(env, packet, dp_offsetID, 0); 898 (*env)->SetIntField(env, packet, dp_lengthID, 0); 899 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 900 "operation interrupted"); 901 } else { 902 int port; 903 jobject packetAddress; 904 905 /* 906 * success - fill in received address... 907 * 908 * REMIND: Fill in an int on the packet, and create inetadd 909 * object in Java, as a performance improvement. Also 910 * construct the inetadd object lazily. 911 */ 912 913 /* 914 * Check if there is an InetAddress already associated with this 915 * packet. If so we check if it is the same source address. We 916 * can't update any existing InetAddress because it is immutable 917 */ 918 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID); 919 if (packetAddress != NULL) { 920 if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) { 921 /* force a new InetAddress to be created */ 922 packetAddress = NULL; 923 } 924 } 925 if (packetAddress == NULL) { 926 packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port); 927 /* stuff the new Inetaddress in the packet */ 928 (*env)->SetObjectField(env, packet, dp_addressID, packetAddress); 929 } else { 930 /* only get the new port number */ 931 port = NET_GetPortFromSockaddr((struct sockaddr *)&remote_addr); 932 } 933 /* and fill in the data, remote address/port and such */ 934 (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n, 935 (jbyte *)fullPacket); 936 (*env)->SetIntField(env, packet, dp_portID, port); 937 (*env)->SetIntField(env, packet, dp_lengthID, n); 938 } 939 940 } while (retry); 941 942 if (mallocedPacket) { 943 free(fullPacket); 944 } 945 } 946 947 /* 948 * Class: java_net_PlainDatagramSocketImpl 949 * Method: datagramSocketCreate 950 * Signature: ()V 951 */ 952 JNIEXPORT void JNICALL 953 Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env, 954 jobject this) { 955 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 956 int arg, fd, t = 1; 957 #ifdef AF_INET6 958 int domain = ipv6_available() ? AF_INET6 : AF_INET; 959 #else 960 int domain = AF_INET; 961 #endif 962 963 if (IS_NULL(fdObj)) { 964 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 965 "Socket closed"); 966 return; 967 } 968 969 if ((fd = JVM_Socket(domain, SOCK_DGRAM, 0)) == JVM_IO_ERR) { 970 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 971 "Error creating socket"); 972 return; 973 } 974 975 #ifdef AF_INET6 976 /* Disable IPV6_V6ONLY to ensure dual-socket support */ 977 if (domain == AF_INET6) { 978 arg = 0; 979 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, 980 sizeof(int)) < 0) { 981 NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6"); 982 close(fd); 983 return; 984 } 985 } 986 #endif /* AF_INET6 */ 987 988 #ifdef __APPLE__ 989 arg = 65507; 990 if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_SNDBUF, 991 (char *)&arg, sizeof(arg)) < 0) { 992 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 993 strerror(errno)); 994 return; 995 } 996 if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_RCVBUF, 997 (char *)&arg, sizeof(arg)) < 0) { 998 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 999 strerror(errno)); 1000 return; 1001 } 1002 #endif /* __APPLE__ */ 1003 1004 setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*) &t, sizeof(int)); 1005 1006 #if defined(__linux__) 1007 arg = 0; 1008 int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP; 1009 if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) && 1010 (errno != ENOPROTOOPT)) { 1011 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1012 strerror(errno)); 1013 close(fd); 1014 return; 1015 } 1016 #endif 1017 1018 #if defined (__linux__) && defined (AF_INET6) 1019 /* 1020 * On Linux for IPv6 sockets we must set the hop limit 1021 * to 1 to be compatible with default TTL of 1 for IPv4 sockets. 1022 */ 1023 if (domain == AF_INET6) { 1024 int ttl = 1; 1025 setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&ttl, 1026 sizeof(ttl)); 1027 } 1028 #endif /* __linux__ */ 1029 1030 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd); 1031 } 1032 1033 /* 1034 * Class: java_net_PlainDatagramSocketImpl 1035 * Method: datagramSocketClose 1036 * Signature: ()V 1037 */ 1038 JNIEXPORT void JNICALL 1039 Java_java_net_PlainDatagramSocketImpl_datagramSocketClose(JNIEnv *env, 1040 jobject this) { 1041 /* 1042 * REMIND: PUT A LOCK AROUND THIS CODE 1043 */ 1044 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 1045 int fd; 1046 1047 if (IS_NULL(fdObj)) { 1048 return; 1049 } 1050 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 1051 if (fd == -1) { 1052 return; 1053 } 1054 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1); 1055 NET_SocketClose(fd); 1056 } 1057 1058 1059 /* 1060 * Set outgoing multicast interface designated by a NetworkInterface. 1061 * Throw exception if failed. 1062 */ 1063 static void mcast_set_if_by_if_v4(JNIEnv *env, jobject this, int fd, jobject value) { 1064 static jfieldID ni_addrsID; 1065 struct in_addr in; 1066 jobjectArray addrArray; 1067 jsize len; 1068 jobject addr; 1069 int i; 1070 1071 if (ni_addrsID == NULL ) { 1072 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface"); 1073 CHECK_NULL(c); 1074 ni_addrsID = (*env)->GetFieldID(env, c, "addrs", 1075 "[Ljava/net/InetAddress;"); 1076 CHECK_NULL(ni_addrsID); 1077 } 1078 1079 addrArray = (*env)->GetObjectField(env, value, ni_addrsID); 1080 len = (*env)->GetArrayLength(env, addrArray); 1081 1082 /* 1083 * Check that there is at least one address bound to this 1084 * interface. 1085 */ 1086 if (len < 1) { 1087 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1088 "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface"); 1089 return; 1090 } 1091 1092 /* 1093 * We need an ipv4 address here 1094 */ 1095 for (i = 0; i < len; i++) { 1096 addr = (*env)->GetObjectArrayElement(env, addrArray, i); 1097 if (getInetAddress_family(env, addr) == IPv4) { 1098 in.s_addr = htonl(getInetAddress_addr(env, addr)); 1099 break; 1100 } 1101 } 1102 1103 if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF, 1104 (const char*)&in, sizeof(in)) < 0) { 1105 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1106 "Error setting socket option"); 1107 } 1108 } 1109 1110 /* 1111 * Set outgoing multicast interface designated by a NetworkInterface. 1112 * Throw exception if failed. 1113 */ 1114 #ifdef AF_INET6 1115 static void mcast_set_if_by_if_v6(JNIEnv *env, jobject this, int fd, jobject value) { 1116 static jfieldID ni_indexID; 1117 int index; 1118 1119 if (ni_indexID == NULL) { 1120 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface"); 1121 CHECK_NULL(c); 1122 ni_indexID = (*env)->GetFieldID(env, c, "index", "I"); 1123 CHECK_NULL(ni_indexID); 1124 } 1125 index = (*env)->GetIntField(env, value, ni_indexID); 1126 1127 if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, 1128 (const char*)&index, sizeof(index)) < 0) { 1129 if (errno == EINVAL && index > 0) { 1130 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1131 "IPV6_MULTICAST_IF failed (interface has IPv4 " 1132 "address only?)"); 1133 } else { 1134 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1135 "Error setting socket option"); 1136 } 1137 return; 1138 } 1139 1140 } 1141 #endif /* AF_INET6 */ 1142 1143 /* 1144 * Set outgoing multicast interface designated by an InetAddress. 1145 * Throw exception if failed. 1146 */ 1147 static void mcast_set_if_by_addr_v4(JNIEnv *env, jobject this, int fd, jobject value) { 1148 struct in_addr in; 1149 1150 in.s_addr = htonl( getInetAddress_addr(env, value) ); 1151 1152 if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF, 1153 (const char*)&in, sizeof(in)) < 0) { 1154 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1155 "Error setting socket option"); 1156 } 1157 } 1158 1159 /* 1160 * Set outgoing multicast interface designated by an InetAddress. 1161 * Throw exception if failed. 1162 */ 1163 #ifdef AF_INET6 1164 static void mcast_set_if_by_addr_v6(JNIEnv *env, jobject this, int fd, jobject value) { 1165 static jclass ni_class; 1166 if (ni_class == NULL) { 1167 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface"); 1168 CHECK_NULL(c); 1169 ni_class = (*env)->NewGlobalRef(env, c); 1170 CHECK_NULL(ni_class); 1171 } 1172 1173 value = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, value); 1174 if (value == NULL) { 1175 if (!(*env)->ExceptionOccurred(env)) { 1176 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1177 "bad argument for IP_MULTICAST_IF" 1178 ": address not bound to any interface"); 1179 } 1180 return; 1181 } 1182 1183 mcast_set_if_by_if_v6(env, this, fd, value); 1184 } 1185 #endif 1186 1187 /* 1188 * Sets the multicast interface. 1189 * 1190 * SocketOptions.IP_MULTICAST_IF :- 1191 * value is a InetAddress 1192 * IPv4: set outgoing multicast interface using 1193 * IPPROTO_IP/IP_MULTICAST_IF 1194 * IPv6: Get the index of the interface to which the 1195 * InetAddress is bound 1196 * Set outgoing multicast interface using 1197 * IPPROTO_IPV6/IPV6_MULTICAST_IF 1198 * 1199 * SockOptions.IF_MULTICAST_IF2 :- 1200 * value is a NetworkInterface 1201 * IPv4: Obtain IP address bound to network interface 1202 * (NetworkInterface.addres[0]) 1203 * set outgoing multicast interface using 1204 * IPPROTO_IP/IP_MULTICAST_IF 1205 * IPv6: Obtain NetworkInterface.index 1206 * Set outgoing multicast interface using 1207 * IPPROTO_IPV6/IPV6_MULTICAST_IF 1208 * 1209 */ 1210 static void setMulticastInterface(JNIEnv *env, jobject this, int fd, 1211 jint opt, jobject value) 1212 { 1213 if (opt == java_net_SocketOptions_IP_MULTICAST_IF) { 1214 /* 1215 * value is an InetAddress. 1216 */ 1217 #ifdef AF_INET6 1218 #ifdef __linux__ 1219 mcast_set_if_by_addr_v4(env, this, fd, value); 1220 if (ipv6_available()) { 1221 mcast_set_if_by_addr_v6(env, this, fd, value); 1222 } 1223 #else /* __linux__ not defined */ 1224 if (ipv6_available()) { 1225 mcast_set_if_by_addr_v6(env, this, fd, value); 1226 } else { 1227 mcast_set_if_by_addr_v4(env, this, fd, value); 1228 } 1229 #endif /* __linux__ */ 1230 #else 1231 mcast_set_if_by_addr_v4(env, this, fd, value); 1232 #endif /* AF_INET6 */ 1233 } 1234 1235 if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) { 1236 /* 1237 * value is a NetworkInterface. 1238 */ 1239 #ifdef AF_INET6 1240 #ifdef __linux__ 1241 mcast_set_if_by_if_v4(env, this, fd, value); 1242 if (ipv6_available()) { 1243 mcast_set_if_by_if_v6(env, this, fd, value); 1244 } 1245 #else /* __linux__ not defined */ 1246 if (ipv6_available()) { 1247 mcast_set_if_by_if_v6(env, this, fd, value); 1248 } else { 1249 mcast_set_if_by_if_v4(env, this, fd, value); 1250 } 1251 #endif /* __linux__ */ 1252 #else 1253 mcast_set_if_by_if_v4(env, this, fd, value); 1254 #endif /* AF_INET6 */ 1255 } 1256 } 1257 1258 /* 1259 * Enable/disable local loopback of multicast datagrams. 1260 */ 1261 static void mcast_set_loop_v4(JNIEnv *env, jobject this, int fd, jobject value) { 1262 jclass cls; 1263 jfieldID fid; 1264 jboolean on; 1265 char loopback; 1266 1267 cls = (*env)->FindClass(env, "java/lang/Boolean"); 1268 CHECK_NULL(cls); 1269 fid = (*env)->GetFieldID(env, cls, "value", "Z"); 1270 CHECK_NULL(fid); 1271 1272 on = (*env)->GetBooleanField(env, value, fid); 1273 loopback = (!on ? 1 : 0); 1274 1275 if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&loopback, sizeof(char)) < 0) { 1276 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option"); 1277 return; 1278 } 1279 } 1280 1281 /* 1282 * Enable/disable local loopback of multicast datagrams. 1283 */ 1284 #ifdef AF_INET6 1285 static void mcast_set_loop_v6(JNIEnv *env, jobject this, int fd, jobject value) { 1286 jclass cls; 1287 jfieldID fid; 1288 jboolean on; 1289 int loopback; 1290 1291 cls = (*env)->FindClass(env, "java/lang/Boolean"); 1292 CHECK_NULL(cls); 1293 fid = (*env)->GetFieldID(env, cls, "value", "Z"); 1294 CHECK_NULL(fid); 1295 1296 on = (*env)->GetBooleanField(env, value, fid); 1297 loopback = (!on ? 1 : 0); 1298 1299 if (NET_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&loopback, sizeof(int)) < 0) { 1300 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option"); 1301 return; 1302 } 1303 1304 } 1305 #endif /* AF_INET6 */ 1306 1307 /* 1308 * Sets the multicast loopback mode. 1309 */ 1310 static void setMulticastLoopbackMode(JNIEnv *env, jobject this, int fd, 1311 jint opt, jobject value) { 1312 #ifdef AF_INET6 1313 #ifdef __linux__ 1314 mcast_set_loop_v4(env, this, fd, value); 1315 if (ipv6_available()) { 1316 mcast_set_loop_v6(env, this, fd, value); 1317 } 1318 #else /* __linux__ not defined */ 1319 if (ipv6_available()) { 1320 mcast_set_loop_v6(env, this, fd, value); 1321 } else { 1322 mcast_set_loop_v4(env, this, fd, value); 1323 } 1324 #endif /* __linux__ */ 1325 #else 1326 mcast_set_loop_v4(env, this, fd, value); 1327 #endif /* AF_INET6 */ 1328 } 1329 1330 /* 1331 * Class: java_net_PlainDatagramSocketImpl 1332 * Method: socketSetOption0 1333 * Signature: (ILjava/lang/Object;)V 1334 */ 1335 JNIEXPORT void JNICALL 1336 Java_java_net_PlainDatagramSocketImpl_socketSetOption0(JNIEnv *env, 1337 jobject this, 1338 jint opt, 1339 jobject value) { 1340 int fd; 1341 int level, optname, optlen; 1342 int optval; 1343 optlen = sizeof(int); 1344 1345 /* 1346 * Check that socket hasn't been closed 1347 */ 1348 fd = getFD(env, this); 1349 if (fd < 0) { 1350 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1351 "Socket closed"); 1352 return; 1353 } 1354 1355 /* 1356 * Check argument has been provided 1357 */ 1358 if (IS_NULL(value)) { 1359 JNU_ThrowNullPointerException(env, "value argument"); 1360 return; 1361 } 1362 1363 /* 1364 * Setting the multicast interface handled separately 1365 */ 1366 if (opt == java_net_SocketOptions_IP_MULTICAST_IF || 1367 opt == java_net_SocketOptions_IP_MULTICAST_IF2) { 1368 1369 setMulticastInterface(env, this, fd, opt, value); 1370 return; 1371 } 1372 1373 /* 1374 * Setting the multicast loopback mode handled separately 1375 */ 1376 if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) { 1377 setMulticastLoopbackMode(env, this, fd, opt, value); 1378 return; 1379 } 1380 1381 /* 1382 * Map the Java level socket option to the platform specific 1383 * level and option name. 1384 */ 1385 if (NET_MapSocketOption(opt, &level, &optname)) { 1386 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option"); 1387 return; 1388 } 1389 1390 switch (opt) { 1391 case java_net_SocketOptions_SO_SNDBUF : 1392 case java_net_SocketOptions_SO_RCVBUF : 1393 case java_net_SocketOptions_IP_TOS : 1394 { 1395 jclass cls; 1396 jfieldID fid; 1397 1398 cls = (*env)->FindClass(env, "java/lang/Integer"); 1399 CHECK_NULL(cls); 1400 fid = (*env)->GetFieldID(env, cls, "value", "I"); 1401 CHECK_NULL(fid); 1402 1403 optval = (*env)->GetIntField(env, value, fid); 1404 break; 1405 } 1406 1407 case java_net_SocketOptions_SO_REUSEADDR: 1408 case java_net_SocketOptions_SO_BROADCAST: 1409 { 1410 jclass cls; 1411 jfieldID fid; 1412 jboolean on; 1413 1414 cls = (*env)->FindClass(env, "java/lang/Boolean"); 1415 CHECK_NULL(cls); 1416 fid = (*env)->GetFieldID(env, cls, "value", "Z"); 1417 CHECK_NULL(fid); 1418 1419 on = (*env)->GetBooleanField(env, value, fid); 1420 1421 /* SO_REUSEADDR or SO_BROADCAST */ 1422 optval = (on ? 1 : 0); 1423 1424 break; 1425 } 1426 1427 default : 1428 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1429 "Socket option not supported by PlainDatagramSocketImp"); 1430 break; 1431 1432 } 1433 1434 if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) { 1435 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option"); 1436 return; 1437 } 1438 } 1439 1440 1441 /* 1442 * Return the multicast interface: 1443 * 1444 * SocketOptions.IP_MULTICAST_IF 1445 * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF 1446 * Create InetAddress 1447 * IP_MULTICAST_IF returns struct ip_mreqn on 2.2 1448 * kernel but struct in_addr on 2.4 kernel 1449 * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF 1450 * If index == 0 return InetAddress representing 1451 * anyLocalAddress. 1452 * If index > 0 query NetworkInterface by index 1453 * and returns addrs[0] 1454 * 1455 * SocketOptions.IP_MULTICAST_IF2 1456 * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF 1457 * Query NetworkInterface by IP address and 1458 * return the NetworkInterface that the address 1459 * is bound too. 1460 * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF 1461 * (except Linux .2 kernel) 1462 * Query NetworkInterface by index and 1463 * return NetworkInterface. 1464 */ 1465 jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, jint opt) { 1466 jboolean isIPV4 = JNI_TRUE; 1467 1468 #ifdef AF_INET6 1469 if (ipv6_available()) { 1470 isIPV4 = JNI_FALSE; 1471 } 1472 #endif 1473 1474 /* 1475 * IPv4 implementation 1476 */ 1477 if (isIPV4) { 1478 static jclass inet4_class; 1479 static jmethodID inet4_ctrID; 1480 1481 static jclass ni_class; 1482 static jmethodID ni_ctrID; 1483 static jfieldID ni_indexID; 1484 static jfieldID ni_addrsID; 1485 static jfieldID ni_nameID; 1486 1487 jobjectArray addrArray; 1488 jobject addr; 1489 jobject ni; 1490 jobject ni_name; 1491 1492 struct in_addr in; 1493 struct in_addr *inP = ∈ 1494 int len = sizeof(struct in_addr); 1495 1496 if (JVM_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF, 1497 (char *)inP, &len) < 0) { 1498 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1499 "Error getting socket option"); 1500 return NULL; 1501 } 1502 1503 /* 1504 * Construct and populate an Inet4Address 1505 */ 1506 if (inet4_class == NULL) { 1507 jclass c = (*env)->FindClass(env, "java/net/Inet4Address"); 1508 CHECK_NULL_RETURN(c, NULL); 1509 inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V"); 1510 CHECK_NULL_RETURN(inet4_ctrID, NULL); 1511 inet4_class = (*env)->NewGlobalRef(env, c); 1512 CHECK_NULL_RETURN(inet4_class, NULL); 1513 } 1514 addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0); 1515 CHECK_NULL_RETURN(addr, NULL); 1516 1517 setInetAddress_addr(env, addr, ntohl(in.s_addr)); 1518 1519 /* 1520 * For IP_MULTICAST_IF return InetAddress 1521 */ 1522 if (opt == java_net_SocketOptions_IP_MULTICAST_IF) { 1523 return addr; 1524 } 1525 1526 /* 1527 * For IP_MULTICAST_IF2 we get the NetworkInterface for 1528 * this address and return it 1529 */ 1530 if (ni_class == NULL) { 1531 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface"); 1532 CHECK_NULL_RETURN(c, NULL); 1533 ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V"); 1534 CHECK_NULL_RETURN(ni_ctrID, NULL); 1535 ni_indexID = (*env)->GetFieldID(env, c, "index", "I"); 1536 CHECK_NULL_RETURN(ni_indexID, NULL); 1537 ni_addrsID = (*env)->GetFieldID(env, c, "addrs", 1538 "[Ljava/net/InetAddress;"); 1539 CHECK_NULL_RETURN(ni_addrsID, NULL); 1540 ni_nameID = (*env)->GetFieldID(env, c,"name", "Ljava/lang/String;"); 1541 CHECK_NULL_RETURN(ni_nameID, NULL); 1542 ni_class = (*env)->NewGlobalRef(env, c); 1543 CHECK_NULL_RETURN(ni_class, NULL); 1544 } 1545 ni = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, addr); 1546 if (ni) { 1547 return ni; 1548 } 1549 1550 /* 1551 * The address doesn't appear to be bound at any known 1552 * NetworkInterface. Therefore we construct a NetworkInterface 1553 * with this address. 1554 */ 1555 ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0); 1556 CHECK_NULL_RETURN(ni, NULL); 1557 1558 (*env)->SetIntField(env, ni, ni_indexID, -1); 1559 addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL); 1560 CHECK_NULL_RETURN(addrArray, NULL); 1561 (*env)->SetObjectArrayElement(env, addrArray, 0, addr); 1562 (*env)->SetObjectField(env, ni, ni_addrsID, addrArray); 1563 ni_name = (*env)->NewStringUTF(env, ""); 1564 if (ni_name != NULL) { 1565 (*env)->SetObjectField(env, ni, ni_nameID, ni_name); 1566 } 1567 return ni; 1568 } 1569 1570 1571 #ifdef AF_INET6 1572 /* 1573 * IPv6 implementation 1574 */ 1575 if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) || 1576 (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) { 1577 1578 static jclass ni_class; 1579 static jmethodID ni_ctrID; 1580 static jfieldID ni_indexID; 1581 static jfieldID ni_addrsID; 1582 static jclass ia_class; 1583 static jfieldID ni_nameID; 1584 static jmethodID ia_anyLocalAddressID; 1585 1586 int index = 0; 1587 int len = sizeof(index); 1588 1589 jobjectArray addrArray; 1590 jobject addr; 1591 jobject ni; 1592 jobject ni_name; 1593 1594 if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, 1595 (char*)&index, &len) < 0) { 1596 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1597 "Error getting socket option"); 1598 return NULL; 1599 } 1600 1601 if (ni_class == NULL) { 1602 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface"); 1603 CHECK_NULL_RETURN(c, NULL); 1604 ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V"); 1605 CHECK_NULL_RETURN(ni_ctrID, NULL); 1606 ni_indexID = (*env)->GetFieldID(env, c, "index", "I"); 1607 CHECK_NULL_RETURN(ni_indexID, NULL); 1608 ni_addrsID = (*env)->GetFieldID(env, c, "addrs", 1609 "[Ljava/net/InetAddress;"); 1610 CHECK_NULL_RETURN(ni_addrsID, NULL); 1611 1612 ia_class = (*env)->FindClass(env, "java/net/InetAddress"); 1613 CHECK_NULL_RETURN(ia_class, NULL); 1614 ia_class = (*env)->NewGlobalRef(env, ia_class); 1615 CHECK_NULL_RETURN(ia_class, NULL); 1616 ia_anyLocalAddressID = (*env)->GetStaticMethodID(env, 1617 ia_class, 1618 "anyLocalAddress", 1619 "()Ljava/net/InetAddress;"); 1620 CHECK_NULL_RETURN(ia_anyLocalAddressID, NULL); 1621 ni_nameID = (*env)->GetFieldID(env, c,"name", "Ljava/lang/String;"); 1622 CHECK_NULL_RETURN(ni_nameID, NULL); 1623 ni_class = (*env)->NewGlobalRef(env, c); 1624 CHECK_NULL_RETURN(ni_class, NULL); 1625 } 1626 1627 /* 1628 * If multicast to a specific interface then return the 1629 * interface (for IF2) or the any address on that interface 1630 * (for IF). 1631 */ 1632 if (index > 0) { 1633 ni = Java_java_net_NetworkInterface_getByIndex0(env, ni_class, 1634 index); 1635 if (ni == NULL) { 1636 char errmsg[255]; 1637 sprintf(errmsg, 1638 "IPV6_MULTICAST_IF returned index to unrecognized interface: %d", 1639 index); 1640 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg); 1641 return NULL; 1642 } 1643 1644 /* 1645 * For IP_MULTICAST_IF2 return the NetworkInterface 1646 */ 1647 if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) { 1648 return ni; 1649 } 1650 1651 /* 1652 * For IP_MULTICAST_IF return addrs[0] 1653 */ 1654 addrArray = (*env)->GetObjectField(env, ni, ni_addrsID); 1655 if ((*env)->GetArrayLength(env, addrArray) < 1) { 1656 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1657 "IPV6_MULTICAST_IF returned interface without IP bindings"); 1658 return NULL; 1659 } 1660 1661 addr = (*env)->GetObjectArrayElement(env, addrArray, 0); 1662 return addr; 1663 } 1664 1665 /* 1666 * Multicast to any address - return anyLocalAddress 1667 * or a NetworkInterface with addrs[0] set to anyLocalAddress 1668 */ 1669 1670 addr = (*env)->CallStaticObjectMethod(env, ia_class, ia_anyLocalAddressID, 1671 NULL); 1672 if (opt == java_net_SocketOptions_IP_MULTICAST_IF) { 1673 return addr; 1674 } 1675 1676 ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0); 1677 CHECK_NULL_RETURN(ni, NULL); 1678 (*env)->SetIntField(env, ni, ni_indexID, -1); 1679 addrArray = (*env)->NewObjectArray(env, 1, ia_class, NULL); 1680 CHECK_NULL_RETURN(addrArray, NULL); 1681 (*env)->SetObjectArrayElement(env, addrArray, 0, addr); 1682 (*env)->SetObjectField(env, ni, ni_addrsID, addrArray); 1683 ni_name = (*env)->NewStringUTF(env, ""); 1684 if (ni_name != NULL) { 1685 (*env)->SetObjectField(env, ni, ni_nameID, ni_name); 1686 } 1687 return ni; 1688 } 1689 #endif 1690 return NULL; 1691 } 1692 1693 1694 1695 /* 1696 * Returns relevant info as a jint. 1697 * 1698 * Class: java_net_PlainDatagramSocketImpl 1699 * Method: socketGetOption 1700 * Signature: (I)Ljava/lang/Object; 1701 */ 1702 JNIEXPORT jobject JNICALL 1703 Java_java_net_PlainDatagramSocketImpl_socketGetOption(JNIEnv *env, jobject this, 1704 jint opt) { 1705 int fd; 1706 int level, optname, optlen; 1707 union { 1708 int i; 1709 char c; 1710 } optval; 1711 1712 fd = getFD(env, this); 1713 if (fd < 0) { 1714 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1715 "socket closed"); 1716 return NULL; 1717 } 1718 1719 /* 1720 * Handle IP_MULTICAST_IF separately 1721 */ 1722 if (opt == java_net_SocketOptions_IP_MULTICAST_IF || 1723 opt == java_net_SocketOptions_IP_MULTICAST_IF2) { 1724 return getMulticastInterface(env, this, fd, opt); 1725 1726 } 1727 1728 /* 1729 * SO_BINDADDR implemented using getsockname 1730 */ 1731 if (opt == java_net_SocketOptions_SO_BINDADDR) { 1732 /* find out local IP address */ 1733 SOCKADDR him; 1734 socklen_t len = 0; 1735 int port; 1736 jobject iaObj; 1737 1738 len = SOCKADDR_LEN; 1739 1740 if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) { 1741 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1742 "Error getting socket name"); 1743 return NULL; 1744 } 1745 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port); 1746 1747 return iaObj; 1748 } 1749 1750 /* 1751 * Map the Java level socket option to the platform specific 1752 * level and option name. 1753 */ 1754 if (NET_MapSocketOption(opt, &level, &optname)) { 1755 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option"); 1756 return NULL; 1757 } 1758 1759 if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP && 1760 level == IPPROTO_IP) { 1761 optlen = sizeof(optval.c); 1762 } else { 1763 optlen = sizeof(optval.i); 1764 } 1765 1766 if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) { 1767 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1768 "Error getting socket option"); 1769 return NULL; 1770 } 1771 1772 switch (opt) { 1773 case java_net_SocketOptions_IP_MULTICAST_LOOP: 1774 /* getLoopbackMode() returns true if IP_MULTICAST_LOOP disabled */ 1775 if (level == IPPROTO_IP) { 1776 return createBoolean(env, (int)!optval.c); 1777 } else { 1778 return createBoolean(env, !optval.i); 1779 } 1780 1781 case java_net_SocketOptions_SO_BROADCAST: 1782 case java_net_SocketOptions_SO_REUSEADDR: 1783 return createBoolean(env, optval.i); 1784 1785 case java_net_SocketOptions_SO_SNDBUF: 1786 case java_net_SocketOptions_SO_RCVBUF: 1787 case java_net_SocketOptions_IP_TOS: 1788 return createInteger(env, optval.i); 1789 1790 } 1791 1792 /* should never reach here */ 1793 return NULL; 1794 } 1795 1796 /* 1797 * Multicast-related calls 1798 */ 1799 1800 JNIEXPORT void JNICALL 1801 Java_java_net_PlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this, 1802 jbyte ttl) { 1803 jint ittl = ttl; 1804 if (ittl < 0) { 1805 ittl += 0x100; 1806 } 1807 Java_java_net_PlainDatagramSocketImpl_setTimeToLive(env, this, ittl); 1808 } 1809 1810 /* 1811 * Set TTL for a socket. Throw exception if failed. 1812 */ 1813 static void setTTL(JNIEnv *env, int fd, jint ttl) { 1814 char ittl = (char)ttl; 1815 if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl, 1816 sizeof(ittl)) < 0) { 1817 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1818 "Error setting socket option"); 1819 } 1820 } 1821 1822 /* 1823 * Set hops limit for a socket. Throw exception if failed. 1824 */ 1825 #ifdef AF_INET6 1826 static void setHopLimit(JNIEnv *env, int fd, jint ttl) { 1827 int ittl = (int)ttl; 1828 if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 1829 (char*)&ittl, sizeof(ittl)) < 0) { 1830 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1831 "Error setting socket option"); 1832 } 1833 } 1834 #endif 1835 1836 /* 1837 * Class: java_net_PlainDatagramSocketImpl 1838 * Method: setTTL 1839 * Signature: (B)V 1840 */ 1841 JNIEXPORT void JNICALL 1842 Java_java_net_PlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this, 1843 jint ttl) { 1844 1845 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 1846 int fd; 1847 /* it is important to cast this to a char, otherwise setsockopt gets confused */ 1848 1849 if (IS_NULL(fdObj)) { 1850 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1851 "Socket closed"); 1852 return; 1853 } else { 1854 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 1855 } 1856 /* setsockopt to be correct TTL */ 1857 #ifdef AF_INET6 1858 #ifdef __linux__ 1859 setTTL(env, fd, ttl); 1860 if (ipv6_available()) { 1861 setHopLimit(env, fd, ttl); 1862 } 1863 #else /* __linux__ not defined */ 1864 if (ipv6_available()) { 1865 setHopLimit(env, fd, ttl); 1866 } else { 1867 setTTL(env, fd, ttl); 1868 } 1869 #endif /* __linux__ */ 1870 #else 1871 setTTL(env, fd, ttl); 1872 #endif /* AF_INET6 */ 1873 } 1874 1875 /* 1876 * Class: java_net_PlainDatagramSocketImpl 1877 * Method: getTTL 1878 * Signature: ()B 1879 */ 1880 JNIEXPORT jbyte JNICALL 1881 Java_java_net_PlainDatagramSocketImpl_getTTL(JNIEnv *env, jobject this) { 1882 return (jbyte)Java_java_net_PlainDatagramSocketImpl_getTimeToLive(env, this); 1883 } 1884 1885 1886 /* 1887 * Class: java_net_PlainDatagramSocketImpl 1888 * Method: getTTL 1889 * Signature: ()B 1890 */ 1891 JNIEXPORT jint JNICALL 1892 Java_java_net_PlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) { 1893 1894 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 1895 jint fd = -1; 1896 1897 if (IS_NULL(fdObj)) { 1898 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1899 "Socket closed"); 1900 return -1; 1901 } else { 1902 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 1903 } 1904 /* getsockopt of TTL */ 1905 #ifdef AF_INET6 1906 if (ipv6_available()) { 1907 int ttl = 0; 1908 int len = sizeof(ttl); 1909 1910 if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 1911 (char*)&ttl, &len) < 0) { 1912 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1913 "Error getting socket option"); 1914 return -1; 1915 } 1916 return (jint)ttl; 1917 } else 1918 #endif /* AF_INET6 */ 1919 { 1920 u_char ttl = 0; 1921 int len = sizeof(ttl); 1922 if (JVM_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, 1923 (char*)&ttl, &len) < 0) { 1924 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 1925 "Error getting socket option"); 1926 return -1; 1927 } 1928 return (jint)ttl; 1929 } 1930 } 1931 1932 1933 /* 1934 * mcast_join_leave: Join or leave a multicast group. 1935 * 1936 * For IPv4 sockets use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option 1937 * to join/leave multicast group. 1938 * 1939 * For IPv6 sockets use IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP socket option 1940 * to join/leave multicast group. If multicast group is an IPv4 address then 1941 * an IPv4-mapped address is used. 1942 * 1943 * On Linux with IPv6 if we wish to join/leave an IPv4 multicast group then 1944 * we must use the IPv4 socket options. This is because the IPv6 socket options 1945 * don't support IPv4-mapped addresses. This is true as per 2.2.19 and 2.4.7 1946 * kernel releases. In the future it's possible that IP_ADD_MEMBERSHIP 1947 * will be updated to return ENOPROTOOPT if uses with an IPv6 socket (Solaris 1948 * already does this). Thus to cater for this we first try with the IPv4 1949 * socket options and if they fail we use the IPv6 socket options. This 1950 * seems a reasonable failsafe solution. 1951 */ 1952 static void mcast_join_leave(JNIEnv *env, jobject this, 1953 jobject iaObj, jobject niObj, 1954 jboolean join) { 1955 1956 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 1957 jint fd; 1958 jint ipv6_join_leave; 1959 1960 if (IS_NULL(fdObj)) { 1961 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 1962 "Socket closed"); 1963 return; 1964 } else { 1965 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 1966 } 1967 if (IS_NULL(iaObj)) { 1968 JNU_ThrowNullPointerException(env, "iaObj"); 1969 return; 1970 } 1971 1972 /* 1973 * Determine if this is an IPv4 or IPv6 join/leave. 1974 */ 1975 #ifdef AF_INET6 1976 ipv6_join_leave = ipv6_available(); 1977 1978 #ifdef __linux__ 1979 if (getInetAddress_family(env, iaObj) == IPv4) { 1980 ipv6_join_leave = JNI_FALSE; 1981 } 1982 #endif 1983 1984 #else 1985 /* 1986 * IPv6 not compiled in 1987 */ 1988 ipv6_join_leave = JNI_FALSE; 1989 #endif 1990 1991 /* 1992 * For IPv4 join use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option 1993 * 1994 * On Linux if IPv4 or IPv6 use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP 1995 */ 1996 if (!ipv6_join_leave) { 1997 #ifdef __linux__ 1998 struct ip_mreqn mname; 1999 #else 2000 struct ip_mreq mname; 2001 #endif 2002 int mname_len; 2003 2004 /* 2005 * joinGroup(InetAddress, NetworkInterface) implementation :- 2006 * 2007 * Linux/IPv6: use ip_mreqn structure populated with multicast 2008 * address and interface index. 2009 * 2010 * IPv4: use ip_mreq structure populated with multicast 2011 * address and first address obtained from 2012 * NetworkInterface 2013 */ 2014 if (niObj != NULL) { 2015 #if defined(__linux__) && defined(AF_INET6) 2016 if (ipv6_available()) { 2017 static jfieldID ni_indexID; 2018 2019 if (ni_indexID == NULL) { 2020 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface"); 2021 CHECK_NULL(c); 2022 ni_indexID = (*env)->GetFieldID(env, c, "index", "I"); 2023 CHECK_NULL(ni_indexID); 2024 } 2025 2026 mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj)); 2027 mname.imr_address.s_addr = 0; 2028 mname.imr_ifindex = (*env)->GetIntField(env, niObj, ni_indexID); 2029 mname_len = sizeof(struct ip_mreqn); 2030 } else 2031 #endif 2032 { 2033 jobjectArray addrArray = (*env)->GetObjectField(env, niObj, ni_addrsID); 2034 jobject addr; 2035 2036 if ((*env)->GetArrayLength(env, addrArray) < 1) { 2037 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 2038 "bad argument for IP_ADD_MEMBERSHIP: " 2039 "No IP addresses bound to interface"); 2040 return; 2041 } 2042 addr = (*env)->GetObjectArrayElement(env, addrArray, 0); 2043 2044 mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj)); 2045 #ifdef __linux__ 2046 mname.imr_address.s_addr = htonl(getInetAddress_addr(env, addr)); 2047 #else 2048 mname.imr_interface.s_addr = htonl(getInetAddress_addr(env, addr)); 2049 #endif 2050 mname_len = sizeof(struct ip_mreq); 2051 } 2052 } 2053 2054 2055 /* 2056 * joinGroup(InetAddress) implementation :- 2057 * 2058 * Linux/IPv6: use ip_mreqn structure populated with multicast 2059 * address and interface index. index obtained 2060 * from cached value or IPV6_MULTICAST_IF. 2061 * 2062 * IPv4: use ip_mreq structure populated with multicast 2063 * address and local address obtained from 2064 * IP_MULTICAST_IF. On Linux IP_MULTICAST_IF 2065 * returns different structure depending on 2066 * kernel. 2067 */ 2068 2069 if (niObj == NULL) { 2070 2071 #if defined(__linux__) && defined(AF_INET6) 2072 if (ipv6_available()) { 2073 2074 int index; 2075 int len = sizeof(index); 2076 2077 if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, 2078 (char*)&index, &len) < 0) { 2079 NET_ThrowCurrent(env, "getsockopt IPV6_MULTICAST_IF failed"); 2080 return; 2081 } 2082 2083 mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj)); 2084 mname.imr_address.s_addr = 0 ; 2085 mname.imr_ifindex = index; 2086 mname_len = sizeof(struct ip_mreqn); 2087 } else 2088 #endif 2089 { 2090 struct in_addr in; 2091 struct in_addr *inP = ∈ 2092 socklen_t len = sizeof(struct in_addr); 2093 2094 if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (char *)inP, &len) < 0) { 2095 NET_ThrowCurrent(env, "getsockopt IP_MULTICAST_IF failed"); 2096 return; 2097 } 2098 2099 #ifdef __linux__ 2100 mname.imr_address.s_addr = in.s_addr; 2101 2102 #else 2103 mname.imr_interface.s_addr = in.s_addr; 2104 #endif 2105 mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj)); 2106 mname_len = sizeof(struct ip_mreq); 2107 } 2108 } 2109 2110 2111 /* 2112 * Join the multicast group. 2113 */ 2114 if (JVM_SetSockOpt(fd, IPPROTO_IP, (join ? IP_ADD_MEMBERSHIP:IP_DROP_MEMBERSHIP), 2115 (char *) &mname, mname_len) < 0) { 2116 2117 /* 2118 * If IP_ADD_MEMBERSHIP returns ENOPROTOOPT on Linux and we've got 2119 * IPv6 enabled then it's possible that the kernel has been fixed 2120 * so we switch to IPV6_ADD_MEMBERSHIP socket option. 2121 * As of 2.4.7 kernel IPV6_ADD_MEMBERSHIP can't handle IPv4-mapped 2122 * addresses so we have to use IP_ADD_MEMBERSHIP for IPv4 multicast 2123 * groups. However if the socket is an IPv6 socket then then setsockopt 2124 * should return ENOPROTOOPT. We assume this will be fixed in Linux 2125 * at some stage. 2126 */ 2127 #if defined(__linux__) && defined(AF_INET6) 2128 if (errno == ENOPROTOOPT) { 2129 if (ipv6_available()) { 2130 ipv6_join_leave = JNI_TRUE; 2131 errno = 0; 2132 } else { 2133 errno = ENOPROTOOPT; /* errno can be changed by ipv6_available */ 2134 } 2135 } 2136 #endif 2137 if (errno) { 2138 if (join) { 2139 NET_ThrowCurrent(env, "setsockopt IP_ADD_MEMBERSHIP failed"); 2140 } else { 2141 if (errno == ENOENT) 2142 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 2143 "Not a member of the multicast group"); 2144 else 2145 NET_ThrowCurrent(env, "setsockopt IP_DROP_MEMBERSHIP failed"); 2146 } 2147 } 2148 } 2149 2150 /* 2151 * If we haven't switched to IPv6 socket option then we're done. 2152 */ 2153 if (!ipv6_join_leave) { 2154 return; 2155 } 2156 } 2157 2158 2159 /* 2160 * IPv6 join. If it's an IPv4 multicast group then we use an IPv4-mapped 2161 * address. 2162 */ 2163 #ifdef AF_INET6 2164 { 2165 struct ipv6_mreq mname6; 2166 jbyteArray ipaddress; 2167 jbyte caddr[16]; 2168 jint family; 2169 jint address; 2170 family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6; 2171 if (family == AF_INET) { /* will convert to IPv4-mapped address */ 2172 memset((char *) caddr, 0, 16); 2173 address = getInetAddress_addr(env, iaObj); 2174 2175 caddr[10] = 0xff; 2176 caddr[11] = 0xff; 2177 2178 caddr[12] = ((address >> 24) & 0xff); 2179 caddr[13] = ((address >> 16) & 0xff); 2180 caddr[14] = ((address >> 8) & 0xff); 2181 caddr[15] = (address & 0xff); 2182 } else { 2183 getInet6Address_ipaddress(env, iaObj, caddr); 2184 } 2185 2186 memcpy((void *)&(mname6.ipv6mr_multiaddr), caddr, sizeof(struct in6_addr)); 2187 if (IS_NULL(niObj)) { 2188 int index; 2189 int len = sizeof(index); 2190 2191 if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, 2192 (char*)&index, &len) < 0) { 2193 NET_ThrowCurrent(env, "getsockopt IPV6_MULTICAST_IF failed"); 2194 return; 2195 } 2196 2197 #ifdef __linux__ 2198 /* 2199 * On 2.4.8+ if we join a group with the interface set to 0 2200 * then the kernel records the interface it decides. This causes 2201 * subsequent leave groups to fail as there is no match. Thus we 2202 * pick the interface if there is a matching route. 2203 */ 2204 if (index == 0) { 2205 int rt_index = getDefaultIPv6Interface(&(mname6.ipv6mr_multiaddr)); 2206 if (rt_index > 0) { 2207 index = rt_index; 2208 } 2209 } 2210 #endif 2211 #ifdef MACOSX 2212 if (family == AF_INET6 && index == 0) { 2213 index = getDefaultScopeID(env); 2214 } 2215 #endif 2216 mname6.ipv6mr_interface = index; 2217 } else { 2218 jint idx = (*env)->GetIntField(env, niObj, ni_indexID); 2219 mname6.ipv6mr_interface = idx; 2220 } 2221 2222 #if defined(_ALLBSD_SOURCE) 2223 #define ADD_MEMBERSHIP IPV6_JOIN_GROUP 2224 #define DRP_MEMBERSHIP IPV6_LEAVE_GROUP 2225 #define S_ADD_MEMBERSHIP "IPV6_JOIN_GROUP" 2226 #define S_DRP_MEMBERSHIP "IPV6_LEAVE_GROUP" 2227 #else 2228 #define ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP 2229 #define DRP_MEMBERSHIP IPV6_DROP_MEMBERSHIP 2230 #define S_ADD_MEMBERSHIP "IPV6_ADD_MEMBERSHIP" 2231 #define S_DRP_MEMBERSHIP "IPV6_DROP_MEMBERSHIP" 2232 #endif 2233 2234 /* Join the multicast group */ 2235 if (JVM_SetSockOpt(fd, IPPROTO_IPV6, (join ? ADD_MEMBERSHIP : DRP_MEMBERSHIP), 2236 (char *) &mname6, sizeof (mname6)) < 0) { 2237 2238 if (join) { 2239 NET_ThrowCurrent(env, "setsockopt " S_ADD_MEMBERSHIP " failed"); 2240 } else { 2241 if (errno == ENOENT) { 2242 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 2243 "Not a member of the multicast group"); 2244 } else { 2245 NET_ThrowCurrent(env, "setsockopt " S_DRP_MEMBERSHIP " failed"); 2246 } 2247 } 2248 } 2249 } 2250 #endif 2251 } 2252 2253 /* 2254 * Class: java_net_PlainDatagramSocketImpl 2255 * Method: join 2256 * Signature: (Ljava/net/InetAddress;)V 2257 */ 2258 JNIEXPORT void JNICALL 2259 Java_java_net_PlainDatagramSocketImpl_join(JNIEnv *env, jobject this, 2260 jobject iaObj, jobject niObj) 2261 { 2262 mcast_join_leave(env, this, iaObj, niObj, JNI_TRUE); 2263 } 2264 2265 /* 2266 * Class: java_net_PlainDatagramSocketImpl 2267 * Method: leave 2268 * Signature: (Ljava/net/InetAddress;)V 2269 */ 2270 JNIEXPORT void JNICALL 2271 Java_java_net_PlainDatagramSocketImpl_leave(JNIEnv *env, jobject this, 2272 jobject iaObj, jobject niObj) 2273 { 2274 mcast_join_leave(env, this, iaObj, niObj, JNI_FALSE); 2275 } 2276 2277 /* 2278 * Class: java_net_PlainDatagramSocketImpl 2279 * Method: dataAvailable 2280 * Signature: ()I 2281 */ 2282 JNIEXPORT jint JNICALL 2283 Java_java_net_PlainDatagramSocketImpl_dataAvailable(JNIEnv *env, jobject this) 2284 { 2285 int fd, retval; 2286 2287 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); 2288 2289 if (IS_NULL(fdObj)) { 2290 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 2291 "Socket closed"); 2292 return -1; 2293 } 2294 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 2295 2296 if (ioctl(fd, FIONREAD, &retval) < 0) { 2297 return -1; 2298 } 2299 return retval; 2300 }