src/solaris/native/java/net/PlainDatagramSocketImpl.c

Print this page




 169     initInetAddressIDs(env);
 170     JNU_CHECK_EXCEPTION(env);
 171     Java_java_net_NetworkInterface_init(env, 0);
 172 
 173 }
 174 
 175 /*
 176  * Class:     java_net_PlainDatagramSocketImpl
 177  * Method:    bind
 178  * Signature: (ILjava/net/InetAddress;)V
 179  */
 180 JNIEXPORT void JNICALL
 181 Java_java_net_PlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this,
 182                                            jint localport, jobject iaObj) {
 183     /* fdObj is the FileDescriptor field on this */
 184     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 185     /* fd is an int field on fdObj */
 186     int fd;
 187     int len = 0;
 188     SOCKADDR him;

 189 
 190     if (IS_NULL(fdObj)) {
 191         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 192                         "Socket closed");
 193         return;
 194     } else {
 195         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 196     }
 197 
 198     if (IS_NULL(iaObj)) {
 199         JNU_ThrowNullPointerException(env, "iaObj is null.");
 200         return;
 201     }
 202 
 203     /* bind */
 204     if (NET_InetAddressToSockaddr(env, iaObj, localport, (struct sockaddr *)&him, &len, JNI_TRUE) != 0) {
 205       return;
 206     }
 207     setDefaultScopeID(env, (struct sockaddr *)&him);
 208 
 209     if (NET_Bind(fd, (struct sockaddr *)&him, len) < 0)  {
 210         if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||
 211             errno == EPERM || errno == EACCES) {
 212             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException",
 213                             "Bind failed");
 214         } else {
 215             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
 216                             "Bind failed");
 217         }
 218         return;
 219     }
 220 
 221     /* initialize the local port */
 222     if (localport == 0) {
 223         /* Now that we're a connected socket, let's extract the port number
 224          * that the system chose for us and store it in the Socket object.
 225          */
 226         if (JVM_GetSockName(fd, (struct sockaddr *)&him, &len) == -1) {
 227             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
 228                             "Error getting socket name");
 229             return;
 230         }
 231 
 232         localport = NET_GetPortFromSockaddr((struct sockaddr *)&him);
 233 
 234         (*env)->SetIntField(env, this, pdsi_localPortID, localport);
 235     } else {
 236         (*env)->SetIntField(env, this, pdsi_localPortID, localport);
 237     }
 238 }
 239 
 240 /*
 241  * Class:     java_net_PlainDatagramSocketImpl
 242  * Method:    connect0
 243  * Signature: (Ljava/net/InetAddress;I)V
 244  */
 245 JNIEXPORT void JNICALL
 246 Java_java_net_PlainDatagramSocketImpl_connect0(JNIEnv *env, jobject this,


 254     int len = 0;
 255 
 256     if (IS_NULL(fdObj)) {
 257         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 258                         "Socket closed");
 259         return;
 260     }
 261     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 262 
 263     if (IS_NULL(address)) {
 264         JNU_ThrowNullPointerException(env, "address");
 265         return;
 266     }
 267 
 268     if (NET_InetAddressToSockaddr(env, address, port, (struct sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) {
 269       return;
 270     }
 271 
 272     setDefaultScopeID(env, (struct sockaddr *)&rmtaddr);
 273 
 274     if (JVM_Connect(fd, (struct sockaddr *)&rmtaddr, len) == -1) {
 275         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
 276                         "Connect failed");
 277         return;
 278     }
 279 
 280 }
 281 
 282 /*
 283  * Class:     java_net_PlainDatagramSocketImpl
 284  * Method:    disconnect0
 285  * Signature: ()V
 286  */
 287 JNIEXPORT void JNICALL
 288 Java_java_net_PlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jint family) {
 289     /* The object's field */
 290     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 291     /* The fdObj'fd */
 292     jint fd;
 293 
 294 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
 295     SOCKADDR addr;
 296     int len;
 297 #endif
 298 
 299     if (IS_NULL(fdObj)) {
 300         return;
 301     }
 302     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 303 
 304 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
 305         memset(&addr, 0, sizeof(addr));
 306 #ifdef AF_INET6
 307         if (ipv6_available()) {
 308             struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)&addr;
 309             him6->sin6_family = AF_UNSPEC;
 310             len = sizeof(struct sockaddr_in6);
 311         } else
 312 #endif
 313         {
 314             struct sockaddr_in *him4 = (struct sockaddr_in*)&addr;
 315             him4->sin_family = AF_UNSPEC;
 316             len = sizeof(struct sockaddr_in);
 317         }
 318         JVM_Connect(fd, (struct sockaddr *)&addr, len);
 319 
 320 #ifdef __linux__
 321         int localPort = 0;
 322         if (JVM_GetSockName(fd, (struct sockaddr *)&addr, &len) == -1)
 323             return;
 324 
 325         localPort = NET_GetPortFromSockaddr((struct sockaddr *)&addr);
 326         if (localPort == 0) {
 327             localPort = (*env)->GetIntField(env, this, pdsi_localPortID);
 328 #ifdef AF_INET6
 329             if (((struct sockaddr*)&addr)->sa_family == AF_INET6) {
 330                 ((struct sockaddr_in6*)&addr)->sin6_port = htons(localPort);
 331             } else
 332 #endif /* AF_INET6 */
 333             {
 334                 ((struct sockaddr_in*)&addr)->sin_port = htons(localPort);
 335             }
 336 
 337             NET_Bind(fd, (struct sockaddr *)&addr, len);
 338         }
 339 
 340 #endif
 341 #else
 342     JVM_Connect(fd, 0, 0);
 343 #endif
 344 }
 345 
 346 /*
 347  * Class:     java_net_PlainDatagramSocketImpl
 348  * Method:    send
 349  * Signature: (Ljava/net/DatagramPacket;)V
 350  */
 351 JNIEXPORT void JNICALL
 352 Java_java_net_PlainDatagramSocketImpl_send(JNIEnv *env, jobject this,
 353                                            jobject packet) {
 354 
 355     char BUF[MAX_BUFFER_LEN];
 356     char *fullPacket = NULL;
 357     int ret, mallocedPacket = JNI_FALSE;
 358     /* The object's field */
 359     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 360     jint trafficClass = (*env)->GetIntField(env, this, pdsi_trafficClassID);
 361 
 362     jbyteArray packetBuffer;


 439     (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset, packetBufferLen,
 440                                (jbyte *)fullPacket);
 441 #ifdef AF_INET6
 442     if (trafficClass != 0 && ipv6_available()) {
 443         NET_SetTrafficClass((struct sockaddr *)&rmtaddr, trafficClass);
 444     }
 445 #endif /* AF_INET6 */
 446 
 447 
 448     /*
 449      * Send the datagram.
 450      *
 451      * If we are connected it's possible that sendto will return
 452      * ECONNREFUSED indicating that an ICMP port unreachable has
 453      * received.
 454      */
 455     ret = NET_SendTo(fd, fullPacket, packetBufferLen, 0,
 456                      (struct sockaddr *)rmtaddrP, len);
 457 
 458     if (ret < 0) {
 459         switch (ret) {
 460             case JVM_IO_ERR :
 461                 if (errno == ECONNREFUSED) {
 462                     JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 463                             "ICMP Port Unreachable");
 464                 } else {
 465                     NET_ThrowByNameWithLastError(env, "java/io/IOException", "sendto failed");
 466                 }
 467                 break;
 468 
 469             case JVM_IO_INTR:
 470                 JNU_ThrowByName(env, "java/io/InterruptedIOException",
 471                                 "operation interrupted");
 472                 break;
 473         }
 474     }
 475 
 476     if (mallocedPacket) {
 477         free(fullPacket);
 478     }
 479     return;
 480 }
 481 
 482 /*
 483  * Class:     java_net_PlainDatagramSocketImpl
 484  * Method:    peek
 485  * Signature: (Ljava/net/InetAddress;)I
 486  */
 487 JNIEXPORT jint JNICALL
 488 Java_java_net_PlainDatagramSocketImpl_peek(JNIEnv *env, jobject this,
 489                                            jobject addressObj) {
 490 
 491     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 492     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
 493     jint fd;
 494     ssize_t n;
 495     SOCKADDR remote_addr;
 496     int len;
 497     char buf[1];
 498     jint family;
 499     jobject iaObj;
 500     int port;
 501     if (IS_NULL(fdObj)) {
 502         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 503         return -1;
 504     } else {
 505         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 506     }
 507     if (IS_NULL(addressObj)) {
 508         JNU_ThrowNullPointerException(env, "Null address in peek()");
 509         return -1;
 510     }
 511     if (timeout) {
 512         int ret = NET_Timeout(fd, timeout);
 513         if (ret == 0) {
 514             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 515                             "Peek timed out");
 516             return ret;
 517         } else if (ret == JVM_IO_ERR) {
 518             if (errno == EBADF) {
 519                  JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 520             } else {
 521                  NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");
 522             }
 523             return ret;
 524         } else if (ret == JVM_IO_INTR) {
 525             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 526                             "operation interrupted");
 527             return ret; /* WARNING: SHOULD WE REALLY RETURN -2??? */
 528         }
 529     }
 530 
 531     len = SOCKADDR_LEN;
 532     n = NET_RecvFrom(fd, buf, 1, MSG_PEEK,
 533                      (struct sockaddr *)&remote_addr, &len);
 534 
 535     if (n == JVM_IO_ERR) {
 536 
 537 #ifdef __solaris__
 538         if (errno == ECONNREFUSED) {
 539             int orig_errno = errno;
 540             (void) recv(fd, buf, 1, 0);
 541             errno = orig_errno;
 542         }
 543 #endif
 544         if (errno == ECONNREFUSED) {
 545             JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 546                             "ICMP Port Unreachable");
 547         } else {
 548             if (errno == EBADF) {
 549                  JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 550             } else {
 551                  NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");
 552             }
 553         }
 554         return 0;
 555     } else if (n == JVM_IO_INTR) {
 556         JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
 557         return 0;
 558     }
 559 
 560     iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
 561 #ifdef AF_INET6
 562     family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
 563 #else
 564     family = AF_INET;
 565 #endif
 566     if (family == AF_INET) { /* this API can't handle IPV6 addresses */
 567         int address = getInetAddress_addr(env, iaObj);
 568         setInetAddress_addr(env, addressObj, address);
 569     }
 570     return port;
 571 }
 572 
 573 JNIEXPORT jint JNICALL
 574 Java_java_net_PlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this,
 575                                            jobject packet) {
 576 
 577     char BUF[MAX_BUFFER_LEN];
 578     char *fullPacket = NULL;
 579     int mallocedPacket = JNI_FALSE;
 580     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 581     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
 582 
 583     jbyteArray packetBuffer;
 584     jint packetBufferOffset, packetBufferLen;
 585 
 586     int fd;
 587 
 588     int n;
 589     SOCKADDR remote_addr;
 590     int len;
 591     int port;
 592 
 593     if (IS_NULL(fdObj)) {
 594         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 595                         "Socket closed");
 596         return -1;
 597     }
 598 
 599     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 600 
 601     if (IS_NULL(packet)) {
 602         JNU_ThrowNullPointerException(env, "packet");
 603         return -1;
 604     }
 605 
 606     packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
 607     if (IS_NULL(packetBuffer)) {
 608         JNU_ThrowNullPointerException(env, "packet buffer");
 609         return -1;
 610     }
 611     packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
 612     packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
 613     if (timeout) {
 614         int ret = NET_Timeout(fd, timeout);
 615         if (ret == 0) {
 616             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 617                             "Receive timed out");
 618             return -1;
 619         } else if (ret == JVM_IO_ERR) {
 620 #ifdef __linux__
 621             if (errno == EBADF) {
 622                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 623             } else {
 624                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
 625             }
 626 #else
 627             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 628 #endif
 629             return -1;
 630         } else if (ret == JVM_IO_INTR) {
 631             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 632                             "operation interrupted");
 633             return -1;
 634         }
 635     }
 636 
 637     if (packetBufferLen > MAX_BUFFER_LEN) {
 638 
 639         /* When JNI-ifying the JDK's IO routines, we turned
 640          * reads and writes of byte arrays of size greater
 641          * than 2048 bytes into several operations of size 2048.
 642          * This saves a malloc()/memcpy()/free() for big
 643          * buffers.  This is OK for file IO and TCP, but that
 644          * strategy violates the semantics of a datagram protocol.
 645          * (one big send) != (several smaller sends).  So here
 646          * we *must* allocate the buffer.  Note it needn't be bigger
 647          * than 65,536 (0xFFFF), the max size of an IP packet.
 648          * anything bigger is truncated anyway.
 649          *
 650          * We may want to use a smarter allocation scheme at some
 651          * point.
 652          */
 653         if (packetBufferLen > MAX_PACKET_LEN) {
 654             packetBufferLen = MAX_PACKET_LEN;
 655         }
 656         fullPacket = (char *)malloc(packetBufferLen);
 657 
 658         if (!fullPacket) {
 659             JNU_ThrowOutOfMemoryError(env, "Peek buffer native heap allocation failed");
 660             return -1;
 661         } else {
 662             mallocedPacket = JNI_TRUE;
 663         }
 664     } else {
 665         fullPacket = &(BUF[0]);
 666     }
 667 
 668     len = SOCKADDR_LEN;
 669     n = NET_RecvFrom(fd, fullPacket, packetBufferLen, MSG_PEEK,
 670                      (struct sockaddr *)&remote_addr, &len);
 671     /* truncate the data if the packet's length is too small */
 672     if (n > packetBufferLen) {
 673         n = packetBufferLen;
 674     }
 675     if (n == JVM_IO_ERR) {
 676 
 677 #ifdef __solaris__
 678         if (errno == ECONNREFUSED) {
 679             int orig_errno = errno;
 680             (void) recv(fd, fullPacket, 1, 0);
 681             errno = orig_errno;
 682         }
 683 #endif
 684         (*env)->SetIntField(env, packet, dp_offsetID, 0);
 685         (*env)->SetIntField(env, packet, dp_lengthID, 0);
 686         if (errno == ECONNREFUSED) {
 687             JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 688                             "ICMP Port Unreachable");
 689         } else {
 690             if (errno == EBADF) {
 691                  JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 692             } else {
 693                  NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
 694             }
 695         }
 696     } else if (n == JVM_IO_INTR) {
 697         (*env)->SetIntField(env, packet, dp_offsetID, 0);
 698         (*env)->SetIntField(env, packet, dp_lengthID, 0);
 699         JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 700                         "operation interrupted");
 701     } else {
 702         /*
 703          * success - fill in received address...
 704          *
 705          * REMIND: Fill in an int on the packet, and create inetadd
 706          * object in Java, as a performance improvement. Also
 707          * construct the inetadd object lazily.
 708          */
 709 
 710         jobject packetAddress;
 711 
 712         /*
 713          * Check if there is an InetAddress already associated with this
 714          * packet. If so we check if it is the same source address. We
 715          * can't update any existing InetAddress because it is immutable
 716          */
 717         packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
 718         if (packetAddress != NULL) {
 719             if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) {
 720                 /* force a new InetAddress to be created */


 747  * Method:    receive
 748  * Signature: (Ljava/net/DatagramPacket;)V
 749  */
 750 JNIEXPORT void JNICALL
 751 Java_java_net_PlainDatagramSocketImpl_receive0(JNIEnv *env, jobject this,
 752                                               jobject packet) {
 753 
 754     char BUF[MAX_BUFFER_LEN];
 755     char *fullPacket = NULL;
 756     int mallocedPacket = JNI_FALSE;
 757     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 758     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
 759 
 760     jbyteArray packetBuffer;
 761     jint packetBufferOffset, packetBufferLen;
 762 
 763     int fd;
 764 
 765     int n;
 766     SOCKADDR remote_addr;
 767     int len;
 768     jboolean retry;
 769 #ifdef __linux__
 770     jboolean connected = JNI_FALSE;
 771     jobject connectedAddress = NULL;
 772     jint connectedPort = 0;
 773     jlong prevTime = 0;
 774 #endif
 775 
 776     if (IS_NULL(fdObj)) {
 777         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 778                         "Socket closed");
 779         return;
 780     }
 781 
 782     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 783 
 784     if (IS_NULL(packet)) {
 785         JNU_ThrowNullPointerException(env, "packet");
 786         return;
 787     }


 817 
 818         if (!fullPacket) {
 819             JNU_ThrowOutOfMemoryError(env, "Receive buffer native heap allocation failed");
 820             return;
 821         } else {
 822             mallocedPacket = JNI_TRUE;
 823         }
 824     } else {
 825         fullPacket = &(BUF[0]);
 826     }
 827 
 828     do {
 829         retry = JNI_FALSE;
 830 
 831         if (timeout) {
 832             int ret = NET_Timeout(fd, timeout);
 833             if (ret <= 0) {
 834                 if (ret == 0) {
 835                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 836                                     "Receive timed out");
 837                 } else if (ret == JVM_IO_ERR) {
 838 #ifdef __linux__
 839                     if (errno == EBADF) {
 840                          JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 841                      } else {
 842                          NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
 843                      }
 844 #else
 845                      JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 846 #endif
 847                 } else if (ret == JVM_IO_INTR) {
 848                     JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 849                                     "operation interrupted");
 850                 }
 851 
 852                 if (mallocedPacket) {
 853                     free(fullPacket);
 854                 }
 855 
 856                 return;
 857             }
 858         }
 859 
 860         len = SOCKADDR_LEN;
 861         n = NET_RecvFrom(fd, fullPacket, packetBufferLen, 0,
 862                          (struct sockaddr *)&remote_addr, &len);
 863         /* truncate the data if the packet's length is too small */
 864         if (n > packetBufferLen) {
 865             n = packetBufferLen;
 866         }
 867         if (n == JVM_IO_ERR) {
 868             (*env)->SetIntField(env, packet, dp_offsetID, 0);
 869             (*env)->SetIntField(env, packet, dp_lengthID, 0);
 870             if (errno == ECONNREFUSED) {
 871                 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 872                                 "ICMP Port Unreachable");
 873             } else {
 874                 if (errno == EBADF) {
 875                      JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 876                  } else {
 877                      NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
 878                  }
 879             }
 880         } else if (n == JVM_IO_INTR) {
 881             (*env)->SetIntField(env, packet, dp_offsetID, 0);
 882             (*env)->SetIntField(env, packet, dp_lengthID, 0);
 883             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 884                             "operation interrupted");
 885         } else {
 886             int port;
 887             jobject packetAddress;
 888 
 889             /*
 890              * success - fill in received address...
 891              *
 892              * REMIND: Fill in an int on the packet, and create inetadd
 893              * object in Java, as a performance improvement. Also
 894              * construct the inetadd object lazily.
 895              */
 896 
 897             /*
 898              * Check if there is an InetAddress already associated with this
 899              * packet. If so we check if it is the same source address. We
 900              * can't update any existing InetAddress because it is immutable
 901              */
 902             packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
 903             if (packetAddress != NULL) {
 904                 if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) {


 933  * Method:    datagramSocketCreate
 934  * Signature: ()V
 935  */
 936 JNIEXPORT void JNICALL
 937 Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
 938                                                            jobject this) {
 939     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 940     int arg, fd, t = 1;
 941 #ifdef AF_INET6
 942     int domain = ipv6_available() ? AF_INET6 : AF_INET;
 943 #else
 944     int domain = AF_INET;
 945 #endif
 946 
 947     if (IS_NULL(fdObj)) {
 948         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 949                         "Socket closed");
 950         return;
 951     }
 952 
 953     if ((fd = JVM_Socket(domain, SOCK_DGRAM, 0)) == JVM_IO_ERR) {
 954         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
 955                        "Error creating socket");
 956         return;
 957     }
 958 
 959 #ifdef AF_INET6
 960     /* Disable IPV6_V6ONLY to ensure dual-socket support */
 961     if (domain == AF_INET6) {
 962         arg = 0;
 963         if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
 964                        sizeof(int)) < 0) {
 965             NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
 966             close(fd);
 967             return;
 968         }
 969     }
 970 #endif /* AF_INET6 */
 971 
 972 #ifdef __APPLE__
 973     arg = 65507;
 974     if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_SNDBUF,
 975                        (char *)&arg, sizeof(arg)) < 0) {
 976         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 977                         strerror(errno));
 978         return;
 979     }
 980     if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_RCVBUF,
 981                        (char *)&arg, sizeof(arg)) < 0) {
 982         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 983                         strerror(errno));
 984         return;
 985     }
 986 #endif /* __APPLE__ */
 987 
 988      setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*) &t, sizeof(int));
 989 
 990 #if defined(__linux__)
 991      arg = 0;
 992      int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP;
 993      if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) &&
 994          (errno != ENOPROTOOPT)) {
 995          JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 996                          strerror(errno));
 997          close(fd);
 998          return;
 999      }
