Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/ikvm-fork.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjfrijters <jfrijters>2010-09-09 10:55:31 +0400
committerjfrijters <jfrijters>2010-09-09 10:55:31 +0400
commite57a3213625777da5740614fc86afb6cb4e9e23e (patch)
treed117f574bdbb2afc471339612187b8bcc5dd57bc /openjdk/java/net/net_util_md.java
parent0720c24a212c240d952a1d20f5595ed15f7fabf3 (diff)
Implemented IPv6 support for java.net package APIs.
Diffstat (limited to 'openjdk/java/net/net_util_md.java')
-rw-r--r--openjdk/java/net/net_util_md.java824
1 files changed, 824 insertions, 0 deletions
diff --git a/openjdk/java/net/net_util_md.java b/openjdk/java/net/net_util_md.java
new file mode 100644
index 00000000..be3d368c
--- /dev/null
+++ b/openjdk/java/net/net_util_md.java
@@ -0,0 +1,824 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.net;
+
+import cli.System.Net.IPAddress;
+import cli.System.Net.IPEndPoint;
+import static ikvm.internal.JNI.*;
+import static ikvm.internal.Winsock.*;
+
+final class net_util_md
+{
+ private net_util_md() { }
+
+ static final int INADDR_ANY = 0;
+
+ static final int IPTOS_TOS_MASK = 0x1e;
+ static final int IPTOS_PREC_MASK = 0xe0;
+
+ static boolean isRcvTimeoutSupported = true;
+
+ /*
+ * Table of Windows Sockets errors, the specific exception we
+ * throw for the error, and the error text.
+ *
+ * Note that this table excludes OS dependent errors.
+ *
+ * Latest list of Windows Sockets errors can be found at :-
+ * http://msdn.microsoft.com/library/psdk/winsock/errors_3wc2.htm
+ */
+ private static class WinsockError
+ {
+ final int errCode;
+ final int exc;
+ final String errString;
+
+ WinsockError(int errCode, int exc, String errString)
+ {
+ this.errCode = errCode;
+ this.exc = exc;
+ this.errString = errString;
+ }
+ }
+
+ private static final int Exception_BindException = 1;
+ private static final int Exception_ConnectException = 2;
+ private static final int Exception_NoRouteToHostException = 3;
+
+ private static final WinsockError[] winsock_errors = {
+ new WinsockError(WSAEACCES, 0, "Permission denied"),
+ new WinsockError(WSAEADDRINUSE, Exception_BindException, "Address already in use"),
+ new WinsockError(WSAEADDRNOTAVAIL, Exception_BindException, "Cannot assign requested address"),
+ new WinsockError(WSAEAFNOSUPPORT, 0, "Address family not supported by protocol family"),
+ new WinsockError(WSAEALREADY, 0, "Operation already in progress"),
+ new WinsockError(WSAECONNABORTED, 0, "Software caused connection abort"),
+ new WinsockError(WSAECONNREFUSED, Exception_ConnectException, "Connection refused"),
+ new WinsockError(WSAECONNRESET, 0, "Connection reset by peer"),
+ new WinsockError(WSAEDESTADDRREQ, 0, "Destination address required"),
+ new WinsockError(WSAEFAULT, 0, "Bad address"),
+ new WinsockError(WSAEHOSTDOWN, 0, "Host is down"),
+ new WinsockError(WSAEHOSTUNREACH, Exception_NoRouteToHostException, "No route to host"),
+ new WinsockError(WSAEINPROGRESS, 0, "Operation now in progress"),
+ new WinsockError(WSAEINTR, 0, "Interrupted function call"),
+ new WinsockError(WSAEINVAL, 0, "Invalid argument"),
+ new WinsockError(WSAEISCONN, 0, "Socket is already connected"),
+ new WinsockError(WSAEMFILE, 0, "Too many open files"),
+ new WinsockError(WSAEMSGSIZE, 0, "The message is larger than the maximum supported by the underlying transport"),
+ new WinsockError(WSAENETDOWN, 0, "Network is down"),
+ new WinsockError(WSAENETRESET, 0, "Network dropped connection on reset"),
+ new WinsockError(WSAENETUNREACH, 0, "Network is unreachable"),
+ new WinsockError(WSAENOBUFS, 0, "No buffer space available (maximum connections reached?)"),
+ new WinsockError(WSAENOPROTOOPT, 0, "Bad protocol option"),
+ new WinsockError(WSAENOTCONN, 0, "Socket is not connected"),
+ new WinsockError(WSAENOTSOCK, 0, "Socket operation on nonsocket"),
+ new WinsockError(WSAEOPNOTSUPP, 0, "Operation not supported"),
+ new WinsockError(WSAEPFNOSUPPORT, 0, "Protocol family not supported"),
+ new WinsockError(WSAEPROCLIM, 0, "Too many processes"),
+ new WinsockError(WSAEPROTONOSUPPORT, 0, "Protocol not supported"),
+ new WinsockError(WSAEPROTOTYPE, 0, "Protocol wrong type for socket"),
+ new WinsockError(WSAESHUTDOWN, 0, "Cannot send after socket shutdown"),
+ new WinsockError(WSAESOCKTNOSUPPORT, 0, "Socket type not supported"),
+ new WinsockError(WSAETIMEDOUT, Exception_ConnectException, "Connection timed out"),
+ new WinsockError(WSATYPE_NOT_FOUND, 0, "Class type not found"),
+ new WinsockError(WSAEWOULDBLOCK, 0, "Resource temporarily unavailable"),
+ new WinsockError(WSAHOST_NOT_FOUND, 0, "Host not found"),
+ new WinsockError(WSA_NOT_ENOUGH_MEMORY, 0, "Insufficient memory available"),
+ new WinsockError(WSANOTINITIALISED, 0, "Successful WSAStartup not yet performed"),
+ new WinsockError(WSANO_DATA, 0, "Valid name, no data record of requested type"),
+ new WinsockError(WSANO_RECOVERY, 0, "This is a nonrecoverable error"),
+ new WinsockError(WSASYSNOTREADY, 0, "Network subsystem is unavailable"),
+ new WinsockError(WSATRY_AGAIN, 0, "Nonauthoritative host not found"),
+ new WinsockError(WSAVERNOTSUPPORTED, 0, "Winsock.dll version out of range"),
+ new WinsockError(WSAEDISCON, 0, "Graceful shutdown in progress"),
+ new WinsockError(WSA_OPERATION_ABORTED, 0, "Overlapped operation aborted")
+ };
+
+ /*
+ * Since winsock doesn't have the equivalent of strerror(errno)
+ * use table to lookup error text for the error.
+ */
+ static SocketException NET_ThrowNew(int errorNum, String msg)
+ {
+ int i;
+ int table_size = winsock_errors.length;
+ int excP = 0;
+ String fullMsg;
+
+ if (msg == null) {
+ msg = "no further information";
+ }
+
+ /*
+ * Check table for known winsock errors
+ */
+ i=0;
+ while (i < table_size) {
+ if (errorNum == winsock_errors[i].errCode) {
+ break;
+ }
+ i++;
+ }
+
+ /*
+ * If found get pick the specific exception and error
+ * message corresponding to this error.
+ */
+ if (i < table_size) {
+ excP = winsock_errors[i].exc;
+ fullMsg = winsock_errors[i].errString + ": " + msg;
+ } else {
+ fullMsg = "Unrecognized Windows Sockets error: " + errorNum + ": " + msg;
+ }
+
+ /*
+ * Throw SocketException if no specific exception for this
+ * error.
+ */
+ switch (excP) {
+ case Exception_BindException:
+ return new BindException(fullMsg);
+ case Exception_ConnectException:
+ return new ConnectException(fullMsg);
+ case Exception_NoRouteToHostException:
+ return new NoRouteToHostException(fullMsg);
+ default:
+ return new SocketException(fullMsg);
+ }
+ }
+
+ static void NET_ThrowNew(JNIEnv env, int errorNum, String msg)
+ {
+ env.Throw(NET_ThrowNew(errorNum, msg));
+ }
+
+ static SocketException NET_ThrowCurrent(String msg)
+ {
+ return NET_ThrowNew(WSAGetLastError(), msg);
+ }
+
+ static void NET_ThrowCurrent(JNIEnv env, String msg)
+ {
+ env.Throw(NET_ThrowCurrent(msg));
+ }
+
+ /*
+ * Return the default TOS value
+ */
+ static int NET_GetDefaultTOS() {
+ // we always use the "default" default...
+ return 0;
+ }
+
+ /*
+ * Map the Java level socket option to the platform specific
+ * level and option name.
+ */
+
+ private static final class sockopts {
+ int cmd;
+ int level;
+ int optname;
+
+ sockopts(int cmd, int level, int optname) {
+ this.cmd = cmd;
+ this.level = level;
+ this.optname = optname;
+ }
+ }
+
+ private static final sockopts opts[] = {
+ new sockopts(SocketOptions.TCP_NODELAY, IPPROTO_TCP, TCP_NODELAY ),
+ new sockopts(SocketOptions.SO_OOBINLINE, SOL_SOCKET, SO_OOBINLINE ),
+ new sockopts(SocketOptions.SO_LINGER, SOL_SOCKET, SO_LINGER ),
+ new sockopts(SocketOptions.SO_SNDBUF, SOL_SOCKET, SO_SNDBUF ),
+ new sockopts(SocketOptions.SO_RCVBUF, SOL_SOCKET, SO_RCVBUF ),
+ new sockopts(SocketOptions.SO_KEEPALIVE, SOL_SOCKET, SO_KEEPALIVE ),
+ new sockopts(SocketOptions.SO_REUSEADDR, SOL_SOCKET, SO_REUSEADDR ),
+ new sockopts(SocketOptions.SO_BROADCAST, SOL_SOCKET, SO_BROADCAST ),
+ new sockopts(SocketOptions.IP_MULTICAST_IF, IPPROTO_IP, IP_MULTICAST_IF ),
+ new sockopts(SocketOptions.IP_MULTICAST_LOOP, IPPROTO_IP, IP_MULTICAST_LOOP ),
+ new sockopts(SocketOptions.IP_TOS, IPPROTO_IP, IP_TOS ),
+
+ };
+
+ /* call NET_MapSocketOptionV6 for the IPv6 fd only
+ * and NET_MapSocketOption for the IPv4 fd
+ */
+ static int NET_MapSocketOptionV6(int cmd, int[] level, int[] optname) {
+
+ switch (cmd) {
+ case SocketOptions.IP_MULTICAST_IF:
+ case SocketOptions.IP_MULTICAST_IF2:
+ level[0] = IPPROTO_IPV6;
+ optname[0] = IPV6_MULTICAST_IF;
+ return 0;
+
+ case SocketOptions.IP_MULTICAST_LOOP:
+ level[0] = IPPROTO_IPV6;
+ optname[0] = IPV6_MULTICAST_LOOP;
+ return 0;
+ }
+ return NET_MapSocketOption (cmd, level, optname);
+ }
+
+ static int NET_MapSocketOption(int cmd, int[] level, int[] optname) {
+ /*
+ * Map the Java level option to the native level
+ */
+ for (int i=0; i<opts.length; i++) {
+ if (cmd == opts[i].cmd) {
+ level[0] = opts[i].level;
+ optname[0] = opts[i].optname;
+ return 0;
+ }
+ }
+
+ /* not found */
+ return -1;
+ }
+
+ static int NET_SetSockOpt(cli.System.Net.Sockets.Socket s, int level, int optname, Object optval)
+ {
+ int rv;
+
+ if (level == IPPROTO_IP && optname == IP_TOS) {
+ int tos = (Integer)optval;
+ tos &= (IPTOS_TOS_MASK | IPTOS_PREC_MASK);
+ optval = tos;
+ }
+
+ rv = setsockopt(s, level, optname, optval);
+
+ if (rv == SOCKET_ERROR) {
+ /*
+ * IP_TOS & IP_MULTICAST_LOOP can't be set on some versions
+ * of Windows.
+ */
+ if ((WSAGetLastError() == WSAENOPROTOOPT) &&
+ (level == IPPROTO_IP) &&
+ (optname == IP_TOS || optname == IP_MULTICAST_LOOP)) {
+ rv = 0;
+ }
+
+ /*
+ * IP_TOS can't be set on unbound UDP sockets.
+ */
+ if ((WSAGetLastError() == WSAEINVAL) &&
+ (level == IPPROTO_IP) &&
+ (optname == IP_TOS)) {
+ rv = 0;
+ }
+ }
+
+ return rv;
+ }
+
+ /*
+ * Wrapper for setsockopt dealing with Windows specific issues :-
+ *
+ * IP_TOS is not supported on some versions of Windows so
+ * instead return the default value for the OS.
+ */
+ static int NET_GetSockOpt(cli.System.Net.Sockets.Socket s, int level, int optname, Object optval)
+ {
+ int rv;
+
+ rv = getsockopt(s, level, optname, optval);
+
+
+ /*
+ * IPPROTO_IP/IP_TOS is not supported on some Windows
+ * editions so return the default type-of-service
+ * value.
+ */
+ if (rv == SOCKET_ERROR) {
+
+ if (WSAGetLastError() == WSAENOPROTOOPT &&
+ level == IPPROTO_IP && optname == IP_TOS) {
+
+ ((int[])optval)[0] = NET_GetDefaultTOS();
+
+ rv = 0;
+ }
+ }
+
+ return rv;
+ }
+
+ /*
+ * Wrapper for bind winsock call - transparent converts an
+ * error related to binding to a port that has exclusive access
+ * into an error indicating the port is in use (facilitates
+ * better error reporting).
+ */
+ static int NET_Bind(cli.System.Net.Sockets.Socket s, SOCKETADDRESS him)
+ {
+ int rv = bind(s, him);
+
+ if (rv == SOCKET_ERROR) {
+ /*
+ * If bind fails with WSAEACCES it means that a privileged
+ * process has done an exclusive bind (NT SP4/2000/XP only).
+ */
+ if (WSAGetLastError() == WSAEACCES) {
+ WSASetLastError(WSAEADDRINUSE);
+ }
+ }
+
+ return rv;
+ }
+
+ static int NET_SocketClose(cli.System.Net.Sockets.Socket fd) {
+ linger l = new linger();
+ int ret;
+ if (getsockopt(fd, SOL_SOCKET, SO_LINGER, l) == 0) {
+ if (l.l_onoff == 0) {
+ WSASendDisconnect(fd);
+ }
+ }
+ ret = closesocket (fd);
+ return ret;
+ }
+
+ static int NET_Timeout(cli.System.Net.Sockets.Socket fd, long timeout) {
+ int ret;
+ fd_set tbl = new fd_set();
+ timeval t = new timeval();
+ t.tv_sec = timeout / 1000;
+ t.tv_usec = (timeout % 1000) * 1000;
+ FD_ZERO(tbl);
+ FD_SET(fd, tbl);
+ ret = select (tbl, null, null, t);
+ return ret;
+ }
+
+ /*
+ * differs from NET_Timeout() as follows:
+ *
+ * If timeout = -1, it blocks forever.
+ *
+ * returns 1 or 2 depending if only one or both sockets
+ * fire at same time.
+ *
+ * *fdret is (one of) the active fds. If both sockets
+ * fire at same time, *fdret = fd always.
+ */
+ static int NET_Timeout2(cli.System.Net.Sockets.Socket fd, cli.System.Net.Sockets.Socket fd1, long timeout, cli.System.Net.Sockets.Socket[] fdret) {
+ int ret;
+ fd_set tbl = new fd_set();
+ timeval t = new timeval();
+ if (timeout == -1) {
+ t = null;
+ } else {
+ t.tv_sec = timeout / 1000;
+ t.tv_usec = (timeout % 1000) * 1000;
+ }
+ FD_ZERO(tbl);
+ FD_SET(fd, tbl);
+ FD_SET(fd1, tbl);
+ ret = select (tbl, null, null, t);
+ switch (ret) {
+ case 0:
+ return 0; /* timeout */
+ case 1:
+ if (FD_ISSET (fd, tbl)) {
+ fdret[0]= fd;
+ } else {
+ fdret[0]= fd1;
+ }
+ return 1;
+ case 2:
+ fdret[0]= fd;
+ return 2;
+ }
+ return -1;
+ }
+
+ /*
+ * if ipv6 is available, call NET_BindV6 to bind to the required address/port.
+ * Because the same port number may need to be reserved in both v4 and v6 space,
+ * this may require socket(s) to be re-opened. Therefore, all of this information
+ * is passed in and returned through the ipv6bind structure.
+ *
+ * If the request is to bind to a specific address, then this (by definition) means
+ * only bind in either v4 or v6, and this is just the same as normal. ie. a single
+ * call to bind() will suffice. The other socket is closed in this case.
+ *
+ * The more complicated case is when the requested address is ::0 or 0.0.0.0.
+ *
+ * Two further cases:
+ * 2. If the reqeusted port is 0 (ie. any port) then we try to bind in v4 space
+ * first with a wild-card port argument. We then try to bind in v6 space
+ * using the returned port number. If this fails, we repeat the process
+ * until a free port common to both spaces becomes available.
+ *
+ * 3. If the requested port is a specific port, then we just try to get that
+ * port in both spaces, and if it is not free in both, then the bind fails.
+ *
+ * On failure, sockets are closed and an error returned with CLOSE_SOCKETS_AND_RETURN
+ */
+
+ static class ipv6bind {
+ SOCKETADDRESS addr;
+ cli.System.Net.Sockets.Socket ipv4_fd;
+ cli.System.Net.Sockets.Socket ipv6_fd;
+ }
+
+ private static int CLOSE_SOCKETS_AND_RETURN(
+ cli.System.Net.Sockets.Socket fd,
+ cli.System.Net.Sockets.Socket ofd,
+ cli.System.Net.Sockets.Socket close_fd,
+ cli.System.Net.Sockets.Socket close_ofd,
+ ipv6bind b) {
+ if (fd != null) {
+ closesocket (fd);
+ }
+ if (ofd != null) {
+ closesocket (ofd);
+ }
+ if (close_fd != null) {
+ closesocket (close_fd);
+ }
+ if (close_ofd != null) {
+ closesocket (close_ofd);
+ }
+ b.ipv4_fd = b.ipv6_fd = null;
+ return SOCKET_ERROR;
+ }
+
+ static int NET_BindV6(ipv6bind b) {
+ cli.System.Net.Sockets.Socket fd = null;
+ cli.System.Net.Sockets.Socket ofd = null;
+ int rv;
+ /* need to defer close until new sockets created */
+ cli.System.Net.Sockets.Socket close_fd = null;
+ cli.System.Net.Sockets.Socket close_ofd = null;
+
+ SOCKETADDRESS oaddr = new SOCKETADDRESS();
+ int family = b.addr.him.sa_family;
+ int ofamily;
+ int port;
+ int bound_port;
+
+ if (family == AF_INET && (b.addr.him4.sin_addr.s_addr != INADDR_ANY)) {
+ /* bind to v4 only */
+ int ret;
+ ret = NET_Bind (b.ipv4_fd, b.addr);
+ if (ret == SOCKET_ERROR) {
+ return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b);
+ }
+ closesocket (b.ipv6_fd);
+ b.ipv6_fd = null;
+ return 0;
+ }
+ if (family == AF_INET6 && (!IN6ADDR_ISANY(b.addr))) {
+ /* bind to v6 only */
+ int ret;
+ ret = NET_Bind (b.ipv6_fd, b.addr);
+ if (ret == SOCKET_ERROR) {
+ return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b);
+ }
+ closesocket (b.ipv4_fd);
+ b.ipv4_fd = null;
+ return 0;
+ }
+
+ /* We need to bind on both stacks, with the same port number */
+
+ if (family == AF_INET) {
+ ofamily = AF_INET6;
+ fd = b.ipv4_fd;
+ ofd = b.ipv6_fd;
+ port = GET_PORT (b.addr);
+ oaddr.set(new IPEndPoint(IPAddress.IPv6Any, htons(port)));
+ } else {
+ ofamily = AF_INET;
+ ofd = b.ipv4_fd;
+ fd = b.ipv6_fd;
+ port = GET_PORT (b.addr);
+ oaddr.set(new IPEndPoint(IPAddress.Any, htons(port)));
+ }
+
+ rv = NET_Bind (fd, b.addr);
+ if (rv == SOCKET_ERROR) {
+ return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b);
+ }
+
+ /* get the port and set it in the other address */
+ if (getsockname(fd, b.addr) == -1) {
+ return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b);
+ }
+ bound_port = b.addr.sin_port;
+ oaddr.sin_port = bound_port;
+ if ((rv=NET_Bind (ofd, oaddr)) == SOCKET_ERROR) {
+
+ /* no retries unless, the request was for any free port */
+
+ if (port != 0) {
+ return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b);
+ }
+
+ int sotype = fd.get_SocketType().Value;
+
+ /* 50 is an arbitrary limit, just to ensure that this
+ * cannot be an endless loop. Would expect socket creation to
+ * succeed sooner.
+ */
+ for (int retries = 0; retries < 50 /*SOCK_RETRIES*/; retries ++) {
+ close_fd = fd;
+ fd = null;
+ close_ofd = ofd;
+ ofd = null;
+ b.ipv4_fd = null;
+ b.ipv6_fd = null;
+
+ /* create two new sockets */
+ fd = socket (family, sotype, 0);
+ if (fd == INVALID_SOCKET) {
+ return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b);
+ }
+ ofd = socket (ofamily, sotype, 0);
+ if (ofd == INVALID_SOCKET) {
+ return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b);
+ }
+
+ /* bind random port on first socket */
+ oaddr.sin_port = 0;
+ rv = NET_Bind (ofd, oaddr);
+ if (rv == SOCKET_ERROR) {
+ return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b);
+ }
+ /* close the original pair of sockets before continuing */
+ closesocket (close_fd);
+ closesocket (close_ofd);
+ close_fd = close_ofd = null;
+
+ /* bind new port on second socket */
+ if (getsockname(ofd, oaddr) == -1) {
+ return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b);
+ }
+ bound_port = oaddr.sin_port;
+ b.addr.sin_port = bound_port;
+ rv = NET_Bind (fd, b.addr);
+
+ if (rv != SOCKET_ERROR) {
+ if (family == AF_INET) {
+ b.ipv4_fd = fd;
+ b.ipv6_fd = ofd;
+ } else {
+ b.ipv4_fd = ofd;
+ b.ipv6_fd = fd;
+ }
+ return 0;
+ }
+ }
+ return CLOSE_SOCKETS_AND_RETURN(fd, ofd, close_fd, close_ofd, b);
+ }
+ return 0;
+ }
+
+ /* If address types is IPv6, then IPv6 must be available. Otherwise
+ * no address can be generated. In the case of an IPv4 Inetaddress this
+ * method will return an IPv4 mapped address where IPv6 is available and
+ * v4MappedAddress is TRUE. Otherwise it will return a sockaddr_in
+ * structure for an IPv4 InetAddress.
+ */
+ static int NET_InetAddressToSockaddr(JNIEnv env, InetAddress iaObj, int port, SOCKETADDRESS him, boolean v4MappedAddress) {
+ if (iaObj.family == InetAddress.IPv4) {
+ him.set(new IPEndPoint(new IPAddress(htonl(iaObj.address) & 0xFFFFFFFFL), port));
+ return 0;
+ } else {
+ Inet6Address v6addr = (Inet6Address)iaObj;
+ int scope = v6addr.getScopeId();
+ if (scope == 0) {
+ him.set(new IPEndPoint(new IPAddress(v6addr.ipaddress), port));
+ return 0;
+ } else {
+ him.set(new IPEndPoint(new IPAddress(v6addr.ipaddress, scope & 0xFFFFFFFFL), port));
+ return 0;
+ }
+ }
+ }
+
+ static int NET_GetPortFromSockaddr(SOCKETADDRESS him) {
+ return ntohs(GET_PORT(him));
+ }
+
+ static boolean NET_IsIPv4Mapped(byte[] caddr) {
+ int i;
+ for (i = 0; i < 10; i++) {
+ if (caddr[i] != 0x00) {
+ return false;
+ }
+ }
+
+ if (((caddr[10] & 0xff) == 0xff) && ((caddr[11] & 0xff) == 0xff)) {
+ return true;
+ }
+ return false;
+ }
+
+ static int NET_IPv4MappedToIPv4(byte[] caddr) {
+ return ((caddr[12] & 0xff) << 24) | ((caddr[13] & 0xff) << 16) | ((caddr[14] & 0xff) << 8)
+ | (caddr[15] & 0xff);
+ }
+
+ static boolean NET_IsEqual(byte[] caddr1, byte[] caddr2) {
+ int i;
+ for (i = 0; i < 16; i++) {
+ if (caddr1[i] != caddr2[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ static int getScopeID (SOCKETADDRESS him) {
+ return him.him6.sin6_scope_id;
+ }
+
+ static boolean cmpScopeID (int scope, SOCKETADDRESS him) {
+ return him.him6.sin6_scope_id == scope;
+ }
+
+ /* these methods are not from net_util_md.c */
+
+ static boolean ipv6_available() {
+ return InetAddressImplFactory.isIPv6Supported();
+ }
+
+ static boolean IS_NULL(Object obj) {
+ return obj == null;
+ }
+
+ static boolean IN6ADDR_ISANY(SOCKETADDRESS him) {
+ if (him.sa_family != AF_INET6) {
+ return false;
+ }
+ byte[] addr = him.him6.sin6_addr;
+ byte b = 0;
+ for (int i = 0; i < addr.length; i++) {
+ b |= addr[i];
+ }
+ return b == 0;
+ }
+
+ static boolean NET_SockaddrEqualsInetAddress(SOCKETADDRESS him, InetAddress iaObj) {
+ int family = iaObj.family == InetAddress.IPv4 ? AF_INET : AF_INET6;
+
+ if (him.sa_family == AF_INET6) {
+ byte[] caddrNew = him.him6.sin6_addr;
+ if (NET_IsIPv4Mapped(caddrNew)) {
+ int addrNew;
+ int addrCur;
+ if (family == AF_INET6) {
+ return false;
+ }
+ addrNew = NET_IPv4MappedToIPv4(caddrNew);
+ addrCur = iaObj.address;
+ if (addrNew == addrCur) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ byte[] caddrCur;
+ int scope;
+
+ if (family == AF_INET) {
+ return false;
+ }
+ scope = ((Inet6Address)iaObj).getScopeId();
+ caddrCur = ((Inet6Address)iaObj).ipaddress;
+ if (NET_IsEqual(caddrNew, caddrCur) && cmpScopeID(scope, him)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ } else {
+ int addrNew, addrCur;
+ if (family != AF_INET) {
+ return false;
+ }
+ addrNew = ntohl(him.him4.sin_addr.s_addr);
+ addrCur = iaObj.address;
+ if (addrNew == addrCur) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ static InetAddress NET_SockaddrToInetAddress(SOCKETADDRESS him, int[] port) {
+ InetAddress iaObj;
+ if (him.sa_family == AF_INET6) {
+ byte[] caddr = him.him6.sin6_addr;
+ if (NET_IsIPv4Mapped(caddr)) {
+ iaObj = new Inet4Address(null, NET_IPv4MappedToIPv4(caddr));
+ } else {
+ iaObj = new Inet6Address(null, caddr, getScopeID(him));
+ }
+ port[0] = ntohs(him.him6.sin_port);
+ } else {
+ iaObj = new Inet4Address(null, ntohl(him.him4.sin_addr.s_addr));
+ port[0] = ntohs(him.him4.sin_port);
+ }
+ return iaObj;
+ }
+
+ static void NET_ThrowByNameWithLastError(JNIEnv env, String exceptionClass, String message) {
+ JNU_ThrowByName(env, exceptionClass, "errno: " + WSAGetLastError() + ", error: " + message + "\n");
+ }
+
+ static boolean IN_MULTICAST(int ipv4address) {
+ return ((ipv4address >> 24) & 0xf0) == 0xe0;
+ }
+
+ static boolean IN6_IS_ADDR_MULTICAST(in6_addr address) {
+ return (address.s6_bytes()[0] & 0xff) == 0xff;
+ }
+
+ static final class SOCKETADDRESS implements IIPEndPointWrapper {
+ final SOCKETADDRESS him = this;
+ final SOCKETADDRESS him4 = this;
+ final SOCKETADDRESS him6 = this;
+ final SOCKETADDRESS sin_addr = this;
+ int sa_family;
+ int sin_port;
+ int s_addr;
+ byte[] sin6_addr;
+ int sin6_scope_id;
+
+ public void set(IPEndPoint ep) {
+ if (ep == null) {
+ sa_family = 0;
+ sin_port = 0;
+ s_addr = 0;
+ sin6_addr = null;
+ sin6_scope_id = 0;
+ } else {
+ sa_family = ep.get_AddressFamily().Value;
+ sin_port = htons(ep.get_Port());
+ if (sa_family == AF_INET) {
+ s_addr = (int)ep.get_Address().get_Address();
+ sin6_addr = null;
+ sin6_scope_id = 0;
+ } else {
+ s_addr = 0;
+ IPAddress addr = ep.get_Address();
+ sin6_addr = addr.GetAddressBytes();
+ sin6_scope_id = (int)addr.get_ScopeId();
+ }
+ }
+ }
+
+ public IPEndPoint get() {
+ if (sa_family == AF_INET) {
+ return new IPEndPoint(new IPAddress(s_addr & 0xFFFFFFFFL), ntohs(sin_port));
+ } else if (sa_family == AF_INET6) {
+ IPAddress addr;
+ if (sin6_addr == null) {
+ addr = IPAddress.IPv6Any;
+ } else {
+ addr = new IPAddress(sin6_addr, sin6_scope_id & 0xFFFFFFFFL);
+ }
+ return new IPEndPoint(addr, ntohs(sin_port));
+ } else {
+ return null;
+ }
+ }
+ }
+
+ static int GET_PORT(SOCKETADDRESS sockaddr) {
+ return sockaddr.sin_port;
+ }
+
+ static void Sleep(int ms) {
+ cli.System.Threading.Thread.Sleep(ms);
+ }
+}