From 279e0061c515ee0a03036bef68eea9738273d785 Mon Sep 17 00:00:00 2001 From: Johan Berntsson Date: Tue, 4 Mar 2008 05:31:54 +0000 Subject: [PATCH] Merged 3Di code that provides scene and avatar serialization, and plugin support for region move/split/merge. See ThirdParty/3Di/README.txt. Unless the new modules are used there should be no noticeable changes when running OpenSim. --- .../LoadRegions/LoadRegionsPlugin.cs | 4 +- .../RemoteController/RemoteAdminPlugin.cs | 2 +- OpenSim/Framework/AvatarWearable.cs | 35 +- OpenSim/Framework/BlockingQueue.cs | 5 + OpenSim/Framework/ClientManager.cs | 2 +- OpenSim/Framework/Data.MySQL/MySQLGridData.cs | 28 +- OpenSim/Framework/Data.MySQL/MySQLManager.cs | 42 +- .../Resources/CreateRegionsTable.sql | 3 +- .../UpgradeRegionsTableToVersion2.sql | 3 + OpenSim/Framework/Data/RegionProfileData.cs | 10 +- OpenSim/Framework/IClientAPI.cs | 19 + OpenSim/Framework/IScene.cs | 5 +- OpenSim/Framework/PacketPool.cs | 106 +- OpenSim/Framework/RegionInfo.cs | 23 +- OpenSim/Framework/SerializableRegionInfo.cs | 60 +- OpenSim/Framework/Util.cs | 58 + OpenSim/Grid/GridServer/GridManager.cs | 76 +- OpenSim/Grid/GridServer/Main.cs | 1 + OpenSim/Grid/UserServer/UserLoginService.cs | 8 +- OpenSim/Region/Application/OpenSimMain.cs | 152 ++- OpenSim/Region/ClientStack/ClientView.cs | 145 ++- OpenSim/Region/ClientStack/PacketQueue.cs | 12 +- OpenSim/Region/ClientStack/PacketServer.cs | 8 +- .../ClientStack/RegionApplicationBase.cs | 11 +- OpenSim/Region/ClientStack/UDPServer.cs | 92 +- .../Communications/OGS1/OGS1GridServices.cs | 28 +- .../Environment/Scenes/AvatarAppearance.cs | 49 +- .../Region/Environment/Scenes/EntityBase.cs | 91 +- .../Region/Environment/Scenes/InnerScene.cs | 43 + OpenSim/Region/Environment/Scenes/Scene.cs | 55 +- .../Environment/Scenes/SceneObjectPart.cs | 119 +- .../Environment/Scenes/ScenePresence.cs | 416 ++++++- .../Region/Environment/Types/UpdateQueue.cs | 50 +- .../Examples/SimpleApp/MyNpcCharacter.cs | 13 + .../3Di/LoadBalancer/LoadBalancerPlugin.cs | 1101 +++++++++++++++++ ThirdParty/3Di/LoadBalancer/TcpClient.cs | 240 ++++ ThirdParty/3Di/LoadBalancer/TcpServer.cs | 219 ++++ ThirdParty/3Di/README.txt | 82 ++ .../MonitorGUI/htdocs/MonitorGUI/View.pm | 214 ++++ .../RegionMonitor/MonitorGUI/htdocs/MyCGI.pm | 91 ++ .../MonitorGUI/htdocs/monitor.cgi | 202 +++ .../ServerPlugin/RegionMonitorPlugin.cs | 129 ++ .../3Di/RegionProxy/RegionProxyPlugin.cs | 513 ++++++++ prebuild.xml | 64 + 44 files changed, 4503 insertions(+), 126 deletions(-) create mode 100644 OpenSim/Framework/Data.MySQL/Resources/UpgradeRegionsTableToVersion2.sql create mode 100644 ThirdParty/3Di/LoadBalancer/LoadBalancerPlugin.cs create mode 100644 ThirdParty/3Di/LoadBalancer/TcpClient.cs create mode 100644 ThirdParty/3Di/LoadBalancer/TcpServer.cs create mode 100644 ThirdParty/3Di/README.txt create mode 100644 ThirdParty/3Di/RegionMonitor/MonitorGUI/htdocs/MonitorGUI/View.pm create mode 100644 ThirdParty/3Di/RegionMonitor/MonitorGUI/htdocs/MyCGI.pm create mode 100644 ThirdParty/3Di/RegionMonitor/MonitorGUI/htdocs/monitor.cgi create mode 100644 ThirdParty/3Di/RegionMonitor/ServerPlugin/RegionMonitorPlugin.cs create mode 100644 ThirdParty/3Di/RegionProxy/RegionProxyPlugin.cs diff --git a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs index ff8802121e..07c9def23b 100644 --- a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs +++ b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs @@ -66,7 +66,7 @@ namespace OpenSim.ApplicationPlugins.LoadRegions for (int i = 0; i < regionsToLoad.Length; i++) { m_log.Debug("[LOADREGIONS]: Creating Region: " + regionsToLoad[i].RegionName + " (ThreadID: " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() + ")"); - openSim.CreateRegion(regionsToLoad[i]); + openSim.CreateRegion(regionsToLoad[i], true); } openSim.ModuleLoader.PostInitialise(); @@ -96,7 +96,7 @@ namespace OpenSim.ApplicationPlugins.LoadRegions if (regionhandle == regionsToLoad[i].RegionHandle) { m_log.Debug("[LOADREGIONS]: Creating Region: " + regionsToLoad[i].RegionName + " (ThreadID: " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() + ")"); - openSim.CreateRegion(regionsToLoad[i]); + openSim.CreateRegion(regionsToLoad[i], true); } } } diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index 005bfd7b31..fba0c3b00b 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs @@ -269,7 +269,7 @@ namespace OpenSim.ApplicationPlugins.LoadRegions newRegionData.MasterAvatarFirstName = (string) requestData["region_master_first"]; newRegionData.MasterAvatarLastName = (string) requestData["region_master_last"]; - m_app.CreateRegion(newRegionData); + m_app.CreateRegion(newRegionData, true); responseData["created"] = "true"; response.Value = responseData; diff --git a/OpenSim/Framework/AvatarWearable.cs b/OpenSim/Framework/AvatarWearable.cs index c7083f39b9..e7c23386a0 100644 --- a/OpenSim/Framework/AvatarWearable.cs +++ b/OpenSim/Framework/AvatarWearable.cs @@ -26,10 +26,14 @@ * */ using libsecondlife; +using System; +using System.Runtime.Serialization; +using System.Security.Permissions; namespace OpenSim.Framework { - public class AvatarWearable + [Serializable] + public class AvatarWearable : ISerializable { public LLUUID AssetID = new LLUUID("00000000-0000-0000-0000-000000000000"); public LLUUID ItemID = new LLUUID("00000000-0000-0000-0000-000000000000"); @@ -67,5 +71,32 @@ namespace OpenSim.Framework return defaultWearables; } } + protected AvatarWearable(SerializationInfo info, StreamingContext context) + { + //System.Console.WriteLine("AvatarWearable Deserialize BGN"); + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + AssetID = new LLUUID((Guid)info.GetValue("AssetID", typeof(Guid))); + ItemID = new LLUUID((Guid)info.GetValue("ItemID", typeof(Guid))); + + //System.Console.WriteLine("AvatarWearable Deserialize END"); + } + + [SecurityPermission(SecurityAction.LinkDemand, + Flags = SecurityPermissionFlag.SerializationFormatter)] + public virtual void GetObjectData( + SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + info.AddValue("AssetID", AssetID.UUID); + info.AddValue("ItemID", ItemID.UUID); + } } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index e72884c013..6f567821d0 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -69,5 +69,10 @@ namespace OpenSim.Framework { return m_queue.Count; } + + public T[] GetQueueArray() + { + return m_queue.ToArray(); + } } } diff --git a/OpenSim/Framework/ClientManager.cs b/OpenSim/Framework/ClientManager.cs index cfdcbf05a6..39d8d99d90 100644 --- a/OpenSim/Framework/ClientManager.cs +++ b/OpenSim/Framework/ClientManager.cs @@ -137,7 +137,7 @@ namespace OpenSim.Framework } } - private uint[] GetAllCircuits(LLUUID agentId) + public uint[] GetAllCircuits(LLUUID agentId) { List circuits = new List(); // Wasteful, I know diff --git a/OpenSim/Framework/Data.MySQL/MySQLGridData.cs b/OpenSim/Framework/Data.MySQL/MySQLGridData.cs index 3737e486ed..eefb4e9f1b 100644 --- a/OpenSim/Framework/Data.MySQL/MySQLGridData.cs +++ b/OpenSim/Framework/Data.MySQL/MySQLGridData.cs @@ -97,6 +97,11 @@ namespace OpenSim.Framework.Data.MySQL database.ExecuteResourceSql("CreateRegionsTable.sql"); return; } + else if (oldVersion.Contains("Rev. 1")) + { + database.ExecuteResourceSql("UpgradeRegionsTableToVersion2.sql"); + return; + } } #endregion @@ -259,6 +264,27 @@ namespace OpenSim.Framework.Data.MySQL } } + /// + /// Deletes a profile from the database + /// + /// The profile to delete + /// Successful? + //public DataResponse DeleteProfile(RegionProfileData profile) + public DataResponse DeleteProfile(string uuid) + { + lock (database) + { + if (database.deleteRegion(uuid)) + { + return DataResponse.RESPONSE_OK; + } + else + { + return DataResponse.RESPONSE_ERROR; + } + } + } + /// /// DEPRECIATED. Attempts to authenticate a region by comparing a shared secret. /// @@ -328,4 +354,4 @@ namespace OpenSim.Framework.Data.MySQL } } } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/Data.MySQL/MySQLManager.cs b/OpenSim/Framework/Data.MySQL/MySQLManager.cs index ea11aa0856..0410643539 100644 --- a/OpenSim/Framework/Data.MySQL/MySQLManager.cs +++ b/OpenSim/Framework/Data.MySQL/MySQLManager.cs @@ -301,6 +301,7 @@ namespace OpenSim.Framework.Data.MySQL // non-critical parts retval.regionName = (string)reader["regionName"]; + retval.originUUID = new LLUUID((string) reader["originUUID"]); // Secrets retval.regionRecvKey = (string) reader["regionRecvKey"]; @@ -752,13 +753,13 @@ namespace OpenSim.Framework.Data.MySQL // server for the UUID of the region's owner (master avatar). It consists of the addition of the column and value to the relevant sql, // as well as the related parameterization sql += - "regionAssetSendKey, regionUserURI, regionUserRecvKey, regionUserSendKey, regionMapTexture, serverHttpPort, serverRemotingPort, owner_uuid) VALUES "; + "regionAssetSendKey, regionUserURI, regionUserRecvKey, regionUserSendKey, regionMapTexture, serverHttpPort, serverRemotingPort, owner_uuid, originUUID) VALUES "; sql += "(?regionHandle, ?regionName, ?uuid, ?regionRecvKey, ?regionSecret, ?regionSendKey, ?regionDataURI, "; sql += "?serverIP, ?serverPort, ?serverURI, ?locX, ?locY, ?locZ, ?eastOverrideHandle, ?westOverrideHandle, ?southOverrideHandle, ?northOverrideHandle, ?regionAssetURI, ?regionAssetRecvKey, "; sql += - "?regionAssetSendKey, ?regionUserURI, ?regionUserRecvKey, ?regionUserSendKey, ?regionMapTexture, ?serverHttpPort, ?serverRemotingPort, ?owner_uuid)"; + "?regionAssetSendKey, ?regionUserURI, ?regionUserRecvKey, ?regionUserSendKey, ?regionMapTexture, ?serverHttpPort, ?serverRemotingPort, ?owner_uuid, ?originUUID)"; if (GRID_ONLY_UPDATE_NECESSARY_DATA) { @@ -798,6 +799,7 @@ namespace OpenSim.Framework.Data.MySQL parameters["?serverHttpPort"] = regiondata.httpPort.ToString(); parameters["?serverRemotingPort"] = regiondata.remotingPort.ToString(); parameters["?owner_uuid"] = regiondata.owner_uuid.ToString(); + parameters["?originUUID"] = regiondata.originUUID.ToString(); bool returnval = false; @@ -819,6 +821,42 @@ namespace OpenSim.Framework.Data.MySQL return false; } + return returnval; + } + /// + /// Delete a region from the database + /// + /// The region to insert + /// Success? + //public bool deleteRegion(RegionProfileData regiondata) + public bool deleteRegion(string uuid) + { + bool returnval = false; + + string sql = + "DELETE FROM regions WHERE uuid = ?uuid;"; + + Dictionary parameters = new Dictionary(); + + try + { + parameters["?uuid"] = uuid; + + IDbCommand result = Query(sql, parameters); + + int x; + if ((x = result.ExecuteNonQuery()) > 0) + { + returnval = true; + } + result.Dispose(); + } + catch (Exception e) + { + m_log.Error(e.ToString()); + return false; + } + return returnval; } } diff --git a/OpenSim/Framework/Data.MySQL/Resources/CreateRegionsTable.sql b/OpenSim/Framework/Data.MySQL/Resources/CreateRegionsTable.sql index 07b0d9b1a1..23535afeb6 100644 --- a/OpenSim/Framework/Data.MySQL/Resources/CreateRegionsTable.sql +++ b/OpenSim/Framework/Data.MySQL/Resources/CreateRegionsTable.sql @@ -23,8 +23,9 @@ CREATE TABLE `regions` ( `regionUserRecvKey` varchar(128) default NULL, `regionUserSendKey` varchar(128) default NULL, `regionMapTexture` varchar(36) default NULL, `serverHttpPort` int(10) default NULL, `serverRemotingPort` int(10) default NULL, + `originUUID` varchar(36), PRIMARY KEY (`uuid`), KEY `regionName` (`regionName`), KEY `regionHandle` (`regionHandle`), KEY `overrideHandles` (`eastOverrideHandle`,`westOverrideHandle`,`southOverrideHandle`,`northOverrideHandle`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Rev. 1'; +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Rev. 2'; diff --git a/OpenSim/Framework/Data.MySQL/Resources/UpgradeRegionsTableToVersion2.sql b/OpenSim/Framework/Data.MySQL/Resources/UpgradeRegionsTableToVersion2.sql new file mode 100644 index 0000000000..5880954229 --- /dev/null +++ b/OpenSim/Framework/Data.MySQL/Resources/UpgradeRegionsTableToVersion2.sql @@ -0,0 +1,3 @@ +ALTER TABLE `regions` + ADD COLUMN `originUUID` varchar(36), +COMMENT='Rev. 2'; diff --git a/OpenSim/Framework/Data/RegionProfileData.cs b/OpenSim/Framework/Data/RegionProfileData.cs index f9f4283615..e4b48b7105 100644 --- a/OpenSim/Framework/Data/RegionProfileData.cs +++ b/OpenSim/Framework/Data/RegionProfileData.cs @@ -129,6 +129,12 @@ namespace OpenSim.Framework.Data /// public LLUUID owner_uuid = LLUUID.Zero; + /// + /// OGS/OpenSim Specific original ID for a region after move/split + /// + public LLUUID originUUID; + + /// /// Get Sim profile data from grid server when in grid mode /// @@ -162,7 +168,7 @@ namespace OpenSim.Framework.Data simData.serverPort = Convert.ToUInt32((string) responseData["sim_port"]); simData.httpPort = Convert.ToUInt32((string) responseData["http_port"]); simData.remotingPort = Convert.ToUInt32((string) responseData["remoting_port"]); - simData.serverURI = "http://" + simData.serverIP + ":" + simData.serverPort.ToString() + "/"; + simData.serverURI = (string)responseData["server_uri"]; simData.httpServerURI = "http://" + simData.serverIP + ":" + simData.httpPort.ToString() + "/"; simData.UUID = new LLUUID((string) responseData["region_UUID"]); simData.regionName = (string) responseData["region_name"]; @@ -205,7 +211,7 @@ namespace OpenSim.Framework.Data simData.httpPort = Convert.ToUInt32((string) responseData["http_port"]); simData.remotingPort = Convert.ToUInt32((string) responseData["remoting_port"]); simData.httpServerURI = "http://" + simData.serverIP + ":" + simData.httpPort.ToString() + "/"; - simData.serverURI = "http://" + simData.serverIP + ":" + simData.serverPort.ToString() + "/"; + simData.serverURI = (string)responseData["server_uri"]; simData.UUID = new LLUUID((string) responseData["region_UUID"]); simData.regionName = (string) responseData["region_name"]; diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 5001f005c6..7a0a232629 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -665,5 +665,24 @@ namespace OpenSim.Framework void SendBlueBoxMessage(LLUUID FromAvatarID, LLUUID fromSessionID, String FromAvatarName, String Message); void SendLogoutPacket(); + ClientInfo GetClientInfo(); + void SetClientInfo(ClientInfo info); + void Terminate(); + } + + [Serializable] + public class ClientInfo + { + public byte[] usecircuit; + public EndPoint userEP; + public EndPoint proxyEP; + public sAgentCircuitData agentcircuit; + + public Dictionary pendingAcks; + public Dictionary needAck; + + public List out_packets; + + public uint sequence; } } diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs index 3445050ee5..0bb0efb551 100644 --- a/OpenSim/Framework/IScene.cs +++ b/OpenSim/Framework/IScene.cs @@ -38,7 +38,8 @@ namespace OpenSim.Framework Down = 0, Up = 1, Crashed = 2, - Starting = 3 + Starting = 3, + SlaveScene = 4 } ; public interface IScene @@ -63,4 +64,4 @@ namespace OpenSim.Framework ClientManager ClientManager { get; } } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/PacketPool.cs b/OpenSim/Framework/PacketPool.cs index 30b6d6a5e7..2c44ae3e78 100644 --- a/OpenSim/Framework/PacketPool.cs +++ b/OpenSim/Framework/PacketPool.cs @@ -26,6 +26,7 @@ * */ using System; +using System.Net; using System.Collections; using libsecondlife.Packets; @@ -33,29 +34,68 @@ namespace OpenSim.Framework { public sealed class PacketPool { + static public void EncodeProxyMessage(byte[] bytes, ref int numBytes, EndPoint trueEP) + { + if( numBytes > 4090 ) // max UPD size = 4096 + { + throw new Exception("ERROR: No space to encode the proxy EP"); + } + + ushort port = (ushort) ((IPEndPoint) trueEP).Port; + bytes[numBytes++] = (byte)(port % 256); + bytes[numBytes++] = (byte)(port / 256); + + foreach (byte b in ((IPEndPoint)trueEP).Address.GetAddressBytes()) + { + bytes[numBytes++] = b; + } + + int x = numBytes; + + DecodeProxyMessage(bytes, ref numBytes); + + numBytes = x; + } + + static public EndPoint DecodeProxyMessage(byte[] bytes, ref int numBytes) + { + // IPv4 Only + byte[] addr = new byte[4]; + + addr[3] = bytes[--numBytes]; + addr[2] = bytes[--numBytes]; + addr[1] = bytes[--numBytes]; + addr[0] = bytes[--numBytes]; + + ushort port = (ushort)(bytes[--numBytes] * 256); + port += (ushort)bytes[--numBytes]; + + return (EndPoint) new IPEndPoint(new IPAddress(addr), (int)port); + } + // Set up a thread-safe singleton pattern static PacketPool() { } - private static readonly PacketPool instance = new PacketPool(); + static readonly PacketPool instance = new PacketPool(); public static PacketPool Instance { - get { return instance; } + get + { + return instance; + } } private Hashtable pool = new Hashtable(); - public Packet GetPacket(PacketType type) - { - return Packet.BuildPacket(type); -/* Skip until PacketPool performance problems have been resolved (mantis 281) + public Packet GetPacket(PacketType type) { Packet packet = null; - lock (pool) + lock(pool) { - if (pool[type] == null || ((Stack) pool[type]).Count == 0) + if(pool[type] == null || ((Stack) pool[type]).Count == 0) { // Creating a new packet if we cannot reuse an old package packet = Packet.BuildPacket(type); @@ -63,39 +103,16 @@ namespace OpenSim.Framework else { // Recycle old packages - packet = (Packet) ((Stack) pool[type]).Pop(); + packet=(Packet) ((Stack) pool[type]).Pop(); } } return packet; -*/ - } - - // Copied from LibSL, and added a check to avoid overwriting the - // buffer - private void ZeroDecodeCommand(byte[] src, byte[] dest) - { - for (int srcPos = 6, destPos = 6; destPos < 10; ++srcPos) - { - if (src[srcPos] == 0x00) - { - for (byte j = 0; j < src[srcPos + 1] && destPos < 10; ++j) - { - dest[destPos++] = 0x00; - } - ++srcPos; - } - else - { - dest[destPos++] = src[srcPos]; - } - } } + private byte[] decoded_header = new byte[10]; private PacketType GetType(byte[] bytes) { - byte[] decoded_header = new byte[10]; - ushort id; libsecondlife.PacketFrequency freq; @@ -103,7 +120,7 @@ namespace OpenSim.Framework if((bytes[0] & libsecondlife.Helpers.MSG_ZEROCODED)!=0) { - ZeroDecodeCommand(bytes, decoded_header); + libsecondlife.Helpers.ZeroDecodeCommand(bytes, decoded_header); } if (decoded_header[6] == 0xFF) @@ -138,21 +155,22 @@ namespace OpenSim.Framework return packet; } - public void ReturnPacket(Packet packet) - { -/* Skip until PacketPool performance problems have been resolved (mantis 281) - lock (pool) - { - PacketType type = packet.Type; + public void ReturnPacket(Packet packet) { + return; // packet pool disabled - if (pool[type] == null) + lock(pool) + { + PacketType type=packet.Type; + + if(pool[type] == null) { pool[type] = new Stack(); } - - ((Stack) pool[type]).Push(packet); + if (((Stack)pool[type]).Count < 50) + { + ((Stack)pool[type]).Push(packet); + } } -*/ } } } diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs index f97db5c208..43e2a24ece 100644 --- a/OpenSim/Framework/RegionInfo.cs +++ b/OpenSim/Framework/RegionInfo.cs @@ -71,6 +71,7 @@ namespace OpenSim.Framework m_allow_alternate_ports = ConvertFrom.m_allow_alternate_ports; RemotingAddress = ConvertFrom.RemotingAddress; RegionID = LLUUID.Zero; + ServerURI = ConvertFrom.ServerURI; } public LLUUID RegionID = LLUUID.Zero; @@ -84,6 +85,19 @@ namespace OpenSim.Framework } public bool m_allow_alternate_ports; + public string m_serverURI; + public string ServerURI + { + get + { + return m_serverURI; + } + set + { + m_serverURI = value; + } + } + public string RemotingAddress; public IPEndPoint ExternalEndPoint @@ -175,6 +189,8 @@ namespace OpenSim.Framework public string MasterAvatarFirstName = String.Empty; public string MasterAvatarLastName = String.Empty; public string MasterAvatarSandboxPassword = String.Empty; + public string proxyUrl = ""; + public LLUUID originRegionID = LLUUID.Zero; // Apparently, we're applying the same estatesettings regardless of whether it's local or remote. private EstateSettings m_estateSettings; @@ -227,6 +243,10 @@ namespace OpenSim.Framework m_allow_alternate_ports = ConvertFrom.m_allow_alternate_ports; RemotingAddress = ConvertFrom.RemotingAddress; RegionID = LLUUID.Zero; + proxyUrl = ConvertFrom.ProxyUrl; + originRegionID = ConvertFrom.OriginRegionID; + RegionName = ConvertFrom.RegionName; + ServerURI = ConvertFrom.ServerURI; } public RegionInfo(SimpleRegionInfo ConvertFrom) @@ -239,6 +259,7 @@ namespace OpenSim.Framework m_allow_alternate_ports = ConvertFrom.m_allow_alternate_ports; RemotingAddress = ConvertFrom.RemotingAddress; RegionID = LLUUID.Zero; + ServerURI = ConvertFrom.ServerURI; } //not in use, should swap to nini though. @@ -411,4 +432,4 @@ namespace OpenSim.Framework } } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/SerializableRegionInfo.cs b/OpenSim/Framework/SerializableRegionInfo.cs index 077ed8da2f..48ddbdf210 100644 --- a/OpenSim/Framework/SerializableRegionInfo.cs +++ b/OpenSim/Framework/SerializableRegionInfo.cs @@ -51,6 +51,10 @@ namespace OpenSim.Framework m_remotingPort = ConvertFrom.RemotingPort; m_allow_alternate_ports = ConvertFrom.m_allow_alternate_ports; RemotingAddress = ConvertFrom.RemotingAddress; + m_proxyUrl = ConvertFrom.proxyUrl; + OriginRegionID = ConvertFrom.originRegionID; + RegionName = ConvertFrom.RegionName; + ServerURI = ConvertFrom.ServerURI; } public SearializableRegionInfo(uint regionLocX, uint regionLocY, IPEndPoint internalEndPoint, string externalUri) @@ -157,5 +161,57 @@ namespace OpenSim.Framework { get { return Util.UIntsToLong((RegionLocX * (uint)Constants.RegionSize), (RegionLocY * (uint)Constants.RegionSize)); } } - } -} \ No newline at end of file + + protected string m_proxyUrl; + public string ProxyUrl + { + get + { + return m_proxyUrl; + } + set + { + m_proxyUrl = value; + } + } + + protected Guid m_originRegionID = LLUUID.Zero.UUID; + public LLUUID OriginRegionID + { + get + { + return new LLUUID(m_originRegionID); + } + set + { + m_originRegionID = value.UUID; + } + } + + protected string m_regionName; + public string RegionName + { + get + { + return m_regionName; + } + set + { + m_regionName = value; + } + } + + protected string m_serverURI; + public string ServerURI + { + get + { + return m_serverURI; + } + set + { + m_serverURI = value; + } + } + } +} diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 35e795b494..8ba6643ccc 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -37,6 +37,8 @@ using System.Text; using libsecondlife; using Nini.Config; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; namespace OpenSim.Framework { public class Util @@ -509,7 +511,63 @@ namespace OpenSim.Framework { return ""; } + } + public static void SerializeToFile(string filename, Object obj) + { + IFormatter formatter = new BinaryFormatter(); + Stream stream = null; + + try + { + stream = new FileStream( + filename, FileMode.Create, + FileAccess.Write, FileShare.None); + + formatter.Serialize(stream, obj); + } + catch (Exception e) + { + System.Console.WriteLine(e.Message); + System.Console.WriteLine(e.StackTrace); + } + finally + { + if (stream != null) + { + stream.Close(); + } + } + } + + public static Object DeserializeFromFile(string filename) + { + IFormatter formatter = new BinaryFormatter(); + Stream stream = null; + Object ret = null; + + try + { + stream = new FileStream( + filename, FileMode.Open, + FileAccess.Read, FileShare.None); + + ret = formatter.Deserialize(stream); + } + catch (Exception e) + { + System.Console.WriteLine(e.Message); + System.Console.WriteLine(e.StackTrace); + } + finally + { + if (stream != null) + { + stream.Close(); + } + } + + return ret; } } } diff --git a/OpenSim/Grid/GridServer/GridManager.cs b/OpenSim/Grid/GridServer/GridManager.cs index e32f551e65..2e6a892858 100644 --- a/OpenSim/Grid/GridServer/GridManager.cs +++ b/OpenSim/Grid/GridServer/GridManager.cs @@ -37,6 +37,7 @@ using OpenSim.Framework; using OpenSim.Framework.Console; using OpenSim.Framework.Data; using OpenSim.Framework.Servers; +using OpenSim.Framework.Data.MySQL; namespace OpenSim.Grid.GridServer { @@ -301,16 +302,20 @@ namespace OpenSim.Grid.GridServer catch (KeyNotFoundException) { } TheSim.regionHandle = Helpers.UIntsToLong((TheSim.regionLocX * Constants.RegionSize), (TheSim.regionLocY * Constants.RegionSize)); - TheSim.serverURI = "http://" + TheSim.serverIP + ":" + TheSim.serverPort + "/"; + TheSim.serverURI = (string)requestData["server_uri"]; + Console.WriteLine("adding region " + TheSim.regionLocX + " , " + TheSim.regionLocY + " , " + + TheSim.serverURI); TheSim.httpServerURI = "http://" + TheSim.serverIP + ":" + TheSim.httpPort + "/"; TheSim.regionName = (string)requestData["sim_name"]; TheSim.UUID = new LLUUID((string)requestData["UUID"]); + TheSim.originUUID = new LLUUID((string) requestData["originUUID"]); //make sure there is not an existing region at this location OldSim = getRegion(TheSim.regionHandle); - if (OldSim == null || OldSim.UUID == TheSim.UUID) + //if (OldSim == null || OldSim.UUID == TheSim.UUID) + if (OldSim == null || OldSim.UUID == TheSim.UUID || TheSim.UUID != TheSim.originUUID) { bool brandNew = ( OldSim == null && TheSim.regionRecvKey == config.SimSendKey && TheSim.regionSendKey == config.SimRecvKey); @@ -500,6 +505,69 @@ namespace OpenSim.Grid.GridServer } + /// + /// Returns an XML RPC response to a simulator profile request + /// Performed after moving a region. + /// + /// + /// + /// The XMLRPC Request + /// Processing parameters + public XmlRpcResponse XmlRpcDeleteRegionMethod(XmlRpcRequest request) + { + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + //RegionProfileData TheSim = null; + string uuid = String.Empty;; + Hashtable requestData = (Hashtable) request.Params[0]; + string myword; + if (requestData.ContainsKey("UUID")) { + //TheSim = getRegion(new LLUUID((string) requestData["UUID"])); + uuid = requestData["UUID"].ToString(); + Console.WriteLine("deleting region " + uuid); +// logToDB((new LLUUID((string)requestData["UUID"])).ToString(),"XmlRpcDeleteRegionMethod","", 5,"Attempting delete with UUID."); + } + else { + responseData["error"] = "No UUID or region_handle passed to grid server - unable to delete"; + return response; + } + + foreach (KeyValuePair kvp in _plugins) { + //OpenSim.Framework.Data.MySQL.MySQLGridData dbengine = new OpenSim.Framework.Data.MySQL.MySQLGridData(); + try { + OpenSim.Framework.Data.MySQL.MySQLGridData mysqldata = (OpenSim.Framework.Data.MySQL.MySQLGridData)(kvp.Value); + //DataResponse insertResponse = mysqldata.DeleteProfile(TheSim); + DataResponse insertResponse = mysqldata.DeleteProfile(uuid); + switch (insertResponse) { + case DataResponse.RESPONSE_OK: + //MainLog.Instance.Verbose("grid", "Deleting region successful: " + uuid); + responseData["status"] = "Deleting region successful: " + uuid; + break; + case DataResponse.RESPONSE_ERROR: + //MainLog.Instance.Warn("storage", "Deleting region failed (Error): " + uuid); + responseData["status"] = "Deleting region failed (Error): " + uuid; + break; + case DataResponse.RESPONSE_INVALIDCREDENTIALS: + //MainLog.Instance.Warn("storage", "Deleting region failed (Invalid Credentials): " + uuid); + responseData["status"] = "Deleting region (Invalid Credentials): " + uuid; + break; + case DataResponse.RESPONSE_AUTHREQUIRED: + //MainLog.Instance.Warn("storage", "Deleting region failed (Authentication Required): " + uuid); + responseData["status"] = "Deleting region (Authentication Required): " + uuid; + break; + } + } + catch (Exception e) { + m_log.Error("storage Unable to delete region " + uuid + " via MySQL"); + //MainLog.Instance.Warn("storage", e.ToString()); + } + } + + return response; + } + /// /// Returns an XML RPC response to a simulator profile request /// @@ -533,6 +601,7 @@ namespace OpenSim.Grid.GridServer (string) requestData["region_handle"]); responseData["sim_ip"] = Util.GetHostFromDNS(simData.serverIP).ToString(); responseData["sim_port"] = simData.serverPort.ToString(); + responseData["server_uri"] = simData.serverURI; responseData["http_port"] = simData.httpPort.ToString(); responseData["remoting_port"] = simData.remotingPort.ToString(); responseData["region_locx"] = simData.regionLocX.ToString(); @@ -798,8 +867,7 @@ namespace OpenSim.Grid.GridServer } } - TheSim.serverURI = "http://" + TheSim.serverIP + ":" + TheSim.serverPort + "/"; - + TheSim.serverURI = "http://" + TheSim.serverIP + ":" + TheSim.serverPort + "/"; bool requirePublic = false; bool requireValid = true; diff --git a/OpenSim/Grid/GridServer/Main.cs b/OpenSim/Grid/GridServer/Main.cs index ff4a888842..ff4cfa2bcb 100644 --- a/OpenSim/Grid/GridServer/Main.cs +++ b/OpenSim/Grid/GridServer/Main.cs @@ -113,6 +113,7 @@ namespace OpenSim.Grid.GridServer httpServer.AddXmlRPCHandler("simulator_login", m_gridManager.XmlRpcSimulatorLoginMethod); httpServer.AddXmlRPCHandler("simulator_data_request", m_gridManager.XmlRpcSimulatorDataRequestMethod); + httpServer.AddXmlRPCHandler("simulator_after_region_moved", m_gridManager.XmlRpcDeleteRegionMethod); httpServer.AddXmlRPCHandler("map_block", m_gridManager.XmlRpcMapBlockMethod); // Message Server ---> Grid Server diff --git a/OpenSim/Grid/UserServer/UserLoginService.cs b/OpenSim/Grid/UserServer/UserLoginService.cs index 0b832f4289..e03ac3a44c 100644 --- a/OpenSim/Grid/UserServer/UserLoginService.cs +++ b/OpenSim/Grid/UserServer/UserLoginService.cs @@ -99,8 +99,8 @@ namespace OpenSim.Grid.UserServer //CFK: the next one for X & Y and comment this one. //CFK: m_log.Info("[LOGIN]: CUSTOMISERESPONSE: Region X: " + SimInfo.regionLocX + //CFK: "; Region Y: " + SimInfo.regionLocY); - response.SimAddress = Util.GetHostFromDNS(SimInfo.serverIP).ToString(); - response.SimPort = (uint) SimInfo.serverPort; + response.SimAddress = Util.GetHostFromDNS(SimInfo.serverURI.Split(new char[] { '/', ':' })[3]).ToString(); + response.SimPort = uint.Parse(SimInfo.serverURI.Split(new char[] { '/', ':' })[4]); response.RegionX = SimInfo.regionLocX; response.RegionY = SimInfo.regionLocY; @@ -190,8 +190,8 @@ namespace OpenSim.Grid.UserServer m_log.Info("[LOGIN]: " + "CUSTOMISERESPONSE: Region X: " + SimInfo.regionLocX + "; Region Y: " + SimInfo.regionLocY); - response.SimAddress = Util.GetHostFromDNS(SimInfo.serverIP).ToString(); - response.SimPort = (uint) SimInfo.serverPort; + response.SimAddress = Util.GetHostFromDNS(SimInfo.serverURI.Split(new char[] { '/', ':' })[3]).ToString(); + response.SimPort = uint.Parse(SimInfo.serverURI.Split(new char[] { '/', ':' })[4]); response.RegionX = SimInfo.regionLocX; response.RegionY = SimInfo.regionLocY; diff --git a/OpenSim/Region/Application/OpenSimMain.cs b/OpenSim/Region/Application/OpenSimMain.cs index bdefd0f4fb..2c9e50e665 100644 --- a/OpenSim/Region/Application/OpenSimMain.cs +++ b/OpenSim/Region/Application/OpenSimMain.cs @@ -33,8 +33,6 @@ using System.IO; using System.Text; using System.Threading; using System.Timers; -using libsecondlife; -using Mono.Addins; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications.Cache; @@ -49,6 +47,13 @@ using OpenSim.Region.Environment.Interfaces; using OpenSim.Region.Environment.Scenes; using OpenSim.Region.Physics.Manager; using Timer=System.Timers.Timer; +using System.Net; +using Nwc.XmlRpc; +using System.Collections; +using System.Reflection; +using libsecondlife; +using Mono.Addins; +using Mono.Addins.Description; namespace OpenSim { @@ -57,6 +62,8 @@ namespace OpenSim public class OpenSimMain : RegionApplicationBase, conscmd_callback { private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private string proxyUrl; + private int proxyOffset = 0; private const string DEFAULT_PRIM_BACKUP_FILENAME = "prim-backup.xml"; @@ -110,6 +117,16 @@ namespace OpenSim get { return m_httpServer; } } + public List UdpServers + { + get { return m_udpServers; } + } + + public List RegionData + { + get { return m_regionData; } + } + private ModuleLoader m_moduleLoader; public ModuleLoader ModuleLoader @@ -350,20 +367,34 @@ namespace OpenSim m_httpServer.AddStreamHandler(new SimStatusHandler()); } + proxyUrl = ConfigSource.Configs["Network"].GetString("proxy_url", ""); + proxyOffset = Int32.Parse(ConfigSource.Configs["Network"].GetString("proxy_offset", "0")); + // Create a ModuleLoader instance m_moduleLoader = new ModuleLoader(m_config); ExtensionNodeList nodes = AddinManager.GetExtensionNodes("/OpenSim/Startup"); m_log.InfoFormat("[PLUGINS]: Loading {0} OpenSim application plugins", nodes.Count); - foreach (TypeExtensionNode node in nodes) { - IApplicationPlugin plugin = (IApplicationPlugin)node.CreateInstance(); - - plugin.Initialise(this); - m_plugins.Add(plugin); + // First load the proxy server (if present) + if(node.Path.Contains("Proxy")) + { + IApplicationPlugin plugin = (IApplicationPlugin)node.CreateInstance(); + plugin.Initialise(this); + m_plugins.Add(plugin); + } + } + // then load the other modules + foreach (TypeExtensionNode node in nodes) + { + if(!node.Path.Contains("Proxy")) + { + IApplicationPlugin plugin = (IApplicationPlugin)node.CreateInstance(); + plugin.Initialise(this); + m_plugins.Add(plugin); + } } - // Start UDP servers //for (int i = 0; i < m_udpServers.Count; i++) //{ @@ -436,10 +467,25 @@ namespace OpenSim return m_commsManager.AddUser(tempfirstname,templastname,tempPasswd,regX,regY); } - public UDPServer CreateRegion(RegionInfo regionInfo) + public UDPServer CreateRegion(RegionInfo regionInfo, bool portadd_flag) { + int port = regionInfo.InternalEndPoint.Port; + if ((proxyOffset != 0) && (portadd_flag)) + { + // set proxy url to RegionInfo + regionInfo.proxyUrl = proxyUrl; + + // set initial RegionID to originRegionID in RegionInfo. (it needs for loding prims) + regionInfo.originRegionID = regionInfo.RegionID; + + // set initial ServerURI + regionInfo.ServerURI = "http://" + regionInfo.ExternalHostName + + ":" + regionInfo.InternalEndPoint.Port.ToString(); + + ProxyCommand(proxyUrl, "AddPort", port, port + proxyOffset, regionInfo.ExternalHostName); + } UDPServer udpServer; - Scene scene = SetupScene(regionInfo, out udpServer, m_permissions); + Scene scene = SetupScene(regionInfo, proxyOffset, out udpServer, m_permissions); m_log.Info("[MODULES]: Loading Region's modules"); @@ -546,7 +592,7 @@ namespace OpenSim m_regionData.RemoveAt(RegionHandleElement); } - CreateRegion(whichRegion); + CreateRegion(whichRegion, true); //UDPServer restartingRegion = CreateRegion(whichRegion); //restartingRegion.ServerListener(); //m_sceneManager.SendSimOnlineNotification(restartingRegion.RegionHandle); @@ -594,6 +640,8 @@ namespace OpenSim /// public virtual void Shutdown() { + ProxyCommand(proxyUrl, "Stop"); + if (m_startupCommandsFile != String.Empty) { RunCommandScript(m_shutdownCommandsFile); @@ -609,7 +657,7 @@ namespace OpenSim m_console.Close(); Environment.Exit(0); - } + } private void RunAutoTimerScript(object sender, EventArgs e) { @@ -882,9 +930,8 @@ namespace OpenSim break; case "create-region": - CreateRegion(new RegionInfo(cmdparams[0], "Regions/" + cmdparams[1],false)); + CreateRegion(new RegionInfo(cmdparams[0], "Regions/" + cmdparams[1],false), true); break; - case "remove-region": string regName = CombineParams(cmdparams, 0); @@ -1120,6 +1167,8 @@ namespace OpenSim presence.ControllingClient.CircuitCode, ep, regionName)); + m_console.Notice(" {0}", (((ClientView)presence.ControllingClient).PacketProcessingEnabled)?"Active client":"Standby client"); + } break; @@ -1167,5 +1216,80 @@ namespace OpenSim } #endregion + // TODO: remove me!! (almost same as XmlRpcCommand) + public object ProxyCommand(string url, string methodName, params object[] args) + { + if(proxyUrl.Length==0) return null; + return SendXmlRpcCommand(url, methodName, args); + } + + public object XmlRpcCommand(uint port, string methodName, params object[] args) + { + return SendXmlRpcCommand("http://localhost:"+port, methodName, args); + } + + public object XmlRpcCommand(string url, string methodName, params object[] args) + { + return SendXmlRpcCommand(url, methodName, args); + } + + private object SendXmlRpcCommand(string url, string methodName, object[] args) + { + try { + //MainLog.Instance.Verbose("XMLRPC", "Sending command {0} to {1}", methodName, url); + XmlRpcRequest client = new XmlRpcRequest(methodName, args); + //MainLog.Instance.Verbose("XMLRPC", client.ToString()); + XmlRpcResponse response = client.Send(url, 6000); + if(!response.IsFault) return response.Value; + } + catch(Exception e) + { + m_log.ErrorFormat("XMLRPC Failed to send command {0} to {1}: {2}", methodName, url, e.Message); + } + return null; + } + + /// + /// Get the start time and up time of Region server + /// + /// The first out parameter describing when the Region server started + /// The second out parameter describing how long the Region server has run + public void GetRunTime(out string starttime, out string uptime) + { + starttime = m_startuptime.ToString(); + uptime = (DateTime.Now - m_startuptime).ToString(); + } + + /// + /// Get the number of the avatars in the Region server + /// + /// The first out parameter describing the number of all the avatars in the Region server + public void GetAvatarNumber(out int usernum) + { + int accounter = 0; + + foreach (ScenePresence presence in m_sceneManager.GetCurrentSceneAvatars()) { + //presence.RegionHandle; + accounter++; + } + + usernum = accounter; + } + + /// + /// Get the number of the avatars in the Region server + /// + /// The first out parameter describing the number of all the avatars in the Region server + public void GetRegionNumber(out int regionnum) + { + int accounter = 0; + //List regionNameList = new List(); + + m_sceneManager.ForEachScene(delegate(Scene scene) { + accounter++; + }); + regionnum = accounter; + + } } } diff --git a/OpenSim/Region/ClientStack/ClientView.cs b/OpenSim/Region/ClientStack/ClientView.cs index b719086d54..b5cd6fb6c5 100644 --- a/OpenSim/Region/ClientStack/ClientView.cs +++ b/OpenSim/Region/ClientStack/ClientView.cs @@ -61,6 +61,8 @@ namespace OpenSim.Region.ClientStack /* static variables */ public static TerrainManager TerrainManager; + public delegate bool SynchronizeClientHandler(IScene scene, Packet packet, LLUUID agentID, ThrottleOutPacketType throttlePacketType); + public static SynchronizeClientHandler SynchronizeClient = null; /* private variables */ private readonly LLUUID m_sessionId; private LLUUID m_secureSessionId = LLUUID.Zero; @@ -118,6 +120,7 @@ namespace OpenSim.Region.ClientStack protected Thread m_clientThread; protected LLVector3 m_startpos; protected EndPoint m_userEndPoint; + protected EndPoint m_proxyEndPoint; /* Instantiated Designated Event Delegates */ //- used so we don't create new objects for each incoming packet and then toss it out later */ @@ -291,7 +294,7 @@ namespace OpenSim.Region.ClientStack /* METHODS */ public ClientView(EndPoint remoteEP, IScene scene, AssetCache assetCache, PacketServer packServer, - AgentCircuitManager authenSessions, LLUUID agentId, LLUUID sessionId, uint circuitCode) + AgentCircuitManager authenSessions, LLUUID agentId, LLUUID sessionId, uint circuitCode, EndPoint proxyEP) { m_moneyBalance = 1000; @@ -311,6 +314,7 @@ namespace OpenSim.Region.ClientStack m_circuitCode = circuitCode; m_userEndPoint = remoteEP; + m_proxyEndPoint = proxyEP; m_startpos = m_authenticateSessionsHandler.GetPosition(circuitCode); @@ -411,7 +415,37 @@ namespace OpenSim.Region.ClientStack public void Stop() { - m_log.Info("[BUG]: Stop called, please find out where and remove it"); + // Shut down timers + m_ackTimer.Stop(); + m_clientPingTimer.Stop(); + } + + public void Restart() + { + // re-construct + m_pendingAcks = new Dictionary(); + m_needAck = new Dictionary(); + m_sequence += 1000000; + + m_ackTimer = new Timer(750); + m_ackTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed); + m_ackTimer.Start(); + + m_clientPingTimer = new Timer(5000); + m_clientPingTimer.Elapsed += new ElapsedEventHandler(CheckClientConnectivity); + m_clientPingTimer.Enabled = true; + } + + public void Terminate() + { + // disable blocking queue + m_packetQueue.Enqueue(null); + + // wait for thread stoped + m_clientThread.Join(); + + // delete circuit code + m_networkServer.CloseClient(this); } #endregion @@ -507,6 +541,10 @@ namespace OpenSim.Region.ClientStack while (true) { QueItem nextPacket = m_packetQueue.Dequeue(); + if (nextPacket == null) + { + break; + } if (nextPacket.Incoming) { if (nextPacket.Packet.Type != PacketType.AgentUpdate) @@ -2642,7 +2680,7 @@ namespace OpenSim.Region.ClientStack try { byte[] sendbuffer = Pack.ToBytes(); - PacketPool.Instance.ReturnPacket(Pack); + PacketPool.Instance.ReturnPacket(Pack); if (Pack.Header.Zerocoded) { @@ -2651,8 +2689,11 @@ namespace OpenSim.Region.ClientStack } else { - m_networkServer.SendPacketTo(sendbuffer, sendbuffer.Length, SocketFlags.None, m_circuitCode); + //Need some extra space in case we need to add proxy information to the message later + Buffer.BlockCopy(sendbuffer, 0, ZeroOutBuffer, 0, sendbuffer.Length); + m_networkServer.SendPacketTo(ZeroOutBuffer, sendbuffer.Length, SocketFlags.None, m_circuitCode); } + } catch (Exception e) { @@ -2666,6 +2707,12 @@ namespace OpenSim.Region.ClientStack public virtual void InPacket(Packet NewPack) { + if(!m_packetProcessingEnabled && NewPack.Type != PacketType.LogoutRequest) + { + PacketPool.Instance.ReturnPacket(NewPack); + return; + } + // Handle appended ACKs if (NewPack != null) { @@ -2726,6 +2773,15 @@ namespace OpenSim.Region.ClientStack public virtual void OutPacket(Packet NewPack, ThrottleOutPacketType throttlePacketType) { + if ((SynchronizeClient != null) && (!PacketProcessingEnabled)) + { + // Sending packet to active client's server. + if (SynchronizeClient(m_scene, NewPack, m_agentId, throttlePacketType)) + { + return; + } + } + QueItem item = new QueItem(); item.Packet = NewPack; item.Incoming = false; @@ -2853,6 +2909,13 @@ namespace OpenSim.Region.ClientStack } } + private bool m_packetProcessingEnabled = true; + + public bool PacketProcessingEnabled { + get { return m_packetProcessingEnabled; } + set { m_packetProcessingEnabled = value; } + } + protected void ProcessInPacket(Packet Pack) { ack_pack(Pack); @@ -4373,5 +4436,79 @@ namespace OpenSim.Region.ClientStack OutPacket(logReply, ThrottleOutPacketType.Task); } + + public ClientInfo GetClientInfo() + { + //MainLog.Instance.Verbose("CLIENT", "GetClientInfo BGN"); + + ClientInfo info = new ClientInfo(); + info.userEP = this.m_userEndPoint; + info.proxyEP = this.m_proxyEndPoint; + info.agentcircuit = new sAgentCircuitData(RequestClientInfo()); + + info.pendingAcks = m_pendingAcks; + + info.needAck = new Dictionary(); + + lock (m_needAck) + { + foreach (uint key in m_needAck.Keys) + { + info.needAck.Add(key, m_needAck[key].ToBytes()); + } + } + +/* pending + QueItem[] queitems = m_packetQueue.GetQueueArray(); + + MainLog.Instance.Verbose("CLIENT", "Queue Count : [{0}]", queitems.Length); + + for (int i = 0; i < queitems.Length; i++) + { + if (queitems[i].Incoming == false) + { + info.out_packets.Add(queitems[i].Packet.ToBytes()); + MainLog.Instance.Verbose("CLIENT", "Add OutPacket [{0}]", queitems[i].Packet.Type.ToString()); + } + } +*/ + + info.sequence = m_sequence; + + //MainLog.Instance.Verbose("CLIENT", "GetClientInfo END"); + + return info; + } + + public void SetClientInfo(ClientInfo info) + { + m_pendingAcks = info.pendingAcks; + + m_needAck = new Dictionary(); + + Packet packet = null; + int packetEnd = 0; + byte[] zero = new byte[3000]; + + foreach (uint key in info.needAck.Keys) + { + byte[] buff = info.needAck[key]; + + packetEnd = buff.Length - 1; + + try + { + packet = PacketPool.Instance.GetPacket(buff, ref packetEnd, zero); + } + catch (Exception) + { + //MainLog.Instance.Debug("UDPSERVER", e.ToString()); + } + + m_needAck.Add(key, packet); + } + + m_sequence = info.sequence; + } } } diff --git a/OpenSim/Region/ClientStack/PacketQueue.cs b/OpenSim/Region/ClientStack/PacketQueue.cs index a04828f1d3..82f96e88bf 100644 --- a/OpenSim/Region/ClientStack/PacketQueue.cs +++ b/OpenSim/Region/ClientStack/PacketQueue.cs @@ -142,8 +142,13 @@ namespace OpenSim.Region.ClientStack // We could micro lock, but that will tend to actually // probably be worse than just synchronizing on SendQueue - lock (this) + if (item == null) { + SendQueue.Enqueue(item); + return; + } + + lock (this) { switch (item.throttleType) { case ThrottleOutPacketType.Resend: @@ -518,5 +523,10 @@ namespace OpenSim.Region.ClientStack TextureOutgoingPacketQueue.Count, AssetOutgoingPacketQueue.Count); } + + public QueItem[] GetQueueArray() + { + return SendQueue.GetQueueArray(); + } } } diff --git a/OpenSim/Region/ClientStack/PacketServer.cs b/OpenSim/Region/ClientStack/PacketServer.cs index 250b90afcb..02ae79be45 100644 --- a/OpenSim/Region/ClientStack/PacketServer.cs +++ b/OpenSim/Region/ClientStack/PacketServer.cs @@ -74,14 +74,14 @@ namespace OpenSim.Region.ClientStack protected virtual IClientAPI CreateNewClient(EndPoint remoteEP, UseCircuitCodePacket initialcirpack, ClientManager clientManager, IScene scene, AssetCache assetCache, PacketServer packServer, AgentCircuitManager authenSessions, - LLUUID agentId, LLUUID sessionId, uint circuitCode) + LLUUID agentId, LLUUID sessionId, uint circuitCode, EndPoint proxyEP) { return - new ClientView(remoteEP, scene, assetCache, packServer, authenSessions, agentId, sessionId, circuitCode); + new ClientView(remoteEP, scene, assetCache, packServer, authenSessions, agentId, sessionId, circuitCode, proxyEP); } public virtual bool AddNewClient(EndPoint epSender, UseCircuitCodePacket useCircuit, AssetCache assetCache, - AgentCircuitManager authenticateSessionsClass) + AgentCircuitManager authenticateSessionsClass, EndPoint proxyEP) { IClientAPI newuser; @@ -93,7 +93,7 @@ namespace OpenSim.Region.ClientStack { newuser = CreateNewClient(epSender, useCircuit, m_scene.ClientManager, m_scene, assetCache, this, authenticateSessionsClass, useCircuit.CircuitCode.ID, - useCircuit.CircuitCode.SessionID, useCircuit.CircuitCode.Code); + useCircuit.CircuitCode.SessionID, useCircuit.CircuitCode.Code, proxyEP); m_scene.ClientManager.Add(useCircuit.CircuitCode.Code, newuser); diff --git a/OpenSim/Region/ClientStack/RegionApplicationBase.cs b/OpenSim/Region/ClientStack/RegionApplicationBase.cs index a760712b84..660c3b302d 100644 --- a/OpenSim/Region/ClientStack/RegionApplicationBase.cs +++ b/OpenSim/Region/ClientStack/RegionApplicationBase.cs @@ -103,6 +103,11 @@ namespace OpenSim.Region.ClientStack } protected Scene SetupScene(RegionInfo regionInfo, out UDPServer udpServer, bool m_permissions) + { + return SetupScene(regionInfo, 0, out udpServer, m_permissions); + } + + protected Scene SetupScene(RegionInfo regionInfo, int proxyOffset, out UDPServer udpServer, bool m_permissions) { AgentCircuitManager circuitManager = new AgentCircuitManager(); IPAddress listenIP = regionInfo.InternalEndPoint.Address; @@ -110,7 +115,7 @@ namespace OpenSim.Region.ClientStack // listenIP = IPAddress.Parse("0.0.0.0"); uint port = (uint) regionInfo.InternalEndPoint.Port; - udpServer = new UDPServer(listenIP, ref port, regionInfo.m_allow_alternate_ports, m_assetCache, circuitManager); + udpServer = new UDPServer(listenIP, ref port, proxyOffset, regionInfo.m_allow_alternate_ports, m_assetCache, circuitManager); regionInfo.InternalEndPoint.Port = (int)port; Scene scene = CreateScene(regionInfo, m_storageManager, circuitManager); @@ -148,8 +153,8 @@ namespace OpenSim.Region.ClientStack scene.RegionInfo.MasterAvatarAssignedUUID = LLUUID.Zero; } - scene.LoadPrimsFromStorage(m_permissions); - scene.loadAllLandObjectsFromStorage(); + scene.LoadPrimsFromStorage(m_permissions, regionInfo.originRegionID); + scene.loadAllLandObjectsFromStorage(regionInfo.originRegionID); scene.performParcelPrimCountUpdate(); scene.StartTimer(); return scene; diff --git a/OpenSim/Region/ClientStack/UDPServer.cs b/OpenSim/Region/ClientStack/UDPServer.cs index 9c572cf44a..5501d3f839 100644 --- a/OpenSim/Region/ClientStack/UDPServer.cs +++ b/OpenSim/Region/ClientStack/UDPServer.cs @@ -43,12 +43,15 @@ namespace OpenSim.Region.ClientStack protected Dictionary clientCircuits = new Dictionary(); public Dictionary clientCircuits_reverse = new Dictionary(); + protected Dictionary proxyCircuits = new Dictionary(); public Socket Server; protected IPEndPoint ServerIncoming; protected byte[] RecvBuffer = new byte[4096]; protected byte[] ZeroBuffer = new byte[8192]; protected IPEndPoint ipeSender; protected EndPoint epSender; + protected EndPoint epProxy; + protected int proxyPortOffset; protected AsyncCallback ReceivedData; protected PacketServer m_packetServer; protected ulong m_regionHandle; @@ -85,10 +88,11 @@ namespace OpenSim.Region.ClientStack { } - public UDPServer(IPAddress _listenIP, ref uint port, bool allow_alternate_port, AssetCache assetCache, AgentCircuitManager authenticateClass) + public UDPServer(IPAddress _listenIP, ref uint port, int proxyPortOffset, bool allow_alternate_port, AssetCache assetCache, AgentCircuitManager authenticateClass) { + this.proxyPortOffset = proxyPortOffset; + listenPort = (uint) (port + proxyPortOffset); listenIP = _listenIP; - listenPort = port; Allow_Alternate_Port = allow_alternate_port; m_assetCache = assetCache; m_authenticateSessionsClass = authenticateClass; @@ -97,7 +101,7 @@ namespace OpenSim.Region.ClientStack // Return new port // This because in Grid mode it is not really important what port the region listens to as long as it is correctly registered. // So the option allow_alternate_ports="true" was added to default.xml - port = listenPort; + port = (uint)(listenPort - proxyPortOffset); } protected virtual void CreatePacketServer() @@ -211,6 +215,13 @@ namespace OpenSim.Region.ClientStack //return; } + //System.Console.WriteLine("UDPServer : recieved message from {0}", epSender.ToString()); + epProxy = epSender; + if (proxyPortOffset != 0) + { + epSender = PacketPool.DecodeProxyMessage(RecvBuffer, ref numBytes); + } + int packetEnd = numBytes - 1; try @@ -318,6 +329,9 @@ namespace OpenSim.Region.ClientStack protected virtual void AddNewClient(Packet packet) { + //Slave regions don't accept new clients + if(m_localScene.Region_Status != RegionStatus.SlaveScene) + { UseCircuitCodePacket useCircuit = (UseCircuitCodePacket) packet; lock (clientCircuits) { @@ -334,7 +348,17 @@ namespace OpenSim.Region.ClientStack m_log.Error("[UDPSERVER]: clientCurcuits_reverse already contains entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding."); } - PacketServer.AddNewClient(epSender, useCircuit, m_assetCache, m_authenticateSessionsClass); + lock (proxyCircuits) + { + if (!proxyCircuits.ContainsKey(useCircuit.CircuitCode.Code)) + proxyCircuits.Add(useCircuit.CircuitCode.Code, epProxy); + else + m_log.Error("[UDPSERVER]: proxyCircuits already contains entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding."); + } + + PacketServer.AddNewClient(epSender, useCircuit, m_assetCache, m_authenticateSessionsClass, epProxy); + } + PacketPool.Instance.ReturnPacket(packet); } public void ServerListener() @@ -387,10 +411,20 @@ namespace OpenSim.Region.ClientStack lock (clientCircuits_reverse) { if (clientCircuits_reverse.TryGetValue(circuitcode, out sendto)) - { - //we found the endpoint so send the packet to it - Server.SendTo(buffer, size, flags, sendto); - } + { + //we found the endpoint so send the packet to it + if (proxyPortOffset != 0) + { + //MainLog.Instance.Verbose("UDPSERVER", "SendPacketTo proxy " + proxyCircuits[circuitcode].ToString() + ": client " + sendto.ToString()); + PacketPool.EncodeProxyMessage(buffer, ref size, sendto); + Server.SendTo(buffer, size, flags, proxyCircuits[circuitcode]); + } + else + { + //MainLog.Instance.Verbose("UDPSERVER", "SendPacketTo : client " + sendto.ToString()); + Server.SendTo(buffer, size, flags, sendto); + } + } } } @@ -404,8 +438,50 @@ namespace OpenSim.Region.ClientStack clientCircuits.Remove(sendto); clientCircuits_reverse.Remove(circuitcode); + proxyCircuits.Remove(circuitcode); } } } + + public void RestoreClient(AgentCircuitData circuit, EndPoint userEP, EndPoint proxyEP) + { + //MainLog.Instance.Verbose("UDPSERVER", "RestoreClient"); + + UseCircuitCodePacket useCircuit = new UseCircuitCodePacket(); + useCircuit.CircuitCode.Code = circuit.circuitcode; + useCircuit.CircuitCode.ID = circuit.AgentID; + useCircuit.CircuitCode.SessionID = circuit.SessionID; + + lock (clientCircuits) + { + if (!clientCircuits.ContainsKey(userEP)) + clientCircuits.Add(userEP, useCircuit.CircuitCode.Code); + else + m_log.Error("[UDPSERVER]: clientCircuits already contans entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding."); + } + lock (clientCircuits_reverse) + { + if (!clientCircuits_reverse.ContainsKey(useCircuit.CircuitCode.Code)) + clientCircuits_reverse.Add(useCircuit.CircuitCode.Code, userEP); + else + m_log.Error("[UDPSERVER]: clientCurcuits_reverse already contains entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding."); + } + + lock (proxyCircuits) + { + if (!proxyCircuits.ContainsKey(useCircuit.CircuitCode.Code)) + { + proxyCircuits.Add(useCircuit.CircuitCode.Code, proxyEP); + } + else + { + // re-set proxy endpoint + proxyCircuits.Remove(useCircuit.CircuitCode.Code); + proxyCircuits.Add(useCircuit.CircuitCode.Code, proxyEP); + } + } + + PacketServer.AddNewClient(userEP, useCircuit, m_assetCache, m_authenticateSessionsClass, proxyEP); + } } } diff --git a/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs b/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs index 12c91acfd2..cdafad31a8 100644 --- a/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs +++ b/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs @@ -111,6 +111,8 @@ namespace OpenSim.Region.Communications.OGS1 GridParams["http_port"] = serversInfo.HttpListenerPort.ToString(); GridParams["remoting_port"] = NetworkServersInfo.RemotingListenerPort.ToString(); GridParams["map-image-id"] = regionInfo.EstateSettings.terrainImageID.ToString(); + GridParams["originUUID"] = regionInfo.originRegionID.ToString(); + GridParams["server_uri"] = regionInfo.ServerURI; // part of an initial brutish effort to provide accurate information (as per the xml region spec) // wrt the ownership of a given region @@ -165,7 +167,30 @@ namespace OpenSim.Region.Communications.OGS1 public bool DeregisterRegion(RegionInfo regionInfo) { - return false; + Hashtable GridParams = new Hashtable(); + + GridParams["UUID"] = regionInfo.RegionID.ToString(); + + // Package into an XMLRPC Request + ArrayList SendParams = new ArrayList(); + SendParams.Add(GridParams); + + // Send Request + XmlRpcRequest GridReq = new XmlRpcRequest("simulator_after_region_moved", SendParams); + XmlRpcResponse GridResp = GridReq.Send(serversInfo.GridURL, 10000); + Hashtable GridRespData = (Hashtable) GridResp.Value; + + Hashtable griddatahash = GridRespData; + + // Process Response + if (GridRespData.ContainsKey("error")) { + string errorstring = (string)GridRespData["error"]; + m_log.Error("Unable to connect to grid: " + errorstring); + return false; + } + + // What does DeregisterRegion() do? + return m_localBackend.DeregisterRegion(regionInfo); } public virtual Dictionary GetGridSettings() @@ -1209,7 +1234,6 @@ namespace OpenSim.Region.Communications.OGS1 } return m_localBackend.TriggerRegionUp(new RegionInfo(regionData), regionhandle); - } catch (RemotingException e) diff --git a/OpenSim/Region/Environment/Scenes/AvatarAppearance.cs b/OpenSim/Region/Environment/Scenes/AvatarAppearance.cs index b54f777404..fcc8fdfaea 100644 --- a/OpenSim/Region/Environment/Scenes/AvatarAppearance.cs +++ b/OpenSim/Region/Environment/Scenes/AvatarAppearance.cs @@ -26,13 +26,16 @@ * */ +using System; using libsecondlife; using libsecondlife.Packets; using OpenSim.Framework; - +using System.Runtime.Serialization; +using System.Security.Permissions; namespace OpenSim.Region.Environment.Scenes { - public class AvatarAppearance + [Serializable] + public class AvatarAppearance : ISerializable { protected LLUUID m_scenePresenceID; @@ -149,5 +152,45 @@ namespace OpenSim.Region.Environment.Scenes textu.CreateFace(6).TextureID = new LLUUID("00000000-0000-1111-9999-000000000011"); return textu; } + + protected AvatarAppearance(SerializationInfo info, StreamingContext context) + { + //System.Console.WriteLine("AvatarAppearance Deserialize BGN"); + + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + m_scenePresenceID = new LLUUID((Guid)info.GetValue("m_scenePresenceID", typeof(Guid))); + m_wearablesSerial = (int)info.GetValue("m_wearablesSerial", typeof(int)); + m_visualParams = (byte[])info.GetValue("m_visualParams", typeof(byte[])); + m_wearables = (AvatarWearable[])info.GetValue("m_wearables", typeof(AvatarWearable[])); + + byte[] m_textureEntry_work = (byte[])info.GetValue("m_textureEntry", typeof(byte[])); + m_textureEntry = new LLObject.TextureEntry(m_textureEntry_work, 0, m_textureEntry_work.Length); + + m_avatarHeight = (float)info.GetValue("m_avatarHeight", typeof(float)); + + //System.Console.WriteLine("AvatarAppearance Deserialize END"); + } + + [SecurityPermission(SecurityAction.LinkDemand, + Flags = SecurityPermissionFlag.SerializationFormatter)] + public virtual void GetObjectData( + SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + info.AddValue("m_scenePresenceID", m_scenePresenceID.UUID); + info.AddValue("m_wearablesSerial", m_wearablesSerial); + info.AddValue("m_visualParams", m_visualParams); + info.AddValue("m_wearables", m_wearables); + info.AddValue("m_textureEntry", m_textureEntry.ToBytes()); + info.AddValue("m_avatarHeight", m_avatarHeight); + } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Environment/Scenes/EntityBase.cs b/OpenSim/Region/Environment/Scenes/EntityBase.cs index 91dda74caa..2a8c1e940f 100644 --- a/OpenSim/Region/Environment/Scenes/EntityBase.cs +++ b/OpenSim/Region/Environment/Scenes/EntityBase.cs @@ -30,9 +30,14 @@ using System.Collections.Generic; using Axiom.Math; using libsecondlife; +using System; +using System.Runtime.Serialization; +using System.Security.Permissions; + namespace OpenSim.Region.Environment.Scenes { - public abstract class EntityBase + [Serializable] + public abstract class EntityBase : ISerializable { protected Scene m_scene; @@ -134,6 +139,90 @@ namespace OpenSim.Region.Environment.Scenes public abstract void SetText(string text, Vector3 color, double alpha); + + protected EntityBase(SerializationInfo info, StreamingContext context) + { + //System.Console.WriteLine("EntityBase Deserialize BGN"); + + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + //JB m_children = (List)info.GetValue("m_children", typeof(List)); +// m_scene = (Scene)info.GetValue("m_scene", typeof(Scene)); + m_uuid = new LLUUID((Guid)info.GetValue("m_uuid", typeof(Guid))); + m_name = (string)info.GetValue("m_name", typeof(string)); + + m_pos + = new LLVector3( + (float)info.GetValue("m_pos.X", typeof(float)), + (float)info.GetValue("m_pos.Y", typeof(float)), + (float)info.GetValue("m_pos.Z", typeof(float))); + + m_velocity + = new LLVector3( + (float)info.GetValue("m_velocity.X", typeof(float)), + (float)info.GetValue("m_velocity.Y", typeof(float)), + (float)info.GetValue("m_velocity.Z", typeof(float))); + + m_rotationalvelocity + = new LLVector3( + (float)info.GetValue("m_rotationalvelocity.X", typeof(float)), + (float)info.GetValue("m_rotationalvelocity.Y", typeof(float)), + (float)info.GetValue("m_rotationalvelocity.Z", typeof(float))); + + m_rotation + = new Quaternion( + (float)info.GetValue("m_rotation.w", typeof(float)), + (float)info.GetValue("m_rotation.x", typeof(float)), + (float)info.GetValue("m_rotation.y", typeof(float)), + (float)info.GetValue("m_rotation.z", typeof(float))); + + m_localId = (uint)info.GetValue("m_localId", typeof(uint)); + + //System.Console.WriteLine("EntityBase Deserialize END"); + } + + [SecurityPermission(SecurityAction.LinkDemand, + Flags = SecurityPermissionFlag.SerializationFormatter)] + public virtual void GetObjectData( + SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + //JB info.AddValue("m_children", m_children); + +// info.AddValue("m_scene", m_scene); + info.AddValue("m_uuid", m_uuid.UUID); + info.AddValue("m_name", m_name); + + // LLVector3 + info.AddValue("m_pos.X", m_pos.X); + info.AddValue("m_pos.Y", m_pos.Y); + info.AddValue("m_pos.Z", m_pos.Z); + + // LLVector3 + info.AddValue("m_velocity.X", m_velocity.X); + info.AddValue("m_velocity.Y", m_velocity.Y); + info.AddValue("m_velocity.Z", m_velocity.Z); + + // LLVector3 + info.AddValue("m_rotationalvelocity.X", m_rotationalvelocity.X); + info.AddValue("m_rotationalvelocity.Y", m_rotationalvelocity.Y); + info.AddValue("m_rotationalvelocity.Z", m_rotationalvelocity.Z); + + // Quaternion + info.AddValue("m_rotation.w", m_rotation.w); + info.AddValue("m_rotation.x", m_rotation.x); + info.AddValue("m_rotation.y", m_rotation.y); + info.AddValue("m_rotation.z", m_rotation.z); + + info.AddValue("m_localId", m_localId); + } } //Nested Classes diff --git a/OpenSim/Region/Environment/Scenes/InnerScene.cs b/OpenSim/Region/Environment/Scenes/InnerScene.cs index 860f5fb69f..882e58985f 100644 --- a/OpenSim/Region/Environment/Scenes/InnerScene.cs +++ b/OpenSim/Region/Environment/Scenes/InnerScene.cs @@ -57,6 +57,7 @@ namespace OpenSim.Region.Environment.Scenes // SceneObjects is not currently populated or used. //public Dictionary SceneObjects; public Dictionary Entities; + public Dictionary RestorePresences; public BasicQuadTreeNode QuadTree; @@ -455,6 +456,48 @@ namespace OpenSim.Region.Environment.Scenes return newAvatar; } + public void AddScenePresence(ScenePresence presence) + { + bool child = presence.IsChildAgent; + + if (child) + { + m_numChildAgents++; + m_log.Info("[SCENE]"+ m_regInfo.RegionName + ": Creating new child agent."); + } + else + { + m_numRootAgents++; + m_log.Info("[SCENE] "+ m_regInfo.RegionName + ": Creating new root agent."); + m_log.Info("[SCENE] "+ m_regInfo.RegionName + ": Adding Physical agent."); + + presence.AddToPhysicalScene(); + } + + lock (Entities) + { + if (!Entities.ContainsKey(presence.m_uuid)) + { + Entities.Add(presence.m_uuid, presence); + } + else + { + Entities[presence.m_uuid] = presence; + } + } + lock (ScenePresences) + { + if (ScenePresences.ContainsKey(presence.m_uuid)) + { + ScenePresences[presence.m_uuid] = presence; + } + else + { + ScenePresences.Add(presence.m_uuid, presence); + } + } + } + public void SwapRootChildAgent(bool direction_RC_CR_T_F) { if (direction_RC_CR_T_F) diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index 845de22807..43e7e99db3 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs @@ -54,6 +54,10 @@ namespace OpenSim.Region.Environment.Scenes public partial class Scene : SceneBase { + public delegate void SynchronizeSceneHandler(Scene scene); + public SynchronizeSceneHandler SynchronizeScene = null; + public int splitID = 0; + #region Fields protected Timer m_heartbeatTimer = new Timer(); @@ -216,7 +220,11 @@ namespace OpenSim.Region.Environment.Scenes get { return m_innerScene.Entities; } set { m_innerScene.Entities = value; } } - + public Dictionary m_restorePresences + { + get { return m_innerScene.RestorePresences; } + set { m_innerScene.RestorePresences = value; } + } #endregion #region Constructors @@ -276,6 +284,7 @@ namespace OpenSim.Region.Environment.Scenes Entities = new Dictionary(); m_scenePresences = new Dictionary(); //m_sceneObjects = new Dictionary(); + m_restorePresences = new Dictionary(); m_log.Info("[SCENE]: Creating LandMap"); Terrain = new TerrainEngine((int)RegionInfo.RegionLocX, (int)RegionInfo.RegionLocY); @@ -701,6 +710,8 @@ namespace OpenSim.Region.Environment.Scenes physicsFPS = m_innerScene.UpdatePhysics( Math.Max(SinceLastFrame.TotalSeconds, m_timespan) ); + if (m_frame % m_update_physics == 0 && SynchronizeScene != null) + SynchronizeScene(this); physicsMS = System.Environment.TickCount - physicsMS; physicsMS += physicsMS2; @@ -719,6 +730,8 @@ namespace OpenSim.Region.Environment.Scenes if (m_frame % m_update_presences == 0) m_innerScene.UpdatePresences(); + if (Region_Status != RegionStatus.SlaveScene) + { if (m_frame % m_update_events == 0) UpdateEvents(); @@ -747,7 +760,7 @@ namespace OpenSim.Region.Environment.Scenes m_statsReporter.addOtherMS(otherMS); m_statsReporter.SetActiveScripts(m_innerScene.GetActiveScripts()); m_statsReporter.addScriptLines(m_innerScene.GetScriptLPS()); - + } } catch (NotImplementedException) { @@ -1058,10 +1071,10 @@ namespace OpenSim.Region.Environment.Scenes #region Load Land - public void loadAllLandObjectsFromStorage() + public void loadAllLandObjectsFromStorage(LLUUID regionID) { m_log.Info("[SCENE]: Loading land objects from storage"); - List landData = m_storageManager.DataStore.LoadLandObjects(RegionInfo.RegionID); + List landData = m_storageManager.DataStore.LoadLandObjects(regionID); if (landData.Count == 0) { @@ -1080,11 +1093,11 @@ namespace OpenSim.Region.Environment.Scenes /// /// Loads the World's objects /// - public virtual void LoadPrimsFromStorage(bool m_permissions) + public virtual void LoadPrimsFromStorage(bool m_permissions, LLUUID regionID) { m_log.Info("[SCENE]: Loading objects from datastore"); - List PrimsFromDB = m_storageManager.DataStore.LoadObjects(m_regInfo.RegionID); + List PrimsFromDB = m_storageManager.DataStore.LoadObjects(regionID); foreach (SceneObjectGroup group in PrimsFromDB) { AddEntityFromStorage(group); @@ -1339,13 +1352,35 @@ namespace OpenSim.Region.Environment.Scenes { m_log.Warn("[CONNECTION DEBUGGING]: Creating new client for " + client.AgentId.ToString()); SubscribeToClientEvents(client); + ScenePresence presence = null; - m_estateManager.sendRegionHandshake(client); + if (m_restorePresences.ContainsKey(client.AgentId)) + { + m_log.Info("REGION Restore Scene Presence"); - CreateAndAddScenePresence(client, child); + presence = m_restorePresences[client.AgentId]; + m_restorePresences.Remove(client.AgentId); - m_LandManager.sendParcelOverlay(client); - CommsManager.UserProfileCacheService.AddNewUser(client.AgentId); + presence.initializeScenePresence(client, RegionInfo, this); + + m_innerScene.AddScenePresence(presence); + + lock (m_restorePresences) + { + Monitor.PulseAll(m_restorePresences); + } + } + else + { + m_log.Info("REGION Add New Scene Presence"); + + m_estateManager.sendRegionHandshake(client); + + CreateAndAddScenePresence(client, child); + + m_LandManager.sendParcelOverlay(client); + CommsManager.UserProfileCacheService.AddNewUser(client.AgentId); + } } protected virtual void SubscribeToClientEvents(IClientAPI client) diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs index a6a5063d0a..46bb89cb87 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs @@ -39,6 +39,8 @@ using OpenSim.Framework.Console; using OpenSim.Region.Environment.Interfaces; using OpenSim.Region.Environment.Scenes.Scripting; using OpenSim.Region.Physics.Manager; +using System.Runtime.Serialization; +using System.Security.Permissions; namespace OpenSim.Region.Environment.Scenes { @@ -82,7 +84,8 @@ namespace OpenSim.Region.Environment.Scenes SCALE = 0x40 } - public partial class SceneObjectPart : IScriptHost + [Serializable] + public partial class SceneObjectPart : IScriptHost, ISerializable { [XmlIgnore] public PhysicsActor PhysActor = null; @@ -1859,5 +1862,119 @@ namespace OpenSim.Region.Environment.Scenes (int) (color.z*0xff)); Text = text; } + + protected SceneObjectPart(SerializationInfo info, StreamingContext context) + { + //System.Console.WriteLine("SceneObjectPart Deserialize BGN"); + + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + /* + m_queue = (Queue)info.GetValue("m_queue", typeof(Queue)); + m_ids = (List)info.GetValue("m_ids", typeof(List)); + */ + + //System.Console.WriteLine("SceneObjectPart Deserialize END"); + } + + [SecurityPermission(SecurityAction.LinkDemand, + Flags = SecurityPermissionFlag.SerializationFormatter)] + public virtual void GetObjectData( + SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + info.AddValue("m_inventoryFileName", m_inventoryFileName); + info.AddValue("m_folderID", m_folderID.UUID); + info.AddValue("PhysActor", PhysActor); + + Dictionary TaskInventory_work = new Dictionary(); + + foreach (LLUUID id in TaskInventory.Keys) + { + TaskInventory_work.Add(id.UUID, TaskInventory[id]); + } + + info.AddValue("TaskInventory", TaskInventory_work); + + info.AddValue("LastOwnerID", LastOwnerID.UUID); + info.AddValue("OwnerID", OwnerID.UUID); + info.AddValue("GroupID", GroupID.UUID); + + info.AddValue("OwnershipCost", OwnershipCost); + info.AddValue("ObjectSaleType", ObjectSaleType); + info.AddValue("SalePrice", SalePrice); + info.AddValue("Category", Category); + + info.AddValue("CreationDate", CreationDate); + info.AddValue("ParentID", ParentID); + + info.AddValue("OwnerMask", OwnerMask); + info.AddValue("NextOwnerMask", NextOwnerMask); + info.AddValue("GroupMask", GroupMask); + info.AddValue("EveryoneMask", EveryoneMask); + info.AddValue("BaseMask", BaseMask); + + info.AddValue("m_particleSystem", m_particleSystem); + + info.AddValue("TimeStampFull", TimeStampFull); + info.AddValue("TimeStampTerse", TimeStampTerse); + info.AddValue("TimeStampLastActivity", TimeStampLastActivity); + + info.AddValue("m_updateFlag", m_updateFlag); + info.AddValue("CreatorID", CreatorID.UUID); + + info.AddValue("m_inventorySerial", m_inventorySerial); + info.AddValue("m_uuid", m_uuid.UUID); + info.AddValue("m_localID", m_localID); + info.AddValue("m_name", m_name); + info.AddValue("m_flags", Flags); + info.AddValue("m_material", m_material); + info.AddValue("m_regionHandle", m_regionHandle); + + info.AddValue("m_groupPosition.X", m_groupPosition.X); + info.AddValue("m_groupPosition.Y", m_groupPosition.Y); + info.AddValue("m_groupPosition.Z", m_groupPosition.Z); + + info.AddValue("m_offsetPosition.X", m_offsetPosition.X); + info.AddValue("m_offsetPosition.Y", m_offsetPosition.Y); + info.AddValue("m_offsetPosition.Z", m_offsetPosition.Z); + + info.AddValue("m_rotationOffset.W", m_rotationOffset.W); + info.AddValue("m_rotationOffset.X", m_rotationOffset.X); + info.AddValue("m_rotationOffset.Y", m_rotationOffset.Y); + info.AddValue("m_rotationOffset.Z", m_rotationOffset.Z); + + info.AddValue("m_velocity.X", m_velocity.X); + info.AddValue("m_velocity.Y", m_velocity.Y); + info.AddValue("m_velocity.Z", m_velocity.Z); + + info.AddValue("m_rotationalvelocity.X", m_rotationalvelocity.X); + info.AddValue("m_rotationalvelocity.Y", m_rotationalvelocity.Y); + info.AddValue("m_rotationalvelocity.Z", m_rotationalvelocity.Z); + + info.AddValue("m_angularVelocity.X", m_angularVelocity.X); + info.AddValue("m_angularVelocity.Y", m_angularVelocity.Y); + info.AddValue("m_angularVelocity.Z", m_angularVelocity.Z); + + info.AddValue("m_acceleration.X", m_acceleration.X); + info.AddValue("m_acceleration.Y", m_acceleration.Y); + info.AddValue("m_acceleration.Z", m_acceleration.Z); + + info.AddValue("m_description", m_description); + info.AddValue("m_color", m_color); + info.AddValue("m_text", m_text); + info.AddValue("m_sitName", m_sitName); + info.AddValue("m_touchName", m_touchName); + info.AddValue("m_clickAction", m_clickAction); + info.AddValue("m_shape", m_shape); + info.AddValue("m_parentGroup", m_parentGroup); + } } } diff --git a/OpenSim/Region/Environment/Scenes/ScenePresence.cs b/OpenSim/Region/Environment/Scenes/ScenePresence.cs index 2c201ba71a..fabc3ed0a6 100644 --- a/OpenSim/Region/Environment/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Environment/Scenes/ScenePresence.cs @@ -34,10 +34,14 @@ using OpenSim.Framework; using OpenSim.Framework.Console; using OpenSim.Region.Environment.Types; using OpenSim.Region.Physics.Manager; +using OpenSim.Region.Environment.Interfaces; +using System.Runtime.Serialization; +using System.Security.Permissions; namespace OpenSim.Region.Environment.Scenes { - public class ScenePresence : EntityBase + [Serializable] + public class ScenePresence : EntityBase, ISerializable { // ~ScenePresence() // { @@ -156,6 +160,12 @@ namespace OpenSim.Region.Environment.Scenes get { return m_physicsActor; } } + public byte MovementFlag + { + set { m_movementflag = value; } + get { return m_movementflag; } + } + public bool KnownPrim(LLUUID primID) { if (m_knownPrimUUID.Contains(primID)) @@ -215,13 +225,14 @@ namespace OpenSim.Region.Environment.Scenes /// /// This works out to be the ClientView object associated with this avatar, or it's UDP connection manager /// - private readonly IClientAPI m_controllingClient; + private IClientAPI m_controllingClient; protected PhysicsActor m_physicsActor; public IClientAPI ControllingClient { get { return m_controllingClient; } + set { m_controllingClient = value; } } protected LLVector3 m_parentPosition = new LLVector3(); @@ -379,7 +390,7 @@ namespace OpenSim.Region.Environment.Scenes m_appearance = appearance; } - private void RegisterToEvents() + public void RegisterToEvents() { m_controllingClient.OnRequestWearables += SendOwnAppearance; m_controllingClient.OnSetAppearance += SetAppearance; @@ -1706,6 +1717,7 @@ namespace OpenSim.Region.Environment.Scenes DefaultTexture = textu.ToBytes(); } + [Serializable] public class NewForce { public float X; @@ -1717,7 +1729,8 @@ namespace OpenSim.Region.Environment.Scenes } } - public class ScenePartUpdate + [Serializable] + public class ScenePartUpdate : ISerializable { public LLUUID FullID; public uint LastFullUpdateTime; @@ -1729,6 +1742,38 @@ namespace OpenSim.Region.Environment.Scenes LastFullUpdateTime = 0; LastTerseUpdateTime = 0; } + + protected ScenePartUpdate(SerializationInfo info, StreamingContext context) + { + //System.Console.WriteLine("ScenePartUpdate Deserialize BGN"); + + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + FullID = new LLUUID((Guid)info.GetValue("FullID", typeof(Guid))); + LastFullUpdateTime = (uint)info.GetValue("LastFullUpdateTime", typeof(uint)); + LastTerseUpdateTime = (uint)info.GetValue("LastTerseUpdateTime", typeof(uint)); + + //System.Console.WriteLine("ScenePartUpdate Deserialize END"); + } + + [SecurityPermission(SecurityAction.LinkDemand, + Flags = SecurityPermissionFlag.SerializationFormatter)] + public virtual void GetObjectData( + SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + info.AddValue("FullID", FullID.UUID); + info.AddValue("LastFullUpdateTime", LastFullUpdateTime); + info.AddValue("LastTerseUpdateTime", LastTerseUpdateTime); + + } } public override void SetText(string text, Vector3 color, double alpha) @@ -1787,5 +1832,368 @@ namespace OpenSim.Region.Environment.Scenes RemoveFromPhysicalScene(); GC.Collect(); } + + public ScenePresence() + { +/* JB + if (Animations == null) + { + Animations = new AvatarAnimations(); + Animations.LoadAnims(); + } +*/ + if (DefaultTexture == null) + { + LLObject.TextureEntry textu = AvatarAppearance.GetDefaultTextureEntry(); + DefaultTexture = textu.ToBytes(); + } + } + + public void initializeScenePresence(IClientAPI client, RegionInfo region, Scene scene) + { + m_controllingClient = client; + m_regionInfo = region; + m_scene = scene; + RegisterToEvents(); + + /* + AbsolutePosition = client.StartPos; + + Animations = new AvatarAnimations(); + Animations.LoadAnims(); + + m_animations = new List(); + m_animations.Add(Animations.AnimsLLUUID["STAND"]); + m_animationSeqs.Add(1); + + SetDirectionVectors(); + */ + } + + protected ScenePresence(SerializationInfo info, StreamingContext context) + : base (info, context) + { + //System.Console.WriteLine("ScenePresence Deserialize BGN"); + + if (info == null) + { + throw new System.ArgumentNullException("info"); + } +/* JB + if (Animations == null) + { + Animations = new AvatarAnimations(); + Animations.LoadAnims(); + } +*/ + if (DefaultTexture == null) + { + LLObject.TextureEntry textu = AvatarAppearance.GetDefaultTextureEntry(); + DefaultTexture = textu.ToBytes(); + } + + List animations_work = (List)info.GetValue("m_animations", typeof(List)); + + foreach (Guid guid in animations_work) + { + m_animations.Add(new LLUUID(guid)); + } + + m_animationSeqs = (List)info.GetValue("m_animationSeqs", typeof(List)); + m_updateflag = (bool)info.GetValue("m_updateflag", typeof(bool)); + m_movementflag = (byte)info.GetValue("m_movementflag", typeof(byte)); + m_forcesList = (List)info.GetValue("m_forcesList", typeof(List)); + m_updateCount = (short)info.GetValue("m_updateCount", typeof(short)); + m_requestedSitTargetID = (uint)info.GetValue("m_requestedSitTargetID", typeof(uint)); + + m_requestedSitOffset + = new LLVector3( + (float)info.GetValue("m_requestedSitOffset.X", typeof(float)), + (float)info.GetValue("m_requestedSitOffset.Y", typeof(float)), + (float)info.GetValue("m_requestedSitOffset.Z", typeof(float))); + + m_sitAvatarHeight = (float)info.GetValue("m_sitAvatarHeight", typeof(float)); + m_godlevel = (float)info.GetValue("m_godlevel", typeof(float)); + m_setAlwaysRun = (bool)info.GetValue("m_setAlwaysRun", typeof(bool)); + + m_bodyRot + = new Quaternion( + (float)info.GetValue("m_bodyRot.w", typeof(float)), + (float)info.GetValue("m_bodyRot.x", typeof(float)), + (float)info.GetValue("m_bodyRot.y", typeof(float)), + (float)info.GetValue("m_bodyRot.z", typeof(float))); + + IsRestrictedToRegion = (bool)info.GetValue("IsRestrictedToRegion", typeof(bool)); + m_newForce = (bool)info.GetValue("m_newForce", typeof(bool)); + //m_newAvatar = (bool)info.GetValue("m_newAvatar", typeof(bool)); + m_newCoarseLocations = (bool)info.GetValue("m_newCoarseLocations", typeof(bool)); + m_gotAllObjectsInScene = (bool)info.GetValue("m_gotAllObjectsInScene", typeof(bool)); + m_avHeight = (float)info.GetValue("m_avHeight", typeof(float)); + crossingFromRegion = (ulong)info.GetValue("crossingFromRegion", typeof(ulong)); + + List Dir_Vectors_work = (List)info.GetValue("Dir_Vectors", typeof(List)); + List Dir_Vectors_work2 = new List(); + + foreach (float[] f3 in Dir_Vectors_work) + { + Dir_Vectors_work2.Add(new Vector3(f3[0], f3[1], f3[2])); + } + + Dir_Vectors = Dir_Vectors_work2.ToArray(); + + lastPhysPos + = new LLVector3( + (float)info.GetValue("lastPhysPos.X", typeof(float)), + (float)info.GetValue("lastPhysPos.Y", typeof(float)), + (float)info.GetValue("lastPhysPos.Z", typeof(float))); + + m_CameraCenter + = new Vector3( + (float)info.GetValue("m_CameraCenter.X", typeof(float)), + (float)info.GetValue("m_CameraCenter.Y", typeof(float)), + (float)info.GetValue("m_CameraCenter.Z", typeof(float))); + + m_CameraAtAxis + = new Vector3( + (float)info.GetValue("m_CameraAtAxis.X", typeof(float)), + (float)info.GetValue("m_CameraAtAxis.Y", typeof(float)), + (float)info.GetValue("m_CameraAtAxis.Z", typeof(float))); + + m_CameraLeftAxis + = new Vector3( + (float)info.GetValue("m_CameraLeftAxis.X", typeof(float)), + (float)info.GetValue("m_CameraLeftAxis.Y", typeof(float)), + (float)info.GetValue("m_CameraLeftAxis.Z", typeof(float))); + + m_CameraUpAxis + = new Vector3( + (float)info.GetValue("m_CameraUpAxis.X", typeof(float)), + (float)info.GetValue("m_CameraUpAxis.Y", typeof(float)), + (float)info.GetValue("m_CameraUpAxis.Z", typeof(float))); + + m_DrawDistance = (float)info.GetValue("m_DrawDistance", typeof(float)); + m_appearance = (AvatarAppearance)info.GetValue("m_appearance", typeof(AvatarAppearance)); + m_knownChildRegions = (List)info.GetValue("m_knownChildRegions", typeof(List)); + + posLastSignificantMove + = new LLVector3( + (float)info.GetValue("posLastSignificantMove.X", typeof(float)), + (float)info.GetValue("posLastSignificantMove.Y", typeof(float)), + (float)info.GetValue("posLastSignificantMove.Z", typeof(float))); + + // m_partsUpdateQueue = (UpdateQueue)info.GetValue("m_partsUpdateQueue", typeof(UpdateQueue)); + + /* + Dictionary updateTimes_work + = (Dictionary)info.GetValue("m_updateTimes", typeof(Dictionary)); + + foreach (Guid id in updateTimes_work.Keys) + { + m_updateTimes.Add(new LLUUID(id), updateTimes_work[id]); + } + */ + m_regionHandle = (ulong)info.GetValue("m_regionHandle", typeof(ulong)); + m_firstname = (string)info.GetValue("m_firstname", typeof(string)); + m_lastname = (string)info.GetValue("m_lastname", typeof(string)); + m_allowMovement = (bool)info.GetValue("m_allowMovement", typeof(bool)); + m_parentPosition = new LLVector3((float)info.GetValue("m_parentPosition.X", typeof(float)), + (float)info.GetValue("m_parentPosition.Y", typeof(float)), + (float)info.GetValue("m_parentPosition.Z", typeof(float))); + + m_isChildAgent = (bool)info.GetValue("m_isChildAgent", typeof(bool)); + m_parentID = (uint)info.GetValue("m_parentID", typeof(uint)); + +// for OpenSim_v0.5 + currentParcelUUID = new LLUUID((Guid)info.GetValue("currentParcelUUID", typeof(Guid))); + + lastKnownAllowedPosition + = new Vector3( + (float)info.GetValue("lastKnownAllowedPosition.X", typeof(float)), + (float)info.GetValue("lastKnownAllowedPosition.Y", typeof(float)), + (float)info.GetValue("lastKnownAllowedPosition.Z", typeof(float))); + + sentMessageAboutRestrictedParcelFlyingDown = (bool)info.GetValue("sentMessageAboutRestrictedParcelFlyingDown", typeof(bool)); + + m_LastChildAgentUpdatePosition + = new LLVector3( + (float)info.GetValue("m_LastChildAgentUpdatePosition.X", typeof(float)), + (float)info.GetValue("m_LastChildAgentUpdatePosition.Y", typeof(float)), + (float)info.GetValue("m_LastChildAgentUpdatePosition.Z", typeof(float))); + + m_perfMonMS = (int)info.GetValue("m_perfMonMS", typeof(int)); + m_AgentControlFlags = (uint)info.GetValue("m_AgentControlFlags", typeof(uint)); + + m_headrotation + = new LLQuaternion( + (float)info.GetValue("m_headrotation.W", typeof(float)), + (float)info.GetValue("m_headrotation.X", typeof(float)), + (float)info.GetValue("m_headrotation.Y", typeof(float)), + (float)info.GetValue("m_headrotation.Z", typeof(float))); + + m_state = (byte)info.GetValue("m_state", typeof(byte)); + + List knownPrimUUID_work = (List)info.GetValue("m_knownPrimUUID", typeof(List)); + + foreach (Guid id in knownPrimUUID_work) + { + m_knownPrimUUID.Add(new LLUUID(id)); + } + + //System.Console.WriteLine("ScenePresence Deserialize END"); + } + + [SecurityPermission(SecurityAction.LinkDemand, + Flags = SecurityPermissionFlag.SerializationFormatter)] + public override void GetObjectData( + SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + base.GetObjectData(info, context); + + List animations_work = new List(); + + foreach (LLUUID uuid in m_animations) + { + animations_work.Add(uuid.UUID); + } + + info.AddValue("m_animations", animations_work); + + info.AddValue("m_animationSeqs", m_animationSeqs); + info.AddValue("m_updateflag", m_updateflag); + info.AddValue("m_movementflag", m_movementflag); + info.AddValue("m_forcesList", m_forcesList); + info.AddValue("m_updateCount", m_updateCount); + info.AddValue("m_requestedSitTargetID", m_requestedSitTargetID); + + // LLVector3 + info.AddValue("m_requestedSitOffset.X", m_requestedSitOffset.X); + info.AddValue("m_requestedSitOffset.Y", m_requestedSitOffset.Y); + info.AddValue("m_requestedSitOffset.Z", m_requestedSitOffset.Z); + + info.AddValue("m_sitAvatarHeight", m_sitAvatarHeight); + info.AddValue("m_godlevel", m_godlevel); + info.AddValue("m_setAlwaysRun", m_setAlwaysRun); + + // Quaternion + info.AddValue("m_bodyRot.w", m_bodyRot.w); + info.AddValue("m_bodyRot.x", m_bodyRot.x); + info.AddValue("m_bodyRot.y", m_bodyRot.y); + info.AddValue("m_bodyRot.z", m_bodyRot.z); + + info.AddValue("IsRestrictedToRegion", IsRestrictedToRegion); + info.AddValue("m_newForce", m_newForce); + //info.AddValue("m_newAvatar", m_newAvatar); + info.AddValue("m_newCoarseLocations", m_newCoarseLocations); + info.AddValue("m_gotAllObjectsInScene", m_gotAllObjectsInScene); + info.AddValue("m_avHeight", m_avHeight); + + // info.AddValue("m_regionInfo", m_regionInfo); + + info.AddValue("crossingFromRegion", crossingFromRegion); + + List Dir_Vectors_work = new List(); + + foreach (Vector3 v3 in Dir_Vectors) + { + Dir_Vectors_work.Add(new float[] { v3.x, v3.y, v3.z }); + } + + info.AddValue("Dir_Vectors", Dir_Vectors_work); + + // LLVector3 + info.AddValue("lastPhysPos.X", lastPhysPos.X); + info.AddValue("lastPhysPos.Y", lastPhysPos.Y); + info.AddValue("lastPhysPos.Z", lastPhysPos.Z); + + // Vector3 + info.AddValue("m_CameraCenter.X", m_CameraCenter.x); + info.AddValue("m_CameraCenter.Y", m_CameraCenter.y); + info.AddValue("m_CameraCenter.Z", m_CameraCenter.z); + + // Vector3 + info.AddValue("m_CameraAtAxis.X", m_CameraAtAxis.x); + info.AddValue("m_CameraAtAxis.Y", m_CameraAtAxis.y); + info.AddValue("m_CameraAtAxis.Z", m_CameraAtAxis.z); + + // Vector3 + info.AddValue("m_CameraLeftAxis.X", m_CameraLeftAxis.x); + info.AddValue("m_CameraLeftAxis.Y", m_CameraLeftAxis.y); + info.AddValue("m_CameraLeftAxis.Z", m_CameraLeftAxis.z); + + // Vector3 + info.AddValue("m_CameraUpAxis.X", m_CameraUpAxis.x); + info.AddValue("m_CameraUpAxis.Y", m_CameraUpAxis.y); + info.AddValue("m_CameraUpAxis.Z", m_CameraUpAxis.z); + + info.AddValue("m_DrawDistance", m_DrawDistance); + info.AddValue("m_appearance", m_appearance); + info.AddValue("m_knownChildRegions", m_knownChildRegions); + + // LLVector3 + info.AddValue("posLastSignificantMove.X", posLastSignificantMove.X); + info.AddValue("posLastSignificantMove.Y", posLastSignificantMove.Y); + info.AddValue("posLastSignificantMove.Z", posLastSignificantMove.Z); + + //info.AddValue("m_partsUpdateQueue", m_partsUpdateQueue); + + /* + Dictionary updateTimes_work = new Dictionary(); + + foreach ( LLUUID id in m_updateTimes.Keys) + { + updateTimes_work.Add(id.UUID, m_updateTimes[id]); + } + + info.AddValue("m_updateTimes", updateTimes_work); + */ + + info.AddValue("m_regionHandle", m_regionHandle); + info.AddValue("m_firstname", m_firstname); + info.AddValue("m_lastname", m_lastname); + info.AddValue("m_allowMovement", m_allowMovement); + //info.AddValue("m_physicsActor", m_physicsActor); + info.AddValue("m_parentPosition.X", m_parentPosition.X); + info.AddValue("m_parentPosition.Y", m_parentPosition.Y); + info.AddValue("m_parentPosition.Z", m_parentPosition.Z); + info.AddValue("m_isChildAgent", m_isChildAgent); + info.AddValue("m_parentID", m_parentID); + +// for OpenSim_v0.5 + info.AddValue("currentParcelUUID", currentParcelUUID.UUID); + + info.AddValue("lastKnownAllowedPosition.X", lastKnownAllowedPosition.x); + info.AddValue("lastKnownAllowedPosition.Y", lastKnownAllowedPosition.y); + info.AddValue("lastKnownAllowedPosition.Z", lastKnownAllowedPosition.z); + + info.AddValue("sentMessageAboutRestrictedParcelFlyingDown", sentMessageAboutRestrictedParcelFlyingDown); + + info.AddValue("m_LastChildAgentUpdatePosition.X", m_LastChildAgentUpdatePosition.X); + info.AddValue("m_LastChildAgentUpdatePosition.Y", m_LastChildAgentUpdatePosition.Y); + info.AddValue("m_LastChildAgentUpdatePosition.Z", m_LastChildAgentUpdatePosition.Z); + + info.AddValue("m_perfMonMS", m_perfMonMS); + info.AddValue("m_AgentControlFlags", m_AgentControlFlags); + + info.AddValue("m_headrotation.W", m_headrotation.W); + info.AddValue("m_headrotation.X", m_headrotation.X); + info.AddValue("m_headrotation.Y", m_headrotation.Y); + info.AddValue("m_headrotation.Z", m_headrotation.Z); + + info.AddValue("m_state", m_state); + + List knownPrimUUID_work = new List(); + + foreach (LLUUID id in m_knownPrimUUID) + { + knownPrimUUID_work.Add(id.UUID); + } + + info.AddValue("m_knownPrimUUID", knownPrimUUID_work); + } } } diff --git a/OpenSim/Region/Environment/Types/UpdateQueue.cs b/OpenSim/Region/Environment/Types/UpdateQueue.cs index 0078678067..ce0927ce9d 100644 --- a/OpenSim/Region/Environment/Types/UpdateQueue.cs +++ b/OpenSim/Region/Environment/Types/UpdateQueue.cs @@ -30,9 +30,14 @@ using System.Collections.Generic; using libsecondlife; using OpenSim.Region.Environment.Scenes; +using System; +using System.Runtime.Serialization; +using System.Security.Permissions; + namespace OpenSim.Region.Environment.Types { - public class UpdateQueue + [Serializable] + public class UpdateQueue : ISerializable { private Queue m_queue; @@ -86,5 +91,46 @@ namespace OpenSim.Region.Environment.Types return part; } + + protected UpdateQueue(SerializationInfo info, StreamingContext context) + { + //System.Console.WriteLine("UpdateQueue Deserialize BGN"); + + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + m_queue = (Queue)info.GetValue("m_queue", typeof(Queue)); + List ids_work = (List)info.GetValue("m_ids", typeof(List)); + + foreach (Guid guid in ids_work) + { + m_ids.Add(new LLUUID(guid)); + } + + //System.Console.WriteLine("UpdateQueue Deserialize END"); + } + + [SecurityPermission(SecurityAction.LinkDemand, + Flags = SecurityPermissionFlag.SerializationFormatter)] + public virtual void GetObjectData( + SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + List ids_work = new List(); + + foreach (LLUUID uuid in m_ids) + { + ids_work.Add(uuid.UUID); + } + + info.AddValue("m_queue", m_queue); + info.AddValue("m_ids", ids_work); + } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Examples/SimpleApp/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleApp/MyNpcCharacter.cs index cb2c9086dc..68fea97909 100644 --- a/OpenSim/Region/Examples/SimpleApp/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleApp/MyNpcCharacter.cs @@ -538,5 +538,18 @@ namespace SimpleApp public void SendLogoutPacket() { } + + public void Terminate() + { + } + + public ClientInfo GetClientInfo() + { + return null; + } + + public void SetClientInfo(ClientInfo info) + { + } } } diff --git a/ThirdParty/3Di/LoadBalancer/LoadBalancerPlugin.cs b/ThirdParty/3Di/LoadBalancer/LoadBalancerPlugin.cs new file mode 100644 index 0000000000..6812777825 --- /dev/null +++ b/ThirdParty/3Di/LoadBalancer/LoadBalancerPlugin.cs @@ -0,0 +1,1101 @@ +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +using System; +using System.IO; +using System.Net; +using System.Xml; +using System.Text; +using System.Xml.Serialization; +using System.Net.Sockets; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; + +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Servers; +using OpenSim.Region.Environment; +using OpenSim.Region.Environment.Scenes; +using OpenSim.Region.ClientStack; + +using Nwc.XmlRpc; +using Nini.Config; + +using Mono.Addins; + +using libsecondlife; +using libsecondlife.Packets; + +[assembly:Addin] +[assembly:AddinDependency ("OpenSim", "0.5")] + +namespace OpenSim.ApplicationPlugins.LoadBalancer +{ + [Extension("/OpenSim/Startup")] + public class LoadBalancerPlugin : IApplicationPlugin + { + private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + private OpenSimMain simMain; + private BaseHttpServer commandServer; + + private List udpServers; + private List regionData; + + private int proxyOffset; + private string proxyURL; + private SceneManager sceneManager; + private string serializeDir; + + private TcpServer mTcpServer; + private TcpClient mTcpClient; + + public void Initialise(OpenSimMain openSim) + { + m_log.Info("[BALANCER] "+"Entering Initialize()"); + + StartTcpServer(); + ClientView.SynchronizeClient = new ClientView.SynchronizeClientHandler(SynchronizePackets); + AsynchronousSocketListener.PacketHandler = new AsynchronousSocketListener.PacketRecieveHandler(SynchronizePacketRecieve); + + this.sceneManager = openSim.SceneManager; + this.udpServers = openSim.UdpServers; + this.regionData = openSim.RegionData; + this.simMain = openSim; + this.commandServer = openSim.HttpServer; + + proxyOffset = Int32.Parse(openSim.ConfigSource.Configs["Network"].GetString("proxy_offset", "0")); + proxyURL = openSim.ConfigSource.Configs["Network"].GetString("proxy_url", ""); + if(proxyURL.Length==0) return; + + serializeDir = openSim.ConfigSource.Configs["Network"].GetString("serialize_dir", "/tmp/"); + + commandServer.AddXmlRPCHandler("SerializeRegion", SerializeRegion); + commandServer.AddXmlRPCHandler("DeserializeRegion_Move", DeserializeRegion_Move); + commandServer.AddXmlRPCHandler("DeserializeRegion_Clone", DeserializeRegion_Clone); + commandServer.AddXmlRPCHandler("TerminateRegion", TerminateRegion); + + commandServer.AddXmlRPCHandler("SplitRegion", SplitRegion); + commandServer.AddXmlRPCHandler("MergeRegions", MergeRegions); + commandServer.AddXmlRPCHandler("UpdatePhysics", UpdatePhysics); + commandServer.AddXmlRPCHandler("GetStatus", GetStatus); + + m_log.Info("[BALANCER] "+"Exiting Initialize()"); + } + + private void StartTcpServer() + { + Thread server_thread = new Thread(new ThreadStart( + delegate { + mTcpServer = new TcpServer(10001); + mTcpServer.start(); + })); + server_thread.Start(); + } + + public void Close() + { + } + + private XmlRpcResponse GetStatus(XmlRpcRequest request) + { + XmlRpcResponse response = new XmlRpcResponse(); + try + { + m_log.Info("[BALANCER] "+"Entering RegionStatus()"); + + int src_port = (int)request.Params[0]; + Scene scene = null; + // try to get the scene object + RegionInfo src_region = SearchRegionFromPortNum(src_port); + if (sceneManager.TryGetScene(src_region.RegionID, out scene) == false) + { + m_log.Error("[BALANCER] "+"The Scene is not found"); + return response; + } + // serialization of client's informations + List presences = scene.GetScenePresences(); + int get_scene_presence = presences.Count; + int get_scene_presence_filter = 0; + foreach (ScenePresence pre in presences) + { + ClientView client = (ClientView) pre.ControllingClient; + //if(pre.MovementFlag!=0 && client.PacketProcessingEnabled==true) { + if(client.PacketProcessingEnabled==true) { + get_scene_presence_filter++; + } + } + List avatars = scene.GetAvatars(); + int get_avatar = avatars.Count; + int get_avatar_filter = 0; + string avatar_names = ""; + foreach (ScenePresence pre in avatars) + { + ClientView client = (ClientView) pre.ControllingClient; + //if(pre.MovementFlag!=0 && client.PacketProcessingEnabled==true) { + if(client.PacketProcessingEnabled==true) { + get_avatar_filter++; + avatar_names += pre.Firstname + " " + pre.Lastname + "; "; + } + } + + Hashtable responseData = new Hashtable(); + responseData["get_scene_presence_filter"] = get_scene_presence_filter; + responseData["get_scene_presence"] = get_scene_presence; + responseData["get_avatar_filter"] = get_avatar_filter; + responseData["get_avatar"] = get_avatar; + responseData["avatar_names"] = avatar_names; + response.Value = responseData; + + m_log.Info("[BALANCER] "+"Exiting RegionStatus()"); + } + catch (Exception e) + { + m_log.Error("[BALANCER] "+e.ToString()); + m_log.Error("[BALANCER] "+e.StackTrace); + } + return response; + } + + private XmlRpcResponse SerializeRegion(XmlRpcRequest request) + { + try + { + m_log.Info("[BALANCER] "+"Entering SerializeRegion()"); + + string src_url = (string)request.Params[0]; + int src_port = (int)request.Params[1]; + + SerializeRegion(src_url, src_port); + + m_log.Info("[BALANCER] "+"Exiting SerializeRegion()"); + } + catch (Exception e) + { + m_log.Error("[BALANCER] "+e.ToString()); + m_log.Error("[BALANCER] "+e.StackTrace); + } + + return new XmlRpcResponse(); + } + + private XmlRpcResponse DeserializeRegion_Move(XmlRpcRequest request) + { + try + { + m_log.Info("[BALANCER] "+"Entering DeserializeRegion_Move()"); + + string src_url = (string)request.Params[0]; + int src_port = (int)request.Params[1]; + string dst_url = (string)request.Params[2]; + int dst_port = (int)request.Params[3]; + + DeserializeRegion_Move(src_port, dst_port, src_url, dst_url); + + m_log.Info("[BALANCER] "+"Exiting DeserializeRegion_Move()"); + } + catch (Exception e) + { + m_log.Error("[BALANCER] "+e.ToString()); + m_log.Error("[BALANCER] "+e.StackTrace); + } + + return new XmlRpcResponse(); + } + + private XmlRpcResponse DeserializeRegion_Clone(XmlRpcRequest request) + { + try + { + m_log.Info("[BALANCER] "+"Entering DeserializeRegion_Clone()"); + + string src_url = (string)request.Params[0]; + int src_port = (int)request.Params[1]; + string dst_url = (string)request.Params[2]; + int dst_port = (int)request.Params[3]; + + DeserializeRegion_Clone(src_port, dst_port, src_url, dst_url); + + m_log.Info("[BALANCER] "+"Exiting DeserializeRegion_Clone()"); + } + catch (Exception e) + { + m_log.Error("[BALANCER] "+e.ToString()); + m_log.Error("[BALANCER] "+e.StackTrace); + throw e; + } + + return new XmlRpcResponse(); + } + + private XmlRpcResponse TerminateRegion(XmlRpcRequest request) + { + try + { + m_log.Info("[BALANCER] "+"Entering TerminateRegion()"); + + int src_port = (int)request.Params[0]; + + // backgroud + WaitCallback callback = new WaitCallback(TerminateRegion); + ThreadPool.QueueUserWorkItem(callback, src_port); + + m_log.Info("[BALANCER] "+"Exiting TerminateRegion()"); + } + catch (Exception e) + { + m_log.Error("[BALANCER] "+e.ToString()); + m_log.Error("[BALANCER] "+e.StackTrace); + } + + return new XmlRpcResponse(); + } + + // internal functions + + private void SerializeRegion(string src_url, int src_port) + { + RegionInfo src_region = null; + + //------------------------------------------ + // Processing of origin region + //------------------------------------------ + + // search origin region + src_region = SearchRegionFromPortNum(src_port); + + if (src_region == null) + { + m_log.Error("[BALANCER] "+"Region not found"); + return; + } + + simMain.ProxyCommand(src_region.proxyUrl, "BlockClientMessages", src_url, src_port + proxyOffset); + + // serialization of origin region's data + SerializeRegion(src_region, serializeDir); + } + + private void DeserializeRegion_Move(int src_port, int dst_port, string src_url, string dst_url) + { + RegionInfo dst_region = null; + + //------------------------------------------ + // Processing of destination region + //------------------------------------------ + + // import the source region's data + dst_region = DeserializeRegion(dst_port, true, serializeDir); + + simMain.ProxyCommand(dst_region.proxyUrl, "ChangeRegion", src_port + proxyOffset, src_url, dst_port + proxyOffset, dst_url); + simMain.ProxyCommand(dst_region.proxyUrl, "UnblockClientMessages", dst_url, dst_port + proxyOffset); + } + + private void DeserializeRegion_Clone(int src_port, int dst_port, string src_url, string dst_url) + { + RegionInfo dst_region = null; + + //------------------------------------------ + // Processing of destination region + //------------------------------------------ + + // import the source region's data + dst_region = DeserializeRegion(dst_port, false, serializeDir); + + // Decide who is in charge for each section + int[] port = new int[] { src_port, dst_port }; + string[] url = new string[] { "http://" + src_url + ":" + commandServer.Port, "http://" + dst_url + ":" + commandServer.Port }; + for(int i=0; i<2; i++) simMain.XmlRpcCommand(url[i], "SplitRegion", i, 2, port[0], port[1], url[0], url[1]); + + // Enable the proxy + simMain.ProxyCommand(dst_region.proxyUrl, "AddRegion", src_port + proxyOffset, src_url, dst_port + proxyOffset, dst_url); + simMain.ProxyCommand(dst_region.proxyUrl, "UnblockClientMessages", dst_url, dst_port + proxyOffset); + } + + private void TerminateRegion(object param) + { + RegionInfo src_region = null; + int src_port = (int)param; + + //------------------------------------------ + // Processing of remove region + //------------------------------------------ + + // search origin region + src_region = SearchRegionFromPortNum(src_port); + + if (src_region == null) + { + m_log.Error("[BALANCER] "+"Region not found"); + return; + } + + isSplit = false; + + // remove client resources + RemoveAllClientResource(src_region); + // remove old region + RemoveRegion(src_region.RegionID, src_region.InternalEndPoint.Port); + + m_log.Info("[BALANCER] "+"Region terminated"); + } + + private RegionInfo SearchRegionFromPortNum(int portnum) + { + RegionInfo result = null; + + foreach (RegionInfo rinfo in regionData) + { + if (rinfo.InternalEndPoint.Port == portnum) + { +// m_log.Info("BALANCER", +// "Region found. Internal Port = {0}, Handle={1}", +// rinfo.InternalEndPoint.Port, rinfo.RegionHandle); + result = rinfo; + break; + } + } + + return result; + } + + private UDPServer SearchUDPServerFromPortNum(int portnum) + { + return udpServers.Find( delegate(UDPServer server) { return (portnum + proxyOffset == ((IPEndPoint) server.Server.LocalEndPoint).Port); }); + } + + private void SerializeRegion(RegionInfo src_region, string export_dir) + { + Scene scene = null; + List presences; + string filename; + int i = 0; + + // try to get the scene object + if (sceneManager.TryGetScene(src_region.RegionID, out scene) == false) + { + m_log.Error("[BALANCER] "+"The Scene is not found"); + return; + } + + // create export directory + DirectoryInfo dirinfo = new DirectoryInfo(export_dir); + if (!dirinfo.Exists) + { + dirinfo.Create(); + } + + // serialization of client's informations + presences = scene.GetScenePresences(); + + foreach (ScenePresence pre in presences) + { + SerializeClient(i, scene, pre, export_dir); + i++; + } + + // serialization of region data + SearializableRegionInfo dst_region = new SearializableRegionInfo(src_region); + + filename = export_dir + "RegionInfo_" + src_region.RegionID.ToString() + ".bin"; + Util.SerializeToFile(filename, dst_region); + + // backup current scene's entities + //scene.Backup(); + + m_log.InfoFormat("[BALANCER] "+"region serialization completed [{0}]", + src_region.RegionID.ToString()); + } + + private void SerializeClient(int idx, Scene scene, ScenePresence pre, string export_dir) + { + string filename; + IClientAPI controller = null; + + m_log.InfoFormat("[BALANCER] "+"agent id : {0}", pre.m_uuid); + + uint[] circuits = scene.ClientManager.GetAllCircuits(pre.m_uuid); + + foreach (uint code in circuits) + { + m_log.InfoFormat("[BALANCER] "+"circuit code : {0}", code); + + if (scene.ClientManager.TryGetClient(code, out controller)) + { + ClientInfo info = controller.GetClientInfo(); + + filename = export_dir + "ClientInfo-" + String.Format("{0:0000}", idx) + "_" + controller.CircuitCode.ToString() + ".bin"; + + Util.SerializeToFile(filename, info); + + m_log.InfoFormat("[BALANCER] "+"client info serialized [filename={0}]", filename); + } + } + + //filename = export_dir + "Presence_" + controller.AgentId.ToString() + ".bin"; + filename = export_dir + "Presence_" + String.Format("{0:0000}", idx) + ".bin"; + + Util.SerializeToFile(filename, pre); + + m_log.InfoFormat("[BALANCER] "+"scene presence serialized [filename={0}]", filename); + } + + private RegionInfo DeserializeRegion(int dst_port, bool move_flag, string import_dir) + { + string[] files = null; + RegionInfo dst_region = null; + + try + { + // deserialization of region data + files = Directory.GetFiles(import_dir, "RegionInfo_*.bin"); + + foreach (string filename in files) + { + m_log.InfoFormat("[BALANCER] RegionInfo filename = [{0}]", filename); + + dst_region = new RegionInfo((SearializableRegionInfo)Util.DeserializeFromFile(filename)); + + m_log.InfoFormat("[BALANCER] "+"RegionID = [{0}]", dst_region.RegionID.ToString()); + m_log.InfoFormat("[BALANCER] "+"RegionHandle = [{0}]", dst_region.RegionHandle); + m_log.InfoFormat("[BALANCER] "+"ProxyUrl = [{0}]", dst_region.proxyUrl); + m_log.InfoFormat("[BALANCER] "+"OriginRegionID = [{0}]", dst_region.originRegionID.ToString()); + + CreateCloneRegion(dst_region, dst_port, true); + + File.Delete(filename); + + m_log.InfoFormat("[BALANCER] "+"region deserialized [{0}]", dst_region.RegionID); + } + + // deserialization of client data + DeserializeClient(dst_region, import_dir); + + m_log.InfoFormat("[BALANCER] "+"region deserialization completed [{0}]", + dst_region.ToString()); + } + catch (Exception e) + { + m_log.Error("[BALANCER] "+e.ToString()); + m_log.Error("[BALANCER] "+e.StackTrace); + throw e; + } + + return dst_region; + } + + private void DeserializeClient(RegionInfo dst_region, string import_dir) + { + ScenePresence sp = null; + ClientInfo data = null; + Scene scene = null; + string[] files = null; + IClientAPI controller = null; + UDPServer udpserv = null; + + if (sceneManager.TryGetScene(dst_region.RegionID, out scene)) + { + // search udpserver + udpserv = SearchUDPServerFromPortNum(scene.RegionInfo.InternalEndPoint.Port); + + // restore the scene presence +/* + files = Directory.GetFiles(import_dir, "Presence_*.bin"); + Array.Sort(files); + + foreach (string filename in files) + { + sp = (ScenePresence)Util.DeserializeFromFile(filename); + Console.WriteLine("agent id = {0}", sp.m_uuid); + + scene.m_restorePresences.Add(sp.m_uuid, sp); + File.Delete(filename); + + m_log.InfoFormat("[BALANCER] "+"scene presence deserialized [{0}]", sp.m_uuid); + } +*/ + for (int i = 0; ; i++) + { + string filename = import_dir + "Presence_" + String.Format("{0:0000}", i) + ".bin"; + + if (!File.Exists(filename)) + { + break; + } + + sp = (ScenePresence)Util.DeserializeFromFile(filename); + Console.WriteLine("agent id = {0}", sp.m_uuid); + + scene.m_restorePresences.Add(sp.m_uuid, sp); + File.Delete(filename); + + m_log.InfoFormat("[BALANCER] " + "scene presence deserialized [{0}]", sp.m_uuid); + + // restore the ClientView + + files = Directory.GetFiles(import_dir, "ClientInfo-" + String.Format("{0:0000}", i) + "_*.bin"); + + foreach (string fname in files) + { + int start = fname.IndexOf('_'); + int end = fname.LastIndexOf('.'); + uint circuit_code = uint.Parse(fname.Substring(start + 1, end - start - 1)); + m_log.InfoFormat("[BALANCER] " + "client circuit code = {0}", circuit_code); + + data = (ClientInfo)Util.DeserializeFromFile(fname); + + AgentCircuitData agentdata = new AgentCircuitData(data.agentcircuit); + scene.AuthenticateHandler.AddNewCircuit(circuit_code, agentdata); + + udpserv.RestoreClient(agentdata, data.userEP, data.proxyEP); + + // waiting for the scene-presense restored + lock (scene.m_restorePresences) + { + Monitor.Wait(scene.m_restorePresences, 3000); + } + + if (scene.ClientManager.TryGetClient(circuit_code, out controller)) + { + m_log.InfoFormat("[BALANCER] " + "get client [{0}]", circuit_code); + controller.SetClientInfo(data); + } + + File.Delete(fname); + + m_log.InfoFormat("[BALANCER] " + "client info deserialized [{0}]", circuit_code); + } + + // backup new scene's entities + //scene.Backup(); + } + } + } + + private void CreateCloneRegion(RegionInfo dst_region, int dst_port, bool createID_flag) + { + if (createID_flag) + { + dst_region.RegionID = LLUUID.Random(); + } + + // change RegionInfo (memory only) + dst_region.InternalEndPoint.Port = dst_port; + dst_region.ExternalHostName = proxyURL.Split(new char[] { '/', ':' })[3]; + + // Create new region + simMain.CreateRegion(dst_region, false); + } + + private void RemoveRegion(LLUUID regionID, int port) + { + Scene killScene; + if (sceneManager.TryGetScene(regionID, out killScene)) + { + Console.WriteLine("scene found."); + + if ((sceneManager.CurrentScene != null) + && (sceneManager.CurrentScene.RegionInfo.RegionID == killScene.RegionInfo.RegionID)) + { + sceneManager.TrySetCurrentScene(".."); + } + + m_log.Info("Removing region : " + killScene.RegionInfo.RegionName); + regionData.Remove(killScene.RegionInfo); + sceneManager.CloseScene(killScene); + } + + // Shutting down the UDP server + UDPServer udpsvr = SearchUDPServerFromPortNum(port); + + if (udpsvr != null) + { + udpsvr.Server.Close(); + udpServers.Remove(udpsvr); + } + } + + private void RemoveAllClientResource(RegionInfo src_region) + { + Scene scene = null; + List presences; + IClientAPI controller = null; + + // try to get the scene object + if (sceneManager.TryGetScene(src_region.RegionID, out scene) == false) + { + m_log.Error("[BALANCER] "+"The Scene is not found"); + return; + } + + // serialization of client's informations + presences = scene.GetScenePresences(); + + // remove all scene presences + foreach (ScenePresence pre in presences) + { + uint[] circuits = scene.ClientManager.GetAllCircuits(pre.m_uuid); + + foreach (uint code in circuits) + { + m_log.InfoFormat("[BALANCER] "+"circuit code : {0}", code); + + if (scene.ClientManager.TryGetClient(code, out controller)) + { + // stopping clientview thread + if (((ClientView)controller).PacketProcessingEnabled) + { + controller.Stop(); + ((ClientView)controller).PacketProcessingEnabled = false; + } + // teminateing clientview thread + controller.Terminate(); + m_log.Info("[BALANCER] "+"client thread stopped"); + } + } + + // remove scene presence + scene.RemoveClient(pre.m_uuid); + } + } + + /* + * This section implements scene splitting and synchronization + */ + + private bool[] isLocalNeighbour; + private string[] sceneURL; + private int[] regionPortList; + private TcpClient[] tcpClientList; + private bool isSplit = false; + + private XmlRpcResponse SplitRegion(XmlRpcRequest request) + { + try + { + int myID = (int) request.Params[0]; + int numRegions = (int) request.Params[1]; + regionPortList = new int[numRegions]; + sceneURL = new string[numRegions]; + tcpClientList = new TcpClient[numRegions]; + + for(int i=0; i presences = scene.GetScenePresences(); +presences.Sort(); + foreach (ScenePresence pre in presences) + { + // Divide the presences evenly over the set of subscenes + ClientView client = (ClientView) pre.ControllingClient; + client.PacketProcessingEnabled = (( (i + myID) % sceneURL.Length) == 0); + + m_log.InfoFormat("[SPLITSCENE] === SplitRegion {0}: SP.PacketEnabled {1}", region.RegionID, client.PacketProcessingEnabled); + + if (!client.PacketProcessingEnabled) + { + // stopping clientview thread + client.Stop(); + } + + ++i; + } + + scene.splitID = myID; + scene.SynchronizeScene = new Scene.SynchronizeSceneHandler(SynchronizeScenes); + isSplit = true; + } + else + { + m_log.Error("[SPLITSCENE] "+String.Format("Scene not found {0}", region.RegionID)); + } + } + catch (Exception e) + { + m_log.Error("[SPLITSCENE] "+e.ToString()); + m_log.Error("[SPLITSCENE] "+e.StackTrace); + } + + return new XmlRpcResponse(); + } + + private XmlRpcResponse MergeRegions(XmlRpcRequest request) + { + // This should only be called for the master scene + try + { + m_log.Info("[BALANCER] "+"Entering MergeRegions()"); + + string src_url = (string) request.Params[0]; + int src_port = (int) request.Params[1]; + + RegionInfo region = SearchRegionFromPortNum(src_port); + + simMain.ProxyCommand(region.proxyUrl, "BlockClientMessages", src_url, src_port + proxyOffset); + + Scene scene; + if (sceneManager.TryGetScene(region.RegionID, out scene)) + { + isSplit = false; + + scene.SynchronizeScene = null; + scene.Region_Status = RegionStatus.Up; + + List presences = scene.GetScenePresences(); + foreach (ScenePresence pre in presences) + { + ClientView client = (ClientView) pre.ControllingClient; + if (!client.PacketProcessingEnabled) + { + client.Restart(); + client.PacketProcessingEnabled = true; + } + } + } + + // Delete the slave scenes + for(int i=1; i presences = scene.GetScenePresences(); + foreach (ScenePresence pre in presences) + { + ClientView client = (ClientView) pre.ControllingClient; + + // Because data changes by the physics simulation when the client doesn't move, + // if MovementFlag is false, It is necessary to synchronize. + //if(pre.MovementFlag!=0 && client.PacketProcessingEnabled==true) + if(client.PacketProcessingEnabled==true) + { + //m_log.Info("[SPLITSCENE] "+String.Format("Client moving in {0} {1}", scene.RegionInfo.RegionID, pre.AbsolutePosition)); + + for (int i = 0; i < sceneURL.Length; i++) + { + if (i == scene.splitID) + { + continue; + } + + if(isLocalNeighbour[i]) + { + //m_log.Info("[SPLITSCENE] "+"Synchronize ScenePresence (Local) [region:{0}=>{1}, client:{2}]", + // scene.RegionInfo.RegionID, regionPortList[i], pre.UUID.ToString()); + LocalUpdatePhysics(regionPortList[i], pre.UUID, pre.AbsolutePosition, pre.Velocity, pre.PhysicsActor.Flying); + } + else + { + //m_log.Info("[SPLITSCENE] "+"Synchronize ScenePresence (Remote) [region port:{0}, client:{1}, position:{2}, velocity:{3}, flying:{4}]", + // regionPortList[i], pre.UUID.ToString(), pre.AbsolutePosition.ToString(), + // pre.Velocity.ToString(), pre.PhysicsActor.Flying); + + + simMain.XmlRpcCommand(sceneURL[i], "UpdatePhysics", + regionPortList[i], pre.UUID.GetBytes(), + pre.AbsolutePosition.GetBytes(), pre.Velocity.GetBytes(), + pre.PhysicsActor.Flying); + +/* + byte[] buff = new byte[12+12+1]; + + Buffer.BlockCopy(pre.AbsolutePosition.GetBytes(), 0, buff, 0, 12); + Buffer.BlockCopy(pre.Velocity.GetBytes(), 0, buff, 12, 12); + buff[24] = (byte)((pre.PhysicsActor.Flying)?1:0); + + // create header + InternalPacketHeader header = new InternalPacketHeader(); + + header.type = 1; + header.throttlePacketType = 0; + header.numbytes = buff.Length; + header.agent_id = pre.UUID.UUID; + header.region_port = regionPortList[i]; + + //Send + tcpClientList[i].send(header, buff); +*/ + } + } + } +// ++i; + } + } + } + + public bool SynchronizePackets(IScene scene, Packet packet, LLUUID agentID, ThrottleOutPacketType throttlePacketType) + { + if (!isSplit) + { + return false; + } + + Scene localScene = (Scene)scene; + + for (int i = 0; i < sceneURL.Length; i++) + { + if (i == localScene.splitID) + { + continue; + } + + if(isLocalNeighbour[i]) + { + //m_log.Info("[SPLITSCENE] "+"Synchronize Packet (Local) [type:{0}, client:{1}]", + // packet.Type.ToString(), agentID.ToString()); + LocalUpdatePacket(regionPortList[i], agentID, packet, throttlePacketType); + } + else + { + //m_log.Info("[SPLITSCENE] "+"Synchronize Packet (Remote) [type:{0}, client:{1}]", + // packet.Type.ToString(), agentID.ToString()); + // to bytes + byte[] buff = packet.ToBytes(); + + // create header + InternalPacketHeader header = new InternalPacketHeader(); + + header.type = 0; + header.throttlePacketType = (int)throttlePacketType; + header.numbytes = buff.Length; + header.agent_id = agentID.UUID; + header.region_port = regionPortList[i]; + + //Send + tcpClientList[i].send(header, buff); + + PacketPool.Instance.ReturnPacket(packet); + } + } + + return true; + } + + private void LocalUpdatePacket(int regionPort, LLUUID agentID, Packet packet, ThrottleOutPacketType throttlePacketType) + { + Scene scene; + + RegionInfo region = SearchRegionFromPortNum(regionPort); + +// m_log.Info("[SPLITSCENE] "+"LocalUpdatePacket [region port:{0}, client:{1}, packet type:{2}]", +// regionPort, agentID.ToString(), packet.GetType().ToString()); + + if (sceneManager.TryGetScene(region.RegionID, out scene)) + { + ScenePresence pre = scene.GetScenePresences().Find(delegate(ScenePresence x) { return x.UUID == agentID; }); + + if (pre == null) + { + m_log.ErrorFormat("[SPLITSCENE] [LocalUpdatePacket] ScenePresence is missing... ({0})", agentID.ToString()); + return; + } + + if (((ClientView)pre.ControllingClient).PacketProcessingEnabled==true) + { + pre.ControllingClient.OutPacket(packet, throttlePacketType); + } + else + { + PacketPool.Instance.ReturnPacket(packet); + } + } + } + + public void SynchronizePacketRecieve(InternalPacketHeader header, byte[] buff) + { +// m_log.Info("[SPLITSCENE] "+"entering SynchronizePacketRecieve[type={0}]", header.type); + + if (!isSplit) + { + return; + } + + switch (header.type) + { + case 0: + + Packet packet = null; + byte[] zero = new byte[3000]; + int packetEnd = 0; + + // deserialize packet + packetEnd = buff.Length - 1; +// packetEnd = buff.Length; + + try + { + //m_log.Info("[SPLITSCENE] "+"PacketPool.Instance : {0}", (PacketPool.Instance == null)?"null":"not null"); + //m_log.Info("[SPLITSCENE] "+"buff length={0}", buff.Length); + + packet = PacketPool.Instance.GetPacket(buff, ref packetEnd, zero); + + LocalUpdatePacket(header.region_port, new LLUUID(header.agent_id), + packet, (ThrottleOutPacketType)header.throttlePacketType); + } + catch (Exception e) + { + m_log.Error("[SPLITSCENE] "+e.ToString()); + m_log.Error("[SPLITSCENE] "+e.StackTrace); + } + + break; + + case 1: + + int regionPort = header.region_port; + LLUUID scenePresenceID = new LLUUID(header.agent_id); + LLVector3 position = new LLVector3(buff, 0); + LLVector3 velocity = new LLVector3(buff, 12); + bool flying = ((buff[24] == (byte)1)?true:false); + + LocalUpdatePhysics(regionPort, scenePresenceID, position, velocity, flying); + + break; + + default: + m_log.Info("[SPLITSCENE] "+"Invalid type"); + break; + } + +// m_log.Info("[SPLITSCENE] "+"exiting SynchronizePacketRecieve"); + } + } +} diff --git a/ThirdParty/3Di/LoadBalancer/TcpClient.cs b/ThirdParty/3Di/LoadBalancer/TcpClient.cs new file mode 100644 index 0000000000..9f62d33035 --- /dev/null +++ b/ThirdParty/3Di/LoadBalancer/TcpClient.cs @@ -0,0 +1,240 @@ +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +using System; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Text; +using System.Runtime.Serialization.Formatters.Binary; + +namespace OpenSim.ApplicationPlugins.LoadBalancer { + public class AsynchronousClient { + private static ManualResetEvent connectDone = new ManualResetEvent(false); + private static ManualResetEvent sendDone = new ManualResetEvent(false); + private static ManualResetEvent receiveDone = new ManualResetEvent(false); + private static String response = String.Empty; + + public static Socket StartClient(string hostname, int port) { + try { + IPHostEntry ipHostInfo = Dns.GetHostEntry(hostname); + IPAddress ipAddress = ipHostInfo.AddressList[0]; + IPEndPoint remoteEP = new IPEndPoint(ipAddress, port); + + Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + client.BeginConnect( remoteEP, new AsyncCallback(ConnectCallback), client); + connectDone.WaitOne(); + /* + Send(client,"This is a test"); + sendDone.WaitOne(); + Receive(client); + receiveDone.WaitOne(); + client.Shutdown(SocketShutdown.Both); + client.Close(); + */ + return client; + } catch (Exception e) { + Console.WriteLine(e.ToString()); + throw new Exception("socket error !!"); + } + } + + private static void ConnectCallback(IAsyncResult ar) { + try { + Socket client = (Socket) ar.AsyncState; + client.EndConnect(ar); + Console.WriteLine("Socket connected to {0}", client.RemoteEndPoint.ToString()); + connectDone.Set(); + } catch (Exception e) { + Console.WriteLine(e.ToString()); + } + } + +/* + public static void Receive(Socket client) { + try { + StateObject state = new StateObject(); + state.workSocket = client; + client.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); + } catch (Exception e) { + Console.WriteLine(e.ToString()); + } + } + + private static void ReceiveCallback( IAsyncResult ar ) { + try { + StateObject state = (StateObject) ar.AsyncState; + Socket client = state.workSocket; + + int bytesRead = client.EndReceive(ar); + if (bytesRead > 0) { + state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead)); + client.BeginReceive(state.buffer,0,StateObject.BufferSize,0, new AsyncCallback(ReceiveCallback), state); + } else { + if (state.sb.Length > 1) { + response = state.sb.ToString(); + } + receiveDone.Set(); + } + } catch (Exception e) { + Console.WriteLine(e.ToString()); + } + } +*/ + public static void Send(Socket client, byte[] byteData) { + client.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), client); + } + + private static void SendCallback(IAsyncResult ar) { + try { + Socket client = (Socket) ar.AsyncState; + int bytesSent = client.EndSend(ar); + //Console.WriteLine("Sent {0} bytes to server.", bytesSent); + sendDone.Set(); + } catch (Exception e) { + Console.WriteLine(e.ToString()); + } + } + } + +public class InternalPacketHeader +{ + private byte[] buffer = new byte[32]; + public int type; + public int throttlePacketType; + public int numbytes; + public Guid agent_id; + public int region_port; + + public void FromBytes(byte[] bytes) + { + int i = 0; // offset + try + { + this.type = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + this.throttlePacketType = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + this.numbytes = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + this.agent_id = new Guid( + bytes[i++] | (bytes[i++] << 8) | (bytes[i++] << 16) | bytes[i++] << 24, + (short)(bytes[i++] | (bytes[i++] << 8)), + (short)(bytes[i++] | (bytes[i++] << 8)), + bytes[i++], bytes[i++], bytes[i++], bytes[i++], + bytes[i++], bytes[i++], bytes[i++], bytes[i++]); + this.region_port = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24)); + } + catch (Exception) + { + throw new Exception("bad format!!!"); + } + } + + public byte[] ToBytes() + { + int i = 0; + this.buffer[i++] = (byte)(this.type % 256); + this.buffer[i++] = (byte)((this.type >> 8) % 256); + this.buffer[i++] = (byte)((this.type >> 16) % 256); + this.buffer[i++] = (byte)((this.type >> 24) % 256); + + this.buffer[i++] = (byte)(this.throttlePacketType % 256); + this.buffer[i++] = (byte)((this.throttlePacketType >> 8) % 256); + this.buffer[i++] = (byte)((this.throttlePacketType >> 16) % 256); + this.buffer[i++] = (byte)((this.throttlePacketType >> 24) % 256); + + this.buffer[i++] = (byte)(this.numbytes % 256); + this.buffer[i++] = (byte)((this.numbytes >> 8) % 256); + this.buffer[i++] = (byte)((this.numbytes >> 16) % 256); + this.buffer[i++] = (byte)((this.numbytes >> 24) % 256); + + // no endian care + Buffer.BlockCopy(agent_id.ToByteArray(), 0, this.buffer, i, 16); i += 16; + + this.buffer[i++] = (byte)(this.region_port % 256); + this.buffer[i++] = (byte)((this.region_port >> 8) % 256); + this.buffer[i++] = (byte)((this.region_port >> 16) % 256); + this.buffer[i++] = (byte)((this.region_port >> 24) % 256); + + return this.buffer; + } +} + public class TcpClient { + + public static int internalPacketHeaderSize = 4*4 + 16*1; + + private string mHostname; + private int mPort; + private Socket mConnection; + public TcpClient(string hostname, int port) { + this.mHostname = hostname; + this.mPort = port; + this.mConnection = null; + } + public void connect() { + this.mConnection = AsynchronousClient.StartClient(mHostname, mPort); + } +/* + public void recevie() { + if (mConnection == null) { + throw new Exception("client not initialized"); + } + try + { + AsynchronousClient.Receive(this.mConnection); + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + mConnection = null; + } + } +*/ + public void send(InternalPacketHeader header, byte[] packet) { + + lock (this) + { + + if (mConnection == null) { +// throw new Exception("client not initialized"); + connect(); + } + + AsynchronousClient.Send(this.mConnection, header.ToBytes()); + +/* +for (int i = 0; i < 10; i++) +{ + Console.Write(packet[i] + " "); +} +Console.WriteLine(""); +*/ + AsynchronousClient.Send(this.mConnection, packet); + } + } + } +} diff --git a/ThirdParty/3Di/LoadBalancer/TcpServer.cs b/ThirdParty/3Di/LoadBalancer/TcpServer.cs new file mode 100644 index 0000000000..ee8bcba255 --- /dev/null +++ b/ThirdParty/3Di/LoadBalancer/TcpServer.cs @@ -0,0 +1,219 @@ +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +using System; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Runtime.Serialization.Formatters.Binary; + +using OpenSim.Framework.Console; + +namespace OpenSim.ApplicationPlugins.LoadBalancer { + + public class StateObject { + public Socket workSocket = null; + public const int BufferSize = 2048; + public byte[] buffer = new byte[BufferSize]; + public MemoryStream ms_ptr = new MemoryStream(); + public InternalPacketHeader header = null; + } + + public class AsynchronousSocketListener { + public static string data = null; + public static ManualResetEvent allDone = new ManualResetEvent(false); + +#region KIRYU + public delegate void PacketRecieveHandler(InternalPacketHeader header, byte[] buff); + public static PacketRecieveHandler PacketHandler = null; +#endregion + + public AsynchronousSocketListener() { } + + public static void StartListening(int port) { + IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName()); + IPAddress ipAddress = ipHostInfo.AddressList[0]; + IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port); + + Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp ); + try { + listener.Bind(localEndPoint); + listener.Listen(100); + while (true) { + allDone.Reset(); + listener.BeginAccept( new AsyncCallback(AcceptCallback), listener ); + allDone.WaitOne(); + } + } catch (Exception e) { + Console.WriteLine(e.ToString()); + } + /* + Console.WriteLine("\nPress ENTER to continue..."); + Console.Read(); + */ + } + + public static void AcceptCallback(IAsyncResult ar) { + allDone.Set(); + Socket listener = (Socket) ar.AsyncState; + Socket handler = listener.EndAccept(ar); + StateObject state = new StateObject(); + state.workSocket = handler; + handler.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state); + } + + public static void ReadCallback(IAsyncResult ar) { + String content = String.Empty; + StateObject state = (StateObject) ar.AsyncState; + Socket handler = state.workSocket; + + try + { + + int bytesRead = handler.EndReceive(ar); + + //MainLog.Instance.Verbose("TCPSERVER", "Received packet [{0}]", bytesRead); + + if (bytesRead > 0) { + state.ms_ptr.Write(state.buffer, 0, bytesRead); + } + else + { + //MainLog.Instance.Verbose("TCPSERVER", "Connection terminated"); + return; + } + + long rest_size = state.ms_ptr.Length; + long current_pos = 0; + while (rest_size > TcpClient.internalPacketHeaderSize) { + + if ((state.header == null) && (rest_size >= TcpClient.internalPacketHeaderSize)) + { + //MainLog.Instance.Verbose("TCPSERVER", "Processing header"); + + // reading header + state.header = new InternalPacketHeader(); + + byte[] headerbytes = new byte[TcpClient.internalPacketHeaderSize]; + state.ms_ptr.Position = current_pos; + state.ms_ptr.Read(headerbytes, 0, TcpClient.internalPacketHeaderSize); + state.ms_ptr.Seek(0, SeekOrigin.End); + state.header.FromBytes(headerbytes); + } + + if ((state.header != null) && (rest_size >= state.header.numbytes + TcpClient.internalPacketHeaderSize)) + { + //MainLog.Instance.Verbose("TCPSERVER", "Processing body"); + + // reading body + byte[] packet = new byte[state.header.numbytes]; + state.ms_ptr.Position = current_pos + TcpClient.internalPacketHeaderSize; + state.ms_ptr.Read(packet, 0, state.header.numbytes); + +/* + for(int i=0; i + + + + +Region Monitor GUI, 3Di + + +HEADER +} + +sub screen_footer { + return << "FOOTER"; + + +FOOTER +} + +sub html { + my $grid_info = shift; + my $regions_list = $grid_info->{"sim-profiles"}; + $regions = undef; + foreach(@$regions_list) { + my $ip = $_->{sim_ip} || "UNKNOWN"; + my $port = $_->{sim_port} || "UNKNOWN"; + $regions->{$ip}->{$port} = $_; + if (!$regions->{max_port} || $regions->{max_port} < $port) { + $regions->{max_port} = $port; + } + } + @server_list = keys %$regions; + $max_port = $regions->{max_port}; + my $html = ""; + foreach my $machine (@server_list) { + next if ($machine eq "max_port"); + $html .= &_machine_view($machine, $regions->{$machine}); + } + return $html; +} + +sub _machine_view { + my ($ip, $info) = @_; + my $region_html = ""; + foreach my $region (keys %$info) { + $region_html .= &_region_html($info->{$region}); + } + my $html =<< "MACHINE_HTML"; +

$ip

+$region_html +
+MACHINE_HTML +} + +sub _region_html { + my $region_info = shift; + my $name = $region_info->{name} || "UNKNOWN"; + my $x = $region_info->{x} || -1; + my $y = $region_info->{y} || -1; + my $ip = $region_info->{sim_ip} || "UNKNOWN"; + my $port = $region_info->{sim_port} || "UNKNOWN"; + my $get_scene_presence_filter = $region_info->{get_scene_presence_filter}; + my $get_scene_presence = $region_info->{get_scene_presence}; + my $get_avatar_filter = $region_info->{get_avatar_filter}; + my $get_avatar = $region_info->{get_avatar}; + my $avatar_names = $region_info->{avatar_names}; + my $action_forms = &_action_forms($region_info); + my $html = <<"REGION_HTML"; +$name
+$ip:$port | X: $x Y: $y
+ + + + + + + + + + + + + + + + + + + + + +
get_avatar$get_avatar
get_avatar_filter$get_avatar_filter$avatar_names
get_scene_presence$get_scene_presence
get_scene_presence_filter$get_scene_presence_filter
+$action_forms +REGION_HTML + return $html; +} + +sub _action_forms { + my $region_info = shift; + my $ip = $region_info->{sim_ip}; + my $port = $region_info->{sim_port}; + my $default_input_port = $max_port + 1; + my $move_to_options = ""; + my $split_to_options = ""; + my $merge_ip_options = ""; + foreach(@server_list) { + next if ($_ eq "max_port"); + $merge_ip_options .= "