diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs')
-rw-r--r-- | OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs | 295 |
1 files changed, 256 insertions, 39 deletions
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 | } |