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 = ∈ 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 = ∈ 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__ |