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 initIDs(); 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 int nativefd = checkAndReturnNativeFD(); 68 69 if (address == null) 70 throw new NullPointerException("inet address argument is null."); 71 72 bind0(nativefd, address, port, exclusiveBind); 73 if (port == 0) { 74 localport = localPort0(nativefd); 75 } else { 76 localport = port; 77 } 78 79 this.address = address; 80 } 81 82 @Override 83 @SuppressWarnings("fallthrough") // Intentional fallthrough after SO_REUSEADDR 84 void socketSetOption(int opt, boolean on, Object value) 85 throws SocketException { 86 int nativefd = checkAndReturnNativeFD(); 87 88 if (opt == SO_TIMEOUT) { // timeout implemented through select. 89 return; 90 } 91 // SO_REUSEPORT is not supported on Windows. 92 if (opt == SO_REUSEPORT) { 93 throw new UnsupportedOperationException("unsupported option"); 94 } 95 96 int optionValue = 0; 97 98 switch(opt) { 99 case SO_REUSEADDR : 100 if (exclusiveBind) { 101 // SO_REUSEADDR emulated when using exclusive bind 102 isReuseAddress = on; 103 return; 104 } 105 // intentional fallthrough 106 case TCP_NODELAY : 107 case SO_OOBINLINE : 108 case SO_KEEPALIVE : 109 optionValue = on ? 1 : 0; 110 break; 111 case SO_SNDBUF : 112 case SO_RCVBUF : 113 case IP_TOS : 114 optionValue = ((Integer)value).intValue(); 115 break; 116 case SO_LINGER : 117 if (on) { 118 optionValue = ((Integer)value).intValue(); 119 } else { 120 optionValue = -1; 121 } 122 break; 123 default :/* shouldn't get here */ 124 throw new SocketException("Option not supported"); 125 } 126 127 setIntOption(nativefd, opt, optionValue); 128 } 129 130 static native void initIDs(); 131 132 void socketCreate(boolean stream) throws IOException { 133 if (fd == null) 134 throw new SocketException("Socket closed"); 135 136 int newfd = socket0(stream, false /*v6 Only*/); 137 138 fdAccess.set(fd, newfd); 139 } 140 static native int socket0(boolean stream, boolean v6Only) throws IOException; 141 142 void socketConnect(InetAddress address, int port, int timeout) 143 throws IOException { 144 int nativefd = checkAndReturnNativeFD(); 145 146 if (address == null) 147 throw new NullPointerException("inet address argument is null."); 148 149 int connectResult; 150 if (timeout <= 0) { 151 connectResult = connect0(nativefd, address, port); 152 } else { 153 configureBlocking(nativefd, false); 154 try { 155 connectResult = connect0(nativefd, address, port); 156 if (connectResult == WOULDBLOCK) { 157 waitForConnect(nativefd, timeout); 158 } 159 } finally { 160 configureBlocking(nativefd, true); 161 } 162 } 163 /* 164 * We need to set the local port field. If bind was called 165 * previous to the connect (by the client) then localport field 166 * will already be set. 167 */ 168 if (localport == 0) 169 localport = localPort0(nativefd); 170 } 171 static native int connect0(int fd, InetAddress remote, int remotePort) 172 throws IOException; 173 static native void waitForConnect(int fd, int timeout) throws IOException; 174 static native void configureBlocking(int fd, boolean blocking) throws IOException; 175 static native int localPort0(int fd) throws IOException; 176 177 178 static native void bind0(int fd, InetAddress localAddress, int localport, 179 boolean exclBind) 180 throws IOException; 181 182 183 void socketListen(int backlog) throws IOException { 184 int nativefd = checkAndReturnNativeFD(); 185 186 listen0(nativefd, backlog); 187 } 188 static native void listen0(int fd, int backlog) throws IOException; 189 190 void socketAccept(SocketImpl s) throws IOException { 191 int nativefd = checkAndReturnNativeFD(); 192 193 if (s == null) 194 throw new NullPointerException("socket is null"); 195 196 int newfd = -1; 197 InetSocketAddress[] isaa = new InetSocketAddress[1]; 198 if (timeout <= 0) { 199 newfd = accept0(nativefd, isaa); 200 } else { 201 configureBlocking(nativefd, false); 202 try { 203 waitForNewConnection(nativefd, timeout); 204 newfd = accept0(nativefd, isaa); 205 if (newfd != -1) { 206 configureBlocking(newfd, true); 207 } 208 } finally { 209 configureBlocking(nativefd, true); 210 } 211 } 212 /* Update (SocketImpl)s' fd */ 213 fdAccess.set(s.fd, newfd); 214 /* Update socketImpls remote port, address and localport */ 215 InetSocketAddress isa = isaa[0]; 216 s.port = isa.getPort(); 217 s.address = isa.getAddress(); 218 s.localport = localport; 219 } 220 static native int accept0(int fd, InetSocketAddress[] isaa) throws IOException; 221 static native void waitForNewConnection(int fd, int timeout) throws IOException; 222 223 224 int socketAvailable() throws IOException { 225 int nativefd = checkAndReturnNativeFD(); 226 return available0(nativefd); 227 } 228 static native int available0(int fd) throws IOException; 229 230 231 void socketClose0(boolean useDeferredClose/*unused*/) throws IOException { 232 if (fd == null) 233 throw new SocketException("Socket closed"); 234 235 if (!fd.valid()) 236 return; 237 238 final int nativefd = fdAccess.get(fd); 239 fdAccess.set(fd, -1); 240 close0(nativefd); 241 } 242 static native void close0(int fd) throws IOException; 243 244 245 void socketShutdown(int howto) throws IOException { 246 int nativefd = checkAndReturnNativeFD(); 247 shutdown0(nativefd, howto); 248 } 249 static native void shutdown0(int fd, int howto) throws IOException; 250 251 252 static native void setIntOption(int fd, int cmd, int optionValue) throws SocketException; 253 254 255 int socketGetOption(int opt, Object iaContainerObj) throws SocketException { 256 int nativefd = checkAndReturnNativeFD(); 257 258 // SO_BINDADDR is not a socket option. 259 if (opt == SO_BINDADDR) { 260 localAddress(nativefd, (InetAddressContainer)iaContainerObj); 261 return 0; // return value doesn't matter. 262 } 263 // SO_REUSEPORT is not supported on Windows. 264 if (opt == SO_REUSEPORT) { 265 throw new UnsupportedOperationException("unsupported option"); 266 } 267 268 // SO_REUSEADDR emulated when using exclusive bind 269 if (opt == SO_REUSEADDR && exclusiveBind) 270 return isReuseAddress? 1 : -1; 271 272 int value = getIntOption(nativefd, opt); 273 274 switch (opt) { 275 case TCP_NODELAY : 276 case SO_OOBINLINE : 277 case SO_KEEPALIVE : 278 case SO_REUSEADDR : 279 return (value == 0) ? -1 : 1; 280 } 281 return value; 282 } 283 static native int getIntOption(int fd, int cmd) throws SocketException; 284 static native void localAddress(int fd, InetAddressContainer in) throws SocketException; 285 286 287 void socketSendUrgentData(int data) throws IOException { 288 int nativefd = checkAndReturnNativeFD(); 289 sendOOB(nativefd, data); 290 } 291 static native void sendOOB(int fd, int data) throws IOException; 292 293 294 private int checkAndReturnNativeFD() throws SocketException { 295 if (fd == null || !fd.valid()) 296 throw new SocketException("Socket closed"); 297 298 return fdAccess.get(fd); 299 } 300 301 static final int WOULDBLOCK = -2; // Nothing available (non-blocking) 302 }