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

Print this page




  66 static jfieldID IO_fd_fdID;
  67 
  68 static jfieldID pdsi_fdID;
  69 static jfieldID pdsi_timeoutID;
  70 static jfieldID pdsi_trafficClassID;
  71 static jfieldID pdsi_localPortID;
  72 static jfieldID pdsi_connected;
  73 static jfieldID pdsi_connectedAddress;
  74 static jfieldID pdsi_connectedPort;
  75 
  76 #ifdef __linux__
  77 static jboolean isOldKernel;
  78 #endif
  79 
  80 #if defined(__linux__) && defined(AF_INET6)
  81 static jfieldID pdsi_multicastInterfaceID;
  82 static jfieldID pdsi_loopbackID;
  83 static jfieldID pdsi_ttlID;
  84 #endif
  85 
  86 /*
  87  * Returns a java.lang.Integer based on 'i'
  88  */
  89 static jobject createInteger(JNIEnv *env, int i) {
  90     static jclass i_class;
  91     static jmethodID i_ctrID;
  92 

  93     if (i_class == NULL) {
  94         jclass c = (*env)->FindClass(env, "java/lang/Integer");
  95         CHECK_NULL_RETURN(c, NULL);
  96         i_ctrID = (*env)->GetMethodID(env, c, "<init>", "(I)V");
  97         CHECK_NULL_RETURN(i_ctrID, NULL);


  98         i_class = (*env)->NewGlobalRef(env, c);
  99         CHECK_NULL_RETURN(i_class, NULL);
 100     }


 101 



 102     return ( (*env)->NewObject(env, i_class, i_ctrID, i) );
 103 }
 104 
 105 /*
 106  * Returns a java.lang.Boolean based on 'b'
 107  */
 108 static jobject createBoolean(JNIEnv *env, int b) {
 109     static jclass b_class;
 110     static jmethodID b_ctrID;
 111 





 112     if (b_class == NULL) {
 113         jclass c = (*env)->FindClass(env, "java/lang/Boolean");
 114         CHECK_NULL_RETURN(c, NULL);
 115         b_ctrID = (*env)->GetMethodID(env, c, "<init>", "(Z)V");
 116         CHECK_NULL_RETURN(b_ctrID, NULL);


 117         b_class = (*env)->NewGlobalRef(env, c);
 118         CHECK_NULL_RETURN(b_class, NULL);
 119     }


 120 



 121     return( (*env)->NewObject(env, b_class, b_ctrID, (jboolean)(b!=0)) );
 122 }
 123 





 124 
 125 /*
 126  * Returns the fd for a PlainDatagramSocketImpl or -1
 127  * if closed.
 128  */
 129 static int getFD(JNIEnv *env, jobject this) {
 130     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 131     if (fdObj == NULL) {
 132         return -1;
 133     }
 134     return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 135 }
 136 
 137 
 138 /*
 139  * Class:     java_net_PlainDatagramSocketImpl
 140  * Method:    init
 141  * Signature: ()V
 142  */
 143 JNIEXPORT void JNICALL


