OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
XferModule.cs
Go to the documentation of this file.
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")]
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  {
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 
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 
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  if (fileName.StartsWith("inventory_"))
164  transaction.isTaskInventory = true;
165 
166  Transfers.Add(xferID, transaction);
167 
168  if (transaction.StartSend())
169  RemoveXferData(xferID);
170 
171  // The transaction for this file is either complete or on its way
172  RemoveOrDecrement(fileName);
173 
174  }
175  }
176  else
177  m_log.WarnFormat("[Xfer]: {0} not found", fileName);
178 
179  }
180  }
181 
182  public void AckPacket(IClientAPI remoteClient, ulong xferID, uint packet)
183  {
184  lock (NewFiles) // This is actually to lock Transfers
185  {
186  if (Transfers.ContainsKey(xferID))
187  {
188  XferDownLoad dl = Transfers[xferID];
189  if (Transfers[xferID].AckPacket(packet))
190  {
191  RemoveXferData(xferID);
192  RemoveOrDecrement(dl.FileName);
193  }
194  }
195  }
196  }
197 
198  private void RemoveXferData(ulong xferID)
199  {
200  // NewFiles must be locked!
201  if (Transfers.ContainsKey(xferID))
202  {
203  XferModule.XferDownLoad xferItem = Transfers[xferID];
204  //string filename = xferItem.FileName;
205  Transfers.Remove(xferID);
206  xferItem.Data = new byte[0]; // Clear the data
207  xferItem.DataPointer = 0;
208 
209  }
210  }
211 
212  public void AbortXfer(IClientAPI remoteClient, ulong xferID)
213  {
214  lock (NewFiles)
215  {
216  if (Transfers.ContainsKey(xferID))
217  RemoveOrDecrement(Transfers[xferID].FileName);
218 
219  RemoveXferData(xferID);
220  }
221  }
222 
223  private void RemoveOrDecrement(string fileName)
224  {
225  // NewFiles must be locked
226 
227  if (NewFiles.ContainsKey(fileName))
228  {
229  if (NewFiles[fileName].Count == 1)
230  NewFiles.Remove(fileName);
231  else
232  NewFiles[fileName].Count--;
233  }
234  }
235 
236  #region Nested type: XferDownLoad
237 
238  public class XferDownLoad
239  {
241  private bool complete;
242  public byte[] Data = new byte[0];
243  public int DataPointer = 0;
244  public string FileName = String.Empty;
245  public uint Packet = 0;
246  public uint Serial = 1;
247  public ulong XferID = 0;
248  public bool isTaskInventory = false;
249 
250  public XferDownLoad(string fileName, byte[] data, ulong xferID, IClientAPI client)
251  {
252  FileName = fileName;
253  Data = data;
254  XferID = xferID;
255  Client = client;
256  }
257 
258  public XferDownLoad()
259  {
260  }
261 
266  public bool StartSend()
267  {
268  if (Data.Length < 1000)
269  {
270  // for now (testing) we only support files under 1000 bytes
271  byte[] transferData = new byte[Data.Length + 4];
272  Array.Copy(Utils.IntToBytes(Data.Length), 0, transferData, 0, 4);
273  Array.Copy(Data, 0, transferData, 4, Data.Length);
274  Client.SendXferPacket(XferID, 0 + 0x80000000, transferData, isTaskInventory);
275  complete = true;
276  }
277  else
278  {
279  byte[] transferData = new byte[1000 + 4];
280  Array.Copy(Utils.IntToBytes(Data.Length), 0, transferData, 0, 4);
281  Array.Copy(Data, 0, transferData, 4, 1000);
282  Client.SendXferPacket(XferID, 0, transferData, isTaskInventory);
283  Packet++;
284  DataPointer = 1000;
285  }
286 
287  return complete;
288  }
289 
295  public bool AckPacket(uint packet)
296  {
297  if (!complete)
298  {
299  if ((Data.Length - DataPointer) > 1000)
300  {
301  byte[] transferData = new byte[1000];
302  Array.Copy(Data, DataPointer, transferData, 0, 1000);
303  Client.SendXferPacket(XferID, Packet, transferData, isTaskInventory);
304  Packet++;
305  DataPointer += 1000;
306  }
307  else
308  {
309  byte[] transferData = new byte[Data.Length - DataPointer];
310  Array.Copy(Data, DataPointer, transferData, 0, Data.Length - DataPointer);
311  uint endPacket = Packet |= (uint) 0x80000000;
312  Client.SendXferPacket(XferID, endPacket, transferData, isTaskInventory);
313  Packet++;
314  DataPointer += (Data.Length - DataPointer);
315 
316  complete = true;
317  }
318  }
319 
320  return complete;
321  }
322  }
323 
324  #endregion
325  }
326 }
delegate void AbortXfer(IClientAPI remoteClient, ulong xferID)
bool AckPacket(uint packet)
Respond to an ack packet from the client
Definition: XferModule.cs:295
void AbortXfer(IClientAPI remoteClient, ulong xferID)
Definition: XferModule.cs:212
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
Definition: XferModule.cs:96
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
Definition: XferModule.cs:79
void RequestXfer(IClientAPI remoteClient, ulong xferID, string fileName)
Definition: XferModule.cs:153
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
Definition: XferModule.cs:71
void AckPacket(IClientAPI remoteClient, ulong xferID, uint packet)
Definition: XferModule.cs:182
void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...
Definition: XferModule.cs:67
Interactive OpenSim region server
Definition: OpenSim.cs:55
bool AddNewFile(string fileName, byte[] data)
Let the Xfer module know about a file that the client is about to request. Caller is responsible for ...
Definition: XferModule.cs:117
delegate void RequestXfer(IClientAPI remoteClient, ulong xferID, string fileName)
XferDownLoad(string fileName, byte[] data, ulong xferID, IClientAPI client)
Definition: XferModule.cs:250
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
Definition: XferModule.cs:87