Major change in Simian to abstract all UDP handling away from Agent into an IUDPProvider. UDPServer is now thinly wrapped with a UDPManager extension to provide the main packet handling facilities of Simian

git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@2180 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
John Hurliman
2008-08-28 22:11:47 +00:00
parent 274ca8a290
commit fe869df89f
17 changed files with 761 additions and 645 deletions

View File

@@ -21,10 +21,10 @@ namespace Simian.Extensions
{
LoadDefaultAssets(Server.DataDir);
Server.UDPServer.RegisterPacketCallback(PacketType.AssetUploadRequest, new UDPServer.PacketCallback(AssetUploadRequestHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.SendXferPacket, new UDPServer.PacketCallback(SendXferPacketHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.AbortXfer, new UDPServer.PacketCallback(AbortXferHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.TransferRequest, new UDPServer.PacketCallback(TransferRequestHandler));
Server.UDP.RegisterPacketCallback(PacketType.AssetUploadRequest, new PacketCallback(AssetUploadRequestHandler));
Server.UDP.RegisterPacketCallback(PacketType.SendXferPacket, new PacketCallback(SendXferPacketHandler));
Server.UDP.RegisterPacketCallback(PacketType.AbortXfer, new PacketCallback(AbortXferHandler));
Server.UDP.RegisterPacketCallback(PacketType.TransferRequest, new PacketCallback(TransferRequestHandler));
}
public void Stop()
@@ -59,7 +59,7 @@ namespace Simian.Extensions
complete.AssetBlock.Success = true;
complete.AssetBlock.Type = request.AssetBlock.Type;
complete.AssetBlock.UUID = request.AssetBlock.TransactionID;
agent.SendPacket(complete);
Server.UDP.SendPacket(agent.AgentID, complete, PacketCategory.Inventory);
}
else
{
@@ -85,7 +85,7 @@ namespace Simian.Extensions
lock (CurrentUploads)
CurrentUploads[xfer.XferID.ID] = asset;
agent.SendPacket(xfer);
Server.UDP.SendPacket(agent.AgentID, xfer, PacketCategory.Inventory);
}
}
@@ -114,7 +114,7 @@ namespace Simian.Extensions
ConfirmXferPacketPacket confirm = new ConfirmXferPacketPacket();
confirm.XferID.ID = xfer.XferID.ID;
confirm.XferID.Packet = xfer.XferID.Packet;
agent.SendPacket(confirm);
Server.UDP.SendPacket(agent.AgentID, confirm, PacketCategory.Asset);
}
else
{
@@ -125,7 +125,7 @@ namespace Simian.Extensions
ConfirmXferPacketPacket confirm = new ConfirmXferPacketPacket();
confirm.XferID.ID = xfer.XferID.ID;
confirm.XferID.Packet = xfer.XferID.Packet;
agent.SendPacket(confirm);
Server.UDP.SendPacket(agent.AgentID, confirm, PacketCategory.Asset);
if ((xfer.XferID.Packet & (uint)0x80000000) != 0)
{
@@ -142,7 +142,7 @@ namespace Simian.Extensions
complete.AssetBlock.Success = true;
complete.AssetBlock.Type = (sbyte)asset.AssetType;
complete.AssetBlock.UUID = asset.AssetID;
agent.SendPacket(complete);
Server.UDP.SendPacket(agent.AgentID, complete, PacketCategory.Asset);
}
}
}
@@ -218,7 +218,7 @@ namespace Simian.Extensions
response.TransferInfo.Status = (int)StatusCode.OK;
response.TransferInfo.TargetType = (int)TargetType.Unknown; // Doesn't seem to be used by the client
agent.SendPacket(response);
Server.UDP.SendPacket(agent.AgentID, response, PacketCategory.Asset);
// Transfer system does not wait for ACKs, just sends all of the
// packets for this transfer out
@@ -242,7 +242,7 @@ namespace Simian.Extensions
else
transfer.TransferData.Status = (int)StatusCode.OK;
agent.SendPacket(transfer);
Server.UDP.SendPacket(agent.AgentID, transfer, PacketCategory.Asset);
}
}
else
@@ -259,7 +259,7 @@ namespace Simian.Extensions
response.TransferInfo.Status = (int)StatusCode.UnknownSource;
response.TransferInfo.TargetType = (int)TargetType.Unknown;
agent.SendPacket(response);
Server.UDP.SendPacket(agent.AgentID, response, PacketCategory.Asset);
}
}
else if (source == SourceType.SimEstate)

View File