1000 #endif


1067      * Check that there is at least one address bound to this
1068      * interface.
1069      */
1070     if (len < 1) {
1071         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1072             "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface");
1073         return;
1074     }
1075 
1076     /*
1077      * We need an ipv4 address here
1078      */
1079     for (i = 0; i < len; i++) {
1080         addr = (*env)->GetObjectArrayElement(env, addrArray, i);
1081         if (getInetAddress_family(env, addr) == IPv4) {
1082             in.s_addr = htonl(getInetAddress_addr(env, addr));
1083             break;
1084         }
1085     }
1086 
1087     if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1088                        (const char*)&in, sizeof(in)) < 0) {
1089         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1090                        "Error setting socket option");
1091     }
1092 }
1093 
1094 /*
1095  * Set outgoing multicast interface designated by a NetworkInterface.
1096  * Throw exception if failed.
1097  */
1098 #ifdef AF_INET6
1099 static void mcast_set_if_by_if_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1100     static jfieldID ni_indexID;
1101     int index;
1102 
1103     if (ni_indexID == NULL) {
1104         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1105         CHECK_NULL(c);
1106         ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1107         CHECK_NULL(ni_indexID);
1108     }
1109     index = (*env)->GetIntField(env, value, ni_indexID);
1110 
1111     if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1112                        (const char*)&index, sizeof(index)) < 0) {
1113         if (errno == EINVAL && index > 0) {
1114             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1115                 "IPV6_MULTICAST_IF failed (interface has IPv4 "
1116                 "address only?)");
1117         } else {
1118             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1119                            "Error setting socket option");
1120         }
1121         return;
1122     }
1123 
1124 }
1125 #endif /* AF_INET6 */
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_v4(JNIEnv *env, jobject this, int fd, jobject value) {
1132     struct in_addr in;
1133 
1134     in.s_addr = htonl( getInetAddress_addr(env, value) );
1135 
1136     if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1137                        (const char*)&in, sizeof(in)) < 0) {
1138         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1139                          "Error setting socket option");
1140     }
1141 }
1142 
1143 /*
1144  * Set outgoing multicast interface designated by an InetAddress.
1145  * Throw exception if failed.
1146  */
1147 #ifdef AF_INET6
1148 static void mcast_set_if_by_addr_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1149     static jclass ni_class;
1150     if (ni_class == NULL) {
1151         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1152         CHECK_NULL(c);
1153         ni_class = (*env)->NewGlobalRef(env, c);
1154         CHECK_NULL(ni_class);
1155     }
1156 