1118     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1119     int fd;
1120 
1121     if (IS_NULL(fdObj)) {
1122         return;
1123     }
1124     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1125     if (fd == -1) {
1126         return;
1127     }
1128     (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
1129     NET_SocketClose(fd);
1130 }
1131 
1132 
1133 /*
1134  * Set outgoing multicast interface designated by a NetworkInterface.
1135  * Throw exception if failed.
1136  */
1137 static void mcast_set_if_by_if_v4(JNIEnv *env, jobject this, int fd, jobject value) {
1138     static jfieldID ni_addrsID;
1139     static jfieldID ia_addressID;
1140     struct in_addr in;
1141     jobjectArray addrArray;
1142     jsize len;
1143     jobject addr;
1144     int i;
1145 
1146     if (ni_addrsID == NULL) {
1147         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1148         CHECK_NULL(c);
1149         ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1150                                         "[Ljava/net/InetAddress;");
1151         CHECK_NULL(ni_addrsID);
1152         c = (*env)->FindClass(env,"java/net/InetAddress");
1153         CHECK_NULL(c);
1154         ia_addressID = (*env)->GetFieldID(env, c, "address", "I");
1155         CHECK_NULL(ia_addressID);
1156     }
1157 
1158     addrArray = (*env)->GetObjectField(env, value, ni_addrsID);
1159     len = (*env)->GetArrayLength(env, addrArray);
1160 
1161     /*
1162      * Check that there is at least one address bound to this
1163      * interface.
1164      */
1165     if (len < 1) {
1166         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1167             "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface");
1168         return;
1169     }
1170 
1171     /*
1172      * We need an ipv4 address here
1173      */
1174     for (i = 0; i < len; i++) {
1175         addr = (*env)->GetObjectArrayElement(env, addrArray, i);
1176         if ((*env)->GetIntField(env, addr, ia_familyID) == IPv4) {
1177             in.s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID));
1178             break;
1179         }
1180     }
1181 
1182     if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1183                        (const char*)&in, sizeof(in)) < 0) {
1184         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1185                        "Error setting socket option");
1186     }
1187 }
1188 
1189 /*
1190  * Set outgoing multicast interface designated by a NetworkInterface.
1191  * Throw exception if failed.
1192  */
1193 #ifdef AF_INET6
1194 static void mcast_set_if_by_if_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1195     static jfieldID ni_indexID;
1196     int index;
1197 
1198     if (ni_indexID == NULL) {
1199         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1200         CHECK_NULL(c);
1201         ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1202         CHECK_NULL(ni_indexID);
1203     }
1204     index = (*env)->GetIntField(env, value, ni_indexID);
1205 
1206     if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1207                        (const char*)&index, sizeof(index)) < 0) {
1208         if (errno == EINVAL && index > 0) {
1209             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1210                 "IPV6_MULTICAST_IF failed (interface has IPv4 "
1211                 "address only?)");
1212         } else {
1213             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1214                            "Error setting socket option");
1215         }
1216         return;
1217     }
1218 
1219 #ifdef __linux__
1220     /*
1221      * Linux 2.2 kernel doesn't support IPV6_MULTICAST_IF socket
1222      * option so record index for later retrival.
1223      */
1224     if (isOldKernel) {
1225         (*env)->SetIntField(env, this, pdsi_multicastInterfaceID,
1226                             (jint)index);
1227     }
1228 #endif
1229 }
1230 #endif /* AF_INET6 */
1231 
1232 /*
1233  * Set outgoing multicast interface designated by an InetAddress.
1234  * Throw exception if failed.
1235  */
1236 static void mcast_set_if_by_addr_v4(JNIEnv *env, jobject this, int fd, jobject value) {
1237     static jfieldID ia_addressID;
1238     struct in_addr in;
1239 
1240     if (ia_addressID == NULL) {
1241         jclass c = (*env)->FindClass(env,"java/net/InetAddress");
1242         CHECK_NULL(c);
1243         ia_addressID = (*env)->GetFieldID(env, c, "address", "I");
1244         CHECK_NULL(ia_addressID);
1245     }
1246 
1247     in.s_addr = htonl( (*env)->GetIntField(env, value, ia_addressID) );
1248 
1249     if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1250                        (const char*)&in, sizeof(in)) < 0) {
1251         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1252                          "Error setting socket option");
1253     }
1254 }
1255 
1256 /*
1257  * Set outgoing multicast interface designated by an InetAddress.
1258  * Throw exception if failed.
1259  */
1260 #ifdef AF_INET6
1261 static void mcast_set_if_by_addr_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1262     static jclass ni_class;
1263     if (ni_class == NULL) {
1264         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1265         CHECK_NULL(c);
1266         ni_class = (*env)->NewGlobalRef(env, c);
1267         CHECK_NULL(ni_class);
1268     }
1269 
1270     value = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, value);
1271     if (value == NULL) {
1272         if (!(*env)->ExceptionOccurred(env)) {
1273             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1274                  "bad argument for IP_MULTICAST_IF"
1275                  ": address not bound to any interface");
1276         }
1277         return;
1278     }
1279 
1280     mcast_set_if_by_if_v6(env, this, fd, value);
1281 }
1282 #endif
1283 
1284 /*
1285  * Sets the multicast interface.
1286  *
1287  * SocketOptions.IP_MULTICAST_IF :-
1288  *      value is a InetAddress
1289  *      IPv4:   set outgoing multicast interface using


1345         } else {
1346             mcast_set_if_by_if_v4(env, this, fd, value);
1347         }
1348 #endif
1349 #ifdef __linux__
1350         mcast_set_if_by_if_v4(env, this, fd, value);
1351         if (ipv6_available()) {
1352             mcast_set_if_by_if_v6(env, this, fd, value);
1353         }
1354 #endif
1355 #else
1356         mcast_set_if_by_if_v4(env, this, fd, value);
1357 #endif  /* AF_INET6 */
1358     }
1359 }
1360 
1361 /*
1362  * Enable/disable local loopback of multicast datagrams.
1363  */
1364 static void mcast_set_loop_v4(JNIEnv *env, jobject this, int fd, jobject value) {
1365     jclass cls;
1366     jfieldID fid;
1367     jboolean on;
1368     char loopback;
1369 
1370     cls = (*env)->FindClass(env, "java/lang/Boolean");
1371     CHECK_NULL(cls);
1372     fid =  (*env)->GetFieldID(env, cls, "value", "Z");
1373     CHECK_NULL(fid);
1374 
1375     on = (*env)->GetBooleanField(env, value, fid);
1376     loopback = (!on ? 1 : 0);
1377 
1378     if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&loopback, sizeof(char)) < 0) {
1379         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1380         return;
1381     }
1382 }
1383 
1384 /*
1385  * Enable/disable local loopback of multicast datagrams.
1386  */
1387 #ifdef AF_INET6
1388 static void mcast_set_loop_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1389     jclass cls;
1390     jfieldID fid;
1391     jboolean on;
1392     int loopback;
1393 
1394     cls = (*env)->FindClass(env, "java/lang/Boolean");
1395     CHECK_NULL(cls);
1396     fid =  (*env)->GetFieldID(env, cls, "value", "Z");
1397     CHECK_NULL(fid);
1398 
1399     on = (*env)->GetBooleanField(env, value, fid);
1400     loopback = (!on ? 1 : 0);
1401 
1402     if (NET_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&loopback, sizeof(int)) < 0) {
1403         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1404         return;
1405     }
1406 
1407 #ifdef __linux__
1408     /*
1409      * Can't query IPV6_MULTICAST_LOOP on Linux 2.2 kernel so
1410      * store it in impl so that we can simulate getsockopt.
1411      */
1412     if (isOldKernel) {
1413         (*env)->SetBooleanField(env, this, pdsi_loopbackID, on);
1414     }
1415 #endif
1416 }
1417 #endif  /* AF_INET6 */
1418 
1419 /*


1490      */
1491     if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) {
1492         setMulticastLoopbackMode(env, this, fd, opt, value);
1493         return;
1494     }
1495 
1496     /*
1497      * Map the Java level socket option to the platform specific
1498      * level and option name.
1499      */
1500     if (NET_MapSocketOption(opt, &level, &optname)) {
1501         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1502         return;
1503     }
1504 
1505     switch (opt) {
1506         case java_net_SocketOptions_SO_SNDBUF :
1507         case java_net_SocketOptions_SO_RCVBUF :
1508         case java_net_SocketOptions_IP_TOS :
1509             {
1510                 jclass cls;
1511                 jfieldID fid;
1512 
1513                 cls = (*env)->FindClass(env, "java/lang/Integer");
1514                 CHECK_NULL(cls);
1515                 fid =  (*env)->GetFieldID(env, cls, "value", "I");
1516                 CHECK_NULL(fid);
1517 
1518                 optval.i = (*env)->GetIntField(env, value, fid);
1519                 optlen = sizeof(optval.i);
1520                 break;
1521             }
1522 
1523         case java_net_SocketOptions_SO_REUSEADDR:
1524         case java_net_SocketOptions_SO_BROADCAST:
1525             {
1526                 jclass cls;
1527                 jfieldID fid;
1528                 jboolean on;
1529 
1530                 cls = (*env)->FindClass(env, "java/lang/Boolean");
1531                 CHECK_NULL(cls);
1532                 fid =  (*env)->GetFieldID(env, cls, "value", "Z");
1533                 CHECK_NULL(fid);
1534 
1535                 on = (*env)->GetBooleanField(env, value, fid);
1536 
1537                 /* SO_REUSEADDR or SO_BROADCAST */
1538                 optval.i = (on ? 1 : 0);
1539                 optlen = sizeof(optval.i);
1540 
1541                 break;
1542             }
1543 
1544         default :
1545             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1546                 "Socket option not supported by PlainDatagramSocketImp");
1547             break;
1548 
1549     }
1550 
1551     if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {
1552         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1553         return;
1554     }
1555 }
1556 