@@ -19,13 +19,13 @@ namespace Simian.Extensions
public void Start()
{
Server.UDPServer.RegisterPacketCallback(PacketType.AvatarPropertiesRequest, new UDPServer.PacketCallback(AvatarPropertiesRequestHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.AgentWearablesRequest, new UDPServer.PacketCallback(AgentWearablesRequestHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.AgentIsNowWearing, new UDPServer.PacketCallback(AgentIsNowWearingHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.AgentSetAppearance, new UDPServer.PacketCallback(AgentSetAppearanceHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.AgentAnimation, new UDPServer.PacketCallback(AgentAnimationHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.ViewerEffect, new UDPServer.PacketCallback(ViewerEffectHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.UUIDNameRequest, new UDPServer.PacketCallback(UUIDNameRequestHandler));
Server.UDP.RegisterPacketCallback(PacketType.AvatarPropertiesRequest, new PacketCallback(AvatarPropertiesRequestHandler));
Server.UDP.RegisterPacketCallback(PacketType.AgentWearablesRequest, new PacketCallback(AgentWearablesRequestHandler));
Server.UDP.RegisterPacketCallback(PacketType.AgentIsNowWearing, new PacketCallback(AgentIsNowWearingHandler));
Server.UDP.RegisterPacketCallback(PacketType.AgentSetAppearance, new PacketCallback(AgentSetAppearanceHandler));
Server.UDP.RegisterPacketCallback(PacketType.AgentAnimation, new PacketCallback(AgentAnimationHandler));
Server.UDP.RegisterPacketCallback(PacketType.ViewerEffect, new PacketCallback(ViewerEffectHandler));
Server.UDP.RegisterPacketCallback(PacketType.UUIDNameRequest, new PacketCallback(UUIDNameRequestHandler));
}
public void Stop()
@@ -67,11 +67,7 @@ namespace Simian.Extensions
sendAnim.AnimationList[i].AnimSequenceID = sequenceNums[i];
}
lock (Server.Agents)
{
foreach (Agent recipient in Server.Agents.Values)
recipient.SendPacket(sendAnim);
}
Server.UDP.BroadcastPacket(sendAnim, PacketCategory.State);
}
void AgentAnimationHandler(Packet packet, Agent agent)
@@ -106,12 +102,7 @@ namespace Simian.Extensions
effect.AgentData.AgentID = UUID.Zero;
effect.AgentData.SessionID = UUID.Zero;
// Broadcast this to everyone
lock (Server.Agents)
{
foreach (Agent recipient in Server.Agents.Values)
recipient.SendPacket(effect);
}
Server.UDP.BroadcastPacket(effect, PacketCategory.State);
}
void AvatarPropertiesRequestHandler(Packet packet, Agent agent)
@@ -139,8 +130,7 @@ namespace Simian.Extensions
reply.PropertiesData.PartnerID = UUID.Zero;
reply.PropertiesData.ProfileURL = Utils.StringToBytes(String.Empty);
agent.SendPacket(reply);
Server.UDP.SendPacket(agent.AgentID, reply, PacketCategory.Transaction);
break;
}
}
@@ -182,7 +172,7 @@ namespace Simian.Extensions
update.WearableData[4].ItemID = UUID.Random();
update.WearableData[4].WearableType = (byte)WearableType.Skin;
agent.SendPacket(update);
Server.UDP.SendPacket(agent.AgentID, update, PacketCategory.Asset);
}
void AgentIsNowWearingHandler(Packet packet, Agent agent)
@@ -218,19 +208,11 @@ namespace Simian.Extensions
ObjectUpdatePacket update = Movement.BuildFullUpdate(agent.Avatar,
NameValue.NameValuesToString(agent.Avatar.NameValues), Server.RegionHandle,
agent.State, agent.Flags | PrimFlags.ObjectYouOwner);
agent.SendPacket(update);
Server.UDP.SendPacket(agent.AgentID, update, PacketCategory.State);
// Send out this appearance to all other connected avatars
AvatarAppearancePacket appearance = BuildAppearancePacket(agent);
lock (Server.Agents)
{
foreach (Agent recipient in Server.Agents.Values)
{
if (recipient != agent)
recipient.SendPacket(appearance);
}
}
Server.UDP.BroadcastPacket(appearance, PacketCategory.State);
}
void UUIDNameRequestHandler(Packet packet, Agent agent)
@@ -268,7 +250,7 @@ namespace Simian.Extensions
reply.UUIDNameBlock[i].LastName = Utils.StringToBytes(kvp.Value.LastName);
}
agent.SendPacket(reply);
Server.UDP.SendPacket(agent.AgentID, reply, PacketCategory.Transaction);
}
}

View File

@@ -33,33 +33,42 @@ namespace Simian.Extensions
{
lock (Server.Agents)
{
List<Vector3> avatarPositions = new List<Vector3>();
CoarseLocationUpdatePacket update = new CoarseLocationUpdatePacket();
update.AgentData = new CoarseLocationUpdatePacket.AgentDataBlock[Server.Agents.Count];
update.Location = new CoarseLocationUpdatePacket.LocationBlock[Server.Agents.Count];
short i = 0;
foreach (Agent agent in Server.Agents.Values)
{
update.AgentData[i] = new CoarseLocationUpdatePacket.AgentDataBlock();
update.AgentData[i].AgentID = agent.AgentID;
update.Location[i] = new CoarseLocationUpdatePacket.LocationBlock();
update.Location[i].X = (byte)((int)agent.Avatar.Position.X);
update.Location[i].Y = (byte)((int)agent.Avatar.Position.Y);
update.Location[i].Z = (byte)((int)agent.Avatar.Position.Z / 4);
update.Index.Prey = -1;
i++;
}
i = 0;
foreach (Agent recipient in Server.Agents.Values)
{
update.Index.You = i;
recipient.SendPacket(update);
i++;
}
int i = 0;
CoarseLocationUpdatePacket update = new CoarseLocationUpdatePacket();
update.Index.Prey = -1;
update.Index.You = 0;
update.AgentData = new CoarseLocationUpdatePacket.AgentDataBlock[Server.Agents.Count];
update.Location = new CoarseLocationUpdatePacket.LocationBlock[Server.Agents.Count];
// Fill in this avatar
update.AgentData[0] = new CoarseLocationUpdatePacket.AgentDataBlock();
update.AgentData[0].AgentID = recipient.AgentID;
update.Location[0] = new CoarseLocationUpdatePacket.LocationBlock();
update.Location[0].X = (byte)((int)recipient.Avatar.Position.X);
update.Location[0].Y = (byte)((int)recipient.Avatar.Position.Y);
update.Location[0].Z = (byte)((int)recipient.Avatar.Position.Z / 4);
++i;
foreach (Agent agent in Server.Agents.Values)
{
if (agent != recipient)
{
update.AgentData[i] = new CoarseLocationUpdatePacket.AgentDataBlock();
update.AgentData[i].AgentID = agent.AgentID;
update.Location[i] = new CoarseLocationUpdatePacket.LocationBlock();
update.Location[i].X = (byte)((int)agent.Avatar.Position.X);
update.Location[i].Y = (byte)((int)agent.Avatar.Position.Y);
update.Location[i].Z = (byte)((int)agent.Avatar.Position.Z / 4);
++i;
}
}
Server.UDP.SendPacket(recipient.AgentID, update, PacketCategory.State);
}
}
}
}

