diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/Agent')
7 files changed, 570 insertions, 155 deletions
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs index f56d17d..f48710f 100644 --- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs +++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs | |||
@@ -127,7 +127,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
127 | if (estateModule.IsTerrainXfer(xferID)) | 127 | if (estateModule.IsTerrainXfer(xferID)) |
128 | return; | 128 | return; |
129 | } | 129 | } |
130 | 130 | ||
131 | m_log.ErrorFormat( | 131 | m_log.ErrorFormat( |
132 | "[AGENT ASSET TRANSACTIONS]: Could not find uploader for xfer id {0}, packet id {1}, data length {2}", | 132 | "[AGENT ASSET TRANSACTIONS]: Could not find uploader for xfer id {0}, packet id {1}, data length {2}", |
133 | xferID, packetID, data.Length); | 133 | xferID, packetID, data.Length); |
@@ -152,7 +152,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
152 | } | 152 | } |
153 | } | 153 | } |
154 | 154 | ||
155 | public void RequestCreateInventoryItem(IClientAPI remoteClient, | 155 | public bool RequestCreateInventoryItem(IClientAPI remoteClient, |
156 | UUID transactionID, UUID folderID, uint callbackID, | 156 | UUID transactionID, UUID folderID, uint callbackID, |
157 | string description, string name, sbyte invType, | 157 | string description, string name, sbyte invType, |
158 | sbyte type, byte wearableType, uint nextOwnerMask) | 158 | sbyte type, byte wearableType, uint nextOwnerMask) |
@@ -162,6 +162,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
162 | uploader.RequestCreateInventoryItem( | 162 | uploader.RequestCreateInventoryItem( |
163 | remoteClient, folderID, callbackID, | 163 | remoteClient, folderID, callbackID, |
164 | description, name, invType, type, wearableType, nextOwnerMask); | 164 | description, name, invType, type, wearableType, nextOwnerMask); |
165 | |||
166 | return true; | ||
165 | } | 167 | } |
166 | 168 | ||
167 | public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient, | 169 | public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient, |
@@ -170,6 +172,17 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
170 | { | 172 | { |
171 | AssetXferUploader uploader = RequestXferUploader(transactionID); | 173 | AssetXferUploader uploader = RequestXferUploader(transactionID); |
172 | 174 | ||
175 | // Here we need to get the old asset to extract the | ||
176 | // texture UUIDs if it's a wearable. | ||
177 | if (item.Type == (int)AssetType.Bodypart || | ||
178 | item.Type == (int)AssetType.Clothing || | ||
179 | item.Type == (int)CustomAssetType.AnimationSet) | ||
180 | { | ||
181 | AssetBase oldAsset = m_Scene.AssetService.Get(item.AssetID.ToString()); | ||
182 | if (oldAsset != null) | ||
183 | uploader.SetOldData(oldAsset.Data); | ||
184 | } | ||
185 | |||
173 | uploader.RequestUpdateTaskInventoryItem(remoteClient, item); | 186 | uploader.RequestUpdateTaskInventoryItem(remoteClient, item); |
174 | } | 187 | } |
175 | 188 | ||
@@ -178,7 +191,18 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
178 | { | 191 | { |
179 | AssetXferUploader uploader = RequestXferUploader(transactionID); | 192 | AssetXferUploader uploader = RequestXferUploader(transactionID); |
180 | 193 | ||
194 | // Here we need to get the old asset to extract the | ||
195 | // texture UUIDs if it's a wearable. | ||
196 | if (item.AssetType == (int)AssetType.Bodypart || | ||
197 | item.AssetType == (int)AssetType.Clothing || | ||
198 | item.AssetType == (int)CustomAssetType.AnimationSet) | ||
199 | { | ||
200 | AssetBase oldAsset = m_Scene.AssetService.Get(item.AssetID.ToString()); | ||
201 | if (oldAsset != null) | ||
202 | uploader.SetOldData(oldAsset.Data); | ||
203 | } | ||
204 | |||
181 | uploader.RequestUpdateInventoryItem(remoteClient, item); | 205 | uploader.RequestUpdateInventoryItem(remoteClient, item); |
182 | } | 206 | } |
183 | } | 207 | } |
184 | } \ No newline at end of file | 208 | } |
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs index b67c0df..7d9f3b3 100644 --- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs +++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs | |||
@@ -43,7 +43,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
43 | IAgentAssetTransactions | 43 | IAgentAssetTransactions |
44 | { | 44 | { |
45 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 45 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
46 | 46 | ||
47 | protected Scene m_Scene; | 47 | protected Scene m_Scene; |
48 | private bool m_dumpAssetsToFile = false; | 48 | private bool m_dumpAssetsToFile = false; |
49 | private int m_levelUpload = 0; | 49 | private int m_levelUpload = 0; |
@@ -53,7 +53,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
53 | /// </summary> | 53 | /// </summary> |
54 | private Dictionary<UUID, AgentAssetTransactions> AgentTransactions = | 54 | private Dictionary<UUID, AgentAssetTransactions> AgentTransactions = |
55 | new Dictionary<UUID, AgentAssetTransactions>(); | 55 | new Dictionary<UUID, AgentAssetTransactions>(); |
56 | 56 | ||
57 | #region Region Module interface | 57 | #region Region Module interface |
58 | 58 | ||
59 | public void Initialise(IConfigSource source) | 59 | public void Initialise(IConfigSource source) |
@@ -158,7 +158,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
158 | /// <param name="type"></param> | 158 | /// <param name="type"></param> |
159 | /// <param name="wearableType"></param> | 159 | /// <param name="wearableType"></param> |
160 | /// <param name="nextOwnerMask"></param> | 160 | /// <param name="nextOwnerMask"></param> |
161 | public void HandleItemCreationFromTransaction(IClientAPI remoteClient, | 161 | public bool HandleItemCreationFromTransaction(IClientAPI remoteClient, |
162 | UUID transactionID, UUID folderID, uint callbackID, | 162 | UUID transactionID, UUID folderID, uint callbackID, |
163 | string description, string name, sbyte invType, | 163 | string description, string name, sbyte invType, |
164 | sbyte type, byte wearableType, uint nextOwnerMask) | 164 | sbyte type, byte wearableType, uint nextOwnerMask) |
@@ -169,7 +169,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
169 | AgentAssetTransactions transactions = | 169 | AgentAssetTransactions transactions = |
170 | GetUserTransactions(remoteClient.AgentId); | 170 | GetUserTransactions(remoteClient.AgentId); |
171 | 171 | ||
172 | transactions.RequestCreateInventoryItem(remoteClient, transactionID, | 172 | return transactions.RequestCreateInventoryItem(remoteClient, transactionID, |
173 | folderID, callbackID, description, name, invType, type, | 173 | folderID, callbackID, description, name, invType, type, |
174 | wearableType, nextOwnerMask); | 174 | wearableType, nextOwnerMask); |
175 | } | 175 | } |
@@ -241,7 +241,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
241 | // m_log.DebugFormat( | 241 | // m_log.DebugFormat( |
242 | // "[ASSET TRANSACTION MODULE]: HandleUDPUploadRequest - assetID: {0}, transaction {1}, type {2}, storeLocal {3}, tempFile {4}, data.Length {5}", | 242 | // "[ASSET TRANSACTION MODULE]: HandleUDPUploadRequest - assetID: {0}, transaction {1}, type {2}, storeLocal {3}, tempFile {4}, data.Length {5}", |
243 | // assetID, transactionID, type, storeLocal, tempFile, data.Length); | 243 | // assetID, transactionID, type, storeLocal, tempFile, data.Length); |
244 | 244 | ||
245 | if (((AssetType)type == AssetType.Texture || | 245 | if (((AssetType)type == AssetType.Texture || |
246 | (AssetType)type == AssetType.Sound || | 246 | (AssetType)type == AssetType.Sound || |
247 | (AssetType)type == AssetType.TextureTGA || | 247 | (AssetType)type == AssetType.TextureTGA || |
@@ -255,7 +255,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
255 | // check user level | 255 | // check user level |
256 | if (avatar != null) | 256 | if (avatar != null) |
257 | { | 257 | { |
258 | if (avatar.UserLevel < m_levelUpload) | 258 | if (avatar.GodController.UserLevel < m_levelUpload) |
259 | { | 259 | { |
260 | remoteClient.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); | 260 | remoteClient.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); |
261 | return; | 261 | return; |
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs index 5143204..52b9d0e 100644 --- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs +++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs | |||
@@ -28,6 +28,7 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.IO; | 29 | using System.IO; |
30 | using System.Reflection; | 30 | using System.Reflection; |
31 | using System.Collections.Generic; | ||
31 | using log4net; | 32 | using log4net; |
32 | using OpenMetaverse; | 33 | using OpenMetaverse; |
33 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
@@ -40,6 +41,23 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
40 | { | 41 | { |
41 | public class AssetXferUploader | 42 | public class AssetXferUploader |
42 | { | 43 | { |
44 | |||
45 | private List<UUID> defaultIDs = new List<UUID> { | ||
46 | // Viewer's notion of the default texture | ||
47 | new UUID("5748decc-f629-461c-9a36-a35a221fe21f"), // others == default blank | ||
48 | new UUID("7ca39b4c-bd19-4699-aff7-f93fd03d3e7b"), // hair | ||
49 | new UUID("6522e74d-1660-4e7f-b601-6f48c1659a77"), // eyes | ||
50 | new UUID("c228d1cf-4b5d-4ba8-84f4-899a0796aa97"), // skin | ||
51 | new UUID("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"), // transparency for alpha | ||
52 | // opensim assets textures possibly obsolete now | ||
53 | new UUID("00000000-0000-1111-9999-000000000010"), | ||
54 | new UUID("00000000-0000-1111-9999-000000000011"), | ||
55 | new UUID("00000000-0000-1111-9999-000000000012"), | ||
56 | // other transparency defined in assets | ||
57 | new UUID("3a367d1c-bef1-6d43-7595-e88c1e3aadb3"), | ||
58 | new UUID("1578a2b1-5179-4b53-b618-fe00ca5a5594"), | ||
59 | }; | ||
60 | |||
43 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 61 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
44 | 62 | ||
45 | /// <summary> | 63 | /// <summary> |
@@ -87,6 +105,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
87 | 105 | ||
88 | private sbyte type = 0; | 106 | private sbyte type = 0; |
89 | private byte wearableType = 0; | 107 | private byte wearableType = 0; |
108 | private byte[] m_oldData = null; | ||
90 | public ulong XferID; | 109 | public ulong XferID; |
91 | private Scene m_Scene; | 110 | private Scene m_Scene; |
92 | 111 | ||
@@ -129,18 +148,27 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
129 | 148 | ||
130 | if (XferID == xferID) | 149 | if (XferID == xferID) |
131 | { | 150 | { |
132 | if (m_asset.Data.Length > 1) | 151 | lock (this) |
133 | { | ||
134 | byte[] destinationArray = new byte[m_asset.Data.Length + data.Length]; | ||
135 | Array.Copy(m_asset.Data, 0, destinationArray, 0, m_asset.Data.Length); | ||
136 | Array.Copy(data, 0, destinationArray, m_asset.Data.Length, data.Length); | ||
137 | m_asset.Data = destinationArray; | ||
138 | } | ||
139 | else | ||
140 | { | 152 | { |
141 | byte[] buffer2 = new byte[data.Length - 4]; | 153 | int assetLength = m_asset.Data.Length; |
142 | Array.Copy(data, 4, buffer2, 0, data.Length - 4); | 154 | int dataLength = data.Length; |
143 | m_asset.Data = buffer2; | 155 | |
156 | if (m_asset.Data.Length > 1) | ||
157 | { | ||
158 | byte[] destinationArray = new byte[assetLength + dataLength]; | ||
159 | Array.Copy(m_asset.Data, 0, destinationArray, 0, assetLength); | ||
160 | Array.Copy(data, 0, destinationArray, assetLength, dataLength); | ||
161 | m_asset.Data = destinationArray; | ||
162 | } | ||
163 | else | ||
164 | { | ||
165 | if (dataLength > 4) | ||
166 | { | ||
167 | byte[] buffer2 = new byte[dataLength - 4]; | ||
168 | Array.Copy(data, 4, buffer2, 0, dataLength - 4); | ||
169 | m_asset.Data = buffer2; | ||
170 | } | ||
171 | } | ||
144 | } | 172 | } |
145 | 173 | ||
146 | ourClient.SendConfirmXfer(xferID, packetID); | 174 | ourClient.SendConfirmXfer(xferID, packetID); |
@@ -230,24 +258,24 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
230 | { | 258 | { |
231 | m_uploadState = UploadState.Complete; | 259 | m_uploadState = UploadState.Complete; |
232 | 260 | ||
233 | ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true, m_asset.FullID); | 261 | bool sucess = true; |
234 | |||
235 | if (m_createItem) | 262 | if (m_createItem) |
236 | { | 263 | { |
237 | CompleteCreateItem(m_createItemCallback); | 264 | sucess = CompleteCreateItem(m_createItemCallback); |
238 | } | 265 | } |
239 | else if (m_updateItem) | 266 | else if (m_updateItem) |
240 | { | 267 | { |
241 | CompleteItemUpdate(m_updateItemData); | 268 | sucess = CompleteItemUpdate(m_updateItemData); |
242 | } | 269 | } |
243 | else if (m_updateTaskItem) | 270 | else if (m_updateTaskItem) |
244 | { | 271 | { |
245 | CompleteTaskItemUpdate(m_updateTaskItemData); | 272 | sucess = CompleteTaskItemUpdate(m_updateTaskItemData); |
246 | } | 273 | } |
247 | // else if (m_storeLocal) | 274 | else if (m_asset.Local) |
248 | // { | 275 | { |
249 | // m_Scene.AssetService.Store(m_asset); | 276 | m_Scene.AssetService.Store(m_asset); |
250 | // } | 277 | } |
278 | ourClient.SendAssetUploadCompleteMessage(m_asset.Type, sucess, m_asset.FullID); | ||
251 | } | 279 | } |
252 | 280 | ||
253 | m_log.DebugFormat( | 281 | m_log.DebugFormat( |
@@ -319,14 +347,16 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
319 | m_asset.Description = item.Description; | 347 | m_asset.Description = item.Description; |
320 | m_asset.Type = (sbyte)item.AssetType; | 348 | m_asset.Type = (sbyte)item.AssetType; |
321 | 349 | ||
322 | if (m_asset.FullID != UUID.Zero) | 350 | // remove redundante m_Scene.InventoryService.UpdateItem |
323 | { | 351 | // if uploadState == UploadState.Complete) |
352 | // if (m_asset.FullID != UUID.Zero) | ||
353 | // { | ||
324 | // We must always store the item at this point even if the asset hasn't finished uploading, in order | 354 | // We must always store the item at this point even if the asset hasn't finished uploading, in order |
325 | // to avoid a race condition when the appearance module retrieves the item to set the asset id in | 355 | // to avoid a race condition when the appearance module retrieves the item to set the asset id in |
326 | // the AvatarAppearance structure. | 356 | // the AvatarAppearance structure. |
327 | item.AssetID = m_asset.FullID; | 357 | // item.AssetID = m_asset.FullID; |
328 | m_Scene.InventoryService.UpdateItem(item); | 358 | // m_Scene.InventoryService.UpdateItem(item); |
329 | } | 359 | // } |
330 | 360 | ||
331 | if (m_uploadState == UploadState.Complete) | 361 | if (m_uploadState == UploadState.Complete) |
332 | { | 362 | { |
@@ -334,10 +364,21 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
334 | } | 364 | } |
335 | else | 365 | else |
336 | { | 366 | { |
337 | // m_log.DebugFormat( | 367 | // do it here to avoid the eventual race condition |
338 | // "[ASSET XFER UPLOADER]: Holding update inventory item request {0} for {1} pending completion of asset xfer for transaction {2}", | 368 | if (m_asset.FullID != UUID.Zero) |
339 | // item.Name, remoteClient.Name, transactionID); | 369 | { |
340 | 370 | // We must always store the item at this point even if the asset hasn't finished uploading, in order | |
371 | // to avoid a race condition when the appearance module retrieves the item to set the asset id in | ||
372 | // the AvatarAppearance structure. | ||
373 | item.AssetID = m_asset.FullID; | ||
374 | m_Scene.InventoryService.UpdateItem(item); | ||
375 | } | ||
376 | |||
377 | |||
378 | // m_log.DebugFormat( | ||
379 | // "[ASSET XFER UPLOADER]: Holding update inventory item request {0} for {1} pending completion of asset xfer for transaction {2}", | ||
380 | // item.Name, remoteClient.Name, transactionID); | ||
381 | |||
341 | m_updateItem = true; | 382 | m_updateItem = true; |
342 | m_updateItemData = item; | 383 | m_updateItemData = item; |
343 | } | 384 | } |
@@ -370,36 +411,70 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
370 | /// Store the asset for the given item when it has been uploaded. | 411 | /// Store the asset for the given item when it has been uploaded. |
371 | /// </summary> | 412 | /// </summary> |
372 | /// <param name="item"></param> | 413 | /// <param name="item"></param> |
373 | private void CompleteItemUpdate(InventoryItemBase item) | 414 | private bool CompleteItemUpdate(InventoryItemBase item) |
374 | { | 415 | { |
375 | // m_log.DebugFormat( | 416 | // m_log.DebugFormat( |
376 | // "[ASSET XFER UPLOADER]: Storing asset {0} for earlier item update for {1} for {2}", | 417 | // "[ASSET XFER UPLOADER]: Storing asset {0} for earlier item update for {1} for {2}", |
377 | // m_asset.FullID, item.Name, ourClient.Name); | 418 | // m_asset.FullID, item.Name, ourClient.Name); |
378 | 419 | ||
379 | m_Scene.AssetService.Store(m_asset); | 420 | uint perms = ValidateAssets(); |
380 | 421 | if(perms == 0) | |
381 | m_transactions.RemoveXferUploader(m_transactionID); | 422 | { |
423 | string error = string.Format("Not enough permissions on asset(s) referenced by item '{0}', update failed", item.Name); | ||
424 | ourClient.SendAlertMessage(error); | ||
425 | m_transactions.RemoveXferUploader(m_transactionID); | ||
426 | ourClient.SendBulkUpdateInventory(item); // invalid the change item on viewer cache | ||
427 | } | ||
428 | else | ||
429 | { | ||
430 | m_Scene.AssetService.Store(m_asset); | ||
431 | if (m_asset.FullID != UUID.Zero) | ||
432 | { | ||
433 | item.AssetID = m_asset.FullID; | ||
434 | m_Scene.InventoryService.UpdateItem(item); | ||
435 | } | ||
436 | ourClient.SendInventoryItemCreateUpdate(item, m_transactionID, 0); | ||
437 | m_transactions.RemoveXferUploader(m_transactionID); | ||
438 | m_Scene.EventManager.TriggerOnNewInventoryItemUploadComplete(item, 0); | ||
439 | } | ||
382 | 440 | ||
383 | m_Scene.EventManager.TriggerOnNewInventoryItemUploadComplete(ourClient.AgentId, (AssetType)type, m_asset.FullID, m_asset.Name, 0); | 441 | return perms != 0; |
384 | } | 442 | } |
385 | 443 | ||
386 | /// <summary> | 444 | /// <summary> |
387 | /// Store the asset for the given task item when it has been uploaded. | 445 | /// Store the asset for the given task item when it has been uploaded. |
388 | /// </summary> | 446 | /// </summary> |
389 | /// <param name="taskItem"></param> | 447 | /// <param name="taskItem"></param> |
390 | private void CompleteTaskItemUpdate(TaskInventoryItem taskItem) | 448 | private bool CompleteTaskItemUpdate(TaskInventoryItem taskItem) |
391 | { | 449 | { |
392 | // m_log.DebugFormat( | 450 | // m_log.DebugFormat( |
393 | // "[ASSET XFER UPLOADER]: Storing asset {0} for earlier task item update for {1} for {2}", | 451 | // "[ASSET XFER UPLOADER]: Storing asset {0} for earlier task item update for {1} for {2}", |
394 | // m_asset.FullID, taskItem.Name, ourClient.Name); | 452 | // m_asset.FullID, taskItem.Name, ourClient.Name); |
395 | 453 | ||
396 | m_Scene.AssetService.Store(m_asset); | 454 | if(ValidateAssets() == 0) |
455 | { | ||
456 | m_transactions.RemoveXferUploader(m_transactionID); | ||
457 | string error = string.Format("Not enough permissions on asset(s) referenced by task item '{0}', update failed", taskItem.Name); | ||
458 | ourClient.SendAlertMessage(error); | ||
459 | // force old asset to viewers ?? | ||
460 | return false; | ||
461 | } | ||
397 | 462 | ||
463 | m_Scene.AssetService.Store(m_asset); | ||
398 | m_transactions.RemoveXferUploader(m_transactionID); | 464 | m_transactions.RemoveXferUploader(m_transactionID); |
465 | return true; | ||
399 | } | 466 | } |
400 | 467 | ||
401 | private void CompleteCreateItem(uint callbackID) | 468 | private bool CompleteCreateItem(uint callbackID) |
402 | { | 469 | { |
470 | if(ValidateAssets() == 0) | ||
471 | { | ||
472 | m_transactions.RemoveXferUploader(m_transactionID); | ||
473 | string error = string.Format("Not enough permissions on asset(s) referenced by item '{0}', creation failed", m_name); | ||
474 | ourClient.SendAlertMessage(error); | ||
475 | return false; | ||
476 | } | ||
477 | |||
403 | m_Scene.AssetService.Store(m_asset); | 478 | m_Scene.AssetService.Store(m_asset); |
404 | 479 | ||
405 | InventoryItemBase item = new InventoryItemBase(); | 480 | InventoryItemBase item = new InventoryItemBase(); |
@@ -420,13 +495,155 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
420 | item.Flags = (uint) wearableType; | 495 | item.Flags = (uint) wearableType; |
421 | item.CreationDate = Util.UnixTimeSinceEpoch(); | 496 | item.CreationDate = Util.UnixTimeSinceEpoch(); |
422 | 497 | ||
498 | m_log.DebugFormat("[XFER]: Created item {0} with asset {1}", | ||
499 | item.ID, item.AssetID); | ||
500 | |||
423 | if (m_Scene.AddInventoryItem(item)) | 501 | if (m_Scene.AddInventoryItem(item)) |
424 | ourClient.SendInventoryItemCreateUpdate(item, callbackID); | 502 | ourClient.SendInventoryItemCreateUpdate(item, m_transactionID, callbackID); |
425 | else | 503 | else |
426 | ourClient.SendAlertMessage("Unable to create inventory item"); | 504 | ourClient.SendAlertMessage("Unable to create inventory item"); |
427 | 505 | ||
428 | m_transactions.RemoveXferUploader(m_transactionID); | 506 | m_transactions.RemoveXferUploader(m_transactionID); |
507 | return true; | ||
508 | } | ||
509 | |||
510 | private uint ValidateAssets() | ||
511 | { | ||
512 | uint retPerms = 0x7fffffff; | ||
513 | // if(m_Scene.Permissions.BypassPermissions()) | ||
514 | // return retPerms; | ||
515 | |||
516 | if (m_asset.Type == (sbyte)CustomAssetType.AnimationSet) | ||
517 | { | ||
518 | |||
519 | AnimationSet animSet = new AnimationSet(m_asset.Data); | ||
520 | |||
521 | retPerms &= animSet.Validate(x => { | ||
522 | const uint required = (uint)(PermissionMask.Transfer | PermissionMask.Copy); | ||
523 | uint perms = (uint)m_Scene.InventoryService.GetAssetPermissions(ourClient.AgentId, x); | ||
524 | // currrent yes/no rule | ||
525 | if ((perms & required) != required) | ||
526 | return 0; | ||
527 | return perms; | ||
528 | }); | ||
529 | |||
530 | return retPerms; | ||
531 | } | ||
532 | |||
533 | if (m_asset.Type == (sbyte)AssetType.Clothing || | ||
534 | m_asset.Type == (sbyte)AssetType.Bodypart) | ||
535 | { | ||
536 | const uint texturesfullPermMask = (uint)(PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Copy); | ||
537 | string content = System.Text.Encoding.ASCII.GetString(m_asset.Data); | ||
538 | string[] lines = content.Split(new char[] {'\n'}); | ||
539 | |||
540 | // on current requiriment of full rigths assume old assets where accepted | ||
541 | Dictionary<int, UUID> allowed = ExtractTexturesFromOldData(); | ||
542 | |||
543 | int textures = 0; | ||
544 | |||
545 | foreach (string line in lines) | ||
546 | { | ||
547 | try | ||
548 | { | ||
549 | if (line.StartsWith("textures ")) | ||
550 | textures = Convert.ToInt32(line.Substring(9)); | ||
551 | |||
552 | else if (textures > 0) | ||
553 | { | ||
554 | string[] parts = line.Split(new char[] {' '}); | ||
555 | |||
556 | UUID tx = new UUID(parts[1]); | ||
557 | int id = Convert.ToInt32(parts[0]); | ||
558 | |||
559 | if (defaultIDs.Contains(tx) || tx == UUID.Zero || | ||
560 | (allowed.ContainsKey(id) && allowed[id] == tx)) | ||
561 | { | ||
562 | continue; | ||
563 | } | ||
564 | else | ||
565 | { | ||
566 | uint perms = (uint)m_Scene.InventoryService.GetAssetPermissions(ourClient.AgentId, tx); | ||
567 | |||
568 | if ((perms & texturesfullPermMask) != texturesfullPermMask) | ||
569 | { | ||
570 | m_log.ErrorFormat("[ASSET UPLOADER]: REJECTED update with texture {0} from {1} because they do not own the texture", tx, ourClient.AgentId); | ||
571 | return 0; | ||
572 | } | ||
573 | else | ||
574 | { | ||
575 | retPerms &= perms; | ||
576 | } | ||
577 | } | ||
578 | textures--; | ||
579 | } | ||
580 | } | ||
581 | catch | ||
582 | { | ||
583 | // If it's malformed, skip it | ||
584 | } | ||
585 | } | ||
586 | } | ||
587 | return retPerms; | ||
588 | } | ||
589 | |||
590 | /* not in use | ||
591 | /// <summary> | ||
592 | /// Get the asset data uploaded in this transfer. | ||
593 | /// </summary> | ||
594 | /// <returns>null if the asset has not finished uploading</returns> | ||
595 | public AssetBase GetAssetData() | ||
596 | { | ||
597 | if (m_uploadState == UploadState.Complete) | ||
598 | { | ||
599 | ValidateAssets(); | ||
600 | return m_asset; | ||
601 | } | ||
602 | |||
603 | return null; | ||
604 | } | ||
605 | */ | ||
606 | public void SetOldData(byte[] d) | ||
607 | { | ||
608 | m_oldData = d; | ||
429 | } | 609 | } |
430 | 610 | ||
611 | private Dictionary<int,UUID> ExtractTexturesFromOldData() | ||
612 | { | ||
613 | Dictionary<int,UUID> result = new Dictionary<int,UUID>(); | ||
614 | if (m_oldData == null) | ||
615 | return result; | ||
616 | |||
617 | string content = System.Text.Encoding.ASCII.GetString(m_oldData); | ||
618 | string[] lines = content.Split(new char[] {'\n'}); | ||
619 | |||
620 | int textures = 0; | ||
621 | |||
622 | foreach (string line in lines) | ||
623 | { | ||
624 | try | ||
625 | { | ||
626 | if (line.StartsWith("textures ")) | ||
627 | { | ||
628 | textures = Convert.ToInt32(line.Substring(9)); | ||
629 | } | ||
630 | else if (textures > 0) | ||
631 | { | ||
632 | string[] parts = line.Split(new char[] {' '}); | ||
633 | |||
634 | UUID tx = new UUID(parts[1]); | ||
635 | int id = Convert.ToInt32(parts[0]); | ||
636 | result[id] = tx; | ||
637 | textures--; | ||
638 | } | ||
639 | } | ||
640 | catch | ||
641 | { | ||
642 | // If it's malformed, skip it | ||
643 | } | ||
644 | } | ||
645 | |||
646 | return result; | ||
647 | } | ||
431 | } | 648 | } |
432 | } \ No newline at end of file | 649 | } |
diff --git a/OpenSim/Region/CoreModules/Agent/IPBan/IPBanModule.cs b/OpenSim/Region/CoreModules/Agent/IPBan/IPBanModule.cs index 4b457b1..ff71593 100644 --- a/OpenSim/Region/CoreModules/Agent/IPBan/IPBanModule.cs +++ b/OpenSim/Region/CoreModules/Agent/IPBan/IPBanModule.cs | |||
@@ -38,7 +38,7 @@ using OpenSim.Region.Framework.Scenes; | |||
38 | namespace OpenSim.Region.CoreModules.Agent.IPBan | 38 | namespace OpenSim.Region.CoreModules.Agent.IPBan |
39 | { | 39 | { |
40 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "IPBanModule")] | 40 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "IPBanModule")] |
41 | public class IPBanModule : ISharedRegionModule | 41 | public class IPBanModule : ISharedRegionModule |
42 | { | 42 | { |
43 | #region Implementation of ISharedRegionModule | 43 | #region Implementation of ISharedRegionModule |
44 | 44 | ||
@@ -86,7 +86,7 @@ namespace OpenSim.Region.CoreModules.Agent.IPBan | |||
86 | 86 | ||
87 | public void Close() | 87 | public void Close() |
88 | { | 88 | { |
89 | 89 | ||
90 | } | 90 | } |
91 | 91 | ||
92 | public string Name | 92 | public string Name |
@@ -107,9 +107,9 @@ namespace OpenSim.Region.CoreModules.Agent.IPBan | |||
107 | /// matching domain (including "betasomewhere.com", "beta.somewhere.com", | 107 | /// matching domain (including "betasomewhere.com", "beta.somewhere.com", |
108 | /// "somewhere.com.beta") - make sure to be reasonably specific in DNS | 108 | /// "somewhere.com.beta") - make sure to be reasonably specific in DNS |
109 | /// bans. | 109 | /// bans. |
110 | /// | 110 | /// |
111 | /// IP address bans match on first characters, so, | 111 | /// IP address bans match on first characters, so, |
112 | /// "127.0.0.1" will ban only that address, | 112 | /// "127.0.0.1" will ban only that address, |
113 | /// "127.0.1" will ban "127.0.10.0" | 113 | /// "127.0.1" will ban "127.0.10.0" |
114 | /// but "127.0.1." will ban only the "127.0.1.*" network | 114 | /// but "127.0.1." will ban only the "127.0.1.*" network |
115 | /// </summary> | 115 | /// </summary> |
diff --git a/OpenSim/Region/CoreModules/Agent/IPBan/SceneBanner.cs b/OpenSim/Region/CoreModules/Agent/IPBan/SceneBanner.cs index 8502006..b4c68e2 100644 --- a/OpenSim/Region/CoreModules/Agent/IPBan/SceneBanner.cs +++ b/OpenSim/Region/CoreModules/Agent/IPBan/SceneBanner.cs | |||
@@ -53,9 +53,9 @@ namespace OpenSim.Region.CoreModules.Agent.IPBan | |||
53 | if (bans.Count > 0) | 53 | if (bans.Count > 0) |
54 | { | 54 | { |
55 | IClientIPEndpoint ipEndpoint; | 55 | IClientIPEndpoint ipEndpoint; |
56 | if (client.TryGet(out ipEndpoint)) | 56 | if (client.TryGet(out ipEndpoint) && ipEndpoint.RemoteEndPoint != null) |
57 | { | 57 | { |
58 | IPAddress end = ipEndpoint.EndPoint; | 58 | IPAddress end = ipEndpoint.RemoteEndPoint.Address; |
59 | 59 | ||
60 | try | 60 | try |
61 | { | 61 | { |
diff --git a/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs b/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs index 47dcbcd..6e4a710 100644 --- a/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs +++ b/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs | |||
@@ -57,13 +57,13 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender | |||
57 | /// <summary>List of client methods to notify of results of decode</summary> | 57 | /// <summary>List of client methods to notify of results of decode</summary> |
58 | private readonly Dictionary<UUID, List<DecodedCallback>> m_notifyList = new Dictionary<UUID, List<DecodedCallback>>(); | 58 | private readonly Dictionary<UUID, List<DecodedCallback>> m_notifyList = new Dictionary<UUID, List<DecodedCallback>>(); |
59 | /// <summary>Cache that will store decoded JPEG2000 layer boundary data</summary> | 59 | /// <summary>Cache that will store decoded JPEG2000 layer boundary data</summary> |
60 | private IImprovedAssetCache m_cache; | 60 | private IAssetCache m_cache; |
61 | private IImprovedAssetCache Cache | 61 | private IAssetCache Cache |
62 | { | 62 | { |
63 | get | 63 | get |
64 | { | 64 | { |
65 | if (m_cache == null) | 65 | if (m_cache == null) |
66 | m_cache = m_scene.RequestModuleInterface<IImprovedAssetCache>(); | 66 | m_cache = m_scene.RequestModuleInterface<IAssetCache>(); |
67 | 67 | ||
68 | return m_cache; | 68 | return m_cache; |
69 | } | 69 | } |
@@ -285,7 +285,7 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender | |||
285 | // Cache Decoded layers | 285 | // Cache Decoded layers |
286 | SaveFileCacheForAsset(assetID, layers); | 286 | SaveFileCacheForAsset(assetID, layers); |
287 | } | 287 | } |
288 | 288 | ||
289 | // Notify Interested Parties | 289 | // Notify Interested Parties |
290 | lock (m_notifyList) | 290 | lock (m_notifyList) |
291 | { | 291 | { |
@@ -369,7 +369,8 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender | |||
369 | else if (Cache != null) | 369 | else if (Cache != null) |
370 | { | 370 | { |
371 | string assetName = "j2kCache_" + AssetId.ToString(); | 371 | string assetName = "j2kCache_" + AssetId.ToString(); |
372 | AssetBase layerDecodeAsset = Cache.Get(assetName); | 372 | AssetBase layerDecodeAsset; |
373 | Cache.Get(assetName, out layerDecodeAsset); | ||
373 | 374 | ||
374 | if (layerDecodeAsset != null) | 375 | if (layerDecodeAsset != null) |
375 | { | 376 | { |
diff --git a/OpenSim/Region/CoreModules/Agent/Xfer/XferModule.cs b/OpenSim/Region/CoreModules/Agent/Xfer/XferModule.cs index 4299726..1b6401a 100644 --- a/OpenSim/Region/CoreModules/Agent/Xfer/XferModule.cs +++ b/OpenSim/Region/CoreModules/Agent/Xfer/XferModule.cs | |||
@@ -28,10 +28,12 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Reflection; | 30 | using System.Reflection; |
31 | using System.Threading; | ||
31 | using Nini.Config; | 32 | using Nini.Config; |
32 | using log4net; | 33 | using log4net; |
33 | using OpenMetaverse; | 34 | using OpenMetaverse; |
34 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
36 | using OpenSim.Framework.Monitoring; | ||
35 | using OpenSim.Region.Framework.Interfaces; | 37 | using OpenSim.Region.Framework.Interfaces; |
36 | using OpenSim.Region.Framework.Scenes; | 38 | using OpenSim.Region.Framework.Scenes; |
37 | 39 | ||
@@ -45,9 +47,13 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer | |||
45 | private Scene m_scene; | 47 | private Scene m_scene; |
46 | private Dictionary<string, FileData> NewFiles = new Dictionary<string, FileData>(); | 48 | private Dictionary<string, FileData> NewFiles = new Dictionary<string, FileData>(); |
47 | private Dictionary<ulong, XferDownLoad> Transfers = new Dictionary<ulong, XferDownLoad>(); | 49 | private Dictionary<ulong, XferDownLoad> Transfers = new Dictionary<ulong, XferDownLoad>(); |
48 | |||
49 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 50 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
50 | 51 | ||
52 | private object timeTickLock = new object(); | ||
53 | private double lastTimeTick = 0.0; | ||
54 | private double lastFilesExpire = 0.0; | ||
55 | private bool inTimeTick = false; | ||
56 | |||
51 | public struct XferRequest | 57 | public struct XferRequest |
52 | { | 58 | { |
53 | public IClientAPI remoteClient; | 59 | public IClientAPI remoteClient; |
@@ -59,26 +65,30 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer | |||
59 | private class FileData | 65 | private class FileData |
60 | { | 66 | { |
61 | public byte[] Data; | 67 | public byte[] Data; |
62 | public int Count; | 68 | public int refsCount; |
69 | public double timeStampMS; | ||
63 | } | 70 | } |
64 | 71 | ||
65 | #region INonSharedRegionModule Members | 72 | #region INonSharedRegionModule Members |
66 | 73 | ||
67 | public void Initialise(IConfigSource config) | 74 | public void Initialise(IConfigSource config) |
68 | { | 75 | { |
76 | lastTimeTick = Util.GetTimeStampMS() + 30000.0; | ||
77 | lastFilesExpire = lastTimeTick + 180000.0; | ||
69 | } | 78 | } |
70 | 79 | ||
71 | public void AddRegion(Scene scene) | 80 | public void AddRegion(Scene scene) |
72 | { | 81 | { |
73 | m_scene = scene; | 82 | m_scene = scene; |
74 | m_scene.EventManager.OnNewClient += NewClient; | ||
75 | |||
76 | m_scene.RegisterModuleInterface<IXfer>(this); | 83 | m_scene.RegisterModuleInterface<IXfer>(this); |
84 | m_scene.EventManager.OnNewClient += NewClient; | ||
85 | m_scene.EventManager.OnRegionHeartbeatEnd += OnTimeTick; | ||
77 | } | 86 | } |
78 | 87 | ||
79 | public void RemoveRegion(Scene scene) | 88 | public void RemoveRegion(Scene scene) |
80 | { | 89 | { |
81 | m_scene.EventManager.OnNewClient -= NewClient; | 90 | m_scene.EventManager.OnNewClient -= NewClient; |
91 | m_scene.EventManager.OnRegionHeartbeatEnd -= OnTimeTick; | ||
82 | 92 | ||
83 | m_scene.UnregisterModuleInterface<IXfer>(this); | 93 | m_scene.UnregisterModuleInterface<IXfer>(this); |
84 | m_scene = null; | 94 | m_scene = null; |
@@ -104,6 +114,41 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer | |||
104 | 114 | ||
105 | #endregion | 115 | #endregion |
106 | 116 | ||
117 | public void OnTimeTick(Scene scene) | ||
118 | { | ||
119 | // we are on a heartbeat thread we there can be several | ||
120 | if(Monitor.TryEnter(timeTickLock)) | ||
121 | { | ||
122 | if(!inTimeTick) | ||
123 | { | ||
124 | double now = Util.GetTimeStampMS(); | ||
125 | if(now - lastTimeTick > 1750.0) | ||
126 | { | ||
127 | |||
128 | if(Transfers.Count == 0 && NewFiles.Count == 0) | ||
129 | lastTimeTick = now; | ||
130 | else | ||
131 | { | ||
132 | inTimeTick = true; | ||
133 | |||
134 | //don't overload busy heartbeat | ||
135 | WorkManager.RunInThreadPool( | ||
136 | delegate | ||
137 | { | ||
138 | transfersTimeTick(now); | ||
139 | expireFiles(now); | ||
140 | |||
141 | lastTimeTick = now; | ||
142 | inTimeTick = false; | ||
143 | }, | ||
144 | null, | ||
145 | "XferTimeTick"); | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | Monitor.Exit(timeTickLock); | ||
150 | } | ||
151 | } | ||
107 | #region IXfer Members | 152 | #region IXfer Members |
108 | 153 | ||
109 | /// <summary> | 154 | /// <summary> |
@@ -118,24 +163,45 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer | |||
118 | { | 163 | { |
119 | lock (NewFiles) | 164 | lock (NewFiles) |
120 | { | 165 | { |
166 | double now = Util.GetTimeStampMS(); | ||
121 | if (NewFiles.ContainsKey(fileName)) | 167 | if (NewFiles.ContainsKey(fileName)) |
122 | { | 168 | { |
123 | NewFiles[fileName].Count++; | 169 | NewFiles[fileName].refsCount++; |
124 | NewFiles[fileName].Data = data; | 170 | NewFiles[fileName].Data = data; |
171 | NewFiles[fileName].timeStampMS = now; | ||
125 | } | 172 | } |
126 | else | 173 | else |
127 | { | 174 | { |
128 | FileData fd = new FileData(); | 175 | FileData fd = new FileData(); |
129 | fd.Count = 1; | 176 | fd.refsCount = 1; |
130 | fd.Data = data; | 177 | fd.Data = data; |
178 | fd.timeStampMS = now; | ||
131 | NewFiles.Add(fileName, fd); | 179 | NewFiles.Add(fileName, fd); |
132 | } | 180 | } |
133 | } | 181 | } |
134 | |||
135 | return true; | 182 | return true; |
136 | } | 183 | } |
137 | 184 | ||
138 | #endregion | 185 | #endregion |
186 | public void expireFiles(double now) | ||
187 | { | ||
188 | lock (NewFiles) | ||
189 | { | ||
190 | // hopefully we will not have many files so nasty code will do it | ||
191 | if(now - lastFilesExpire > 120000.0) | ||
192 | { | ||
193 | lastFilesExpire = now; | ||
194 | List<string> expires = new List<string>(); | ||
195 | foreach(string fname in NewFiles.Keys) | ||
196 | { | ||
197 | if(NewFiles[fname].refsCount == 0 && now - NewFiles[fname].timeStampMS > 120000.0) | ||
198 | expires.Add(fname); | ||
199 | } | ||
200 | foreach(string fname in expires) | ||
201 | NewFiles.Remove(fname); | ||
202 | } | ||
203 | } | ||
204 | } | ||
139 | 205 | ||
140 | public void NewClient(IClientAPI client) | 206 | public void NewClient(IClientAPI client) |
141 | { | 207 | { |
@@ -144,6 +210,51 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer | |||
144 | client.OnAbortXfer += AbortXfer; | 210 | client.OnAbortXfer += AbortXfer; |
145 | } | 211 | } |
146 | 212 | ||
213 | public void OnClientClosed(IClientAPI client) | ||
214 | { | ||
215 | client.OnRequestXfer -= RequestXfer; | ||
216 | client.OnConfirmXfer -= AckPacket; | ||
217 | client.OnAbortXfer -= AbortXfer; | ||
218 | } | ||
219 | |||
220 | private void RemoveOrDecrementFile(string fileName) | ||
221 | { | ||
222 | // NewFiles must be locked | ||
223 | |||
224 | if (NewFiles.ContainsKey(fileName)) | ||
225 | { | ||
226 | if (NewFiles[fileName].refsCount == 1) | ||
227 | NewFiles.Remove(fileName); | ||
228 | else | ||
229 | NewFiles[fileName].refsCount--; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | public void transfersTimeTick(double now) | ||
234 | { | ||
235 | XferDownLoad[] xfrs; | ||
236 | lock(Transfers) | ||
237 | { | ||
238 | if(Transfers.Count == 0) | ||
239 | return; | ||
240 | |||
241 | xfrs = new XferDownLoad[Transfers.Count]; | ||
242 | Transfers.Values.CopyTo(xfrs,0); | ||
243 | } | ||
244 | foreach(XferDownLoad xfr in xfrs) | ||
245 | { | ||
246 | if(xfr.checkTime(now)) | ||
247 | { | ||
248 | ulong xfrID = xfr.XferID; | ||
249 | lock(Transfers) | ||
250 | { | ||
251 | if(Transfers.ContainsKey(xfrID)) | ||
252 | Transfers.Remove(xfrID); | ||
253 | } | ||
254 | } | ||
255 | } | ||
256 | } | ||
257 | |||
147 | /// <summary> | 258 | /// <summary> |
148 | /// | 259 | /// |
149 | /// </summary> | 260 | /// </summary> |
@@ -156,78 +267,52 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer | |||
156 | { | 267 | { |
157 | if (NewFiles.ContainsKey(fileName)) | 268 | if (NewFiles.ContainsKey(fileName)) |
158 | { | 269 | { |
159 | if (!Transfers.ContainsKey(xferID)) | 270 | lock(Transfers) |
160 | { | 271 | { |
161 | byte[] fileData = NewFiles[fileName].Data; | 272 | if (!Transfers.ContainsKey(xferID)) |
162 | XferDownLoad transaction = new XferDownLoad(fileName, fileData, xferID, remoteClient); | 273 | { |
163 | 274 | byte[] fileData = NewFiles[fileName].Data; | |
164 | Transfers.Add(xferID, transaction); | 275 | int burstSize = remoteClient.GetAgentThrottleSilent((int)ThrottleOutPacketType.Asset) >> 11; |
165 | 276 | if(Transfers.Count > 1) | |
166 | if (transaction.StartSend()) | 277 | burstSize /= Transfers.Count; |
167 | RemoveXferData(xferID); | 278 | XferDownLoad transaction = |
168 | 279 | new XferDownLoad(fileName, fileData, xferID, remoteClient, burstSize); | |
169 | // The transaction for this file is either complete or on its way | 280 | |
170 | RemoveOrDecrement(fileName); | 281 | Transfers.Add(xferID, transaction); |
171 | 282 | ||
283 | transaction.StartSend(); | ||
284 | |||
285 | // The transaction for this file is on its way | ||
286 | RemoveOrDecrementFile(fileName); | ||
287 | } | ||
172 | } | 288 | } |
173 | } | 289 | } |
174 | else | 290 | else |
175 | m_log.WarnFormat("[Xfer]: {0} not found", fileName); | 291 | m_log.WarnFormat("[Xfer]: {0} not found", fileName); |
176 | |||
177 | } | 292 | } |
178 | } | 293 | } |
179 | 294 | ||
180 | public void AckPacket(IClientAPI remoteClient, ulong xferID, uint packet) | 295 | public void AckPacket(IClientAPI remoteClient, ulong xferID, uint packet) |
181 | { | 296 | { |
182 | lock (NewFiles) // This is actually to lock Transfers | 297 | lock (Transfers) |
183 | { | 298 | { |
184 | if (Transfers.ContainsKey(xferID)) | 299 | if (Transfers.ContainsKey(xferID)) |
185 | { | 300 | { |
186 | XferDownLoad dl = Transfers[xferID]; | ||
187 | if (Transfers[xferID].AckPacket(packet)) | 301 | if (Transfers[xferID].AckPacket(packet)) |
188 | { | 302 | Transfers.Remove(xferID); |
189 | RemoveXferData(xferID); | ||
190 | RemoveOrDecrement(dl.FileName); | ||
191 | } | ||
192 | } | 303 | } |
193 | } | 304 | } |
194 | } | 305 | } |
195 | 306 | ||
196 | private void RemoveXferData(ulong xferID) | ||
197 | { | ||
198 | // NewFiles must be locked! | ||
199 | if (Transfers.ContainsKey(xferID)) | ||
200 | { | ||
201 | XferModule.XferDownLoad xferItem = Transfers[xferID]; | ||
202 | //string filename = xferItem.FileName; | ||
203 | Transfers.Remove(xferID); | ||
204 | xferItem.Data = new byte[0]; // Clear the data | ||
205 | xferItem.DataPointer = 0; | ||
206 | |||
207 | } | ||
208 | } | ||
209 | |||
210 | public void AbortXfer(IClientAPI remoteClient, ulong xferID) | 307 | public void AbortXfer(IClientAPI remoteClient, ulong xferID) |
211 | { | 308 | { |
212 | lock (NewFiles) | 309 | lock (Transfers) |
213 | { | 310 | { |
214 | if (Transfers.ContainsKey(xferID)) | 311 | if (Transfers.ContainsKey(xferID)) |
215 | RemoveOrDecrement(Transfers[xferID].FileName); | 312 | { |
216 | 313 | Transfers[xferID].done(); | |
217 | RemoveXferData(xferID); | 314 | Transfers.Remove(xferID); |
218 | } | 315 | } |
219 | } | ||
220 | |||
221 | private void RemoveOrDecrement(string fileName) | ||
222 | { | ||
223 | // NewFiles must be locked | ||
224 | |||
225 | if (NewFiles.ContainsKey(fileName)) | ||
226 | { | ||
227 | if (NewFiles[fileName].Count == 1) | ||
228 | NewFiles.Remove(fileName); | ||
229 | else | ||
230 | NewFiles[fileName].Count--; | ||
231 | } | 316 | } |
232 | } | 317 | } |
233 | 318 | ||
@@ -236,52 +321,124 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer | |||
236 | public class XferDownLoad | 321 | public class XferDownLoad |
237 | { | 322 | { |
238 | public IClientAPI Client; | 323 | public IClientAPI Client; |
239 | private bool complete; | ||
240 | public byte[] Data = new byte[0]; | 324 | public byte[] Data = new byte[0]; |
241 | public int DataPointer = 0; | ||
242 | public string FileName = String.Empty; | 325 | public string FileName = String.Empty; |
243 | public uint Packet = 0; | ||
244 | public uint Serial = 1; | ||
245 | public ulong XferID = 0; | 326 | public ulong XferID = 0; |
246 | 327 | public bool isDeleted = false; | |
247 | public XferDownLoad(string fileName, byte[] data, ulong xferID, IClientAPI client) | 328 | |
329 | private object myLock = new object(); | ||
330 | private double lastsendTimeMS; | ||
331 | private int LastPacket; | ||
332 | private int lastBytes; | ||
333 | private int lastSentPacket; | ||
334 | private int lastAckPacket; | ||
335 | private int burstSize; | ||
336 | private int retries = 0; | ||
337 | |||
338 | public XferDownLoad(string fileName, byte[] data, ulong xferID, IClientAPI client, int burstsz) | ||
248 | { | 339 | { |
249 | FileName = fileName; | 340 | FileName = fileName; |
250 | Data = data; | 341 | Data = data; |
251 | XferID = xferID; | 342 | XferID = xferID; |
252 | Client = client; | 343 | Client = client; |
344 | burstSize = burstsz; | ||
253 | } | 345 | } |
254 | 346 | ||
255 | public XferDownLoad() | 347 | public XferDownLoad() |
256 | { | 348 | { |
257 | } | 349 | } |
258 | 350 | ||
351 | public void done() | ||
352 | { | ||
353 | if(!isDeleted) | ||
354 | { | ||
355 | Data = new byte[0]; | ||
356 | isDeleted = true; | ||
357 | } | ||
358 | } | ||
359 | |||
259 | /// <summary> | 360 | /// <summary> |
260 | /// Start a transfer | 361 | /// Start a transfer |
261 | /// </summary> | 362 | /// </summary> |
262 | /// <returns>True if the transfer is complete, false if not</returns> | 363 | /// <returns>True if the transfer is complete, false if not</returns> |
263 | public bool StartSend() | 364 | public void StartSend() |
264 | { | 365 | { |
265 | if (Data.Length < 1000) | 366 | lock(myLock) |
266 | { | 367 | { |
267 | // for now (testing) we only support files under 1000 bytes | 368 | if(Data.Length == 0) //?? |
268 | byte[] transferData = new byte[Data.Length + 4]; | 369 | { |
269 | Array.Copy(Utils.IntToBytes(Data.Length), 0, transferData, 0, 4); | 370 | LastPacket = 0; |
270 | Array.Copy(Data, 0, transferData, 4, Data.Length); | 371 | lastBytes = 0; |
271 | Client.SendXferPacket(XferID, 0 + 0x80000000, transferData); | 372 | burstSize = 0; |
272 | complete = true; | 373 | } |
374 | else | ||
375 | { | ||
376 | // payload of 1024bytes | ||
377 | LastPacket = Data.Length >> 10; | ||
378 | lastBytes = Data.Length & 0x3ff; | ||
379 | if(lastBytes == 0) | ||
380 | { | ||
381 | lastBytes = 1024; | ||
382 | LastPacket--; | ||
383 | } | ||
384 | |||
385 | } | ||
386 | |||
387 | lastAckPacket = -1; | ||
388 | lastSentPacket = -1; | ||
389 | |||
390 | double now = Util.GetTimeStampMS(); | ||
391 | |||
392 | SendBurst(now); | ||
393 | return; | ||
394 | } | ||
395 | } | ||
396 | |||
397 | private void SendBurst(double now) | ||
398 | { | ||
399 | int start = lastAckPacket + 1; | ||
400 | int end = start + burstSize; | ||
401 | if (end > LastPacket) | ||
402 | end = LastPacket; | ||
403 | while(start <= end) | ||
404 | SendPacket(start++ , now); | ||
405 | } | ||
406 | |||
407 | private void SendPacket(int pkt, double now) | ||
408 | { | ||
409 | if(pkt > LastPacket) | ||
410 | return; | ||
411 | |||
412 | int pktsize; | ||
413 | uint pktid; | ||
414 | if (pkt == LastPacket) | ||
415 | { | ||
416 | pktsize = lastBytes; | ||
417 | pktid = (uint)pkt | 0x80000000u; | ||
273 | } | 418 | } |
274 | else | 419 | else |
275 | { | 420 | { |
276 | byte[] transferData = new byte[1000 + 4]; | 421 | pktsize = 1024; |
422 | pktid = (uint)pkt; | ||
423 | } | ||
424 | |||
425 | byte[] transferData; | ||
426 | if(pkt == 0) | ||
427 | { | ||
428 | transferData = new byte[pktsize + 4]; | ||
277 | Array.Copy(Utils.IntToBytes(Data.Length), 0, transferData, 0, 4); | 429 | Array.Copy(Utils.IntToBytes(Data.Length), 0, transferData, 0, 4); |
278 | Array.Copy(Data, 0, transferData, 4, 1000); | 430 | Array.Copy(Data, 0, transferData, 4, pktsize); |
279 | Client.SendXferPacket(XferID, 0, transferData); | ||
280 | Packet++; | ||
281 | DataPointer = 1000; | ||
282 | } | 431 | } |
432 | else | ||
433 | { | ||
434 | transferData = new byte[pktsize]; | ||
435 | Array.Copy(Data, pkt << 10, transferData, 0, pktsize); | ||
436 | } | ||
437 | |||
438 | Client.SendXferPacket(XferID, pktid, transferData, false); | ||
283 | 439 | ||
284 | return complete; | 440 | lastSentPacket = pkt; |
441 | lastsendTimeMS = now; | ||
285 | } | 442 | } |
286 | 443 | ||
287 | /// <summary> | 444 | /// <summary> |
@@ -291,30 +448,46 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer | |||
291 | /// <returns>True if the transfer is complete, false otherwise</returns> | 448 | /// <returns>True if the transfer is complete, false otherwise</returns> |
292 | public bool AckPacket(uint packet) | 449 | public bool AckPacket(uint packet) |
293 | { | 450 | { |
294 | if (!complete) | 451 | lock(myLock) |
295 | { | 452 | { |
296 | if ((Data.Length - DataPointer) > 1000) | 453 | if(isDeleted) |
454 | return true; | ||
455 | |||
456 | packet &= 0x7fffffff; | ||
457 | if(lastAckPacket < packet) | ||
458 | lastAckPacket = (int)packet; | ||
459 | |||
460 | if(lastAckPacket == LastPacket) | ||
297 | { | 461 | { |
298 | byte[] transferData = new byte[1000]; | 462 | done(); |
299 | Array.Copy(Data, DataPointer, transferData, 0, 1000); | 463 | return true; |
300 | Client.SendXferPacket(XferID, Packet, transferData); | ||
301 | Packet++; | ||
302 | DataPointer += 1000; | ||
303 | } | 464 | } |
304 | else | 465 | double now = Util.GetTimeStampMS(); |
466 | SendPacket(lastSentPacket + 1, now); | ||
467 | return false; | ||
468 | } | ||
469 | } | ||
470 | |||
471 | public bool checkTime(double now) | ||
472 | { | ||
473 | if(Monitor.TryEnter(myLock)) | ||
474 | { | ||
475 | if(!isDeleted) | ||
305 | { | 476 | { |
306 | byte[] transferData = new byte[Data.Length - DataPointer]; | 477 | double timeMS = now - lastsendTimeMS; |
307 | Array.Copy(Data, DataPointer, transferData, 0, Data.Length - DataPointer); | 478 | if(timeMS > 60000.0) |
308 | uint endPacket = Packet |= (uint) 0x80000000; | 479 | done(); |
309 | Client.SendXferPacket(XferID, endPacket, transferData); | 480 | else if(timeMS > 3500.0 && retries++ < 3) |
310 | Packet++; | 481 | { |
311 | DataPointer += (Data.Length - DataPointer); | 482 | burstSize >>= 1; |
312 | 483 | SendBurst(now); | |
313 | complete = true; | 484 | } |
314 | } | 485 | } |
315 | } | ||
316 | 486 | ||
317 | return complete; | 487 | Monitor.Exit(myLock); |
488 | return isDeleted; | ||
489 | } | ||
490 | return false; | ||
318 | } | 491 | } |
319 | } | 492 | } |
320 | 493 | ||