Archiviert
13
0

Properly remove previous hook, even if socket is NULL. FIXES Ticket-1.

Dieser Commit ist enthalten in:
Kristian S. Stangeland 2012-10-21 20:31:20 +02:00
Ursprung c08106a923
Commit a51ad1f50f
9 geänderte Dateien mit 159 neuen und 27 gelöschten Zeilen

Datei anzeigen

@ -4,7 +4,7 @@
<groupId>com.comphenix.protocol</groupId> <groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId> <artifactId>ProtocolLib</artifactId>
<name>ProtocolLib</name> <name>ProtocolLib</name>
<version>1.4.1</version> <version>1.4.2-SNAPSHOT</version>
<description>Provides read/write access to the Minecraft protocol.</description> <description>Provides read/write access to the Minecraft protocol.</description>
<url>http://dev.bukkit.org/server-mods/protocollib/</url> <url>http://dev.bukkit.org/server-mods/protocollib/</url>
<developers> <developers>

Datei anzeigen

@ -63,6 +63,9 @@ class NetLoginInjector {
InjectContainer container = (InjectContainer) fakePlayer; InjectContainer container = (InjectContainer) fakePlayer;
container.setInjector(injector); container.setInjector(injector);
// Save the login
injectedLogins.putIfAbsent(inserting, injector);
// NetServerInjector can never work (currently), so we don't need to replace the NetLoginHandler // NetServerInjector can never work (currently), so we don't need to replace the NetLoginHandler
return inserting; return inserting;
@ -93,8 +96,30 @@ class NetLoginInjector {
PlayerInjector injected = injectedLogins.get(removing); PlayerInjector injected = injectedLogins.get(removing);
if (injected != null) { if (injected != null) {
injected.cleanupAll(); PlayerInjector newInjector = null;
Player player = injected.getPlayer();
// Clean up list
injectedLogins.remove(removing); injectedLogins.remove(removing);
// No need to clean up twice
if (injected.isClean())
return;
// Hack to clean up other references
newInjector = injectionHandler.getInjectorByNetworkHandler(injected.getNetworkManager());
// Update NetworkManager
if (newInjector == null) {
injectionHandler.uninjectPlayer(player);
} else {
injectionHandler.uninjectPlayer(player, false);
if (injected instanceof NetworkObjectInjector)
newInjector.setNetworkManager(injected.getNetworkManager(), true);
}
//logger.warning("Using alternative cleanup method.");
} }
} }

Datei anzeigen