View File

@@ -15,9 +15,9 @@ namespace Simian.Extensions
public void Start()
{
server.UDPServer.RegisterPacketCallback(PacketType.UseCircuitCode, new UDPServer.PacketCallback(UseCircuitCodeHandler));
server.UDPServer.RegisterPacketCallback(PacketType.StartPingCheck, new UDPServer.PacketCallback(StartPingCheckHandler));
server.UDPServer.RegisterPacketCallback(PacketType.LogoutRequest, new UDPServer.PacketCallback(LogoutRequestHandler));
server.UDP.RegisterPacketCallback(PacketType.UseCircuitCode, new PacketCallback(UseCircuitCodeHandler));
server.UDP.RegisterPacketCallback(PacketType.StartPingCheck, new PacketCallback(StartPingCheckHandler));
server.UDP.RegisterPacketCallback(PacketType.LogoutRequest, new PacketCallback(LogoutRequestHandler));
}
@@ -54,7 +54,7 @@ namespace Simian.Extensions
handshake.RegionInfo.TerrainStartHeight11 = 40f;
handshake.RegionInfo2.RegionID = UUID.Random();
agent.SendPacket(handshake);
server.UDP.SendPacket(agent.AgentID, handshake, PacketCategory.Transaction);
}
void StartPingCheckHandler(Packet packet, Agent agent)
@@ -65,7 +65,7 @@ namespace Simian.Extensions
complete.Header.Reliable = false;
complete.PingID.PingID = start.PingID.PingID;
agent.SendPacket(complete);
server.UDP.SendPacket(agent.AgentID, complete, PacketCategory.Overhead);
}
void LogoutRequestHandler(Packet packet, Agent agent)
@@ -79,24 +79,24 @@ namespace Simian.Extensions
reply.InventoryData[0] = new LogoutReplyPacket.InventoryDataBlock();
reply.InventoryData[0].ItemID = UUID.Zero;
agent.SendPacket(reply);
server.UDP.SendPacket(agent.AgentID, reply, PacketCategory.Transaction);
lock (server.Agents)
{
if (server.Agents.ContainsKey(agent.Address))
if (server.Agents.ContainsKey(agent.AgentID))
{
KillObjectPacket kill = new KillObjectPacket();
kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
kill.ObjectData[0].ID = agent.Avatar.LocalID;
agent.Dispose();
server.Agents.Remove(agent.Address);
server.UDP.BroadcastPacket(kill, PacketCategory.State);
foreach (Agent recipient in server.Agents.Values)
recipient.SendPacket(kill);
server.Agents.Remove(agent.AgentID);
}
}
server.UDP.RemoveClient(agent);
}
}
}

View File

@@ -20,7 +20,7 @@ namespace Simian.Extensions
public void Start()
{
Server.UDPServer.RegisterPacketCallback(PacketType.RequestImage, new UDPServer.PacketCallback(RequestImageHandler));
Server.UDP.RegisterPacketCallback(PacketType.RequestImage, new PacketCallback(RequestImageHandler));
Bitmap defaultImage = new Bitmap(32, 32);
Graphics gfx = Graphics.FromImage(defaultImage);
@@ -69,7 +69,7 @@ namespace Simian.Extensions
}
imageData.ImageID.Size = (uint)imageData.ImageData.Data.Length;
agent.SendPacket(imageData);
Server.UDP.SendPacket(agent.AgentID, imageData, PacketCategory.Texture);
}
}
}

View File

@@ -16,10 +16,10 @@ namespace Simian.Extensions
public void Start()
{
Server.UDPServer.RegisterPacketCallback(PacketType.CreateInventoryItem, new UDPServer.PacketCallback(CreateInventoryItemHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.CreateInventoryFolder, new UDPServer.PacketCallback(CreateInventoryFolderHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.UpdateInventoryItem, new UDPServer.PacketCallback(UpdateInventoryItemHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.FetchInventoryDescendents, new UDPServer.PacketCallback(FetchInventoryDescendentsHandler));
Server.UDP.RegisterPacketCallback(PacketType.CreateInventoryItem, new PacketCallback(CreateInventoryItemHandler));
Server.UDP.RegisterPacketCallback(PacketType.CreateInventoryFolder, new PacketCallback(CreateInventoryFolderHandler));
Server.UDP.RegisterPacketCallback(PacketType.UpdateInventoryItem, new PacketCallback(UpdateInventoryItemHandler));
Server.UDP.RegisterPacketCallback(PacketType.FetchInventoryDescendents, new PacketCallback(FetchInventoryDescendentsHandler));
}
public void Stop()
@@ -275,7 +275,7 @@ namespace Simian.Extensions
}
}
agent.SendPacket(descendents);
Server.UDP.SendPacket(agent.AgentID, descendents, PacketCategory.Inventory);
}
}
else
@@ -358,8 +358,7 @@ namespace Simian.Extensions
update.InventoryData[0].SaleType = (byte)item.SaleType;
update.InventoryData[0].Type = (sbyte)item.AssetType;
agent.SendPacket(update);
Server.UDP.SendPacket(agent.AgentID, update, PacketCategory.Inventory);
return item.ID;
}
else

