aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs2
-rw-r--r--OpenSim/Region/CoreModules/Agent/TextureDownload/TextureDownloadModule.cs302
-rw-r--r--OpenSim/Region/CoreModules/Agent/TextureDownload/TextureNotFoundSender.cs87
-rw-r--r--OpenSim/Region/CoreModules/Agent/TextureDownload/UserTextureDownloadService.cs265
-rw-r--r--OpenSim/Region/CoreModules/Agent/TextureSender/TextureSender.cs212
-rw-r--r--OpenSim/Region/Framework/Interfaces/ITextureSender.cs58
6 files changed, 926 insertions, 0 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
index 4b6a358..4a3a04e 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -163,7 +163,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
163 CircuitCode = circuitCode; 163 CircuitCode = circuitCode;
164 m_udpServer = server; 164 m_udpServer = server;
165 m_defaultThrottleRates = rates; 165 m_defaultThrottleRates = rates;
166 // Create a token bucket throttle for this client that has the scene token bucket as a parent
166 m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total); 167 m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total);
168 // Create an array of token buckets for this clients different throttle categories
167 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; 169 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
168 170
169 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) 171 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
diff --git a/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureDownloadModule.cs b/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureDownloadModule.cs
new file mode 100644
index 0000000..71ff28c
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureDownloadModule.cs
@@ -0,0 +1,302 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Threading;
32using log4net;
33using Nini.Config;
34using OpenMetaverse;
35using OpenSim.Framework;
36using OpenSim.Framework.Communications.Cache;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using BlockingQueue = OpenSim.Framework.BlockingQueue<OpenSim.Region.Framework.Interfaces.ITextureSender>;
40using OpenSim.Services.Interfaces;
41
42namespace OpenSim.Region.CoreModules.Agent.TextureDownload
43{
44 public class TextureDownloadModule : IRegionModule
45 {
46 private static readonly ILog m_log
47 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 /// <summary>
50 /// There is one queue for all textures waiting to be sent, regardless of the requesting user.
51 /// </summary>
52 private readonly BlockingQueue m_queueSenders
53 = new BlockingQueue();
54
55 /// <summary>
56 /// Each user has their own texture download service.
57 /// </summary>
58 private readonly Dictionary<UUID, UserTextureDownloadService> m_userTextureServices =
59 new Dictionary<UUID, UserTextureDownloadService>();
60
61 private Scene m_scene;
62 private List<Scene> m_scenes = new List<Scene>();
63
64 public TextureDownloadModule()
65 {
66 }
67
68 #region IRegionModule Members
69
70 public void Initialise(Scene scene, IConfigSource config)
71 {
72
73 if (m_scene == null)
74 {
75 //m_log.Debug("Creating Texture download module");
76 m_scene = scene;
77 //m_thread = new Thread(new ThreadStart(ProcessTextureSenders));
78 //m_thread.Name = "ProcessTextureSenderThread";
79 //m_thread.IsBackground = true;
80 //m_thread.Start();
81 //ThreadTracker.Add(m_thread);
82 }
83
84 if (!m_scenes.Contains(scene))
85 {
86 m_scenes.Add(scene);
87 m_scene = scene;
88 m_scene.EventManager.OnNewClient += NewClient;
89 m_scene.EventManager.OnRemovePresence += EventManager_OnRemovePresence;
90 }
91 }
92
93 public void PostInitialise()
94 {
95 }
96
97 public void Close()
98 {
99 }
100
101 public string Name
102 {
103 get { return "TextureDownloadModule"; }
104 }
105
106 public bool IsSharedModule
107 {
108 get { return false; }
109 }
110
111 #endregion
112
113 /// <summary>
114 /// Cleanup the texture service related objects for the removed presence.
115 /// </summary>
116 /// <param name="agentId"> </param>
117 private void EventManager_OnRemovePresence(UUID agentId)
118 {
119 UserTextureDownloadService textureService;
120
121 lock (m_userTextureServices)
122 {
123 if (m_userTextureServices.TryGetValue(agentId, out textureService))
124 {
125 textureService.Close();
126 //m_log.DebugFormat("[TEXTURE MODULE]: Removing UserTextureServices from {0}", m_scene.RegionInfo.RegionName);
127 m_userTextureServices.Remove(agentId);
128 }
129 }
130 }
131
132 public void NewClient(IClientAPI client)
133 {
134 UserTextureDownloadService textureService;
135
136 lock (m_userTextureServices)
137 {
138 if (m_userTextureServices.TryGetValue(client.AgentId, out textureService))
139 {
140 textureService.Close();
141 //m_log.DebugFormat("[TEXTURE MODULE]: Removing outdated UserTextureServices from {0}", m_scene.RegionInfo.RegionName);
142 m_userTextureServices.Remove(client.AgentId);
143 }
144 m_userTextureServices.Add(client.AgentId, new UserTextureDownloadService(client, m_scene, m_queueSenders));
145 }
146
147 client.OnRequestTexture += TextureRequest;
148 }
149
150 /// I'm commenting this out, and replacing it with the implementation below, which
151 /// may return a null value. This is necessary for avoiding race conditions
152 /// recreating UserTextureServices for clients that have just been closed.
153 /// That behavior of always returning a UserTextureServices was causing the
154 /// A-B-A problem (mantis #2855).
155 ///
156 ///// <summary>
157 ///// Does this user have a registered texture download service?
158 ///// </summary>
159 ///// <param name="userID"></param>
160 ///// <param name="textureService"></param>
161 ///// <returns>Always returns true, since a service is created if one does not already exist</returns>
162 //private bool TryGetUserTextureService(
163 // IClientAPI client, out UserTextureDownloadService textureService)
164 //{
165 // lock (m_userTextureServices)
166 // {
167 // if (m_userTextureServices.TryGetValue(client.AgentId, out textureService))
168 // {
169 // //m_log.DebugFormat("[TEXTURE MODULE]: Found existing UserTextureServices in ", m_scene.RegionInfo.RegionName);
170 // return true;
171 // }
172
173 // m_log.DebugFormat("[TEXTURE MODULE]: Creating new UserTextureServices in ", m_scene.RegionInfo.RegionName);
174 // textureService = new UserTextureDownloadService(client, m_scene, m_queueSenders);
175 // m_userTextureServices.Add(client.AgentId, textureService);
176
177 // return true;
178 // }
179 //}
180
181 /// <summary>
182 /// Does this user have a registered texture download service?
183 /// </summary>
184 /// <param name="userID"></param>
185 /// <param name="textureService"></param>
186 /// <returns>A UserTextureDownloadService or null in the output parameter, and true or false accordingly.</returns>
187 private bool TryGetUserTextureService(IClientAPI client, out UserTextureDownloadService textureService)
188 {
189 lock (m_userTextureServices)
190 {
191 if (m_userTextureServices.TryGetValue(client.AgentId, out textureService))
192 {
193 //m_log.DebugFormat("[TEXTURE MODULE]: Found existing UserTextureServices in ", m_scene.RegionInfo.RegionName);
194 return true;
195 }
196
197 textureService = null;
198 return false;
199 }
200 }
201
202 /// <summary>
203 /// Start the process of requesting a given texture.
204 /// </summary>
205 /// <param name="sender"> </param>
206 /// <param name="e"></param>
207 public void TextureRequest(Object sender, TextureRequestArgs e)
208 {
209 IClientAPI client = (IClientAPI)sender;
210
211 if (e.Priority == 1016001f) // Preview
212 {
213 if (client.Scene is Scene)
214 {
215 Scene scene = (Scene)client.Scene;
216
217 CachedUserInfo profile = scene.CommsManager.UserProfileCacheService.GetUserDetails(client.AgentId);
218 if (profile == null) // Deny unknown user
219 return;
220
221 IInventoryService invService = scene.InventoryService;
222 if (invService.GetRootFolder(client.AgentId) == null) // Deny no inventory
223 return;
224
225 // Diva 2009-08-13: this test doesn't make any sense to many devs
226 //if (profile.UserProfile.GodLevel < 200 && profile.RootFolder.FindAsset(e.RequestedAssetID) == null) // Deny if not owned
227 //{
228 // m_log.WarnFormat("[TEXTURE]: user {0} doesn't have permissions to texture {1}");
229 // return;
230 //}
231
232 m_log.Debug("Texture preview");
233 }
234 }
235
236 UserTextureDownloadService textureService;
237
238 if (TryGetUserTextureService(client, out textureService))
239 {
240 textureService.HandleTextureRequest(e);
241 }
242 }
243
244 /// <summary>
245 /// Entry point for the thread dedicated to processing the texture queue.
246 /// </summary>
247 public void ProcessTextureSenders()
248 {
249 ITextureSender sender = null;
250
251 try
252 {
253 while (true)
254 {
255 sender = m_queueSenders.Dequeue();
256
257 if (sender.Cancel)
258 {
259 TextureSent(sender);
260
261 sender.Cancel = false;
262 }
263 else
264 {
265 bool finished = sender.SendTexturePacket();
266 if (finished)
267 {
268 TextureSent(sender);
269 }
270 else
271 {
272 m_queueSenders.Enqueue(sender);
273 }
274 }
275
276 // Make sure that any sender we currently have can get garbage collected
277 sender = null;
278
279 //m_log.InfoFormat("[TEXTURE] Texture sender queue size: {0}", m_queueSenders.Count());
280 }
281 }
282 catch (Exception e)
283 {
284 // TODO: Let users in the sim and those entering it and possibly an external watchdog know what has happened
285 m_log.ErrorFormat(
286 "[TEXTURE]: Texture send thread terminating with exception. PLEASE REBOOT YOUR SIM - TEXTURES WILL NOT BE AVAILABLE UNTIL YOU DO. Exception is {0}",
287 e);
288 }
289 }
290
291 /// <summary>
292 /// Called when the texture has finished sending.
293 /// </summary>
294 /// <param name="sender"></param>
295 private void TextureSent(ITextureSender sender)
296 {
297 sender.Sending = false;
298 //m_log.DebugFormat("[TEXTURE]: Removing download stat for {0}", sender.assetID);
299 m_scene.StatsReporter.AddPendingDownloads(-1);
300 }
301 }
302}
diff --git a/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureNotFoundSender.cs b/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureNotFoundSender.cs
new file mode 100644
index 0000000..ba735a7
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureNotFoundSender.cs
@@ -0,0 +1,87 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenMetaverse;
29using OpenSim.Framework;
30using OpenSim.Region.Framework.Interfaces;
31
32namespace OpenSim.Region.CoreModules.Agent.TextureDownload
33{
34 /// <summary>
35 /// Sends a 'texture not found' packet back to the client
36 /// </summary>
37 public class TextureNotFoundSender : ITextureSender
38 {
39 // private static readonly log4net.ILog m_log
40 // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
41
42 // private IClientAPI m_client;
43 // private UUID m_textureId;
44
45 public TextureNotFoundSender(IClientAPI client, UUID textureID)
46 {
47 //m_client = client;
48 //m_textureId = textureID;
49 }
50
51 #region ITextureSender Members
52
53 public bool Sending
54 {
55 get { return false; }
56 set { }
57 }
58
59 public bool Cancel
60 {
61 get { return false; }
62 set { }
63 }
64
65 // See ITextureSender
66 public void UpdateRequest(int discardLevel, uint packetNumber)
67 {
68 // No need to implement since priority changes don't affect this operation
69 }
70
71 // See ITextureSender
72 public bool SendTexturePacket()
73 {
74 // m_log.DebugFormat(
75 // "[TEXTURE NOT FOUND SENDER]: Informing the client that texture {0} cannot be found",
76 // m_textureId);
77
78 // XXX Temporarily disabling as this appears to be causing client crashes on at least
79 // 1.19.0(5) of the Linden Second Life client.
80 // m_client.SendImageNotFound(m_textureId);
81
82 return true;
83 }
84
85 #endregion
86 }
87}
diff --git a/OpenSim/Region/CoreModules/Agent/TextureDownload/UserTextureDownloadService.cs b/OpenSim/Region/CoreModules/Agent/TextureDownload/UserTextureDownloadService.cs
new file mode 100644
index 0000000..19f0f90
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Agent/TextureDownload/UserTextureDownloadService.cs
@@ -0,0 +1,265 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using log4net;
32using OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Framework.Communications.Limit;
35using OpenSim.Framework.Statistics;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38
39namespace OpenSim.Region.CoreModules.Agent.TextureDownload
40{
41 /// <summary>
42 /// This module sets up texture senders in response to client texture requests, and places them on a
43 /// processing queue once those senders have the appropriate data (i.e. a texture retrieved from the
44 /// asset cache).
45 /// </summary>
46 public class UserTextureDownloadService
47 {
48// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50 /// <summary>
51 /// True if the service has been closed, probably because a user with texture requests still queued
52 /// logged out.
53 /// </summary>
54 private bool closed;
55
56 /// <summary>
57 /// We will allow the client to request the same texture n times before dropping further requests
58 ///
59 /// This number includes repeated requests for the same texture at different resolutions (which we don't
60 /// currently handle properly as far as I know). However, this situation should be handled in a more
61 /// sophisticated way.
62 /// </summary>
63// private static readonly int MAX_ALLOWED_TEXTURE_REQUESTS = 5;
64
65 /// <summary>
66 /// XXX Also going to limit requests for found textures.
67 /// </summary>
68// private readonly IRequestLimitStrategy<UUID> foundTextureLimitStrategy
69// = new RepeatLimitStrategy<UUID>(MAX_ALLOWED_TEXTURE_REQUESTS);
70
71// private readonly IClientAPI m_client;
72 private readonly Scene m_scene;
73
74 /// <summary>
75 /// Texture Senders are placed in this queue once they have received their texture from the asset
76 /// cache. Another module actually invokes the send.
77 /// </summary>
78// private readonly OpenSim.Framework.BlockingQueue<ITextureSender> m_sharedSendersQueue;
79
80 /// <summary>
81 /// Holds texture senders before they have received the appropriate texture from the asset cache.
82 /// </summary>
83 private readonly Dictionary<UUID, TextureSender.TextureSender> m_textureSenders = new Dictionary<UUID, TextureSender.TextureSender>();
84
85 /// <summary>
86 /// We're going to limit requests for the same missing texture.
87 /// XXX This is really a temporary solution to deal with the situation where a client continually requests
88 /// the same missing textures
89 /// </summary>
90// private readonly IRequestLimitStrategy<UUID> missingTextureLimitStrategy
91// = new RepeatLimitStrategy<UUID>(MAX_ALLOWED_TEXTURE_REQUESTS);
92
93 public UserTextureDownloadService(
94 IClientAPI client, Scene scene, OpenSim.Framework.BlockingQueue<ITextureSender> sharedQueue)
95 {
96// m_client = client;
97 m_scene = scene;
98// m_sharedSendersQueue = sharedQueue;
99 }
100
101 /// <summary>
102 /// Handle a texture request. This involves creating a texture sender and placing it on the
103 /// previously passed in shared queue.
104 /// </summary>
105 /// <param name="e"></param>
106 public void HandleTextureRequest(TextureRequestArgs e)
107 {
108
109 //TextureSender.TextureSender textureSender;
110
111 //TODO: should be working out the data size/ number of packets to be sent for each discard level
112 //if ((e.DiscardLevel >= 0) || (e.Priority != 0))
113 //{
114 //lock (m_textureSenders)
115 //{
116 //if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender))
117 //{
118 // If we've received new non UUID information for this request and it hasn't dispatched
119 // yet, then update the request accordingly.
120 // textureSender.UpdateRequest(e.DiscardLevel, e.PacketNumber);
121 //}
122 //else
123 //{
124 // m_log.DebugFormat("[TEXTURE]: Received a request for texture {0}", e.RequestedAssetID);
125
126 //if (!foundTextureLimitStrategy.AllowRequest(e.RequestedAssetID))
127 //{
128 // m_log.DebugFormat(
129 // "[TEXTURE]: Refusing request for {0} from client {1}",
130 // e.RequestedAssetID, m_client.AgentId);
131
132 //return;
133 //}
134 //else if (!missingTextureLimitStrategy.AllowRequest(e.RequestedAssetID))
135 //{
136 // if (missingTextureLimitStrategy.IsFirstRefusal(e.RequestedAssetID))
137 // {
138 // if (StatsManager.SimExtraStats != null)
139 // StatsManager.SimExtraStats.AddBlockedMissingTextureRequest();
140
141 // Commenting out this message for now as it causes too much noise with other
142 // debug messages.
143 // m_log.DebugFormat(
144 // "[TEXTURE]: Dropping requests for notified missing texture {0} for client {1} since we have received more than {2} requests",
145 // e.RequestedAssetID, m_client.AgentId, MAX_ALLOWED_TEXTURE_REQUESTS);
146 // }
147
148 // return;
149 //}
150
151 m_scene.StatsReporter.AddPendingDownloads(1);
152
153 //TextureSender.TextureSender requestHandler = new TextureSender.TextureSender(m_client, e.DiscardLevel, e.PacketNumber);
154 //m_textureSenders.Add(e.RequestedAssetID, null);
155
156 m_scene.AssetService.Get(e.RequestedAssetID.ToString(), this, TextureReceived);
157
158
159 }
160
161 protected void TextureReceived(string id, Object sender, AssetBase asset)
162 {
163 if (asset != null)
164 TextureCallback(asset.FullID, asset);
165 }
166
167 /// <summary>
168 /// The callback for the asset cache when a texture has been retrieved. This method queues the
169 /// texture sender for processing.
170 /// </summary>
171 /// <param name="textureID"></param>
172 /// <param name="texture"></param>
173 public void TextureCallback(UUID textureID, AssetBase texture)
174 {
175 //m_log.DebugFormat("[USER TEXTURE DOWNLOAD SERVICE]: Calling TextureCallback with {0}, texture == null is {1}", textureID, (texture == null ? true : false));
176
177 // There may still be texture requests pending for a logged out client
178 if (closed)
179 return;
180
181 /*
182 lock (m_textureSenders)
183 {
184 TextureSender.TextureSender textureSender;
185 if (m_textureSenders.TryGetValue(textureID, out textureSender))
186 {
187 // XXX It may be perfectly valid for a texture to have no data... but if we pass
188 // this on to the TextureSender it will blow up, so just discard for now.
189 // Needs investigation.
190 if (texture == null || texture.Data == null)
191 {
192 if (!missingTextureLimitStrategy.IsMonitoringRequests(textureID))
193 {
194 missingTextureLimitStrategy.MonitorRequests(textureID);
195
196 // m_log.DebugFormat(
197 // "[TEXTURE]: Queueing first TextureNotFoundSender for {0}, client {1}",
198 // textureID, m_client.AgentId);
199 }
200
201 ITextureSender textureNotFoundSender = new TextureNotFoundSender(m_client, textureID);
202 EnqueueTextureSender(textureNotFoundSender);
203 }
204 else
205 {
206 if (!textureSender.ImageLoaded)
207 {
208 textureSender.TextureReceived(texture);
209 EnqueueTextureSender(textureSender);
210
211 foundTextureLimitStrategy.MonitorRequests(textureID);
212 }
213 }
214
215 //m_log.InfoFormat("[TEXTURE] Removing texture sender with uuid {0}", textureID);
216 m_textureSenders.Remove(textureID);
217 //m_log.InfoFormat("[TEXTURE] Current texture senders in dictionary: {0}", m_textureSenders.Count);
218 }
219 else
220 {
221 m_log.WarnFormat(
222 "[TEXTURE]: Got a texture uuid {0} with no sender object to handle it, this shouldn't happen",
223 textureID);
224 }
225 }
226 */
227 }
228
229 /// <summary>
230 /// Place a ready texture sender on the processing queue.
231 /// </summary>
232 /// <param name="textureSender"></param>
233// private void EnqueueTextureSender(ITextureSender textureSender)
234// {
235// textureSender.Cancel = false;
236// textureSender.Sending = true;
237//
238// if (!m_sharedSendersQueue.Contains(textureSender))
239// {
240// m_sharedSendersQueue.Enqueue(textureSender);
241// }
242// }
243
244 /// <summary>
245 /// Close this module.
246 /// </summary>
247 internal void Close()
248 {
249 closed = true;
250
251 lock (m_textureSenders)
252 {
253 foreach (TextureSender.TextureSender textureSender in m_textureSenders.Values)
254 {
255 textureSender.Cancel = true;
256 }
257
258 m_textureSenders.Clear();
259 }
260
261 // XXX: It might be possible to also remove pending texture requests from the asset cache queues,
262 // though this might also be more trouble than it's worth.
263 }
264 }
265}
diff --git a/OpenSim/Region/CoreModules/Agent/TextureSender/TextureSender.cs b/OpenSim/Region/CoreModules/Agent/TextureSender/TextureSender.cs
new file mode 100644
index 0000000..62c5a32
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Agent/TextureSender/TextureSender.cs
@@ -0,0 +1,212 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Reflection;
30using log4net;
31using OpenSim.Framework;
32using OpenSim.Region.Framework.Interfaces;
33
34namespace OpenSim.Region.CoreModules.Agent.TextureSender
35{
36 /// <summary>
37 /// A TextureSender handles the process of receiving a texture requested by the client from the
38 /// AssetCache, and then sending that texture back to the client.
39 /// </summary>
40 public class TextureSender : ITextureSender
41 {
42 private static readonly ILog m_log
43 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44
45 /// <summary>
46 /// Records the number of times texture send has been called.
47 /// </summary>
48 public int counter = 0;
49
50 public bool ImageLoaded = false;
51
52 /// <summary>
53 /// Holds the texture asset to send.
54 /// </summary>
55 private AssetBase m_asset;
56
57 //public UUID assetID { get { return m_asset.FullID; } }
58
59 // private bool m_cancel = false;
60
61 // See ITextureSender
62
63 // private bool m_sending = false;
64
65 /// <summary>
66 /// This is actually the number of extra packets required to send the texture data! We always assume
67 /// at least one is required.
68 /// </summary>
69 private int NumPackets = 0;
70
71 /// <summary>
72 /// Holds the packet number to send next. In this case, each packet is 1000 bytes long and starts
73 /// at the 600th byte (0th indexed).
74 /// </summary>
75 private int PacketCounter = 0;
76
77 private int RequestedDiscardLevel = -1;
78 private IClientAPI RequestUser;
79 private uint StartPacketNumber = 0;
80
81 public TextureSender(IClientAPI client, int discardLevel, uint packetNumber)
82 {
83 RequestUser = client;
84 RequestedDiscardLevel = discardLevel;
85 StartPacketNumber = packetNumber;
86 }
87
88 #region ITextureSender Members
89
90 public bool Cancel
91 {
92 get { return false; }
93 set
94 {
95 // m_cancel = value;
96 }
97 }
98
99 public bool Sending
100 {
101 get { return false; }
102 set
103 {
104 // m_sending = value;
105 }
106 }
107
108 // See ITextureSender
109 public void UpdateRequest(int discardLevel, uint packetNumber)
110 {
111 RequestedDiscardLevel = discardLevel;
112 StartPacketNumber = packetNumber;
113 PacketCounter = (int)StartPacketNumber;
114 }
115
116 // See ITextureSender
117 public bool SendTexturePacket()
118 {
119 //m_log.DebugFormat("[TEXTURE SENDER]: Sending packet for {0}", m_asset.FullID);
120
121 SendPacket();
122 counter++;
123 if ((NumPackets == 0) || (RequestedDiscardLevel == -1) || (PacketCounter > NumPackets) ||
124 ((RequestedDiscardLevel > 0) && (counter > 50 + (NumPackets / (RequestedDiscardLevel + 1)))))
125 {
126 return true;
127 }
128 return false;
129 }
130
131 #endregion
132
133 /// <summary>
134 /// Load up the texture data to send.
135 /// </summary>
136 /// <param name="asset"></param>
137 public void TextureReceived(AssetBase asset)
138 {
139 m_asset = asset;
140 NumPackets = CalculateNumPackets(asset.Data.Length);
141 PacketCounter = (int)StartPacketNumber;
142 ImageLoaded = true;
143 }
144
145 /// <summary>
146 /// Sends a texture packet to the client.
147 /// </summary>
148 private void SendPacket()
149 {
150 if (PacketCounter <= NumPackets)
151 {
152 if (PacketCounter == 0)
153 {
154 if (NumPackets == 0)
155 {
156 RequestUser.SendImageFirstPart(1, m_asset.FullID, (uint)m_asset.Data.Length, m_asset.Data, 2);
157 PacketCounter++;
158 }
159 else
160 {
161 byte[] ImageData1 = new byte[600];
162 Array.Copy(m_asset.Data, 0, ImageData1, 0, 600);
163
164 RequestUser.SendImageFirstPart(
165 (ushort)(NumPackets), m_asset.FullID, (uint)m_asset.Data.Length, ImageData1, 2);
166 PacketCounter++;
167 }
168 }
169 else
170 {
171 int size = m_asset.Data.Length - 600 - (1000 * (PacketCounter - 1));
172 if (size > 1000) size = 1000;
173 byte[] imageData = new byte[size];
174 try
175 {
176 Array.Copy(m_asset.Data, 600 + (1000 * (PacketCounter - 1)), imageData, 0, size);
177 }
178 catch (ArgumentOutOfRangeException)
179 {
180 m_log.Error("[TEXTURE SENDER]: Unable to separate texture into multiple packets: Array bounds failure on asset:" +
181 m_asset.ID);
182 return;
183 }
184
185 RequestUser.SendImageNextPart((ushort)PacketCounter, m_asset.FullID, imageData);
186 PacketCounter++;
187 }
188 }
189 }
190
191 /// <summary>
192 /// Calculate the number of packets that will be required to send the texture loaded into this sender
193 /// This is actually the number of 1000 byte packets not including an initial 600 byte packet...
194 /// </summary>
195 /// <param name="length"></param>
196 /// <returns></returns>
197 private int CalculateNumPackets(int length)
198 {
199 int numPackets = 0;
200
201 if (length > 600)
202 {
203 //over 600 bytes so split up file
204 int restData = (length - 600);
205 int restPackets = ((restData + 999) / 1000);
206 numPackets = restPackets;
207 }
208
209 return numPackets;
210 }
211 }
212}
diff --git a/OpenSim/Region/Framework/Interfaces/ITextureSender.cs b/OpenSim/Region/Framework/Interfaces/ITextureSender.cs
new file mode 100644
index 0000000..c469ae8
--- /dev/null
+++ b/OpenSim/Region/Framework/Interfaces/ITextureSender.cs
@@ -0,0 +1,58 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28namespace OpenSim.Region.Framework.Interfaces
29{
30 /// <summary>
31 /// Interface for an object which can send texture information to a client
32 /// </summary>
33 public interface ITextureSender
34 {
35 /// <summary>
36 /// Are we in the process of sending the texture?
37 /// </summary>
38 bool Sending { get; set; }
39
40 /// <summary>
41 /// Has the texture send been cancelled?
42 /// </summary>
43 bool Cancel { get; set; }
44
45 /// <summary>
46 /// Update the non data properties of a texture request
47 /// </summary>
48 /// <param name="discardLevel"></param>
49 /// <param name="packetNumber"></param>
50 void UpdateRequest(int discardLevel, uint packetNumber);
51
52 /// <summary>
53 /// Send a texture packet to the client.
54 /// </summary>
55 /// <returns>True if the last packet has been sent, false otherwise.</returns>
56 bool SendTexturePacket();
57 }
58}