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