1 /*
   2  * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package java.net;
  26 
  27 import java.io.IOException;
  28 import java.io.FileDescriptor;
  29 import jdk.internal.misc.SharedSecrets;
  30 import jdk.internal.misc.JavaIOFileDescriptorAccess;
  31 
  32 /**
  33  * This class defines the plain SocketImpl that is used on Windows platforms
  34  * greater or equal to Windows Vista. These platforms have a dual
  35  * layer TCP/IP stack and can handle both IPv4 and IPV6 through a
  36  * single file descriptor.
  37  *
  38  * @author Chris Hegarty
  39  */
  40 
  41 class DualStackPlainSocketImpl extends AbstractPlainSocketImpl
  42 {
  43     static JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess();
  44 
  45 
  46     // true if this socket is exclusively bound
  47     private final boolean exclusiveBind;
  48 
  49     // emulates SO_REUSEADDR when exclusiveBind is true
  50     private boolean isReuseAddress;
  51 
  52     static {
  53         initProto();
  54     }
  55 
  56     public DualStackPlainSocketImpl(boolean exclBind) {
  57         exclusiveBind = exclBind;
  58     }
  59 
  60     public DualStackPlainSocketImpl(FileDescriptor fd, boolean exclBind) {
  61         this.fd = fd;
  62         exclusiveBind = exclBind;
  63     }
  64 
  65     @Override
  66     void socketBind(InetAddress address, int port) throws IOException {
  67         socketBind(address, port, exclusiveBind);
  68     }
  69 
  70     @Override
  71     void socketSetOption(int opt, boolean on, Object value)
  72         throws SocketException
  73     {
  74         if (opt == SO_REUSEADDR && exclusiveBind) {
  75             // SO_REUSEADDR emulated when using exclusive bind
  76             isReuseAddress = on;
  77         } else if (opt == SO_REUSEPORT) {
  78             // SO_REUSEPORT is not supported on Windows.
  79             throw new UnsupportedOperationException("unsupported option");
  80         } else {
  81             socketNativeSetOption(opt, on, value);
  82         }
  83     }
  84 
  85     @Override
  86     int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
  87         int nativefd = checkAndReturnNativeFD();
  88 
  89         // SO_BINDADDR is not a socket option.
  90         if (opt == SO_BINDADDR) {
  91             localAddress(nativefd, (InetAddressContainer)iaContainerObj);
  92             return 0;  // return value doesn't matter.
  93         }
  94         // SO_REUSEPORT is not supported on Windows.
  95         if (opt == SO_REUSEPORT) {
  96             throw new UnsupportedOperationException("unsupported option");
  97         }
  98 
  99         // SO_REUSEADDR emulated when using exclusive bind
 100         if (opt == SO_REUSEADDR && exclusiveBind)
 101             return isReuseAddress? 1 : -1;
 102 
 103         int value = getIntOption(nativefd, opt);
 104 
 105         switch (opt) {
 106             case TCP_NODELAY :
 107             case SO_OOBINLINE :
 108             case SO_KEEPALIVE :
 109             case SO_REUSEADDR :
 110                 return (value == 0) ? -1 : 1;
 111         }
 112         return value;
 113     }
 114 
 115     /* Native methods */
 116 
 117     static native void initProto();
 118 
 119     native void socketCreate(boolean stream) throws IOException;
 120 
 121     native void socketConnect(InetAddress address, int port, int timeout)
 122         throws IOException;
 123 
 124     native void socketBind(InetAddress address, int port, boolean exclBind)
 125         throws IOException;
 126 
 127     native void socketListen(int count) throws IOException;
 128 
 129     native void socketAccept(SocketImpl s) throws IOException;
 130 
 131     native int socketAvailable() throws IOException;
 132 
 133     native void socketClose0(boolean useDeferredClose) throws IOException;
 134 
 135     native void socketShutdown(int howto) throws IOException;
 136 
 137     static native int getIntOption(int fd, int cmd) throws SocketException;
 138     static native void localAddress(int fd, InetAddressContainer in) throws SocketException;
 139 
 140     native void socketNativeSetOption(int cmd, boolean on, Object value)
 141         throws SocketException;
 142 
 143     native int socketNativeGetOption(int opt, Object iaContainerObj)
 144         throws SocketException;
 145 
 146     native void socketSendUrgentData(int data) throws IOException;
 147 
 148     private int checkAndReturnNativeFD() throws SocketException {
 149         if (fd == null || !fd.valid())
 150             throw new SocketException("Socket closed");
 151 
 152         return fdAccess.get(fd);
 153     }
 154 }