1576  *              return the NetworkInterface that the address
1577  *              is bound too.
1578  *      IPv6:   Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
1579  *              (except Linux .2 kernel)
1580  *              Query NetworkInterface by index and
1581  *              return NetworkInterface.
1582  */
1583 jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, jint opt) {
1584     jboolean isIPV4 = JNI_TRUE;
1585 
1586 #ifdef AF_INET6
1587     if (ipv6_available()) {
1588         isIPV4 = JNI_FALSE;
1589     }
1590 #endif
1591 
1592     /*
1593      * IPv4 implementation
1594      */
1595     if (isIPV4) {
1596         static jclass inet4_class;
1597         static jmethodID inet4_ctrID;
1598         static jfieldID inet4_addrID;
1599 
1600         static jclass ni_class;
1601         static jmethodID ni_ctrID;
1602         static jfieldID ni_indexID;
1603         static jfieldID ni_addrsID;
1604 
1605         jobjectArray addrArray;
1606         jobject addr;
1607         jobject ni;
1608 
1609         struct in_addr in;
1610         struct in_addr *inP = &in;
1611         int len = sizeof(struct in_addr);
1612 
1613 #ifdef __linux__
1614         struct ip_mreqn mreqn;
1615         if (isOldKernel) {
1616             inP = (struct in_addr *)&mreqn;
1617             len = sizeof(struct ip_mreqn);
1618         }
1619 #endif
1620 
1621         if (JVM_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1622                            (char *)inP, &len) < 0) {
1623             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1624                              "Error getting socket option");
1625             return NULL;
1626         }
1627 
1628         /*
1629          * Construct and populate an Inet4Address
1630          */
1631         if (inet4_class == NULL) {
1632             jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
1633             CHECK_NULL_RETURN(c, NULL);
1634             inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1635             CHECK_NULL_RETURN(inet4_ctrID, NULL);
1636             inet4_addrID = (*env)->GetFieldID(env, c, "address", "I");
1637             CHECK_NULL_RETURN(inet4_addrID, NULL);
1638             inet4_class = (*env)->NewGlobalRef(env, c);
1639             CHECK_NULL_RETURN(inet4_class, NULL);
1640         }
1641         addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0);
1642         CHECK_NULL_RETURN(addr, NULL);
1643 
1644 #ifdef __linux__
1645         (*env)->SetIntField(env, addr, inet4_addrID,
1646                 (isOldKernel ? ntohl(mreqn.imr_address.s_addr) : ntohl(in.s_addr)) );
1647 #else
1648         (*env)->SetIntField(env, addr, inet4_addrID, ntohl(in.s_addr));
1649 #endif
1650 
1651         /*
1652          * For IP_MULTICAST_IF return InetAddress
1653          */
1654         if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1655             return addr;
1656         }
1657 
1658         /*
1659          * For IP_MULTICAST_IF2 we get the NetworkInterface for
1660          * this address and return it
1661          */
1662         if (ni_class == NULL) {
1663             jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1664             CHECK_NULL_RETURN(c, NULL);
1665             ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1666             CHECK_NULL_RETURN(ni_ctrID, NULL);
1667             ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1668             CHECK_NULL_RETURN(ni_indexID, NULL);
1669             ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1670                                             "[Ljava/net/InetAddress;");
1671             CHECK_NULL_RETURN(ni_addrsID, NULL);
1672             ni_class = (*env)->NewGlobalRef(env, c);
1673             CHECK_NULL_RETURN(ni_class, NULL);
1674         }
1675         ni = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, addr);
1676         if (ni) {
1677             return ni;
1678         }
1679 
1680         /*
1681          * The address doesn't appear to be bound at any known
1682          * NetworkInterface. Therefore we construct a NetworkInterface
1683          * with this address.
1684          */
1685         ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
1686         CHECK_NULL_RETURN(ni, NULL);
1687 
1688         (*env)->SetIntField(env, ni, ni_indexID, -1);
1689         addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL);
1690         CHECK_NULL_RETURN(addrArray, NULL);
1691         (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
1692         (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
1693         return ni;
1694     }
1695 
1696 
1697 #ifdef AF_INET6
1698     /*
1699      * IPv6 implementation
1700      */
1701     if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
1702         (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1703 
1704         static jclass ni_class;
1705         static jmethodID ni_ctrID;
1706         static jfieldID ni_indexID;
1707         static jfieldID ni_addrsID;
1708         static jclass ia_class;
1709         static jmethodID ia_anyLocalAddressID;
1710 
1711         int index;
1712         int len = sizeof(index);
1713 
1714         jobjectArray addrArray;
1715         jobject addr;
1716         jobject ni;
1717 
1718 #ifdef __linux__
1719         /*
1720          * Linux 2.2 kernel doesn't support IPV6_MULTICAST_IF socke option
1721          * so use cached index.
1722          */
1723         if (isOldKernel) {
1724             index = (*env)->GetIntField(env, this, pdsi_multicastInterfaceID);
1725         } else
1726 #endif
1727         {
1728             if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1729                                (char*)&index, &len) < 0) {
1730                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1731                                "Error getting socket option");
1732                 return NULL;
1733             }
1734         }
1735 
1736         if (ni_class == NULL) {
1737             jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1738             CHECK_NULL_RETURN(c, NULL);
1739             ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1740             CHECK_NULL_RETURN(ni_ctrID, NULL);
1741             ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1742             CHECK_NULL_RETURN(ni_indexID, NULL);
1743             ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1744                                             "[Ljava/net/InetAddress;");
1745             CHECK_NULL_RETURN(ni_addrsID, NULL);
1746 
1747             ia_class = (*env)->FindClass(env, "java/net/InetAddress");
1748             CHECK_NULL_RETURN(ia_class, NULL);
1749             ia_class = (*env)->NewGlobalRef(env, ia_class);
1750             CHECK_NULL_RETURN(ia_class, NULL);
1751             ia_anyLocalAddressID = (*env)->GetStaticMethodID(env,
1752                                                              ia_class,
1753                                                              "anyLocalAddress",
1754                                                              "()Ljava/net/InetAddress;");
1755             CHECK_NULL_RETURN(ia_anyLocalAddressID, NULL);
1756             ni_class = (*env)->NewGlobalRef(env, c);
1757             CHECK_NULL_RETURN(ni_class, NULL);
1758         }
1759 
1760         /*
1761          * If multicast to a specific interface then return the
1762          * interface (for IF2) or the any address on that interface
1763          * (for IF).
1764          */
1765         if (index > 0) {
1766             ni = Java_java_net_NetworkInterface_getByIndex0(env, ni_class,
1767                                                                    index);
1768             if (ni == NULL) {
1769                 char errmsg[255];
1770                 sprintf(errmsg,
1771                         "IPV6_MULTICAST_IF returned index to unrecognized interface: %d",
1772                         index);
1773                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg);
1774                 return NULL;
1775             }
1776 
1777             /*


2151 #ifdef __linux__
2152         struct ip_mreqn mname;
2153 #else
2154         struct ip_mreq mname;
2155 #endif
2156         int mname_len;
2157 
2158         /*
2159          * joinGroup(InetAddress, NetworkInterface) implementation :-
2160          *
2161          * Linux/IPv6:  use ip_mreqn structure populated with multicast
2162          *              address and interface index.
2163          *
2164          * IPv4:        use ip_mreq structure populated with multicast
2165          *              address and first address obtained from
2166          *              NetworkInterface
2167          */
2168         if (niObj != NULL) {
2169 #if defined(__linux__) && defined(AF_INET6)
2170             if (ipv6_available()) {
2171                 static jfieldID ni_indexID;
2172 
2173                 if (ni_indexID == NULL) {
2174                     jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
2175                     CHECK_NULL(c);
2176                     ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
2177                     CHECK_NULL(ni_indexID);
2178                 }
2179 
2180                 mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, ia_addressID));
2181                 mname.imr_address.s_addr = 0;
2182                 mname.imr_ifindex =  (*env)->GetIntField(env, niObj, ni_indexID);
2183                 mname_len = sizeof(struct ip_mreqn);
2184             } else
2185 #endif
2186             {
2187                 jobjectArray addrArray = (*env)->GetObjectField(env, niObj, ni_addrsID);
2188                 jobject addr;
2189 
2190                 if ((*env)->GetArrayLength(env, addrArray) < 1) {
2191                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2192                         "bad argument for IP_ADD_MEMBERSHIP: "
2193                         "No IP addresses bound to interface");
2194                     return;
2195                 }
2196                 addr = (*env)->GetObjectArrayElement(env, addrArray, 0);
2197 
2198                 mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, ia_addressID));
2199 #ifdef __linux__




  66 static jfieldID IO_fd_fdID;
  67 
  68 static jfieldID pdsi_fdID;
  69 static jfieldID pdsi_timeoutID;
  70 static jfieldID pdsi_trafficClassID;
  71 static jfieldID pdsi_localPortID;
  72 static jfieldID pdsi_connected;
  73 static jfieldID pdsi_connectedAddress;
  74 static jfieldID pdsi_connectedPort;
  75 
  76 #ifdef __linux__
  77 static jboolean isOldKernel;
  78 #endif
  79 
  80 #if defined(__linux__) && defined(AF_INET6)
  81 static jfieldID pdsi_multicastInterfaceID;
  82 static jfieldID pdsi_loopbackID;
  83 static jfieldID pdsi_ttlID;
  84 #endif
  85 
  86 static jclass i_class;
  87 static jmethodID i_ctrID;
  88 static jfieldID i_valueID;



  89 
  90 int initIntegerIDs(JNIEnv* env) {
  91     if (i_class == NULL) {
  92         jclass c = (*env)->FindClass(env, "java/lang/Integer");
  93         CHECK_NULL_RETURN(c, NULL);
  94         i_ctrID = (*env)->GetMethodID(env, c, "<init>", "(I)V");
  95         CHECK_NULL_RETURN(i_ctrID, NULL);
  96         i_valueID = (*env)->GetFieldID(env, c, "value", "I");
  97         CHECK_NULL_RETURN(i_valueID, NULL);
  98         i_class = (*env)->NewGlobalRef(env, c);
  99         CHECK_NULL_RETURN(i_class, NULL);
 100     }
 101     return 1;
 102 }
 103 
 104 /* Returns a java.lang.Integer based on 'i' */
 105 static jobject createInteger(JNIEnv *env, int i) {
 106     CHECK_NULL_RETURN(initIntegerIDs(env), NULL);
 107     return ( (*env)->NewObject(env, i_class, i_ctrID, i) );
 108 }
 109 
 110 /* Returns a jint based on the given java.lang.Integer */
 111 static jint retrieveInteger(JNIEnv *env, jobject i) {
 112     CHECK_NULL_RETURN(initIntegerIDs(env), NULL);
 113     return (*env)->GetIntField(env, i, i_valueID);
 114 }

 115 
 116 static jclass b_class;
 117 static jmethodID b_ctrID;
 118 static jfieldID b_valueID;
 119 
 120 int initBooleanIDs(JNIEnv* env) {
 121     if (b_class == NULL) {
 122         jclass c = (*env)->FindClass(env, "java/lang/Boolean");
 123         CHECK_NULL_RETURN(c, NULL);
 124         b_ctrID = (*env)->GetMethodID(env, c, "<init>", "(Z)V");
 125         CHECK_NULL_RETURN(b_ctrID, NULL);
 126         b_valueID = (*env)->GetFieldID(env, c, "value", "Z");
 127         CHECK_NULL_RETURN(b_valueID, NULL);
 128         b_class = (*env)->NewGlobalRef(env, c);
 129         CHECK_NULL_RETURN(b_class, NULL);
 130     }
 131     return 1;
 132 }
 133 
 134 /* Returns a java.lang.Boolean based on 'b' */
 135 static jobject createBoolean(JNIEnv *env, int b) {
 136     CHECK_NULL_RETURN(initBooleanIDs(env), NULL);
 137     return( (*env)->NewObject(env, b_class, b_ctrID, (jboolean)(b!=0)) );
 138 }
 139 
 140 /* Returns a jboolean based on the given java.lang.Boolean */
 141 static jboolean retrieveBoolean(JNIEnv *env, jobject b) {
 142     CHECK_NULL_RETURN(initBooleanIDs(env), NULL);
 143     return (*env)->GetBooleanField(env, b, b_valueID);
 144 }
 145 
 146 /*
 147  * Returns the fd for a PlainDatagramSocketImpl or -1
 148  * if closed.
 149  */
 150 static int getFD(JNIEnv *env, jobject this) {
 151     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 152     if (fdObj == NULL) {
 153         return -1;
 154     }
 155     return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 156 }
 157 
 158 
 159 /*
 160  * Class:     java_net_PlainDatagramSocketImpl
 161  * Method:    init
 162  * Signature: ()V
 163  */
 164 JNIEXPORT void JNICALL