1465 #endif
1466 
1467     /*
1468      * IPv4 implementation
1469      */
1470     if (isIPV4) {
1471         static jclass inet4_class;
1472         static jmethodID inet4_ctrID;
1473 
1474         static jclass ni_class;
1475         static jmethodID ni_ctrID;
1476         static jfieldID ni_indexID;
1477         static jfieldID ni_addrsID;
1478 
1479         jobjectArray addrArray;
1480         jobject addr;
1481         jobject ni;
1482 
1483         struct in_addr in;
1484         struct in_addr *inP = &in;
1485         int len = sizeof(struct in_addr);
1486 
1487         if (JVM_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1488                            (char *)inP, &len) < 0) {
1489             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1490                              "Error getting socket option");
1491             return NULL;
1492         }
1493 
1494         /*
1495          * Construct and populate an Inet4Address
1496          */
1497         if (inet4_class == NULL) {
1498             jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
1499             CHECK_NULL_RETURN(c, NULL);
1500             inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1501             CHECK_NULL_RETURN(inet4_ctrID, NULL);
1502             inet4_class = (*env)->NewGlobalRef(env, c);
1503             CHECK_NULL_RETURN(inet4_class, NULL);
1504         }
1505         addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0);
1506         CHECK_NULL_RETURN(addr, NULL);
1507 


1551         (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
1552         return ni;
1553     }
1554 
1555 
1556 #ifdef AF_INET6
1557     /*
1558      * IPv6 implementation
1559      */
1560     if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
1561         (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1562 
1563         static jclass ni_class;
1564         static jmethodID ni_ctrID;
1565         static jfieldID ni_indexID;
1566         static jfieldID ni_addrsID;
1567         static jclass ia_class;
1568         static jmethodID ia_anyLocalAddressID;
1569 
1570         int index;
1571         int len = sizeof(index);
1572 
1573         jobjectArray addrArray;
1574         jobject addr;
1575         jobject ni;
1576 
1577         if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1578                            (char*)&index, &len) < 0) {
1579             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1580                            "Error getting socket option");
1581             return NULL;
1582         }
1583 
1584         if (ni_class == NULL) {
1585             jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1586             CHECK_NULL_RETURN(c, NULL);
1587             ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1588             CHECK_NULL_RETURN(ni_ctrID, NULL);
1589             ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1590             CHECK_NULL_RETURN(ni_indexID, NULL);
1591             ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1592                                             "[Ljava/net/InetAddress;");
1593             CHECK_NULL_RETURN(ni_addrsID, NULL);
1594 
1595             ia_class = (*env)->FindClass(env, "java/net/InetAddress");
1596             CHECK_NULL_RETURN(ia_class, NULL);
1597             ia_class = (*env)->NewGlobalRef(env, ia_class);


