Merge branch 'master' into careminster

Conflicts:
	OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
	OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
	OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
	OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
	OpenSim/Region/Framework/Scenes/ScenePresence.cs
	OpenSim/Region/Physics/Manager/PhysicsActor.cs
	OpenSim/Region/Physics/Manager/PhysicsScene.cs
This commit is contained in:
Melanie
2013-07-24 04:45:07 +01:00
31 changed files with 915 additions and 252 deletions

View File

@@ -96,6 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
public event UpdateAgent OnPreAgentUpdate;
public event UpdateAgent OnAgentUpdate;
public event UpdateAgent OnAgentCameraUpdate;
public event AgentRequestSit OnAgentRequestSit;
public event AgentSit OnAgentSit;
public event AvatarPickerRequest OnAvatarPickerRequest;
@@ -368,7 +369,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
/// cannot retain a reference to it outside of that method.
/// </remarks>
private AgentUpdateArgs m_lastAgentUpdateArgs;
private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs();
protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@@ -505,6 +506,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_udpServer = udpServer;
m_udpClient = udpClient;
m_udpClient.OnQueueEmpty += HandleQueueEmpty;
m_udpClient.HasUpdates += HandleHasUpdates;
m_udpClient.OnPacketStats += PopulateStats;
m_prioritizer = new Prioritizer(m_scene);
@@ -4164,8 +4166,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
{
// if (!m_udpServer.IsRunningOutbound)
// return;
if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
{
// if (!m_udpServer.IsRunningOutbound)
// return;
if (m_maxUpdates == 0 || m_LastQueueFill == 0)
{
m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
@@ -4191,6 +4199,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit);
}
internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories)
{
bool hasUpdates = false;
if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
{
if (m_entityUpdates.Count > 0)
hasUpdates = true;
else if (m_entityProps.Count > 0)
hasUpdates = true;
}
if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
{
if (ImageManager.HasUpdates())
hasUpdates = true;
}
return hasUpdates;
}
public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
{
AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
@@ -5058,7 +5087,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
SceneObjectPart part = (SceneObjectPart)entity;
attachPoint = part.ParentGroup.AttachmentPoint;
attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16));
// m_log.DebugFormat(
// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}",
// attachPoint, part.Name, part.LocalId, Name);
@@ -5086,7 +5115,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
pos += 4;
// Avatar/CollisionPlane
data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ;
data[pos++] = (byte) attachPoint;
if (avatar)
{
data[pos++] = 1;
@@ -5618,83 +5647,137 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region Packet Handlers
public int TotalAgentUpdates { get; set; }
#region Scene/Avatar
private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
// Threshold for body rotation to be a significant agent update
private const float QDELTA = 0.000001f;
// Threshold for camera rotation to be a significant agent update
private const float VDELTA = 0.01f;
/// <summary>
/// This checks the update significance against the last update made.
/// </summary>
/// <remarks>Can only be called by one thread at a time</remarks>
/// <returns></returns>
/// <param name='x'></param>
public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
{
if (OnAgentUpdate != null)
return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x);
}
/// <summary>
/// This checks the movement/state update significance against the last update made.
/// </summary>
/// <remarks>Can only be called by one thread at a time</remarks>
/// <returns></returns>
/// <param name='x'></param>
private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
{
float qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2);
//qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2);
bool movementSignificant =
(qdelta1 > QDELTA) // significant if body rotation above threshold
// Ignoring head rotation altogether, because it's not being used for anything interesting up the stack
// || (qdelta2 > QDELTA * 10) // significant if head rotation above threshold
|| (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed
|| (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands
|| (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed
|| (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed
|| (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed
;
//if (movementSignificant)
//{
//m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}",
// qdelta1, qdelta2);
//m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}",
// x.ControlFlags, x.Flags, x.Far, x.State);
//}
return movementSignificant;
}
/// <summary>
/// This checks the camera update significance against the last update made.
/// </summary>
/// <remarks>Can only be called by one thread at a time</remarks>
/// <returns></returns>
/// <param name='x'></param>
private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
{
float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis);
float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter);
float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis);
float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis);
bool cameraSignificant =
(vdelta1 > VDELTA) ||
(vdelta2 > VDELTA) ||
(vdelta3 > VDELTA) ||
(vdelta4 > VDELTA)
;
//if (cameraSignificant)
//{
//m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}",
// x.CameraAtAxis, x.CameraCenter);
//m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}",
// x.CameraLeftAxis, x.CameraUpAxis);
//}
return cameraSignificant;
}
private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
{
// We got here, which means that something in agent update was significant
AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
if (x.AgentID != AgentId || x.SessionID != SessionId)
return false;
// Before we update the current m_thisAgentUpdateArgs, let's check this again
// to see what exactly changed
bool movement = CheckAgentMovementUpdateSignificance(x);
bool camera = CheckAgentCameraUpdateSignificance(x);
m_thisAgentUpdateArgs.AgentID = x.AgentID;
m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation;
m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter;
m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags;
m_thisAgentUpdateArgs.Far = x.Far;
m_thisAgentUpdateArgs.Flags = x.Flags;
m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation;
m_thisAgentUpdateArgs.SessionID = x.SessionID;
m_thisAgentUpdateArgs.State = x.State;
UpdateAgent handlerAgentUpdate = OnAgentUpdate;
UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate;
// Was there a significant movement/state change?
if (movement)
{
AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
if (handlerPreAgentUpdate != null)
OnPreAgentUpdate(this, m_thisAgentUpdateArgs);
#region Packet Session and User Check
if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId)
{
PacketPool.Instance.ReturnPacket(packet);
return false;
}
#endregion
bool update = false;
AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
if (m_lastAgentUpdateArgs != null)
{
// These should be ordered from most-likely to
// least likely to change. I've made an initial
// guess at that.
update =
(
(x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) ||
(x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) ||
(x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) ||
(x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
(x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
(x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
(x.ControlFlags != 0) ||
(x.Far != m_lastAgentUpdateArgs.Far) ||
(x.Flags != m_lastAgentUpdateArgs.Flags) ||
(x.State != m_lastAgentUpdateArgs.State) ||
(x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) ||
(x.SessionID != m_lastAgentUpdateArgs.SessionID) ||
(x.AgentID != m_lastAgentUpdateArgs.AgentID)
);
}
else
{
m_lastAgentUpdateArgs = new AgentUpdateArgs();
update = true;
}
if (update)
{
// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name);
m_lastAgentUpdateArgs.AgentID = x.AgentID;
m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation;
m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter;
m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags;
m_lastAgentUpdateArgs.Far = x.Far;
m_lastAgentUpdateArgs.Flags = x.Flags;
m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation;
m_lastAgentUpdateArgs.SessionID = x.SessionID;
m_lastAgentUpdateArgs.State = x.State;
UpdateAgent handlerAgentUpdate = OnAgentUpdate;
UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
if (handlerPreAgentUpdate != null)
OnPreAgentUpdate(this, m_lastAgentUpdateArgs);
if (handlerAgentUpdate != null)
OnAgentUpdate(this, m_lastAgentUpdateArgs);
handlerAgentUpdate = null;
handlerPreAgentUpdate = null;
}
if (handlerAgentUpdate != null)
OnAgentUpdate(this, m_thisAgentUpdateArgs);
}
// Was there a significant camera(s) change?
if (camera)
if (handlerAgentCameraUpdate != null)
handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs);
handlerAgentUpdate = null;
handlerPreAgentUpdate = null;
handlerAgentCameraUpdate = null;
PacketPool.Instance.ReturnPacket(packet);
@@ -12813,7 +12896,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
OutPacket(dialog, ThrottleOutPacketType.Task);
}
public void StopFlying(ISceneEntity p)
public void SendAgentTerseUpdate(ISceneEntity p)
{
if (p is ScenePresence)
{
@@ -12827,25 +12910,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
Vector3 pos = presence.AbsolutePosition;
if (presence.Appearance.AvatarHeight != 127.0f)
pos += new Vector3(0f, 0f, (presence.Appearance.AvatarHeight/6f));
else
pos += new Vector3(0f, 0f, (1.56f/6f));
presence.AbsolutePosition = pos;
// attach a suitable collision plane regardless of the actual situation to force the LLClient to land.
// Collision plane below the avatar's position a 6th of the avatar's height is suitable.
// Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a
// certain amount.. because the LLClient wouldn't land in that situation anyway.
// why are we still testing for this really old height value default???
if (presence.Appearance.AvatarHeight != 127.0f)
presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - presence.Appearance.AvatarHeight/6f);
else
presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f/6f));
ImprovedTerseObjectUpdatePacket.ObjectDataBlock block =
CreateImprovedTerseBlock(p, false);

