clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Collections.Generic;
30 using System.Reflection;
31 using Nini.Config;
32 using log4net;
33 using OpenMetaverse;
34 using OpenSim.Framework;
35 using OpenSim.Region.Framework.Interfaces;
36 using OpenSim.Region.Framework.Scenes;
37  
38 using Mono.Addins;
39  
40 namespace OpenSim.Region.CoreModules.Agent.Xfer
41 {
42 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XferModule")]
43 public class XferModule : INonSharedRegionModule, IXfer
44 {
45 private Scene m_scene;
46 private Dictionary<string, FileData> NewFiles = new Dictionary<string, FileData>();
47 private Dictionary<ulong, XferDownLoad> Transfers = new Dictionary<ulong, XferDownLoad>();
48  
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50  
51 public struct XferRequest
52 {
53 public IClientAPI remoteClient;
54 public ulong xferID;
55 public string fileName;
56 public DateTime timeStamp;
57 }
58  
59 private class FileData
60 {
61 public byte[] Data;
62 public int Count;
63 }
64  
65 #region INonSharedRegionModule Members
66  
67 public void Initialise(IConfigSource config)
68 {
69 }
70  
71 public void AddRegion(Scene scene)
72 {
73 m_scene = scene;
74 m_scene.EventManager.OnNewClient += NewClient;
75  
76 m_scene.RegisterModuleInterface<IXfer>(this);
77 }
78  
79 public void RemoveRegion(Scene scene)
80 {
81 m_scene.EventManager.OnNewClient -= NewClient;
82  
83 m_scene.UnregisterModuleInterface<IXfer>(this);
84 m_scene = null;
85 }
86  
87 public void RegionLoaded(Scene scene)
88 {
89 }
90  
91 public Type ReplaceableInterface
92 {
93 get { return null; }
94 }
95  
96 public void Close()
97 {
98 }
99  
100 public string Name
101 {
102 get { return "XferModule"; }
103 }
104  
105 #endregion
106  
107 #region IXfer Members
108  
109 /// <summary>
110 /// Let the Xfer module know about a file that the client is about to request.
111 /// Caller is responsible for making sure that the file is here before
112 /// the client starts the XferRequest.
113 /// </summary>
114 /// <param name="fileName"></param>
115 /// <param name="data"></param>
116 /// <returns></returns>
117 public bool AddNewFile(string fileName, byte[] data)
118 {
119 lock (NewFiles)
120 {
121 if (NewFiles.ContainsKey(fileName))
122 {
123 NewFiles[fileName].Count++;
124 NewFiles[fileName].Data = data;
125 }
126 else
127 {
128 FileData fd = new FileData();
129 fd.Count = 1;
130 fd.Data = data;
131 NewFiles.Add(fileName, fd);
132 }
133 }
134  
135 return true;
136 }
137  
138 #endregion
139  
140 public void NewClient(IClientAPI client)
141 {
142 client.OnRequestXfer += RequestXfer;
143 client.OnConfirmXfer += AckPacket;
144 client.OnAbortXfer += AbortXfer;
145 }
146  
147 /// <summary>
148 ///
149 /// </summary>
150 /// <param name="remoteClient"></param>
151 /// <param name="xferID"></param>
152 /// <param name="fileName"></param>
153 public void RequestXfer(IClientAPI remoteClient, ulong xferID, string fileName)
154 {
155 lock (NewFiles)
156 {
157 if (NewFiles.ContainsKey(fileName))
158 {
159 if (!Transfers.ContainsKey(xferID))
160 {
161 byte[] fileData = NewFiles[fileName].Data;
162 XferDownLoad transaction = new XferDownLoad(fileName, fileData, xferID, remoteClient);
163  
164 Transfers.Add(xferID, transaction);
165  
166 if (transaction.StartSend())
167 RemoveXferData(xferID);
168  
169 // The transaction for this file is either complete or on its way
170 RemoveOrDecrement(fileName);
171  
172 }
173 }
174 else
175 m_log.WarnFormat("[Xfer]: {0} not found", fileName);
176  
177 }
178 }
179  
180 public void AckPacket(IClientAPI remoteClient, ulong xferID, uint packet)
181 {
182 lock (NewFiles) // This is actually to lock Transfers
183 {
184 if (Transfers.ContainsKey(xferID))
185 {
186 XferDownLoad dl = Transfers[xferID];
187 if (Transfers[xferID].AckPacket(packet))
188 {
189 RemoveXferData(xferID);
190 RemoveOrDecrement(dl.FileName);
191 }
192 }
193 }
194 }
195  
196 private void RemoveXferData(ulong xferID)
197 {
198 // NewFiles must be locked!
199 if (Transfers.ContainsKey(xferID))
200 {
201 XferModule.XferDownLoad xferItem = Transfers[xferID];
202 //string filename = xferItem.FileName;
203 Transfers.Remove(xferID);
204 xferItem.Data = new byte[0]; // Clear the data
205 xferItem.DataPointer = 0;
206  
207 }
208 }
209  
210 public void AbortXfer(IClientAPI remoteClient, ulong xferID)
211 {
212 lock (NewFiles)
213 {
214 if (Transfers.ContainsKey(xferID))
215 RemoveOrDecrement(Transfers[xferID].FileName);
216  
217 RemoveXferData(xferID);
218 }
219 }
220  
221 private void RemoveOrDecrement(string fileName)
222 {
223 // NewFiles must be locked
224  
225 if (NewFiles.ContainsKey(fileName))
226 {
227 if (NewFiles[fileName].Count == 1)
228 NewFiles.Remove(fileName);
229 else
230 NewFiles[fileName].Count--;
231 }
232 }
233  
234 #region Nested type: XferDownLoad
235  
236 public class XferDownLoad
237 {
238 public IClientAPI Client;
239 private bool complete;
240 public byte[] Data = new byte[0];
241 public int DataPointer = 0;
242 public string FileName = String.Empty;
243 public uint Packet = 0;
244 public uint Serial = 1;
245 public ulong XferID = 0;
246  
247 public XferDownLoad(string fileName, byte[] data, ulong xferID, IClientAPI client)
248 {
249 FileName = fileName;
250 Data = data;
251 XferID = xferID;
252 Client = client;
253 }
254  
255 public XferDownLoad()
256 {
257 }
258  
259 /// <summary>
260 /// Start a transfer
261 /// </summary>
262 /// <returns>True if the transfer is complete, false if not</returns>
263 public bool StartSend()
264 {
265 if (Data.Length < 1000)
266 {
267 // for now (testing) we only support files under 1000 bytes
268 byte[] transferData = new byte[Data.Length + 4];
269 Array.Copy(Utils.IntToBytes(Data.Length), 0, transferData, 0, 4);
270 Array.Copy(Data, 0, transferData, 4, Data.Length);
271 Client.SendXferPacket(XferID, 0 + 0x80000000, transferData);
272 complete = true;
273 }
274 else
275 {
276 byte[] transferData = new byte[1000 + 4];
277 Array.Copy(Utils.IntToBytes(Data.Length), 0, transferData, 0, 4);
278 Array.Copy(Data, 0, transferData, 4, 1000);
279 Client.SendXferPacket(XferID, 0, transferData);
280 Packet++;
281 DataPointer = 1000;
282 }
283  
284 return complete;
285 }
286  
287 /// <summary>
288 /// Respond to an ack packet from the client
289 /// </summary>
290 /// <param name="packet"></param>
291 /// <returns>True if the transfer is complete, false otherwise</returns>
292 public bool AckPacket(uint packet)
293 {
294 if (!complete)
295 {
296 if ((Data.Length - DataPointer) > 1000)
297 {
298 byte[] transferData = new byte[1000];
299 Array.Copy(Data, DataPointer, transferData, 0, 1000);
300 Client.SendXferPacket(XferID, Packet, transferData);
301 Packet++;
302 DataPointer += 1000;
303 }
304 else
305 {
306 byte[] transferData = new byte[Data.Length - DataPointer];
307 Array.Copy(Data, DataPointer, transferData, 0, Data.Length - DataPointer);
308 uint endPacket = Packet |= (uint) 0x80000000;
309 Client.SendXferPacket(XferID, endPacket, transferData);
310 Packet++;
311 DataPointer += (Data.Length - DataPointer);
312  
313 complete = true;
314 }
315 }
316  
317 return complete;
318 }
319 }
320  
321 #endregion
322 }
323 }