View File

@@ -18,8 +18,8 @@ namespace Simian.Extensions
public void Start()
{
Server.UDPServer.RegisterPacketCallback(PacketType.ChatFromViewer, new UDPServer.PacketCallback(ChatFromViewerHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.ImprovedInstantMessage, new UDPServer.PacketCallback(ImprovedInstantMessageHandler));
Server.UDP.RegisterPacketCallback(PacketType.ChatFromViewer, new PacketCallback(ChatFromViewerHandler));
Server.UDP.RegisterPacketCallback(PacketType.ImprovedInstantMessage, new PacketCallback(ImprovedInstantMessageHandler));
}
public void Stop()
@@ -44,11 +44,7 @@ namespace Simian.Extensions
chat.ChatData.FromName = Utils.StringToBytes(agent.Avatar.Name);
chat.ChatData.Message = viewerChat.ChatData.Message;
lock (Server.Agents)
{
foreach(Agent recipient in Server.Agents.Values)
recipient.SendPacket(chat);
}
Server.UDP.BroadcastPacket(chat, PacketCategory.Transaction);
}
void ImprovedInstantMessageHandler(Packet packet, Agent agent)
@@ -76,8 +72,9 @@ namespace Simian.Extensions
sendIM.MessageBlock.Message = im.MessageBlock.Message;
sendIM.MessageBlock.BinaryBucket = new byte[0];
sendIM.MessageBlock.Timestamp = 0;
sendIM.MessageBlock.Position = agent.Avatar.Position;
recipient.SendPacket(sendIM);
sendIM.MessageBlock.Position = agent.Avatar.Position;
Server.UDP.SendPacket(recipient.AgentID, sendIM, PacketCategory.Transaction);
break;
}

View File

@@ -17,8 +17,8 @@ namespace Simian.Extensions
public void Start()
{
Server.UDPServer.RegisterPacketCallback(PacketType.MoneyBalanceRequest, new UDPServer.PacketCallback(MoneyBalanceRequestHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.MoneyTransferRequest, new UDPServer.PacketCallback(MoneyTransferRequestHandler));
Server.UDP.RegisterPacketCallback(PacketType.MoneyBalanceRequest, new PacketCallback(MoneyBalanceRequestHandler));
Server.UDP.RegisterPacketCallback(PacketType.MoneyTransferRequest, new PacketCallback(MoneyTransferRequestHandler));
}
public void Stop()
@@ -33,7 +33,7 @@ namespace Simian.Extensions
reply.MoneyData.TransactionID = transactionID;
reply.MoneyData.Description = Utils.StringToBytes(message);
agent.SendPacket(reply);
Server.UDP.SendPacket(agent.AgentID, reply, PacketCategory.Transaction);
}
void MoneyBalanceRequestHandler(Packet packet, Agent agent)

View File

@@ -41,9 +41,9 @@ namespace Simian.Extensions
public void Start()
{
server.UDPServer.RegisterPacketCallback(PacketType.AgentUpdate, new UDPServer.PacketCallback(AgentUpdateHandler));
server.UDPServer.RegisterPacketCallback(PacketType.AgentHeightWidth, new UDPServer.PacketCallback(AgentHeightWidthHandler));
server.UDPServer.RegisterPacketCallback(PacketType.SetAlwaysRun, new UDPServer.PacketCallback(SetAlwaysRunHandler));
server.UDP.RegisterPacketCallback(PacketType.AgentUpdate, new PacketCallback(AgentUpdateHandler));
server.UDP.RegisterPacketCallback(PacketType.AgentHeightWidth, new PacketCallback(AgentHeightWidthHandler));
server.UDP.RegisterPacketCallback(PacketType.SetAlwaysRun, new PacketCallback(SetAlwaysRunHandler));
updateTimer = new Timer(new TimerCallback(UpdateTimer_Elapsed));
LastTick = Environment.TickCount;
@@ -324,11 +324,7 @@ namespace Simian.Extensions
NameValue.NameValuesToString(agent.Avatar.NameValues), server.RegionHandle,
agent.State, agent.Flags);
lock (server.Agents)
{
foreach (Agent recipient in server.Agents.Values)
recipient.SendPacket(fullUpdate);
}
server.UDP.BroadcastPacket(fullUpdate, PacketCategory.State);
}
void SetAlwaysRunHandler(Packet packet, Agent agent)

View File