1139     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1140     int fd;
1141 
1142     if (IS_NULL(fdObj)) {
1143         return;
1144     }
1145     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1146     if (fd == -1) {
1147         return;
1148     }
1149     (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
1150     NET_SocketClose(fd);
1151 }
1152 
1153 
1154 /*
1155  * Set outgoing multicast interface designated by a NetworkInterface.
1156  * Throw exception if failed.
1157  */
1158 static void mcast_set_if_by_if_v4(JNIEnv *env, jobject this, int fd, jobject value) {


1159     struct in_addr in;
1160     jobjectArray addrArray;
1161     jsize len;
1162     jobject addr;
1163     int i;
1164 












1165     addrArray = (*env)->GetObjectField(env, value, ni_addrsID);
1166     len = (*env)->GetArrayLength(env, addrArray);
1167 
1168     /*
1169      * Check that there is at least one address bound to this
1170      * interface.
1171      */
1172     if (len < 1) {
1173         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1174             "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface");
1175         return;
1176     }
1177 
1178     /*
1179      * We need an ipv4 address here
1180      */
1181     for (i = 0; i < len; i++) {
1182         addr = (*env)->GetObjectArrayElement(env, addrArray, i);
1183         if ((*env)->GetIntField(env, addr, ia_familyID) == IPv4) {
1184             in.s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID));
1185             break;
1186         }
1187     }
1188 
1189     if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1190                        (const char*)&in, sizeof(in)) < 0) {
1191         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1192                        "Error setting socket option");
1193     }
1194 }
1195 
1196 /*
1197  * Set outgoing multicast interface designated by a NetworkInterface.
1198  * Throw exception if failed.
1199  */
1200 #ifdef AF_INET6
1201 static void mcast_set_if_by_if_v6(JNIEnv *env, jobject this, int fd, jobject value) {

1202     int index;
1203 






1204     index = (*env)->GetIntField(env, value, ni_indexID);
1205 
1206     if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1207                        (const char*)&index, sizeof(index)) < 0) {
1208         if (errno == EINVAL && index > 0) {
1209             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1210                 "IPV6_MULTICAST_IF failed (interface has IPv4 "
1211                 "address only?)");
1212         } else {
1213             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1214                            "Error setting socket option");
1215         }
1216         return;
1217     }
1218 
1219 #ifdef __linux__
1220     /*
1221      * Linux 2.2 kernel doesn't support IPV6_MULTICAST_IF socket
1222      * option so record index for later retrival.
1223      */
1224     if (isOldKernel) {
1225         (*env)->SetIntField(env, this, pdsi_multicastInterfaceID,
1226                             (jint)index);
1227     }
1228 #endif
1229 }
1230 #endif /* AF_INET6 */
1231 
1232 /*
1233  * Set outgoing multicast interface designated by an InetAddress.
1234  * Throw exception if failed.
1235  */
1236 static void mcast_set_if_by_addr_v4(JNIEnv *env, jobject this, int fd, jobject value) {

1237     struct in_addr in;
1238 







1239     in.s_addr = htonl( (*env)->GetIntField(env, value, ia_addressID) );
1240 
1241     if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1242                        (const char*)&in, sizeof(in)) < 0) {
1243         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1244                          "Error setting socket option");
1245     }
1246 }
1247 
1248 /*
1249  * Set outgoing multicast interface designated by an InetAddress.
1250  * Throw exception if failed.
1251  */
1252 #ifdef AF_INET6
1253 static void mcast_set_if_by_addr_v6(JNIEnv *env, jobject this, int fd, jobject value) {








1254     value = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, value);
1255     if (value == NULL) {
1256         if (!(*env)->ExceptionOccurred(env)) {
1257             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1258                  "bad argument for IP_MULTICAST_IF"
1259                  ": address not bound to any interface");
1260         }
1261         return;
1262     }
1263 
1264     mcast_set_if_by_if_v6(env, this, fd, value);
1265 }
1266 #endif
1267 
1268 /*
1269  * Sets the multicast interface.
1270  *
1271  * SocketOptions.IP_MULTICAST_IF :-
1272  *      value is a InetAddress
1273  *      IPv4:   set outgoing multicast interface using


1329         } else {
1330             mcast_set_if_by_if_v4(env, this, fd, value);
1331         }
1332 #endif
1333 #ifdef __linux__
1334         mcast_set_if_by_if_v4(env, this, fd, value);
1335         if (ipv6_available()) {
1336             mcast_set_if_by_if_v6(env, this, fd, value);
1337         }
1338 #endif
1339 #else
1340         mcast_set_if_by_if_v4(env, this, fd, value);
1341 #endif  /* AF_INET6 */
1342     }
1343 }
1344 
1345 /*
1346  * Enable/disable local loopback of multicast datagrams.
1347  */
1348 static void mcast_set_loop_v4(JNIEnv *env, jobject this, int fd, jobject value) {


1349     jboolean on;
1350     char loopback;
1351 
1352     on = retrieveBoolean(env, value);





1353     loopback = (!on ? 1 : 0);
1354 
1355     if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&loopback, sizeof(char)) < 0) {
1356         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1357         return;
1358     }
1359 }
1360 
1361 /*
1362  * Enable/disable local loopback of multicast datagrams.
1363  */
1364 #ifdef AF_INET6
1365 static void mcast_set_loop_v6(JNIEnv *env, jobject this, int fd, jobject value) {


1366     jboolean on;
1367     int loopback;
1368 
1369     on = retrieveBoolean(env, value);





1370     loopback = (!on ? 1 : 0);
1371 
1372     if (NET_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&loopback, sizeof(int)) < 0) {
1373         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1374         return;
1375     }
1376 
1377 #ifdef __linux__
1378     /*
1379      * Can't query IPV6_MULTICAST_LOOP on Linux 2.2 kernel so
1380      * store it in impl so that we can simulate getsockopt.
1381      */
1382     if (isOldKernel) {
1383         (*env)->SetBooleanField(env, this, pdsi_loopbackID, on);
1384     }
1385 #endif
1386 }
1387 #endif  /* AF_INET6 */
1388 
1389 /*


1460      */
1461     if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) {
1462         setMulticastLoopbackMode(env, this, fd, opt, value);
1463         return;
1464     }
1465 
1466     /*
1467      * Map the Java level socket option to the platform specific
1468      * level and option name.
1469      */
1470     if (NET_MapSocketOption(opt, &level, &optname)) {
1471         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1472         return;
1473     }
1474 
1475     switch (opt) {
1476         case java_net_SocketOptions_SO_SNDBUF :
1477         case java_net_SocketOptions_SO_RCVBUF :
1478         case java_net_SocketOptions_IP_TOS :
1479             {
1480                 optval.i = retrieveInteger(env, value);








1481                 optlen = sizeof(optval.i);
1482                 break;
1483             }
1484 
1485         case java_net_SocketOptions_SO_REUSEADDR:
1486         case java_net_SocketOptions_SO_BROADCAST:
1487             {
1488                 jboolean on = retrieveBoolean(env, value);


1489 







1490                 /* SO_REUSEADDR or SO_BROADCAST */
1491                 optval.i = (on ? 1 : 0);
1492                 optlen = sizeof(optval.i);
1493 
1494                 break;
1495             }
1496 
1497         default :
1498             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1499                 "Socket option not supported by PlainDatagramSocketImp");
1500             break;
1501 
1502     }
1503 
1504     if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {
1505         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1506         return;
1507     }
1508 }
1509 


