/Aurora/Modules/Scripting/XMLRPC/XMLRPCModule.cs

https://bitbucket.org/VirtualReality/software-testing · C# · 793 lines · 584 code · 99 blank · 110 comment · 62 complexity · 70af6071e193f2996ad262000e2ecbd8 MD5 · raw file

  1. /*
  2. * Copyright (c) Contributors, http://aurora-sim.org/, 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 Aurora-Sim 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 Aurora.Framework;
  28. using Aurora.Framework.ConsoleFramework;
  29. using Aurora.Framework.Modules;
  30. using Aurora.Framework.SceneInfo;
  31. using Aurora.Framework.Servers;
  32. using Aurora.Framework.Servers.HttpServer;
  33. using Aurora.Framework.Servers.HttpServer.Interfaces;
  34. using Aurora.Framework.Utilities;
  35. using Nini.Config;
  36. using Nwc.XmlRpc;
  37. using OpenMetaverse;
  38. using System;
  39. using System.Collections;
  40. using System.Collections.Generic;
  41. using System.Linq;
  42. using System.Net;
  43. using System.Threading;
  44. /*****************************************************
  45. *
  46. * XMLRPCModule
  47. *
  48. * Module for accepting incoming communications from
  49. * external XMLRPC client and calling a remote data
  50. * procedure for a registered data channel/prim.
  51. *
  52. *
  53. * 1. On module load, open a listener port
  54. * 2. Attach an XMLRPC handler
  55. * 3. When a request is received:
  56. * 3.1 Parse into components: channel key, int, string
  57. * 3.2 Look up registered channel listeners
  58. * 3.3 Call the channel (prim) remote data method
  59. * 3.4 Capture the response (llRemoteDataReply)
  60. * 3.5 Return response to client caller
  61. * 3.6 If no response from llRemoteDataReply within
  62. * RemoteReplyScriptTimeout, generate script timeout fault
  63. *
  64. * Prims in script must:
  65. * 1. Open a remote data channel
  66. * 1.1 Generate a channel ID
  67. * 1.2 Register primid,channelid pair with module
  68. * 2. Implement the remote data procedure handler
  69. *
  70. * llOpenRemoteDataChannel
  71. * llRemoteDataReply
  72. * remote_data(integer type, key channel, key messageid, string sender, integer ival, string sval)
  73. * llCloseRemoteDataChannel
  74. *
  75. * **************************************************/
  76. namespace Aurora.Modules.Scripting
  77. {
  78. public class XMLRPCModule : INonSharedRegionModule, IXMLRPC
  79. {
  80. private readonly object XMLRPCListLock = new object();
  81. private int RemoteReplyScriptTimeout = 9000;
  82. private int RemoteReplyScriptWait = 300;
  83. private bool m_httpServerStarted;
  84. private string m_name = "XMLRPCModule";
  85. // <channel id, RPCChannelInfo>
  86. private Dictionary<UUID, RPCChannelInfo> m_openChannels;
  87. private Dictionary<UUID, SendRemoteDataRequest> m_pendingSRDResponses;
  88. private int m_remoteDataPort;
  89. private Dictionary<UUID, RPCRequestInfo> m_rpcPending;
  90. private Dictionary<UUID, RPCRequestInfo> m_rpcPendingResponses;
  91. private IScriptModule m_scriptModule;
  92. #region INonSharedRegionModule Members
  93. public void Initialise(IConfigSource config)
  94. {
  95. // We need to create these early because the scripts might be calling
  96. // But since this gets called for every region, we need to make sure they
  97. // get called only one time (or we lose any open channels)
  98. if (null == m_openChannels)
  99. {
  100. m_openChannels = new Dictionary<UUID, RPCChannelInfo>();
  101. m_rpcPending = new Dictionary<UUID, RPCRequestInfo>();
  102. m_rpcPendingResponses = new Dictionary<UUID, RPCRequestInfo>();
  103. m_pendingSRDResponses = new Dictionary<UUID, SendRemoteDataRequest>();
  104. if (config.Configs["XMLRPC"] != null)
  105. m_remoteDataPort = config.Configs["XMLRPC"].GetInt("XmlRpcPort", m_remoteDataPort);
  106. }
  107. }
  108. public void AddRegion(IScene scene)
  109. {
  110. scene.RegisterModuleInterface<IXMLRPC>(this);
  111. }
  112. public void RemoveRegion(IScene scene)
  113. {
  114. scene.UnregisterModuleInterface<IXMLRPC>(this);
  115. }
  116. public void RegionLoaded(IScene scene)
  117. {
  118. if (IsEnabled() && !m_httpServerStarted)
  119. {
  120. m_httpServerStarted = true;
  121. // Start http server
  122. // Attach xmlrpc handlers
  123. MainConsole.Instance.Info("[XMLRPC MODULE]: " +
  124. "Starting up XMLRPC Server on port " + m_remoteDataPort +
  125. " for llRemoteData commands.");
  126. IHttpServer httpServer = new BaseHttpServer((uint) m_remoteDataPort, MainServer.Instance.HostName,
  127. false);
  128. httpServer.AddXmlRPCHandler("llRemoteData", XmlRpcRemoteData);
  129. httpServer.Start();
  130. }
  131. m_scriptModule = scene.RequestModuleInterface<IScriptModule>();
  132. }
  133. public Type ReplaceableInterface
  134. {
  135. get { return null; }
  136. }
  137. public void Close()
  138. {
  139. }
  140. public string Name
  141. {
  142. get { return m_name; }
  143. }
  144. #endregion
  145. #region IXMLRPC Members
  146. public int Port
  147. {
  148. get { return m_remoteDataPort; }
  149. }
  150. public bool IsEnabled()
  151. {
  152. return (m_remoteDataPort > 0);
  153. }
  154. /**********************************************
  155. * OpenXMLRPCChannel
  156. *
  157. * Generate a UUID channel key and add it and
  158. * the prim id to dictionary <channelUUID, primUUID>
  159. *
  160. * A custom channel key can be proposed.
  161. * Otherwise, passing UUID.Zero will generate
  162. * and return a random channel
  163. *
  164. * First check if there is a channel assigned for
  165. * this itemID. If there is, then someone called
  166. * llOpenRemoteDataChannel twice. Just return the
  167. * original channel. Other option is to delete the
  168. * current channel and assign a new one.
  169. *
  170. * ********************************************/
  171. public UUID OpenXMLRPCChannel(UUID primID, UUID itemID, UUID channelID)
  172. {
  173. UUID newChannel = UUID.Zero;
  174. // This should no longer happen, but the check is reasonable anyway
  175. if (null == m_openChannels)
  176. {
  177. MainConsole.Instance.Warn("[XML RPC MODULE]: Attempt to open channel before initialization is complete");
  178. return newChannel;
  179. }
  180. //Is a dupe?
  181. #if (!ISWIN)
  182. foreach (RPCChannelInfo ci in m_openChannels.Values)
  183. {
  184. if (ci.GetItemID().Equals(itemID))
  185. {
  186. // return the original channel ID for this item
  187. newChannel = ci.GetChannelID();
  188. break;
  189. }
  190. }
  191. #else
  192. foreach (RPCChannelInfo ci in m_openChannels.Values.Where(ci => ci.GetItemID().Equals(itemID)))
  193. {
  194. // return the original channel ID for this item
  195. newChannel = ci.GetChannelID();
  196. break;
  197. }
  198. #endif
  199. if (newChannel == UUID.Zero)
  200. {
  201. newChannel = (channelID == UUID.Zero) ? UUID.Random() : channelID;
  202. RPCChannelInfo rpcChanInfo = new RPCChannelInfo(primID, itemID, newChannel);
  203. lock (XMLRPCListLock)
  204. {
  205. m_openChannels.Add(newChannel, rpcChanInfo);
  206. }
  207. }
  208. //Make sure that the cmd handler thread is running
  209. m_scriptModule.PokeThreads(itemID);
  210. return newChannel;
  211. }
  212. // Delete channels based on itemID
  213. // for when a script is deleted
  214. public void DeleteChannels(UUID itemID)
  215. {
  216. if (m_openChannels != null)
  217. {
  218. ArrayList tmp = new ArrayList();
  219. lock (XMLRPCListLock)
  220. {
  221. #if (!ISWIN)
  222. foreach (RPCChannelInfo li in m_openChannels.Values)
  223. {
  224. if (li.GetItemID().Equals(itemID))
  225. {
  226. tmp.Add(itemID);
  227. }
  228. }
  229. #else
  230. foreach (RPCChannelInfo li in m_openChannels.Values.Where(li => li.GetItemID().Equals(itemID)))
  231. {
  232. tmp.Add(itemID);
  233. }
  234. #endif
  235. IEnumerator tmpEnumerator = tmp.GetEnumerator();
  236. while (tmpEnumerator.MoveNext())
  237. m_openChannels.Remove((UUID) tmpEnumerator.Current);
  238. }
  239. }
  240. //Make sure that the cmd handler thread is running
  241. m_scriptModule.PokeThreads(itemID);
  242. }
  243. /**********************************************
  244. * Remote Data Reply
  245. *
  246. * Response to RPC message
  247. *
  248. *********************************************/
  249. public void RemoteDataReply(string channel, string message_id, string sdata, int idata)
  250. {
  251. UUID message_key = new UUID(message_id);
  252. UUID channel_key = new UUID(channel);
  253. RPCRequestInfo rpcInfo = null;
  254. if (message_key == UUID.Zero)
  255. {
  256. #if (!ISWIN)
  257. foreach (RPCRequestInfo oneRpcInfo in m_rpcPendingResponses.Values)
  258. {
  259. if (oneRpcInfo.GetChannelKey() == channel_key) rpcInfo = oneRpcInfo;
  260. }
  261. #else
  262. foreach (
  263. RPCRequestInfo oneRpcInfo in
  264. m_rpcPendingResponses.Values.Where(oneRpcInfo => oneRpcInfo.GetChannelKey() == channel_key))
  265. rpcInfo = oneRpcInfo;
  266. #endif
  267. }
  268. else
  269. {
  270. m_rpcPendingResponses.TryGetValue(message_key, out rpcInfo);
  271. }
  272. if (rpcInfo != null)
  273. {
  274. rpcInfo.SetStrRetval(sdata);
  275. rpcInfo.SetIntRetval(idata);
  276. rpcInfo.SetProcessed(true);
  277. m_rpcPendingResponses.Remove(message_key);
  278. //Make sure that the cmd handler thread is running
  279. m_scriptModule.PokeThreads(rpcInfo.GetItemID());
  280. }
  281. else
  282. {
  283. MainConsole.Instance.Warn("[XML RPC MODULE]: Channel or message_id not found");
  284. }
  285. }
  286. /**********************************************
  287. * CloseXMLRPCChannel
  288. *
  289. * Remove channel from dictionary
  290. *
  291. *********************************************/
  292. public void CloseXMLRPCChannel(UUID channelKey)
  293. {
  294. if (m_openChannels.ContainsKey(channelKey))
  295. m_openChannels.Remove(channelKey);
  296. }
  297. public bool hasRequests()
  298. {
  299. lock (XMLRPCListLock)
  300. {
  301. if (m_rpcPending != null)
  302. if (m_rpcPending.Count > 0)
  303. return true;
  304. if (m_pendingSRDResponses != null)
  305. if (m_pendingSRDResponses.Count > 0)
  306. return true;
  307. return false;
  308. }
  309. }
  310. public IXmlRpcRequestInfo GetNextCompletedRequest()
  311. {
  312. if (m_rpcPending != null)
  313. {
  314. if (m_rpcPending.Count == 0)
  315. return null;
  316. lock (XMLRPCListLock)
  317. {
  318. #if (!ISWIN)
  319. foreach (RPCRequestInfo luid in m_rpcPending.Values)
  320. {
  321. if (!luid.IsProcessed())
  322. {
  323. return luid;
  324. }
  325. }
  326. #else
  327. foreach (RPCRequestInfo luid in m_rpcPending.Values.Where(luid => !luid.IsProcessed()))
  328. {
  329. return luid;
  330. }
  331. #endif
  332. }
  333. }
  334. return null;
  335. }
  336. public void RemoveCompletedRequest(UUID id)
  337. {
  338. lock (XMLRPCListLock)
  339. {
  340. RPCRequestInfo tmp;
  341. if (m_rpcPending.TryGetValue(id, out tmp))
  342. {
  343. m_rpcPending.Remove(id);
  344. m_rpcPendingResponses.Add(id, tmp);
  345. }
  346. else
  347. {
  348. MainConsole.Instance.Error("[XML RPC MODULE]: UNABLE TO REMOVE COMPLETED REQUEST");
  349. }
  350. }
  351. }
  352. public UUID SendRemoteData(UUID primID, UUID itemID, string channel, string dest, int idata, string sdata)
  353. {
  354. SendRemoteDataRequest req = new SendRemoteDataRequest(
  355. primID, itemID, channel, dest, idata, sdata
  356. );
  357. m_pendingSRDResponses.Add(req.GetReqID(), req);
  358. req.Process();
  359. //Make sure that the cmd handler thread is running
  360. m_scriptModule.PokeThreads(itemID);
  361. return req.ReqID;
  362. }
  363. public IServiceRequest GetNextCompletedSRDRequest()
  364. {
  365. if (m_pendingSRDResponses != null)
  366. {
  367. if (m_pendingSRDResponses.Count == 0)
  368. return null;
  369. lock (XMLRPCListLock)
  370. {
  371. #if (!ISWIN)
  372. foreach (SendRemoteDataRequest luid in m_pendingSRDResponses.Values)
  373. {
  374. if (luid.Finished)
  375. {
  376. return luid;
  377. }
  378. }
  379. #else
  380. foreach (SendRemoteDataRequest luid in m_pendingSRDResponses.Values.Where(luid => luid.Finished))
  381. {
  382. return luid;
  383. }
  384. #endif
  385. }
  386. }
  387. return null;
  388. }
  389. public void RemoveCompletedSRDRequest(UUID id)
  390. {
  391. lock (XMLRPCListLock)
  392. {
  393. SendRemoteDataRequest tmpReq;
  394. if (m_pendingSRDResponses.TryGetValue(id, out tmpReq))
  395. {
  396. m_pendingSRDResponses.Remove(id);
  397. }
  398. }
  399. }
  400. public void CancelSRDRequests(UUID itemID)
  401. {
  402. if (m_pendingSRDResponses != null)
  403. {
  404. lock (XMLRPCListLock)
  405. {
  406. #if (!ISWIN)
  407. foreach (SendRemoteDataRequest li in m_pendingSRDResponses.Values)
  408. {
  409. if (li.ItemID.Equals(itemID))
  410. {
  411. m_pendingSRDResponses.Remove(li.GetReqID());
  412. }
  413. }
  414. #else
  415. foreach (
  416. SendRemoteDataRequest li in m_pendingSRDResponses.Values.Where(li => li.ItemID.Equals(itemID)))
  417. {
  418. m_pendingSRDResponses.Remove(li.GetReqID());
  419. }
  420. #endif
  421. }
  422. }
  423. }
  424. #endregion
  425. public XmlRpcResponse XmlRpcRemoteData(XmlRpcRequest request, IPEndPoint remoteClient)
  426. {
  427. XmlRpcResponse response = new XmlRpcResponse();
  428. Hashtable requestData = (Hashtable) request.Params[0];
  429. bool GoodXML = (requestData.Contains("Channel") && requestData.Contains("IntValue") &&
  430. requestData.Contains("StringValue"));
  431. if (GoodXML)
  432. {
  433. UUID channel = new UUID((string) requestData["Channel"]);
  434. RPCChannelInfo rpcChanInfo;
  435. if (m_openChannels.TryGetValue(channel, out rpcChanInfo))
  436. {
  437. string intVal = Convert.ToInt32(requestData["IntValue"]).ToString();
  438. string strVal = (string) requestData["StringValue"];
  439. RPCRequestInfo rpcInfo;
  440. lock (XMLRPCListLock)
  441. {
  442. rpcInfo =
  443. new RPCRequestInfo(rpcChanInfo.GetPrimID(), rpcChanInfo.GetItemID(), channel, strVal,
  444. intVal);
  445. m_rpcPending.Add(rpcInfo.GetMessageID(), rpcInfo);
  446. }
  447. int timeoutCtr = 0;
  448. while (!rpcInfo.IsProcessed() && (timeoutCtr < RemoteReplyScriptTimeout))
  449. {
  450. Thread.Sleep(RemoteReplyScriptWait);
  451. timeoutCtr += RemoteReplyScriptWait;
  452. }
  453. if (rpcInfo.IsProcessed())
  454. {
  455. Hashtable param = new Hashtable();
  456. param["StringValue"] = rpcInfo.GetStrRetval();
  457. param["IntValue"] = rpcInfo.GetIntRetval();
  458. ArrayList parameters = new ArrayList {param};
  459. response.Value = parameters;
  460. rpcInfo = null;
  461. }
  462. else
  463. {
  464. response.SetFault(-1, "Script timeout");
  465. rpcInfo = null;
  466. }
  467. }
  468. else
  469. {
  470. response.SetFault(-1, "Invalid channel");
  471. }
  472. }
  473. //Make sure that the cmd handler thread is running
  474. m_scriptModule.PokeThreads(UUID.Zero);
  475. return response;
  476. }
  477. }
  478. public class RPCRequestInfo : IXmlRpcRequestInfo
  479. {
  480. private readonly UUID m_ChannelKey;
  481. private readonly string m_IntVal;
  482. private readonly UUID m_ItemID;
  483. private readonly UUID m_MessageID;
  484. private readonly UUID m_PrimID;
  485. private readonly string m_StrVal;
  486. private bool m_processed;
  487. private int m_respInt;
  488. private string m_respStr;
  489. public RPCRequestInfo(UUID primID, UUID itemID, UUID channelKey, string strVal, string intVal)
  490. {
  491. m_PrimID = primID;
  492. m_StrVal = strVal;
  493. m_IntVal = intVal;
  494. m_ItemID = itemID;
  495. m_ChannelKey = channelKey;
  496. m_MessageID = UUID.Random();
  497. m_processed = false;
  498. m_respStr = String.Empty;
  499. m_respInt = 0;
  500. }
  501. #region IXmlRpcRequestInfo Members
  502. public bool IsProcessed()
  503. {
  504. return m_processed;
  505. }
  506. public UUID GetChannelKey()
  507. {
  508. return m_ChannelKey;
  509. }
  510. public void SetProcessed(bool processed)
  511. {
  512. m_processed = processed;
  513. }
  514. public void SetStrRetval(string resp)
  515. {
  516. m_respStr = resp;
  517. }
  518. public string GetStrRetval()
  519. {
  520. return m_respStr;
  521. }
  522. public void SetIntRetval(int resp)
  523. {
  524. m_respInt = resp;
  525. }
  526. public int GetIntRetval()
  527. {
  528. return m_respInt;
  529. }
  530. public UUID GetPrimID()
  531. {
  532. return m_PrimID;
  533. }
  534. public UUID GetItemID()
  535. {
  536. return m_ItemID;
  537. }
  538. public string GetStrVal()
  539. {
  540. return m_StrVal;
  541. }
  542. public int GetIntValue()
  543. {
  544. return int.Parse(m_IntVal);
  545. }
  546. public UUID GetMessageID()
  547. {
  548. return m_MessageID;
  549. }
  550. #endregion
  551. }
  552. public class RPCChannelInfo
  553. {
  554. private readonly UUID m_ChannelKey;
  555. private readonly UUID m_itemID;
  556. private readonly UUID m_primID;
  557. public RPCChannelInfo(UUID primID, UUID itemID, UUID channelID)
  558. {
  559. m_ChannelKey = channelID;
  560. m_primID = primID;
  561. m_itemID = itemID;
  562. }
  563. public UUID GetItemID()
  564. {
  565. return m_itemID;
  566. }
  567. public UUID GetChannelID()
  568. {
  569. return m_ChannelKey;
  570. }
  571. public UUID GetPrimID()
  572. {
  573. return m_primID;
  574. }
  575. }
  576. public class SendRemoteDataRequest : ISendRemoteDataRequest
  577. {
  578. public string Channel { get; set; }
  579. public string DestURL { get; set; }
  580. public int Idata { get; set; }
  581. public XmlRpcRequest Request { get; set; }
  582. public int ResponseIdata { get; set; }
  583. public string ResponseSdata { get; set; }
  584. public string Sdata { get; set; }
  585. private bool _finished;
  586. private Thread httpThread;
  587. public SendRemoteDataRequest(UUID primID, UUID itemID, string channel, string dest, int idata, string sdata)
  588. {
  589. this.Channel = channel;
  590. DestURL = dest;
  591. this.Idata = idata;
  592. this.Sdata = sdata;
  593. ItemID = itemID;
  594. PrimID = primID;
  595. ReqID = UUID.Random();
  596. }
  597. #region IServiceRequest Members
  598. public bool Finished
  599. {
  600. get { return _finished; }
  601. set { _finished = value; }
  602. }
  603. public UUID ItemID { get; set; }
  604. public UUID PrimID { get; set; }
  605. public UUID ReqID { get; set; }
  606. public void Process()
  607. {
  608. httpThread = new Thread(SendRequest)
  609. {Name = "HttpRequestThread", Priority = ThreadPriority.BelowNormal, IsBackground = true};
  610. _finished = false;
  611. httpThread.Start();
  612. }
  613. /*
  614. * TODO: More work on the response codes. Right now
  615. * returning 200 for success or 499 for exception
  616. */
  617. public void SendRequest()
  618. {
  619. Culture.SetCurrentCulture();
  620. Hashtable param = new Hashtable();
  621. // Check if channel is an UUID
  622. // if not, use as method name
  623. UUID parseUID;
  624. string mName = "llRemoteData";
  625. if (!string.IsNullOrEmpty(Channel))
  626. if (!UUID.TryParse(Channel, out parseUID))
  627. mName = Channel;
  628. else
  629. param["Channel"] = Channel;
  630. param["StringValue"] = Sdata;
  631. param["IntValue"] = Convert.ToString(Idata);
  632. ArrayList parameters = new ArrayList {param};
  633. XmlRpcRequest req = new XmlRpcRequest(mName, parameters);
  634. try
  635. {
  636. XmlRpcResponse resp = req.Send(DestURL, 30000);
  637. if (resp != null)
  638. {
  639. Hashtable respParms;
  640. if (resp.Value.GetType().Equals(typeof (Hashtable)))
  641. {
  642. respParms = (Hashtable) resp.Value;
  643. }
  644. else
  645. {
  646. ArrayList respData = (ArrayList) resp.Value;
  647. respParms = (Hashtable) respData[0];
  648. }
  649. if (respParms != null)
  650. {
  651. if (respParms.Contains("StringValue"))
  652. {
  653. Sdata = (string) respParms["StringValue"];
  654. }
  655. if (respParms.Contains("IntValue"))
  656. {
  657. Idata = Convert.ToInt32(respParms["IntValue"]);
  658. }
  659. if (respParms.Contains("faultString"))
  660. {
  661. Sdata = (string) respParms["faultString"];
  662. }
  663. if (respParms.Contains("faultCode"))
  664. {
  665. Idata = Convert.ToInt32(respParms["faultCode"]);
  666. }
  667. }
  668. }
  669. }
  670. catch (Exception we)
  671. {
  672. Sdata = we.Message;
  673. MainConsole.Instance.Warn("[SendRemoteDataRequest]: Request failed");
  674. MainConsole.Instance.Warn(we.StackTrace);
  675. }
  676. _finished = true;
  677. }
  678. public void Stop()
  679. {
  680. try
  681. {
  682. httpThread.Abort();
  683. }
  684. catch (Exception)
  685. {
  686. }
  687. }
  688. #endregion
  689. public UUID GetReqID()
  690. {
  691. return ReqID;
  692. }
  693. }
  694. }