1772 
1773 /*
1774  * Multicast-related calls
1775  */
1776 
1777 JNIEXPORT void JNICALL
1778 Java_java_net_PlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this,
1779                                              jbyte ttl) {
1780     jint ittl = ttl;
1781     if (ittl < 0) {
1782         ittl += 0x100;
1783     }
1784     Java_java_net_PlainDatagramSocketImpl_setTimeToLive(env, this, ittl);
1785 }
1786 
1787 /*
1788  * Set TTL for a socket. Throw exception if failed.
1789  */
1790 static void setTTL(JNIEnv *env, int fd, jint ttl) {
1791     char ittl = (char)ttl;
1792     if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
1793                        sizeof(ittl)) < 0) {
1794         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1795                        "Error setting socket option");
1796     }
1797 }
1798 
1799 /*
1800  * Set hops limit for a socket. Throw exception if failed.
1801  */
1802 #ifdef AF_INET6
1803 static void setHopLimit(JNIEnv *env, int fd, jint ttl) {
1804     int ittl = (int)ttl;
1805     if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1806                        (char*)&ittl, sizeof(ittl)) < 0) {
1807         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1808                        "Error setting socket option");
1809     }
1810 }
1811 #endif
1812 
1813 /*
1814  * Class:     java_net_PlainDatagramSocketImpl
1815  * Method:    setTTL
1816  * Signature: (B)V
1817  */
1818 JNIEXPORT void JNICALL
1819 Java_java_net_PlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this,
1820                                                     jint ttl) {
1821 
1822     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1823     int fd;
1824     /* it is important to cast this to a char, otherwise setsockopt gets confused */
1825 


1866  * Method:    getTTL
1867  * Signature: ()B
1868  */
1869 JNIEXPORT jint JNICALL
1870 Java_java_net_PlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) {
1871 
1872     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1873     jint fd = -1;
1874 
1875     if (IS_NULL(fdObj)) {
1876         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1877                         "Socket closed");
1878         return -1;
1879     } else {
1880         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1881     }
1882     /* getsockopt of TTL */
1883 #ifdef AF_INET6
1884     if (ipv6_available()) {
1885         int ttl = 0;
1886         int len = sizeof(ttl);
1887 
1888         if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1889                                (char*)&ttl, &len) < 0) {
1890                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1891                                "Error getting socket option");
1892                 return -1;
1893             }
1894         return (jint)ttl;
1895     } else
1896 #endif /* AF_INET6 */
1897         {
1898             u_char ttl = 0;
1899             int len = sizeof(ttl);
1900             if (JVM_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
1901                                (char*)&ttl, &len) < 0) {
1902                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1903                                "Error getting socket option");
1904                 return -1;
1905             }
1906             return (jint)ttl;
1907         }
1908 }
1909 
1910 
1911 /*
1912  * mcast_join_leave: Join or leave a multicast group.
1913  *
1914  * For IPv4 sockets use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option
1915  * to join/leave multicast group.
1916  *
1917  * For IPv6 sockets use IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP socket option
1918  * to join/leave multicast group. If multicast group is an IPv4 address then
1919  * an IPv4-mapped address is used.
1920  *


2033         /*
2034          * joinGroup(InetAddress) implementation :-
2035          *
2036          * Linux/IPv6:  use ip_mreqn structure populated with multicast
2037          *              address and interface index. index obtained
2038          *              from cached value or IPV6_MULTICAST_IF.
2039          *
2040          * IPv4:        use ip_mreq structure populated with multicast
2041          *              address and local address obtained from
2042          *              IP_MULTICAST_IF. On Linux IP_MULTICAST_IF
2043          *              returns different structure depending on
2044          *              kernel.
2045          */
2046 
2047         if (niObj == NULL) {
2048 
2049 #if defined(__linux__) && defined(AF_INET6)
2050             if (ipv6_available()) {
2051 
2052                 int index;
2053                 int len = sizeof(index);
2054 
2055                 if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
2056                                    (char*)&index, &len) < 0) {
2057                     NET_ThrowCurrent(env, "getsockopt IPV6_MULTICAST_IF failed");
2058                     return;
2059                 }
2060 
2061                 mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj));
2062                 mname.imr_address.s_addr = 0 ;
2063                 mname.imr_ifindex = index;
2064                 mname_len = sizeof(struct ip_mreqn);
2065             } else
2066 #endif
2067             {
2068                 struct in_addr in;
2069                 struct in_addr *inP = &in;
2070                 socklen_t len = sizeof(struct in_addr);
2071 
2072                 if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (char *)inP, &len) < 0) {
2073                     NET_ThrowCurrent(env, "getsockopt IP_MULTICAST_IF failed");
2074                     return;
2075                 }
2076 
2077 #ifdef __linux__
2078                 mname.imr_address.s_addr = in.s_addr;
2079 
2080 #else
2081                 mname.imr_interface.s_addr = in.s_addr;
2082 #endif
2083                 mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj));
2084                 mname_len = sizeof(struct ip_mreq);
2085             }
2086         }
2087 
2088 
2089         /*
2090          * Join the multicast group.
2091          */
2092         if (JVM_SetSockOpt(fd, IPPROTO_IP, (join ? IP_ADD_MEMBERSHIP:IP_DROP_MEMBERSHIP),
2093                            (char *) &mname, mname_len) < 0) {
2094 
2095             /*
2096              * If IP_ADD_MEMBERSHIP returns ENOPROTOOPT on Linux and we've got
2097              * IPv6 enabled then it's possible that the kernel has been fixed
2098              * so we switch to IPV6_ADD_MEMBERSHIP socket option.
2099              * As of 2.4.7 kernel IPV6_ADD_MEMBERSHIP can't handle IPv4-mapped
2100              * addresses so we have to use IP_ADD_MEMBERSHIP for IPv4 multicast
2101              * groups. However if the socket is an IPv6 socket then then setsockopt
2102              * should return ENOPROTOOPT. We assume this will be fixed in Linux
2103              * at some stage.
2104              */
2105 #if defined(__linux__) && defined(AF_INET6)
2106             if (errno == ENOPROTOOPT) {
2107                 if (ipv6_available()) {
2108                     ipv6_join_leave = JNI_TRUE;
2109                     errno = 0;
2110                 } else  {
2111                     errno = ENOPROTOOPT;    /* errno can be changed by ipv6_available */
2112                 }


2148         jint address;
2149         family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
2150         if (family == AF_INET) { /* will convert to IPv4-mapped address */
2151             memset((char *) caddr, 0, 16);
2152             address = getInetAddress_addr(env, iaObj);
2153 
2154             caddr[10] = 0xff;
2155             caddr[11] = 0xff;
2156 
2157             caddr[12] = ((address >> 24) & 0xff);
2158             caddr[13] = ((address >> 16) & 0xff);
2159             caddr[14] = ((address >> 8) & 0xff);
2160             caddr[15] = (address & 0xff);
2161         } else {
2162             getInet6Address_ipaddress(env, iaObj, (char*)caddr);
2163         }
2164 
2165         memcpy((void *)&(mname6.ipv6mr_multiaddr), caddr, sizeof(struct in6_addr));
2166         if (IS_NULL(niObj)) {
2167             int index;
2168             int len = sizeof(index);
2169 
2170             if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
2171                              (char*)&index, &len) < 0) {
2172                 NET_ThrowCurrent(env, "getsockopt IPV6_MULTICAST_IF failed");
2173                return;
2174             }
2175 
2176 #ifdef __linux__
2177             /*
2178              * On 2.4.8+ if we join a group with the interface set to 0
2179              * then the kernel records the interface it decides. This causes
2180              * subsequent leave groups to fail as there is no match. Thus we
2181              * pick the interface if there is a matching route.
2182              */
2183             if (index == 0) {
2184                 int rt_index = getDefaultIPv6Interface(&(mname6.ipv6mr_multiaddr));
2185                 if (rt_index > 0) {
2186                     index = rt_index;
2187                 }
2188             }
2189 #endif
2190 #ifdef MACOSX


2194 #endif
2195             mname6.ipv6mr_interface = index;
2196         } else {
2197             jint idx = (*env)->GetIntField(env, niObj, ni_indexID);
2198             mname6.ipv6mr_interface = idx;
2199         }
2200 
2201 #if defined(_ALLBSD_SOURCE)
2202 #define ADD_MEMBERSHIP          IPV6_JOIN_GROUP
2203 #define DRP_MEMBERSHIP          IPV6_LEAVE_GROUP
2204 #define S_ADD_MEMBERSHIP        "IPV6_JOIN_GROUP"
2205 #define S_DRP_MEMBERSHIP        "IPV6_LEAVE_GROUP"
2206 #else
2207 #define ADD_MEMBERSHIP          IPV6_ADD_MEMBERSHIP
2208 #define DRP_MEMBERSHIP          IPV6_DROP_MEMBERSHIP
2209 #define S_ADD_MEMBERSHIP        "IPV6_ADD_MEMBERSHIP"
2210 #define S_DRP_MEMBERSHIP        "IPV6_DROP_MEMBERSHIP"
2211 #endif
2212 
2213         /* Join the multicast group */
2214         if (JVM_SetSockOpt(fd, IPPROTO_IPV6, (join ? ADD_MEMBERSHIP : DRP_MEMBERSHIP),
2215                            (char *) &mname6, sizeof (mname6)) < 0) {
2216 
2217             if (join) {
2218                 NET_ThrowCurrent(env, "setsockopt " S_ADD_MEMBERSHIP " failed");
2219             } else {
2220                 if (errno == ENOENT) {
2221                    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2222                         "Not a member of the multicast group");
2223                 } else {
2224                     NET_ThrowCurrent(env, "setsockopt " S_DRP_MEMBERSHIP " failed");
2225                 }
2226             }
2227         }
2228     }
2229 #endif
2230 }
2231 
2232 /*
2233  * Class:     java_net_PlainDatagramSocketImpl
2234  * Method:    join


 169     initInetAddressIDs(env);
 170     JNU_CHECK_EXCEPTION(env);
 171     Java_java_net_NetworkInterface_init(env, 0);
 172 
 173 }
 174 
 175 /*
 176  * Class:     java_net_PlainDatagramSocketImpl
 177  * Method:    bind
 178  * Signature: (ILjava/net/InetAddress;)V
 179  */
 180 JNIEXPORT void JNICALL
 181 Java_java_net_PlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this,
 182                                            jint localport, jobject iaObj) {
 183     /* fdObj is the FileDescriptor field on this */
 184     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 185     /* fd is an int field on fdObj */
 186     int fd;
 187     int len = 0;
 188     SOCKADDR him;
 189     socklen_t slen = sizeof(him);
 190 
 191     if (IS_NULL(fdObj)) {
 192         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 193                         "Socket closed");
 194         return;
 195     } else {
 196         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 197     }
 198 
 199     if (IS_NULL(iaObj)) {
 200         JNU_ThrowNullPointerException(env, "iaObj is null.");
 201         return;
 202     }
 203 
 204     /* bind */
 205     if (NET_InetAddressToSockaddr(env, iaObj, localport, (struct sockaddr *)&him, &len, JNI_TRUE) != 0) {
 206       return;
 207     }
 208     setDefaultScopeID(env, (struct sockaddr *)&him);
 209 
 210     if (NET_Bind(fd, (struct sockaddr *)&him, len) < 0)  {
 211         if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||
 212             errno == EPERM || errno == EACCES) {
 213             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException",
 214                             "Bind failed");
 215         } else {
 216             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
 217                             "Bind failed");
 218         }
 219         return;
 220     }
 221 
 222     /* initialize the local port */
 223     if (localport == 0) {
 224         /* Now that we're a connected socket, let's extract the port number
 225          * that the system chose for us and store it in the Socket object.
 226          */
 227         if (getsockname(fd, (struct sockaddr *)&him, &slen) == -1) {
 228             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
 229                             "Error getting socket name");
 230             return;
 231         }
 232 
 233         localport = NET_GetPortFromSockaddr((struct sockaddr *)&him);
 234 
 235         (*env)->SetIntField(env, this, pdsi_localPortID, localport);
 236     } else {
 237         (*env)->SetIntField(env, this, pdsi_localPortID, localport);
 238     }
 239 }
 240 
 241 /*
 242  * Class:     java_net_PlainDatagramSocketImpl
 243  * Method:    connect0
 244  * Signature: (Ljava/net/InetAddress;I)V
 245  */
 246 JNIEXPORT void JNICALL
 247 Java_java_net_PlainDatagramSocketImpl_connect0(JNIEnv *env, jobject this,


 255     int len = 0;
 256 
 257     if (IS_NULL(fdObj)) {
 258         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 259                         "Socket closed");
 260         return;
 261     }
 262     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 263 
 264     if (IS_NULL(address)) {
 265         JNU_ThrowNullPointerException(env, "address");
 266         return;
 267     }
 268 
 269     if (NET_InetAddressToSockaddr(env, address, port, (struct sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) {
 270       return;
 271     }
 272 
 273     setDefaultScopeID(env, (struct sockaddr *)&rmtaddr);
 274 
 275     if (NET_Connect(fd, (struct sockaddr *)&rmtaddr, len) == -1) {
 276         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
 277                         "Connect failed");
 278         return;
 279     }
 280 
 281 }
 282 
 283 /*
 284  * Class:     java_net_PlainDatagramSocketImpl
 285  * Method:    disconnect0
 286  * Signature: ()V
 287  */
 288 JNIEXPORT void JNICALL
 289 Java_java_net_PlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jint family) {
 290     /* The object's field */
 291     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 292     /* The fdObj'fd */
 293     jint fd;
 294 
 295 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
 296     SOCKADDR addr;
 297     socklen_t len;
 298 #endif
 299 
 300     if (IS_NULL(fdObj)) {
 301         return;
 302     }
 303     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 304 
 305 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
 306         memset(&addr, 0, sizeof(addr));
 307 #ifdef AF_INET6
 308         if (ipv6_available()) {
 309             struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)&addr;
 310             him6->sin6_family = AF_UNSPEC;
 311             len = sizeof(struct sockaddr_in6);
 312         } else
 313 #endif
 314         {
 315             struct sockaddr_in *him4 = (struct sockaddr_in*)&addr;
 316             him4->sin_family = AF_UNSPEC;
 317             len = sizeof(struct sockaddr_in);
 318         }
 319         NET_Connect(fd, (struct sockaddr *)&addr, len);
 320 
 321 #ifdef __linux__
 322         int localPort = 0;
 323         if (getsockname(fd, (struct sockaddr *)&addr, &len) == -1)
 324             return;
 325 
 326         localPort = NET_GetPortFromSockaddr((struct sockaddr *)&addr);
 327         if (localPort == 0) {
 328             localPort = (*env)->GetIntField(env, this, pdsi_localPortID);
 329 #ifdef AF_INET6
 330             if (((struct sockaddr*)&addr)->sa_family == AF_INET6) {
 331                 ((struct sockaddr_in6*)&addr)->sin6_port = htons(localPort);
 332             } else
 333 #endif /* AF_INET6 */
 334             {
 335                 ((struct sockaddr_in*)&addr)->sin_port = htons(localPort);
 336             }
 337 
 338             NET_Bind(fd, (struct sockaddr *)&addr, len);
 339         }
 340 
 341 #endif
 342 #else
 343     NET_Connect(fd, 0, 0);
 344 #endif
 345 }
 346 
 347 /*
 348  * Class:     java_net_PlainDatagramSocketImpl
 349  * Method:    send
 350  * Signature: (Ljava/net/DatagramPacket;)V
 351  */
 352 JNIEXPORT void JNICALL
 353 Java_java_net_PlainDatagramSocketImpl_send(JNIEnv *env, jobject this,
 354                                            jobject packet) {
 355 
 356     char BUF[MAX_BUFFER_LEN];
 357     char *fullPacket = NULL;
 358     int ret, mallocedPacket = JNI_FALSE;
 359     /* The object's field */
 360     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 361     jint trafficClass = (*env)->GetIntField(env, this, pdsi_trafficClassID);
 362 
 363     jbyteArray packetBuffer;


 440     (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset, packetBufferLen,
 441                                (jbyte *)fullPacket);
 442 #ifdef AF_INET6
 443     if (trafficClass != 0 && ipv6_available()) {
 444         NET_SetTrafficClass((struct sockaddr *)&rmtaddr, trafficClass);
 445     }
 446 #endif /* AF_INET6 */
 447 
 448 
 449     /*
 450      * Send the datagram.
 451      *
 452      * If we are connected it's possible that sendto will return
 453      * ECONNREFUSED indicating that an ICMP port unreachable has
 454      * received.
 455      */
 456     ret = NET_SendTo(fd, fullPacket, packetBufferLen, 0,
 457                      (struct sockaddr *)rmtaddrP, len);
 458 
 459     if (ret < 0) {


 460         if (errno == ECONNREFUSED) {
 461             JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 462                             "ICMP Port Unreachable");
 463         } else {
 464             NET_ThrowByNameWithLastError(env, "java/io/IOException", "sendto failed");
 465         }







 466     }
 467 
 468     if (mallocedPacket) {
 469         free(fullPacket);
 470     }
 471     return;
 472 }
 473 
 474 /*
 475  * Class:     java_net_PlainDatagramSocketImpl
 476  * Method:    peek
 477  * Signature: (Ljava/net/InetAddress;)I
 478  */
 479 JNIEXPORT jint JNICALL
 480 Java_java_net_PlainDatagramSocketImpl_peek(JNIEnv *env, jobject this,
 481                                            jobject addressObj) {
 482 
 483     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 484     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
 485     jint fd;
 486     ssize_t n;
 487     SOCKADDR remote_addr;
 488     socklen_t slen = SOCKADDR_LEN;
 489     char buf[1];
 490     jint family;
 491     jobject iaObj;
 492     int port;
 493     if (IS_NULL(fdObj)) {
 494         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 495         return -1;
 496     } else {
 497         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 498     }
 499     if (IS_NULL(addressObj)) {
 500         JNU_ThrowNullPointerException(env, "Null address in peek()");
 501         return -1;
 502     }
 503     if (timeout) {
 504         int ret = NET_Timeout(fd, timeout);
 505         if (ret == 0) {
 506             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 507                             "Peek timed out");
 508             return ret;
 509         } else if (ret == -1) {
 510             if (errno == EBADF) {
 511                  JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 512             } else {
 513                  NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");
 514             }
 515             return ret;




 516         }
 517     }
 518 
 519     n = NET_RecvFrom(fd, buf, 1, MSG_PEEK, (struct sockaddr *)&remote_addr, &slen);


 520 
 521     if (n == -1) {
 522 
 523 #ifdef __solaris__
 524         if (errno == ECONNREFUSED) {
 525             int orig_errno = errno;
 526             (void) recv(fd, buf, 1, 0);
 527             errno = orig_errno;
 528         }
 529 #endif
 530         if (errno == ECONNREFUSED) {
 531             JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 532                             "ICMP Port Unreachable");
 533         } else {
 534             if (errno == EBADF) {
 535                  JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 536             } else {
 537                  NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");
 538             }
 539         }
 540         return 0;



 541     }
 542 
 543     iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
 544 #ifdef AF_INET6
 545     family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
 546 #else
 547     family = AF_INET;
 548 #endif
 549     if (family == AF_INET) { /* this API can't handle IPV6 addresses */
 550         int address = getInetAddress_addr(env, iaObj);
 551         setInetAddress_addr(env, addressObj, address);
 552     }
 553     return port;
 554 }
 555 
 556 JNIEXPORT jint JNICALL
 557 Java_java_net_PlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this,
 558                                            jobject packet) {
 559 
 560     char BUF[MAX_BUFFER_LEN];
 561     char *fullPacket = NULL;
 562     int mallocedPacket = JNI_FALSE;
 563     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 564     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
 565 
 566     jbyteArray packetBuffer;
 567     jint packetBufferOffset, packetBufferLen;
 568 
 569     int fd;
 570 
 571     int n;
 572     SOCKADDR remote_addr;
 573     socklen_t slen = SOCKADDR_LEN;
 574     int port;
 575 
 576     if (IS_NULL(fdObj)) {
 577         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 578                         "Socket closed");
 579         return -1;
 580     }
 581 
 582     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 583 
 584     if (IS_NULL(packet)) {
 585         JNU_ThrowNullPointerException(env, "packet");
 586         return -1;
 587     }
 588 
 589     packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
 590     if (IS_NULL(packetBuffer)) {
 591         JNU_ThrowNullPointerException(env, "packet buffer");
 592         return -1;
 593     }
 594     packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
 595     packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
 596     if (timeout) {
 597         int ret = NET_Timeout(fd, timeout);
 598         if (ret == 0) {
 599             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 600                             "Receive timed out");
 601             return -1;
 602         } else if (ret == -1) {
 603 #ifdef __linux__
 604             if (errno == EBADF) {
 605                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 606             } else {
 607                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
 608             }
 609 #else
 610             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 611 #endif
 612             return -1;




 613         }
 614     }
 615 
 616     if (packetBufferLen > MAX_BUFFER_LEN) {
 617 
 618         /* When JNI-ifying the JDK's IO routines, we turned
 619          * reads and writes of byte arrays of size greater
 620          * than 2048 bytes into several operations of size 2048.
 621          * This saves a malloc()/memcpy()/free() for big
 622          * buffers.  This is OK for file IO and TCP, but that
 623          * strategy violates the semantics of a datagram protocol.
 624          * (one big send) != (several smaller sends).  So here
 625          * we *must* allocate the buffer.  Note it needn't be bigger
 626          * than 65,536 (0xFFFF), the max size of an IP packet.
 627          * anything bigger is truncated anyway.
 628          *
 629          * We may want to use a smarter allocation scheme at some
 630          * point.
 631          */
 632         if (packetBufferLen > MAX_PACKET_LEN) {
 633             packetBufferLen = MAX_PACKET_LEN;
 634         }
 635         fullPacket = (char *)malloc(packetBufferLen);
 636 
 637         if (!fullPacket) {
 638             JNU_ThrowOutOfMemoryError(env, "Peek buffer native heap allocation failed");
 639             return -1;
 640         } else {
 641             mallocedPacket = JNI_TRUE;
 642         }
 643     } else {
 644         fullPacket = &(BUF[0]);
 645     }
 646 

 647     n = NET_RecvFrom(fd, fullPacket, packetBufferLen, MSG_PEEK,
 648                      (struct sockaddr *)&remote_addr, &slen);
 649     /* truncate the data if the packet's length is too small */
 650     if (n > packetBufferLen) {
 651         n = packetBufferLen;
 652     }
 653     if (n == -1) {
 654 
 655 #ifdef __solaris__
 656         if (errno == ECONNREFUSED) {
 657             int orig_errno = errno;
 658             (void) recv(fd, fullPacket, 1, 0);
 659             errno = orig_errno;
 660         }
 661 #endif
 662         (*env)->SetIntField(env, packet, dp_offsetID, 0);
 663         (*env)->SetIntField(env, packet, dp_lengthID, 0);
 664         if (errno == ECONNREFUSED) {
 665             JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 666                             "ICMP Port Unreachable");
 667         } else {
 668             if (errno == EBADF) {
 669                  JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 670             } else {
 671                  NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
 672             }
 673         }





 674     } else {
 675         /*
 676          * success - fill in received address...
 677          *
 678          * REMIND: Fill in an int on the packet, and create inetadd
 679          * object in Java, as a performance improvement. Also
 680          * construct the inetadd object lazily.
 681          */
 682 
 683         jobject packetAddress;
 684 
 685         /*
 686          * Check if there is an InetAddress already associated with this
 687          * packet. If so we check if it is the same source address. We
 688          * can't update any existing InetAddress because it is immutable
 689          */
 690         packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
 691         if (packetAddress != NULL) {
 692             if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) {
 693                 /* force a new InetAddress to be created */


 720  * Method:    receive
 721  * Signature: (Ljava/net/DatagramPacket;)V
 722  */
 723 JNIEXPORT void JNICALL
 724 Java_java_net_PlainDatagramSocketImpl_receive0(JNIEnv *env, jobject this,
 725                                               jobject packet) {
 726 
 727     char BUF[MAX_BUFFER_LEN];
 728     char *fullPacket = NULL;
 729     int mallocedPacket = JNI_FALSE;
 730     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 731     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
 732 
 733     jbyteArray packetBuffer;
 734     jint packetBufferOffset, packetBufferLen;
 735 
 736     int fd;
 737 
 738     int n;
 739     SOCKADDR remote_addr;
 740     socklen_t slen = SOCKADDR_LEN;
 741     jboolean retry;
 742 #ifdef __linux__
 743     jboolean connected = JNI_FALSE;
 744     jobject connectedAddress = NULL;
 745     jint connectedPort = 0;
 746     jlong prevTime = 0;
 747 #endif
 748 
 749     if (IS_NULL(fdObj)) {
 750         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 751                         "Socket closed");
 752         return;
 753     }
 754 
 755     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 756 
 757     if (IS_NULL(packet)) {
 758         JNU_ThrowNullPointerException(env, "packet");
 759         return;
 760     }


 790 
 791         if (!fullPacket) {
 792             JNU_ThrowOutOfMemoryError(env, "Receive buffer native heap allocation failed");
 793             return;
 794         } else {
 795             mallocedPacket = JNI_TRUE;
 796         }
 797     } else {
 798         fullPacket = &(BUF[0]);
 799     }
 800 
 801     do {
 802         retry = JNI_FALSE;
 803 
 804         if (timeout) {
 805             int ret = NET_Timeout(fd, timeout);
 806             if (ret <= 0) {
 807                 if (ret == 0) {
 808                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 809                                     "Receive timed out");
 810                 } else if (ret == -1) {
 811 #ifdef __linux__
 812                     if (errno == EBADF) {
 813                          JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 814                      } else {
 815                          NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
 816                      }
 817 #else
 818                      JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 819 #endif



 820                 }
 821 
 822                 if (mallocedPacket) {
 823                     free(fullPacket);
 824                 }
 825 
 826                 return;
 827             }
 828         }
 829 

 830         n = NET_RecvFrom(fd, fullPacket, packetBufferLen, 0,
 831                          (struct sockaddr *)&remote_addr, &slen);
 832         /* truncate the data if the packet's length is too small */
 833         if (n > packetBufferLen) {
 834             n = packetBufferLen;
 835         }
 836         if (n == -1) {
 837             (*env)->SetIntField(env, packet, dp_offsetID, 0);
 838             (*env)->SetIntField(env, packet, dp_lengthID, 0);
 839             if (errno == ECONNREFUSED) {
 840                 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 841                                 "ICMP Port Unreachable");
 842             } else {
 843                 if (errno == EBADF) {
 844                      JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 845                  } else {
 846                      NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
 847                  }
 848             }





 849         } else {
 850             int port;
 851             jobject packetAddress;
 852 
 853             /*
 854              * success - fill in received address...
 855              *
 856              * REMIND: Fill in an int on the packet, and create inetadd
 857              * object in Java, as a performance improvement. Also
 858              * construct the inetadd object lazily.
 859              */
 860 
 861             /*
 862              * Check if there is an InetAddress already associated with this
 863              * packet. If so we check if it is the same source address. We
 864              * can't update any existing InetAddress because it is immutable
 865              */
 866             packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
 867             if (packetAddress != NULL) {
 868                 if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) {


 897  * Method:    datagramSocketCreate
 898  * Signature: ()V
 899  */
 900 JNIEXPORT void JNICALL
 901 Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
 902                                                            jobject this) {
 903     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 904     int arg, fd, t = 1;
 905 #ifdef AF_INET6
 906     int domain = ipv6_available() ? AF_INET6 : AF_INET;
 907 #else
 908     int domain = AF_INET;
 909 #endif
 910 
 911     if (IS_NULL(fdObj)) {
 912         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 913                         "Socket closed");
 914         return;
 915     }
 916 
 917     if ((fd = socket(domain, SOCK_DGRAM, 0)) == -1) {
 918         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
 919                        "Error creating socket");
 920         return;
 921     }
 922 
 923 #ifdef AF_INET6
 924     /* Disable IPV6_V6ONLY to ensure dual-socket support */
 925     if (domain == AF_INET6) {
 926         arg = 0;
 927         if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
 928                        sizeof(int)) < 0) {
 929             NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
 930             close(fd);
 931             return;
 932         }
 933     }
 934 #endif /* AF_INET6 */
 935 
 936 #ifdef __APPLE__
 937     arg = 65507;
 938     if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
 939                    (char *)&arg, sizeof(arg)) < 0) {
 940         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 941                         strerror(errno));
 942         return;
 943     }
 944     if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
 945                    (char *)&arg, sizeof(arg)) < 0) {
 946         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 947                         strerror(errno));
 948         return;
 949     }
 950 #endif /* __APPLE__ */
 951 
 952      setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*) &t, sizeof(int));
 953 
 954 #if defined(__linux__)
 955      arg = 0;
 956      int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP;
 957      if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) &&
 958          (errno != ENOPROTOOPT)) {
 959          JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 960                          strerror(errno));
 961          close(fd);
 962          return;
 963      }
 964 #endif