@@ -21,13 +21,13 @@ namespace Simian.Extensions
public void Start()
{
Server.UDPServer.RegisterPacketCallback(PacketType.ObjectAdd, new UDPServer.PacketCallback(ObjectAddHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.ObjectSelect, new UDPServer.PacketCallback(ObjectSelectHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.ObjectDeselect, new UDPServer.PacketCallback(ObjectDeselectHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.ObjectShape, new UDPServer.PacketCallback(ObjectShapeHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.DeRezObject, new UDPServer.PacketCallback(DeRezObjectHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.MultipleObjectUpdate, new UDPServer.PacketCallback(MultipleObjectUpdateHandler));
Server.UDPServer.RegisterPacketCallback(PacketType.RequestObjectPropertiesFamily, new UDPServer.PacketCallback(RequestObjectPropertiesFamilyHandler));
Server.UDP.RegisterPacketCallback(PacketType.ObjectAdd, new PacketCallback(ObjectAddHandler));
Server.UDP.RegisterPacketCallback(PacketType.ObjectSelect, new PacketCallback(ObjectSelectHandler));
Server.UDP.RegisterPacketCallback(PacketType.ObjectDeselect, new PacketCallback(ObjectDeselectHandler));
Server.UDP.RegisterPacketCallback(PacketType.ObjectShape, new PacketCallback(ObjectShapeHandler));
Server.UDP.RegisterPacketCallback(PacketType.DeRezObject, new PacketCallback(DeRezObjectHandler));
Server.UDP.RegisterPacketCallback(PacketType.MultipleObjectUpdate, new PacketCallback(MultipleObjectUpdateHandler));
Server.UDP.RegisterPacketCallback(PacketType.RequestObjectPropertiesFamily, new PacketCallback(RequestObjectPropertiesFamilyHandler));
}
public void Stop()
@@ -172,7 +172,7 @@ namespace Simian.Extensions
// Send an update out to the creator
ObjectUpdatePacket updateToOwner = Movement.BuildFullUpdate(prim, String.Empty, prim.RegionHandle, 0,
prim.Flags | PrimFlags.CreateSelected | PrimFlags.ObjectYouOwner);
agent.SendPacket(updateToOwner);
Server.UDP.SendPacket(agent.AgentID, updateToOwner, PacketCategory.State);
// Send an update out to everyone else
ObjectUpdatePacket updateToOthers = Movement.BuildFullUpdate(prim, String.Empty, prim.RegionHandle, 0,
@@ -182,7 +182,7 @@ namespace Simian.Extensions
foreach (Agent recipient in Server.Agents.Values)
{
if (recipient != agent)
recipient.SendPacket(updateToOthers);
Server.UDP.SendPacket(recipient.AgentID, updateToOthers, PacketCategory.State);
}
}
}
@@ -223,7 +223,7 @@ namespace Simian.Extensions
}
}
agent.SendPacket(properties);
Server.UDP.SendPacket(agent.AgentID, properties, PacketCategory.Transaction);
}
void ObjectDeselectHandler(Packet packet, Agent agent)
@@ -266,11 +266,7 @@ namespace Simian.Extensions
// Send the update out to everyone
ObjectUpdatePacket editedobj = Movement.BuildFullUpdate(obj.Prim, String.Empty, obj.Prim.RegionHandle, 0,
obj.Prim.Flags);
lock (Server.Agents)
{
foreach (Agent recipient in Server.Agents.Values)
recipient.SendPacket(editedobj);
}
Server.UDP.BroadcastPacket(editedobj, PacketCategory.State);
}
else
{
@@ -408,11 +404,7 @@ namespace Simian.Extensions
// Send the update out to everyone
ObjectUpdatePacket editedobj = Movement.BuildFullUpdate(obj.Prim, String.Empty, obj.Prim.RegionHandle, 0,
obj.Prim.Flags);
lock (Server.Agents)
{
foreach (Agent recipient in Server.Agents.Values)
recipient.SendPacket(editedobj);
}
Server.UDP.BroadcastPacket(editedobj, PacketCategory.State);
}
else
{
@@ -422,7 +414,7 @@ namespace Simian.Extensions
kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
kill.ObjectData[0].ID = block.ObjectLocalID;
agent.SendPacket(kill);
Server.UDP.SendPacket(agent.AgentID, kill, PacketCategory.State);
}
}
}
@@ -453,7 +445,7 @@ namespace Simian.Extensions
props.ObjectData.SalePrice = obj.Prim.Properties.SalePrice;
props.ObjectData.SaleType = (byte)obj.Prim.Properties.SaleType;
agent.SendPacket(props);
Server.UDP.SendPacket(agent.AgentID, props, PacketCategory.Transaction);
}
else
{
@@ -474,11 +466,7 @@ namespace Simian.Extensions
kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
kill.ObjectData[0].ID = obj.Prim.LocalID;
lock (Server.Agents)
{
foreach (Agent recipient in Server.Agents.Values)
recipient.SendPacket(kill);
}
Server.UDP.BroadcastPacket(kill, PacketCategory.State);
}
Vector3 FullSceneCollisionTest(Vector3 rayStart, Vector3 rayEnd)

View File

