Reverting the deletion of files related to texture sending until we figure out exactly what is and isn't needed
							parent
							
								
									8151190a45
								
							
						
					
					
						commit
						edd393ff30
					
				|  | @ -163,7 +163,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
|             CircuitCode = circuitCode; | ||||
|             m_udpServer = server; | ||||
|             m_defaultThrottleRates = rates; | ||||
|             // Create a token bucket throttle for this client that has the scene token bucket as a parent | ||||
|             m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total); | ||||
|             // Create an array of token buckets for this clients different throttle categories | ||||
|             m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; | ||||
| 
 | ||||
|             for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | ||||
|  |  | |||
|  | @ -0,0 +1,302 @@ | |||
| /* | ||||
|  * 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 OpenSimulator 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 System.Threading; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Communications.Cache; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| using OpenSim.Region.Framework.Scenes; | ||||
| using BlockingQueue = OpenSim.Framework.BlockingQueue<OpenSim.Region.Framework.Interfaces.ITextureSender>; | ||||
| using OpenSim.Services.Interfaces; | ||||
| 
 | ||||
| namespace OpenSim.Region.CoreModules.Agent.TextureDownload | ||||
| { | ||||
|     public class TextureDownloadModule : IRegionModule | ||||
|     { | ||||
|         private static readonly ILog m_log | ||||
|             = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// There is one queue for all textures waiting to be sent, regardless of the requesting user. | ||||
|         /// </summary> | ||||
|         private readonly BlockingQueue m_queueSenders | ||||
|             = new BlockingQueue(); | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Each user has their own texture download service. | ||||
|         /// </summary> | ||||
|         private readonly Dictionary<UUID, UserTextureDownloadService> m_userTextureServices = | ||||
|             new Dictionary<UUID, UserTextureDownloadService>(); | ||||
| 
 | ||||
|         private Scene m_scene; | ||||
|         private List<Scene> m_scenes = new List<Scene>(); | ||||
| 
 | ||||
|         public TextureDownloadModule() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         #region IRegionModule Members | ||||
| 
 | ||||
|         public void Initialise(Scene scene, IConfigSource config) | ||||
|         { | ||||
|              | ||||
|             if (m_scene == null) | ||||
|             { | ||||
|                 //m_log.Debug("Creating Texture download module"); | ||||
|                 m_scene = scene; | ||||
|                 //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 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Cleanup the texture service related objects for the removed presence. | ||||
|         /// </summary> | ||||
|         /// <param name="agentId"> </param> | ||||
|         private void EventManager_OnRemovePresence(UUID agentId) | ||||
|         { | ||||
|             UserTextureDownloadService textureService; | ||||
| 
 | ||||
|             lock (m_userTextureServices) | ||||
|             { | ||||
|                 if (m_userTextureServices.TryGetValue(agentId, out textureService)) | ||||
|                 { | ||||
|                     textureService.Close(); | ||||
|                     //m_log.DebugFormat("[TEXTURE MODULE]: Removing UserTextureServices from {0}", m_scene.RegionInfo.RegionName); | ||||
|                     m_userTextureServices.Remove(agentId); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void NewClient(IClientAPI client) | ||||
|         { | ||||
|             UserTextureDownloadService textureService; | ||||
| 
 | ||||
|             lock (m_userTextureServices) | ||||
|             { | ||||
|                 if (m_userTextureServices.TryGetValue(client.AgentId, out textureService)) | ||||
|                 { | ||||
|                     textureService.Close(); | ||||
|                     //m_log.DebugFormat("[TEXTURE MODULE]: Removing outdated UserTextureServices from {0}", m_scene.RegionInfo.RegionName); | ||||
|                     m_userTextureServices.Remove(client.AgentId); | ||||
|                 } | ||||
|                 m_userTextureServices.Add(client.AgentId, new UserTextureDownloadService(client, m_scene, m_queueSenders)); | ||||
|             } | ||||
| 
 | ||||
|             client.OnRequestTexture += TextureRequest; | ||||
|         } | ||||
| 
 | ||||
|         /// I'm commenting this out, and replacing it with the implementation below, which | ||||
|         /// may return a null value. This is necessary for avoiding race conditions  | ||||
|         /// recreating UserTextureServices for clients that have just been closed. | ||||
|         /// That behavior of always returning a UserTextureServices was causing the | ||||
|         /// A-B-A problem (mantis #2855). | ||||
|         ///  | ||||
|         ///// <summary> | ||||
|         ///// Does this user have a registered texture download service? | ||||
|         ///// </summary> | ||||
|         ///// <param name="userID"></param> | ||||
|         ///// <param name="textureService"></param> | ||||
|         ///// <returns>Always returns true, since a service is created if one does not already exist</returns> | ||||
|         //private bool TryGetUserTextureService( | ||||
|         //    IClientAPI client, out UserTextureDownloadService textureService) | ||||
|         //{ | ||||
|         //    lock (m_userTextureServices) | ||||
|         //    { | ||||
|         //        if (m_userTextureServices.TryGetValue(client.AgentId, out textureService)) | ||||
|         //        { | ||||
|         //            //m_log.DebugFormat("[TEXTURE MODULE]: Found existing UserTextureServices in ", m_scene.RegionInfo.RegionName); | ||||
|         //            return true; | ||||
|         //        } | ||||
| 
 | ||||
|         //        m_log.DebugFormat("[TEXTURE MODULE]: Creating new UserTextureServices in ", m_scene.RegionInfo.RegionName); | ||||
|         //        textureService = new UserTextureDownloadService(client, m_scene, m_queueSenders); | ||||
|         //        m_userTextureServices.Add(client.AgentId, textureService); | ||||
| 
 | ||||
|         //        return true; | ||||
|         //    } | ||||
|         //} | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Does this user have a registered texture download service? | ||||
|         /// </summary> | ||||
|         /// <param name="userID"></param> | ||||
|         /// <param name="textureService"></param> | ||||
|         /// <returns>A UserTextureDownloadService or null in the output parameter, and true or false accordingly.</returns> | ||||
|         private bool TryGetUserTextureService(IClientAPI client, out UserTextureDownloadService textureService) | ||||
|         { | ||||
|             lock (m_userTextureServices) | ||||
|             { | ||||
|                 if (m_userTextureServices.TryGetValue(client.AgentId, out textureService)) | ||||
|                 { | ||||
|                     //m_log.DebugFormat("[TEXTURE MODULE]: Found existing UserTextureServices in ", m_scene.RegionInfo.RegionName); | ||||
|                     return true; | ||||
|                 } | ||||
| 
 | ||||
|                 textureService = null; | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Start the process of requesting a given texture. | ||||
|         /// </summary> | ||||
|         /// <param name="sender"> </param> | ||||
|         /// <param name="e"></param> | ||||
|         public void TextureRequest(Object sender, TextureRequestArgs e) | ||||
|         { | ||||
|             IClientAPI client = (IClientAPI)sender; | ||||
| 
 | ||||
|             if (e.Priority == 1016001f) // Preview | ||||
|             { | ||||
|                 if (client.Scene is Scene) | ||||
|                 { | ||||
|                     Scene scene = (Scene)client.Scene; | ||||
| 
 | ||||
|                     CachedUserInfo profile = scene.CommsManager.UserProfileCacheService.GetUserDetails(client.AgentId); | ||||
|                     if (profile == null) // Deny unknown user | ||||
|                         return; | ||||
| 
 | ||||
|                     IInventoryService invService = scene.InventoryService; | ||||
|                     if (invService.GetRootFolder(client.AgentId) == null) // Deny no inventory | ||||
|                         return; | ||||
| 
 | ||||
|                     // Diva 2009-08-13: this test doesn't make any sense to many devs | ||||
|                     //if (profile.UserProfile.GodLevel < 200 && profile.RootFolder.FindAsset(e.RequestedAssetID) == null) // Deny if not owned | ||||
|                     //{ | ||||
|                     //    m_log.WarnFormat("[TEXTURE]: user {0} doesn't have permissions to texture {1}"); | ||||
|                     //    return; | ||||
|                     //} | ||||
| 
 | ||||
|                     m_log.Debug("Texture preview"); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             UserTextureDownloadService textureService; | ||||
| 
 | ||||
|             if (TryGetUserTextureService(client, out textureService)) | ||||
|             { | ||||
|                 textureService.HandleTextureRequest(e); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Entry point for the thread dedicated to processing the texture queue. | ||||
|         /// </summary> | ||||
|         public void ProcessTextureSenders() | ||||
|         { | ||||
|             ITextureSender sender = null; | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 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] Texture sender queue size: {0}", m_queueSenders.Count()); | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 // TODO: Let users in the sim and those entering it and possibly an external watchdog know what has happened | ||||
|                 m_log.ErrorFormat( | ||||
|                     "[TEXTURE]: Texture send thread terminating with exception.  PLEASE REBOOT YOUR SIM - TEXTURES WILL NOT BE AVAILABLE UNTIL YOU DO.  Exception is {0}", | ||||
|                     e); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Called when the texture has finished sending. | ||||
|         /// </summary> | ||||
|         /// <param name="sender"></param> | ||||
|         private void TextureSent(ITextureSender sender) | ||||
|         { | ||||
|             sender.Sending = false; | ||||
|             //m_log.DebugFormat("[TEXTURE]: Removing download stat for {0}", sender.assetID); | ||||
|             m_scene.StatsReporter.AddPendingDownloads(-1); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,87 @@ | |||
| /* | ||||
|  * 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 OpenSimulator 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 OpenMetaverse; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| 
 | ||||
| namespace OpenSim.Region.CoreModules.Agent.TextureDownload | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Sends a 'texture not found' packet back to the client | ||||
|     /// </summary> | ||||
|     public class TextureNotFoundSender : ITextureSender | ||||
|     { | ||||
|         //        private static readonly log4net.ILog m_log | ||||
|         //            = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         //        private IClientAPI m_client; | ||||
|         //        private UUID m_textureId; | ||||
| 
 | ||||
|         public TextureNotFoundSender(IClientAPI client, UUID textureID) | ||||
|         { | ||||
|             //m_client = client; | ||||
|             //m_textureId = textureID; | ||||
|         } | ||||
| 
 | ||||
|         #region ITextureSender Members | ||||
| 
 | ||||
|         public bool Sending | ||||
|         { | ||||
|             get { return false; } | ||||
|             set { } | ||||
|         } | ||||
| 
 | ||||
|         public bool Cancel | ||||
|         { | ||||
|             get { return false; } | ||||
|             set { } | ||||
|         } | ||||
| 
 | ||||
|         // See ITextureSender | ||||
|         public void UpdateRequest(int discardLevel, uint packetNumber) | ||||
|         { | ||||
|             // No need to implement since priority changes don't affect this operation | ||||
|         } | ||||
| 
 | ||||
|         // See ITextureSender | ||||
|         public bool SendTexturePacket() | ||||
|         { | ||||
|             //            m_log.DebugFormat( | ||||
|             //                "[TEXTURE NOT FOUND SENDER]: Informing the client that texture {0} cannot be found", | ||||
|             //                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.SendImageNotFound(m_textureId); | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,265 @@ | |||
| /* | ||||
|  * 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 OpenSimulator 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 log4net; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Communications.Limit; | ||||
| using OpenSim.Framework.Statistics; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| using OpenSim.Region.Framework.Scenes; | ||||
| 
 | ||||
| namespace OpenSim.Region.CoreModules.Agent.TextureDownload | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 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). | ||||
|     /// </summary> | ||||
|     public class UserTextureDownloadService | ||||
|     { | ||||
| //        private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// True if the service has been closed, probably because a user with texture requests still queued | ||||
|         /// logged out. | ||||
|         /// </summary> | ||||
|         private bool closed; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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. | ||||
|         /// </summary> | ||||
| //        private static readonly int MAX_ALLOWED_TEXTURE_REQUESTS = 5; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// XXX Also going to limit requests for found textures. | ||||
|         /// </summary> | ||||
| //        private readonly IRequestLimitStrategy<UUID> foundTextureLimitStrategy | ||||
| //            = new RepeatLimitStrategy<UUID>(MAX_ALLOWED_TEXTURE_REQUESTS); | ||||
| 
 | ||||
| //        private readonly IClientAPI m_client; | ||||
|         private readonly Scene m_scene; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Texture Senders are placed in this queue once they have received their texture from the asset | ||||
|         /// cache.  Another module actually invokes the send. | ||||
|         /// </summary> | ||||
| //        private readonly OpenSim.Framework.BlockingQueue<ITextureSender> m_sharedSendersQueue; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Holds texture senders before they have received the appropriate texture from the asset cache. | ||||
|         /// </summary> | ||||
|         private readonly Dictionary<UUID, TextureSender.TextureSender> m_textureSenders = new Dictionary<UUID, TextureSender.TextureSender>(); | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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 | ||||
|         /// </summary> | ||||
| //        private readonly IRequestLimitStrategy<UUID> missingTextureLimitStrategy | ||||
| //            = new RepeatLimitStrategy<UUID>(MAX_ALLOWED_TEXTURE_REQUESTS); | ||||
| 
 | ||||
|         public UserTextureDownloadService( | ||||
|             IClientAPI client, Scene scene, OpenSim.Framework.BlockingQueue<ITextureSender> sharedQueue) | ||||
|         { | ||||
| //            m_client = client; | ||||
|             m_scene = scene; | ||||
| //            m_sharedSendersQueue = sharedQueue; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Handle a texture request.  This involves creating a texture sender and placing it on the | ||||
|         /// previously passed in shared queue. | ||||
|         /// </summary> | ||||
|         /// <param name="e"></param> | ||||
|         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 | ||||
|                     //{ | ||||
|                         //                        m_log.DebugFormat("[TEXTURE]: Received a request for texture {0}", e.RequestedAssetID); | ||||
| 
 | ||||
|                         //if (!foundTextureLimitStrategy.AllowRequest(e.RequestedAssetID)) | ||||
|                         //{ | ||||
|                             //                            m_log.DebugFormat( | ||||
|                             //                                "[TEXTURE]: Refusing request for {0} from client {1}", | ||||
|                             //                                e.RequestedAssetID, m_client.AgentId); | ||||
| 
 | ||||
|                             //return; | ||||
|                         //} | ||||
|                         //else if (!missingTextureLimitStrategy.AllowRequest(e.RequestedAssetID)) | ||||
|                         //{ | ||||
|                         //    if (missingTextureLimitStrategy.IsFirstRefusal(e.RequestedAssetID)) | ||||
|                         //    { | ||||
|                          //       if (StatsManager.SimExtraStats != null) | ||||
|                          //           StatsManager.SimExtraStats.AddBlockedMissingTextureRequest(); | ||||
| 
 | ||||
|                                 // Commenting out this message for now as it causes too much noise with other | ||||
|                                 // debug messages. | ||||
|                                 //                                m_log.DebugFormat( | ||||
|                                 //                                    "[TEXTURE]: 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.StatsReporter.AddPendingDownloads(1); | ||||
| 
 | ||||
|                 //TextureSender.TextureSender requestHandler = new TextureSender.TextureSender(m_client, e.DiscardLevel, e.PacketNumber); | ||||
|                 //m_textureSenders.Add(e.RequestedAssetID, null); | ||||
| 
 | ||||
|                 m_scene.AssetService.Get(e.RequestedAssetID.ToString(), this, TextureReceived); | ||||
|                 | ||||
|             | ||||
|         } | ||||
| 
 | ||||
|         protected void TextureReceived(string id, Object sender, AssetBase asset) | ||||
|         { | ||||
|             if (asset != null) | ||||
|                 TextureCallback(asset.FullID, asset); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// The callback for the asset cache when a texture has been retrieved.  This method queues the | ||||
|         /// texture sender for processing. | ||||
|         /// </summary> | ||||
|         /// <param name="textureID"></param> | ||||
|         /// <param name="texture"></param> | ||||
|         public void TextureCallback(UUID textureID, AssetBase texture) | ||||
|         { | ||||
|             //m_log.DebugFormat("[USER TEXTURE DOWNLOAD SERVICE]: Calling TextureCallback with {0}, texture == null is {1}", textureID, (texture == null ? true : false)); | ||||
| 
 | ||||
|             // There may still be texture requests pending for a logged out client | ||||
|             if (closed) | ||||
|                 return; | ||||
| 
 | ||||
|             /* | ||||
|             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( | ||||
|                             //                                "[TEXTURE]: 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] Removing texture sender with uuid {0}", textureID); | ||||
|                     m_textureSenders.Remove(textureID); | ||||
|                     //m_log.InfoFormat("[TEXTURE] Current texture senders in dictionary: {0}", m_textureSenders.Count); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     m_log.WarnFormat( | ||||
|                         "[TEXTURE]: Got a texture uuid {0} with no sender object to handle it, this shouldn't happen", | ||||
|                         textureID); | ||||
|                 } | ||||
|             } | ||||
|           */ | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Place a ready texture sender on the processing queue. | ||||
|         /// </summary> | ||||
|         /// <param name="textureSender"></param> | ||||
| //        private void EnqueueTextureSender(ITextureSender textureSender) | ||||
| //        { | ||||
| //            textureSender.Cancel = false; | ||||
| //            textureSender.Sending = true; | ||||
| // | ||||
| //            if (!m_sharedSendersQueue.Contains(textureSender)) | ||||
| //            { | ||||
| //                m_sharedSendersQueue.Enqueue(textureSender); | ||||
| //            } | ||||
| //        } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Close this module. | ||||
|         /// </summary> | ||||
|         internal void Close() | ||||
|         { | ||||
|             closed = true; | ||||
| 
 | ||||
|             lock (m_textureSenders) | ||||
|             { | ||||
|                 foreach (TextureSender.TextureSender textureSender in m_textureSenders.Values) | ||||
|                 { | ||||
|                     textureSender.Cancel = true; | ||||
|                 } | ||||
| 
 | ||||
|                 m_textureSenders.Clear(); | ||||
|             } | ||||
| 
 | ||||
|             // XXX: It might be possible to also remove pending texture requests from the asset cache queues, | ||||
|             // though this might also be more trouble than it's worth. | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,212 @@ | |||
| /* | ||||
|  * 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 OpenSimulator 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 log4net; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| 
 | ||||
| namespace OpenSim.Region.CoreModules.Agent.TextureSender | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 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. | ||||
|     /// </summary> | ||||
|     public class TextureSender : ITextureSender | ||||
|     { | ||||
|         private static readonly ILog m_log | ||||
|             = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Records the number of times texture send has been called. | ||||
|         /// </summary> | ||||
|         public int counter = 0; | ||||
| 
 | ||||
|         public bool ImageLoaded = false; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Holds the texture asset to send. | ||||
|         /// </summary> | ||||
|         private AssetBase m_asset; | ||||
| 
 | ||||
|         //public UUID assetID { get { return m_asset.FullID; } } | ||||
| 
 | ||||
|         // private bool m_cancel = false; | ||||
| 
 | ||||
|         // See ITextureSender | ||||
| 
 | ||||
|         // private bool m_sending = false; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// This is actually the number of extra packets required to send the texture data!  We always assume | ||||
|         /// at least one is required. | ||||
|         /// </summary> | ||||
|         private int NumPackets = 0; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Holds the packet number to send next.  In this case, each packet is 1000 bytes long and starts | ||||
|         /// at the 600th byte (0th indexed). | ||||
|         /// </summary> | ||||
|         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 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Load up the texture data to send. | ||||
|         /// </summary> | ||||
|         /// <param name="asset"></param> | ||||
|         public void TextureReceived(AssetBase asset) | ||||
|         { | ||||
|             m_asset = asset; | ||||
|             NumPackets = CalculateNumPackets(asset.Data.Length); | ||||
|             PacketCounter = (int)StartPacketNumber; | ||||
|             ImageLoaded = true; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Sends a texture packet to the client. | ||||
|         /// </summary> | ||||
|         private void SendPacket() | ||||
|         { | ||||
|             if (PacketCounter <= NumPackets) | ||||
|             { | ||||
|                 if (PacketCounter == 0) | ||||
|                 { | ||||
|                     if (NumPackets == 0) | ||||
|                     { | ||||
|                         RequestUser.SendImageFirstPart(1, m_asset.FullID, (uint)m_asset.Data.Length, m_asset.Data, 2); | ||||
|                         PacketCounter++; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         byte[] ImageData1 = new byte[600]; | ||||
|                         Array.Copy(m_asset.Data, 0, ImageData1, 0, 600); | ||||
| 
 | ||||
|                         RequestUser.SendImageFirstPart( | ||||
|                             (ushort)(NumPackets), m_asset.FullID, (uint)m_asset.Data.Length, ImageData1, 2); | ||||
|                         PacketCounter++; | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     int size = m_asset.Data.Length - 600 - (1000 * (PacketCounter - 1)); | ||||
|                     if (size > 1000) size = 1000; | ||||
|                     byte[] imageData = new byte[size]; | ||||
|                     try | ||||
|                     { | ||||
|                         Array.Copy(m_asset.Data, 600 + (1000 * (PacketCounter - 1)), imageData, 0, size); | ||||
|                     } | ||||
|                     catch (ArgumentOutOfRangeException) | ||||
|                     { | ||||
|                         m_log.Error("[TEXTURE SENDER]: Unable to separate texture into multiple packets: Array bounds failure on asset:" + | ||||
|                                     m_asset.ID); | ||||
|                         return; | ||||
|                     } | ||||
| 
 | ||||
|                     RequestUser.SendImageNextPart((ushort)PacketCounter, m_asset.FullID, imageData); | ||||
|                     PacketCounter++; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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... | ||||
|         /// </summary> | ||||
|         /// <param name="length"></param> | ||||
|         /// <returns></returns> | ||||
|         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; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,58 @@ | |||
| /* | ||||
|  * 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 OpenSimulator 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. | ||||
|  */ | ||||
| 
 | ||||
| namespace OpenSim.Region.Framework.Interfaces | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Interface for an object which can send texture information to a client | ||||
|     /// </summary> | ||||
|     public interface ITextureSender | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Are we in the process of sending the texture? | ||||
|         /// </summary> | ||||
|         bool Sending { get; set; } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Has the texture send been cancelled? | ||||
|         /// </summary> | ||||
|         bool Cancel { get; set; } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Update the non data properties of a texture request | ||||
|         /// </summary> | ||||
|         /// <param name="discardLevel"></param> | ||||
|         /// <param name="packetNumber"></param> | ||||
|         void UpdateRequest(int discardLevel, uint packetNumber); | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Send a texture packet to the client. | ||||
|         /// </summary> | ||||
|         /// <returns>True if the last packet has been sent, false otherwise.</returns> | ||||
|         bool SendTexturePacket(); | ||||
|     } | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	 John Hurliman
						John Hurliman