/* * Copyright (c) 2007, 2008, Oracle and/or its affiliates. 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. 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. */ package java.net; import java.io.IOException; import java.io.FileDescriptor; /** * This class defines the plain SocketImpl that is used on Windows platforms * greater or equal to Windows Vista. These platforms have a dual * layer TCP/IP stack and can handle both IPv4 and IPV6 through a * single file descriptor. * * @author Chris Hegarty */ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl { // true if this socket is exclusively bound private final boolean exclusiveBind; // emulates SO_REUSEADDR when exclusiveBind is true private boolean isReuseAddress; public DualStackPlainSocketImpl(boolean exclBind) { exclusiveBind = exclBind; } public DualStackPlainSocketImpl(FileDescriptor fd, boolean exclBind) { this.fd = fd; exclusiveBind = exclBind; } void socketCreate(boolean stream) throws IOException { if (fd == null) throw new SocketException("Socket closed"); cli.System.Net.Sockets.Socket newfd = socket0(stream, false /*v6 Only*/); fd.setSocket(newfd); } void socketConnect(InetAddress address, int port, int timeout) throws IOException { cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); if (address == null) throw new NullPointerException("inet address argument is null."); int connectResult; if (timeout <= 0) { connectResult = connect0(nativefd, address, port); } else { configureBlocking(nativefd, false); try { connectResult = connect0(nativefd, address, port); if (connectResult == WOULDBLOCK) { waitForConnect(nativefd, timeout); } } finally { configureBlocking(nativefd, true); } } /* * We need to set the local port field. If bind was called * previous to the connect (by the client) then localport field * will already be set. */ if (localport == 0) localport = localPort0(nativefd); } void socketBind(InetAddress address, int port) throws IOException { cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); if (address == null) throw new NullPointerException("inet address argument is null."); bind0(nativefd, address, port, exclusiveBind); if (port == 0) { localport = localPort0(nativefd); } else { localport = port; } this.address = address; } void socketListen(int backlog) throws IOException { cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); listen0(nativefd, backlog); } void socketAccept(SocketImpl s) throws IOException { cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); if (s == null) throw new NullPointerException("socket is null"); cli.System.Net.Sockets.Socket newfd = null; InetSocketAddress[] isaa = new InetSocketAddress[1]; if (timeout <= 0) { newfd = accept0(nativefd, isaa); } else { configureBlocking(nativefd, false); try { waitForNewConnection(nativefd, timeout); newfd = accept0(nativefd, isaa); if (newfd != null) { configureBlocking(newfd, true); } } finally { configureBlocking(nativefd, true); } } /* Update (SocketImpl)s' fd */ s.fd.setSocket(newfd); /* Update socketImpls remote port, address and localport */ InetSocketAddress isa = isaa[0]; s.port = isa.getPort(); s.address = isa.getAddress(); s.localport = localport; } int socketAvailable() throws IOException { cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); return available0(nativefd); } void socketClose0(boolean useDeferredClose/*unused*/) throws IOException { if (fd == null) throw new SocketException("Socket closed"); if (!fd.valid()) return; close0(fd.getSocket()); fd.setSocket(null); } void socketShutdown(int howto) throws IOException { cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); shutdown0(nativefd, howto); } // Intentional fallthrough after SO_REUSEADDR @SuppressWarnings("fallthrough") void socketSetOption(int opt, boolean on, Object value) throws SocketException { cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); if (opt == SO_TIMEOUT) { // timeout implemented through select. return; } int optionValue = 0; switch(opt) { case SO_REUSEADDR : if (exclusiveBind) { // SO_REUSEADDR emulated when using exclusive bind isReuseAddress = on; return; } // intentional fallthrough case TCP_NODELAY : case SO_OOBINLINE : case SO_KEEPALIVE : optionValue = on ? 1 : 0; break; case SO_SNDBUF : case SO_RCVBUF : case IP_TOS : optionValue = ((Integer)value).intValue(); break; case SO_LINGER : if (on) { optionValue = ((Integer)value).intValue(); } else { optionValue = -1; } break; default :/* shouldn't get here */ throw new SocketException("Option not supported"); } setIntOption(nativefd, opt, optionValue); } int socketGetOption(int opt, Object iaContainerObj) throws SocketException { cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); // SO_BINDADDR is not a socket option. if (opt == SO_BINDADDR) { localAddress(nativefd, (InetAddressContainer)iaContainerObj); return 0; // return value doesn't matter. } // SO_REUSEADDR emulated when using exclusive bind if (opt == SO_REUSEADDR && exclusiveBind) return isReuseAddress? 1 : -1; int value = getIntOption(nativefd, opt); switch (opt) { case TCP_NODELAY : case SO_OOBINLINE : case SO_KEEPALIVE : case SO_REUSEADDR : return (value == 0) ? -1 : 1; } return value; } void socketSendUrgentData(int data) throws IOException { cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD(); sendOOB(nativefd, data); } private cli.System.Net.Sockets.Socket checkAndReturnNativeFD() throws SocketException { if (fd == null || !fd.valid()) throw new SocketException("Socket closed"); return fd.getSocket(); } static final int WOULDBLOCK = -2; // Nothing available (non-blocking) /* Native methods */ static cli.System.Net.Sockets.Socket socket0(boolean stream, boolean v6Only) throws IOException { ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); cli.System.Net.Sockets.Socket ret = DualStackPlainSocketImpl_c.socket0(env, stream, v6Only); env.ThrowPendingException(); return ret; } static void bind0(cli.System.Net.Sockets.Socket fd, InetAddress localAddress, int localport, boolean exclBind) throws IOException { ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); DualStackPlainSocketImpl_c.bind0(env, fd, localAddress, localport, exclBind); env.ThrowPendingException(); } static int connect0(cli.System.Net.Sockets.Socket fd, InetAddress remote, int remotePort) throws IOException { ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); int ret = DualStackPlainSocketImpl_c.connect0(env, fd, remote, remotePort); env.ThrowPendingException(); return ret; } static void waitForConnect(cli.System.Net.Sockets.Socket fd, int timeout) throws IOException { ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); DualStackPlainSocketImpl_c.waitForConnect(env, fd, timeout); env.ThrowPendingException(); } static int localPort0(cli.System.Net.Sockets.Socket fd) throws IOException { ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); int ret = DualStackPlainSocketImpl_c.localPort0(env, fd); env.ThrowPendingException(); return ret; } static void localAddress(cli.System.Net.Sockets.Socket fd, InetAddressContainer in) throws SocketException { ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); DualStackPlainSocketImpl_c.localAddress(env, fd, in); env.ThrowPendingException(); } static void listen0(cli.System.Net.Sockets.Socket fd, int backlog) throws IOException { ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); DualStackPlainSocketImpl_c.listen0(env, fd, backlog); env.ThrowPendingException(); } static cli.System.Net.Sockets.Socket accept0(cli.System.Net.Sockets.Socket fd, InetSocketAddress[] isaa) throws IOException { ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); cli.System.Net.Sockets.Socket ret = DualStackPlainSocketImpl_c.accept0(env, fd, isaa); env.ThrowPendingException(); return ret; } static void waitForNewConnection(cli.System.Net.Sockets.Socket fd, int timeout) throws IOException { ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); DualStackPlainSocketImpl_c.waitForNewConnection(env, fd, timeout); env.ThrowPendingException(); } static int available0(cli.System.Net.Sockets.Socket fd) throws IOException { ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); int ret = DualStackPlainSocketImpl_c.available0(env, fd); env.ThrowPendingException(); return ret; } static void close0(cli.System.Net.Sockets.Socket fd) throws IOException { ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); DualStackPlainSocketImpl_c.close0(env, fd); env.ThrowPendingException(); } static void shutdown0(cli.System.Net.Sockets.Socket fd, int howto) throws IOException { ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); DualStackPlainSocketImpl_c.shutdown0(env, fd, howto); env.ThrowPendingException(); } static void setIntOption(cli.System.Net.Sockets.Socket fd, int cmd, int optionValue) throws SocketException { ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); DualStackPlainSocketImpl_c.setIntOption(env, fd, cmd, optionValue); env.ThrowPendingException(); } static int getIntOption(cli.System.Net.Sockets.Socket fd, int cmd) throws SocketException { ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); int ret = DualStackPlainSocketImpl_c.getIntOption(env, fd, cmd); env.ThrowPendingException(); return ret; } static void sendOOB(cli.System.Net.Sockets.Socket fd, int data) throws IOException { ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); DualStackPlainSocketImpl_c.sendOOB(env, fd, data); env.ThrowPendingException(); } static void configureBlocking(cli.System.Net.Sockets.Socket fd, boolean blocking) throws IOException { ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv(); DualStackPlainSocketImpl_c.configureBlocking(env, fd, blocking); env.ThrowPendingException(); } }