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