1529  *              return the NetworkInterface that the address
1530  *              is bound too.
1531  *      IPv6:   Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
1532  *              (except Linux .2 kernel)
1533  *              Query NetworkInterface by index and
1534  *              return NetworkInterface.
1535  */
1536 jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, jint opt) {
1537     jboolean isIPV4 = JNI_TRUE;
1538 
1539 #ifdef AF_INET6
1540     if (ipv6_available()) {
1541         isIPV4 = JNI_FALSE;
1542     }
1543 #endif
1544 
1545     /*
1546      * IPv4 implementation
1547      */
1548     if (isIPV4) {









1549         jobjectArray addrArray;
1550         jobject addr;
1551         jobject ni;
1552 
1553         struct in_addr in;
1554         struct in_addr *inP = &in;
1555         int len = sizeof(struct in_addr);
1556 
1557 #ifdef __linux__
1558         struct ip_mreqn mreqn;
1559         if (isOldKernel) {
1560             inP = (struct in_addr *)&mreqn;
1561             len = sizeof(struct ip_mreqn);
1562         }
1563 #endif
1564 
1565         if (JVM_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1566                            (char *)inP, &len) < 0) {
1567             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1568                              "Error getting socket option");
1569             return NULL;
1570         }
1571 
1572         /*
1573          * Construct and populate an Inet4Address
1574          */
1575         addr = (*env)->NewObject(env, ia4_class, ia4_ctrID, 0);