1031      * Check that there is at least one address bound to this
1032      * interface.
1033      */
1034     if (len < 1) {
1035         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1036             "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface");
1037         return;
1038     }
1039 
1040     /*
1041      * We need an ipv4 address here
1042      */
1043     for (i = 0; i < len; i++) {
1044         addr = (*env)->GetObjectArrayElement(env, addrArray, i);
1045         if (getInetAddress_family(env, addr) == IPv4) {
1046             in.s_addr = htonl(getInetAddress_addr(env, addr));
1047             break;
1048         }
1049     }
1050 
1051     if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1052                    (const char*)&in, sizeof(in)) < 0) {
1053         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1054                        "Error setting socket option");
1055     }
1056 }
1057 
1058 /*
1059  * Set outgoing multicast interface designated by a NetworkInterface.
1060  * Throw exception if failed.
1061  */
1062 #ifdef AF_INET6
1063 static void mcast_set_if_by_if_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1064     static jfieldID ni_indexID;
1065     int index;
1066 
1067     if (ni_indexID == NULL) {
1068         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1069         CHECK_NULL(c);
1070         ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1071         CHECK_NULL(ni_indexID);
1072     }
1073     index = (*env)->GetIntField(env, value, ni_indexID);
1074 
1075     if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1076                    (const char*)&index, sizeof(index)) < 0) {
1077         if (errno == EINVAL && index > 0) {
1078             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1079                 "IPV6_MULTICAST_IF failed (interface has IPv4 "
1080                 "address only?)");
1081         } else {
1082             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1083                            "Error setting socket option");
1084         }
1085         return;
1086     }
1087 
1088 }
1089 #endif /* AF_INET6 */
1090 
1091 /*
1092  * Set outgoing multicast interface designated by an InetAddress.
1093  * Throw exception if failed.
1094  */
1095 static void mcast_set_if_by_addr_v4(JNIEnv *env, jobject this, int fd, jobject value) {
1096     struct in_addr in;
1097 
1098     in.s_addr = htonl( getInetAddress_addr(env, value) );
1099 
1100     if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1101                    (const char*)&in, sizeof(in)) < 0) {
1102         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1103                          "Error setting socket option");
1104     }
1105 }
1106 
1107 /*
1108  * Set outgoing multicast interface designated by an InetAddress.
1109  * Throw exception if failed.
1110  */
1111 #ifdef AF_INET6
1112 static void mcast_set_if_by_addr_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1113     static jclass ni_class;
1114     if (ni_class == NULL) {
1115         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1116         CHECK_NULL(c);
1117         ni_class = (*env)->NewGlobalRef(env, c);
1118         CHECK_NULL(ni_class);
1119     }
1120 


