mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
8220493: Prepare Socket/ServerSocket for alternative platform SocketImpl
Co-authored-by: Michael McMahon <michael.x.mcmahon@oracle.com> Reviewed-by: chegar
This commit is contained in:
parent
c306e3f059
commit
8743be63c4
12 changed files with 1525 additions and 188 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -30,12 +30,16 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import sun.net.ConnectionResetException;
|
||||
import sun.net.NetHooks;
|
||||
import sun.net.PlatformSocketImpl;
|
||||
import sun.net.ResourceManager;
|
||||
import sun.net.util.SocketExceptions;
|
||||
|
||||
|
@ -46,7 +50,7 @@ import sun.net.util.SocketExceptions;
|
|||
*
|
||||
* @author Steven B. Byrne
|
||||
*/
|
||||
abstract class AbstractPlainSocketImpl extends SocketImpl {
|
||||
abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSocketImpl {
|
||||
/* instance variable for SO_TIMEOUT */
|
||||
int timeout; // timeout in millisec
|
||||
// traffic class
|
||||
|
@ -450,15 +454,17 @@ abstract class AbstractPlainSocketImpl extends SocketImpl {
|
|||
|
||||
/**
|
||||
* Accepts connections.
|
||||
* @param s the connection
|
||||
* @param si the socket impl
|
||||
*/
|
||||
protected void accept(SocketImpl s) throws IOException {
|
||||
protected void accept(SocketImpl si) throws IOException {
|
||||
si.fd = new FileDescriptor();
|
||||
acquireFD();
|
||||
try {
|
||||
socketAccept(s);
|
||||
socketAccept(si);
|
||||
} finally {
|
||||
releaseFD();
|
||||
}
|
||||
SocketCleanable.register(si.fd);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -470,8 +476,14 @@ abstract class AbstractPlainSocketImpl extends SocketImpl {
|
|||
throw new IOException("Socket Closed");
|
||||
if (shut_rd)
|
||||
throw new IOException("Socket input is shutdown");
|
||||
if (socketInputStream == null)
|
||||
socketInputStream = new SocketInputStream(this);
|
||||
if (socketInputStream == null) {
|
||||
PrivilegedExceptionAction<SocketInputStream> pa = () -> new SocketInputStream(this);
|
||||
try {
|
||||
socketInputStream = AccessController.doPrivileged(pa);
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw (IOException) e.getCause();
|
||||
}
|
||||
}
|
||||
}
|
||||
return socketInputStream;
|
||||
}
|
||||
|
@ -489,8 +501,14 @@ abstract class AbstractPlainSocketImpl extends SocketImpl {
|
|||
throw new IOException("Socket Closed");
|
||||
if (shut_wr)
|
||||
throw new IOException("Socket output is shutdown");
|
||||
if (socketOutputStream == null)
|
||||
socketOutputStream = new SocketOutputStream(this);
|
||||
if (socketOutputStream == null) {
|
||||
PrivilegedExceptionAction<SocketOutputStream> pa = () -> new SocketOutputStream(this);
|
||||
try {
|
||||
socketOutputStream = AccessController.doPrivileged(pa);
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw (IOException) e.getCause();
|
||||
}
|
||||
}
|
||||
}
|
||||
return socketOutputStream;
|
||||
}
|
||||
|
@ -589,15 +607,10 @@ abstract class AbstractPlainSocketImpl extends SocketImpl {
|
|||
}
|
||||
}
|
||||
|
||||
void reset() throws IOException {
|
||||
if (fd != null) {
|
||||
socketClose();
|
||||
}
|
||||
fd = null;
|
||||
super.reset();
|
||||
void reset() {
|
||||
throw new InternalError("should not get here");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shutdown read-half of the socket connection;
|
||||
*/
|
||||
|
|
171
src/java.base/share/classes/java/net/DelegatingSocketImpl.java
Normal file
171
src/java.base/share/classes/java/net/DelegatingSocketImpl.java
Normal file
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.net;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import sun.net.PlatformSocketImpl;
|
||||
|
||||
/**
|
||||
* A SocketImpl that delegates all methods to another SocketImpl.
|
||||
*/
|
||||
|
||||
class DelegatingSocketImpl extends SocketImpl {
|
||||
protected final SocketImpl delegate;
|
||||
|
||||
DelegatingSocketImpl(SocketImpl delegate) {
|
||||
assert delegate instanceof PlatformSocketImpl;
|
||||
this.delegate = Objects.requireNonNull(delegate);
|
||||
}
|
||||
|
||||
final SocketImpl delegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FileDescriptor getFileDescriptor() {
|
||||
return delegate.getFileDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InetAddress getInetAddress() {
|
||||
return delegate.getInetAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPort() {
|
||||
return delegate.getPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getLocalPort() {
|
||||
return delegate.getLocalPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void create(boolean stream) throws IOException {
|
||||
delegate.create(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void connect(String host, int port) throws IOException {
|
||||
delegate.connect(host, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void connect(InetAddress address, int port) throws IOException {
|
||||
delegate.connect(address, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void connect(SocketAddress address, int timeout) throws IOException {
|
||||
delegate.connect(address, timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bind(InetAddress host, int port) throws IOException {
|
||||
delegate.bind(host, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void listen(int backlog) throws IOException {
|
||||
delegate.listen(backlog);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void accept(SocketImpl s) throws IOException {
|
||||
delegate.accept(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InputStream getInputStream() throws IOException {
|
||||
return delegate.getInputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OutputStream getOutputStream() throws IOException {
|
||||
return delegate.getOutputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int available() throws IOException {
|
||||
return delegate.available();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void close() throws IOException {
|
||||
delegate.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsUrgentData() {
|
||||
return delegate.supportsUrgentData();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendUrgentData(int data) throws IOException {
|
||||
delegate.sendUrgentData(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<SocketOption<?>> supportedOptions() {
|
||||
return delegate.supportedOptions();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> void setOption(SocketOption<T> opt, T value) throws IOException {
|
||||
delegate.setOption(opt, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> T getOption(SocketOption<T> opt) throws IOException {
|
||||
return delegate.getOption(opt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOption(int optID, Object value) throws SocketException {
|
||||
delegate.setOption(optID, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOption(int optID) throws SocketException {
|
||||
return delegate.getOption(optID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutdownInput() throws IOException {
|
||||
delegate.shutdownInput();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutdownOutput() throws IOException {
|
||||
delegate.shutdownOutput();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -34,14 +34,13 @@ import java.util.Set;
|
|||
|
||||
/**
|
||||
* Basic SocketImpl that relies on the internal HTTP protocol handler
|
||||
* implementation to perform the HTTP tunneling and authentication. The
|
||||
* sockets impl is swapped out and replaced with the socket from the HTTP
|
||||
* handler after the tunnel is successfully setup.
|
||||
* implementation to perform the HTTP tunneling and authentication. Once
|
||||
* connected, all socket operations delegate to a platform SocketImpl.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
|
||||
/*package*/ class HttpConnectSocketImpl extends PlainSocketImpl {
|
||||
/*package*/ class HttpConnectSocketImpl extends DelegatingSocketImpl {
|
||||
|
||||
private static final String httpURLClazzStr =
|
||||
"sun.net.www.protocol.http.HttpURLConnection";
|
||||
|
@ -76,12 +75,8 @@ import java.util.Set;
|
|||
}
|
||||
}
|
||||
|
||||
HttpConnectSocketImpl(String server, int port) {
|
||||
this.server = server;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
HttpConnectSocketImpl(Proxy proxy) {
|
||||
HttpConnectSocketImpl(Proxy proxy, SocketImpl delegate) {
|
||||
super(delegate);
|
||||
SocketAddress a = proxy.address();
|
||||
if ( !(a instanceof InetSocketAddress) )
|
||||
throw new IllegalArgumentException("Unsupported address type");
|
||||
|
@ -91,6 +86,27 @@ import java.util.Set;
|
|||
port = ad.getPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void connect(String host, int port) throws IOException {
|
||||
connect(new InetSocketAddress(host, port), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void connect(InetAddress address, int port) throws IOException {
|
||||
connect(new InetSocketAddress(address, port), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
void setSocket(Socket socket) {
|
||||
delegate.socket = socket;
|
||||
super.setSocket(socket);
|
||||
}
|
||||
|
||||
@Override
|
||||
void setServerSocket(ServerSocket socket) {
|
||||
throw new InternalError("should not get here");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void connect(SocketAddress endpoint, int timeout)
|
||||
throws IOException
|
||||
|
@ -117,21 +133,37 @@ import java.util.Set;
|
|||
close();
|
||||
|
||||
// update the Sockets impl to the impl from the http Socket
|
||||
AbstractPlainSocketImpl psi = (AbstractPlainSocketImpl) httpSocket.impl;
|
||||
this.getSocket().impl = psi;
|
||||
SocketImpl si = httpSocket.impl;
|
||||
getSocket().setImpl(si);
|
||||
|
||||
// best effort is made to try and reset options previously set
|
||||
Set<Map.Entry<Integer,Object>> options = optionsMap.entrySet();
|
||||
try {
|
||||
for(Map.Entry<Integer,Object> entry : options) {
|
||||
psi.setOption(entry.getKey(), entry.getValue());
|
||||
si.setOption(entry.getKey(), entry.getValue());
|
||||
}
|
||||
} catch (IOException x) { /* gulp! */ }
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void listen(int backlog) {
|
||||
throw new InternalError("should not get here");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void accept(SocketImpl s) {
|
||||
throw new InternalError("should not get here");
|
||||
}
|
||||
|
||||
@Override
|
||||
void reset() {
|
||||
throw new InternalError("should not get here");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOption(int opt, Object val) throws SocketException {
|
||||
super.setOption(opt, val);
|
||||
delegate.setOption(opt, val);
|
||||
|
||||
if (external_address != null)
|
||||
return; // we're connected, just return
|
||||
|
@ -163,7 +195,10 @@ import java.util.Set;
|
|||
URL destURL = new URL(urlString);
|
||||
HttpURLConnection conn = (HttpURLConnection) destURL.openConnection(proxy);
|
||||
conn.setConnectTimeout(connectTimeout);
|
||||
conn.setReadTimeout(this.timeout);
|
||||
int timeout = (int) getOption(SocketOptions.SO_TIMEOUT);
|
||||
if (timeout > 0) {
|
||||
conn.setReadTimeout(timeout);
|
||||
}
|
||||
conn.connect();
|
||||
doTunneling(conn);
|
||||
try {
|
||||
|
@ -174,10 +209,14 @@ import java.util.Set;
|
|||
}
|
||||
}
|
||||
|
||||
private void doTunneling(HttpURLConnection conn) {
|
||||
private void doTunneling(HttpURLConnection conn) throws IOException {
|
||||
try {
|
||||
doTunneling.invoke(conn);
|
||||
} catch (ReflectiveOperationException x) {
|
||||
Throwable cause = x.getCause();
|
||||
if (cause instanceof IOException) {
|
||||
throw (IOException) cause;
|
||||
}
|
||||
throw new InternalError("Should not reach here", x);
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +226,7 @@ import java.util.Set;
|
|||
if (external_address != null)
|
||||
return external_address.getAddress();
|
||||
else
|
||||
return super.getInetAddress();
|
||||
return delegate.getInetAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -195,6 +234,6 @@ import java.util.Set;
|
|||
if (external_address != null)
|
||||
return external_address.getPort();
|
||||
else
|
||||
return super.getPort();
|
||||
return delegate.getPort();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -25,9 +25,6 @@
|
|||
|
||||
package java.net;
|
||||
|
||||
import jdk.internal.access.JavaNetSocketAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
@ -38,6 +35,10 @@ import java.security.PrivilegedExceptionAction;
|
|||
import java.util.Set;
|
||||
import java.util.Collections;
|
||||
|
||||
import jdk.internal.access.JavaNetSocketAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import sun.net.PlatformSocketImpl;
|
||||
|
||||
/**
|
||||
* This class implements server sockets. A server socket waits for
|
||||
* requests to come in over the network. It performs some operation
|
||||
|
@ -290,13 +291,12 @@ class ServerSocket implements java.io.Closeable {
|
|||
}
|
||||
|
||||
private void setImpl() {
|
||||
SocketImplFactory factory = ServerSocket.factory;
|
||||
if (factory != null) {
|
||||
impl = factory.createSocketImpl();
|
||||
checkOldImpl();
|
||||
} else {
|
||||
// No need to do a checkOldImpl() here, we know it's an up to date
|
||||
// SocketImpl!
|
||||
impl = new SocksSocketImpl();
|
||||
impl = SocketImpl.createPlatformSocketImpl(true);
|
||||
}
|
||||
if (impl != null)
|
||||
impl.setServerSocket(this);
|
||||
|
@ -542,38 +542,134 @@ class ServerSocket implements java.io.Closeable {
|
|||
* @spec JSR-51
|
||||
*/
|
||||
protected final void implAccept(Socket s) throws IOException {
|
||||
SocketImpl si = null;
|
||||
try {
|
||||
if (s.impl == null)
|
||||
s.setImpl();
|
||||
else {
|
||||
s.impl.reset();
|
||||
}
|
||||
si = s.impl;
|
||||
s.impl = null;
|
||||
si.address = new InetAddress();
|
||||
si.fd = new FileDescriptor();
|
||||
getImpl().accept(si);
|
||||
SocketCleanable.register(si.fd); // raw fd has been set
|
||||
SocketImpl si = s.impl;
|
||||
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
if (security != null) {
|
||||
security.checkAccept(si.getInetAddress().getHostAddress(),
|
||||
si.getPort());
|
||||
// Socket has no SocketImpl
|
||||
if (si == null) {
|
||||
si = implAccept();
|
||||
s.setImpl(si);
|
||||
s.postAccept();
|
||||
return;
|
||||
}
|
||||
|
||||
// Socket has a SOCKS or HTTP SocketImpl, need delegate
|
||||
if (si instanceof DelegatingSocketImpl) {
|
||||
si = ((DelegatingSocketImpl) si).delegate();
|
||||
assert si instanceof PlatformSocketImpl;
|
||||
}
|
||||
|
||||
// Accept connection with a platform or custom SocketImpl.
|
||||
// For the platform SocketImpl case:
|
||||
// - the connection is accepted with a new SocketImpl
|
||||
// - the SO_TIMEOUT socket option is copied to the new SocketImpl
|
||||
// - the Socket is connected to the new SocketImpl
|
||||
// - the existing/old SocketImpl is closed
|
||||
// For the custom SocketImpl case, the connection is accepted with the
|
||||
// existing custom SocketImpl.
|
||||
ensureCompatible(si);
|
||||
if (impl instanceof PlatformSocketImpl) {
|
||||
SocketImpl psi = platformImplAccept();
|
||||
si.copyOptionsTo(psi);
|
||||
s.setImpl(psi);
|
||||
si.closeQuietly();
|
||||
} else {
|
||||
s.impl = null; // temporarily break connection to impl
|
||||
try {
|
||||
customImplAccept(si);
|
||||
} finally {
|
||||
s.impl = si; // restore connection to impl
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (si != null)
|
||||
si.reset();
|
||||
s.impl = si;
|
||||
throw e;
|
||||
} catch (SecurityException e) {
|
||||
if (si != null)
|
||||
si.reset();
|
||||
s.impl = si;
|
||||
}
|
||||
s.postAccept();
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a connection with a new SocketImpl.
|
||||
* @return the new SocketImpl
|
||||
*/
|
||||
private SocketImpl implAccept() throws IOException {
|
||||
if (impl instanceof PlatformSocketImpl) {
|
||||
return platformImplAccept();
|
||||
} else {
|
||||
// custom server SocketImpl, client SocketImplFactory must be set
|
||||
SocketImplFactory factory = Socket.socketImplFactory();
|
||||
if (factory == null) {
|
||||
throw new IOException("An instance of " + impl.getClass() +
|
||||
" cannot accept connection with 'null' SocketImpl:" +
|
||||
" client socket implementation factory not set");
|
||||
}
|
||||
SocketImpl si = factory.createSocketImpl();
|
||||
customImplAccept(si);
|
||||
return si;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a connection with a new platform SocketImpl.
|
||||
* @return the new platform SocketImpl
|
||||
*/
|
||||
private SocketImpl platformImplAccept() throws IOException {
|
||||
assert impl instanceof PlatformSocketImpl;
|
||||
|
||||
// create a new platform SocketImpl and accept the connection
|
||||
SocketImpl psi = SocketImpl.createPlatformSocketImpl(false);
|
||||
implAccept(psi);
|
||||
return psi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a new connection with the given custom SocketImpl.
|
||||
*/
|
||||
private void customImplAccept(SocketImpl si) throws IOException {
|
||||
assert !(impl instanceof PlatformSocketImpl)
|
||||
&& !(si instanceof PlatformSocketImpl);
|
||||
|
||||
si.reset();
|
||||
try {
|
||||
// custom SocketImpl may expect fd/address objects to be created
|
||||
si.fd = new FileDescriptor();
|
||||
si.address = new InetAddress();
|
||||
implAccept(si);
|
||||
} catch (Exception e) {
|
||||
si.reset();
|
||||
throw e;
|
||||
}
|
||||
s.impl = si;
|
||||
s.postAccept();
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a new connection so that the given SocketImpl is connected to
|
||||
* the peer. The SocketImpl and connection are closed if the connection is
|
||||
* denied by the security manager.
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws SecurityException if the security manager's checkAccept method fails
|
||||
*/
|
||||
private void implAccept(SocketImpl si) throws IOException {
|
||||
assert !(si instanceof DelegatingSocketImpl);
|
||||
|
||||
// accept a connection
|
||||
impl.accept(si);
|
||||
|
||||
// check permission, close SocketImpl/connection if denied
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
try {
|
||||
sm.checkAccept(si.getInetAddress().getHostAddress(), si.getPort());
|
||||
} catch (SecurityException se) {
|
||||
si.close();
|
||||
throw se;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws IOException if the server SocketImpl and the given client
|
||||
* SocketImpl are not both platform or custom SocketImpls.
|
||||
*/
|
||||
private void ensureCompatible(SocketImpl si) throws IOException {
|
||||
if ((impl instanceof PlatformSocketImpl) != (si instanceof PlatformSocketImpl)) {
|
||||
throw new IOException("An instance of " + impl.getClass() +
|
||||
" cannot accept a connection with an instance of " + si.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -778,7 +874,7 @@ class ServerSocket implements java.io.Closeable {
|
|||
/**
|
||||
* The factory for all server sockets.
|
||||
*/
|
||||
private static SocketImplFactory factory = null;
|
||||
private static volatile SocketImplFactory factory;
|
||||
|
||||
/**
|
||||
* Sets the server socket implementation factory for the
|
||||
|
|
|
@ -28,9 +28,10 @@ package java.net;
|
|||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Set;
|
||||
import java.util.Collections;
|
||||
|
@ -75,6 +76,22 @@ class Socket implements java.io.Closeable {
|
|||
*/
|
||||
private boolean oldImpl = false;
|
||||
|
||||
/**
|
||||
* Socket input/output streams
|
||||
*/
|
||||
private volatile InputStream in;
|
||||
private volatile OutputStream out;
|
||||
private static final VarHandle IN, OUT;
|
||||
static {
|
||||
try {
|
||||
MethodHandles.Lookup l = MethodHandles.lookup();
|
||||
IN = l.findVarHandle(Socket.class, "in", InputStream.class);
|
||||
OUT = l.findVarHandle(Socket.class, "out", OutputStream.class);
|
||||
} catch (Exception e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unconnected socket, with the
|
||||
* system-default type of SocketImpl.
|
||||
|
@ -137,16 +154,22 @@ class Socket implements java.io.Closeable {
|
|||
security.checkConnect(epoint.getAddress().getHostAddress(),
|
||||
epoint.getPort());
|
||||
}
|
||||
impl = type == Proxy.Type.SOCKS ? new SocksSocketImpl(p)
|
||||
: new HttpConnectSocketImpl(p);
|
||||
|
||||
// create a SOCKS or HTTP SocketImpl that delegates to a platform SocketImpl
|
||||
SocketImpl delegate = SocketImpl.createPlatformSocketImpl(false);
|
||||
impl = (type == Proxy.Type.SOCKS) ? new SocksSocketImpl(p, delegate)
|
||||
: new HttpConnectSocketImpl(p, delegate);
|
||||
impl.setSocket(this);
|
||||
} else {
|
||||
if (p == Proxy.NO_PROXY) {
|
||||
// create a platform or custom SocketImpl for the DIRECT case
|
||||
SocketImplFactory factory = Socket.factory;
|
||||
if (factory == null) {
|
||||
impl = new PlainSocketImpl();
|
||||
impl.setSocket(this);
|
||||
} else
|
||||
setImpl();
|
||||
impl = SocketImpl.createPlatformSocketImpl(false);
|
||||
} else {
|
||||
impl = factory.createSocketImpl();
|
||||
}
|
||||
impl.setSocket(this);
|
||||
} else
|
||||
throw new IllegalArgumentException("Invalid Proxy");
|
||||
}
|
||||
|
@ -491,24 +514,29 @@ class Socket implements java.io.Closeable {
|
|||
});
|
||||
}
|
||||
|
||||
void setImpl(SocketImpl si) {
|
||||
impl = si;
|
||||
impl.setSocket(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets impl to the system-default type of SocketImpl.
|
||||
* @since 1.4
|
||||
*/
|
||||
void setImpl() {
|
||||
SocketImplFactory factory = Socket.factory;
|
||||
if (factory != null) {
|
||||
impl = factory.createSocketImpl();
|
||||
checkOldImpl();
|
||||
} else {
|
||||
// No need to do a checkOldImpl() here, we know it's an up to date
|
||||
// SocketImpl!
|
||||
impl = new SocksSocketImpl();
|
||||
// create a SOCKS SocketImpl that delegates to a platform SocketImpl
|
||||
SocketImpl delegate = SocketImpl.createPlatformSocketImpl(false);
|
||||
impl = new SocksSocketImpl(delegate);
|
||||
}
|
||||
if (impl != null)
|
||||
impl.setSocket(this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the {@code SocketImpl} attached to this socket, creating
|
||||
* it if necessary.
|
||||
|
@ -907,18 +935,49 @@ class Socket implements java.io.Closeable {
|
|||
throw new SocketException("Socket is not connected");
|
||||
if (isInputShutdown())
|
||||
throw new SocketException("Socket input is shutdown");
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<>() {
|
||||
public InputStream run() throws IOException {
|
||||
return impl.getInputStream();
|
||||
}
|
||||
});
|
||||
} catch (java.security.PrivilegedActionException e) {
|
||||
throw (IOException) e.getException();
|
||||
InputStream in = this.in;
|
||||
if (in == null) {
|
||||
// wrap the input stream so that the close method closes this socket
|
||||
in = new SocketInputStream(this, impl.getInputStream());
|
||||
if (!IN.compareAndSet(this, null, in)) {
|
||||
in = this.in;
|
||||
}
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
/**
|
||||
* An InputStream that delegates read/available operations to an underlying
|
||||
* input stream. The close method is overridden to close the Socket.
|
||||
*
|
||||
* This class is instrumented by Java Flight Recorder (JFR) to get socket
|
||||
* I/O events.
|
||||
*/
|
||||
private static class SocketInputStream extends InputStream {
|
||||
private final Socket parent;
|
||||
private final InputStream in;
|
||||
SocketInputStream(Socket parent, InputStream in) {
|
||||
this.parent = parent;
|
||||
this.in = in;
|
||||
}
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
byte[] a = new byte[1];
|
||||
int n = read(a, 0, 1);
|
||||
return (n > 0) ? (a[0] & 0xff) : -1;
|
||||
}
|
||||
@Override
|
||||
public int read(byte b[], int off, int len) throws IOException {
|
||||
return in.read(b, off, len);
|
||||
}
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return in.available();
|
||||
}
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
parent.close();
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -946,18 +1005,44 @@ class Socket implements java.io.Closeable {
|
|||
throw new SocketException("Socket is not connected");
|
||||
if (isOutputShutdown())
|
||||
throw new SocketException("Socket output is shutdown");
|
||||
OutputStream os = null;
|
||||
try {
|
||||
os = AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<>() {
|
||||
public OutputStream run() throws IOException {
|
||||
return impl.getOutputStream();
|
||||
}
|
||||
});
|
||||
} catch (java.security.PrivilegedActionException e) {
|
||||
throw (IOException) e.getException();
|
||||
OutputStream out = this.out;
|
||||
if (out == null) {
|
||||
// wrap the output stream so that the close method closes this socket
|
||||
out = new SocketOutputStream(this, impl.getOutputStream());
|
||||
if (!OUT.compareAndSet(this, null, out)) {
|
||||
out = this.out;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* An OutputStream that delegates write operations to an underlying output
|
||||
* stream. The close method is overridden to close the Socket.
|
||||
*
|
||||
* This class is instrumented by Java Flight Recorder (JFR) to get socket
|
||||
* I/O events.
|
||||
*/
|
||||
private static class SocketOutputStream extends OutputStream {
|
||||
private final Socket parent;
|
||||
private final OutputStream out;
|
||||
SocketOutputStream(Socket parent, OutputStream out) {
|
||||
this.parent = parent;
|
||||
this.out = out;
|
||||
}
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
byte[] a = new byte[] { (byte) b };
|
||||
write(a, 0, 1);
|
||||
}
|
||||
@Override
|
||||
public void write(byte b[], int off, int len) throws IOException {
|
||||
out.write(b, off, len);
|
||||
}
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
parent.close();
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1644,7 +1729,11 @@ class Socket implements java.io.Closeable {
|
|||
/**
|
||||
* The factory for all client sockets.
|
||||
*/
|
||||
private static SocketImplFactory factory = null;
|
||||
private static volatile SocketImplFactory factory;
|
||||
|
||||
static SocketImplFactory socketImplFactory() {
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the client socket implementation factory for the
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -31,6 +31,8 @@ import java.io.OutputStream;
|
|||
import java.io.FileDescriptor;
|
||||
import java.util.Set;
|
||||
|
||||
import sun.net.PlatformSocketImpl;
|
||||
|
||||
/**
|
||||
* The abstract class {@code SocketImpl} is a common superclass
|
||||
* of all classes that actually implement sockets. It is used to
|
||||
|
@ -43,6 +45,15 @@ import java.util.Set;
|
|||
* @since 1.0
|
||||
*/
|
||||
public abstract class SocketImpl implements SocketOptions {
|
||||
|
||||
/**
|
||||
* Creates an instance of platform's SocketImpl
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static <S extends SocketImpl & PlatformSocketImpl> S createPlatformSocketImpl(boolean server) {
|
||||
return (S) new PlainSocketImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual Socket object.
|
||||
*/
|
||||
|
@ -177,6 +188,15 @@ public abstract class SocketImpl implements SocketOptions {
|
|||
*/
|
||||
protected abstract void close() throws IOException;
|
||||
|
||||
/**
|
||||
* Closes this socket, ignoring any IOException that is thrown by close.
|
||||
*/
|
||||
void closeQuietly() {
|
||||
try {
|
||||
close();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* Places the input stream for this socket at "end of stream".
|
||||
* Any data sent to this socket is acknowledged and then
|
||||
|
@ -306,7 +326,8 @@ public abstract class SocketImpl implements SocketOptions {
|
|||
",port=" + getPort() + ",localport=" + getLocalPort() + "]";
|
||||
}
|
||||
|
||||
void reset() throws IOException {
|
||||
void reset() {
|
||||
fd = null;
|
||||
address = null;
|
||||
port = 0;
|
||||
localport = 0;
|
||||
|
@ -443,6 +464,19 @@ public abstract class SocketImpl implements SocketOptions {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to copy socket options from this SocketImpl to a target SocketImpl.
|
||||
* At this time, only the SO_TIMEOUT make sense to copy.
|
||||
*/
|
||||
void copyOptionsTo(SocketImpl target) {
|
||||
try {
|
||||
Object timeout = getOption(SocketOptions.SO_TIMEOUT);
|
||||
if (timeout instanceof Integer) {
|
||||
target.setOption(SocketOptions.SO_TIMEOUT, timeout);
|
||||
}
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
|
||||
private static final Set<SocketOption<?>> socketOptions;
|
||||
|
||||
private static final Set<SocketOption<?>> serverSocketOptions;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -23,6 +23,7 @@
|
|||
* questions.
|
||||
*/
|
||||
package java.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
@ -36,11 +37,9 @@ import sun.net.www.ParseUtil;
|
|||
|
||||
/**
|
||||
* SOCKS (V4 & V5) TCP socket implementation (RFC 1928).
|
||||
* This is a subclass of PlainSocketImpl.
|
||||
* Note this class should <b>NOT</b> be public.
|
||||
*/
|
||||
|
||||
class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
||||
class SocksSocketImpl extends DelegatingSocketImpl implements SocksConsts {
|
||||
private String server = null;
|
||||
private int serverPort = DEFAULT_PORT;
|
||||
private InetSocketAddress external_address;
|
||||
|
@ -49,11 +48,12 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
|||
private InputStream cmdIn = null;
|
||||
private OutputStream cmdOut = null;
|
||||
|
||||
SocksSocketImpl() {
|
||||
// Nothing needed
|
||||
SocksSocketImpl(SocketImpl delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
SocksSocketImpl(Proxy proxy) {
|
||||
SocksSocketImpl(Proxy proxy, SocketImpl delegate) {
|
||||
super(delegate);
|
||||
SocketAddress a = proxy.address();
|
||||
if (a instanceof InetSocketAddress) {
|
||||
InetSocketAddress ad = (InetSocketAddress) a;
|
||||
|
@ -75,7 +75,7 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
|||
private synchronized void privilegedConnect(final String host,
|
||||
final int port,
|
||||
final int timeout)
|
||||
throws IOException
|
||||
throws IOException
|
||||
{
|
||||
try {
|
||||
AccessController.doPrivileged(
|
||||
|
@ -94,7 +94,7 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
|||
|
||||
private void superConnectServer(String host, int port,
|
||||
int timeout) throws IOException {
|
||||
super.connect(new InetSocketAddress(host, port), timeout);
|
||||
delegate.connect(new InetSocketAddress(host, port), timeout);
|
||||
}
|
||||
|
||||
private static int remainingMillis(long deadlineMillis) throws IOException {
|
||||
|
@ -111,16 +111,23 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
|||
private int readSocksReply(InputStream in, byte[] data, long deadlineMillis) throws IOException {
|
||||
int len = data.length;
|
||||
int received = 0;
|
||||
while (received < len) {
|
||||
int count;
|
||||
try {
|
||||
count = ((SocketInputStream)in).read(data, received, len - received, remainingMillis(deadlineMillis));
|
||||
} catch (SocketTimeoutException e) {
|
||||
throw new SocketTimeoutException("Connect timed out");
|
||||
int originalTimeout = (int) getOption(SocketOptions.SO_TIMEOUT);
|
||||
try {
|
||||
while (received < len) {
|
||||
int count;
|
||||
int remaining = remainingMillis(deadlineMillis);
|
||||
setOption(SocketOptions.SO_TIMEOUT, remaining);
|
||||
try {
|
||||
count = in.read(data, received, len - received);
|
||||
} catch (SocketTimeoutException e) {
|
||||
throw new SocketTimeoutException("Connect timed out");
|
||||
}
|
||||
if (count < 0)
|
||||
throw new SocketException("Malformed reply from SOCKS server");
|
||||
received += count;
|
||||
}
|
||||
if (count < 0)
|
||||
throw new SocketException("Malformed reply from SOCKS server");
|
||||
received += count;
|
||||
} finally {
|
||||
setOption(SocketOptions.SO_TIMEOUT, originalTimeout);
|
||||
}
|
||||
return received;
|
||||
}
|
||||
|
@ -239,6 +246,27 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void connect(String host, int port) throws IOException {
|
||||
connect(new InetSocketAddress(host, port), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void connect(InetAddress address, int port) throws IOException {
|
||||
connect(new InetSocketAddress(address, port), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
void setSocket(Socket soc) {
|
||||
delegate.socket = soc;
|
||||
super.setSocket(soc);
|
||||
}
|
||||
|
||||
@Override
|
||||
void setServerSocket(ServerSocket soc) {
|
||||
throw new InternalError("should not get here");
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects the Socks Socket to the specified endpoint. It will first
|
||||
* connect to the SOCKS proxy and negotiate the access. If the proxy
|
||||
|
@ -290,7 +318,7 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
|||
/*
|
||||
* No default proxySelector --> direct connection
|
||||
*/
|
||||
super.connect(epoint, remainingMillis(deadlineMillis));
|
||||
delegate.connect(epoint, remainingMillis(deadlineMillis));
|
||||
return;
|
||||
}
|
||||
URI uri;
|
||||
|
@ -313,13 +341,13 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
|||
java.util.Iterator<Proxy> iProxy = null;
|
||||
iProxy = sel.select(uri).iterator();
|
||||
if (iProxy == null || !(iProxy.hasNext())) {
|
||||
super.connect(epoint, remainingMillis(deadlineMillis));
|
||||
delegate.connect(epoint, remainingMillis(deadlineMillis));
|
||||
return;
|
||||
}
|
||||
while (iProxy.hasNext()) {
|
||||
p = iProxy.next();
|
||||
if (p == null || p.type() != Proxy.Type.SOCKS) {
|
||||
super.connect(epoint, remainingMillis(deadlineMillis));
|
||||
delegate.connect(epoint, remainingMillis(deadlineMillis));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -509,7 +537,15 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
|||
external_address = epoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void listen(int backlog) {
|
||||
throw new InternalError("should not get here");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void accept(SocketImpl s) {
|
||||
throw new InternalError("should not get here");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this socket's {@code address} field.
|
||||
|
@ -522,7 +558,7 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
|||
if (external_address != null)
|
||||
return external_address.getAddress();
|
||||
else
|
||||
return super.getInetAddress();
|
||||
return delegate.getInetAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -536,7 +572,7 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
|||
if (external_address != null)
|
||||
return external_address.getPort();
|
||||
else
|
||||
return super.getPort();
|
||||
return delegate.getPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -544,10 +580,15 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
|||
if (cmdsock != null)
|
||||
cmdsock.close();
|
||||
cmdsock = null;
|
||||
super.close();
|
||||
delegate.close();
|
||||
}
|
||||
|
||||
private String getUserName() {
|
||||
return StaticProperty.userName();
|
||||
}
|
||||
|
||||
@Override
|
||||
void reset() {
|
||||
throw new InternalError("should not get here");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue