Handle exceptions in injected code.
This is very important, otherwise the server may crash unnecessarily.
Dieser Commit ist enthalten in:
Ursprung
f9c0f212c1
Commit
0dc2bfef0c
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren