aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Framework/IClientAPI.cs59
-rw-r--r--OpenSim/Framework/Util.cs17
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs96
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs64
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs6
5 files changed, 176 insertions, 66 deletions
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index f573c32..069987b 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -572,34 +572,69 @@ namespace OpenSim.Framework
572 572
573 public class IEntityUpdate 573 public class IEntityUpdate
574 { 574 {
575 public ISceneEntity Entity; 575 private ISceneEntity m_entity;
576 public uint Flags; 576 private uint m_flags;
577 private int m_updateTime;
578
579 public ISceneEntity Entity
580 {
581 get { return m_entity; }
582 }
583
584 public uint Flags
585 {
586 get { return m_flags; }
587 }
588
589 public int UpdateTime
590 {
591 get { return m_updateTime; }
592 }
577 593
578 public virtual void Update(IEntityUpdate update) 594 public virtual void Update(IEntityUpdate update)
579 { 595 {
580 this.Flags |= update.Flags; 596 m_flags |= update.Flags;
597
598 // Use the older of the updates as the updateTime
599 if (Util.EnvironmentTickCountCompare(UpdateTime, update.UpdateTime) > 0)
600 m_updateTime = update.UpdateTime;
581 } 601 }
582 602
583 public IEntityUpdate(ISceneEntity entity, uint flags) 603 public IEntityUpdate(ISceneEntity entity, uint flags)
584 { 604 {
585 Entity = entity; 605 m_entity = entity;
586 Flags = flags; 606 m_flags = flags;
607 m_updateTime = Util.EnvironmentTickCount();
608 }
609
610 public IEntityUpdate(ISceneEntity entity, uint flags, Int32 updateTime)
611 {
612 m_entity = entity;
613 m_flags = flags;
614 m_updateTime = updateTime;
587 } 615 }
588 } 616 }
589
590 617
591 public class EntityUpdate : IEntityUpdate 618 public class EntityUpdate : IEntityUpdate
592 { 619 {
593 // public ISceneEntity Entity; 620 private float m_timeDilation;
594 // public PrimUpdateFlags Flags; 621
595 public float TimeDilation; 622 public float TimeDilation
623 {
624 get { return m_timeDilation; }
625 }
596 626
597 public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation) 627 public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation)
598 : base(entity,(uint)flags) 628 : base(entity, (uint)flags)
599 { 629 {
600 //Entity = entity;
601 // Flags = flags; 630 // Flags = flags;
602 TimeDilation = timedilation; 631 m_timeDilation = timedilation;
632 }
633
634 public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation, Int32 updateTime)
635 : base(entity,(uint)flags,updateTime)
636 {
637 m_timeDilation = timedilation;
603 } 638 }
604 } 639 }
605 640
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index 5a5046e..aaa2724 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -1537,6 +1537,23 @@ namespace OpenSim.Framework
1537 return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1); 1537 return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1);
1538 } 1538 }
1539 1539
1540 // Returns value of Tick Count A - TickCount B accounting for wrapping of TickCount
1541 // Assumes both tcA and tcB came from previous calls to Util.EnvironmentTickCount().
1542 // A positive return value indicates A occured later than B
1543 public static Int32 EnvironmentTickCountCompare(Int32 tcA, Int32 tcB)
1544 {
1545 // A, B and TC are all between 0 and 0x3fffffff
1546 int tc = EnvironmentTickCount();
1547
1548 if (tc - tcA >= 0)
1549 tcA += EnvironmentTickCountMask + 1;
1550
1551 if (tc - tcB >= 0)
1552 tcB += EnvironmentTickCountMask + 1;
1553
1554 return tcA - tcB;
1555 }
1556
1540 /// <summary> 1557 /// <summary>
1541 /// Prints the call stack at any given point. Useful for debugging. 1558 /// Prints the call stack at any given point. Useful for debugging.
1542 /// </summary> 1559 /// </summary>
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 1f7e66d..14c5d6c 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -3561,6 +3561,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3561 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); 3561 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation));
3562 } 3562 }
3563 3563
3564 /// <summary>
3565 /// Requeue an EntityUpdate when it was not acknowledged by the client.
3566 /// We will update the priority and put it in the correct queue, merging update flags
3567 /// with any other updates that may be queued for the same entity.
3568 /// The original update time is used for the merged update.
3569 /// </summary>
3570 public void ResendPrimUpdate(EntityUpdate update)
3571 {
3572 // If the update exists in priority queue, it will be updated.
3573 // If it does not exist then it will be added with the current (rather than its original) priority
3574 uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity);
3575
3576 lock (m_entityUpdates.SyncRoot)
3577 m_entityUpdates.Enqueue(priority, update);
3578 }
3579
3580 /// <summary>
3581 /// Requeue a list of EntityUpdates when they were not acknowledged by the client.
3582 /// We will update the priority and put it in the correct queue, merging update flags
3583 /// with any other updates that may be queued for the same entity.
3584 /// The original update time is used for the merged update.
3585 /// </summary>
3586 void ResendPrimUpdates(List<EntityUpdate> updates)
3587 {
3588 foreach (EntityUpdate update in updates)
3589 ResendPrimUpdate(update);
3590 }
3591
3564 private void ProcessEntityUpdates(int maxUpdates) 3592 private void ProcessEntityUpdates(int maxUpdates)
3565 { 3593 {
3566 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); 3594 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
@@ -3568,6 +3596,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3568 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); 3596 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3569 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); 3597 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3570 3598
3599 OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3600 OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3601 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3602 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3603
3571 // Check to see if this is a flush 3604 // Check to see if this is a flush
3572 if (maxUpdates <= 0) 3605 if (maxUpdates <= 0)
3573 { 3606 {
@@ -3583,7 +3616,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3583 float avgTimeDilation = 1.0f; 3616 float avgTimeDilation = 1.0f;
3584 IEntityUpdate iupdate; 3617 IEntityUpdate iupdate;
3585 Int32 timeinqueue; // this is just debugging code & can be dropped later 3618 Int32 timeinqueue; // this is just debugging code & can be dropped later
3586 3619
3587 while (updatesThisCall < maxUpdates) 3620 while (updatesThisCall < maxUpdates)
3588 { 3621 {
3589 lock (m_entityUpdates.SyncRoot) 3622 lock (m_entityUpdates.SyncRoot)
@@ -3688,24 +3721,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3688 if (update.Entity is ScenePresence) 3721 if (update.Entity is ScenePresence)
3689 { 3722 {
3690 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity)); 3723 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3724 objectUpdates.Value.Add(update);
3691 } 3725 }
3692 else 3726 else
3693 { 3727 {
3694 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId)); 3728 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3729 objectUpdates.Value.Add(update);
3695 } 3730 }
3696 } 3731 }
3697 else if (!canUseImproved) 3732 else if (!canUseImproved)
3698 { 3733 {
3699 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags)); 3734 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3735 compressedUpdates.Value.Add(update);
3700 } 3736 }
3701 else 3737 else
3702 { 3738 {
3703 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 3739 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
3740 {
3704 // Self updates go into a special list 3741 // Self updates go into a special list
3705 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); 3742 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3743 terseAgentUpdates.Value.Add(update);
3744 }
3706 else 3745 else
3746 {
3707 // Everything else goes here 3747 // Everything else goes here
3708 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); 3748 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3749 terseUpdates.Value.Add(update);
3750 }
3709 } 3751 }
3710 3752
3711 #endregion Block Construction 3753 #endregion Block Construction
@@ -3713,28 +3755,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3713 3755
3714 3756
3715 #region Packet Sending 3757 #region Packet Sending
3716
3717 //const float TIME_DILATION = 1.0f;
3718
3719
3720 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); 3758 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
3721 3759
3722 if (terseAgentUpdateBlocks.IsValueCreated) 3760 if (terseAgentUpdateBlocks.IsValueCreated)
3723 { 3761 {
3724 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 3762 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3725 3763
3726 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 3764 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3727 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3765 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3728 packet.RegionData.TimeDilation = timeDilation; 3766 packet.RegionData.TimeDilation = timeDilation;
3729 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3767 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3730 3768
3731 for (int i = 0; i < blocks.Count; i++) 3769 for (int i = 0; i < blocks.Count; i++)
3732 packet.ObjectData[i] = blocks[i]; 3770 packet.ObjectData[i] = blocks[i];
3733 3771 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3734 3772 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate() { ResendPrimUpdates(terseAgentUpdates.Value); });
3735 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
3736 } 3773 }
3737 3774
3738 if (objectUpdateBlocks.IsValueCreated) 3775 if (objectUpdateBlocks.IsValueCreated)
3739 { 3776 {
3740 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; 3777 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
@@ -3746,8 +3783,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3746 3783
3747 for (int i = 0; i < blocks.Count; i++) 3784 for (int i = 0; i < blocks.Count; i++)
3748 packet.ObjectData[i] = blocks[i]; 3785 packet.ObjectData[i] = blocks[i];
3749 3786 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3750 OutPacket(packet, ThrottleOutPacketType.Task, true); 3787 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate() { ResendPrimUpdates(objectUpdates.Value); });
3751 } 3788 }
3752 3789
3753 if (compressedUpdateBlocks.IsValueCreated) 3790 if (compressedUpdateBlocks.IsValueCreated)
@@ -3761,10 +3798,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3761 3798
3762 for (int i = 0; i < blocks.Count; i++) 3799 for (int i = 0; i < blocks.Count; i++)
3763 packet.ObjectData[i] = blocks[i]; 3800 packet.ObjectData[i] = blocks[i];
3764 3801 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3765 OutPacket(packet, ThrottleOutPacketType.Task, true); 3802 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate() { ResendPrimUpdates(compressedUpdates.Value); });
3766 } 3803 }
3767 3804
3768 if (terseUpdateBlocks.IsValueCreated) 3805 if (terseUpdateBlocks.IsValueCreated)
3769 { 3806 {
3770 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; 3807 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
@@ -3776,8 +3813,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3776 3813
3777 for (int i = 0; i < blocks.Count; i++) 3814 for (int i = 0; i < blocks.Count; i++)
3778 packet.ObjectData[i] = blocks[i]; 3815 packet.ObjectData[i] = blocks[i];
3779 3816 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3780 OutPacket(packet, ThrottleOutPacketType.Task, true); 3817 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate() { ResendPrimUpdates(terseUpdates.Value); });
3781 } 3818 }
3782 } 3819 }
3783 3820
@@ -3969,7 +4006,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3969 { 4006 {
3970 SendFamilyProps = SendFamilyProps || update.SendFamilyProps; 4007 SendFamilyProps = SendFamilyProps || update.SendFamilyProps;
3971 SendObjectProps = SendObjectProps || update.SendObjectProps; 4008 SendObjectProps = SendObjectProps || update.SendObjectProps;
3972 Flags |= update.Flags; 4009 // other properties may need to be updated by base class
4010 base.Update(update);
3973 } 4011 }
3974 } 4012 }
3975 4013
@@ -11363,6 +11401,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11363 /// handles splitting manually</param> 11401 /// handles splitting manually</param>
11364 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting) 11402 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting)
11365 { 11403 {
11404 OutPacket(packet, throttlePacketType, doAutomaticSplitting, null);
11405 }
11406
11407 /// <summary>
11408 /// This is the starting point for sending a simulator packet out to the client
11409 /// </summary>
11410 /// <param name="packet">Packet to send</param>
11411 /// <param name="throttlePacketType">Throttling category for the packet</param>
11412 /// <param name="doAutomaticSplitting">True to automatically split oversized
11413 /// packets (the default), or false to disable splitting if the calling code
11414 /// handles splitting manually</param>
11415 /// <param name="method">The method to be called in the event this packet is reliable
11416 /// and unacknowledged. The server will provide normal resend capability if you do not
11417 /// provide your own method.</param>
11418 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method)
11419 {
11366 if (m_debugPacketLevel > 0) 11420 if (m_debugPacketLevel > 0)
11367 { 11421 {
11368 bool logPacket = true; 11422 bool logPacket = true;
@@ -11388,7 +11442,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11388 m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); 11442 m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type);
11389 } 11443 }
11390 11444
11391 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); 11445 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method);
11392 } 11446 }
11393 11447
11394 public bool AddMoney(int debit) 11448 public bool AddMoney(int debit)
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index d08b25f..0848979 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -297,7 +297,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
297 delegate(IClientAPI client) 297 delegate(IClientAPI client)
298 { 298 {
299 if (client is LLClientView) 299 if (client is LLClientView)
300 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category); 300 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
301 } 301 }
302 ); 302 );
303 } 303 }
@@ -309,7 +309,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
309 delegate(IClientAPI client) 309 delegate(IClientAPI client)
310 { 310 {
311 if (client is LLClientView) 311 if (client is LLClientView)
312 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category); 312 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
313 } 313 }
314 ); 314 );
315 } 315 }
@@ -322,7 +322,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
322 /// <param name="packet"></param> 322 /// <param name="packet"></param>
323 /// <param name="category"></param> 323 /// <param name="category"></param>
324 /// <param name="allowSplitting"></param> 324 /// <param name="allowSplitting"></param>
325 public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting) 325 public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method)
326 { 326 {
327 // CoarseLocationUpdate packets cannot be split in an automated way 327 // CoarseLocationUpdate packets cannot be split in an automated way
328 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) 328 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
@@ -339,13 +339,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
339 for (int i = 0; i < packetCount; i++) 339 for (int i = 0; i < packetCount; i++)
340 { 340 {
341 byte[] data = datas[i]; 341 byte[] data = datas[i];
342 SendPacketData(udpClient, data, packet.Type, category); 342 SendPacketData(udpClient, data, packet.Type, category, method);
343 } 343 }
344 } 344 }
345 else 345 else
346 { 346 {
347 byte[] data = packet.ToBytes(); 347 byte[] data = packet.ToBytes();
348 SendPacketData(udpClient, data, packet.Type, category); 348 SendPacketData(udpClient, data, packet.Type, category, method);
349 } 349 }
350 } 350 }
351 351
@@ -356,7 +356,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
356 /// <param name="data"></param> 356 /// <param name="data"></param>
357 /// <param name="type"></param> 357 /// <param name="type"></param>
358 /// <param name="category"></param> 358 /// <param name="category"></param>
359 public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category) 359 public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
360 { 360 {
361 int dataLength = data.Length; 361 int dataLength = data.Length;
362 bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; 362 bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
@@ -411,7 +411,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
411 411
412 #region Queue or Send 412 #region Queue or Send
413 413
414 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); 414 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
415 // If we were not provided a method for handling unacked, use the UDPServer default method
416 outgoingPacket.UnackedMethod = ((method == null) ? delegate() { ResendUnacked(outgoingPacket); } : method);
415 417
416 // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will 418 // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will
417 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object 419 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object
@@ -445,7 +447,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
445 packet.Header.Reliable = false; 447 packet.Header.Reliable = false;
446 packet.Packets = blocks.ToArray(); 448 packet.Packets = blocks.ToArray();
447 449
448 SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true); 450 SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true, null);
449 } 451 }
450 } 452 }
451 453
@@ -458,17 +460,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
458 // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit 460 // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit
459 pc.PingID.OldestUnacked = 0; 461 pc.PingID.OldestUnacked = 0;
460 462
461 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false); 463 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null);
462 } 464 }
463 465
464 public void CompletePing(LLUDPClient udpClient, byte pingID) 466 public void CompletePing(LLUDPClient udpClient, byte pingID)
465 { 467 {
466 CompletePingCheckPacket completePing = new CompletePingCheckPacket(); 468 CompletePingCheckPacket completePing = new CompletePingCheckPacket();
467 completePing.PingID.PingID = pingID; 469 completePing.PingID.PingID = pingID;
468 SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false); 470 SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false, null);
469 } 471 }
470 472
471 public void ResendUnacked(LLUDPClient udpClient) 473 public void HandleUnacked(LLUDPClient udpClient)
472 { 474 {
473 if (!udpClient.IsConnected) 475 if (!udpClient.IsConnected)
474 return; 476 return;
@@ -488,31 +490,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
488 490
489 if (expiredPackets != null) 491 if (expiredPackets != null)
490 { 492 {
491 //m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO); 493 //m_log.Debug("[LLUDPSERVER]: Handling " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO);
492
493 // Exponential backoff of the retransmission timeout 494 // Exponential backoff of the retransmission timeout
494 udpClient.BackoffRTO(); 495 udpClient.BackoffRTO();
496 for (int i = 0; i < expiredPackets.Count; ++i)
497 expiredPackets[i].UnackedMethod();
498 }
499 }
495 500
496 // Resend packets 501 public void ResendUnacked(OutgoingPacket outgoingPacket)
497 for (int i = 0; i < expiredPackets.Count; i++) 502 {
498 { 503 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
499 OutgoingPacket outgoingPacket = expiredPackets[i]; 504 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
500
501 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
502 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
503 505
504 // Set the resent flag 506 // Set the resent flag
505 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); 507 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
506 outgoingPacket.Category = ThrottleOutPacketType.Resend; 508 outgoingPacket.Category = ThrottleOutPacketType.Resend;
507 509
508 // Bump up the resend count on this packet 510 // Bump up the resend count on this packet
509 Interlocked.Increment(ref outgoingPacket.ResendCount); 511 Interlocked.Increment(ref outgoingPacket.ResendCount);
510 512
511 // Requeue or resend the packet 513 // Requeue or resend the packet
512 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false)) 514 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false))
513 SendPacketFinal(outgoingPacket); 515 SendPacketFinal(outgoingPacket);
514 }
515 }
516 } 516 }
517 517
518 public void Flush(LLUDPClient udpClient) 518 public void Flush(LLUDPClient udpClient)
@@ -1096,7 +1096,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1096 if (udpClient.IsConnected) 1096 if (udpClient.IsConnected)
1097 { 1097 {
1098 if (m_resendUnacked) 1098 if (m_resendUnacked)
1099 ResendUnacked(udpClient); 1099 HandleUnacked(udpClient);
1100 1100
1101 if (m_sendAcks) 1101 if (m_sendAcks)
1102 SendAcks(udpClient); 1102 SendAcks(udpClient);
@@ -1152,7 +1152,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1152 nticksUnack++; 1152 nticksUnack++;
1153 watch2.Start(); 1153 watch2.Start();
1154 1154
1155 ResendUnacked(udpClient); 1155 HandleUnacked(udpClient);
1156 1156
1157 watch2.Stop(); 1157 watch2.Stop();
1158 avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack); 1158 avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack);
diff --git a/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs b/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs
index 1a1a1cb..f4f024b 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs
@@ -31,6 +31,7 @@ using OpenMetaverse;
31 31
32namespace OpenSim.Region.ClientStack.LindenUDP 32namespace OpenSim.Region.ClientStack.LindenUDP
33{ 33{
34 public delegate void UnackedPacketMethod();
34 /// <summary> 35 /// <summary>
35 /// Holds a reference to the <seealso cref="LLUDPClient"/> this packet is 36 /// Holds a reference to the <seealso cref="LLUDPClient"/> this packet is
36 /// destined for, along with the serialized packet data, sequence number 37 /// destined for, along with the serialized packet data, sequence number
@@ -52,6 +53,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
52 public int TickCount; 53 public int TickCount;
53 /// <summary>Category this packet belongs to</summary> 54 /// <summary>Category this packet belongs to</summary>
54 public ThrottleOutPacketType Category; 55 public ThrottleOutPacketType Category;
56 /// <summary>The delegate to be called if this packet is determined to be unacknowledged</summary>
57 public UnackedPacketMethod UnackedMethod;
55 58
56 /// <summary> 59 /// <summary>
57 /// Default constructor 60 /// Default constructor
@@ -60,11 +63,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
60 /// <param name="buffer">Serialized packet data. If the flags or sequence number 63 /// <param name="buffer">Serialized packet data. If the flags or sequence number
61 /// need to be updated, they will be injected directly into this binary buffer</param> 64 /// need to be updated, they will be injected directly into this binary buffer</param>
62 /// <param name="category">Throttling category for this packet</param> 65 /// <param name="category">Throttling category for this packet</param>
63 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category) 66 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category, UnackedPacketMethod method)
64 { 67 {
65 Client = client; 68 Client = client;
66 Buffer = buffer; 69 Buffer = buffer;
67 Category = category; 70 Category = category;
71 UnackedMethod = method;
68 } 72 }
69 } 73 }
70} 74}