aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Framework/PriorityQueue.cs (renamed from OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs)43
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs3
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs798
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs19
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs68
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs4
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs7
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs92
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs8
9 files changed, 667 insertions, 375 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs b/OpenSim/Framework/PriorityQueue.cs
index b62ec07..eec2a92 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs
+++ b/OpenSim/Framework/PriorityQueue.cs
@@ -34,20 +34,21 @@ using OpenSim.Framework;
34using OpenSim.Framework.Client; 34using OpenSim.Framework.Client;
35using log4net; 35using log4net;
36 36
37namespace OpenSim.Region.ClientStack.LindenUDP 37namespace OpenSim.Framework
38{ 38{
39 public class PriorityQueue 39 public class PriorityQueue
40 { 40 {
41 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 41 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42 42
43 internal delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity); 43 public delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity);
44 44
45 // Heap[0] for self updates 45 // Heap[0] for self updates
46 // Heap[1..12] for entity updates 46 // Heap[1..12] for entity updates
47 47
48 internal const uint m_numberOfQueues = 12; 48 public const uint NumberOfQueues = 12;
49 public const uint ImmediateQueue = 0;
49 50
50 private MinHeap<MinHeapItem>[] m_heaps = new MinHeap<MinHeapItem>[m_numberOfQueues]; 51 private MinHeap<MinHeapItem>[] m_heaps = new MinHeap<MinHeapItem>[NumberOfQueues];
51 private Dictionary<uint, LookupItem> m_lookupTable; 52 private Dictionary<uint, LookupItem> m_lookupTable;
52 private uint m_nextQueue = 0; 53 private uint m_nextQueue = 0;
53 private UInt64 m_nextRequest = 0; 54 private UInt64 m_nextRequest = 0;
@@ -57,9 +58,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
57 get { return this.m_syncRoot; } 58 get { return this.m_syncRoot; }
58 } 59 }
59 60
60 internal PriorityQueue() : this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY) { } 61 public PriorityQueue() : this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY) { }
61 62
62 internal PriorityQueue(int capacity) 63 public PriorityQueue(int capacity)
63 { 64 {
64 m_lookupTable = new Dictionary<uint, LookupItem>(capacity); 65 m_lookupTable = new Dictionary<uint, LookupItem>(capacity);
65 66
@@ -67,7 +68,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
67 m_heaps[i] = new MinHeap<MinHeapItem>(capacity); 68 m_heaps[i] = new MinHeap<MinHeapItem>(capacity);
68 } 69 }
69 70
70 internal int Count 71 public int Count
71 { 72 {
72 get 73 get
73 { 74 {
@@ -91,7 +92,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
91 lookup.Heap.Remove(lookup.Handle); 92 lookup.Heap.Remove(lookup.Handle);
92 } 93 }
93 94
94 pqueue = Util.Clamp<uint>(pqueue, 0, m_numberOfQueues - 1); 95 pqueue = Util.Clamp<uint>(pqueue, 0, NumberOfQueues - 1);
95 lookup.Heap = m_heaps[pqueue]; 96 lookup.Heap = m_heaps[pqueue];
96 lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle); 97 lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle);
97 m_lookupTable[localid] = lookup; 98 m_lookupTable[localid] = lookup;
@@ -99,18 +100,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
99 return true; 100 return true;
100 } 101 }
101 102
102 internal bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue) 103 public bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue)
103 { 104 {
104 for (int i = 0; i < m_numberOfQueues; ++i) 105 // If there is anything in priority queue 0, return it first no
106 // matter what else. Breaks fairness. But very useful.
107 if (m_heaps[ImmediateQueue].Count > 0)
108 {
109 MinHeapItem item = m_heaps[ImmediateQueue].RemoveMin();
110 m_lookupTable.Remove(item.Value.Entity.LocalId);
111 timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
112 value = item.Value;
113
114 return true;
115 }
116
117 for (int i = 0; i < NumberOfQueues; ++i)
105 { 118 {
106 // To get the fair queing, we cycle through each of the 119 // To get the fair queing, we cycle through each of the
107 // queues when finding an element to dequeue, this code 120 // queues when finding an element to dequeue, this code
108 // assumes that the distribution of updates in the queues 121 // assumes that the distribution of updates in the queues
109 // is polynomial, probably quadractic (eg distance of PI * R^2) 122 // is polynomial, probably quadractic (eg distance of PI * R^2)
110 uint h = (uint)((m_nextQueue + i) % m_numberOfQueues); 123 uint h = (uint)((m_nextQueue + i) % NumberOfQueues);
111 if (m_heaps[h].Count > 0) 124 if (m_heaps[h].Count > 0)
112 { 125 {
113 m_nextQueue = (uint)((h + 1) % m_numberOfQueues); 126 m_nextQueue = (uint)((h + 1) % NumberOfQueues);
114 127
115 MinHeapItem item = m_heaps[h].RemoveMin(); 128 MinHeapItem item = m_heaps[h].RemoveMin();
116 m_lookupTable.Remove(item.Value.Entity.LocalId); 129 m_lookupTable.Remove(item.Value.Entity.LocalId);
@@ -126,7 +139,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
126 return false; 139 return false;
127 } 140 }
128 141
129 internal void Reprioritize(UpdatePriorityHandler handler) 142 public void Reprioritize(UpdatePriorityHandler handler)
130 { 143 {
131 MinHeapItem item; 144 MinHeapItem item;
132 foreach (LookupItem lookup in new List<LookupItem>(this.m_lookupTable.Values)) 145 foreach (LookupItem lookup in new List<LookupItem>(this.m_lookupTable.Values))
@@ -140,7 +153,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
140 { 153 {
141 // unless the priority queue has changed, there is no need to modify 154 // unless the priority queue has changed, there is no need to modify
142 // the entry 155 // the entry
143 pqueue = Util.Clamp<uint>(pqueue, 0, m_numberOfQueues - 1); 156 pqueue = Util.Clamp<uint>(pqueue, 0, NumberOfQueues - 1);
144 if (pqueue != item.PriorityQueue) 157 if (pqueue != item.PriorityQueue)
145 { 158 {
146 lookup.Heap.Remove(lookup.Handle); 159 lookup.Heap.Remove(lookup.Handle);
@@ -164,7 +177,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
164 public override string ToString() 177 public override string ToString()
165 { 178 {
166 string s = ""; 179 string s = "";
167 for (int i = 0; i < m_numberOfQueues; i++) 180 for (int i = 0; i < NumberOfQueues; i++)
168 { 181 {
169 if (s != "") s += ","; 182 if (s != "") s += ",";
170 s += m_heaps[i].Count.ToString(); 183 s += m_heaps[i].Count.ToString();
diff --git a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
index e9e2dca..9dd6663 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
@@ -202,6 +202,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
202 m_stopPacket = TexturePacketCount(); 202 m_stopPacket = TexturePacketCount();
203 } 203 }
204 204
205 //Give them at least two packets, to play nice with some broken viewers (SL also behaves this way)
206 if (m_stopPacket == 1 && Layers[0].End > FIRST_PACKET_SIZE) m_stopPacket++;
207
205 m_currentPacket = StartPacket; 208 m_currentPacket = StartPacket;
206 } 209 }
207 } 210 }
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 1f7e66d..cd438d6 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -157,6 +157,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
157 public event RequestTaskInventory OnRequestTaskInventory; 157 public event RequestTaskInventory OnRequestTaskInventory;
158 public event UpdateInventoryItem OnUpdateInventoryItem; 158 public event UpdateInventoryItem OnUpdateInventoryItem;
159 public event CopyInventoryItem OnCopyInventoryItem; 159 public event CopyInventoryItem OnCopyInventoryItem;
160 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
160 public event MoveInventoryItem OnMoveInventoryItem; 161 public event MoveInventoryItem OnMoveInventoryItem;
161 public event RemoveInventoryItem OnRemoveInventoryItem; 162 public event RemoveInventoryItem OnRemoveInventoryItem;
162 public event RemoveInventoryFolder OnRemoveInventoryFolder; 163 public event RemoveInventoryFolder OnRemoveInventoryFolder;
@@ -254,7 +255,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
254 public event ClassifiedInfoRequest OnClassifiedInfoRequest; 255 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
255 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; 256 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
256 public event ClassifiedDelete OnClassifiedDelete; 257 public event ClassifiedDelete OnClassifiedDelete;
257 public event ClassifiedDelete OnClassifiedGodDelete; 258 public event ClassifiedGodDelete OnClassifiedGodDelete;
258 public event EventNotificationAddRequest OnEventNotificationAddRequest; 259 public event EventNotificationAddRequest OnEventNotificationAddRequest;
259 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; 260 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
260 public event EventGodDelete OnEventGodDelete; 261 public event EventGodDelete OnEventGodDelete;
@@ -330,7 +331,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
330 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an 331 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
331 /// ownerless phantom. 332 /// ownerless phantom.
332 /// 333 ///
333 /// All manipulation of this set has to occur under a lock 334 /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock
334 /// 335 ///
335 /// </value> 336 /// </value>
336 protected HashSet<uint> m_killRecord; 337 protected HashSet<uint> m_killRecord;
@@ -338,6 +339,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
338// protected HashSet<uint> m_attachmentsSent; 339// protected HashSet<uint> m_attachmentsSent;
339 340
340 private int m_moneyBalance; 341 private int m_moneyBalance;
342 private bool m_deliverPackets = true;
341 private int m_animationSequenceNumber = 1; 343 private int m_animationSequenceNumber = 1;
342 private bool m_SendLogoutPacketWhenClosing = true; 344 private bool m_SendLogoutPacketWhenClosing = true;
343 private AgentUpdateArgs lastarg; 345 private AgentUpdateArgs lastarg;
@@ -378,6 +380,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
378 get { return m_startpos; } 380 get { return m_startpos; }
379 set { m_startpos = value; } 381 set { m_startpos = value; }
380 } 382 }
383 public bool DeliverPackets
384 {
385 get { return m_deliverPackets; }
386 set {
387 m_deliverPackets = value;
388 m_udpClient.m_deliverPackets = value;
389 }
390 }
381 public UUID AgentId { get { return m_agentId; } } 391 public UUID AgentId { get { return m_agentId; } }
382 public UUID ActiveGroupId { get { return m_activeGroupID; } } 392 public UUID ActiveGroupId { get { return m_activeGroupID; } }
383 public string ActiveGroupName { get { return m_activeGroupName; } } 393 public string ActiveGroupName { get { return m_activeGroupName; } }
@@ -474,18 +484,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
474 484
475 #region Client Methods 485 #region Client Methods
476 486
487
477 /// <summary> 488 /// <summary>
478 /// Shut down the client view 489 /// Shut down the client view
479 /// </summary> 490 /// </summary>
480 public void Close() 491 public void Close()
481 { 492 {
493 Close(true);
494 }
495
496 /// <summary>
497 /// Shut down the client view
498 /// </summary>
499 public void Close(bool sendStop)
500 {
482 m_log.DebugFormat( 501 m_log.DebugFormat(
483 "[CLIENT]: Close has been called for {0} attached to scene {1}", 502 "[CLIENT]: Close has been called for {0} attached to scene {1}",
484 Name, m_scene.RegionInfo.RegionName); 503 Name, m_scene.RegionInfo.RegionName);
485 504
486 // Send the STOP packet 505 if (sendStop)
487 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); 506 {
488 OutPacket(disable, ThrottleOutPacketType.Unknown); 507 // Send the STOP packet
508 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
509 OutPacket(disable, ThrottleOutPacketType.Unknown);
510 }
489 511
490 IsActive = false; 512 IsActive = false;
491 513
@@ -766,7 +788,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
766 reply.ChatData.OwnerID = fromAgentID; 788 reply.ChatData.OwnerID = fromAgentID;
767 reply.ChatData.SourceID = fromAgentID; 789 reply.ChatData.SourceID = fromAgentID;
768 790
769 OutPacket(reply, ThrottleOutPacketType.Task); 791 OutPacket(reply, ThrottleOutPacketType.Unknown);
770 } 792 }
771 793
772 /// <summary> 794 /// <summary>
@@ -1052,6 +1074,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1052 public virtual void SendLayerData(float[] map) 1074 public virtual void SendLayerData(float[] map)
1053 { 1075 {
1054 Util.FireAndForget(DoSendLayerData, map); 1076 Util.FireAndForget(DoSendLayerData, map);
1077
1078 // Send it sync, and async. It's not that much data
1079 // and it improves user experience just so much!
1080 DoSendLayerData(map);
1055 } 1081 }
1056 1082
1057 /// <summary> 1083 /// <summary>
@@ -1064,16 +1090,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1064 1090
1065 try 1091 try
1066 { 1092 {
1067 //for (int y = 0; y < 16; y++) 1093 for (int y = 0; y < 16; y++)
1068 //{ 1094 {
1069 // for (int x = 0; x < 16; x++) 1095 for (int x = 0; x < 16; x+=4)
1070 // { 1096 {
1071 // SendLayerData(x, y, map); 1097 SendLayerPacket(x, y, map);
1072 // } 1098 }
1073 //} 1099 }
1074
1075 // Send LayerData in a spiral pattern. Fun!
1076 SendLayerTopRight(map, 0, 0, 15, 15);
1077 } 1100 }
1078 catch (Exception e) 1101 catch (Exception e)
1079 { 1102 {
@@ -1081,51 +1104,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1081 } 1104 }
1082 } 1105 }
1083 1106
1084 private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2)
1085 {
1086 // Row
1087 for (int i = x1; i <= x2; i++)
1088 SendLayerData(i, y1, map);
1089
1090 // Column
1091 for (int j = y1 + 1; j <= y2; j++)
1092 SendLayerData(x2, j, map);
1093
1094 if (x2 - x1 > 0)
1095 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1096 }
1097
1098 void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2)
1099 {
1100 // Row in reverse
1101 for (int i = x2; i >= x1; i--)
1102 SendLayerData(i, y2, map);
1103
1104 // Column in reverse
1105 for (int j = y2 - 1; j >= y1; j--)
1106 SendLayerData(x1, j, map);
1107
1108 if (x2 - x1 > 0)
1109 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1110 }
1111
1112 /// <summary> 1107 /// <summary>
1113 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1108 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1114 /// </summary> 1109 /// </summary>
1115 /// <param name="map">heightmap</param> 1110 /// <param name="map">heightmap</param>
1116 /// <param name="px">X coordinate for patches 0..12</param> 1111 /// <param name="px">X coordinate for patches 0..12</param>
1117 /// <param name="py">Y coordinate for patches 0..15</param> 1112 /// <param name="py">Y coordinate for patches 0..15</param>
1118 // private void SendLayerPacket(float[] map, int y, int x) 1113 private void SendLayerPacket(int x, int y, float[] map)
1119 // { 1114 {
1120 // int[] patches = new int[4]; 1115 int[] patches = new int[4];
1121 // patches[0] = x + 0 + y * 16; 1116 patches[0] = x + 0 + y * 16;
1122 // patches[1] = x + 1 + y * 16; 1117 patches[1] = x + 1 + y * 16;
1123 // patches[2] = x + 2 + y * 16; 1118 patches[2] = x + 2 + y * 16;
1124 // patches[3] = x + 3 + y * 16; 1119 patches[3] = x + 3 + y * 16;
1125 1120
1126 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); 1121 float[] heightmap = (map.Length == 65536) ?
1127 // OutPacket(layerpack, ThrottleOutPacketType.Land); 1122 map :
1128 // } 1123 LLHeightFieldMoronize(map);
1124
1125 try
1126 {
1127 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1128 OutPacket(layerpack, ThrottleOutPacketType.Land);
1129 }
1130 catch
1131 {
1132 for (int px = x ; px < x + 4 ; px++)
1133 SendLayerData(px, y, map);
1134 }
1135 }
1129 1136
1130 /// <summary> 1137 /// <summary>
1131 /// Sends a specified patch to a client 1138 /// Sends a specified patch to a client
@@ -1145,7 +1152,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1145 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1152 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1146 layerpack.Header.Reliable = true; 1153 layerpack.Header.Reliable = true;
1147 1154
1148 OutPacket(layerpack, ThrottleOutPacketType.Land); 1155 OutPacket(layerpack, ThrottleOutPacketType.Task);
1149 } 1156 }
1150 catch (Exception e) 1157 catch (Exception e)
1151 { 1158 {
@@ -1506,38 +1513,49 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1506 OutPacket(pc, ThrottleOutPacketType.Unknown); 1513 OutPacket(pc, ThrottleOutPacketType.Unknown);
1507 } 1514 }
1508 1515
1509 public void SendKillObject(ulong regionHandle, uint localID) 1516 public void SendKillObject(ulong regionHandle, List<uint> localIDs)
1510 { 1517 {
1511// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1518// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle);
1512 1519
1513 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1520 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1514 // TODO: don't create new blocks if recycling an old packet 1521 // TODO: don't create new blocks if recycling an old packet
1515 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1]; 1522 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count];
1516 kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock(); 1523 for (int i = 0 ; i < localIDs.Count ; i++ )
1517 kill.ObjectData[0].ID = localID; 1524 {
1525 kill.ObjectData[i] = new KillObjectPacket.ObjectDataBlock();
1526 kill.ObjectData[i].ID = localIDs[i];
1527 }
1518 kill.Header.Reliable = true; 1528 kill.Header.Reliable = true;
1519 kill.Header.Zerocoded = true; 1529 kill.Header.Zerocoded = true;
1520 1530
1521 if (m_scene.GetScenePresence(localID) == null) 1531 lock (m_killRecord)
1522 { 1532 {
1523 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 1533 if (localIDs.Count == 1)
1524 // condition where a kill can be processed before an out-of-date update for the same object.
1525 lock (m_killRecord)
1526 { 1534 {
1527 m_killRecord.Add(localID); 1535 if (m_scene.GetScenePresence(localIDs[0]) != null)
1528 1536 {
1529 // The throttle queue used here must match that being used for updates. Otherwise, there is a 1537 OutPacket(kill, ThrottleOutPacketType.State);
1530 // chance that a kill packet put on a separate queue will be sent to the client before an existing 1538 return;
1531 // update packet on another queue. Receiving updates after kills results in unowned and undeletable 1539 }
1532 // scene objects in a viewer until that viewer is relogged in. 1540 m_killRecord.Add(localIDs[0]);
1533 OutPacket(kill, ThrottleOutPacketType.Task); 1541 }
1542 else
1543 {
1544 lock (m_entityUpdates.SyncRoot)
1545 {
1546 foreach (uint localID in localIDs)
1547 m_killRecord.Add(localID);
1548 }
1534 } 1549 }
1535 } 1550 }
1536 else 1551
1537 { 1552 // The throttle queue used here must match that being used for
1538 // OutPacket(kill, ThrottleOutPacketType.State); 1553 // updates. Otherwise, there is a chance that a kill packet put
1539 OutPacket(kill, ThrottleOutPacketType.Task); 1554 // on a separate queue will be sent to the client before an
1540 } 1555 // existing update packet on another queue. Receiving updates
1556 // after kills results in unowned and undeletable
1557 // scene objects in a viewer until that viewer is relogged in.
1558 OutPacket(kill, ThrottleOutPacketType.Task);
1541 } 1559 }
1542 1560
1543 /// <summary> 1561 /// <summary>
@@ -2250,6 +2268,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2250 OutPacket(sound, ThrottleOutPacketType.Task); 2268 OutPacket(sound, ThrottleOutPacketType.Task);
2251 } 2269 }
2252 2270
2271 public void SendTransferAbort(TransferRequestPacket transferRequest)
2272 {
2273 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2274 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2275 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2276 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2277 OutPacket(abort, ThrottleOutPacketType.Task);
2278 }
2279
2253 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2280 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2254 { 2281 {
2255 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2282 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -3554,13 +3581,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3554 /// </summary> 3581 /// </summary>
3555 public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3582 public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3556 { 3583 {
3557 //double priority = m_prioritizer.GetUpdatePriority(this, entity); 3584 if (entity is SceneObjectPart)
3585 {
3586 SceneObjectPart e = (SceneObjectPart)entity;
3587 SceneObjectGroup g = e.ParentGroup;
3588 if (g.RootPart.Shape.State > 30) // HUD
3589 if (g.OwnerID != AgentId)
3590 return; // Don't send updates for other people's HUDs
3591 }
3592
3558 uint priority = m_prioritizer.GetUpdatePriority(this, entity); 3593 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
3559 3594
3560 lock (m_entityUpdates.SyncRoot) 3595 lock (m_entityUpdates.SyncRoot)
3561 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); 3596 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation));
3562 } 3597 }
3563 3598
3599 /// <summary>
3600 /// Requeue an EntityUpdate when it was not acknowledged by the client.
3601 /// We will update the priority and put it in the correct queue, merging update flags
3602 /// with any other updates that may be queued for the same entity.
3603 /// The original update time is used for the merged update.
3604 /// </summary>
3605 private void ResendPrimUpdate(EntityUpdate update)
3606 {
3607 // If the update exists in priority queue, it will be updated.
3608 // If it does not exist then it will be added with the current (rather than its original) priority
3609 uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity);
3610
3611 lock (m_entityUpdates.SyncRoot)
3612 m_entityUpdates.Enqueue(priority, update);
3613 }
3614
3615 /// <summary>
3616 /// Requeue a list of EntityUpdates when they were not acknowledged by the client.
3617 /// We will update the priority and put it in the correct queue, merging update flags
3618 /// with any other updates that may be queued for the same entity.
3619 /// The original update time is used for the merged update.
3620 /// </summary>
3621 private void ResendPrimUpdates(List<EntityUpdate> updates, OutgoingPacket oPacket)
3622 {
3623 // m_log.WarnFormat("[CLIENT] resending prim update {0}",updates[0].UpdateTime);
3624
3625 // Remove the update packet from the list of packets waiting for acknowledgement
3626 // because we are requeuing the list of updates. They will be resent in new packets
3627 // with the most recent state and priority.
3628 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber, 0, true);
3629 foreach (EntityUpdate update in updates)
3630 ResendPrimUpdate(update);
3631 }
3632
3564 private void ProcessEntityUpdates(int maxUpdates) 3633 private void ProcessEntityUpdates(int maxUpdates)
3565 { 3634 {
3566 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); 3635 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
@@ -3568,6 +3637,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3568 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); 3637 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>>(); 3638 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3570 3639
3640 OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3641 OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3642 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3643 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3644
3571 // Check to see if this is a flush 3645 // Check to see if this is a flush
3572 if (maxUpdates <= 0) 3646 if (maxUpdates <= 0)
3573 { 3647 {
@@ -3578,207 +3652,230 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3578 3652
3579 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 3653 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
3580 // condition where a kill can be processed before an out-of-date update for the same object. 3654 // condition where a kill can be processed before an out-of-date update for the same object.
3581 lock (m_killRecord) 3655 float avgTimeDilation = 1.0f;
3582 { 3656 IEntityUpdate iupdate;
3583 float avgTimeDilation = 1.0f; 3657 Int32 timeinqueue; // this is just debugging code & can be dropped later
3584 IEntityUpdate iupdate;
3585 Int32 timeinqueue; // this is just debugging code & can be dropped later
3586 3658
3587 while (updatesThisCall < maxUpdates) 3659 while (updatesThisCall < maxUpdates)
3588 { 3660 {
3589 lock (m_entityUpdates.SyncRoot) 3661 lock (m_entityUpdates.SyncRoot)
3590 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue)) 3662 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3591 break; 3663 break;
3592 3664
3593 EntityUpdate update = (EntityUpdate)iupdate; 3665 EntityUpdate update = (EntityUpdate)iupdate;
3594 3666
3595 avgTimeDilation += update.TimeDilation; 3667 avgTimeDilation += update.TimeDilation;
3596 avgTimeDilation *= 0.5f; 3668 avgTimeDilation *= 0.5f;
3597 3669
3598 if (update.Entity is SceneObjectPart) 3670 if (update.Entity is SceneObjectPart)
3671 {
3672 SceneObjectPart part = (SceneObjectPart)update.Entity;
3673
3674 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3675 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3676 // safety measure.
3677 //
3678 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
3679 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
3680 // updates and kills on different threads with different scheduling strategies, hence this protection.
3681 //
3682 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3683 // after the root prim has been deleted.
3684 lock (m_killRecord)
3599 { 3685 {
3600 SceneObjectPart part = (SceneObjectPart)update.Entity;
3601
3602 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3603 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3604 // safety measure.
3605 //
3606 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
3607 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
3608 // updates and kills on different threads with different scheduling strategies, hence this protection.
3609 //
3610 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3611 // after the root prim has been deleted.
3612 if (m_killRecord.Contains(part.LocalId)) 3686 if (m_killRecord.Contains(part.LocalId))
3613 {
3614 // m_log.WarnFormat(
3615 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted",
3616 // part.LocalId, Name);
3617 continue; 3687 continue;
3618 } 3688 if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3619 3689 continue;
3620 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3690 }
3691
3692 if (part.ParentGroup.IsDeleted)
3693 continue;
3694
3695 if (part.ParentGroup.IsAttachment)
3696 { // Someone else's HUD, why are we getting these?
3697 if (part.ParentGroup.OwnerID != AgentId &&
3698 part.ParentGroup.RootPart.Shape.State >= 30)
3699 continue;
3700 ScenePresence sp;
3701 // Owner is not in the sim, don't update it to
3702 // anyone
3703 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3704 continue;
3705
3706 List<SceneObjectGroup> atts = sp.Attachments;
3707 bool found = false;
3708 foreach (SceneObjectGroup att in atts)
3621 { 3709 {
3622 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 3710 if (att == part.ParentGroup)
3623 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3624 { 3711 {
3625 part.Shape.LightEntry = false; 3712 found = true;
3713 break;
3626 } 3714 }
3627 } 3715 }
3716
3717 // It's an attachment of a valid avatar, but
3718 // doesn't seem to be attached, skip
3719 if (!found)
3720 continue;
3628 } 3721 }
3629 3722 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3630 ++updatesThisCall;
3631
3632 #region UpdateFlags to packet type conversion
3633
3634 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3635
3636 bool canUseCompressed = true;
3637 bool canUseImproved = true;
3638
3639 // Compressed object updates only make sense for LL primitives
3640 if (!(update.Entity is SceneObjectPart))
3641 {
3642 canUseCompressed = false;
3643 }
3644
3645 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3646 {
3647 canUseCompressed = false;
3648 canUseImproved = false;
3649 }
3650 else
3651 { 3723 {
3652 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || 3724 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3653 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) || 3725 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3654 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3655 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3656 { 3726 {
3657 canUseCompressed = false; 3727 part.Shape.LightEntry = false;
3658 }
3659
3660 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3661 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3662 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3663 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3664 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3665 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3666 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3667 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3668 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3669 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3670 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3671 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3672 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3673 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3674 {
3675 canUseImproved = false;
3676 } 3728 }
3677 } 3729 }
3678 3730 }
3679 #endregion UpdateFlags to packet type conversion 3731
3680 3732 ++updatesThisCall;
3681 #region Block Construction 3733
3682 3734 #region UpdateFlags to packet type conversion
3683 // TODO: Remove this once we can build compressed updates 3735
3736 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3737
3738 bool canUseCompressed = true;
3739 bool canUseImproved = true;
3740
3741 // Compressed object updates only make sense for LL primitives
3742 if (!(update.Entity is SceneObjectPart))
3743 {
3684 canUseCompressed = false; 3744 canUseCompressed = false;
3685 3745 }
3686 if (!canUseImproved && !canUseCompressed) 3746
3747 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3748 {
3749 canUseCompressed = false;
3750 canUseImproved = false;
3751 }
3752 else
3753 {
3754 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3755 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3756 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3757 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3687 { 3758 {
3688 if (update.Entity is ScenePresence) 3759 canUseCompressed = false;
3689 {
3690 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3691 }
3692 else
3693 {
3694 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3695 }
3696 } 3760 }
3697 else if (!canUseImproved) 3761
3762 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3763 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3764 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3765 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3766 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3767 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3768 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3769 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3770 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3771 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3772 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3773 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3774 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3775 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3776 {
3777 canUseImproved = false;
3778 }
3779 }
3780
3781 #endregion UpdateFlags to packet type conversion
3782
3783 #region Block Construction
3784
3785 // TODO: Remove this once we can build compressed updates
3786 canUseCompressed = false;
3787
3788 if (!canUseImproved && !canUseCompressed)
3789 {
3790 if (update.Entity is ScenePresence)
3698 { 3791 {
3699 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags)); 3792 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3700 } 3793 }
3701 else 3794 else
3702 { 3795 {
3703 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 3796 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3704 // Self updates go into a special list
3705 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3706 else
3707 // Everything else goes here
3708 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3709 } 3797 }
3710
3711 #endregion Block Construction
3712 } 3798 }
3713 3799 else if (!canUseImproved)
3800 {
3801 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3802 }
3803 else
3804 {
3805 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
3806 // Self updates go into a special list
3807 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3808 else
3809 // Everything else goes here
3810 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3811 }
3812
3813 #endregion Block Construction
3814 }
3815
3816 #region Packet Sending
3714 3817
3715 #region Packet Sending 3818 const float TIME_DILATION = 1.0f;
3716 3819 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
3717 //const float TIME_DILATION = 1.0f; 3820
3821 if (terseAgentUpdateBlocks.IsValueCreated)
3822 {
3823 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3824
3825 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3826 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3827 packet.RegionData.TimeDilation = timeDilation;
3828 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3718 3829
3830 for (int i = 0; i < blocks.Count; i++)
3831 packet.ObjectData[i] = blocks[i];
3832
3833 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
3834 }
3719 3835
3720 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); 3836 if (objectUpdateBlocks.IsValueCreated)
3837 {
3838 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
3721 3839
3722 if (terseAgentUpdateBlocks.IsValueCreated) 3840 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3723 { 3841 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3724 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 3842 packet.RegionData.TimeDilation = timeDilation;
3843 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3725 3844
3726 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 3845 for (int i = 0; i < blocks.Count; i++)
3727 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3846 packet.ObjectData[i] = blocks[i];
3728 packet.RegionData.TimeDilation = timeDilation; 3847
3729 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3848 OutPacket(packet, ThrottleOutPacketType.Task, true);
3849 }
3730 3850
3731 for (int i = 0; i < blocks.Count; i++) 3851 if (compressedUpdateBlocks.IsValueCreated)
3732 packet.ObjectData[i] = blocks[i]; 3852 {
3853 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
3854
3855 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3856 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3857 packet.RegionData.TimeDilation = timeDilation;
3858 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3733 3859
3734 3860 for (int i = 0; i < blocks.Count; i++)
3735 OutPacket(packet, ThrottleOutPacketType.Unknown, true); 3861 packet.ObjectData[i] = blocks[i];
3736 }
3737 3862
3738 if (objectUpdateBlocks.IsValueCreated) 3863 OutPacket(packet, ThrottleOutPacketType.Task, true);
3739 { 3864 }
3740 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; 3865
3741 3866 if (terseUpdateBlocks.IsValueCreated)
3742 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); 3867 {
3743 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3868 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3744 packet.RegionData.TimeDilation = timeDilation; 3869
3745 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3870 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3746 3871 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3747 for (int i = 0; i < blocks.Count; i++) 3872 packet.RegionData.TimeDilation = timeDilation;
3748 packet.ObjectData[i] = blocks[i]; 3873 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3749 3874
3750 OutPacket(packet, ThrottleOutPacketType.Task, true); 3875 for (int i = 0; i < blocks.Count; i++)
3751 } 3876 packet.ObjectData[i] = blocks[i];
3752 3877
3753 if (compressedUpdateBlocks.IsValueCreated) 3878 OutPacket(packet, ThrottleOutPacketType.Task, true);
3754 {
3755 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
3756
3757 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3758 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3759 packet.RegionData.TimeDilation = timeDilation;
3760 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3761
3762 for (int i = 0; i < blocks.Count; i++)
3763 packet.ObjectData[i] = blocks[i];
3764
3765 OutPacket(packet, ThrottleOutPacketType.Task, true);
3766 }
3767
3768 if (terseUpdateBlocks.IsValueCreated)
3769 {
3770 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3771
3772 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3773 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3774 packet.RegionData.TimeDilation = timeDilation;
3775 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3776
3777 for (int i = 0; i < blocks.Count; i++)
3778 packet.ObjectData[i] = blocks[i];
3779
3780 OutPacket(packet, ThrottleOutPacketType.Task, true);
3781 }
3782 } 3879 }
3783 3880
3784 #endregion Packet Sending 3881 #endregion Packet Sending
@@ -3969,7 +4066,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3969 { 4066 {
3970 SendFamilyProps = SendFamilyProps || update.SendFamilyProps; 4067 SendFamilyProps = SendFamilyProps || update.SendFamilyProps;
3971 SendObjectProps = SendObjectProps || update.SendObjectProps; 4068 SendObjectProps = SendObjectProps || update.SendObjectProps;
3972 Flags |= update.Flags; 4069 // other properties may need to be updated by base class
4070 base.Update(update);
3973 } 4071 }
3974 } 4072 }
3975 4073
@@ -3980,6 +4078,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3980 m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false)); 4078 m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false));
3981 } 4079 }
3982 4080
4081 private void ResendPropertyUpdate(ObjectPropertyUpdate update)
4082 {
4083 uint priority = 0;
4084 lock (m_entityProps.SyncRoot)
4085 m_entityProps.Enqueue(priority, update);
4086 }
4087
4088 private void ResendPropertyUpdates(List<ObjectPropertyUpdate> updates, OutgoingPacket oPacket)
4089 {
4090 // m_log.WarnFormat("[CLIENT] resending object property {0}",updates[0].UpdateTime);
4091
4092 // Remove the update packet from the list of packets waiting for acknowledgement
4093 // because we are requeuing the list of updates. They will be resent in new packets
4094 // with the most recent state.
4095 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber, 0, true);
4096 foreach (ObjectPropertyUpdate update in updates)
4097 ResendPropertyUpdate(update);
4098 }
4099
3983 public void SendObjectPropertiesReply(ISceneEntity entity) 4100 public void SendObjectPropertiesReply(ISceneEntity entity)
3984 { 4101 {
3985 uint priority = 0; // time based ordering only 4102 uint priority = 0; // time based ordering only
@@ -3995,6 +4112,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3995 OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks = 4112 OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks =
3996 new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>(); 4113 new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>();
3997 4114
4115 OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> familyUpdates =
4116 new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
4117
4118 OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> propertyUpdates =
4119 new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
4120
3998 IEntityUpdate iupdate; 4121 IEntityUpdate iupdate;
3999 Int32 timeinqueue; // this is just debugging code & can be dropped later 4122 Int32 timeinqueue; // this is just debugging code & can be dropped later
4000 4123
@@ -4013,6 +4136,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4013 SceneObjectPart sop = (SceneObjectPart)update.Entity; 4136 SceneObjectPart sop = (SceneObjectPart)update.Entity;
4014 ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); 4137 ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags);
4015 objectFamilyBlocks.Value.Add(objPropDB); 4138 objectFamilyBlocks.Value.Add(objPropDB);
4139 familyUpdates.Value.Add(update);
4016 } 4140 }
4017 } 4141 }
4018 4142
@@ -4023,6 +4147,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4023 SceneObjectPart sop = (SceneObjectPart)update.Entity; 4147 SceneObjectPart sop = (SceneObjectPart)update.Entity;
4024 ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); 4148 ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop);
4025 objectPropertiesBlocks.Value.Add(objPropDB); 4149 objectPropertiesBlocks.Value.Add(objPropDB);
4150 propertyUpdates.Value.Add(update);
4026 } 4151 }
4027 } 4152 }
4028 4153
@@ -4030,12 +4155,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4030 } 4155 }
4031 4156
4032 4157
4033 Int32 ppcnt = 0; 4158 // Int32 ppcnt = 0;
4034 Int32 pbcnt = 0; 4159 // Int32 pbcnt = 0;
4035 4160
4036 if (objectPropertiesBlocks.IsValueCreated) 4161 if (objectPropertiesBlocks.IsValueCreated)
4037 { 4162 {
4038 List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value; 4163 List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value;
4164 List<ObjectPropertyUpdate> updates = propertyUpdates.Value;
4039 4165
4040 ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); 4166 ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
4041 packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count]; 4167 packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count];
@@ -4043,28 +4169,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4043 packet.ObjectData[i] = blocks[i]; 4169 packet.ObjectData[i] = blocks[i];
4044 4170
4045 packet.Header.Zerocoded = true; 4171 packet.Header.Zerocoded = true;
4046 OutPacket(packet, ThrottleOutPacketType.Task, true);
4047 4172
4048 pbcnt += blocks.Count; 4173 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4049 ppcnt++; 4174 // of the object rather than the properties when the packet was created
4175 OutPacket(packet, ThrottleOutPacketType.Task, true,
4176 delegate(OutgoingPacket oPacket)
4177 {
4178 ResendPropertyUpdates(updates, oPacket);
4179 });
4180
4181 // pbcnt += blocks.Count;
4182 // ppcnt++;
4050 } 4183 }
4051 4184
4052 Int32 fpcnt = 0; 4185 // Int32 fpcnt = 0;
4053 Int32 fbcnt = 0; 4186 // Int32 fbcnt = 0;
4054 4187
4055 if (objectFamilyBlocks.IsValueCreated) 4188 if (objectFamilyBlocks.IsValueCreated)
4056 { 4189 {
4057 List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value; 4190 List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value;
4058 4191
4059 // ObjectPropertiesFamilyPacket objPropFamilyPack =
4060 // (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily);
4061 //
4062 // objPropFamilyPack.ObjectData = new ObjectPropertiesFamilyPacket.ObjectDataBlock[blocks.Count];
4063 // for (int i = 0; i < blocks.Count; i++)
4064 // objPropFamilyPack.ObjectData[i] = blocks[i];
4065 //
4066 // OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task, true);
4067
4068 // one packet per object block... uggh... 4192 // one packet per object block... uggh...
4069 for (int i = 0; i < blocks.Count; i++) 4193 for (int i = 0; i < blocks.Count; i++)
4070 { 4194 {
@@ -4073,10 +4197,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4073 4197
4074 packet.ObjectData = blocks[i]; 4198 packet.ObjectData = blocks[i];
4075 packet.Header.Zerocoded = true; 4199 packet.Header.Zerocoded = true;
4076 OutPacket(packet, ThrottleOutPacketType.Task);
4077 4200
4078 fpcnt++; 4201 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4079 fbcnt++; 4202 // of the object rather than the properties when the packet was created
4203 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4204 updates.Add(familyUpdates.Value[i]);
4205 OutPacket(packet, ThrottleOutPacketType.Task, true,
4206 delegate(OutgoingPacket oPacket)
4207 {
4208 ResendPropertyUpdates(updates, oPacket);
4209 });
4210
4211 // fpcnt++;
4212 // fbcnt++;
4080 } 4213 }
4081 4214
4082 } 4215 }
@@ -4113,7 +4246,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4113 4246
4114 return block; 4247 return block;
4115 } 4248 }
4116 4249
4117 private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) 4250 private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop)
4118 { 4251 {
4119 //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); 4252 //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
@@ -4550,14 +4683,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4550 4683
4551 if (notifyCount > 0) 4684 if (notifyCount > 0)
4552 { 4685 {
4553 if (notifyCount > 32) 4686// if (notifyCount > 32)
4554 { 4687// {
4555 m_log.InfoFormat( 4688// m_log.InfoFormat(
4556 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 4689// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
4557 + " - a developer might want to investigate whether this is a hard limit", 32); 4690// + " - a developer might want to investigate whether this is a hard limit", 32);
4558 4691//
4559 notifyCount = 32; 4692// notifyCount = 32;
4560 } 4693// }
4561 4694
4562 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 4695 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
4563 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 4696 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -5065,6 +5198,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5065 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 5198 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
5066 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 5199 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
5067 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 5200 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5201 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
5068 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 5202 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
5069 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 5203 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
5070 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 5204 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5164,6 +5298,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5164 (x.CameraLeftAxis != lastarg.CameraLeftAxis) || 5298 (x.CameraLeftAxis != lastarg.CameraLeftAxis) ||
5165 (x.CameraUpAxis != lastarg.CameraUpAxis) || 5299 (x.CameraUpAxis != lastarg.CameraUpAxis) ||
5166 (x.ControlFlags != lastarg.ControlFlags) || 5300 (x.ControlFlags != lastarg.ControlFlags) ||
5301 (x.ControlFlags != 0) ||
5167 (x.Far != lastarg.Far) || 5302 (x.Far != lastarg.Far) ||
5168 (x.Flags != lastarg.Flags) || 5303 (x.Flags != lastarg.Flags) ||
5169 (x.State != lastarg.State) || 5304 (x.State != lastarg.State) ||
@@ -5537,7 +5672,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5537 args.Channel = ch; 5672 args.Channel = ch;
5538 args.From = String.Empty; 5673 args.From = String.Empty;
5539 args.Message = Utils.BytesToString(msg); 5674 args.Message = Utils.BytesToString(msg);
5540 args.Type = ChatTypeEnum.Shout; 5675 args.Type = ChatTypeEnum.Region; //Behaviour in SL is that the response can be heard from any distance
5541 args.Position = new Vector3(); 5676 args.Position = new Vector3();
5542 args.Scene = Scene; 5677 args.Scene = Scene;
5543 args.Sender = this; 5678 args.Sender = this;
@@ -9525,7 +9660,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9525 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, 9660 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
9526 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), 9661 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
9527 UpdateMuteListEntry.MuteData.MuteType, 9662 UpdateMuteListEntry.MuteData.MuteType,
9528 UpdateMuteListEntry.AgentData.AgentID); 9663 UpdateMuteListEntry.MuteData.MuteFlags);
9529 return true; 9664 return true;
9530 } 9665 }
9531 return false; 9666 return false;
@@ -9540,8 +9675,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9540 { 9675 {
9541 handlerRemoveMuteListEntry(this, 9676 handlerRemoveMuteListEntry(this,
9542 RemoveMuteListEntry.MuteData.MuteID, 9677 RemoveMuteListEntry.MuteData.MuteID,
9543 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), 9678 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
9544 RemoveMuteListEntry.AgentData.AgentID);
9545 return true; 9679 return true;
9546 } 9680 }
9547 return false; 9681 return false;
@@ -9589,6 +9723,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9589 { 9723 {
9590 return true; 9724 return true;
9591 } 9725 }
9726
9727 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
9728 {
9729 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
9730
9731 #region Packet Session and User Check
9732 if (m_checkPackets)
9733 {
9734 if (packet.AgentData.SessionID != SessionId ||
9735 packet.AgentData.AgentID != AgentId)
9736 return true;
9737 }
9738 #endregion
9739 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
9740 List<InventoryItemBase> items = new List<InventoryItemBase>();
9741 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
9742 {
9743 InventoryItemBase b = new InventoryItemBase();
9744 b.ID = n.OldItemID;
9745 b.Folder = n.OldFolderID;
9746 items.Add(b);
9747 }
9748
9749 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
9750 if (handlerMoveItemsAndLeaveCopy != null)
9751 {
9752 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
9753 }
9754
9755 return true;
9756 }
9592 9757
9593 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 9758 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
9594 { 9759 {
@@ -10015,6 +10180,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10015 groupProfileReply.GroupData.MaturePublish = d.MaturePublish; 10180 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
10016 groupProfileReply.GroupData.OwnerRole = d.OwnerRole; 10181 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
10017 10182
10183 Scene scene = (Scene)m_scene;
10184 if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID)))
10185 {
10186 ScenePresence p;
10187 if (scene.TryGetScenePresence(sender.AgentId, out p))
10188 {
10189 if (p.GodLevel >= 200)
10190 {
10191 groupProfileReply.GroupData.OpenEnrollment = true;
10192 groupProfileReply.GroupData.MembershipFee = 0;
10193 }
10194 }
10195 }
10196
10018 OutPacket(groupProfileReply, ThrottleOutPacketType.Task); 10197 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
10019 } 10198 }
10020 return true; 10199 return true;
@@ -10587,11 +10766,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10587 10766
10588 StartLure handlerStartLure = OnStartLure; 10767 StartLure handlerStartLure = OnStartLure;
10589 if (handlerStartLure != null) 10768 if (handlerStartLure != null)
10590 handlerStartLure(startLureRequest.Info.LureType, 10769 {
10591 Utils.BytesToString( 10770 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
10592 startLureRequest.Info.Message), 10771 {
10593 startLureRequest.TargetData[0].TargetID, 10772 handlerStartLure(startLureRequest.Info.LureType,
10594 this); 10773 Utils.BytesToString(
10774 startLureRequest.Info.Message),
10775 startLureRequest.TargetData[i].TargetID,
10776 this);
10777 }
10778 }
10595 return true; 10779 return true;
10596 } 10780 }
10597 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 10781 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -10705,10 +10889,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10705 } 10889 }
10706 #endregion 10890 #endregion
10707 10891
10708 ClassifiedDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; 10892 ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete;
10709 if (handlerClassifiedGodDelete != null) 10893 if (handlerClassifiedGodDelete != null)
10710 handlerClassifiedGodDelete( 10894 handlerClassifiedGodDelete(
10711 classifiedGodDelete.Data.ClassifiedID, 10895 classifiedGodDelete.Data.ClassifiedID,
10896 classifiedGodDelete.Data.QueryID,
10712 this); 10897 this);
10713 return true; 10898 return true;
10714 } 10899 }
@@ -11086,7 +11271,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11086 { 11271 {
11087 // It's a ghost! tell the client to delete it from view. 11272 // It's a ghost! tell the client to delete it from view.
11088 simClient.SendKillObject(Scene.RegionInfo.RegionHandle, 11273 simClient.SendKillObject(Scene.RegionInfo.RegionHandle,
11089 localId); 11274 new List<uint>() { localId });
11090 } 11275 }
11091 else 11276 else
11092 { 11277 {
@@ -11363,6 +11548,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11363 /// handles splitting manually</param> 11548 /// handles splitting manually</param>
11364 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting) 11549 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting)
11365 { 11550 {
11551 OutPacket(packet, throttlePacketType, doAutomaticSplitting, null);
11552 }
11553
11554 /// <summary>
11555 /// This is the starting point for sending a simulator packet out to the client
11556 /// </summary>
11557 /// <param name="packet">Packet to send</param>
11558 /// <param name="throttlePacketType">Throttling category for the packet</param>
11559 /// <param name="doAutomaticSplitting">True to automatically split oversized
11560 /// packets (the default), or false to disable splitting if the calling code
11561 /// handles splitting manually</param>
11562 /// <param name="method">The method to be called in the event this packet is reliable
11563 /// and unacknowledged. The server will provide normal resend capability if you do not
11564 /// provide your own method.</param>
11565 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method)
11566 {
11366 if (m_debugPacketLevel > 0) 11567 if (m_debugPacketLevel > 0)
11367 { 11568 {
11368 bool logPacket = true; 11569 bool logPacket = true;
@@ -11388,7 +11589,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11388 m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); 11589 m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type);
11389 } 11590 }
11390 11591
11391 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); 11592 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method);
11392 } 11593 }
11393 11594
11394 public bool AddMoney(int debit) 11595 public bool AddMoney(int debit)
@@ -11459,22 +11660,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11459 /// <param name="Pack">OpenMetaverse.packet</param> 11660 /// <param name="Pack">OpenMetaverse.packet</param>
11460 public void ProcessInPacket(Packet packet) 11661 public void ProcessInPacket(Packet packet)
11461 { 11662 {
11462 if (m_debugPacketLevel > 0) 11663 if (m_debugPacketLevel >= 255)
11463 { 11664 m_log.DebugFormat("[CLIENT]: Packet IN {0}", packet.Type);
11464 bool outputPacket = true;
11465
11466 if (m_debugPacketLevel <= 255 && packet.Type == PacketType.AgentUpdate)
11467 outputPacket = false;
11468
11469 if (m_debugPacketLevel <= 200 && packet.Type == PacketType.RequestImage)
11470 outputPacket = false;
11471
11472 if (m_debugPacketLevel <= 100 && (packet.Type == PacketType.ViewerEffect || packet.Type == PacketType.AgentAnimation))
11473 outputPacket = false;
11474
11475 if (outputPacket)
11476 m_log.DebugFormat("[CLIENT]: Packet IN {0}", packet.Type);
11477 }
11478 11665
11479 if (!ProcessPacketMethod(packet)) 11666 if (!ProcessPacketMethod(packet))
11480 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type); 11667 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type);
@@ -11716,7 +11903,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11716 11903
11717// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID); 11904// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID);
11718 11905
11906
11907 //Note, the bool returned from the below function is useless since it is always false.
11719 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 11908 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
11909
11720 } 11910 }
11721 11911
11722 /// <summary> 11912 /// <summary>
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
index 7be8a0a..e54d326 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -135,7 +135,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
135 private int m_nextOnQueueEmpty = 1; 135 private int m_nextOnQueueEmpty = 1;
136 136
137 /// <summary>Throttle bucket for this agent's connection</summary> 137 /// <summary>Throttle bucket for this agent's connection</summary>
138 private readonly TokenBucket m_throttleClient; 138 private readonly AdaptiveTokenBucket m_throttleClient;
139 public AdaptiveTokenBucket FlowThrottle
140 {
141 get { return m_throttleClient; }
142 }
143
139 /// <summary>Throttle bucket for this agent's connection</summary> 144 /// <summary>Throttle bucket for this agent's connection</summary>
140 private readonly TokenBucket m_throttleCategory; 145 private readonly TokenBucket m_throttleCategory;
141 /// <summary>Throttle buckets for each packet category</summary> 146 /// <summary>Throttle buckets for each packet category</summary>
@@ -153,6 +158,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
153 158
154 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC 159 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC
155 private int m_maxRTO = 60000; 160 private int m_maxRTO = 60000;
161 public bool m_deliverPackets = true;
156 162
157 /// <summary> 163 /// <summary>
158 /// Default constructor 164 /// Default constructor
@@ -176,7 +182,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
176 m_maxRTO = maxRTO; 182 m_maxRTO = maxRTO;
177 183
178 // Create a token bucket throttle for this client that has the scene token bucket as a parent 184 // Create a token bucket throttle for this client that has the scene token bucket as a parent
179 m_throttleClient = new TokenBucket(parentThrottle, rates.TotalLimit); 185 m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.TotalLimit);
180 // Create a token bucket throttle for the total categary with the client bucket as a throttle 186 // Create a token bucket throttle for the total categary with the client bucket as a throttle
181 m_throttleCategory = new TokenBucket(m_throttleClient, rates.TotalLimit); 187 m_throttleCategory = new TokenBucket(m_throttleClient, rates.TotalLimit);
182 // Create an array of token buckets for this clients different throttle categories 188 // Create an array of token buckets for this clients different throttle categories
@@ -438,6 +444,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
438 if (category >= 0 && category < m_packetOutboxes.Length) 444 if (category >= 0 && category < m_packetOutboxes.Length)
439 { 445 {
440 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; 446 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
447
448 if (m_deliverPackets == false)
449 {
450 queue.Enqueue(packet);
451 return true;
452 }
453
441 TokenBucket bucket = m_throttleCategories[category]; 454 TokenBucket bucket = m_throttleCategories[category];
442 455
443 // Don't send this packet if there is already a packet waiting in the queue 456 // Don't send this packet if there is already a packet waiting in the queue
@@ -487,6 +500,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
487 /// <returns>True if any packets were sent, otherwise false</returns> 500 /// <returns>True if any packets were sent, otherwise false</returns>
488 public bool DequeueOutgoing() 501 public bool DequeueOutgoing()
489 { 502 {
503 if (m_deliverPackets == false) return false;
504
490 OutgoingPacket packet; 505 OutgoingPacket packet;
491 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; 506 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue;
492 TokenBucket bucket; 507 TokenBucket bucket;
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index d08b25f..a1a58e5 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(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : 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(expiredPackets[i]);
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)
@@ -960,7 +960,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
960 if (m_scene.TryGetClient(udpClient.AgentID, out client)) 960 if (m_scene.TryGetClient(udpClient.AgentID, out client))
961 { 961 {
962 client.IsLoggingOut = true; 962 client.IsLoggingOut = true;
963 client.Close(); 963 client.Close(false);
964 } 964 }
965 } 965 }
966 966
@@ -972,6 +972,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
972 972
973 while (base.IsRunning) 973 while (base.IsRunning)
974 { 974 {
975 m_scene.ThreadAlive(1);
975 try 976 try
976 { 977 {
977 IncomingPacket incomingPacket = null; 978 IncomingPacket incomingPacket = null;
@@ -1014,6 +1015,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1014 1015
1015 while (base.IsRunning) 1016 while (base.IsRunning)
1016 { 1017 {
1018 m_scene.ThreadAlive(2);
1017 try 1019 try
1018 { 1020 {
1019 m_packetSent = false; 1021 m_packetSent = false;
@@ -1096,7 +1098,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1096 if (udpClient.IsConnected) 1098 if (udpClient.IsConnected)
1097 { 1099 {
1098 if (m_resendUnacked) 1100 if (m_resendUnacked)
1099 ResendUnacked(udpClient); 1101 HandleUnacked(udpClient);
1100 1102
1101 if (m_sendAcks) 1103 if (m_sendAcks)
1102 SendAcks(udpClient); 1104 SendAcks(udpClient);
@@ -1152,7 +1154,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1152 nticksUnack++; 1154 nticksUnack++;
1153 watch2.Start(); 1155 watch2.Start();
1154 1156
1155 ResendUnacked(udpClient); 1157 HandleUnacked(udpClient);
1156 1158
1157 watch2.Stop(); 1159 watch2.Stop();
1158 avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack); 1160 avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack);
diff --git a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs
index 6eebd9d..d2779ba 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs
@@ -100,10 +100,6 @@ namespace OpenMetaverse
100 const int SIO_UDP_CONNRESET = -1744830452; 100 const int SIO_UDP_CONNRESET = -1744830452;
101 101
102 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); 102 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
103
104 m_log.DebugFormat(
105 "[UDPBASE]: Binding UDP listener using internal IP address config {0}:{1}",
106 ipep.Address, ipep.Port);
107 103
108 m_udpSocket = new Socket( 104 m_udpSocket = new Socket(
109 AddressFamily.InterNetwork, 105 AddressFamily.InterNetwork,
diff --git a/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs b/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs
index 1a1a1cb..76c6c14 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs
@@ -31,6 +31,8 @@ using OpenMetaverse;
31 31
32namespace OpenSim.Region.ClientStack.LindenUDP 32namespace OpenSim.Region.ClientStack.LindenUDP
33{ 33{
34
35 public delegate void UnackedPacketMethod(OutgoingPacket oPacket);
34 /// <summary> 36 /// <summary>
35 /// Holds a reference to the <seealso cref="LLUDPClient"/> this packet is 37 /// Holds a reference to the <seealso cref="LLUDPClient"/> this packet is
36 /// destined for, along with the serialized packet data, sequence number 38 /// destined for, along with the serialized packet data, sequence number
@@ -52,6 +54,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
52 public int TickCount; 54 public int TickCount;
53 /// <summary>Category this packet belongs to</summary> 55 /// <summary>Category this packet belongs to</summary>
54 public ThrottleOutPacketType Category; 56 public ThrottleOutPacketType Category;
57 /// <summary>The delegate to be called if this packet is determined to be unacknowledged</summary>
58 public UnackedPacketMethod UnackedMethod;
55 59
56 /// <summary> 60 /// <summary>
57 /// Default constructor 61 /// Default constructor
@@ -60,11 +64,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
60 /// <param name="buffer">Serialized packet data. If the flags or sequence number 64 /// <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> 65 /// need to be updated, they will be injected directly into this binary buffer</param>
62 /// <param name="category">Throttling category for this packet</param> 66 /// <param name="category">Throttling category for this packet</param>
63 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category) 67 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category, UnackedPacketMethod method)
64 { 68 {
65 Client = client; 69 Client = client;
66 Buffer = buffer; 70 Buffer = buffer;
67 Category = category; 71 Category = category;
72 UnackedMethod = method;
68 } 73 }
69 } 74 }
70} 75}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
index 07b0a1d..4ee6d3a 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
@@ -48,31 +48,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
48 /// Number of ticks (ms) per quantum, drip rate and max burst 48 /// Number of ticks (ms) per quantum, drip rate and max burst
49 /// are defined over this interval. 49 /// are defined over this interval.
50 /// </summary> 50 /// </summary>
51 private const Int32 m_ticksPerQuantum = 1000; 51 protected const Int32 m_ticksPerQuantum = 1000;
52 52
53 /// <summary> 53 /// <summary>
54 /// This is the number of quantums worth of packets that can 54 /// This is the number of quantums worth of packets that can
55 /// be accommodated during a burst 55 /// be accommodated during a burst
56 /// </summary> 56 /// </summary>
57 private const Double m_quantumsPerBurst = 1.5; 57 protected const Double m_quantumsPerBurst = 1.5;
58 58
59 /// <summary> 59 /// <summary>
60 /// </summary> 60 /// </summary>
61 private const Int32 m_minimumDripRate = 1400; 61 protected const Int32 m_minimumDripRate = 1400;
62 62
63 /// <summary>Time of the last drip, in system ticks</summary> 63 /// <summary>Time of the last drip, in system ticks</summary>
64 private Int32 m_lastDrip; 64 protected Int32 m_lastDrip;
65 65
66 /// <summary> 66 /// <summary>
67 /// The number of bytes that can be sent at this moment. This is the 67 /// The number of bytes that can be sent at this moment. This is the
68 /// current number of tokens in the bucket 68 /// current number of tokens in the bucket
69 /// </summary> 69 /// </summary>
70 private Int64 m_tokenCount; 70 protected Int64 m_tokenCount;
71 71
72 /// <summary> 72 /// <summary>
73 /// Map of children buckets and their requested maximum burst rate 73 /// Map of children buckets and their requested maximum burst rate
74 /// </summary> 74 /// </summary>
75 private Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); 75 protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>();
76 76
77#region Properties 77#region Properties
78 78
@@ -81,7 +81,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
81 /// parent. The parent bucket will limit the aggregate bandwidth of all 81 /// parent. The parent bucket will limit the aggregate bandwidth of all
82 /// of its children buckets 82 /// of its children buckets
83 /// </summary> 83 /// </summary>
84 private TokenBucket m_parent; 84 protected TokenBucket m_parent;
85 public TokenBucket Parent 85 public TokenBucket Parent
86 { 86 {
87 get { return m_parent; } 87 get { return m_parent; }
@@ -93,7 +93,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
93 /// of tokens that can accumulate in the bucket at any one time. This 93 /// of tokens that can accumulate in the bucket at any one time. This
94 /// also sets the total request for leaf nodes 94 /// also sets the total request for leaf nodes
95 /// </summary> 95 /// </summary>
96 private Int64 m_burstRate; 96 protected Int64 m_burstRate;
97 public Int64 RequestedBurstRate 97 public Int64 RequestedBurstRate
98 { 98 {
99 get { return m_burstRate; } 99 get { return m_burstRate; }
@@ -118,8 +118,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
118 /// <remarks>Tokens are added to the bucket any time 118 /// <remarks>Tokens are added to the bucket any time
119 /// <seealso cref="RemoveTokens"/> is called, at the granularity of 119 /// <seealso cref="RemoveTokens"/> is called, at the granularity of
120 /// the system tick interval (typically around 15-22ms)</remarks> 120 /// the system tick interval (typically around 15-22ms)</remarks>
121 private Int64 m_dripRate; 121 protected Int64 m_dripRate;
122 public Int64 RequestedDripRate 122 public virtual Int64 RequestedDripRate
123 { 123 {
124 get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } 124 get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); }
125 set { 125 set {
@@ -131,7 +131,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
131 } 131 }
132 } 132 }
133 133
134 public Int64 DripRate 134 public virtual Int64 DripRate
135 { 135 {
136 get { 136 get {
137 if (m_parent == null) 137 if (m_parent == null)
@@ -149,7 +149,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
149 /// The current total of the requested maximum burst rates of 149 /// The current total of the requested maximum burst rates of
150 /// this bucket's children buckets. 150 /// this bucket's children buckets.
151 /// </summary> 151 /// </summary>
152 private Int64 m_totalDripRequest; 152 protected Int64 m_totalDripRequest;
153 public Int64 TotalDripRequest 153 public Int64 TotalDripRequest
154 { 154 {
155 get { return m_totalDripRequest; } 155 get { return m_totalDripRequest; }
@@ -189,7 +189,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
189 /// hierarchy. However, if any of the parents is over-booked, then 189 /// hierarchy. However, if any of the parents is over-booked, then
190 /// the modifier will be less than 1. 190 /// the modifier will be less than 1.
191 /// </summary> 191 /// </summary>
192 private double DripRateModifier() 192 protected double DripRateModifier()
193 { 193 {
194 Int64 driprate = DripRate; 194 Int64 driprate = DripRate;
195 return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; 195 return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest;
@@ -197,7 +197,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
197 197
198 /// <summary> 198 /// <summary>
199 /// </summary> 199 /// </summary>
200 private double BurstRateModifier() 200 protected double BurstRateModifier()
201 { 201 {
202 // for now... burst rate is always m_quantumsPerBurst (constant) 202 // for now... burst rate is always m_quantumsPerBurst (constant)
203 // larger than drip rate so the ratio of burst requests is the 203 // larger than drip rate so the ratio of burst requests is the
@@ -268,7 +268,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
268 /// Deposit tokens into the bucket from a child bucket that did 268 /// Deposit tokens into the bucket from a child bucket that did
269 /// not use all of its available tokens 269 /// not use all of its available tokens
270 /// </summary> 270 /// </summary>
271 private void Deposit(Int64 count) 271 protected void Deposit(Int64 count)
272 { 272 {
273 m_tokenCount += count; 273 m_tokenCount += count;
274 274
@@ -285,7 +285,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
285 /// call to Drip 285 /// call to Drip
286 /// </summary> 286 /// </summary>
287 /// <returns>True if tokens were added to the bucket, otherwise false</returns> 287 /// <returns>True if tokens were added to the bucket, otherwise false</returns>
288 private void Drip() 288 protected void Drip()
289 { 289 {
290 // This should never happen... means we are a leaf node and were created 290 // This should never happen... means we are a leaf node and were created
291 // with no drip rate... 291 // with no drip rate...
@@ -310,4 +310,64 @@ namespace OpenSim.Region.ClientStack.LindenUDP
310 Deposit(deltaMS * DripRate / m_ticksPerQuantum); 310 Deposit(deltaMS * DripRate / m_ticksPerQuantum);
311 } 311 }
312 } 312 }
313
314 public class AdaptiveTokenBucket : TokenBucket
315 {
316 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
317
318 // <summary>
319 // The minimum rate for flow control.
320 // </summary>
321 protected const Int64 m_minimumFlow = m_minimumDripRate * 10;
322
323 // <summary>
324 // The maximum rate for flow control. Drip rate can never be
325 // greater than this.
326 // </summary>
327 protected Int64 m_maxDripRate = 0;
328 protected Int64 MaxDripRate
329 {
330 get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); }
331 set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); }
332 }
333
334 // <summary>
335 //
336 // </summary>
337 public virtual Int64 AdjustedDripRate
338 {
339 get { return m_dripRate; }
340 set {
341 m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value,m_minimumFlow,MaxDripRate);
342 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
343 if (m_parent != null)
344 m_parent.RegisterRequest(this,m_dripRate);
345 }
346 }
347
348 // <summary>
349 //
350 // </summary>
351 public AdaptiveTokenBucket(TokenBucket parent, Int64 maxDripRate) : base(parent,m_minimumFlow)
352 {
353 MaxDripRate = maxDripRate;
354 }
355
356 // <summary>
357 //
358 // </summary>
359 public void ExpirePackets(Int32 count)
360 {
361 // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count);
362 AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,count));
363 }
364
365 // <summary>
366 //
367 // </summary>
368 public void AcknowledgePackets(Int32 count)
369 {
370 AdjustedDripRate = AdjustedDripRate + count;
371 }
372 }
313} 373}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
index d195110..b170964 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
@@ -130,6 +130,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
130 // is actually sent out again 130 // is actually sent out again
131 packet.TickCount = 0; 131 packet.TickCount = 0;
132 132
133 // As with other network applications, assume that an expired packet is
134 // an indication of some network problem, slow transmission
135 packet.Client.FlowThrottle.ExpirePackets(1);
136
133 expiredPackets.Add(packet); 137 expiredPackets.Add(packet);
134 } 138 }
135 } 139 }
@@ -157,6 +161,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
157 { 161 {
158 m_packets.Remove(pendingRemove.SequenceNumber); 162 m_packets.Remove(pendingRemove.SequenceNumber);
159 163
164 // As with other network applications, assume that an acknowledged packet is an
165 // indication that the network can handle a little more load, speed up the transmission
166 ackedPacket.Client.FlowThrottle.AcknowledgePackets(ackedPacket.Buffer.DataLength);
167
160 // Update stats 168 // Update stats
161 Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength); 169 Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength);
162 170