LoadBalancerPlugin.cs 42 KB

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