1429 #endif
1430 
1431     /*
1432      * IPv4 implementation
1433      */
1434     if (isIPV4) {
1435         static jclass inet4_class;
1436         static jmethodID inet4_ctrID;
1437 
1438         static jclass ni_class;
1439         static jmethodID ni_ctrID;
1440         static jfieldID ni_indexID;
1441         static jfieldID ni_addrsID;
1442 
1443         jobjectArray addrArray;
1444         jobject addr;
1445         jobject ni;
1446 
1447         struct in_addr in;
1448         struct in_addr *inP = &in;
1449         socklen_t len = sizeof(struct in_addr);
1450 
1451         if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1452                        (char *)inP, &len) < 0) {
1453             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1454                              "Error getting socket option");
1455             return NULL;
1456         }
1457 
1458         /*
1459          * Construct and populate an Inet4Address
1460          */
1461         if (inet4_class == NULL) {
1462             jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
1463             CHECK_NULL_RETURN(c, NULL);
1464             inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1465             CHECK_NULL_RETURN(inet4_ctrID, NULL);
1466             inet4_class = (*env)->NewGlobalRef(env, c);
1467             CHECK_NULL_RETURN(inet4_class, NULL);
1468         }
1469         addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0);
1470         CHECK_NULL_RETURN(addr, NULL);
1471 


