diff --git a/applications/SLProxy/Analyst.cs b/applications/SLProxy/Analyst.cs index e1fec5de..9e1d43cd 100644 --- a/applications/SLProxy/Analyst.cs +++ b/applications/SLProxy/Analyst.cs @@ -70,7 +70,6 @@ public class Analyst proxy.SetLoginResponseDelegate(new XmlRpcResponseDelegate(LoginResponse)); // add a delegate for outgoing chat - proxy.AddDelegate(PacketType.ChatFromViewer, Direction.Incoming, new PacketDelegate(ChatFromViewerIn)); proxy.AddDelegate(PacketType.ChatFromViewer, Direction.Outgoing, new PacketDelegate(ChatFromViewerOut)); // handle command line arguments @@ -110,17 +109,6 @@ public class Analyst } } - // ChatFromViewerIn: incoming ChatFromViewer delegate; shouldn't be possible, but just in case... - private static Packet ChatFromViewerIn(Packet packet, IPEndPoint sim) - { - if (loggedPackets.Contains(PacketType.ChatFromViewer) || modifiedPackets.Contains(PacketType.ChatFromViewer)) - // user has asked to log or modify this packet - return Analyze(packet, sim, Direction.Incoming); - else - // return the packet unmodified - return packet; - } - // ChatFromViewerOut: outgoing ChatFromViewer delegate; check for Analyst commands private static Packet ChatFromViewerOut(Packet packet, IPEndPoint sim) { @@ -138,13 +126,8 @@ public class Analyst return null; } } - - if (loggedPackets.Contains(PacketType.ChatFromViewer) || modifiedPackets.Contains(PacketType.ChatFromViewer)) - // user has asked to log or modify this packet - return Analyze(packet, sim, Direction.Outgoing); - else - // return the packet unmodified - return packet; + + return packet; } // CommandDelegate: specifies a callback delegate for a /command @@ -193,11 +176,8 @@ public class Analyst return; } loggedPackets[pType] = null; - if (words[1] != "ChatFromViewer") - { - proxy.AddDelegate(pType, Direction.Incoming, new PacketDelegate(AnalyzeIn)); - proxy.AddDelegate(pType, Direction.Outgoing, new PacketDelegate(AnalyzeOut)); - } + proxy.AddDelegate(pType, Direction.Incoming, new PacketDelegate(LogPacketIn)); + proxy.AddDelegate(pType, Direction.Outgoing, new PacketDelegate(LogPacketOut)); SayToUser("logging " + words[1]); } } @@ -217,15 +197,8 @@ public class Analyst PacketType pType = packetTypeFromName(words[1]); loggedPackets.Remove(pType); - if (!modifiedPackets.Contains(words[1])) - { - if (words[1] != "ChatFromViewer") - { - proxy.RemoveDelegate(pType, Direction.Incoming); - proxy.RemoveDelegate(pType, Direction.Outgoing); - } - } - + proxy.RemoveDelegate(pType, Direction.Incoming, new PacketDelegate(LogPacketIn)); + proxy.RemoveDelegate(pType, Direction.Outgoing, new PacketDelegate(LogPacketOut)); SayToUser("stopped logging " + words[1]); } } @@ -284,11 +257,8 @@ public class Analyst fields[new BlockField(words[2], words[3])] = value; modifiedPackets[pType] = fields; - if (words[1] != "ChatFromViewer") - { - proxy.AddDelegate(pType, Direction.Incoming, new PacketDelegate(AnalyzeIn)); - proxy.AddDelegate(pType, Direction.Outgoing, new PacketDelegate(AnalyzeOut)); - } + proxy.AddDelegate(pType, Direction.Incoming, new PacketDelegate(ModifyIn)); + proxy.AddDelegate(pType, Direction.Outgoing, new PacketDelegate(ModifyOut)); SayToUser("setting " + words[1] + "." + words[2] + "." + words[3] + " = " + valueString); } @@ -300,10 +270,9 @@ public class Analyst if (words.Length == 2 && words[1] == "*") { foreach (PacketType pType in modifiedPackets.Keys) - if (!loggedPackets.Contains(pType) && pType != PacketType.ChatFromViewer) { - proxy.RemoveDelegate(pType, Direction.Incoming); - proxy.RemoveDelegate(pType, Direction.Outgoing); + proxy.RemoveDelegate(pType, Direction.Incoming, new PacketDelegate(ModifyIn)); + proxy.RemoveDelegate(pType, Direction.Outgoing, new PacketDelegate(ModifyOut)); } modifiedPackets = new Hashtable(); @@ -332,14 +301,8 @@ public class Analyst { modifiedPackets.Remove(pType); - if (!loggedPackets.Contains(pType)) - { - if (words[1] != "ChatFromViewer") - { - proxy.RemoveDelegate(pType, Direction.Incoming); - proxy.RemoveDelegate(pType, Direction.Outgoing); - } - } + proxy.RemoveDelegate(pType, Direction.Incoming, new PacketDelegate(ModifyIn)); + proxy.RemoveDelegate(pType, Direction.Outgoing, new PacketDelegate(ModifyOut)); } } @@ -410,21 +373,36 @@ public class Analyst ConstructorInfo ctr = packetClass.GetConstructor(new Type[] { }); if (ctr == null) throw new Exception("Couldn't get suitable constructor for " + name + "Packet"); packet = (Packet)ctr.Invoke(new object[] { }); - Console.WriteLine("Created new " + name + "Packet"); + //Console.WriteLine("Created new " + name + "Packet"); } else { match = (new Regex(@"^\s*\[(\w+)\]\s*$")).Match(line); if (match.Success) { - //FIXME: support variable blocks - block = match.Groups[1].Captures[0].ToString(); FieldInfo blockField = packetClass.GetField(block); if (blockField == null) throw new Exception("Couldn't get " + name + "Packet." + block); - blockObj = blockField.GetValue(packet); + Type blockClass = blockField.FieldType; + if (blockClass.IsArray) + { + blockClass = blockClass.GetElementType(); + ConstructorInfo ctr = blockClass.GetConstructor(new Type[] { }); + if (ctr == null) throw new Exception("Couldn't get suitable constructor for " + blockClass.Name); + blockObj = ctr.Invoke(new object[] { }); + object[] arr = (object[])blockField.GetValue(packet); + object[] narr = (object[])Array.CreateInstance(blockClass, arr.Length + 1); + Array.Copy(arr,narr,arr.Length); + narr[arr.Length] = blockObj; + blockField.SetValue(packet,narr); + //Console.WriteLine("Added block "+block); + } + else + { + blockObj = blockField.GetValue(packet); + } if (blockObj == null) throw new Exception("Got " + name + "Packet." + block + " == null"); - Console.WriteLine("Got block " + name + "Packet." + block); + //Console.WriteLine("Got block " + name + "Packet." + block); continue; } @@ -543,20 +521,12 @@ public class Analyst { Type packetClass = libslAssembly.GetType("libsecondlife.Packets." + name + "Packet"); if (packetClass == null) throw new Exception("Couldn't get class " + name + "Packet"); - /* try { - packetMap = protocolManager.Command(name); - } catch { - throw new Exception("unkown packet " + name); - } */ - - - //FIXME: support variable blocks FieldInfo blockField = packetClass.GetField(block); if (blockField == null) throw new Exception("Couldn't get " + name + "Packet." + block); Type blockClass = blockField.FieldType; if (blockClass.IsArray) blockClass = blockClass.GetElementType(); - Console.WriteLine("DEBUG: " + blockClass.Name); + // Console.WriteLine("DEBUG: " + blockClass.Name); FieldInfo fieldField = blockClass.GetField(field); PropertyInfo fieldProp = null; Type fieldClass = null; @@ -719,20 +689,20 @@ public class Analyst throw new Exception("unknown block " + name + "." + block); */ } - // AnalyzeIn: analyze an incoming packet - private static Packet AnalyzeIn(Packet packet, IPEndPoint endPoint) + // ModifyIn: modify an incoming packet + private static Packet ModifyIn(Packet packet, IPEndPoint endPoint) { - return Analyze(packet, endPoint, Direction.Incoming); + return Modify(packet, endPoint, Direction.Incoming); } - // AnalyzeOut: analyze an outgoing packet - private static Packet AnalyzeOut(Packet packet, IPEndPoint endPoint) + // ModifyOut: modify an outgoing packet + private static Packet ModifyOut(Packet packet, IPEndPoint endPoint) { - return Analyze(packet, endPoint, Direction.Outgoing); + return Modify(packet, endPoint, Direction.Outgoing); } - // Analyze: modify and/or log a packet - private static Packet Analyze(Packet packet, IPEndPoint endPoint, Direction direction) + // Modify: modify a packet + private static Packet Modify(Packet packet, IPEndPoint endPoint, Direction direction) { if (modifiedPackets.Contains(packet.Type)) { @@ -758,9 +728,20 @@ public class Analyst } } - if (loggedPackets.Contains(packet.Type)) - LogPacket(packet, endPoint, direction); + return packet; + } + // LogPacketIn: log an incoming packet + private static Packet LogPacketIn(Packet packet, IPEndPoint endPoint) + { + LogPacket(packet, endPoint, Direction.Incoming); + return packet; + } + + // LogPacketOut: log an outgoing packet + private static Packet LogPacketOut(Packet packet, IPEndPoint endPoint) + { + LogPacket(packet, endPoint, Direction.Outgoing); return packet; } @@ -788,11 +769,8 @@ public class Analyst loggedPackets[pType] = null; - if (pType != PacketType.ChatFromViewer) - { - proxy.AddDelegate(pType, Direction.Incoming, new PacketDelegate(AnalyzeIn)); - proxy.AddDelegate(pType, Direction.Outgoing, new PacketDelegate(AnalyzeOut)); - } + proxy.AddDelegate(pType, Direction.Incoming, new PacketDelegate(LogPacketIn)); + proxy.AddDelegate(pType, Direction.Outgoing, new PacketDelegate(LogPacketOut)); } } } @@ -821,11 +799,8 @@ public class Analyst loggedPackets.Remove(pType); - if (pType != PacketType.ChatFromViewer) - { - proxy.RemoveDelegate(pType, Direction.Incoming); - proxy.RemoveDelegate(pType, Direction.Outgoing); - } + proxy.RemoveDelegate(pType, Direction.Incoming, new PacketDelegate(LogPacketIn)); + proxy.RemoveDelegate(pType, Direction.Outgoing, new PacketDelegate(LogPacketOut)); } } } diff --git a/applications/SLProxy/SLProxy.cs b/applications/SLProxy/SLProxy.cs index c7b09241..1e4c72c3 100644 --- a/applications/SLProxy/SLProxy.cs +++ b/applications/SLProxy/SLProxy.cs @@ -208,14 +208,39 @@ namespace SLProxy { // AddDelegate: add callback packetDelegate for packets of type packetName going direction public void AddDelegate(PacketType packetType, Direction direction, PacketDelegate packetDelegate) { lock(this) { - (direction == Direction.Incoming ? incomingDelegates : outgoingDelegates)[packetType] = packetDelegate; + Dictionary> delegates = (direction == Direction.Incoming ? incomingDelegates : outgoingDelegates); + if (!delegates.ContainsKey(packetType)) { + delegates[packetType] = new List(); + } + List delegateArray = delegates[packetType]; + if(!delegateArray.Contains(packetDelegate)) { + delegateArray.Add(packetDelegate); + } }} // RemoveDelegate: remove callback for packets of type packetName going direction - public void RemoveDelegate(PacketType packetType, Direction direction) { lock(this) { - (direction == Direction.Incoming ? incomingDelegates : outgoingDelegates).Remove(packetType); + public void RemoveDelegate(PacketType packetType, Direction direction, PacketDelegate packetDelegate) { lock(this) { + Dictionary> delegates = (direction == Direction.Incoming ? incomingDelegates : outgoingDelegates); + if (!delegates.ContainsKey(packetType)) { + return; + } + List delegateArray = delegates[packetType]; + if(delegateArray.Contains(packetDelegate)) { + delegateArray.Remove(packetDelegate); + } }} + private Packet callDelegates(Dictionary> delegates, Packet packet, IPEndPoint remoteEndPoint) { + PacketType origType = packet.Type; + foreach (PacketDelegate del in delegates[origType]) { + packet = del(packet, remoteEndPoint); + + // FIXME: how should we handle the packet type changing? + if(packet == null || packet.Type != origType) break; + } + return packet; + } + // InjectPacket: send packet to the client or server when direction is Incoming or Outgoing, respectively public void InjectPacket(Packet packet, Direction direction) { lock(this) { if (activeCircuit == null) { @@ -376,8 +401,8 @@ namespace SLProxy { private Hashtable proxyHandlers = new Hashtable(); private XmlRpcRequestDelegate loginRequestDelegate = null; private XmlRpcResponseDelegate loginResponseDelegate = null; - private Hashtable incomingDelegates = new Hashtable(); - private Hashtable outgoingDelegates = new Hashtable(); + private Dictionary> incomingDelegates = new Dictionary>(); + private Dictionary> outgoingDelegates = new Dictionary>(); private ArrayList queuedIncomingInjections = new ArrayList(); private ArrayList queuedOutgoingInjections = new ArrayList(); @@ -452,7 +477,7 @@ namespace SLProxy { } // pass the packet to any callback delegates - if (incomingDelegates.Contains(packet.Type)) { + if (incomingDelegates.ContainsKey(packet.Type)) { /* if (needsZero) { length = Helpers.ZeroDecode(packet.Header.Data, length, zeroBuffer); packet.Header.Data = zeroBuffer; @@ -466,7 +491,7 @@ namespace SLProxy { } try { - Packet newPacket = ((PacketDelegate)incomingDelegates[packet.Type])(packet, (IPEndPoint)remoteEndPoint); + Packet newPacket = callDelegates(incomingDelegates, packet, (IPEndPoint)remoteEndPoint); if (newPacket == null) { if ((packet.Header.Flags & Helpers.MSG_RELIABLE) != 0) simProxy.Inject(SpoofAck(oldSequence), Direction.Outgoing); @@ -766,7 +791,7 @@ namespace SLProxy { } // pass the packet to any callback delegates - if (proxy.outgoingDelegates.Contains(packet.Type)) { + if (proxy.outgoingDelegates.ContainsKey(packet.Type)) { /* if (packet.Header.Zerocoded) { length = Helpers.ZeroDecode(packet.Header.Data, length, zeroBuffer); packet.Header.Data = zeroBuffer; @@ -780,7 +805,7 @@ namespace SLProxy { } try { - Packet newPacket = ((PacketDelegate)proxy.outgoingDelegates[packet.Type])(packet, remoteEndPoint); + Packet newPacket = proxy.callDelegates(proxy.outgoingDelegates, packet, remoteEndPoint); if (newPacket == null) { if ((packet.Header.Flags & Helpers.MSG_RELIABLE) != 0) Inject(proxy.SpoofAck(oldSequence), Direction.Incoming); @@ -952,10 +977,8 @@ namespace SLProxy { #endif } if (ackCount == 0) { - byte[] newData = new byte[length -= 1]; - Array.Copy(packet.Header.Data, 0, newData, 0, length); - newData[0] ^= Helpers.MSG_APPENDED_ACKS; - packet.Header.Data = newData; + packet.Header.Flags ^= Helpers.MSG_APPENDED_ACKS; + packet.Header.AckList = new uint[0]; } }