aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs4
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs644
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs7
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs96
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs436
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs72
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs25
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs6
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs16
9 files changed, 996 insertions, 310 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
index 3995620..15d6f7f 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
@@ -424,12 +424,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
424 // foreign user is visiting, we need to try again after the first fail to the local 424 // foreign user is visiting, we need to try again after the first fail to the local
425 // asset service. 425 // asset service.
426 string assetServerURL = string.Empty; 426 string assetServerURL = string.Empty;
427 if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL)) 427 if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL) && !string.IsNullOrEmpty(assetServerURL))
428 { 428 {
429 if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("=")) 429 if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("="))
430 assetServerURL = assetServerURL + "/"; 430 assetServerURL = assetServerURL + "/";
431 431
432 m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id); 432// m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id);
433 AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived); 433 AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived);
434 return; 434 return;
435 } 435 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index f4ea975..36edd0b 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -84,6 +84,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
84 public event ModifyTerrain OnModifyTerrain; 84 public event ModifyTerrain OnModifyTerrain;
85 public event Action<IClientAPI> OnRegionHandShakeReply; 85 public event Action<IClientAPI> OnRegionHandShakeReply;
86 public event GenericCall1 OnRequestWearables; 86 public event GenericCall1 OnRequestWearables;
87 public event CachedTextureRequest OnCachedTextureRequest;
87 public event SetAppearance OnSetAppearance; 88 public event SetAppearance OnSetAppearance;
88 public event AvatarNowWearing OnAvatarNowWearing; 89 public event AvatarNowWearing OnAvatarNowWearing;
89 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; 90 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv;
@@ -95,6 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
95 public event Action<IClientAPI, bool> OnCompleteMovementToRegion; 96 public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
96 public event UpdateAgent OnPreAgentUpdate; 97 public event UpdateAgent OnPreAgentUpdate;
97 public event UpdateAgent OnAgentUpdate; 98 public event UpdateAgent OnAgentUpdate;
99 public event UpdateAgent OnAgentCameraUpdate;
98 public event AgentRequestSit OnAgentRequestSit; 100 public event AgentRequestSit OnAgentRequestSit;
99 public event AgentSit OnAgentSit; 101 public event AgentSit OnAgentSit;
100 public event AvatarPickerRequest OnAvatarPickerRequest; 102 public event AvatarPickerRequest OnAvatarPickerRequest;
@@ -335,6 +337,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
335 private bool m_VelocityInterpolate = false; 337 private bool m_VelocityInterpolate = false;
336 private const uint MaxTransferBytesPerPacket = 600; 338 private const uint MaxTransferBytesPerPacket = 600;
337 339
340 private volatile bool m_justEditedTerrain = false;
338 341
339 /// <value> 342 /// <value>
340 /// List used in construction of data blocks for an object update packet. This is to stop us having to 343 /// List used in construction of data blocks for an object update packet. This is to stop us having to
@@ -367,7 +370,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
367 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods 370 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
368 /// cannot retain a reference to it outside of that method. 371 /// cannot retain a reference to it outside of that method.
369 /// </remarks> 372 /// </remarks>
370 private AgentUpdateArgs m_lastAgentUpdateArgs; 373 private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs();
371 374
372 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); 375 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
373 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers 376 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@@ -504,6 +507,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
504 m_udpServer = udpServer; 507 m_udpServer = udpServer;
505 m_udpClient = udpClient; 508 m_udpClient = udpClient;
506 m_udpClient.OnQueueEmpty += HandleQueueEmpty; 509 m_udpClient.OnQueueEmpty += HandleQueueEmpty;
510 m_udpClient.HasUpdates += HandleHasUpdates;
507 m_udpClient.OnPacketStats += PopulateStats; 511 m_udpClient.OnPacketStats += PopulateStats;
508 512
509 m_prioritizer = new Prioritizer(m_scene); 513 m_prioritizer = new Prioritizer(m_scene);
@@ -533,7 +537,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
533 // We still perform a force close inside the sync lock since this is intended to attempt close where 537 // We still perform a force close inside the sync lock since this is intended to attempt close where
534 // there is some unidentified connection problem, not where we have issues due to deadlock 538 // there is some unidentified connection problem, not where we have issues due to deadlock
535 if (!IsActive && !force) 539 if (!IsActive && !force)
540 {
541 m_log.DebugFormat(
542 "[CLIENT]: Not attempting to close inactive client {0} in {1} since force flag is not set",
543 Name, m_scene.Name);
544
536 return; 545 return;
546 }
537 547
538 IsActive = false; 548 IsActive = false;
539 CloseWithoutChecks(sendStop); 549 CloseWithoutChecks(sendStop);
@@ -709,12 +719,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
709 //there is a local handler for this packet type 719 //there is a local handler for this packet type
710 if (pprocessor.Async) 720 if (pprocessor.Async)
711 { 721 {
722 ClientInfo cinfo = UDPClient.GetClientInfo();
723 if (!cinfo.AsyncRequests.ContainsKey(packet.Type.ToString()))
724 cinfo.AsyncRequests[packet.Type.ToString()] = 0;
725 cinfo.AsyncRequests[packet.Type.ToString()]++;
726
712 object obj = new AsyncPacketProcess(this, pprocessor.method, packet); 727 object obj = new AsyncPacketProcess(this, pprocessor.method, packet);
713 Util.FireAndForget(ProcessSpecificPacketAsync, obj); 728 Util.FireAndForget(ProcessSpecificPacketAsync, obj);
714 result = true; 729 result = true;
715 } 730 }
716 else 731 else
717 { 732 {
733 ClientInfo cinfo = UDPClient.GetClientInfo();
734 if (!cinfo.SyncRequests.ContainsKey(packet.Type.ToString()))
735 cinfo.SyncRequests[packet.Type.ToString()] = 0;
736 cinfo.SyncRequests[packet.Type.ToString()]++;
737
718 result = pprocessor.method(this, packet); 738 result = pprocessor.method(this, packet);
719 } 739 }
720 } 740 }
@@ -729,6 +749,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
729 } 749 }
730 if (found) 750 if (found)
731 { 751 {
752 ClientInfo cinfo = UDPClient.GetClientInfo();
753 if (!cinfo.GenericRequests.ContainsKey(packet.Type.ToString()))
754 cinfo.GenericRequests[packet.Type.ToString()] = 0;
755 cinfo.GenericRequests[packet.Type.ToString()]++;
756
732 result = method(this, packet); 757 result = method(this, packet);
733 } 758 }
734 } 759 }
@@ -820,12 +845,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
820 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); 845 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType);
821 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; 846 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes;
822 847
823 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0]; 848 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1];
824// OutPacket(handshake, ThrottleOutPacketType.Task); 849 handshake.RegionInfo4[0] = new RegionHandshakePacket.RegionInfo4Block();
825 // use same as MoveAgentIntoRegion (both should be task ) 850 handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags;
851 handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported
852
826 OutPacket(handshake, ThrottleOutPacketType.Unknown); 853 OutPacket(handshake, ThrottleOutPacketType.Unknown);
827 } 854 }
828 855
856
829 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) 857 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
830 { 858 {
831 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); 859 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete);
@@ -1210,9 +1238,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1210 LLHeightFieldMoronize(map); 1238 LLHeightFieldMoronize(map);
1211 1239
1212 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1240 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1213 layerpack.Header.Reliable = true; 1241
1242 // When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience.
1243 // To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain.
1244 // We also make them unreliable because it's extremely likely that multiple packets will be sent for a terrain patch area
1245 // invalidating previous packets for that area.
1214 1246
1215 OutPacket(layerpack, ThrottleOutPacketType.Task); 1247 // It's possible for an editing user to flood themselves with edited packets but the majority of use cases are such that only a
1248 // tiny percentage of users will be editing the terrain. Other, non-editing users will see the edits much slower.
1249
1250 // One last note on this topic, by the time users are going to be editing the terrain, it's extremely likely that the sim will
1251 // have rezzed already and therefore this is not likely going to cause any additional issues with lost packets, objects or terrain
1252 // patches.
1253
1254 // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we only have one cache miss.
1255 if (m_justEditedTerrain)
1256 {
1257 layerpack.Header.Reliable = false;
1258 OutPacket(layerpack,
1259 ThrottleOutPacketType.Unknown );
1260 }
1261 else
1262 {
1263 layerpack.Header.Reliable = true;
1264 OutPacket(layerpack,
1265 ThrottleOutPacketType.Task);
1266 }
1216 } 1267 }
1217 catch (Exception e) 1268 catch (Exception e)
1218 { 1269 {
@@ -1580,7 +1631,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1580 OutPacket(pc, ThrottleOutPacketType.Unknown); 1631 OutPacket(pc, ThrottleOutPacketType.Unknown);
1581 } 1632 }
1582 1633
1583 public void SendKillObject(ulong regionHandle, List<uint> localIDs) 1634 public void SendKillObject(List<uint> localIDs)
1584 { 1635 {
1585// foreach (uint id in localIDs) 1636// foreach (uint id in localIDs)
1586// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); 1637// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
@@ -3797,6 +3848,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3797 ResendPrimUpdate(update); 3848 ResendPrimUpdate(update);
3798 } 3849 }
3799 3850
3851// OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
3852// OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>();
3853// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3854// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3855//
3856// OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3857// OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3858// OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3859// OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3860
3861
3800 private void ProcessEntityUpdates(int maxUpdates) 3862 private void ProcessEntityUpdates(int maxUpdates)
3801 { 3863 {
3802 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); 3864 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
@@ -3809,6 +3871,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3809 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); 3871 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3810 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); 3872 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3811 3873
3874// objectUpdateBlocks.Value.Clear();
3875// compressedUpdateBlocks.Value.Clear();
3876// terseUpdateBlocks.Value.Clear();
3877// terseAgentUpdateBlocks.Value.Clear();
3878// objectUpdates.Value.Clear();
3879// compressedUpdates.Value.Clear();
3880// terseUpdates.Value.Clear();
3881// terseAgentUpdates.Value.Clear();
3882
3812 // Check to see if this is a flush 3883 // Check to see if this is a flush
3813 if (maxUpdates <= 0) 3884 if (maxUpdates <= 0)
3814 { 3885 {
@@ -4137,8 +4208,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4137 4208
4138 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) 4209 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
4139 { 4210 {
4211// if (!m_udpServer.IsRunningOutbound)
4212// return;
4213
4140 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) 4214 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4141 { 4215 {
4216// if (!m_udpServer.IsRunningOutbound)
4217// return;
4218
4142 if (m_maxUpdates == 0 || m_LastQueueFill == 0) 4219 if (m_maxUpdates == 0 || m_LastQueueFill == 0)
4143 { 4220 {
4144 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; 4221 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
@@ -4164,6 +4241,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4164 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); 4241 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit);
4165 } 4242 }
4166 4243
4244 internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories)
4245 {
4246 bool hasUpdates = false;
4247
4248 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4249 {
4250 if (m_entityUpdates.Count > 0)
4251 hasUpdates = true;
4252 else if (m_entityProps.Count > 0)
4253 hasUpdates = true;
4254 }
4255
4256 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
4257 {
4258 if (ImageManager.HasUpdates())
4259 hasUpdates = true;
4260 }
4261
4262 return hasUpdates;
4263 }
4264
4167 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) 4265 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
4168 { 4266 {
4169 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); 4267 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
@@ -4874,7 +4972,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4874 4972
4875 public void SendForceClientSelectObjects(List<uint> ObjectIDs) 4973 public void SendForceClientSelectObjects(List<uint> ObjectIDs)
4876 { 4974 {
4877 m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); 4975// m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count);
4878 4976
4879 bool firstCall = true; 4977 bool firstCall = true;
4880 const int MAX_OBJECTS_PER_PACKET = 251; 4978 const int MAX_OBJECTS_PER_PACKET = 251;
@@ -5031,7 +5129,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5031 SceneObjectPart part = (SceneObjectPart)entity; 5129 SceneObjectPart part = (SceneObjectPart)entity;
5032 5130
5033 attachPoint = part.ParentGroup.AttachmentPoint; 5131 attachPoint = part.ParentGroup.AttachmentPoint;
5034 5132 attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16));
5035// m_log.DebugFormat( 5133// m_log.DebugFormat(
5036// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", 5134// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}",
5037// attachPoint, part.Name, part.LocalId, Name); 5135// attachPoint, part.Name, part.LocalId, Name);
@@ -5059,7 +5157,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5059 pos += 4; 5157 pos += 4;
5060 5158
5061 // Avatar/CollisionPlane 5159 // Avatar/CollisionPlane
5062 data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ; 5160 data[pos++] = (byte) attachPoint;
5063 if (avatar) 5161 if (avatar)
5064 { 5162 {
5065 data[pos++] = 1; 5163 data[pos++] = 1;
@@ -5384,7 +5482,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5384 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); 5482 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject);
5385 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); 5483 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject);
5386 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); 5484 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand);
5387 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply); 5485 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false);
5388 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); 5486 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest);
5389 AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance); 5487 AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance);
5390 AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing); 5488 AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing);
@@ -5445,8 +5543,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5445 AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); 5543 AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false);
5446 AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); 5544 AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false);
5447 AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); 5545 AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false);
5448 AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage); 5546 AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false);
5449 AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest); 5547 AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false);
5450 AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); 5548 AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest);
5451 AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); 5549 AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer);
5452 AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); 5550 AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket);
@@ -5478,7 +5576,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5478 AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); 5576 AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel);
5479 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); 5577 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest);
5480 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); 5578 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false);
5481 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest); 5579 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest, false);
5482 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); 5580 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest);
5483 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); 5581 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false);
5484 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); 5582 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false);
@@ -5591,83 +5689,137 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5591 5689
5592 #region Packet Handlers 5690 #region Packet Handlers
5593 5691
5692 public int TotalAgentUpdates { get; set; }
5693
5594 #region Scene/Avatar 5694 #region Scene/Avatar
5595 5695
5596 private bool HandleAgentUpdate(IClientAPI sener, Packet packet) 5696 // Threshold for body rotation to be a significant agent update
5697 private const float QDELTA = 0.000001f;
5698 // Threshold for camera rotation to be a significant agent update
5699 private const float VDELTA = 0.01f;
5700
5701 /// <summary>
5702 /// This checks the update significance against the last update made.
5703 /// </summary>
5704 /// <remarks>Can only be called by one thread at a time</remarks>
5705 /// <returns></returns>
5706 /// <param name='x'></param>
5707 public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5597 { 5708 {
5598 if (OnAgentUpdate != null) 5709 return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x);
5599 { 5710 }
5600 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5601 5711
5602 #region Packet Session and User Check 5712 /// <summary>
5603 if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId) 5713 /// This checks the movement/state update significance against the last update made.
5604 { 5714 /// </summary>
5605 PacketPool.Instance.ReturnPacket(packet); 5715 /// <remarks>Can only be called by one thread at a time</remarks>
5606 return false; 5716 /// <returns></returns>
5607 } 5717 /// <param name='x'></param>
5608 #endregion 5718 private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5719 {
5720 float qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2);
5721 //qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2);
5722
5723 bool movementSignificant =
5724 (qdelta1 > QDELTA) // significant if body rotation above threshold
5725 // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack
5726 // || (qdelta2 > QDELTA * 10) // significant if head rotation above threshold
5727 || (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed
5728 || (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands
5729 || (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed
5730 || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed
5731 || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed
5732 ;
5733 //if (movementSignificant)
5734 //{
5735 //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}",
5736 // qdelta1, qdelta2);
5737 //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}",
5738 // x.ControlFlags, x.Flags, x.Far, x.State);
5739 //}
5740 return movementSignificant;
5741 }
5609 5742
5610 bool update = false; 5743 /// <summary>
5611 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; 5744 /// This checks the camera update significance against the last update made.
5612 5745 /// </summary>
5613 if (m_lastAgentUpdateArgs != null) 5746 /// <remarks>Can only be called by one thread at a time</remarks>
5614 { 5747 /// <returns></returns>
5615 // These should be ordered from most-likely to 5748 /// <param name='x'></param>
5616 // least likely to change. I've made an initial 5749 private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5617 // guess at that. 5750 {
5618 update = 5751 float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis);
5619 ( 5752 float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter);
5620 (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || 5753 float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis);
5621 (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || 5754 float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis);
5622 (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) ||
5623 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
5624 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
5625 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
5626 (x.ControlFlags != 0) ||
5627 (x.Far != m_lastAgentUpdateArgs.Far) ||
5628 (x.Flags != m_lastAgentUpdateArgs.Flags) ||
5629 (x.State != m_lastAgentUpdateArgs.State) ||
5630 (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) ||
5631 (x.SessionID != m_lastAgentUpdateArgs.SessionID) ||
5632 (x.AgentID != m_lastAgentUpdateArgs.AgentID)
5633 );
5634 }
5635 else
5636 {
5637 m_lastAgentUpdateArgs = new AgentUpdateArgs();
5638 update = true;
5639 }
5640 5755
5641 if (update) 5756 bool cameraSignificant =
5642 { 5757 (vdelta1 > VDELTA) ||
5643// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); 5758 (vdelta2 > VDELTA) ||
5759 (vdelta3 > VDELTA) ||
5760 (vdelta4 > VDELTA)
5761 ;
5644 5762
5645 m_lastAgentUpdateArgs.AgentID = x.AgentID; 5763 //if (cameraSignificant)
5646 m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; 5764 //{
5647 m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; 5765 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}",
5648 m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter; 5766 // x.CameraAtAxis, x.CameraCenter);
5649 m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; 5767 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}",
5650 m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; 5768 // x.CameraLeftAxis, x.CameraUpAxis);
5651 m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags; 5769 //}
5652 m_lastAgentUpdateArgs.Far = x.Far;
5653 m_lastAgentUpdateArgs.Flags = x.Flags;
5654 m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation;
5655 m_lastAgentUpdateArgs.SessionID = x.SessionID;
5656 m_lastAgentUpdateArgs.State = x.State;
5657 5770
5658 UpdateAgent handlerAgentUpdate = OnAgentUpdate; 5771 return cameraSignificant;
5659 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; 5772 }
5660 5773
5661 if (handlerPreAgentUpdate != null) 5774 private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
5662 OnPreAgentUpdate(this, m_lastAgentUpdateArgs); 5775 {
5776 // We got here, which means that something in agent update was significant
5663 5777
5664 if (handlerAgentUpdate != null) 5778 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5665 OnAgentUpdate(this, m_lastAgentUpdateArgs); 5779 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
5666 5780
5667 handlerAgentUpdate = null; 5781 if (x.AgentID != AgentId || x.SessionID != SessionId)
5668 handlerPreAgentUpdate = null; 5782 return false;
5669 } 5783
5670 } 5784 // Before we update the current m_thisAgentUpdateArgs, let's check this again
5785 // to see what exactly changed
5786 bool movement = CheckAgentMovementUpdateSignificance(x);
5787 bool camera = CheckAgentCameraUpdateSignificance(x);
5788
5789 m_thisAgentUpdateArgs.AgentID = x.AgentID;
5790 m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation;
5791 m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
5792 m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter;
5793 m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
5794 m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
5795 m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags;
5796 m_thisAgentUpdateArgs.Far = x.Far;
5797 m_thisAgentUpdateArgs.Flags = x.Flags;
5798 m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation;
5799 m_thisAgentUpdateArgs.SessionID = x.SessionID;
5800 m_thisAgentUpdateArgs.State = x.State;
5801
5802 UpdateAgent handlerAgentUpdate = OnAgentUpdate;
5803 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
5804 UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate;
5805
5806 // Was there a significant movement/state change?
5807 if (movement)
5808 {
5809 if (handlerPreAgentUpdate != null)
5810 OnPreAgentUpdate(this, m_thisAgentUpdateArgs);
5811
5812 if (handlerAgentUpdate != null)
5813 OnAgentUpdate(this, m_thisAgentUpdateArgs);
5814 }
5815 // Was there a significant camera(s) change?
5816 if (camera)
5817 if (handlerAgentCameraUpdate != null)
5818 handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs);
5819
5820 handlerAgentUpdate = null;
5821 handlerPreAgentUpdate = null;
5822 handlerAgentCameraUpdate = null;
5671 5823
5672 PacketPool.Instance.ReturnPacket(packet); 5824 PacketPool.Instance.ReturnPacket(packet);
5673 5825
@@ -6257,6 +6409,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6257 //m_log.Info("[LAND]: LAND:" + modify.ToString()); 6409 //m_log.Info("[LAND]: LAND:" + modify.ToString());
6258 if (modify.ParcelData.Length > 0) 6410 if (modify.ParcelData.Length > 0)
6259 { 6411 {
6412 // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore,
6413 // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit.
6414 m_justEditedTerrain = true; // Prevent terrain packet (Land layer) from being queued, make it unreliable
6260 if (OnModifyTerrain != null) 6415 if (OnModifyTerrain != null)
6261 { 6416 {
6262 for (int i = 0; i < modify.ParcelData.Length; i++) 6417 for (int i = 0; i < modify.ParcelData.Length; i++)
@@ -6272,6 +6427,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6272 } 6427 }
6273 } 6428 }
6274 } 6429 }
6430 m_justEditedTerrain = false; // Queue terrain packet (Land layer) if necessary, make it reliable again
6275 } 6431 }
6276 6432
6277 return true; 6433 return true;
@@ -6633,6 +6789,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6633 } 6789 }
6634 #endregion 6790 #endregion
6635 6791
6792 if (SceneAgent.IsChildAgent)
6793 {
6794 SendCantSitBecauseChildAgentResponse();
6795 return true;
6796 }
6797
6636 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; 6798 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit;
6637 6799
6638 if (handlerAgentRequestSit != null) 6800 if (handlerAgentRequestSit != null)
@@ -6657,6 +6819,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6657 } 6819 }
6658 #endregion 6820 #endregion
6659 6821
6822 if (SceneAgent.IsChildAgent)
6823 {
6824 SendCantSitBecauseChildAgentResponse();
6825 return true;
6826 }
6827
6660 AgentSit handlerAgentSit = OnAgentSit; 6828 AgentSit handlerAgentSit = OnAgentSit;
6661 if (handlerAgentSit != null) 6829 if (handlerAgentSit != null)
6662 { 6830 {
@@ -6666,6 +6834,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6666 return true; 6834 return true;
6667 } 6835 }
6668 6836
6837 /// <summary>
6838 /// Used when a child agent gets a sit response which should not be fulfilled.
6839 /// </summary>
6840 private void SendCantSitBecauseChildAgentResponse()
6841 {
6842 SendAlertMessage("Try moving closer. Can't sit on object because it is not in the same region as you.");
6843 }
6844
6669 private bool HandleSoundTrigger(IClientAPI sender, Packet Pack) 6845 private bool HandleSoundTrigger(IClientAPI sender, Packet Pack)
6670 { 6846 {
6671 SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack; 6847 SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack;
@@ -7876,129 +8052,145 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7876 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); 8052 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request");
7877 8053
7878 TransferRequestPacket transfer = (TransferRequestPacket)Pack; 8054 TransferRequestPacket transfer = (TransferRequestPacket)Pack;
7879 //m_log.Debug("Transfer Request: " + transfer.ToString());
7880 // Validate inventory transfers
7881 // Has to be done here, because AssetCache can't do it
7882 //
7883 UUID taskID = UUID.Zero; 8055 UUID taskID = UUID.Zero;
7884 if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) 8056 if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem)
7885 { 8057 {
7886 taskID = new UUID(transfer.TransferInfo.Params, 48);
7887 UUID itemID = new UUID(transfer.TransferInfo.Params, 64);
7888 UUID requestID = new UUID(transfer.TransferInfo.Params, 80);
7889
7890// m_log.DebugFormat(
7891// "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}",
7892// requestID, itemID, taskID, Name);
7893
7894 if (!(((Scene)m_scene).Permissions.BypassPermissions())) 8058 if (!(((Scene)m_scene).Permissions.BypassPermissions()))
7895 { 8059 {
7896 if (taskID != UUID.Zero) // Prim 8060 // We're spawning a thread because the permissions check can block this thread
8061 Util.FireAndForget(delegate
7897 { 8062 {
7898 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); 8063 // This requests the asset if needed
8064 HandleSimInventoryTransferRequestWithPermsCheck(sender, transfer);
8065 });
8066 return true;
8067 }
8068 }
8069 else if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate)
8070 {
8071 //TransferRequestPacket does not include covenant uuid?
8072 //get scene covenant uuid
8073 taskID = m_scene.RegionInfo.RegionSettings.Covenant;
8074 }
7899 8075
7900 if (part == null) 8076 // This is non-blocking
7901 { 8077 MakeAssetRequest(transfer, taskID);
7902 m_log.WarnFormat(
7903 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist",
7904 Name, requestID, itemID, taskID);
7905 return true;
7906 }
7907 8078
7908 TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); 8079 return true;
7909 if (tii == null) 8080 }
7910 {
7911 m_log.WarnFormat(
7912 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist",
7913 Name, requestID, itemID, taskID);
7914 return true;
7915 }
7916 8081
7917 if (tii.Type == (int)AssetType.LSLText) 8082 private void HandleSimInventoryTransferRequestWithPermsCheck(IClientAPI sender, TransferRequestPacket transfer)
7918 { 8083 {
7919 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) 8084 UUID taskID = new UUID(transfer.TransferInfo.Params, 48);
7920 return true; 8085 UUID itemID = new UUID(transfer.TransferInfo.Params, 64);
7921 } 8086 UUID requestID = new UUID(transfer.TransferInfo.Params, 80);
7922 else if (tii.Type == (int)AssetType.Notecard)
7923 {
7924 if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId))
7925 return true;
7926 }
7927 else
7928 {
7929 // TODO: Change this code to allow items other than notecards and scripts to be successfully
7930 // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule
7931 if (part.OwnerID != AgentId)
7932 {
7933 m_log.WarnFormat(
7934 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}",
7935 Name, requestID, itemID, taskID, part.OwnerID);
7936 return true;
7937 }
7938 8087
7939 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) 8088 //m_log.DebugFormat(
7940 { 8089 // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}",
7941 m_log.WarnFormat( 8090 // requestID, itemID, taskID, Name);
7942 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set",
7943 Name, requestID, itemID, taskID);
7944 return true;
7945 }
7946 8091
7947 if (tii.OwnerID != AgentId) 8092 //m_log.Debug("Transfer Request: " + transfer.ToString());
7948 { 8093 // Validate inventory transfers
7949 m_log.WarnFormat( 8094 // Has to be done here, because AssetCache can't do it
7950 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}", 8095 //
7951 Name, requestID, itemID, taskID, tii.OwnerID); 8096 if (taskID != UUID.Zero) // Prim
7952 return true; 8097 {
7953 } 8098 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID);
7954 8099
7955 if (( 8100 if (part == null)
7956 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) 8101 {
7957 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) 8102 m_log.WarnFormat(
7958 { 8103 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist",
7959 m_log.WarnFormat( 8104 Name, requestID, itemID, taskID);
7960 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", 8105 return;
7961 Name, requestID, itemID, taskID); 8106 }
7962 return true;
7963 }
7964 8107
7965 if (tii.AssetID != requestID) 8108 TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID);
7966 { 8109 if (tii == null)
7967 m_log.WarnFormat( 8110 {
7968 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", 8111 m_log.WarnFormat(
7969 Name, requestID, itemID, taskID, tii.AssetID); 8112 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist",
7970 return true; 8113 Name, requestID, itemID, taskID);
7971 } 8114 return;
7972 } 8115 }
8116
8117 if (tii.Type == (int)AssetType.LSLText)
8118 {
8119 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId))
8120 return;
8121 }
8122 else if (tii.Type == (int)AssetType.Notecard)
8123 {
8124 if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId))
8125 return;
8126 }
8127 else
8128 {
8129 // TODO: Change this code to allow items other than notecards and scripts to be successfully
8130 // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule
8131 if (part.OwnerID != AgentId)
8132 {
8133 m_log.WarnFormat(
8134 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}",
8135 Name, requestID, itemID, taskID, part.OwnerID);
8136 return;
7973 } 8137 }
7974 else // Agent 8138
8139 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0)
7975 { 8140 {
7976 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); 8141 m_log.WarnFormat(
7977 if (invAccess != null) 8142 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set",
7978 { 8143 Name, requestID, itemID, taskID);
7979 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID)) 8144 return;
7980 return false; 8145 }
7981 } 8146
7982 else 8147 if (tii.OwnerID != AgentId)
7983 { 8148 {
7984 return false; 8149 m_log.WarnFormat(
7985 } 8150 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}",
8151 Name, requestID, itemID, taskID, tii.OwnerID);
8152 return;
8153 }
8154
8155 if ((
8156 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8157 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8158 {
8159 m_log.WarnFormat(
8160 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer",
8161 Name, requestID, itemID, taskID);
8162 return;
8163 }
8164
8165 if (tii.AssetID != requestID)
8166 {
8167 m_log.WarnFormat(
8168 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}",
8169 Name, requestID, itemID, taskID, tii.AssetID);
8170 return;
7986 } 8171 }
7987 } 8172 }
7988 } 8173 }
7989 else 8174 else // Agent
7990 if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate) 8175 {
8176 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
8177 if (invAccess != null)
8178 {
8179 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID))
8180 return;
8181 }
8182 else
7991 { 8183 {
7992 //TransferRequestPacket does not include covenant uuid? 8184 return;
7993 //get scene covenant uuid
7994 taskID = m_scene.RegionInfo.RegionSettings.Covenant;
7995 } 8185 }
8186 }
7996 8187
8188 // Permissions out of the way, let's request the asset
7997 MakeAssetRequest(transfer, taskID); 8189 MakeAssetRequest(transfer, taskID);
7998 8190
7999 return true;
8000 } 8191 }
8001 8192
8193
8002 private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack) 8194 private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack)
8003 { 8195 {
8004 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; 8196 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack;
@@ -11729,8 +11921,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11729 } 11921 }
11730 11922
11731 /// <summary> 11923 /// <summary>
11732 /// Send a response back to a client when it asks the asset server (via the region server) if it has
11733 /// its appearance texture cached.
11734 /// </summary> 11924 /// </summary>
11735 /// <remarks> 11925 /// <remarks>
11736 /// At the moment, we always reply that there is no cached texture. 11926 /// At the moment, we always reply that there is no cached texture.
@@ -11738,6 +11928,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11738 /// <param name="simclient"></param> 11928 /// <param name="simclient"></param>
11739 /// <param name="packet"></param> 11929 /// <param name="packet"></param>
11740 /// <returns></returns> 11930 /// <returns></returns>
11931 // TODO: Convert old handler to use new method
11932 /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11933 {
11934 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11935
11936 if (cachedtex.AgentData.SessionID != SessionId)
11937 return false;
11938
11939
11940 List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>();
11941
11942 for (int i = 0; i < cachedtex.WearableData.Length; i++)
11943 {
11944 CachedTextureRequestArg arg = new CachedTextureRequestArg();
11945 arg.BakedTextureIndex = cachedtex.WearableData[i].TextureIndex;
11946 arg.WearableHashID = cachedtex.WearableData[i].ID;
11947
11948 requestArgs.Add(arg);
11949 }
11950
11951 CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest;
11952 if (handlerCachedTextureRequest != null)
11953 {
11954 handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs);
11955 }
11956
11957 return true;
11958 }*/
11959
11741 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) 11960 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11742 { 11961 {
11743 //m_log.Debug("texture cached: " + packet.ToString()); 11962 //m_log.Debug("texture cached: " + packet.ToString());
@@ -11896,6 +12115,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11896 return true; 12115 return true;
11897 } 12116 }
11898 12117
12118 /// <summary>
12119 /// Send a response back to a client when it asks the asset server (via the region server) if it has
12120 /// its appearance texture cached.
12121 /// </summary>
12122 /// <param name="avatar"></param>
12123 /// <param name="serial"></param>
12124 /// <param name="cachedTextures"></param>
12125 /// <returns></returns>
12126 public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures)
12127 {
12128 ScenePresence presence = avatar as ScenePresence;
12129 if (presence == null)
12130 return;
12131
12132 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
12133
12134 // TODO: don't create new blocks if recycling an old packet
12135 cachedresp.AgentData.AgentID = m_agentId;
12136 cachedresp.AgentData.SessionID = m_sessionId;
12137 cachedresp.AgentData.SerialNum = serial;
12138 cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cachedTextures.Count];
12139
12140 for (int i = 0; i < cachedTextures.Count; i++)
12141 {
12142 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12143 cachedresp.WearableData[i].TextureIndex = (byte)cachedTextures[i].BakedTextureIndex;
12144 cachedresp.WearableData[i].TextureID = cachedTextures[i].BakedTextureID;
12145 cachedresp.WearableData[i].HostName = new byte[0];
12146 }
12147
12148 cachedresp.Header.Zerocoded = true;
12149 OutPacket(cachedresp, ThrottleOutPacketType.Task);
12150 }
12151
11899 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) 12152 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet)
11900 { 12153 {
11901 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; 12154 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet;
@@ -11921,8 +12174,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11921 if (part == null) 12174 if (part == null)
11922 { 12175 {
11923 // It's a ghost! tell the client to delete it from view. 12176 // It's a ghost! tell the client to delete it from view.
11924 simClient.SendKillObject(Scene.RegionInfo.RegionHandle, 12177 simClient.SendKillObject(new List<uint> { localId });
11925 new List<uint> { localId });
11926 } 12178 }
11927 else 12179 else
11928 { 12180 {
@@ -12326,7 +12578,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12326 ClientInfo info = m_udpClient.GetClientInfo(); 12578 ClientInfo info = m_udpClient.GetClientInfo();
12327 12579
12328 info.proxyEP = null; 12580 info.proxyEP = null;
12329 info.agentcircuit = RequestClientInfo(); 12581 if (info.agentcircuit == null)
12582 info.agentcircuit = RequestClientInfo();
12330 12583
12331 return info; 12584 return info;
12332 } 12585 }
@@ -12709,11 +12962,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12709 OutPacket(dialog, ThrottleOutPacketType.Task); 12962 OutPacket(dialog, ThrottleOutPacketType.Task);
12710 } 12963 }
12711 12964
12712 public void StopFlying(ISceneEntity p) 12965 public void SendAgentTerseUpdate(ISceneEntity p)
12713 { 12966 {
12714 if (p is ScenePresence) 12967 if (p is ScenePresence)
12715 { 12968 {
12716 ScenePresence presence = p as ScenePresence;
12717 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities 12969 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities
12718 // There's no explicit message to send the client to tell it to stop flying.. it relies on the 12970 // There's no explicit message to send the client to tell it to stop flying.. it relies on the
12719 // velocity, collision plane and avatar height 12971 // velocity, collision plane and avatar height
@@ -12721,34 +12973,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12721 // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air 12973 // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air
12722 // when the avatar stands up 12974 // when the avatar stands up
12723 12975
12724 Vector3 pos = presence.AbsolutePosition;
12725
12726 if (presence.Appearance.AvatarHeight != 127.0f)
12727 pos += new Vector3(0f, 0f, (presence.Appearance.AvatarHeight/6f));
12728 else
12729 pos += new Vector3(0f, 0f, (1.56f/6f));
12730
12731 presence.AbsolutePosition = pos;
12732
12733 // attach a suitable collision plane regardless of the actual situation to force the LLClient to land.
12734 // Collision plane below the avatar's position a 6th of the avatar's height is suitable.
12735 // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a
12736 // certain amount.. because the LLClient wouldn't land in that situation anyway.
12737
12738 // why are we still testing for this really old height value default???
12739 if (presence.Appearance.AvatarHeight != 127.0f)
12740 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - presence.Appearance.AvatarHeight/6f);
12741 else
12742 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f/6f));
12743
12744
12745 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = 12976 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block =
12746 CreateImprovedTerseBlock(p, false); 12977 CreateImprovedTerseBlock(p, false);
12747 12978
12748 const float TIME_DILATION = 1.0f; 12979 const float TIME_DILATION = 1.0f;
12749 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); 12980 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
12750 12981
12751
12752 ImprovedTerseObjectUpdatePacket packet 12982 ImprovedTerseObjectUpdatePacket packet
12753 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( 12983 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
12754 PacketType.ImprovedTerseObjectUpdate); 12984 PacketType.ImprovedTerseObjectUpdate);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
index 073c357..41dd4d1 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
@@ -206,6 +206,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
206 } 206 }
207 } 207 }
208 208
209 public bool HasUpdates()
210 {
211 J2KImage image = GetHighestPriorityImage();
212
213 return image != null && image.IsDecoded;
214 }
215
209 public bool ProcessImageQueue(int packetsToSend) 216 public bool ProcessImageQueue(int packetsToSend)
210 { 217 {
211 int packetsSent = 0; 218 int packetsSent = 0;
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index e52ac37..d52ad7e 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -31,6 +31,7 @@ using System.Net;
31using System.Threading; 31using System.Threading;
32using log4net; 32using log4net;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Monitoring;
34using OpenMetaverse; 35using OpenMetaverse;
35using OpenMetaverse.Packets; 36using OpenMetaverse.Packets;
36 37
@@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
81 /// hooked to put more data on the empty queue</summary> 82 /// hooked to put more data on the empty queue</summary>
82 public event QueueEmpty OnQueueEmpty; 83 public event QueueEmpty OnQueueEmpty;
83 84
85 public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates;
86
84 /// <summary>AgentID for this client</summary> 87 /// <summary>AgentID for this client</summary>
85 public readonly UUID AgentID; 88 public readonly UUID AgentID;
86 /// <summary>The remote address of the connected client</summary> 89 /// <summary>The remote address of the connected client</summary>
@@ -160,6 +163,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
160 private int m_maxRTO = 60000; 163 private int m_maxRTO = 60000;
161 public bool m_deliverPackets = true; 164 public bool m_deliverPackets = true;
162 165
166 private ClientInfo m_info = new ClientInfo();
167
163 /// <summary> 168 /// <summary>
164 /// Default constructor 169 /// Default constructor
165 /// </summary> 170 /// </summary>
@@ -241,20 +246,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
241 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists 246 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists
242 // of pending and needed ACKs for every client every time some method wants information about 247 // of pending and needed ACKs for every client every time some method wants information about
243 // this connection is a recipe for poor performance 248 // this connection is a recipe for poor performance
244 ClientInfo info = new ClientInfo(); 249
245 info.pendingAcks = new Dictionary<uint, uint>(); 250 m_info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
246 info.needAck = new Dictionary<uint, byte[]>(); 251 m_info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
247 252 m_info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
248 info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; 253 m_info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
249 info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; 254 m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
250 info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; 255 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
251 info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; 256 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
252 info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; 257 m_info.totalThrottle = (int)m_throttleCategory.DripRate;
253 info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; 258
254 info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; 259 return m_info;
255 info.totalThrottle = (int)m_throttleCategory.DripRate;
256
257 return info;
258 } 260 }
259 261
260 /// <summary> 262 /// <summary>
@@ -646,15 +648,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
646 /// <param name="categories">Throttle categories to fire the callback for</param> 648 /// <param name="categories">Throttle categories to fire the callback for</param>
647 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) 649 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
648 { 650 {
649 if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) 651// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
652 if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
650 { 653 {
654 m_isQueueEmptyRunning = true;
655
656 int start = Environment.TickCount & Int32.MaxValue;
657 const int MIN_CALLBACK_MS = 30;
658
659 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
660 if (m_nextOnQueueEmpty == 0)
661 m_nextOnQueueEmpty = 1;
662
651 // Use a value of 0 to signal that FireQueueEmpty is running 663 // Use a value of 0 to signal that FireQueueEmpty is running
652 m_nextOnQueueEmpty = 0; 664// m_nextOnQueueEmpty = 0;
653 // Asynchronously run the callback 665
654 Util.FireAndForget(FireQueueEmpty, categories); 666 m_categories = categories;
667
668 if (HasUpdates(m_categories))
669 {
670 // Asynchronously run the callback
671 Util.FireAndForget(FireQueueEmpty, categories);
672 }
673 else
674 {
675 m_isQueueEmptyRunning = false;
676 }
655 } 677 }
656 } 678 }
657 679
680 private bool m_isQueueEmptyRunning;
681 private ThrottleOutPacketTypeFlags m_categories = 0;
682
658 /// <summary> 683 /// <summary>
659 /// Fires the OnQueueEmpty callback and sets the minimum time that it 684 /// Fires the OnQueueEmpty callback and sets the minimum time that it
660 /// can be called again 685 /// can be called again
@@ -664,22 +689,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
664 /// signature</param> 689 /// signature</param>
665 private void FireQueueEmpty(object o) 690 private void FireQueueEmpty(object o)
666 { 691 {
667 const int MIN_CALLBACK_MS = 30; 692// int start = Environment.TickCount & Int32.MaxValue;
693// const int MIN_CALLBACK_MS = 30;
668 694
669 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; 695// if (m_udpServer.IsRunningOutbound)
670 QueueEmpty callback = OnQueueEmpty; 696// {
671 697 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
672 int start = Environment.TickCount & Int32.MaxValue; 698 QueueEmpty callback = OnQueueEmpty;
673 699
674 if (callback != null) 700 if (callback != null)
675 { 701 {
676 try { callback(categories); } 702// if (m_udpServer.IsRunningOutbound)
677 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } 703// {
678 } 704 try { callback(categories); }
705 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
706// }
707 }
708// }
709
710// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
711// if (m_nextOnQueueEmpty == 0)
712// m_nextOnQueueEmpty = 1;
713
714// }
679 715
680 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; 716 m_isQueueEmptyRunning = false;
681 if (m_nextOnQueueEmpty == 0)
682 m_nextOnQueueEmpty = 1;
683 } 717 }
684 internal void ForceThrottleSetting(int throttle, int setting) 718 internal void ForceThrottleSetting(int throttle, int setting)
685 { 719 {
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 4154ef2..ad3f715 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -34,6 +34,7 @@ using System.Net.Sockets;
34using System.Reflection; 34using System.Reflection;
35using System.Threading; 35using System.Threading;
36using log4net; 36using log4net;
37using NDesk.Options;
37using Nini.Config; 38using Nini.Config;
38using OpenMetaverse.Packets; 39using OpenMetaverse.Packets;
39using OpenSim.Framework; 40using OpenSim.Framework;
@@ -62,20 +63,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP
62 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); 63 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager);
63 } 64 }
64 65
65 public void NetworkStop()
66 {
67 m_udpServer.Stop();
68 }
69
70 public void AddScene(IScene scene) 66 public void AddScene(IScene scene)
71 { 67 {
72 m_udpServer.AddScene(scene); 68 m_udpServer.AddScene(scene);
73 69
74 StatsManager.RegisterStat( 70 StatsManager.RegisterStat(
75 new Stat( 71 new Stat(
72 "ClientLogoutsDueToNoReceives",
73 "Number of times a client has been logged out because no packets were received before the timeout.",
74 "",
75 "",
76 "clientstack",
77 scene.Name,
78 StatType.Pull,
79 MeasuresOfInterest.None,
80 stat => stat.Value = m_udpServer.ClientLogoutsDueToNoReceives,
81 StatVerbosity.Debug));
82
83 StatsManager.RegisterStat(
84 new Stat(
85 "IncomingUDPReceivesCount",
86 "Number of UDP receives performed",
87 "",
88 "",
89 "clientstack",
90 scene.Name,
91 StatType.Pull,
92 MeasuresOfInterest.AverageChangeOverTime,
93 stat => stat.Value = m_udpServer.UdpReceives,
94 StatVerbosity.Debug));
95
96 StatsManager.RegisterStat(
97 new Stat(
76 "IncomingPacketsProcessedCount", 98 "IncomingPacketsProcessedCount",
77 "Number of inbound UDP packets processed", 99 "Number of inbound LL protocol packets processed",
78 "Number of inbound UDP packets processed", 100 "",
79 "", 101 "",
80 "clientstack", 102 "clientstack",
81 scene.Name, 103 scene.Name,
@@ -83,6 +105,60 @@ namespace OpenSim.Region.ClientStack.LindenUDP
83 MeasuresOfInterest.AverageChangeOverTime, 105 MeasuresOfInterest.AverageChangeOverTime,
84 stat => stat.Value = m_udpServer.IncomingPacketsProcessed, 106 stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
85 StatVerbosity.Debug)); 107 StatVerbosity.Debug));
108
109 StatsManager.RegisterStat(
110 new Stat(
111 "IncomingPacketsMalformedCount",
112 "Number of inbound UDP packets that could not be recognized as LL protocol packets.",
113 "",
114 "",
115 "clientstack",
116 scene.Name,
117 StatType.Pull,
118 MeasuresOfInterest.AverageChangeOverTime,
119 stat => stat.Value = m_udpServer.IncomingMalformedPacketCount,
120 StatVerbosity.Info));
121
122 StatsManager.RegisterStat(
123 new Stat(
124 "IncomingPacketsOrphanedCount",
125 "Number of inbound packets that were not initial connections packets and could not be associated with a viewer.",
126 "",
127 "",
128 "clientstack",
129 scene.Name,
130 StatType.Pull,
131 MeasuresOfInterest.AverageChangeOverTime,
132 stat => stat.Value = m_udpServer.IncomingOrphanedPacketCount,
133 StatVerbosity.Info));
134
135 StatsManager.RegisterStat(
136 new Stat(
137 "OutgoingUDPSendsCount",
138 "Number of UDP sends performed",
139 "",
140 "",
141 "clientstack",
142 scene.Name,
143 StatType.Pull,
144 MeasuresOfInterest.AverageChangeOverTime,
145 stat => stat.Value = m_udpServer.UdpSends,
146 StatVerbosity.Debug));
147
148 StatsManager.RegisterStat(
149 new Stat(
150 "AverageUDPProcessTime",
151 "Average number of milliseconds taken to process each incoming UDP packet in a sample.",
152 "This is for initial receive processing which is separate from the later client LL packet processing stage.",
153 "ms",
154 "clientstack",
155 scene.Name,
156 StatType.Pull,
157 MeasuresOfInterest.None,
158 stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond,
159// stat =>
160// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, 7),
161 StatVerbosity.Debug));
86 } 162 }
87 163
88 public bool HandlesRegion(Location x) 164 public bool HandlesRegion(Location x)
@@ -107,10 +183,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
107 /// </summary> 183 /// </summary>
108 public class LLUDPServer : OpenSimUDPBase 184 public class LLUDPServer : OpenSimUDPBase
109 { 185 {
186 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
187
110 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> 188 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary>
111 public const int MTU = 1400; 189 public const int MTU = 1400;
112 190
113 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 191 /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary>
192 public int ClientLogoutsDueToNoReceives { get; private set; }
193
194 /// <summary>
195 /// Default packet debug level given to new clients
196 /// </summary>
197 public int DefaultClientPacketDebugLevel { get; set; }
114 198
115 /// <summary>The measured resolution of Environment.TickCount</summary> 199 /// <summary>The measured resolution of Environment.TickCount</summary>
116 public readonly float TickCountResolution; 200 public readonly float TickCountResolution;
@@ -184,6 +268,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
184 protected bool m_sendPing; 268 protected bool m_sendPing;
185 269
186 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); 270 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
271
272 /// <summary>
273 /// Event used to signal when queued packets are available for sending.
274 /// </summary>
275 /// <remarks>
276 /// This allows the outbound loop to only operate when there is data to send rather than continuously polling.
277 /// Some data is sent immediately and not queued. That data would not trigger this event.
278 /// </remarks>
279 private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
280
187 private Pool<IncomingPacket> m_incomingPacketPool; 281 private Pool<IncomingPacket> m_incomingPacketPool;
188 282
189 /// <summary> 283 /// <summary>
@@ -204,7 +298,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
204 298
205 public Socket Server { get { return null; } } 299 public Socket Server { get { return null; } }
206 300
207 private int m_malformedCount = 0; // Guard against a spamming attack 301 /// <summary>
302 /// Record how many inbound packets could not be recognized as LLUDP packets.
303 /// </summary>
304 public int IncomingMalformedPacketCount { get; private set; }
305
306 /// <summary>
307 /// Record how many inbound packets could not be associated with a simulator circuit.
308 /// </summary>
309 public int IncomingOrphanedPacketCount { get; private set; }
208 310
209 /// <summary> 311 /// <summary>
210 /// Record current outgoing client for monitoring purposes. 312 /// Record current outgoing client for monitoring purposes.
@@ -461,6 +563,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
461 m_scene = (Scene)scene; 563 m_scene = (Scene)scene;
462 m_location = new Location(m_scene.RegionInfo.RegionHandle); 564 m_location = new Location(m_scene.RegionInfo.RegionHandle);
463 565
566 StatsManager.RegisterStat(
567 new Stat(
568 "InboxPacketsCount",
569 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
570 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
571 "",
572 "clientstack",
573 scene.Name,
574 StatType.Pull,
575 MeasuresOfInterest.AverageChangeOverTime,
576 stat => stat.Value = packetInbox.Count,
577 StatVerbosity.Debug));
578
464 // XXX: These stats are also pool stats but we register them separately since they are currently not 579 // XXX: These stats are also pool stats but we register them separately since they are currently not
465 // turned on and off by EnablePools()/DisablePools() 580 // turned on and off by EnablePools()/DisablePools()
466 StatsManager.RegisterStat( 581 StatsManager.RegisterStat(
@@ -521,6 +636,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
521 EnablePoolStats(); 636 EnablePoolStats();
522 637
523 MainConsole.Instance.Commands.AddCommand( 638 MainConsole.Instance.Commands.AddCommand(
639 "Debug", false, "debug lludp packet",
640 "debug lludp packet [--default] <level> [<avatar-first-name> <avatar-last-name>]",
641 "Turn on packet debugging",
642 "If level > 255 then all incoming and outgoing packets are logged.\n"
643 + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n"
644 + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n"
645 + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n"
646 + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n"
647 + "If level <= 0 then no packets are logged.\n"
648 + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n"
649 + "In this case, you cannot also specify an avatar name.\n"
650 + "If an avatar name is given then only packets from that avatar are logged.",
651 HandlePacketCommand);
652
653 MainConsole.Instance.Commands.AddCommand(
524 "Debug", 654 "Debug",
525 false, 655 false,
526 "debug lludp start", 656 "debug lludp start",
@@ -559,10 +689,78 @@ namespace OpenSim.Region.ClientStack.LindenUDP
559 "debug lludp status", 689 "debug lludp status",
560 "Return status of LLUDP packet processing.", 690 "Return status of LLUDP packet processing.",
561 HandleStatusCommand); 691 HandleStatusCommand);
692
693 MainConsole.Instance.Commands.AddCommand(
694 "Debug",
695 false,
696 "debug lludp toggle agentupdate",
697 "debug lludp toggle agentupdate",
698 "Toggle whether agentupdate packets are processed or simply discarded.",
699 HandleAgentUpdateCommand);
700 }
701
702 private void HandlePacketCommand(string module, string[] args)
703 {
704 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
705 return;
706
707 bool setAsDefaultLevel = false;
708 OptionSet optionSet = new OptionSet().Add("default", o => setAsDefaultLevel = o != null);
709 List<string> filteredArgs = optionSet.Parse(args);
710
711 string name = null;
712
713 if (filteredArgs.Count == 6)
714 {
715 if (!setAsDefaultLevel)
716 {
717 name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]);
718 }
719 else
720 {
721 MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default logging level");
722 return;
723 }
724 }
725
726 if (filteredArgs.Count > 3)
727 {
728 int newDebug;
729 if (int.TryParse(filteredArgs[3], out newDebug))
730 {
731 if (setAsDefaultLevel)
732 {
733 DefaultClientPacketDebugLevel = newDebug;
734 MainConsole.Instance.OutputFormat(
735 "Debug packet debug for new clients set to {0} in {1}", DefaultClientPacketDebugLevel, m_scene.Name);
736 }
737 else
738 {
739 m_scene.ForEachScenePresence(sp =>
740 {
741 if (name == null || sp.Name == name)
742 {
743 MainConsole.Instance.OutputFormat(
744 "Packet debug for {0} ({1}) set to {2} in {3}",
745 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name);
746
747 sp.ControllingClient.DebugPacketLevel = newDebug;
748 }
749 });
750 }
751 }
752 else
753 {
754 MainConsole.Instance.Output("Usage: debug lludp packet [--default] 0..255 [<first-name> <last-name>]");
755 }
756 }
562 } 757 }
563 758
564 private void HandleStartCommand(string module, string[] args) 759 private void HandleStartCommand(string module, string[] args)
565 { 760 {
761 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
762 return;
763
566 if (args.Length != 4) 764 if (args.Length != 4)
567 { 765 {
568 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); 766 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
@@ -580,6 +778,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
580 778
581 private void HandleStopCommand(string module, string[] args) 779 private void HandleStopCommand(string module, string[] args)
582 { 780 {
781 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
782 return;
783
583 if (args.Length != 4) 784 if (args.Length != 4)
584 { 785 {
585 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); 786 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
@@ -597,6 +798,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
597 798
598 private void HandlePoolCommand(string module, string[] args) 799 private void HandlePoolCommand(string module, string[] args)
599 { 800 {
801 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
802 return;
803
600 if (args.Length != 4) 804 if (args.Length != 4)
601 { 805 {
602 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); 806 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
@@ -627,8 +831,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
627 } 831 }
628 } 832 }
629 833
834 bool m_discardAgentUpdates;
835
836 private void HandleAgentUpdateCommand(string module, string[] args)
837 {
838 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
839 return;
840
841 m_discardAgentUpdates = !m_discardAgentUpdates;
842
843 MainConsole.Instance.OutputFormat(
844 "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name);
845 }
846
630 private void HandleStatusCommand(string module, string[] args) 847 private void HandleStatusCommand(string module, string[] args)
631 { 848 {
849 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
850 return;
851
632 MainConsole.Instance.OutputFormat( 852 MainConsole.Instance.OutputFormat(
633 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); 853 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled");
634 854
@@ -636,6 +856,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
636 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); 856 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
637 857
638 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); 858 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off");
859
860 MainConsole.Instance.OutputFormat(
861 "Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel);
639 } 862 }
640 863
641 public bool HandlesRegion(Location x) 864 public bool HandlesRegion(Location x)
@@ -721,6 +944,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
721 } 944 }
722 945
723 PacketPool.Instance.ReturnPacket(packet); 946 PacketPool.Instance.ReturnPacket(packet);
947
948 m_dataPresentEvent.Set();
724 } 949 }
725 950
726 /// <summary> 951 /// <summary>
@@ -883,7 +1108,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
883 // Fire this out on a different thread so that we don't hold up outgoing packet processing for 1108 // Fire this out on a different thread so that we don't hold up outgoing packet processing for
884 // everybody else if this is being called due to an ack timeout. 1109 // everybody else if this is being called due to an ack timeout.
885 // This is the same as processing as the async process of a logout request. 1110 // This is the same as processing as the async process of a logout request.
886 Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); 1111 Util.FireAndForget(o => DeactivateClientDueToTimeout(client, timeoutTicks));
887 1112
888 return; 1113 return;
889 } 1114 }
@@ -1002,6 +1227,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1002 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; 1227 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
1003 } 1228 }
1004 1229
1230 private void RecordMalformedInboundPacket(IPEndPoint endPoint)
1231 {
1232// if (m_malformedCount < 100)
1233// m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1234
1235 IncomingMalformedPacketCount++;
1236
1237 if ((IncomingMalformedPacketCount % 10000) == 0)
1238 m_log.WarnFormat(
1239 "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}",
1240 IncomingMalformedPacketCount, endPoint);
1241 }
1242
1005 public override void PacketReceived(UDPPacketBuffer buffer) 1243 public override void PacketReceived(UDPPacketBuffer buffer)
1006 { 1244 {
1007 // Debugging/Profiling 1245 // Debugging/Profiling
@@ -1023,6 +1261,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1023// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", 1261// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
1024// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 1262// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1025 1263
1264 RecordMalformedInboundPacket(endPoint);
1265
1026 return; // Drop undersized packet 1266 return; // Drop undersized packet
1027 } 1267 }
1028 1268
@@ -1041,6 +1281,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1041// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", 1281// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}",
1042// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 1282// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1043 1283
1284 RecordMalformedInboundPacket(endPoint);
1285
1044 return; // Malformed header 1286 return; // Malformed header
1045 } 1287 }
1046 1288
@@ -1056,34 +1298,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1056 // Only allocate a buffer for zerodecoding if the packet is zerocoded 1298 // Only allocate a buffer for zerodecoding if the packet is zerocoded
1057 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 1299 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
1058 } 1300 }
1059 catch (MalformedDataException)
1060 {
1061 }
1062 catch (IndexOutOfRangeException)
1063 {
1064// m_log.WarnFormat(
1065// "[LLUDPSERVER]: Dropping short packet received from {0} in {1}",
1066// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1067
1068 return; // Drop short packet
1069 }
1070 catch (Exception e) 1301 catch (Exception e)
1071 { 1302 {
1072 if (m_malformedCount < 100) 1303 if (IncomingMalformedPacketCount < 100)
1073 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); 1304 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1074
1075 m_malformedCount++;
1076
1077 if ((m_malformedCount % 100000) == 0)
1078 m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
1079 } 1305 }
1080 1306
1081 // Fail-safe check 1307 // Fail-safe check
1082 if (packet == null) 1308 if (packet == null)
1083 { 1309 {
1084 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:", 1310 if (IncomingMalformedPacketCount < 100)
1085 buffer.DataLength, buffer.RemoteEndPoint); 1311 {
1086 m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); 1312 m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:",
1313 buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
1314 }
1315
1316 RecordMalformedInboundPacket(endPoint);
1317
1087 return; 1318 return;
1088 } 1319 }
1089 1320
@@ -1127,12 +1358,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1127 queue.Enqueue(buffer); 1358 queue.Enqueue(buffer);
1128 return; 1359 return;
1129 } 1360 }
1361 else if (packet.Type == PacketType.CompleteAgentMovement)
1362 {
1363 // Send ack straight away to let the viewer know that we got it.
1364 SendAckImmediate(endPoint, packet.Header.Sequence);
1365
1366 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1367 // buffer.
1368 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1369
1370 Util.FireAndForget(HandleCompleteMovementIntoRegion, array);
1371
1372 return;
1373 }
1130 } 1374 }
1131 1375
1132 // Determine which agent this packet came from 1376 // Determine which agent this packet came from
1133 if (client == null || !(client is LLClientView)) 1377 if (client == null || !(client is LLClientView))
1134 { 1378 {
1135 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1379 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1380
1381 IncomingOrphanedPacketCount++;
1382
1383 if ((IncomingOrphanedPacketCount % 10000) == 0)
1384 m_log.WarnFormat(
1385 "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}",
1386 IncomingOrphanedPacketCount, endPoint);
1387
1136 return; 1388 return;
1137 } 1389 }
1138 1390
@@ -1233,6 +1485,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1233 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); 1485 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
1234 #endregion BinaryStats 1486 #endregion BinaryStats
1235 1487
1488 if (packet.Type == PacketType.AgentUpdate)
1489 {
1490 if (m_discardAgentUpdates)
1491 return;
1492
1493 ((LLClientView)client).TotalAgentUpdates++;
1494
1495 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
1496
1497 LLClientView llClient = client as LLClientView;
1498 if (agentUpdate.AgentData.SessionID != client.SessionId
1499 || agentUpdate.AgentData.AgentID != client.AgentId
1500 || !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) )
1501 {
1502 PacketPool.Instance.ReturnPacket(packet);
1503 return;
1504 }
1505 }
1506
1236 #region Ping Check Handling 1507 #region Ping Check Handling
1237 1508
1238 if (packet.Type == PacketType.StartPingCheck) 1509 if (packet.Type == PacketType.StartPingCheck)
@@ -1421,7 +1692,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1421 1692
1422 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1693 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1423 if (client != null) 1694 if (client != null)
1424 client.SceneAgent.SendInitialDataToMe(); 1695 {
1696 AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1697 bool tp = (aCircuit.teleportFlags > 0);
1698 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from
1699 if (!tp)
1700 client.SceneAgent.SendInitialDataToMe();
1701 }
1425 1702
1426 // Now we know we can handle more data 1703 // Now we know we can handle more data
1427 Thread.Sleep(200); 1704 Thread.Sleep(200);
@@ -1476,6 +1753,72 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1476 } 1753 }
1477 } 1754 }
1478 1755
1756 private void HandleCompleteMovementIntoRegion(object o)
1757 {
1758 IPEndPoint endPoint = null;
1759 IClientAPI client = null;
1760
1761 try
1762 {
1763 object[] array = (object[])o;
1764 endPoint = (IPEndPoint)array[0];
1765 CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1];
1766
1767 // Determine which agent this packet came from
1768 int count = 20;
1769 bool ready = false;
1770 while (!ready && count-- > 0)
1771 {
1772 if (m_scene.TryGetClient(endPoint, out client) && client.IsActive && client.SceneAgent != null)
1773 {
1774 LLClientView llClientView = (LLClientView)client;
1775 LLUDPClient udpClient = llClientView.UDPClient;
1776 if (udpClient != null && udpClient.IsConnected)
1777 ready = true;
1778 else
1779 {
1780 m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)");
1781 Thread.Sleep(200);
1782 }
1783 }
1784 else
1785 {
1786 m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)");
1787 Thread.Sleep(200);
1788 }
1789 }
1790
1791 if (client == null)
1792 return;
1793
1794 IncomingPacket incomingPacket1;
1795
1796 // Inbox insertion
1797 if (UsePools)
1798 {
1799 incomingPacket1 = m_incomingPacketPool.GetObject();
1800 incomingPacket1.Client = (LLClientView)client;
1801 incomingPacket1.Packet = packet;
1802 }
1803 else
1804 {
1805 incomingPacket1 = new IncomingPacket((LLClientView)client, packet);
1806 }
1807
1808 packetInbox.Enqueue(incomingPacket1);
1809 }
1810 catch (Exception e)
1811 {
1812 m_log.ErrorFormat(
1813 "[LLUDPSERVER]: CompleteMovementIntoRegion handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1814 endPoint != null ? endPoint.ToString() : "n/a",
1815 client != null ? client.Name : "unknown",
1816 client != null ? client.AgentId.ToString() : "unknown",
1817 e.Message,
1818 e.StackTrace);
1819 }
1820 }
1821
1479 /// <summary> 1822 /// <summary>
1480 /// Send an ack immediately to the given endpoint. 1823 /// Send an ack immediately to the given endpoint.
1481 /// </summary> 1824 /// </summary>
@@ -1544,6 +1887,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1544 1887
1545 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 1888 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1546 client.OnLogout += LogoutHandler; 1889 client.OnLogout += LogoutHandler;
1890 client.DebugPacketLevel = DefaultClientPacketDebugLevel;
1547 1891
1548 ((LLClientView)client).DisableFacelights = m_disableFacelights; 1892 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1549 1893
@@ -1562,21 +1906,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1562 /// regular client pings. 1906 /// regular client pings.
1563 /// </remarks> 1907 /// </remarks>
1564 /// <param name='client'></param> 1908 /// <param name='client'></param>
1565 private void DeactivateClientDueToTimeout(LLClientView client) 1909 /// <param name='timeoutTicks'></param>
1910 private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks)
1566 { 1911 {
1567 lock (client.CloseSyncLock) 1912 lock (client.CloseSyncLock)
1568 { 1913 {
1914 ClientLogoutsDueToNoReceives++;
1915
1569 m_log.WarnFormat( 1916 m_log.WarnFormat(
1570 "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", 1917 "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.",
1571 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName); 1918 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, m_scene.Name);
1572
1573 StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
1574 1919
1575 if (!client.SceneAgent.IsChildAgent) 1920 if (!client.SceneAgent.IsChildAgent)
1576 client.Kick("Simulator logged you out due to connection timeout"); 1921 client.Kick("Simulator logged you out due to connection timeout.");
1577
1578 client.CloseWithoutChecks(true);
1579 } 1922 }
1923
1924 m_scene.IncomingCloseAgent(client.AgentId, true);
1580 } 1925 }
1581 1926
1582 private void IncomingPacketHandler() 1927 private void IncomingPacketHandler()
@@ -1592,6 +1937,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1592 { 1937 {
1593 IncomingPacket incomingPacket = null; 1938 IncomingPacket incomingPacket = null;
1594 1939
1940 /*
1595 // HACK: This is a test to try and rate limit packet handling on Mono. 1941 // HACK: This is a test to try and rate limit packet handling on Mono.
1596 // If it works, a more elegant solution can be devised 1942 // If it works, a more elegant solution can be devised
1597 if (Util.FireAndForgetCount() < 2) 1943 if (Util.FireAndForgetCount() < 2)
@@ -1599,6 +1945,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1599 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); 1945 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping");
1600 Thread.Sleep(30); 1946 Thread.Sleep(30);
1601 } 1947 }
1948 */
1602 1949
1603 if (packetInbox.Dequeue(100, ref incomingPacket)) 1950 if (packetInbox.Dequeue(100, ref incomingPacket))
1604 { 1951 {
@@ -1694,8 +2041,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1694 2041
1695 // If nothing was sent, sleep for the minimum amount of time before a 2042 // If nothing was sent, sleep for the minimum amount of time before a
1696 // token bucket could get more tokens 2043 // token bucket could get more tokens
2044 //if (!m_packetSent)
2045 // Thread.Sleep((int)TickCountResolution);
2046 //
2047 // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with
2048 // modern mono it reduces CPU base load since there is no more continuous polling.
1697 if (!m_packetSent) 2049 if (!m_packetSent)
1698 Thread.Sleep((int)TickCountResolution); 2050 m_dataPresentEvent.WaitOne(100);
1699 2051
1700 Watchdog.UpdateThread(); 2052 Watchdog.UpdateThread();
1701 } 2053 }
@@ -1912,7 +2264,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1912 if (!client.IsLoggingOut) 2264 if (!client.IsLoggingOut)
1913 { 2265 {
1914 client.IsLoggingOut = true; 2266 client.IsLoggingOut = true;
1915 client.Close(false, false); 2267 m_scene.IncomingCloseAgent(client.AgentId, false);
1916 } 2268 }
1917 } 2269 }
1918 } 2270 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index 7035e38..48c5b37 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -78,6 +78,36 @@ namespace OpenMetaverse
78 public bool IsRunningOutbound { get; private set; } 78 public bool IsRunningOutbound { get; private set; }
79 79
80 /// <summary> 80 /// <summary>
81 /// Number of UDP receives.
82 /// </summary>
83 public int UdpReceives { get; private set; }
84
85 /// <summary>
86 /// Number of UDP sends
87 /// </summary>
88 public int UdpSends { get; private set; }
89
90 /// <summary>
91 /// Number of receives over which to establish a receive time average.
92 /// </summary>
93 private readonly static int s_receiveTimeSamples = 500;
94
95 /// <summary>
96 /// Current number of samples taken to establish a receive time average.
97 /// </summary>
98 private int m_currentReceiveTimeSamples;
99
100 /// <summary>
101 /// Cumulative receive time for the sample so far.
102 /// </summary>
103 private int m_receiveTicksInCurrentSamplePeriod;
104
105 /// <summary>
106 /// The average time taken for each require receive in the last sample.
107 /// </summary>
108 public float AverageReceiveTicksForLastSamplePeriod { get; private set; }
109
110 /// <summary>
81 /// Default constructor 111 /// Default constructor
82 /// </summary> 112 /// </summary>
83 /// <param name="bindAddress">Local IP address to bind the server to</param> 113 /// <param name="bindAddress">Local IP address to bind the server to</param>
@@ -111,6 +141,8 @@ namespace OpenMetaverse
111 141
112 if (!IsRunningInbound) 142 if (!IsRunningInbound)
113 { 143 {
144 m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop");
145
114 const int SIO_UDP_CONNRESET = -1744830452; 146 const int SIO_UDP_CONNRESET = -1744830452;
115 147
116 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); 148 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
@@ -151,6 +183,8 @@ namespace OpenMetaverse
151 /// </summary> 183 /// </summary>
152 public void StartOutbound() 184 public void StartOutbound()
153 { 185 {
186 m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop");
187
154 IsRunningOutbound = true; 188 IsRunningOutbound = true;
155 } 189 }
156 190
@@ -158,10 +192,8 @@ namespace OpenMetaverse
158 { 192 {
159 if (IsRunningInbound) 193 if (IsRunningInbound)
160 { 194 {
161 // wait indefinitely for a writer lock. Once this is called, the .NET runtime 195 m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop");
162 // will deny any more reader locks, in effect blocking all other send/receive 196
163 // threads. Once we have the lock, we set IsRunningInbound = false to inform the other
164 // threads that the socket is closed.
165 IsRunningInbound = false; 197 IsRunningInbound = false;
166 m_udpSocket.Close(); 198 m_udpSocket.Close();
167 } 199 }
@@ -169,6 +201,8 @@ namespace OpenMetaverse
169 201
170 public void StopOutbound() 202 public void StopOutbound()
171 { 203 {
204 m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop");
205
172 IsRunningOutbound = false; 206 IsRunningOutbound = false;
173 } 207 }
174 208
@@ -267,6 +301,8 @@ namespace OpenMetaverse
267 // to AsyncBeginReceive 301 // to AsyncBeginReceive
268 if (IsRunningInbound) 302 if (IsRunningInbound)
269 { 303 {
304 UdpReceives++;
305
270 // Asynchronous mode will start another receive before the 306 // Asynchronous mode will start another receive before the
271 // callback for this packet is even fired. Very parallel :-) 307 // callback for this packet is even fired. Very parallel :-)
272 if (m_asyncPacketHandling) 308 if (m_asyncPacketHandling)
@@ -278,6 +314,8 @@ namespace OpenMetaverse
278 314
279 try 315 try
280 { 316 {
317 int startTick = Util.EnvironmentTickCount();
318
281 // get the length of data actually read from the socket, store it with the 319 // get the length of data actually read from the socket, store it with the
282 // buffer 320 // buffer
283 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); 321 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
@@ -285,6 +323,23 @@ namespace OpenMetaverse
285 // call the abstract method PacketReceived(), passing the buffer that 323 // call the abstract method PacketReceived(), passing the buffer that
286 // has just been filled from the socket read. 324 // has just been filled from the socket read.
287 PacketReceived(buffer); 325 PacketReceived(buffer);
326
327 // If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler)
328 // then a particular stat may be inaccurate due to a race condition. We won't worry about this
329 // since this should be rare and won't cause a runtime problem.
330 if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
331 {
332 AverageReceiveTicksForLastSamplePeriod
333 = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
334
335 m_receiveTicksInCurrentSamplePeriod = 0;
336 m_currentReceiveTimeSamples = 0;
337 }
338 else
339 {
340 m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick);
341 m_currentReceiveTimeSamples++;
342 }
288 } 343 }
289 catch (SocketException) { } 344 catch (SocketException) { }
290 catch (ObjectDisposedException) { } 345 catch (ObjectDisposedException) { }
@@ -298,14 +353,13 @@ namespace OpenMetaverse
298 if (!m_asyncPacketHandling) 353 if (!m_asyncPacketHandling)
299 AsyncBeginReceive(); 354 AsyncBeginReceive();
300 } 355 }
301
302 } 356 }
303 } 357 }
304 358
305 public void AsyncBeginSend(UDPPacketBuffer buf) 359 public void AsyncBeginSend(UDPPacketBuffer buf)
306 { 360 {
307 if (IsRunningOutbound) 361// if (IsRunningOutbound)
308 { 362// {
309 try 363 try
310 { 364 {
311 m_udpSocket.BeginSendTo( 365 m_udpSocket.BeginSendTo(
@@ -319,7 +373,7 @@ namespace OpenMetaverse
319 } 373 }
320 catch (SocketException) { } 374 catch (SocketException) { }
321 catch (ObjectDisposedException) { } 375 catch (ObjectDisposedException) { }
322 } 376// }
323 } 377 }
324 378
325 void AsyncEndSend(IAsyncResult result) 379 void AsyncEndSend(IAsyncResult result)
@@ -328,6 +382,8 @@ namespace OpenMetaverse
328 { 382 {
329// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; 383// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
330 m_udpSocket.EndSendTo(result); 384 m_udpSocket.EndSendTo(result);
385
386 UdpSends++;
331 } 387 }
332 catch (SocketException) { } 388 catch (SocketException) { }
333 catch (ObjectDisposedException) { } 389 catch (ObjectDisposedException) { }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
index 1fdc410..5a2bcee 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -145,39 +145,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
145 return packet; 145 return packet;
146 } 146 }
147 147
148 // private byte[] decoded_header = new byte[10];
149 private static PacketType GetType(byte[] bytes) 148 private static PacketType GetType(byte[] bytes)
150 { 149 {
151 byte[] decoded_header = new byte[10 + 8];
152 ushort id; 150 ushort id;
153 PacketFrequency freq; 151 PacketFrequency freq;
152 bool isZeroCoded = (bytes[0] & Helpers.MSG_ZEROCODED) != 0;
154 153
155 if ((bytes[0] & Helpers.MSG_ZEROCODED) != 0) 154 if (bytes[6] == 0xFF)
156 { 155 {
157 Helpers.ZeroDecode(bytes, 16, decoded_header); 156 if (bytes[7] == 0xFF)
158 }
159 else
160 {
161 Buffer.BlockCopy(bytes, 0, decoded_header, 0, 10);
162 }
163
164 if (decoded_header[6] == 0xFF)
165 {
166 if (decoded_header[7] == 0xFF)
167 { 157 {
168 id = (ushort) ((decoded_header[8] << 8) + decoded_header[9]);
169 freq = PacketFrequency.Low; 158 freq = PacketFrequency.Low;
159 if (isZeroCoded && bytes[8] == 0)
160 id = bytes[10];
161 else
162 id = (ushort)((bytes[8] << 8) + bytes[9]);
170 } 163 }
171 else 164 else
172 { 165 {
173 id = decoded_header[7];
174 freq = PacketFrequency.Medium; 166 freq = PacketFrequency.Medium;
167 id = bytes[7];
175 } 168 }
176 } 169 }
177 else 170 else
178 { 171 {
179 id = decoded_header[6];
180 freq = PacketFrequency.High; 172 freq = PacketFrequency.High;
173 id = bytes[6];
181 } 174 }
182 175
183 return Packet.GetType(id, freq); 176 return Packet.GetType(id, freq);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
index 556df30..9700224 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
@@ -33,6 +33,7 @@ using NUnit.Framework;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenMetaverse.Packets; 34using OpenMetaverse.Packets;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
37using OpenSim.Tests.Common; 38using OpenSim.Tests.Common;
38using OpenSim.Tests.Common.Mock; 39using OpenSim.Tests.Common.Mock;
@@ -69,6 +70,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
69 { 70 {
70 base.SetUp(); 71 base.SetUp();
71 m_scene = new SceneHelpers().SetupScene(); 72 m_scene = new SceneHelpers().SetupScene();
73 StatsManager.SimExtraStats = new SimExtraStatsCollector();
72 } 74 }
73 75
74 /// <summary> 76 /// <summary>
@@ -198,7 +200,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
198 public void TestLogoutClientDueToAck() 200 public void TestLogoutClientDueToAck()
199 { 201 {
200 TestHelpers.InMethod(); 202 TestHelpers.InMethod();
201// TestHelpers.EnableLogging(); 203 TestHelpers.EnableLogging();
202 204
203 IniConfigSource ics = new IniConfigSource(); 205 IniConfigSource ics = new IniConfigSource();
204 IConfig config = ics.AddConfig("ClientStack.LindenUDP"); 206 IConfig config = ics.AddConfig("ClientStack.LindenUDP");
@@ -210,8 +212,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
210 212
211 ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); 213 ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID);
212 Assert.That(spAfterAckTimeout, Is.Null); 214 Assert.That(spAfterAckTimeout, Is.Null);
213
214// TestHelpers.DisableLogging();
215 } 215 }
216 216
217// /// <summary> 217// /// <summary>
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
index 7d9f581..575e54c 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
@@ -29,6 +29,7 @@ using System;
29using System.IO; 29using System.IO;
30using System.Net; 30using System.Net;
31using System.Reflection; 31using System.Reflection;
32using System.Threading;
32using log4net.Config; 33using log4net.Config;
33using Nini.Config; 34using Nini.Config;
34using NUnit.Framework; 35using NUnit.Framework;
@@ -53,6 +54,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
53 [TestFixtureSetUp] 54 [TestFixtureSetUp]
54 public void FixtureInit() 55 public void FixtureInit()
55 { 56 {
57 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
58 Util.FireAndForgetMethod = FireAndForgetMethod.None;
59
56 using ( 60 using (
57 Stream resource 61 Stream resource
58 = GetType().Assembly.GetManifestResourceStream( 62 = GetType().Assembly.GetManifestResourceStream(
@@ -72,9 +76,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
72 } 76 }
73 } 77 }
74 78
79 [TestFixtureTearDown]
80 public void TearDown()
81 {
82 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
83 // threads. Possibly, later tests should be rewritten not to worry about such things.
84 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
85 }
86
75 [SetUp] 87 [SetUp]
76 public void SetUp() 88 public override void SetUp()
77 { 89 {
90 base.SetUp();
91
78 UUID userId = TestHelpers.ParseTail(0x3); 92 UUID userId = TestHelpers.ParseTail(0x3);
79 93
80 J2KDecoderModule j2kdm = new J2KDecoderModule(); 94 J2KDecoderModule j2kdm = new J2KDecoderModule();