@@ -23,7 +23,7 @@ namespace Simian.Extensions
public void Start()
{
server.UDPServer.RegisterPacketCallback(PacketType.CompleteAgentMovement, new UDPServer.PacketCallback(CompleteAgentMovementHandler));
server.UDP.RegisterPacketCallback(PacketType.CompleteAgentMovement, new PacketCallback(CompleteAgentMovementHandler));
LoadTerrain(server.DataDir + "heightmap.tga");
}
@@ -72,7 +72,7 @@ namespace Simian.Extensions
complete.Data.Timestamp = Utils.DateTimeToUnixTime(DateTime.Now);
complete.SimData.ChannelVersion = Utils.StringToBytes("Simian");
agent.SendPacket(complete);
server.UDP.SendPacket(agent.AgentID, complete, PacketCategory.Transaction);
lock (server.Agents)
{
@@ -82,11 +82,11 @@ namespace Simian.Extensions
ObjectUpdatePacket update = Movement.BuildFullUpdate(otherAgent.Avatar,
NameValue.NameValuesToString(otherAgent.Avatar.NameValues),
server.RegionHandle, otherAgent.State, otherAgent.Flags);
agent.SendPacket(update);
server.UDP.SendPacket(agent.AgentID, update, PacketCategory.State);
// Send appearances for this avatar
AvatarAppearancePacket appearance = AvatarManager.BuildAppearancePacket(otherAgent);
agent.SendPacket(appearance);
server.UDP.SendPacket(agent.AgentID, appearance, PacketCategory.State);
}
}
@@ -136,11 +136,10 @@ namespace Simian.Extensions
int[] patches = new int[1];
patches[0] = (y * 16) + x;
LayerDataPacket layer = TerrainCompressor.CreateLandPacket(server.Heightmap, patches);
agent.SendPacket(layer);
server.UDP.SendPacket(agent.AgentID, layer, PacketCategory.Terrain);
}
}
}
}
}
}

View File

