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