48 #include "net_util.h"
49
50 #define IN_CLASSD(i) (((long)(i) & 0xf0000000) == 0xe0000000)
51 #define IN_MULTICAST(i) IN_CLASSD(i)
52
53 /************************************************************************
54 * TwoStacksPlainDatagramSocketImpl
55 */
56
57 static jfieldID IO_fd_fdID;
58 static jfieldID pdsi_trafficClassID;
59 jfieldID pdsi_fdID;
60 jfieldID pdsi_fd1ID;
61 jfieldID pdsi_fduseID;
62 jfieldID pdsi_lastfdID;
63 jfieldID pdsi_timeoutID;
64
65 jfieldID pdsi_localPortID;
66 jfieldID pdsi_connected;
67
68 static jclass ia4_clazz;
69 static jmethodID ia4_ctor;
70
71 static CRITICAL_SECTION sizeCheckLock;
72
73 /* Windows OS version is XP or better */
74 static int xp_or_later = 0;
75 /* Windows OS version is Windows 2000 or better */
76 static int w2k_or_later = 0;
77
78 /*
79 * Notes about UDP/IPV6 on Windows (XP and 2003 server):
80 *
81 * fd always points to the IPv4 fd, and fd1 points to the IPv6 fd.
82 * Both fds are used when we bind to a wild-card address. When a specific
83 * address is used, only one of them is used.
84 */
85
86 /*
87 * Returns a java.lang.Integer based on 'i'
88 */
89 jobject createInteger(JNIEnv *env, int i) {
90 static jclass i_class;
91 static jmethodID i_ctrID;
92 static jfieldID i_valueID;
93
94 if (i_class == NULL) {
95 jclass c = (*env)->FindClass(env, "java/lang/Integer");
96 CHECK_NULL_RETURN(c, NULL);
97 i_ctrID = (*env)->GetMethodID(env, c, "<init>", "(I)V");
98 CHECK_NULL_RETURN(i_ctrID, NULL);
99 i_class = (*env)->NewGlobalRef(env, c);
100 CHECK_NULL_RETURN(i_class, NULL);
101 }
102
103 return ( (*env)->NewObject(env, i_class, i_ctrID, i) );
104 }
105
106 /*
107 * Returns a java.lang.Boolean based on 'b'
108 */
109 jobject createBoolean(JNIEnv *env, int b) {
110 static jclass b_class;
111 static jmethodID b_ctrID;
112 static jfieldID b_valueID;
113
114 if (b_class == NULL) {
115 jclass c = (*env)->FindClass(env, "java/lang/Boolean");
116 CHECK_NULL_RETURN(c, NULL);
117 b_ctrID = (*env)->GetMethodID(env, c, "<init>", "(Z)V");
118 CHECK_NULL_RETURN(b_ctrID, NULL);
119 b_class = (*env)->NewGlobalRef(env, c);
120 CHECK_NULL_RETURN(b_class, NULL);
121 }
122
123 return( (*env)->NewObject(env, b_class, b_ctrID, (jboolean)(b!=0)) );
124 }
125
126
127 static int getFD(JNIEnv *env, jobject this) {
128 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
129
130 if (fdObj == NULL) {
131 return -1;
132 }
133 return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
134 }
135
136 static int getFD1(JNIEnv *env, jobject this) {
137 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
138
139 if (fdObj == NULL) {
140 return -1;
141 }
142 return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
143 }
144
145 /*
391 pdsi_fd1ID = (*env)->GetFieldID(env, cls, "fd1", "Ljava/io/FileDescriptor;");
392 CHECK_NULL(pdsi_fd1ID);
393 pdsi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
394 CHECK_NULL(pdsi_timeoutID);
395 pdsi_fduseID = (*env)->GetFieldID(env, cls, "fduse", "I");
396 CHECK_NULL(pdsi_fduseID);
397 pdsi_lastfdID = (*env)->GetFieldID(env, cls, "lastfd", "I");
398 CHECK_NULL(pdsi_lastfdID);
399 pdsi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
400 CHECK_NULL(pdsi_trafficClassID);
401 pdsi_localPortID = (*env)->GetFieldID(env, cls, "localPort", "I");
402 CHECK_NULL(pdsi_localPortID);
403 pdsi_connected = (*env)->GetFieldID(env, cls, "connected", "Z");
404 CHECK_NULL(pdsi_connected);
405
406 cls = (*env)->FindClass(env, "java/io/FileDescriptor");
407 CHECK_NULL(cls);
408 IO_fd_fdID = NET_GetFileDescriptorID(env);
409 CHECK_NULL(IO_fd_fdID);
410
411 ia4_clazz = (*env)->FindClass(env, "java/net/Inet4Address");
412 CHECK_NULL(ia4_clazz);
413 ia4_clazz = (*env)->NewGlobalRef(env, ia4_clazz);
414 CHECK_NULL(ia4_clazz);
415 ia4_ctor = (*env)->GetMethodID(env, ia4_clazz, "<init>", "()V");
416 CHECK_NULL(ia4_ctor);
417
418
419 InitializeCriticalSection(&sizeCheckLock);
420 }
421
422 JNIEXPORT void JNICALL
423 Java_java_net_TwoStacksPlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this,
424 jint port, jobject addressObj) {
425 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
426 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
427
428 int fd, fd1, family;
429 int ipv6_supported = ipv6_available();
430
431 SOCKETADDRESS lcladdr;
432 int lcladdrlen;
433 int address;
434
435 family = (*env)->GetIntField(env, addressObj, ia_familyID);
436 if (family == IPv6 && !ipv6_supported) {
437 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
438 "Protocol family not supported");
450 }
451 if (IS_NULL(addressObj)) {
452 JNU_ThrowNullPointerException(env, "argument address");
453 return;
454 } else {
455 address = (*env)->GetIntField(env, addressObj, ia_addressID);
456 }
457
458 if (NET_InetAddressToSockaddr(env, addressObj, port, (struct sockaddr *)&lcladdr, &lcladdrlen, JNI_FALSE) != 0) {
459 return;
460 }
461
462 if (ipv6_supported) {
463 struct ipv6bind v6bind;
464 v6bind.addr = &lcladdr;
465 v6bind.ipv4_fd = fd;
466 v6bind.ipv6_fd = fd1;
467 if (NET_BindV6(&v6bind) != -1) {
468 /* check if the fds have changed */
469 if (v6bind.ipv4_fd != fd) {
470 fd = v6bind.ipv4_fd;
471 if (fd == -1) {
472 /* socket is closed. */
473 (*env)->SetObjectField(env, this, pdsi_fdID, NULL);
474 } else {
475 /* socket was re-created */
476 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
477 }
478 }
479 if (v6bind.ipv6_fd != fd1) {
480 fd1 = v6bind.ipv6_fd;
481 if (fd1 == -1) {
482 /* socket is closed. */
483 (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL);
484 } else {
485 /* socket was re-created */
486 (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
487 }
488 }
489 } else {
490 NET_ThrowCurrent (env, "Cannot bind");
491 return;
492 }
493 } else {
494 if (bind(fd, (struct sockaddr *)&lcladdr, lcladdrlen) == -1) {
495 if (WSAGetLastError() == WSAEACCES) {
496 WSASetLastError(WSAEADDRINUSE);
497 }
498 NET_ThrowCurrent(env, "Cannot bind");
499 return;
500 }
1493 } else {
1494 fd = (int) socket (AF_INET, SOCK_DGRAM, 0);
1495 }
1496 if (fd == JVM_IO_ERR) {
1497 NET_ThrowCurrent(env, "Socket creation failed");
1498 return;
1499 }
1500 SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
1501 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
1502 NET_SetSockOpt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
1503
1504 if (ipv6_supported) {
1505 /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which
1506 * returns connection reset errors un connected UDP sockets (as well
1507 * as connected sockets. The solution is to only enable this feature
1508 * when the socket is connected
1509 */
1510 t = FALSE;
1511 WSAIoctl(fd,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
1512 t = TRUE;
1513 fd1 = socket (AF_INET6, SOCK_DGRAM, 0);
1514 if (fd1 == JVM_IO_ERR) {
1515 NET_ThrowCurrent(env, "Socket creation failed");
1516 return;
1517 }
1518 NET_SetSockOpt(fd1, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
1519 t = FALSE;
1520 WSAIoctl(fd1,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
1521 (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
1522 SetHandleInformation((HANDLE)(UINT_PTR)fd1, HANDLE_FLAG_INHERIT, FALSE);
1523 } else {
1524 /* drop the second fd */
1525 (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL);
1526 }
1527 }
1528
1529 /*
1530 * Class: java_net_TwoStacksPlainDatagramSocketImpl
1531 * Method: datagramSocketClose
1532 * Signature: ()V
1533 */
1556
1557 if (ipv6_supported && fd1Obj != NULL) {
1558 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
1559 if (fd1 == -1) {
1560 return;
1561 }
1562 (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, -1);
1563 NET_SocketClose(fd1);
1564 }
1565 }
1566
1567 /*
1568 * check the addresses attached to the NetworkInterface object
1569 * and return the first one (of the requested family Ipv4 or Ipv6)
1570 * in *iaddr
1571 */
1572
1573 static int getInetAddrFromIf (JNIEnv *env, int family, jobject nif, jobject *iaddr)
1574 {
1575 jobjectArray addrArray;
1576 static jfieldID ni_addrsID=0;
1577 static jfieldID ia_familyID=0;
1578 jsize len;
1579 jobject addr;
1580 int i;
1581
1582 if (ni_addrsID == NULL) {
1583 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1584 CHECK_NULL_RETURN (c, -1);
1585 ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1586 "[Ljava/net/InetAddress;");
1587 CHECK_NULL_RETURN (ni_addrsID, -1);
1588 c = (*env)->FindClass(env,"java/net/InetAddress");
1589 CHECK_NULL_RETURN (c, -1);
1590 ia_familyID = (*env)->GetFieldID(env, c, "family", "I");
1591 CHECK_NULL_RETURN (ia_familyID, -1);
1592 }
1593
1594 addrArray = (*env)->GetObjectField(env, nif, ni_addrsID);
1595 len = (*env)->GetArrayLength(env, addrArray);
1596
1597 /*
1598 * Check that there is at least one address bound to this
1599 * interface.
1600 */
1601 if (len < 1) {
1602 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1603 "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface");
1604 return -1;
1605 }
1606 for (i=0; i<len; i++) {
1607 int fam;
1608 addr = (*env)->GetObjectArrayElement(env, addrArray, i);
1609 fam = (*env)->GetIntField(env, addr, ia_familyID);
1610 if (fam == family) {
1611 *iaddr = addr;
1612 return 0;
1613 }
1614 }
1615 return -1;
1616 }
1617
1618 static int getInet4AddrFromIf (JNIEnv *env, jobject nif, struct in_addr *iaddr)
1619 {
1620 jobject addr;
1621 static jfieldID ia_addressID;
1622
1623 int ret = getInetAddrFromIf (env, IPv4, nif, &addr);
1624 if (ret == -1) {
1625 return -1;
1626 }
1627
1628 if (ia_addressID == 0) {
1629 jclass c = (*env)->FindClass(env,"java/net/InetAddress");
1630 CHECK_NULL_RETURN (c, -1);
1631 ia_addressID = (*env)->GetFieldID(env, c, "address", "I");
1632 CHECK_NULL_RETURN (ia_addressID, -1);
1633 }
1634 iaddr->s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID));
1635 return 0;
1636 }
1637
1638 /* Get the multicasting index from the interface */
1639
1640 static int getIndexFromIf (JNIEnv *env, jobject nif) {
1641 static jfieldID ni_indexID;
1642
1643 if (ni_indexID == NULL) {
1644 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1645 CHECK_NULL_RETURN(c, -1);
1646 ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1647 CHECK_NULL_RETURN(ni_indexID, -1);
1648 }
1649
1650 return (*env)->GetIntField(env, nif, ni_indexID);
1651 }
1652
1653 /*
1654 * Sets the multicast interface.
1655 *
1656 * SocketOptions.IP_MULTICAST_IF (argument is an InetAddress) :-
1657 * IPv4: set outgoing multicast interface using
1658 * IPPROTO_IP/IP_MULTICAST_IF
1659 *
1660 * IPv6: Get the interface to which the
1661 * InetAddress is bound
1662 * and do same as SockOptions.IF_MULTICAST_IF2
1663 *
1664 * SockOptions.IF_MULTICAST_IF2 (argument is a NetworkInterface ) :-
1665 * For each stack:
1666 * IPv4: Obtain IP address bound to network interface
1667 * (NetworkInterface.addres[0])
1668 * set outgoing multicast interface using
1669 * IPPROTO_IP/IP_MULTICAST_IF
1670 *
1671 * IPv6: Obtain NetworkInterface.index
1672 * Set outgoing multicast interface using
1673 * IPPROTO_IPV6/IPV6_MULTICAST_IF
1674 *
1675 */
1676 static void setMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1,
1677 jint opt, jobject value)
1678 {
1679 int ipv6_supported = ipv6_available();
1680
1681 if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1682 /*
1683 * value is an InetAddress.
1684 * On IPv4 system use IP_MULTICAST_IF socket option
1685 * On IPv6 system get the NetworkInterface that this IP
1686 * address is bound to and use the IPV6_MULTICAST_IF
1687 * option instead of IP_MULTICAST_IF
1688 */
1689 if (ipv6_supported) {
1690 static jclass ni_class;
1691 if (ni_class == NULL) {
1692 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1693 CHECK_NULL(c);
1694 ni_class = (*env)->NewGlobalRef(env, c);
1695 CHECK_NULL(ni_class);
1696 }
1697
1698 value = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, value);
1699 if (value == NULL) {
1700 if (!(*env)->ExceptionOccurred(env)) {
1701 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1702 "bad argument for IP_MULTICAST_IF"
1703 ": address not bound to any interface");
1704 }
1705 return;
1706 }
1707 opt = java_net_SocketOptions_IP_MULTICAST_IF2;
1708 } else {
1709 static jfieldID ia_addressID;
1710 struct in_addr in;
1711
1712 if (ia_addressID == NULL) {
1713 jclass c = (*env)->FindClass(env,"java/net/InetAddress");
1714 CHECK_NULL(c);
1715 ia_addressID = (*env)->GetFieldID(env, c, "address", "I");
1716 CHECK_NULL(ia_addressID);
1717 }
1718
1719 in.s_addr = htonl((*env)->GetIntField(env, value, ia_addressID));
1720
1721 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1722 (const char*)&in, sizeof(in)) < 0) {
1723 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1724 "Error setting socket option");
1725 }
1726 return;
1727 }
1728 }
1729
1730 if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1731 /*
1732 * value is a NetworkInterface.
1733 * On IPv6 system get the index of the interface and use the
1734 * IPV6_MULTICAST_IF socket option
1735 * On IPv4 system extract addr[0] and use the IP_MULTICAST_IF
1736 * option. For IPv6 both must be done.
1737 */
1738 if (ipv6_supported) {
1739 static jfieldID ni_indexID;
1740 struct in_addr in;
1741 int index;
1742
1743 if (ni_indexID == NULL) {
1744 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1745 CHECK_NULL(c);
1746 ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1747 CHECK_NULL(ni_indexID);
1748 }
1749 index = (*env)->GetIntField(env, value, ni_indexID);
1750
1751 if (setsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1752 (const char*)&index, sizeof(index)) < 0) {
1753 if (errno == EINVAL && index > 0) {
1754 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1755 "IPV6_MULTICAST_IF failed (interface has IPv4 "
1756 "address only?)");
1757 } else {
1758 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1759 "Error setting socket option");
1760 }
1761 return;
1762 }
1763
1764 /* If there are any IPv4 addresses on this interface then
1765 * repeat the operation on the IPv4 fd */
1766
1767 if (getInet4AddrFromIf (env, value, &in) < 0) {
1768 return;
1834 * level(s) and option name(s).
1835 */
1836 if (fd1 != -1) {
1837 if (NET_MapSocketOptionV6(opt, &levelv6, &optnamev6)) {
1838 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1839 return;
1840 }
1841 }
1842 if (fd != -1) {
1843 if (NET_MapSocketOption(opt, &levelv4, &optnamev4)) {
1844 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1845 return;
1846 }
1847 }
1848
1849 switch (opt) {
1850 case java_net_SocketOptions_SO_SNDBUF :
1851 case java_net_SocketOptions_SO_RCVBUF :
1852 case java_net_SocketOptions_IP_TOS :
1853 {
1854 jclass cls;
1855 jfieldID fid;
1856
1857 cls = (*env)->FindClass(env, "java/lang/Integer");
1858 CHECK_NULL(cls);
1859 fid = (*env)->GetFieldID(env, cls, "value", "I");
1860 CHECK_NULL(fid);
1861
1862 optval.i = (*env)->GetIntField(env, value, fid);
1863 optlen = sizeof(optval.i);
1864 }
1865 break;
1866
1867 case java_net_SocketOptions_SO_REUSEADDR:
1868 case java_net_SocketOptions_SO_BROADCAST:
1869 case java_net_SocketOptions_IP_MULTICAST_LOOP:
1870 {
1871 jclass cls;
1872 jfieldID fid;
1873 jboolean on;
1874
1875 cls = (*env)->FindClass(env, "java/lang/Boolean");
1876 CHECK_NULL(cls);
1877 fid = (*env)->GetFieldID(env, cls, "value", "Z");
1878 CHECK_NULL(fid);
1879
1880 on = (*env)->GetBooleanField(env, value, fid);
1881 optval.i = (on ? 1 : 0);
1882 /*
1883 * setLoopbackMode (true) disables IP_MULTICAST_LOOP rather
1884 * than enabling it.
1885 */
1886 if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) {
1887 optval.i = !optval.i;
1888 }
1889 optlen = sizeof(optval.i);
1890 }
1891 break;
1892
1893 default :
1894 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1895 "Socket option not supported by PlainDatagramSocketImp");
1896 break;
1897
1898 }
1899
1900 if (fd1 != -1) {
1926 * If index > 0 query NetworkInterface by index
1927 * and returns addrs[0]
1928 *
1929 * SocketOptions.IP_MULTICAST_IF2
1930 * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
1931 * Query NetworkInterface by IP address and
1932 * return the NetworkInterface that the address
1933 * is bound too.
1934 * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
1935 * (except Linux .2 kernel)
1936 * Query NetworkInterface by index and
1937 * return NetworkInterface.
1938 */
1939 jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint opt) {
1940 jboolean isIPV4 = !ipv6_available() || fd1 == -1;
1941
1942 /*
1943 * IPv4 implementation
1944 */
1945 if (isIPV4) {
1946 static jclass inet4_class;
1947 static jmethodID inet4_ctrID;
1948 static jfieldID inet4_addrID;
1949
1950 static jclass ni_class;
1951 static jmethodID ni_ctrID;
1952 static jfieldID ni_indexID;
1953 static jfieldID ni_addrsID;
1954
1955 jobjectArray addrArray;
1956 jobject addr;
1957 jobject ni;
1958
1959 struct in_addr in;
1960 struct in_addr *inP = ∈
1961 int len = sizeof(struct in_addr);
1962
1963 if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1964 (char *)inP, &len) < 0) {
1965 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1966 "Error getting socket option");
1967 return NULL;
1968 }
1969
1970 /*
1971 * Construct and populate an Inet4Address
1972 */
1973 if (inet4_class == NULL) {
1974 jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
1975 CHECK_NULL_RETURN(c, NULL);
1976 inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1977 CHECK_NULL_RETURN(inet4_ctrID, NULL);
1978 inet4_addrID = (*env)->GetFieldID(env, c, "address", "I");
1979 CHECK_NULL_RETURN(inet4_addrID, NULL);
1980 inet4_class = (*env)->NewGlobalRef(env, c);
1981 CHECK_NULL_RETURN(inet4_class, NULL);
1982 }
1983 addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0);
1984 CHECK_NULL_RETURN(addr, NULL);
1985
1986 (*env)->SetIntField(env, addr, inet4_addrID, ntohl(in.s_addr));
1987
1988 /*
1989 * For IP_MULTICAST_IF return InetAddress
1990 */
1991 if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1992 return addr;
1993 }
1994
1995 /*
1996 * For IP_MULTICAST_IF2 we get the NetworkInterface for
1997 * this address and return it
1998 */
1999 if (ni_class == NULL) {
2000 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
2001 CHECK_NULL_RETURN(c, NULL);
2002 ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
2003 CHECK_NULL_RETURN(ni_ctrID, NULL);
2004 ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
2005 CHECK_NULL_RETURN(ni_indexID, NULL);
2006 ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
2007 "[Ljava/net/InetAddress;");
2008 CHECK_NULL_RETURN(ni_addrsID, NULL);
2009 ni_class = (*env)->NewGlobalRef(env, c);
2010 CHECK_NULL_RETURN(ni_class, NULL);
2011 }
2012 ni = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, addr);
2013 if (ni) {
2014 return ni;
2015 }
2016
2017 /*
2018 * The address doesn't appear to be bound at any known
2019 * NetworkInterface. Therefore we construct a NetworkInterface
2020 * with this address.
2021 */
2022 ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
2023 CHECK_NULL_RETURN(ni, NULL);
2024
2025 (*env)->SetIntField(env, ni, ni_indexID, -1);
2026 addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL);
2027 CHECK_NULL_RETURN(addrArray, NULL);
2028 (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
2029 (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
2030 return ni;
2031 }
2032
2033
2034 /*
2035 * IPv6 implementation
2036 */
2037 if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
2038 (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
2039
2040 static jclass ni_class;
2041 static jmethodID ni_ctrID;
2042 static jfieldID ni_indexID;
2043 static jfieldID ni_addrsID;
2044 static jclass ia_class;
2045 static jmethodID ia_anyLocalAddressID;
2046
2047 int index;
2048 int len = sizeof(index);
2049
2050 jobjectArray addrArray;
2051 jobject addr;
2052 jobject ni;
2053
2054 {
2055 if (getsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
2056 (char*)&index, &len) < 0) {
2057 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
2058 "Error getting socket option");
2059 return NULL;
2060 }
2061 }
2062
2063 if (ni_class == NULL) {
2064 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
2065 CHECK_NULL_RETURN(c, NULL);
2066 ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
2067 CHECK_NULL_RETURN(ni_ctrID, NULL);
2068 ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
2069 CHECK_NULL_RETURN(ni_indexID, NULL);
2070 ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
2071 "[Ljava/net/InetAddress;");
2072 CHECK_NULL_RETURN(ni_addrsID, NULL);
2073
2074 ia_class = (*env)->FindClass(env, "java/net/InetAddress");
2075 CHECK_NULL_RETURN(ia_class, NULL);
2076 ia_class = (*env)->NewGlobalRef(env, ia_class);
2077 CHECK_NULL_RETURN(ia_class, NULL);
2078 ia_anyLocalAddressID = (*env)->GetStaticMethodID(env,
2079 ia_class,
2080 "anyLocalAddress",
2081 "()Ljava/net/InetAddress;");
2082 CHECK_NULL_RETURN(ia_anyLocalAddressID, NULL);
2083 ni_class = (*env)->NewGlobalRef(env, c);
2084 CHECK_NULL_RETURN(ni_class, NULL);
2085 }
2086
2087 /*
2088 * If multicast to a specific interface then return the
2089 * interface (for IF2) or the any address on that interface
2090 * (for IF).
2091 */
2092 if (index > 0) {
2093 ni = Java_java_net_NetworkInterface_getByIndex0(env, ni_class,
2094 index);
2095 if (ni == NULL) {
2096 char errmsg[255];
2097 sprintf(errmsg,
2098 "IPV6_MULTICAST_IF returned index to unrecognized interface: %d",
2099 index);
2100 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg);
2101 return NULL;
2102 }
2103
2104 /*
|
48 #include "net_util.h"
49
50 #define IN_CLASSD(i) (((long)(i) & 0xf0000000) == 0xe0000000)
51 #define IN_MULTICAST(i) IN_CLASSD(i)
52
53 /************************************************************************
54 * TwoStacksPlainDatagramSocketImpl
55 */
56
57 static jfieldID IO_fd_fdID;
58 static jfieldID pdsi_trafficClassID;
59 jfieldID pdsi_fdID;
60 jfieldID pdsi_fd1ID;
61 jfieldID pdsi_fduseID;
62 jfieldID pdsi_lastfdID;
63 jfieldID pdsi_timeoutID;
64
65 jfieldID pdsi_localPortID;
66 jfieldID pdsi_connected;
67
68 static CRITICAL_SECTION sizeCheckLock;
69
70 /* Windows OS version is XP or better */
71 static int xp_or_later = 0;
72 /* Windows OS version is Windows 2000 or better */
73 static int w2k_or_later = 0;
74
75 /*
76 * Notes about UDP/IPV6 on Windows (XP and 2003 server):
77 *
78 * fd always points to the IPv4 fd, and fd1 points to the IPv6 fd.
79 * Both fds are used when we bind to a wild-card address. When a specific
80 * address is used, only one of them is used.
81 */
82
83 static jclass i_class;
84 static jmethodID i_ctrID;
85 static jfieldID i_valueID;
86
87 int initIntegerIDs(JNIEnv* env) {
88 if (i_class == NULL) {
89 jclass c = (*env)->FindClass(env, "java/lang/Integer");
90 CHECK_NULL_RETURN(c, NULL);
91 i_ctrID = (*env)->GetMethodID(env, c, "<init>", "(I)V");
92 CHECK_NULL_RETURN(i_ctrID, NULL);
93 i_valueID = (*env)->GetFieldID(env, c, "value", "I");
94 CHECK_NULL_RETURN(i_valueID, NULL);
95 i_class = (*env)->NewGlobalRef(env, c);
96 CHECK_NULL_RETURN(i_class, NULL);
97 }
98 return 1;
99 }
100
101 /* Returns a java.lang.Integer based on 'i' */
102 static jobject createInteger(JNIEnv *env, int i) {
103 CHECK_NULL_RETURN(initIntegerIDs(env), NULL);
104 return ( (*env)->NewObject(env, i_class, i_ctrID, i) );
105 }
106
107 /* Returns a jint based on the given java.lang.Integer */
108 static jint retrieveInteger(JNIEnv *env, jobject i) {
109 CHECK_NULL_RETURN(initIntegerIDs(env), NULL);
110 return (*env)->GetIntField(env, i, i_valueID);
111 }
112
113 static jclass b_class;
114 static jmethodID b_ctrID;
115 static jfieldID b_valueID;
116
117 int initBooleanIDs(JNIEnv* env) {
118 if (b_class == NULL) {
119 jclass c = (*env)->FindClass(env, "java/lang/Boolean");
120 CHECK_NULL_RETURN(c, NULL);
121 b_ctrID = (*env)->GetMethodID(env, c, "<init>", "(Z)V");
122 CHECK_NULL_RETURN(b_ctrID, NULL);
123 b_valueID = (*env)->GetFieldID(env, c, "value", "Z");
124 CHECK_NULL_RETURN(b_valueID, NULL);
125 b_class = (*env)->NewGlobalRef(env, c);
126 CHECK_NULL_RETURN(b_class, NULL);
127 }
128 return 1;
129 }
130
131 /* Returns a java.lang.Boolean based on 'b' */
132 static jobject createBoolean(JNIEnv *env, int b) {
133 CHECK_NULL_RETURN(initBooleanIDs(env), NULL);
134 return( (*env)->NewObject(env, b_class, b_ctrID, (jboolean)(b!=0)) );
135 }
136
137 /* Returns a jboolean based on the given java.lang.Boolean */
138 static jboolean retrieveBoolean(JNIEnv *env, jobject b) {
139 CHECK_NULL_RETURN(initBooleanIDs(env), NULL);
140 return (*env)->GetBooleanField(env, b, b_valueID);
141 }
142
143 static int getFD(JNIEnv *env, jobject this) {
144 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
145
146 if (fdObj == NULL) {
147 return -1;
148 }
149 return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
150 }
151
152 static int getFD1(JNIEnv *env, jobject this) {
153 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
154
155 if (fdObj == NULL) {
156 return -1;
157 }
158 return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
159 }
160
161 /*
407 pdsi_fd1ID = (*env)->GetFieldID(env, cls, "fd1", "Ljava/io/FileDescriptor;");
408 CHECK_NULL(pdsi_fd1ID);
409 pdsi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
410 CHECK_NULL(pdsi_timeoutID);
411 pdsi_fduseID = (*env)->GetFieldID(env, cls, "fduse", "I");
412 CHECK_NULL(pdsi_fduseID);
413 pdsi_lastfdID = (*env)->GetFieldID(env, cls, "lastfd", "I");
414 CHECK_NULL(pdsi_lastfdID);
415 pdsi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
416 CHECK_NULL(pdsi_trafficClassID);
417 pdsi_localPortID = (*env)->GetFieldID(env, cls, "localPort", "I");
418 CHECK_NULL(pdsi_localPortID);
419 pdsi_connected = (*env)->GetFieldID(env, cls, "connected", "Z");
420 CHECK_NULL(pdsi_connected);
421
422 cls = (*env)->FindClass(env, "java/io/FileDescriptor");
423 CHECK_NULL(cls);
424 IO_fd_fdID = NET_GetFileDescriptorID(env);
425 CHECK_NULL(IO_fd_fdID);
426
427 // Load static data (jclass, methodIDs, fieldID ) from InetAddress,
428 // Inet4Address, Inet6Address and NetorkInterface.
429 init(env);
430 (*env)->FindClass(env, "java/net/NetworkInterface");
431
432 InitializeCriticalSection(&sizeCheckLock);
433 }
434
435 JNIEXPORT void JNICALL
436 Java_java_net_TwoStacksPlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this,
437 jint port, jobject addressObj) {
438 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
439 jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
440
441 int fd, fd1, family;
442 int ipv6_supported = ipv6_available();
443
444 SOCKETADDRESS lcladdr;
445 int lcladdrlen;
446 int address;
447
448 family = (*env)->GetIntField(env, addressObj, ia_familyID);
449 if (family == IPv6 && !ipv6_supported) {
450 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
451 "Protocol family not supported");
463 }
464 if (IS_NULL(addressObj)) {
465 JNU_ThrowNullPointerException(env, "argument address");
466 return;
467 } else {
468 address = (*env)->GetIntField(env, addressObj, ia_addressID);
469 }
470
471 if (NET_InetAddressToSockaddr(env, addressObj, port, (struct sockaddr *)&lcladdr, &lcladdrlen, JNI_FALSE) != 0) {
472 return;
473 }
474
475 if (ipv6_supported) {
476 struct ipv6bind v6bind;
477 v6bind.addr = &lcladdr;
478 v6bind.ipv4_fd = fd;
479 v6bind.ipv6_fd = fd1;
480 if (NET_BindV6(&v6bind) != -1) {
481 /* check if the fds have changed */
482 if (v6bind.ipv4_fd != fd) {
483 fd = (int)v6bind.ipv4_fd;
484 if (fd == -1) {
485 /* socket is closed. */
486 (*env)->SetObjectField(env, this, pdsi_fdID, NULL);
487 } else {
488 /* socket was re-created */
489 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
490 }
491 }
492 if (v6bind.ipv6_fd != fd1) {
493 fd1 = (int)v6bind.ipv6_fd;
494 if (fd1 == -1) {
495 /* socket is closed. */
496 (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL);
497 } else {
498 /* socket was re-created */
499 (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
500 }
501 }
502 } else {
503 NET_ThrowCurrent (env, "Cannot bind");
504 return;
505 }
506 } else {
507 if (bind(fd, (struct sockaddr *)&lcladdr, lcladdrlen) == -1) {
508 if (WSAGetLastError() == WSAEACCES) {
509 WSASetLastError(WSAEADDRINUSE);
510 }
511 NET_ThrowCurrent(env, "Cannot bind");
512 return;
513 }
1506 } else {
1507 fd = (int) socket (AF_INET, SOCK_DGRAM, 0);
1508 }
1509 if (fd == JVM_IO_ERR) {
1510 NET_ThrowCurrent(env, "Socket creation failed");
1511 return;
1512 }
1513 SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
1514 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
1515 NET_SetSockOpt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
1516
1517 if (ipv6_supported) {
1518 /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which
1519 * returns connection reset errors un connected UDP sockets (as well
1520 * as connected sockets. The solution is to only enable this feature
1521 * when the socket is connected
1522 */
1523 t = FALSE;
1524 WSAIoctl(fd,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
1525 t = TRUE;
1526 fd1 = (int)socket (AF_INET6, SOCK_DGRAM, 0);
1527 if (fd1 == JVM_IO_ERR) {
1528 NET_ThrowCurrent(env, "Socket creation failed");
1529 return;
1530 }
1531 NET_SetSockOpt(fd1, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
1532 t = FALSE;
1533 WSAIoctl(fd1,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
1534 (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
1535 SetHandleInformation((HANDLE)(UINT_PTR)fd1, HANDLE_FLAG_INHERIT, FALSE);
1536 } else {
1537 /* drop the second fd */
1538 (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL);
1539 }
1540 }
1541
1542 /*
1543 * Class: java_net_TwoStacksPlainDatagramSocketImpl
1544 * Method: datagramSocketClose
1545 * Signature: ()V
1546 */
1569
1570 if (ipv6_supported && fd1Obj != NULL) {
1571 fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
1572 if (fd1 == -1) {
1573 return;
1574 }
1575 (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, -1);
1576 NET_SocketClose(fd1);
1577 }
1578 }
1579
1580 /*
1581 * check the addresses attached to the NetworkInterface object
1582 * and return the first one (of the requested family Ipv4 or Ipv6)
1583 * in *iaddr
1584 */
1585
1586 static int getInetAddrFromIf (JNIEnv *env, int family, jobject nif, jobject *iaddr)
1587 {
1588 jobjectArray addrArray;
1589 jsize len;
1590 jobject addr;
1591 int i;
1592
1593 addrArray = (*env)->GetObjectField(env, nif, ni_addrsID);
1594 len = (*env)->GetArrayLength(env, addrArray);
1595
1596 /*
1597 * Check that there is at least one address bound to this
1598 * interface.
1599 */
1600 if (len < 1) {
1601 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1602 "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface");
1603 return -1;
1604 }
1605 for (i=0; i<len; i++) {
1606 int fam;
1607 addr = (*env)->GetObjectArrayElement(env, addrArray, i);
1608 fam = (*env)->GetIntField(env, addr, ia_familyID);
1609 if (fam == family) {
1610 *iaddr = addr;
1611 return 0;
1612 }
1613 }
1614 return -1;
1615 }
1616
1617 static int getInet4AddrFromIf (JNIEnv *env, jobject nif, struct in_addr *iaddr)
1618 {
1619 jobject addr;
1620
1621 int ret = getInetAddrFromIf (env, IPv4, nif, &addr);
1622 if (ret == -1) {
1623 return -1;
1624 }
1625
1626 iaddr->s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID));
1627 return 0;
1628 }
1629
1630 /* Get the multicasting index from the interface */
1631
1632 static int getIndexFromIf (JNIEnv *env, jobject nif) {
1633 return (*env)->GetIntField(env, nif, ni_indexID);
1634 }
1635
1636 /*
1637 * Sets the multicast interface.
1638 *
1639 * SocketOptions.IP_MULTICAST_IF (argument is an InetAddress) :-
1640 * IPv4: set outgoing multicast interface using
1641 * IPPROTO_IP/IP_MULTICAST_IF
1642 *
1643 * IPv6: Get the interface to which the
1644 * InetAddress is bound
1645 * and do same as SockOptions.IF_MULTICAST_IF2
1646 *
1647 * SockOptions.IF_MULTICAST_IF2 (argument is a NetworkInterface ) :-
1648 * For each stack:
1649 * IPv4: Obtain IP address bound to network interface
1650 * (NetworkInterface.addres[0])
1651 * set outgoing multicast interface using
1652 * IPPROTO_IP/IP_MULTICAST_IF
1653 *
1654 * IPv6: Obtain NetworkInterface.index
1655 * Set outgoing multicast interface using
1656 * IPPROTO_IPV6/IPV6_MULTICAST_IF
1657 *
1658 */
1659 static void setMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1,
1660 jint opt, jobject value)
1661 {
1662 int ipv6_supported = ipv6_available();
1663
1664 if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1665 /*
1666 * value is an InetAddress.
1667 * On IPv4 system use IP_MULTICAST_IF socket option
1668 * On IPv6 system get the NetworkInterface that this IP
1669 * address is bound to and use the IPV6_MULTICAST_IF
1670 * option instead of IP_MULTICAST_IF
1671 */
1672 if (ipv6_supported) {
1673 value = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, value);
1674 if (value == NULL) {
1675 if (!(*env)->ExceptionOccurred(env)) {
1676 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1677 "bad argument for IP_MULTICAST_IF"
1678 ": address not bound to any interface");
1679 }
1680 return;
1681 }
1682 opt = java_net_SocketOptions_IP_MULTICAST_IF2;
1683 } else {
1684 struct in_addr in;
1685
1686 in.s_addr = htonl((*env)->GetIntField(env, value, ia_addressID));
1687
1688 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1689 (const char*)&in, sizeof(in)) < 0) {
1690 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1691 "Error setting socket option");
1692 }
1693 return;
1694 }
1695 }
1696
1697 if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1698 /*
1699 * value is a NetworkInterface.
1700 * On IPv6 system get the index of the interface and use the
1701 * IPV6_MULTICAST_IF socket option
1702 * On IPv4 system extract addr[0] and use the IP_MULTICAST_IF
1703 * option. For IPv6 both must be done.
1704 */
1705 if (ipv6_supported) {
1706 struct in_addr in;
1707 int index;
1708
1709 index = (*env)->GetIntField(env, value, ni_indexID);
1710
1711 if (setsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1712 (const char*)&index, sizeof(index)) < 0) {
1713 if (errno == EINVAL && index > 0) {
1714 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1715 "IPV6_MULTICAST_IF failed (interface has IPv4 "
1716 "address only?)");
1717 } else {
1718 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1719 "Error setting socket option");
1720 }
1721 return;
1722 }
1723
1724 /* If there are any IPv4 addresses on this interface then
1725 * repeat the operation on the IPv4 fd */
1726
1727 if (getInet4AddrFromIf (env, value, &in) < 0) {
1728 return;
1794 * level(s) and option name(s).
1795 */
1796 if (fd1 != -1) {
1797 if (NET_MapSocketOptionV6(opt, &levelv6, &optnamev6)) {
1798 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1799 return;
1800 }
1801 }
1802 if (fd != -1) {
1803 if (NET_MapSocketOption(opt, &levelv4, &optnamev4)) {
1804 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1805 return;
1806 }
1807 }
1808
1809 switch (opt) {
1810 case java_net_SocketOptions_SO_SNDBUF :
1811 case java_net_SocketOptions_SO_RCVBUF :
1812 case java_net_SocketOptions_IP_TOS :
1813 {
1814 optval.i = retrieveInteger(env, value);
1815 optlen = sizeof(optval.i);
1816 }
1817 break;
1818
1819 case java_net_SocketOptions_SO_REUSEADDR:
1820 case java_net_SocketOptions_SO_BROADCAST:
1821 case java_net_SocketOptions_IP_MULTICAST_LOOP:
1822 {
1823 jboolean on = retrieveBoolean(env, value);
1824 optval.i = (on ? 1 : 0);
1825 /*
1826 * setLoopbackMode (true) disables IP_MULTICAST_LOOP rather
1827 * than enabling it.
1828 */
1829 if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) {
1830 optval.i = !optval.i;
1831 }
1832 optlen = sizeof(optval.i);
1833 }
1834 break;
1835
1836 default :
1837 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1838 "Socket option not supported by PlainDatagramSocketImp");
1839 break;
1840
1841 }
1842
1843 if (fd1 != -1) {
1869 * If index > 0 query NetworkInterface by index
1870 * and returns addrs[0]
1871 *
1872 * SocketOptions.IP_MULTICAST_IF2
1873 * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
1874 * Query NetworkInterface by IP address and
1875 * return the NetworkInterface that the address
1876 * is bound too.
1877 * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
1878 * (except Linux .2 kernel)
1879 * Query NetworkInterface by index and
1880 * return NetworkInterface.
1881 */
1882 jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint opt) {
1883 jboolean isIPV4 = !ipv6_available() || fd1 == -1;
1884
1885 /*
1886 * IPv4 implementation
1887 */
1888 if (isIPV4) {
1889 jobjectArray addrArray;
1890 jobject addr;
1891 jobject ni;
1892
1893 struct in_addr in;
1894 struct in_addr *inP = ∈
1895 int len = sizeof(struct in_addr);
1896
1897 if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1898 (char *)inP, &len) < 0) {
1899 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1900 "Error getting socket option");
1901 return NULL;
1902 }
1903
1904 /*
1905 * Construct and populate an Inet4Address
1906 */
1907 addr = (*env)->NewObject(env, ia4_class, ia4_ctrID, 0);
1908 CHECK_NULL_RETURN(addr, NULL);
1909
1910 (*env)->SetIntField(env, addr, ia_addressID, ntohl(in.s_addr));
1911
1912 /*
1913 * For IP_MULTICAST_IF return InetAddress
1914 */
1915 if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1916 return addr;
1917 }
1918
1919 /*
1920 * For IP_MULTICAST_IF2 we get the NetworkInterface for
1921 * this address and return it
1922 */
1923 ni = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, addr);
1924 if (ni) {
1925 return ni;
1926 }
1927
1928 /*
1929 * The address doesn't appear to be bound at any known
1930 * NetworkInterface. Therefore we construct a NetworkInterface
1931 * with this address.
1932 */
1933 ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
1934 CHECK_NULL_RETURN(ni, NULL);
1935
1936 (*env)->SetIntField(env, ni, ni_indexID, -1);
1937 addrArray = (*env)->NewObjectArray(env, 1, ia4_class, NULL);
1938 CHECK_NULL_RETURN(addrArray, NULL);
1939 (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
1940 (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
1941 return ni;
1942 }
1943
1944
1945 /*
1946 * IPv6 implementation
1947 */
1948 if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
1949 (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1950
1951 static jmethodID ia_anyLocalAddressID;
1952
1953 int index;
1954 int len = sizeof(index);
1955
1956 jobjectArray addrArray;
1957 jobject addr;
1958 jobject ni;
1959
1960 {
1961 if (getsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1962 (char*)&index, &len) < 0) {
1963 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1964 "Error getting socket option");
1965 return NULL;
1966 }
1967 }
1968
1969 if (ia_anyLocalAddressID == NULL) {
1970 ia_anyLocalAddressID = (*env)->GetStaticMethodID(env,
1971 ia_class,
1972 "anyLocalAddress",
1973 "()Ljava/net/InetAddress;");
1974 CHECK_NULL_RETURN(ia_anyLocalAddressID, NULL);
1975 }
1976
1977 /*
1978 * If multicast to a specific interface then return the
1979 * interface (for IF2) or the any address on that interface
1980 * (for IF).
1981 */
1982 if (index > 0) {
1983 ni = Java_java_net_NetworkInterface_getByIndex0(env, ni_class,
1984 index);
1985 if (ni == NULL) {
1986 char errmsg[255];
1987 sprintf(errmsg,
1988 "IPV6_MULTICAST_IF returned index to unrecognized interface: %d",
1989 index);
1990 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg);
1991 return NULL;
1992 }
1993
1994 /*
|