aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
authorMelanie2009-10-15 21:14:13 +0100
committerMelanie2009-10-15 21:14:13 +0100
commit6deef7d0f3e9657bdc7bc4c41011dba15fea944b (patch)
treeffa84d5963afbb5390b132278c95df20b21681d5 /OpenSim/Region
parentMerge branch 'master' into vehicles (diff)
parentMerge branch 'htb-throttle' of ssh://opensimulator.org/var/git/opensim into h... (diff)
downloadopensim-SC-6deef7d0f3e9657bdc7bc4c41011dba15fea944b.zip
opensim-SC-6deef7d0f3e9657bdc7bc4c41011dba15fea944b.tar.gz
opensim-SC-6deef7d0f3e9657bdc7bc4c41011dba15fea944b.tar.bz2
opensim-SC-6deef7d0f3e9657bdc7bc4c41011dba15fea944b.tar.xz
Merge branch 'master' into vehicles
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/Application/OpenSim.cs24
-rw-r--r--OpenSim/Region/Application/OpenSimBackground.cs1
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs39
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs668
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs76
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs242
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs282
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs420
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs520
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs97
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs9
-rw-r--r--OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs307
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs18
-rw-r--r--OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs4
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs44
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs1
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/BaseInventoryConnector.cs3
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Land/RegionCombinerModule.cs10
-rw-r--r--OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs7
-rw-r--r--OpenSim/Region/Framework/Interfaces/IHyperService.cs37
-rw-r--r--OpenSim/Region/Framework/Scenes/Hypergrid/HGAssetMapper.cs98
-rw-r--r--OpenSim/Region/Framework/Scenes/Hypergrid/HGScene.Inventory.cs26
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs9
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs26
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs230
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneBase.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs28
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs15
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneBaseTests.cs5
-rw-r--r--OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/IRCStackModule.cs1
-rw-r--r--OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs8
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs10
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs14
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs1
-rw-r--r--OpenSim/Region/Physics/Meshing/PrimMesher.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs10
38 files changed, 1650 insertions, 1648 deletions
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs
index 4d8409bb..ca6a2a3 100644
--- a/OpenSim/Region/Application/OpenSim.cs
+++ b/OpenSim/Region/Application/OpenSim.cs
@@ -239,6 +239,10 @@ namespace OpenSim
239 "show users [full]", 239 "show users [full]",
240 "Show user data", HandleShow); 240 "Show user data", HandleShow);
241 241
242 m_console.Commands.AddCommand("region", false, "show connections",
243 "show connections",
244 "Show connection data", HandleShow);
245
242 m_console.Commands.AddCommand("region", false, "show users full", 246 m_console.Commands.AddCommand("region", false, "show users full",
243 "show users full", 247 "show users full",
244 String.Empty, HandleShow); 248 String.Empty, HandleShow);
@@ -921,7 +925,25 @@ namespace OpenSim
921 regionName)); 925 regionName));
922 } 926 }
923 927
924 m_log.Info(""); 928 m_log.Info(String.Empty);
929 break;
930
931 case "connections":
932 System.Text.StringBuilder connections = new System.Text.StringBuilder("Connections:\n");
933 m_sceneManager.ForEachScene(
934 delegate(Scene scene)
935 {
936 scene.ClientManager.ForEachSync(
937 delegate(IClientAPI client)
938 {
939 connections.AppendFormat("{0}: {1} ({2}) from {3} on circuit {4}\n",
940 scene.RegionInfo.RegionName, client.Name, client.AgentId, client.RemoteEndPoint, client.CircuitCode);
941 }
942 );
943 }
944 );
945
946 m_log.Info(connections.ToString());
925 break; 947 break;
926 948
927 case "modules": 949 case "modules":
diff --git a/OpenSim/Region/Application/OpenSimBackground.cs b/OpenSim/Region/Application/OpenSimBackground.cs
index ac5e241..008c6b0 100644
--- a/OpenSim/Region/Application/OpenSimBackground.cs
+++ b/OpenSim/Region/Application/OpenSimBackground.cs
@@ -58,6 +58,7 @@ namespace OpenSim
58 m_clientServers.Count.ToString(), m_clientServers.Count > 1 ? "s" : ""); 58 m_clientServers.Count.ToString(), m_clientServers.Count > 1 ? "s" : "");
59 59
60 WorldHasComeToAnEnd.WaitOne(); 60 WorldHasComeToAnEnd.WaitOne();
61 WorldHasComeToAnEnd.Close();
61 } 62 }
62 63
63 /// <summary> 64 /// <summary>
diff --git a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
index 5877779..b53a2fb 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
@@ -31,6 +31,7 @@ using OpenMetaverse;
31using OpenMetaverse.Imaging; 31using OpenMetaverse.Imaging;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Framework.Interfaces; 33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes.Hypergrid;
34using OpenSim.Services.Interfaces; 35using OpenSim.Services.Interfaces;
35using log4net; 36using log4net;
36using System.Reflection; 37using System.Reflection;
@@ -54,6 +55,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
54 public UUID TextureID; 55 public UUID TextureID;
55 public IJ2KDecoder J2KDecoder; 56 public IJ2KDecoder J2KDecoder;
56 public IAssetService AssetService; 57 public IAssetService AssetService;
58 public UUID AgentID;
59 public IHyperAssetService HyperAssets;
57 public OpenJPEG.J2KLayerInfo[] Layers; 60 public OpenJPEG.J2KLayerInfo[] Layers;
58 public bool IsDecoded; 61 public bool IsDecoded;
59 public bool HasAsset; 62 public bool HasAsset;
@@ -72,14 +75,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
72 m_imageManager = imageManager; 75 m_imageManager = imageManager;
73 } 76 }
74 77
75 public bool SendPackets(LLClientView client, int maxpack) 78 /// <summary>
79 /// Sends packets for this texture to a client until packetsToSend is
80 /// hit or the transfer completes
81 /// </summary>
82 /// <param name="client">Reference to the client that the packets are destined for</param>
83 /// <param name="packetsToSend">Maximum number of packets to send during this call</param>
84 /// <param name="packetsSent">Number of packets sent during this call</param>
85 /// <returns>True if the transfer completes at the current discard level, otherwise false</returns>
86 public bool SendPackets(LLClientView client, int packetsToSend, out int packetsSent)
76 { 87 {
77 if (client == null) 88 packetsSent = 0;
78 return false;
79 89
80 if (m_currentPacket <= m_stopPacket) 90 if (m_currentPacket <= m_stopPacket)
81 { 91 {
82 int count = 0;
83 bool sendMore = true; 92 bool sendMore = true;
84 93
85 if (!m_sentInfo || (m_currentPacket == 0)) 94 if (!m_sentInfo || (m_currentPacket == 0))
@@ -88,25 +97,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
88 97
89 m_sentInfo = true; 98 m_sentInfo = true;
90 ++m_currentPacket; 99 ++m_currentPacket;
91 ++count; 100 ++packetsSent;
92 } 101 }
93 if (m_currentPacket < 2) 102 if (m_currentPacket < 2)
94 { 103 {
95 m_currentPacket = 2; 104 m_currentPacket = 2;
96 } 105 }
97 106
98 while (sendMore && count < maxpack && m_currentPacket <= m_stopPacket) 107 while (sendMore && packetsSent < packetsToSend && m_currentPacket <= m_stopPacket)
99 { 108 {
100 sendMore = SendPacket(client); 109 sendMore = SendPacket(client);
101 ++m_currentPacket; 110 ++m_currentPacket;
102 ++count; 111 ++packetsSent;
103 } 112 }
104
105 if (m_currentPacket > m_stopPacket)
106 return true;
107 } 113 }
108 114
109 return false; 115 return (m_currentPacket > m_stopPacket);
110 } 116 }
111 117
112 public void RunUpdate() 118 public void RunUpdate()
@@ -370,6 +376,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
370 UUID assetID = UUID.Zero; 376 UUID assetID = UUID.Zero;
371 if (asset != null) 377 if (asset != null)
372 assetID = asset.FullID; 378 assetID = asset.FullID;
379 else if ((HyperAssets != null) && (sender != HyperAssets))
380 {
381 // Try the user's inventory, but only if it's different from the regions'
382 string userAssets = HyperAssets.GetUserAssetServer(AgentID);
383 if ((userAssets != string.Empty) && (userAssets != HyperAssets.GetSimAssetServer()))
384 {
385 m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", id);
386 AssetService.Get(userAssets + "/" + id, HyperAssets, AssetReceived);
387 return;
388 }
389 }
373 390
374 AssetDataCallback(assetID, asset); 391 AssetDataCallback(assetID, asset);
375 392
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 84e705a..8487adc 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -43,6 +43,7 @@ using OpenSim.Framework.Communications.Cache;
43using OpenSim.Framework.Statistics; 43using OpenSim.Framework.Statistics;
44using OpenSim.Region.Framework.Interfaces; 44using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Region.Framework.Scenes; 45using OpenSim.Region.Framework.Scenes;
46using OpenSim.Region.Framework.Scenes.Hypergrid;
46using OpenSim.Services.Interfaces; 47using OpenSim.Services.Interfaces;
47using Timer=System.Timers.Timer; 48using Timer=System.Timers.Timer;
48using AssetLandmark = OpenSim.Framework.AssetLandmark; 49using AssetLandmark = OpenSim.Framework.AssetLandmark;
@@ -58,6 +59,209 @@ namespace OpenSim.Region.ClientStack.LindenUDP
58 /// </summary> 59 /// </summary>
59 public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientIPEndpoint, IStatsCollector 60 public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientIPEndpoint, IStatsCollector
60 { 61 {
62 #region Events
63
64 public event GenericMessage OnGenericMessage;
65 public event BinaryGenericMessage OnBinaryGenericMessage;
66 public event Action<IClientAPI> OnLogout;
67 public event ObjectPermissions OnObjectPermissions;
68 public event Action<IClientAPI> OnConnectionClosed;
69 public event ViewerEffectEventHandler OnViewerEffect;
70 public event ImprovedInstantMessage OnInstantMessage;
71 public event ChatMessage OnChatFromClient;
72 public event TextureRequest OnRequestTexture;
73 public event RezObject OnRezObject;
74 public event DeRezObject OnDeRezObject;
75 public event ModifyTerrain OnModifyTerrain;
76 public event Action<IClientAPI> OnRegionHandShakeReply;
77 public event GenericCall2 OnRequestWearables;
78 public event SetAppearance OnSetAppearance;
79 public event AvatarNowWearing OnAvatarNowWearing;
80 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv;
81 public event RezMultipleAttachmentsFromInv OnRezMultipleAttachmentsFromInv;
82 public event UUIDNameRequest OnDetachAttachmentIntoInv;
83 public event ObjectAttach OnObjectAttach;
84 public event ObjectDeselect OnObjectDetach;
85 public event ObjectDrop OnObjectDrop;
86 public event GenericCall2 OnCompleteMovementToRegion;
87 public event UpdateAgent OnAgentUpdate;
88 public event AgentRequestSit OnAgentRequestSit;
89 public event AgentSit OnAgentSit;
90 public event AvatarPickerRequest OnAvatarPickerRequest;
91 public event StartAnim OnStartAnim;
92 public event StopAnim OnStopAnim;
93 public event Action<IClientAPI> OnRequestAvatarsData;
94 public event LinkObjects OnLinkObjects;
95 public event DelinkObjects OnDelinkObjects;
96 public event GrabObject OnGrabObject;
97 public event DeGrabObject OnDeGrabObject;
98 public event SpinStart OnSpinStart;
99 public event SpinStop OnSpinStop;
100 public event ObjectDuplicate OnObjectDuplicate;
101 public event ObjectDuplicateOnRay OnObjectDuplicateOnRay;
102 public event MoveObject OnGrabUpdate;
103 public event SpinObject OnSpinUpdate;
104 public event AddNewPrim OnAddPrim;
105 public event RequestGodlikePowers OnRequestGodlikePowers;
106 public event GodKickUser OnGodKickUser;
107 public event ObjectExtraParams OnUpdateExtraParams;
108 public event UpdateShape OnUpdatePrimShape;
109 public event ObjectRequest OnObjectRequest;
110 public event ObjectSelect OnObjectSelect;
111 public event ObjectDeselect OnObjectDeselect;
112 public event GenericCall7 OnObjectDescription;
113 public event GenericCall7 OnObjectName;
114 public event GenericCall7 OnObjectClickAction;
115 public event GenericCall7 OnObjectMaterial;
116 public event ObjectIncludeInSearch OnObjectIncludeInSearch;
117 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily;
118 public event UpdatePrimFlags OnUpdatePrimFlags;
119 public event UpdatePrimTexture OnUpdatePrimTexture;
120 public event UpdateVector OnUpdatePrimGroupPosition;
121 public event UpdateVector OnUpdatePrimSinglePosition;
122 public event UpdatePrimRotation OnUpdatePrimGroupRotation;
123 public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation;
124 public event UpdatePrimSingleRotationPosition OnUpdatePrimSingleRotationPosition;
125 public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation;
126 public event UpdateVector OnUpdatePrimScale;
127 public event UpdateVector OnUpdatePrimGroupScale;
128 public event StatusChange OnChildAgentStatus;
129 public event GenericCall2 OnStopMovement;
130 public event Action<UUID> OnRemoveAvatar;
131 public event RequestMapBlocks OnRequestMapBlocks;
132 public event RequestMapName OnMapNameRequest;
133 public event TeleportLocationRequest OnTeleportLocationRequest;
134 public event TeleportLandmarkRequest OnTeleportLandmarkRequest;
135 public event DisconnectUser OnDisconnectUser;
136 public event RequestAvatarProperties OnRequestAvatarProperties;
137 public event SetAlwaysRun OnSetAlwaysRun;
138 public event FetchInventory OnAgentDataUpdateRequest;
139 public event TeleportLocationRequest OnSetStartLocationRequest;
140 public event UpdateAvatarProperties OnUpdateAvatarProperties;
141 public event CreateNewInventoryItem OnCreateNewInventoryItem;
142 public event CreateInventoryFolder OnCreateNewInventoryFolder;
143 public event UpdateInventoryFolder OnUpdateInventoryFolder;
144 public event MoveInventoryFolder OnMoveInventoryFolder;
145 public event FetchInventoryDescendents OnFetchInventoryDescendents;
146 public event PurgeInventoryDescendents OnPurgeInventoryDescendents;
147 public event FetchInventory OnFetchInventory;
148 public event RequestTaskInventory OnRequestTaskInventory;
149 public event UpdateInventoryItem OnUpdateInventoryItem;
150 public event CopyInventoryItem OnCopyInventoryItem;
151 public event MoveInventoryItem OnMoveInventoryItem;
152 public event RemoveInventoryItem OnRemoveInventoryItem;
153 public event RemoveInventoryFolder OnRemoveInventoryFolder;
154 public event UDPAssetUploadRequest OnAssetUploadRequest;
155 public event XferReceive OnXferReceive;
156 public event RequestXfer OnRequestXfer;
157 public event ConfirmXfer OnConfirmXfer;
158 public event AbortXfer OnAbortXfer;
159 public event RequestTerrain OnRequestTerrain;
160 public event RezScript OnRezScript;
161 public event UpdateTaskInventory OnUpdateTaskInventory;
162 public event MoveTaskInventory OnMoveTaskItem;
163 public event RemoveTaskInventory OnRemoveTaskItem;
164 public event RequestAsset OnRequestAsset;
165 public event UUIDNameRequest OnNameFromUUIDRequest;
166 public event ParcelAccessListRequest OnParcelAccessListRequest;
167 public event ParcelAccessListUpdateRequest OnParcelAccessListUpdateRequest;
168 public event ParcelPropertiesRequest OnParcelPropertiesRequest;
169 public event ParcelDivideRequest OnParcelDivideRequest;
170 public event ParcelJoinRequest OnParcelJoinRequest;
171 public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest;
172 public event ParcelSelectObjects OnParcelSelectObjects;
173 public event ParcelObjectOwnerRequest OnParcelObjectOwnerRequest;
174 public event ParcelAbandonRequest OnParcelAbandonRequest;
175 public event ParcelGodForceOwner OnParcelGodForceOwner;
176 public event ParcelReclaim OnParcelReclaim;
177 public event ParcelReturnObjectsRequest OnParcelReturnObjectsRequest;
178 public event ParcelDeedToGroup OnParcelDeedToGroup;
179 public event RegionInfoRequest OnRegionInfoRequest;
180 public event EstateCovenantRequest OnEstateCovenantRequest;
181 public event FriendActionDelegate OnApproveFriendRequest;
182 public event FriendActionDelegate OnDenyFriendRequest;
183 public event FriendshipTermination OnTerminateFriendship;
184 public event MoneyTransferRequest OnMoneyTransferRequest;
185 public event EconomyDataRequest OnEconomyDataRequest;
186 public event MoneyBalanceRequest OnMoneyBalanceRequest;
187 public event ParcelBuy OnParcelBuy;
188 public event UUIDNameRequest OnTeleportHomeRequest;
189 public event UUIDNameRequest OnUUIDGroupNameRequest;
190 public event ScriptAnswer OnScriptAnswer;
191 public event RequestPayPrice OnRequestPayPrice;
192 public event ObjectSaleInfo OnObjectSaleInfo;
193 public event ObjectBuy OnObjectBuy;
194 public event BuyObjectInventory OnBuyObjectInventory;
195 public event AgentSit OnUndo;
196 public event ForceReleaseControls OnForceReleaseControls;
197 public event GodLandStatRequest OnLandStatRequest;
198 public event RequestObjectPropertiesFamily OnObjectGroupRequest;
199 public event DetailedEstateDataRequest OnDetailedEstateDataRequest;
200 public event SetEstateFlagsRequest OnSetEstateFlagsRequest;
201 public event SetEstateTerrainBaseTexture OnSetEstateTerrainBaseTexture;
202 public event SetEstateTerrainDetailTexture OnSetEstateTerrainDetailTexture;
203 public event SetEstateTerrainTextureHeights OnSetEstateTerrainTextureHeights;
204 public event CommitEstateTerrainTextureRequest OnCommitEstateTerrainTextureRequest;
205 public event SetRegionTerrainSettings OnSetRegionTerrainSettings;
206 public event BakeTerrain OnBakeTerrain;
207 public event RequestTerrain OnUploadTerrain;
208 public event EstateChangeInfo OnEstateChangeInfo;
209 public event EstateRestartSimRequest OnEstateRestartSimRequest;
210 public event EstateChangeCovenantRequest OnEstateChangeCovenantRequest;
211 public event UpdateEstateAccessDeltaRequest OnUpdateEstateAccessDeltaRequest;
212 public event SimulatorBlueBoxMessageRequest OnSimulatorBlueBoxMessageRequest;
213 public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest;
214 public event EstateDebugRegionRequest OnEstateDebugRegionRequest;
215 public event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest;
216 public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest;
217 public event RegionHandleRequest OnRegionHandleRequest;
218 public event ParcelInfoRequest OnParcelInfoRequest;
219 public event ScriptReset OnScriptReset;
220 public event GetScriptRunning OnGetScriptRunning;
221 public event SetScriptRunning OnSetScriptRunning;
222 public event UpdateVector OnAutoPilotGo;
223 public event TerrainUnacked OnUnackedTerrain;
224 public event ActivateGesture OnActivateGesture;
225 public event DeactivateGesture OnDeactivateGesture;
226 public event ObjectOwner OnObjectOwner;
227 public event DirPlacesQuery OnDirPlacesQuery;
228 public event DirFindQuery OnDirFindQuery;
229 public event DirLandQuery OnDirLandQuery;
230 public event DirPopularQuery OnDirPopularQuery;
231 public event DirClassifiedQuery OnDirClassifiedQuery;
232 public event EventInfoRequest OnEventInfoRequest;
233 public event ParcelSetOtherCleanTime OnParcelSetOtherCleanTime;
234 public event MapItemRequest OnMapItemRequest;
235 public event OfferCallingCard OnOfferCallingCard;
236 public event AcceptCallingCard OnAcceptCallingCard;
237 public event DeclineCallingCard OnDeclineCallingCard;
238 public event SoundTrigger OnSoundTrigger;
239 public event StartLure OnStartLure;
240 public event TeleportLureRequest OnTeleportLureRequest;
241 public event NetworkStats OnNetworkStatsUpdate;
242 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
243 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
244 public event ClassifiedDelete OnClassifiedDelete;
245 public event ClassifiedDelete OnClassifiedGodDelete;
246 public event EventNotificationAddRequest OnEventNotificationAddRequest;
247 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
248 public event EventGodDelete OnEventGodDelete;
249 public event ParcelDwellRequest OnParcelDwellRequest;
250 public event UserInfoRequest OnUserInfoRequest;
251 public event UpdateUserInfo OnUpdateUserInfo;
252 public event RetrieveInstantMessages OnRetrieveInstantMessages;
253 public event PickDelete OnPickDelete;
254 public event PickGodDelete OnPickGodDelete;
255 public event PickInfoUpdate OnPickInfoUpdate;
256 public event AvatarNotesUpdate OnAvatarNotesUpdate;
257 public event MuteListRequest OnMuteListRequest;
258 public event AvatarInterestUpdate OnAvatarInterestUpdate;
259 public event PlacesQuery OnPlacesQuery;
260
261 #endregion Events
262
263 #region Class Members
264
61 // LLClientView Only 265 // LLClientView Only
62 public delegate void BinaryGenericMessage(Object sender, string method, byte[][] args); 266 public delegate void BinaryGenericMessage(Object sender, string method, byte[][] args);
63 267
@@ -110,15 +314,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
110 protected int m_primFullUpdatesPerPacket = 14; 314 protected int m_primFullUpdatesPerPacket = 14;
111 protected int m_primTerseUpdateRate = 10; 315 protected int m_primTerseUpdateRate = 10;
112 protected int m_primFullUpdateRate = 14; 316 protected int m_primFullUpdateRate = 14;
113 protected int m_textureSendLimit = 20;
114 protected int m_textureDataLimit = 10;
115 protected int m_avatarTerseUpdateRate = 50; 317 protected int m_avatarTerseUpdateRate = 50;
116 protected int m_avatarTerseUpdatesPerPacket = 5; 318 protected int m_avatarTerseUpdatesPerPacket = 5;
117 protected int m_packetMTU = 1400; 319 /// <summary>Number of texture packets to put on the queue each time the
320 /// OnQueueEmpty event is triggered for the texture category</summary>
321 protected int m_textureSendLimit = 20;
118 protected IAssetService m_assetService; 322 protected IAssetService m_assetService;
323 private IHyperAssetService m_hyperAssets;
324
325
326 #endregion Class Members
119 327
120 #region Properties 328 #region Properties
121 329
330 public LLUDPClient UDPClient { get { return m_udpClient; } }
331 public IPEndPoint RemoteEndPoint { get { return m_udpClient.RemoteEndPoint; } }
122 public UUID SecureSessionId { get { return m_secureSessionId; } } 332 public UUID SecureSessionId { get { return m_secureSessionId; } }
123 public IScene Scene { get { return m_scene; } } 333 public IScene Scene { get { return m_scene; } }
124 public UUID SessionId { get { return m_sessionId; } } 334 public UUID SessionId { get { return m_sessionId; } }
@@ -170,6 +380,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
170 380
171 m_scene = scene; 381 m_scene = scene;
172 m_assetService = m_scene.RequestModuleInterface<IAssetService>(); 382 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
383 m_hyperAssets = m_scene.RequestModuleInterface<IHyperAssetService>();
173 m_GroupsModule = scene.RequestModuleInterface<IGroupsModule>(); 384 m_GroupsModule = scene.RequestModuleInterface<IGroupsModule>();
174 m_imageManager = new LLImageManager(this, m_assetService, Scene.RequestModuleInterface<IJ2KDecoder>()); 385 m_imageManager = new LLImageManager(this, m_assetService, Scene.RequestModuleInterface<IJ2KDecoder>());
175 m_channelVersion = Utils.StringToBytes(scene.GetSimulatorVersion()); 386 m_channelVersion = Utils.StringToBytes(scene.GetSimulatorVersion());
@@ -198,51 +409,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
198 #region Client Methods 409 #region Client Methods
199 410
200 /// <summary> 411 /// <summary>
201 /// Close down the client view. This *must* be the last method called, since the last # 412 /// Shut down the client view
202 /// statement of CloseCleanup() aborts the thread.
203 /// </summary> 413 /// </summary>
204 /// <param name="shutdownCircuit"></param> 414 public void Close()
205 public void Close(bool shutdownCircuit)
206 { 415 {
207 m_log.DebugFormat( 416 m_log.DebugFormat(
208 "[CLIENT]: Close has been called with shutdownCircuit = {0} for {1} attached to scene {2}", 417 "[CLIENT]: Close has been called for {0} attached to scene {1}",
209 shutdownCircuit, Name, m_scene.RegionInfo.RegionName); 418 Name, m_scene.RegionInfo.RegionName);
419
420 // Send the STOP packet
421 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
422 OutPacket(disable, ThrottleOutPacketType.Unknown);
423
424 IsActive = false;
210 425
426 // Shutdown the image manager
211 if (m_imageManager != null) 427 if (m_imageManager != null)
212 m_imageManager.Close(); 428 m_imageManager.Close();
213 429
430 // Fire the callback for this connection closing
431 if (OnConnectionClosed != null)
432 OnConnectionClosed(this);
433
434 // Flush all of the packets out of the UDP server for this client
214 if (m_udpServer != null) 435 if (m_udpServer != null)
215 m_udpServer.Flush(); 436 m_udpServer.Flush(m_udpClient);
216
217 // raise an event on the packet server to Shutdown the circuit
218 // Now, if we raise the event then the packet server will call this method itself, so don't try cleanup
219 // here otherwise we'll end up calling it twice.
220 // FIXME: In truth, I might be wrong but this whole business of calling this method twice (with different args) looks
221 // horribly tangly. Hopefully it should be possible to greatly simplify it.
222 if (shutdownCircuit)
223 {
224 if (OnConnectionClosed != null)
225 OnConnectionClosed(this);
226 }
227 else
228 {
229 CloseCleanup(shutdownCircuit);
230 }
231 }
232 437
233 private void CloseCleanup(bool shutdownCircuit) 438 // Remove ourselves from the scene
234 {
235 m_scene.RemoveClient(AgentId); 439 m_scene.RemoveClient(AgentId);
236 440
237 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false));
238 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true));
239
240 // Send the STOP packet
241 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
242 OutPacket(disable, ThrottleOutPacketType.Unknown);
243
244 Thread.Sleep(2000);
245
246 // Shut down timers. Thread Context of this method is murky. Lock all timers 441 // Shut down timers. Thread Context of this method is murky. Lock all timers
247 if (m_avatarTerseUpdateTimer.Enabled) 442 if (m_avatarTerseUpdateTimer.Enabled)
248 lock (m_avatarTerseUpdateTimer) 443 lock (m_avatarTerseUpdateTimer)
@@ -254,43 +449,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
254 lock (m_primFullUpdateTimer) 449 lock (m_primFullUpdateTimer)
255 m_primFullUpdateTimer.Stop(); 450 m_primFullUpdateTimer.Stop();
256 451
257 // This is just to give the client a reasonable chance of
258 // flushing out all it's packets. There should probably
259 // be a better mechanism here
260
261 // We can't reach into other scenes and close the connection 452 // We can't reach into other scenes and close the connection
262 // We need to do this over grid communications 453 // We need to do this over grid communications
263 //m_scene.CloseAllAgents(CircuitCode); 454 //m_scene.CloseAllAgents(CircuitCode);
264 455
265 // If we're not shutting down the circuit, then this is the last time we'll go here. 456 m_avatarTerseUpdateTimer.Dispose();
266 // If we are shutting down the circuit, the UDP Server will come back here with 457 m_primTerseUpdateTimer.Dispose();
267 // ShutDownCircuit = false 458 m_primFullUpdateTimer.Dispose();
268 if (!(shutdownCircuit))
269 {
270 GC.Collect();
271 m_imageManager = null;
272 // Sends a KillPacket object, with which, the
273 // blockingqueue dequeues and sees it's a killpacket
274 // and terminates within the context of the client thread.
275 // This ensures that it's done from within the context
276 // of the client thread regardless of where Close() is called.
277 KillEndDone();
278 }
279
280 IsActive = false;
281
282 m_avatarTerseUpdateTimer.Close();
283 m_primTerseUpdateTimer.Close();
284 m_primFullUpdateTimer.Close();
285 459
286 //m_udpServer.OnPacketStats -= PopulateStats; 460 // Disable UDP handling for this client
287 m_udpClient.Shutdown(); 461 m_udpClient.Shutdown();
288 462
289 // wait for thread stoped 463 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false));
290 // m_clientThread.Join(); 464 //GC.Collect();
291 465 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true));
292 // delete circuit code
293 //m_networkServer.CloseClient(this);
294 } 466 }
295 467
296 public void Kick(string message) 468 public void Kick(string message)
@@ -412,43 +584,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
412 return result; 584 return result;
413 } 585 }
414 586
415 /*protected void DebugPacket(string direction, Packet packet)
416 {
417 string info;
418
419 if (m_debugPacketLevel < 255 && packet.Type == PacketType.AgentUpdate)
420 return;
421 if (m_debugPacketLevel < 254 && packet.Type == PacketType.ViewerEffect)
422 return;
423 if (m_debugPacketLevel < 253 && (
424 packet.Type == PacketType.CompletePingCheck ||
425 packet.Type == PacketType.StartPingCheck
426 ))
427 return;
428 if (m_debugPacketLevel < 252 && packet.Type == PacketType.PacketAck)
429 return;
430
431 if (m_debugPacketLevel > 1)
432 {
433 info = packet.ToString();
434 }
435 else
436 {
437 info = packet.Type.ToString();
438 }
439
440 Console.WriteLine(m_circuitCode + ":" + direction + ": " + info);
441 }*/
442
443 #endregion Packet Handling 587 #endregion Packet Handling
444 588
445 # region Setup 589 # region Setup
446 590
447 /// <summary> 591 public virtual void Start()
448 /// Starts up the timers to check the client and resend unacked packets
449 /// Adds the client to the OpenSim.Region.Framework.Scenes.Scene
450 /// </summary>
451 protected virtual void InitNewClient()
452 { 592 {
453 m_avatarTerseUpdateTimer = new Timer(m_avatarTerseUpdateRate); 593 m_avatarTerseUpdateTimer = new Timer(m_avatarTerseUpdateRate);
454 m_avatarTerseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessAvatarTerseUpdates); 594 m_avatarTerseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessAvatarTerseUpdates);
@@ -467,262 +607,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
467 RefreshGroupMembership(); 607 RefreshGroupMembership();
468 } 608 }
469 609
470 public virtual void Start()
471 {
472 // This sets up all the timers
473 InitNewClient();
474 }
475
476 /// <summary>
477 /// Run a user session. This method lies at the base of the entire client thread.
478 /// </summary>
479 protected void RunUserSession()
480 {
481 try
482 {
483
484 }
485 catch (Exception e)
486 {
487 if (e is ThreadAbortException)
488 throw;
489
490 if (StatsManager.SimExtraStats != null)
491 StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
492
493 // Don't let a failure in an individual client thread crash the whole sim.
494 m_log.ErrorFormat(
495 "[CLIENT]: Client thread for {0} {1} crashed. Logging them out.", Name, AgentId);
496 m_log.Error(e.ToString());
497
498 try
499 {
500 // Make an attempt to alert the user that their session has crashed
501 AgentAlertMessagePacket packet
502 = BuildAgentAlertPacket(
503 "Unfortunately the session for this client on the server has crashed.\n"
504 + "Any further actions taken will not be processed.\n"
505 + "Please relog", true);
506
507 m_udpServer.SendPacket(m_agentId, packet, ThrottleOutPacketType.Unknown, false);
508
509 // There may be a better way to do this. Perhaps kick? Not sure this propogates notifications to
510 // listeners yet, though.
511 Logout(this);
512 }
513 catch (Exception e2)
514 {
515 if (e2 is ThreadAbortException)
516 throw;
517
518 m_log.ErrorFormat("[CLIENT]: Further exception thrown on forced session logout. {0}", e2);
519 }
520 }
521 }
522
523 # endregion 610 # endregion
524 611
525 #region Events
526
527 public event GenericMessage OnGenericMessage;
528 public event BinaryGenericMessage OnBinaryGenericMessage;
529 public event Action<IClientAPI> OnLogout;
530 public event ObjectPermissions OnObjectPermissions;
531 public event Action<IClientAPI> OnConnectionClosed;
532 public event ViewerEffectEventHandler OnViewerEffect;
533 public event ImprovedInstantMessage OnInstantMessage;
534 public event ChatMessage OnChatFromClient;
535 public event TextureRequest OnRequestTexture;
536 public event RezObject OnRezObject;
537 public event DeRezObject OnDeRezObject;
538 public event ModifyTerrain OnModifyTerrain;
539 public event Action<IClientAPI> OnRegionHandShakeReply;
540 public event GenericCall2 OnRequestWearables;
541 public event SetAppearance OnSetAppearance;
542 public event AvatarNowWearing OnAvatarNowWearing;
543 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv;
544 public event RezMultipleAttachmentsFromInv OnRezMultipleAttachmentsFromInv;
545 public event UUIDNameRequest OnDetachAttachmentIntoInv;
546 public event ObjectAttach OnObjectAttach;
547 public event ObjectDeselect OnObjectDetach;
548 public event ObjectDrop OnObjectDrop;
549 public event GenericCall2 OnCompleteMovementToRegion;
550 public event UpdateAgent OnAgentUpdate;
551 public event AgentRequestSit OnAgentRequestSit;
552 public event AgentSit OnAgentSit;
553 public event AvatarPickerRequest OnAvatarPickerRequest;
554 public event StartAnim OnStartAnim;
555 public event StopAnim OnStopAnim;
556 public event Action<IClientAPI> OnRequestAvatarsData;
557 public event LinkObjects OnLinkObjects;
558 public event DelinkObjects OnDelinkObjects;
559 public event GrabObject OnGrabObject;
560 public event DeGrabObject OnDeGrabObject;
561 public event SpinStart OnSpinStart;
562 public event SpinStop OnSpinStop;
563 public event ObjectDuplicate OnObjectDuplicate;
564 public event ObjectDuplicateOnRay OnObjectDuplicateOnRay;
565 public event MoveObject OnGrabUpdate;
566 public event SpinObject OnSpinUpdate;
567 public event AddNewPrim OnAddPrim;
568 public event RequestGodlikePowers OnRequestGodlikePowers;
569 public event GodKickUser OnGodKickUser;
570 public event ObjectExtraParams OnUpdateExtraParams;
571 public event UpdateShape OnUpdatePrimShape;
572 public event ObjectRequest OnObjectRequest;
573 public event ObjectSelect OnObjectSelect;
574 public event ObjectDeselect OnObjectDeselect;
575 public event GenericCall7 OnObjectDescription;
576 public event GenericCall7 OnObjectName;
577 public event GenericCall7 OnObjectClickAction;
578 public event GenericCall7 OnObjectMaterial;
579 public event ObjectIncludeInSearch OnObjectIncludeInSearch;
580 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily;
581 public event UpdatePrimFlags OnUpdatePrimFlags;
582 public event UpdatePrimTexture OnUpdatePrimTexture;
583 public event UpdateVector OnUpdatePrimGroupPosition;
584 public event UpdateVector OnUpdatePrimSinglePosition;
585 public event UpdatePrimRotation OnUpdatePrimGroupRotation;
586 public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation;
587 public event UpdatePrimSingleRotationPosition OnUpdatePrimSingleRotationPosition;
588 public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation;
589 public event UpdateVector OnUpdatePrimScale;
590 public event UpdateVector OnUpdatePrimGroupScale;
591 public event StatusChange OnChildAgentStatus;
592 public event GenericCall2 OnStopMovement;
593 public event Action<UUID> OnRemoveAvatar;
594 public event RequestMapBlocks OnRequestMapBlocks;
595 public event RequestMapName OnMapNameRequest;
596 public event TeleportLocationRequest OnTeleportLocationRequest;
597 public event TeleportLandmarkRequest OnTeleportLandmarkRequest;
598 public event DisconnectUser OnDisconnectUser;
599 public event RequestAvatarProperties OnRequestAvatarProperties;
600 public event SetAlwaysRun OnSetAlwaysRun;
601 public event FetchInventory OnAgentDataUpdateRequest;
602 public event TeleportLocationRequest OnSetStartLocationRequest;
603 public event UpdateAvatarProperties OnUpdateAvatarProperties;
604 public event CreateNewInventoryItem OnCreateNewInventoryItem;
605 public event CreateInventoryFolder OnCreateNewInventoryFolder;
606 public event UpdateInventoryFolder OnUpdateInventoryFolder;
607 public event MoveInventoryFolder OnMoveInventoryFolder;
608 public event FetchInventoryDescendents OnFetchInventoryDescendents;
609 public event PurgeInventoryDescendents OnPurgeInventoryDescendents;
610 public event FetchInventory OnFetchInventory;
611 public event RequestTaskInventory OnRequestTaskInventory;
612 public event UpdateInventoryItem OnUpdateInventoryItem;
613 public event CopyInventoryItem OnCopyInventoryItem;
614 public event MoveInventoryItem OnMoveInventoryItem;
615 public event RemoveInventoryItem OnRemoveInventoryItem;
616 public event RemoveInventoryFolder OnRemoveInventoryFolder;
617 public event UDPAssetUploadRequest OnAssetUploadRequest;
618 public event XferReceive OnXferReceive;
619 public event RequestXfer OnRequestXfer;
620 public event ConfirmXfer OnConfirmXfer;
621 public event AbortXfer OnAbortXfer;
622 public event RequestTerrain OnRequestTerrain;
623 public event RezScript OnRezScript;
624 public event UpdateTaskInventory OnUpdateTaskInventory;
625 public event MoveTaskInventory OnMoveTaskItem;
626 public event RemoveTaskInventory OnRemoveTaskItem;
627 public event RequestAsset OnRequestAsset;
628 public event UUIDNameRequest OnNameFromUUIDRequest;
629 public event ParcelAccessListRequest OnParcelAccessListRequest;
630 public event ParcelAccessListUpdateRequest OnParcelAccessListUpdateRequest;
631 public event ParcelPropertiesRequest OnParcelPropertiesRequest;
632 public event ParcelDivideRequest OnParcelDivideRequest;
633 public event ParcelJoinRequest OnParcelJoinRequest;
634 public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest;
635 public event ParcelSelectObjects OnParcelSelectObjects;
636 public event ParcelObjectOwnerRequest OnParcelObjectOwnerRequest;
637 public event ParcelAbandonRequest OnParcelAbandonRequest;
638 public event ParcelGodForceOwner OnParcelGodForceOwner;
639 public event ParcelReclaim OnParcelReclaim;
640 public event ParcelReturnObjectsRequest OnParcelReturnObjectsRequest;
641 public event ParcelDeedToGroup OnParcelDeedToGroup;
642 public event RegionInfoRequest OnRegionInfoRequest;
643 public event EstateCovenantRequest OnEstateCovenantRequest;
644 public event FriendActionDelegate OnApproveFriendRequest;
645 public event FriendActionDelegate OnDenyFriendRequest;
646 public event FriendshipTermination OnTerminateFriendship;
647 public event MoneyTransferRequest OnMoneyTransferRequest;
648 public event EconomyDataRequest OnEconomyDataRequest;
649 public event MoneyBalanceRequest OnMoneyBalanceRequest;
650 public event ParcelBuy OnParcelBuy;
651 public event UUIDNameRequest OnTeleportHomeRequest;
652 public event UUIDNameRequest OnUUIDGroupNameRequest;
653 public event ScriptAnswer OnScriptAnswer;
654 public event RequestPayPrice OnRequestPayPrice;
655 public event ObjectSaleInfo OnObjectSaleInfo;
656 public event ObjectBuy OnObjectBuy;
657 public event BuyObjectInventory OnBuyObjectInventory;
658 public event AgentSit OnUndo;
659 public event ForceReleaseControls OnForceReleaseControls;
660 public event GodLandStatRequest OnLandStatRequest;
661 public event RequestObjectPropertiesFamily OnObjectGroupRequest;
662 public event DetailedEstateDataRequest OnDetailedEstateDataRequest;
663 public event SetEstateFlagsRequest OnSetEstateFlagsRequest;
664 public event SetEstateTerrainBaseTexture OnSetEstateTerrainBaseTexture;
665 public event SetEstateTerrainDetailTexture OnSetEstateTerrainDetailTexture;
666 public event SetEstateTerrainTextureHeights OnSetEstateTerrainTextureHeights;
667 public event CommitEstateTerrainTextureRequest OnCommitEstateTerrainTextureRequest;
668 public event SetRegionTerrainSettings OnSetRegionTerrainSettings;
669 public event BakeTerrain OnBakeTerrain;
670 public event RequestTerrain OnUploadTerrain;
671 public event EstateChangeInfo OnEstateChangeInfo;
672 public event EstateRestartSimRequest OnEstateRestartSimRequest;
673 public event EstateChangeCovenantRequest OnEstateChangeCovenantRequest;
674 public event UpdateEstateAccessDeltaRequest OnUpdateEstateAccessDeltaRequest;
675 public event SimulatorBlueBoxMessageRequest OnSimulatorBlueBoxMessageRequest;
676 public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest;
677 public event EstateDebugRegionRequest OnEstateDebugRegionRequest;
678 public event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest;
679 public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest;
680 public event RegionHandleRequest OnRegionHandleRequest;
681 public event ParcelInfoRequest OnParcelInfoRequest;
682 public event ScriptReset OnScriptReset;
683 public event GetScriptRunning OnGetScriptRunning;
684 public event SetScriptRunning OnSetScriptRunning;
685 public event UpdateVector OnAutoPilotGo;
686 public event TerrainUnacked OnUnackedTerrain;
687 public event ActivateGesture OnActivateGesture;
688 public event DeactivateGesture OnDeactivateGesture;
689 public event ObjectOwner OnObjectOwner;
690 public event DirPlacesQuery OnDirPlacesQuery;
691 public event DirFindQuery OnDirFindQuery;
692 public event DirLandQuery OnDirLandQuery;
693 public event DirPopularQuery OnDirPopularQuery;
694 public event DirClassifiedQuery OnDirClassifiedQuery;
695 public event EventInfoRequest OnEventInfoRequest;
696 public event ParcelSetOtherCleanTime OnParcelSetOtherCleanTime;
697 public event MapItemRequest OnMapItemRequest;
698 public event OfferCallingCard OnOfferCallingCard;
699 public event AcceptCallingCard OnAcceptCallingCard;
700 public event DeclineCallingCard OnDeclineCallingCard;
701 public event SoundTrigger OnSoundTrigger;
702 public event StartLure OnStartLure;
703 public event TeleportLureRequest OnTeleportLureRequest;
704 public event NetworkStats OnNetworkStatsUpdate;
705 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
706 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
707 public event ClassifiedDelete OnClassifiedDelete;
708 public event ClassifiedDelete OnClassifiedGodDelete;
709 public event EventNotificationAddRequest OnEventNotificationAddRequest;
710 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
711 public event EventGodDelete OnEventGodDelete;
712 public event ParcelDwellRequest OnParcelDwellRequest;
713 public event UserInfoRequest OnUserInfoRequest;
714 public event UpdateUserInfo OnUpdateUserInfo;
715 public event RetrieveInstantMessages OnRetrieveInstantMessages;
716 public event PickDelete OnPickDelete;
717 public event PickGodDelete OnPickGodDelete;
718 public event PickInfoUpdate OnPickInfoUpdate;
719 public event AvatarNotesUpdate OnAvatarNotesUpdate;
720 public event MuteListRequest OnMuteListRequest;
721 public event AvatarInterestUpdate OnAvatarInterestUpdate;
722 public event PlacesQuery OnPlacesQuery;
723
724 #endregion Events
725
726 public void ActivateGesture(UUID assetId, UUID gestureId) 612 public void ActivateGesture(UUID assetId, UUID gestureId)
727 { 613 {
728 } 614 }
@@ -1342,7 +1228,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1342 kill.ObjectData[0].ID = localID; 1228 kill.ObjectData[0].ID = localID;
1343 kill.Header.Reliable = true; 1229 kill.Header.Reliable = true;
1344 kill.Header.Zerocoded = true; 1230 kill.Header.Zerocoded = true;
1345 OutPacket(kill, ThrottleOutPacketType.Task); 1231 OutPacket(kill, ThrottleOutPacketType.State);
1346 } 1232 }
1347 1233
1348 /// <summary> 1234 /// <summary>
@@ -1936,7 +1822,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1936 sendXfer.XferID.ID = xferID; 1822 sendXfer.XferID.ID = xferID;
1937 sendXfer.XferID.Packet = packet; 1823 sendXfer.XferID.Packet = packet;
1938 sendXfer.DataPacket.Data = data; 1824 sendXfer.DataPacket.Data = data;
1939 OutPacket(sendXfer, ThrottleOutPacketType.Task); 1825 OutPacket(sendXfer, ThrottleOutPacketType.Asset);
1940 } 1826 }
1941 1827
1942 public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit, 1828 public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit,
@@ -2218,7 +2104,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2218 packet.AgentData.SessionID = SessionId; 2104 packet.AgentData.SessionID = SessionId;
2219 packet.Header.Reliable = false; 2105 packet.Header.Reliable = false;
2220 packet.Header.Zerocoded = true; 2106 packet.Header.Zerocoded = true;
2221 OutPacket(packet, ThrottleOutPacketType.Task); 2107 OutPacket(packet, ThrottleOutPacketType.State);
2222 } 2108 }
2223 2109
2224 public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, 2110 public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember,
@@ -3241,7 +3127,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3241 3127
3242 avp.Sender.IsTrial = false; 3128 avp.Sender.IsTrial = false;
3243 avp.Sender.ID = agentID; 3129 avp.Sender.ID = agentID;
3244 OutPacket(avp, ThrottleOutPacketType.Task); 3130 OutPacket(avp, ThrottleOutPacketType.State);
3245 } 3131 }
3246 3132
3247 public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) 3133 public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs)
@@ -3366,7 +3252,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3366 int length = 0; 3252 int length = 0;
3367 m_avatarTerseUpdates[count].ToBytes(blockbuffer, ref length); 3253 m_avatarTerseUpdates[count].ToBytes(blockbuffer, ref length);
3368 length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); 3254 length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer);
3369 if (size + length > m_packetMTU) 3255 if (size + length > Packet.MTU)
3370 break; 3256 break;
3371 size += length; 3257 size += length;
3372 } 3258 }
@@ -3381,6 +3267,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3381 3267
3382 terse.Header.Reliable = false; 3268 terse.Header.Reliable = false;
3383 terse.Header.Zerocoded = true; 3269 terse.Header.Zerocoded = true;
3270 // FIXME: Move this to ThrottleOutPacketType.State when the real prioritization code is committed
3384 OutPacket(terse, ThrottleOutPacketType.Task); 3271 OutPacket(terse, ThrottleOutPacketType.Task);
3385 3272
3386 if (m_avatarTerseUpdates.Count == 0) 3273 if (m_avatarTerseUpdates.Count == 0)
@@ -3571,7 +3458,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3571 void ProcessTextureRequests() 3458 void ProcessTextureRequests()
3572 { 3459 {
3573 if (m_imageManager != null) 3460 if (m_imageManager != null)
3574 m_imageManager.ProcessImageQueue(m_textureSendLimit, m_textureDataLimit); 3461 m_imageManager.ProcessImageQueue(m_textureSendLimit);
3575 } 3462 }
3576 3463
3577 void ProcessPrimFullUpdates(object sender, ElapsedEventArgs e) 3464 void ProcessPrimFullUpdates(object sender, ElapsedEventArgs e)
@@ -3610,7 +3497,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3610 int length = 0; 3497 int length = 0;
3611 m_primFullUpdates[count].ToBytes(blockbuffer, ref length); 3498 m_primFullUpdates[count].ToBytes(blockbuffer, ref length);
3612 length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); 3499 length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer);
3613 if (size + length > m_packetMTU) 3500 if (size + length > Packet.MTU)
3614 break; 3501 break;
3615 size += length; 3502 size += length;
3616 } 3503 }
@@ -3625,7 +3512,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3625 } 3512 }
3626 3513
3627 outPacket.Header.Zerocoded = true; 3514 outPacket.Header.Zerocoded = true;
3628 OutPacket(outPacket, ThrottleOutPacketType.Task); 3515 OutPacket(outPacket, ThrottleOutPacketType.State);
3629 3516
3630 if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled) 3517 if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled)
3631 lock (m_primFullUpdateTimer) 3518 lock (m_primFullUpdateTimer)
@@ -3698,7 +3585,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3698 int length = 0; 3585 int length = 0;
3699 m_primTerseUpdates[count].ToBytes(blockbuffer, ref length); 3586 m_primTerseUpdates[count].ToBytes(blockbuffer, ref length);
3700 length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); 3587 length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer);
3701 if (size + length > m_packetMTU) 3588 if (size + length > Packet.MTU)
3702 break; 3589 break;
3703 size += length; 3590 size += length;
3704 } 3591 }
@@ -3715,7 +3602,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3715 3602
3716 outPacket.Header.Reliable = false; 3603 outPacket.Header.Reliable = false;
3717 outPacket.Header.Zerocoded = true; 3604 outPacket.Header.Zerocoded = true;
3718 OutPacket(outPacket, ThrottleOutPacketType.Task); 3605 OutPacket(outPacket, ThrottleOutPacketType.State);
3719 3606
3720 if (m_primTerseUpdates.Count == 0) 3607 if (m_primTerseUpdates.Count == 0)
3721 lock (m_primTerseUpdateTimer) 3608 lock (m_primTerseUpdateTimer)
@@ -4801,7 +4688,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4801 4688
4802 public bool HandleObjectGroupRequest(IClientAPI sender, Packet Pack) 4689 public bool HandleObjectGroupRequest(IClientAPI sender, Packet Pack)
4803 { 4690 {
4804
4805 ObjectGroupPacket ogpack = (ObjectGroupPacket)Pack; 4691 ObjectGroupPacket ogpack = (ObjectGroupPacket)Pack;
4806 if (ogpack.AgentData.SessionID != SessionId) return false; 4692 if (ogpack.AgentData.SessionID != SessionId) return false;
4807 4693
@@ -7013,7 +6899,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7013 #endregion 6899 #endregion
7014 6900
7015 //handlerTextureRequest = null; 6901 //handlerTextureRequest = null;
7016
7017 for (int i = 0; i < imageRequest.RequestImage.Length; i++) 6902 for (int i = 0; i < imageRequest.RequestImage.Length; i++)
7018 { 6903 {
7019 if (OnRequestTexture != null) 6904 if (OnRequestTexture != null)
@@ -7024,7 +6909,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7024 args.PacketNumber = imageRequest.RequestImage[i].Packet; 6909 args.PacketNumber = imageRequest.RequestImage[i].Packet;
7025 args.Priority = imageRequest.RequestImage[i].DownloadPriority; 6910 args.Priority = imageRequest.RequestImage[i].DownloadPriority;
7026 args.requestSequence = imageRequest.Header.Sequence; 6911 args.requestSequence = imageRequest.Header.Sequence;
7027
7028 //handlerTextureRequest = OnRequestTexture; 6912 //handlerTextureRequest = OnRequestTexture;
7029 6913
7030 //if (handlerTextureRequest != null) 6914 //if (handlerTextureRequest != null)
@@ -7047,10 +6931,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7047 // Validate inventory transfers 6931 // Validate inventory transfers
7048 // Has to be done here, because AssetCache can't do it 6932 // Has to be done here, because AssetCache can't do it
7049 // 6933 //
7050 6934 UUID taskID = UUID.Zero;
7051 if (transfer.TransferInfo.SourceType == 3) 6935 if (transfer.TransferInfo.SourceType == 3)
7052 { 6936 {
7053 UUID taskID = new UUID(transfer.TransferInfo.Params, 48); 6937 taskID = new UUID(transfer.TransferInfo.Params, 48);
7054 UUID itemID = new UUID(transfer.TransferInfo.Params, 64); 6938 UUID itemID = new UUID(transfer.TransferInfo.Params, 64);
7055 UUID requestID = new UUID(transfer.TransferInfo.Params, 80); 6939 UUID requestID = new UUID(transfer.TransferInfo.Params, 80);
7056 if (!(((Scene)m_scene).Permissions.BypassPermissions())) 6940 if (!(((Scene)m_scene).Permissions.BypassPermissions()))
@@ -7121,7 +7005,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7121 7005
7122 //m_assetCache.AddAssetRequest(this, transfer); 7006 //m_assetCache.AddAssetRequest(this, transfer);
7123 7007
7124 MakeAssetRequest(transfer); 7008 MakeAssetRequest(transfer, taskID);
7125 7009
7126 /* RequestAsset = OnRequestAsset; 7010 /* RequestAsset = OnRequestAsset;
7127 if (RequestAsset != null) 7011 if (RequestAsset != null)
@@ -10250,7 +10134,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10250 10134
10251 public void KillEndDone() 10135 public void KillEndDone()
10252 { 10136 {
10253 m_udpClient.Shutdown();
10254 } 10137 }
10255 10138
10256 #region IClientCore 10139 #region IClientCore
@@ -10293,15 +10176,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10293 { 10176 {
10294 Kick(reason); 10177 Kick(reason);
10295 Thread.Sleep(1000); 10178 Thread.Sleep(1000);
10296 Close(true); 10179 Close();
10297 } 10180 }
10298 10181
10299 public void Disconnect() 10182 public void Disconnect()
10300 { 10183 {
10301 Close(true); 10184 Close();
10302 } 10185 }
10303 10186
10304
10305 #endregion 10187 #endregion
10306 10188
10307 public void RefreshGroupMembership() 10189 public void RefreshGroupMembership()
@@ -10330,7 +10212,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10330 return String.Empty; 10212 return String.Empty;
10331 } 10213 }
10332 10214
10333 public void MakeAssetRequest(TransferRequestPacket transferRequest) 10215 public void MakeAssetRequest(TransferRequestPacket transferRequest, UUID taskID)
10334 { 10216 {
10335 UUID requestID = UUID.Zero; 10217 UUID requestID = UUID.Zero;
10336 if (transferRequest.TransferInfo.SourceType == 2) 10218 if (transferRequest.TransferInfo.SourceType == 2)
@@ -10342,12 +10224,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10342 { 10224 {
10343 //inventory asset request 10225 //inventory asset request
10344 requestID = new UUID(transferRequest.TransferInfo.Params, 80); 10226 requestID = new UUID(transferRequest.TransferInfo.Params, 80);
10345 //m_log.Debug("asset request " + requestID); 10227 //m_log.Debug("[XXX] inventory asset request " + requestID);
10228 //if (taskID == UUID.Zero) // Agent
10229 // if (m_scene is HGScene)
10230 // {
10231 // m_log.Debug("[XXX] hg asset request " + requestID);
10232 // // We may need to fetch the asset from the user's asset server into the local asset server
10233 // HGAssetMapper mapper = ((HGScene)m_scene).AssetMapper;
10234 // mapper.Get(requestID, AgentId);
10235 // }
10346 } 10236 }
10347 10237
10348 //check to see if asset is in local cache, if not we need to request it from asset server. 10238 //check to see if asset is in local cache, if not we need to request it from asset server.
10349 //m_log.Debug("asset request " + requestID); 10239 //m_log.Debug("asset request " + requestID);
10350 10240
10351 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 10241 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
10352 10242
10353 } 10243 }
@@ -10358,12 +10248,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10358 10248
10359 UUID requestID = UUID.Zero; 10249 UUID requestID = UUID.Zero;
10360 byte source = 2; 10250 byte source = 2;
10361 if (transferRequest.TransferInfo.SourceType == 2) 10251 if ((transferRequest.TransferInfo.SourceType == 2) || (transferRequest.TransferInfo.SourceType == 2222))
10362 { 10252 {
10363 //direct asset request 10253 //direct asset request
10364 requestID = new UUID(transferRequest.TransferInfo.Params, 0); 10254 requestID = new UUID(transferRequest.TransferInfo.Params, 0);
10365 } 10255 }
10366 else if (transferRequest.TransferInfo.SourceType == 3) 10256 else if ((transferRequest.TransferInfo.SourceType == 3) || (transferRequest.TransferInfo.SourceType == 3333))
10367 { 10257 {
10368 //inventory asset request 10258 //inventory asset request
10369 requestID = new UUID(transferRequest.TransferInfo.Params, 80); 10259 requestID = new UUID(transferRequest.TransferInfo.Params, 80);
@@ -10371,10 +10261,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10371 //m_log.Debug("asset request " + requestID); 10261 //m_log.Debug("asset request " + requestID);
10372 } 10262 }
10373 10263
10374 // FIXME: We never tell the client about assets which do not exist when requested by this transfer mechanism, which can't be right.
10375 if (null == asset) 10264 if (null == asset)
10376 { 10265 {
10266 if ((m_hyperAssets != null) && (transferRequest.TransferInfo.SourceType < 2000))
10267 {
10268 // Try the user's inventory, but only if it's different from the regions'
10269 string userAssets = m_hyperAssets.GetUserAssetServer(AgentId);
10270 if ((userAssets != string.Empty) && (userAssets != m_hyperAssets.GetSimAssetServer()))
10271 {
10272 m_log.DebugFormat("[CLIENT]: asset {0} not found in local asset storage. Trying user's storage.", id);
10273 if (transferRequest.TransferInfo.SourceType == 2)
10274 transferRequest.TransferInfo.SourceType = 2222; // marker
10275 else if (transferRequest.TransferInfo.SourceType == 3)
10276 transferRequest.TransferInfo.SourceType = 3333; // marker
10277
10278 m_assetService.Get(userAssets + "/" + id, transferRequest, AssetReceived);
10279 return;
10280 }
10281 }
10282
10377 //m_log.DebugFormat("[ASSET CACHE]: Asset transfer request for asset which is {0} already known to be missing. Dropping", requestID); 10283 //m_log.DebugFormat("[ASSET CACHE]: Asset transfer request for asset which is {0} already known to be missing. Dropping", requestID);
10284
10285 // FIXME: We never tell the client about assets which do not exist when requested by this transfer mechanism, which can't be right.
10378 return; 10286 return;
10379 } 10287 }
10380 10288
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs
index 343f537..d25bf95 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs
@@ -59,6 +59,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
59 private C5.IntervalHeap<J2KImage> m_priorityQueue = new C5.IntervalHeap<J2KImage>(10, new J2KImageComparer()); 59 private C5.IntervalHeap<J2KImage> m_priorityQueue = new C5.IntervalHeap<J2KImage>(10, new J2KImageComparer());
60 private object m_syncRoot = new object(); 60 private object m_syncRoot = new object();
61 61
62 private IHyperAssetService m_hyperAssets;
63
62 public LLClientView Client { get { return m_client; } } 64 public LLClientView Client { get { return m_client; } }
63 public AssetBase MissingImage { get { return m_missingImage; } } 65 public AssetBase MissingImage { get { return m_missingImage; } }
64 66
@@ -74,6 +76,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
74 m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client"); 76 m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client");
75 77
76 m_j2kDecodeModule = pJ2kDecodeModule; 78 m_j2kDecodeModule = pJ2kDecodeModule;
79 m_hyperAssets = client.Scene.RequestModuleInterface<IHyperAssetService>();
77 } 80 }
78 81
79 /// <summary> 82 /// <summary>
@@ -146,6 +149,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
146 imgrequest = new J2KImage(this); 149 imgrequest = new J2KImage(this);
147 imgrequest.J2KDecoder = m_j2kDecodeModule; 150 imgrequest.J2KDecoder = m_j2kDecodeModule;
148 imgrequest.AssetService = m_assetCache; 151 imgrequest.AssetService = m_assetCache;
152 imgrequest.AgentID = m_client.AgentId;
153 imgrequest.HyperAssets = m_hyperAssets;
149 imgrequest.DiscardLevel = newRequest.DiscardLevel; 154 imgrequest.DiscardLevel = newRequest.DiscardLevel;
150 imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber); 155 imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber);
151 imgrequest.Priority = newRequest.Priority; 156 imgrequest.Priority = newRequest.Priority;
@@ -162,47 +167,48 @@ namespace OpenSim.Region.ClientStack.LindenUDP
162 } 167 }
163 } 168 }
164 169
165 public bool ProcessImageQueue(int count, int maxpack) 170 public bool ProcessImageQueue(int packetsToSend)
166 { 171 {
167 J2KImage imagereq; 172 m_lastloopprocessed = DateTime.Now.Ticks;
168 int numCollected = 0; 173 int packetsSent = 0;
169 174
170 //lock (m_syncRoot) 175 while (packetsSent < packetsToSend)
171 //{ 176 {
172 m_lastloopprocessed = DateTime.Now.Ticks; 177 J2KImage image = GetHighestPriorityImage();
173 178
174 // This can happen during Close() 179 // If null was returned, the texture priority queue is currently empty
175 if (m_client == null) 180 if (image == null)
176 return false; 181 return false;
177
178 while ((imagereq = GetHighestPriorityImage()) != null)
179 {
180 if (imagereq.IsDecoded == true)
181 {
182 ++numCollected;
183 182
184 if (imagereq.SendPackets(m_client, maxpack)) 183 if (image.IsDecoded)
185 { 184 {
186 // Send complete. Destroy any knowledge of this transfer 185 int sent;
187 RemoveImageFromQueue(imagereq); 186 bool imageDone = image.SendPackets(m_client, packetsToSend - packetsSent, out sent);
188 } 187 packetsSent += sent;
189 }
190 188
191 if (numCollected == count) 189 // If the send is complete, destroy any knowledge of this transfer
192 break; 190 if (imageDone)
191 RemoveImageFromQueue(image);
192 }
193 else
194 {
195 // TODO: This is a limitation of how LLImageManager is currently
196 // written. Undecoded textures should not be going into the priority
197 // queue, because a high priority undecoded texture will clog up the
198 // pipeline for a client
199 return true;
193 } 200 }
194 //} 201 }
195 202
196 return m_priorityQueue.Count > 0; 203 return m_priorityQueue.Count > 0;
197 } 204 }
198 205
199 //Faux destructor 206 /// <summary>
207 /// Faux destructor
208 /// </summary>
200 public void Close() 209 public void Close()
201 { 210 {
202 m_shuttingdown = true; 211 m_shuttingdown = true;
203 m_j2kDecodeModule = null;
204 m_assetCache = null;
205 m_client = null;
206 } 212 }
207 213
208 #region Priority Queue Helpers 214 #region Priority Queue Helpers
@@ -213,13 +219,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
213 219
214 lock (m_syncRoot) 220 lock (m_syncRoot)
215 { 221 {
216
217 if (m_priorityQueue.Count > 0) 222 if (m_priorityQueue.Count > 0)
218 { 223 {
219 try 224 try { image = m_priorityQueue.FindMax(); }
220 {
221 image = m_priorityQueue.FindMax();
222 }
223 catch (Exception) { } 225 catch (Exception) { }
224 } 226 }
225 } 227 }
@@ -231,20 +233,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
231 image.PriorityQueueHandle = null; 233 image.PriorityQueueHandle = null;
232 234
233 lock (m_syncRoot) 235 lock (m_syncRoot)
234 try 236 try { m_priorityQueue.Add(ref image.PriorityQueueHandle, image); }
235 {
236 m_priorityQueue.Add(ref image.PriorityQueueHandle, image);
237 }
238 catch (Exception) { } 237 catch (Exception) { }
239 } 238 }
240 239
241 void RemoveImageFromQueue(J2KImage image) 240 void RemoveImageFromQueue(J2KImage image)
242 { 241 {
243 lock (m_syncRoot) 242 lock (m_syncRoot)
244 try 243 try { m_priorityQueue.Delete(image.PriorityQueueHandle); }
245 {
246 m_priorityQueue.Delete(image.PriorityQueueHandle);
247 }
248 catch (Exception) { } 244 catch (Exception) { }
249 } 245 }
250 246
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
index 871e8e8..4eee6b6 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -28,8 +28,10 @@
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Net; 30using System.Net;
31using log4net;
31using OpenSim.Framework; 32using OpenSim.Framework;
32using OpenMetaverse; 33using OpenMetaverse;
34using OpenMetaverse.Packets;
33 35
34namespace OpenSim.Region.ClientStack.LindenUDP 36namespace OpenSim.Region.ClientStack.LindenUDP
35{ 37{
@@ -59,9 +61,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
59 /// </summary> 61 /// </summary>
60 public sealed class LLUDPClient 62 public sealed class LLUDPClient
61 { 63 {
64 // TODO: Make this a config setting
65 /// <summary>Percentage of the task throttle category that is allocated to avatar and prim
66 /// state updates</summary>
67 const float STATE_TASK_PERCENTAGE = 0.8f;
68
69 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
70
62 /// <summary>The number of packet categories to throttle on. If a throttle category is added 71 /// <summary>The number of packet categories to throttle on. If a throttle category is added
63 /// or removed, this number must also change</summary> 72 /// or removed, this number must also change</summary>
64 const int THROTTLE_CATEGORY_COUNT = 7; 73 const int THROTTLE_CATEGORY_COUNT = 8;
65 74
66 /// <summary>Fired when updated networking stats are produced for this client</summary> 75 /// <summary>Fired when updated networking stats are produced for this client</summary>
67 public event PacketStats OnPacketStats; 76 public event PacketStats OnPacketStats;
@@ -80,10 +89,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
80 /// <summary>Packets we have sent that need to be ACKed by the client</summary> 89 /// <summary>Packets we have sent that need to be ACKed by the client</summary>
81 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); 90 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection();
82 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> 91 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary>
83 public readonly LocklessQueue<uint> PendingAcks = new LocklessQueue<uint>(); 92 public readonly OpenSim.Framework.LocklessQueue<uint> PendingAcks = new OpenSim.Framework.LocklessQueue<uint>();
84 93
85 /// <summary>Reference to the IClientAPI for this client</summary>
86 public LLClientView ClientAPI;
87 /// <summary>Current packet sequence number</summary> 94 /// <summary>Current packet sequence number</summary>
88 public int CurrentSequence; 95 public int CurrentSequence;
89 /// <summary>Current ping sequence number</summary> 96 /// <summary>Current ping sequence number</summary>
@@ -123,21 +130,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
123 private int m_packetsSentReported; 130 private int m_packetsSentReported;
124 131
125 /// <summary>Throttle bucket for this agent's connection</summary> 132 /// <summary>Throttle bucket for this agent's connection</summary>
126 private readonly TokenBucket throttle; 133 private readonly TokenBucket m_throttle;
127 /// <summary>Throttle buckets for each packet category</summary> 134 /// <summary>Throttle buckets for each packet category</summary>
128 private readonly TokenBucket[] throttleCategories; 135 private readonly TokenBucket[] m_throttleCategories;
129 /// <summary>Throttle rate defaults and limits</summary> 136 /// <summary>Throttle rate defaults and limits</summary>
130 private readonly ThrottleRates defaultThrottleRates; 137 private readonly ThrottleRates m_defaultThrottleRates;
131 /// <summary>Outgoing queues for throttled packets</summary> 138 /// <summary>Outgoing queues for throttled packets</summary>
132 private readonly LocklessQueue<OutgoingPacket>[] packetOutboxes = new LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; 139 private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] m_packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT];
133 /// <summary>A container that can hold one packet for each outbox, used to store 140 /// <summary>A container that can hold one packet for each outbox, used to store
134 /// dequeued packets that are being held for throttling</summary> 141 /// dequeued packets that are being held for throttling</summary>
135 private readonly OutgoingPacket[] nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; 142 private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
136 /// <summary>An optimization to store the length of dequeued packets being held 143 /// <summary>Flags to prevent queue empty callbacks from stacking up on
137 /// for throttling. This avoids expensive calls to Packet.Length</summary> 144 /// top of each other</summary>
138 private readonly int[] nextPacketLengths = new int[THROTTLE_CATEGORY_COUNT]; 145 private readonly bool[] m_onQueueEmptyRunning = new bool[THROTTLE_CATEGORY_COUNT];
139 /// <summary>A reference to the LLUDPServer that is managing this client</summary> 146 /// <summary>A reference to the LLUDPServer that is managing this client</summary>
140 private readonly LLUDPServer udpServer; 147 private readonly LLUDPServer m_udpServer;
141 148
142 /// <summary> 149 /// <summary>
143 /// Default constructor 150 /// Default constructor
@@ -151,24 +158,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
151 /// <param name="remoteEndPoint">Remote endpoint for this connection</param> 158 /// <param name="remoteEndPoint">Remote endpoint for this connection</param>
152 public LLUDPClient(LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID, IPEndPoint remoteEndPoint) 159 public LLUDPClient(LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID, IPEndPoint remoteEndPoint)
153 { 160 {
154 udpServer = server;
155 AgentID = agentID; 161 AgentID = agentID;
156 RemoteEndPoint = remoteEndPoint; 162 RemoteEndPoint = remoteEndPoint;
157 CircuitCode = circuitCode; 163 CircuitCode = circuitCode;
158 defaultThrottleRates = rates; 164 m_udpServer = server;
165 m_defaultThrottleRates = rates;
166 m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total);
167 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
159 168
160 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) 169 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
161 packetOutboxes[i] = new LocklessQueue<OutgoingPacket>(); 170 {
162 171 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
163 throttle = new TokenBucket(parentThrottle, 0, 0); 172
164 throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; 173 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
165 throttleCategories[(int)ThrottleOutPacketType.Resend] = new TokenBucket(throttle, rates.ResendLimit, rates.Resend); 174 m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type));
166 throttleCategories[(int)ThrottleOutPacketType.Land] = new TokenBucket(throttle, rates.LandLimit, rates.Land); 175 }
167 throttleCategories[(int)ThrottleOutPacketType.Wind] = new TokenBucket(throttle, rates.WindLimit, rates.Wind);
168 throttleCategories[(int)ThrottleOutPacketType.Cloud] = new TokenBucket(throttle, rates.CloudLimit, rates.Cloud);
169 throttleCategories[(int)ThrottleOutPacketType.Task] = new TokenBucket(throttle, rates.TaskLimit, rates.Task);
170 throttleCategories[(int)ThrottleOutPacketType.Texture] = new TokenBucket(throttle, rates.TextureLimit, rates.Texture);
171 throttleCategories[(int)ThrottleOutPacketType.Asset] = new TokenBucket(throttle, rates.AssetLimit, rates.Asset);
172 176
173 // Set the granularity variable used for retransmission calculations to 177 // Set the granularity variable used for retransmission calculations to
174 // the measured resolution of Environment.TickCount 178 // the measured resolution of Environment.TickCount
@@ -176,6 +180,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
176 180
177 // Default the retransmission timeout to three seconds 181 // Default the retransmission timeout to three seconds
178 RTO = 3000; 182 RTO = 3000;
183
184 // Initialize this to a sane value to prevent early disconnects
185 TickLastPacketReceived = Environment.TickCount;
179 } 186 }
180 187
181 /// <summary> 188 /// <summary>
@@ -183,8 +190,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
183 /// </summary> 190 /// </summary>
184 public void Shutdown() 191 public void Shutdown()
185 { 192 {
186 // TODO: Do we need to invalidate the circuit?
187 IsConnected = false; 193 IsConnected = false;
194 NeedAcks.Clear();
195 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
196 {
197 m_packetOutboxes[i].Clear();
198 m_nextPackets[i] = null;
199 }
200 OnPacketStats = null;
201 OnQueueEmpty = null;
188 } 202 }
189 203
190 /// <summary> 204 /// <summary>
@@ -200,13 +214,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
200 info.pendingAcks = new Dictionary<uint, uint>(); 214 info.pendingAcks = new Dictionary<uint, uint>();
201 info.needAck = new Dictionary<uint, byte[]>(); 215 info.needAck = new Dictionary<uint, byte[]>();
202 216
203 info.resendThrottle = throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; 217 info.resendThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
204 info.landThrottle = throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; 218 info.landThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
205 info.windThrottle = throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; 219 info.windThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
206 info.cloudThrottle = throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; 220 info.cloudThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
207 info.taskThrottle = throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; 221 info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
208 info.assetThrottle = throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; 222 info.assetThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
209 info.textureThrottle = throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; 223 info.textureThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
210 info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + 224 info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle +
211 info.taskThrottle + info.assetThrottle + info.textureThrottle; 225 info.taskThrottle + info.assetThrottle + info.textureThrottle;
212 226
@@ -267,6 +281,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
267 adjData = throttleData; 281 adjData = throttleData;
268 } 282 }
269 283
284 // 0.125f converts from bits to bytes
270 int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 285 int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
271 int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 286 int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
272 int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 287 int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
@@ -274,22 +289,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP
274 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 289 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
275 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 290 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
276 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); 291 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
292 // State is a subcategory of task that we allocate a percentage to
293 int state = (int)((float)task * STATE_TASK_PERCENTAGE);
294 task -= state;
295
296 int ceiling = Int32.MaxValue;
297 if (m_defaultThrottleRates.Total != 0)
298 {
299 ceiling = m_defaultThrottleRates.Total;
300 if (ceiling < Packet.MTU) ceiling = Packet.MTU;
301 }
277 302
278 resend = (resend <= defaultThrottleRates.ResendLimit) ? resend : defaultThrottleRates.ResendLimit; 303 resend = Utils.Clamp(resend, Packet.MTU, ceiling);
279 land = (land <= defaultThrottleRates.LandLimit) ? land : defaultThrottleRates.LandLimit; 304 land = Utils.Clamp(land, Packet.MTU, ceiling);
280 wind = (wind <= defaultThrottleRates.WindLimit) ? wind : defaultThrottleRates.WindLimit; 305 wind = Utils.Clamp(wind, Packet.MTU, ceiling);
281 cloud = (cloud <= defaultThrottleRates.CloudLimit) ? cloud : defaultThrottleRates.CloudLimit; 306 cloud = Utils.Clamp(cloud, Packet.MTU, ceiling);
282 task = (task <= defaultThrottleRates.TaskLimit) ? task : defaultThrottleRates.TaskLimit; 307 task = Utils.Clamp(task, Packet.MTU, ceiling);
283 texture = (texture <= defaultThrottleRates.TextureLimit) ? texture : defaultThrottleRates.TextureLimit; 308 texture = Utils.Clamp(texture, Packet.MTU, ceiling);
284 asset = (asset <= defaultThrottleRates.AssetLimit) ? asset : defaultThrottleRates.AssetLimit; 309 asset = Utils.Clamp(asset, Packet.MTU, ceiling);
285 310 state = Utils.Clamp(state, Packet.MTU, ceiling);
286 SetThrottle(ThrottleOutPacketType.Resend, resend); 311
287 SetThrottle(ThrottleOutPacketType.Land, land); 312 int total = resend + land + wind + cloud + task + texture + asset + state;
288 SetThrottle(ThrottleOutPacketType.Wind, wind); 313 int taskTotal = task + state;
289 SetThrottle(ThrottleOutPacketType.Cloud, cloud); 314
290 SetThrottle(ThrottleOutPacketType.Task, task); 315 m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, State={8}, Total={9}",
291 SetThrottle(ThrottleOutPacketType.Texture, texture); 316 AgentID, resend, land, wind, cloud, task, texture, asset, state, total);
292 SetThrottle(ThrottleOutPacketType.Asset, asset); 317
318 SetThrottle(ThrottleOutPacketType.Resend, resend, resend);
319 SetThrottle(ThrottleOutPacketType.Land, land, land);
320 SetThrottle(ThrottleOutPacketType.Wind, wind, wind);
321 SetThrottle(ThrottleOutPacketType.Cloud, cloud, cloud);
322 SetThrottle(ThrottleOutPacketType.Task, task, taskTotal);
323 SetThrottle(ThrottleOutPacketType.Texture, texture, texture);
324 SetThrottle(ThrottleOutPacketType.Asset, asset, asset);
325 SetThrottle(ThrottleOutPacketType.State, state, taskTotal);
293 } 326 }
294 327
295 public byte[] GetThrottlesPacked() 328 public byte[] GetThrottlesPacked()
@@ -297,25 +330,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
297 byte[] data = new byte[7 * 4]; 330 byte[] data = new byte[7 * 4];
298 int i = 0; 331 int i = 0;
299 332
300 Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4; 333 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4;
301 Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4; 334 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4;
302 Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4; 335 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4;
303 Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4; 336 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4;
304 Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Task].DripRate), 0, data, i, 4); i += 4; 337 Buffer.BlockCopy(Utils.FloatToBytes((float)(m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) +
305 Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4; 338 m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4;
306 Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4; 339 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4;
340 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4;
307 341
308 return data; 342 return data;
309 } 343 }
310 344
311 public void SetThrottle(ThrottleOutPacketType category, int rate) 345 public void SetThrottle(ThrottleOutPacketType category, int rate, int maxBurst)
312 { 346 {
313 int i = (int)category; 347 int i = (int)category;
314 if (i >= 0 && i < throttleCategories.Length) 348 if (i >= 0 && i < m_throttleCategories.Length)
315 { 349 {
316 TokenBucket bucket = throttleCategories[(int)category]; 350 TokenBucket bucket = m_throttleCategories[(int)category];
317 bucket.MaxBurst = rate;
318 bucket.DripRate = rate; 351 bucket.DripRate = rate;
352 bucket.MaxBurst = maxBurst;
319 } 353 }
320 } 354 }
321 355
@@ -323,12 +357,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
323 { 357 {
324 int category = (int)packet.Category; 358 int category = (int)packet.Category;
325 359
326 if (category >= 0 && category < packetOutboxes.Length) 360 if (category >= 0 && category < m_packetOutboxes.Length)
327 { 361 {
328 LocklessQueue<OutgoingPacket> queue = packetOutboxes[category]; 362 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
329 TokenBucket bucket = throttleCategories[category]; 363 TokenBucket bucket = m_throttleCategories[category];
330 364
331 if (throttleCategories[category].RemoveTokens(packet.Buffer.DataLength)) 365 if (m_throttleCategories[category].RemoveTokens(packet.Buffer.DataLength))
332 { 366 {
333 // Enough tokens were removed from the bucket, the packet will not be queued 367 // Enough tokens were removed from the bucket, the packet will not be queued
334 return false; 368 return false;
@@ -357,24 +391,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
357 public bool DequeueOutgoing() 391 public bool DequeueOutgoing()
358 { 392 {
359 OutgoingPacket packet; 393 OutgoingPacket packet;
360 LocklessQueue<OutgoingPacket> queue; 394 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue;
361 TokenBucket bucket; 395 TokenBucket bucket;
362 bool packetSent = false; 396 bool packetSent = false;
363 397
364 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) 398 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
365 { 399 {
366 bucket = throttleCategories[i]; 400 bucket = m_throttleCategories[i];
367 401
368 if (nextPackets[i] != null) 402 if (m_nextPackets[i] != null)
369 { 403 {
370 // This bucket was empty the last time we tried to send a packet, 404 // This bucket was empty the last time we tried to send a packet,
371 // leaving a dequeued packet still waiting to be sent out. Try to 405 // leaving a dequeued packet still waiting to be sent out. Try to
372 // send it again 406 // send it again
373 if (bucket.RemoveTokens(nextPacketLengths[i])) 407 OutgoingPacket nextPacket = m_nextPackets[i];
408 if (bucket.RemoveTokens(nextPacket.Buffer.DataLength))
374 { 409 {
375 // Send the packet 410 // Send the packet
376 udpServer.SendPacketFinal(nextPackets[i]); 411 m_udpServer.SendPacketFinal(nextPacket);
377 nextPackets[i] = null; 412 m_nextPackets[i] = null;
378 packetSent = true; 413 packetSent = true;
379 } 414 }
380 } 415 }
@@ -382,7 +417,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
382 { 417 {
383 // No dequeued packet waiting to be sent, try to pull one off 418 // No dequeued packet waiting to be sent, try to pull one off
384 // this queue 419 // this queue
385 queue = packetOutboxes[i]; 420 queue = m_packetOutboxes[i];
386 if (queue.Dequeue(out packet)) 421 if (queue.Dequeue(out packet))
387 { 422 {
388 // A packet was pulled off the queue. See if we have 423 // A packet was pulled off the queue. See if we have
@@ -390,23 +425,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
390 if (bucket.RemoveTokens(packet.Buffer.DataLength)) 425 if (bucket.RemoveTokens(packet.Buffer.DataLength))
391 { 426 {
392 // Send the packet 427 // Send the packet
393 udpServer.SendPacketFinal(packet); 428 m_udpServer.SendPacketFinal(packet);
394 packetSent = true; 429 packetSent = true;
395 } 430 }
396 else 431 else
397 { 432 {
398 // Save the dequeued packet and the length calculation for 433 // Save the dequeued packet for the next iteration
399 // the next iteration 434 m_nextPackets[i] = packet;
400 nextPackets[i] = packet;
401 nextPacketLengths[i] = packet.Buffer.DataLength;
402 } 435 }
436
437 // If the queue is empty after this dequeue, fire the queue
438 // empty callback now so it has a chance to fill before we
439 // get back here
440 if (queue.Count == 0)
441 BeginFireQueueEmpty(i);
403 } 442 }
404 else 443 else
405 { 444 {
406 // No packets in this queue. Fire the queue empty callback 445 // No packets in this queue. Fire the queue empty callback
407 QueueEmpty callback = OnQueueEmpty; 446 // if it has not been called recently
408 if (callback != null) 447 BeginFireQueueEmpty(i);
409 callback((ThrottleOutPacketType)i);
410 } 448 }
411 } 449 }
412 } 450 }
@@ -414,6 +452,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
414 return packetSent; 452 return packetSent;
415 } 453 }
416 454
455 /// <summary>
456 /// Called when an ACK packet is received and a round-trip time for a
457 /// packet is calculated. This is used to calculate the smoothed
458 /// round-trip time, round trip time variance, and finally the
459 /// retransmission timeout
460 /// </summary>
461 /// <param name="r">Round-trip time of a single packet and its
462 /// acknowledgement</param>
417 public void UpdateRoundTrip(float r) 463 public void UpdateRoundTrip(float r)
418 { 464 {
419 const float ALPHA = 0.125f; 465 const float ALPHA = 0.125f;
@@ -435,8 +481,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP
435 481
436 // Always round retransmission timeout up to two seconds 482 // Always round retransmission timeout up to two seconds
437 RTO = Math.Max(2000, (int)(SRTT + Math.Max(G, K * RTTVAR))); 483 RTO = Math.Max(2000, (int)(SRTT + Math.Max(G, K * RTTVAR)));
438 //Logger.Debug("Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " + 484 //m_log.Debug("[LLUDPCLIENT]: Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " +
439 // RTTVAR + " based on new RTT of " + r + "ms"); 485 // RTTVAR + " based on new RTT of " + r + "ms");
440 } 486 }
487
488 /// <summary>
489 /// Does an early check to see if this queue empty callback is already
490 /// running, then asynchronously firing the event
491 /// </summary>
492 /// <param name="throttleIndex">Throttle category to fire the callback
493 /// for</param>
494 private void BeginFireQueueEmpty(int throttleIndex)
495 {
496 if (!m_onQueueEmptyRunning[throttleIndex])
497 Util.FireAndForget(FireQueueEmpty, throttleIndex);
498 }
499
500 /// <summary>
501 /// Checks to see if this queue empty callback is already running,
502 /// then firing the event
503 /// </summary>
504 /// <param name="o">Throttle category to fire the callback for, stored
505 /// as an object to match the WaitCallback delegate signature</param>
506 private void FireQueueEmpty(object o)
507 {
508 int i = (int)o;
509 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
510 QueueEmpty callback = OnQueueEmpty;
511
512 if (callback != null)
513 {
514 if (!m_onQueueEmptyRunning[i])
515 {
516 m_onQueueEmptyRunning[i] = true;
517 try { callback(type); }
518 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + type + ") threw an exception: " + e.Message, e); }
519 m_onQueueEmptyRunning[i] = false;
520 }
521 }
522 }
441 } 523 }
442} 524}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs
deleted file mode 100644
index dbb9861..0000000
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs
+++ /dev/null
@@ -1,282 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
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
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
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Net;
31using OpenSim.Framework;
32using OpenMetaverse;
33
34using ReaderWriterLockImpl = OpenMetaverse.ReaderWriterLockSlim;
35
36namespace OpenSim.Region.ClientStack.LindenUDP
37{
38 public sealed class UDPClientCollection
39 {
40 Dictionary<UUID, LLUDPClient> Dictionary1;
41 Dictionary<IPEndPoint, LLUDPClient> Dictionary2;
42 LLUDPClient[] Array;
43 ReaderWriterLockImpl rwLock = new ReaderWriterLockImpl();
44 object m_sync = new object();
45
46 public UDPClientCollection()
47 {
48 Dictionary1 = new Dictionary<UUID, LLUDPClient>();
49 Dictionary2 = new Dictionary<IPEndPoint, LLUDPClient>();
50 Array = new LLUDPClient[0];
51 }
52
53 public UDPClientCollection(int capacity)
54 {
55 Dictionary1 = new Dictionary<UUID, LLUDPClient>(capacity);
56 Dictionary2 = new Dictionary<IPEndPoint, LLUDPClient>(capacity);
57 Array = new LLUDPClient[0];
58 }
59
60 public void Add(UUID key1, IPEndPoint key2, LLUDPClient value)
61 {
62 //rwLock.EnterWriteLock();
63
64 //try
65 //{
66 // if (Dictionary1.ContainsKey(key1))
67 // {
68 // if (!Dictionary2.ContainsKey(key2))
69 // throw new ArgumentException("key1 exists in the dictionary but not key2");
70 // }
71 // else if (Dictionary2.ContainsKey(key2))
72 // {
73 // if (!Dictionary1.ContainsKey(key1))
74 // throw new ArgumentException("key2 exists in the dictionary but not key1");
75 // }
76
77 // Dictionary1[key1] = value;
78 // Dictionary2[key2] = value;
79
80 // LLUDPClient[] oldArray = Array;
81 // int oldLength = oldArray.Length;
82
83 // LLUDPClient[] newArray = new LLUDPClient[oldLength + 1];
84 // for (int i = 0; i < oldLength; i++)
85 // newArray[i] = oldArray[i];
86 // newArray[oldLength] = value;
87
88 // Array = newArray;
89 //}
90 //finally { rwLock.ExitWriteLock(); }
91
92 lock (m_sync)
93 {
94 if (Dictionary1.ContainsKey(key1))
95 {
96 if (!Dictionary2.ContainsKey(key2))
97 throw new ArgumentException("key1 exists in the dictionary but not key2");
98 }
99 else if (Dictionary2.ContainsKey(key2))
100 {
101 if (!Dictionary1.ContainsKey(key1))
102 throw new ArgumentException("key2 exists in the dictionary but not key1");
103 }
104
105 Dictionary1[key1] = value;
106 Dictionary2[key2] = value;
107
108 LLUDPClient[] oldArray = Array;
109 int oldLength = oldArray.Length;
110
111 LLUDPClient[] newArray = new LLUDPClient[oldLength + 1];
112 for (int i = 0; i < oldLength; i++)
113 newArray[i] = oldArray[i];
114 newArray[oldLength] = value;
115
116 Array = newArray;
117 }
118
119 }
120
121 public bool Remove(UUID key1, IPEndPoint key2)
122 {
123 //rwLock.EnterWriteLock();
124
125 //try
126 //{
127 // LLUDPClient value;
128 // if (Dictionary1.TryGetValue(key1, out value))
129 // {
130 // Dictionary1.Remove(key1);
131 // Dictionary2.Remove(key2);
132
133 // LLUDPClient[] oldArray = Array;
134 // int oldLength = oldArray.Length;
135
136 // LLUDPClient[] newArray = new LLUDPClient[oldLength - 1];
137 // int j = 0;
138 // for (int i = 0; i < oldLength; i++)
139 // {
140 // if (oldArray[i] != value)
141 // newArray[j++] = oldArray[i];
142 // }
143
144 // Array = newArray;
145 // return true;
146 // }
147 //}
148 //finally { rwLock.ExitWriteLock(); }
149
150 //return false;
151
152 lock (m_sync)
153 {
154 LLUDPClient value;
155 if (Dictionary1.TryGetValue(key1, out value))
156 {
157 Dictionary1.Remove(key1);
158 Dictionary2.Remove(key2);
159
160 LLUDPClient[] oldArray = Array;
161 int oldLength = oldArray.Length;
162
163 LLUDPClient[] newArray = new LLUDPClient[oldLength - 1];
164 int j = 0;
165 for (int i = 0; i < oldLength; i++)
166 {
167 if (oldArray[i] != value)
168 newArray[j++] = oldArray[i];
169 }
170
171 Array = newArray;
172 return true;
173 }
174 }
175
176 return false;
177
178 }
179
180 public void Clear()
181 {
182 //rwLock.EnterWriteLock();
183
184 //try
185 //{
186 // Dictionary1.Clear();
187 // Dictionary2.Clear();
188 // Array = new LLUDPClient[0];
189 //}
190 //finally { rwLock.ExitWriteLock(); }
191
192 lock (m_sync)
193 {
194 Dictionary1.Clear();
195 Dictionary2.Clear();
196 Array = new LLUDPClient[0];
197 }
198
199 }
200
201 public int Count
202 {
203 get { return Array.Length; }
204 }
205
206 public bool ContainsKey(UUID key)
207 {
208 return Dictionary1.ContainsKey(key);
209 }
210
211 public bool ContainsKey(IPEndPoint key)
212 {
213 return Dictionary2.ContainsKey(key);
214 }
215
216 public bool TryGetValue(UUID key, out LLUDPClient value)
217 {
218 ////bool success;
219 ////bool doLock = !rwLock.IsUpgradeableReadLockHeld;
220 ////if (doLock) rwLock.EnterReadLock();
221
222 ////try { success = Dictionary1.TryGetValue(key, out value); }
223 ////finally { if (doLock) rwLock.ExitReadLock(); }
224
225 ////return success;
226
227 lock (m_sync)
228 return Dictionary1.TryGetValue(key, out value);
229
230 //try
231 //{
232 // return Dictionary1.TryGetValue(key, out value);
233 //}
234 //catch { }
235 //value = null;
236 //return false;
237 }
238
239 public bool TryGetValue(IPEndPoint key, out LLUDPClient value)
240 {
241 ////bool success;
242 ////bool doLock = !rwLock.IsUpgradeableReadLockHeld;
243 ////if (doLock) rwLock.EnterReadLock();
244
245 ////try { success = Dictionary2.TryGetValue(key, out value); }
246 ////finally { if (doLock) rwLock.ExitReadLock(); }
247
248 ////return success;
249
250 lock (m_sync)
251 return Dictionary2.TryGetValue(key, out value);
252
253 //try
254 //{
255 // return Dictionary2.TryGetValue(key, out value);
256 //}
257 //catch { }
258 //value = null;
259 //return false;
260
261 }
262
263 public void ForEach(Action<LLUDPClient> action)
264 {
265 //bool doLock = !rwLock.IsUpgradeableReadLockHeld;
266 //if (doLock) rwLock.EnterUpgradeableReadLock();
267
268 //try { Parallel.ForEach<LLUDPClient>(Array, action); }
269 //finally { if (doLock) rwLock.ExitUpgradeableReadLock(); }
270
271 LLUDPClient[] localArray = null;
272 lock (m_sync)
273 {
274 localArray = new LLUDPClient[Array.Length];
275 Array.CopyTo(localArray, 0);
276 }
277
278 Parallel.ForEach<LLUDPClient>(localArray, action);
279
280 }
281 }
282}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index c356f02..545a0bc 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -96,7 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
96 /// <summary>Incoming packets that are awaiting handling</summary> 96 /// <summary>Incoming packets that are awaiting handling</summary>
97 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); 97 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
98 /// <summary></summary> 98 /// <summary></summary>
99 private UDPClientCollection clients = new UDPClientCollection(); 99 //private UDPClientCollection m_clients = new UDPClientCollection();
100 /// <summary>Bandwidth throttle for this UDP server</summary> 100 /// <summary>Bandwidth throttle for this UDP server</summary>
101 private TokenBucket m_throttle; 101 private TokenBucket m_throttle;
102 /// <summary>Bandwidth throttle rates for this UDP server</summary> 102 /// <summary>Bandwidth throttle rates for this UDP server</summary>
@@ -109,13 +109,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
109 private Location m_location; 109 private Location m_location;
110 /// <summary>The measured resolution of Environment.TickCount</summary> 110 /// <summary>The measured resolution of Environment.TickCount</summary>
111 private float m_tickCountResolution; 111 private float m_tickCountResolution;
112 /// <summary>The size of the receive buffer for the UDP socket. This value
113 /// is passed up to the operating system and used in the system networking
114 /// stack. Use zero to leave this value as the default</summary>
115 private int m_recvBufferSize;
116 /// <summary>Flag to process packets asynchronously or synchronously</summary>
117 private bool m_asyncPacketHandling;
112 118
113 /// <summary>The measured resolution of Environment.TickCount</summary> 119 /// <summary>The measured resolution of Environment.TickCount</summary>
114 public float TickCountResolution { get { return m_tickCountResolution; } } 120 public float TickCountResolution { get { return m_tickCountResolution; } }
115 public Socket Server { get { return null; } } 121 public Socket Server { get { return null; } }
116 122
117 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) 123 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
118 : base((int)port) 124 : base(listenIP, (int)port)
119 { 125 {
120 #region Environment.TickCount Measurement 126 #region Environment.TickCount Measurement
121 127
@@ -134,18 +140,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
134 #endregion Environment.TickCount Measurement 140 #endregion Environment.TickCount Measurement
135 141
136 m_circuitManager = circuitManager; 142 m_circuitManager = circuitManager;
143 int sceneThrottleBps = 0;
137 144
138 // TODO: Config support for throttling the entire connection 145 IConfig config = configSource.Configs["ClientStack.LindenUDP"];
139 m_throttle = new TokenBucket(null, 0, 0); 146 if (config != null)
147 {
148 m_asyncPacketHandling = config.GetBoolean("async_packet_handling", false);
149 m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0);
150 sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0);
151 }
152
153 m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps);
140 m_throttleRates = new ThrottleRates(configSource); 154 m_throttleRates = new ThrottleRates(configSource);
141 } 155 }
142 156
143 public new void Start() 157 public void Start()
144 { 158 {
145 if (m_scene == null) 159 if (m_scene == null)
146 throw new InvalidOperationException("Cannot LLUDPServer.Start() without an IScene reference"); 160 throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference");
161
162 m_log.Info("[LLUDPSERVER]: Starting the LLUDP server in " + (m_asyncPacketHandling ? "asynchronous" : "synchronous") + " mode");
147 163
148 base.Start(); 164 base.Start(m_recvBufferSize, m_asyncPacketHandling);
149 165
150 // Start the incoming packet processing thread 166 // Start the incoming packet processing thread
151 Thread incomingThread = new Thread(IncomingPacketHandler); 167 Thread incomingThread = new Thread(IncomingPacketHandler);
@@ -181,24 +197,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
181 return x == m_location; 197 return x == m_location;
182 } 198 }
183 199
184 public void RemoveClient(IClientAPI client)
185 {
186 m_scene.ClientManager.Remove(client.CircuitCode);
187 client.Close(false);
188
189 LLUDPClient udpClient;
190 if (clients.TryGetValue(client.AgentId, out udpClient))
191 {
192 m_log.Debug("[LLUDPSERVER]: Removing LLUDPClient for " + client.Name + " in " + m_scene.RegionInfo.RegionName);
193 udpClient.Shutdown();
194 clients.Remove(client.AgentId, udpClient.RemoteEndPoint);
195 }
196 else
197 {
198 m_log.Warn("[LLUDPSERVER]: Failed to remove LLUDPClient for " + client.Name);
199 }
200 }
201
202 public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) 200 public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
203 { 201 {
204 // CoarseLocationUpdate packets cannot be split in an automated way 202 // CoarseLocationUpdate packets cannot be split in an automated way
@@ -216,30 +214,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
216 for (int i = 0; i < packetCount; i++) 214 for (int i = 0; i < packetCount; i++)
217 { 215 {
218 byte[] data = datas[i]; 216 byte[] data = datas[i];
219 clients.ForEach( 217 m_scene.ClientManager.ForEach(
220 delegate(LLUDPClient client) 218 delegate(IClientAPI client)
221 { SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); }); 219 {
220 if (client is LLClientView)
221 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category);
222 }
223 );
222 } 224 }
223 } 225 }
224 else 226 else
225 { 227 {
226 byte[] data = packet.ToBytes(); 228 byte[] data = packet.ToBytes();
227 clients.ForEach( 229 m_scene.ClientManager.ForEach(
228 delegate(LLUDPClient client) 230 delegate(IClientAPI client)
229 { SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); }); 231 {
232 if (client is LLClientView)
233 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category);
234 }
235 );
230 } 236 }
231 } 237 }
232 238
233 public void SendPacket(UUID agentID, Packet packet, ThrottleOutPacketType category, bool allowSplitting) 239 public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting)
234 {
235 LLUDPClient client;
236 if (clients.TryGetValue(agentID, out client))
237 SendPacket(client, packet, category, allowSplitting);
238 else
239 m_log.Warn("[LLUDPSERVER]: Attempted to send a packet to unknown agentID " + agentID);
240 }
241
242 public void SendPacket(LLUDPClient client, Packet packet, ThrottleOutPacketType category, bool allowSplitting)
243 { 240 {
244 // CoarseLocationUpdate packets cannot be split in an automated way 241 // CoarseLocationUpdate packets cannot be split in an automated way
245 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) 242 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
@@ -256,25 +253,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
256 for (int i = 0; i < packetCount; i++) 253 for (int i = 0; i < packetCount; i++)
257 { 254 {
258 byte[] data = datas[i]; 255 byte[] data = datas[i];
259 SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); 256 SendPacketData(udpClient, data, packet.Type, category);
260 } 257 }
261 } 258 }
262 else 259 else
263 { 260 {
264 byte[] data = packet.ToBytes(); 261 byte[] data = packet.ToBytes();
265 SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); 262 SendPacketData(udpClient, data, packet.Type, category);
266 } 263 }
267 } 264 }
268 265
269 public void SendPacketData(LLUDPClient client, byte[] data, int dataLength, PacketType type, bool doZerocode, ThrottleOutPacketType category) 266 public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category)
270 { 267 {
268 int dataLength = data.Length;
269 bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
270
271 // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. 271 // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum.
272 // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting 272 // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting
273 // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here 273 // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here
274 // to accomodate for both common scenarios and provide ample room for ACK appending in both 274 // to accomodate for both common scenarios and provide ample room for ACK appending in both
275 int bufferSize = (dataLength > 180) ? Packet.MTU : 200; 275 int bufferSize = (dataLength > 180) ? Packet.MTU : 200;
276 276
277 UDPPacketBuffer buffer = new UDPPacketBuffer(client.RemoteEndPoint, bufferSize); 277 UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
278 278
279 // Zerocode if needed 279 // Zerocode if needed
280 if (doZerocode) 280 if (doZerocode)
@@ -285,17 +285,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
285 // The packet grew larger than the bufferSize while zerocoding. 285 // The packet grew larger than the bufferSize while zerocoding.
286 // Remove the MSG_ZEROCODED flag and send the unencoded data 286 // Remove the MSG_ZEROCODED flag and send the unencoded data
287 // instead 287 // instead
288 m_log.Info("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding. Removing MSG_ZEROCODED flag"); 288 m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". Removing MSG_ZEROCODED flag");
289 data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); 289 data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED);
290 //
291 buffer = new UDPPacketBuffer(client.RemoteEndPoint, dataLength);
292 //
293 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); 290 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
294 } 291 }
295 } 292 }
296 else 293 else
297 { 294 {
298 // ??? will it fit?
299 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); 295 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
300 } 296 }
301 buffer.DataLength = dataLength; 297 buffer.DataLength = dataLength;
@@ -303,7 +299,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
303 #region Queue or Send 299 #region Queue or Send
304 300
305 // Look up the UDPClient this is going to 301 // Look up the UDPClient this is going to
306 OutgoingPacket outgoingPacket = new OutgoingPacket(client, buffer, category); 302 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category);
307 303
308 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) 304 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
309 SendPacketFinal(outgoingPacket); 305 SendPacketFinal(outgoingPacket);
@@ -311,18 +307,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
311 #endregion Queue or Send 307 #endregion Queue or Send
312 } 308 }
313 309
314 public void SendAcks(LLUDPClient client) 310 public void SendAcks(LLUDPClient udpClient)
315 { 311 {
316 uint ack; 312 uint ack;
317 313
318 if (client.PendingAcks.Dequeue(out ack)) 314 if (udpClient.PendingAcks.Dequeue(out ack))
319 { 315 {
320 List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>(); 316 List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>();
321 PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock(); 317 PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock();
322 block.ID = ack; 318 block.ID = ack;
323 blocks.Add(block); 319 blocks.Add(block);
324 320
325 while (client.PendingAcks.Dequeue(out ack)) 321 while (udpClient.PendingAcks.Dequeue(out ack))
326 { 322 {
327 block = new PacketAckPacket.PacketsBlock(); 323 block = new PacketAckPacket.PacketsBlock();
328 block.ID = ack; 324 block.ID = ack;
@@ -333,22 +329,39 @@ namespace OpenSim.Region.ClientStack.LindenUDP
333 packet.Header.Reliable = false; 329 packet.Header.Reliable = false;
334 packet.Packets = blocks.ToArray(); 330 packet.Packets = blocks.ToArray();
335 331
336 SendPacket(client, packet, ThrottleOutPacketType.Unknown, true); 332 SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true);
337 } 333 }
338 } 334 }
339 335
340 public void SendPing(LLUDPClient client) 336 public void SendPing(LLUDPClient udpClient)
341 { 337 {
342 IClientAPI api = client.ClientAPI; 338 StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
343 if (api != null) 339 pc.Header.Reliable = false;
344 api.SendStartPingCheck(client.CurrentPingSequence++); 340
341 OutgoingPacket oldestPacket = udpClient.NeedAcks.GetOldest();
342
343 pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++;
344 pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0;
345
346 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false);
345 } 347 }
346 348
347 public void ResendUnacked(LLUDPClient client) 349 public void ResendUnacked(LLUDPClient udpClient)
348 { 350 {
349 if (client.NeedAcks.Count > 0) 351 if (udpClient.IsConnected && udpClient.NeedAcks.Count > 0)
350 { 352 {
351 List<OutgoingPacket> expiredPackets = client.NeedAcks.GetExpiredPackets(client.RTO); 353 // Disconnect an agent if no packets are received for some time
354 //FIXME: Make 60 an .ini setting
355 if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60)
356 {
357 m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID);
358
359 RemoveClient(udpClient);
360 return;
361 }
362
363 // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO
364 List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);
352 365
353 if (expiredPackets != null) 366 if (expiredPackets != null)
354 { 367 {
@@ -357,54 +370,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
357 { 370 {
358 OutgoingPacket outgoingPacket = expiredPackets[i]; 371 OutgoingPacket outgoingPacket = expiredPackets[i];
359 372
360 // FIXME: Make this an .ini setting 373 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
361 if (outgoingPacket.ResendCount < 3) 374 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
362 {
363 //Logger.Debug(String.Format("Resending packet #{0} (attempt {1}), {2}ms have passed",
364 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount));
365
366 // Set the resent flag
367 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
368 outgoingPacket.Category = ThrottleOutPacketType.Resend;
369 375
370 // The TickCount will be set to the current time when the packet 376 // Set the resent flag
371 // is actually sent out again 377 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
372 outgoingPacket.TickCount = 0; 378 outgoingPacket.Category = ThrottleOutPacketType.Resend;
373 379
374 // Bump up the resend count on this packet 380 // The TickCount will be set to the current time when the packet
375 Interlocked.Increment(ref outgoingPacket.ResendCount); 381 // is actually sent out again
376 //Interlocked.Increment(ref Stats.ResentPackets); 382 outgoingPacket.TickCount = 0;
377 383
378 // Queue or (re)send the packet 384 // Bump up the resend count on this packet
379 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) 385 Interlocked.Increment(ref outgoingPacket.ResendCount);
380 SendPacketFinal(outgoingPacket); 386 //Interlocked.Increment(ref Stats.ResentPackets);
381 }
382 else
383 {
384 m_log.DebugFormat("[LLUDPSERVER]: Dropping packet #{0} for agent {1} after {2} failed attempts",
385 outgoingPacket.SequenceNumber, outgoingPacket.Client.RemoteEndPoint, outgoingPacket.ResendCount);
386 387
387 lock (client.NeedAcks.SyncRoot) 388 // Requeue or resend the packet
388 client.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber); 389 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
389 390 SendPacketFinal(outgoingPacket);
390 //Interlocked.Increment(ref Stats.DroppedPackets);
391
392 // Disconnect an agent if no packets are received for some time
393 //FIXME: Make 60 an .ini setting
394 if (Environment.TickCount - client.TickLastPacketReceived > 1000 * 60)
395 {
396 m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + client.ClientAPI.Name);
397
398 RemoveClient(client.ClientAPI);
399 return;
400 }
401 }
402 } 391 }
403 } 392 }
404 } 393 }
405 } 394 }
406 395
407 public void Flush() 396 public void Flush(LLUDPClient udpClient)
408 { 397 {
409 // FIXME: Implement? 398 // FIXME: Implement?
410 } 399 }
@@ -415,7 +404,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
415 byte flags = buffer.Data[0]; 404 byte flags = buffer.Data[0];
416 bool isResend = (flags & Helpers.MSG_RESENT) != 0; 405 bool isResend = (flags & Helpers.MSG_RESENT) != 0;
417 bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; 406 bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0;
418 LLUDPClient client = outgoingPacket.Client; 407 LLUDPClient udpClient = outgoingPacket.Client;
408
409 if (!udpClient.IsConnected)
410 return;
419 411
420 // Keep track of when this packet was sent out (right now) 412 // Keep track of when this packet was sent out (right now)
421 outgoingPacket.TickCount = Environment.TickCount; 413 outgoingPacket.TickCount = Environment.TickCount;
@@ -424,11 +416,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
424 416
425 int dataLength = buffer.DataLength; 417 int dataLength = buffer.DataLength;
426 418
427 // Keep appending ACKs until there is no room left in the packet or there are 419 // Keep appending ACKs until there is no room left in the buffer or there are
428 // no more ACKs to append 420 // no more ACKs to append
429 uint ackCount = 0; 421 uint ackCount = 0;
430 uint ack; 422 uint ack;
431 while (dataLength + 5 < buffer.Data.Length && client.PendingAcks.Dequeue(out ack)) 423 while (dataLength + 5 < buffer.Data.Length && udpClient.PendingAcks.Dequeue(out ack))
432 { 424 {
433 Utils.UIntToBytesBig(ack, buffer.Data, dataLength); 425 Utils.UIntToBytesBig(ack, buffer.Data, dataLength);
434 dataLength += 4; 426 dataLength += 4;
@@ -447,24 +439,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
447 439
448 #endregion ACK Appending 440 #endregion ACK Appending
449 441
442 #region Sequence Number Assignment
443
450 if (!isResend) 444 if (!isResend)
451 { 445 {
452 // Not a resend, assign a new sequence number 446 // Not a resend, assign a new sequence number
453 uint sequenceNumber = (uint)Interlocked.Increment(ref client.CurrentSequence); 447 uint sequenceNumber = (uint)Interlocked.Increment(ref udpClient.CurrentSequence);
454 Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); 448 Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
455 outgoingPacket.SequenceNumber = sequenceNumber; 449 outgoingPacket.SequenceNumber = sequenceNumber;
456 450
457 if (isReliable) 451 if (isReliable)
458 { 452 {
459 // Add this packet to the list of ACK responses we are waiting on from the server 453 // Add this packet to the list of ACK responses we are waiting on from the server
460 client.NeedAcks.Add(outgoingPacket); 454 udpClient.NeedAcks.Add(outgoingPacket);
461 } 455 }
462 } 456 }
463 457
458 #endregion Sequence Number Assignment
459
464 // Stats tracking 460 // Stats tracking
465 Interlocked.Increment(ref client.PacketsSent); 461 Interlocked.Increment(ref udpClient.PacketsSent);
466 if (isReliable) 462 if (isReliable)
467 Interlocked.Add(ref client.UnackedBytes, outgoingPacket.Buffer.DataLength); 463 Interlocked.Add(ref udpClient.UnackedBytes, outgoingPacket.Buffer.DataLength);
468 464
469 // Put the UDP payload on the wire 465 // Put the UDP payload on the wire
470 AsyncBeginSend(buffer); 466 AsyncBeginSend(buffer);
@@ -473,10 +469,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
473 protected override void PacketReceived(UDPPacketBuffer buffer) 469 protected override void PacketReceived(UDPPacketBuffer buffer)
474 { 470 {
475 // Debugging/Profiling 471 // Debugging/Profiling
476 //try { Thread.CurrentThread.Name = "PacketReceived (" + scene.RegionName + ")"; } 472 //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; }
477 //catch (Exception) { } 473 //catch (Exception) { }
478 474
479 LLUDPClient client = null; 475 LLUDPClient udpClient = null;
480 Packet packet = null; 476 Packet packet = null;
481 int packetEnd = buffer.DataLength - 1; 477 int packetEnd = buffer.DataLength - 1;
482 IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; 478 IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint;
@@ -491,61 +487,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP
491 } 487 }
492 catch (MalformedDataException) 488 catch (MalformedDataException)
493 { 489 {
494 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet:\n{0}", 490 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet from {0}:\n{1}",
495 Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); 491 buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
496 } 492 }
497 493
498 // Fail-safe check 494 // Fail-safe check
499 if (packet == null) 495 if (packet == null)
500 { 496 {
501 m_log.Warn("[LLUDPSERVER]: Couldn't build a message from the incoming data"); 497 m_log.Warn("[LLUDPSERVER]: Couldn't build a message from incoming data " + buffer.DataLength +
498 " bytes long from " + buffer.RemoteEndPoint);
502 return; 499 return;
503 } 500 }
504 501
505 //Stats.RecvBytes += (ulong)buffer.DataLength;
506 //++Stats.RecvPackets;
507
508 #endregion Decoding 502 #endregion Decoding
509 503
510 #region UseCircuitCode Handling 504 #region Packet to Client Mapping
511 505
506 // UseCircuitCode handling
512 if (packet.Type == PacketType.UseCircuitCode) 507 if (packet.Type == PacketType.UseCircuitCode)
513 { 508 {
514 UseCircuitCodePacket useCircuitCode = (UseCircuitCodePacket)packet; 509 AddNewClient((UseCircuitCodePacket)packet, (IPEndPoint)buffer.RemoteEndPoint);
515 IClientAPI newuser;
516 uint circuitCode = useCircuitCode.CircuitCode.Code;
517
518 // Check if the client is already established
519 if (!m_scene.ClientManager.TryGetClient(circuitCode, out newuser))
520 {
521 AddNewClient(useCircuitCode, (IPEndPoint)buffer.RemoteEndPoint);
522 }
523 } 510 }
524 511
525 // Determine which agent this packet came from 512 // Determine which agent this packet came from
526 if (!clients.TryGetValue(address, out client)) 513 IClientAPI client;
514 if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView))
527 { 515 {
528 m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 516 m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address +
517 " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients");
529 return; 518 return;
530 } 519 }
531 520
532 #endregion UseCircuitCode Handling 521 udpClient = ((LLClientView)client).UDPClient;
522
523 if (!udpClient.IsConnected)
524 return;
525
526 #endregion Packet to Client Mapping
533 527
534 // Stats tracking 528 // Stats tracking
535 Interlocked.Increment(ref client.PacketsReceived); 529 Interlocked.Increment(ref udpClient.PacketsReceived);
536 530
537 #region ACK Receiving 531 #region ACK Receiving
538 532
539 int now = Environment.TickCount; 533 int now = Environment.TickCount;
540 client.TickLastPacketReceived = now; 534 udpClient.TickLastPacketReceived = now;
541 535
542 // Handle appended ACKs 536 // Handle appended ACKs
543 if (packet.Header.AppendedAcks && packet.Header.AckList != null) 537 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
544 { 538 {
545 lock (client.NeedAcks.SyncRoot) 539 lock (udpClient.NeedAcks.SyncRoot)
546 { 540 {
547 for (int i = 0; i < packet.Header.AckList.Length; i++) 541 for (int i = 0; i < packet.Header.AckList.Length; i++)
548 AcknowledgePacket(client, packet.Header.AckList[i], now, packet.Header.Resent); 542 AcknowledgePacket(udpClient, packet.Header.AckList[i], now, packet.Header.Resent);
549 } 543 }
550 } 544 }
551 545
@@ -554,10 +548,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
554 { 548 {
555 PacketAckPacket ackPacket = (PacketAckPacket)packet; 549 PacketAckPacket ackPacket = (PacketAckPacket)packet;
556 550
557 lock (client.NeedAcks.SyncRoot) 551 lock (udpClient.NeedAcks.SyncRoot)
558 { 552 {
559 for (int i = 0; i < ackPacket.Packets.Length; i++) 553 for (int i = 0; i < ackPacket.Packets.Length; i++)
560 AcknowledgePacket(client, ackPacket.Packets[i].ID, now, packet.Header.Resent); 554 AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent);
561 } 555 }
562 } 556 }
563 557
@@ -566,27 +560,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
566 #region ACK Sending 560 #region ACK Sending
567 561
568 if (packet.Header.Reliable) 562 if (packet.Header.Reliable)
569 client.PendingAcks.Enqueue((uint)packet.Header.Sequence); 563 udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
570 564
571 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, 565 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
572 // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove 566 // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove
573 // 2*MTU bytes from the value and send ACKs, and finally add the local value back to 567 // 2*MTU bytes from the value and send ACKs, and finally add the local value back to
574 // client.BytesSinceLastACK. Lockless thread safety 568 // client.BytesSinceLastACK. Lockless thread safety
575 int bytesSinceLastACK = Interlocked.Exchange(ref client.BytesSinceLastACK, 0); 569 int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0);
576 bytesSinceLastACK += buffer.DataLength; 570 bytesSinceLastACK += buffer.DataLength;
577 if (bytesSinceLastACK > Packet.MTU * 2) 571 if (bytesSinceLastACK > Packet.MTU * 2)
578 { 572 {
579 bytesSinceLastACK -= Packet.MTU * 2; 573 bytesSinceLastACK -= Packet.MTU * 2;
580 SendAcks(client); 574 SendAcks(udpClient);
581 } 575 }
582 Interlocked.Add(ref client.BytesSinceLastACK, bytesSinceLastACK); 576 Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK);
583 577
584 #endregion ACK Sending 578 #endregion ACK Sending
585 579
586 #region Incoming Packet Accounting 580 #region Incoming Packet Accounting
587 581
588 // Check the archive of received reliable packet IDs to see whether we already received this packet 582 // Check the archive of received reliable packet IDs to see whether we already received this packet
589 if (packet.Header.Reliable && !client.PacketArchive.TryEnqueue(packet.Header.Sequence)) 583 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
590 { 584 {
591 if (packet.Header.Resent) 585 if (packet.Header.Resent)
592 m_log.Debug("[LLUDPSERVER]: Received a resend of already processed packet #" + packet.Header.Sequence + ", type: " + packet.Type); 586 m_log.Debug("[LLUDPSERVER]: Received a resend of already processed packet #" + packet.Header.Sequence + ", type: " + packet.Type);
@@ -603,7 +597,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
603 if (packet.Type != PacketType.PacketAck) 597 if (packet.Type != PacketType.PacketAck)
604 { 598 {
605 // Inbox insertion 599 // Inbox insertion
606 packetInbox.Enqueue(new IncomingPacket(client, packet)); 600 packetInbox.Enqueue(new IncomingPacket(udpClient, packet));
607 } 601 }
608 } 602 }
609 603
@@ -623,53 +617,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP
623 617
624 private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint) 618 private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint)
625 { 619 {
626 //Slave regions don't accept new clients 620 UUID agentID = useCircuitCode.CircuitCode.ID;
621 UUID sessionID = useCircuitCode.CircuitCode.SessionID;
622 uint circuitCode = useCircuitCode.CircuitCode.Code;
623
627 if (m_scene.RegionStatus != RegionStatus.SlaveScene) 624 if (m_scene.RegionStatus != RegionStatus.SlaveScene)
628 { 625 {
629 AuthenticateResponse sessionInfo; 626 AuthenticateResponse sessionInfo;
630 bool isNewCircuit = !clients.ContainsKey(remoteEndPoint); 627 if (IsClientAuthorized(useCircuitCode, out sessionInfo))
631
632 if (!IsClientAuthorized(useCircuitCode, out sessionInfo))
633 { 628 {
634 m_log.WarnFormat( 629 AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo);
635 "[CONNECTION FAILURE]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}",
636 useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint);
637 return;
638 } 630 }
639 631 else
640 if (isNewCircuit)
641 { 632 {
642 UUID agentID = useCircuitCode.CircuitCode.ID; 633 // Don't create circuits for unauthorized clients
643 UUID sessionID = useCircuitCode.CircuitCode.SessionID; 634 m_log.WarnFormat(
644 uint circuitCode = useCircuitCode.CircuitCode.Code; 635 "[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}",
645 636 useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint);
646 AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo);
647 } 637 }
648 } 638 }
639 else
640 {
641 // Slave regions don't accept new clients
642 m_log.Debug("[LLUDPSERVER]: Slave region " + m_scene.RegionInfo.RegionName + " ignoring UseCircuitCode packet");
643 }
649 } 644 }
650 645
651 private void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) 646 private void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
652 { 647 {
653 // Create the LLUDPClient 648 // Create the LLUDPClient
654 LLUDPClient client = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint); 649 LLUDPClient udpClient = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint);
655
656 // Create the LLClientView
657 LLClientView clientApi = new LLClientView(remoteEndPoint, m_scene, this, client, sessionInfo, agentID, sessionID, circuitCode);
658 clientApi.OnViewerEffect += m_scene.ClientManager.ViewerEffectHandler;
659 clientApi.OnLogout += LogoutHandler;
660 clientApi.OnConnectionClosed += RemoveClient;
661
662 // Start the IClientAPI
663 m_scene.ClientManager.Add(circuitCode, clientApi);
664 clientApi.Start();
665 650
666 // Give LLUDPClient a reference to IClientAPI 651 if (!m_scene.ClientManager.ContainsKey(agentID))
667 client.ClientAPI = clientApi; 652 {
653 // Create the LLClientView
654 LLClientView client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
655 client.OnLogout += LogoutHandler;
668 656
669 // Add the new client to our list of tracked clients 657 // Start the IClientAPI
670 clients.Add(agentID, client.RemoteEndPoint, client); 658 client.Start();
659 }
660 else
661 {
662 m_log.WarnFormat("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from {0} at {1} for circuit {2}",
663 udpClient.AgentID, remoteEndPoint, circuitCode);
664 }
665 }
671 666
672 m_log.DebugFormat("[LLUDPSERVER]: Added new client {0} to region {1}", agentID, m_scene.RegionInfo.RegionName); 667 private void RemoveClient(LLUDPClient udpClient)
668 {
669 // Remove this client from the scene
670 IClientAPI client;
671 if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client))
672 client.Close();
673 } 673 }
674 674
675 private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend) 675 private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend)
@@ -747,20 +747,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
747 elapsed500MS = 0; 747 elapsed500MS = 0;
748 } 748 }
749 749
750 clients.ForEach( 750 m_scene.ClientManager.ForEach(
751 delegate(LLUDPClient client) 751 delegate(IClientAPI client)
752 { 752 {
753 if (client.DequeueOutgoing()) 753 if (client is LLClientView)
754 packetSent = true;
755 if (resendUnacked)
756 ResendUnacked(client);
757 if (sendAcks)
758 { 754 {
759 SendAcks(client); 755 LLUDPClient udpClient = ((LLClientView)client).UDPClient;
760 client.SendPacketStats(); 756
757 if (udpClient.IsConnected)
758 {
759 if (udpClient.DequeueOutgoing())
760 packetSent = true;
761 if (resendUnacked)
762 ResendUnacked(udpClient);
763 if (sendAcks)
764 {
765 SendAcks(udpClient);
766 udpClient.SendPacketStats();
767 }
768 if (sendPings)
769 SendPing(udpClient);
770 }
761 } 771 }
762 if (sendPings)
763 SendPing(client);
764 } 772 }
765 ); 773 );
766 774
@@ -773,38 +781,48 @@ namespace OpenSim.Region.ClientStack.LindenUDP
773 { 781 {
774 IncomingPacket incomingPacket = (IncomingPacket)state; 782 IncomingPacket incomingPacket = (IncomingPacket)state;
775 Packet packet = incomingPacket.Packet; 783 Packet packet = incomingPacket.Packet;
776 LLUDPClient client = incomingPacket.Client; 784 LLUDPClient udpClient = incomingPacket.Client;
785 IClientAPI client;
777 786
778 // Sanity check 787 // Sanity check
779 if (packet == null || client == null || client.ClientAPI == null) 788 if (packet == null || udpClient == null)
780 { 789 {
781 m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", Client=\"{1}\", Client.ClientAPI=\"{2}\"", 790 m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"",
782 packet, client, (client != null) ? client.ClientAPI : null); 791 packet, udpClient);
783 } 792 }
784 793
785 try 794 // Make sure this client is still alive
786 { 795 if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client))
787 // Process this packet
788 client.ClientAPI.ProcessInPacket(packet);
789 }
790 catch (ThreadAbortException)
791 { 796 {
792 // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down 797 try
793 m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server"); 798 {
794 Stop(); 799 // Process this packet
800 client.ProcessInPacket(packet);
801 }
802 catch (ThreadAbortException)
803 {
804 // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down
805 m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server");
806 Stop();
807 }
808 catch (Exception e)
809 {
810 // Don't let a failure in an individual client thread crash the whole sim.
811 m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", udpClient.AgentID, packet.Type);
812 m_log.Error(e.Message, e);
813 }
795 } 814 }
796 catch (Exception e) 815 else
797 { 816 {
798 // Don't let a failure in an individual client thread crash the whole sim. 817 m_log.DebugFormat("[LLUDPSERVER]: Dropping incoming {0} packet for dead client {1}", packet.Type, udpClient.AgentID);
799 m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", client.AgentID, packet.Type);
800 m_log.Error(e.Message, e);
801 } 818 }
802 } 819 }
803 820
804 private void LogoutHandler(IClientAPI client) 821 private void LogoutHandler(IClientAPI client)
805 { 822 {
806 client.SendLogoutPacket(); 823 client.SendLogoutPacket();
807 RemoveClient(client); 824 if (client.IsActive)
825 RemoveClient(((LLClientView)client).UDPClient);
808 } 826 }
809 } 827 }
810} 828}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs
index 43a68ec..d16837d 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs
@@ -1,419 +1,137 @@
1//--------- Modified Version ------------------- 1/*
2///* 2 * Copyright (c) 2006, Clutch, Inc.
3// * Copyright (c) 2006, Clutch, Inc. 3 * Original Author: Jeff Cesnik
4// * Original Author: Jeff Cesnik 4 * All rights reserved.
5// * All rights reserved. 5 *
6// * 6 * - Redistribution and use in source and binary forms, with or without
7// * - Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met:
8// * modification, are permitted provided that the following conditions are met: 8 *
9// * 9 * - Redistributions of source code must retain the above copyright notice, this
10// * - Redistributions of source code must retain the above copyright notice, this 10 * list of conditions and the following disclaimer.
11// * list of conditions and the following disclaimer. 11 * - Neither the name of the openmetaverse.org nor the names
12// * - Neither the name of the openmetaverse.org nor the names 12 * of its contributors may be used to endorse or promote products derived from
13// * of its contributors may be used to endorse or promote products derived from 13 * this software without specific prior written permission.
14// * this software without specific prior written permission. 14 *
15// * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16// * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17// * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18// * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19// * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20// * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21// * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22// * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23// * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24// * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25// * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE.
26// * POSSIBILITY OF SUCH DAMAGE. 26 */
27// */
28 27
29using System; 28using System;
30using System.Net; 29using System.Net;
31using System.Net.Sockets; 30using System.Net.Sockets;
32using System.Threading; 31using System.Threading;
33using OpenMetaverse; 32using log4net;
34 33
35//namespace OpenSim.Region.ClientStack.LindenUDP 34namespace OpenMetaverse
36//{
37// /// <summary>
38// ///
39// /// </summary>
40// public abstract class OpenSimUDPBase
41// {
42// // these abstract methods must be implemented in a derived class to actually do
43// // something with the packets that are sent and received.
44// protected abstract void PacketReceived(UDPPacketBuffer buffer);
45// protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent);
46
47// // the port to listen on
48// internal int udpPort;
49
50// // the UDP socket
51// private Socket udpSocket;
52
53// // the ReaderWriterLock is used solely for the purposes of shutdown (Stop()).
54// // since there are potentially many "reader" threads in the internal .NET IOCP
55// // thread pool, this is a cheaper synchronization primitive than using
56// // a Mutex object. This allows many UDP socket "reads" concurrently - when
57// // Stop() is called, it attempts to obtain a writer lock which will then
58// // wait until all outstanding operations are completed before shutting down.
59// // this avoids the problem of closing the socket with outstanding operations
60// // and trying to catch the inevitable ObjectDisposedException.
61// private ReaderWriterLock rwLock = new ReaderWriterLock();
62
63// // number of outstanding operations. This is a reference count
64// // which we use to ensure that the threads exit cleanly. Note that
65// // we need this because the threads will potentially still need to process
66// // data even after the socket is closed.
67// private int rwOperationCount = 0;
68
69// // the all important shutdownFlag. This is synchronized through the ReaderWriterLock.
70// private volatile bool shutdownFlag = true;
71
72// // the remote endpoint to communicate with
73// protected IPEndPoint remoteEndPoint = null;
74
75
76// /// <summary>
77// /// Initialize the UDP packet handler in server mode
78// /// </summary>
79// /// <param name="port">Port to listening for incoming UDP packets on</param>
80// public OpenSimUDPBase(int port)
81// {
82// udpPort = port;
83// }
84
85// /// <summary>
86// /// Initialize the UDP packet handler in client mode
87// /// </summary>
88// /// <param name="endPoint">Remote UDP server to connect to</param>
89// public OpenSimUDPBase(IPEndPoint endPoint)
90// {
91// remoteEndPoint = endPoint;
92// udpPort = 0;
93// }
94
95// /// <summary>
96// ///
97// /// </summary>
98// public void Start()
99// {
100// if (shutdownFlag)
101// {
102// if (remoteEndPoint == null)
103// {
104// // Server mode
105
106// // create and bind the socket
107// IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort);
108// udpSocket = new Socket(
109// AddressFamily.InterNetwork,
110// SocketType.Dgram,
111// ProtocolType.Udp);
112// udpSocket.Bind(ipep);
113// }
114// else
115// {
116// // Client mode
117// IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort);
118// udpSocket = new Socket(
119// AddressFamily.InterNetwork,
120// SocketType.Dgram,
121// ProtocolType.Udp);
122// udpSocket.Bind(ipep);
123// //udpSocket.Connect(remoteEndPoint);
124// }
125
126// // we're not shutting down, we're starting up
127// shutdownFlag = false;
128
129// // kick off an async receive. The Start() method will return, the
130// // actual receives will occur asynchronously and will be caught in
131// // AsyncEndRecieve().
132// AsyncBeginReceive();
133// }
134// }
135
136// /// <summary>
137// ///
138// /// </summary>
139// public void Stop()
140// {
141// if (!shutdownFlag)
142// {
143// // wait indefinitely for a writer lock. Once this is called, the .NET runtime
144// // will deny any more reader locks, in effect blocking all other send/receive
145// // threads. Once we have the lock, we set shutdownFlag to inform the other
146// // threads that the socket is closed.
147// rwLock.AcquireWriterLock(-1);
148// shutdownFlag = true;
149// udpSocket.Close();
150// rwLock.ReleaseWriterLock();
151
152// // wait for any pending operations to complete on other
153// // threads before exiting.
154// const int FORCE_STOP = 100;
155// int i = 0;
156// while (rwOperationCount > 0 && i < FORCE_STOP)
157// {
158// Thread.Sleep(10);
159// ++i;
160// }
161
162// if (i >= FORCE_STOP)
163// {
164// Logger.Log("UDPBase.Stop() forced shutdown while waiting on pending operations",
165// Helpers.LogLevel.Warning);
166// }
167// }
168// }
169
170// /// <summary>
171// ///
172// /// </summary>
173// public bool IsRunning
174// {
175// get { return !shutdownFlag; }
176// }
177
178// private void AsyncBeginReceive()
179// {
180// // this method actually kicks off the async read on the socket.
181// // we aquire a reader lock here to ensure that no other thread
182// // is trying to set shutdownFlag and close the socket.
183// rwLock.AcquireReaderLock(-1);
184
185// if (!shutdownFlag)
186// {
187// // increment the count of pending operations
188// Interlocked.Increment(ref rwOperationCount);
189
190// // allocate a packet buffer
191// //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut();
192// UDPPacketBuffer buf = new UDPPacketBuffer();
193
194// try
195// {
196// // kick off an async read
197// udpSocket.BeginReceiveFrom(
198// //wrappedBuffer.Instance.Data,
199// buf.Data,
200// 0,
201// UDPPacketBuffer.BUFFER_SIZE,
202// SocketFlags.None,
203// //ref wrappedBuffer.Instance.RemoteEndPoint,
204// ref buf.RemoteEndPoint,
205// new AsyncCallback(AsyncEndReceive),
206// //wrappedBuffer);
207// buf);
208// }
209// catch (SocketException)
210// {
211// // something bad happened
212// //Logger.Log(
213// // "A SocketException occurred in UDPServer.AsyncBeginReceive()",
214// // Helpers.LogLevel.Error, se);
215
216// // an error occurred, therefore the operation is void. Decrement the reference count.
217// Interlocked.Decrement(ref rwOperationCount);
218// }
219// }
220
221// // we're done with the socket for now, release the reader lock.
222// rwLock.ReleaseReaderLock();
223// }
224
225// private void AsyncEndReceive(IAsyncResult iar)
226// {
227// // Asynchronous receive operations will complete here through the call
228// // to AsyncBeginReceive
229
230// // aquire a reader lock
231// rwLock.AcquireReaderLock(-1);
232
233// if (!shutdownFlag)
234// {
235// // get the buffer that was created in AsyncBeginReceive
236// // this is the received data
237// //WrappedObject<UDPPacketBuffer> wrappedBuffer = (WrappedObject<UDPPacketBuffer>)iar.AsyncState;
238// //UDPPacketBuffer buffer = wrappedBuffer.Instance;
239// UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
240
241// try
242// {
243// // get the length of data actually read from the socket, store it with the
244// // buffer
245// buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
246
247// // this operation is now complete, decrement the reference count
248// Interlocked.Decrement(ref rwOperationCount);
249
250// // we're done with the socket, release the reader lock
251// rwLock.ReleaseReaderLock();
252
253// // call the abstract method PacketReceived(), passing the buffer that
254// // has just been filled from the socket read.
255// PacketReceived(buffer);
256// }
257// catch (SocketException)
258// {
259// // an error occurred, therefore the operation is void. Decrement the reference count.
260// Interlocked.Decrement(ref rwOperationCount);
261
262// // we're done with the socket for now, release the reader lock.
263// rwLock.ReleaseReaderLock();
264// }
265// finally
266// {
267// // start another receive - this keeps the server going!
268// AsyncBeginReceive();
269
270// //wrappedBuffer.Dispose();
271// }
272// }
273// else
274// {
275// // nothing bad happened, but we are done with the operation
276// // decrement the reference count and release the reader lock
277// Interlocked.Decrement(ref rwOperationCount);
278// rwLock.ReleaseReaderLock();
279// }
280// }
281
282// public void AsyncBeginSend(UDPPacketBuffer buf)
283// {
284// rwLock.AcquireReaderLock(-1);
285
286// if (!shutdownFlag)
287// {
288// try
289// {
290// Interlocked.Increment(ref rwOperationCount);
291// udpSocket.BeginSendTo(
292// buf.Data,
293// 0,
294// buf.DataLength,
295// SocketFlags.None,
296// buf.RemoteEndPoint,
297// new AsyncCallback(AsyncEndSend),
298// buf);
299// }
300// catch (SocketException)
301// {
302// //Logger.Log(
303// // "A SocketException occurred in UDPServer.AsyncBeginSend()",
304// // Helpers.LogLevel.Error, se);
305// }
306// }
307
308// rwLock.ReleaseReaderLock();
309// }
310
311// private void AsyncEndSend(IAsyncResult iar)
312// {
313// rwLock.AcquireReaderLock(-1);
314
315// if (!shutdownFlag)
316// {
317// UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
318
319// try
320// {
321// int bytesSent = udpSocket.EndSendTo(iar);
322
323// // note that call to the abstract PacketSent() method - we are passing the number
324// // of bytes sent in a separate parameter, since we can't use buffer.DataLength which
325// // is the number of bytes to send (or bytes received depending upon whether this
326// // buffer was part of a send or a receive).
327// PacketSent(buffer, bytesSent);
328// }
329// catch (SocketException)
330// {
331// //Logger.Log(
332// // "A SocketException occurred in UDPServer.AsyncEndSend()",
333// // Helpers.LogLevel.Error, se);
334// }
335// }
336
337// Interlocked.Decrement(ref rwOperationCount);
338// rwLock.ReleaseReaderLock();
339// }
340// }
341//}
342
343//--------- Original Version -------------------
344
345
346namespace OpenSim.Region.ClientStack.LindenUDP
347{ 35{
348 /// <summary> 36 /// <summary>
349 /// 37 /// Base UDP server
350 /// </summary> 38 /// </summary>
351 public abstract class OpenSimUDPBase 39 public abstract class OpenSimUDPBase
352 { 40 {
353 // these abstract methods must be implemented in a derived class to actually do 41 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
354 // something with the packets that are sent and received. 42
43 /// <summary>
44 /// This method is called when an incoming packet is received
45 /// </summary>
46 /// <param name="buffer">Incoming packet buffer</param>
355 protected abstract void PacketReceived(UDPPacketBuffer buffer); 47 protected abstract void PacketReceived(UDPPacketBuffer buffer);
48
49 /// <summary>
50 /// This method is called when an outgoing packet is sent
51 /// </summary>
52 /// <param name="buffer">Outgoing packet buffer</param>
53 /// <param name="bytesSent">Number of bytes written to the wire</param>
356 protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent); 54 protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent);
357 55
358 // the port to listen on 56 /// <summary>UDP port to bind to in server mode</summary>
359 internal int udpPort; 57 protected int m_udpPort;
58
59 /// <summary>Local IP address to bind to in server mode</summary>
60 protected IPAddress m_localBindAddress;
360 61
361 // the UDP socket 62 /// <summary>UDP socket, used in either client or server mode</summary>
362 private Socket udpSocket; 63 private Socket m_udpSocket;
363 64
364 // the all important shutdownFlag. 65 /// <summary>Flag to process packets asynchronously or synchronously</summary>
365 private volatile bool shutdownFlag = true; 66 private bool m_asyncPacketHandling;
366 67
367 // the remote endpoint to communicate with 68 /// <summary>The all important shutdown flag</summary>
368 protected IPEndPoint remoteEndPoint = null; 69 private volatile bool m_shutdownFlag = true;
70
71 /// <summary>Returns true if the server is currently listening, otherwise false</summary>
72 public bool IsRunning { get { return !m_shutdownFlag; } }
369 73
370 /// <summary> 74 /// <summary>
371 /// Initialize the UDP packet handler in server mode 75 /// Default constructor
372 /// </summary> 76 /// </summary>
77 /// <param name="bindAddress">Local IP address to bind the server to</param>
373 /// <param name="port">Port to listening for incoming UDP packets on</param> 78 /// <param name="port">Port to listening for incoming UDP packets on</param>
374 public OpenSimUDPBase(int port) 79 public OpenSimUDPBase(IPAddress bindAddress, int port)
375 { 80 {
376 udpPort = port; 81 m_localBindAddress = bindAddress;
82 m_udpPort = port;
377 } 83 }
378 84
379 /// <summary> 85 /// <summary>
380 /// Initialize the UDP packet handler in client mode 86 /// Start the UDP server
381 /// </summary> 87 /// </summary>
382 /// <param name="endPoint">Remote UDP server to connect to</param> 88 /// <param name="recvBufferSize">The size of the receive buffer for
383 public OpenSimUDPBase(IPEndPoint endPoint) 89 /// the UDP socket. This value is passed up to the operating system
90 /// and used in the system networking stack. Use zero to leave this
91 /// value as the default</param>
92 /// <param name="asyncPacketHandling">Set this to true to start
93 /// receiving more packets while current packet handler callbacks are
94 /// still running. Setting this to false will complete each packet
95 /// callback before the next packet is processed</param>
96 /// <remarks>This method will attempt to set the SIO_UDP_CONNRESET flag
97 /// on the socket to get newer versions of Windows to behave in a sane
98 /// manner (not throwing an exception when the remote side resets the
99 /// connection). This call is ignored on Mono where the flag is not
100 /// necessary</remarks>
101 public void Start(int recvBufferSize, bool asyncPacketHandling)
384 { 102 {
385 remoteEndPoint = endPoint; 103 m_asyncPacketHandling = asyncPacketHandling;
386 udpPort = 0;
387 }
388 104
389 /// <summary> 105 if (m_shutdownFlag)
390 ///
391 /// </summary>
392 public void Start()
393 {
394 if (shutdownFlag)
395 { 106 {
396 const int SIO_UDP_CONNRESET = -1744830452; 107 const int SIO_UDP_CONNRESET = -1744830452;
397 108
398 IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); 109 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
399 udpSocket = new Socket( 110
111 m_udpSocket = new Socket(
400 AddressFamily.InterNetwork, 112 AddressFamily.InterNetwork,
401 SocketType.Dgram, 113 SocketType.Dgram,
402 ProtocolType.Udp); 114 ProtocolType.Udp);
115
403 try 116 try
404 { 117 {
405 // this udp socket flag is not supported under mono, 118 // This udp socket flag is not supported under mono,
406 // so we'll catch the exception and continue 119 // so we'll catch the exception and continue
407 udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); 120 m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null);
121 m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag set");
408 } 122 }
409 catch (SocketException) 123 catch (SocketException)
410 { 124 {
411 Logger.DebugLog("UDP SIO_UDP_CONNRESET flag not supported on this platform"); 125 m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring");
412 } 126 }
413 udpSocket.Bind(ipep); 127
128 if (recvBufferSize != 0)
129 m_udpSocket.ReceiveBufferSize = recvBufferSize;
130
131 m_udpSocket.Bind(ipep);
414 132
415 // we're not shutting down, we're starting up 133 // we're not shutting down, we're starting up
416 shutdownFlag = false; 134 m_shutdownFlag = false;
417 135
418 // kick off an async receive. The Start() method will return, the 136 // kick off an async receive. The Start() method will return, the
419 // actual receives will occur asynchronously and will be caught in 137 // actual receives will occur asynchronously and will be caught in
@@ -423,41 +141,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
423 } 141 }
424 142
425 /// <summary> 143 /// <summary>
426 /// 144 /// Stops the UDP server
427 /// </summary> 145 /// </summary>
428 public void Stop() 146 public void Stop()
429 { 147 {
430 if (!shutdownFlag) 148 if (!m_shutdownFlag)
431 { 149 {
432 // wait indefinitely for a writer lock. Once this is called, the .NET runtime 150 // wait indefinitely for a writer lock. Once this is called, the .NET runtime
433 // will deny any more reader locks, in effect blocking all other send/receive 151 // will deny any more reader locks, in effect blocking all other send/receive
434 // threads. Once we have the lock, we set shutdownFlag to inform the other 152 // threads. Once we have the lock, we set shutdownFlag to inform the other
435 // threads that the socket is closed. 153 // threads that the socket is closed.
436 shutdownFlag = true; 154 m_shutdownFlag = true;
437 udpSocket.Close(); 155 m_udpSocket.Close();
438 } 156 }
439 } 157 }
440 158
441 /// <summary>
442 ///
443 /// </summary>
444 public bool IsRunning
445 {
446 get { return !shutdownFlag; }
447 }
448
449 private void AsyncBeginReceive() 159 private void AsyncBeginReceive()
450 { 160 {
451 // allocate a packet buffer 161 // allocate a packet buffer
452 //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); 162 //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut();
453 UDPPacketBuffer buf = new UDPPacketBuffer(); 163 UDPPacketBuffer buf = new UDPPacketBuffer();
454 164
455 if (!shutdownFlag) 165 if (!m_shutdownFlag)
456 { 166 {
457 try 167 try
458 { 168 {
459 // kick off an async read 169 // kick off an async read
460 udpSocket.BeginReceiveFrom( 170 m_udpSocket.BeginReceiveFrom(
461 //wrappedBuffer.Instance.Data, 171 //wrappedBuffer.Instance.Data,
462 buf.Data, 172 buf.Data,
463 0, 173 0,
@@ -472,13 +182,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
472 { 182 {
473 if (e.SocketErrorCode == SocketError.ConnectionReset) 183 if (e.SocketErrorCode == SocketError.ConnectionReset)
474 { 184 {
475 Logger.Log("SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + udpPort, Helpers.LogLevel.Error); 185 m_log.Warn("[UDPBASE]: SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + m_udpPort);
476 bool salvaged = false; 186 bool salvaged = false;
477 while (!salvaged) 187 while (!salvaged)
478 { 188 {
479 try 189 try
480 { 190 {
481 udpSocket.BeginReceiveFrom( 191 m_udpSocket.BeginReceiveFrom(
482 //wrappedBuffer.Instance.Data, 192 //wrappedBuffer.Instance.Data,
483 buf.Data, 193 buf.Data,
484 0, 194 0,
@@ -494,7 +204,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
494 catch (ObjectDisposedException) { return; } 204 catch (ObjectDisposedException) { return; }
495 } 205 }
496 206
497 Logger.Log("Salvaged the UDP listener on port " + udpPort, Helpers.LogLevel.Info); 207 m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort);
498 } 208 }
499 } 209 }
500 catch (ObjectDisposedException) { } 210 catch (ObjectDisposedException) { }
@@ -505,10 +215,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
505 { 215 {
506 // Asynchronous receive operations will complete here through the call 216 // Asynchronous receive operations will complete here through the call
507 // to AsyncBeginReceive 217 // to AsyncBeginReceive
508 if (!shutdownFlag) 218 if (!m_shutdownFlag)
509 { 219 {
510 // start another receive - this keeps the server going! 220 // Asynchronous mode will start another receive before the
511 AsyncBeginReceive(); 221 // callback for this packet is even fired. Very parallel :-)
222 if (m_asyncPacketHandling)
223 AsyncBeginReceive();
512 224
513 // get the buffer that was created in AsyncBeginReceive 225 // get the buffer that was created in AsyncBeginReceive
514 // this is the received data 226 // this is the received data
@@ -520,7 +232,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
520 { 232 {
521 // get the length of data actually read from the socket, store it with the 233 // get the length of data actually read from the socket, store it with the
522 // buffer 234 // buffer
523 buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); 235 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
524 236
525 // call the abstract method PacketReceived(), passing the buffer that 237 // call the abstract method PacketReceived(), passing the buffer that
526 // has just been filled from the socket read. 238 // has just been filled from the socket read.
@@ -528,17 +240,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
528 } 240 }
529 catch (SocketException) { } 241 catch (SocketException) { }
530 catch (ObjectDisposedException) { } 242 catch (ObjectDisposedException) { }
531 //finally { wrappedBuffer.Dispose(); } 243 finally
244 {
245 //wrappedBuffer.Dispose();
246
247 // Synchronous mode waits until the packet callback completes
248 // before starting the receive to fetch another packet
249 if (!m_asyncPacketHandling)
250 AsyncBeginReceive();
251 }
252
532 } 253 }
533 } 254 }
534 255
535 public void AsyncBeginSend(UDPPacketBuffer buf) 256 public void AsyncBeginSend(UDPPacketBuffer buf)
536 { 257 {
537 if (!shutdownFlag) 258 if (!m_shutdownFlag)
538 { 259 {
539 try 260 try
540 { 261 {
541 udpSocket.BeginSendTo( 262 m_udpSocket.BeginSendTo(
542 buf.Data, 263 buf.Data,
543 0, 264 0,
544 buf.DataLength, 265 buf.DataLength,
@@ -557,7 +278,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
557 try 278 try
558 { 279 {
559 UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; 280 UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
560 int bytesSent = udpSocket.EndSendTo(result); 281 int bytesSent = m_udpSocket.EndSendTo(result);
561 282
562 PacketSent(buf, bytesSent); 283 PacketSent(buf, bytesSent);
563 } 284 }
@@ -566,4 +287,3 @@ namespace OpenSim.Region.ClientStack.LindenUDP
566 } 287 }
567 } 288 }
568} 289}
569
diff --git a/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs
index 858a03c..008d827 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using OpenSim.Framework;
29using Nini.Config; 30using Nini.Config;
30 31
31namespace OpenSim.Region.ClientStack.LindenUDP 32namespace OpenSim.Region.ClientStack.LindenUDP
@@ -45,12 +46,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
45 public int Wind; 46 public int Wind;
46 /// <summary>Drip rate for cloud packets</summary> 47 /// <summary>Drip rate for cloud packets</summary>
47 public int Cloud; 48 public int Cloud;
48 /// <summary>Drip rate for task (state and transaction) packets</summary> 49 /// <summary>Drip rate for task packets</summary>
49 public int Task; 50 public int Task;
50 /// <summary>Drip rate for texture packets</summary> 51 /// <summary>Drip rate for texture packets</summary>
51 public int Texture; 52 public int Texture;
52 /// <summary>Drip rate for asset packets</summary> 53 /// <summary>Drip rate for asset packets</summary>
53 public int Asset; 54 public int Asset;
55 /// <summary>Drip rate for state packets</summary>
56 public int State;
57 /// <summary>Drip rate for the parent token bucket</summary>
58 public int Total;
54 59
55 /// <summary>Maximum burst rate for resent packets</summary> 60 /// <summary>Maximum burst rate for resent packets</summary>
56 public int ResendLimit; 61 public int ResendLimit;
@@ -66,6 +71,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
66 public int TextureLimit; 71 public int TextureLimit;
67 /// <summary>Maximum burst rate for asset packets</summary> 72 /// <summary>Maximum burst rate for asset packets</summary>
68 public int AssetLimit; 73 public int AssetLimit;
74 /// <summary>Maximum burst rate for state packets</summary>
75 public int StateLimit;
76 /// <summary>Burst rate for the parent token bucket</summary>
77 public int TotalLimit;
69 78
70 /// <summary> 79 /// <summary>
71 /// Default constructor 80 /// Default constructor
@@ -77,23 +86,81 @@ namespace OpenSim.Region.ClientStack.LindenUDP
77 { 86 {
78 IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"]; 87 IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"];
79 88
80 Resend = throttleConfig.GetInt("ResendDefault", 12500); 89 Resend = throttleConfig.GetInt("resend_default", 12500);
81 Land = throttleConfig.GetInt("LandDefault", 500); 90 Land = throttleConfig.GetInt("land_default", 500);
82 Wind = throttleConfig.GetInt("WindDefault", 500); 91 Wind = throttleConfig.GetInt("wind_default", 500);
83 Cloud = throttleConfig.GetInt("CloudDefault", 500); 92 Cloud = throttleConfig.GetInt("cloud_default", 500);
84 Task = throttleConfig.GetInt("TaskDefault", 500); 93 Task = throttleConfig.GetInt("task_default", 500);
85 Texture = throttleConfig.GetInt("TextureDefault", 500); 94 Texture = throttleConfig.GetInt("texture_default", 500);
86 Asset = throttleConfig.GetInt("AssetDefault", 500); 95 Asset = throttleConfig.GetInt("asset_default", 500);
96 State = throttleConfig.GetInt("state_default", 500);
87 97
88 ResendLimit = throttleConfig.GetInt("ResendLimit", 18750); 98 Total = throttleConfig.GetInt("client_throttle_max_bps", 0);
89 LandLimit = throttleConfig.GetInt("LandLimit", 29750); 99
90 WindLimit = throttleConfig.GetInt("WindLimit", 18750); 100 ResendLimit = throttleConfig.GetInt("resend_limit", 18750);
91 CloudLimit = throttleConfig.GetInt("CloudLimit", 18750); 101 LandLimit = throttleConfig.GetInt("land_limit", 29750);
92 TaskLimit = throttleConfig.GetInt("TaskLimit", 55750); 102 WindLimit = throttleConfig.GetInt("wind_limit", 18750);
93 TextureLimit = throttleConfig.GetInt("TextureLimit", 55750); 103 CloudLimit = throttleConfig.GetInt("cloud_limit", 18750);
94 AssetLimit = throttleConfig.GetInt("AssetLimit", 27500); 104 TaskLimit = throttleConfig.GetInt("task_limit", 18750);
105 TextureLimit = throttleConfig.GetInt("texture_limit", 55750);
106 AssetLimit = throttleConfig.GetInt("asset_limit", 27500);
107 State = throttleConfig.GetInt("state_limit", 37000);
108
109 TotalLimit = throttleConfig.GetInt("client_throttle_max_bps", 0);
95 } 110 }
96 catch (Exception) { } 111 catch (Exception) { }
97 } 112 }
113
114 public int GetRate(ThrottleOutPacketType type)
115 {
116 switch (type)
117 {
118 case ThrottleOutPacketType.Resend:
119 return Resend;
120 case ThrottleOutPacketType.Land:
121 return Land;
122 case ThrottleOutPacketType.Wind:
123 return Wind;
124 case ThrottleOutPacketType.Cloud:
125 return Cloud;
126 case ThrottleOutPacketType.Task:
127 return Task;
128 case ThrottleOutPacketType.Texture:
129 return Texture;
130 case ThrottleOutPacketType.Asset:
131 return Asset;
132 case ThrottleOutPacketType.State:
133 return State;
134 case ThrottleOutPacketType.Unknown:
135 default:
136 return 0;
137 }
138 }
139
140 public int GetLimit(ThrottleOutPacketType type)
141 {
142 switch (type)
143 {
144 case ThrottleOutPacketType.Resend:
145 return ResendLimit;
146 case ThrottleOutPacketType.Land:
147 return LandLimit;
148 case ThrottleOutPacketType.Wind:
149 return WindLimit;
150 case ThrottleOutPacketType.Cloud:
151 return CloudLimit;
152 case ThrottleOutPacketType.Task:
153 return TaskLimit;
154 case ThrottleOutPacketType.Texture:
155 return TextureLimit;
156 case ThrottleOutPacketType.Asset:
157 return AssetLimit;
158 case ThrottleOutPacketType.State:
159 return StateLimit;
160 case ThrottleOutPacketType.Unknown:
161 default:
162 return 0;
163 }
164 }
98 } 165 }
99} 166}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
index 195ca57..f3242c1 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
@@ -103,6 +103,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
103 } 103 }
104 104
105 /// <summary> 105 /// <summary>
106 /// Removes all elements from the collection
107 /// </summary>
108 public void Clear()
109 {
110 lock (SyncRoot)
111 packets.Clear();
112 }
113
114 /// <summary>
106 /// Gets the packet with the lowest sequence number 115 /// Gets the packet with the lowest sequence number
107 /// </summary> 116 /// </summary>
108 /// <returns>The packet with the lowest sequence number, or null if the 117 /// <returns>The packet with the lowest sequence number, or null if the
diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
index b81ab41..4041b63 100644
--- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
@@ -43,6 +43,7 @@ using Mono.Addins;
43using OpenMetaverse; 43using OpenMetaverse;
44 44
45using OpenSim.Framework; 45using OpenSim.Framework;
46using OpenSim.Framework.Console;
46using OpenSim.Region.Framework.Interfaces; 47using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Region.Framework.Scenes; 48using OpenSim.Region.Framework.Scenes;
48using OpenSim.Services.Interfaces; 49using OpenSim.Services.Interfaces;
@@ -54,7 +55,7 @@ using OpenSim.Services.Interfaces;
54namespace Flotsam.RegionModules.AssetCache 55namespace Flotsam.RegionModules.AssetCache
55{ 56{
56 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] 57 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
57 public class FlotsamAssetCache : ISharedRegionModule, IImprovedAssetCache 58 public class FlotsamAssetCache : ISharedRegionModule, IImprovedAssetCache, IAssetService
58 { 59 {
59 private static readonly ILog m_log = 60 private static readonly ILog m_log =
60 LogManager.GetLogger( 61 LogManager.GetLogger(
@@ -102,6 +103,11 @@ namespace Flotsam.RegionModules.AssetCache
102 103
103 private System.Timers.Timer m_CachCleanTimer = new System.Timers.Timer(); 104 private System.Timers.Timer m_CachCleanTimer = new System.Timers.Timer();
104 105
106 private IAssetService m_AssetService = null;
107 private List<Scene> m_Scenes = new List<Scene>();
108
109 private bool m_DeepScanBeforePurge = false;
110
105 public FlotsamAssetCache() 111 public FlotsamAssetCache()
106 { 112 {
107 m_InvalidChars.AddRange(Path.GetInvalidPathChars()); 113 m_InvalidChars.AddRange(Path.GetInvalidPathChars());
@@ -121,6 +127,7 @@ namespace Flotsam.RegionModules.AssetCache
121 public void Initialise(IConfigSource source) 127 public void Initialise(IConfigSource source)
122 { 128 {
123 IConfig moduleConfig = source.Configs["Modules"]; 129 IConfig moduleConfig = source.Configs["Modules"];
130
124 131
125 if (moduleConfig != null) 132 if (moduleConfig != null)
126 { 133 {
@@ -195,7 +202,13 @@ namespace Flotsam.RegionModules.AssetCache
195 202
196 m_CacheWarnAt = assetConfig.GetInt("CacheWarnAt", 30000); 203 m_CacheWarnAt = assetConfig.GetInt("CacheWarnAt", 30000);
197 204
198 205 m_DeepScanBeforePurge = assetConfig.GetBoolean("DeepScanBeforePurge", false);
206
207 MainConsole.Instance.Commands.AddCommand(this.Name, true, "fcache status", "fcache status", "Display cache status", HandleConsoleCommand);
208 MainConsole.Instance.Commands.AddCommand(this.Name, true, "fcache clear", "fcache clear [file] [memory]", "Remove all assets in the file and/or memory cache", HandleConsoleCommand);
209 MainConsole.Instance.Commands.AddCommand(this.Name, true, "fcache assets", "fcache assets", "Attempt a deep scan and cache of all assets in all scenes", HandleConsoleCommand);
210 MainConsole.Instance.Commands.AddCommand(this.Name, true, "fcache expire", "fcache expire <datetime>", "Purge cached assets older then the specified date/time", HandleConsoleCommand);
211
199 } 212 }
200 } 213 }
201 } 214 }
@@ -213,16 +226,23 @@ namespace Flotsam.RegionModules.AssetCache
213 if (m_Enabled) 226 if (m_Enabled)
214 { 227 {
215 scene.RegisterModuleInterface<IImprovedAssetCache>(this); 228 scene.RegisterModuleInterface<IImprovedAssetCache>(this);
229 m_Scenes.Add(scene);
216 230
217 //scene.AddCommand(this, "flotsamcache", "", "Display a list of console commands for the Flotsam Asset Cache", HandleConsoleCommand); 231 if (m_AssetService == null)
218 scene.AddCommand(this, "flotsamcache counts", "flotsamcache counts", "Display the number of cached assets", HandleConsoleCommand); 232 {
219 scene.AddCommand(this, "flotsamcache clearmem", "flotsamcache clearmem", "Remove all assets cached in memory", HandleConsoleCommand); 233 m_AssetService = scene.RequestModuleInterface<IAssetService>();
220 scene.AddCommand(this, "flotsamcache clearfile", "flotsamcache clearfile", "Remove all assets cached on disk", HandleConsoleCommand); 234
235 }
221 } 236 }
222 } 237 }
223 238
224 public void RemoveRegion(Scene scene) 239 public void RemoveRegion(Scene scene)
225 { 240 {
241 if (m_Enabled)
242 {
243 scene.UnregisterModuleInterface<IImprovedAssetCache>(this);
244 m_Scenes.Remove(scene);
245 }
226 } 246 }
227 247
228 public void RegionLoaded(Scene scene) 248 public void RegionLoaded(Scene scene)
@@ -442,31 +462,47 @@ namespace Flotsam.RegionModules.AssetCache
442 if (m_LogLevel >= 2) 462 if (m_LogLevel >= 2)
443 m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Checking for expired files older then {0}.", m_FileExpiration.ToString()); 463 m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Checking for expired files older then {0}.", m_FileExpiration.ToString());
444 464
465 // Purge all files last accessed prior to this point
466 DateTime purgeLine = DateTime.Now - m_FileExpiration;
467
468 // An optional deep scan at this point will ensure assets present in scenes,
469 // or referenced by objects in the scene, but not recently accessed
470 // are not purged.
471 if (m_DeepScanBeforePurge)
472 {
473 CacheScenes();
474 }
475
445 foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) 476 foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
446 { 477 {
447 CleanExpiredFiles(dir); 478 CleanExpiredFiles(dir, purgeLine);
448 } 479 }
449 } 480 }
450 481
451 /// <summary> 482 /// <summary>
452 /// Recurses through specified directory checking for expired asset files and deletes them. Also removes empty directories. 483 /// Recurses through specified directory checking for asset files last
484 /// accessed prior to the specified purge line and deletes them. Also
485 /// removes empty tier directories.
453 /// </summary> 486 /// </summary>
454 /// <param name="dir"></param> 487 /// <param name="dir"></param>
455 private void CleanExpiredFiles(string dir) 488 private void CleanExpiredFiles(string dir, DateTime purgeLine)
456 { 489 {
490
457 foreach (string file in Directory.GetFiles(dir)) 491 foreach (string file in Directory.GetFiles(dir))
458 { 492 {
459 if (DateTime.Now - File.GetLastAccessTime(file) > m_FileExpiration) 493 if (File.GetLastAccessTime(file) < purgeLine)
460 { 494 {
461 File.Delete(file); 495 File.Delete(file);
462 } 496 }
463 } 497 }
464 498
499 // Recurse into lower tiers
465 foreach (string subdir in Directory.GetDirectories(dir)) 500 foreach (string subdir in Directory.GetDirectories(dir))
466 { 501 {
467 CleanExpiredFiles(subdir); 502 CleanExpiredFiles(subdir, purgeLine);
468 } 503 }
469 504
505 // Check if a tier directory is empty, if so, delete it
470 int dirSize = Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length; 506 int dirSize = Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length;
471 if (dirSize == 0) 507 if (dirSize == 0)
472 { 508 {
@@ -478,6 +514,11 @@ namespace Flotsam.RegionModules.AssetCache
478 } 514 }
479 } 515 }
480 516
517 /// <summary>
518 /// Determines the filename for an AssetID stored in the file cache
519 /// </summary>
520 /// <param name="id"></param>
521 /// <returns></returns>
481 private string GetFileName(string id) 522 private string GetFileName(string id)
482 { 523 {
483 // Would it be faster to just hash the darn thing? 524 // Would it be faster to just hash the darn thing?
@@ -496,14 +537,23 @@ namespace Flotsam.RegionModules.AssetCache
496 return Path.Combine(path, id); 537 return Path.Combine(path, id);
497 } 538 }
498 539
540 /// <summary>
541 /// Writes a file to the file cache, creating any nessesary
542 /// tier directories along the way
543 /// </summary>
544 /// <param name="filename"></param>
545 /// <param name="asset"></param>
499 private void WriteFileCache(string filename, AssetBase asset) 546 private void WriteFileCache(string filename, AssetBase asset)
500 { 547 {
501 Stream stream = null; 548 Stream stream = null;
549
502 // Make sure the target cache directory exists 550 // Make sure the target cache directory exists
503 string directory = Path.GetDirectoryName(filename); 551 string directory = Path.GetDirectoryName(filename);
552
504 // Write file first to a temp name, so that it doesn't look 553 // Write file first to a temp name, so that it doesn't look
505 // like it's already cached while it's still writing. 554 // like it's already cached while it's still writing.
506 string tempname = Path.Combine(directory, Path.GetRandomFileName()); 555 string tempname = Path.Combine(directory, Path.GetRandomFileName());
556
507 try 557 try
508 { 558 {
509 if (!Directory.Exists(directory)) 559 if (!Directory.Exists(directory))
@@ -563,6 +613,11 @@ namespace Flotsam.RegionModules.AssetCache
563 } 613 }
564 } 614 }
565 615
616 /// <summary>
617 /// Scan through the file cache, and return number of assets currently cached.
618 /// </summary>
619 /// <param name="dir"></param>
620 /// <returns></returns>
566 private int GetFileCacheCount(string dir) 621 private int GetFileCacheCount(string dir)
567 { 622 {
568 int count = Directory.GetFiles(dir).Length; 623 int count = Directory.GetFiles(dir).Length;
@@ -575,55 +630,180 @@ namespace Flotsam.RegionModules.AssetCache
575 return count; 630 return count;
576 } 631 }
577 632
633 /// <summary>
634 /// This notes the last time the Region had a deep asset scan performed on it.
635 /// </summary>
636 /// <param name="RegionID"></param>
637 private void StampRegionStatusFile(UUID RegionID)
638 {
639 string RegionCacheStatusFile = Path.Combine(m_CacheDirectory, "RegionStatus_" + RegionID.ToString() + ".fac");
640 if (File.Exists(RegionCacheStatusFile))
641 {
642 File.SetLastWriteTime(RegionCacheStatusFile, DateTime.Now);
643 }
644 else
645 {
646 File.WriteAllText(RegionCacheStatusFile, "Please do not delete this file unless you are manually clearing your Flotsam Asset Cache.");
647 }
648 }
649
650 /// <summary>
651 /// Iterates through all Scenes, doing a deep scan through assets
652 /// to cache all assets present in the scene or referenced by assets
653 /// in the scene
654 /// </summary>
655 /// <returns></returns>
656 private int CacheScenes()
657 {
658 UuidGatherer gatherer = new UuidGatherer(m_AssetService);
659
660 Dictionary<UUID, int> assets = new Dictionary<UUID, int>();
661 foreach (Scene s in m_Scenes)
662 {
663 StampRegionStatusFile(s.RegionInfo.RegionID);
664
665 s.ForEachSOG(delegate(SceneObjectGroup e)
666 {
667 gatherer.GatherAssetUuids(e, assets);
668 }
669 );
670 }
671
672 foreach (UUID assetID in assets.Keys)
673 {
674 string filename = GetFileName(assetID.ToString());
675
676 if (File.Exists(filename))
677 {
678 File.SetLastAccessTime(filename, DateTime.Now);
679 }
680 else
681 {
682 m_AssetService.Get(assetID.ToString());
683 }
684 }
685
686 return assets.Keys.Count;
687 }
688
689 /// <summary>
690 /// Deletes all cache contents
691 /// </summary>
692 private void ClearFileCache()
693 {
694 foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
695 {
696 try
697 {
698 Directory.Delete(dir, true);
699 }
700 catch (Exception e)
701 {
702 LogException(e);
703 }
704 }
705
706 foreach (string file in Directory.GetFiles(m_CacheDirectory))
707 {
708 try
709 {
710 File.Delete(file);
711 }
712 catch (Exception e)
713 {
714 LogException(e);
715 }
716 }
717 }
718
578 #region Console Commands 719 #region Console Commands
579 private void HandleConsoleCommand(string module, string[] cmdparams) 720 private void HandleConsoleCommand(string module, string[] cmdparams)
580 { 721 {
581 if (cmdparams.Length == 2) 722 if (cmdparams.Length >= 2)
582 { 723 {
583 string cmd = cmdparams[1]; 724 string cmd = cmdparams[1];
584 switch (cmd) 725 switch (cmd)
585 { 726 {
586 case "count": 727 case "status":
587 case "counts": 728 m_log.InfoFormat("[FLOTSAM ASSET CACHE] Memory Cache : {0} assets", m_MemoryCache.Count);
588 m_log.InfoFormat("[FLOTSAM ASSET CACHE] Memory Cache : {0}", m_MemoryCache.Count);
589 729
590 int fileCount = GetFileCacheCount(m_CacheDirectory); 730 int fileCount = GetFileCacheCount(m_CacheDirectory);
591 m_log.InfoFormat("[FLOTSAM ASSET CACHE] File Cache : {0}", fileCount); 731 m_log.InfoFormat("[FLOTSAM ASSET CACHE] File Cache : {0} assets", fileCount);
592 732
593 break; 733 foreach ( string s in Directory.GetFiles(m_CacheDirectory, "*.fac" ) )
734 {
735 m_log.Info("[FLOTSAM ASSET CACHE] Deep Scans were performed on the following regions:");
736
737 string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac","");
738 DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s);
739 m_log.InfoFormat("[FLOTSAM ASSET CACHE] Region: {0}, {1}", RegionID, RegionDeepScanTMStamp.ToString("MM/dd/yyyy hh:mm:ss"));
740 }
594 741
595 case "clearmem":
596 m_MemoryCache.Clear();
597 m_log.InfoFormat("[FLOTSAM ASSET CACHE] Memory Cache Cleared, there are now {0} items in the memory cache", m_MemoryCache.Count);
598 break; 742 break;
599 743
600 case "clearfile": 744 case "clear":
601 foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) 745 if (cmdparams.Length < 3)
602 { 746 {
603 try 747 m_log.Warn("[FLOTSAM ASSET CACHE] Please specify memory and/or file cache.");
604 { 748 break;
605 Directory.Delete(dir, true);
606 }
607 catch (Exception e)
608 {
609 LogException(e);
610 }
611 } 749 }
612 750 foreach (string s in cmdparams)
613 foreach (string file in Directory.GetFiles(m_CacheDirectory))
614 { 751 {
615 try 752 if (s.ToLower() == "memory")
616 { 753 {
617 File.Delete(file); 754 m_MemoryCache.Clear();
755 m_log.Info("[FLOTSAM ASSET CACHE] Memory cache cleared.");
618 } 756 }
619 catch (Exception e) 757 else if (s.ToLower() == "file")
620 { 758 {
621 LogException(e); 759 ClearFileCache();
760 m_log.Info("[FLOTSAM ASSET CACHE] File cache cleared.");
622 } 761 }
623 } 762 }
763 break;
764
765
766 case "assets":
767 m_log.Info("[FLOTSAM ASSET CACHE] Caching all assets, in all scenes.");
768
769 Util.FireAndForget(delegate {
770 int assetsCached = CacheScenes();
771 m_log.InfoFormat("[FLOTSAM ASSET CACHE] Completed Scene Caching, {0} assets found.", assetsCached);
772
773 });
624 774
625 break; 775 break;
626 776
777 case "expire":
778
779
780 if (cmdparams.Length >= 3)
781 {
782 m_log.InfoFormat("[FLOTSAM ASSET CACHE] Invalid parameters for Expire, please specify a valid date & time", cmd);
783 break;
784 }
785
786 string s_expirationDate = "";
787 DateTime expirationDate;
788
789 if (cmdparams.Length > 3)
790 {
791 s_expirationDate = string.Join(" ", cmdparams, 2, cmdparams.Length - 2);
792 }
793 else
794 {
795 s_expirationDate = cmdparams[2];
796 }
797
798 if (!DateTime.TryParse(s_expirationDate, out expirationDate))
799 {
800 m_log.InfoFormat("[FLOTSAM ASSET CACHE] {0} is not a valid date & time", cmd);
801 break;
802 }
803
804 CleanExpiredFiles(m_CacheDirectory, expirationDate);
805
806 break;
627 default: 807 default:
628 m_log.InfoFormat("[FLOTSAM ASSET CACHE] Unknown command {0}", cmd); 808 m_log.InfoFormat("[FLOTSAM ASSET CACHE] Unknown command {0}", cmd);
629 break; 809 break;
@@ -631,13 +811,66 @@ namespace Flotsam.RegionModules.AssetCache
631 } 811 }
632 else if (cmdparams.Length == 1) 812 else if (cmdparams.Length == 1)
633 { 813 {
634 m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache counts - Display the number of cached assets"); 814 m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache status - Display cache status");
635 m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearmem - Remove all assets cached in memory"); 815 m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearmem - Remove all assets cached in memory");
636 m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearfile - Remove all assets cached on disk"); 816 m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearfile - Remove all assets cached on disk");
817 m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache cachescenes - Attempt a deep cache of all assets in all scenes");
818 m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache <datetime> - Purge assets older then the specified date & time");
637 819
638 } 820 }
639 } 821 }
640 822
641 #endregion 823 #endregion
824
825 #region IAssetService Members
826
827
828 public AssetMetadata GetMetadata(string id)
829 {
830 AssetBase asset = Get(id);
831 return asset.Metadata;
832 }
833
834 public byte[] GetData(string id)
835 {
836 AssetBase asset = Get(id);
837 return asset.Data;
838 }
839
840 public bool Get(string id, object sender, AssetRetrieved handler)
841 {
842 AssetBase asset = Get(id);
843 handler(id, sender, asset);
844 return true;
845 }
846
847 public string Store(AssetBase asset)
848 {
849 if ((asset.FullID == null) || (asset.FullID == UUID.Zero))
850 {
851 asset.FullID = UUID.Random();
852 }
853
854 Cache(asset);
855
856 return asset.ID;
857
858 }
859
860 public bool UpdateContent(string id, byte[] data)
861 {
862 AssetBase asset = Get(id);
863 asset.Data = data;
864 Cache(asset);
865 return true;
866 }
867
868 public bool Delete(string id)
869 {
870 Expire(id);
871 return true;
872 }
873
874 #endregion
642 } 875 }
643} \ No newline at end of file 876} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
index f941728..7855862 100644
--- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
@@ -36,6 +36,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
36{ 36{
37 public class GodsModule : IRegionModule, IGodsModule 37 public class GodsModule : IRegionModule, IGodsModule
38 { 38 {
39 /// <summary>Special UUID for actions that apply to all agents</summary>
40 private static readonly UUID ALL_AGENTS = new UUID("44e87126-e794-4ded-05b3-7c42da3d5cdb");
41
39 protected Scene m_scene; 42 protected Scene m_scene;
40 protected IDialogModule m_dialogModule; 43 protected IDialogModule m_dialogModule;
41 44
@@ -99,8 +102,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
99 /// <param name="reason">The message to send to the user after it's been turned into a field</param> 102 /// <param name="reason">The message to send to the user after it's been turned into a field</param>
100 public void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason) 103 public void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason)
101 { 104 {
102 // For some reason the client sends this seemingly hard coded UUID for kicking everyone. Dun-know. 105 UUID kickUserID = ALL_AGENTS;
103 UUID kickUserID = new UUID("44e87126e7944ded05b37c42da3d5cdb");
104 106
105 ScenePresence sp = m_scene.GetScenePresence(agentID); 107 ScenePresence sp = m_scene.GetScenePresence(agentID);
106 108
@@ -110,15 +112,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
110 { 112 {
111 if (agentID == kickUserID) 113 if (agentID == kickUserID)
112 { 114 {
113 m_scene.ClientManager.ForEachClient( 115 string reasonStr = Utils.BytesToString(reason);
116
117 m_scene.ClientManager.ForEach(
114 delegate(IClientAPI controller) 118 delegate(IClientAPI controller)
115 { 119 {
116 if (controller.AgentId != godID) 120 if (controller.AgentId != godID)
117 controller.Kick(Utils.BytesToString(reason)); 121 controller.Kick(reasonStr);
118 } 122 }
119 ); 123 );
120 124
121 // This is a bit crude. It seems the client will be null before it actually stops the thread 125 // This is a bit crude. It seems the client will be null before it actually stops the thread
122 // The thread will kill itself eventually :/ 126 // The thread will kill itself eventually :/
123 // Is there another way to make sure *all* clients get this 'inter region' message? 127 // Is there another way to make sure *all* clients get this 'inter region' message?
124 m_scene.ForEachScenePresence( 128 m_scene.ForEachScenePresence(
@@ -128,7 +132,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
128 { 132 {
129 // Possibly this should really be p.Close() though that method doesn't send a close 133 // Possibly this should really be p.Close() though that method doesn't send a close
130 // to the client 134 // to the client
131 p.ControllingClient.Close(true); 135 p.ControllingClient.Close();
132 } 136 }
133 } 137 }
134 ); 138 );
@@ -138,7 +142,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
138 m_scene.SceneGraph.removeUserCount(!sp.IsChildAgent); 142 m_scene.SceneGraph.removeUserCount(!sp.IsChildAgent);
139 143
140 sp.ControllingClient.Kick(Utils.BytesToString(reason)); 144 sp.ControllingClient.Kick(Utils.BytesToString(reason));
141 sp.ControllingClient.Close(true); 145 sp.ControllingClient.Close();
142 } 146 }
143 } 147 }
144 else 148 else
diff --git a/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs b/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs
index 7d6f150..d636b1c 100644
--- a/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs
+++ b/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs
@@ -1267,7 +1267,7 @@ namespace OpenSim.Region.CoreModules.InterGrid
1267 if (avToBeKilled.IsChildAgent) 1267 if (avToBeKilled.IsChildAgent)
1268 { 1268 {
1269 m_mod.DeleteOGPState(avUUID); 1269 m_mod.DeleteOGPState(avUUID);
1270 avToBeKilled.ControllingClient.Close(true); 1270 avToBeKilled.ControllingClient.Close();
1271 } 1271 }
1272 } 1272 }
1273 } 1273 }
diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
index b885420..9b565ed 100644
--- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
@@ -57,7 +57,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
57 public string body; 57 public string body;
58 public int responseCode; 58 public int responseCode;
59 public string responseBody; 59 public string responseBody;
60 public ManualResetEvent ev; 60 //public ManualResetEvent ev;
61 public bool requestDone; 61 public bool requestDone;
62 public int startTime; 62 public int startTime;
63 public string uri; 63 public string uri;
@@ -456,7 +456,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
456 requestData.headers["x-query-string"] = queryString; 456 requestData.headers["x-query-string"] = queryString;
457 requestData.headers["x-script-url"] = url.url; 457 requestData.headers["x-script-url"] = url.url;
458 458
459 requestData.ev = new ManualResetEvent(false); 459 //requestData.ev = new ManualResetEvent(false);
460 lock (url.requests) 460 lock (url.requests)
461 { 461 {
462 url.requests.Add(requestID, requestData); 462 url.requests.Add(requestID, requestData);
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs
index 7b4e374..0aa753d 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs
@@ -31,6 +31,7 @@ using System;
31using System.Collections.Generic; 31using System.Collections.Generic;
32using System.Reflection; 32using System.Reflection;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Communications.Cache;
34using OpenSim.Server.Base; 35using OpenSim.Server.Base;
35using OpenSim.Region.Framework.Interfaces; 36using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
@@ -40,7 +41,7 @@ using OpenMetaverse;
40namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset 41namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
41{ 42{
42 public class HGAssetBroker : 43 public class HGAssetBroker :
43 ISharedRegionModule, IAssetService 44 ISharedRegionModule, IAssetService, IHyperAssetService
44 { 45 {
45 private static readonly ILog m_log = 46 private static readonly ILog m_log =
46 LogManager.GetLogger( 47 LogManager.GetLogger(
@@ -50,6 +51,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
50 private IAssetService m_GridService; 51 private IAssetService m_GridService;
51 private IAssetService m_HGService; 52 private IAssetService m_HGService;
52 53
54 private Scene m_aScene;
55 private string m_LocalAssetServiceURI;
56
53 private bool m_Enabled = false; 57 private bool m_Enabled = false;
54 58
55 public Type ReplaceableInterface 59 public Type ReplaceableInterface
@@ -114,6 +118,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
114 return; 118 return;
115 } 119 }
116 120
121 m_LocalAssetServiceURI = assetConfig.GetString("AssetServerURI", string.Empty);
122 if (m_LocalAssetServiceURI == string.Empty)
123 {
124 IConfig netConfig = source.Configs["Network"];
125 m_LocalAssetServiceURI = netConfig.GetString("asset_server_url", string.Empty);
126 }
127
128 if (m_LocalAssetServiceURI != string.Empty)
129 m_LocalAssetServiceURI = m_LocalAssetServiceURI.Trim('/');
130
117 m_Enabled = true; 131 m_Enabled = true;
118 m_log.Info("[HG ASSET CONNECTOR]: HG asset broker enabled"); 132 m_log.Info("[HG ASSET CONNECTOR]: HG asset broker enabled");
119 } 133 }
@@ -132,8 +146,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
132 { 146 {
133 if (!m_Enabled) 147 if (!m_Enabled)
134 return; 148 return;
149
150 m_aScene = scene;
135 151
136 scene.RegisterModuleInterface<IAssetService>(this); 152 scene.RegisterModuleInterface<IAssetService>(this);
153 scene.RegisterModuleInterface<IHyperAssetService>(this);
137 } 154 }
138 155
139 public void RemoveRegion(Scene scene) 156 public void RemoveRegion(Scene scene)
@@ -344,5 +361,30 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
344 else 361 else
345 return m_GridService.Delete(id); 362 return m_GridService.Delete(id);
346 } 363 }
364
365 #region IHyperAssetService
366
367 public string GetUserAssetServer(UUID userID)
368 {
369 CachedUserInfo uinfo = m_aScene.CommsManager.UserProfileCacheService.GetUserDetails(userID);
370 if ((uinfo != null) && (uinfo.UserProfile != null))
371 {
372 if ((uinfo.UserProfile.UserAssetURI == string.Empty) || (uinfo.UserProfile.UserAssetURI == ""))
373 return m_LocalAssetServiceURI;
374 return uinfo.UserProfile.UserAssetURI.Trim('/');
375 }
376 else
377 {
378 // we don't know anyting about this user
379 return string.Empty;
380 }
381 }
382
383 public string GetSimAssetServer()
384 {
385 return m_LocalAssetServiceURI;
386 }
387
388 #endregion
347 } 389 }
348} 390}
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs
index 148331b..1422add 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs
@@ -759,6 +759,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
759 759
760 } 760 }
761 761
762
762 protected bool IsLocalRegion(ulong handle) 763 protected bool IsLocalRegion(ulong handle)
763 { 764 {
764 return m_LocalScenes.ContainsKey(handle); 765 return m_LocalScenes.ContainsKey(handle);
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/BaseInventoryConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/BaseInventoryConnector.cs
index bd32f3b..811569f 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/BaseInventoryConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/BaseInventoryConnector.cs
@@ -159,6 +159,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
159 /// <returns>true if the item was successfully added</returns> 159 /// <returns>true if the item was successfully added</returns>
160 public bool AddItem(InventoryItemBase item) 160 public bool AddItem(InventoryItemBase item)
161 { 161 {
162 if (item == null)
163 return false;
164
162 if (item.Folder == UUID.Zero) 165 if (item.Folder == UUID.Zero)
163 { 166 {
164 InventoryFolderBase f = GetFolderForType(item.Owner, (AssetType)item.AssetType); 167 InventoryFolderBase f = GetFolderForType(item.Owner, (AssetType)item.AssetType);
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs
index fd1a759..f073f32 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs
@@ -386,7 +386,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
386 return false; 386 return false;
387 387
388 if (IsLocalGridUser(item.Owner)) 388 if (IsLocalGridUser(item.Owner))
389 {
389 return m_GridService.AddItem(item); 390 return m_GridService.AddItem(item);
391 }
390 else 392 else
391 { 393 {
392 UUID sessionID = GetSessionID(item.Owner); 394 UUID sessionID = GetSessionID(item.Owner);
diff --git a/OpenSim/Region/CoreModules/World/Land/RegionCombinerModule.cs b/OpenSim/Region/CoreModules/World/Land/RegionCombinerModule.cs
index 05d19a2..6499915 100644
--- a/OpenSim/Region/CoreModules/World/Land/RegionCombinerModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/RegionCombinerModule.cs
@@ -343,7 +343,9 @@ namespace OpenSim.Region.CoreModules.World.Land
343 343
344 lock (scene.WestBorders) 344 lock (scene.WestBorders)
345 { 345 {
346 scene.WestBorders[0].BorderLine.Z += (int) Constants.RegionSize; //auto teleport West 346
347
348 scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - conn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West
347 349
348 // Trigger auto teleport to root region 350 // Trigger auto teleport to root region
349 scene.WestBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX; 351 scene.WestBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX;
@@ -410,7 +412,7 @@ namespace OpenSim.Region.CoreModules.World.Land
410 conn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize; 412 conn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize;
411 lock (scene.SouthBorders) 413 lock (scene.SouthBorders)
412 { 414 {
413 scene.SouthBorders[0].BorderLine.Z += (int) Constants.RegionSize; //auto teleport south 415 scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - conn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south
414 scene.SouthBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX; 416 scene.SouthBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX;
415 scene.SouthBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY; 417 scene.SouthBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY;
416 } 418 }
@@ -481,7 +483,7 @@ namespace OpenSim.Region.CoreModules.World.Land
481 483
482 lock (scene.SouthBorders) 484 lock (scene.SouthBorders)
483 { 485 {
484 scene.SouthBorders[0].BorderLine.Z += (int) Constants.RegionSize; //auto teleport south 486 scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - conn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south
485 scene.SouthBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX; 487 scene.SouthBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX;
486 scene.SouthBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY; 488 scene.SouthBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY;
487 } 489 }
@@ -503,7 +505,7 @@ namespace OpenSim.Region.CoreModules.World.Land
503 505
504 lock (scene.WestBorders) 506 lock (scene.WestBorders)
505 { 507 {
506 scene.WestBorders[0].BorderLine.Z += (int) Constants.RegionSize; //auto teleport West 508 scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - conn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West
507 scene.WestBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX; 509 scene.WestBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX;
508 scene.WestBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY; 510 scene.WestBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY;
509 } 511 }
diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
index 8ad4844..d651fd4 100644
--- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
+++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
@@ -813,7 +813,7 @@ namespace OpenSim.Region.Examples.SimpleModule
813 { 813 {
814 } 814 }
815 815
816 public void Close(bool ShutdownCircuit) 816 public void Close()
817 { 817 {
818 } 818 }
819 819
@@ -833,6 +833,11 @@ namespace OpenSim.Region.Examples.SimpleModule
833 set { m_circuitCode = value; } 833 set { m_circuitCode = value; }
834 } 834 }
835 835
836 public IPEndPoint RemoteEndPoint
837 {
838 get { return new IPEndPoint(IPAddress.Loopback, (ushort)m_circuitCode); }
839 }
840
836 public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message) 841 public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message)
837 { 842 {
838 843
diff --git a/OpenSim/Region/Framework/Interfaces/IHyperService.cs b/OpenSim/Region/Framework/Interfaces/IHyperService.cs
new file mode 100644
index 0000000..51ea28a
--- /dev/null
+++ b/OpenSim/Region/Framework/Interfaces/IHyperService.cs
@@ -0,0 +1,37 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
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
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
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using OpenMetaverse;
29
30namespace OpenSim.Region.Framework.Interfaces
31{
32 public interface IHyperAssetService
33 {
34 string GetUserAssetServer(UUID userID);
35 string GetSimAssetServer();
36 }
37}
diff --git a/OpenSim/Region/Framework/Scenes/Hypergrid/HGAssetMapper.cs b/OpenSim/Region/Framework/Scenes/Hypergrid/HGAssetMapper.cs
index b6fa41d..244ac3b 100644
--- a/OpenSim/Region/Framework/Scenes/Hypergrid/HGAssetMapper.cs
+++ b/OpenSim/Region/Framework/Scenes/Hypergrid/HGAssetMapper.cs
@@ -35,6 +35,7 @@ using OpenSim.Framework;
35using OpenSim.Framework.Communications.Cache; 35using OpenSim.Framework.Communications.Cache;
36using OpenSim.Framework.Communications.Clients; 36using OpenSim.Framework.Communications.Clients;
37using OpenSim.Region.Framework.Scenes.Serialization; 37using OpenSim.Region.Framework.Scenes.Serialization;
38using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Services.Interfaces; 39using OpenSim.Services.Interfaces;
39 40
40//using HyperGrid.Framework; 41//using HyperGrid.Framework;
@@ -52,13 +53,13 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid
52 53
53 private Scene m_scene; 54 private Scene m_scene;
54 55
55 private IHyperlinkService m_hyper; 56 private IHyperAssetService m_hyper;
56 IHyperlinkService HyperlinkService 57 IHyperAssetService HyperlinkAssets
57 { 58 {
58 get 59 get
59 { 60 {
60 if (m_hyper == null) 61 if (m_hyper == null)
61 m_hyper = m_scene.RequestModuleInterface<IHyperlinkService>(); 62 m_hyper = m_scene.RequestModuleInterface<IHyperAssetService>();
62 return m_hyper; 63 return m_hyper;
63 } 64 }
64 } 65 }
@@ -99,7 +100,7 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid
99 100
100 if (asset != null) 101 if (asset != null)
101 { 102 {
102 m_log.Debug("[HGScene]: Asset made it to asset cache. " + asset.Name + " " + assetID); 103 m_log.DebugFormat("[HGScene]: Copied asset {0} from {1} to local asset server. ", asset.ID, url);
103 return asset; 104 return asset;
104 } 105 }
105 return null; 106 return null;
@@ -129,6 +130,7 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid
129 } 130 }
130 131
131 m_scene.AssetService.Store(asset1); 132 m_scene.AssetService.Store(asset1);
133 m_log.DebugFormat("[HGScene]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url);
132 } 134 }
133 return true; 135 return true;
134 } 136 }
@@ -167,34 +169,32 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid
167 169
168 public void Get(UUID assetID, UUID ownerID) 170 public void Get(UUID assetID, UUID ownerID)
169 { 171 {
170 if (!HyperlinkService.IsLocalUser(ownerID)) 172 // Get the item from the remote asset server onto the local AssetCache
173 // and place an entry in m_assetMap
174
175 string userAssetURL = HyperlinkAssets.GetUserAssetServer(ownerID);
176 if ((userAssetURL != string.Empty) && (userAssetURL != HyperlinkAssets.GetSimAssetServer()))
171 { 177 {
172 // Get the item from the remote asset server onto the local AssetCache 178 m_log.Debug("[HGScene]: Fetching object " + assetID + " from asset server " + userAssetURL);
173 // and place an entry in m_assetMap 179 AssetBase asset = FetchAsset(userAssetURL, assetID);
174 180
175 string userAssetURL = UserAssetURL(ownerID); 181 if (asset != null)
176 if (userAssetURL != null)
177 { 182 {
178 m_log.Debug("[HGScene]: Fetching object " + assetID + " to asset server " + userAssetURL); 183 // OK, now fetch the inside.
179 AssetBase asset = FetchAsset(userAssetURL, assetID); 184 Dictionary<UUID, int> ids = new Dictionary<UUID, int>();
185 HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, userAssetURL);
186 uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids);
187 foreach (UUID uuid in ids.Keys)
188 FetchAsset(userAssetURL, uuid);
189
190 m_log.DebugFormat("[HGScene]: Successfully fetched asset {0} from asset server {1}", asset.ID, userAssetURL);
180 191
181 if (asset != null)
182 {
183 m_log.Debug("[HGScene]: Successfully fetched item from remote asset server " + userAssetURL);
184
185 // OK, now fetch the inside.
186 Dictionary<UUID, int> ids = new Dictionary<UUID, int>();
187 HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, userAssetURL);
188 uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids);
189 foreach (UUID uuid in ids.Keys)
190 FetchAsset(userAssetURL, uuid);
191 }
192 else
193 m_log.Warn("[HGScene]: Could not fetch asset from remote asset server " + userAssetURL);
194 } 192 }
195 else 193 else
196 m_log.Warn("[HGScene]: Unable to locate foreign user's asset server"); 194 m_log.Warn("[HGScene]: Could not fetch asset from remote asset server " + userAssetURL);
197 } 195 }
196 else
197 m_log.Debug("[HGScene]: user's asset server is the local region's asset server");
198 } 198 }
199 199
200 //public InventoryItemBase Get(InventoryItemBase item, UUID rootFolder, CachedUserInfo userInfo) 200 //public InventoryItemBase Get(InventoryItemBase item, UUID rootFolder, CachedUserInfo userInfo)
@@ -225,44 +225,38 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid
225 225
226 public void Post(UUID assetID, UUID ownerID) 226 public void Post(UUID assetID, UUID ownerID)
227 { 227 {
228 if (!HyperlinkService.IsLocalUser(ownerID))
229 {
230 // Post the item from the local AssetCache onto the remote asset server 228 // Post the item from the local AssetCache onto the remote asset server
231 // and place an entry in m_assetMap 229 // and place an entry in m_assetMap
232 230
233 string userAssetURL = UserAssetURL(ownerID); 231 string userAssetURL = HyperlinkAssets.GetUserAssetServer(ownerID);
234 if (userAssetURL != null) 232 if ((userAssetURL != string.Empty) && (userAssetURL != HyperlinkAssets.GetSimAssetServer()))
233 {
234 m_log.Debug("[HGScene]: Posting object " + assetID + " to asset server " + userAssetURL);
235 AssetBase asset = m_scene.AssetService.Get(assetID.ToString());
236 if (asset != null)
235 { 237 {
236 m_log.Debug("[HGScene]: Posting object " + assetID + " to asset server " + userAssetURL); 238 Dictionary<UUID, int> ids = new Dictionary<UUID, int>();
237 AssetBase asset = m_scene.AssetService.Get(assetID.ToString()); 239 HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, string.Empty);
238 if (asset != null) 240 uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids);
241 foreach (UUID uuid in ids.Keys)
239 { 242 {
240 Dictionary<UUID, int> ids = new Dictionary<UUID, int>(); 243 asset = m_scene.AssetService.Get(uuid.ToString());
241 HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, string.Empty); 244 if (asset == null)
242 uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids); 245 m_log.DebugFormat("[HGScene]: Could not find asset {0}", uuid);
243 foreach (UUID uuid in ids.Keys) 246 else
244 {
245 asset = m_scene.AssetService.Get(uuid.ToString());
246 if (asset != null)
247 m_log.DebugFormat("[HGScene]: Posting {0} {1}", asset.Type.ToString(), asset.Name);
248 else
249 m_log.DebugFormat("[HGScene]: Could not find asset {0}", uuid);
250 PostAsset(userAssetURL, asset); 247 PostAsset(userAssetURL, asset);
251 } 248 }
252 249
253 if (ids.Count > 0) // maybe it succeeded... 250 // maybe all pieces got there...
254 m_log.DebugFormat("[HGScene]: Successfully posted item {0} to remote asset server {1}", assetID, userAssetURL); 251 m_log.DebugFormat("[HGScene]: Successfully posted item {0} to asset server {1}", assetID, userAssetURL);
255 else
256 m_log.WarnFormat("[HGScene]: Could not post asset {0} to remote asset server {1}", assetID, userAssetURL);
257 252
258 }
259 else
260 m_log.Debug("[HGScene]: Something wrong with asset, it could not be found");
261 } 253 }
262 else 254 else
263 m_log.Warn("[HGScene]: Unable to locate foreign user's asset server"); 255 m_log.DebugFormat("[HGScene]: Something wrong with asset {0}, it could not be found", assetID);
264
265 } 256 }
257 else
258 m_log.Debug("[HGScene]: user's asset server is local region's asset server");
259
266 } 260 }
267 261
268 #endregion 262 #endregion
diff --git a/OpenSim/Region/Framework/Scenes/Hypergrid/HGScene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Hypergrid/HGScene.Inventory.cs
index 8fe3565..6f7f34f 100644
--- a/OpenSim/Region/Framework/Scenes/Hypergrid/HGScene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Hypergrid/HGScene.Inventory.cs
@@ -32,6 +32,7 @@ using OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Framework.Communications; 33using OpenSim.Framework.Communications;
34using OpenSim.Framework.Communications.Cache; 34using OpenSim.Framework.Communications.Cache;
35using OpenSim.Region.Framework.Interfaces;
35 36
36namespace OpenSim.Region.Framework.Scenes.Hypergrid 37namespace OpenSim.Region.Framework.Scenes.Hypergrid
37{ 38{
@@ -41,6 +42,21 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid
41 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42 43
43 private HGAssetMapper m_assMapper; 44 private HGAssetMapper m_assMapper;
45 public HGAssetMapper AssetMapper
46 {
47 get { return m_assMapper; }
48 }
49
50 private IHyperAssetService m_hyper;
51 private IHyperAssetService HyperAssets
52 {
53 get
54 {
55 if (m_hyper == null)
56 m_hyper = RequestModuleInterface<IHyperAssetService>();
57 return m_hyper;
58 }
59 }
44 60
45 #endregion 61 #endregion
46 62
@@ -140,6 +156,16 @@ namespace OpenSim.Region.Framework.Scenes.Hypergrid
140 156
141 } 157 }
142 158
159 protected override void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver)
160 {
161 string userAssetServer = HyperAssets.GetUserAssetServer(sender);
162 if ((userAssetServer != string.Empty) && (userAssetServer != HyperAssets.GetSimAssetServer()))
163 m_assMapper.Get(item.AssetID, sender);
164
165 userAssetServer = HyperAssets.GetUserAssetServer(receiver);
166 if ((userAssetServer != string.Empty) && (userAssetServer != HyperAssets.GetSimAssetServer()))
167 m_assMapper.Post(item.AssetID, receiver);
168 }
143 169
144 #endregion 170 #endregion
145 171
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index 9f7083f..890126f 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -408,7 +408,7 @@ namespace OpenSim.Region.Framework.Scenes
408 public virtual InventoryItemBase GiveInventoryItem( 408 public virtual InventoryItemBase GiveInventoryItem(
409 UUID recipient, UUID senderId, UUID itemId, UUID recipientFolderId) 409 UUID recipient, UUID senderId, UUID itemId, UUID recipientFolderId)
410 { 410 {
411 Console.WriteLine("Scene.Inventory.cs: GiveInventoryItem"); 411 //Console.WriteLine("Scene.Inventory.cs: GiveInventoryItem");
412 412
413 InventoryItemBase item = new InventoryItemBase(itemId, senderId); 413 InventoryItemBase item = new InventoryItemBase(itemId, senderId);
414 item = InventoryService.GetItem(item); 414 item = InventoryService.GetItem(item);
@@ -472,7 +472,8 @@ namespace OpenSim.Region.Framework.Scenes
472 itemCopy.SalePrice = item.SalePrice; 472 itemCopy.SalePrice = item.SalePrice;
473 itemCopy.SaleType = item.SaleType; 473 itemCopy.SaleType = item.SaleType;
474 474
475 InventoryService.AddItem(itemCopy); 475 if (InventoryService.AddItem(itemCopy))
476 TransferInventoryAssets(itemCopy, senderId, recipient);
476 477
477 if (!Permissions.BypassPermissions()) 478 if (!Permissions.BypassPermissions())
478 { 479 {
@@ -494,6 +495,10 @@ namespace OpenSim.Region.Framework.Scenes
494 495
495 } 496 }
496 497
498 protected virtual void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver)
499 {
500 }
501
497 /// <summary> 502 /// <summary>
498 /// Give an entire inventory folder from one user to another. The entire contents (including all descendent 503 /// Give an entire inventory folder from one user to another. The entire contents (including all descendent
499 /// folders) is given. 504 /// folders) is given.
diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
index 4ae4dc3..ac89f7b 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
@@ -390,6 +390,32 @@ namespace OpenSim.Region.Framework.Scenes
390 EventManager.TriggerScriptReset(part.LocalId, itemID); 390 EventManager.TriggerScriptReset(part.LocalId, itemID);
391 } 391 }
392 } 392 }
393
394 void ProcessViewerEffect(IClientAPI remoteClient, List<ViewerEffectEventHandlerArg> args)
395 {
396 // TODO: don't create new blocks if recycling an old packet
397 List<ViewerEffectPacket.EffectBlock> effectBlock = new List<ViewerEffectPacket.EffectBlock>();
398 for (int i = 0; i < args.Count; i++)
399 {
400 ViewerEffectPacket.EffectBlock effect = new ViewerEffectPacket.EffectBlock();
401 effect.AgentID = args[i].AgentID;
402 effect.Color = args[i].Color;
403 effect.Duration = args[i].Duration;
404 effect.ID = args[i].ID;
405 effect.Type = args[i].Type;
406 effect.TypeData = args[i].TypeData;
407 effectBlock.Add(effect);
408 }
409 ViewerEffectPacket.EffectBlock[] effectBlockArray = effectBlock.ToArray();
410
411 ClientManager.ForEach(
412 delegate(IClientAPI client)
413 {
414 if (client.AgentId != remoteClient.AgentId)
415 client.SendViewerEffect(effectBlockArray);
416 }
417 );
418 }
393 419
394 /// <summary> 420 /// <summary>
395 /// Handle a fetch inventory request from the client 421 /// Handle a fetch inventory request from the client
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 03111a6..fba9ea8 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -117,6 +117,8 @@ namespace OpenSim.Region.Framework.Scenes
117 private volatile bool m_backingup = false; 117 private volatile bool m_backingup = false;
118 118
119 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>(); 119 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
120
121 private Dictionary<UUID, SceneObjectGroup> m_groupsWithTargets = new Dictionary<UUID, SceneObjectGroup>();
120 122
121 protected string m_simulatorVersion = "OpenSimulator Server"; 123 protected string m_simulatorVersion = "OpenSimulator Server";
122 124
@@ -246,8 +248,7 @@ namespace OpenSim.Region.Framework.Scenes
246 248
247 private int m_update_physics = 1; 249 private int m_update_physics = 1;
248 private int m_update_entitymovement = 1; 250 private int m_update_entitymovement = 1;
249 private int m_update_entities = 1; // Run through all objects checking for updates 251 private int m_update_objects = 1; // Update objects which have scheduled themselves for updates
250 private int m_update_entitiesquick = 200; // Run through objects that have scheduled updates checking for updates
251 private int m_update_presences = 1; // Update scene presence movements 252 private int m_update_presences = 1; // Update scene presence movements
252 private int m_update_events = 1; 253 private int m_update_events = 1;
253 private int m_update_backup = 200; 254 private int m_update_backup = 200;
@@ -867,7 +868,7 @@ namespace OpenSim.Region.Framework.Scenes
867 Thread.Sleep(500); 868 Thread.Sleep(500);
868 869
869 // Stop all client threads. 870 // Stop all client threads.
870 ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(true); }); 871 ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(); });
871 872
872 // Stop updating the scene objects and agents. 873 // Stop updating the scene objects and agents.
873 //m_heartbeatTimer.Close(); 874 //m_heartbeatTimer.Close();
@@ -979,28 +980,7 @@ namespace OpenSim.Region.Framework.Scenes
979 maintc = Environment.TickCount; 980 maintc = Environment.TickCount;
980 981
981 TimeSpan SinceLastFrame = DateTime.Now - m_lastupdate; 982 TimeSpan SinceLastFrame = DateTime.Now - m_lastupdate;
982 // Aquire a lock so only one update call happens at once
983 //updateLock.WaitOne();
984 float physicsFPS = 0; 983 float physicsFPS = 0;
985 //m_log.Info("sadfadf" + m_neighbours.Count.ToString());
986 int agentsInScene = m_sceneGraph.GetRootAgentCount() + m_sceneGraph.GetChildAgentCount();
987
988 if (agentsInScene > 21)
989 {
990 if (m_update_entities == 1)
991 {
992 m_update_entities = 5;
993 StatsReporter.SetUpdateMS(6000);
994 }
995 }
996 else
997 {
998 if (m_update_entities == 5)
999 {
1000 m_update_entities = 1;
1001 StatsReporter.SetUpdateMS(3000);
1002 }
1003 }
1004 984
1005 frameMS = Environment.TickCount; 985 frameMS = Environment.TickCount;
1006 try 986 try
@@ -1013,30 +993,17 @@ namespace OpenSim.Region.Framework.Scenes
1013 m_frame = 0; 993 m_frame = 0;
1014 994
1015 otherMS = Environment.TickCount; 995 otherMS = Environment.TickCount;
1016 // run through all entities looking for updates (slow)
1017 if (m_frame % m_update_entities == 0)
1018 {
1019 /* // Adam Experimental
1020 if (m_updateEntitiesThread == null)
1021 {
1022 m_updateEntitiesThread = new Thread(m_sceneGraph.UpdateEntities);
1023
1024 ThreadTracker.Add(m_updateEntitiesThread);
1025 }
1026
1027 if (m_updateEntitiesThread.ThreadState == ThreadState.Stopped)
1028 m_updateEntitiesThread.Start();
1029 */
1030 996
1031 m_sceneGraph.UpdateEntities(); 997 // Check if any objects have reached their targets
1032 } 998 CheckAtTargets();
999
1000 // Update SceneObjectGroups that have scheduled themselves for updates
1001 // Objects queue their updates onto all scene presences
1002 if (m_frame % m_update_objects == 0)
1003 m_sceneGraph.UpdateObjectGroups();
1033 1004
1034 // run through entities that have scheduled themselves for 1005 // Run through all ScenePresences looking for updates
1035 // updates looking for updates(faster) 1006 // Presence updates and queued object updates for each presence are sent to clients
1036 if (m_frame % m_update_entitiesquick == 0)
1037 m_sceneGraph.ProcessUpdates();
1038
1039 // Run through scenepresences looking for updates
1040 if (m_frame % m_update_presences == 0) 1007 if (m_frame % m_update_presences == 0)
1041 m_sceneGraph.UpdatePresences(); 1008 m_sceneGraph.UpdatePresences();
1042 1009
@@ -1140,6 +1107,31 @@ namespace OpenSim.Region.Framework.Scenes
1140 } 1107 }
1141 } 1108 }
1142 1109
1110
1111 public void AddGroupTarget(SceneObjectGroup grp)
1112 {
1113 lock(m_groupsWithTargets)
1114 m_groupsWithTargets[grp.UUID] = grp;
1115 }
1116
1117 public void RemoveGroupTarget(SceneObjectGroup grp)
1118 {
1119 lock(m_groupsWithTargets)
1120 m_groupsWithTargets.Remove(grp.UUID);
1121 }
1122
1123 private void CheckAtTargets()
1124 {
1125 lock (m_groupsWithTargets)
1126 {
1127 foreach (KeyValuePair<UUID, SceneObjectGroup> kvp in m_groupsWithTargets)
1128 {
1129 kvp.Value.checkAtTargets();
1130 }
1131 }
1132 }
1133
1134
1143 /// <summary> 1135 /// <summary>
1144 /// Send out simstats data to all clients 1136 /// Send out simstats data to all clients
1145 /// </summary> 1137 /// </summary>
@@ -1186,10 +1178,10 @@ namespace OpenSim.Region.Framework.Scenes
1186 if (!m_backingup) 1178 if (!m_backingup)
1187 { 1179 {
1188 m_backingup = true; 1180 m_backingup = true;
1189 Thread backupthread = new Thread(Backup); 1181
1190 backupthread.Name = "BackupWriter"; 1182 System.ComponentModel.BackgroundWorker backupWorker = new System.ComponentModel.BackgroundWorker();
1191 backupthread.IsBackground = true; 1183 backupWorker.DoWork += delegate(object sender, System.ComponentModel.DoWorkEventArgs e) { Backup(); };
1192 backupthread.Start(); 1184 backupWorker.RunWorkerAsync();
1193 } 1185 }
1194 } 1186 }
1195 1187
@@ -1780,36 +1772,87 @@ namespace OpenSim.Region.Framework.Scenes
1780 1772
1781 Vector3 pos = attemptedPosition; 1773 Vector3 pos = attemptedPosition;
1782 1774
1775 int changeX = 1;
1776 int changeY = 1;
1777
1783 if (TestBorderCross(attemptedPosition + WestCross, Cardinals.W)) 1778 if (TestBorderCross(attemptedPosition + WestCross, Cardinals.W))
1784 { 1779 {
1785 if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) 1780 if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
1786 { 1781 {
1787 //Border crossedBorderx = GetCrossedBorder(attemptedPosition,Cardinals.W); 1782
1788 //Border crossedBordery = GetCrossedBorder(attemptedPosition, Cardinals.S); 1783 Border crossedBorderx = GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
1784
1785 if (crossedBorderx.BorderLine.Z > 0)
1786 {
1787 pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
1788 changeX = (int)(crossedBorderx.BorderLine.Z /(int) Constants.RegionSize);
1789 }
1790 else
1791 pos.X = ((pos.X + Constants.RegionSize));
1792
1793 Border crossedBordery = GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1789 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) 1794 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1790 pos.X = ((pos.X + Constants.RegionSize)); 1795
1791 pos.Y = ((pos.Y + Constants.RegionSize)); 1796 if (crossedBordery.BorderLine.Z > 0)
1797 {
1798 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
1799 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1800 }
1801 else
1802 pos.Y = ((pos.Y + Constants.RegionSize));
1803
1804
1805
1792 newRegionHandle 1806 newRegionHandle
1793 = Util.UIntsToLong((uint)((thisx - 1) * Constants.RegionSize), 1807 = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
1794 (uint)((thisy - 1) * Constants.RegionSize)); 1808 (uint)((thisy - changeY) * Constants.RegionSize));
1795 // x - 1 1809 // x - 1
1796 // y - 1 1810 // y - 1
1797 } 1811 }
1798 else if (TestBorderCross(attemptedPosition + NorthCross, Cardinals.N)) 1812 else if (TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
1799 { 1813 {
1800 pos.X = ((pos.X + Constants.RegionSize)); 1814 Border crossedBorderx = GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
1801 pos.Y = ((pos.Y - Constants.RegionSize)); 1815
1816 if (crossedBorderx.BorderLine.Z > 0)
1817 {
1818 pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
1819 changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
1820 }
1821 else
1822 pos.X = ((pos.X + Constants.RegionSize));
1823
1824
1825 Border crossedBordery = GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1826 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1827
1828 if (crossedBordery.BorderLine.Z > 0)
1829 {
1830 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
1831 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1832 }
1833 else
1834 pos.Y = ((pos.Y + Constants.RegionSize));
1835
1802 newRegionHandle 1836 newRegionHandle
1803 = Util.UIntsToLong((uint)((thisx - 1) * Constants.RegionSize), 1837 = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
1804 (uint)((thisy + 1) * Constants.RegionSize)); 1838 (uint)((thisy + changeY) * Constants.RegionSize));
1805 // x - 1 1839 // x - 1
1806 // y + 1 1840 // y + 1
1807 } 1841 }
1808 else 1842 else
1809 { 1843 {
1810 pos.X = ((pos.X + Constants.RegionSize)); 1844 Border crossedBorderx = GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
1845
1846 if (crossedBorderx.BorderLine.Z > 0)
1847 {
1848 pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
1849 changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
1850 }
1851 else
1852 pos.X = ((pos.X + Constants.RegionSize));
1853
1811 newRegionHandle 1854 newRegionHandle
1812 = Util.UIntsToLong((uint) ((thisx - 1)*Constants.RegionSize), 1855 = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
1813 (uint) (thisy*Constants.RegionSize)); 1856 (uint) (thisy*Constants.RegionSize));
1814 // x - 1 1857 // x - 1
1815 } 1858 }
@@ -1818,11 +1861,23 @@ namespace OpenSim.Region.Framework.Scenes
1818 { 1861 {
1819 if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) 1862 if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
1820 { 1863 {
1864
1821 pos.X = ((pos.X - Constants.RegionSize)); 1865 pos.X = ((pos.X - Constants.RegionSize));
1822 pos.Y = ((pos.Y + Constants.RegionSize)); 1866 Border crossedBordery = GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1867 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1868
1869 if (crossedBordery.BorderLine.Z > 0)
1870 {
1871 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
1872 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1873 }
1874 else
1875 pos.Y = ((pos.Y + Constants.RegionSize));
1876
1877
1823 newRegionHandle 1878 newRegionHandle
1824 = Util.UIntsToLong((uint)((thisx + 1) * Constants.RegionSize), 1879 = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
1825 (uint)((thisy - 1) * Constants.RegionSize)); 1880 (uint)((thisy - changeY) * Constants.RegionSize));
1826 // x + 1 1881 // x + 1
1827 // y - 1 1882 // y - 1
1828 } 1883 }
@@ -1831,8 +1886,8 @@ namespace OpenSim.Region.Framework.Scenes
1831 pos.X = ((pos.X - Constants.RegionSize)); 1886 pos.X = ((pos.X - Constants.RegionSize));
1832 pos.Y = ((pos.Y - Constants.RegionSize)); 1887 pos.Y = ((pos.Y - Constants.RegionSize));
1833 newRegionHandle 1888 newRegionHandle
1834 = Util.UIntsToLong((uint)((thisx + 1) * Constants.RegionSize), 1889 = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
1835 (uint)((thisy + 1) * Constants.RegionSize)); 1890 (uint)((thisy + changeY) * Constants.RegionSize));
1836 // x + 1 1891 // x + 1
1837 // y + 1 1892 // y + 1
1838 } 1893 }
@@ -1840,16 +1895,26 @@ namespace OpenSim.Region.Framework.Scenes
1840 { 1895 {
1841 pos.X = ((pos.X - Constants.RegionSize)); 1896 pos.X = ((pos.X - Constants.RegionSize));
1842 newRegionHandle 1897 newRegionHandle
1843 = Util.UIntsToLong((uint) ((thisx + 1)*Constants.RegionSize), 1898 = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
1844 (uint) (thisy*Constants.RegionSize)); 1899 (uint) (thisy*Constants.RegionSize));
1845 // x + 1 1900 // x + 1
1846 } 1901 }
1847 } 1902 }
1848 else if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) 1903 else if (TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
1849 { 1904 {
1850 pos.Y = ((pos.Y + Constants.RegionSize)); 1905 Border crossedBordery = GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1906 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1907
1908 if (crossedBordery.BorderLine.Z > 0)
1909 {
1910 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
1911 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1912 }
1913 else
1914 pos.Y = ((pos.Y + Constants.RegionSize));
1915
1851 newRegionHandle 1916 newRegionHandle
1852 = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy - 1) * Constants.RegionSize)); 1917 = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy - changeY) * Constants.RegionSize));
1853 // y - 1 1918 // y - 1
1854 } 1919 }
1855 else if (TestBorderCross(attemptedPosition + NorthCross, Cardinals.N)) 1920 else if (TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
@@ -1857,7 +1922,7 @@ namespace OpenSim.Region.Framework.Scenes
1857 1922
1858 pos.Y = ((pos.Y - Constants.RegionSize)); 1923 pos.Y = ((pos.Y - Constants.RegionSize));
1859 newRegionHandle 1924 newRegionHandle
1860 = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy + 1) * Constants.RegionSize)); 1925 = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy + changeY) * Constants.RegionSize));
1861 // y + 1 1926 // y + 1
1862 } 1927 }
1863 1928
@@ -2363,6 +2428,8 @@ namespace OpenSim.Region.Framework.Scenes
2363 /// <param name="client"></param> 2428 /// <param name="client"></param>
2364 public override void AddNewClient(IClientAPI client) 2429 public override void AddNewClient(IClientAPI client)
2365 { 2430 {
2431 ClientManager.Add(client);
2432
2366 CheckHeartbeat(); 2433 CheckHeartbeat();
2367 SubscribeToClientEvents(client); 2434 SubscribeToClientEvents(client);
2368 ScenePresence presence; 2435 ScenePresence presence;
@@ -2572,6 +2639,7 @@ namespace OpenSim.Region.Framework.Scenes
2572 public virtual void SubscribeToClientNetworkEvents(IClientAPI client) 2639 public virtual void SubscribeToClientNetworkEvents(IClientAPI client)
2573 { 2640 {
2574 client.OnNetworkStatsUpdate += StatsReporter.AddPacketsStats; 2641 client.OnNetworkStatsUpdate += StatsReporter.AddPacketsStats;
2642 client.OnViewerEffect += ProcessViewerEffect;
2575 } 2643 }
2576 2644
2577 protected virtual void UnsubscribeToClientEvents(IClientAPI client) 2645 protected virtual void UnsubscribeToClientEvents(IClientAPI client)
@@ -2726,11 +2794,9 @@ namespace OpenSim.Region.Framework.Scenes
2726 public virtual void UnSubscribeToClientNetworkEvents(IClientAPI client) 2794 public virtual void UnSubscribeToClientNetworkEvents(IClientAPI client)
2727 { 2795 {
2728 client.OnNetworkStatsUpdate -= StatsReporter.AddPacketsStats; 2796 client.OnNetworkStatsUpdate -= StatsReporter.AddPacketsStats;
2797 client.OnViewerEffect -= ProcessViewerEffect;
2729 } 2798 }
2730 2799
2731
2732
2733
2734 /// <summary> 2800 /// <summary>
2735 /// Teleport an avatar to their home region 2801 /// Teleport an avatar to their home region
2736 /// </summary> 2802 /// </summary>
@@ -3003,7 +3069,9 @@ namespace OpenSim.Region.Framework.Scenes
3003 agentTransactions.RemoveAgentAssetTransactions(agentID); 3069 agentTransactions.RemoveAgentAssetTransactions(agentID);
3004 } 3070 }
3005 3071
3072 // Remove the avatar from the scene
3006 m_sceneGraph.RemoveScenePresence(agentID); 3073 m_sceneGraph.RemoveScenePresence(agentID);
3074 ClientManager.Remove(agentID);
3007 3075
3008 try 3076 try
3009 { 3077 {
@@ -3053,16 +3121,6 @@ namespace OpenSim.Region.Framework.Scenes
3053 } 3121 }
3054 3122
3055 /// <summary> 3123 /// <summary>
3056 /// Closes all endpoints with the circuitcode provided.
3057 /// </summary>
3058 /// <param name="circuitcode">Circuit Code of the endpoint to close</param>
3059 public override void CloseAllAgents(uint circuitcode)
3060 {
3061 // Called by ClientView to kill all circuit codes
3062 ClientManager.CloseAllAgents(circuitcode);
3063 }
3064
3065 /// <summary>
3066 /// Inform all other ScenePresences on this Scene that someone else has changed position on the minimap. 3124 /// Inform all other ScenePresences on this Scene that someone else has changed position on the minimap.
3067 /// </summary> 3125 /// </summary>
3068 public void NotifyMyCoarseLocationChange() 3126 public void NotifyMyCoarseLocationChange()
@@ -3383,7 +3441,7 @@ namespace OpenSim.Region.Framework.Scenes
3383 loggingOffUser.ControllingClient.Kick(message); 3441 loggingOffUser.ControllingClient.Kick(message);
3384 // Give them a second to receive the message! 3442 // Give them a second to receive the message!
3385 Thread.Sleep(1000); 3443 Thread.Sleep(1000);
3386 loggingOffUser.ControllingClient.Close(true); 3444 loggingOffUser.ControllingClient.Close();
3387 } 3445 }
3388 else 3446 else
3389 { 3447 {
@@ -3554,7 +3612,7 @@ namespace OpenSim.Region.Framework.Scenes
3554 presence.ControllingClient.SendShutdownConnectionNotice(); 3612 presence.ControllingClient.SendShutdownConnectionNotice();
3555 } 3613 }
3556 3614
3557 presence.ControllingClient.Close(true); 3615 presence.ControllingClient.Close();
3558 return true; 3616 return true;
3559 } 3617 }
3560 3618
diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs
index 0ac4ed4..cf5c3c8 100644
--- a/OpenSim/Region/Framework/Scenes/SceneBase.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs
@@ -196,8 +196,6 @@ namespace OpenSim.Region.Framework.Scenes
196 /// <param name="agentID"></param> 196 /// <param name="agentID"></param>
197 public abstract void RemoveClient(UUID agentID); 197 public abstract void RemoveClient(UUID agentID);
198 198
199 public abstract void CloseAllAgents(uint circuitcode);
200
201 #endregion 199 #endregion
202 200
203 /// <summary> 201 /// <summary>
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index cda0bfc..ba5119f 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -77,7 +77,7 @@ namespace OpenSim.Region.Framework.Scenes
77 77
78 protected RegionInfo m_regInfo; 78 protected RegionInfo m_regInfo;
79 protected Scene m_parentScene; 79 protected Scene m_parentScene;
80 protected Dictionary<UUID, EntityBase> m_updateList = new Dictionary<UUID, EntityBase>(); 80 protected Dictionary<UUID, SceneObjectGroup> m_updateList = new Dictionary<UUID, SceneObjectGroup>();
81 protected int m_numRootAgents = 0; 81 protected int m_numRootAgents = 0;
82 protected int m_numPrim = 0; 82 protected int m_numPrim = 0;
83 protected int m_numChildAgents = 0; 83 protected int m_numChildAgents = 0;
@@ -155,16 +155,6 @@ namespace OpenSim.Region.Framework.Scenes
155 } 155 }
156 } 156 }
157 157
158 protected internal void UpdateEntities()
159 {
160 List<EntityBase> updateEntities = GetEntities();
161
162 foreach (EntityBase entity in updateEntities)
163 {
164 entity.Update();
165 }
166 }
167
168 protected internal void UpdatePresences() 158 protected internal void UpdatePresences()
169 { 159 {
170 List<ScenePresence> updateScenePresences = GetScenePresences(); 160 List<ScenePresence> updateScenePresences = GetScenePresences();
@@ -365,12 +355,12 @@ namespace OpenSim.Region.Framework.Scenes
365 } 355 }
366 356
367 /// <summary> 357 /// <summary>
368 /// Add an entity to the list of prims to process on the next update 358 /// Add an object to the list of prims to process on the next update
369 /// </summary> 359 /// </summary>
370 /// <param name="obj"> 360 /// <param name="obj">
371 /// A <see cref="EntityBase"/> 361 /// A <see cref="SceneObjectGroup"/>
372 /// </param> 362 /// </param>
373 protected internal void AddToUpdateList(EntityBase obj) 363 protected internal void AddToUpdateList(SceneObjectGroup obj)
374 { 364 {
375 lock (m_updateList) 365 lock (m_updateList)
376 { 366 {
@@ -381,18 +371,18 @@ namespace OpenSim.Region.Framework.Scenes
381 /// <summary> 371 /// <summary>
382 /// Process all pending updates 372 /// Process all pending updates
383 /// </summary> 373 /// </summary>
384 protected internal void ProcessUpdates() 374 protected internal void UpdateObjectGroups()
385 { 375 {
386 Dictionary<UUID, EntityBase> updates; 376 Dictionary<UUID, SceneObjectGroup> updates;
387 // Some updates add more updates to the updateList. 377 // Some updates add more updates to the updateList.
388 // Get the current list of updates and clear the list before iterating 378 // Get the current list of updates and clear the list before iterating
389 lock (m_updateList) 379 lock (m_updateList)
390 { 380 {
391 updates = new Dictionary<UUID, EntityBase>(m_updateList); 381 updates = new Dictionary<UUID, SceneObjectGroup>(m_updateList);
392 m_updateList.Clear(); 382 m_updateList.Clear();
393 } 383 }
394 // Go through all timers 384 // Go through all updates
395 foreach (KeyValuePair<UUID, EntityBase> kvp in updates) 385 foreach (KeyValuePair<UUID, SceneObjectGroup> kvp in updates)
396 { 386 {
397 // Don't abort the whole update if one entity happens to give us an exception. 387 // Don't abort the whole update if one entity happens to give us an exception.
398 try 388 try
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index be8a6c9..b8bd9b4 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -1241,6 +1241,7 @@ namespace OpenSim.Region.Framework.Scenes
1241 { 1241 {
1242 lock (m_targets) 1242 lock (m_targets)
1243 m_targets.Clear(); 1243 m_targets.Clear();
1244 m_scene.RemoveGroupTarget(this);
1244 } 1245 }
1245 1246
1246 ScheduleGroupForFullUpdate(); 1247 ScheduleGroupForFullUpdate();
@@ -1871,12 +1872,6 @@ namespace OpenSim.Region.Framework.Scenes
1871 m_rootPart.UpdateFlag = 1; 1872 m_rootPart.UpdateFlag = 1;
1872 lastPhysGroupPos = AbsolutePosition; 1873 lastPhysGroupPos = AbsolutePosition;
1873 } 1874 }
1874 //foreach (SceneObjectPart part in m_parts.Values)
1875 //{
1876 //if (part.UpdateFlag == 0) part.UpdateFlag = 1;
1877 //}
1878
1879 checkAtTargets();
1880 1875
1881 if (UsePhysics && ((Math.Abs(lastPhysGroupRot.W - GroupRotation.W) > 0.1) 1876 if (UsePhysics && ((Math.Abs(lastPhysGroupRot.W - GroupRotation.W) > 0.1)
1882 || (Math.Abs(lastPhysGroupRot.X - GroupRotation.X) > 0.1) 1877 || (Math.Abs(lastPhysGroupRot.X - GroupRotation.X) > 0.1)
@@ -3126,6 +3121,7 @@ namespace OpenSim.Region.Framework.Scenes
3126 { 3121 {
3127 m_targets.Add(handle, waypoint); 3122 m_targets.Add(handle, waypoint);
3128 } 3123 }
3124 m_scene.AddGroupTarget(this);
3129 return (int)handle; 3125 return (int)handle;
3130 } 3126 }
3131 3127
@@ -3133,12 +3129,13 @@ namespace OpenSim.Region.Framework.Scenes
3133 { 3129 {
3134 lock (m_targets) 3130 lock (m_targets)
3135 { 3131 {
3136 if (m_targets.ContainsKey((uint)handle)) 3132 m_targets.Remove((uint)handle);
3137 m_targets.Remove((uint)handle); 3133 if (m_targets.Count == 0)
3134 m_scene.RemoveGroupTarget(this);
3138 } 3135 }
3139 } 3136 }
3140 3137
3141 private void checkAtTargets() 3138 public void checkAtTargets()
3142 { 3139 {
3143 if (m_scriptListens_atTarget || m_scriptListens_notAtTarget) 3140 if (m_scriptListens_atTarget || m_scriptListens_notAtTarget)
3144 { 3141 {
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneBaseTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneBaseTests.cs
index 5c9e66f..8230f32 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneBaseTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneBaseTests.cs
@@ -61,11 +61,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests
61 throw new NotImplementedException(); 61 throw new NotImplementedException();
62 } 62 }
63 63
64 public override void CloseAllAgents(uint circuitcode)
65 {
66 throw new NotImplementedException();
67 }
68
69 public override void OtherRegionUp(GridRegion otherRegion) 64 public override void OtherRegionUp(GridRegion otherRegion)
70 { 65 {
71 throw new NotImplementedException(); 66 throw new NotImplementedException();
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/IRCStackModule.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/IRCStackModule.cs
index 4b199ac..4c2a4b9 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/IRCStackModule.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/IRCStackModule.cs
@@ -64,7 +64,6 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView
64 void user_OnIRCReady(IRCClientView cv) 64 void user_OnIRCReady(IRCClientView cv)
65 { 65 {
66 m_log.Info("[IRCd] Adding user..."); 66 m_log.Info("[IRCd] Adding user...");
67 m_scene.ClientManager.Add(cv.CircuitCode, cv);
68 cv.Start(); 67 cv.Start();
69 m_log.Info("[IRCd] Added user to Scene"); 68 m_log.Info("[IRCd] Added user to Scene");
70 } 69 }
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
index 4364627..a8acf0d 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
@@ -634,6 +634,12 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
634 { 634 {
635 get { return (uint)Util.RandomClass.Next(0,int.MaxValue); } 635 get { return (uint)Util.RandomClass.Next(0,int.MaxValue); }
636 } 636 }
637
638 public IPEndPoint RemoteEndPoint
639 {
640 get { return (IPEndPoint)m_client.Client.RemoteEndPoint; }
641 }
642
637#pragma warning disable 67 643#pragma warning disable 67
638 public event GenericMessage OnGenericMessage; 644 public event GenericMessage OnGenericMessage;
639 public event ImprovedInstantMessage OnInstantMessage; 645 public event ImprovedInstantMessage OnInstantMessage;
@@ -843,7 +849,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
843 849
844 } 850 }
845 851
846 public void Close(bool ShutdownCircuit) 852 public void Close()
847 { 853 {
848 Disconnect(); 854 Disconnect();
849 } 855 }
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs
index d6dacbc..b6513e2 100644
--- a/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs
@@ -183,8 +183,9 @@ namespace OpenSim.Region.OptionalModules.ContentManagement
183 public virtual void HideFromAll() 183 public virtual void HideFromAll()
184 { 184 {
185 foreach (SceneObjectPart part in m_Entity.Children.Values) 185 foreach (SceneObjectPart part in m_Entity.Children.Values)
186 m_Entity.Scene.ClientManager.ForEachClient(delegate(IClientAPI controller) 186 m_Entity.Scene.ClientManager.ForEach(
187 { controller.SendKillObject(m_Entity.RegionHandle, part.LocalId); } 187 delegate(IClientAPI controller)
188 { controller.SendKillObject(m_Entity.RegionHandle, part.LocalId); }
188 ); 189 );
189 } 190 }
190 191
@@ -201,8 +202,9 @@ namespace OpenSim.Region.OptionalModules.ContentManagement
201 202
202 public void SendFullUpdateToAll() 203 public void SendFullUpdateToAll()
203 { 204 {
204 m_Entity.Scene.ClientManager.ForEachClient(delegate(IClientAPI controller) 205 m_Entity.Scene.ClientManager.ForEach(
205 { m_Entity.SendFullUpdateToClient(controller); } 206 delegate(IClientAPI controller)
207 { m_Entity.SendFullUpdateToClient(controller); }
206 ); 208 );
207 } 209 }
208 210
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
index ac8b98c..f7c63ac 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -825,7 +825,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
825 { 825 {
826 } 826 }
827 827
828 public void Close(bool ShutdownCircuit) 828 public void Close()
829 { 829 {
830 } 830 }
831 831
@@ -838,11 +838,21 @@ namespace OpenSim.Region.OptionalModules.World.NPC
838 } 838 }
839 839
840 private uint m_circuitCode; 840 private uint m_circuitCode;
841 private IPEndPoint m_remoteEndPoint;
841 842
842 public uint CircuitCode 843 public uint CircuitCode
843 { 844 {
844 get { return m_circuitCode; } 845 get { return m_circuitCode; }
845 set { m_circuitCode = value; } 846 set
847 {
848 m_circuitCode = value;
849 m_remoteEndPoint = new IPEndPoint(IPAddress.Loopback, (ushort)m_circuitCode);
850 }
851 }
852
853 public IPEndPoint RemoteEndPoint
854 {
855 get { return m_remoteEndPoint; }
846 } 856 }
847 857
848 public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message) 858 public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message)
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
index 30a2675..41a6255 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
@@ -155,7 +155,6 @@ namespace OpenSim.Region.OptionalModules.World.NPC
155 NPCAvatar npcAvatar = new NPCAvatar(p_firstname, p_lastname, p_position, p_scene); 155 NPCAvatar npcAvatar = new NPCAvatar(p_firstname, p_lastname, p_position, p_scene);
156 npcAvatar.CircuitCode = (uint) Util.RandomClass.Next(0, int.MaxValue); 156 npcAvatar.CircuitCode = (uint) Util.RandomClass.Next(0, int.MaxValue);
157 157
158 p_scene.ClientManager.Add(npcAvatar.CircuitCode, npcAvatar);
159 p_scene.AddNewClient(npcAvatar); 158 p_scene.AddNewClient(npcAvatar);
160 159
161 ScenePresence sp; 160 ScenePresence sp;
diff --git a/OpenSim/Region/Physics/Meshing/PrimMesher.cs b/OpenSim/Region/Physics/Meshing/PrimMesher.cs
index a283840..47ce615 100644
--- a/OpenSim/Region/Physics/Meshing/PrimMesher.cs
+++ b/OpenSim/Region/Physics/Meshing/PrimMesher.cs
@@ -69,7 +69,7 @@ namespace PrimMesher
69 69
70 public Quat Identity() 70 public Quat Identity()
71 { 71 {
72 return new Quat(0.0f, 0.0f, 0.0f, 1.1f); 72 return new Quat(0.0f, 0.0f, 0.0f, 1.0f);
73 } 73 }
74 74
75 public float Length() 75 public float Length()
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index b79c356..7c176bb 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -863,7 +863,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
863 World.Entities.TryGetValue(objecUUID, out SensedObject); 863 World.Entities.TryGetValue(objecUUID, out SensedObject);
864 864
865 if (SensedObject == null) 865 if (SensedObject == null)
866 {
867 IGroupsModule groups = World.RequestModuleInterface<IGroupsModule>();
868 if (groups != null)
869 {
870 GroupRecord gr = groups.GetGroupRecord(objecUUID);
871 if (gr != null)
872 return gr.GroupName;
873 }
866 return String.Empty; 874 return String.Empty;
875 }
876
867 return SensedObject.Name; 877 return SensedObject.Name;
868 } 878 }
869 879