View File

@@ -206,6 +206,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
}
public bool HasUpdates()
{
J2KImage image = GetHighestPriorityImage();
return image != null && image.IsDecoded;
}
public bool ProcessImageQueue(int packetsToSend)
{
int packetsSent = 0;

View File

@@ -31,6 +31,7 @@ using System.Net;
using System.Threading;
using log4net;
using OpenSim.Framework;
using OpenSim.Framework.Monitoring;
using OpenMetaverse;
using OpenMetaverse.Packets;
@@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// hooked to put more data on the empty queue</summary>
public event QueueEmpty OnQueueEmpty;
public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates;
/// <summary>AgentID for this client</summary>
public readonly UUID AgentID;
/// <summary>The remote address of the connected client</summary>
@@ -645,15 +648,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <param name="categories">Throttle categories to fire the callback for</param>
private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
{
if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
{
m_isQueueEmptyRunning = true;
int start = Environment.TickCount & Int32.MaxValue;
const int MIN_CALLBACK_MS = 30;
m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
if (m_nextOnQueueEmpty == 0)
m_nextOnQueueEmpty = 1;
// Use a value of 0 to signal that FireQueueEmpty is running
m_nextOnQueueEmpty = 0;
// Asynchronously run the callback
Util.FireAndForget(FireQueueEmpty, categories);
// m_nextOnQueueEmpty = 0;
m_categories = categories;
if (HasUpdates(m_categories))
{
// Asynchronously run the callback
Util.FireAndForget(FireQueueEmpty, categories);
}
else
{
m_isQueueEmptyRunning = false;
}
}
}
private bool m_isQueueEmptyRunning;
private ThrottleOutPacketTypeFlags m_categories = 0;
/// <summary>
/// Fires the OnQueueEmpty callback and sets the minimum time that it
/// can be called again
@@ -663,22 +689,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// signature</param>
private void FireQueueEmpty(object o)
{
const int MIN_CALLBACK_MS = 30;
// int start = Environment.TickCount & Int32.MaxValue;
// const int MIN_CALLBACK_MS = 30;
ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
QueueEmpty callback = OnQueueEmpty;
int start = Environment.TickCount & Int32.MaxValue;
// if (m_udpServer.IsRunningOutbound)
// {
ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
QueueEmpty callback = OnQueueEmpty;
if (callback != null)
{
try { callback(categories); }
catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
}
if (callback != null)
{
// if (m_udpServer.IsRunningOutbound)
// {
try { callback(categories); }
catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
// }
}
// }
m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
if (m_nextOnQueueEmpty == 0)
m_nextOnQueueEmpty = 1;
// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
// if (m_nextOnQueueEmpty == 0)
// m_nextOnQueueEmpty = 1;
// }
m_isQueueEmptyRunning = false;
}
internal void ForceThrottleSetting(int throttle, int setting)
{

View File

@@ -67,11 +67,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
m_udpServer.AddScene(scene);
StatsManager.RegisterStat(
new Stat(
"IncomingUDPReceivesCount",
"Number of UDP receives performed",
"Number of UDP receives performed",
"",
"clientstack",
scene.Name,
StatType.Pull,
MeasuresOfInterest.AverageChangeOverTime,
stat => stat.Value = m_udpServer.UdpReceives,
StatVerbosity.Debug));
StatsManager.RegisterStat(
new Stat(
"IncomingPacketsProcessedCount",
"Number of inbound UDP packets processed",
"Number of inbound UDP packets processed",
"Number of inbound LL protocol packets processed",
"Number of inbound LL protocol packets processed",
"",
"clientstack",
scene.Name,
@@ -79,6 +92,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
MeasuresOfInterest.AverageChangeOverTime,
stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
StatVerbosity.Debug));
StatsManager.RegisterStat(
new Stat(
"OutgoingUDPSendsCount",
"Number of UDP sends performed",
"Number of UDP sends performed",
"",
"clientstack",
scene.Name,
StatType.Pull,
MeasuresOfInterest.AverageChangeOverTime,
stat => stat.Value = m_udpServer.UdpSends,
StatVerbosity.Debug));
StatsManager.RegisterStat(
new Stat(
"AverageUDPProcessTime",
"Average number of milliseconds taken to process each incoming UDP packet in a sample.",
"This is for initial receive processing which is separate from the later client LL packet processing stage.",
"ms",
"clientstack",
scene.Name,
StatType.Pull,
MeasuresOfInterest.None,
stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond,
// stat =>
// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, 7),
StatVerbosity.Debug));
}
public bool HandlesRegion(Location x)
@@ -185,6 +226,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
protected bool m_sendPing;
private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
/// <summary>
/// Event used to signal when queued packets are available for sending.
/// </summary>
/// <remarks>
/// This allows the outbound loop to only operate when there is data to send rather than continuously polling.
/// Some data is sent immediately and not queued. That data would not trigger this event.
/// </remarks>
private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
private Pool<IncomingPacket> m_incomingPacketPool;
/// <summary>
@@ -462,6 +513,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_scene = (Scene)scene;
m_location = new Location(m_scene.RegionInfo.RegionHandle);
StatsManager.RegisterStat(
new Stat(
"InboxPacketsCount",
"Number of LL protocol packets waiting for the second stage of processing after initial receive.",
"Number of LL protocol packets waiting for the second stage of processing after initial receive.",
"",
"clientstack",
scene.Name,
StatType.Pull,
MeasuresOfInterest.AverageChangeOverTime,
stat => stat.Value = packetInbox.Count,
StatVerbosity.Debug));
// XXX: These stats are also pool stats but we register them separately since they are currently not
// turned on and off by EnablePools()/DisablePools()
StatsManager.RegisterStat(
@@ -575,6 +639,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
"debug lludp status",
"Return status of LLUDP packet processing.",
HandleStatusCommand);
MainConsole.Instance.Commands.AddCommand(
"Debug",
false,
"debug lludp toggle agentupdate",
"debug lludp toggle agentupdate",
"Toggle whether agentupdate packets are processed or simply discarded.",
HandleAgentUpdateCommand);
}
private void HandlePacketCommand(string module, string[] args)
@@ -709,6 +781,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
}
bool m_discardAgentUpdates;
private void HandleAgentUpdateCommand(string module, string[] args)
{
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
return;
m_discardAgentUpdates = !m_discardAgentUpdates;
MainConsole.Instance.OutputFormat(
"Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name);
}
private void HandleStatusCommand(string module, string[] args)
{
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
@@ -809,12 +894,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
PacketPool.Instance.ReturnPacket(packet);
m_dataPresentEvent.Set();
}
private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
/// <summary>
/// Start the process of sending a packet to the client.
/// </summary>
@@ -1325,6 +1408,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
#endregion BinaryStats
if (packet.Type == PacketType.AgentUpdate)
{
if (m_discardAgentUpdates)
return;
((LLClientView)client).TotalAgentUpdates++;
AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
LLClientView llClient = client as LLClientView;
if (agentUpdate.AgentData.SessionID != client.SessionId
|| agentUpdate.AgentData.AgentID != client.AgentId
|| !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) )
{
PacketPool.Instance.ReturnPacket(packet);
return;
}
}
#region Ping Check Handling
if (packet.Type == PacketType.StartPingCheck)
@@ -1734,7 +1836,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Action generic every round
Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
// while (true)
while (base.IsRunningOutbound)
{
m_scene.ThreadAlive(2);
@@ -1798,6 +1899,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// token bucket could get more tokens
//if (!m_packetSent)
// Thread.Sleep((int)TickCountResolution);
//
// Instead, now wait for data present to be explicitly signalled. Evidence so far is that with
// modern mono it reduces CPU base load since there is no more continuous polling.
m_dataPresentEvent.WaitOne(100);
Watchdog.UpdateThread();

View File

@@ -77,6 +77,36 @@ namespace OpenMetaverse
/// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
public bool IsRunningOutbound { get; private set; }
/// <summary>
/// Number of UDP receives.
/// </summary>
public int UdpReceives { get; private set; }
/// <summary>
/// Number of UDP sends
/// </summary>
public int UdpSends { get; private set; }
/// <summary>
/// Number of receives over which to establish a receive time average.
/// </summary>
private readonly static int s_receiveTimeSamples = 500;
/// <summary>
/// Current number of samples taken to establish a receive time average.
/// </summary>
private int m_currentReceiveTimeSamples;
/// <summary>
/// Cumulative receive time for the sample so far.
/// </summary>
private int m_receiveTicksInCurrentSamplePeriod;
/// <summary>
/// The average time taken for each require receive in the last sample.
/// </summary>
public float AverageReceiveTicksForLastSamplePeriod { get; private set; }
/// <summary>
/// Default constructor
/// </summary>
@@ -111,6 +141,8 @@ namespace OpenMetaverse
if (!IsRunningInbound)
{
m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop");
const int SIO_UDP_CONNRESET = -1744830452;
IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
@@ -151,6 +183,8 @@ namespace OpenMetaverse
/// </summary>
public void StartOutbound()
{
m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop");
IsRunningOutbound = true;
}
@@ -158,10 +192,8 @@ namespace OpenMetaverse
{
if (IsRunningInbound)
{
// wait indefinitely for a writer lock. Once this is called, the .NET runtime
// will deny any more reader locks, in effect blocking all other send/receive
// threads. Once we have the lock, we set IsRunningInbound = false to inform the other
// threads that the socket is closed.
m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop");
IsRunningInbound = false;
m_udpSocket.Close();
}
@@ -169,6 +201,8 @@ namespace OpenMetaverse
public void StopOutbound()
{
m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop");
IsRunningOutbound = false;
}
@@ -267,6 +301,8 @@ namespace OpenMetaverse
// to AsyncBeginReceive
if (IsRunningInbound)
{
UdpReceives++;
// Asynchronous mode will start another receive before the
// callback for this packet is even fired. Very parallel :-)
if (m_asyncPacketHandling)
@@ -278,6 +314,8 @@ namespace OpenMetaverse
try
{
int startTick = Util.EnvironmentTickCount();
// get the length of data actually read from the socket, store it with the
// buffer
buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
@@ -285,6 +323,23 @@ namespace OpenMetaverse
// call the abstract method PacketReceived(), passing the buffer that
// has just been filled from the socket read.
PacketReceived(buffer);
// If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler)
// then a particular stat may be inaccurate due to a race condition. We won't worry about this
// since this should be rare and won't cause a runtime problem.
if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
{
AverageReceiveTicksForLastSamplePeriod
= (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
m_receiveTicksInCurrentSamplePeriod = 0;
m_currentReceiveTimeSamples = 0;
}
else
{
m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick);
m_currentReceiveTimeSamples++;
}
}
catch (SocketException) { }
catch (ObjectDisposedException) { }
@@ -298,14 +353,13 @@ namespace OpenMetaverse
if (!m_asyncPacketHandling)
AsyncBeginReceive();
}
}
}
public void AsyncBeginSend(UDPPacketBuffer buf)
{
if (IsRunningOutbound)
{
// if (IsRunningOutbound)
// {
try
{
m_udpSocket.BeginSendTo(
@@ -319,7 +373,7 @@ namespace OpenMetaverse
}
catch (SocketException) { }
catch (ObjectDisposedException) { }
}
// }
}
void AsyncEndSend(IAsyncResult result)
@@ -328,6 +382,8 @@ namespace OpenMetaverse
{
// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
m_udpSocket.EndSendTo(result);
UdpSends++;
}
catch (SocketException) { }
catch (ObjectDisposedException) { }