/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#ifndef IPTOS_TOS_MASK
#endif
#ifndef IPTOS_PREC_MASK
#endif
#include "java_net_TwoStacksPlainDatagramSocketImpl.h"
#include "java_net_SocketOptions.h"
#include "java_net_NetworkInterface.h"
#include "jvm.h"
#include "jni_util.h"
#include "net_util.h"
/************************************************************************
* TwoStacksPlainDatagramSocketImpl
*/
/* Windows OS version is XP or better */
static int xp_or_later = 0;
/* Windows OS version is Windows 2000 or better */
static int w2k_or_later = 0;
/*
*
* fd always points to the IPv4 fd, and fd1 points to the IPv6 fd.
* Both fds are used when we bind to a wild-card address. When a specific
* address is used, only one of them is used.
*/
/*
* Returns a java.lang.Integer based on 'i'
*/
CHECK_NULL_RETURN(c, NULL);
}
}
/*
* Returns a java.lang.Boolean based on 'b'
*/
CHECK_NULL_RETURN(c, NULL);
}
}
return -1;
}
}
return -1;
}
}
/*
* This function returns JNI_TRUE if the datagram size exceeds the underlying
* provider's ability to send to the target address. The following OS
* oddies have been observed :-
*
* 1. On Windows 95/98 if we try to send a datagram > 12k to an application
* on the same machine then the send will fail silently.
*
* 2. On Windows ME if we try to send a datagram > supported by underlying
* provider then send will not return an error.
*
* 3. On Windows NT/2000 if we exceeds the maximum size then send will fail
* with WSAEADDRNOTAVAIL.
*
* 4. On Windows 95/98 if we exceed the maximum size when sending to
* another machine then WSAEINVAL is returned.
*
*/
{
static int maxmsg;
unsigned long addr;
} netaddr;
/*
* First time we are called we must determine which OS this is and also
* get the maximum size supported by the underlying provider.
*
* In addition on 95/98 we must enumerate our IP addresses.
*/
if (!initDone) {
if (initDone) {
/* another thread got there first */
} else {
int len;
/*
* Step 1: Determine which OS this is.
*/
GetVersionEx(&ver);
}
/*
* Step 2: Determine the maximum datagram supported by the
* underlying provider. On Windows 95 if winsock hasn't been
* upgraded (ie: unsupported configuration) then we assume
* the default 64k limit.
*/
}
/*
* Step 3: On Windows 95/98 then enumerate the IP addresses on
* this machine. This is necesary because we need to check if the
* datagram is being sent to an application on the same machine.
*/
if (is95or98) {
return JNI_TRUE;
}
}
return JNI_TRUE;
}
addrp++;
}
}
}
/*
* Step 4: initialization is done so set flag and unlock cs
*/
}
}
/*
* Now examine the size of the datagram :-
*
* (a) If exceeds size of service provider return 'false' to indicate that
* we exceed the limit.
* (b) If not 95/98 then return 'true' to indicate that the size is okay.
* (c) On 95/98 if the size is <12k we are okay.
* (d) On 95/98 if size > 12k then check if the destination is the current
* machine.
*/
return JNI_TRUE;
}
if (!is95or98) { /* step (b) */
return JNI_FALSE;
}
return JNI_FALSE;
}
/* step (d) */
return JNI_TRUE;
}
return JNI_TRUE;
}
}
return JNI_FALSE;
}
/*
* Return JNI_TRUE if this Windows edition supports ICMP Port Unreachable
*/
if (!initDone) {
GetVersionEx(&ver);
} else {
}
}
return portUnreachableSupported;
}
/*
* This function "purges" all outstanding ICMP port unreachable packets
* outstanding on a socket and returns JNI_TRUE if any ICMP messages
* have been purged. The rational for purging is to emulate normal BSD
* behaviour whereby receiving a "connection reset" status resets the
* socket.
*/
{
struct timeval t = { 0, 0 };
/*
* A no-op if this OS doesn't support it.
*/
if (!supportPortUnreachable()) {
return JNI_FALSE;
}
/*
* Peek at the queue to see if there is an ICMP port unreachable. If there
* is then receive it.
*/
while(1) {
break;
}
break;
}
if (WSAGetLastError() != WSAECONNRESET) {
/* some other error - we don't care here */
break;
}
}
return got_icmp;
}
/*
* Class: java_net_TwoStacksPlainDatagramSocketImpl
* Method: init
* Signature: ()V
*/
int version;
GetVersionEx(&ver);
/* get fieldIDs */
}
int lcladdrlen;
int address;
"Protocol family not supported");
return;
}
return;
} else {
if (ipv6_supported) {
}
}
if (IS_NULL(addressObj)) {
return;
} else {
}
if (NET_InetAddressToSockaddr(env, addressObj, port, (struct sockaddr *)&lcladdr, &lcladdrlen, JNI_FALSE) != 0) {
return;
}
if (ipv6_supported) {
/* check if the fds have changed */
if (fd == -1) {
/* socket is closed. */
} else {
/* socket was re-created */
}
}
if (fd1 == -1) {
/* socket is closed. */
} else {
/* socket was re-created */
}
}
} else {
return;
}
} else {
if (WSAGetLastError() == WSAEACCES) {
}
return;
}
}
if (port == 0) {
if (fd == -1) {
/* must be an IPV6 only socket. */
}
return;
}
}
}
/*
* Class: java_net_TwoStacksPlainDatagramSocketImpl
* Method: connect0
* Signature: (Ljava/net/InetAddress;I)V
*/
/* The object's field */
/* The fdObj'fd */
/* The packetAddress address, family and port */
int rmtaddrlen;
"Socket closed");
return;
}
}
}
return;
}
"Protocol family not supported");
return;
}
if (xp_or_later) {
/* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which
* returns connection reset errors un connected UDP sockets (as well
* as connected sockets. The solution is to only enable this feature
* when the socket is connected
*/
}
if (NET_InetAddressToSockaddr(env, address, port,(struct sockaddr *)&rmtaddr, &rmtaddrlen, JNI_FALSE) != 0) {
return;
}
return;
}
}
/*
* Class: java_net_TwoStacksPlainDatagramSocketImpl
* Method: disconnect0
* Signature: ()V
*/
Java_java_net_TwoStacksPlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jint family) {
/* The object's field */
/* The fdObj'fd */
len = sizeof (struct sockaddr_in);
} else {
len = sizeof (struct SOCKADDR_IN6);
}
/* disconnect doesn't throw any exceptions */
return;
}
/*
* use SIO_UDP_CONNRESET
* to disable ICMP port unreachable handling here.
*/
if (xp_or_later) {
int t = FALSE;
}
}
/*
* Class: java_net_TwoStacksPlainDatagramSocketImpl
* Method: send
* Signature: (Ljava/net/DatagramPacket;)V
*/
char *fullPacket;
int addrlen;
return;
}
return;
}
} else {
if (!ipv6_available()) {
"Protocol not allowed");
return;
}
}
"Socket closed");
return;
}
if (connected) {
addrp = 0; /* arg to JVM_Sendto () null in this case */
addrlen = 0;
} else {
if (NET_InetAddressToSockaddr(env, iaObj, packetPort, (struct sockaddr *)&rmtaddr, &addrlen, JNI_FALSE) != 0) {
return;
}
}
if (packetBufferLen > MAX_BUFFER_LEN) {
/*
* On 95/98 if we try to send a datagram >12k to an application
* on the same machine then this will fail silently. Thus we
* catch this situation here so that we can throw an exception
* when this arises.
* On ME if we try to send a datagram with a size greater than
* that supported by the service provider then no error is
* returned.
*/
if (!w2k_or_later) { /* avoid this check on Win 2K or better. Does not work with IPv6.
* Check is not necessary on these OSes */
if (connected) {
} else {
}
}
return;
}
}
/* When JNI-ifying the JDK's IO routines, we turned
* read's and write's of byte arrays of size greater
* than 2048 bytes into several operations of size 2048.
* This saves a malloc()/memcpy()/free() for big
* buffers. This is OK for file IO and TCP, but that
* strategy violates the semantics of a datagram protocol.
* (one big send) != (several smaller sends). So here
* we *must* alloc the buffer. Note it needn't be bigger
* than 65,536 (0xFFFF) the max size of an IP packet.
* anything bigger is truncated anyway.
*/
if (!fullPacket) {
return;
}
} else {
fullPacket = &(BUF[0]);
}
(jbyte *)fullPacket);
case JVM_IO_ERR:
break;
case JVM_IO_INTR:
"operation interrupted");
}
if (packetBufferLen > MAX_BUFFER_LEN) {
}
}
/*
* check which socket was last serviced when there was data on both sockets.
* Only call this if sure that there is data on both sockets.
*/
if (lastfd == -1) {
/* arbitrary. Choose fd */
return fd;
} else {
} else {
}
return nextfd;
}
}
/*
* Class: java_net_TwoStacksPlainDatagramSocketImpl
* Method: peek
* Signature: (Ljava/net/InetAddress;)I
*/
/* The address and family fields of addressObj */
int n;
return -1;
} else {
if (fd < 0) {
"socket closed");
return -1;
}
}
if (IS_NULL(addressObj)) {
} else {
/* We only handle IPv4 for now. Will support IPv6 once its in the os */
}
do {
/*
* If a timeout has been specified then we select on the socket
* waiting for a read event or a timeout.
*/
if (timeout) {
int ret;
if (ret == 0) {
"Peek timed out");
return ret;
} else if (ret == JVM_IO_ERR) {
return ret;
} else if (ret == JVM_IO_INTR) {
"operation interrupted");
return ret;
}
}
/* now try the peek */
if (n == JVM_IO_ERR) {
if (WSAGetLastError() == WSAECONNRESET) {
/*
* An icmp port unreachable - we must receive this as Windows
* does not reset the state of the socket until this has been
* received.
*/
if (connected) {
"ICMP Port Unreachable");
return 0;
}
/*
* If a timeout was specified then we need to adjust it because
* we may have used up some of the timeout befor the icmp port
* unreachable arrived.
*/
if (timeout) {
if (timeout <= 0) {
"Receive timed out");
return 0;
}
}
/* Need to retry the recv */
}
}
} while (retry);
return 0;
}
if (n == JVM_IO_INTR) {
return 0;
}
/* return port */
}
char *fullPacket;
int port;
int checkBoth = 0;
int n;
if (fd < 0) {
"socket closed");
return -1;
}
nsockets = 1;
}
if (fd1 < 0) {
"socket closed");
return -1;
}
nsockets ++;
}
switch (nsockets) {
case 0:
"socket closed");
return -1;
case 1:
} else {
}
break;
case 2:
break;
}
return -1;
}
if (IS_NULL(packetBuffer)) {
return -1;
}
if (packetBufferLen > MAX_BUFFER_LEN) {
/* When JNI-ifying the JDK's IO routines, we turned
* read's and write's of byte arrays of size greater
* than 2048 bytes into several operations of size 2048.
* This saves a malloc()/memcpy()/free() for big
* buffers. This is OK for file IO and TCP, but that
* strategy violates the semantics of a datagram protocol.
* (one big send) != (several smaller sends). So here
* we *must* alloc the buffer. Note it needn't be bigger
* than 65,536 (0xFFFF) the max size of an IP packet.
* anything bigger is truncated anyway.
*/
if (!fullPacket) {
return -1;
}
} else {
fullPacket = &(BUF[0]);
}
do {
int ret;
/*
* If a timeout has been specified then we select on the socket
* waiting for a read event or a timeout.
*/
if (checkBoth) {
/* all subsequent calls to recv() or select() will use the same fd
* for this call to peek() */
if (ret <= 0) {
if (ret == 0) {
"Peek timed out");
} else if (ret == JVM_IO_ERR) {
} else if (ret == JVM_IO_INTR) {
"operation interrupted");
}
if (packetBufferLen > MAX_BUFFER_LEN) {
}
return -1;
}
if (ret == 2) {
}
} else if (timeout) {
if (prevTime == 0) {
}
if (ret <= 0) {
if (ret == 0) {
"Receive timed out");
} else if (ret == JVM_IO_ERR) {
"Socket closed");
} else if (ret == JVM_IO_INTR) {
"operation interrupted");
}
if (packetBufferLen > MAX_BUFFER_LEN) {
}
return -1;
}
}
/* receive the packet */
if (n == JVM_IO_ERR) {
if (WSAGetLastError() == WSAECONNRESET) {
/*
* An icmp port unreachable - we must receive this as Windows
* does not reset the state of the socket until this has been
* received.
*/
if (connected) {
"ICMP Port Unreachable");
if (packetBufferLen > MAX_BUFFER_LEN) {
}
return -1;
}
/*
* If a timeout was specified then we need to adjust it because
* we may have used up some of the timeout befor the icmp port
* unreachable arrived.
*/
if (timeout) {
if (timeout <= 0) {
"Receive timed out");
if (packetBufferLen > MAX_BUFFER_LEN) {
}
return -1;
}
}
}
}
} while (retry);
/* truncate the data if the packet's length is too small */
if (n > packetBufferLen) {
n = packetBufferLen;
}
if (n < 0) {
errorCode = WSAGetLastError();
/* check to see if it's because the buffer was too small */
if (errorCode == WSAEMSGSIZE) {
/* it is because the buffer is too small. It's UDP, it's
* unreliable, it's all good. discard the rest of the
* data..
*/
n = packetBufferLen;
} else {
/* failure */
}
}
if (n == -1) {
} else if (n == -2) {
"operation interrupted");
} else if (n < 0) {
} else {
/*
* Check if there is an InetAddress already associated with this
* packet. If so we check if it is the same source address. We
* can't update any existing InetAddress because it is immutable
*/
if (packetAddress != NULL) {
&remote_addr, packetAddress)) {
/* force a new InetAddress to be created */
}
}
if (packetAddress == NULL) {
&remote_addr, &port);
/* stuff the new Inetaddress in the packet */
}
/* populate the packet */
(jbyte *)fullPacket);
}
/* make sure receive() picks up the right fd */
if (packetBufferLen > MAX_BUFFER_LEN) {
}
return port;
}
/*
* Class: java_net_TwoStacksPlainDatagramSocketImpl
* Method: receive
* Signature: (Ljava/net/DatagramPacket;)V
*/
char *fullPacket;
/* as a result of the changes for ipv6, peek() or peekData()
* must be called prior to receive() so that fduse can be set.
*/
int n, nsockets=0;
"Socket closed");
return;
}
nsockets ++;
}
nsockets ++;
}
/* was fduse set in peek? */
if (fduse == -1) {
/* not set in peek(), must select on both sockets */
if (ret == 2) {
} else if (ret <= 0) {
if (ret == 0) {
"Receive timed out");
} else if (ret == JVM_IO_ERR) {
"Socket closed");
} else if (ret == JVM_IO_INTR) {
"operation interrupted");
}
return;
}
}
} else if (!ipv6_supported) {
/* ipv6 supported: and this socket bound to an IPV6 only address */
} else {
/* ipv6 supported: and this socket bound to an IPV4 only address */
}
return;
}
if (IS_NULL(packetBuffer)) {
return;
}
if (packetBufferLen > MAX_BUFFER_LEN) {
/* When JNI-ifying the JDK's IO routines, we turned
* read's and write's of byte arrays of size greater
* than 2048 bytes into several operations of size 2048.
* This saves a malloc()/memcpy()/free() for big
* buffers. This is OK for file IO and TCP, but that
* strategy violates the semantics of a datagram protocol.
* (one big send) != (several smaller sends). So here
* we *must* alloc the buffer. Note it needn't be bigger
* than 65,536 (0xFFFF) the max size of an IP packet.
* anything bigger is truncated anyway.
*/
if (!fullPacket) {
return;
}
} else {
fullPacket = &(BUF[0]);
}
/*
* If this Windows edition supports ICMP port unreachable and if we
* are not connected then we need to know if a timeout has been specified
* and if so we need to pick up the current time. These are required in
* order to implement the semantics of timeout, viz :-
* timeout set to t1 but ICMP port unreachable arrives in t2 where
* t2 < t1. In this case we must discard the ICMP packets and then
* wait for the next packet up to a maximum of t1 minus t2.
*/
}
int ret;
if (ret <= 0) {
if (ret == 0) {
"Receive timed out");
} else if (ret == JVM_IO_ERR) {
"Socket closed");
} else if (ret == JVM_IO_INTR) {
"operation interrupted");
}
if (packetBufferLen > MAX_BUFFER_LEN) {
}
return;
}
}
/*
* Loop only if we discarding ICMP port unreachable packets
*/
do {
/* receive the packet */
if (n == JVM_IO_ERR) {
if (WSAGetLastError() == WSAECONNRESET) {
/*
* An icmp port unreachable has been received - consume any other
* outstanding packets.
*/
/*
* If connected throw a PortUnreachableException
*/
if (connected) {
"ICMP Port Unreachable");
if (packetBufferLen > MAX_BUFFER_LEN) {
}
return;
}
/*
* If a timeout was specified then we need to adjust it because
* we may have used up some of the timeout before the icmp port
* unreachable arrived.
*/
if (timeout) {
int ret;
if (timeout <= 0) {
ret = 0;
} else {
}
if (ret <= 0) {
if (ret == 0) {
"Receive timed out");
} else if (ret == JVM_IO_ERR) {
"Socket closed");
} else if (ret == JVM_IO_INTR) {
"operation interrupted");
}
if (packetBufferLen > MAX_BUFFER_LEN) {
}
return;
}
}
/*
* An ICMP port unreachable was received but we are
* not connected so ignore it.
*/
}
}
} while (retry);
/* truncate the data if the packet's length is too small */
if (n > packetBufferLen) {
n = packetBufferLen;
}
if (n < 0) {
errorCode = WSAGetLastError();
/* check to see if it's because the buffer was too small */
if (errorCode == WSAEMSGSIZE) {
/* it is because the buffer is too small. It's UDP, it's
* unreliable, it's all good. discard the rest of the
* data..
*/
n = packetBufferLen;
} else {
/* failure */
}
}
if (n == -1) {
} else if (n == -2) {
"operation interrupted");
} else if (n < 0) {
} else {
int port;
/*
* Check if there is an InetAddress already associated with this
* packet. If so we check if it is the same source address. We
* can't update any existing InetAddress because it is immutable
*/
if (packetAddress != NULL) {
/* force a new InetAddress to be created */
}
}
if (packetAddress == NULL) {
/* stuff the new Inetaddress in the packet */
} else {
/* only get the new port number */
}
/* populate the packet */
(jbyte *)fullPacket);
}
if (packetBufferLen > MAX_BUFFER_LEN) {
}
}
/*
* Class: java_net_TwoStacksPlainDatagramSocketImpl
* Method: datagramSocketCreate
* Signature: ()V
*/
int t = TRUE;
return;
} else {
}
if (fd == JVM_IO_ERR) {
return;
}
if (ipv6_supported) {
/* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which
* returns connection reset errors un connected UDP sockets (as well
* as connected sockets. The solution is to only enable this feature
* when the socket is connected
*/
t = FALSE;
t = TRUE;
if (fd1 == JVM_IO_ERR) {
return;
}
t = FALSE;
} else {
/* drop the second fd */
}
}
/*
* Class: java_net_TwoStacksPlainDatagramSocketImpl
* Method: datagramSocketClose
* Signature: ()V
*/
/*
* REMIND: PUT A LOCK AROUND THIS CODE
*/
return;
}
if (fd != -1) {
}
}
if (fd1 == -1) {
return;
}
}
}
/*
* check the addresses attached to the NetworkInterface object
* and return the first one (of the requested family Ipv4 or Ipv6)
* in *iaddr
*/
{
int i;
if (ni_addrsID == NULL ) {
CHECK_NULL_RETURN (c, -1);
"[Ljava/net/InetAddress;");
}
/*
* Check that there is at least one address bound to this
* interface.
*/
if (len < 1) {
"bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface");
return -1;
}
for (i=0; i<len; i++) {
int fam;
return 0;
}
}
return -1;
}
{
if (ret == -1) {
return -1;
}
return 0;
}
/* Get the multicasting index from the interface */
if (ni_indexID == NULL) {
CHECK_NULL_RETURN(c, -1);
}
}
/*
* Sets the multicast interface.
*
* SocketOptions.IP_MULTICAST_IF (argument is an InetAddress) :-
* IPv4: set outgoing multicast interface using
*
* IPv6: Get the interface to which the
* InetAddress is bound
* and do same as SockOptions.IF_MULTICAST_IF2
*
* SockOptions.IF_MULTICAST_IF2 (argument is a NetworkInterface ) :-
* For each stack:
* IPv4: Obtain IP address bound to network interface
* (NetworkInterface.addres[0])
* set outgoing multicast interface using
*
* IPv6: Obtain NetworkInterface.index
* Set outgoing multicast interface using
*
*/
{
if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
/*
* value is an InetAddress.
* On IPv4 system use IP_MULTICAST_IF socket option
* On IPv6 system get the NetworkInterface that this IP
* address is bound to and use the IPV6_MULTICAST_IF
* option instead of IP_MULTICAST_IF
*/
if (ipv6_supported) {
CHECK_NULL(c);
}
"bad argument for IP_MULTICAST_IF"
": address not bound to any interface");
}
return;
}
} else {
"Error setting socket option");
}
return;
}
}
if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
/*
* value is a NetworkInterface.
* On IPv6 system get the index of the interface and use the
* IPV6_MULTICAST_IF socket option
* On IPv4 system extract addr[0] and use the IP_MULTICAST_IF
* option. For IPv6 both must be done.
*/
if (ipv6_supported) {
int index;
if (ni_indexID == NULL) {
CHECK_NULL(c);
}
"IPV6_MULTICAST_IF failed (interface has IPv4 "
"address only?)");
} else {
"Error setting socket option");
}
return;
}
/* If there are any IPv4 addresses on this interface then
* repeat the operation on the IPv4 fd */
return;
}
"Error setting socket option");
}
return;
} else {
return;
}
"no InetAddress instances of requested type");
return;
}
"Error setting socket option");
}
return;
}
}
}
/*
* Class: java_net_TwoStacksPlainDatagramSocketImpl
* Method: socketNativeSetOption
*/
union {
int i;
char c;
} optval;
if (ipv6_supported) {
}
return;
}
if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
return;
}
/*
* Map the Java level socket option to the platform specific
* level(s) and option name(s).
*/
if (fd1 != -1) {
return;
}
}
if (fd != -1) {
return;
}
}
switch (opt) {
{
}
break;
{
/*
* setLoopbackMode (true) disables IP_MULTICAST_LOOP rather
* than enabling it.
*/
if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) {
}
}
break;
default :
"Socket option not supported by PlainDatagramSocketImp");
break;
}
if (fd1 != -1) {
return;
}
}
if (fd != -1) {
return;
}
}
}
/*
* Return the multicast interface:
*
* SocketOptions.IP_MULTICAST_IF
* IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
* Create InetAddress
* IP_MULTICAST_IF returns struct ip_mreqn on 2.2
* kernel but struct in_addr on 2.4 kernel
* IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF or
* obtain from impl is Linux 2.2 kernel
* If index == 0 return InetAddress representing
* anyLocalAddress.
* If index > 0 query NetworkInterface by index
* and returns addrs[0]
*
* SocketOptions.IP_MULTICAST_IF2
* IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
* Query NetworkInterface by IP address and
* return the NetworkInterface that the address
* is bound too.
* IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
* (except Linux .2 kernel)
* Query NetworkInterface by index and
* return NetworkInterface.
*/
/*
* IPv4 implementation
*/
if (isIPV4) {
"Error getting socket option");
return NULL;
}
/*
* Construct and populate an Inet4Address
*/
if (inet4_class == NULL) {
CHECK_NULL_RETURN(c, NULL);
}
/*
* For IP_MULTICAST_IF return InetAddress
*/
if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
return addr;
}
/*
* For IP_MULTICAST_IF2 we get the NetworkInterface for
* this address and return it
*/
CHECK_NULL_RETURN(c, NULL);
"[Ljava/net/InetAddress;");
}
if (ni) {
return ni;
}
/*
* The address doesn't appear to be bound at any known
* NetworkInterface. Therefore we construct a NetworkInterface
* with this address.
*/
return ni;
}
/*
* IPv6 implementation
*/
if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
int index;
{
"Error getting socket option");
return NULL;
}
}
CHECK_NULL_RETURN(c, NULL);
"[Ljava/net/InetAddress;");
"anyLocalAddress",
"()Ljava/net/InetAddress;");
}
/*
* If multicast to a specific interface then return the
* interface (for IF2) or the any address on that interface
* (for IF).
*/
if (index > 0) {
index);
"IPV6_MULTICAST_IF returned index to unrecognized interface: %d",
index);
return NULL;
}
/*
* For IP_MULTICAST_IF2 return the NetworkInterface
*/
if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
return ni;
}
/*
* For IP_MULTICAST_IF return addrs[0]
*/
"IPV6_MULTICAST_IF returned interface without IP bindings");
return NULL;
}
return addr;
}
/*
* Multicast to any address - return anyLocalAddress
* or a NetworkInterface with addrs[0] set to anyLocalAddress
*/
NULL);
if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
return addr;
}
return ni;
}
return NULL;
}
/*
* Returns relevant info as a jint.
*
* Class: java_net_TwoStacksPlainDatagramSocketImpl
* Method: socketGetOption
*/
union {
int i;
} optval;
if (ipv6_supported) {
}
"Socket closed");
return NULL;
}
/*
* Handle IP_MULTICAST_IF separately
*/
if (opt == java_net_SocketOptions_IP_MULTICAST_IF ||
}
if (opt == java_net_SocketOptions_SO_BINDADDR) {
/* find out local IP address */
int len = 0;
int port;
len = sizeof (struct sockaddr_in);
if (fd == -1) {
len = sizeof (struct SOCKADDR_IN6);
}
"Error getting socket name");
return NULL;
}
return iaObj;
}
/*
* Map the Java level socket option to the platform specific
* level and option name.
*/
return NULL;
}
if (fd == -1) {
return NULL;
}
}
return NULL;
}
switch (opt) {
/* getLoopbackMode() returns true if IP_MULTICAST_LOOP is disabled */
default :
"Socket option not supported by TwoStacksPlainDatagramSocketImpl");
return NULL;
}
}
/*
* Class: java_net_TwoStacksPlainDatagramSocketImpl
* Method: setTimeToLive
* Signature: (I)V
*/
"Socket closed");
return;
} else {
}
}
}
/* setsockopt to be correct ttl */
if (fd >= 0) {
sizeof (ittl)) < 0) {
}
}
if (fd1 >= 0) {
sizeof(ittl)) <0) {
}
}
}
/*
* Class: java_net_TwoStacksPlainDatagramSocketImpl
* Method: setTTL
* Signature: (B)V
*/
}
/*
* Class: java_net_TwoStacksPlainDatagramSocketImpl
* Method: getTimeToLive
* Signature: ()I
*/
int ttl = 0;
"Socket closed");
return -1;
} else {
}
}
}
/* getsockopt of ttl */
if (fd >= 0) {
return -1;
}
}
if (fd1 >= 0) {
return -1;
}
}
return -1;
}
/*
* Class: java_net_TwoStacksPlainDatagramSocketImpl
* Method: getTTL
* Signature: ()B
*/
}
* then the interface set with setInterfac(), or the default interface otherwise */
{
int cmd ;
"Socket closed");
return;
}
}
}
return;
}
return;
}
/* Set the multicast group address in the ip_mreq field
* eventually this check should be done by the security manager
*/
return;
}
if (fd < 0) {
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Can't join an IPv4 group on an IPv6 only socket");
return;
}
return;
}
} else {
return;
}
}
/* Join the multicast group */
if (WSAGetLastError() == WSAENOBUFS) {
"IP_ADD_MEMBERSHIP failed (out of hardware filters?)");
} else {
}
}
} else /* AF_INET6 */ {
if (ipv6_supported) {
if (!IN6_IS_ADDR_MULTICAST(address)) {
return;
}
} else {
return;
}
if (fd1 < 0) {
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Can't join an IPv6 group on a IPv4 socket");
return;
}
return;
}
} else {
if (ifindex == -1) {
return;
}
}
/* Join the multicast group */
if (WSAGetLastError() == WSAENOBUFS) {
"IP_ADD_MEMBERSHIP failed (out of hardware filters?)");
} else {
}
}
}
return;
}
/*
* Class: java_net_TwoStacksPlainDatagramSocketImpl
* Method: join
* Signature: (Ljava/net/InetAddress;)V
*/
{
}
/*
* Class: java_net_TwoStacksPlainDatagramSocketImpl
* Method: leave
* Signature: (Ljava/net/InetAddress;)V
*/
{
}