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