1515         (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
1516         return ni;
1517     }
1518 
1519 
1520 #ifdef AF_INET6
1521     /*
1522      * IPv6 implementation
1523      */
1524     if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
1525         (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1526 
1527         static jclass ni_class;
1528         static jmethodID ni_ctrID;
1529         static jfieldID ni_indexID;
1530         static jfieldID ni_addrsID;
1531         static jclass ia_class;
1532         static jmethodID ia_anyLocalAddressID;
1533 
1534         int index;
1535         socklen_t len = sizeof(index);
1536 
1537         jobjectArray addrArray;
1538         jobject addr;
1539         jobject ni;
1540 
1541         if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1542                        (char*)&index, &len) < 0) {
1543             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1544                            "Error getting socket option");
1545             return NULL;
1546         }
1547 
1548         if (ni_class == NULL) {
1549             jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1550             CHECK_NULL_RETURN(c, NULL);
1551             ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1552             CHECK_NULL_RETURN(ni_ctrID, NULL);
1553             ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1554             CHECK_NULL_RETURN(ni_indexID, NULL);
1555             ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1556                                             "[Ljava/net/InetAddress;");
1557             CHECK_NULL_RETURN(ni_addrsID, NULL);
1558 
1559             ia_class = (*env)->FindClass(env, "java/net/InetAddress");
1560             CHECK_NULL_RETURN(ia_class, NULL);
1561             ia_class = (*env)->NewGlobalRef(env, ia_class);


1736 
1737 /*
1738  * Multicast-related calls
1739  */
1740 
1741 JNIEXPORT void JNICALL
1742 Java_java_net_PlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this,
1743                                              jbyte ttl) {
1744     jint ittl = ttl;
1745     if (ittl < 0) {
1746         ittl += 0x100;
1747     }
1748     Java_java_net_PlainDatagramSocketImpl_setTimeToLive(env, this, ittl);
1749 }
1750 
1751 /*
1752  * Set TTL for a socket. Throw exception if failed.
1753  */
1754 static void setTTL(JNIEnv *env, int fd, jint ttl) {
1755     char ittl = (char)ttl;
1756     if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
1757                    sizeof(ittl)) < 0) {
1758         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1759                        "Error setting socket option");
1760     }
1761 }
1762 
1763 /*
1764  * Set hops limit for a socket. Throw exception if failed.
1765  */
1766 #ifdef AF_INET6
1767 static void setHopLimit(JNIEnv *env, int fd, jint ttl) {
1768     int ittl = (int)ttl;
1769     if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1770                    (char*)&ittl, sizeof(ittl)) < 0) {
1771         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1772                        "Error setting socket option");
1773     }
1774 }
1775 #endif
1776 
1777 /*
1778  * Class:     java_net_PlainDatagramSocketImpl
1779  * Method:    setTTL
1780  * Signature: (B)V
1781  */
1782 JNIEXPORT void JNICALL
1783 Java_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 


