XferModule.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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. using System;
  28. using System.Collections.Generic;
  29. using System.Reflection;
  30. using Nini.Config;
  31. using log4net;
  32. using OpenMetaverse;
  33. using OpenSim.Framework;
  34. using OpenSim.Region.Framework.Interfaces;
  35. using OpenSim.Region.Framework.Scenes;
  36. using Mono.Addins;
  37. namespace OpenSim.Region.CoreModules.Agent.Xfer
  38. {
  39. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XferModule")]
  40. public class XferModule : INonSharedRegionModule, IXfer
  41. {
  42. private Scene m_scene;
  43. private Dictionary<string, FileData> NewFiles = new Dictionary<string, FileData>();
  44. private Dictionary<ulong, XferDownLoad> Transfers = new Dictionary<ulong, XferDownLoad>();
  45. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  46. public struct XferRequest
  47. {
  48. public IClientAPI remoteClient;
  49. public ulong xferID;
  50. public string fileName;
  51. public DateTime timeStamp;
  52. }
  53. private class FileData
  54. {
  55. public byte[] Data;
  56. public int Count;
  57. }
  58. #region INonSharedRegionModule Members
  59. public void Initialise(IConfigSource config)
  60. {
  61. }
  62. public void AddRegion(Scene scene)
  63. {
  64. m_scene = scene;
  65. m_scene.EventManager.OnNewClient += NewClient;
  66. m_scene.RegisterModuleInterface<IXfer>(this);
  67. }
  68. public void RemoveRegion(Scene scene)
  69. {
  70. m_scene.EventManager.OnNewClient -= NewClient;
  71. m_scene.UnregisterModuleInterface<IXfer>(this);
  72. m_scene = null;
  73. }
  74. public void RegionLoaded(Scene scene)
  75. {
  76. }
  77. public Type ReplaceableInterface
  78. {
  79. get { return null; }
  80. }
  81. public void Close()
  82. {
  83. }
  84. public string Name
  85. {
  86. get { return "XferModule"; }
  87. }
  88. #endregion
  89. #region IXfer Members
  90. /// <summary>
  91. /// Let the Xfer module know about a file that the client is about to request.
  92. /// Caller is responsible for making sure that the file is here before
  93. /// the client starts the XferRequest.
  94. /// </summary>
  95. /// <param name="fileName"></param>
  96. /// <param name="data"></param>
  97. /// <returns></returns>
  98. public bool AddNewFile(string fileName, byte[] data)
  99. {
  100. lock (NewFiles)
  101. {
  102. if (NewFiles.ContainsKey(fileName))
  103. {
  104. NewFiles[fileName].Count++;
  105. NewFiles[fileName].Data = data;
  106. }
  107. else
  108. {
  109. FileData fd = new FileData();
  110. fd.Count = 1;
  111. fd.Data = data;
  112. NewFiles.Add(fileName, fd);
  113. }
  114. }
  115. return true;
  116. }
  117. #endregion
  118. public void NewClient(IClientAPI client)
  119. {
  120. client.OnRequestXfer += RequestXfer;
  121. client.OnConfirmXfer += AckPacket;
  122. client.OnAbortXfer += AbortXfer;
  123. }
  124. /// <summary>
  125. ///
  126. /// </summary>
  127. /// <param name="remoteClient"></param>
  128. /// <param name="xferID"></param>
  129. /// <param name="fileName"></param>
  130. public void RequestXfer(IClientAPI remoteClient, ulong xferID, string fileName)
  131. {
  132. lock (NewFiles)
  133. {
  134. if (NewFiles.ContainsKey(fileName))
  135. {
  136. if (!Transfers.ContainsKey(xferID))
  137. {
  138. byte[] fileData = NewFiles[fileName].Data;
  139. XferDownLoad transaction = new XferDownLoad(fileName, fileData, xferID, remoteClient);
  140. Transfers.Add(xferID, transaction);
  141. if (transaction.StartSend())
  142. RemoveXferData(xferID);
  143. // The transaction for this file is either complete or on its way
  144. RemoveOrDecrement(fileName);
  145. }
  146. }
  147. else
  148. m_log.WarnFormat("[Xfer]: {0} not found", fileName);
  149. }
  150. }
  151. public void AckPacket(IClientAPI remoteClient, ulong xferID, uint packet)
  152. {
  153. lock (NewFiles) // This is actually to lock Transfers
  154. {
  155. if (Transfers.ContainsKey(xferID))
  156. {
  157. XferDownLoad dl = Transfers[xferID];
  158. if (Transfers[xferID].AckPacket(packet))
  159. {
  160. RemoveXferData(xferID);
  161. RemoveOrDecrement(dl.FileName);
  162. }
  163. }
  164. }
  165. }
  166. private void RemoveXferData(ulong xferID)
  167. {
  168. // NewFiles must be locked!
  169. if (Transfers.ContainsKey(xferID))
  170. {
  171. XferModule.XferDownLoad xferItem = Transfers[xferID];
  172. //string filename = xferItem.FileName;
  173. Transfers.Remove(xferID);
  174. xferItem.Data = new byte[0]; // Clear the data
  175. xferItem.DataPointer = 0;
  176. }
  177. }
  178. public void AbortXfer(IClientAPI remoteClient, ulong xferID)
  179. {
  180. lock (NewFiles)
  181. {
  182. if (Transfers.ContainsKey(xferID))
  183. RemoveOrDecrement(Transfers[xferID].FileName);
  184. RemoveXferData(xferID);
  185. }
  186. }
  187. private void RemoveOrDecrement(string fileName)
  188. {
  189. // NewFiles must be locked
  190. if (NewFiles.ContainsKey(fileName))
  191. {
  192. if (NewFiles[fileName].Count == 1)
  193. NewFiles.Remove(fileName);
  194. else
  195. NewFiles[fileName].Count--;
  196. }
  197. }
  198. #region Nested type: XferDownLoad
  199. public class XferDownLoad
  200. {
  201. public IClientAPI Client;
  202. private bool complete;
  203. public byte[] Data = new byte[0];
  204. public int DataPointer = 0;
  205. public string FileName = String.Empty;
  206. public uint Packet = 0;
  207. public uint Serial = 1;
  208. public ulong XferID = 0;
  209. public XferDownLoad(string fileName, byte[] data, ulong xferID, IClientAPI client)
  210. {
  211. FileName = fileName;
  212. Data = data;
  213. XferID = xferID;
  214. Client = client;
  215. }
  216. public XferDownLoad()
  217. {
  218. }
  219. /// <summary>
  220. /// Start a transfer
  221. /// </summary>
  222. /// <returns>True if the transfer is complete, false if not</returns>
  223. public bool StartSend()
  224. {
  225. if (Data.Length < 1000)
  226. {
  227. // for now (testing) we only support files under 1000 bytes
  228. byte[] transferData = new byte[Data.Length + 4];
  229. Array.Copy(Utils.IntToBytes(Data.Length), 0, transferData, 0, 4);
  230. Array.Copy(Data, 0, transferData, 4, Data.Length);
  231. Client.SendXferPacket(XferID, 0 + 0x80000000, transferData);
  232. complete = true;
  233. }
  234. else
  235. {
  236. byte[] transferData = new byte[1000 + 4];
  237. Array.Copy(Utils.IntToBytes(Data.Length), 0, transferData, 0, 4);
  238. Array.Copy(Data, 0, transferData, 4, 1000);
  239. Client.SendXferPacket(XferID, 0, transferData);
  240. Packet++;
  241. DataPointer = 1000;
  242. }
  243. return complete;
  244. }
  245. /// <summary>
  246. /// Respond to an ack packet from the client
  247. /// </summary>
  248. /// <param name="packet"></param>
  249. /// <returns>True if the transfer is complete, false otherwise</returns>
  250. public bool AckPacket(uint packet)
  251. {
  252. if (!complete)
  253. {
  254. if ((Data.Length - DataPointer) > 1000)
  255. {
  256. byte[] transferData = new byte[1000];
  257. Array.Copy(Data, DataPointer, transferData, 0, 1000);
  258. Client.SendXferPacket(XferID, Packet, transferData);
  259. Packet++;
  260. DataPointer += 1000;
  261. }
  262. else
  263. {
  264. byte[] transferData = new byte[Data.Length - DataPointer];
  265. Array.Copy(Data, DataPointer, transferData, 0, Data.Length - DataPointer);
  266. uint endPacket = Packet |= (uint) 0x80000000;
  267. Client.SendXferPacket(XferID, endPacket, transferData);
  268. Packet++;
  269. DataPointer += (Data.Length - DataPointer);
  270. complete = true;
  271. }
  272. }
  273. return complete;
  274. }
  275. }
  276. #endregion
  277. }
  278. }