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