aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs3
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs231
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs10
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs27
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs66
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs353
6 files changed, 406 insertions, 284 deletions
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 0d142f4..105501f 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -155,6 +155,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
155 public event RequestTaskInventory OnRequestTaskInventory; 155 public event RequestTaskInventory OnRequestTaskInventory;
156 public event UpdateInventoryItem OnUpdateInventoryItem; 156 public event UpdateInventoryItem OnUpdateInventoryItem;
157 public event CopyInventoryItem OnCopyInventoryItem; 157 public event CopyInventoryItem OnCopyInventoryItem;
158 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
158 public event MoveInventoryItem OnMoveInventoryItem; 159 public event MoveInventoryItem OnMoveInventoryItem;
159 public event RemoveInventoryItem OnRemoveInventoryItem; 160 public event RemoveInventoryItem OnRemoveInventoryItem;
160 public event RemoveInventoryFolder OnRemoveInventoryFolder; 161 public event RemoveInventoryFolder OnRemoveInventoryFolder;
@@ -336,11 +337,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
336// protected HashSet<uint> m_attachmentsSent; 337// protected HashSet<uint> m_attachmentsSent;
337 338
338 private int m_moneyBalance; 339 private int m_moneyBalance;
340 private bool m_deliverPackets = true;
339 private int m_animationSequenceNumber = 1; 341 private int m_animationSequenceNumber = 1;
340 private bool m_SendLogoutPacketWhenClosing = true; 342 private bool m_SendLogoutPacketWhenClosing = true;
341 private AgentUpdateArgs lastarg; 343 private AgentUpdateArgs lastarg;
342 private bool m_IsActive = true; 344 private bool m_IsActive = true;
343 private bool m_IsLoggingOut = false; 345 private bool m_IsLoggingOut = false;
346 private bool m_IsPresenceReady = false;
344 347
345 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); 348 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
346 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers 349 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@@ -363,6 +366,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
363 366
364 private Timer m_propertiesPacketTimer; 367 private Timer m_propertiesPacketTimer;
365 private List<ObjectPropertiesPacket.ObjectDataBlock> m_propertiesBlocks = new List<ObjectPropertiesPacket.ObjectDataBlock>(); 368 private List<ObjectPropertiesPacket.ObjectDataBlock> m_propertiesBlocks = new List<ObjectPropertiesPacket.ObjectDataBlock>();
369 private List<Packet> m_pendingPackets;
366 370
367 #endregion Class Members 371 #endregion Class Members
368 372
@@ -378,6 +382,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
378 get { return m_startpos; } 382 get { return m_startpos; }
379 set { m_startpos = value; } 383 set { m_startpos = value; }
380 } 384 }
385 public bool DeliverPackets
386 {
387 get { return m_deliverPackets; }
388 set {
389 m_deliverPackets = value;
390 m_udpClient.m_deliverPackets = value;
391 }
392 }
381 public UUID AgentId { get { return m_agentId; } } 393 public UUID AgentId { get { return m_agentId; } }
382 public UUID ActiveGroupId { get { return m_activeGroupID; } } 394 public UUID ActiveGroupId { get { return m_activeGroupID; } }
383 public string ActiveGroupName { get { return m_activeGroupName; } } 395 public string ActiveGroupName { get { return m_activeGroupName; } }
@@ -407,6 +419,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
407 get { return m_IsActive; } 419 get { return m_IsActive; }
408 set { m_IsActive = value; } 420 set { m_IsActive = value; }
409 } 421 }
422
410 public bool IsLoggingOut 423 public bool IsLoggingOut
411 { 424 {
412 get { return m_IsLoggingOut; } 425 get { return m_IsLoggingOut; }
@@ -476,18 +489,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
476 489
477 #region Client Methods 490 #region Client Methods
478 491
492
479 /// <summary> 493 /// <summary>
480 /// Shut down the client view 494 /// Shut down the client view
481 /// </summary> 495 /// </summary>
482 public void Close() 496 public void Close()
483 { 497 {
498 Close(true);
499 }
500
501 /// <summary>
502 /// Shut down the client view
503 /// </summary>
504 public void Close(bool sendStop)
505 {
484 m_log.DebugFormat( 506 m_log.DebugFormat(
485 "[CLIENT]: Close has been called for {0} attached to scene {1}", 507 "[CLIENT]: Close has been called for {0} attached to scene {1}",
486 Name, m_scene.RegionInfo.RegionName); 508 Name, m_scene.RegionInfo.RegionName);
487 509
488 // Send the STOP packet 510 if (sendStop)
489 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); 511 {
490 OutPacket(disable, ThrottleOutPacketType.Unknown); 512 // Send the STOP packet
513 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
514 OutPacket(disable, ThrottleOutPacketType.Unknown);
515 }
491 516
492 IsActive = false; 517 IsActive = false;
493 518
@@ -767,7 +792,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
767 reply.ChatData.OwnerID = fromAgentID; 792 reply.ChatData.OwnerID = fromAgentID;
768 reply.ChatData.SourceID = fromAgentID; 793 reply.ChatData.SourceID = fromAgentID;
769 794
770 OutPacket(reply, ThrottleOutPacketType.Task); 795 OutPacket(reply, ThrottleOutPacketType.Unknown);
771 } 796 }
772 797
773 /// <summary> 798 /// <summary>
@@ -1053,6 +1078,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1053 public virtual void SendLayerData(float[] map) 1078 public virtual void SendLayerData(float[] map)
1054 { 1079 {
1055 Util.FireAndForget(DoSendLayerData, map); 1080 Util.FireAndForget(DoSendLayerData, map);
1081
1082 // Send it sync, and async. It's not that much data
1083 // and it improves user experience just so much!
1084 DoSendLayerData(map);
1056 } 1085 }
1057 1086
1058 /// <summary> 1087 /// <summary>
@@ -1065,16 +1094,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1065 1094
1066 try 1095 try
1067 { 1096 {
1068 //for (int y = 0; y < 16; y++) 1097 for (int y = 0; y < 16; y++)
1069 //{ 1098 {
1070 // for (int x = 0; x < 16; x++) 1099 for (int x = 0; x < 16; x+=4)
1071 // { 1100 {
1072 // SendLayerData(x, y, map); 1101 SendLayerPacket(x, y, map);
1073 // } 1102 }
1074 //} 1103 }
1075
1076 // Send LayerData in a spiral pattern. Fun!
1077 SendLayerTopRight(map, 0, 0, 15, 15);
1078 } 1104 }
1079 catch (Exception e) 1105 catch (Exception e)
1080 { 1106 {
@@ -1082,51 +1108,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1082 } 1108 }
1083 } 1109 }
1084 1110
1085 private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2)
1086 {
1087 // Row
1088 for (int i = x1; i <= x2; i++)
1089 SendLayerData(i, y1, map);
1090
1091 // Column
1092 for (int j = y1 + 1; j <= y2; j++)
1093 SendLayerData(x2, j, map);
1094
1095 if (x2 - x1 > 0)
1096 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1097 }
1098
1099 void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2)
1100 {
1101 // Row in reverse
1102 for (int i = x2; i >= x1; i--)
1103 SendLayerData(i, y2, map);
1104
1105 // Column in reverse
1106 for (int j = y2 - 1; j >= y1; j--)
1107 SendLayerData(x1, j, map);
1108
1109 if (x2 - x1 > 0)
1110 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1111 }
1112
1113 /// <summary> 1111 /// <summary>
1114 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1112 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1115 /// </summary> 1113 /// </summary>
1116 /// <param name="map">heightmap</param> 1114 /// <param name="map">heightmap</param>
1117 /// <param name="px">X coordinate for patches 0..12</param> 1115 /// <param name="px">X coordinate for patches 0..12</param>
1118 /// <param name="py">Y coordinate for patches 0..15</param> 1116 /// <param name="py">Y coordinate for patches 0..15</param>
1119 // private void SendLayerPacket(float[] map, int y, int x) 1117 private void SendLayerPacket(int x, int y, float[] map)
1120 // { 1118 {
1121 // int[] patches = new int[4]; 1119 int[] patches = new int[4];
1122 // patches[0] = x + 0 + y * 16; 1120 patches[0] = x + 0 + y * 16;
1123 // patches[1] = x + 1 + y * 16; 1121 patches[1] = x + 1 + y * 16;
1124 // patches[2] = x + 2 + y * 16; 1122 patches[2] = x + 2 + y * 16;
1125 // patches[3] = x + 3 + y * 16; 1123 patches[3] = x + 3 + y * 16;
1126 1124
1127 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); 1125 float[] heightmap = (map.Length == 65536) ?
1128 // OutPacket(layerpack, ThrottleOutPacketType.Land); 1126 map :
1129 // } 1127 LLHeightFieldMoronize(map);
1128
1129 try
1130 {
1131 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1132 OutPacket(layerpack, ThrottleOutPacketType.Land);
1133 }
1134 catch
1135 {
1136 for (int px = x ; px < x + 4 ; px++)
1137 SendLayerData(px, y, map);
1138 }
1139 }
1130 1140
1131 /// <summary> 1141 /// <summary>
1132 /// Sends a specified patch to a client 1142 /// Sends a specified patch to a client
@@ -1146,7 +1156,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1146 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1156 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1147 layerpack.Header.Reliable = true; 1157 layerpack.Header.Reliable = true;
1148 1158
1149 OutPacket(layerpack, ThrottleOutPacketType.Land); 1159 OutPacket(layerpack, ThrottleOutPacketType.Task);
1150 } 1160 }
1151 catch (Exception e) 1161 catch (Exception e)
1152 { 1162 {
@@ -2229,6 +2239,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2229 OutPacket(sound, ThrottleOutPacketType.Task); 2239 OutPacket(sound, ThrottleOutPacketType.Task);
2230 } 2240 }
2231 2241
2242 public void SendTransferAbort(TransferRequestPacket transferRequest)
2243 {
2244 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2245 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2246 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2247 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2248 OutPacket(abort, ThrottleOutPacketType.Task);
2249 }
2250
2232 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2251 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2233 { 2252 {
2234 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2253 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -3516,6 +3535,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3516 /// </summary> 3535 /// </summary>
3517 public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3536 public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3518 { 3537 {
3538 if (entity is SceneObjectPart)
3539 {
3540 SceneObjectPart e = (SceneObjectPart)entity;
3541 SceneObjectGroup g = e.ParentGroup;
3542 if (g.RootPart.Shape.State > 30) // HUD
3543 if (g.OwnerID != AgentId)
3544 return; // Don't send updates for other people's HUDs
3545 }
3546
3519 double priority = m_prioritizer.GetUpdatePriority(this, entity); 3547 double priority = m_prioritizer.GetUpdatePriority(this, entity);
3520 3548
3521 lock (m_entityUpdates.SyncRoot) 3549 lock (m_entityUpdates.SyncRoot)
@@ -3536,23 +3564,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3536 EntityUpdate update; 3564 EntityUpdate update;
3537 while (updatesThisCall < maxUpdates && m_entityUpdates.TryDequeue(out update)) 3565 while (updatesThisCall < maxUpdates && m_entityUpdates.TryDequeue(out update))
3538 { 3566 {
3539 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client 3567 // If we have sent a kill packet for this object
3540 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good 3568 // drop any updates on the floor
3541 // safety measure.
3542 //
3543 // Receiving updates after kills results in undeleteable prims that persist until relog and
3544 // currently occurs because prims can be deleted before all queued updates are sent.
3545 if (m_killRecord.Contains(update.Entity.LocalId))
3546 {
3547// m_log.WarnFormat(
3548// "[CLIENT]: Preventing full update for prim with local id {0} after client for user {1} told it was deleted",
3549// update.Entity.LocalId, Name);
3550 continue;
3551 }
3552
3553 if (update.Entity is SceneObjectPart) 3569 if (update.Entity is SceneObjectPart)
3554 { 3570 {
3555 SceneObjectPart part = (SceneObjectPart)update.Entity; 3571 SceneObjectPart part = (SceneObjectPart)update.Entity;
3572 if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3573 continue;
3556 3574
3557 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3575 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3558 { 3576 {
@@ -3986,6 +4004,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3986 { 4004 {
3987 m_propertiesPacketTimer.Stop(); 4005 m_propertiesPacketTimer.Stop();
3988 4006
4007 if (m_propertiesBlocks.Count == 0)
4008 return;
4009
3989 proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count]; 4010 proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count];
3990 4011
3991 int index = 0; 4012 int index = 0;
@@ -4892,6 +4913,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4892 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 4913 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
4893 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 4914 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
4894 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 4915 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
4916 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
4895 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 4917 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
4896 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 4918 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
4897 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 4919 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -4991,6 +5013,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4991 (x.CameraLeftAxis != lastarg.CameraLeftAxis) || 5013 (x.CameraLeftAxis != lastarg.CameraLeftAxis) ||
4992 (x.CameraUpAxis != lastarg.CameraUpAxis) || 5014 (x.CameraUpAxis != lastarg.CameraUpAxis) ||
4993 (x.ControlFlags != lastarg.ControlFlags) || 5015 (x.ControlFlags != lastarg.ControlFlags) ||
5016 (x.ControlFlags != 0) ||
4994 (x.Far != lastarg.Far) || 5017 (x.Far != lastarg.Far) ||
4995 (x.Flags != lastarg.Flags) || 5018 (x.Flags != lastarg.Flags) ||
4996 (x.State != lastarg.State) || 5019 (x.State != lastarg.State) ||
@@ -5362,7 +5385,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5362 args.Channel = ch; 5385 args.Channel = ch;
5363 args.From = String.Empty; 5386 args.From = String.Empty;
5364 args.Message = Utils.BytesToString(msg); 5387 args.Message = Utils.BytesToString(msg);
5365 args.Type = ChatTypeEnum.Shout; 5388 args.Type = ChatTypeEnum.Region; //Behaviour in SL is that the response can be heard from any distance
5366 args.Position = new Vector3(); 5389 args.Position = new Vector3();
5367 args.Scene = Scene; 5390 args.Scene = Scene;
5368 args.Sender = this; 5391 args.Sender = this;
@@ -9400,6 +9423,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9400 { 9423 {
9401 return true; 9424 return true;
9402 } 9425 }
9426
9427 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
9428 {
9429 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
9430
9431 #region Packet Session and User Check
9432 if (m_checkPackets)
9433 {
9434 if (packet.AgentData.SessionID != SessionId ||
9435 packet.AgentData.AgentID != AgentId)
9436 return true;
9437 }
9438 #endregion
9439 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
9440 List<InventoryItemBase> items = new List<InventoryItemBase>();
9441 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
9442 {
9443 InventoryItemBase b = new InventoryItemBase();
9444 b.ID = n.OldItemID;
9445 b.Folder = n.OldFolderID;
9446 items.Add(b);
9447 }
9448
9449 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
9450 if (handlerMoveItemsAndLeaveCopy != null)
9451 {
9452 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
9453 }
9454
9455 return true;
9456 }
9403 9457
9404 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 9458 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
9405 { 9459 {
@@ -11243,18 +11297,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11243 } 11297 }
11244 11298
11245 /// <summary> 11299 /// <summary>
11300 /// This processes packets which have accumulated while the presence was still in the process of initialising.
11301 /// </summary>
11302 public void ProcessPendingPackets()
11303 {
11304 m_IsPresenceReady = true;
11305 if (m_pendingPackets == null)
11306 return;
11307 foreach (Packet p in m_pendingPackets)
11308 {
11309 ProcessInPacket(p);
11310 }
11311 m_pendingPackets.Clear();
11312 }
11313
11314 /// <summary>
11246 /// Entryway from the client to the simulator. All UDP packets from the client will end up here 11315 /// Entryway from the client to the simulator. All UDP packets from the client will end up here
11247 /// </summary> 11316 /// </summary>
11248 /// <param name="Pack">OpenMetaverse.packet</param> 11317 /// <param name="Pack">OpenMetaverse.packet</param>
11249 public void ProcessInPacket(Packet Pack) 11318 public void ProcessInPacket(Packet Pack)
11250 { 11319 {
11251 if (m_debugPacketLevel >= 255) 11320 if (!m_IsPresenceReady)
11252 m_log.DebugFormat("[CLIENT]: Packet IN {0}", Pack.Type); 11321 {
11322 if (m_pendingPackets == null)
11323 {
11324 m_pendingPackets = new List<Packet>();
11325 }
11326 m_pendingPackets.Add(Pack);
11327 }
11328 else
11329 {
11330 if (m_debugPacketLevel >= 255)
11331 m_log.DebugFormat("[CLIENT]: Packet IN {0}", Pack.Type);
11253 11332
11254 if (!ProcessPacketMethod(Pack)) 11333 if (!ProcessPacketMethod(Pack))
11255 m_log.Warn("[CLIENT]: unhandled packet " + Pack.Type); 11334 m_log.Warn("[CLIENT]: unhandled packet " + Pack.Type);
11256 11335
11257 PacketPool.Instance.ReturnPacket(Pack); 11336 PacketPool.Instance.ReturnPacket(Pack);
11337 }
11258 } 11338 }
11259 11339
11260 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket) 11340 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
@@ -11491,7 +11571,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11491 11571
11492// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID); 11572// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID);
11493 11573
11574
11575 //Note, the bool returned from the below function is useless since it is always false.
11494 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 11576 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
11577
11495 } 11578 }
11496 11579
11497 /// <summary> 11580 /// <summary>
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
index 6232c48..eebbfa5 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -149,6 +149,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
149 149
150 private int m_defaultRTO = 3000; 150 private int m_defaultRTO = 3000;
151 private int m_maxRTO = 60000; 151 private int m_maxRTO = 60000;
152 public bool m_deliverPackets = true;
152 153
153 /// <summary> 154 /// <summary>
154 /// Default constructor 155 /// Default constructor
@@ -389,6 +390,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
389 if (category >= 0 && category < m_packetOutboxes.Length) 390 if (category >= 0 && category < m_packetOutboxes.Length)
390 { 391 {
391 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; 392 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
393
394 if (m_deliverPackets == false)
395 {
396 queue.Enqueue(packet);
397 return true;
398 }
399
392 TokenBucket bucket = m_throttleCategories[category]; 400 TokenBucket bucket = m_throttleCategories[category];
393 401
394 if (bucket.RemoveTokens(packet.Buffer.DataLength)) 402 if (bucket.RemoveTokens(packet.Buffer.DataLength))
@@ -419,6 +427,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
419 /// <returns>True if any packets were sent, otherwise false</returns> 427 /// <returns>True if any packets were sent, otherwise false</returns>
420 public bool DequeueOutgoing() 428 public bool DequeueOutgoing()
421 { 429 {
430 if (m_deliverPackets == false) return false;
431
422 OutgoingPacket packet; 432 OutgoingPacket packet;
423 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; 433 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue;
424 TokenBucket bucket; 434 TokenBucket bucket;
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index ca5a297..209e35c 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -904,7 +904,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
904 client.DisableFacelights = m_disableFacelights; 904 client.DisableFacelights = m_disableFacelights;
905 905
906 // Start the IClientAPI 906 // Start the IClientAPI
907 client.Start(); 907 // Spin it off so that it doesn't clog up the LLUDPServer
908
909 //First, and very importantly:
910 //
911 //Set our DeliverPackets flag in the client to *false*
912 //this will prevent us from missing important messages
913 //before the modules are bound
914 client.DeliverPackets = false;
915 client.DisableFacelights = m_disableFacelights;
916
917 Util.FireAndForget(
918 delegate
919 {
920 try
921 {
922 client.Start();
923 }
924 finally
925 {
926 //Now, release the hounds. er, packets.
927 client.DeliverPackets = true;
928 }
929 }
930 );
908 } 931 }
909 else 932 else
910 { 933 {
@@ -920,7 +943,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
920 if (m_scene.TryGetClient(udpClient.AgentID, out client)) 943 if (m_scene.TryGetClient(udpClient.AgentID, out client))
921 { 944 {
922 client.IsLoggingOut = true; 945 client.IsLoggingOut = true;
923 client.Close(); 946 client.Close(false);
924 } 947 }
925 } 948 }
926 949
diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
index bdbd284..91e3d20 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
@@ -133,7 +133,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
133 this.parent = parent; 133 this.parent = parent;
134 MaxBurst = maxBurst; 134 MaxBurst = maxBurst;
135 DripRate = dripRate; 135 DripRate = dripRate;
136 lastDrip = Environment.TickCount & Int32.MaxValue; 136 lastDrip = Environment.TickCount;
137 } 137 }
138 138
139 /// <summary> 139 /// <summary>
@@ -144,40 +144,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
144 /// the bucket, otherwise false</returns> 144 /// the bucket, otherwise false</returns>
145 public bool RemoveTokens(int amount) 145 public bool RemoveTokens(int amount)
146 { 146 {
147 bool dummy;
148 return RemoveTokens(amount, out dummy);
149 }
150
151 /// <summary>
152 /// Remove a given number of tokens from the bucket
153 /// </summary>
154 /// <param name="amount">Number of tokens to remove from the bucket</param>
155 /// <param name="dripSucceeded">True if tokens were added to the bucket
156 /// during this call, otherwise false</param>
157 /// <returns>True if the requested number of tokens were removed from
158 /// the bucket, otherwise false</returns>
159 public bool RemoveTokens(int amount, out bool dripSucceeded)
160 {
161 if (maxBurst == 0) 147 if (maxBurst == 0)
162 { 148 {
163 dripSucceeded = true;
164 return true; 149 return true;
165 } 150 }
166 151
167 dripSucceeded = Drip(); 152 if (amount > maxBurst)
168
169 if (content - amount >= 0)
170 { 153 {
171 if (parent != null && !parent.RemoveTokens(amount)) 154 throw new Exception("amount " + amount + " exceeds maxBurst " + maxBurst);
172 return false; 155 }
173 156
174 content -= amount; 157 Drip();
175 return true; 158
159 if (content < amount)
160 {
161 return false;
176 } 162 }
177 else 163
164 if (parent != null && !parent.RemoveTokens(amount))
178 { 165 {
179 return false; 166 return false;
180 } 167 }
168
169 content -= amount;
170 return true;
181 } 171 }
182 172
183 /// <summary> 173 /// <summary>
@@ -193,25 +183,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
193 content = maxBurst; 183 content = maxBurst;
194 return true; 184 return true;
195 } 185 }
196 else
197 {
198 int now = Environment.TickCount & Int32.MaxValue;
199 int deltaMS = now - lastDrip;
200 186
201 if (deltaMS <= 0) 187 int now = Environment.TickCount;
202 { 188 int deltaMS = now - lastDrip;
203 if (deltaMS < 0) 189 lastDrip = now;
204 lastDrip = now;
205 return false;
206 }
207 190
208 int dripAmount = deltaMS * tokensPerMS; 191 if (deltaMS <= 0)
209 192 {
210 content = Math.Min(content + dripAmount, maxBurst); 193 return false;
211 lastDrip = now; 194 }
212 195
213 return true; 196 long dripAmount = (long)deltaMS * (long)tokensPerMS + (long)content;
197 if (dripAmount > maxBurst)
198 {
199 dripAmount = maxBurst;
214 } 200 }
201 content = (int)dripAmount;
202 return true;
215 } 203 }
216 } 204 }
217} 205}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
index e43f7cf..c120a12 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
@@ -1,169 +1,184 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright 9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Net; 30using System.Net;
31using OpenMetaverse; 31using OpenMetaverse;
32 32
33namespace OpenSim.Region.ClientStack.LindenUDP 33namespace OpenSim.Region.ClientStack.LindenUDP
34{ 34{
35 /// <summary> 35 /// <summary>
36 /// Special collection that is optimized for tracking unacknowledged packets 36 /// Special collection that is optimized for tracking unacknowledged packets
37 /// </summary> 37 /// </summary>
38 public sealed class UnackedPacketCollection 38 public sealed class UnackedPacketCollection
39 { 39 {
40 /// <summary> 40 /// <summary>
41 /// Holds information about a pending acknowledgement 41 /// Holds information about a pending acknowledgement
42 /// </summary> 42 /// </summary>
43 private struct PendingAck 43 private struct PendingAck
44 { 44 {
45 /// <summary>Sequence number of the packet to remove</summary> 45 /// <summary>Sequence number of the packet to remove</summary>
46 public uint SequenceNumber; 46 public uint SequenceNumber;
47 /// <summary>Environment.TickCount value when the remove was queued. 47 /// <summary>Environment.TickCount value when the remove was queued.
48 /// This is used to update round-trip times for packets</summary> 48 /// This is used to update round-trip times for packets</summary>
49 public int RemoveTime; 49 public int RemoveTime;
50 /// <summary>Whether or not this acknowledgement was attached to a 50 /// <summary>Whether or not this acknowledgement was attached to a
51 /// resent packet. If so, round-trip time will not be calculated</summary> 51 /// resent packet. If so, round-trip time will not be calculated</summary>
52 public bool FromResend; 52 public bool FromResend;
53 53
54 public PendingAck(uint sequenceNumber, int currentTime, bool fromResend) 54 public PendingAck(uint sequenceNumber, int currentTime, bool fromResend)
55 { 55 {
56 SequenceNumber = sequenceNumber; 56 SequenceNumber = sequenceNumber;
57 RemoveTime = currentTime; 57 RemoveTime = currentTime;
58 FromResend = fromResend; 58 FromResend = fromResend;
59 } 59 }
60 } 60 }
61 61
62 /// <summary>Holds the actual unacked packet data, sorted by sequence number</summary> 62 /// <summary>Holds the actual unacked packet data, sorted by sequence number</summary>
63 private Dictionary<uint, OutgoingPacket> m_packets = new Dictionary<uint, OutgoingPacket>(); 63 private Dictionary<uint, OutgoingPacket> m_packets = new Dictionary<uint, OutgoingPacket>();
64 /// <summary>Holds packets that need to be added to the unacknowledged list</summary> 64 /// <summary>Holds packets that need to be added to the unacknowledged list</summary>
65 private LocklessQueue<OutgoingPacket> m_pendingAdds = new LocklessQueue<OutgoingPacket>(); 65 private LocklessQueue<OutgoingPacket> m_pendingAdds = new LocklessQueue<OutgoingPacket>();
66 /// <summary>Holds information about pending acknowledgements</summary> 66 /// <summary>Holds information about pending acknowledgements</summary>
67 private LocklessQueue<PendingAck> m_pendingRemoves = new LocklessQueue<PendingAck>(); 67 private LocklessQueue<PendingAck> m_pendingRemoves = new LocklessQueue<PendingAck>();
68 68
69 /// <summary> 69 /// <summary>
70 /// Add an unacked packet to the collection 70 /// Add an unacked packet to the collection
71 /// </summary> 71 /// </summary>
72 /// <param name="packet">Packet that is awaiting acknowledgement</param> 72 /// <param name="packet">Packet that is awaiting acknowledgement</param>
73 /// <returns>True if the packet was successfully added, false if the 73 /// <returns>True if the packet was successfully added, false if the
74 /// packet already existed in the collection</returns> 74 /// packet already existed in the collection</returns>
75 /// <remarks>This does not immediately add the ACK to the collection, 75 /// <remarks>This does not immediately add the ACK to the collection,
76 /// it only queues it so it can be added in a thread-safe way later</remarks> 76 /// it only queues it so it can be added in a thread-safe way later</remarks>
77 public void Add(OutgoingPacket packet) 77 public void Add(OutgoingPacket packet)
78 { 78 {
79 m_pendingAdds.Enqueue(packet); 79 m_pendingAdds.Enqueue(packet);
80 } 80 }
81 81
82 /// <summary> 82 /// <summary>
83 /// Marks a packet as acknowledged 83 /// Marks a packet as acknowledged
84 /// </summary> 84 /// </summary>
85 /// <param name="sequenceNumber">Sequence number of the packet to 85 /// <param name="sequenceNumber">Sequence number of the packet to
86 /// acknowledge</param> 86 /// acknowledge</param>
87 /// <param name="currentTime">Current value of Environment.TickCount</param> 87 /// <param name="currentTime">Current value of Environment.TickCount</param>
88 /// <remarks>This does not immediately acknowledge the packet, it only 88 /// <remarks>This does not immediately acknowledge the packet, it only
89 /// queues the ack so it can be handled in a thread-safe way later</remarks> 89 /// queues the ack so it can be handled in a thread-safe way later</remarks>
90 public void Remove(uint sequenceNumber, int currentTime, bool fromResend) 90 public void Remove(uint sequenceNumber, int currentTime, bool fromResend)
91 { 91 {
92 m_pendingRemoves.Enqueue(new PendingAck(sequenceNumber, currentTime, fromResend)); 92 m_pendingRemoves.Enqueue(new PendingAck(sequenceNumber, currentTime, fromResend));
93 } 93 }
94 94
95 /// <summary> 95 /// <summary>
96 /// Returns a list of all of the packets with a TickCount older than 96 /// Returns a list of all of the packets with a TickCount older than
97 /// the specified timeout 97 /// the specified timeout
98 /// </summary> 98 /// </summary>
99 /// <param name="timeoutMS">Number of ticks (milliseconds) before a 99 /// <param name="timeoutMS">Number of ticks (milliseconds) before a
100 /// packet is considered expired</param> 100 /// packet is considered expired</param>
101 /// <returns>A list of all expired packets according to the given 101 /// <returns>A list of all expired packets according to the given
102 /// expiration timeout</returns> 102 /// expiration timeout</returns>
103 /// <remarks>This function is not thread safe, and cannot be called 103 /// <remarks>This function is not thread safe, and cannot be called
104 /// multiple times concurrently</remarks> 104 /// multiple times concurrently</remarks>
105 public List<OutgoingPacket> GetExpiredPackets(int timeoutMS) 105 public List<OutgoingPacket> GetExpiredPackets(int timeoutMS)
106 { 106 {
107 ProcessQueues(); 107 ProcessQueues();
108 108
109 List<OutgoingPacket> expiredPackets = null; 109 List<OutgoingPacket> expiredPackets = null;
110 110
111 if (m_packets.Count > 0) 111 if (m_packets.Count > 0)
112 { 112 {
113 int now = Environment.TickCount & Int32.MaxValue; 113 int now = Environment.TickCount & Int32.MaxValue;
114 114
115 foreach (OutgoingPacket packet in m_packets.Values) 115 foreach (OutgoingPacket packet in m_packets.Values)
116 { 116 {
117 // TickCount of zero means a packet is in the resend queue 117 // TickCount of zero means a packet is in the resend queue
118 // but hasn't actually been sent over the wire yet 118 // but hasn't actually been sent over the wire yet
119 if (packet.TickCount == 0) 119 if (packet.TickCount == 0)
120 continue; 120 continue;
121 121
122 if (now - packet.TickCount >= timeoutMS) 122 if (now - packet.TickCount >= timeoutMS)
123 { 123 {
124 if (expiredPackets == null) 124 if (expiredPackets == null)
125 expiredPackets = new List<OutgoingPacket>(); 125 expiredPackets = new List<OutgoingPacket>();
126 126
127 // The TickCount will be set to the current time when the packet 127 // The TickCount will be set to the current time when the packet
128 // is actually sent out again 128 // is actually sent out again
129 packet.TickCount = 0; 129 packet.TickCount = 0;
130 130
131 expiredPackets.Add(packet); 131 expiredPackets.Add(packet);
132 } 132 }
133 } 133 }
134 } 134 }
135 135
136 return expiredPackets; 136 return expiredPackets;
137 } 137 }
138 138
139 private void ProcessQueues() 139 private void ProcessQueues()
140 { 140 {
141 // Process all the pending adds 141 // Process all the pending adds
142 OutgoingPacket pendingAdd; 142
143 while (m_pendingAdds.Dequeue(out pendingAdd)) 143 OutgoingPacket pendingAdd;
144 m_packets[pendingAdd.SequenceNumber] = pendingAdd; 144 if (m_pendingAdds != null)
145 145 {
146 // Process all the pending removes, including updating statistics and round-trip times 146 while (m_pendingAdds.Dequeue(out pendingAdd))
147 PendingAck pendingRemove; 147 {
148 OutgoingPacket ackedPacket; 148 if (pendingAdd != null && m_packets != null)
149 while (m_pendingRemoves.Dequeue(out pendingRemove)) 149 {
150 { 150 m_packets[pendingAdd.SequenceNumber] = pendingAdd;
151 if (m_packets.TryGetValue(pendingRemove.SequenceNumber, out ackedPacket)) 151 }
152 { 152 }
153 m_packets.Remove(pendingRemove.SequenceNumber); 153 }
154 154
155 // Update stats 155 // Process all the pending removes, including updating statistics and round-trip times
156 System.Threading.Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength); 156 PendingAck pendingRemove;
157 157 OutgoingPacket ackedPacket;
158 if (!pendingRemove.FromResend) 158 if (m_pendingRemoves != null)
159 { 159 {
160 // Calculate the round-trip time for this packet and its ACK 160 while (m_pendingRemoves.Dequeue(out pendingRemove))
161 int rtt = pendingRemove.RemoveTime - ackedPacket.TickCount; 161 {
162 if (rtt > 0) 162 if (m_pendingRemoves != null && m_packets != null)
163 ackedPacket.Client.UpdateRoundTrip(rtt); 163 {
164 } 164 if (m_packets.TryGetValue(pendingRemove.SequenceNumber, out ackedPacket))
165 } 165 {
166 } 166 m_packets.Remove(pendingRemove.SequenceNumber);
167 } 167
168 } 168 // Update stats
169} 169 System.Threading.Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength);
170
171 if (!pendingRemove.FromResend)
172 {
173 // Calculate the round-trip time for this packet and its ACK
174 int rtt = pendingRemove.RemoveTime - ackedPacket.TickCount;
175 if (rtt > 0)
176 ackedPacket.Client.UpdateRoundTrip(rtt);
177 }
178 }
179 }
180 }
181 }
182 }
183 }
184}