1830  * Method:    getTTL
1831  * Signature: ()B
1832  */
1833 JNIEXPORT jint JNICALL
1834 Java_java_net_PlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) {
1835 
1836     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1837     jint fd = -1;
1838 
1839     if (IS_NULL(fdObj)) {
1840         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1841                         "Socket closed");
1842         return -1;
1843     } else {
1844         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1845     }
1846     /* getsockopt of TTL */
1847 #ifdef AF_INET6
1848     if (ipv6_available()) {
1849         int ttl = 0;
1850         socklen_t len = sizeof(ttl);
1851 
1852         if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1853                        (char*)&ttl, &len) < 0) {
1854             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1855                                          "Error getting socket option");
1856             return -1;
1857         }
1858         return (jint)ttl;
1859     } else
1860 #endif /* AF_INET6 */
1861         {
1862             u_char ttl = 0;
1863             socklen_t len = sizeof(ttl);
1864             if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
1865                            (char*)&ttl, &len) < 0) {
1866                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1867                                "Error getting socket option");
1868                 return -1;
1869             }
1870             return (jint)ttl;
1871         }
1872 }
1873 
1874 
1875 /*
1876  * mcast_join_leave: Join or leave a multicast group.
1877  *
1878  * For IPv4 sockets use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option
1879  * to join/leave multicast group.
1880  *
1881  * For IPv6 sockets use IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP socket option
1882  * to join/leave multicast group. If multicast group is an IPv4 address then
1883  * an IPv4-mapped address is used.
1884  *


1997         /*
1998          * joinGroup(InetAddress) implementation :-
1999          *
2000          * Linux/IPv6:  use ip_mreqn structure populated with multicast
2001          *              address and interface index. index obtained
2002          *              from cached value or IPV6_MULTICAST_IF.
2003          *
2004          * IPv4:        use ip_mreq structure populated with multicast
2005          *              address and local address obtained from
2006          *              IP_MULTICAST_IF. On Linux IP_MULTICAST_IF
2007          *              returns different structure depending on
2008          *              kernel.
2009          */
2010 
2011         if (niObj == NULL) {
2012 
2013 #if defined(__linux__) && defined(AF_INET6)
2014             if (ipv6_available()) {
2015 
2016                 int index;
2017                 socklen_t len = sizeof(index);
2018 
2019                 if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
2020                                (char*)&index, &len) < 0) {
2021                     NET_ThrowCurrent(env, "getsockopt IPV6_MULTICAST_IF failed");
2022                     return;
2023                 }
2024 
2025                 mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj));
2026                 mname.imr_address.s_addr = 0 ;
2027                 mname.imr_ifindex = index;
2028                 mname_len = sizeof(struct ip_mreqn);
2029             } else
2030 #endif
2031             {
2032                 struct in_addr in;
2033                 struct in_addr *inP = &in;
2034                 socklen_t len = sizeof(struct in_addr);
2035 
2036                 if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (char *)inP, &len) < 0) {
2037                     NET_ThrowCurrent(env, "getsockopt IP_MULTICAST_IF failed");
2038                     return;
2039                 }
2040 
2041 #ifdef __linux__
2042                 mname.imr_address.s_addr = in.s_addr;
2043 
2044 #else
2045                 mname.imr_interface.s_addr = in.s_addr;
2046 #endif
2047                 mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj));
2048                 mname_len = sizeof(struct ip_mreq);
2049             }
2050         }
2051 
2052 
2053         /*
2054          * Join the multicast group.
2055          */
2056         if (setsockopt(fd, IPPROTO_IP, (join ? IP_ADD_MEMBERSHIP:IP_DROP_MEMBERSHIP),
2057                        (char *) &mname, mname_len) < 0) {
2058 
2059             /*
2060              * If IP_ADD_MEMBERSHIP returns ENOPROTOOPT on Linux and we've got
2061              * IPv6 enabled then it's possible that the kernel has been fixed
2062              * so we switch to IPV6_ADD_MEMBERSHIP socket option.
2063              * As of 2.4.7 kernel IPV6_ADD_MEMBERSHIP can't handle IPv4-mapped
2064              * addresses so we have to use IP_ADD_MEMBERSHIP for IPv4 multicast
2065              * groups. However if the socket is an IPv6 socket then then setsockopt
2066              * should return ENOPROTOOPT. We assume this will be fixed in Linux
2067              * at some stage.
2068              */
2069 #if defined(__linux__) && defined(AF_INET6)
2070             if (errno == ENOPROTOOPT) {
2071                 if (ipv6_available()) {
2072                     ipv6_join_leave = JNI_TRUE;
2073                     errno = 0;
2074                 } else  {
2075                     errno = ENOPROTOOPT;    /* errno can be changed by ipv6_available */
2076                 }


2112         jint address;
2113         family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
2114         if (family == AF_INET) { /* will convert to IPv4-mapped address */
2115             memset((char *) caddr, 0, 16);
2116             address = getInetAddress_addr(env, iaObj);
2117 
2118             caddr[10] = 0xff;
2119             caddr[11] = 0xff;
2120 
2121             caddr[12] = ((address >> 24) & 0xff);
2122             caddr[13] = ((address >> 16) & 0xff);
2123             caddr[14] = ((address >> 8) & 0xff);
2124             caddr[15] = (address & 0xff);
2125         } else {
2126             getInet6Address_ipaddress(env, iaObj, (char*)caddr);
2127         }
2128 
2129         memcpy((void *)&(mname6.ipv6mr_multiaddr), caddr, sizeof(struct in6_addr));
2130         if (IS_NULL(niObj)) {
2131             int index;
2132             socklen_t len = sizeof(index);
2133 
2134             if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
2135                            (char*)&index, &len) < 0) {
2136                 NET_ThrowCurrent(env, "getsockopt IPV6_MULTICAST_IF failed");
2137                 return;
2138             }
2139 
2140 #ifdef __linux__
2141             /*
2142              * On 2.4.8+ if we join a group with the interface set to 0
2143              * then the kernel records the interface it decides. This causes
2144              * subsequent leave groups to fail as there is no match. Thus we
2145              * pick the interface if there is a matching route.
2146              */
2147             if (index == 0) {
2148                 int rt_index = getDefaultIPv6Interface(&(mname6.ipv6mr_multiaddr));
2149                 if (rt_index > 0) {
2150                     index = rt_index;
2151                 }
2152             }
2153 #endif
2154 #ifdef MACOSX


2158 #endif
2159             mname6.ipv6mr_interface = index;
2160         } else {
2161             jint idx = (*env)->GetIntField(env, niObj, ni_indexID);
2162             mname6.ipv6mr_interface = idx;
2163         }
2164 
2165 #if defined(_ALLBSD_SOURCE)
2166 #define ADD_MEMBERSHIP          IPV6_JOIN_GROUP
2167 #define DRP_MEMBERSHIP          IPV6_LEAVE_GROUP
2168 #define S_ADD_MEMBERSHIP        "IPV6_JOIN_GROUP"
2169 #define S_DRP_MEMBERSHIP        "IPV6_LEAVE_GROUP"
2170 #else
2171 #define ADD_MEMBERSHIP          IPV6_ADD_MEMBERSHIP
2172 #define DRP_MEMBERSHIP          IPV6_DROP_MEMBERSHIP
2173 #define S_ADD_MEMBERSHIP        "IPV6_ADD_MEMBERSHIP"
2174 #define S_DRP_MEMBERSHIP        "IPV6_DROP_MEMBERSHIP"
2175 #endif
2176 
2177         /* Join the multicast group */
2178         if (setsockopt(fd, IPPROTO_IPV6, (join ? ADD_MEMBERSHIP : DRP_MEMBERSHIP),
2179                        (char *) &mname6, sizeof (mname6)) < 0) {
2180 
2181             if (join) {
2182                 NET_ThrowCurrent(env, "setsockopt " S_ADD_MEMBERSHIP " failed");
2183             } else {
2184                 if (errno == ENOENT) {
2185                    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2186                         "Not a member of the multicast group");
2187                 } else {
2188                     NET_ThrowCurrent(env, "setsockopt " S_DRP_MEMBERSHIP " failed");
2189                 }
2190             }
2191         }
2192     }
2193 #endif
2194 }
2195 
2196 /*
2197  * Class:     java_net_PlainDatagramSocketImpl
2198  * Method:    join