aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/Agent
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Environment/Modules/Agent')
-rw-r--r--OpenSim/Region/Environment/Modules/Agent/AssetDownload/AssetDownloadModule.cs333
-rw-r--r--OpenSim/Region/Environment/Modules/Agent/AssetTransaction/AgentAssetsTransactions.cs407
-rw-r--r--OpenSim/Region/Environment/Modules/Agent/AssetTransaction/AssetTransactionModule.cs286
-rw-r--r--OpenSim/Region/Environment/Modules/Agent/TextureDownload/TextureDownloadModule.cs215
-rw-r--r--OpenSim/Region/Environment/Modules/Agent/TextureDownload/TextureNotFoundSender.cs93
-rw-r--r--OpenSim/Region/Environment/Modules/Agent/TextureDownload/UserTextureDownloadService.cs252
-rw-r--r--OpenSim/Region/Environment/Modules/Agent/TextureSender/TextureSender.cs220
-rw-r--r--OpenSim/Region/Environment/Modules/Agent/Xfer/XferModule.cs225
8 files changed, 2031 insertions, 0 deletions
diff --git a/OpenSim/Region/Environment/Modules/Agent/AssetDownload/AssetDownloadModule.cs b/OpenSim/Region/Environment/Modules/Agent/AssetDownload/AssetDownloadModule.cs
new file mode 100644
index 0000000..47c1479
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Agent/AssetDownload/AssetDownloadModule.cs
@@ -0,0 +1,333 @@
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 OpenSim 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.Collections.Generic;
29using libsecondlife;
30using libsecondlife.Packets;
31using Nini.Config;
32using OpenSim.Framework;
33using OpenSim.Region.Environment.Interfaces;
34using OpenSim.Region.Environment.Scenes;
35
36namespace OpenSim.Region.Environment.Modules.Agent.AssetDownload
37{
38 public class AssetDownloadModule : IRegionModule
39 {
40 private Scene m_scene;
41 private Dictionary<LLUUID, Scene> RegisteredScenes = new Dictionary<LLUUID, Scene>();
42 ///
43 /// Assets requests (for each user) which are waiting for asset server data. This includes texture requests
44 /// </summary>
45 private Dictionary<LLUUID, Dictionary<LLUUID,AssetRequest>> RequestedAssets;
46
47 /// <summary>
48 /// Asset requests with data which are ready to be sent back to requesters. This includes textures.
49 /// </summary>
50 private List<AssetRequest> AssetRequests;
51
52 public AssetDownloadModule()
53 {
54 RequestedAssets = new Dictionary<LLUUID, Dictionary<LLUUID, AssetRequest>>();
55 AssetRequests = new List<AssetRequest>();
56 }
57
58 public void Initialise(Scene scene, IConfigSource config)
59 {
60 if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID))
61 {
62 RegisteredScenes.Add(scene.RegionInfo.RegionID, scene);
63 // scene.EventManager.OnNewClient += NewClient;
64 }
65
66 if (m_scene == null)
67 {
68 m_scene = scene;
69 // m_thread = new Thread(new ThreadStart(RunAssetQueue));
70 // m_thread.Name = "AssetDownloadQueueThread";
71 // m_thread.IsBackground = true;
72 // m_thread.Start();
73 // OpenSim.Framework.ThreadTracker.Add(m_thread);
74 }
75 }
76
77 public void PostInitialise()
78 {
79 }
80
81 public void Close()
82 {
83 }
84
85 public string Name
86 {
87 get { return "AssetDownloadModule"; }
88 }
89
90 public bool IsSharedModule
91 {
92 get { return true; }
93 }
94
95 public void NewClient(IClientAPI client)
96 {
97 // client.OnRequestAsset += AddAssetRequest;
98 }
99
100 /// <summary>
101 /// Make an asset request the result of which will be packeted up and sent directly back to the client.
102 /// </summary>
103 /// <param name="userInfo"></param>
104 /// <param name="transferRequest"></param>
105 public void AddAssetRequest(IClientAPI userInfo, TransferRequestPacket transferRequest)
106 {
107 LLUUID requestID = null;
108 byte source = 2;
109 if (transferRequest.TransferInfo.SourceType == 2)
110 {
111 //direct asset request
112 requestID = new LLUUID(transferRequest.TransferInfo.Params, 0);
113 }
114 else if (transferRequest.TransferInfo.SourceType == 3)
115 {
116 //inventory asset request
117 requestID = new LLUUID(transferRequest.TransferInfo.Params, 80);
118 source = 3;
119 //Console.WriteLine("asset request " + requestID);
120 }
121
122 //not found asset
123 // so request from asset server
124 Dictionary<LLUUID, AssetRequest> userRequests = null;
125 if (RequestedAssets.TryGetValue(userInfo.AgentId, out userRequests))
126 {
127 if (!userRequests.ContainsKey(requestID))
128 {
129 AssetRequest request = new AssetRequest();
130 request.RequestUser = userInfo;
131 request.RequestAssetID = requestID;
132 request.TransferRequestID = transferRequest.TransferInfo.TransferID;
133 request.AssetRequestSource = source;
134 request.Params = transferRequest.TransferInfo.Params;
135 userRequests[requestID] = request;
136 m_scene.AssetCache.GetAsset(requestID, AssetCallback, false);
137 }
138 }
139 else
140 {
141 userRequests = new Dictionary<LLUUID, AssetRequest>();
142 AssetRequest request = new AssetRequest();
143 request.RequestUser = userInfo;
144 request.RequestAssetID = requestID;
145 request.TransferRequestID = transferRequest.TransferInfo.TransferID;
146 request.AssetRequestSource = source;
147 request.Params = transferRequest.TransferInfo.Params;
148 userRequests.Add(requestID, request);
149 RequestedAssets[userInfo.AgentId] = userRequests;
150 m_scene.AssetCache.GetAsset(requestID, AssetCallback, false);
151 }
152 }
153
154 public void AssetCallback(LLUUID assetID, AssetBase asset)
155 {
156 if (asset != null)
157 {
158 foreach (Dictionary<LLUUID, AssetRequest> userRequests in RequestedAssets.Values)
159 {
160 if (userRequests.ContainsKey(assetID))
161 {
162 AssetRequest req = userRequests[assetID];
163 if (req != null)
164 {
165 req.AssetInf = asset;
166 req.NumPackets = CalculateNumPackets(asset.Data);
167
168 userRequests.Remove(assetID);
169 AssetRequests.Add(req);
170 }
171 }
172 }
173 }
174 }
175
176// TODO: unused
177// private void RunAssetQueue()
178// {
179// while (true)
180// {
181// try
182// {
183// ProcessAssetQueue();
184// Thread.Sleep(500);
185// }
186// catch (Exception)
187// {
188// // m_log.Error("[ASSET CACHE]: " + e.ToString());
189// }
190// }
191// }
192
193// TODO: unused
194// /// <summary>
195// /// Process the asset queue which sends packets directly back to the client.
196// /// </summary>
197// private void ProcessAssetQueue()
198// {
199// //should move the asset downloading to a module, like has been done with texture downloading
200// if (AssetRequests.Count == 0)
201// {
202// //no requests waiting
203// return;
204// }
205// // if less than 5, do all of them
206// int num = Math.Min(5, AssetRequests.Count);
207
208// AssetRequest req;
209// for (int i = 0; i < num; i++)
210// {
211// req = (AssetRequest)AssetRequests[i];
212// //Console.WriteLine("sending asset " + req.RequestAssetID);
213// TransferInfoPacket Transfer = new TransferInfoPacket();
214// Transfer.TransferInfo.ChannelType = 2;
215// Transfer.TransferInfo.Status = 0;
216// Transfer.TransferInfo.TargetType = 0;
217// if (req.AssetRequestSource == 2)
218// {
219// Transfer.TransferInfo.Params = new byte[20];
220// Array.Copy(req.RequestAssetID.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16);
221// int assType = (int)req.AssetInf.Type;
222// Array.Copy(Helpers.IntToBytes(assType), 0, Transfer.TransferInfo.Params, 16, 4);
223// }
224// else if (req.AssetRequestSource == 3)
225// {
226// Transfer.TransferInfo.Params = req.Params;
227// // Transfer.TransferInfo.Params = new byte[100];
228// //Array.Copy(req.RequestUser.AgentId.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16);
229// //Array.Copy(req.RequestUser.SessionId.GetBytes(), 0, Transfer.TransferInfo.Params, 16, 16);
230// }
231// Transfer.TransferInfo.Size = (int)req.AssetInf.Data.Length;
232// Transfer.TransferInfo.TransferID = req.TransferRequestID;
233// req.RequestUser.OutPacket(Transfer, ThrottleOutPacketType.Asset);
234
235// if (req.NumPackets == 1)
236// {
237// TransferPacketPacket TransferPacket = new TransferPacketPacket();
238// TransferPacket.TransferData.Packet = 0;
239// TransferPacket.TransferData.ChannelType = 2;
240// TransferPacket.TransferData.TransferID = req.TransferRequestID;
241// TransferPacket.TransferData.Data = req.AssetInf.Data;
242// TransferPacket.TransferData.Status = 1;
243// req.RequestUser.OutPacket(TransferPacket, ThrottleOutPacketType.Asset);
244// }
245// else
246// {
247// int processedLength = 0;
248// // libsecondlife hardcodes 1500 as the maximum data chunk size
249// int maxChunkSize = 1250;
250// int packetNumber = 0;
251
252// while (processedLength < req.AssetInf.Data.Length)
253// {
254// TransferPacketPacket TransferPacket = new TransferPacketPacket();
255// TransferPacket.TransferData.Packet = packetNumber;
256// TransferPacket.TransferData.ChannelType = 2;
257// TransferPacket.TransferData.TransferID = req.TransferRequestID;
258
259// int chunkSize = Math.Min(req.AssetInf.Data.Length - processedLength, maxChunkSize);
260// byte[] chunk = new byte[chunkSize];
261// Array.Copy(req.AssetInf.Data, processedLength, chunk, 0, chunk.Length);
262
263// TransferPacket.TransferData.Data = chunk;
264
265// // 0 indicates more packets to come, 1 indicates last packet
266// if (req.AssetInf.Data.Length - processedLength > maxChunkSize)
267// {
268// TransferPacket.TransferData.Status = 0;
269// }
270// else
271// {
272// TransferPacket.TransferData.Status = 1;
273// }
274
275// req.RequestUser.OutPacket(TransferPacket, ThrottleOutPacketType.Asset);
276
277// processedLength += chunkSize;
278// packetNumber++;
279// }
280// }
281// }
282
283// //remove requests that have been completed
284// for (int i = 0; i < num; i++)
285// {
286// AssetRequests.RemoveAt(0);
287// }
288// }
289
290 /// <summary>
291 /// Calculate the number of packets required to send the asset to the client.
292 /// </summary>
293 /// <param name="data"></param>
294 /// <returns></returns>
295 private int CalculateNumPackets(byte[] data)
296 {
297 const uint m_maxPacketSize = 600;
298 int numPackets = 1;
299
300 if (data.LongLength > m_maxPacketSize)
301 {
302 // over max number of bytes so split up file
303 long restData = data.LongLength - m_maxPacketSize;
304 int restPackets = (int)((restData + m_maxPacketSize - 1) / m_maxPacketSize);
305 numPackets += restPackets;
306 }
307
308 return numPackets;
309 }
310
311 public class AssetRequest
312 {
313 public IClientAPI RequestUser;
314 public LLUUID RequestAssetID;
315 public AssetBase AssetInf;
316 public AssetBase ImageInfo;
317 public LLUUID TransferRequestID;
318 public long DataPointer = 0;
319 public int NumPackets = 0;
320 public int PacketCounter = 0;
321 public bool IsTextureRequest;
322 public byte AssetRequestSource = 2;
323 public byte[] Params = null;
324 //public bool AssetInCache;
325 //public int TimeRequested;
326 public int DiscardLevel = -1;
327
328 public AssetRequest()
329 {
330 }
331 }
332 }
333} \ 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
new file mode 100644
index 0000000..74bb247
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Agent/AssetTransaction/AgentAssetsTransactions.cs
@@ -0,0 +1,407 @@
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 OpenSim 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.IO;
31using libsecondlife;
32using libsecondlife.Packets;
33using OpenSim.Framework;
34using OpenSim.Framework.Communications.Cache;
35
36namespace OpenSim.Region.Environment.Modules.Agent.AssetTransaction
37{
38 /// <summary>
39 /// Manage asset transactions for a single agent.
40 /// </summary>
41 public class AgentAssetTransactions
42 {
43 //private static readonly log4net.ILog m_log
44 // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
45
46 // Fields
47 public LLUUID UserID;
48 public Dictionary<LLUUID, AssetXferUploader> XferUploaders = new Dictionary<LLUUID, AssetXferUploader>();
49 public AgentAssetTransactionsManager Manager;
50 private bool m_dumpAssetsToFile;
51
52 // Methods
53 public AgentAssetTransactions(LLUUID agentID, AgentAssetTransactionsManager manager, bool dumpAssetsToFile)
54 {
55 UserID = agentID;
56 Manager = manager;
57 m_dumpAssetsToFile = dumpAssetsToFile;
58 }
59
60 public AssetXferUploader RequestXferUploader(LLUUID transactionID)
61 {
62 if (!XferUploaders.ContainsKey(transactionID))
63 {
64 AssetXferUploader uploader = new AssetXferUploader(this, m_dumpAssetsToFile);
65
66 lock (XferUploaders)
67 {
68 XferUploaders.Add(transactionID, uploader);
69 }
70
71 return uploader;
72 }
73 return null;
74 }
75
76 public void HandleXfer(ulong xferID, uint packetID, byte[] data)
77 {
78 // AssetXferUploader uploaderFound = null;
79
80 lock (XferUploaders)
81 {
82 foreach (AssetXferUploader uploader in XferUploaders.Values)
83 {
84 if (uploader.XferID == xferID)
85 {
86 uploader.HandleXferPacket(xferID, packetID, data);
87 break;
88 }
89 }
90 }
91 }
92
93 public void RequestCreateInventoryItem(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID,
94 uint callbackID, string description, string name, sbyte invType,
95 sbyte type, byte wearableType, uint nextOwnerMask)
96 {
97 if (XferUploaders.ContainsKey(transactionID))
98 {
99 XferUploaders[transactionID].RequestCreateInventoryItem(remoteClient, transactionID, folderID,
100 callbackID, description, name, invType, type,
101 wearableType, nextOwnerMask);
102 }
103 }
104
105 public void RequestUpdateInventoryItem(IClientAPI remoteClient, LLUUID transactionID,
106 InventoryItemBase item)
107 {
108 if (XferUploaders.ContainsKey(transactionID))
109 {
110 XferUploaders[transactionID].RequestUpdateInventoryItem(remoteClient, transactionID, item);
111 }
112 }
113
114 /// <summary>
115 /// Get an uploaded asset. If the data is successfully retrieved, the transaction will be removed.
116 /// </summary>
117 /// <param name="transactionID"></param>
118 /// <returns>The asset if the upload has completed, null if it has not.</returns>
119 public AssetBase GetTransactionAsset(LLUUID transactionID)
120 {
121 if (XferUploaders.ContainsKey(transactionID))
122 {
123 AssetXferUploader uploader = XferUploaders[transactionID];
124 AssetBase asset = uploader.GetAssetData();
125
126 lock (XferUploaders)
127 {
128 XferUploaders.Remove(transactionID);
129 }
130
131 return asset;
132 }
133
134 return null;
135 }
136
137 // Nested Types
138 public class AssetXferUploader
139 {
140 // Fields
141 public bool AddToInventory;
142 public AssetBase Asset;
143 public LLUUID InventFolder = LLUUID.Zero;
144 private IClientAPI ourClient;
145 public LLUUID TransactionID = LLUUID.Zero;
146 public bool UploadComplete;
147 public ulong XferID;
148 private string m_name = String.Empty;
149 private string m_description = String.Empty;
150 private sbyte type = 0;
151 private sbyte invType = 0;
152 private byte wearableType = 0;
153 private uint nextPerm = 0;
154 private bool m_finished = false;
155 private bool m_createItem = false;
156 private AgentAssetTransactions m_userTransactions;
157 private bool m_storeLocal;
158 private bool m_dumpAssetToFile;
159
160 public AssetXferUploader(AgentAssetTransactions transactions, bool dumpAssetToFile)
161 {
162 m_userTransactions = transactions;
163 m_dumpAssetToFile = dumpAssetToFile;
164 }
165
166 /// <summary>
167 /// Process transfer data received from the client.
168 /// </summary>
169 /// <param name="xferID"></param>
170 /// <param name="packetID"></param>
171 /// <param name="data"></param>
172 /// <returns>True if the transfer is complete, false otherwise or if the xferID was not valid</returns>
173 public bool HandleXferPacket(ulong xferID, uint packetID, byte[] data)
174 {
175 if (XferID == xferID)
176 {
177 if (Asset.Data.Length > 1)
178 {
179 byte[] destinationArray = new byte[Asset.Data.Length + data.Length];
180 Array.Copy(Asset.Data, 0, destinationArray, 0, Asset.Data.Length);
181 Array.Copy(data, 0, destinationArray, Asset.Data.Length, data.Length);
182 Asset.Data = destinationArray;
183 }
184 else
185 {
186 byte[] buffer2 = new byte[data.Length - 4];
187 Array.Copy(data, 4, buffer2, 0, data.Length - 4);
188 Asset.Data = buffer2;
189 }
190 ConfirmXferPacketPacket newPack = new ConfirmXferPacketPacket();
191 newPack.XferID.ID = xferID;
192 newPack.XferID.Packet = packetID;
193 ourClient.OutPacket(newPack, ThrottleOutPacketType.Asset);
194 if ((packetID & 0x80000000) != 0)
195 {
196 SendCompleteMessage();
197 return true;
198 }
199 }
200
201 return false;
202 }
203
204 /// <summary>
205 /// Initialise asset transfer from the client
206 /// </summary>
207 /// <param name="xferID"></param>
208 /// <param name="packetID"></param>
209 /// <param name="data"></param>
210 /// <returns>True if the transfer is complete, false otherwise</returns>
211 public bool Initialise(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, byte[] data,
212 bool storeLocal, bool tempFile)
213 {
214 ourClient = remoteClient;
215 Asset = new AssetBase();
216 Asset.FullID = assetID;
217 Asset.InvType = type;
218 Asset.Type = type;
219 Asset.Data = data;
220 Asset.Name = "blank";
221 Asset.Description = "empty";
222 Asset.Local = storeLocal;
223 Asset.Temporary = tempFile;
224
225 TransactionID = transaction;
226 m_storeLocal = storeLocal;
227 if (Asset.Data.Length > 2)
228 {
229 SendCompleteMessage();
230 return true;
231 }
232 else
233 {
234 RequestStartXfer();
235 }
236
237 return false;
238 }
239
240 protected void RequestStartXfer()
241 {
242 UploadComplete = false;
243 XferID = Util.GetNextXferID();
244 RequestXferPacket newPack = new RequestXferPacket();
245 newPack.XferID.ID = XferID;
246 newPack.XferID.VFileType = Asset.Type;
247 newPack.XferID.VFileID = Asset.FullID;
248 newPack.XferID.FilePath = 0;
249 newPack.XferID.Filename = new byte[0];
250 ourClient.OutPacket(newPack, ThrottleOutPacketType.Asset);
251 }
252
253 protected void SendCompleteMessage()
254 {
255 UploadComplete = true;
256 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
257 newPack.AssetBlock.Type = Asset.Type;
258 newPack.AssetBlock.Success = true;
259 newPack.AssetBlock.UUID = Asset.FullID;
260 ourClient.OutPacket(newPack, ThrottleOutPacketType.Asset);
261 m_finished = true;
262 if (m_createItem)
263 {
264 DoCreateItem();
265 }
266 else if (m_storeLocal)
267 {
268 m_userTransactions.Manager.MyScene.CommsManager.AssetCache.AddAsset(Asset);
269 }
270
271 // Console.WriteLine("upload complete "+ this.TransactionID);
272
273 if (m_dumpAssetToFile)
274 {
275 DateTime now = DateTime.Now;
276 string filename =
277 String.Format("{6}_{7}_{0:d2}{1:d2}{2:d2}_{3:d2}{4:d2}{5:d2}.dat", now.Year, now.Month, now.Day,
278 now.Hour, now.Minute, now.Second, Asset.Name, Asset.Type);
279 SaveAssetToFile(filename, Asset.Data);
280 }
281 }
282
283 ///Left this in and commented in case there are unforseen issues
284 //private void SaveAssetToFile(string filename, byte[] data)
285 //{
286 // FileStream fs = File.Create(filename);
287 // BinaryWriter bw = new BinaryWriter(fs);
288 // bw.Write(data);
289 // bw.Close();
290 // fs.Close();
291 //}
292 private void SaveAssetToFile(string filename, byte[] data)
293 {
294 string assetPath = "UserAssets";
295 if (!Directory.Exists(assetPath))
296 {
297 Directory.CreateDirectory(assetPath);
298 }
299 FileStream fs = File.Create(Path.Combine(assetPath, filename));
300 BinaryWriter bw = new BinaryWriter(fs);
301 bw.Write(data);
302 bw.Close();
303 fs.Close();
304 }
305
306 public void RequestCreateInventoryItem(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID,
307 uint callbackID, string description, string name, sbyte invType,
308 sbyte type, byte wearableType, uint nextOwnerMask)
309 {
310 if (TransactionID == transactionID)
311 {
312 InventFolder = folderID;
313 m_name = name;
314 m_description = description;
315 this.type = type;
316 this.invType = invType;
317 this.wearableType = wearableType;
318 nextPerm = nextOwnerMask;
319 Asset.Name = name;
320 Asset.Description = description;
321 Asset.Type = type;
322 Asset.InvType = invType;
323 m_createItem = true;
324 if (m_finished)
325 {
326 DoCreateItem();
327 }
328 }
329 }
330
331 public void RequestUpdateInventoryItem(IClientAPI remoteClient, LLUUID transactionID,
332 InventoryItemBase item)
333 {
334 if (TransactionID == transactionID)
335 {
336 CachedUserInfo userInfo =
337 m_userTransactions.Manager.MyScene.CommsManager.UserProfileCacheService.GetUserDetails(
338 remoteClient.AgentId);
339
340 if (userInfo != null)
341 {
342 LLUUID assetID = LLUUID.Combine(transactionID, remoteClient.SecureSessionId);
343
344 AssetBase asset
345 = m_userTransactions.Manager.MyScene.CommsManager.AssetCache.GetAsset(
346 assetID, (item.AssetType == (int) AssetType.Texture ? true : false));
347
348 if (asset == null)
349 {
350 asset = m_userTransactions.GetTransactionAsset(transactionID);
351 }
352
353 if (asset != null && asset.FullID == assetID)
354 {
355 asset.Name = item.Name;
356 asset.Description = item.Description;
357 asset.InvType = (sbyte) item.InvType;
358 asset.Type = (sbyte) item.AssetType;
359 item.AssetID = asset.FullID;
360
361 m_userTransactions.Manager.MyScene.CommsManager.AssetCache.AddAsset(Asset);
362 }
363
364 userInfo.UpdateItem(remoteClient.AgentId, item);
365 }
366 }
367 }
368
369 private void DoCreateItem()
370 {
371 //really need to fix this call, if lbsa71 saw this he would die.
372 m_userTransactions.Manager.MyScene.CommsManager.AssetCache.AddAsset(Asset);
373 CachedUserInfo userInfo =
374 m_userTransactions.Manager.MyScene.CommsManager.UserProfileCacheService.GetUserDetails(ourClient.AgentId);
375 if (userInfo != null)
376 {
377 InventoryItemBase item = new InventoryItemBase();
378 item.Owner = ourClient.AgentId;
379 item.Creator = ourClient.AgentId;
380 item.ID = LLUUID.Random();
381 item.AssetID = Asset.FullID;
382 item.Description = m_description;
383 item.Name = m_name;
384 item.AssetType = type;
385 item.InvType = invType;
386 item.Folder = InventFolder;
387 item.BasePermissions = 2147483647;
388 item.CurrentPermissions = 2147483647;
389 item.NextPermissions = nextPerm;
390 item.Flags = (uint)wearableType;
391
392 userInfo.AddItem(ourClient.AgentId, item);
393 ourClient.SendInventoryItemCreateUpdate(item);
394 }
395 }
396
397 public AssetBase GetAssetData()
398 {
399 if (m_finished)
400 {
401 return Asset;
402 }
403 return null;
404 }
405 }
406 }
407} \ 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
new file mode 100644
index 0000000..ef81625
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Agent/AssetTransaction/AssetTransactionModule.cs
@@ -0,0 +1,286 @@
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 OpenSim 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 libsecondlife;
32using log4net;
33using Nini.Config;
34using OpenSim.Framework;
35using OpenSim.Region.Environment.Interfaces;
36using OpenSim.Region.Environment.Modules.Agent.AssetTransaction;
37using OpenSim.Region.Environment.Scenes;
38
39namespace OpenSim.Region.Environment.Modules.Agent.AssetTransaction
40{
41 public class AssetTransactionModule : IRegionModule, IAgentAssetTransactions
42 {
43 private readonly Dictionary<LLUUID, Scene> RegisteredScenes = new Dictionary<LLUUID, Scene>();
44 private Scene m_scene = null;
45 private bool m_dumpAssetsToFile = false;
46
47 private AgentAssetTransactionsManager m_transactionManager;
48
49 public AssetTransactionModule()
50 {
51 // System.Console.WriteLine("creating AgentAssetTransactionModule");
52 }
53
54 public void Initialise(Scene scene, IConfigSource config)
55 {
56 if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID))
57 {
58 // System.Console.WriteLine("initialising AgentAssetTransactionModule");
59 RegisteredScenes.Add(scene.RegionInfo.RegionID, scene);
60 scene.RegisterModuleInterface<IAgentAssetTransactions>(this);
61
62 scene.EventManager.OnNewClient += NewClient;
63 }
64
65 if (m_scene == null)
66 {
67 m_scene = scene;
68 if (config.Configs["StandAlone"] != null)
69 {
70 try
71 {
72 m_dumpAssetsToFile = config.Configs["StandAlone"].GetBoolean("dump_assets_to_file", false);
73 m_transactionManager = new AgentAssetTransactionsManager(m_scene, m_dumpAssetsToFile);
74 }
75 catch (Exception)
76 {
77 m_transactionManager = new AgentAssetTransactionsManager(m_scene, false);
78 }
79 }
80 else
81 {
82 m_transactionManager = new AgentAssetTransactionsManager(m_scene, false);
83 }
84
85 }
86 }
87
88 public void PostInitialise()
89 {
90
91 }
92
93 public void Close()
94 {
95 }
96
97 public string Name
98 {
99 get { return "AgentTransactionModule"; }
100 }
101
102 public bool IsSharedModule
103 {
104 get { return true; }
105 }
106
107 public void NewClient(IClientAPI client)
108 {
109 client.OnAssetUploadRequest += m_transactionManager.HandleUDPUploadRequest;
110 client.OnXferReceive += m_transactionManager.HandleXfer;
111 }
112
113 public void HandleItemCreationFromTransaction(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID,
114 uint callbackID, string description, string name, sbyte invType,
115 sbyte type, byte wearableType, uint nextOwnerMask)
116 {
117 m_transactionManager.HandleItemCreationFromTransaction(remoteClient, transactionID, folderID, callbackID, description, name, invType, type, wearableType, nextOwnerMask);
118 }
119
120 public void HandleItemUpdateFromTransaction(IClientAPI remoteClient, LLUUID transactionID,
121 InventoryItemBase item)
122 {
123 m_transactionManager.HandleItemUpdateFromTransaction(remoteClient, transactionID, item);
124 }
125
126 public void RemoveAgentAssetTransactions(LLUUID userID)
127 {
128 m_transactionManager.RemoveAgentAssetTransactions(userID);
129 }
130 }
131
132 public class AgentAssetTransactionsManager
133 {
134 private static readonly ILog m_log
135 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
136
137 // Fields
138 public Scene MyScene;
139
140 /// <summary>
141 /// Each agent has its own singleton collection of transactions
142 /// </summary>
143 private Dictionary<LLUUID, AgentAssetTransactions> AgentTransactions =
144 new Dictionary<LLUUID, AgentAssetTransactions>();
145
146 /// <summary>
147 /// Should we dump uploaded assets to the filesystem?
148 /// </summary>
149 private bool m_dumpAssetsToFile;
150
151 public AgentAssetTransactionsManager(Scene scene, bool dumpAssetsToFile)
152 {
153 MyScene = scene;
154 m_dumpAssetsToFile = dumpAssetsToFile;
155 }
156
157 /// <summary>
158 /// Get the collection of asset transactions for the given user. If one does not already exist, it
159 /// is created.
160 /// </summary>
161 /// <param name="userID"></param>
162 /// <returns></returns>
163 private AgentAssetTransactions GetUserTransactions(LLUUID userID)
164 {
165 lock (AgentTransactions)
166 {
167 if (!AgentTransactions.ContainsKey(userID))
168 {
169 AgentAssetTransactions transactions
170 = new AgentAssetTransactions(userID, this, m_dumpAssetsToFile);
171 AgentTransactions.Add(userID, transactions);
172 }
173
174 return AgentTransactions[userID];
175 }
176 }
177
178 /// <summary>
179 /// Remove the given agent asset transactions. This should be called when a client is departing
180 /// from a scene (and hence won't be making any more transactions here).
181 /// </summary>
182 /// <param name="userID"></param>
183 public void RemoveAgentAssetTransactions(LLUUID userID)
184 {
185 // m_log.DebugFormat("Removing agent asset transactions structure for agent {0}", userID);
186
187 lock (AgentTransactions)
188 {
189 AgentTransactions.Remove(userID);
190 }
191 }
192
193 /// <summary>
194 /// Create an inventory item from data that has been received through a transaction.
195 ///
196 /// This is called when new clothing or body parts are created. It may also be called in other
197 /// situations.
198 /// </summary>
199 /// <param name="remoteClient"></param>
200 /// <param name="transactionID"></param>
201 /// <param name="folderID"></param>
202 /// <param name="callbackID"></param>
203 /// <param name="description"></param>
204 /// <param name="name"></param>
205 /// <param name="invType"></param>
206 /// <param name="type"></param>
207 /// <param name="wearableType"></param>
208 /// <param name="nextOwnerMask"></param>
209 public void HandleItemCreationFromTransaction(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID,
210 uint callbackID, string description, string name, sbyte invType,
211 sbyte type, byte wearableType, uint nextOwnerMask)
212 {
213 m_log.DebugFormat(
214 "[TRANSACTIONS MANAGER] Called HandleItemCreationFromTransaction with item {0}", name);
215
216 AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId);
217
218 transactions.RequestCreateInventoryItem(
219 remoteClient, transactionID, folderID, callbackID, description,
220 name, invType, type, wearableType, nextOwnerMask);
221 }
222
223 /// <summary>
224 /// Update an inventory item with data that has been received through a transaction.
225 ///
226 /// This is called when clothing or body parts are updated (for instance, with new textures or
227 /// colours). It may also be called in other situations.
228 /// </summary>
229 /// <param name="remoteClient"></param>
230 /// <param name="transactionID"></param>
231 /// <param name="item"></param>
232 public void HandleItemUpdateFromTransaction(IClientAPI remoteClient, LLUUID transactionID,
233 InventoryItemBase item)
234 {
235 m_log.DebugFormat(
236 "[TRANSACTIONS MANAGER] Called HandleItemUpdateFromTransaction with item {0}",
237 item.Name);
238
239 AgentAssetTransactions transactions
240 = GetUserTransactions(remoteClient.AgentId);
241
242 transactions.RequestUpdateInventoryItem(remoteClient, transactionID, item);
243 }
244
245 /// <summary>
246 /// Request that a client (agent) begin an asset transfer.
247 /// </summary>
248 /// <param name="remoteClient"></param>
249 /// <param name="assetID"></param>
250 /// <param name="transaction"></param>
251 /// <param name="type"></param>
252 /// <param name="data"></param></param>
253 /// <param name="tempFile"></param>
254 public void HandleUDPUploadRequest(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type,
255 byte[] data, bool storeLocal, bool tempFile)
256 {
257 // Console.WriteLine("asset upload of " + assetID);
258 AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId);
259
260 AgentAssetTransactions.AssetXferUploader uploader = transactions.RequestXferUploader(transaction);
261 if (uploader != null)
262 {
263
264 if (uploader.Initialise(remoteClient, assetID, transaction, type, data, storeLocal, tempFile))
265 {
266
267 }
268 }
269 }
270
271 /// <summary>
272 /// Handle asset transfer data packets received in response to the asset upload request in
273 /// HandleUDPUploadRequest()
274 /// </summary>
275 /// <param name="remoteClient"></param>
276 /// <param name="xferID"></param>
277 /// <param name="packetID"></param>
278 /// <param name="data"></param>
279 public void HandleXfer(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data)
280 {
281 AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId);
282
283 transactions.HandleXfer(xferID, packetID, data);
284 }
285 }
286} \ 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
new file mode 100644
index 0000000..b8899d2
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Agent/TextureDownload/TextureDownloadModule.cs
@@ -0,0 +1,215 @@
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 OpenSim 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.Threading;
31using libsecondlife;
32using Nini.Config;
33using OpenSim.Framework;
34using OpenSim.Region.Environment.Interfaces;
35using OpenSim.Region.Environment.Scenes;
36
37namespace OpenSim.Region.Environment.Modules.Agent.TextureDownload
38{
39 public class TextureDownloadModule : IRegionModule
40 {
41 //private static readonly log4net.ILog m_log
42 // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
43
44 private Scene m_scene;
45 private List<Scene> m_scenes = new List<Scene>();
46
47 /// <summary>
48 /// There is one queue for all textures waiting to be sent, regardless of the requesting user.
49 /// </summary>
50 private readonly BlockingQueue<ITextureSender> m_queueSenders
51 = new BlockingQueue<ITextureSender>();
52
53 /// <summary>
54 /// Each user has their own texture download service.
55 /// </summary>
56 private readonly Dictionary<LLUUID, UserTextureDownloadService> m_userTextureServices =
57 new Dictionary<LLUUID, UserTextureDownloadService>();
58
59 private Thread m_thread;
60
61 public TextureDownloadModule()
62 {
63 }
64
65 public void Initialise(Scene scene, IConfigSource config)
66 {
67 if (m_scene == null)
68 {
69 //Console.WriteLine("Creating Texture download module");
70 m_thread = new Thread(new ThreadStart(ProcessTextureSenders));
71 m_thread.Name = "ProcessTextureSenderThread";
72 m_thread.IsBackground = true;
73 m_thread.Start();
74 ThreadTracker.Add(m_thread);
75 }
76
77 if (!m_scenes.Contains(scene))
78 {
79 m_scenes.Add(scene);
80 m_scene = scene;
81 m_scene.EventManager.OnNewClient += NewClient;
82 m_scene.EventManager.OnRemovePresence += EventManager_OnRemovePresence;
83 }
84 }
85
86 /// <summary>
87 /// Cleanup the texture service related objects for the removed presence.
88 /// </summary>
89 /// <param name="agentId"> </param>
90 private void EventManager_OnRemovePresence(LLUUID agentId)
91 {
92 UserTextureDownloadService textureService;
93
94 lock (m_userTextureServices)
95 {
96 if (m_userTextureServices.TryGetValue(agentId, out textureService))
97 {
98 textureService.Close();
99
100 m_userTextureServices.Remove(agentId);
101 }
102 }
103 }
104
105 public void PostInitialise()
106 {
107 }
108
109 public void Close()
110 {
111 }
112
113 public string Name
114 {
115 get { return "TextureDownloadModule"; }
116 }
117
118 public bool IsSharedModule
119 {
120 get { return false; }
121 }
122
123 public void NewClient(IClientAPI client)
124 {
125 client.OnRequestTexture += TextureRequest;
126 }
127
128 /// <summary>
129 /// Does this user have a registered texture download service?
130 /// </summary>
131 /// <param name="userID"></param>
132 /// <param name="textureService"></param>
133 /// <returns>Always returns true, since a service is created if one does not already exist</returns>
134 private bool TryGetUserTextureService(
135 IClientAPI client, out UserTextureDownloadService textureService)
136 {
137 lock (m_userTextureServices)
138 {
139 if (m_userTextureServices.TryGetValue(client.AgentId, out textureService))
140 {
141 return true;
142 }
143
144 textureService = new UserTextureDownloadService(client, m_scene, m_queueSenders);
145 m_userTextureServices.Add(client.AgentId, textureService);
146
147 return true;
148 }
149 }
150
151 /// <summary>
152 /// Start the process of requesting a given texture.
153 /// </summary>
154 /// <param name="sender"> </param>
155 /// <param name="e"></param>
156 public void TextureRequest(Object sender, TextureRequestArgs e)
157 {
158 IClientAPI client = (IClientAPI) sender;
159 UserTextureDownloadService textureService;
160
161 if (TryGetUserTextureService(client, out textureService))
162 {
163 textureService.HandleTextureRequest(e);
164 }
165 }
166
167 /// <summary>
168 /// Entry point for the thread dedicated to processing the texture queue.
169 /// </summary>
170 public void ProcessTextureSenders()
171 {
172 ITextureSender sender = null;
173
174 while (true)
175 {
176 sender = m_queueSenders.Dequeue();
177
178 if (sender.Cancel)
179 {
180 TextureSent(sender);
181
182 sender.Cancel = false;
183 }
184 else
185 {
186 bool finished = sender.SendTexturePacket();
187 if (finished)
188 {
189 TextureSent(sender);
190 }
191 else
192 {
193 m_queueSenders.Enqueue(sender);
194 }
195 }
196
197 // Make sure that any sender we currently have can get garbage collected
198 sender = null;
199
200 //m_log.InfoFormat("[TEXTURE DOWNLOAD] Texture sender queue size: {0}", m_queueSenders.Count());
201 }
202 }
203
204 /// <summary>
205 /// Called when the texture has finished sending.
206 /// </summary>
207 /// <param name="sender"></param>
208 private void TextureSent(ITextureSender sender)
209 {
210 sender.Sending = false;
211 //m_log.DebugFormat("[TEXTURE DOWNLOAD]: Removing download stat for {0}", sender.assetID);
212 m_scene.AddPendingDownloads(-1);
213 }
214 }
215} \ 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
new file mode 100644
index 0000000..6f11f73
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Agent/TextureDownload/TextureNotFoundSender.cs
@@ -0,0 +1,93 @@
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 OpenSim 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 libsecondlife;
29using libsecondlife.Packets;
30using OpenSim.Framework;
31using OpenSim.Region.Environment.Interfaces;
32
33namespace OpenSim.Region.Environment.Modules.Agent.TextureDownload
34{
35 /// <summary>
36 /// Sends a 'texture not found' packet back to the client
37 /// </summary>
38 public class TextureNotFoundSender : ITextureSender
39 {
40 //private static readonly log4net.ILog m_log
41 // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
42
43 private LLUUID m_textureId;
44 private IClientAPI m_client;
45
46 // See ITextureSender
47 public bool Sending
48 {
49 get { return false; }
50 set { m_sending = value; }
51 }
52
53 private bool m_sending = false;
54
55 // See ITextureSender
56 public bool Cancel
57 {
58 get { return false; }
59 set { m_cancel = value; }
60 }
61
62 private bool m_cancel = false;
63
64 public TextureNotFoundSender(IClientAPI client, LLUUID textureID)
65 {
66 m_client = client;
67 m_textureId = textureID;
68 }
69
70 // See ITextureSender
71 public void UpdateRequest(int discardLevel, uint packetNumber)
72 {
73 // Not need to implement since priority changes don't affect this operation
74 }
75
76 // See ITextureSender
77 public bool SendTexturePacket()
78 {
79 //m_log.InfoFormat(
80 // "[TEXTURE NOT FOUND SENDER]: Informing the client that texture {0} cannot be found",
81 // m_textureId);
82
83 ImageNotInDatabasePacket notFound = new ImageNotInDatabasePacket();
84 notFound.ImageID.ID = m_textureId;
85
86 // XXX Temporarily disabling as this appears to be causing client crashes on at least
87 // 1.19.0(5) of the Linden Second Life client.
88 // m_client.OutPacket(notFound, ThrottleOutPacketType.Texture);
89
90 return true;
91 }
92 }
93} \ 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
new file mode 100644
index 0000000..08a22d6
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Agent/TextureDownload/UserTextureDownloadService.cs
@@ -0,0 +1,252 @@
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 OpenSim 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.Collections.Generic;
29using System.Reflection;
30using libsecondlife;
31using log4net;
32using OpenSim.Framework;
33using OpenSim.Framework.Communications.Limit;
34using OpenSim.Region.Environment.Interfaces;
35using OpenSim.Region.Environment.Modules.Agent.TextureDownload;
36using OpenSim.Region.Environment.Modules.Agent.TextureSender;
37using OpenSim.Region.Environment.Scenes;
38
39namespace OpenSim.Region.Environment.Modules.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
49 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 /// <summary>
52 /// We will allow the client to request the same texture n times before dropping further requests
53 ///
54 /// This number includes repeated requests for the same texture at different resolutions (which we don't
55 /// currently handle properly as far as I know). However, this situation should be handled in a more
56 /// sophisticated way.
57 /// </summary>
58 private static readonly int MAX_ALLOWED_TEXTURE_REQUESTS = 5;
59
60 /// <summary>
61 /// We're going to limit requests for the same missing texture.
62 /// XXX This is really a temporary solution to deal with the situation where a client continually requests
63 /// the same missing textures
64 /// </summary>
65 private readonly IRequestLimitStrategy<LLUUID> missingTextureLimitStrategy
66 = new RepeatLimitStrategy<LLUUID>(MAX_ALLOWED_TEXTURE_REQUESTS);
67
68 /// <summary>
69 /// XXX Also going to limit requests for found textures.
70 /// </summary>
71 private readonly IRequestLimitStrategy<LLUUID> foundTextureLimitStrategy
72 = new RepeatLimitStrategy<LLUUID>(MAX_ALLOWED_TEXTURE_REQUESTS);
73
74 /// <summary>
75 /// Holds texture senders before they have received the appropriate texture from the asset cache.
76 /// </summary>
77 private readonly Dictionary<LLUUID, TextureSender.TextureSender> m_textureSenders = new Dictionary<LLUUID, TextureSender.TextureSender>();
78
79 /// <summary>
80 /// Texture Senders are placed in this queue once they have received their texture from the asset
81 /// cache. Another module actually invokes the send.
82 /// </summary>
83 private readonly BlockingQueue<ITextureSender> m_sharedSendersQueue;
84
85 private readonly Scene m_scene;
86
87 private readonly IClientAPI m_client;
88
89 public UserTextureDownloadService(
90 IClientAPI client, Scene scene, BlockingQueue<ITextureSender> sharedQueue)
91 {
92 m_client = client;
93 m_scene = scene;
94 m_sharedSendersQueue = sharedQueue;
95 }
96
97 /// <summary>
98 /// Handle a texture request. This involves creating a texture sender and placing it on the
99 /// previously passed in shared queue.
100 /// </summary>
101 /// <param name="e"></param>
102 public void HandleTextureRequest(TextureRequestArgs e)
103 {
104 TextureSender.TextureSender textureSender;
105
106 //TODO: should be working out the data size/ number of packets to be sent for each discard level
107 if ((e.DiscardLevel >= 0) || (e.Priority != 0))
108 {
109 lock (m_textureSenders)
110 {
111 if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender))
112 {
113 // If we've received new non UUID information for this request and it hasn't dispatched
114 // yet, then update the request accordingly.
115 textureSender.UpdateRequest(e.DiscardLevel, e.PacketNumber);
116 }
117 else
118 {
119 if (!foundTextureLimitStrategy.AllowRequest(e.RequestedAssetID))
120 {
121// m_log.DebugFormat(
122// "[USER TEXTURE DOWNLOAD SERVICE]: Refusing request for {0} from client {1}",
123// e.RequestedAssetID, m_client.AgentId);
124
125 return;
126 }
127 else if (!missingTextureLimitStrategy.AllowRequest(e.RequestedAssetID))
128 {
129 if (missingTextureLimitStrategy.IsFirstRefusal(e.RequestedAssetID))
130 {
131 // Commenting out this message for now as it causes too much noise with other
132 // debug messages.
133 // TODO: possibly record this as a statistic in the future
134 //
135// m_log.DebugFormat(
136// "[USER TEXTURE DOWNLOAD SERVICE]: Dropping requests for notified missing texture {0} for client {1} since we have received more than {2} requests",
137// e.RequestedAssetID, m_client.AgentId, MAX_ALLOWED_TEXTURE_REQUESTS);
138 }
139
140 return;
141 }
142
143 m_scene.AddPendingDownloads(1);
144
145 TextureSender.TextureSender requestHandler = new TextureSender.TextureSender(m_client, e.DiscardLevel, e.PacketNumber);
146 m_textureSenders.Add(e.RequestedAssetID, requestHandler);
147
148 m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback, true);
149 }
150 }
151 }
152 else
153 {
154 lock (m_textureSenders)
155 {
156 if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender))
157 {
158 textureSender.Cancel = true;
159 }
160 }
161 }
162 }
163
164 /// <summary>
165 /// The callback for the asset cache when a texture has been retrieved. This method queues the
166 /// texture sender for processing.
167 /// </summary>
168 /// <param name="textureID"></param>
169 /// <param name="texture"></param>
170 public void TextureCallback(LLUUID textureID, AssetBase texture)
171 {
172 //m_log.DebugFormat("[USER TEXTURE DOWNLOAD SERVICE]: Calling TextureCallback with {0}, texture == null is {1}", textureID, (texture == null ? true : false));
173
174 lock (m_textureSenders)
175 {
176 TextureSender.TextureSender textureSender;
177
178 if (m_textureSenders.TryGetValue(textureID, out textureSender))
179 {
180 // XXX It may be perfectly valid for a texture to have no data... but if we pass
181 // this on to the TextureSender it will blow up, so just discard for now.
182 // Needs investigation.
183 if (texture == null || texture.Data == null)
184 {
185 if (!missingTextureLimitStrategy.IsMonitoringRequests(textureID))
186 {
187 missingTextureLimitStrategy.MonitorRequests(textureID);
188
189 m_log.DebugFormat(
190 "[USER TEXTURE DOWNLOAD SERVICE]: Queueing first TextureNotFoundSender for {0}, client {1}",
191 textureID, m_client.AgentId);
192 }
193
194 ITextureSender textureNotFoundSender = new TextureNotFoundSender(m_client, textureID);
195 EnqueueTextureSender(textureNotFoundSender);
196 }
197 else
198 {
199 if (!textureSender.ImageLoaded)
200 {
201 textureSender.TextureReceived(texture);
202 EnqueueTextureSender(textureSender);
203
204 foundTextureLimitStrategy.MonitorRequests(textureID);
205 }
206 }
207
208 //m_log.InfoFormat("[TEXTURE SENDER] Removing texture sender with uuid {0}", textureID);
209 m_textureSenders.Remove(textureID);
210 //m_log.InfoFormat("[TEXTURE SENDER] Current texture senders in dictionary: {0}", m_textureSenders.Count);
211 }
212 else
213 {
214 m_log.WarnFormat(
215 "Got a texture uuid {0} with no sender object to handle it, this shouldn't happen",
216 textureID);
217 }
218 }
219 }
220
221 /// <summary>
222 /// Place a ready texture sender on the processing queue.
223 /// </summary>
224 /// <param name="textureSender"></param>
225 private void EnqueueTextureSender(ITextureSender textureSender)
226 {
227 textureSender.Cancel = false;
228 textureSender.Sending = true;
229
230 if (!m_sharedSendersQueue.Contains(textureSender))
231 {
232 m_sharedSendersQueue.Enqueue(textureSender);
233 }
234 }
235
236 /// <summary>
237 /// Close this module.
238 /// </summary>
239 internal void Close()
240 {
241 lock (m_textureSenders)
242 {
243 foreach( TextureSender.TextureSender textureSender in m_textureSenders.Values )
244 {
245 textureSender.Cancel = true;
246 }
247
248 m_textureSenders.Clear();
249 }
250 }
251 }
252} \ 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
new file mode 100644
index 0000000..37b0652
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Agent/TextureSender/TextureSender.cs
@@ -0,0 +1,220 @@
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 OpenSim 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 libsecondlife.Packets;
31using log4net;
32using OpenSim.Framework;
33using OpenSim.Region.Environment.Interfaces;
34
35namespace OpenSim.Region.Environment.Modules.Agent.TextureSender
36{
37 /// <summary>
38 /// A TextureSender handles the process of receiving a texture requested by the client from the
39 /// AssetCache, and then sending that texture back to the client.
40 /// </summary>
41 public class TextureSender : ITextureSender
42 {
43 private static readonly ILog m_log
44 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 /// <summary>
47 /// Records the number of times texture send has been called.
48 /// </summary>
49 public int counter = 0;
50
51 /// <summary>
52 /// Holds the texture asset to send.
53 /// </summary>
54 private AssetBase m_asset;
55
56 //public LLUUID assetID { get { return m_asset.FullID; } }
57
58 /// <summary>
59 /// This is actually the number of extra packets required to send the texture data! We always assume
60 /// at least one is required.
61 /// </summary>
62 private int NumPackets = 0;
63
64 /// <summary>
65 /// Holds the packet number to send next. In this case, each packet is 1000 bytes long and starts
66 /// at the 600th byte (0th indexed).
67 /// </summary>
68 private int PacketCounter = 0;
69
70 // See ITextureSender
71 public bool Cancel
72 {
73 get { return false; }
74 set { m_cancel = value; }
75 }
76
77 private bool m_cancel = false;
78
79 // See ITextureSender
80 public bool Sending
81 {
82 get { return false; }
83 set { m_sending = value; }
84 }
85
86 private bool m_sending = false;
87
88 public bool ImageLoaded = false;
89
90 private IClientAPI RequestUser;
91
92 private int RequestedDiscardLevel = -1;
93 private uint StartPacketNumber = 0;
94
95 public TextureSender(IClientAPI client, int discardLevel, uint packetNumber)
96 {
97 RequestUser = client;
98 RequestedDiscardLevel = discardLevel;
99 StartPacketNumber = packetNumber;
100 }
101
102 /// <summary>
103 /// Load up the texture data to send.
104 /// </summary>
105 /// <param name="asset">
106 /// A <see cref="AssetBase"/>
107 /// </param>
108 public void TextureReceived(AssetBase asset)
109 {
110 m_asset = asset;
111 NumPackets = CalculateNumPackets(asset.Data.Length);
112 PacketCounter = (int) StartPacketNumber;
113 ImageLoaded = true;
114 }
115
116 // See ITextureSender
117 public void UpdateRequest(int discardLevel, uint packetNumber)
118 {
119 RequestedDiscardLevel = discardLevel;
120 StartPacketNumber = packetNumber;
121 PacketCounter = (int) StartPacketNumber;
122 }
123
124 // See ITextureSender
125 public bool SendTexturePacket()
126 {
127 //m_log.DebugFormat("[TEXTURE SENDER]: Sending packet for {0}", m_asset.FullID);
128
129 SendPacket();
130 counter++;
131 if ((NumPackets == 0) || (RequestedDiscardLevel == -1) || (PacketCounter > NumPackets) ||
132 ((RequestedDiscardLevel > 0) && (counter > 50 + (NumPackets/(RequestedDiscardLevel + 1)))))
133 {
134 return true;
135 }
136 return false;
137 }
138
139 /// <summary>
140 /// Sends a texture packet to the client.
141 /// </summary>
142 private void SendPacket()
143 {
144 if (PacketCounter <= NumPackets)
145 {
146 if (PacketCounter == 0)
147 {
148 if (NumPackets == 0)
149 {
150 ImageDataPacket im = new ImageDataPacket();
151 im.Header.Reliable = false;
152 im.ImageID.Packets = 1;
153 im.ImageID.ID = m_asset.FullID;
154 im.ImageID.Size = (uint) m_asset.Data.Length;
155 im.ImageData.Data = m_asset.Data;
156 im.ImageID.Codec = 2;
157 RequestUser.OutPacket(im, ThrottleOutPacketType.Texture);
158 PacketCounter++;
159 }
160 else
161 {
162 ImageDataPacket im = new ImageDataPacket();
163 im.Header.Reliable = false;
164 im.ImageID.Packets = (ushort) (NumPackets);
165 im.ImageID.ID = m_asset.FullID;
166 im.ImageID.Size = (uint) m_asset.Data.Length;
167 im.ImageData.Data = new byte[600];
168 Array.Copy(m_asset.Data, 0, im.ImageData.Data, 0, 600);
169 im.ImageID.Codec = 2;
170 RequestUser.OutPacket(im, ThrottleOutPacketType.Texture);
171 PacketCounter++;
172 }
173 }
174 else
175 {
176 ImagePacketPacket im = new ImagePacketPacket();
177 im.Header.Reliable = false;
178 im.ImageID.Packet = (ushort) (PacketCounter);
179 im.ImageID.ID = m_asset.FullID;
180 int size = m_asset.Data.Length - 600 - (1000*(PacketCounter - 1));
181 if (size > 1000) size = 1000;
182 im.ImageData.Data = new byte[size];
183 try
184 {
185 Array.Copy(m_asset.Data, 600 + (1000*(PacketCounter - 1)), im.ImageData.Data, 0, size);
186 }
187 catch (ArgumentOutOfRangeException)
188 {
189 m_log.Error("[TEXTURE SENDER]: Unable to separate texture into multiple packets: Array bounds failure on asset:" +
190 m_asset.FullID.ToString() );
191 return;
192 }
193 RequestUser.OutPacket(im, ThrottleOutPacketType.Texture);
194 PacketCounter++;
195 }
196 }
197 }
198
199 /// <summary>
200 /// Calculate the number of packets that will be required to send the texture loaded into this sender
201 /// This is actually the number of 1000 byte packets not including an initial 600 byte packet...
202 /// </summary>
203 /// <param name="length"></param>
204 /// <returns></returns>
205 private int CalculateNumPackets(int length)
206 {
207 int numPackets = 0;
208
209 if (length > 600)
210 {
211 //over 600 bytes so split up file
212 int restData = (length - 600);
213 int restPackets = ((restData + 999)/1000);
214 numPackets = restPackets;
215 }
216
217 return numPackets;
218 }
219 }
220} \ 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
new file mode 100644
index 0000000..b609f93
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Agent/Xfer/XferModule.cs
@@ -0,0 +1,225 @@
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 OpenSim 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 libsecondlife;
31using Nini.Config;
32using OpenSim.Framework;
33using OpenSim.Region.Environment.Interfaces;
34using OpenSim.Region.Environment.Scenes;
35
36namespace OpenSim.Region.Environment.Modules.Agent.Xfer
37{
38 public class XferModule : IRegionModule, IXfer
39 {
40 public Dictionary<string, byte[]> NewFiles = new Dictionary<string, byte[]>();
41 public Dictionary<ulong, XferDownLoad> Transfers = new Dictionary<ulong, XferDownLoad>();
42
43 private Scene m_scene;
44
45 public XferModule()
46 {
47 }
48
49 public void Initialise(Scene scene, IConfigSource config)
50 {
51 m_scene = scene;
52 m_scene.EventManager.OnNewClient += NewClient;
53
54 m_scene.RegisterModuleInterface<IXfer>(this);
55 }
56
57 public void PostInitialise()
58 {
59 }
60
61 public void Close()
62 {
63 }
64
65 public string Name
66 {
67 get { return "XferModule"; }
68 }
69
70 public bool IsSharedModule
71 {
72 get { return false; }
73 }
74
75 public void NewClient(IClientAPI client)
76 {
77 client.OnRequestXfer += RequestXfer;
78 client.OnConfirmXfer += AckPacket;
79 }
80
81 /// <summary>
82 ///
83 /// </summary>
84 /// <param name="remoteClient"></param>
85 /// <param name="xferID"></param>
86 /// <param name="fileName"></param>
87 public void RequestXfer(IClientAPI remoteClient, ulong xferID, string fileName)
88 {
89 lock (NewFiles)
90 {
91 if (NewFiles.ContainsKey(fileName))
92 {
93 if (!Transfers.ContainsKey(xferID))
94 {
95 byte[] fileData = NewFiles[fileName];
96 XferDownLoad transaction = new XferDownLoad(fileName, fileData, xferID, remoteClient);
97 Transfers.Add(xferID, transaction);
98 NewFiles.Remove(fileName);
99
100 if (transaction.StartSend())
101 {
102 Transfers.Remove(xferID);
103 }
104 }
105 }
106 }
107 }
108
109 public void AckPacket(IClientAPI remoteClient, ulong xferID, uint packet)
110 {
111 if (Transfers.ContainsKey(xferID))
112 {
113 if (Transfers[xferID].AckPacket(packet))
114 {
115 {
116 Transfers.Remove(xferID);
117 }
118 }
119 }
120 }
121
122 public bool AddNewFile(string fileName, byte[] data)
123 {
124 lock (NewFiles)
125 {
126 if (NewFiles.ContainsKey(fileName))
127 {
128 NewFiles[fileName] = data;
129 }
130 else
131 {
132 NewFiles.Add(fileName, data);
133 }
134 }
135 return true;
136 }
137
138
139 public class XferDownLoad
140 {
141 public byte[] Data = new byte[0];
142 public string FileName = String.Empty;
143 public ulong XferID = 0;
144 public int DataPointer = 0;
145 public uint Packet = 0;
146 public IClientAPI Client;
147 public uint Serial = 1;
148 private bool complete;
149
150 public XferDownLoad(string fileName, byte[] data, ulong xferID, IClientAPI client)
151 {
152 FileName = fileName;
153 Data = data;
154 XferID = xferID;
155 Client = client;
156 }
157
158 public XferDownLoad()
159 {
160 }
161
162 /// <summary>
163 /// Start a transfer
164 /// </summary>
165 /// <returns>True if the transfer is complete, false if not</returns>
166 public bool StartSend()
167 {
168 if (Data.Length < 1000)
169 {
170 // for now (testing ) we only support files under 1000 bytes
171 byte[] transferData = new byte[Data.Length + 4];
172 Array.Copy(Helpers.IntToBytes(Data.Length), 0, transferData, 0, 4);
173 Array.Copy(Data, 0, transferData, 4, Data.Length);
174 Client.SendXferPacket(XferID, 0 + 0x80000000, transferData);
175
176 complete = true;
177 }
178 else
179 {
180 byte[] transferData = new byte[1000 + 4];
181 Array.Copy(Helpers.IntToBytes(Data.Length), 0, transferData, 0, 4);
182 Array.Copy(Data, 0, transferData, 4, 1000);
183 Client.SendXferPacket(XferID, 0, transferData);
184 Packet++;
185 DataPointer = 1000;
186 }
187
188 return complete;
189 }
190
191 /// <summary>
192 /// Respond to an ack packet from the client
193 /// </summary>
194 /// <param name="packet"></param>
195 /// <returns>True if the transfer is complete, false otherwise</returns>
196 public bool AckPacket(uint packet)
197 {
198 if (!complete)
199 {
200 if ((Data.Length - DataPointer) > 1000)
201 {
202 byte[] transferData = new byte[1000];
203 Array.Copy(Data, DataPointer, transferData, 0, 1000);
204 Client.SendXferPacket(XferID, Packet, transferData);
205 Packet++;
206 DataPointer += 1000;
207 }
208 else
209 {
210 byte[] transferData = new byte[Data.Length - DataPointer];
211 Array.Copy(Data, DataPointer, transferData, 0, Data.Length - DataPointer);
212 uint endPacket = Packet |= (uint) 0x80000000;
213 Client.SendXferPacket(XferID, endPacket, transferData);
214 Packet++;
215 DataPointer += (Data.Length - DataPointer);
216
217 complete = true;
218 }
219 }
220
221 return complete;
222 }
223 }
224 }
225} \ No newline at end of file