From d51ce47b2d7635b17f3dd429158e8f59b78b83aa Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Thu, 1 May 2008 14:31:30 +0000 Subject: Update svn properties. Minor formatting cleanup. --- .../Agent/AssetDownload/AssetDownloadModule.cs | 454 ++++++------ .../AssetTransaction/AgentAssetsTransactions.cs | 822 ++++++++++----------- .../AssetTransaction/AssetTransactionModule.cs | 580 +++++++-------- .../Agent/TextureDownload/TextureDownloadModule.cs | 436 +++++------ .../Agent/TextureDownload/TextureNotFoundSender.cs | 194 ++--- .../TextureDownload/UserTextureDownloadService.cs | 496 ++++++------- .../Modules/Agent/TextureSender/TextureSender.cs | 444 +++++------ .../Environment/Modules/Agent/Xfer/XferModule.cs | 468 ++++++------ 8 files changed, 1947 insertions(+), 1947 deletions(-) (limited to 'OpenSim/Region/Environment/Modules/Agent') diff --git a/OpenSim/Region/Environment/Modules/Agent/AssetDownload/AssetDownloadModule.cs b/OpenSim/Region/Environment/Modules/Agent/AssetDownload/AssetDownloadModule.cs index c0b7380..48db51b 100644 --- a/OpenSim/Region/Environment/Modules/Agent/AssetDownload/AssetDownloadModule.cs +++ b/OpenSim/Region/Environment/Modules/Agent/AssetDownload/AssetDownloadModule.cs @@ -1,228 +1,228 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSim Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Collections.Generic; -using libsecondlife; -using libsecondlife.Packets; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules.Agent.AssetDownload -{ - public class AssetDownloadModule : IRegionModule - { - /// - /// Asset requests with data which are ready to be sent back to requesters. This includes textures. - /// - private List AssetRequests; - - private Scene m_scene; - private Dictionary RegisteredScenes = new Dictionary(); - - /// - /// Assets requests (for each user) which are waiting for asset server data. This includes texture requests - /// - private Dictionary> RequestedAssets; - - public AssetDownloadModule() - { - RequestedAssets = new Dictionary>(); - AssetRequests = new List(); - } - - #region IRegionModule Members - - public void Initialise(Scene scene, IConfigSource config) - { - if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID)) - { - RegisteredScenes.Add(scene.RegionInfo.RegionID, scene); - // scene.EventManager.OnNewClient += NewClient; - } - - if (m_scene == null) - { - m_scene = scene; - // m_thread = new Thread(new ThreadStart(RunAssetQueue)); - // m_thread.Name = "AssetDownloadQueueThread"; - // m_thread.IsBackground = true; - // m_thread.Start(); - // OpenSim.Framework.ThreadTracker.Add(m_thread); - } - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "AssetDownloadModule"; } - } - - public bool IsSharedModule - { - get { return true; } - } - - #endregion - - public void NewClient(IClientAPI client) - { - // client.OnRequestAsset += AddAssetRequest; - } - - /// - /// Make an asset request the result of which will be packeted up and sent directly back to the client. - /// - /// - /// - public void AddAssetRequest(IClientAPI userInfo, TransferRequestPacket transferRequest) - { - LLUUID requestID = null; - byte source = 2; - if (transferRequest.TransferInfo.SourceType == 2) - { - //direct asset request - requestID = new LLUUID(transferRequest.TransferInfo.Params, 0); - } - else if (transferRequest.TransferInfo.SourceType == 3) - { - //inventory asset request - requestID = new LLUUID(transferRequest.TransferInfo.Params, 80); - source = 3; - //Console.WriteLine("asset request " + requestID); - } - - //not found asset - // so request from asset server - Dictionary userRequests = null; - if (RequestedAssets.TryGetValue(userInfo.AgentId, out userRequests)) - { - if (!userRequests.ContainsKey(requestID)) - { - AssetRequest request = new AssetRequest(); - request.RequestUser = userInfo; - request.RequestAssetID = requestID; - request.TransferRequestID = transferRequest.TransferInfo.TransferID; - request.AssetRequestSource = source; - request.Params = transferRequest.TransferInfo.Params; - userRequests[requestID] = request; - m_scene.AssetCache.GetAsset(requestID, AssetCallback, false); - } - } - else - { - userRequests = new Dictionary(); - AssetRequest request = new AssetRequest(); - request.RequestUser = userInfo; - request.RequestAssetID = requestID; - request.TransferRequestID = transferRequest.TransferInfo.TransferID; - request.AssetRequestSource = source; - request.Params = transferRequest.TransferInfo.Params; - userRequests.Add(requestID, request); - RequestedAssets[userInfo.AgentId] = userRequests; - m_scene.AssetCache.GetAsset(requestID, AssetCallback, false); - } - } - - public void AssetCallback(LLUUID assetID, AssetBase asset) - { - if (asset != null) - { - foreach (Dictionary userRequests in RequestedAssets.Values) - { - if (userRequests.ContainsKey(assetID)) - { - AssetRequest req = userRequests[assetID]; - if (req != null) - { - req.AssetInf = asset; - req.NumPackets = CalculateNumPackets(asset.Data); - - userRequests.Remove(assetID); - AssetRequests.Add(req); - } - } - } - } - } - - /// - /// Calculate the number of packets required to send the asset to the client. - /// - /// - /// - private int CalculateNumPackets(byte[] data) - { - const uint m_maxPacketSize = 600; - int numPackets = 1; - - if (data.LongLength > m_maxPacketSize) - { - // over max number of bytes so split up file - long restData = data.LongLength - m_maxPacketSize; - int restPackets = (int) ((restData + m_maxPacketSize - 1) / m_maxPacketSize); - numPackets += restPackets; - } - - return numPackets; - } - - #region Nested type: AssetRequest - - public class AssetRequest - { - public AssetBase AssetInf; - public byte AssetRequestSource = 2; - public long DataPointer = 0; - public int DiscardLevel = -1; - public AssetBase ImageInfo; - public bool IsTextureRequest; - public int NumPackets = 0; - public int PacketCounter = 0; - public byte[] Params = null; - public LLUUID RequestAssetID; - public IClientAPI RequestUser; - public LLUUID TransferRequestID; - //public bool AssetInCache; - //public int TimeRequested; - - public AssetRequest() - { - } - } - - #endregion - } +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Collections.Generic; +using libsecondlife; +using libsecondlife.Packets; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules.Agent.AssetDownload +{ + public class AssetDownloadModule : IRegionModule + { + /// + /// Asset requests with data which are ready to be sent back to requesters. This includes textures. + /// + private List AssetRequests; + + private Scene m_scene; + private Dictionary RegisteredScenes = new Dictionary(); + + /// + /// Assets requests (for each user) which are waiting for asset server data. This includes texture requests + /// + private Dictionary> RequestedAssets; + + public AssetDownloadModule() + { + RequestedAssets = new Dictionary>(); + AssetRequests = new List(); + } + + #region IRegionModule Members + + public void Initialise(Scene scene, IConfigSource config) + { + if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID)) + { + RegisteredScenes.Add(scene.RegionInfo.RegionID, scene); + // scene.EventManager.OnNewClient += NewClient; + } + + if (m_scene == null) + { + m_scene = scene; + // m_thread = new Thread(new ThreadStart(RunAssetQueue)); + // m_thread.Name = "AssetDownloadQueueThread"; + // m_thread.IsBackground = true; + // m_thread.Start(); + // OpenSim.Framework.ThreadTracker.Add(m_thread); + } + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "AssetDownloadModule"; } + } + + public bool IsSharedModule + { + get { return true; } + } + + #endregion + + public void NewClient(IClientAPI client) + { + // client.OnRequestAsset += AddAssetRequest; + } + + /// + /// Make an asset request the result of which will be packeted up and sent directly back to the client. + /// + /// + /// + public void AddAssetRequest(IClientAPI userInfo, TransferRequestPacket transferRequest) + { + LLUUID requestID = null; + byte source = 2; + if (transferRequest.TransferInfo.SourceType == 2) + { + //direct asset request + requestID = new LLUUID(transferRequest.TransferInfo.Params, 0); + } + else if (transferRequest.TransferInfo.SourceType == 3) + { + //inventory asset request + requestID = new LLUUID(transferRequest.TransferInfo.Params, 80); + source = 3; + //Console.WriteLine("asset request " + requestID); + } + + //not found asset + // so request from asset server + Dictionary userRequests = null; + if (RequestedAssets.TryGetValue(userInfo.AgentId, out userRequests)) + { + if (!userRequests.ContainsKey(requestID)) + { + AssetRequest request = new AssetRequest(); + request.RequestUser = userInfo; + request.RequestAssetID = requestID; + request.TransferRequestID = transferRequest.TransferInfo.TransferID; + request.AssetRequestSource = source; + request.Params = transferRequest.TransferInfo.Params; + userRequests[requestID] = request; + m_scene.AssetCache.GetAsset(requestID, AssetCallback, false); + } + } + else + { + userRequests = new Dictionary(); + AssetRequest request = new AssetRequest(); + request.RequestUser = userInfo; + request.RequestAssetID = requestID; + request.TransferRequestID = transferRequest.TransferInfo.TransferID; + request.AssetRequestSource = source; + request.Params = transferRequest.TransferInfo.Params; + userRequests.Add(requestID, request); + RequestedAssets[userInfo.AgentId] = userRequests; + m_scene.AssetCache.GetAsset(requestID, AssetCallback, false); + } + } + + public void AssetCallback(LLUUID assetID, AssetBase asset) + { + if (asset != null) + { + foreach (Dictionary userRequests in RequestedAssets.Values) + { + if (userRequests.ContainsKey(assetID)) + { + AssetRequest req = userRequests[assetID]; + if (req != null) + { + req.AssetInf = asset; + req.NumPackets = CalculateNumPackets(asset.Data); + + userRequests.Remove(assetID); + AssetRequests.Add(req); + } + } + } + } + } + + /// + /// Calculate the number of packets required to send the asset to the client. + /// + /// + /// + private int CalculateNumPackets(byte[] data) + { + const uint m_maxPacketSize = 600; + int numPackets = 1; + + if (data.LongLength > m_maxPacketSize) + { + // over max number of bytes so split up file + long restData = data.LongLength - m_maxPacketSize; + int restPackets = (int) ((restData + m_maxPacketSize - 1) / m_maxPacketSize); + numPackets += restPackets; + } + + return numPackets; + } + + #region Nested type: AssetRequest + + public class AssetRequest + { + public AssetBase AssetInf; + public byte AssetRequestSource = 2; + public long DataPointer = 0; + public int DiscardLevel = -1; + public AssetBase ImageInfo; + public bool IsTextureRequest; + public int NumPackets = 0; + public int PacketCounter = 0; + public byte[] Params = null; + public LLUUID RequestAssetID; + public IClientAPI RequestUser; + public LLUUID TransferRequestID; + //public bool AssetInCache; + //public int TimeRequested; + + public AssetRequest() + { + } + } + + #endregion + } } \ No newline at end of file diff --git a/OpenSim/Region/Environment/Modules/Agent/AssetTransaction/AgentAssetsTransactions.cs b/OpenSim/Region/Environment/Modules/Agent/AssetTransaction/AgentAssetsTransactions.cs index 8192be4..555d5f4 100644 --- a/OpenSim/Region/Environment/Modules/Agent/AssetTransaction/AgentAssetsTransactions.cs +++ b/OpenSim/Region/Environment/Modules/Agent/AssetTransaction/AgentAssetsTransactions.cs @@ -1,412 +1,412 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSim Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.IO; -using libsecondlife; -using libsecondlife.Packets; -using OpenSim.Framework; -using OpenSim.Framework.Communications.Cache; - -namespace OpenSim.Region.Environment.Modules.Agent.AssetTransaction -{ - /// - /// Manage asset transactions for a single agent. - /// - public class AgentAssetTransactions - { - //private static readonly log4net.ILog m_log - // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - - // Fields - private bool m_dumpAssetsToFile; - public AgentAssetTransactionsManager Manager; - public LLUUID UserID; - public Dictionary XferUploaders = new Dictionary(); - - // Methods - public AgentAssetTransactions(LLUUID agentID, AgentAssetTransactionsManager manager, bool dumpAssetsToFile) - { - UserID = agentID; - Manager = manager; - m_dumpAssetsToFile = dumpAssetsToFile; - } - - public AssetXferUploader RequestXferUploader(LLUUID transactionID) - { - if (!XferUploaders.ContainsKey(transactionID)) - { - AssetXferUploader uploader = new AssetXferUploader(this, m_dumpAssetsToFile); - - lock (XferUploaders) - { - XferUploaders.Add(transactionID, uploader); - } - - return uploader; - } - return null; - } - - public void HandleXfer(ulong xferID, uint packetID, byte[] data) - { - // AssetXferUploader uploaderFound = null; - - lock (XferUploaders) - { - foreach (AssetXferUploader uploader in XferUploaders.Values) - { - if (uploader.XferID == xferID) - { - uploader.HandleXferPacket(xferID, packetID, data); - break; - } - } - } - } - - public void RequestCreateInventoryItem(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID, - uint callbackID, string description, string name, sbyte invType, - sbyte type, byte wearableType, uint nextOwnerMask) - { - if (XferUploaders.ContainsKey(transactionID)) - { - XferUploaders[transactionID].RequestCreateInventoryItem(remoteClient, transactionID, folderID, - callbackID, description, name, invType, type, - wearableType, nextOwnerMask); - } - } - - public void RequestUpdateInventoryItem(IClientAPI remoteClient, LLUUID transactionID, - InventoryItemBase item) - { - if (XferUploaders.ContainsKey(transactionID)) - { - XferUploaders[transactionID].RequestUpdateInventoryItem(remoteClient, transactionID, item); - } - } - - /// - /// Get an uploaded asset. If the data is successfully retrieved, the transaction will be removed. - /// - /// - /// The asset if the upload has completed, null if it has not. - public AssetBase GetTransactionAsset(LLUUID transactionID) - { - if (XferUploaders.ContainsKey(transactionID)) - { - AssetXferUploader uploader = XferUploaders[transactionID]; - AssetBase asset = uploader.GetAssetData(); - - lock (XferUploaders) - { - XferUploaders.Remove(transactionID); - } - - return asset; - } - - return null; - } - - // Nested Types - - #region Nested type: AssetXferUploader - - public class AssetXferUploader - { - // Fields - public bool AddToInventory; - public AssetBase Asset; - public LLUUID InventFolder = LLUUID.Zero; - private sbyte invType = 0; - private bool m_createItem = false; - private string m_description = String.Empty; - private bool m_dumpAssetToFile; - private bool m_finished = false; - private string m_name = String.Empty; - private bool m_storeLocal; - private AgentAssetTransactions m_userTransactions; - private uint nextPerm = 0; - private IClientAPI ourClient; - public LLUUID TransactionID = LLUUID.Zero; - private sbyte type = 0; - public bool UploadComplete; - private byte wearableType = 0; - public ulong XferID; - - public AssetXferUploader(AgentAssetTransactions transactions, bool dumpAssetToFile) - { - m_userTransactions = transactions; - m_dumpAssetToFile = dumpAssetToFile; - } - - /// - /// Process transfer data received from the client. - /// - /// - /// - /// - /// True if the transfer is complete, false otherwise or if the xferID was not valid - public bool HandleXferPacket(ulong xferID, uint packetID, byte[] data) - { - if (XferID == xferID) - { - if (Asset.Data.Length > 1) - { - byte[] destinationArray = new byte[Asset.Data.Length + data.Length]; - Array.Copy(Asset.Data, 0, destinationArray, 0, Asset.Data.Length); - Array.Copy(data, 0, destinationArray, Asset.Data.Length, data.Length); - Asset.Data = destinationArray; - } - else - { - byte[] buffer2 = new byte[data.Length - 4]; - Array.Copy(data, 4, buffer2, 0, data.Length - 4); - Asset.Data = buffer2; - } - ConfirmXferPacketPacket newPack = new ConfirmXferPacketPacket(); - newPack.XferID.ID = xferID; - newPack.XferID.Packet = packetID; - ourClient.OutPacket(newPack, ThrottleOutPacketType.Asset); - if ((packetID & 0x80000000) != 0) - { - SendCompleteMessage(); - return true; - } - } - - return false; - } - - /// - /// Initialise asset transfer from the client - /// - /// - /// - /// - /// True if the transfer is complete, false otherwise - public bool Initialise(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, byte[] data, - bool storeLocal, bool tempFile) - { - ourClient = remoteClient; - Asset = new AssetBase(); - Asset.FullID = assetID; - Asset.InvType = type; - Asset.Type = type; - Asset.Data = data; - Asset.Name = "blank"; - Asset.Description = "empty"; - Asset.Local = storeLocal; - Asset.Temporary = tempFile; - - TransactionID = transaction; - m_storeLocal = storeLocal; - if (Asset.Data.Length > 2) - { - SendCompleteMessage(); - return true; - } - else - { - RequestStartXfer(); - } - - return false; - } - - protected void RequestStartXfer() - { - UploadComplete = false; - XferID = Util.GetNextXferID(); - RequestXferPacket newPack = new RequestXferPacket(); - newPack.XferID.ID = XferID; - newPack.XferID.VFileType = Asset.Type; - newPack.XferID.VFileID = Asset.FullID; - newPack.XferID.FilePath = 0; - newPack.XferID.Filename = new byte[0]; - ourClient.OutPacket(newPack, ThrottleOutPacketType.Asset); - } - - protected void SendCompleteMessage() - { - UploadComplete = true; - AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); - newPack.AssetBlock.Type = Asset.Type; - newPack.AssetBlock.Success = true; - newPack.AssetBlock.UUID = Asset.FullID; - ourClient.OutPacket(newPack, ThrottleOutPacketType.Asset); - m_finished = true; - if (m_createItem) - { - DoCreateItem(); - } - else if (m_storeLocal) - { - m_userTransactions.Manager.MyScene.CommsManager.AssetCache.AddAsset(Asset); - } - - // Console.WriteLine("upload complete "+ this.TransactionID); - - if (m_dumpAssetToFile) - { - DateTime now = DateTime.Now; - string filename = - String.Format("{6}_{7}_{0:d2}{1:d2}{2:d2}_{3:d2}{4:d2}{5:d2}.dat", now.Year, now.Month, now.Day, - now.Hour, now.Minute, now.Second, Asset.Name, Asset.Type); - SaveAssetToFile(filename, Asset.Data); - } - } - - ///Left this in and commented in case there are unforseen issues - //private void SaveAssetToFile(string filename, byte[] data) - //{ - // FileStream fs = File.Create(filename); - // BinaryWriter bw = new BinaryWriter(fs); - // bw.Write(data); - // bw.Close(); - // fs.Close(); - //} - private void SaveAssetToFile(string filename, byte[] data) - { - string assetPath = "UserAssets"; - if (!Directory.Exists(assetPath)) - { - Directory.CreateDirectory(assetPath); - } - FileStream fs = File.Create(Path.Combine(assetPath, filename)); - BinaryWriter bw = new BinaryWriter(fs); - bw.Write(data); - bw.Close(); - fs.Close(); - } - - public void RequestCreateInventoryItem(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID, - uint callbackID, string description, string name, sbyte invType, - sbyte type, byte wearableType, uint nextOwnerMask) - { - if (TransactionID == transactionID) - { - InventFolder = folderID; - m_name = name; - m_description = description; - this.type = type; - this.invType = invType; - this.wearableType = wearableType; - nextPerm = nextOwnerMask; - Asset.Name = name; - Asset.Description = description; - Asset.Type = type; - Asset.InvType = invType; - m_createItem = true; - if (m_finished) - { - DoCreateItem(); - } - } - } - - public void RequestUpdateInventoryItem(IClientAPI remoteClient, LLUUID transactionID, - InventoryItemBase item) - { - if (TransactionID == transactionID) - { - CachedUserInfo userInfo = - m_userTransactions.Manager.MyScene.CommsManager.UserProfileCacheService.GetUserDetails( - remoteClient.AgentId); - - if (userInfo != null) - { - LLUUID assetID = LLUUID.Combine(transactionID, remoteClient.SecureSessionId); - - AssetBase asset - = m_userTransactions.Manager.MyScene.CommsManager.AssetCache.GetAsset( - assetID, (item.AssetType == (int) AssetType.Texture ? true : false)); - - if (asset == null) - { - asset = m_userTransactions.GetTransactionAsset(transactionID); - } - - if (asset != null && asset.FullID == assetID) - { - asset.Name = item.Name; - asset.Description = item.Description; - asset.InvType = (sbyte) item.InvType; - asset.Type = (sbyte) item.AssetType; - item.AssetID = asset.FullID; - - m_userTransactions.Manager.MyScene.CommsManager.AssetCache.AddAsset(Asset); - } - - userInfo.UpdateItem(remoteClient.AgentId, item); - } - } - } - - private void DoCreateItem() - { - //really need to fix this call, if lbsa71 saw this he would die. - m_userTransactions.Manager.MyScene.CommsManager.AssetCache.AddAsset(Asset); - CachedUserInfo userInfo = - m_userTransactions.Manager.MyScene.CommsManager.UserProfileCacheService.GetUserDetails(ourClient.AgentId); - if (userInfo != null) - { - InventoryItemBase item = new InventoryItemBase(); - item.Owner = ourClient.AgentId; - item.Creator = ourClient.AgentId; - item.ID = LLUUID.Random(); - item.AssetID = Asset.FullID; - item.Description = m_description; - item.Name = m_name; - item.AssetType = type; - item.InvType = invType; - item.Folder = InventFolder; - item.BasePermissions = 2147483647; - item.CurrentPermissions = 2147483647; - item.NextPermissions = nextPerm; - item.Flags = (uint) wearableType; - - userInfo.AddItem(ourClient.AgentId, item); - ourClient.SendInventoryItemCreateUpdate(item); - } - } - - public AssetBase GetAssetData() - { - if (m_finished) - { - return Asset; - } - return null; - } - } - - #endregion - } +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using libsecondlife; +using libsecondlife.Packets; +using OpenSim.Framework; +using OpenSim.Framework.Communications.Cache; + +namespace OpenSim.Region.Environment.Modules.Agent.AssetTransaction +{ + /// + /// Manage asset transactions for a single agent. + /// + public class AgentAssetTransactions + { + //private static readonly log4net.ILog m_log + // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + // Fields + private bool m_dumpAssetsToFile; + public AgentAssetTransactionsManager Manager; + public LLUUID UserID; + public Dictionary XferUploaders = new Dictionary(); + + // Methods + public AgentAssetTransactions(LLUUID agentID, AgentAssetTransactionsManager manager, bool dumpAssetsToFile) + { + UserID = agentID; + Manager = manager; + m_dumpAssetsToFile = dumpAssetsToFile; + } + + public AssetXferUploader RequestXferUploader(LLUUID transactionID) + { + if (!XferUploaders.ContainsKey(transactionID)) + { + AssetXferUploader uploader = new AssetXferUploader(this, m_dumpAssetsToFile); + + lock (XferUploaders) + { + XferUploaders.Add(transactionID, uploader); + } + + return uploader; + } + return null; + } + + public void HandleXfer(ulong xferID, uint packetID, byte[] data) + { + // AssetXferUploader uploaderFound = null; + + lock (XferUploaders) + { + foreach (AssetXferUploader uploader in XferUploaders.Values) + { + if (uploader.XferID == xferID) + { + uploader.HandleXferPacket(xferID, packetID, data); + break; + } + } + } + } + + public void RequestCreateInventoryItem(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID, + uint callbackID, string description, string name, sbyte invType, + sbyte type, byte wearableType, uint nextOwnerMask) + { + if (XferUploaders.ContainsKey(transactionID)) + { + XferUploaders[transactionID].RequestCreateInventoryItem(remoteClient, transactionID, folderID, + callbackID, description, name, invType, type, + wearableType, nextOwnerMask); + } + } + + public void RequestUpdateInventoryItem(IClientAPI remoteClient, LLUUID transactionID, + InventoryItemBase item) + { + if (XferUploaders.ContainsKey(transactionID)) + { + XferUploaders[transactionID].RequestUpdateInventoryItem(remoteClient, transactionID, item); + } + } + + /// + /// Get an uploaded asset. If the data is successfully retrieved, the transaction will be removed. + /// + /// + /// The asset if the upload has completed, null if it has not. + public AssetBase GetTransactionAsset(LLUUID transactionID) + { + if (XferUploaders.ContainsKey(transactionID)) + { + AssetXferUploader uploader = XferUploaders[transactionID]; + AssetBase asset = uploader.GetAssetData(); + + lock (XferUploaders) + { + XferUploaders.Remove(transactionID); + } + + return asset; + } + + return null; + } + + // Nested Types + + #region Nested type: AssetXferUploader + + public class AssetXferUploader + { + // Fields + public bool AddToInventory; + public AssetBase Asset; + public LLUUID InventFolder = LLUUID.Zero; + private sbyte invType = 0; + private bool m_createItem = false; + private string m_description = String.Empty; + private bool m_dumpAssetToFile; + private bool m_finished = false; + private string m_name = String.Empty; + private bool m_storeLocal; + private AgentAssetTransactions m_userTransactions; + private uint nextPerm = 0; + private IClientAPI ourClient; + public LLUUID TransactionID = LLUUID.Zero; + private sbyte type = 0; + public bool UploadComplete; + private byte wearableType = 0; + public ulong XferID; + + public AssetXferUploader(AgentAssetTransactions transactions, bool dumpAssetToFile) + { + m_userTransactions = transactions; + m_dumpAssetToFile = dumpAssetToFile; + } + + /// + /// Process transfer data received from the client. + /// + /// + /// + /// + /// True if the transfer is complete, false otherwise or if the xferID was not valid + public bool HandleXferPacket(ulong xferID, uint packetID, byte[] data) + { + if (XferID == xferID) + { + if (Asset.Data.Length > 1) + { + byte[] destinationArray = new byte[Asset.Data.Length + data.Length]; + Array.Copy(Asset.Data, 0, destinationArray, 0, Asset.Data.Length); + Array.Copy(data, 0, destinationArray, Asset.Data.Length, data.Length); + Asset.Data = destinationArray; + } + else + { + byte[] buffer2 = new byte[data.Length - 4]; + Array.Copy(data, 4, buffer2, 0, data.Length - 4); + Asset.Data = buffer2; + } + ConfirmXferPacketPacket newPack = new ConfirmXferPacketPacket(); + newPack.XferID.ID = xferID; + newPack.XferID.Packet = packetID; + ourClient.OutPacket(newPack, ThrottleOutPacketType.Asset); + if ((packetID & 0x80000000) != 0) + { + SendCompleteMessage(); + return true; + } + } + + return false; + } + + /// + /// Initialise asset transfer from the client + /// + /// + /// + /// + /// True if the transfer is complete, false otherwise + public bool Initialise(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, byte[] data, + bool storeLocal, bool tempFile) + { + ourClient = remoteClient; + Asset = new AssetBase(); + Asset.FullID = assetID; + Asset.InvType = type; + Asset.Type = type; + Asset.Data = data; + Asset.Name = "blank"; + Asset.Description = "empty"; + Asset.Local = storeLocal; + Asset.Temporary = tempFile; + + TransactionID = transaction; + m_storeLocal = storeLocal; + if (Asset.Data.Length > 2) + { + SendCompleteMessage(); + return true; + } + else + { + RequestStartXfer(); + } + + return false; + } + + protected void RequestStartXfer() + { + UploadComplete = false; + XferID = Util.GetNextXferID(); + RequestXferPacket newPack = new RequestXferPacket(); + newPack.XferID.ID = XferID; + newPack.XferID.VFileType = Asset.Type; + newPack.XferID.VFileID = Asset.FullID; + newPack.XferID.FilePath = 0; + newPack.XferID.Filename = new byte[0]; + ourClient.OutPacket(newPack, ThrottleOutPacketType.Asset); + } + + protected void SendCompleteMessage() + { + UploadComplete = true; + AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); + newPack.AssetBlock.Type = Asset.Type; + newPack.AssetBlock.Success = true; + newPack.AssetBlock.UUID = Asset.FullID; + ourClient.OutPacket(newPack, ThrottleOutPacketType.Asset); + m_finished = true; + if (m_createItem) + { + DoCreateItem(); + } + else if (m_storeLocal) + { + m_userTransactions.Manager.MyScene.CommsManager.AssetCache.AddAsset(Asset); + } + + // Console.WriteLine("upload complete "+ this.TransactionID); + + if (m_dumpAssetToFile) + { + DateTime now = DateTime.Now; + string filename = + String.Format("{6}_{7}_{0:d2}{1:d2}{2:d2}_{3:d2}{4:d2}{5:d2}.dat", now.Year, now.Month, now.Day, + now.Hour, now.Minute, now.Second, Asset.Name, Asset.Type); + SaveAssetToFile(filename, Asset.Data); + } + } + + ///Left this in and commented in case there are unforseen issues + //private void SaveAssetToFile(string filename, byte[] data) + //{ + // FileStream fs = File.Create(filename); + // BinaryWriter bw = new BinaryWriter(fs); + // bw.Write(data); + // bw.Close(); + // fs.Close(); + //} + private void SaveAssetToFile(string filename, byte[] data) + { + string assetPath = "UserAssets"; + if (!Directory.Exists(assetPath)) + { + Directory.CreateDirectory(assetPath); + } + FileStream fs = File.Create(Path.Combine(assetPath, filename)); + BinaryWriter bw = new BinaryWriter(fs); + bw.Write(data); + bw.Close(); + fs.Close(); + } + + public void RequestCreateInventoryItem(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID, + uint callbackID, string description, string name, sbyte invType, + sbyte type, byte wearableType, uint nextOwnerMask) + { + if (TransactionID == transactionID) + { + InventFolder = folderID; + m_name = name; + m_description = description; + this.type = type; + this.invType = invType; + this.wearableType = wearableType; + nextPerm = nextOwnerMask; + Asset.Name = name; + Asset.Description = description; + Asset.Type = type; + Asset.InvType = invType; + m_createItem = true; + if (m_finished) + { + DoCreateItem(); + } + } + } + + public void RequestUpdateInventoryItem(IClientAPI remoteClient, LLUUID transactionID, + InventoryItemBase item) + { + if (TransactionID == transactionID) + { + CachedUserInfo userInfo = + m_userTransactions.Manager.MyScene.CommsManager.UserProfileCacheService.GetUserDetails( + remoteClient.AgentId); + + if (userInfo != null) + { + LLUUID assetID = LLUUID.Combine(transactionID, remoteClient.SecureSessionId); + + AssetBase asset + = m_userTransactions.Manager.MyScene.CommsManager.AssetCache.GetAsset( + assetID, (item.AssetType == (int) AssetType.Texture ? true : false)); + + if (asset == null) + { + asset = m_userTransactions.GetTransactionAsset(transactionID); + } + + if (asset != null && asset.FullID == assetID) + { + asset.Name = item.Name; + asset.Description = item.Description; + asset.InvType = (sbyte) item.InvType; + asset.Type = (sbyte) item.AssetType; + item.AssetID = asset.FullID; + + m_userTransactions.Manager.MyScene.CommsManager.AssetCache.AddAsset(Asset); + } + + userInfo.UpdateItem(remoteClient.AgentId, item); + } + } + } + + private void DoCreateItem() + { + //really need to fix this call, if lbsa71 saw this he would die. + m_userTransactions.Manager.MyScene.CommsManager.AssetCache.AddAsset(Asset); + CachedUserInfo userInfo = + m_userTransactions.Manager.MyScene.CommsManager.UserProfileCacheService.GetUserDetails(ourClient.AgentId); + if (userInfo != null) + { + InventoryItemBase item = new InventoryItemBase(); + item.Owner = ourClient.AgentId; + item.Creator = ourClient.AgentId; + item.ID = LLUUID.Random(); + item.AssetID = Asset.FullID; + item.Description = m_description; + item.Name = m_name; + item.AssetType = type; + item.InvType = invType; + item.Folder = InventFolder; + item.BasePermissions = 2147483647; + item.CurrentPermissions = 2147483647; + item.NextPermissions = nextPerm; + item.Flags = (uint) wearableType; + + userInfo.AddItem(ourClient.AgentId, item); + ourClient.SendInventoryItemCreateUpdate(item); + } + } + + public AssetBase GetAssetData() + { + if (m_finished) + { + return Asset; + } + return null; + } + } + + #endregion + } } \ No newline at end of file diff --git a/OpenSim/Region/Environment/Modules/Agent/AssetTransaction/AssetTransactionModule.cs b/OpenSim/Region/Environment/Modules/Agent/AssetTransaction/AssetTransactionModule.cs index b264c8a..fcd0e0c 100644 --- a/OpenSim/Region/Environment/Modules/Agent/AssetTransaction/AssetTransactionModule.cs +++ b/OpenSim/Region/Environment/Modules/Agent/AssetTransaction/AssetTransactionModule.cs @@ -1,291 +1,291 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSim Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Reflection; -using libsecondlife; -using log4net; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules.Agent.AssetTransaction -{ - public class AssetTransactionModule : IRegionModule, IAgentAssetTransactions - { - private readonly Dictionary RegisteredScenes = new Dictionary(); - private bool m_dumpAssetsToFile = false; - private Scene m_scene = null; - - private AgentAssetTransactionsManager m_transactionManager; - - public AssetTransactionModule() - { - // System.Console.WriteLine("creating AgentAssetTransactionModule"); - } - - #region IAgentAssetTransactions Members - - public void HandleItemCreationFromTransaction(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID, - uint callbackID, string description, string name, sbyte invType, - sbyte type, byte wearableType, uint nextOwnerMask) - { - m_transactionManager.HandleItemCreationFromTransaction(remoteClient, transactionID, folderID, callbackID, description, name, invType, type, - wearableType, nextOwnerMask); - } - - public void HandleItemUpdateFromTransaction(IClientAPI remoteClient, LLUUID transactionID, - InventoryItemBase item) - { - m_transactionManager.HandleItemUpdateFromTransaction(remoteClient, transactionID, item); - } - - public void RemoveAgentAssetTransactions(LLUUID userID) - { - m_transactionManager.RemoveAgentAssetTransactions(userID); - } - - #endregion - - #region IRegionModule Members - - public void Initialise(Scene scene, IConfigSource config) - { - if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID)) - { - // System.Console.WriteLine("initialising AgentAssetTransactionModule"); - RegisteredScenes.Add(scene.RegionInfo.RegionID, scene); - scene.RegisterModuleInterface(this); - - scene.EventManager.OnNewClient += NewClient; - } - - if (m_scene == null) - { - m_scene = scene; - if (config.Configs["StandAlone"] != null) - { - try - { - m_dumpAssetsToFile = config.Configs["StandAlone"].GetBoolean("dump_assets_to_file", false); - m_transactionManager = new AgentAssetTransactionsManager(m_scene, m_dumpAssetsToFile); - } - catch (Exception) - { - m_transactionManager = new AgentAssetTransactionsManager(m_scene, false); - } - } - else - { - m_transactionManager = new AgentAssetTransactionsManager(m_scene, false); - } - } - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "AgentTransactionModule"; } - } - - public bool IsSharedModule - { - get { return true; } - } - - #endregion - - public void NewClient(IClientAPI client) - { - client.OnAssetUploadRequest += m_transactionManager.HandleUDPUploadRequest; - client.OnXferReceive += m_transactionManager.HandleXfer; - } - } - - public class AgentAssetTransactionsManager - { - private static readonly ILog m_log - = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - // Fields - - /// - /// Each agent has its own singleton collection of transactions - /// - private Dictionary AgentTransactions = - new Dictionary(); - - /// - /// Should we dump uploaded assets to the filesystem? - /// - private bool m_dumpAssetsToFile; - - public Scene MyScene; - - public AgentAssetTransactionsManager(Scene scene, bool dumpAssetsToFile) - { - MyScene = scene; - m_dumpAssetsToFile = dumpAssetsToFile; - } - - /// - /// Get the collection of asset transactions for the given user. If one does not already exist, it - /// is created. - /// - /// - /// - private AgentAssetTransactions GetUserTransactions(LLUUID userID) - { - lock (AgentTransactions) - { - if (!AgentTransactions.ContainsKey(userID)) - { - AgentAssetTransactions transactions - = new AgentAssetTransactions(userID, this, m_dumpAssetsToFile); - AgentTransactions.Add(userID, transactions); - } - - return AgentTransactions[userID]; - } - } - - /// - /// Remove the given agent asset transactions. This should be called when a client is departing - /// from a scene (and hence won't be making any more transactions here). - /// - /// - public void RemoveAgentAssetTransactions(LLUUID userID) - { - // m_log.DebugFormat("Removing agent asset transactions structure for agent {0}", userID); - - lock (AgentTransactions) - { - AgentTransactions.Remove(userID); - } - } - - /// - /// Create an inventory item from data that has been received through a transaction. - /// - /// This is called when new clothing or body parts are created. It may also be called in other - /// situations. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public void HandleItemCreationFromTransaction(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID, - uint callbackID, string description, string name, sbyte invType, - sbyte type, byte wearableType, uint nextOwnerMask) - { - m_log.DebugFormat( - "[TRANSACTIONS MANAGER] Called HandleItemCreationFromTransaction with item {0}", name); - - AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); - - transactions.RequestCreateInventoryItem( - remoteClient, transactionID, folderID, callbackID, description, - name, invType, type, wearableType, nextOwnerMask); - } - - /// - /// Update an inventory item with data that has been received through a transaction. - /// - /// This is called when clothing or body parts are updated (for instance, with new textures or - /// colours). It may also be called in other situations. - /// - /// - /// - /// - public void HandleItemUpdateFromTransaction(IClientAPI remoteClient, LLUUID transactionID, - InventoryItemBase item) - { - m_log.DebugFormat( - "[TRANSACTIONS MANAGER] Called HandleItemUpdateFromTransaction with item {0}", - item.Name); - - AgentAssetTransactions transactions - = GetUserTransactions(remoteClient.AgentId); - - transactions.RequestUpdateInventoryItem(remoteClient, transactionID, item); - } - - /// - /// Request that a client (agent) begin an asset transfer. - /// - /// - /// - /// - /// - /// - /// - public void HandleUDPUploadRequest(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, - byte[] data, bool storeLocal, bool tempFile) - { - // Console.WriteLine("asset upload of " + assetID); - AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); - - AgentAssetTransactions.AssetXferUploader uploader = transactions.RequestXferUploader(transaction); - if (uploader != null) - { - if (uploader.Initialise(remoteClient, assetID, transaction, type, data, storeLocal, tempFile)) - { - } - } - } - - /// - /// Handle asset transfer data packets received in response to the asset upload request in - /// HandleUDPUploadRequest() - /// - /// - /// - /// - /// - public void HandleXfer(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data) - { - AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); - - transactions.HandleXfer(xferID, packetID, data); - } - } +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using libsecondlife; +using log4net; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules.Agent.AssetTransaction +{ + public class AssetTransactionModule : IRegionModule, IAgentAssetTransactions + { + private readonly Dictionary RegisteredScenes = new Dictionary(); + private bool m_dumpAssetsToFile = false; + private Scene m_scene = null; + + private AgentAssetTransactionsManager m_transactionManager; + + public AssetTransactionModule() + { + // System.Console.WriteLine("creating AgentAssetTransactionModule"); + } + + #region IAgentAssetTransactions Members + + public void HandleItemCreationFromTransaction(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID, + uint callbackID, string description, string name, sbyte invType, + sbyte type, byte wearableType, uint nextOwnerMask) + { + m_transactionManager.HandleItemCreationFromTransaction(remoteClient, transactionID, folderID, callbackID, description, name, invType, type, + wearableType, nextOwnerMask); + } + + public void HandleItemUpdateFromTransaction(IClientAPI remoteClient, LLUUID transactionID, + InventoryItemBase item) + { + m_transactionManager.HandleItemUpdateFromTransaction(remoteClient, transactionID, item); + } + + public void RemoveAgentAssetTransactions(LLUUID userID) + { + m_transactionManager.RemoveAgentAssetTransactions(userID); + } + + #endregion + + #region IRegionModule Members + + public void Initialise(Scene scene, IConfigSource config) + { + if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID)) + { + // System.Console.WriteLine("initialising AgentAssetTransactionModule"); + RegisteredScenes.Add(scene.RegionInfo.RegionID, scene); + scene.RegisterModuleInterface(this); + + scene.EventManager.OnNewClient += NewClient; + } + + if (m_scene == null) + { + m_scene = scene; + if (config.Configs["StandAlone"] != null) + { + try + { + m_dumpAssetsToFile = config.Configs["StandAlone"].GetBoolean("dump_assets_to_file", false); + m_transactionManager = new AgentAssetTransactionsManager(m_scene, m_dumpAssetsToFile); + } + catch (Exception) + { + m_transactionManager = new AgentAssetTransactionsManager(m_scene, false); + } + } + else + { + m_transactionManager = new AgentAssetTransactionsManager(m_scene, false); + } + } + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "AgentTransactionModule"; } + } + + public bool IsSharedModule + { + get { return true; } + } + + #endregion + + public void NewClient(IClientAPI client) + { + client.OnAssetUploadRequest += m_transactionManager.HandleUDPUploadRequest; + client.OnXferReceive += m_transactionManager.HandleXfer; + } + } + + public class AgentAssetTransactionsManager + { + private static readonly ILog m_log + = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // Fields + + /// + /// Each agent has its own singleton collection of transactions + /// + private Dictionary AgentTransactions = + new Dictionary(); + + /// + /// Should we dump uploaded assets to the filesystem? + /// + private bool m_dumpAssetsToFile; + + public Scene MyScene; + + public AgentAssetTransactionsManager(Scene scene, bool dumpAssetsToFile) + { + MyScene = scene; + m_dumpAssetsToFile = dumpAssetsToFile; + } + + /// + /// Get the collection of asset transactions for the given user. If one does not already exist, it + /// is created. + /// + /// + /// + private AgentAssetTransactions GetUserTransactions(LLUUID userID) + { + lock (AgentTransactions) + { + if (!AgentTransactions.ContainsKey(userID)) + { + AgentAssetTransactions transactions + = new AgentAssetTransactions(userID, this, m_dumpAssetsToFile); + AgentTransactions.Add(userID, transactions); + } + + return AgentTransactions[userID]; + } + } + + /// + /// Remove the given agent asset transactions. This should be called when a client is departing + /// from a scene (and hence won't be making any more transactions here). + /// + /// + public void RemoveAgentAssetTransactions(LLUUID userID) + { + // m_log.DebugFormat("Removing agent asset transactions structure for agent {0}", userID); + + lock (AgentTransactions) + { + AgentTransactions.Remove(userID); + } + } + + /// + /// Create an inventory item from data that has been received through a transaction. + /// + /// This is called when new clothing or body parts are created. It may also be called in other + /// situations. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public void HandleItemCreationFromTransaction(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID, + uint callbackID, string description, string name, sbyte invType, + sbyte type, byte wearableType, uint nextOwnerMask) + { + m_log.DebugFormat( + "[TRANSACTIONS MANAGER] Called HandleItemCreationFromTransaction with item {0}", name); + + AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); + + transactions.RequestCreateInventoryItem( + remoteClient, transactionID, folderID, callbackID, description, + name, invType, type, wearableType, nextOwnerMask); + } + + /// + /// Update an inventory item with data that has been received through a transaction. + /// + /// This is called when clothing or body parts are updated (for instance, with new textures or + /// colours). It may also be called in other situations. + /// + /// + /// + /// + public void HandleItemUpdateFromTransaction(IClientAPI remoteClient, LLUUID transactionID, + InventoryItemBase item) + { + m_log.DebugFormat( + "[TRANSACTIONS MANAGER] Called HandleItemUpdateFromTransaction with item {0}", + item.Name); + + AgentAssetTransactions transactions + = GetUserTransactions(remoteClient.AgentId); + + transactions.RequestUpdateInventoryItem(remoteClient, transactionID, item); + } + + /// + /// Request that a client (agent) begin an asset transfer. + /// + /// + /// + /// + /// + /// + /// + public void HandleUDPUploadRequest(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, + byte[] data, bool storeLocal, bool tempFile) + { + // Console.WriteLine("asset upload of " + assetID); + AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); + + AgentAssetTransactions.AssetXferUploader uploader = transactions.RequestXferUploader(transaction); + if (uploader != null) + { + if (uploader.Initialise(remoteClient, assetID, transaction, type, data, storeLocal, tempFile)) + { + } + } + } + + /// + /// Handle asset transfer data packets received in response to the asset upload request in + /// HandleUDPUploadRequest() + /// + /// + /// + /// + /// + public void HandleXfer(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data) + { + AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); + + transactions.HandleXfer(xferID, packetID, data); + } + } } \ No newline at end of file diff --git a/OpenSim/Region/Environment/Modules/Agent/TextureDownload/TextureDownloadModule.cs b/OpenSim/Region/Environment/Modules/Agent/TextureDownload/TextureDownloadModule.cs index ae2df69..474ac75 100644 --- a/OpenSim/Region/Environment/Modules/Agent/TextureDownload/TextureDownloadModule.cs +++ b/OpenSim/Region/Environment/Modules/Agent/TextureDownload/TextureDownloadModule.cs @@ -1,219 +1,219 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSim Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Threading; -using libsecondlife; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules.Agent.TextureDownload -{ - public class TextureDownloadModule : IRegionModule - { - //private static readonly log4net.ILog m_log - // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - - /// - /// There is one queue for all textures waiting to be sent, regardless of the requesting user. - /// - private readonly BlockingQueue m_queueSenders - = new BlockingQueue(); - - /// - /// Each user has their own texture download service. - /// - private readonly Dictionary m_userTextureServices = - new Dictionary(); - - private Scene m_scene; - private List m_scenes = new List(); - - private Thread m_thread; - - public TextureDownloadModule() - { - } - - #region IRegionModule Members - - public void Initialise(Scene scene, IConfigSource config) - { - if (m_scene == null) - { - //Console.WriteLine("Creating Texture download module"); - m_thread = new Thread(new ThreadStart(ProcessTextureSenders)); - m_thread.Name = "ProcessTextureSenderThread"; - m_thread.IsBackground = true; - m_thread.Start(); - ThreadTracker.Add(m_thread); - } - - if (!m_scenes.Contains(scene)) - { - m_scenes.Add(scene); - m_scene = scene; - m_scene.EventManager.OnNewClient += NewClient; - m_scene.EventManager.OnRemovePresence += EventManager_OnRemovePresence; - } - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "TextureDownloadModule"; } - } - - public bool IsSharedModule - { - get { return false; } - } - - #endregion - - /// - /// Cleanup the texture service related objects for the removed presence. - /// - /// - private void EventManager_OnRemovePresence(LLUUID agentId) - { - UserTextureDownloadService textureService; - - lock (m_userTextureServices) - { - if (m_userTextureServices.TryGetValue(agentId, out textureService)) - { - textureService.Close(); - - m_userTextureServices.Remove(agentId); - } - } - } - - public void NewClient(IClientAPI client) - { - client.OnRequestTexture += TextureRequest; - } - - /// - /// Does this user have a registered texture download service? - /// - /// - /// - /// Always returns true, since a service is created if one does not already exist - private bool TryGetUserTextureService( - IClientAPI client, out UserTextureDownloadService textureService) - { - lock (m_userTextureServices) - { - if (m_userTextureServices.TryGetValue(client.AgentId, out textureService)) - { - return true; - } - - textureService = new UserTextureDownloadService(client, m_scene, m_queueSenders); - m_userTextureServices.Add(client.AgentId, textureService); - - return true; - } - } - - /// - /// Start the process of requesting a given texture. - /// - /// - /// - public void TextureRequest(Object sender, TextureRequestArgs e) - { - IClientAPI client = (IClientAPI) sender; - UserTextureDownloadService textureService; - - if (TryGetUserTextureService(client, out textureService)) - { - textureService.HandleTextureRequest(e); - } - } - - /// - /// Entry point for the thread dedicated to processing the texture queue. - /// - public void ProcessTextureSenders() - { - ITextureSender sender = null; - - while (true) - { - sender = m_queueSenders.Dequeue(); - - if (sender.Cancel) - { - TextureSent(sender); - - sender.Cancel = false; - } - else - { - bool finished = sender.SendTexturePacket(); - if (finished) - { - TextureSent(sender); - } - else - { - m_queueSenders.Enqueue(sender); - } - } - - // Make sure that any sender we currently have can get garbage collected - sender = null; - - //m_log.InfoFormat("[TEXTURE DOWNLOAD] Texture sender queue size: {0}", m_queueSenders.Count()); - } - } - - /// - /// Called when the texture has finished sending. - /// - /// - private void TextureSent(ITextureSender sender) - { - sender.Sending = false; - //m_log.DebugFormat("[TEXTURE DOWNLOAD]: Removing download stat for {0}", sender.assetID); - m_scene.AddPendingDownloads(-1); - } - } +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Threading; +using libsecondlife; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules.Agent.TextureDownload +{ + public class TextureDownloadModule : IRegionModule + { + //private static readonly log4net.ILog m_log + // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// There is one queue for all textures waiting to be sent, regardless of the requesting user. + /// + private readonly BlockingQueue m_queueSenders + = new BlockingQueue(); + + /// + /// Each user has their own texture download service. + /// + private readonly Dictionary m_userTextureServices = + new Dictionary(); + + private Scene m_scene; + private List m_scenes = new List(); + + private Thread m_thread; + + public TextureDownloadModule() + { + } + + #region IRegionModule Members + + public void Initialise(Scene scene, IConfigSource config) + { + if (m_scene == null) + { + //Console.WriteLine("Creating Texture download module"); + m_thread = new Thread(new ThreadStart(ProcessTextureSenders)); + m_thread.Name = "ProcessTextureSenderThread"; + m_thread.IsBackground = true; + m_thread.Start(); + ThreadTracker.Add(m_thread); + } + + if (!m_scenes.Contains(scene)) + { + m_scenes.Add(scene); + m_scene = scene; + m_scene.EventManager.OnNewClient += NewClient; + m_scene.EventManager.OnRemovePresence += EventManager_OnRemovePresence; + } + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "TextureDownloadModule"; } + } + + public bool IsSharedModule + { + get { return false; } + } + + #endregion + + /// + /// Cleanup the texture service related objects for the removed presence. + /// + /// + private void EventManager_OnRemovePresence(LLUUID agentId) + { + UserTextureDownloadService textureService; + + lock (m_userTextureServices) + { + if (m_userTextureServices.TryGetValue(agentId, out textureService)) + { + textureService.Close(); + + m_userTextureServices.Remove(agentId); + } + } + } + + public void NewClient(IClientAPI client) + { + client.OnRequestTexture += TextureRequest; + } + + /// + /// Does this user have a registered texture download service? + /// + /// + /// + /// Always returns true, since a service is created if one does not already exist + private bool TryGetUserTextureService( + IClientAPI client, out UserTextureDownloadService textureService) + { + lock (m_userTextureServices) + { + if (m_userTextureServices.TryGetValue(client.AgentId, out textureService)) + { + return true; + } + + textureService = new UserTextureDownloadService(client, m_scene, m_queueSenders); + m_userTextureServices.Add(client.AgentId, textureService); + + return true; + } + } + + /// + /// Start the process of requesting a given texture. + /// + /// + /// + public void TextureRequest(Object sender, TextureRequestArgs e) + { + IClientAPI client = (IClientAPI) sender; + UserTextureDownloadService textureService; + + if (TryGetUserTextureService(client, out textureService)) + { + textureService.HandleTextureRequest(e); + } + } + + /// + /// Entry point for the thread dedicated to processing the texture queue. + /// + public void ProcessTextureSenders() + { + ITextureSender sender = null; + + while (true) + { + sender = m_queueSenders.Dequeue(); + + if (sender.Cancel) + { + TextureSent(sender); + + sender.Cancel = false; + } + else + { + bool finished = sender.SendTexturePacket(); + if (finished) + { + TextureSent(sender); + } + else + { + m_queueSenders.Enqueue(sender); + } + } + + // Make sure that any sender we currently have can get garbage collected + sender = null; + + //m_log.InfoFormat("[TEXTURE DOWNLOAD] Texture sender queue size: {0}", m_queueSenders.Count()); + } + } + + /// + /// Called when the texture has finished sending. + /// + /// + private void TextureSent(ITextureSender sender) + { + sender.Sending = false; + //m_log.DebugFormat("[TEXTURE DOWNLOAD]: Removing download stat for {0}", sender.assetID); + m_scene.AddPendingDownloads(-1); + } + } } \ No newline at end of file diff --git a/OpenSim/Region/Environment/Modules/Agent/TextureDownload/TextureNotFoundSender.cs b/OpenSim/Region/Environment/Modules/Agent/TextureDownload/TextureNotFoundSender.cs index b181d20..70e44d4 100644 --- a/OpenSim/Region/Environment/Modules/Agent/TextureDownload/TextureNotFoundSender.cs +++ b/OpenSim/Region/Environment/Modules/Agent/TextureDownload/TextureNotFoundSender.cs @@ -1,98 +1,98 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSim Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using libsecondlife; -using libsecondlife.Packets; -using OpenSim.Framework; -using OpenSim.Region.Environment.Interfaces; - -namespace OpenSim.Region.Environment.Modules.Agent.TextureDownload -{ - /// - /// Sends a 'texture not found' packet back to the client - /// - public class TextureNotFoundSender : ITextureSender - { - //private static readonly log4net.ILog m_log - // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - - private bool m_cancel = false; - private IClientAPI m_client; - - // See ITextureSender - - private bool m_sending = false; - private LLUUID m_textureId; - - // See ITextureSender - - public TextureNotFoundSender(IClientAPI client, LLUUID textureID) - { - m_client = client; - m_textureId = textureID; - } - - #region ITextureSender Members - - public bool Sending - { - get { return false; } - set { m_sending = value; } - } - - public bool Cancel - { - get { return false; } - set { m_cancel = value; } - } - - // See ITextureSender - public void UpdateRequest(int discardLevel, uint packetNumber) - { - // Not need to implement since priority changes don't affect this operation - } - - // See ITextureSender - public bool SendTexturePacket() - { - //m_log.InfoFormat( - // "[TEXTURE NOT FOUND SENDER]: Informing the client that texture {0} cannot be found", - // m_textureId); - - ImageNotInDatabasePacket notFound = new ImageNotInDatabasePacket(); - notFound.ImageID.ID = m_textureId; - - // XXX Temporarily disabling as this appears to be causing client crashes on at least - // 1.19.0(5) of the Linden Second Life client. - // m_client.OutPacket(notFound, ThrottleOutPacketType.Texture); - - return true; - } - - #endregion - } +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using libsecondlife; +using libsecondlife.Packets; +using OpenSim.Framework; +using OpenSim.Region.Environment.Interfaces; + +namespace OpenSim.Region.Environment.Modules.Agent.TextureDownload +{ + /// + /// Sends a 'texture not found' packet back to the client + /// + public class TextureNotFoundSender : ITextureSender + { + //private static readonly log4net.ILog m_log + // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + private bool m_cancel = false; + private IClientAPI m_client; + + // See ITextureSender + + private bool m_sending = false; + private LLUUID m_textureId; + + // See ITextureSender + + public TextureNotFoundSender(IClientAPI client, LLUUID textureID) + { + m_client = client; + m_textureId = textureID; + } + + #region ITextureSender Members + + public bool Sending + { + get { return false; } + set { m_sending = value; } + } + + public bool Cancel + { + get { return false; } + set { m_cancel = value; } + } + + // See ITextureSender + public void UpdateRequest(int discardLevel, uint packetNumber) + { + // Not need to implement since priority changes don't affect this operation + } + + // See ITextureSender + public bool SendTexturePacket() + { + //m_log.InfoFormat( + // "[TEXTURE NOT FOUND SENDER]: Informing the client that texture {0} cannot be found", + // m_textureId); + + ImageNotInDatabasePacket notFound = new ImageNotInDatabasePacket(); + notFound.ImageID.ID = m_textureId; + + // XXX Temporarily disabling as this appears to be causing client crashes on at least + // 1.19.0(5) of the Linden Second Life client. + // m_client.OutPacket(notFound, ThrottleOutPacketType.Texture); + + return true; + } + + #endregion + } } \ No newline at end of file diff --git a/OpenSim/Region/Environment/Modules/Agent/TextureDownload/UserTextureDownloadService.cs b/OpenSim/Region/Environment/Modules/Agent/TextureDownload/UserTextureDownloadService.cs index 4f63fd0..a450cdc 100644 --- a/OpenSim/Region/Environment/Modules/Agent/TextureDownload/UserTextureDownloadService.cs +++ b/OpenSim/Region/Environment/Modules/Agent/TextureDownload/UserTextureDownloadService.cs @@ -1,249 +1,249 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSim Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Collections.Generic; -using System.Reflection; -using libsecondlife; -using log4net; -using OpenSim.Framework; -using OpenSim.Framework.Communications.Limit; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules.Agent.TextureDownload -{ - /// - /// This module sets up texture senders in response to client texture requests, and places them on a - /// processing queue once those senders have the appropriate data (i.e. a texture retrieved from the - /// asset cache). - /// - public class UserTextureDownloadService - { - private static readonly ILog m_log - = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - /// - /// We will allow the client to request the same texture n times before dropping further requests - /// - /// This number includes repeated requests for the same texture at different resolutions (which we don't - /// currently handle properly as far as I know). However, this situation should be handled in a more - /// sophisticated way. - /// - private static readonly int MAX_ALLOWED_TEXTURE_REQUESTS = 5; - - /// - /// XXX Also going to limit requests for found textures. - /// - private readonly IRequestLimitStrategy foundTextureLimitStrategy - = new RepeatLimitStrategy(MAX_ALLOWED_TEXTURE_REQUESTS); - - private readonly IClientAPI m_client; - private readonly Scene m_scene; - - /// - /// Texture Senders are placed in this queue once they have received their texture from the asset - /// cache. Another module actually invokes the send. - /// - private readonly BlockingQueue m_sharedSendersQueue; - - /// - /// Holds texture senders before they have received the appropriate texture from the asset cache. - /// - private readonly Dictionary m_textureSenders = new Dictionary(); - - /// - /// We're going to limit requests for the same missing texture. - /// XXX This is really a temporary solution to deal with the situation where a client continually requests - /// the same missing textures - /// - private readonly IRequestLimitStrategy missingTextureLimitStrategy - = new RepeatLimitStrategy(MAX_ALLOWED_TEXTURE_REQUESTS); - - public UserTextureDownloadService( - IClientAPI client, Scene scene, BlockingQueue sharedQueue) - { - m_client = client; - m_scene = scene; - m_sharedSendersQueue = sharedQueue; - } - - /// - /// Handle a texture request. This involves creating a texture sender and placing it on the - /// previously passed in shared queue. - /// - /// - public void HandleTextureRequest(TextureRequestArgs e) - { - TextureSender.TextureSender textureSender; - - //TODO: should be working out the data size/ number of packets to be sent for each discard level - if ((e.DiscardLevel >= 0) || (e.Priority != 0)) - { - lock (m_textureSenders) - { - if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender)) - { - // If we've received new non UUID information for this request and it hasn't dispatched - // yet, then update the request accordingly. - textureSender.UpdateRequest(e.DiscardLevel, e.PacketNumber); - } - else - { - if (!foundTextureLimitStrategy.AllowRequest(e.RequestedAssetID)) - { -// m_log.DebugFormat( -// "[USER TEXTURE DOWNLOAD SERVICE]: Refusing request for {0} from client {1}", -// e.RequestedAssetID, m_client.AgentId); - - return; - } - else if (!missingTextureLimitStrategy.AllowRequest(e.RequestedAssetID)) - { - if (missingTextureLimitStrategy.IsFirstRefusal(e.RequestedAssetID)) - { - // Commenting out this message for now as it causes too much noise with other - // debug messages. - // TODO: possibly record this as a statistic in the future - // -// m_log.DebugFormat( -// "[USER TEXTURE DOWNLOAD SERVICE]: Dropping requests for notified missing texture {0} for client {1} since we have received more than {2} requests", -// e.RequestedAssetID, m_client.AgentId, MAX_ALLOWED_TEXTURE_REQUESTS); - } - - return; - } - - m_scene.AddPendingDownloads(1); - - TextureSender.TextureSender requestHandler = new TextureSender.TextureSender(m_client, e.DiscardLevel, e.PacketNumber); - m_textureSenders.Add(e.RequestedAssetID, requestHandler); - - m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback, true); - } - } - } - else - { - lock (m_textureSenders) - { - if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender)) - { - textureSender.Cancel = true; - } - } - } - } - - /// - /// The callback for the asset cache when a texture has been retrieved. This method queues the - /// texture sender for processing. - /// - /// - /// - public void TextureCallback(LLUUID textureID, AssetBase texture) - { - //m_log.DebugFormat("[USER TEXTURE DOWNLOAD SERVICE]: Calling TextureCallback with {0}, texture == null is {1}", textureID, (texture == null ? true : false)); - - lock (m_textureSenders) - { - TextureSender.TextureSender textureSender; - - if (m_textureSenders.TryGetValue(textureID, out textureSender)) - { - // XXX It may be perfectly valid for a texture to have no data... but if we pass - // this on to the TextureSender it will blow up, so just discard for now. - // Needs investigation. - if (texture == null || texture.Data == null) - { - if (!missingTextureLimitStrategy.IsMonitoringRequests(textureID)) - { - missingTextureLimitStrategy.MonitorRequests(textureID); - - m_log.DebugFormat( - "[USER TEXTURE DOWNLOAD SERVICE]: Queueing first TextureNotFoundSender for {0}, client {1}", - textureID, m_client.AgentId); - } - - ITextureSender textureNotFoundSender = new TextureNotFoundSender(m_client, textureID); - EnqueueTextureSender(textureNotFoundSender); - } - else - { - if (!textureSender.ImageLoaded) - { - textureSender.TextureReceived(texture); - EnqueueTextureSender(textureSender); - - foundTextureLimitStrategy.MonitorRequests(textureID); - } - } - - //m_log.InfoFormat("[TEXTURE SENDER] Removing texture sender with uuid {0}", textureID); - m_textureSenders.Remove(textureID); - //m_log.InfoFormat("[TEXTURE SENDER] Current texture senders in dictionary: {0}", m_textureSenders.Count); - } - else - { - m_log.WarnFormat( - "Got a texture uuid {0} with no sender object to handle it, this shouldn't happen", - textureID); - } - } - } - - /// - /// Place a ready texture sender on the processing queue. - /// - /// - private void EnqueueTextureSender(ITextureSender textureSender) - { - textureSender.Cancel = false; - textureSender.Sending = true; - - if (!m_sharedSendersQueue.Contains(textureSender)) - { - m_sharedSendersQueue.Enqueue(textureSender); - } - } - - /// - /// Close this module. - /// - internal void Close() - { - lock (m_textureSenders) - { - foreach (TextureSender.TextureSender textureSender in m_textureSenders.Values) - { - textureSender.Cancel = true; - } - - m_textureSenders.Clear(); - } - } - } +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Collections.Generic; +using System.Reflection; +using libsecondlife; +using log4net; +using OpenSim.Framework; +using OpenSim.Framework.Communications.Limit; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules.Agent.TextureDownload +{ + /// + /// This module sets up texture senders in response to client texture requests, and places them on a + /// processing queue once those senders have the appropriate data (i.e. a texture retrieved from the + /// asset cache). + /// + public class UserTextureDownloadService + { + private static readonly ILog m_log + = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// We will allow the client to request the same texture n times before dropping further requests + /// + /// This number includes repeated requests for the same texture at different resolutions (which we don't + /// currently handle properly as far as I know). However, this situation should be handled in a more + /// sophisticated way. + /// + private static readonly int MAX_ALLOWED_TEXTURE_REQUESTS = 5; + + /// + /// XXX Also going to limit requests for found textures. + /// + private readonly IRequestLimitStrategy foundTextureLimitStrategy + = new RepeatLimitStrategy(MAX_ALLOWED_TEXTURE_REQUESTS); + + private readonly IClientAPI m_client; + private readonly Scene m_scene; + + /// + /// Texture Senders are placed in this queue once they have received their texture from the asset + /// cache. Another module actually invokes the send. + /// + private readonly BlockingQueue m_sharedSendersQueue; + + /// + /// Holds texture senders before they have received the appropriate texture from the asset cache. + /// + private readonly Dictionary m_textureSenders = new Dictionary(); + + /// + /// We're going to limit requests for the same missing texture. + /// XXX This is really a temporary solution to deal with the situation where a client continually requests + /// the same missing textures + /// + private readonly IRequestLimitStrategy missingTextureLimitStrategy + = new RepeatLimitStrategy(MAX_ALLOWED_TEXTURE_REQUESTS); + + public UserTextureDownloadService( + IClientAPI client, Scene scene, BlockingQueue sharedQueue) + { + m_client = client; + m_scene = scene; + m_sharedSendersQueue = sharedQueue; + } + + /// + /// Handle a texture request. This involves creating a texture sender and placing it on the + /// previously passed in shared queue. + /// + /// + public void HandleTextureRequest(TextureRequestArgs e) + { + TextureSender.TextureSender textureSender; + + //TODO: should be working out the data size/ number of packets to be sent for each discard level + if ((e.DiscardLevel >= 0) || (e.Priority != 0)) + { + lock (m_textureSenders) + { + if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender)) + { + // If we've received new non UUID information for this request and it hasn't dispatched + // yet, then update the request accordingly. + textureSender.UpdateRequest(e.DiscardLevel, e.PacketNumber); + } + else + { + if (!foundTextureLimitStrategy.AllowRequest(e.RequestedAssetID)) + { +// m_log.DebugFormat( +// "[USER TEXTURE DOWNLOAD SERVICE]: Refusing request for {0} from client {1}", +// e.RequestedAssetID, m_client.AgentId); + + return; + } + else if (!missingTextureLimitStrategy.AllowRequest(e.RequestedAssetID)) + { + if (missingTextureLimitStrategy.IsFirstRefusal(e.RequestedAssetID)) + { + // Commenting out this message for now as it causes too much noise with other + // debug messages. + // TODO: possibly record this as a statistic in the future + // +// m_log.DebugFormat( +// "[USER TEXTURE DOWNLOAD SERVICE]: Dropping requests for notified missing texture {0} for client {1} since we have received more than {2} requests", +// e.RequestedAssetID, m_client.AgentId, MAX_ALLOWED_TEXTURE_REQUESTS); + } + + return; + } + + m_scene.AddPendingDownloads(1); + + TextureSender.TextureSender requestHandler = new TextureSender.TextureSender(m_client, e.DiscardLevel, e.PacketNumber); + m_textureSenders.Add(e.RequestedAssetID, requestHandler); + + m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback, true); + } + } + } + else + { + lock (m_textureSenders) + { + if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender)) + { + textureSender.Cancel = true; + } + } + } + } + + /// + /// The callback for the asset cache when a texture has been retrieved. This method queues the + /// texture sender for processing. + /// + /// + /// + public void TextureCallback(LLUUID textureID, AssetBase texture) + { + //m_log.DebugFormat("[USER TEXTURE DOWNLOAD SERVICE]: Calling TextureCallback with {0}, texture == null is {1}", textureID, (texture == null ? true : false)); + + lock (m_textureSenders) + { + TextureSender.TextureSender textureSender; + + if (m_textureSenders.TryGetValue(textureID, out textureSender)) + { + // XXX It may be perfectly valid for a texture to have no data... but if we pass + // this on to the TextureSender it will blow up, so just discard for now. + // Needs investigation. + if (texture == null || texture.Data == null) + { + if (!missingTextureLimitStrategy.IsMonitoringRequests(textureID)) + { + missingTextureLimitStrategy.MonitorRequests(textureID); + + m_log.DebugFormat( + "[USER TEXTURE DOWNLOAD SERVICE]: Queueing first TextureNotFoundSender for {0}, client {1}", + textureID, m_client.AgentId); + } + + ITextureSender textureNotFoundSender = new TextureNotFoundSender(m_client, textureID); + EnqueueTextureSender(textureNotFoundSender); + } + else + { + if (!textureSender.ImageLoaded) + { + textureSender.TextureReceived(texture); + EnqueueTextureSender(textureSender); + + foundTextureLimitStrategy.MonitorRequests(textureID); + } + } + + //m_log.InfoFormat("[TEXTURE SENDER] Removing texture sender with uuid {0}", textureID); + m_textureSenders.Remove(textureID); + //m_log.InfoFormat("[TEXTURE SENDER] Current texture senders in dictionary: {0}", m_textureSenders.Count); + } + else + { + m_log.WarnFormat( + "Got a texture uuid {0} with no sender object to handle it, this shouldn't happen", + textureID); + } + } + } + + /// + /// Place a ready texture sender on the processing queue. + /// + /// + private void EnqueueTextureSender(ITextureSender textureSender) + { + textureSender.Cancel = false; + textureSender.Sending = true; + + if (!m_sharedSendersQueue.Contains(textureSender)) + { + m_sharedSendersQueue.Enqueue(textureSender); + } + } + + /// + /// Close this module. + /// + internal void Close() + { + lock (m_textureSenders) + { + foreach (TextureSender.TextureSender textureSender in m_textureSenders.Values) + { + textureSender.Cancel = true; + } + + m_textureSenders.Clear(); + } + } + } } \ No newline at end of file diff --git a/OpenSim/Region/Environment/Modules/Agent/TextureSender/TextureSender.cs b/OpenSim/Region/Environment/Modules/Agent/TextureSender/TextureSender.cs index b6f7095..02c541b 100644 --- a/OpenSim/Region/Environment/Modules/Agent/TextureSender/TextureSender.cs +++ b/OpenSim/Region/Environment/Modules/Agent/TextureSender/TextureSender.cs @@ -1,223 +1,223 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSim Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Reflection; -using libsecondlife.Packets; -using log4net; -using OpenSim.Framework; -using OpenSim.Region.Environment.Interfaces; - -namespace OpenSim.Region.Environment.Modules.Agent.TextureSender -{ - /// - /// A TextureSender handles the process of receiving a texture requested by the client from the - /// AssetCache, and then sending that texture back to the client. - /// - public class TextureSender : ITextureSender - { - private static readonly ILog m_log - = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - /// - /// Records the number of times texture send has been called. - /// - public int counter = 0; - - public bool ImageLoaded = false; - - /// - /// Holds the texture asset to send. - /// - private AssetBase m_asset; - - //public LLUUID assetID { get { return m_asset.FullID; } } - - private bool m_cancel = false; - - // See ITextureSender - - private bool m_sending = false; - - /// - /// This is actually the number of extra packets required to send the texture data! We always assume - /// at least one is required. - /// - private int NumPackets = 0; - - /// - /// Holds the packet number to send next. In this case, each packet is 1000 bytes long and starts - /// at the 600th byte (0th indexed). - /// - private int PacketCounter = 0; - - private int RequestedDiscardLevel = -1; - private IClientAPI RequestUser; - private uint StartPacketNumber = 0; - - public TextureSender(IClientAPI client, int discardLevel, uint packetNumber) - { - RequestUser = client; - RequestedDiscardLevel = discardLevel; - StartPacketNumber = packetNumber; - } - - #region ITextureSender Members - - public bool Cancel - { - get { return false; } - set { m_cancel = value; } - } - - public bool Sending - { - get { return false; } - set { m_sending = value; } - } - - // See ITextureSender - public void UpdateRequest(int discardLevel, uint packetNumber) - { - RequestedDiscardLevel = discardLevel; - StartPacketNumber = packetNumber; - PacketCounter = (int) StartPacketNumber; - } - - // See ITextureSender - public bool SendTexturePacket() - { - //m_log.DebugFormat("[TEXTURE SENDER]: Sending packet for {0}", m_asset.FullID); - - SendPacket(); - counter++; - if ((NumPackets == 0) || (RequestedDiscardLevel == -1) || (PacketCounter > NumPackets) || - ((RequestedDiscardLevel > 0) && (counter > 50 + (NumPackets / (RequestedDiscardLevel + 1))))) - { - return true; - } - return false; - } - - #endregion - - /// - /// Load up the texture data to send. - /// - /// - /// A - /// - public void TextureReceived(AssetBase asset) - { - m_asset = asset; - NumPackets = CalculateNumPackets(asset.Data.Length); - PacketCounter = (int) StartPacketNumber; - ImageLoaded = true; - } - - /// - /// Sends a texture packet to the client. - /// - private void SendPacket() - { - if (PacketCounter <= NumPackets) - { - if (PacketCounter == 0) - { - if (NumPackets == 0) - { - ImageDataPacket im = new ImageDataPacket(); - im.Header.Reliable = false; - im.ImageID.Packets = 1; - im.ImageID.ID = m_asset.FullID; - im.ImageID.Size = (uint) m_asset.Data.Length; - im.ImageData.Data = m_asset.Data; - im.ImageID.Codec = 2; - RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); - PacketCounter++; - } - else - { - ImageDataPacket im = new ImageDataPacket(); - im.Header.Reliable = false; - im.ImageID.Packets = (ushort) (NumPackets); - im.ImageID.ID = m_asset.FullID; - im.ImageID.Size = (uint) m_asset.Data.Length; - im.ImageData.Data = new byte[600]; - Array.Copy(m_asset.Data, 0, im.ImageData.Data, 0, 600); - im.ImageID.Codec = 2; - RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); - PacketCounter++; - } - } - else - { - ImagePacketPacket im = new ImagePacketPacket(); - im.Header.Reliable = false; - im.ImageID.Packet = (ushort) (PacketCounter); - im.ImageID.ID = m_asset.FullID; - int size = m_asset.Data.Length - 600 - (1000 * (PacketCounter - 1)); - if (size > 1000) size = 1000; - im.ImageData.Data = new byte[size]; - try - { - Array.Copy(m_asset.Data, 600 + (1000 * (PacketCounter - 1)), im.ImageData.Data, 0, size); - } - catch (ArgumentOutOfRangeException) - { - m_log.Error("[TEXTURE SENDER]: Unable to separate texture into multiple packets: Array bounds failure on asset:" + - m_asset.FullID.ToString()); - return; - } - RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); - PacketCounter++; - } - } - } - - /// - /// Calculate the number of packets that will be required to send the texture loaded into this sender - /// This is actually the number of 1000 byte packets not including an initial 600 byte packet... - /// - /// - /// - private int CalculateNumPackets(int length) - { - int numPackets = 0; - - if (length > 600) - { - //over 600 bytes so split up file - int restData = (length - 600); - int restPackets = ((restData + 999) / 1000); - numPackets = restPackets; - } - - return numPackets; - } - } +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using libsecondlife.Packets; +using log4net; +using OpenSim.Framework; +using OpenSim.Region.Environment.Interfaces; + +namespace OpenSim.Region.Environment.Modules.Agent.TextureSender +{ + /// + /// A TextureSender handles the process of receiving a texture requested by the client from the + /// AssetCache, and then sending that texture back to the client. + /// + public class TextureSender : ITextureSender + { + private static readonly ILog m_log + = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Records the number of times texture send has been called. + /// + public int counter = 0; + + public bool ImageLoaded = false; + + /// + /// Holds the texture asset to send. + /// + private AssetBase m_asset; + + //public LLUUID assetID { get { return m_asset.FullID; } } + + private bool m_cancel = false; + + // See ITextureSender + + private bool m_sending = false; + + /// + /// This is actually the number of extra packets required to send the texture data! We always assume + /// at least one is required. + /// + private int NumPackets = 0; + + /// + /// Holds the packet number to send next. In this case, each packet is 1000 bytes long and starts + /// at the 600th byte (0th indexed). + /// + private int PacketCounter = 0; + + private int RequestedDiscardLevel = -1; + private IClientAPI RequestUser; + private uint StartPacketNumber = 0; + + public TextureSender(IClientAPI client, int discardLevel, uint packetNumber) + { + RequestUser = client; + RequestedDiscardLevel = discardLevel; + StartPacketNumber = packetNumber; + } + + #region ITextureSender Members + + public bool Cancel + { + get { return false; } + set { m_cancel = value; } + } + + public bool Sending + { + get { return false; } + set { m_sending = value; } + } + + // See ITextureSender + public void UpdateRequest(int discardLevel, uint packetNumber) + { + RequestedDiscardLevel = discardLevel; + StartPacketNumber = packetNumber; + PacketCounter = (int) StartPacketNumber; + } + + // See ITextureSender + public bool SendTexturePacket() + { + //m_log.DebugFormat("[TEXTURE SENDER]: Sending packet for {0}", m_asset.FullID); + + SendPacket(); + counter++; + if ((NumPackets == 0) || (RequestedDiscardLevel == -1) || (PacketCounter > NumPackets) || + ((RequestedDiscardLevel > 0) && (counter > 50 + (NumPackets / (RequestedDiscardLevel + 1))))) + { + return true; + } + return false; + } + + #endregion + + /// + /// Load up the texture data to send. + /// + /// + /// A + /// + public void TextureReceived(AssetBase asset) + { + m_asset = asset; + NumPackets = CalculateNumPackets(asset.Data.Length); + PacketCounter = (int) StartPacketNumber; + ImageLoaded = true; + } + + /// + /// Sends a texture packet to the client. + /// + private void SendPacket() + { + if (PacketCounter <= NumPackets) + { + if (PacketCounter == 0) + { + if (NumPackets == 0) + { + ImageDataPacket im = new ImageDataPacket(); + im.Header.Reliable = false; + im.ImageID.Packets = 1; + im.ImageID.ID = m_asset.FullID; + im.ImageID.Size = (uint) m_asset.Data.Length; + im.ImageData.Data = m_asset.Data; + im.ImageID.Codec = 2; + RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); + PacketCounter++; + } + else + { + ImageDataPacket im = new ImageDataPacket(); + im.Header.Reliable = false; + im.ImageID.Packets = (ushort) (NumPackets); + im.ImageID.ID = m_asset.FullID; + im.ImageID.Size = (uint) m_asset.Data.Length; + im.ImageData.Data = new byte[600]; + Array.Copy(m_asset.Data, 0, im.ImageData.Data, 0, 600); + im.ImageID.Codec = 2; + RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); + PacketCounter++; + } + } + else + { + ImagePacketPacket im = new ImagePacketPacket(); + im.Header.Reliable = false; + im.ImageID.Packet = (ushort) (PacketCounter); + im.ImageID.ID = m_asset.FullID; + int size = m_asset.Data.Length - 600 - (1000 * (PacketCounter - 1)); + if (size > 1000) size = 1000; + im.ImageData.Data = new byte[size]; + try + { + Array.Copy(m_asset.Data, 600 + (1000 * (PacketCounter - 1)), im.ImageData.Data, 0, size); + } + catch (ArgumentOutOfRangeException) + { + m_log.Error("[TEXTURE SENDER]: Unable to separate texture into multiple packets: Array bounds failure on asset:" + + m_asset.FullID.ToString()); + return; + } + RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); + PacketCounter++; + } + } + } + + /// + /// Calculate the number of packets that will be required to send the texture loaded into this sender + /// This is actually the number of 1000 byte packets not including an initial 600 byte packet... + /// + /// + /// + private int CalculateNumPackets(int length) + { + int numPackets = 0; + + if (length > 600) + { + //over 600 bytes so split up file + int restData = (length - 600); + int restPackets = ((restData + 999) / 1000); + numPackets = restPackets; + } + + return numPackets; + } + } } \ No newline at end of file diff --git a/OpenSim/Region/Environment/Modules/Agent/Xfer/XferModule.cs b/OpenSim/Region/Environment/Modules/Agent/Xfer/XferModule.cs index e35b6f5..8e90d17 100644 --- a/OpenSim/Region/Environment/Modules/Agent/Xfer/XferModule.cs +++ b/OpenSim/Region/Environment/Modules/Agent/Xfer/XferModule.cs @@ -1,235 +1,235 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSim Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using libsecondlife; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules.Agent.Xfer -{ - public class XferModule : IRegionModule, IXfer - { - private Scene m_scene; - public Dictionary NewFiles = new Dictionary(); - public Dictionary Transfers = new Dictionary(); - - public XferModule() - { - } - - #region IRegionModule Members - - public void Initialise(Scene scene, IConfigSource config) - { - m_scene = scene; - m_scene.EventManager.OnNewClient += NewClient; - - m_scene.RegisterModuleInterface(this); - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "XferModule"; } - } - - public bool IsSharedModule - { - get { return false; } - } - - #endregion - - #region IXfer Members - - public bool AddNewFile(string fileName, byte[] data) - { - lock (NewFiles) - { - if (NewFiles.ContainsKey(fileName)) - { - NewFiles[fileName] = data; - } - else - { - NewFiles.Add(fileName, data); - } - } - return true; - } - - #endregion - - public void NewClient(IClientAPI client) - { - client.OnRequestXfer += RequestXfer; - client.OnConfirmXfer += AckPacket; - } - - /// - /// - /// - /// - /// - /// - public void RequestXfer(IClientAPI remoteClient, ulong xferID, string fileName) - { - lock (NewFiles) - { - if (NewFiles.ContainsKey(fileName)) - { - if (!Transfers.ContainsKey(xferID)) - { - byte[] fileData = NewFiles[fileName]; - XferDownLoad transaction = new XferDownLoad(fileName, fileData, xferID, remoteClient); - Transfers.Add(xferID, transaction); - NewFiles.Remove(fileName); - - if (transaction.StartSend()) - { - Transfers.Remove(xferID); - } - } - } - } - } - - public void AckPacket(IClientAPI remoteClient, ulong xferID, uint packet) - { - if (Transfers.ContainsKey(xferID)) - { - if (Transfers[xferID].AckPacket(packet)) - { - { - Transfers.Remove(xferID); - } - } - } - } - - #region Nested type: XferDownLoad - - public class XferDownLoad - { - public IClientAPI Client; - private bool complete; - public byte[] Data = new byte[0]; - public int DataPointer = 0; - public string FileName = String.Empty; - public uint Packet = 0; - public uint Serial = 1; - public ulong XferID = 0; - - public XferDownLoad(string fileName, byte[] data, ulong xferID, IClientAPI client) - { - FileName = fileName; - Data = data; - XferID = xferID; - Client = client; - } - - public XferDownLoad() - { - } - - /// - /// Start a transfer - /// - /// True if the transfer is complete, false if not - public bool StartSend() - { - if (Data.Length < 1000) - { - // for now (testing ) we only support files under 1000 bytes - byte[] transferData = new byte[Data.Length + 4]; - Array.Copy(Helpers.IntToBytes(Data.Length), 0, transferData, 0, 4); - Array.Copy(Data, 0, transferData, 4, Data.Length); - Client.SendXferPacket(XferID, 0 + 0x80000000, transferData); - - complete = true; - } - else - { - byte[] transferData = new byte[1000 + 4]; - Array.Copy(Helpers.IntToBytes(Data.Length), 0, transferData, 0, 4); - Array.Copy(Data, 0, transferData, 4, 1000); - Client.SendXferPacket(XferID, 0, transferData); - Packet++; - DataPointer = 1000; - } - - return complete; - } - - /// - /// Respond to an ack packet from the client - /// - /// - /// True if the transfer is complete, false otherwise - public bool AckPacket(uint packet) - { - if (!complete) - { - if ((Data.Length - DataPointer) > 1000) - { - byte[] transferData = new byte[1000]; - Array.Copy(Data, DataPointer, transferData, 0, 1000); - Client.SendXferPacket(XferID, Packet, transferData); - Packet++; - DataPointer += 1000; - } - else - { - byte[] transferData = new byte[Data.Length - DataPointer]; - Array.Copy(Data, DataPointer, transferData, 0, Data.Length - DataPointer); - uint endPacket = Packet |= (uint) 0x80000000; - Client.SendXferPacket(XferID, endPacket, transferData); - Packet++; - DataPointer += (Data.Length - DataPointer); - - complete = true; - } - } - - return complete; - } - } - - #endregion - } +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using libsecondlife; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules.Agent.Xfer +{ + public class XferModule : IRegionModule, IXfer + { + private Scene m_scene; + public Dictionary NewFiles = new Dictionary(); + public Dictionary Transfers = new Dictionary(); + + public XferModule() + { + } + + #region IRegionModule Members + + public void Initialise(Scene scene, IConfigSource config) + { + m_scene = scene; + m_scene.EventManager.OnNewClient += NewClient; + + m_scene.RegisterModuleInterface(this); + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "XferModule"; } + } + + public bool IsSharedModule + { + get { return false; } + } + + #endregion + + #region IXfer Members + + public bool AddNewFile(string fileName, byte[] data) + { + lock (NewFiles) + { + if (NewFiles.ContainsKey(fileName)) + { + NewFiles[fileName] = data; + } + else + { + NewFiles.Add(fileName, data); + } + } + return true; + } + + #endregion + + public void NewClient(IClientAPI client) + { + client.OnRequestXfer += RequestXfer; + client.OnConfirmXfer += AckPacket; + } + + /// + /// + /// + /// + /// + /// + public void RequestXfer(IClientAPI remoteClient, ulong xferID, string fileName) + { + lock (NewFiles) + { + if (NewFiles.ContainsKey(fileName)) + { + if (!Transfers.ContainsKey(xferID)) + { + byte[] fileData = NewFiles[fileName]; + XferDownLoad transaction = new XferDownLoad(fileName, fileData, xferID, remoteClient); + Transfers.Add(xferID, transaction); + NewFiles.Remove(fileName); + + if (transaction.StartSend()) + { + Transfers.Remove(xferID); + } + } + } + } + } + + public void AckPacket(IClientAPI remoteClient, ulong xferID, uint packet) + { + if (Transfers.ContainsKey(xferID)) + { + if (Transfers[xferID].AckPacket(packet)) + { + { + Transfers.Remove(xferID); + } + } + } + } + + #region Nested type: XferDownLoad + + public class XferDownLoad + { + public IClientAPI Client; + private bool complete; + public byte[] Data = new byte[0]; + public int DataPointer = 0; + public string FileName = String.Empty; + public uint Packet = 0; + public uint Serial = 1; + public ulong XferID = 0; + + public XferDownLoad(string fileName, byte[] data, ulong xferID, IClientAPI client) + { + FileName = fileName; + Data = data; + XferID = xferID; + Client = client; + } + + public XferDownLoad() + { + } + + /// + /// Start a transfer + /// + /// True if the transfer is complete, false if not + public bool StartSend() + { + if (Data.Length < 1000) + { + // for now (testing ) we only support files under 1000 bytes + byte[] transferData = new byte[Data.Length + 4]; + Array.Copy(Helpers.IntToBytes(Data.Length), 0, transferData, 0, 4); + Array.Copy(Data, 0, transferData, 4, Data.Length); + Client.SendXferPacket(XferID, 0 + 0x80000000, transferData); + + complete = true; + } + else + { + byte[] transferData = new byte[1000 + 4]; + Array.Copy(Helpers.IntToBytes(Data.Length), 0, transferData, 0, 4); + Array.Copy(Data, 0, transferData, 4, 1000); + Client.SendXferPacket(XferID, 0, transferData); + Packet++; + DataPointer = 1000; + } + + return complete; + } + + /// + /// Respond to an ack packet from the client + /// + /// + /// True if the transfer is complete, false otherwise + public bool AckPacket(uint packet) + { + if (!complete) + { + if ((Data.Length - DataPointer) > 1000) + { + byte[] transferData = new byte[1000]; + Array.Copy(Data, DataPointer, transferData, 0, 1000); + Client.SendXferPacket(XferID, Packet, transferData); + Packet++; + DataPointer += 1000; + } + else + { + byte[] transferData = new byte[Data.Length - DataPointer]; + Array.Copy(Data, DataPointer, transferData, 0, Data.Length - DataPointer); + uint endPacket = Packet |= (uint) 0x80000000; + Client.SendXferPacket(XferID, endPacket, transferData); + Packet++; + DataPointer += (Data.Length - DataPointer); + + complete = true; + } + } + + return complete; + } + } + + #endregion + } } \ No newline at end of file -- cgit v1.1