@@ -0,0 +1,551 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace Simian
{
public class UDPClient
{
/// <summary></summary>
public Agent Agent;
/// <summary></summary>
public IPEndPoint Address;
/// <summary>Sequence numbers of packets we've received (for duplicate checking)</summary>
public Queue<uint> PacketArchive = new Queue<uint>();
/// <summary>Packets we have sent that need to be ACKed by the client</summary>
public Dictionary<uint, Packet> NeedAcks = new Dictionary<uint, Packet>();
/// <summary>ACKs that are queued up, waiting to be sent to the client</summary>
public SortedList<uint, uint> PendingAcks = new SortedList<uint, uint>();
/// <summary>Current packet sequence number</summary>
public int CurrentSequence = 0;
Timer ackTimer;
UDPServer udpServer;
public UDPClient(UDPServer server, Agent agent, IPEndPoint address)
{
udpServer = server;
Agent = agent;
Address = address;
ackTimer = new Timer(new TimerCallback(AckTimer_Elapsed), null, Settings.NETWORK_TICK_INTERVAL,
Settings.NETWORK_TICK_INTERVAL);
}
public void Dispose()
{
ackTimer.Dispose();
}
private void AckTimer_Elapsed(object obj)
{
udpServer.SendAcks(this);
udpServer.ResendUnacked(this);
}
}
public struct IncomingPacket
{
public UDPClient Client;
public Packet Packet;
}
public class UDPManager : ISimianExtension, IUDPProvider
{
Simian Server;
UDPServer udpServer;
public UDPManager(Simian server)
{
Server = server;
// Have to do this in the constructor, because we don't know that the
// UDP extension will be started before other extensions
udpServer = new UDPServer(Server.UDPPort, Server);
}
public void Start()
{
}
public void Stop()
{
udpServer.Stop();
}
public void AddClient(Agent agent, IPEndPoint endpoint)
{
udpServer.AddClient(agent, endpoint);
}
public bool RemoveClient(Agent agent)
{
return udpServer.RemoveClient(agent);
}
public bool RemoveClient(Agent agent, IPEndPoint endpoint)
{
return udpServer.RemoveClient(agent, endpoint);
}
public void SendPacket(UUID agentID, Packet packet, PacketCategory category)
{
udpServer.SendPacket(agentID, packet, category);
}
public void BroadcastPacket(Packet packet, PacketCategory category)
{
udpServer.BroadcastPacket(packet, category);
}
public void RegisterPacketCallback(PacketType type, PacketCallback callback)
{
udpServer.RegisterPacketCallback(type, callback);
}
}
public class UDPServer : UDPBase
{
/// <summary>This is only used to fetch unassociated agents, which will
/// be exposed through a login interface at some point</summary>
Simian server;
/// <summary>Handlers for incoming packets</summary>
PacketEventDictionary packetEvents = new PacketEventDictionary();
/// <summary>Incoming packets that are awaiting handling</summary>
BlockingQueue<IncomingPacket> packetInbox = new BlockingQueue<IncomingPacket>(Settings.PACKET_INBOX_SIZE);
/// <summary></summary>
DoubleDictionary<UUID, IPEndPoint, UDPClient> clients = new DoubleDictionary<UUID, IPEndPoint, UDPClient>();
public UDPServer(int port, Simian server)
: base(port)
{
this.server = server;
Start();
// Start the incoming packet processing thread
Thread incomingThread = new Thread(new ThreadStart(IncomingPacketHandler));
incomingThread.Start();
}
public void RegisterPacketCallback(PacketType type, PacketCallback callback)
{
packetEvents.RegisterEvent(type, callback);
}
public void AddClient(Agent agent, IPEndPoint endpoint)
{
UDPClient client = new UDPClient(this, agent, endpoint);
clients.Add(agent.AgentID, endpoint, client);
}
public bool RemoveClient(Agent agent)
{
UDPClient client;
if (clients.TryGetValue(agent.AgentID, out client))
return clients.Remove(agent.AgentID, client.Address);
else
return false;
}
public bool RemoveClient(Agent agent, IPEndPoint endpoint)
{
return clients.Remove(agent.AgentID, endpoint);
}
public void BroadcastPacket(Packet packet, PacketCategory category)
{
clients.ForEach(
delegate(UDPClient client) { SendPacket(client, packet, category, true); });
}
public void SendPacket(UUID agentID, Packet packet, PacketCategory category)
{
// Look up the UDPClient this is going to
UDPClient client;
if (!clients.TryGetValue(agentID, out client))
{
Logger.Log("Attempted to send a packet to unknown UDP client " +
agentID.ToString(), Helpers.LogLevel.Warning);
return;
}
SendPacket(client, packet, category, true);
}
void SendPacket(UDPClient client, Packet packet, PacketCategory category, bool setSequence)
{
byte[] buffer;
int bytes;
// Keep track of when this packet was sent out
packet.TickCount = Environment.TickCount;
if (setSequence)
{
// Reset to zero if we've hit the upper sequence number limit
Interlocked.CompareExchange(ref client.CurrentSequence, 0, 0xFFFFFF);
// Increment and fetch the current sequence number
uint sequence = (uint)Interlocked.Increment(ref client.CurrentSequence);
packet.Header.Sequence = sequence;
if (packet.Header.Reliable)
{
// Add this packet to the list of ACK responses we are waiting on from this client
lock (client.NeedAcks)
client.NeedAcks[sequence] = packet;
if (packet.Header.Resent)
{
// This packet has already been sent out once, strip any appended ACKs
// off it and reinsert them into the outgoing ACK queue under the
// assumption that this packet will continually be rejected from the
// client or that the appended ACKs are possibly making the delivery fail
if (packet.Header.AckList.Length > 0)
{
Logger.DebugLog(String.Format("Purging ACKs from packet #{0} ({1}) which will be resent.",
packet.Header.Sequence, packet.GetType()));
lock (client.PendingAcks)
{
foreach (uint ack in packet.Header.AckList)
{
if (!client.PendingAcks.ContainsKey(ack))
client.PendingAcks[ack] = ack;
}
}
packet.Header.AppendedAcks = false;
packet.Header.AckList = new uint[0];
}
}
else
{
// This packet is not a resend, check if the conditions are favorable
// to ACK appending
if (packet.Type != PacketType.PacketAck)
{
lock (client.PendingAcks)
{
int count = client.PendingAcks.Count;
if (count > 0 && count < 10)
{
// Append all of the queued up outgoing ACKs to this packet
packet.Header.AckList = new uint[count];
for (int i = 0; i < count; i++)
packet.Header.AckList[i] = client.PendingAcks.Values[i];
client.PendingAcks.Clear();
packet.Header.AppendedAcks = true;
}
}
}
}
}
else if (packet.Header.AckList.Length > 0)
{
// Sanity check for ACKS appended on an unreliable packet, this is bad form
Logger.Log("Sending appended ACKs on an unreliable packet", Helpers.LogLevel.Warning);
}
}
// Serialize the packet
buffer = packet.ToBytes();
bytes = buffer.Length;
//Stats.SentBytes += (ulong)bytes;
//++Stats.SentPackets;
UDPPacketBuffer buf = new UDPPacketBuffer(client.Address);
// Zerocode if needed
if (packet.Header.Zerocoded)
bytes = Helpers.ZeroEncode(buffer, bytes, buf.Data);
else
Buffer.BlockCopy(buffer, 0, buf.Data, 0, bytes);
buf.DataLength = bytes;
AsyncBeginSend(buf);
}
void QueueAck(UDPClient client, uint ack)
{
// Add this packet to the list of ACKs that need to be sent out
lock (client.PendingAcks)
client.PendingAcks[ack] = ack;
// Send out ACKs if we have a lot of them
if (client.PendingAcks.Count >= 10)
SendAcks(client);
}
void ProcessAcks(UDPClient client, List<uint> acks)
{
lock (client.NeedAcks)
{
foreach (uint ack in acks)
client.NeedAcks.Remove(ack);
}
}
void SendAck(UDPClient client, uint ack)
{
PacketAckPacket acks = new PacketAckPacket();
acks.Header.Reliable = false;
acks.Packets = new PacketAckPacket.PacketsBlock[1];
acks.Packets[0] = new PacketAckPacket.PacketsBlock();
acks.Packets[0].ID = ack;
SendPacket(client, acks, PacketCategory.Overhead, true);
}
public void SendAcks(UDPClient client)
{
PacketAckPacket acks = null;
lock (client.PendingAcks)
{
int count = client.PendingAcks.Count;
if (count > 250)
{
Logger.Log("Too many ACKs queued up!", Helpers.LogLevel.Error);
return;
}
else if (count > 0)
{
acks = new PacketAckPacket();
acks.Header.Reliable = false;
acks.Packets = new PacketAckPacket.PacketsBlock[count];
for (int i = 0; i < count; i++)
{
acks.Packets[i] = new PacketAckPacket.PacketsBlock();
acks.Packets[i].ID = client.PendingAcks.Values[i];
}
client.PendingAcks.Clear();
}
}
if (acks != null)
SendPacket(client, acks, PacketCategory.Overhead, true);
}
public void ResendUnacked(UDPClient client)
{
lock (client.NeedAcks)
{
List<uint> dropAck = new List<uint>();
int now = Environment.TickCount;
// Resend packets
foreach (Packet packet in client.NeedAcks.Values)
{
if (packet.TickCount != 0 && now - packet.TickCount > 4000)
{
if (packet.ResendCount < 3)
{
Logger.DebugLog(String.Format("Resending packet #{0} ({1}), {2}ms have passed",
packet.Header.Sequence, packet.GetType(), now - packet.TickCount));
packet.TickCount = 0;
packet.Header.Resent = true;
//++Stats.ResentPackets;
++packet.ResendCount;
SendPacket(client, packet, PacketCategory.Overhead, false);
}
else
{
Logger.Log(String.Format("Dropping packet #{0} ({1}) after {2} failed attempts",
packet.Header.Sequence, packet.GetType(), packet.ResendCount), Helpers.LogLevel.Warning);
dropAck.Add(packet.Header.Sequence);
}
}
}
if (dropAck.Count != 0)
{
for (int i = 0; i < dropAck.Count; i++)
client.NeedAcks.Remove(dropAck[i]);
}
}
}
protected override void PacketReceived(UDPPacketBuffer buffer)
{
UDPClient client = null;
Packet packet = null;
int packetEnd = buffer.DataLength - 1;
IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint;
// Decoding
try
{
packet = Packet.BuildPacket(buffer.Data, ref packetEnd, buffer.ZeroData);
}
catch (MalformedDataException)
{
Logger.Log(String.Format("Malformed data, cannot parse packet:\n{0}",
Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)), Helpers.LogLevel.Error);
}
// Fail-safe check
if (packet == null)
{
Logger.Log("Couldn't build a message from the incoming data", Helpers.LogLevel.Warning);
return;
}
//Stats.RecvBytes += (ulong)buffer.DataLength;
//++Stats.RecvPackets;
if (packet.Type == PacketType.UseCircuitCode)
{
UseCircuitCodePacket useCircuitCode = (UseCircuitCodePacket)packet;
Agent agent;
if (server.CompleteAgentConnection(useCircuitCode.CircuitCode.Code, out agent))
{
AddClient(agent, address);
if (clients.TryGetValue(agent.AgentID, out client))
{
Logger.Log("Activated UDP circuit " + useCircuitCode.CircuitCode.Code, Helpers.LogLevel.Info);
}
else
{
Logger.Log("Failed to locate newly created UDPClient", Helpers.LogLevel.Error);
return;
}
}
else
{
Logger.Log("Received a UseCircuitCode packet for an unrecognized circuit: " +
useCircuitCode.CircuitCode.Code.ToString(), Helpers.LogLevel.Warning);
return;
}
}
else
{
// Determine which agent this packet came from
if (!clients.TryGetValue(address, out client))
{
Logger.Log("Received UDP packet from an unrecognized source: " + address.ToString(),
Helpers.LogLevel.Warning);
return;
}
}
// Reliable handling
if (packet.Header.Reliable)
{
// Queue up this sequence number for acknowledgement
QueueAck(client, (uint)packet.Header.Sequence);
//if (packet.Header.Resent) ++Stats.ReceivedResends;
}
// Inbox insertion
IncomingPacket incomingPacket;
incomingPacket.Client = client;
incomingPacket.Packet = packet;
// TODO: Prioritize the queue
packetInbox.Enqueue(incomingPacket);
}
protected override void PacketSent(UDPPacketBuffer buffer, int bytesSent)
{
}
private void IncomingPacketHandler()
{
IncomingPacket incomingPacket = new IncomingPacket();
Packet packet = null;
UDPClient client = null;
while (IsRunning)
{
// Reset packet to null for the check below
packet = null;
if (packetInbox.Dequeue(100, ref incomingPacket))
{
packet = incomingPacket.Packet;
client = incomingPacket.Client;
if (packet != null)
{
#region ACK accounting
// Check the archives to see whether we already received this packet
lock (client.PacketArchive)
{
if (client.PacketArchive.Contains(packet.Header.Sequence))
{
if (packet.Header.Resent)
{
Logger.DebugLog("Received resent packet #" + packet.Header.Sequence);
}
else
{
Logger.Log(String.Format("Received a duplicate of packet #{0}, current type: {1}",
packet.Header.Sequence, packet.Type), Helpers.LogLevel.Warning);
}
// Avoid firing a callback twice for the same packet
continue;
}
else
{
// Keep the PacketArchive size within a certain capacity
while (client.PacketArchive.Count >= Settings.PACKET_ARCHIVE_SIZE)
{
client.PacketArchive.Dequeue(); client.PacketArchive.Dequeue();
client.PacketArchive.Dequeue(); client.PacketArchive.Dequeue();
}
client.PacketArchive.Enqueue(packet.Header.Sequence);
}
}
#endregion ACK accounting
#region ACK handling
// Handle appended ACKs
if (packet.Header.AppendedAcks)
{
lock (client.NeedAcks)
{
for (int i = 0; i < packet.Header.AckList.Length; i++)
client.NeedAcks.Remove(packet.Header.AckList[i]);
}
}
// Handle PacketAck packets
if (packet.Type == PacketType.PacketAck)
{
PacketAckPacket ackPacket = (PacketAckPacket)packet;
lock (client.NeedAcks)
{
for (int i = 0; i < ackPacket.Packets.Length; i++)
client.NeedAcks.Remove(ackPacket.Packets[i].ID);
}
}
#endregion ACK handling
packetEvents.BeginRaiseEvent(packet.Type, packet, client.Agent);
}
}
}
}
}
}