@ -166,7 +166,7 @@ class NetworkFieldInjector extends PlayerInjector {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void cleanupAll() { protected void cleanHook() {
// Clean up // Clean up
for (VolatileField overriden : overridenLists) { for (VolatileField overriden : overridenLists) {
List<Packet> minecraftList = (List<Packet>) overriden.getOldValue(); List<Packet> minecraftList = (List<Packet>) overriden.getOldValue();

Datei anzeigen

@ -152,7 +152,7 @@ class NetworkObjectInjector extends PlayerInjector {
} }
@Override @Override
public void cleanupAll() { protected void cleanHook() {
// Clean up // Clean up
if (networkManagerRef != null && networkManagerRef.isCurrentSet()) { if (networkManagerRef != null && networkManagerRef.isCurrentSet()) {
networkManagerRef.revertValue(); networkManagerRef.revertValue();

Datei anzeigen

@ -232,7 +232,7 @@ public class NetworkServerInjector extends PlayerInjector {
} }
@Override @Override
public void cleanupAll() { protected void cleanHook() {
if (serverHandlerRef != null && serverHandlerRef.isCurrentSet()) { if (serverHandlerRef != null && serverHandlerRef.isCurrentSet()) {
ObjectCloner.copyTo(serverHandlerRef.getValue(), serverHandlerRef.getOldValue(), serverHandler.getClass()); ObjectCloner.copyTo(serverHandlerRef.getValue(), serverHandlerRef.getOldValue(), serverHandler.getClass());
serverHandlerRef.revertValue(); serverHandlerRef.revertValue();

Datei anzeigen

@ -281,28 +281,27 @@ public class PlayerInjectionHandler {
DataInputStream inputStream = injector.getInputStream(false); DataInputStream inputStream = injector.getInputStream(false);
Socket socket = injector.getSocket(); Socket socket = injector.getSocket();
SocketAddress address = socket.getRemoteSocketAddress(); SocketAddress address = socket != null ? socket.getRemoteSocketAddress() : null;
// Make sure the current player is not logged out // Make sure the current player is not logged out
if (socket.isClosed()) { if (socket != null && socket.isClosed()) {
throw new PlayerLoggedOutException(); throw new PlayerLoggedOutException();
} }
PlayerInjector previous = addressLookup.get(address); // Guard against NPE here too
PlayerInjector previous = address != null ? addressLookup.get(address) : null;
// Close any previously associated hooks before we proceed // Close any previously associated hooks before we proceed
if (previous != null) { if (previous != null) {
uninjectPlayer(previous.getPlayer()); uninjectPlayer(previous.getPlayer(), false, true);
// Remove the "hooked" network manager in our instance as well
if (previous instanceof NetworkObjectInjector) {
injector.setNetworkManager(previous.getNetworkManager(), true);
}
} }
injector.injectManager(); injector.injectManager();
dataInputLookup.put(inputStream, injector);
addressLookup.put(address, injector); if (inputStream != null)
dataInputLookup.put(inputStream, injector);
if (address != null)
addressLookup.put(address, injector);
break; break;
} }
@ -362,8 +361,30 @@ public class PlayerInjectionHandler {
/** /**
* Unregisters the given player. * Unregisters the given player.
* @param player - player to unregister. * @param player - player to unregister.
* @return TRUE if a player has been uninjected, FALSE otherwise.
*/ */
public void uninjectPlayer(Player player) { public boolean uninjectPlayer(Player player) {
return uninjectPlayer(player, true, false);
}
/**
* Unregisters the given player.
* @param player - player to unregister.
* @param removeAuxiliary - TRUE to remove auxiliary information, such as input stream and address.
* @return TRUE if a player has been uninjected, FALSE otherwise.
*/
public boolean uninjectPlayer(Player player, boolean removeAuxiliary) {
return uninjectPlayer(player, removeAuxiliary, false);
}
/**
* Unregisters the given player.
* @param player - player to unregister.
* @param removeAuxiliary - TRUE to remove auxiliary information, such as input stream and address.
* @param prepareNextHook - whether or not we need to fix any lingering hooks.
* @return TRUE if a player has been uninjected, FALSE otherwise.
*/
private boolean uninjectPlayer(Player player, boolean removeAuxiliary, boolean prepareNextHook) {
if (!hasClosed && player != null) { if (!hasClosed && player != null) {
PlayerInjector injector = playerInjection.remove(player); PlayerInjector injector = playerInjection.remove(player);
@ -373,26 +394,54 @@ public class PlayerInjectionHandler {
InetSocketAddress address = player.getAddress(); InetSocketAddress address = player.getAddress();
injector.cleanupAll(); injector.cleanupAll();
dataInputLookup.remove(input); // Remove the "hooked" network manager in our instance as well
if (prepareNextHook && injector instanceof NetworkObjectInjector) {
try {
PlayerInjector dummyInjector = getHookInstance(player, PlayerInjectHooks.NETWORK_SERVER_OBJECT);
dummyInjector.initializePlayer(player);
dummyInjector.setNetworkManager(injector.getNetworkManager(), true);
} catch (IllegalAccessException e) {
// Let the user know
logger.log(Level.WARNING, "Unable to fully revert old injector. May cause conflicts.", e);
}
}
if (address != null) // Clean up
addressLookup.remove(address); if (removeAuxiliary) {
if (input != null)
dataInputLookup.remove(input);
if (address != null)
addressLookup.remove(address);
}
return true;
} }
} }
return false;
} }
/** /**
* Unregisters a player by the given address. * Unregisters a player by the given address.
* <p>
* If the server handler has been created before we've gotten a chance to unject the player,
* the method will try a workaround to remove the injected hook in the NetServerHandler.
*
* @param address - address of the player to unregister. * @param address - address of the player to unregister.
* @param serverHandler - whether or not the net server handler has already been created.
* @return TRUE if a player has been uninjected, FALSE otherwise.
*/ */
public void uninjectPlayer(InetSocketAddress address) { public boolean uninjectPlayer(InetSocketAddress address) {
if (!hasClosed && address != null) { if (!hasClosed && address != null) {
PlayerInjector injector = addressLookup.get(address); PlayerInjector injector = addressLookup.get(address);
// Clean up // Clean up
if (injector != null) if (injector != null)
uninjectPlayer(injector.getPlayer()); uninjectPlayer(injector.getPlayer(), false, true);
return true;
} }
return false;
} }
/** /**
@ -445,6 +494,26 @@ public class PlayerInjectionHandler {
return playerInjection.get(player); return playerInjection.get(player);
} }
/**
* Retrieve a player injector by looking for its NetworkManager.
* @param networkManager - current network manager.
* @return Related player injector.
*/
PlayerInjector getInjectorByNetworkHandler(Object networkManager) {
// That's not legal
if (networkManager == null)
return null;
// O(n) is okay in this instance. This is only a backup solution.
for (PlayerInjector injector : playerInjection.values()) {
if (injector.getNetworkManager() == networkManager)
return injector;
}
// None found
return null;
}
/** /**
* Determine if the given listeners are valid. * Determine if the given listeners are valid.
* @param listeners - listeners to check. * @param listeners - listeners to check.

Datei anzeigen

@ -23,6 +23,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.Socket; import java.net.Socket;
import java.net.SocketAddress;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -104,6 +105,9 @@ abstract class PlayerInjector {
// Scheduled action on the next packet event // Scheduled action on the next packet event
protected Runnable scheduledAction; protected Runnable scheduledAction;
// Whether or not the injector has been cleaned
private boolean clean;
// Whether or not to update the current player on the first Packet1Login // Whether or not to update the current player on the first Packet1Login
boolean updateOnLogin; boolean updateOnLogin;
Player updatedPlayer; Player updatedPlayer;
@ -256,6 +260,21 @@ abstract class PlayerInjector {
} }
} }
/**
* Retrieve the associated address of this player.
* @return The associated address.
* @throws IllegalAccessException If we're unable to read the socket field.
*/
public SocketAddress getAddress() throws IllegalAccessException {
Socket socket = getSocket();
// Guard against NULL
if (socket != null)
return socket.getRemoteSocketAddress();
else
return null;
}
/** /**
* Attempt to disconnect the current client. * Attempt to disconnect the current client.
* @param message - the message to display. * @param message - the message to display.
@ -427,7 +446,24 @@ abstract class PlayerInjector {
/** /**
* Remove all hooks and modifications. * Remove all hooks and modifications.
*/ */
public abstract void cleanupAll(); public final void cleanupAll() {
if (!clean)
cleanHook();
clean = true;
}
/**
* Override to add custom cleanup behavior.
*/
protected abstract void cleanHook();
/**
* Determine whether or not this hook has already been cleaned.
* @return TRUE if it has, FALSE otherwise.
*/
public boolean isClean() {
return clean;
}
/** /**
* Determine if this inject method can even be attempted. * Determine if this inject method can even be attempted.

Datei anzeigen

@ -76,13 +76,16 @@ class TemporaryPlayerFactory {
String methodName = method.getName(); String methodName = method.getName();
PlayerInjector injector = ((InjectContainer) obj).getInjector(); PlayerInjector injector = ((InjectContainer) obj).getInjector();
if (injector == null)
throw new IllegalStateException("Unable to find injector.");
// Use the socket to get the address // Use the socket to get the address
if (methodName.equalsIgnoreCase("getName")) if (methodName.equalsIgnoreCase("getName"))
return "UNKNOWN[" + injector.getSocket().getRemoteSocketAddress() + "]"; return "UNKNOWN[" + injector.getSocket().getRemoteSocketAddress() + "]";
if (methodName.equalsIgnoreCase("getPlayer")) if (methodName.equalsIgnoreCase("getPlayer"))
return injector.getUpdatedPlayer(); return injector.getUpdatedPlayer();
if (methodName.equalsIgnoreCase("getAddress")) if (methodName.equalsIgnoreCase("getAddress"))
return injector.getSocket().getRemoteSocketAddress(); return injector.getAddress();
if (methodName.equalsIgnoreCase("getServer")) if (methodName.equalsIgnoreCase("getServer"))
return server; return server;

Datei anzeigen

@ -206,7 +206,6 @@ public class DefaultInstances {
// Just check if any of them are NULL // Just check if any of them are NULL
for (Class<?> type : types) { for (Class<?> type : types) {
if (getDefaultInternal(type, providers, recursionLevel) == null) { if (getDefaultInternal(type, providers, recursionLevel) == null) {
System.out.println(type.getName() + " is NULL!");
return true; return true;
} }
} }