< prev index next >

src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c

Print this page
rev 14618 : 8158023: SocketExceptions contain too little information sometimes


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


 264 
 265     if (IS_NULL(fdObj)) {
 266         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 267                         "Socket closed");
 268         return;
 269     }
 270     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 271 
 272     if (IS_NULL(address)) {
 273         JNU_ThrowNullPointerException(env, "address");
 274         return;
 275     }
 276 
 277     if (NET_InetAddressToSockaddr(env, address, port, (struct sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) {
 278       return;
 279     }
 280 
 281     setDefaultScopeID(env, (struct sockaddr *)&rmtaddr);
 282 
 283     if (NET_Connect(fd, (struct sockaddr *)&rmtaddr, len) == -1) {
 284         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
 285                         "Connect failed");
 286         return;
 287     }
 288 
 289 }
 290 
 291 /*
 292  * Class:     java_net_PlainDatagramSocketImpl
 293  * Method:    disconnect0
 294  * Signature: ()V
 295  */
 296 JNIEXPORT void JNICALL
 297 Java_java_net_PlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jint family) {
 298     /* The object's field */
 299     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 300     /* The fdObj'fd */
 301     jint fd;
 302 
 303 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
 304     SOCKADDR addr;
 305     socklen_t len;


 452         NET_SetTrafficClass((struct sockaddr *)&rmtaddr, trafficClass);
 453     }
 454 #endif /* AF_INET6 */
 455 
 456 
 457     /*
 458      * Send the datagram.
 459      *
 460      * If we are connected it's possible that sendto will return
 461      * ECONNREFUSED indicating that an ICMP port unreachable has
 462      * received.
 463      */
 464     ret = NET_SendTo(fd, fullPacket, packetBufferLen, 0,
 465                      (struct sockaddr *)rmtaddrP, len);
 466 
 467     if (ret < 0) {
 468         if (errno == ECONNREFUSED) {
 469             JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 470                             "ICMP Port Unreachable");
 471         } else {
 472             NET_ThrowByNameWithLastError(env, "java/io/IOException", "sendto failed");
 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);


 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 == -1) {
 518             if (errno == EBADF) {
 519                  JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 520             } else if (errno == ENOMEM) {
 521                  JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
 522             } else {
 523                  NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");

 524             }
 525             return ret;
 526         }
 527     }
 528 
 529     n = NET_RecvFrom(fd, buf, 1, MSG_PEEK, (struct sockaddr *)&remote_addr, &slen);
 530 
 531     if (n == -1) {
 532 
 533 #ifdef __solaris__
 534         if (errno == ECONNREFUSED) {
 535             int orig_errno = errno;
 536             (void) recv(fd, buf, 1, 0);
 537             errno = orig_errno;
 538         }
 539 #endif
 540         if (errno == ECONNREFUSED) {
 541             JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 542                             "ICMP Port Unreachable");
 543         } else {
 544             if (errno == EBADF) {
 545                  JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 546             } else {
 547                  NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");

 548             }
 549         }
 550         return 0;
 551     }
 552 
 553     iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
 554 #ifdef AF_INET6
 555     family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
 556 #else
 557     family = AF_INET;
 558 #endif
 559     if (family == AF_INET) { /* this API can't handle IPV6 addresses */
 560         int address = getInetAddress_addr(env, iaObj);
 561         setInetAddress_addr(env, addressObj, address);
 562     }
 563     return port;
 564 }
 565 
 566 JNIEXPORT jint JNICALL
 567 Java_java_net_PlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this,


 599     packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
 600     if (IS_NULL(packetBuffer)) {
 601         JNU_ThrowNullPointerException(env, "packet buffer");
 602         return -1;
 603     }
 604     packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
 605     packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
 606     if (timeout) {
 607         int ret = NET_Timeout(fd, timeout);
 608         if (ret == 0) {
 609             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 610                             "Receive timed out");
 611             return -1;
 612         } else if (ret == -1) {
 613             if (errno == ENOMEM) {
 614                 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
 615 #ifdef __linux__
 616             } else if (errno == EBADF) {
 617                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 618             } else {
 619                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");

 620 #else
 621             } else {
 622                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 623 #endif
 624             }
 625             return -1;
 626         }
 627     }
 628 
 629     if (packetBufferLen > MAX_BUFFER_LEN) {
 630 
 631         /* When JNI-ifying the JDK's IO routines, we turned
 632          * reads and writes of byte arrays of size greater
 633          * than 2048 bytes into several operations of size 2048.
 634          * This saves a malloc()/memcpy()/free() for big
 635          * buffers.  This is OK for file IO and TCP, but that
 636          * strategy violates the semantics of a datagram protocol.
 637          * (one big send) != (several smaller sends).  So here
 638          * we *must* allocate the buffer.  Note it needn't be bigger
 639          * than 65,536 (0xFFFF), the max size of an IP packet.


 664         n = packetBufferLen;
 665     }
 666     if (n == -1) {
 667 
 668 #ifdef __solaris__
 669         if (errno == ECONNREFUSED) {
 670             int orig_errno = errno;
 671             (void) recv(fd, fullPacket, 1, 0);
 672             errno = orig_errno;
 673         }
 674 #endif
 675         (*env)->SetIntField(env, packet, dp_offsetID, 0);
 676         (*env)->SetIntField(env, packet, dp_lengthID, 0);
 677         if (errno == ECONNREFUSED) {
 678             JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 679                             "ICMP Port Unreachable");
 680         } else {
 681             if (errno == EBADF) {
 682                  JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 683             } else {
 684                  NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");

 685             }
 686         }
 687     } else {
 688         /*
 689          * success - fill in received address...
 690          *
 691          * REMIND: Fill in an int on the packet, and create inetadd
 692          * object in Java, as a performance improvement. Also
 693          * construct the inetadd object lazily.
 694          */
 695 
 696         jobject packetAddress;
 697 
 698         /*
 699          * Check if there is an InetAddress already associated with this
 700          * packet. If so we check if it is the same source address. We
 701          * can't update any existing InetAddress because it is immutable
 702          */
 703         packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
 704         if (packetAddress != NULL) {


 810     } else {
 811         fullPacket = &(BUF[0]);
 812     }
 813 
 814     do {
 815         retry = JNI_FALSE;
 816 
 817         if (timeout) {
 818             int ret = NET_Timeout(fd, timeout);
 819             if (ret <= 0) {
 820                 if (ret == 0) {
 821                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 822                                     "Receive timed out");
 823                 } else if (ret == -1) {
 824                     if (errno == ENOMEM) {
 825                         JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
 826 #ifdef __linux__
 827                     } else if (errno == EBADF) {
 828                          JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 829                     } else {
 830                         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");

 831 #else
 832                     } else {
 833                         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 834 #endif
 835                     }
 836                 }
 837 
 838                 if (mallocedPacket) {
 839                     free(fullPacket);
 840                 }
 841 
 842                 return;
 843             }
 844         }
 845 
 846         n = NET_RecvFrom(fd, fullPacket, packetBufferLen, 0,
 847                          (struct sockaddr *)&remote_addr, &slen);
 848         /* truncate the data if the packet's length is too small */
 849         if (n > packetBufferLen) {
 850             n = packetBufferLen;
 851         }
 852         if (n == -1) {
 853             (*env)->SetIntField(env, packet, dp_offsetID, 0);
 854             (*env)->SetIntField(env, packet, dp_lengthID, 0);
 855             if (errno == ECONNREFUSED) {
 856                 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 857                                 "ICMP Port Unreachable");
 858             } else {
 859                 if (errno == EBADF) {
 860                      JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 861                  } else {
 862                      NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");

 863                  }
 864             }
 865         } else {
 866             int port;
 867             jobject packetAddress;
 868 
 869             /*
 870              * success - fill in received address...
 871              *
 872              * REMIND: Fill in an int on the packet, and create inetadd
 873              * object in Java, as a performance improvement. Also
 874              * construct the inetadd object lazily.
 875              */
 876 
 877             /*
 878              * Check if there is an InetAddress already associated with this
 879              * packet. If so we check if it is the same source address. We
 880              * can't update any existing InetAddress because it is immutable
 881              */
 882             packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);


 915  */
 916 JNIEXPORT void JNICALL
 917 Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
 918                                                            jobject this) {
 919     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 920     int arg, fd, t = 1;
 921     char tmpbuf[1024];
 922 #ifdef AF_INET6
 923     int domain = ipv6_available() ? AF_INET6 : AF_INET;
 924 #else
 925     int domain = AF_INET;
 926 #endif
 927 
 928     if (IS_NULL(fdObj)) {
 929         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 930                         "Socket closed");
 931         return;
 932     }
 933 
 934     if ((fd = socket(domain, SOCK_DGRAM, 0)) == -1) {
 935         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
 936                        "Error creating socket");
 937         return;
 938     }
 939 
 940 #ifdef AF_INET6
 941     /* Disable IPV6_V6ONLY to ensure dual-socket support */
 942     if (domain == AF_INET6) {
 943         arg = 0;
 944         if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
 945                        sizeof(int)) < 0) {
 946             NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
 947             close(fd);
 948             return;
 949         }
 950     }
 951 #endif /* AF_INET6 */
 952 
 953 #ifdef __APPLE__
 954     arg = 65507;
 955     if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
 956                    (char *)&arg, sizeof(arg)) < 0) {


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


1239     }
1240 }
1241 
1242 /*
1243  * Enable/disable local loopback of multicast datagrams.
1244  */
1245 static void mcast_set_loop_v4(JNIEnv *env, jobject this, int fd, jobject value) {
1246     jclass cls;
1247     jfieldID fid;
1248     jboolean on;
1249     char loopback;
1250 
1251     cls = (*env)->FindClass(env, "java/lang/Boolean");
1252     CHECK_NULL(cls);
1253     fid =  (*env)->GetFieldID(env, cls, "value", "Z");
1254     CHECK_NULL(fid);
1255 
1256     on = (*env)->GetBooleanField(env, value, fid);
1257     loopback = (!on ? 1 : 0);
1258 
1259     if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&loopback, sizeof(char)) < 0) {
1260         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");


1261         return;
1262     }
1263 }
1264 
1265 /*
1266  * Enable/disable local loopback of multicast datagrams.
1267  */
1268 #ifdef AF_INET6
1269 static void mcast_set_loop_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1270     jclass cls;
1271     jfieldID fid;
1272     jboolean on;
1273     int loopback;
1274 
1275     cls = (*env)->FindClass(env, "java/lang/Boolean");
1276     CHECK_NULL(cls);
1277     fid =  (*env)->GetFieldID(env, cls, "value", "Z");
1278     CHECK_NULL(fid);
1279 
1280     on = (*env)->GetBooleanField(env, value, fid);
1281     loopback = (!on ? 1 : 0);
1282 
1283     if (NET_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&loopback, sizeof(int)) < 0) {
1284         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");


1285         return;
1286     }
1287 
1288 }
1289 #endif  /* AF_INET6 */
1290 
1291 /*
1292  * Sets the multicast loopback mode.
1293  */
1294 static void setMulticastLoopbackMode(JNIEnv *env, jobject this, int fd,
1295                                   jint opt, jobject value) {
1296 #ifdef AF_INET6
1297 #ifdef __linux__
1298     mcast_set_loop_v4(env, this, fd, value);
1299     if (ipv6_available()) {
1300         if ((*env)->ExceptionCheck(env)){
1301             (*env)->ExceptionClear(env);
1302         }
1303         mcast_set_loop_v6(env, this, fd, value);
1304     }


1403                 CHECK_NULL(cls);
1404                 fid =  (*env)->GetFieldID(env, cls, "value", "Z");
1405                 CHECK_NULL(fid);
1406 
1407                 on = (*env)->GetBooleanField(env, value, fid);
1408 
1409                 /* SO_REUSEADDR or SO_BROADCAST */
1410                 optval = (on ? 1 : 0);
1411 
1412                 break;
1413             }
1414 
1415         default :
1416             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1417                 "Socket option not supported by PlainDatagramSocketImp");
1418             return;
1419 
1420     }
1421 
1422     if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {
1423         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");

1424         return;
1425     }
1426 }
1427 
1428 
1429 /*
1430  * Return the multicast interface:
1431  *
1432  * SocketOptions.IP_MULTICAST_IF
1433  *      IPv4:   Query IPPROTO_IP/IP_MULTICAST_IF
1434  *              Create InetAddress
1435  *              IP_MULTICAST_IF returns struct ip_mreqn on 2.2
1436  *              kernel but struct in_addr on 2.4 kernel
1437  *      IPv6:   Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
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


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


1564         (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1565 
1566         static jclass ni_class;
1567         static jmethodID ni_ctrID;
1568         static jfieldID ni_indexID;
1569         static jfieldID ni_addrsID;
1570         static jclass ia_class;
1571         static jfieldID ni_nameID;
1572         static jmethodID ia_anyLocalAddressID;
1573 
1574         int index = 0;
1575         socklen_t len = sizeof(index);
1576 
1577         jobjectArray addrArray;
1578         jobject addr;
1579         jobject ni;
1580         jobject ni_name;
1581 
1582         if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1583                        (char*)&index, &len) < 0) {
1584             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1585                            "Error getting socket option");
1586             return NULL;
1587         }
1588 
1589         if (ni_class == NULL) {
1590             jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1591             CHECK_NULL_RETURN(c, NULL);
1592             ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1593             CHECK_NULL_RETURN(ni_ctrID, NULL);
1594             ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1595             CHECK_NULL_RETURN(ni_indexID, NULL);
1596             ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1597                                             "[Ljava/net/InetAddress;");
1598             CHECK_NULL_RETURN(ni_addrsID, NULL);
1599 
1600             ia_class = (*env)->FindClass(env, "java/net/InetAddress");
1601             CHECK_NULL_RETURN(ia_class, NULL);
1602             ia_class = (*env)->NewGlobalRef(env, ia_class);
1603             CHECK_NULL_RETURN(ia_class, NULL);
1604             ia_anyLocalAddressID = (*env)->GetStaticMethodID(env,
1605                                                              ia_class,


1709      */
1710     if (opt == java_net_SocketOptions_IP_MULTICAST_IF ||
1711         opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1712         return getMulticastInterface(env, this, fd, opt);
1713 
1714     }
1715 
1716     /*
1717      * SO_BINDADDR implemented using getsockname
1718      */
1719     if (opt == java_net_SocketOptions_SO_BINDADDR) {
1720         /* find out local IP address */
1721         SOCKADDR him;
1722         socklen_t len = 0;
1723         int port;
1724         jobject iaObj;
1725 
1726         len = SOCKADDR_LEN;
1727 
1728         if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) {
1729             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1730                            "Error getting socket name");
1731             return NULL;
1732         }
1733         iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
1734 
1735         return iaObj;
1736     }
1737 
1738     /*
1739      * Map the Java level socket option to the platform specific
1740      * level and option name.
1741      */
1742     if (NET_MapSocketOption(opt, &level, &optname)) {
1743         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1744         return NULL;
1745     }
1746 
1747     if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP &&
1748         level == IPPROTO_IP) {
1749         optlen = sizeof(optval.c);
1750     } else {
1751         optlen = sizeof(optval.i);
1752     }
1753 
1754     if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
1755         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1756                          "Error getting socket option");
1757         return NULL;
1758     }
1759 
1760     switch (opt) {
1761         case java_net_SocketOptions_IP_MULTICAST_LOOP:
1762             /* getLoopbackMode() returns true if IP_MULTICAST_LOOP disabled */
1763             if (level == IPPROTO_IP) {
1764                 return createBoolean(env, (int)!optval.c);
1765             } else {
1766                 return createBoolean(env, !optval.i);
1767             }
1768 
1769         case java_net_SocketOptions_SO_BROADCAST:
1770         case java_net_SocketOptions_SO_REUSEADDR:
1771             return createBoolean(env, optval.i);
1772 
1773         case java_net_SocketOptions_SO_REUSEPORT:
1774             return createBoolean(env, optval.i);
1775 
1776         case java_net_SocketOptions_SO_SNDBUF:


1788  * Multicast-related calls
1789  */
1790 
1791 JNIEXPORT void JNICALL
1792 Java_java_net_PlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this,
1793                                              jbyte ttl) {
1794     jint ittl = ttl;
1795     if (ittl < 0) {
1796         ittl += 0x100;
1797     }
1798     Java_java_net_PlainDatagramSocketImpl_setTimeToLive(env, this, ittl);
1799 }
1800 
1801 /*
1802  * Set TTL for a socket. Throw exception if failed.
1803  */
1804 static void setTTL(JNIEnv *env, int fd, jint ttl) {
1805     char ittl = (char)ttl;
1806     if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
1807                    sizeof(ittl)) < 0) {
1808         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1809                        "Error setting socket option");
1810     }
1811 }
1812 
1813 /*
1814  * Set hops limit for a socket. Throw exception if failed.
1815  */
1816 #ifdef AF_INET6
1817 static void setHopLimit(JNIEnv *env, int fd, jint ttl) {
1818     int ittl = (int)ttl;
1819     if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1820                    (char*)&ittl, sizeof(ittl)) < 0) {
1821         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1822                        "Error setting socket option");
1823     }
1824 }
1825 #endif
1826 
1827 /*
1828  * Class:     java_net_PlainDatagramSocketImpl
1829  * Method:    setTTL
1830  * Signature: (B)V
1831  */
1832 JNIEXPORT void JNICALL
1833 Java_java_net_PlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this,
1834                                                     jint ttl) {
1835 
1836     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1837     int fd;
1838     /* it is important to cast this to a char, otherwise setsockopt gets confused */
1839 
1840     if (IS_NULL(fdObj)) {
1841         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1842                         "Socket closed");


1884 Java_java_net_PlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) {
1885 
1886     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1887     jint fd = -1;
1888 
1889     if (IS_NULL(fdObj)) {
1890         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1891                         "Socket closed");
1892         return -1;
1893     } else {
1894         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1895     }
1896     /* getsockopt of TTL */
1897 #ifdef AF_INET6
1898     if (ipv6_available()) {
1899         int ttl = 0;
1900         socklen_t len = sizeof(ttl);
1901 
1902         if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1903                        (char*)&ttl, &len) < 0) {
1904             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1905                                          "Error getting socket option");
1906             return -1;
1907         }
1908         return (jint)ttl;
1909     } else
1910 #endif /* AF_INET6 */
1911         {
1912             u_char ttl = 0;
1913             socklen_t len = sizeof(ttl);
1914             if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
1915                            (char*)&ttl, &len) < 0) {
1916                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1917                                "Error getting socket option");
1918                 return -1;
1919             }
1920             return (jint)ttl;
1921         }
1922 }
1923 
1924 
1925 /*
1926  * mcast_join_leave: Join or leave a multicast group.
1927  *
1928  * For IPv4 sockets use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option
1929  * to join/leave multicast group.
1930  *
1931  * For IPv6 sockets use IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP socket option
1932  * to join/leave multicast group. If multicast group is an IPv4 address then
1933  * an IPv4-mapped address is used.
1934  *
1935  * On Linux with IPv6 if we wish to join/leave an IPv4 multicast group then
1936  * we must use the IPv4 socket options. This is because the IPv6 socket options
1937  * don't support IPv4-mapped addresses. This is true as per 2.2.19 and 2.4.7




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


 264 
 265     if (IS_NULL(fdObj)) {
 266         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 267                         "Socket closed");
 268         return;
 269     }
 270     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 271 
 272     if (IS_NULL(address)) {
 273         JNU_ThrowNullPointerException(env, "address");
 274         return;
 275     }
 276 
 277     if (NET_InetAddressToSockaddr(env, address, port, (struct sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) {
 278       return;
 279     }
 280 
 281     setDefaultScopeID(env, (struct sockaddr *)&rmtaddr);
 282 
 283     if (NET_Connect(fd, (struct sockaddr *)&rmtaddr, len) == -1) {
 284         JNU_ThrowByNameWithLastError
 285             (env, JNU_JAVANETPKG "ConnectException", "Connect failed");
 286         return;
 287     }
 288 
 289 }
 290 
 291 /*
 292  * Class:     java_net_PlainDatagramSocketImpl
 293  * Method:    disconnect0
 294  * Signature: ()V
 295  */
 296 JNIEXPORT void JNICALL
 297 Java_java_net_PlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jint family) {
 298     /* The object's field */
 299     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 300     /* The fdObj'fd */
 301     jint fd;
 302 
 303 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
 304     SOCKADDR addr;
 305     socklen_t len;


 452         NET_SetTrafficClass((struct sockaddr *)&rmtaddr, trafficClass);
 453     }
 454 #endif /* AF_INET6 */
 455 
 456 
 457     /*
 458      * Send the datagram.
 459      *
 460      * If we are connected it's possible that sendto will return
 461      * ECONNREFUSED indicating that an ICMP port unreachable has
 462      * received.
 463      */
 464     ret = NET_SendTo(fd, fullPacket, packetBufferLen, 0,
 465                      (struct sockaddr *)rmtaddrP, len);
 466 
 467     if (ret < 0) {
 468         if (errno == ECONNREFUSED) {
 469             JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 470                             "ICMP Port Unreachable");
 471         } else {
 472             JNU_ThrowIOExceptionWithLastError(env, "sendto failed");
 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);


 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 == -1) {
 518             if (errno == EBADF) {
 519                  JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 520             } else if (errno == ENOMEM) {
 521                  JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
 522             } else {
 523                  JNU_ThrowByNameWithMessageAndLastError
 524                      (env, JNU_JAVANETPKG "SocketException", "Peek failed");
 525             }
 526             return ret;
 527         }
 528     }
 529 
 530     n = NET_RecvFrom(fd, buf, 1, MSG_PEEK, (struct sockaddr *)&remote_addr, &slen);
 531 
 532     if (n == -1) {
 533 
 534 #ifdef __solaris__
 535         if (errno == ECONNREFUSED) {
 536             int orig_errno = errno;
 537             (void) recv(fd, buf, 1, 0);
 538             errno = orig_errno;
 539         }
 540 #endif
 541         if (errno == ECONNREFUSED) {
 542             JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 543                             "ICMP Port Unreachable");
 544         } else {
 545             if (errno == EBADF) {
 546                  JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 547             } else {
 548                  JNU_ThrowByNameWithMessageAndLastError
 549                      (env, JNU_JAVANETPKG "SocketException", "Peek failed");
 550             }
 551         }
 552         return 0;
 553     }
 554 
 555     iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
 556 #ifdef AF_INET6
 557     family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
 558 #else
 559     family = AF_INET;
 560 #endif
 561     if (family == AF_INET) { /* this API can't handle IPV6 addresses */
 562         int address = getInetAddress_addr(env, iaObj);
 563         setInetAddress_addr(env, addressObj, address);
 564     }
 565     return port;
 566 }
 567 
 568 JNIEXPORT jint JNICALL
 569 Java_java_net_PlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this,


 601     packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
 602     if (IS_NULL(packetBuffer)) {
 603         JNU_ThrowNullPointerException(env, "packet buffer");
 604         return -1;
 605     }
 606     packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
 607     packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
 608     if (timeout) {
 609         int ret = NET_Timeout(fd, timeout);
 610         if (ret == 0) {
 611             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 612                             "Receive timed out");
 613             return -1;
 614         } else if (ret == -1) {
 615             if (errno == ENOMEM) {
 616                 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
 617 #ifdef __linux__
 618             } else if (errno == EBADF) {
 619                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 620             } else {
 621                 JNU_ThrowByNameWithMessageAndLastError
 622                     (env, JNU_JAVANETPKG "SocketException", "Receive failed");
 623 #else
 624             } else {
 625                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 626 #endif
 627             }
 628             return -1;
 629         }
 630     }
 631 
 632     if (packetBufferLen > MAX_BUFFER_LEN) {
 633 
 634         /* When JNI-ifying the JDK's IO routines, we turned
 635          * reads and writes of byte arrays of size greater
 636          * than 2048 bytes into several operations of size 2048.
 637          * This saves a malloc()/memcpy()/free() for big
 638          * buffers.  This is OK for file IO and TCP, but that
 639          * strategy violates the semantics of a datagram protocol.
 640          * (one big send) != (several smaller sends).  So here
 641          * we *must* allocate the buffer.  Note it needn't be bigger
 642          * than 65,536 (0xFFFF), the max size of an IP packet.


 667         n = packetBufferLen;
 668     }
 669     if (n == -1) {
 670 
 671 #ifdef __solaris__
 672         if (errno == ECONNREFUSED) {
 673             int orig_errno = errno;
 674             (void) recv(fd, fullPacket, 1, 0);
 675             errno = orig_errno;
 676         }
 677 #endif
 678         (*env)->SetIntField(env, packet, dp_offsetID, 0);
 679         (*env)->SetIntField(env, packet, dp_lengthID, 0);
 680         if (errno == ECONNREFUSED) {
 681             JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 682                             "ICMP Port Unreachable");
 683         } else {
 684             if (errno == EBADF) {
 685                  JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 686             } else {
 687                  JNU_ThrowByNameWithMessageAndLastError
 688                      (env, JNU_JAVANETPKG "SocketException", "Receive failed");
 689             }
 690         }
 691     } else {
 692         /*
 693          * success - fill in received address...
 694          *
 695          * REMIND: Fill in an int on the packet, and create inetadd
 696          * object in Java, as a performance improvement. Also
 697          * construct the inetadd object lazily.
 698          */
 699 
 700         jobject packetAddress;
 701 
 702         /*
 703          * Check if there is an InetAddress already associated with this
 704          * packet. If so we check if it is the same source address. We
 705          * can't update any existing InetAddress because it is immutable
 706          */
 707         packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
 708         if (packetAddress != NULL) {


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


 921  */
 922 JNIEXPORT void JNICALL
 923 Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
 924                                                            jobject this) {
 925     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 926     int arg, fd, t = 1;
 927     char tmpbuf[1024];
 928 #ifdef AF_INET6
 929     int domain = ipv6_available() ? AF_INET6 : AF_INET;
 930 #else
 931     int domain = AF_INET;
 932 #endif
 933 
 934     if (IS_NULL(fdObj)) {
 935         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 936                         "Socket closed");
 937         return;
 938     }
 939 
 940     if ((fd = socket(domain, SOCK_DGRAM, 0)) == -1) {
 941         JNU_ThrowByNameWithMessageAndLastError
 942             (env, JNU_JAVANETPKG "SocketException", "Error creating socket");
 943         return;
 944     }
 945 
 946 #ifdef AF_INET6
 947     /* Disable IPV6_V6ONLY to ensure dual-socket support */
 948     if (domain == AF_INET6) {
 949         arg = 0;
 950         if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
 951                        sizeof(int)) < 0) {
 952             NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
 953             close(fd);
 954             return;
 955         }
 956     }
 957 #endif /* AF_INET6 */
 958 
 959 #ifdef __APPLE__
 960     arg = 65507;
 961     if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
 962                    (char *)&arg, sizeof(arg)) < 0) {


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 (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1088                    (const char*)&in, sizeof(in)) < 0) {
1089         JNU_ThrowByNameWithMessageAndLastError
1090             (env, JNU_JAVANETPKG "SocketException", "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 (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             JNU_ThrowByNameWithMessageAndLastError
1119                 (env, JNU_JAVANETPKG "SocketException", "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 (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1137                    (const char*)&in, sizeof(in)) < 0) {
1138         JNU_ThrowByNameWithMessageAndLastError
1139             (env, JNU_JAVANETPKG "SocketException", "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 
1157     value = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, value);
1158     if (value == NULL) {
1159         if (!(*env)->ExceptionOccurred(env)) {


1245     }
1246 }
1247 
1248 /*
1249  * Enable/disable local loopback of multicast datagrams.
1250  */
1251 static void mcast_set_loop_v4(JNIEnv *env, jobject this, int fd, jobject value) {
1252     jclass cls;
1253     jfieldID fid;
1254     jboolean on;
1255     char loopback;
1256 
1257     cls = (*env)->FindClass(env, "java/lang/Boolean");
1258     CHECK_NULL(cls);
1259     fid =  (*env)->GetFieldID(env, cls, "value", "Z");
1260     CHECK_NULL(fid);
1261 
1262     on = (*env)->GetBooleanField(env, value, fid);
1263     loopback = (!on ? 1 : 0);
1264 
1265     if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
1266                        (const void *)&loopback, sizeof(char)) < 0) {
1267         JNU_ThrowByNameWithMessageAndLastError
1268             (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1269         return;
1270     }
1271 }
1272 
1273 /*
1274  * Enable/disable local loopback of multicast datagrams.
1275  */
1276 #ifdef AF_INET6
1277 static void mcast_set_loop_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1278     jclass cls;
1279     jfieldID fid;
1280     jboolean on;
1281     int loopback;
1282 
1283     cls = (*env)->FindClass(env, "java/lang/Boolean");
1284     CHECK_NULL(cls);
1285     fid =  (*env)->GetFieldID(env, cls, "value", "Z");
1286     CHECK_NULL(fid);
1287 
1288     on = (*env)->GetBooleanField(env, value, fid);
1289     loopback = (!on ? 1 : 0);
1290 
1291     if (NET_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
1292                        (const void *)&loopback, sizeof(int)) < 0) {
1293         JNU_ThrowByNameWithMessageAndLastError
1294             (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1295         return;
1296     }
1297 
1298 }
1299 #endif  /* AF_INET6 */
1300 
1301 /*
1302  * Sets the multicast loopback mode.
1303  */
1304 static void setMulticastLoopbackMode(JNIEnv *env, jobject this, int fd,
1305                                   jint opt, jobject value) {
1306 #ifdef AF_INET6
1307 #ifdef __linux__
1308     mcast_set_loop_v4(env, this, fd, value);
1309     if (ipv6_available()) {
1310         if ((*env)->ExceptionCheck(env)){
1311             (*env)->ExceptionClear(env);
1312         }
1313         mcast_set_loop_v6(env, this, fd, value);
1314     }


1413                 CHECK_NULL(cls);
1414                 fid =  (*env)->GetFieldID(env, cls, "value", "Z");
1415                 CHECK_NULL(fid);
1416 
1417                 on = (*env)->GetBooleanField(env, value, fid);
1418 
1419                 /* SO_REUSEADDR or SO_BROADCAST */
1420                 optval = (on ? 1 : 0);
1421 
1422                 break;
1423             }
1424 
1425         default :
1426             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1427                 "Socket option not supported by PlainDatagramSocketImp");
1428             return;
1429 
1430     }
1431 
1432     if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {
1433         JNU_ThrowByNameWithMessageAndLastError
1434             (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1435         return;
1436     }
1437 }
1438 
1439 
1440 /*
1441  * Return the multicast interface:
1442  *
1443  * SocketOptions.IP_MULTICAST_IF
1444  *      IPv4:   Query IPPROTO_IP/IP_MULTICAST_IF
1445  *              Create InetAddress
1446  *              IP_MULTICAST_IF returns struct ip_mreqn on 2.2
1447  *              kernel but struct in_addr on 2.4 kernel
1448  *      IPv6:   Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
1449  *              If index == 0 return InetAddress representing
1450  *              anyLocalAddress.
1451  *              If index > 0 query NetworkInterface by index
1452  *              and returns addrs[0]
1453  *
1454  * SocketOptions.IP_MULTICAST_IF2


1477         static jclass inet4_class;
1478         static jmethodID inet4_ctrID;
1479 
1480         static jclass ni_class;
1481         static jmethodID ni_ctrID;
1482         static jfieldID ni_indexID;
1483         static jfieldID ni_addrsID;
1484         static jfieldID ni_nameID;
1485 
1486         jobjectArray addrArray;
1487         jobject addr;
1488         jobject ni;
1489         jobject ni_name;
1490 
1491         struct in_addr in;
1492         struct in_addr *inP = &in;
1493         socklen_t len = sizeof(struct in_addr);
1494 
1495         if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1496                        (char *)inP, &len) < 0) {
1497             JNU_ThrowByNameWithMessageAndLastError
1498                 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
1499             return NULL;
1500         }
1501 
1502         /*
1503          * Construct and populate an Inet4Address
1504          */
1505         if (inet4_class == NULL) {
1506             jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
1507             CHECK_NULL_RETURN(c, NULL);
1508             inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1509             CHECK_NULL_RETURN(inet4_ctrID, NULL);
1510             inet4_class = (*env)->NewGlobalRef(env, c);
1511             CHECK_NULL_RETURN(inet4_class, NULL);
1512         }
1513         addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0);
1514         CHECK_NULL_RETURN(addr, NULL);
1515 
1516         setInetAddress_addr(env, addr, ntohl(in.s_addr));
1517 
1518         /*


1575         (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1576 
1577         static jclass ni_class;
1578         static jmethodID ni_ctrID;
1579         static jfieldID ni_indexID;
1580         static jfieldID ni_addrsID;
1581         static jclass ia_class;
1582         static jfieldID ni_nameID;
1583         static jmethodID ia_anyLocalAddressID;
1584 
1585         int index = 0;
1586         socklen_t len = sizeof(index);
1587 
1588         jobjectArray addrArray;
1589         jobject addr;
1590         jobject ni;
1591         jobject ni_name;
1592 
1593         if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1594                        (char*)&index, &len) < 0) {
1595             JNU_ThrowByNameWithMessageAndLastError
1596                 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
1597             return NULL;
1598         }
1599 
1600         if (ni_class == NULL) {
1601             jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1602             CHECK_NULL_RETURN(c, NULL);
1603             ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1604             CHECK_NULL_RETURN(ni_ctrID, NULL);
1605             ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1606             CHECK_NULL_RETURN(ni_indexID, NULL);
1607             ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1608                                             "[Ljava/net/InetAddress;");
1609             CHECK_NULL_RETURN(ni_addrsID, NULL);
1610 
1611             ia_class = (*env)->FindClass(env, "java/net/InetAddress");
1612             CHECK_NULL_RETURN(ia_class, NULL);
1613             ia_class = (*env)->NewGlobalRef(env, ia_class);
1614             CHECK_NULL_RETURN(ia_class, NULL);
1615             ia_anyLocalAddressID = (*env)->GetStaticMethodID(env,
1616                                                              ia_class,


1720      */
1721     if (opt == java_net_SocketOptions_IP_MULTICAST_IF ||
1722         opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1723         return getMulticastInterface(env, this, fd, opt);
1724 
1725     }
1726 
1727     /*
1728      * SO_BINDADDR implemented using getsockname
1729      */
1730     if (opt == java_net_SocketOptions_SO_BINDADDR) {
1731         /* find out local IP address */
1732         SOCKADDR him;
1733         socklen_t len = 0;
1734         int port;
1735         jobject iaObj;
1736 
1737         len = SOCKADDR_LEN;
1738 
1739         if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) {
1740             JNU_ThrowByNameWithMessageAndLastError
1741                 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
1742             return NULL;
1743         }
1744         iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
1745 
1746         return iaObj;
1747     }
1748 
1749     /*
1750      * Map the Java level socket option to the platform specific
1751      * level and option name.
1752      */
1753     if (NET_MapSocketOption(opt, &level, &optname)) {
1754         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1755         return NULL;
1756     }
1757 
1758     if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP &&
1759         level == IPPROTO_IP) {
1760         optlen = sizeof(optval.c);
1761     } else {
1762         optlen = sizeof(optval.i);
1763     }
1764 
1765     if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
1766         JNU_ThrowByNameWithMessageAndLastError
1767             (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
1768         return NULL;
1769     }
1770 
1771     switch (opt) {
1772         case java_net_SocketOptions_IP_MULTICAST_LOOP:
1773             /* getLoopbackMode() returns true if IP_MULTICAST_LOOP disabled */
1774             if (level == IPPROTO_IP) {
1775                 return createBoolean(env, (int)!optval.c);
1776             } else {
1777                 return createBoolean(env, !optval.i);
1778             }
1779 
1780         case java_net_SocketOptions_SO_BROADCAST:
1781         case java_net_SocketOptions_SO_REUSEADDR:
1782             return createBoolean(env, optval.i);
1783 
1784         case java_net_SocketOptions_SO_REUSEPORT:
1785             return createBoolean(env, optval.i);
1786 
1787         case java_net_SocketOptions_SO_SNDBUF:


1799  * Multicast-related calls
1800  */
1801 
1802 JNIEXPORT void JNICALL
1803 Java_java_net_PlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this,
1804                                              jbyte ttl) {
1805     jint ittl = ttl;
1806     if (ittl < 0) {
1807         ittl += 0x100;
1808     }
1809     Java_java_net_PlainDatagramSocketImpl_setTimeToLive(env, this, ittl);
1810 }
1811 
1812 /*
1813  * Set TTL for a socket. Throw exception if failed.
1814  */
1815 static void setTTL(JNIEnv *env, int fd, jint ttl) {
1816     char ittl = (char)ttl;
1817     if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
1818                    sizeof(ittl)) < 0) {
1819         JNU_ThrowByNameWithMessageAndLastError
1820             (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1821     }
1822 }
1823 
1824 /*
1825  * Set hops limit for a socket. Throw exception if failed.
1826  */
1827 #ifdef AF_INET6
1828 static void setHopLimit(JNIEnv *env, int fd, jint ttl) {
1829     int ittl = (int)ttl;
1830     if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1831                    (char*)&ittl, sizeof(ittl)) < 0) {
1832         JNU_ThrowByNameWithMessageAndLastError
1833             (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1834     }
1835 }
1836 #endif
1837 
1838 /*
1839  * Class:     java_net_PlainDatagramSocketImpl
1840  * Method:    setTTL
1841  * Signature: (B)V
1842  */
1843 JNIEXPORT void JNICALL
1844 Java_java_net_PlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this,
1845                                                     jint ttl) {
1846 
1847     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1848     int fd;
1849     /* it is important to cast this to a char, otherwise setsockopt gets confused */
1850 
1851     if (IS_NULL(fdObj)) {
1852         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1853                         "Socket closed");


1895 Java_java_net_PlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) {
1896 
1897     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1898     jint fd = -1;
1899 
1900     if (IS_NULL(fdObj)) {
1901         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1902                         "Socket closed");
1903         return -1;
1904     } else {
1905         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1906     }
1907     /* getsockopt of TTL */
1908 #ifdef AF_INET6
1909     if (ipv6_available()) {
1910         int ttl = 0;
1911         socklen_t len = sizeof(ttl);
1912 
1913         if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1914                        (char*)&ttl, &len) < 0) {
1915             JNU_ThrowByNameWithMessageAndLastError
1916                 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
1917             return -1;
1918         }
1919         return (jint)ttl;
1920     } else
1921 #endif /* AF_INET6 */
1922         {
1923             u_char ttl = 0;
1924             socklen_t len = sizeof(ttl);
1925             if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
1926                            (char*)&ttl, &len) < 0) {
1927                 JNU_ThrowByNameWithMessageAndLastError
1928                     (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
1929                 return -1;
1930             }
1931             return (jint)ttl;
1932         }
1933 }
1934 
1935 
1936 /*
1937  * mcast_join_leave: Join or leave a multicast group.
1938  *
1939  * For IPv4 sockets use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option
1940  * to join/leave multicast group.
1941  *
1942  * For IPv6 sockets use IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP socket option
1943  * to join/leave multicast group. If multicast group is an IPv4 address then
1944  * an IPv4-mapped address is used.
1945  *
1946  * On Linux with IPv6 if we wish to join/leave an IPv4 multicast group then
1947  * we must use the IPv4 socket options. This is because the IPv6 socket options
1948  * don't support IPv4-mapped addresses. This is true as per 2.2.19 and 2.4.7


< prev index next >