1
0

LoadBalancerPlugin.cs 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099
  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. using System;
  28. using System.Collections;
  29. using System.Collections.Generic;
  30. using System.IO;
  31. using System.Net;
  32. using System.Reflection;
  33. using System.Threading;
  34. using libsecondlife;
  35. using libsecondlife.Packets;
  36. using log4net;
  37. using Mono.Addins;
  38. using Nwc.XmlRpc;
  39. using OpenSim.Framework;
  40. using OpenSim.Framework.Servers;
  41. using OpenSim.Region.ClientStack;
  42. using OpenSim.Region.ClientStack.LindenUDP;
  43. using OpenSim.Region.Environment.Scenes;
  44. // TODO: remove LindenUDP dependency
  45. [assembly : Addin]
  46. [assembly : AddinDependency("OpenSim", "0.5")]
  47. [assembly : AddinDependency("RegionProxy", "0.1")]
  48. namespace OpenSim.ApplicationPlugins.LoadBalancer
  49. {
  50. [Extension("/OpenSim/Startup")]
  51. public class LoadBalancerPlugin : IApplicationPlugin
  52. {
  53. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  54. private BaseHttpServer commandServer;
  55. private bool[] isLocalNeighbour;
  56. private bool isSplit;
  57. private TcpServer mTcpServer;
  58. private readonly object padlock = new object();
  59. private int proxyOffset;
  60. private string proxyURL;
  61. private List<RegionInfo> regionData;
  62. private int[] regionPortList;
  63. private SceneManager sceneManager;
  64. private string[] sceneURL;
  65. private string serializeDir;
  66. private OpenSimBase simMain;
  67. private TcpClient[] tcpClientList;
  68. private List<IClientNetworkServer> m_clientServers;
  69. #region IApplicationPlugin Members
  70. // TODO: required by IPlugin, but likely not at all right
  71. string m_name = "LoadBalancerPlugin";
  72. string m_version = "0.0";
  73. public string Version { get { return m_version; } }
  74. public string Name { get { return m_name; } }
  75. public void Initialise()
  76. {
  77. m_log.Info("[BALANCER]: " + Name + " cannot be default-initialized!");
  78. throw new PluginNotInitialisedException (Name);
  79. }
  80. public void Initialise(OpenSimBase openSim)
  81. {
  82. m_log.Info("[BALANCER] " + "Entering Initialize()");
  83. proxyURL = openSim.ConfigSource.Source.Configs["Network"].GetString("proxy_url", "");
  84. if (proxyURL.Length == 0) return;
  85. StartTcpServer();
  86. LLClientView.SynchronizeClient = SynchronizePackets;
  87. AsynchronousSocketListener.PacketHandler = SynchronizePacketRecieve;
  88. sceneManager = openSim.SceneManager;
  89. m_clientServers = openSim.ClientServers;
  90. regionData = openSim.RegionData;
  91. simMain = openSim;
  92. commandServer = openSim.HttpServer;
  93. proxyOffset = Int32.Parse(openSim.ConfigSource.Source.Configs["Network"].GetString("proxy_offset", "0"));
  94. serializeDir = openSim.ConfigSource.Source.Configs["Network"].GetString("serialize_dir", "/tmp/");
  95. commandServer.AddXmlRPCHandler("SerializeRegion", SerializeRegion);
  96. commandServer.AddXmlRPCHandler("DeserializeRegion_Move", DeserializeRegion_Move);
  97. commandServer.AddXmlRPCHandler("DeserializeRegion_Clone", DeserializeRegion_Clone);
  98. commandServer.AddXmlRPCHandler("TerminateRegion", TerminateRegion);
  99. commandServer.AddXmlRPCHandler("SplitRegion", SplitRegion);
  100. commandServer.AddXmlRPCHandler("MergeRegions", MergeRegions);
  101. commandServer.AddXmlRPCHandler("UpdatePhysics", UpdatePhysics);
  102. commandServer.AddXmlRPCHandler("GetStatus", GetStatus);
  103. m_log.Info("[BALANCER] " + "Exiting Initialize()");
  104. }
  105. public void Dispose()
  106. {
  107. }
  108. #endregion
  109. private void StartTcpServer()
  110. {
  111. Thread server_thread = new Thread(new ThreadStart(
  112. delegate
  113. {
  114. mTcpServer = new TcpServer(10001);
  115. mTcpServer.start();
  116. }));
  117. server_thread.Start();
  118. }
  119. private XmlRpcResponse GetStatus(XmlRpcRequest request)
  120. {
  121. XmlRpcResponse response = new XmlRpcResponse();
  122. try
  123. {
  124. m_log.Info("[BALANCER] " + "Entering RegionStatus()");
  125. int src_port = (int) request.Params[0];
  126. Scene scene;
  127. // try to get the scene object
  128. RegionInfo src_region = SearchRegionFromPortNum(src_port);
  129. if (sceneManager.TryGetScene(src_region.RegionID, out scene) == false)
  130. {
  131. m_log.Error("[BALANCER] " + "The Scene is not found");
  132. return response;
  133. }
  134. // serialization of client's informations
  135. List<ScenePresence> presences = scene.GetScenePresences();
  136. int get_scene_presence = presences.Count;
  137. int get_scene_presence_filter = 0;
  138. foreach (ScenePresence pre in presences)
  139. {
  140. IClientAPI client = pre.ControllingClient;
  141. //if (pre.MovementFlag!=0 && client.PacketProcessingEnabled==true)
  142. if (client.IsActive)
  143. {
  144. get_scene_presence_filter++;
  145. }
  146. }
  147. List<ScenePresence> avatars = scene.GetAvatars();
  148. int get_avatar = avatars.Count;
  149. int get_avatar_filter = 0;
  150. string avatar_names = "";
  151. foreach (ScenePresence pre in avatars)
  152. {
  153. IClientAPI client = pre.ControllingClient;
  154. //if (pre.MovementFlag!=0 && client.PacketProcessingEnabled==true)
  155. if (client.IsActive)
  156. {
  157. get_avatar_filter++;
  158. avatar_names += pre.Firstname + " " + pre.Lastname + "; ";
  159. }
  160. }
  161. Hashtable responseData = new Hashtable();
  162. responseData["get_scene_presence_filter"] = get_scene_presence_filter;
  163. responseData["get_scene_presence"] = get_scene_presence;
  164. responseData["get_avatar_filter"] = get_avatar_filter;
  165. responseData["get_avatar"] = get_avatar;
  166. responseData["avatar_names"] = avatar_names;
  167. response.Value = responseData;
  168. m_log.Info("[BALANCER] " + "Exiting RegionStatus()");
  169. }
  170. catch (Exception e)
  171. {
  172. m_log.Error("[BALANCER] " + e);
  173. m_log.Error("[BALANCER] " + e.StackTrace);
  174. }
  175. return response;
  176. }
  177. private XmlRpcResponse SerializeRegion(XmlRpcRequest request)
  178. {
  179. try
  180. {
  181. m_log.Info("[BALANCER] " + "Entering SerializeRegion()");
  182. string src_url = (string) request.Params[0];
  183. int src_port = (int) request.Params[1];
  184. SerializeRegion(src_url, src_port);
  185. m_log.Info("[BALANCER] " + "Exiting SerializeRegion()");
  186. }
  187. catch (Exception e)
  188. {
  189. m_log.Error("[BALANCER] " + e);
  190. m_log.Error("[BALANCER] " + e.StackTrace);
  191. }
  192. return new XmlRpcResponse();
  193. }
  194. private XmlRpcResponse DeserializeRegion_Move(XmlRpcRequest request)
  195. {
  196. try
  197. {
  198. m_log.Info("[BALANCER] " + "Entering DeserializeRegion_Move()");
  199. string src_url = (string) request.Params[0];
  200. int src_port = (int) request.Params[1];
  201. string dst_url = (string) request.Params[2];
  202. int dst_port = (int) request.Params[3];
  203. DeserializeRegion_Move(src_port, dst_port, src_url, dst_url);
  204. m_log.Info("[BALANCER] " + "Exiting DeserializeRegion_Move()");
  205. }
  206. catch (Exception e)
  207. {
  208. m_log.Error("[BALANCER] " + e);
  209. m_log.Error("[BALANCER] " + e.StackTrace);
  210. }
  211. return new XmlRpcResponse();
  212. }
  213. private XmlRpcResponse DeserializeRegion_Clone(XmlRpcRequest request)
  214. {
  215. try
  216. {
  217. m_log.Info("[BALANCER] " + "Entering DeserializeRegion_Clone()");
  218. string src_url = (string) request.Params[0];
  219. int src_port = (int) request.Params[1];
  220. string dst_url = (string) request.Params[2];
  221. int dst_port = (int) request.Params[3];
  222. DeserializeRegion_Clone(src_port, dst_port, src_url, dst_url);
  223. m_log.Info("[BALANCER] " + "Exiting DeserializeRegion_Clone()");
  224. }
  225. catch (Exception e)
  226. {
  227. m_log.Error("[BALANCER] " + e);
  228. m_log.Error("[BALANCER] " + e.StackTrace);
  229. throw;
  230. }
  231. return new XmlRpcResponse();
  232. }
  233. private XmlRpcResponse TerminateRegion(XmlRpcRequest request)
  234. {
  235. try
  236. {
  237. m_log.Info("[BALANCER] " + "Entering TerminateRegion()");
  238. int src_port = (int) request.Params[0];
  239. // backgroud
  240. WaitCallback callback = TerminateRegion;
  241. ThreadPool.QueueUserWorkItem(callback, src_port);
  242. m_log.Info("[BALANCER] " + "Exiting TerminateRegion()");
  243. }
  244. catch (Exception e)
  245. {
  246. m_log.Error("[BALANCER] " + e);
  247. m_log.Error("[BALANCER] " + e.StackTrace);
  248. }
  249. return new XmlRpcResponse();
  250. }
  251. // internal functions
  252. private void SerializeRegion(string src_url, int src_port)
  253. {
  254. //------------------------------------------
  255. // Processing of origin region
  256. //------------------------------------------
  257. // search origin region
  258. RegionInfo src_region = SearchRegionFromPortNum(src_port);
  259. if (src_region == null)
  260. {
  261. m_log.Error("[BALANCER] " + "Region not found");
  262. return;
  263. }
  264. Util.XmlRpcCommand(src_region.proxyUrl, "BlockClientMessages", src_url, src_port + proxyOffset);
  265. // serialization of origin region's data
  266. SerializeRegion(src_region, serializeDir);
  267. }
  268. private void DeserializeRegion_Move(int src_port, int dst_port, string src_url, string dst_url)
  269. {
  270. //------------------------------------------
  271. // Processing of destination region
  272. //------------------------------------------
  273. // import the source region's data
  274. RegionInfo dst_region = DeserializeRegion(dst_port, serializeDir);
  275. Util.XmlRpcCommand(dst_region.proxyUrl, "ChangeRegion", src_port + proxyOffset, src_url, dst_port + proxyOffset, dst_url);
  276. Util.XmlRpcCommand(dst_region.proxyUrl, "UnblockClientMessages", dst_url, dst_port + proxyOffset);
  277. }
  278. private void DeserializeRegion_Clone(int src_port, int dst_port, string src_url, string dst_url)
  279. {
  280. //------------------------------------------
  281. // Processing of destination region
  282. //------------------------------------------
  283. // import the source region's data
  284. RegionInfo dst_region = DeserializeRegion(dst_port, serializeDir);
  285. // Decide who is in charge for each section
  286. int[] port = new int[] {src_port, dst_port};
  287. string[] url = new string[] {"http://" + src_url + ":" + commandServer.Port, "http://" + dst_url + ":" + commandServer.Port};
  288. for (int i = 0; i < 2; i++) Util.XmlRpcCommand(url[i], "SplitRegion", i, 2, port[0], port[1], url[0], url[1]);
  289. // Enable the proxy
  290. Util.XmlRpcCommand(dst_region.proxyUrl, "AddRegion", src_port + proxyOffset, src_url, dst_port + proxyOffset, dst_url);
  291. Util.XmlRpcCommand(dst_region.proxyUrl, "UnblockClientMessages", dst_url, dst_port + proxyOffset);
  292. }
  293. private void TerminateRegion(object param)
  294. {
  295. int src_port = (int) param;
  296. //------------------------------------------
  297. // Processing of remove region
  298. //------------------------------------------
  299. // search origin region
  300. RegionInfo src_region = SearchRegionFromPortNum(src_port);
  301. if (src_region == null)
  302. {
  303. m_log.Error("[BALANCER] " + "Region not found");
  304. return;
  305. }
  306. isSplit = false;
  307. // remove client resources
  308. RemoveAllClientResource(src_region);
  309. // remove old region
  310. RemoveRegion(src_region.RegionID, src_region.InternalEndPoint.Port);
  311. m_log.Info("[BALANCER] " + "Region terminated");
  312. }
  313. private RegionInfo SearchRegionFromPortNum(int portnum)
  314. {
  315. RegionInfo result = null;
  316. foreach (RegionInfo rinfo in regionData)
  317. {
  318. if (rinfo.InternalEndPoint.Port == portnum)
  319. {
  320. // m_log.Info("BALANCER",
  321. // "Region found. Internal Port = {0}, Handle={1}",
  322. // rinfo.InternalEndPoint.Port, rinfo.RegionHandle);
  323. result = rinfo;
  324. break;
  325. }
  326. }
  327. return result;
  328. }
  329. private IClientNetworkServer SearchClientServerFromPortNum(int portnum)
  330. {
  331. return m_clientServers.Find(
  332. delegate(IClientNetworkServer server)
  333. {
  334. // ReSharper disable PossibleNullReferenceException
  335. return (portnum + proxyOffset == ((IPEndPoint) server.Server.LocalEndPoint).Port);
  336. // ReSharper restore PossibleNullReferenceException
  337. }
  338. );
  339. }
  340. private void SerializeRegion(RegionInfo src_region, string export_dir)
  341. {
  342. Scene scene;
  343. int i = 0;
  344. // try to get the scene object
  345. if (sceneManager.TryGetScene(src_region.RegionID, out scene) == false)
  346. {
  347. m_log.Error("[BALANCER] " + "The Scene is not found");
  348. return;
  349. }
  350. // create export directory
  351. DirectoryInfo dirinfo = new DirectoryInfo(export_dir);
  352. if (!dirinfo.Exists)
  353. {
  354. dirinfo.Create();
  355. }
  356. // serialization of client's informations
  357. List<ScenePresence> presences = scene.GetScenePresences();
  358. foreach (ScenePresence pre in presences)
  359. {
  360. SerializeClient(i, scene, pre, export_dir);
  361. i++;
  362. }
  363. // serialization of region data
  364. SerializableRegionInfo dst_region = new SerializableRegionInfo(src_region);
  365. string filename = export_dir + "RegionInfo_" + src_region.RegionID + ".bin";
  366. Util.SerializeToFile(filename, dst_region);
  367. // backup current scene's entities
  368. //scene.Backup();
  369. m_log.InfoFormat("[BALANCER] " + "region serialization completed [{0}]",
  370. src_region.RegionID.ToString());
  371. }
  372. private static void SerializeClient(int idx, IScene scene, EntityBase pre, string export_dir)
  373. {
  374. string filename;
  375. IClientAPI controller;
  376. m_log.InfoFormat("[BALANCER] " + "agent id : {0}", pre.UUID);
  377. uint[] circuits = scene.ClientManager.GetAllCircuits(pre.UUID);
  378. foreach (uint code in circuits)
  379. {
  380. m_log.InfoFormat("[BALANCER] " + "circuit code : {0}", code);
  381. if (scene.ClientManager.TryGetClient(code, out controller))
  382. {
  383. ClientInfo info = controller.GetClientInfo();
  384. filename = export_dir + "ClientInfo-" + String.Format("{0:0000}", idx) + "_" + controller.CircuitCode + ".bin";
  385. Util.SerializeToFile(filename, info);
  386. m_log.InfoFormat("[BALANCER] " + "client info serialized [filename={0}]", filename);
  387. }
  388. }
  389. //filename = export_dir + "Presence_" + controller.AgentId.ToString() + ".bin";
  390. filename = export_dir + "Presence_" + String.Format("{0:0000}", idx) + ".bin";
  391. Util.SerializeToFile(filename, pre);
  392. m_log.InfoFormat("[BALANCER] " + "scene presence serialized [filename={0}]", filename);
  393. }
  394. private RegionInfo DeserializeRegion(int dst_port, string import_dir)
  395. {
  396. RegionInfo dst_region = null;
  397. try
  398. {
  399. // deserialization of region data
  400. string[] files = Directory.GetFiles(import_dir, "RegionInfo_*.bin");
  401. foreach (string filename in files)
  402. {
  403. m_log.InfoFormat("[BALANCER] RegionInfo filename = [{0}]", filename);
  404. dst_region = new RegionInfo((SerializableRegionInfo) Util.DeserializeFromFile(filename));
  405. m_log.InfoFormat("[BALANCER] " + "RegionID = [{0}]", dst_region.RegionID.ToString());
  406. m_log.InfoFormat("[BALANCER] " + "RegionHandle = [{0}]", dst_region.RegionHandle);
  407. m_log.InfoFormat("[BALANCER] " + "ProxyUrl = [{0}]", dst_region.proxyUrl);
  408. m_log.InfoFormat("[BALANCER] " + "OriginRegionID = [{0}]", dst_region.originRegionID.ToString());
  409. CreateCloneRegion(dst_region, dst_port, true);
  410. File.Delete(filename);
  411. m_log.InfoFormat("[BALANCER] " + "region deserialized [{0}]", dst_region.RegionID);
  412. }
  413. if (dst_region != null)
  414. {
  415. // deserialization of client data
  416. DeserializeClient(dst_region, import_dir);
  417. m_log.InfoFormat("[BALANCER] " + "region deserialization completed [{0}]",
  418. dst_region.ToString());
  419. }
  420. }
  421. catch (Exception e)
  422. {
  423. m_log.Error("[BALANCER] " + e);
  424. m_log.Error("[BALANCER] " + e.StackTrace);
  425. throw;
  426. }
  427. return dst_region;
  428. }
  429. private void DeserializeClient(SimpleRegionInfo dst_region, string import_dir)
  430. {
  431. ScenePresence sp;
  432. ClientInfo data;
  433. Scene scene;
  434. IClientAPI controller;
  435. if (sceneManager.TryGetScene(dst_region.RegionID, out scene))
  436. {
  437. IClientNetworkServer clientserv = SearchClientServerFromPortNum(scene.RegionInfo.InternalEndPoint.Port);
  438. // restore the scene presence
  439. for (int i = 0;; i++)
  440. {
  441. string filename = import_dir + "Presence_" + String.Format("{0:0000}", i) + ".bin";
  442. if (!File.Exists(filename))
  443. {
  444. break;
  445. }
  446. sp = (ScenePresence) Util.DeserializeFromFile(filename);
  447. Console.WriteLine("agent id = {0}", sp.UUID);
  448. scene.m_restorePresences.Add(sp.UUID, sp);
  449. File.Delete(filename);
  450. m_log.InfoFormat("[BALANCER] " + "scene presence deserialized [{0}]", sp.UUID);
  451. // restore the ClientView
  452. string[] files = Directory.GetFiles(import_dir, "ClientInfo-" + String.Format("{0:0000}", i) + "_*.bin");
  453. foreach (string fname in files)
  454. {
  455. int start = fname.IndexOf('_');
  456. int end = fname.LastIndexOf('.');
  457. uint circuit_code = uint.Parse(fname.Substring(start + 1, end - start - 1));
  458. m_log.InfoFormat("[BALANCER] " + "client circuit code = {0}", circuit_code);
  459. data = (ClientInfo) Util.DeserializeFromFile(fname);
  460. AgentCircuitData agentdata = new AgentCircuitData(data.agentcircuit);
  461. scene.AuthenticateHandler.AddNewCircuit(circuit_code, agentdata);
  462. // TODO: This needs to be abstracted and converted into IClientNetworkServer
  463. if (clientserv is LLUDPServer)
  464. {
  465. ((LLUDPServer) clientserv).RestoreClient(agentdata, data.userEP, data.proxyEP);
  466. }
  467. // waiting for the scene-presense restored
  468. lock (scene.m_restorePresences)
  469. {
  470. Monitor.Wait(scene.m_restorePresences, 3000);
  471. }
  472. if (scene.ClientManager.TryGetClient(circuit_code, out controller))
  473. {
  474. m_log.InfoFormat("[BALANCER] " + "get client [{0}]", circuit_code);
  475. controller.SetClientInfo(data);
  476. }
  477. File.Delete(fname);
  478. m_log.InfoFormat("[BALANCER] " + "client info deserialized [{0}]", circuit_code);
  479. }
  480. // backup new scene's entities
  481. //scene.Backup();
  482. }
  483. }
  484. }
  485. private void CreateCloneRegion(RegionInfo dst_region, int dst_port, bool createID_flag)
  486. {
  487. if (createID_flag)
  488. {
  489. dst_region.RegionID = LLUUID.Random();
  490. }
  491. // change RegionInfo (memory only)
  492. dst_region.InternalEndPoint.Port = dst_port;
  493. dst_region.ExternalHostName = proxyURL.Split(new char[] {'/', ':'})[3];
  494. // Create new region
  495. simMain.CreateRegion(dst_region, false);
  496. }
  497. private void RemoveRegion(LLUUID regionID, int port)
  498. {
  499. Scene killScene;
  500. if (sceneManager.TryGetScene(regionID, out killScene))
  501. {
  502. Console.WriteLine("scene found.");
  503. if ((sceneManager.CurrentScene != null)
  504. && (sceneManager.CurrentScene.RegionInfo.RegionID == killScene.RegionInfo.RegionID))
  505. {
  506. sceneManager.TrySetCurrentScene("..");
  507. }
  508. m_log.Info("Removing region : " + killScene.RegionInfo.RegionName);
  509. regionData.Remove(killScene.RegionInfo);
  510. sceneManager.CloseScene(killScene);
  511. }
  512. // Shutting down the UDP server
  513. IClientNetworkServer clientsvr = SearchClientServerFromPortNum(port);
  514. if (clientsvr != null)
  515. {
  516. clientsvr.Server.Close();
  517. m_clientServers.Remove(clientsvr);
  518. }
  519. }
  520. private void RemoveAllClientResource(SimpleRegionInfo src_region)
  521. {
  522. Scene scene;
  523. IClientAPI controller;
  524. // try to get the scene object
  525. if (sceneManager.TryGetScene(src_region.RegionID, out scene) == false)
  526. {
  527. m_log.Error("[BALANCER] " + "The Scene is not found");
  528. return;
  529. }
  530. // serialization of client's informations
  531. List<ScenePresence> presences = scene.GetScenePresences();
  532. // remove all scene presences
  533. foreach (ScenePresence pre in presences)
  534. {
  535. uint[] circuits = scene.ClientManager.GetAllCircuits(pre.UUID);
  536. foreach (uint code in circuits)
  537. {
  538. m_log.InfoFormat("[BALANCER] " + "circuit code : {0}", code);
  539. if (scene.ClientManager.TryGetClient(code, out controller))
  540. {
  541. // stopping clientview thread
  542. if ((controller).IsActive)
  543. {
  544. controller.Stop();
  545. (controller).IsActive = false;
  546. }
  547. // teminateing clientview thread
  548. controller.Terminate();
  549. m_log.Info("[BALANCER] " + "client thread stopped");
  550. }
  551. }
  552. // remove scene presence
  553. scene.RemoveClient(pre.UUID);
  554. }
  555. }
  556. /*
  557. * This section implements scene splitting and synchronization
  558. */
  559. private XmlRpcResponse SplitRegion(XmlRpcRequest request)
  560. {
  561. try
  562. {
  563. int myID = (int) request.Params[0];
  564. int numRegions = (int) request.Params[1];
  565. regionPortList = new int[numRegions];
  566. sceneURL = new string[numRegions];
  567. tcpClientList = new TcpClient[numRegions];
  568. for (int i = 0; i < numRegions; i++)
  569. {
  570. regionPortList[i] = (int) request.Params[i + 2];
  571. sceneURL[i] = (string) request.Params[i + 2 + numRegions];
  572. }
  573. for (int i = 0; i < numRegions; i++)
  574. {
  575. string hostname = sceneURL[i].Split(new char[] {'/', ':'})[3];
  576. m_log.InfoFormat("[SPLITSCENE] " + "creating tcp client host:{0}", hostname);
  577. tcpClientList[i] = new TcpClient(hostname, 10001);
  578. }
  579. bool isMaster = (myID == 0);
  580. isLocalNeighbour = new bool[numRegions];
  581. for (int i = 0; i < numRegions; i++) isLocalNeighbour[i] = (sceneURL[i] == sceneURL[myID]);
  582. RegionInfo region = SearchRegionFromPortNum(regionPortList[myID]);
  583. //Console.WriteLine("\n === SplitRegion {0}\n", region.RegionID);
  584. Scene scene;
  585. if (sceneManager.TryGetScene(region.RegionID, out scene))
  586. {
  587. // Disable event updates, backups etc in the slave(s)
  588. scene.Region_Status = isMaster ? RegionStatus.Up : RegionStatus.SlaveScene;
  589. //Console.WriteLine("=== SplitRegion {0}: Scene found, status {1}", region.RegionID, scene.Region_Status);
  590. // Disabling half of the avatars in master, and the other half in slave
  591. int i = 0;
  592. List<uint> circuits = scene.ClientManager.GetAllCircuitCodes();
  593. circuits.Sort();
  594. foreach (uint code in circuits)
  595. {
  596. m_log.InfoFormat("[BALANCER] " + "circuit code : {0}", code);
  597. IClientAPI controller;
  598. if (scene.ClientManager.TryGetClient(code, out controller))
  599. {
  600. // Divide the presences evenly over the set of subscenes
  601. LLClientView client = (LLClientView) controller;
  602. client.IsActive = (((i + myID) % sceneURL.Length) == 0);
  603. m_log.InfoFormat("[SPLITSCENE] === SplitRegion {0}: SP.PacketEnabled {1}", region.RegionID, client.IsActive);
  604. if (!client.IsActive)
  605. {
  606. // stopping clientview thread
  607. client.Stop();
  608. }
  609. ++i;
  610. }
  611. }
  612. scene.splitID = myID;
  613. scene.SynchronizeScene = SynchronizeScenes;
  614. isSplit = true;
  615. }
  616. else
  617. {
  618. m_log.Error("[SPLITSCENE] " + String.Format("Scene not found {0}", region.RegionID));
  619. }
  620. }
  621. catch (Exception e)
  622. {
  623. m_log.Error("[SPLITSCENE] " + e);
  624. m_log.Error("[SPLITSCENE] " + e.StackTrace);
  625. }
  626. return new XmlRpcResponse();
  627. }
  628. private XmlRpcResponse MergeRegions(XmlRpcRequest request)
  629. {
  630. // This should only be called for the master scene
  631. try
  632. {
  633. m_log.Info("[BALANCER] " + "Entering MergeRegions()");
  634. string src_url = (string) request.Params[0];
  635. int src_port = (int) request.Params[1];
  636. RegionInfo region = SearchRegionFromPortNum(src_port);
  637. Util.XmlRpcCommand(region.proxyUrl, "BlockClientMessages", src_url, src_port + proxyOffset);
  638. Scene scene;
  639. if (sceneManager.TryGetScene(region.RegionID, out scene))
  640. {
  641. isSplit = false;
  642. scene.SynchronizeScene = null;
  643. scene.Region_Status = RegionStatus.Up;
  644. List<ScenePresence> presences = scene.GetScenePresences();
  645. foreach (ScenePresence pre in presences)
  646. {
  647. LLClientView client = (LLClientView) pre.ControllingClient;
  648. if (!client.IsActive)
  649. {
  650. client.Restart();
  651. client.IsActive = true;
  652. }
  653. }
  654. }
  655. // Delete the slave scenes
  656. for (int i = 1; i < sceneURL.Length; i++)
  657. {
  658. string url = (sceneURL[i].Split('/')[2]).Split(':')[0]; // get URL part from EP
  659. Util.XmlRpcCommand(region.proxyUrl, "DeleteRegion", regionPortList[i] + proxyOffset, url);
  660. Thread.Sleep(1000);
  661. Util.XmlRpcCommand(sceneURL[i], "TerminateRegion", regionPortList[i]); // TODO: need + proxyOffset?
  662. }
  663. Util.XmlRpcCommand(region.proxyUrl, "UnblockClientMessages", src_url, src_port + proxyOffset);
  664. }
  665. catch (Exception e)
  666. {
  667. m_log.Error("[BALANCER] " + e);
  668. m_log.Error("[BALANCER] " + e.StackTrace);
  669. throw;
  670. }
  671. return new XmlRpcResponse();
  672. }
  673. private XmlRpcResponse UpdatePhysics(XmlRpcRequest request)
  674. {
  675. // this callback receives physic scene updates from the other sub-scenes (in split mode)
  676. int regionPort = (int) request.Params[0];
  677. LLUUID scenePresenceID = new LLUUID((byte[]) request.Params[1], 0);
  678. LLVector3 position = new LLVector3((byte[]) request.Params[2], 0);
  679. LLVector3 velocity = new LLVector3((byte[]) request.Params[3], 0);
  680. bool flying = (bool) request.Params[4];
  681. LocalUpdatePhysics(regionPort, scenePresenceID, position, velocity, flying);
  682. return new XmlRpcResponse();
  683. }
  684. private void LocalUpdatePhysics(int regionPort, LLUUID scenePresenceID, LLVector3 position, LLVector3 velocity, bool flying)
  685. {
  686. //m_log.Info("[SPLITSCENE] "+String.Format("UpdatePhysics called {0}", regionID));
  687. //m_log.Info("[SPLITSCENE] "+"LocalUpdatePhysics [region port:{0}, client:{1}, position:{2}, velocity:{3}, flying:{4}]",
  688. // regionPort, scenePresenceID.ToString(), position.ToString(),
  689. // velocity.ToString(), flying);
  690. RegionInfo region = SearchRegionFromPortNum(regionPort);
  691. // Find and update the scene precense
  692. Scene scene;
  693. if (sceneManager.TryGetScene(region.RegionID, out scene))
  694. {
  695. ScenePresence pre = scene.GetScenePresences().Find(delegate(ScenePresence x) { return x.UUID == scenePresenceID; });
  696. if (pre == null)
  697. {
  698. m_log.ErrorFormat("[SPLITSCENE] [LocalUpdatePhysics] ScenePresence is missing... ({0})", scenePresenceID.ToString());
  699. return;
  700. }
  701. // m_log.Info("[SPLITSCENE] "+"LocalUpdatePhysics [region:{0}, client:{1}]",
  702. // regionID.ToString(), pre.UUID.ToString());
  703. pre.AbsolutePosition = position; // will set PhysicsActor.Position
  704. pre.Velocity = velocity; // will set PhysicsActor.Velocity
  705. pre.PhysicsActor.Flying = flying;
  706. }
  707. }
  708. private void SynchronizeScenes(Scene scene)
  709. {
  710. if (!isSplit)
  711. {
  712. return;
  713. }
  714. lock (padlock)
  715. {
  716. // Callback activated after a physics scene update
  717. // int i = 0;
  718. List<ScenePresence> presences = scene.GetScenePresences();
  719. foreach (ScenePresence pre in presences)
  720. {
  721. LLClientView client = (LLClientView) pre.ControllingClient;
  722. // Because data changes by the physics simulation when the client doesn't move,
  723. // if MovementFlag is false, It is necessary to synchronize.
  724. //if (pre.MovementFlag!=0 && client.PacketProcessingEnabled==true)
  725. if (client.IsActive)
  726. {
  727. //m_log.Info("[SPLITSCENE] "+String.Format("Client moving in {0} {1}", scene.RegionInfo.RegionID, pre.AbsolutePosition));
  728. for (int i = 0; i < sceneURL.Length; i++)
  729. {
  730. if (i == scene.splitID)
  731. {
  732. continue;
  733. }
  734. if (isLocalNeighbour[i])
  735. {
  736. //m_log.Info("[SPLITSCENE] "+"Synchronize ScenePresence (Local) [region:{0}=>{1}, client:{2}]",
  737. // scene.RegionInfo.RegionID, regionPortList[i], pre.UUID.ToString());
  738. LocalUpdatePhysics(regionPortList[i], pre.UUID, pre.AbsolutePosition, pre.Velocity, pre.PhysicsActor.Flying);
  739. }
  740. else
  741. {
  742. //m_log.Info("[SPLITSCENE] "+"Synchronize ScenePresence (Remote) [region port:{0}, client:{1}, position:{2}, velocity:{3}, flying:{4}]",
  743. // regionPortList[i], pre.UUID.ToString(), pre.AbsolutePosition.ToString(),
  744. // pre.Velocity.ToString(), pre.PhysicsActor.Flying);
  745. Util.XmlRpcCommand(sceneURL[i], "UpdatePhysics",
  746. regionPortList[i], pre.UUID.GetBytes(),
  747. pre.AbsolutePosition.GetBytes(), pre.Velocity.GetBytes(),
  748. pre.PhysicsActor.Flying);
  749. /*
  750. byte[] buff = new byte[12+12+1];
  751. Buffer.BlockCopy(pre.AbsolutePosition.GetBytes(), 0, buff, 0, 12);
  752. Buffer.BlockCopy(pre.Velocity.GetBytes(), 0, buff, 12, 12);
  753. buff[24] = (byte)((pre.PhysicsActor.Flying)?1:0);
  754. // create header
  755. InternalPacketHeader header = new InternalPacketHeader();
  756. header.type = 1;
  757. header.throttlePacketType = 0;
  758. header.numbytes = buff.Length;
  759. header.agent_id = pre.UUID.UUID;
  760. header.region_port = regionPortList[i];
  761. //Send
  762. tcpClientList[i].send(header, buff);
  763. */
  764. }
  765. }
  766. }
  767. // ++i;
  768. }
  769. }
  770. }
  771. public bool SynchronizePackets(IScene scene, Packet packet, LLUUID agentID, ThrottleOutPacketType throttlePacketType)
  772. {
  773. if (!isSplit)
  774. {
  775. return false;
  776. }
  777. Scene localScene = (Scene) scene;
  778. for (int i = 0; i < sceneURL.Length; i++)
  779. {
  780. if (i == localScene.splitID)
  781. {
  782. continue;
  783. }
  784. if (isLocalNeighbour[i])
  785. {
  786. //m_log.Info("[SPLITSCENE] "+"Synchronize Packet (Local) [type:{0}, client:{1}]",
  787. // packet.Type.ToString(), agentID.ToString());
  788. LocalUpdatePacket(regionPortList[i], agentID, packet, throttlePacketType);
  789. }
  790. else
  791. {
  792. //m_log.Info("[SPLITSCENE] "+"Synchronize Packet (Remote) [type:{0}, client:{1}]",
  793. // packet.Type.ToString(), agentID.ToString());
  794. // to bytes
  795. byte[] buff = packet.ToBytes();
  796. // create header
  797. InternalPacketHeader header = new InternalPacketHeader();
  798. header.type = 0;
  799. header.throttlePacketType = (int) throttlePacketType;
  800. header.numbytes = buff.Length;
  801. header.agent_id = agentID.UUID;
  802. header.region_port = regionPortList[i];
  803. //Send
  804. tcpClientList[i].send(header, buff);
  805. PacketPool.Instance.ReturnPacket(packet);
  806. }
  807. }
  808. return true;
  809. }
  810. private void LocalUpdatePacket(int regionPort, LLUUID agentID, Packet packet, ThrottleOutPacketType throttlePacketType)
  811. {
  812. Scene scene;
  813. RegionInfo region = SearchRegionFromPortNum(regionPort);
  814. // m_log.Info("[SPLITSCENE] "+"LocalUpdatePacket [region port:{0}, client:{1}, packet type:{2}]",
  815. // regionPort, agentID.ToString(), packet.GetType().ToString());
  816. if (sceneManager.TryGetScene(region.RegionID, out scene))
  817. {
  818. ScenePresence pre = scene.GetScenePresences().Find(delegate(ScenePresence x) { return x.UUID == agentID; });
  819. if (pre == null)
  820. {
  821. m_log.ErrorFormat("[SPLITSCENE] [LocalUpdatePacket] ScenePresence is missing... ({0})", agentID.ToString());
  822. return;
  823. }
  824. if (pre.ControllingClient is LLClientView)
  825. {
  826. if (((LLClientView)pre.ControllingClient).IsActive)
  827. {
  828. ((LLClientView)pre.ControllingClient).OutPacket(packet, throttlePacketType);
  829. }
  830. else
  831. {
  832. PacketPool.Instance.ReturnPacket(packet);
  833. }
  834. }
  835. else
  836. {
  837. PacketPool.Instance.ReturnPacket(packet);
  838. }
  839. }
  840. }
  841. public void SynchronizePacketRecieve(InternalPacketHeader header, byte[] buff)
  842. {
  843. // m_log.Info("[SPLITSCENE] "+"entering SynchronizePacketRecieve[type={0}]", header.type);
  844. if (!isSplit)
  845. {
  846. return;
  847. }
  848. switch (header.type)
  849. {
  850. case 0:
  851. byte[] zero = new byte[3000];
  852. // deserialize packet
  853. int packetEnd = buff.Length - 1;
  854. // packetEnd = buff.Length;
  855. try
  856. {
  857. //m_log.Info("[SPLITSCENE] "+"PacketPool.Instance : {0}", (PacketPool.Instance == null)?"null":"not null");
  858. //m_log.Info("[SPLITSCENE] "+"buff length={0}", buff.Length);
  859. Packet packet = PacketPool.Instance.GetPacket(buff, ref packetEnd, zero);
  860. LocalUpdatePacket(header.region_port, new LLUUID(header.agent_id),
  861. packet, (ThrottleOutPacketType) header.throttlePacketType);
  862. }
  863. catch (Exception e)
  864. {
  865. m_log.Error("[SPLITSCENE] " + e);
  866. m_log.Error("[SPLITSCENE] " + e.StackTrace);
  867. }
  868. break;
  869. case 1:
  870. int regionPort = header.region_port;
  871. LLUUID scenePresenceID = new LLUUID(header.agent_id);
  872. LLVector3 position = new LLVector3(buff, 0);
  873. LLVector3 velocity = new LLVector3(buff, 12);
  874. bool flying = ((buff[24] == 1) ? true : false);
  875. LocalUpdatePhysics(regionPort, scenePresenceID, position, velocity, flying);
  876. break;
  877. default:
  878. m_log.Info("[SPLITSCENE] " + "Invalid type");
  879. break;
  880. }
  881. // m_log.Info("[SPLITSCENE] "+"exiting SynchronizePacketRecieve");
  882. }
  883. }
  884. }