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