diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP')
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; | |||
31 | using System.Threading; | 31 | using System.Threading; |
32 | using log4net; | 32 | using log4net; |
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Framework.Monitoring; | ||
34 | using OpenMetaverse; | 35 | using OpenMetaverse; |
35 | using OpenMetaverse.Packets; | 36 | using 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; | |||
34 | using System.Reflection; | 34 | using System.Reflection; |
35 | using System.Threading; | 35 | using System.Threading; |
36 | using log4net; | 36 | using log4net; |
37 | using NDesk.Options; | ||
37 | using Nini.Config; | 38 | using Nini.Config; |
38 | using OpenMetaverse.Packets; | 39 | using OpenMetaverse.Packets; |
39 | using OpenSim.Framework; | 40 | using 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; | |||
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenMetaverse.Packets; | 34 | using OpenMetaverse.Packets; |
35 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
36 | using OpenSim.Framework.Monitoring; | ||
36 | using OpenSim.Region.Framework.Scenes; | 37 | using OpenSim.Region.Framework.Scenes; |
37 | using OpenSim.Tests.Common; | 38 | using OpenSim.Tests.Common; |
38 | using OpenSim.Tests.Common.Mock; | 39 | using 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; | |||
29 | using System.IO; | 29 | using System.IO; |
30 | using System.Net; | 30 | using System.Net; |
31 | using System.Reflection; | 31 | using System.Reflection; |
32 | using System.Threading; | ||
32 | using log4net.Config; | 33 | using log4net.Config; |
33 | using Nini.Config; | 34 | using Nini.Config; |
34 | using NUnit.Framework; | 35 | using 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(); |