aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/Agent
diff options
context:
space:
mode:
authorAdam Frisby2008-04-30 21:16:36 +0000
committerAdam Frisby2008-04-30 21:16:36 +0000
commitf5c312bc3c2567449c7268a54a08a54119f58d53 (patch)
tree424668a4bbec6873ebc5b8256f3671db102f5e9c /OpenSim/Region/Environment/Modules/Agent
parent* Adds the AuthbuyerID field to sqlite and makes use of it. (diff)
downloadopensim-SC-f5c312bc3c2567449c7268a54a08a54119f58d53.zip
opensim-SC-f5c312bc3c2567449c7268a54a08a54119f58d53.tar.gz
opensim-SC-f5c312bc3c2567449c7268a54a08a54119f58d53.tar.bz2
opensim-SC-f5c312bc3c2567449c7268a54a08a54119f58d53.tar.xz
* Refactored Environment/Modules directory - modules now reside in their own directory with any associated module-specific classes.
* Each module directory is currently inside one of the following category folders: Agent (Anything relating to do with Client<->Server communications.), Avatar (Anything to do with the avatar or presence inworld), Framework (Classes modules can use), Grid (Grid traffic, new OGS2 grid comms), Scripting (Scripting functions, etc), World (The enrivonment/scene, IE Sun/Tree modules.) * This should be moved into a seperate project file.
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