We might revert this some other time, if we need to support other JVMs
Dieser Commit ist enthalten in:
Ursprung
c7737ca96e
Commit
fbfbd28bea
@ -47,8 +47,6 @@ class ProtocolConfig {
|
||||
private static final String UPDATER_DELAY = "delay";
|
||||
private static final String UPDATER_LAST_TIME = "last";
|
||||
|
||||
private static final String ALTERNATIVE_JVM = "alternate jvm";
|
||||
|
||||
// Defaults
|
||||
private static final long DEFAULT_UPDATER_DELAY = 43200;
|
||||
|
||||
@ -231,22 +229,6 @@ class ProtocolConfig {
|
||||
global.set(BACKGROUND_COMPILER_ENABLED, enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve whether the current JVM is a non-standard implementation and require some workarounds.
|
||||
* @return TRUE if it does, FALSE otherwise.
|
||||
*/
|
||||
public boolean isAlternateJVM() {
|
||||
return global.getBoolean(ALTERNATIVE_JVM, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the current JVM is a non-standard implementation and require some workarounds.
|
||||
* @param value - TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public void setAlternateJVM(boolean value) {
|
||||
global.set(ALTERNATIVE_JVM, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the last time we updated, in seconds since 1970.01.01 00:00.
|
||||
* @param lastTimeSeconds - new last update time.
|
||||
|
@ -137,7 +137,7 @@ public class ProtocolLibrary extends JavaPlugin {
|
||||
|
||||
unhookTask = new DelayedSingleTask(this);
|
||||
protocolManager = new PacketFilterManager(
|
||||
getClassLoader(), getServer(), unhookTask, detailedReporter, config.isAlternateJVM());
|
||||
getClassLoader(), getServer(), unhookTask, detailedReporter);
|
||||
|
||||
// Setup error reporter
|
||||
detailedReporter.addGlobalParameter("manager", protocolManager);
|
||||
|
@ -150,7 +150,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
* Only create instances of this class if protocol lib is disabled.
|
||||
* @param unhookTask
|
||||
*/
|
||||
public PacketFilterManager(ClassLoader classLoader, Server server, DelayedSingleTask unhookTask, ErrorReporter reporter, boolean alternateJVM) {
|
||||
public PacketFilterManager(ClassLoader classLoader, Server server, DelayedSingleTask unhookTask, ErrorReporter reporter) {
|
||||
if (reporter == null)
|
||||
throw new IllegalArgumentException("reporter cannot be NULL.");
|
||||
if (classLoader == null)
|
||||
@ -200,7 +200,6 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
classLoader(classLoader).
|
||||
packetListeners(packetListeners).
|
||||
injectionFilter(isInjectionNecessary).
|
||||
alternativeJVM(alternateJVM).
|
||||
buildHandler();
|
||||
|
||||
this.packetInjector = PacketInjectorBuilder.newBuilder().
|
||||
|
@ -37,7 +37,6 @@ public class PlayerInjectorBuilder {
|
||||
protected ListenerInvoker invoker;
|
||||
protected Set<PacketListener> packetListeners;
|
||||
protected Server server;
|
||||
protected boolean alternativeJVM;
|
||||
|
||||
/**
|
||||
* Set the class loader to use during class generation.
|
||||
@ -108,16 +107,6 @@ public class PlayerInjectorBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not the current JVM implementation is alternative.
|
||||
* @param value - TRUE if it is, FALSE otherwise.
|
||||
* @return The current builder, for chaining.
|
||||
*/
|
||||
public PlayerInjectorBuilder alternativeJVM(boolean value) {
|
||||
alternativeJVM = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before an object is created with this builder.
|
||||
*/
|
||||
@ -151,6 +140,6 @@ public class PlayerInjectorBuilder {
|
||||
|
||||
return new ProxyPlayerInjectionHandler(
|
||||
classLoader, reporter, injectionFilter,
|
||||
invoker, packetListeners, server, alternativeJVM);
|
||||
invoker, packetListeners, server);
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
|
||||
|
||||
public ProxyPlayerInjectionHandler(
|
||||
ClassLoader classLoader, ErrorReporter reporter, Predicate<GamePhase> injectionFilter,
|
||||
ListenerInvoker invoker, Set<PacketListener> packetListeners, Server server, boolean alternateJVM) {
|
||||
ListenerInvoker invoker, Set<PacketListener> packetListeners, Server server) {
|
||||
|
||||
this.classLoader = classLoader;
|
||||
this.reporter = reporter;
|
||||
@ -102,7 +102,6 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
|
||||
this.inputStreamLookup = InputStreamLookupBuilder.newBuilder().
|
||||
server(server).
|
||||
reporter(reporter).
|
||||
alternativeJVM(alternateJVM).
|
||||
build();
|
||||
|
||||
// Create net login injectors and the server connection injector
|
||||
@ -323,6 +322,7 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
|
||||
if (previous != null && previous instanceof PlayerInjector) {
|
||||
uninjectPlayer(previous.getPlayer(), true);
|
||||
}
|
||||
|
||||
injector.injectManager();
|
||||
|
||||
// Save injector
|
||||
|
@ -1,122 +0,0 @@
|
||||
package com.comphenix.protocol.injector.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
|
||||
class DelegatedServerSocket extends ServerSocket {
|
||||
protected ServerSocket delegate;
|
||||
|
||||
public DelegatedServerSocket(ServerSocket delegate) throws IOException {
|
||||
super();
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
delegate.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket accept() throws IOException {
|
||||
return delegate.accept();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(SocketAddress endpoint) throws IOException {
|
||||
delegate.bind(endpoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(SocketAddress endpoint, int backlog) throws IOException {
|
||||
delegate.bind(endpoint, backlog);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return delegate.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerSocketChannel getChannel() {
|
||||
return delegate.getChannel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddress getInetAddress() {
|
||||
return delegate.getInetAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalPort() {
|
||||
return delegate.getLocalPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getLocalSocketAddress() {
|
||||
return delegate.getLocalSocketAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getReceiveBufferSize() throws SocketException {
|
||||
return delegate.getReceiveBufferSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getReuseAddress() throws SocketException {
|
||||
return delegate.getReuseAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getSoTimeout() throws IOException {
|
||||
return delegate.getSoTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBound() {
|
||||
return delegate.isBound();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return delegate.isClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
|
||||
delegate.setPerformancePreferences(connectionTime, latency, bandwidth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setReceiveBufferSize(int size) throws SocketException {
|
||||
delegate.setReceiveBufferSize(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReuseAddress(boolean on) throws SocketException {
|
||||
delegate.setReuseAddress(on);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setSoTimeout(int timeout) throws SocketException {
|
||||
delegate.setSoTimeout(timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
public ServerSocket getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
@ -1,241 +0,0 @@
|
||||
package com.comphenix.protocol.injector.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
// This is a fixed JVM class, so there's probably no need to use CGLib
|
||||
class DelegatedSocket extends Socket {
|
||||
protected Socket delegate;
|
||||
|
||||
public DelegatedSocket(Socket delegate) {
|
||||
super();
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(SocketAddress arg0) throws IOException {
|
||||
delegate.bind(arg0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() throws IOException {
|
||||
delegate.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(SocketAddress endpoint) throws IOException {
|
||||
delegate.connect(endpoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(SocketAddress endpoint, int timeout) throws IOException {
|
||||
delegate.connect(endpoint, timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return delegate.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketChannel getChannel() {
|
||||
return delegate.getChannel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddress getInetAddress() {
|
||||
return delegate.getInetAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return delegate.getInputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getKeepAlive() throws SocketException {
|
||||
return delegate.getKeepAlive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddress getLocalAddress() {
|
||||
return delegate.getLocalAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalPort() {
|
||||
return delegate.getLocalPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getLocalSocketAddress() {
|
||||
return delegate.getLocalSocketAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getOOBInline() throws SocketException {
|
||||
return delegate.getOOBInline();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
return delegate.getOutputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPort() {
|
||||
return delegate.getPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getReceiveBufferSize() throws SocketException {
|
||||
return delegate.getReceiveBufferSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getRemoteSocketAddress() {
|
||||
return delegate.getRemoteSocketAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getReuseAddress() throws SocketException {
|
||||
return delegate.getReuseAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getSendBufferSize() throws SocketException {
|
||||
return delegate.getSendBufferSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSoLinger() throws SocketException {
|
||||
return delegate.getSoLinger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getSoTimeout() throws SocketException {
|
||||
return delegate.getSoTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getTcpNoDelay() throws SocketException {
|
||||
return delegate.getTcpNoDelay();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrafficClass() throws SocketException {
|
||||
return delegate.getTrafficClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBound() {
|
||||
return delegate.isBound();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return delegate.isClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return delegate.isConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInputShutdown() {
|
||||
return delegate.isInputShutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOutputShutdown() {
|
||||
return delegate.isOutputShutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendUrgentData(int data) throws IOException {
|
||||
delegate.sendUrgentData(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKeepAlive(boolean on) throws SocketException {
|
||||
delegate.setKeepAlive(on);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOOBInline(boolean on) throws SocketException {
|
||||
delegate.setOOBInline(on);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
|
||||
delegate.setPerformancePreferences(connectionTime, latency, bandwidth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setReceiveBufferSize(int size) throws SocketException {
|
||||
delegate.setReceiveBufferSize(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReuseAddress(boolean on) throws SocketException {
|
||||
delegate.setReuseAddress(on);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setSendBufferSize(int size) throws SocketException {
|
||||
|
||||
delegate.setSendBufferSize(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSoLinger(boolean on, int linger) throws SocketException {
|
||||
delegate.setSoLinger(on, linger);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setSoTimeout(int timeout) throws SocketException {
|
||||
delegate.setSoTimeout(timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTcpNoDelay(boolean on) throws SocketException {
|
||||
delegate.setTcpNoDelay(on);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrafficClass(int tc) throws SocketException {
|
||||
delegate.setTrafficClass(tc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdownInput() throws IOException {
|
||||
delegate.shutdownInput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdownOutput() throws IOException {
|
||||
delegate.shutdownOutput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
public Socket getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
|
@ -1,64 +0,0 @@
|
||||
package com.comphenix.protocol.injector.server;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
/**
|
||||
* Represents a socket injector that delegates to a passed injector.
|
||||
* @author Kristian
|
||||
*
|
||||
*/
|
||||
class DelegatedSocketInjector implements SocketInjector {
|
||||
private volatile SocketInjector delegate;
|
||||
|
||||
public DelegatedSocketInjector(SocketInjector delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(String message) throws InvocationTargetException {
|
||||
delegate.disconnect(message);
|
||||
}
|
||||
@Override
|
||||
public SocketAddress getAddress() throws IllegalAccessException {
|
||||
return delegate.getAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player getPlayer() {
|
||||
return delegate.getPlayer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket getSocket() throws IllegalAccessException {
|
||||
return delegate.getSocket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player getUpdatedPlayer() {
|
||||
return delegate.getUpdatedPlayer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException {
|
||||
delegate.sendServerPacket(packet, filtered);
|
||||
}
|
||||
|
||||
public SocketInjector getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferState(SocketInjector delegate) {
|
||||
delegate.transferState(delegate);
|
||||
}
|
||||
|
||||
public synchronized void setDelegate(SocketInjector delegate) {
|
||||
// Let the old delegate pass values to the new
|
||||
this.delegate.transferState(delegate);
|
||||
this.delegate = delegate;
|
||||
}
|
||||
}
|
@ -20,7 +20,6 @@ public class InputStreamLookupBuilder {
|
||||
|
||||
private Server server;
|
||||
private ErrorReporter reporter;
|
||||
private boolean alternativeJVM;
|
||||
|
||||
/**
|
||||
* Set the server instance to use.
|
||||
@ -42,20 +41,7 @@ public class InputStreamLookupBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not the current JVM implementation is alternative.
|
||||
* @param value - TRUE if it is, FALSE otherwise.
|
||||
* @return The current builder, for chaining.
|
||||
*/
|
||||
public InputStreamLookupBuilder alternativeJVM(boolean value) {
|
||||
alternativeJVM = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AbstractInputStreamLookup build() {
|
||||
if (alternativeJVM)
|
||||
return new InputStreamProxyLookup(reporter, server);
|
||||
else
|
||||
return new InputStreamReflectLookup(reporter, server);
|
||||
return new InputStreamReflectLookup(reporter, server);
|
||||
}
|
||||
}
|
||||
|
@ -1,293 +0,0 @@
|
||||
package com.comphenix.protocol.injector.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.Packets;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.VolatileField;
|
||||
import com.google.common.collect.MapMaker;
|
||||
|
||||
/**
|
||||
* Injection hook used to determine which Socket, and thus address, created any given DataInputStream.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
class InputStreamProxyLookup extends AbstractInputStreamLookup {
|
||||
/**
|
||||
* The read and connect timeout for our built-in MOTD reader.
|
||||
*/
|
||||
private static final int READ_TIMEOUT = 5000;
|
||||
private static final int CONNECT_TIMEOUT = 1000;
|
||||
|
||||
// Using weak keys and values ensures that we will not hold up garbage collection
|
||||
protected ConcurrentMap<InputStream, SocketInjector> ownerSocket = new MapMaker().weakKeys().makeMap();
|
||||
protected ConcurrentMap<SocketAddress, InputStream> addressLookup = new MapMaker().weakValues().makeMap();
|
||||
protected ConcurrentMap<Socket, InputStream> socketLookup = new MapMaker().weakKeys().makeMap();
|
||||
|
||||
// Fake connections
|
||||
private Set<SocketAddress> fakeConnections = Collections.newSetFromMap(
|
||||
new MapMaker().weakKeys().<SocketAddress, Boolean>makeMap()
|
||||
);
|
||||
|
||||
// The server socket that has been injected
|
||||
private VolatileField injectedServerSocket;
|
||||
|
||||
// Used to create fake players
|
||||
private TemporaryPlayerFactory tempPlayerFactory = new TemporaryPlayerFactory();
|
||||
|
||||
public InputStreamProxyLookup(ErrorReporter reporter, Server server) {
|
||||
super(reporter, server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inject(Object container) {
|
||||
if (injectedServerSocket != null)
|
||||
throw new IllegalStateException("Can only inject once. Create a new object instead.");
|
||||
|
||||
Field selected = FuzzyReflection.fromObject(container, true).
|
||||
getFieldByType("serverSocket", ServerSocket.class);
|
||||
injectedServerSocket = new VolatileField(selected, container, true);
|
||||
|
||||
// Load socket
|
||||
ServerSocket socket = (ServerSocket) injectedServerSocket.getValue();
|
||||
|
||||
// Make sure it exists
|
||||
if (socket == null) {
|
||||
throw new IllegalStateException("Cannot find socket to inject. Reference " + selected + " contains NULL.");
|
||||
}
|
||||
|
||||
// Next, let us create the injected server socket
|
||||
try {
|
||||
injectedServerSocket.setValue(new DelegatedServerSocket(socket) {
|
||||
@Override
|
||||
public Socket accept() throws IOException {
|
||||
Socket accepted = super.accept();
|
||||
|
||||
if (fakeConnections.contains(accepted.getRemoteSocketAddress())) {
|
||||
// Don't intercept this connection
|
||||
return accepted;
|
||||
}
|
||||
|
||||
// Wrap the socket we return
|
||||
return new DelegatedSocket(accepted) {
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
InputStream input = super.getInputStream();
|
||||
SocketAddress address = delegate.getRemoteSocketAddress();
|
||||
|
||||
// Make sure that the address is actually valid
|
||||
if (address != null) {
|
||||
InputStream previousStream = addressLookup.
|
||||
putIfAbsent(delegate.getRemoteSocketAddress(), input);
|
||||
|
||||
// Ensure that this is our first time
|
||||
if (previousStream == null) {
|
||||
// Create a new temporary player
|
||||
Player temporaryPlayer = tempPlayerFactory.createTemporaryPlayer(server);
|
||||
TemporarySocketInjector temporaryInjector = new TemporarySocketInjector(temporaryPlayer, delegate);
|
||||
DelegatedSocketInjector socketInjector = new DelegatedSocketInjector(temporaryInjector);
|
||||
|
||||
// Update it
|
||||
TemporaryPlayerFactory.setInjectorInPlayer(temporaryPlayer, socketInjector);
|
||||
|
||||
// Socket lookup
|
||||
socketLookup.put(this, input);
|
||||
|
||||
// Associate the socket with a given input stream
|
||||
setSocketInjector(input, socketInjector);
|
||||
}
|
||||
}
|
||||
return input;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Unbound socket threw an exception. Should never occur.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketInjector getSocketInjector(Socket socket) {
|
||||
InputStream stream = getStream(socket);
|
||||
|
||||
if (stream != null)
|
||||
return getSocketInjector(stream);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSocketInjector(Socket socket, SocketInjector injector) {
|
||||
InputStream stream = getStream(socket);
|
||||
|
||||
if (stream != null) {
|
||||
socketLookup.put(socket, stream);
|
||||
setSocketInjector(stream, injector);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the referenced socket injector by input stream.
|
||||
* @param stream - the input stream.
|
||||
* @param injector - the injector to reference.
|
||||
*/
|
||||
public void setSocketInjector(InputStream stream, SocketInjector injector) {
|
||||
SocketInjector previous = ownerSocket.put(stream, injector);
|
||||
|
||||
// Handle overwrite
|
||||
if (previous != null) {
|
||||
onPreviousSocketOverwritten(previous, injector);
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream getStream(Socket socket) {
|
||||
InputStream result = socketLookup.get(socket);
|
||||
|
||||
// Use the socket as well
|
||||
if (result == null) {
|
||||
try {
|
||||
result = socket.getInputStream();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Unable to retrieve input stream from socket " + socket, e);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketInjector getSocketInjector(InputStream input) {
|
||||
return ownerSocket.get(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketInjector getSocketInjector(SocketAddress address) {
|
||||
InputStream input = addressLookup.get(address);
|
||||
|
||||
if (input != null) {
|
||||
return ownerSocket.get(input);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postWorldLoaded() {
|
||||
cycleServerPorts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when we need to cycle the injected server port.
|
||||
* <p>
|
||||
* This uses a fairly significant hack - we connect to our own server.
|
||||
*/
|
||||
void cycleServerPorts() {
|
||||
final ServerSocket serverSocket = (ServerSocket) injectedServerSocket.getValue();
|
||||
final SocketAddress address = new InetSocketAddress("127.0.0.1", serverSocket.getLocalPort());
|
||||
|
||||
// Sorry
|
||||
Thread consumeThread = new Thread("ProtocolLib - Hack Thread") {
|
||||
@Override
|
||||
public void run() {
|
||||
Socket socket = null;
|
||||
OutputStream output = null;
|
||||
InputStream input = null;
|
||||
InputStreamReader reader = null;
|
||||
|
||||
try {
|
||||
socket = new Socket();
|
||||
socket.connect(address, CONNECT_TIMEOUT);
|
||||
|
||||
// Ignore packets from this connection
|
||||
fakeConnections.add(socket.getLocalSocketAddress());
|
||||
|
||||
// Shouldn't take that long
|
||||
socket.setSoTimeout(READ_TIMEOUT);
|
||||
|
||||
// Retrieve sockets
|
||||
output = socket.getOutputStream();
|
||||
input = socket.getInputStream();
|
||||
reader = new InputStreamReader(input, Charset.forName("UTF-16BE"));
|
||||
|
||||
// Get the server to send a MOTD
|
||||
output.write(new byte[] { (byte) 0xFE, (byte) 0x01 });
|
||||
|
||||
int packetId = input.read();
|
||||
int length = reader.read();
|
||||
|
||||
if (packetId != Packets.Server.KICK_DISCONNECT) {
|
||||
throw new IOException("Invalid packet ID: " + packetId);
|
||||
}
|
||||
if (length <= 0) {
|
||||
throw new IOException("Invalid string length.");
|
||||
}
|
||||
char[] chars = new char[length];
|
||||
|
||||
// Read all the characters
|
||||
if (reader.read(chars, 0, length) != length) {
|
||||
throw new IOException("Premature end of stream.");
|
||||
}
|
||||
|
||||
System.out.println("Read: " + new String(chars));
|
||||
|
||||
} catch (Exception e) {
|
||||
reporter.reportWarning(this, "Cannot simulate MOTD.", e);
|
||||
} finally {
|
||||
try {
|
||||
if (reader != null)
|
||||
reader.close();
|
||||
if (input != null)
|
||||
input.close();
|
||||
if (output != null)
|
||||
output.close();
|
||||
if (socket != null)
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
reporter.reportWarning(this, "Cannot clean up socket.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
consumeThread.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreviousSocketOverwritten(SocketInjector previous, SocketInjector current) {
|
||||
// Don't forget this
|
||||
super.onPreviousSocketOverwritten(previous, current);
|
||||
|
||||
if (previous instanceof DelegatedSocketInjector) {
|
||||
DelegatedSocketInjector delegated = (DelegatedSocketInjector) previous;
|
||||
|
||||
// Update the delegate
|
||||
delegated.setDelegate(current);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanupAll() {
|
||||
if (injectedServerSocket != null && injectedServerSocket.isCurrentSet()) {
|
||||
injectedServerSocket.revertValue();
|
||||
|
||||
// This is going to suck
|
||||
cycleServerPorts();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
package com.comphenix.protocol.injector.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
class TemporarySocketInjector implements SocketInjector {
|
||||
/**
|
||||
* Represents a single send packet command.
|
||||
* @author Kristian
|
||||
*/
|
||||
static class SendPacketCommand {
|
||||
private final Object packet;
|
||||
private final boolean filtered;
|
||||
|
||||
public SendPacketCommand(Object packet, boolean filtered) {
|
||||
this.packet = packet;
|
||||
this.filtered = filtered;
|
||||
}
|
||||
|
||||
public Object getPacket() {
|
||||
return packet;
|
||||
}
|
||||
|
||||
public boolean isFiltered() {
|
||||
return filtered;
|
||||
}
|
||||
}
|
||||
|
||||
private Player temporaryPlayer;
|
||||
private Socket socket;
|
||||
|
||||
// Queue of server packets
|
||||
private List<SendPacketCommand> syncronizedQueue = Collections.synchronizedList(new ArrayList<SendPacketCommand>());
|
||||
|
||||
/**
|
||||
* Represents a temporary socket injector.
|
||||
* @param temporaryPlayer - temporary player instance.
|
||||
* @param socket - the socket we are representing.
|
||||
* @param fake - whether or not this connection should be ignored.
|
||||
*/
|
||||
public TemporarySocketInjector(Player temporaryPlayer, Socket socket) {
|
||||
this.temporaryPlayer = temporaryPlayer;
|
||||
this.socket = socket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket getSocket() throws IllegalAccessException {
|
||||
return socket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getAddress() throws IllegalAccessException {
|
||||
if (socket != null)
|
||||
return socket.getRemoteSocketAddress();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(String message) throws InvocationTargetException {
|
||||
// We have no choice - disregard message too
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
throw new InvocationTargetException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendServerPacket(Object packet, boolean filtered)
|
||||
throws InvocationTargetException {
|
||||
SendPacketCommand command = new SendPacketCommand(packet, filtered);
|
||||
|
||||
// Queue until we can find something better
|
||||
syncronizedQueue.add(command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player getPlayer() {
|
||||
return temporaryPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player getUpdatedPlayer() {
|
||||
return temporaryPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferState(SocketInjector delegate) {
|
||||
// Transmit all queued packets to a different injector.
|
||||
try {
|
||||
synchronized(syncronizedQueue) {
|
||||
for (SendPacketCommand command : syncronizedQueue) {
|
||||
delegate.sendServerPacket(command.getPacket(), command.isFiltered());
|
||||
}
|
||||
syncronizedQueue.clear();
|
||||
}
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException("Unable to transmit packets to " + delegate + " from old injector.", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -17,8 +17,5 @@ global:
|
||||
# Disable version checking for the given Minecraft version. Backup your world first!
|
||||
ignore version check:
|
||||
|
||||
# Set to TRUE if you're on a custom JVM implementation and you're having problems
|
||||
alternate jvm: false
|
||||
|
||||
# Override the starting injecting method
|
||||
injection method:
|
In neuem Issue referenzieren
Einen Benutzer sperren