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