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 java.security.AccessController; 30 import java.security.PrivilegedAction; 31 import sun.security.action.GetPropertyAction; 32 import jdk.internal.misc.SharedSecrets; 33 import jdk.internal.misc.JavaIOFileDescriptorAccess; 34 35 /** 36 * This class defines the plain SocketImpl. 37 * When java.net.preferIPv4Stack system property is set to true, it uses 38 * IPv4-only socket. 39 * When java.net.preferIPv4Stack is set to false, it handles both IPv4 40 * and IPv6 through a single file descriptor. 41 * 42 * @author Chris Hegarty 43 */ 44 45 class DualStackPlainSocketImpl extends AbstractPlainSocketImpl { 46 47 private static final JavaIOFileDescriptorAccess fdAccess = 48 SharedSecrets.getJavaIOFileDescriptorAccess(); 49 50 private static final boolean preferIPv4Stack = 51 Boolean.parseBoolean(AccessController.doPrivileged( 52 new GetPropertyAction("java.net.preferIPv4Stack", "false"))); 53 54 private static final boolean useExclusiveBind = 55 Boolean.parseBoolean(AccessController.doPrivileged( 56 new GetPropertyAction("sun.net.useExclusiveBind", "true"))); 57 58 // emulates SO_REUSEADDR when useExclusiveBind is true 59 private boolean isReuseAddress; 60 61 public DualStackPlainSocketImpl() { 62 } 63 64 public DualStackPlainSocketImpl(FileDescriptor fd) { 65 this.fd = fd; 66 } 67 68 @Override 69 void socketCreate(boolean stream) throws IOException { 70 if (fd == null) 71 throw new SocketException("Socket closed"); 72 73 int newfd = socket0(stream); 74 75 fdAccess.set(fd, newfd); 76 } 77 78 @Override 79 void socketConnect(InetAddress address, int port, int timeout) 80 throws IOException { 81 int nativefd = checkAndReturnNativeFD(); 82 83 if (address == null) 84 throw new NullPointerException("inet address argument is null."); 85 86 if (preferIPv4Stack && !(address instanceof Inet4Address)) 87 throw new SocketException("Protocol family not supported"); 88 89 int connectResult; 90 if (timeout <= 0) { 91 connectResult = connect0(nativefd, address, port); 92 } else { 93 configureBlocking(nativefd, false); 94 try { 95 connectResult = connect0(nativefd, address, port); 96 if (connectResult == WOULDBLOCK) { 97 waitForConnect(nativefd, timeout); 98 } 99 } finally { 100 configureBlocking(nativefd, true); 101 } 102 } 103 /* 104 * We need to set the local port field. If bind was called 105 * previous to the connect (by the client) then localport field 106 * will already be set. 107 */ 108 if (localport == 0) 109 localport = localPort0(nativefd); 110 } 111 112 @Override 113 void socketBind(InetAddress address, int port) throws IOException { 114 int nativefd = checkAndReturnNativeFD(); 115 116 if (address == null) 117 throw new NullPointerException("inet address argument is null."); 118 119 if (preferIPv4Stack && !(address instanceof Inet4Address)) 120 throw new SocketException("Protocol family not supported"); 121 122 bind0(nativefd, address, port, useExclusiveBind); 123 if (port == 0) { 124 localport = localPort0(nativefd); 125 } else { 126 localport = port; 127 } 128 129 this.address = address; 130 } 131 132 @Override 133 void socketListen(int backlog) throws IOException { 134 int nativefd = checkAndReturnNativeFD(); 135 136 listen0(nativefd, backlog); 137 } 138 139 @Override 140 void socketAccept(SocketImpl s) throws IOException { 141 int nativefd = checkAndReturnNativeFD(); 142 143 if (s == null) 144 throw new NullPointerException("socket is null"); 145 146 int newfd = -1; 147 InetSocketAddress[] isaa = new InetSocketAddress[1]; 148 if (timeout <= 0) { 149 newfd = accept0(nativefd, isaa); 150 } else { 151 configureBlocking(nativefd, false); 152 try { 153 waitForNewConnection(nativefd, timeout); 154 newfd = accept0(nativefd, isaa); 155 if (newfd != -1) { 156 configureBlocking(newfd, true); 157 } 158 } finally { 159 configureBlocking(nativefd, true); 160 } 161 } 162 /* Update (SocketImpl)s' fd */ 163 fdAccess.set(s.fd, newfd); 164 /* Update socketImpls remote port, address and localport */ 165 InetSocketAddress isa = isaa[0]; 166 s.port = isa.getPort(); 167 s.address = isa.getAddress(); 168 s.localport = localport; 169 if (preferIPv4Stack && !(s.address instanceof Inet4Address)) 170 throw new SocketException("Protocol family not supported"); 171 } 172 173 @Override 174 int socketAvailable() throws IOException { 175 int nativefd = checkAndReturnNativeFD(); 176 return available0(nativefd); 177 } 178 179 @Override 180 void socketClose0(boolean useDeferredClose/*unused*/) throws IOException { 181 if (fd == null) 182 throw new SocketException("Socket closed"); 183 184 if (!fd.valid()) 185 return; 186 187 final int nativefd = fdAccess.get(fd); 188 fdAccess.set(fd, -1); 189 close0(nativefd); 190 } 191 192 @Override 193 void socketShutdown(int howto) throws IOException { 194 int nativefd = checkAndReturnNativeFD(); 195 shutdown0(nativefd, howto); 196 } 197 198 // Intentional fallthrough after SO_REUSEADDR 199 @SuppressWarnings("fallthrough") 200 @Override 201 void socketSetOption(int opt, boolean on, Object value) 202 throws SocketException { 203 204 // SO_REUSEPORT is not supported on Windows. 205 if (opt == SO_REUSEPORT) { 206 throw new UnsupportedOperationException("unsupported option"); 207 } 208 209 int nativefd = checkAndReturnNativeFD(); 210 211 if (opt == SO_TIMEOUT) { 212 if (preferIPv4Stack) { 213 // Don't enable the socket option on ServerSocket as it's 214 // meaningless (we don't receive on a ServerSocket). 215 if (serverSocket == null) { 216 setSoTimeout0(nativefd, ((Integer)value).intValue()); 217 } 218 } // else timeout is implemented through select. 219 return; 220 } 221 222 int optionValue = 0; 223 224 switch(opt) { 225 case SO_REUSEADDR: 226 if (useExclusiveBind) { 227 // SO_REUSEADDR emulated when using exclusive bind 228 isReuseAddress = on; 229 return; 230 } 231 // intentional fallthrough 232 case TCP_NODELAY: 233 case SO_OOBINLINE: 234 case SO_KEEPALIVE: 235 optionValue = on ? 1 : 0; 236 break; 237 case SO_SNDBUF: 238 case SO_RCVBUF: 239 case IP_TOS: 240 optionValue = ((Integer)value).intValue(); 241 break; 242 case SO_LINGER: 243 if (on) { 244 optionValue = ((Integer)value).intValue(); 245 } else { 246 optionValue = -1; 247 } 248 break; 249 default :/* shouldn't get here */ 250 throw new SocketException("Option not supported"); 251 } 252 253 setIntOption(nativefd, opt, optionValue); 254 } 255 256 @Override 257 int socketGetOption(int opt, Object iaContainerObj) 258 throws SocketException { 259 260 // SO_REUSEPORT is not supported on Windows. 261 if (opt == SO_REUSEPORT) { 262 throw new UnsupportedOperationException("unsupported option"); 263 } 264 265 int nativefd = checkAndReturnNativeFD(); 266 267 // SO_BINDADDR is not a socket option. 268 if (opt == SO_BINDADDR) { 269 localAddress(nativefd, (InetAddressContainer)iaContainerObj); 270 return 0; // return value doesn't matter. 271 } 272 273 // SO_REUSEADDR emulated when using exclusive bind 274 if (opt == SO_REUSEADDR && useExclusiveBind) 275 return isReuseAddress ? 1 : -1; 276 277 int value = getIntOption(nativefd, opt); 278 279 switch (opt) { 280 case TCP_NODELAY: 281 case SO_OOBINLINE: 282 case SO_KEEPALIVE: 283 case SO_REUSEADDR: 284 return (value == 0) ? -1 : 1; 285 } 286 return value; 287 } 288 289 @Override 290 void socketSendUrgentData(int data) throws IOException { 291 int nativefd = checkAndReturnNativeFD(); 292 sendOOB(nativefd, data); 293 } 294 295 private int checkAndReturnNativeFD() throws SocketException { 296 if (fd == null || !fd.valid()) 297 throw new SocketException("Socket closed"); 298 299 return fdAccess.get(fd); 300 } 301 302 static final int WOULDBLOCK = -2; // Nothing available (non-blocking) 303 304 static { 305 initIDs(); 306 } 307 308 /* Native methods */ 309 310 static native void initIDs(); 311 312 static native int socket0(boolean stream) throws IOException; 313 314 static native void bind0(int fd, InetAddress localAddress, int localport, 315 boolean exclBind) 316 throws IOException; 317 318 static native int connect0(int fd, InetAddress remote, int remotePort) 319 throws IOException; 320 321 static native void waitForConnect(int fd, int timeout) throws IOException; 322 323 static native int localPort0(int fd) throws IOException; 324 325 static native void localAddress(int fd, InetAddressContainer in) throws SocketException; 326 327 static native void listen0(int fd, int backlog) throws IOException; 328 329 static native int accept0(int fd, InetSocketAddress[] isaa) throws IOException; 330 331 static native void waitForNewConnection(int fd, int timeout) throws IOException; 332 333 static native int available0(int fd) throws IOException; 334 335 static native void close0(int fd) throws IOException; 336 337 static native void shutdown0(int fd, int howto) throws IOException; 338 339 static native void setIntOption(int fd, int cmd, int optionValue) throws SocketException; 340 341 static native void setSoTimeout0(int fd, int timeout) throws SocketException; 342 343 static native int getIntOption(int fd, int cmd) throws SocketException; 344 345 static native void sendOOB(int fd, int data) throws IOException; 346 347 static native void configureBlocking(int fd, boolean blocking) throws IOException; 348 }