diff options
author | jfrijters <jfrijters> | 2010-09-09 10:55:31 +0400 |
---|---|---|
committer | jfrijters <jfrijters> | 2010-09-09 10:55:31 +0400 |
commit | e57a3213625777da5740614fc86afb6cb4e9e23e (patch) | |
tree | d117f574bdbb2afc471339612187b8bcc5dd57bc /openjdk/java/net/net_util_md.java | |
parent | 0720c24a212c240d952a1d20f5595ed15f7fabf3 (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.java | 824 |
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); + } +} |