LoadBalancerPlugin.cs 42 KB

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