1576         CHECK_NULL_RETURN(addr, NULL);
1577 
1578 #ifdef __linux__
1579         (*env)->SetIntField(env, addr, ia_addressID,
1580                 (isOldKernel ? ntohl(mreqn.imr_address.s_addr) : ntohl(in.s_addr)) );
1581 #else
1582         (*env)->SetIntField(env, addr, ia_addressID, ntohl(in.s_addr));
1583 #endif
1584 
1585         /*
1586          * For IP_MULTICAST_IF return InetAddress
1587          */
1588         if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1589             return addr;
1590         }
1591 
1592         /*
1593          * For IP_MULTICAST_IF2 we get the NetworkInterface for
1594          * this address and return it
1595          */













1596         ni = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, addr);
1597         if (ni) {
1598             return ni;
1599         }
1600 
1601         /*
1602          * The address doesn't appear to be bound at any known
1603          * NetworkInterface. Therefore we construct a NetworkInterface
1604          * with this address.
1605          */
1606         ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
1607         CHECK_NULL_RETURN(ni, NULL);
1608 
1609         (*env)->SetIntField(env, ni, ni_indexID, -1);
1610         addrArray = (*env)->NewObjectArray(env, 1, ia4_class, NULL);
1611         CHECK_NULL_RETURN(addrArray, NULL);
1612         (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
1613         (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
1614         return ni;
1615     }
1616 
1617 
1618 #ifdef AF_INET6
1619     /*
1620      * IPv6 implementation
1621      */
1622     if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
1623         (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {






1624         static jmethodID ia_anyLocalAddressID;
1625 
1626         int index;
1627         int len = sizeof(index);
1628 
1629         jobjectArray addrArray;
1630         jobject addr;
1631         jobject ni;
1632 
1633 #ifdef __linux__
1634         /*
1635          * Linux 2.2 kernel doesn't support IPV6_MULTICAST_IF socke option
1636          * so use cached index.
1637          */
1638         if (isOldKernel) {
1639             index = (*env)->GetIntField(env, this, pdsi_multicastInterfaceID);
1640         } else
1641 #endif
1642         {
1643             if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1644                                (char*)&index, &len) < 0) {
1645                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1646                                "Error getting socket option");
1647                 return NULL;
1648             }
1649         }
1650 
1651         if (ia_anyLocalAddressID == NULL) {














1652             ia_anyLocalAddressID = (*env)->GetStaticMethodID(env,
1653                                                              ia_class,
1654                                                              "anyLocalAddress",
1655                                                              "()Ljava/net/InetAddress;");
1656             CHECK_NULL_RETURN(ia_anyLocalAddressID, NULL);


1657         }
1658 
1659         /*
1660          * If multicast to a specific interface then return the
1661          * interface (for IF2) or the any address on that interface
1662          * (for IF).
1663          */
1664         if (index > 0) {
1665             ni = Java_java_net_NetworkInterface_getByIndex0(env, ni_class,
1666                                                                    index);
1667             if (ni == NULL) {
1668                 char errmsg[255];
1669                 sprintf(errmsg,
1670                         "IPV6_MULTICAST_IF returned index to unrecognized interface: %d",
1671                         index);
1672                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg);
1673                 return NULL;
1674             }
1675 
1676             /*


2050 #ifdef __linux__
2051         struct ip_mreqn mname;
2052 #else
2053         struct ip_mreq mname;
2054 #endif
2055         int mname_len;
2056 
2057         /*
2058          * joinGroup(InetAddress, NetworkInterface) implementation :-
2059          *
2060          * Linux/IPv6:  use ip_mreqn structure populated with multicast
2061          *              address and interface index.
2062          *
2063          * IPv4:        use ip_mreq structure populated with multicast
2064          *              address and first address obtained from
2065          *              NetworkInterface
2066          */
2067         if (niObj != NULL) {
2068 #if defined(__linux__) && defined(AF_INET6)
2069             if (ipv6_available()) {









2070                 mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, ia_addressID));
2071                 mname.imr_address.s_addr = 0;
2072                 mname.imr_ifindex =  (*env)->GetIntField(env, niObj, ni_indexID);
2073                 mname_len = sizeof(struct ip_mreqn);
2074             } else
2075 #endif
2076             {
2077                 jobjectArray addrArray = (*env)->GetObjectField(env, niObj, ni_addrsID);
2078                 jobject addr;
2079 
2080                 if ((*env)->GetArrayLength(env, addrArray) < 1) {
2081                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2082                         "bad argument for IP_ADD_MEMBERSHIP: "
2083                         "No IP addresses bound to interface");
2084                     return;
2085                 }
2086                 addr = (*env)->GetObjectArrayElement(env, addrArray, 0);
2087 
2088                 mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, ia_addressID));
2089 #ifdef __linux__