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