Archiviert
13
0

Handle exceptions in injected code.

This is very important, otherwise the server may crash unnecessarily.
Dieser Commit ist enthalten in:
Kristian S. Stangeland 2012-10-29 17:20:04 +01:00
Ursprung f9c0f212c1
Commit 0dc2bfef0c
6 geänderte Dateien mit 109 neuen und 81 gelöschten Zeilen

Datei anzeigen

@ -49,7 +49,6 @@ import com.comphenix.protocol.AsynchronousManager;
import com.comphenix.protocol.ProtocolManager; import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.async.AsyncFilterManager; import com.comphenix.protocol.async.AsyncFilterManager;
import com.comphenix.protocol.async.AsyncMarker; import com.comphenix.protocol.async.AsyncMarker;
import com.comphenix.protocol.error.DetailedErrorReporter;
import com.comphenix.protocol.error.ErrorReporter; import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.events.*; import com.comphenix.protocol.events.*;
import com.comphenix.protocol.injector.player.PlayerInjectionHandler; import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
@ -142,7 +141,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
* Only create instances of this class if protocol lib is disabled. * Only create instances of this class if protocol lib is disabled.
* @param unhookTask * @param unhookTask
*/ */
public PacketFilterManager(ClassLoader classLoader, Server server, DelayedSingleTask unhookTask, DetailedErrorReporter reporter) { public PacketFilterManager(ClassLoader classLoader, Server server, DelayedSingleTask unhookTask, ErrorReporter reporter) {
if (reporter == null) if (reporter == null)
throw new IllegalArgumentException("reporter cannot be NULL."); throw new IllegalArgumentException("reporter cannot be NULL.");
if (classLoader == null) if (classLoader == null)
@ -175,7 +174,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
try { try {
// Initialize injection mangers // Initialize injection mangers
this.playerInjection = new PlayerInjectionHandler(classLoader, reporter, isInjectionNecessary, this, packetListeners, server); this.playerInjection = new PlayerInjectionHandler(classLoader, reporter, isInjectionNecessary, this, packetListeners, server);
this.packetInjector = new PacketInjector(classLoader, this, playerInjection); this.packetInjector = new PacketInjector(classLoader, this, playerInjection, reporter);
this.asyncFilterManager = new AsyncFilterManager(reporter, server.getScheduler(), this); this.asyncFilterManager = new AsyncFilterManager(reporter, server.getScheduler(), this);
// Attempt to load the list of server and client packets // Attempt to load the list of server and client packets

Datei anzeigen

@ -31,6 +31,7 @@ import net.minecraft.server.Packet;
import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.Enhancer;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.player.PlayerInjectionHandler; import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
@ -51,6 +52,9 @@ class PacketInjector {
// The packet filter manager // The packet filter manager
private ListenerInvoker manager; private ListenerInvoker manager;
// Error reporter
private ErrorReporter reporter;
// Allows us to determine the sender // Allows us to determine the sender
private PlayerInjectionHandler playerInjection; private PlayerInjectionHandler playerInjection;
@ -61,11 +65,12 @@ class PacketInjector {
private ClassLoader classLoader; private ClassLoader classLoader;
public PacketInjector(ClassLoader classLoader, ListenerInvoker manager, public PacketInjector(ClassLoader classLoader, ListenerInvoker manager,
PlayerInjectionHandler playerInjection) throws IllegalAccessException { PlayerInjectionHandler playerInjection, ErrorReporter reporter) throws IllegalAccessException {
this.classLoader = classLoader; this.classLoader = classLoader;
this.manager = manager; this.manager = manager;
this.playerInjection = playerInjection; this.playerInjection = playerInjection;
this.reporter = reporter;
this.readModifier = new ConcurrentHashMap<Integer, ReadPacketModifier>(); this.readModifier = new ConcurrentHashMap<Integer, ReadPacketModifier>();
initialize(); initialize();
} }
@ -133,7 +138,7 @@ class PacketInjector {
Class proxy = ex.createClass(); Class proxy = ex.createClass();
// Create the proxy handler // Create the proxy handler
ReadPacketModifier modifier = new ReadPacketModifier(packetID, this); ReadPacketModifier modifier = new ReadPacketModifier(packetID, this, reporter);
readModifier.put(packetID, modifier); readModifier.put(packetID, modifier);
// Add a static reference // Add a static reference

Datei anzeigen

@ -25,6 +25,7 @@ import java.util.Map;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import com.comphenix.protocol.Packets; import com.comphenix.protocol.Packets;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketEvent;
@ -44,12 +45,16 @@ class ReadPacketModifier implements MethodInterceptor {
private PacketInjector packetInjector; private PacketInjector packetInjector;
private int packetID; private int packetID;
// Report errors
private ErrorReporter reporter;
// Whether or not a packet has been cancelled // Whether or not a packet has been cancelled
private static Map<Object, Object> override = Collections.synchronizedMap(new WeakHashMap<Object, Object>()); private static Map<Object, Object> override = Collections.synchronizedMap(new WeakHashMap<Object, Object>());
public ReadPacketModifier(int packetID, PacketInjector packetInjector) { public ReadPacketModifier(int packetID, PacketInjector packetInjector, ErrorReporter reporter) {
this.packetID = packetID; this.packetID = packetID;
this.packetInjector = packetInjector; this.packetInjector = packetInjector;
this.reporter = reporter;
} }
/** /**
@ -102,27 +107,32 @@ class ReadPacketModifier implements MethodInterceptor {
if (returnValue == null && if (returnValue == null &&
Arrays.equals(method.getParameterTypes(), parameters)) { Arrays.equals(method.getParameterTypes(), parameters)) {
// We need this in order to get the correct player try {
DataInputStream input = (DataInputStream) args[0]; // We need this in order to get the correct player
DataInputStream input = (DataInputStream) args[0];
// Let the people know
PacketContainer container = new PacketContainer(packetID, (Packet) thisObj); // Let the people know
PacketEvent event = packetInjector.packetRecieved(container, input); PacketContainer container = new PacketContainer(packetID, (Packet) thisObj);
PacketEvent event = packetInjector.packetRecieved(container, input);
// Handle override
if (event != null) {
Packet result = event.getPacket().getHandle();
if (event.isCancelled()) { // Handle override
override.put(thisObj, CANCEL_MARKER); if (event != null) {
} else if (!objectEquals(thisObj, result)) { Packet result = event.getPacket().getHandle();
override.put(thisObj, result);
} if (event.isCancelled()) {
override.put(thisObj, CANCEL_MARKER);
// Update DataInputStream next time } else if (!objectEquals(thisObj, result)) {
if (!event.isCancelled() && packetID == Packets.Server.KEY_RESPONSE) { override.put(thisObj, result);
packetInjector.scheduleDataInputRefresh(event.getPlayer()); }
// Update DataInputStream next time
if (!event.isCancelled() && packetID == Packets.Server.KEY_RESPONSE) {
packetInjector.scheduleDataInputRefresh(event.getPlayer());
}
} }
} catch (Throwable e) {
// Minecraft cannot handle this error
reporter.reportDetailed(this, "Cannot handle clienet packet.", e, args[0]);
} }
} }

Datei anzeigen

@ -217,7 +217,12 @@ class InjectedServerConnection {
// Is this a normal Minecraft object? // Is this a normal Minecraft object?
if (!(inserting instanceof Factory)) { if (!(inserting instanceof Factory)) {
// If so, copy the content of the old element to the new // If so, copy the content of the old element to the new
ObjectCloner.copyTo(inserting, replacement, inserting.getClass()); try {
ObjectCloner.copyTo(inserting, replacement, inserting.getClass());
} catch (Throwable e) {
reporter.reportDetailed(InjectedServerConnection.this, "Cannot copy old " + inserting +
" to new.", e, inserting, replacement);
}
} }
} }

Datei anzeigen

@ -95,30 +95,34 @@ class NetLoginInjector {
PlayerInjector injected = injectedLogins.get(removing); PlayerInjector injected = injectedLogins.get(removing);
if (injected != null) { if (injected != null) {
PlayerInjector newInjector = null; try {
Player player = injected.getPlayer(); PlayerInjector newInjector = null;
Player player = injected.getPlayer();
// Clean up list
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) // Clean up list
newInjector.setNetworkManager(injected.getNetworkManager(), true); 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);
}
} catch (Throwable e) {
// Don't leak this to Minecraft
reporter.reportDetailed(this, "Cannot cleanup NetLoginHandler.", e, removing);
} }
//logger.warning("Using alternative cleanup method.");
} }
} }

Datei anzeigen

@ -502,43 +502,48 @@ abstract class PlayerInjector {
* @return The given packet, or the packet replaced by the listeners. * @return The given packet, or the packet replaced by the listeners.
*/ */
public Packet handlePacketSending(Packet packet) { public Packet handlePacketSending(Packet packet) {
// Get the packet ID too try {
Integer id = invoker.getPacketID(packet); // Get the packet ID too
Player currentPlayer = player; Integer id = invoker.getPacketID(packet);
Player currentPlayer = player;
// Hack #1: Handle a single scheduled action
if (scheduledAction != null) { // Hack #1: Handle a single scheduled action
scheduledAction.run(); if (scheduledAction != null) {
scheduledAction = null; scheduledAction.run();
} scheduledAction = null;
// Hack #2 }
if (updateOnLogin) { // Hack #2
if (id == Packets.Server.LOGIN) { if (updateOnLogin) {
try { if (id == Packets.Server.LOGIN) {
updatedPlayer = getEntityPlayer(getNetHandler()).getBukkitEntity(); try {
} catch (IllegalAccessException e) { updatedPlayer = getEntityPlayer(getNetHandler()).getBukkitEntity();
reporter.reportDetailed(this, "Cannot update player in PlayerEvent.", e, packet); } catch (IllegalAccessException e) {
reporter.reportDetailed(this, "Cannot update player in PlayerEvent.", e, packet);
}
} }
// This will only occur in the NetLoginHandler injection
if (updatedPlayer != null)
currentPlayer = updatedPlayer;
} }
// This will only occur in the NetLoginHandler injection // Make sure we're listening
if (updatedPlayer != null) if (id != null && hasListener(id)) {
currentPlayer = updatedPlayer; // A packet has been sent guys!
} PacketContainer container = new PacketContainer(id, packet);
PacketEvent event = PacketEvent.fromServer(invoker, container, currentPlayer);
// Make sure we're listening invoker.invokePacketSending(event);
if (id != null && hasListener(id)) {
// A packet has been sent guys! // Cancelling is pretty simple. Just ignore the packet.
PacketContainer container = new PacketContainer(id, packet); if (event.isCancelled())
PacketEvent event = PacketEvent.fromServer(invoker, container, currentPlayer); return null;
invoker.invokePacketSending(event);
// Right, remember to replace the packet again
return event.getPacket().getHandle();
}
// Cancelling is pretty simple. Just ignore the packet. } catch (Throwable e) {
if (event.isCancelled()) reporter.reportDetailed(this, "Cannot handle server packet.", e, packet);
return null;
// Right, remember to replace the packet again
return event.getPacket().getHandle();
} }
return packet; return packet;