mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +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
|
||||
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue