* Internal callback mechanism, user callback hashtable is now UserCallbacks
* Moved some of the packet receiving logic in to internal callbacks * Fixed HORRIBLE threading race condition with Circuit.Buffer[] git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@22 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
@@ -9,7 +9,7 @@ using System.Security.Cryptography;
|
||||
|
||||
namespace libsecondlife
|
||||
{
|
||||
public delegate void PacketCallback(Packet packet);
|
||||
public delegate void PacketCallback(Packet packet, Circuit circuit);
|
||||
|
||||
internal class AcceptAllCertificatePolicy : ICertificatePolicy
|
||||
{
|
||||
@@ -36,6 +36,8 @@ namespace libsecondlife
|
||||
private EndPoint endPoint;
|
||||
private ProtocolManager Protocol;
|
||||
private NetworkManager Network;
|
||||
private Hashtable UserCallbacks;
|
||||
private Hashtable InternalCallbacks;
|
||||
private byte[] Buffer;
|
||||
private Socket Connection;
|
||||
private AsyncCallback ReceivedData;
|
||||
@@ -48,10 +50,13 @@ namespace libsecondlife
|
||||
private Mutex NeedAckMutex;
|
||||
private int ResendTick;
|
||||
|
||||
public Circuit(ProtocolManager protocol, NetworkManager network, uint circuitCode)
|
||||
public Circuit(ProtocolManager protocol, NetworkManager network, Hashtable userCallbacks,
|
||||
Hashtable internalCallbacks, uint circuitCode)
|
||||
{
|
||||
Protocol = protocol;
|
||||
Network = network;
|
||||
UserCallbacks = userCallbacks;
|
||||
InternalCallbacks = internalCallbacks;
|
||||
CircuitCode = circuitCode;
|
||||
Sequence = 0;
|
||||
Buffer = new byte[4096];
|
||||
@@ -177,6 +182,7 @@ namespace libsecondlife
|
||||
byte[] zeroBuffer = new byte[4096];
|
||||
int zeroBytes;
|
||||
|
||||
// DEBUG
|
||||
//Console.WriteLine("Sending " + packet.Data.Length + " byte " + packet.Layout.Name);
|
||||
|
||||
try
|
||||
@@ -241,6 +247,7 @@ namespace libsecondlife
|
||||
|
||||
int numSent = Connection.Send(zeroBuffer, zeroBytes, SocketFlags.None);
|
||||
|
||||
// DEBUG
|
||||
//Console.WriteLine("Sent " + numSent + " bytes");
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -275,6 +282,7 @@ namespace libsecondlife
|
||||
// Bypass SendPacket since we are taking care of the AckOutbox ourself
|
||||
int numSent = Connection.Send(packet.Data);
|
||||
|
||||
// DEBUG
|
||||
//Console.WriteLine("Sent " + numSent + " byte " + packet.Layout.Name);
|
||||
|
||||
AckOutbox.Clear();
|
||||
@@ -302,9 +310,6 @@ namespace libsecondlife
|
||||
// Retrieve the incoming packet
|
||||
int numBytes = Connection.EndReceiveFrom(result, ref endPoint);
|
||||
|
||||
// Start listening again immediately
|
||||
Connection.BeginReceiveFrom(Buffer, 0, Buffer.Length, SocketFlags.None, ref endPoint, ReceivedData, null);
|
||||
|
||||
if ((Buffer[Buffer.Length - 1] & Helpers.MSG_APPENDED_ACKS) != 0)
|
||||
{
|
||||
// Grab the ACKs that are appended to this packet
|
||||
@@ -345,14 +350,22 @@ namespace libsecondlife
|
||||
// Allocate a temporary buffer for the zerodecoded packet
|
||||
byte[] zeroBuffer = new byte[4096];
|
||||
int zeroBytes = Helpers.ZeroDecode(Buffer, numBytes, zeroBuffer);
|
||||
Array.Copy(zeroBuffer, 0, Buffer, 0, zeroBytes);
|
||||
packet = new Packet(zeroBuffer, zeroBytes, Protocol);
|
||||
numBytes = zeroBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create the packet object from our byte array
|
||||
packet = new Packet(Buffer, numBytes, Protocol);
|
||||
}
|
||||
|
||||
// Create the packet object from our byte array
|
||||
packet = new Packet(Buffer, numBytes, Protocol);
|
||||
// DEBUG
|
||||
//Console.WriteLine("Received a " + numBytes + " byte " + packet.Layout.Name);
|
||||
|
||||
if ((Buffer[0] & Helpers.MSG_RELIABLE) != 0)
|
||||
// Start listening again since we're done with Buffer
|
||||
Connection.BeginReceiveFrom(Buffer, 0, Buffer.Length, SocketFlags.None, ref endPoint, ReceivedData, null);
|
||||
|
||||
if ((packet.Data[0] & Helpers.MSG_RELIABLE) != 0)
|
||||
{
|
||||
if (!AckOutbox.Contains((uint)packet.Sequence))
|
||||
{
|
||||
@@ -383,19 +396,13 @@ namespace libsecondlife
|
||||
Helpers.Log("Received an unrecognized packet", Helpers.LogLevel.Warning);
|
||||
return;
|
||||
}
|
||||
else if (packet.Layout.Name == "StartPingCheck")
|
||||
{
|
||||
//TODO: Should we care about OldestUnacked?
|
||||
|
||||
// Respond to the ping request
|
||||
Packet pingPacket = PacketBuilder.CompletePingCheck(Protocol, packet.Data[5]);
|
||||
SendPacket(pingPacket, true);
|
||||
}
|
||||
else if (packet.Layout.Name == "PacketAck")
|
||||
{
|
||||
// PacketAck is handled directly instead of using a callback to simplify access to
|
||||
// the NeedAck hashtable and its mutex
|
||||
|
||||
ArrayList blocks = packet.Blocks();
|
||||
|
||||
// Claim the NeedAck mutex
|
||||
NeedAckMutex.WaitOne();
|
||||
|
||||
// Remove each ACK in this packet from the NeedAck waiting list
|
||||
@@ -412,30 +419,39 @@ namespace libsecondlife
|
||||
if ((uint)reliablePacket.Sequence == (uint)field.Data)
|
||||
{
|
||||
NeedAck.Remove(reliablePacket);
|
||||
// Restart the loop to avoid upsetting the enumerator
|
||||
goto Beginning;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Release the mutex
|
||||
NeedAckMutex.ReleaseMutex();
|
||||
}
|
||||
|
||||
// Fire any internal callbacks registered with this packet type
|
||||
PacketCallback callback = (PacketCallback)InternalCallbacks[packet.Layout.Name];
|
||||
|
||||
// Fire any callbacks registered with this packet type
|
||||
PacketCallback callback = (PacketCallback)Network.Callbacks[packet.Layout.Name];
|
||||
if (callback != null)
|
||||
{
|
||||
callback(packet, this);
|
||||
}
|
||||
|
||||
// Fire any user callbacks registered with this packet type
|
||||
callback = (PacketCallback)UserCallbacks[packet.Layout.Name];
|
||||
|
||||
if (callback != null)
|
||||
{
|
||||
callback(packet);
|
||||
callback(packet, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
callback = (PacketCallback)Network.Callbacks["Default"];
|
||||
// Attempt to fire a default user callback
|
||||
callback = (PacketCallback)UserCallbacks["Default"];
|
||||
|
||||
if (callback != null)
|
||||
{
|
||||
callback(packet);
|
||||
callback(packet, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -537,20 +553,27 @@ namespace libsecondlife
|
||||
{
|
||||
public LoginReply LoginValues;
|
||||
public string LoginError;
|
||||
public Hashtable Callbacks;
|
||||
public Hashtable UserCallbacks;
|
||||
public Circuit CurrentCircuit;
|
||||
|
||||
private ProtocolManager Protocol;
|
||||
private string LoginBuffer;
|
||||
private ArrayList Circuits;
|
||||
//private Hashtable InternalCallbacks;
|
||||
private Hashtable InternalCallbacks;
|
||||
|
||||
public NetworkManager(ProtocolManager protocol)
|
||||
{
|
||||
Protocol = protocol;
|
||||
Circuits = new ArrayList();
|
||||
Callbacks = new Hashtable();
|
||||
UserCallbacks = new Hashtable();
|
||||
InternalCallbacks = new Hashtable();
|
||||
CurrentCircuit = null;
|
||||
|
||||
// Register the internal callbacks
|
||||
PacketCallback callback = new PacketCallback(RegionHandshakeHandler);
|
||||
InternalCallbacks["RegionHandshake"] = callback;
|
||||
callback = new PacketCallback(StartPingCheckHandler);
|
||||
InternalCallbacks["StartPingCheck"] = callback;
|
||||
}
|
||||
|
||||
public void SendPacket(Packet packet)
|
||||
@@ -565,6 +588,11 @@ namespace libsecondlife
|
||||
}
|
||||
}
|
||||
|
||||
public void SendPacket(Packet packet, Circuit circuit)
|
||||
{
|
||||
circuit.SendPacket(packet, true);
|
||||
}
|
||||
|
||||
public bool Login(string firstName, string lastName, string password, string mac,
|
||||
int major, int minor, int patch, int build, string platform, string viewerDigest,
|
||||
string userAgent, string author)
|
||||
@@ -654,7 +682,7 @@ namespace libsecondlife
|
||||
}
|
||||
|
||||
// Connect to the sim given in the login reply
|
||||
Circuit circuit = new Circuit(Protocol, this, LoginValues.CircuitCode);
|
||||
Circuit circuit = new Circuit(Protocol, this, UserCallbacks, InternalCallbacks, LoginValues.CircuitCode);
|
||||
if (!circuit.Open(LoginValues.IP, LoginValues.Port))
|
||||
{
|
||||
return false;
|
||||
@@ -784,5 +812,21 @@ namespace libsecondlife
|
||||
|
||||
return Int32.Parse(rpc.Substring(0, pos2));
|
||||
}
|
||||
|
||||
private void StartPingCheckHandler(Packet packet, Circuit circuit)
|
||||
{
|
||||
//TODO: Should we care about OldestUnacked?
|
||||
|
||||
// Respond to the ping request
|
||||
Packet pingPacket = PacketBuilder.CompletePingCheck(Protocol, packet.Data[5]);
|
||||
SendPacket(pingPacket, circuit);
|
||||
}
|
||||
|
||||
private void RegionHandshakeHandler(Packet packet, Circuit circuit)
|
||||
{
|
||||
// Send a RegionHandshakeReply
|
||||
Packet replyPacket = new Packet("RegionHandshakeReply", Protocol, 12);
|
||||
SendPacket(replyPacket, circuit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,6 +435,41 @@ namespace libsecondlife
|
||||
return packet;
|
||||
}
|
||||
|
||||
public static Packet TeleportLocationRequest(ProtocolManager protocol, long regionHandle, LLVector3 lookAt,
|
||||
LLVector3 position, LLUUID agentID, LLUUID sessionID)
|
||||
{
|
||||
Packet packet = new Packet("LogoutRequest", protocol, 72);
|
||||
|
||||
Array.Copy(BitConverter.GetBytes(regionHandle), 0, packet.Data, 8, 8);
|
||||
Array.Copy(lookAt.GetBytes(), 0, packet.Data, 16, 12);
|
||||
Array.Copy(position.GetBytes(), 0, packet.Data, 28, 12);
|
||||
Array.Copy(agentID.Data, 0, packet.Data, 40, 16);
|
||||
Array.Copy(sessionID.Data, 0, packet.Data, 56, 16);
|
||||
|
||||
packet.Data[0] = Helpers.MSG_RELIABLE;
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
public static Packet DirLandQuery(ProtocolManager protocol, bool reservedNewbie, bool forSale,
|
||||
LLUUID queryID, bool auction, uint queryFlags, LLUUID agentID, LLUUID sessionID)
|
||||
{
|
||||
Packet packet = new Packet("DirLandQuery", protocol, 63);
|
||||
|
||||
packet.Data[8] = BitConverter.GetBytes(reservedNewbie)[0];
|
||||
packet.Data[9] = BitConverter.GetBytes(forSale)[0];
|
||||
Array.Copy(queryID.Data, 0, packet.Data, 10, 16);
|
||||
packet.Data[26] = BitConverter.GetBytes(auction)[0];
|
||||
Array.Copy(BitConverter.GetBytes(queryFlags), 0, packet.Data, 27, 4);
|
||||
Array.Copy(agentID.Data, 0, packet.Data, 31, 16);
|
||||
Array.Copy(sessionID.Data, 0, packet.Data, 47, 16);
|
||||
|
||||
// Set the packet flags
|
||||
packet.Data[0] = Helpers.MSG_RELIABLE;
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
public static Packet DirFindQuery(ProtocolManager protocol, string queryText, LLUUID queryID,
|
||||
LLUUID agentID, LLUUID sessionID)
|
||||
{
|
||||
|
||||
@@ -28,40 +28,47 @@ namespace libsecondlife
|
||||
|
||||
public static int ZeroDecode(byte[] src, int srclen, byte[] dest)
|
||||
{
|
||||
int zerolen = 0;
|
||||
uint zerolen = 0;
|
||||
|
||||
Array.Copy(src, 0, dest, 0, 4);
|
||||
zerolen += 4;
|
||||
|
||||
for (int i = zerolen; i < srclen; i++)
|
||||
try
|
||||
{
|
||||
if (src[i] == 0x00)
|
||||
{
|
||||
for (byte j = 0; j < src[i + 1]; j++)
|
||||
{
|
||||
dest[zerolen++] = 0x00;
|
||||
}
|
||||
Array.Copy(src, 0, dest, 0, 4);
|
||||
zerolen += 4;
|
||||
|
||||
i++;
|
||||
}
|
||||
else
|
||||
for (uint i = zerolen; i < srclen; i++)
|
||||
{
|
||||
dest[zerolen++] = src[i];
|
||||
if (src[i] == 0x00)
|
||||
{
|
||||
for (byte j = 0; j < src[i + 1]; j++)
|
||||
{
|
||||
dest[zerolen++] = 0x00;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest[zerolen++] = src[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Helpers.Log(e.ToString(), Helpers.LogLevel.Error);
|
||||
}
|
||||
|
||||
return zerolen;
|
||||
return (int)zerolen;
|
||||
}
|
||||
|
||||
public static int ZeroEncode(byte[] src, int srclen, byte[] dest)
|
||||
{
|
||||
int zerolen = 0;
|
||||
uint zerolen = 0;
|
||||
byte zerocount = 0;
|
||||
|
||||
Array.Copy(src, 0, dest, 0, 4);
|
||||
zerolen += 4;
|
||||
|
||||
for (int i = zerolen; i < srclen; i++)
|
||||
for (uint i = zerolen; i < srclen; i++)
|
||||
{
|
||||
if (src[i] == 0x00)
|
||||
{
|
||||
@@ -93,7 +100,7 @@ namespace libsecondlife
|
||||
dest[zerolen++] = (byte)zerocount;
|
||||
}
|
||||
|
||||
return zerolen;
|
||||
return (int)zerolen;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace name2key
|
||||
static bool waiting = true;
|
||||
|
||||
//
|
||||
public static void QueryHandler(Packet packet)
|
||||
public static void QueryHandler(Packet packet, Circuit circuit)
|
||||
{
|
||||
if (packet.Layout.Name.IndexOf("Dir") > -1)
|
||||
{
|
||||
@@ -67,10 +67,10 @@ namespace name2key
|
||||
|
||||
// Setup the callback
|
||||
PacketCallback queryCallback = new PacketCallback(QueryHandler);
|
||||
client.Network.Callbacks["DirPeopleReply"] = queryCallback;
|
||||
client.Network.UserCallbacks["DirPeopleReply"] = queryCallback;
|
||||
|
||||
if (!client.Network.Login(args[0], args[1], args[2], "00:00:00:00:00:00", 1, 10, 2, 2, "Win",
|
||||
"0", "sldump", "jhurliman@wsu.edu"))
|
||||
"0", "name2key", "jhurliman@wsu.edu"))
|
||||
{
|
||||
// Login failed
|
||||
Console.WriteLine("ERROR: " + client.Network.LoginError);
|
||||
|
||||
@@ -7,10 +7,8 @@ namespace sldump
|
||||
class sldump
|
||||
{
|
||||
//
|
||||
public static void DefaultHandler(Packet packet)
|
||||
{
|
||||
Console.WriteLine("Received " + packet.Layout.Name);
|
||||
|
||||
public static void DefaultHandler(Packet packet, Circuit circuit)
|
||||
{
|
||||
string output = "";
|
||||
ArrayList blocks = packet.Blocks();
|
||||
|
||||
@@ -62,7 +60,7 @@ namespace sldump
|
||||
|
||||
// Setup the callback
|
||||
PacketCallback defaultCallback = new PacketCallback(DefaultHandler);
|
||||
client.Network.Callbacks["Default"] = defaultCallback;
|
||||
client.Network.UserCallbacks["Default"] = defaultCallback;
|
||||
|
||||
if (!client.Network.Login(args[0], args[1], args[2], "00:00:00:00:00:00", 1, 10, 2, 2, "Win",
|
||||
"0", "sldump", "jhurliman@wsu.edu"))
|
||||
|
||||
Reference in New Issue
Block a user