diff --git a/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs b/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs index 6ba022cd93..6731923c3b 100644 --- a/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs +++ b/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs @@ -46,7 +46,7 @@ namespace OpenSim.OfflineIM { public class OfflineIMService : OfflineIMServiceBase, IOfflineIMService { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private const int MAX_IM = 25; private XmlSerializer m_serializer; diff --git a/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs b/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs index c0ca1e1896..2c91328e56 100644 --- a/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs +++ b/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs @@ -46,7 +46,7 @@ namespace OpenSim.Capabilities.Handlers { public class FetchInventory2Handler { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private IInventoryService m_inventoryService; @@ -121,4 +121,4 @@ namespace OpenSim.Capabilities.Handlers return llsdItem; } } -} +} \ No newline at end of file diff --git a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs index be1d02bd10..20495f6e95 100644 --- a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -45,16 +45,16 @@ namespace OpenSim.Framework.Monitoring sb.Append(Environment.NewLine); sb.AppendFormat( - "Allocated to OpenSim objects: {0} MB\n", + "Heap allocated to OpenSim : {0} MB\n", Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0)); sb.AppendFormat( - "OpenSim last object memory churn : {0} MB/s\n", - Math.Round((MemoryWatchdog.LastMemoryChurn * 1000) / 1024.0 / 1024, 3)); + "Last heap allocation rate : {0} MB/s\n", + Math.Round((MemoryWatchdog.LastHeapAllocationRate * 1000) / 1024.0 / 1024, 3)); sb.AppendFormat( - "OpenSim average object memory churn : {0} MB/s\n", - Math.Round((MemoryWatchdog.AverageMemoryChurn * 1000) / 1024.0 / 1024, 3)); + "Average heap allocation rate: {0} MB/s\n", + Math.Round((MemoryWatchdog.AverageHeapAllocationRate * 1000) / 1024.0 / 1024, 3)); sb.AppendFormat( "Process memory : {0} MB\n", diff --git a/OpenSim/Framework/Monitoring/MemoryWatchdog.cs b/OpenSim/Framework/Monitoring/MemoryWatchdog.cs index c6010cd092..c47462225b 100644 --- a/OpenSim/Framework/Monitoring/MemoryWatchdog.cs +++ b/OpenSim/Framework/Monitoring/MemoryWatchdog.cs @@ -60,17 +60,17 @@ namespace OpenSim.Framework.Monitoring private static bool m_enabled; /// - /// Last memory churn in bytes per millisecond. + /// Average heap allocation rate in bytes per millisecond. /// - public static double AverageMemoryChurn + public static double AverageHeapAllocationRate { get { if (m_samples.Count > 0) return m_samples.Average(); else return 0; } } /// - /// Average memory churn in bytes per millisecond. + /// Last heap allocation in bytes /// - public static double LastMemoryChurn + public static double LastHeapAllocationRate { get { if (m_samples.Count > 0) return m_samples.Last(); else return 0; } } diff --git a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs new file mode 100644 index 0000000000..ac0f0bc7be --- /dev/null +++ b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs @@ -0,0 +1,349 @@ +/* + * 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 OpenSimulator 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.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Net.NetworkInformation; +using System.Text; +using System.Threading; +using log4net; +using Nini.Config; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; + +namespace OpenSim.Framework.Monitoring +{ + public class ServerStatsCollector + { + private readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private readonly string LogHeader = "[SERVER STATS]"; + + public bool Enabled = false; + private static Dictionary RegisteredStats = new Dictionary(); + + public readonly string CategoryServer = "server"; + + public readonly string ContainerThreadpool = "threadpool"; + public readonly string ContainerProcessor = "processor"; + public readonly string ContainerMemory = "memory"; + public readonly string ContainerNetwork = "network"; + public readonly string ContainerProcess = "process"; + + public string NetworkInterfaceTypes = "Ethernet"; + + readonly int performanceCounterSampleInterval = 500; +// int lastperformanceCounterSampleTime = 0; + + private class PerfCounterControl + { + public PerformanceCounter perfCounter; + public int lastFetch; + public string name; + public PerfCounterControl(PerformanceCounter pPc) + : this(pPc, String.Empty) + { + } + public PerfCounterControl(PerformanceCounter pPc, string pName) + { + perfCounter = pPc; + lastFetch = 0; + name = pName; + } + } + + PerfCounterControl processorPercentPerfCounter = null; + + // IRegionModuleBase.Initialize + public void Initialise(IConfigSource source) + { + IConfig cfg = source.Configs["Monitoring"]; + + if (cfg != null) + Enabled = cfg.GetBoolean("ServerStatsEnabled", true); + + if (Enabled) + { + NetworkInterfaceTypes = cfg.GetString("NetworkInterfaceTypes", "Ethernet"); + } + } + + public void Start() + { + if (RegisteredStats.Count == 0) + RegisterServerStats(); + } + + public void Close() + { + if (RegisteredStats.Count > 0) + { + foreach (Stat stat in RegisteredStats.Values) + { + StatsManager.DeregisterStat(stat); + stat.Dispose(); + } + RegisteredStats.Clear(); + } + } + + private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action act) + { + MakeStat(pName, pDesc, pUnit, pContainer, act, MeasuresOfInterest.None); + } + + private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action act, MeasuresOfInterest moi) + { + string desc = pDesc; + if (desc == null) + desc = pName; + Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, moi, act, StatVerbosity.Debug); + StatsManager.RegisterStat(stat); + RegisteredStats.Add(pName, stat); + } + + public void RegisterServerStats() + { +// lastperformanceCounterSampleTime = Util.EnvironmentTickCount(); + PerformanceCounter tempPC; + Stat tempStat; + string tempName; + + try + { + tempName = "CPUPercent"; + tempPC = new PerformanceCounter("Processor", "% Processor Time", "_Total"); + processorPercentPerfCounter = new PerfCounterControl(tempPC); + // A long time bug in mono is that CPU percent is reported as CPU percent idle. Windows reports CPU percent busy. + tempStat = new Stat(tempName, tempName, "", "percent", CategoryServer, ContainerProcessor, + StatType.Pull, (s) => { GetNextValue(s, processorPercentPerfCounter, Util.IsWindows() ? 1 : -1); }, + StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor, + (s) => { s.Value = Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds; }); + + MakeStat("UserProcessorTime", null, "sec", ContainerProcessor, + (s) => { s.Value = Process.GetCurrentProcess().UserProcessorTime.TotalSeconds; }); + + MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor, + (s) => { s.Value = Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds; }); + + MakeStat("Threads", null, "threads", ContainerProcessor, + (s) => { s.Value = Process.GetCurrentProcess().Threads.Count; }); + } + catch (Exception e) + { + m_log.ErrorFormat("{0} Exception creating 'Process': {1}", LogHeader, e); + } + + MakeStat("BuiltinThreadpoolWorkerThreadsAvailable", null, "threads", ContainerThreadpool, + s => + { + int workerThreads, iocpThreads; + ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); + s.Value = workerThreads; + }); + + MakeStat("BuiltinThreadpoolIOCPThreadsAvailable", null, "threads", ContainerThreadpool, + s => + { + int workerThreads, iocpThreads; + ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); + s.Value = iocpThreads; + }); + + if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool && Util.GetSmartThreadPoolInfo() != null) + { + MakeStat("STPMaxThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxThreads); + MakeStat("STPMinThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MinThreads); + MakeStat("STPConcurrency", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxConcurrentWorkItems); + MakeStat("STPActiveThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().ActiveThreads); + MakeStat("STPInUseThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().InUseThreads); + MakeStat("STPWorkItemsWaiting", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().WaitingCallbacks); + } + + MakeStat( + "HTTPRequestsMade", + "Number of outbound HTTP requests made", + "requests", + ContainerNetwork, + s => s.Value = WebUtil.RequestNumber, + MeasuresOfInterest.AverageChangeOverTime); + + try + { + List okInterfaceTypes = new List(NetworkInterfaceTypes.Split(',')); + + IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces(); + foreach (NetworkInterface nic in nics) + { + if (nic.OperationalStatus != OperationalStatus.Up) + continue; + + string nicInterfaceType = nic.NetworkInterfaceType.ToString(); + if (!okInterfaceTypes.Contains(nicInterfaceType)) + { + m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'.", + LogHeader, nic.Name, nicInterfaceType); + m_log.DebugFormat("{0} To include, add to comma separated list in [Monitoring]NetworkInterfaceTypes={1}", + LogHeader, NetworkInterfaceTypes); + continue; + } + + if (nic.Supports(NetworkInterfaceComponent.IPv4)) + { + IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics(); + if (nicStats != null) + { + MakeStat("BytesRcvd/" + nic.Name, nic.Name, "KB", ContainerNetwork, + (s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); }); + MakeStat("BytesSent/" + nic.Name, nic.Name, "KB", ContainerNetwork, + (s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); }); + MakeStat("TotalBytes/" + nic.Name, nic.Name, "KB", ContainerNetwork, + (s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); }); + } + } + // TODO: add IPv6 (it may actually happen someday) + } + } + catch (Exception e) + { + m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e); + } + + MakeStat("ProcessMemory", null, "MB", ContainerMemory, + (s) => { s.Value = Math.Round(Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d, 3); }); + MakeStat("HeapMemory", null, "MB", ContainerMemory, + (s) => { s.Value = Math.Round(GC.GetTotalMemory(false) / 1024d / 1024d, 3); }); + MakeStat("LastHeapAllocationRate", null, "MB/sec", ContainerMemory, + (s) => { s.Value = Math.Round(MemoryWatchdog.LastHeapAllocationRate * 1000d / 1024d / 1024d, 3); }); + MakeStat("AverageHeapAllocationRate", null, "MB/sec", ContainerMemory, + (s) => { s.Value = Math.Round(MemoryWatchdog.AverageHeapAllocationRate * 1000d / 1024d / 1024d, 3); }); + } + + // Notes on performance counters: + // "How To Read Performance Counters": http://blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx + // "How to get the CPU Usage in C#": http://stackoverflow.com/questions/278071/how-to-get-the-cpu-usage-in-c + // "Mono Performance Counters": http://www.mono-project.com/Mono_Performance_Counters + private delegate double PerfCounterNextValue(); + private void GetNextValue(Stat stat, PerfCounterControl perfControl) + { + GetNextValue(stat, perfControl, 1.0); + } + private void GetNextValue(Stat stat, PerfCounterControl perfControl, double factor) + { + if (Util.EnvironmentTickCountSubtract(perfControl.lastFetch) > performanceCounterSampleInterval) + { + if (perfControl != null && perfControl.perfCounter != null) + { + try + { + // Kludge for factor to run double duty. If -1, subtract the value from one + if (factor == -1) + stat.Value = 1 - perfControl.perfCounter.NextValue(); + else + stat.Value = perfControl.perfCounter.NextValue() / factor; + } + catch (Exception e) + { + m_log.ErrorFormat("{0} Exception on NextValue fetching {1}: {2}", LogHeader, stat.Name, e); + } + perfControl.lastFetch = Util.EnvironmentTickCount(); + } + } + } + + // Lookup the nic that goes with this stat and set the value by using a fetch action. + // Not sure about closure with delegates inside delegates. + private delegate double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat); + private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor) + { + // Get the one nic that has the name of this stat + IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces().Where( + (network) => network.Name == stat.Description); + try + { + foreach (NetworkInterface nic in nics) + { + IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics(); + if (intrStats != null) + { + double newVal = Math.Round(getter(intrStats) / factor, 3); + stat.Value = newVal; + } + break; + } + } + catch + { + // There are times interfaces go away so we just won't update the stat for this + m_log.ErrorFormat("{0} Exception fetching stat on interface '{1}'", LogHeader, stat.Description); + } + } + } + + public class ServerStatsAggregator : Stat + { + public ServerStatsAggregator( + string shortName, + string name, + string description, + string unitName, + string category, + string container + ) + : base( + shortName, + name, + description, + unitName, + category, + container, + StatType.Push, + MeasuresOfInterest.None, + null, + StatVerbosity.Info) + { + } + public override string ToConsoleString() + { + StringBuilder sb = new StringBuilder(); + + return sb.ToString(); + } + + public override OSDMap ToOSDMap() + { + OSDMap ret = new OSDMap(); + + return ret; + } + } +} diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index 2e7665f5a1..c57ee0c3e8 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs @@ -27,8 +27,10 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Reflection; using System.Text; - +using log4net; using OpenMetaverse.StructuredData; namespace OpenSim.Framework.Monitoring @@ -38,6 +40,10 @@ namespace OpenSim.Framework.Monitoring /// public class Stat : IDisposable { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public static readonly char[] DisallowedShortNameCharacters = { '.' }; + /// /// Category of this stat (e.g. cache, scene, etc). /// @@ -95,7 +101,7 @@ namespace OpenSim.Framework.Monitoring /// /// Will be null if no measures of interest require samples. /// - private static Queue m_samples; + private Queue m_samples; /// /// Maximum number of statistical samples. @@ -162,6 +168,12 @@ namespace OpenSim.Framework.Monitoring throw new Exception( string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category)); + foreach (char c in DisallowedShortNameCharacters) + { + if (shortName.IndexOf(c) != -1) + throw new Exception(string.Format("Stat name {0} cannot contain character {1}", shortName, c)); + } + ShortName = shortName; Name = name; Description = description; @@ -204,6 +216,8 @@ namespace OpenSim.Framework.Monitoring if (m_samples.Count >= m_maxSamples) m_samples.Dequeue(); +// m_log.DebugFormat("[STAT]: Recording value {0} for {1}", newValue, Name); + m_samples.Enqueue(newValue); } } @@ -242,6 +256,10 @@ namespace OpenSim.Framework.Monitoring lock (m_samples) { +// m_log.DebugFormat( +// "[STAT]: Samples for {0} are {1}", +// Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray())); + foreach (double s in m_samples) { if (lastSample != null) @@ -253,7 +271,7 @@ namespace OpenSim.Framework.Monitoring int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1; - sb.AppendFormat(", {0:0.##}{1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName); + sb.AppendFormat(", {0:0.##} {1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName); } } } diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index 24db6d44c0..12d3a75d50 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; namespace OpenSim.Framework.Monitoring @@ -54,13 +55,13 @@ namespace OpenSim.Framework.Monitoring public static SortedDictionary>> RegisteredStats = new SortedDictionary>>(); - private static AssetStatsCollector assetStats; - private static UserStatsCollector userStats; - private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector(); +// private static AssetStatsCollector assetStats; +// private static UserStatsCollector userStats; +// private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector(); - public static AssetStatsCollector AssetStats { get { return assetStats; } } - public static UserStatsCollector UserStats { get { return userStats; } } - public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } } +// public static AssetStatsCollector AssetStats { get { return assetStats; } } +// public static UserStatsCollector UserStats { get { return userStats; } } + public static SimExtraStatsCollector SimExtraStats { get; set; } public static void RegisterConsoleCommands(ICommandConsole console) { @@ -68,12 +69,14 @@ namespace OpenSim.Framework.Monitoring "General", false, "show stats", - "show stats [list|all|]", + "show stats [list|all|([.])+", "Show statistical information for this server", "If no final argument is specified then legacy statistics information is currently shown.\n" - + "If list is specified then statistic categories are shown.\n" - + "If all is specified then all registered statistics are shown.\n" - + "If a category name is specified then only statistics from that category are shown.\n" + + "'list' argument will show statistic categories.\n" + + "'all' will show all statistics.\n" + + "A name will show statistics from that category.\n" + + "A . name will show statistics from that category in that container.\n" + + "More than one name can be given separated by spaces.\n" + "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS", HandleShowStatsCommand); } @@ -84,43 +87,47 @@ namespace OpenSim.Framework.Monitoring if (cmd.Length > 2) { - var categoryName = cmd[2]; - var containerName = cmd.Length > 3 ? cmd[3] : String.Empty; + foreach (string name in cmd.Skip(2)) + { + string[] components = name.Split('.'); - if (categoryName == AllSubCommand) - { - foreach (var category in RegisteredStats.Values) + string categoryName = components[0]; + string containerName = components.Length > 1 ? components[1] : null; + + if (categoryName == AllSubCommand) { - OutputCategoryStatsToConsole(con, category); + OutputAllStatsToConsole(con); } - } - else if (categoryName == ListSubCommand) - { - con.Output("Statistic categories available are:"); - foreach (string category in RegisteredStats.Keys) - con.OutputFormat(" {0}", category); - } - else - { - SortedDictionary> category; - if (!RegisteredStats.TryGetValue(categoryName, out category)) + else if (categoryName == ListSubCommand) { - con.OutputFormat("No such category as {0}", categoryName); + con.Output("Statistic categories available are:"); + foreach (string category in RegisteredStats.Keys) + con.OutputFormat(" {0}", category); } else { - if (String.IsNullOrEmpty(containerName)) - OutputCategoryStatsToConsole(con, category); + SortedDictionary> category; + if (!RegisteredStats.TryGetValue(categoryName, out category)) + { + con.OutputFormat("No such category as {0}", categoryName); + } else { - SortedDictionary container; - if (category.TryGetValue(containerName, out container)) + if (String.IsNullOrEmpty(containerName)) { - OutputContainerStatsToConsole(con, container); + OutputCategoryStatsToConsole(con, category); } else { - con.OutputFormat("No such container {0} in category {1}", containerName, categoryName); + SortedDictionary container; + if (category.TryGetValue(containerName, out container)) + { + OutputContainerStatsToConsole(con, container); + } + else + { + con.OutputFormat("No such container {0} in category {1}", containerName, categoryName); + } } } } @@ -129,7 +136,18 @@ namespace OpenSim.Framework.Monitoring else { // Legacy - con.Output(SimExtraStats.Report()); + if (SimExtraStats != null) + con.Output(SimExtraStats.Report()); + else + OutputAllStatsToConsole(con); + } + } + + private static void OutputAllStatsToConsole(ICommandConsole con) + { + foreach (var category in RegisteredStats.Values) + { + OutputCategoryStatsToConsole(con, category); } } @@ -150,27 +168,27 @@ namespace OpenSim.Framework.Monitoring } } - /// - /// Start collecting statistics related to assets. - /// Should only be called once. - /// - public static AssetStatsCollector StartCollectingAssetStats() - { - assetStats = new AssetStatsCollector(); - - return assetStats; - } - - /// - /// Start collecting statistics related to users. - /// Should only be called once. - /// - public static UserStatsCollector StartCollectingUserStats() - { - userStats = new UserStatsCollector(); - - return userStats; - } +// /// +// /// Start collecting statistics related to assets. +// /// Should only be called once. +// /// +// public static AssetStatsCollector StartCollectingAssetStats() +// { +// assetStats = new AssetStatsCollector(); +// +// return assetStats; +// } +// +// /// +// /// Start collecting statistics related to users. +// /// Should only be called once. +// /// +// public static UserStatsCollector StartCollectingUserStats() +// { +// userStats = new UserStatsCollector(); +// +// return userStats; +// } /// /// Registers a statistic. diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index 035b3ad180..4ab6908e90 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs @@ -86,25 +86,22 @@ namespace OpenSim.Framework.Servers /// protected virtual void StartupSpecific() { - if (m_console == null) - return; - + StatsManager.SimExtraStats = new SimExtraStatsCollector(); RegisterCommonCommands(); - - m_console.Commands.AddCommand("General", false, "quit", - "quit", - "Quit the application", HandleQuit); + RegisterCommonComponents(Config); + } - m_console.Commands.AddCommand("General", false, "shutdown", - "shutdown", - "Quit the application", HandleQuit); + protected override void ShutdownSpecific() + { + m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting..."); + + RemovePIDFile(); + + base.ShutdownSpecific(); + + Environment.Exit(0); } - /// - /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing - /// - public virtual void ShutdownSpecific() {} - /// /// Provides a list of help topics that are available. Overriding classes should append their topics to the /// information returned when the base method is called. @@ -143,25 +140,8 @@ namespace OpenSim.Framework.Servers timeTaken.Minutes, timeTaken.Seconds); } - /// - /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing - /// - public virtual void Shutdown() + public string osSecret { - ShutdownSpecific(); - - m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting..."); - RemovePIDFile(); - - Environment.Exit(0); - } - - private void HandleQuit(string module, string[] args) - { - Shutdown(); - } - - public string osSecret { // Secret uuid for the simulator get { return m_osSecret; } } diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 96a030bba0..40b8c5c1ed 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -54,7 +54,6 @@ namespace OpenSim.Framework.Servers.HttpServer private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); - /// /// This is a pending websocket request before it got an sucessful upgrade response. /// The consumer must call handler.HandshakeAndUpgrade() to signal to the handler to @@ -81,6 +80,11 @@ namespace OpenSim.Framework.Servers.HttpServer /// public int RequestNumber { get; private set; } + /// + /// Statistic for holding number of requests processed. + /// + private Stat m_requestsProcessedStat; + private volatile int NotSocketErrors = 0; public volatile bool HTTPDRunning = false; @@ -436,9 +440,8 @@ namespace OpenSim.Framework.Servers.HttpServer } } - public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) + private void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) { - OSHttpRequest req = new OSHttpRequest(context, request); WebSocketRequestDelegate dWebSocketRequestDelegate = null; lock (m_WebSocketHandlers) @@ -454,8 +457,7 @@ namespace OpenSim.Framework.Servers.HttpServer OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); resp.ReuseContext = true; - HandleRequest(req, resp); - + HandleRequest(req, resp); // !!!HACK ALERT!!! // There seems to be a bug in the underlying http code that makes subsequent requests @@ -1824,6 +1826,21 @@ namespace OpenSim.Framework.Servers.HttpServer // useful without inbound HTTP. throw e; } + + m_requestsProcessedStat + = new Stat( + "HTTPRequestsServed", + "Number of inbound HTTP requests processed", + "", + "requests", + "httpserver", + Port.ToString(), + StatType.Pull, + MeasuresOfInterest.AverageChangeOverTime, + stat => stat.Value = RequestNumber, + StatVerbosity.Debug); + + StatsManager.RegisterStat(m_requestsProcessedStat); } public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err) @@ -1854,6 +1871,9 @@ namespace OpenSim.Framework.Servers.HttpServer public void Stop() { HTTPDRunning = false; + + StatsManager.DeregisterStat(m_requestsProcessedStat); + try { m_PollServiceManager.Stop(); diff --git a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs index ee96b47c69..de89e2e638 100644 --- a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs @@ -75,7 +75,7 @@ namespace OpenSim.Framework.Servers.HttpServer /// /// This is a regular HTTP Request... This may be removed in the future. /// - public event RegularHttpRequestDelegate OnRegularHttpRequest; +// public event RegularHttpRequestDelegate OnRegularHttpRequest; /// /// When the upgrade from a HTTP request to a Websocket is completed, this will be fired @@ -304,15 +304,14 @@ namespace OpenSim.Framework.Servers.HttpServer if (d != null) d(this, new UpgradeCompletedEventArgs()); } - catch (IOException fail) + catch (IOException) { Close(string.Empty); } - catch (ObjectDisposedException fail) + catch (ObjectDisposedException) { Close(string.Empty); - } - + } } /// @@ -414,8 +413,6 @@ namespace OpenSim.Framework.Servers.HttpServer _socketState.Header = pheader; } - - if (_socketState.FrameComplete) { ProcessFrame(_socketState); @@ -424,7 +421,6 @@ namespace OpenSim.Framework.Servers.HttpServer _socketState.ExpectedBytes = 0; } - } } else @@ -457,8 +453,7 @@ namespace OpenSim.Framework.Servers.HttpServer _socketState.ReceivedBytes.Clear(); _socketState.ExpectedBytes = 0; // do some processing - } - + } } } if (offset > 0) @@ -477,13 +472,12 @@ namespace OpenSim.Framework.Servers.HttpServer { // We can't read the stream anymore... } - } - catch (IOException fail) + catch (IOException) { Close(string.Empty); } - catch (ObjectDisposedException fail) + catch (ObjectDisposedException) { Close(string.Empty); } diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs index 2c4a687237..029b848946 100644 --- a/OpenSim/Framework/Servers/ServerBase.cs +++ b/OpenSim/Framework/Servers/ServerBase.cs @@ -62,6 +62,8 @@ namespace OpenSim.Framework.Servers protected string m_pidFile = String.Empty; + protected ServerStatsCollector m_serverStatsCollector; + /// /// Server version information. Usually VersionInfo + information about git commit, operating system, etc. /// @@ -259,6 +261,25 @@ namespace OpenSim.Framework.Servers "force gc", "Manually invoke runtime garbage collection. For debugging purposes", HandleForceGc); + + m_console.Commands.AddCommand( + "General", false, "quit", + "quit", + "Quit the application", (mod, args) => Shutdown()); + + m_console.Commands.AddCommand( + "General", false, "shutdown", + "shutdown", + "Quit the application", (mod, args) => Shutdown()); + + StatsManager.RegisterConsoleCommands(m_console); + } + + public void RegisterCommonComponents(IConfigSource configSource) + { + m_serverStatsCollector = new ServerStatsCollector(); + m_serverStatsCollector.Initialise(configSource); + m_serverStatsCollector.Start(); } private void HandleForceGc(string module, string[] args) @@ -646,7 +667,68 @@ namespace OpenSim.Framework.Servers sb.AppendFormat("Total threads active: {0}\n\n", totalThreads); sb.Append("Main threadpool (excluding script engine pools)\n"); - sb.Append(Util.GetThreadPoolReport()); + sb.Append(GetThreadPoolReport()); + + return sb.ToString(); + } + + /// + /// Get a thread pool report. + /// + /// + public static string GetThreadPoolReport() + { + string threadPoolUsed = null; + int maxThreads = 0; + int minThreads = 0; + int allocatedThreads = 0; + int inUseThreads = 0; + int waitingCallbacks = 0; + int completionPortThreads = 0; + + StringBuilder sb = new StringBuilder(); + if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) + { + STPInfo stpi = Util.GetSmartThreadPoolInfo(); + + // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool. + if (stpi != null) + { + threadPoolUsed = "SmartThreadPool"; + maxThreads = stpi.MaxThreads; + minThreads = stpi.MinThreads; + inUseThreads = stpi.InUseThreads; + allocatedThreads = stpi.ActiveThreads; + waitingCallbacks = stpi.WaitingCallbacks; + } + } + else if ( + Util.FireAndForgetMethod == FireAndForgetMethod.QueueUserWorkItem + || Util.FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) + { + threadPoolUsed = "BuiltInThreadPool"; + ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); + ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); + int availableThreads; + ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); + inUseThreads = maxThreads - availableThreads; + allocatedThreads = -1; + waitingCallbacks = -1; + } + + if (threadPoolUsed != null) + { + sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); + sb.AppendFormat("Max threads : {0}\n", maxThreads); + sb.AppendFormat("Min threads : {0}\n", minThreads); + sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); + sb.AppendFormat("In use threads : {0}\n", inUseThreads); + sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); + } + else + { + sb.AppendFormat("Thread pool not used\n"); + } return sb.ToString(); } @@ -698,5 +780,16 @@ namespace OpenSim.Framework.Servers if (m_console != null) m_console.OutputFormat(format, components); } + + public virtual void Shutdown() + { + m_serverStatsCollector.Close(); + ShutdownSpecific(); + } + + /// + /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing + /// + protected virtual void ShutdownSpecific() {} } } \ No newline at end of file diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 7f0850fba0..ba6cc75e12 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -88,10 +88,31 @@ namespace OpenSim.Framework Thread, } + /// + /// Class for delivering SmartThreadPool statistical information + /// + /// + /// We do it this way so that we do not directly expose STP. + /// + public class STPInfo + { + public string Name { get; set; } + public STPStartInfo STPStartInfo { get; set; } + public WIGStartInfo WIGStartInfo { get; set; } + public bool IsIdle { get; set; } + public bool IsShuttingDown { get; set; } + public int MaxThreads { get; set; } + public int MinThreads { get; set; } + public int InUseThreads { get; set; } + public int ActiveThreads { get; set; } + public int WaitingCallbacks { get; set; } + public int MaxConcurrentWorkItems { get; set; } + } + /// /// Miscellaneous utility functions /// - public class Util + public static class Util { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -1852,74 +1873,31 @@ namespace OpenSim.Framework } /// - /// Get a thread pool report. + /// Get information about the current state of the smart thread pool. /// - /// - public static string GetThreadPoolReport() + /// + /// null if this isn't the pool being used for non-scriptengine threads. + /// + public static STPInfo GetSmartThreadPoolInfo() { - string threadPoolUsed = null; - int maxThreads = 0; - int minThreads = 0; - int allocatedThreads = 0; - int inUseThreads = 0; - int waitingCallbacks = 0; - int completionPortThreads = 0; + if (m_ThreadPool == null) + return null; - StringBuilder sb = new StringBuilder(); - if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) - { - // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool. - if (m_ThreadPool != null) - { - threadPoolUsed = "SmartThreadPool"; - maxThreads = m_ThreadPool.MaxThreads; - minThreads = m_ThreadPool.MinThreads; - inUseThreads = m_ThreadPool.InUseThreads; - allocatedThreads = m_ThreadPool.ActiveThreads; - waitingCallbacks = m_ThreadPool.WaitingCallbacks; - } - } - else if ( - FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem - || FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) - { - threadPoolUsed = "BuiltInThreadPool"; - ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); - ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); - int availableThreads; - ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); - inUseThreads = maxThreads - availableThreads; - allocatedThreads = -1; - waitingCallbacks = -1; - } + STPInfo stpi = new STPInfo(); + stpi.Name = m_ThreadPool.Name; + stpi.STPStartInfo = m_ThreadPool.STPStartInfo; + stpi.IsIdle = m_ThreadPool.IsIdle; + stpi.IsShuttingDown = m_ThreadPool.IsShuttingdown; + stpi.MaxThreads = m_ThreadPool.MaxThreads; + stpi.MinThreads = m_ThreadPool.MinThreads; + stpi.InUseThreads = m_ThreadPool.InUseThreads; + stpi.ActiveThreads = m_ThreadPool.ActiveThreads; + stpi.WaitingCallbacks = m_ThreadPool.WaitingCallbacks; + stpi.MaxConcurrentWorkItems = m_ThreadPool.Concurrency; - if (threadPoolUsed != null) - { - sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); - sb.AppendFormat("Max threads : {0}\n", maxThreads); - sb.AppendFormat("Min threads : {0}\n", minThreads); - sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); - sb.AppendFormat("In use threads : {0}\n", inUseThreads); - sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); - } - else - { - sb.AppendFormat("Thread pool not used\n"); - } - - return sb.ToString(); + return stpi; } -// private static object SmartThreadPoolCallback(object o) -// { -// object[] array = (object[])o; -// WaitCallback callback = (WaitCallback)array[0]; -// object obj = array[1]; -// -// callback(obj); -// return null; -// } - #endregion FireAndForget Threading Pattern /// diff --git a/OpenSim/Region/Application/Application.cs b/OpenSim/Region/Application/Application.cs index c3e7ec2e67..e451aa8148 100644 --- a/OpenSim/Region/Application/Application.cs +++ b/OpenSim/Region/Application/Application.cs @@ -124,6 +124,7 @@ namespace OpenSim workerThreads = workerThreadsMax; m_log.InfoFormat("[OPENSIM MAIN]: Limiting worker threads to {0}",workerThreads); } + // Increase the number of IOCP threads available. // Mono defaults to a tragically low number (24 on 6-core / 8GB Fedora 17) if (iocpThreads < iocpThreadsMin) diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 11dd052a19..9325b12220 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -372,7 +372,7 @@ namespace OpenSim "Unload a module", HandleModules); } - public override void ShutdownSpecific() + protected override void ShutdownSpecific() { if (m_shutdownCommandsFile != String.Empty) { diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index f9e0cf1b49..7ca87a3134 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -231,10 +231,7 @@ namespace OpenSim } if (m_console != null) - { - StatsManager.RegisterConsoleCommands(m_console); AddPluginCommands(m_console); - } } protected virtual void AddPluginCommands(ICommandConsole console) @@ -880,7 +877,7 @@ namespace OpenSim /// /// Performs any last-minute sanity checking and shuts down the region server /// - public override void ShutdownSpecific() + protected override void ShutdownSpecific() { if (proxyUrl.Length > 0) { @@ -900,6 +897,8 @@ namespace OpenSim { m_log.Error("[SHUTDOWN]: Ignoring failure during shutdown - ", e); } + + base.ShutdownSpecific(); } /// diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 2024018aa3..0e3cd6b283 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -34,6 +34,7 @@ using log4net; using Nini.Config; using Mono.Addins; using OpenMetaverse; +using OpenMetaverse.StructuredData; using OpenSim.Framework; using OpenSim.Framework.Monitoring; using OpenSim.Framework.Servers; @@ -44,8 +45,6 @@ using OpenSim.Framework.Capabilities; using OpenSim.Services.Interfaces; using Caps = OpenSim.Framework.Capabilities.Caps; using OpenSim.Capabilities.Handlers; -using OpenMetaverse; -using OpenMetaverse.StructuredData; namespace OpenSim.Region.ClientStack.Linden { @@ -64,7 +63,7 @@ namespace OpenSim.Region.ClientStack.Linden public List folders; } - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private Scene m_scene; diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs index 556df305ab..b47ff54efe 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs @@ -33,6 +33,7 @@ using NUnit.Framework; using OpenMetaverse; using OpenMetaverse.Packets; using OpenSim.Framework; +using OpenSim.Framework.Monitoring; using OpenSim.Region.Framework.Scenes; using OpenSim.Tests.Common; using OpenSim.Tests.Common.Mock; @@ -69,6 +70,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests { base.SetUp(); m_scene = new SceneHelpers().SetupScene(); + StatsManager.SimExtraStats = new SimExtraStatsCollector(); } /// @@ -210,8 +212,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); Assert.That(spAfterAckTimeout, Is.Null); - -// TestHelpers.DisableLogging(); } // /// diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs index 7d763faf10..7f3d0a2584 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs @@ -182,7 +182,10 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage "POST", m_RestURL + "/RetrieveMessages/", client.AgentId); if (msglist == null) + { m_log.WarnFormat("[OFFLINE MESSAGING]: WARNING null message list."); + return; + } foreach (GridInstantMessage im in msglist) { diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index 02ed1a08e3..630d1c376f 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs @@ -53,8 +53,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private int m_levelHGTeleport = 0; + private string m_ThisHomeURI; private GatekeeperServiceConnector m_GatekeeperConnector; + private IUserAgentService m_UAS; protected bool m_RestrictAppearanceAbroad; protected string m_AccountName; @@ -143,6 +145,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: {0} enabled.", Name); } } + + moduleConfig = source.Configs["Hypergrid"]; + if (moduleConfig != null) + { + m_ThisHomeURI = moduleConfig.GetString("HomeURI", string.Empty); + if (m_ThisHomeURI != string.Empty && !m_ThisHomeURI.EndsWith("/")) + m_ThisHomeURI += '/'; + } } public override void AddRegion(Scene scene) @@ -194,7 +204,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer base.RegionLoaded(scene); if (m_Enabled) + { m_GatekeeperConnector = new GatekeeperServiceConnector(scene.AssetService); + m_UAS = scene.RequestModuleInterface(); + } } public override void RemoveRegion(Scene scene) @@ -272,8 +285,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (agentCircuit.ServiceURLs.ContainsKey("HomeURI")) { string userAgentDriver = agentCircuit.ServiceURLs["HomeURI"].ToString(); - IUserAgentService connector = new UserAgentServiceConnector(userAgentDriver); - bool success = connector.LoginAgentToGrid(agentCircuit, reg, finalDestination, out reason); + IUserAgentService connector; + + if (userAgentDriver.Equals(m_ThisHomeURI) && m_UAS != null) + connector = m_UAS; + else + connector = new UserAgentServiceConnector(userAgentDriver); + + bool success = connector.LoginAgentToGrid(agentCircuit, reg, finalDestination, false, out reason); logout = success; // flag for later logout from this grid; this is an HG TP if (success) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs index b2a1b23279..d120e11c2c 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs @@ -194,7 +194,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return false; // Try local first - if (m_localBackend.IsLocalRegion(destination.RegionHandle)) + if (m_localBackend.IsLocalRegion(destination.RegionID)) return m_localBackend.UpdateAgent(destination, cAgentData); return m_remoteConnector.UpdateAgent(destination, cAgentData); @@ -206,7 +206,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return false; // Try local first - if (m_localBackend.IsLocalRegion(destination.RegionHandle)) + if (m_localBackend.IsLocalRegion(destination.RegionID)) return m_localBackend.UpdateAgent(destination, cAgentData); return m_remoteConnector.UpdateAgent(destination, cAgentData); @@ -224,7 +224,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return true; // else do the remote thing - if (!m_localBackend.IsLocalRegion(destination.RegionHandle)) + if (!m_localBackend.IsLocalRegion(destination.RegionID)) return m_remoteConnector.RetrieveAgent(destination, id, out agent); return false; @@ -273,7 +273,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return true; // else do the remote thing - if (!m_localBackend.IsLocalRegion(destination.RegionHandle)) + if (!m_localBackend.IsLocalRegion(destination.RegionID)) return m_remoteConnector.CloseAgent(destination, id); return false; @@ -296,7 +296,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation } // else do the remote thing - if (!m_localBackend.IsLocalRegion(destination.RegionHandle)) + if (!m_localBackend.IsLocalRegion(destination.RegionID)) return m_remoteConnector.CreateObject(destination, newPosition, sog, isLocalCall); return false; diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index 84064427e0..e55c9ed87f 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs @@ -81,14 +81,14 @@ namespace OpenSim.Region.CoreModules.World.Land set { m_landData = value; } } - + public IPrimCounts PrimCounts { get; set; } public UUID RegionUUID { get { return m_scene.RegionInfo.RegionID; } } - + public Vector3 StartPoint { get @@ -101,11 +101,11 @@ namespace OpenSim.Region.CoreModules.World.Land return new Vector3(x * 4, y * 4, 0); } } - + return new Vector3(-1, -1, -1); } - } - + } + public Vector3 EndPoint { get @@ -116,15 +116,15 @@ namespace OpenSim.Region.CoreModules.World.Land { if (LandBitmap[x, y]) { - return new Vector3(x * 4, y * 4, 0); - } + return new Vector3(x * 4 + 4, y * 4 + 4, 0); + } } - } - + } + return new Vector3(-1, -1, -1); } } - + #region Constructors public LandObject(UUID owner_id, bool is_group_owned, Scene scene) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 6c79b13e2e..1e4d558de5 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -326,7 +326,7 @@ namespace OpenSim.Region.Framework.Scenes // Update item with new asset item.AssetID = asset.FullID; if (group.UpdateInventoryItem(item)) - remoteClient.SendAgentAlertMessage("Script saved", false); + remoteClient.SendAlertMessage("Script saved"); part.SendPropertiesToClient(remoteClient); @@ -342,7 +342,7 @@ namespace OpenSim.Region.Framework.Scenes } else { - remoteClient.SendAgentAlertMessage("Script saved", false); + remoteClient.SendAlertMessage("Script saved"); } // Tell anyone managing scripts that a script has been reloaded/changed @@ -1616,11 +1616,11 @@ namespace OpenSim.Region.Framework.Scenes remoteClient, part, transactionID, currentItem); if ((InventoryType)itemInfo.InvType == InventoryType.Notecard) - remoteClient.SendAgentAlertMessage("Notecard saved", false); + remoteClient.SendAlertMessage("Notecard saved"); else if ((InventoryType)itemInfo.InvType == InventoryType.LSL) - remoteClient.SendAgentAlertMessage("Script saved", false); + remoteClient.SendAlertMessage("Script saved"); else - remoteClient.SendAgentAlertMessage("Item saved", false); + remoteClient.SendAlertMessage("Item saved"); } // Base ALWAYS has move diff --git a/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs b/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs deleted file mode 100644 index 6e74ce0f50..0000000000 --- a/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs +++ /dev/null @@ -1,339 +0,0 @@ -/* - * 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 OpenSimulator 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.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Net.NetworkInformation; -using System.Text; -using System.Threading; - -using log4net; -using Mono.Addins; -using Nini.Config; - -using OpenSim.Framework; -using OpenSim.Framework.Console; -using OpenSim.Framework.Monitoring; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -using OpenMetaverse.StructuredData; - -namespace OpenSim.Region.OptionalModules.Framework.Monitoring -{ -[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ServerStatistics")] -public class ServerStats : ISharedRegionModule -{ - private readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - private readonly string LogHeader = "[SERVER STATS]"; - - public bool Enabled = false; - private static Dictionary RegisteredStats = new Dictionary(); - - public readonly string CategoryServer = "server"; - - public readonly string ContainerProcessor = "processor"; - public readonly string ContainerMemory = "memory"; - public readonly string ContainerNetwork = "network"; - public readonly string ContainerProcess = "process"; - - public string NetworkInterfaceTypes = "Ethernet"; - - readonly int performanceCounterSampleInterval = 500; - int lastperformanceCounterSampleTime = 0; - - private class PerfCounterControl - { - public PerformanceCounter perfCounter; - public int lastFetch; - public string name; - public PerfCounterControl(PerformanceCounter pPc) - : this(pPc, String.Empty) - { - } - public PerfCounterControl(PerformanceCounter pPc, string pName) - { - perfCounter = pPc; - lastFetch = 0; - name = pName; - } - } - - PerfCounterControl processorPercentPerfCounter = null; - - #region ISharedRegionModule - // IRegionModuleBase.Name - public string Name { get { return "Server Stats"; } } - // IRegionModuleBase.ReplaceableInterface - public Type ReplaceableInterface { get { return null; } } - // IRegionModuleBase.Initialize - public void Initialise(IConfigSource source) - { - IConfig cfg = source.Configs["Monitoring"]; - - if (cfg != null) - Enabled = cfg.GetBoolean("ServerStatsEnabled", true); - - if (Enabled) - { - NetworkInterfaceTypes = cfg.GetString("NetworkInterfaceTypes", "Ethernet"); - } - } - // IRegionModuleBase.Close - public void Close() - { - if (RegisteredStats.Count > 0) - { - foreach (Stat stat in RegisteredStats.Values) - { - StatsManager.DeregisterStat(stat); - stat.Dispose(); - } - RegisteredStats.Clear(); - } - } - // IRegionModuleBase.AddRegion - public void AddRegion(Scene scene) - { - } - // IRegionModuleBase.RemoveRegion - public void RemoveRegion(Scene scene) - { - } - // IRegionModuleBase.RegionLoaded - public void RegionLoaded(Scene scene) - { - } - // ISharedRegionModule.PostInitialize - public void PostInitialise() - { - if (RegisteredStats.Count == 0) - { - RegisterServerStats(); - } - } - #endregion ISharedRegionModule - - private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action act) - { - string desc = pDesc; - if (desc == null) - desc = pName; - Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, act, StatVerbosity.Info); - StatsManager.RegisterStat(stat); - RegisteredStats.Add(pName, stat); - } - - public void RegisterServerStats() - { - lastperformanceCounterSampleTime = Util.EnvironmentTickCount(); - PerformanceCounter tempPC; - Stat tempStat; - string tempName; - - try - { - tempName = "CPUPercent"; - tempPC = new PerformanceCounter("Processor", "% Processor Time", "_Total"); - processorPercentPerfCounter = new PerfCounterControl(tempPC); - // A long time bug in mono is that CPU percent is reported as CPU percent idle. Windows reports CPU percent busy. - tempStat = new Stat(tempName, tempName, "", "percent", CategoryServer, ContainerProcessor, - StatType.Pull, (s) => { GetNextValue(s, processorPercentPerfCounter, Util.IsWindows() ? 1 : -1); }, - StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); - - MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor, - (s) => { s.Value = Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds; }); - - MakeStat("UserProcessorTime", null, "sec", ContainerProcessor, - (s) => { s.Value = Process.GetCurrentProcess().UserProcessorTime.TotalSeconds; }); - - MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor, - (s) => { s.Value = Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds; }); - - MakeStat("Threads", null, "threads", ContainerProcessor, - (s) => { s.Value = Process.GetCurrentProcess().Threads.Count; }); - } - catch (Exception e) - { - m_log.ErrorFormat("{0} Exception creating 'Process': {1}", LogHeader, e); - } - - try - { - List okInterfaceTypes = new List(NetworkInterfaceTypes.Split(',')); - - IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces(); - foreach (NetworkInterface nic in nics) - { - if (nic.OperationalStatus != OperationalStatus.Up) - continue; - - string nicInterfaceType = nic.NetworkInterfaceType.ToString(); - if (!okInterfaceTypes.Contains(nicInterfaceType)) - { - m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'.", - LogHeader, nic.Name, nicInterfaceType); - m_log.DebugFormat("{0} To include, add to comma separated list in [Monitoring]NetworkInterfaceTypes={1}", - LogHeader, NetworkInterfaceTypes); - continue; - } - - if (nic.Supports(NetworkInterfaceComponent.IPv4)) - { - IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics(); - if (nicStats != null) - { - MakeStat("BytesRcvd/" + nic.Name, nic.Name, "KB", ContainerNetwork, - (s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); }); - MakeStat("BytesSent/" + nic.Name, nic.Name, "KB", ContainerNetwork, - (s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); }); - MakeStat("TotalBytes/" + nic.Name, nic.Name, "KB", ContainerNetwork, - (s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); }); - } - } - // TODO: add IPv6 (it may actually happen someday) - } - } - catch (Exception e) - { - m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e); - } - - MakeStat("ProcessMemory", null, "MB", ContainerMemory, - (s) => { s.Value = Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d; }); - MakeStat("ObjectMemory", null, "MB", ContainerMemory, - (s) => { s.Value = GC.GetTotalMemory(false) / 1024d / 1024d; }); - MakeStat("LastMemoryChurn", null, "MB/sec", ContainerMemory, - (s) => { s.Value = Math.Round(MemoryWatchdog.LastMemoryChurn * 1000d / 1024d / 1024d, 3); }); - MakeStat("AverageMemoryChurn", null, "MB/sec", ContainerMemory, - (s) => { s.Value = Math.Round(MemoryWatchdog.AverageMemoryChurn * 1000d / 1024d / 1024d, 3); }); - } - - // Notes on performance counters: - // "How To Read Performance Counters": http://blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx - // "How to get the CPU Usage in C#": http://stackoverflow.com/questions/278071/how-to-get-the-cpu-usage-in-c - // "Mono Performance Counters": http://www.mono-project.com/Mono_Performance_Counters - private delegate double PerfCounterNextValue(); - private void GetNextValue(Stat stat, PerfCounterControl perfControl) - { - GetNextValue(stat, perfControl, 1.0); - } - private void GetNextValue(Stat stat, PerfCounterControl perfControl, double factor) - { - if (Util.EnvironmentTickCountSubtract(perfControl.lastFetch) > performanceCounterSampleInterval) - { - if (perfControl != null && perfControl.perfCounter != null) - { - try - { - // Kludge for factor to run double duty. If -1, subtract the value from one - if (factor == -1) - stat.Value = 1 - perfControl.perfCounter.NextValue(); - else - stat.Value = perfControl.perfCounter.NextValue() / factor; - } - catch (Exception e) - { - m_log.ErrorFormat("{0} Exception on NextValue fetching {1}: {2}", LogHeader, stat.Name, e); - } - perfControl.lastFetch = Util.EnvironmentTickCount(); - } - } - } - - // Lookup the nic that goes with this stat and set the value by using a fetch action. - // Not sure about closure with delegates inside delegates. - private delegate double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat); - private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor) - { - // Get the one nic that has the name of this stat - IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces().Where( - (network) => network.Name == stat.Description); - try - { - foreach (NetworkInterface nic in nics) - { - IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics(); - if (intrStats != null) - { - double newVal = Math.Round(getter(intrStats) / factor, 3); - stat.Value = newVal; - } - break; - } - } - catch - { - // There are times interfaces go away so we just won't update the stat for this - m_log.ErrorFormat("{0} Exception fetching stat on interface '{1}'", LogHeader, stat.Description); - } - } -} - -public class ServerStatsAggregator : Stat -{ - public ServerStatsAggregator( - string shortName, - string name, - string description, - string unitName, - string category, - string container - ) - : base( - shortName, - name, - description, - unitName, - category, - container, - StatType.Push, - MeasuresOfInterest.None, - null, - StatVerbosity.Info) - { - } - public override string ToConsoleString() - { - StringBuilder sb = new StringBuilder(); - - return sb.ToString(); - } - - public override OSDMap ToOSDMap() - { - OSDMap ret = new OSDMap(); - - return ret; - } -} - -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs index ac8c30c9cd..928b350645 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs @@ -43,8 +43,14 @@ public class BSActorAvatarMove : BSActor // Set to true if we think we're going up stairs. // This state is remembered because collisions will turn on and off as we go up stairs. int m_walkingUpStairs; + // The amount the step up is applying. Used to smooth stair walking. float m_lastStepUp; + // Jumping happens over several frames. If use applies up force while colliding, start the + // jump and allow the jump to continue for this number of frames. + int m_jumpFrames = 0; + float m_jumpVelocity = 0f; + public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName) : base(physicsScene, pObj, actorName) { @@ -206,17 +212,45 @@ public class BSActorAvatarMove : BSActor if (m_controllingPrim.Friction != BSParam.AvatarFriction) { - // Probably starting up walking. Set friction to moving friction. + // Probably starting to walk. Set friction to moving friction. m_controllingPrim.Friction = BSParam.AvatarFriction; m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); } - // If falling, we keep the world's downward vector no matter what the other axis specify. - // The check for RawVelocity.Z < 0 makes jumping work (temporary upward force). if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding) { - if (m_controllingPrim.RawVelocity.Z < 0) + stepVelocity.Z = m_controllingPrim.RawVelocity.Z; + } + + + // Colliding and not flying with an upward force. The avatar must be trying to jump. + if (!m_controllingPrim.Flying && m_controllingPrim.IsColliding && stepVelocity.Z > 0) + { + // We allow the upward force to happen for this many frames. + m_jumpFrames = BSParam.AvatarJumpFrames; + m_jumpVelocity = stepVelocity.Z; + } + + // The case where the avatar is not colliding and is not flying is special. + // The avatar is either falling or jumping and the user can be applying force to the avatar + // (force in some direction or force up or down). + // If the avatar has negative Z velocity and is not colliding, presume we're falling and keep the velocity. + // If the user is trying to apply upward force but we're not colliding, assume the avatar + // is trying to jump and don't apply the upward force if not touching the ground any more. + if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding) + { + // If upward velocity is being applied, this must be a jump and only allow that to go on so long + if (m_jumpFrames > 0) + { + // Since not touching the ground, only apply upward force for so long. + m_jumpFrames--; + stepVelocity.Z = m_jumpVelocity; + } + else + { + // Since we're not affected by anything, whatever vertical motion the avatar has, continue that. stepVelocity.Z = m_controllingPrim.RawVelocity.Z; + } // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); } @@ -241,7 +275,7 @@ public class BSActorAvatarMove : BSActor m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}", m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying, m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z); - // This test is done if moving forward, not flying and is colliding with something. + // Check for stairs climbing if colliding, not flying and moving forward if ( m_controllingPrim.IsColliding && !m_controllingPrim.Flying diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 311cf4f220..07e87d13eb 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -209,7 +209,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin m_VhoverTimescale = Math.Max(pValue, 0.01f); break; case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: - m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f); + m_linearDeflectionEfficiency = ClampInRange(0f, pValue, 1f); break; case Vehicle.LINEAR_DEFLECTION_TIMESCALE: m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); @@ -707,7 +707,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin private Vector3 m_knownRotationalVelocity; private Vector3 m_knownRotationalForce; private Vector3 m_knownRotationalImpulse; - private Vector3 m_knownForwardVelocity; // vehicle relative forward speed private const int m_knownChangedPosition = 1 << 0; private const int m_knownChangedVelocity = 1 << 1; @@ -719,7 +718,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin private const int m_knownChangedRotationalImpulse = 1 << 7; private const int m_knownChangedTerrainHeight = 1 << 8; private const int m_knownChangedWaterLevel = 1 << 9; - private const int m_knownChangedForwardVelocity = 1 <<10; public void ForgetKnownVehicleProperties() { @@ -923,12 +921,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin { get { - if ((m_knownHas & m_knownChangedForwardVelocity) == 0) - { - m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation)); - m_knownHas |= m_knownChangedForwardVelocity; - } - return m_knownForwardVelocity; + return VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation)); } } private float VehicleForwardSpeed @@ -981,6 +974,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin { ComputeLinearVelocity(pTimestep); + ComputeLinearDeflection(pTimestep); + ComputeLinearTerrainHeightCorrection(pTimestep); ComputeLinearHover(pTimestep); @@ -1026,12 +1021,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin { // Step the motor from the current value. Get the correction needed this step. Vector3 origVelW = VehicleVelocity; // DEBUG - Vector3 currentVelV = VehicleVelocity * Quaternion.Inverse(VehicleOrientation); + Vector3 currentVelV = VehicleForwardVelocity; Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV); - // Friction reduces vehicle motion - Vector3 frictionFactorW = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep); - linearMotorCorrectionV -= (currentVelV * frictionFactorW); + // Friction reduces vehicle motion based on absolute speed. Slow vehicle down by friction. + Vector3 frictionFactorV = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep); + linearMotorCorrectionV -= (currentVelV * frictionFactorV); // Motor is vehicle coordinates. Rotate it to world coordinates Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation; @@ -1046,11 +1041,38 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Add this correction to the velocity to make it faster/slower. VehicleVelocity += linearMotorVelocityW; - - VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6}", ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, - linearMotorVelocityW, VehicleVelocity, frictionFactorW); + linearMotorVelocityW, VehicleVelocity, frictionFactorV); + } + + //Given a Deflection Effiency and a Velocity, Returns a Velocity that is Partially Deflected onto the X Axis + //Clamped so that a DeflectionTimescale of less then 1 does not increase force over original velocity + private void ComputeLinearDeflection(float pTimestep) + { + Vector3 linearDeflectionV = Vector3.Zero; + Vector3 velocityV = VehicleForwardVelocity; + + // Velocity in Y and Z dimensions is movement to the side or turning. + // Compute deflection factor from the to the side and rotational velocity + linearDeflectionV.Y = SortedClampInRange(0, (velocityV.Y * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Y); + linearDeflectionV.Z = SortedClampInRange(0, (velocityV.Z * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Z); + + // Velocity to the side and around is corrected and moved into the forward direction + linearDeflectionV.X += Math.Abs(linearDeflectionV.Y); + linearDeflectionV.X += Math.Abs(linearDeflectionV.Z); + + // Scale the deflection to the fractional simulation time + linearDeflectionV *= pTimestep; + + // Subtract the sideways and rotational velocity deflection factors while adding the correction forward + linearDeflectionV *= new Vector3(1,-1,-1); + + // Correciont is vehicle relative. Convert to world coordinates and add to the velocity + VehicleVelocity += linearDeflectionV * VehicleOrientation; + + VDetailLog("{0}, MoveLinear,LinearDeflection,linDefEff={1},linDefTS={2},linDeflectionV={3}", + ControllingPrim.LocalID, m_linearDeflectionEfficiency, m_linearDeflectionTimescale, linearDeflectionV); } public void ComputeLinearTerrainHeightCorrection(float pTimestep) @@ -1652,6 +1674,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin return frictionFactor; } + private float SortedClampInRange(float clampa, float val, float clampb) + { + if (clampa > clampb) + { + float temp = clampa; + clampa = clampb; + clampb = temp; + } + return ClampInRange(clampa, val, clampb); + + } + private float ClampInRange(float low, float val, float high) { return Math.Max(low, Math.Min(val, high)); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index aad1108cbc..6437b04896 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -134,6 +134,7 @@ public static class BSParam public static float AvatarHeightMidFudge { get; private set; } public static float AvatarHeightHighFudge { get; private set; } public static float AvatarContactProcessingThreshold { get; private set; } + public static int AvatarJumpFrames { get; private set; } public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } public static float AvatarStepHeight { get; private set; } public static float AvatarStepApproachFactor { get; private set; } @@ -567,6 +568,8 @@ public static class BSParam 0.1f ), new ParameterDefn("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", 1.0f ), + new ParameterDefn("AvatarJumpFrames", "Number of frames to allow jump forces. Changes jump height.", + 4 ), new ParameterDefn("AvatarStepHeight", "Height of a step obstacle to consider step correction", 0.6f ) , new ParameterDefn("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)", diff --git a/OpenSim/Server/Base/ServicesServerBase.cs b/OpenSim/Server/Base/ServicesServerBase.cs index b13c87d000..667cef80c5 100644 --- a/OpenSim/Server/Base/ServicesServerBase.cs +++ b/OpenSim/Server/Base/ServicesServerBase.cs @@ -34,6 +34,7 @@ using System.Text; using System.Xml; using OpenSim.Framework; using OpenSim.Framework.Console; +using OpenSim.Framework.Monitoring; using OpenSim.Framework.Servers; using log4net; using log4net.Config; @@ -190,16 +191,7 @@ namespace OpenSim.Server.Base } RegisterCommonCommands(); - - // Register the quit command - // - MainConsole.Instance.Commands.AddCommand("General", false, "quit", - "quit", - "Quit the application", HandleQuit); - - MainConsole.Instance.Commands.AddCommand("General", false, "shutdown", - "shutdown", - "Quit the application", HandleQuit); + RegisterCommonComponents(Config); // Allow derived classes to perform initialization that // needs to be done after the console has opened @@ -214,6 +206,9 @@ namespace OpenSim.Server.Base public virtual int Run() { + Watchdog.Enabled = true; + MemoryWatchdog.Enabled = true; + while (m_Running) { try @@ -231,11 +226,12 @@ namespace OpenSim.Server.Base return 0; } - protected virtual void HandleQuit(string module, string[] args) + protected override void ShutdownSpecific() { m_Running = false; m_log.Info("[CONSOLE] Quitting"); + base.ShutdownSpecific(); } protected virtual void ReadConfig() @@ -246,4 +242,4 @@ namespace OpenSim.Server.Base { } } -} +} \ No newline at end of file diff --git a/OpenSim/Server/Handlers/Hypergrid/AgentHandlers.cs b/OpenSim/Server/Handlers/Hypergrid/AgentHandlers.cs index cf1af15a37..adc2fbc081 100644 --- a/OpenSim/Server/Handlers/Hypergrid/AgentHandlers.cs +++ b/OpenSim/Server/Handlers/Hypergrid/AgentHandlers.cs @@ -61,7 +61,7 @@ namespace OpenSim.Server.Handlers.Hypergrid m_Proxy = proxy; } - protected override bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, out string reason) + protected override bool CreateAgent(GridRegion gatekeeper, GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, bool fromLogin, out string reason) { return m_GatekeeperService.LoginAgent(aCircuit, destination, out reason); } diff --git a/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs b/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs index 968c1e64c3..df875af14d 100644 --- a/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs +++ b/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs @@ -49,191 +49,87 @@ using log4net; namespace OpenSim.Server.Handlers.Hypergrid { - public class HomeAgentHandler + public class HomeAgentHandler : AgentPostHandler { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private IUserAgentService m_UserAgentService; private string m_LoginServerIP; - private bool m_Proxy = false; - public HomeAgentHandler(IUserAgentService userAgentService, string loginServerIP, bool proxy) + public HomeAgentHandler(IUserAgentService userAgentService, string loginServerIP, bool proxy) : + base("/homeagent") { m_UserAgentService = userAgentService; m_LoginServerIP = loginServerIP; m_Proxy = proxy; } - public Hashtable Handler(Hashtable request) + protected override AgentDestinationData CreateAgentDestinationData() { -// m_log.Debug("[CONNECTION DEBUGGING]: HomeAgentHandler Called"); -// -// m_log.Debug("---------------------------"); -// m_log.Debug(" >> uri=" + request["uri"]); -// m_log.Debug(" >> content-type=" + request["content-type"]); -// m_log.Debug(" >> http-method=" + request["http-method"]); -// m_log.Debug("---------------------------\n"); - - Hashtable responsedata = new Hashtable(); - responsedata["content_type"] = "text/html"; - responsedata["keepalive"] = false; - - - UUID agentID; - UUID regionID; - string action; - if (!Utils.GetParams((string)request["uri"], out agentID, out regionID, out action)) - { - m_log.InfoFormat("[HOME AGENT HANDLER]: Invalid parameters for agent message {0}", request["uri"]); - responsedata["int_response_code"] = 404; - responsedata["str_response_string"] = "false"; - - return responsedata; - } - - // Next, let's parse the verb - string method = (string)request["http-method"]; - if (method.Equals("POST")) - { - DoAgentPost(request, responsedata, agentID); - return responsedata; - } - else - { - m_log.InfoFormat("[HOME AGENT HANDLER]: method {0} not supported in agent message", method); - responsedata["int_response_code"] = HttpStatusCode.MethodNotAllowed; - responsedata["str_response_string"] = "Method not allowed"; - - return responsedata; - } - + return new ExtendedAgentDestinationData(); } - - protected void DoAgentPost(Hashtable request, Hashtable responsedata, UUID id) + protected override void UnpackData(OSDMap args, AgentDestinationData d, Hashtable request) { - OSDMap args = Utils.GetOSDMap((string)request["body"]); - if (args == null) - { - responsedata["int_response_code"] = HttpStatusCode.BadRequest; - responsedata["str_response_string"] = "Bad request"; - return; - } - - // retrieve the input arguments - int x = 0, y = 0; - UUID uuid = UUID.Zero; - string regionname = string.Empty; - string gatekeeper_host = string.Empty; - string gatekeeper_serveruri = string.Empty; - string destination_serveruri = string.Empty; - int gatekeeper_port = 0; - IPEndPoint client_ipaddress = null; - - if (args.ContainsKey("gatekeeper_host") && args["gatekeeper_host"] != null) - gatekeeper_host = args["gatekeeper_host"].AsString(); - if (args.ContainsKey("gatekeeper_port") && args["gatekeeper_port"] != null) - Int32.TryParse(args["gatekeeper_port"].AsString(), out gatekeeper_port); - if (args.ContainsKey("gatekeeper_serveruri") && args["gatekeeper_serveruri"] !=null) - gatekeeper_serveruri = args["gatekeeper_serveruri"]; - if (args.ContainsKey("destination_serveruri") && args["destination_serveruri"] !=null) - destination_serveruri = args["destination_serveruri"]; - - GridRegion gatekeeper = new GridRegion(); - gatekeeper.ServerURI = gatekeeper_serveruri; - gatekeeper.ExternalHostName = gatekeeper_host; - gatekeeper.HttpPort = (uint)gatekeeper_port; - gatekeeper.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0); - - if (args.ContainsKey("destination_x") && args["destination_x"] != null) - Int32.TryParse(args["destination_x"].AsString(), out x); - else - m_log.WarnFormat(" -- request didn't have destination_x"); - if (args.ContainsKey("destination_y") && args["destination_y"] != null) - Int32.TryParse(args["destination_y"].AsString(), out y); - else - m_log.WarnFormat(" -- request didn't have destination_y"); - if (args.ContainsKey("destination_uuid") && args["destination_uuid"] != null) - UUID.TryParse(args["destination_uuid"].AsString(), out uuid); - if (args.ContainsKey("destination_name") && args["destination_name"] != null) - regionname = args["destination_name"].ToString(); - - if (args.ContainsKey("client_ip") && args["client_ip"] != null) - { - string ip_str = args["client_ip"].ToString(); - try - { - string callerIP = GetCallerIP(request); - // Verify if this caller has authority to send the client IP - if (callerIP == m_LoginServerIP) - client_ipaddress = new IPEndPoint(IPAddress.Parse(ip_str), 0); - else // leaving this for now, but this warning should be removed - m_log.WarnFormat("[HOME AGENT HANDLER]: Unauthorized machine {0} tried to set client ip to {1}", callerIP, ip_str); - } - catch - { - m_log.DebugFormat("[HOME AGENT HANDLER]: Exception parsing client ip address from {0}", ip_str); - } - } - - GridRegion destination = new GridRegion(); - destination.RegionID = uuid; - destination.RegionLocX = x; - destination.RegionLocY = y; - destination.RegionName = regionname; - destination.ServerURI = destination_serveruri; - - AgentCircuitData aCircuit = new AgentCircuitData(); + base.UnpackData(args, d, request); + ExtendedAgentDestinationData data = (ExtendedAgentDestinationData)d; try { - aCircuit.UnpackAgentCircuitData(args); + if (args.ContainsKey("gatekeeper_host") && args["gatekeeper_host"] != null) + data.host = args["gatekeeper_host"].AsString(); + if (args.ContainsKey("gatekeeper_port") && args["gatekeeper_port"] != null) + Int32.TryParse(args["gatekeeper_port"].AsString(), out data.port); + if (args.ContainsKey("gatekeeper_serveruri") && args["gatekeeper_serveruri"] != null) + data.gatekeeperServerURI = args["gatekeeper_serveruri"]; + if (args.ContainsKey("destination_serveruri") && args["destination_serveruri"] != null) + data.destinationServerURI = args["destination_serveruri"]; + } - catch (Exception ex) + catch (InvalidCastException e) { - m_log.InfoFormat("[HOME AGENT HANDLER]: exception on unpacking ChildCreate message {0}", ex.Message); - responsedata["int_response_code"] = HttpStatusCode.BadRequest; - responsedata["str_response_string"] = "Bad request"; - return; + m_log.ErrorFormat("[HOME AGENT HANDLER]: Bad cast in UnpackData"); } - OSDMap resp = new OSDMap(2); - string reason = String.Empty; + string callerIP = GetCallerIP(request); + // Verify if this call came from the login server + if (callerIP == m_LoginServerIP) + data.fromLogin = true; - bool result = m_UserAgentService.LoginAgentToGrid(aCircuit, gatekeeper, destination, client_ipaddress, out reason); - - resp["reason"] = OSD.FromString(reason); - resp["success"] = OSD.FromBoolean(result); - - // TODO: add reason if not String.Empty? - responsedata["int_response_code"] = HttpStatusCode.OK; - responsedata["str_response_string"] = OSDParser.SerializeJsonString(resp); } - private string GetCallerIP(Hashtable request) + protected override GridRegion ExtractGatekeeper(AgentDestinationData d) { - if (!m_Proxy) - return Util.GetCallerIP(request); - - // We're behind a proxy - Hashtable headers = (Hashtable)request["headers"]; - string xff = "X-Forwarded-For"; - if (headers.ContainsKey(xff.ToLower())) - xff = xff.ToLower(); - - if (!headers.ContainsKey(xff) || headers[xff] == null) + if (d is ExtendedAgentDestinationData) { - m_log.WarnFormat("[AGENT HANDLER]: No XFF header"); - return Util.GetCallerIP(request); + ExtendedAgentDestinationData data = (ExtendedAgentDestinationData)d; + GridRegion gatekeeper = new GridRegion(); + gatekeeper.ServerURI = data.gatekeeperServerURI; + gatekeeper.ExternalHostName = data.host; + gatekeeper.HttpPort = (uint)data.port; + gatekeeper.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0); + + return gatekeeper; } + else + m_log.WarnFormat("[HOME AGENT HANDLER]: Wrong data type"); - m_log.DebugFormat("[AGENT HANDLER]: XFF is {0}", headers[xff]); - - IPEndPoint ep = Util.GetClientIPFromXFF((string)headers[xff]); - if (ep != null) - return ep.Address.ToString(); - - // Oops - return Util.GetCallerIP(request); + return null; } + + + protected override bool CreateAgent(GridRegion gatekeeper, GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, bool fromLogin, out string reason) + { + return m_UserAgentService.LoginAgentToGrid(aCircuit, gatekeeper, destination, fromLogin, out reason); + } + + } + + public class ExtendedAgentDestinationData : AgentDestinationData + { + public string host; + public int port; + public string gatekeeperServerURI; + public string destinationServerURI; + } } diff --git a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs index b20f4672db..d9c1bd3d52 100644 --- a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs +++ b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs @@ -108,7 +108,7 @@ namespace OpenSim.Server.Handlers.Hypergrid server.AddXmlRPCHandler("get_uui", GetUUI, false); server.AddXmlRPCHandler("get_uuid", GetUUID, false); - server.AddHTTPHandler("/homeagent/", new HomeAgentHandler(m_HomeUsersService, loginServerIP, proxy).Handler); + server.AddStreamHandler(new HomeAgentHandler(m_HomeUsersService, loginServerIP, proxy)); } public XmlRpcResponse GetHomeRegion(XmlRpcRequest request, IPEndPoint remoteClient) diff --git a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs index ae37ca7d23..71a9e6fa41 100644 --- a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs +++ b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs @@ -328,31 +328,16 @@ namespace OpenSim.Server.Handlers.Simulation return; } - // retrieve the input arguments - int x = 0, y = 0; - UUID uuid = UUID.Zero; - string regionname = string.Empty; - uint teleportFlags = 0; - if (args.ContainsKey("destination_x") && args["destination_x"] != null) - Int32.TryParse(args["destination_x"].AsString(), out x); - else - m_log.WarnFormat(" -- request didn't have destination_x"); - if (args.ContainsKey("destination_y") && args["destination_y"] != null) - Int32.TryParse(args["destination_y"].AsString(), out y); - else - m_log.WarnFormat(" -- request didn't have destination_y"); - if (args.ContainsKey("destination_uuid") && args["destination_uuid"] != null) - UUID.TryParse(args["destination_uuid"].AsString(), out uuid); - if (args.ContainsKey("destination_name") && args["destination_name"] != null) - regionname = args["destination_name"].ToString(); - if (args.ContainsKey("teleport_flags") && args["teleport_flags"] != null) - teleportFlags = args["teleport_flags"].AsUInteger(); + AgentDestinationData data = CreateAgentDestinationData(); + UnpackData(args, data, request); GridRegion destination = new GridRegion(); - destination.RegionID = uuid; - destination.RegionLocX = x; - destination.RegionLocY = y; - destination.RegionName = regionname; + destination.RegionID = data.uuid; + destination.RegionLocX = data.x; + destination.RegionLocY = data.y; + destination.RegionName = data.name; + + GridRegion gatekeeper = ExtractGatekeeper(data); AgentCircuitData aCircuit = new AgentCircuitData(); try @@ -373,7 +358,7 @@ namespace OpenSim.Server.Handlers.Simulation // This is the meaning of POST agent //m_regionClient.AdjustUserInformation(aCircuit); //bool result = m_SimulationService.CreateAgent(destination, aCircuit, teleportFlags, out reason); - bool result = CreateAgent(destination, aCircuit, teleportFlags, out reason); + bool result = CreateAgent(gatekeeper, destination, aCircuit, data.flags, data.fromLogin, out reason); resp["reason"] = OSD.FromString(reason); resp["success"] = OSD.FromBoolean(result); @@ -385,7 +370,36 @@ namespace OpenSim.Server.Handlers.Simulation responsedata["str_response_string"] = OSDParser.SerializeJsonString(resp); } - private string GetCallerIP(Hashtable request) + protected virtual AgentDestinationData CreateAgentDestinationData() + { + return new AgentDestinationData(); + } + + protected virtual void UnpackData(OSDMap args, AgentDestinationData data, Hashtable request) + { + // retrieve the input arguments + if (args.ContainsKey("destination_x") && args["destination_x"] != null) + Int32.TryParse(args["destination_x"].AsString(), out data.x); + else + m_log.WarnFormat(" -- request didn't have destination_x"); + if (args.ContainsKey("destination_y") && args["destination_y"] != null) + Int32.TryParse(args["destination_y"].AsString(), out data.y); + else + m_log.WarnFormat(" -- request didn't have destination_y"); + if (args.ContainsKey("destination_uuid") && args["destination_uuid"] != null) + UUID.TryParse(args["destination_uuid"].AsString(), out data.uuid); + if (args.ContainsKey("destination_name") && args["destination_name"] != null) + data.name = args["destination_name"].ToString(); + if (args.ContainsKey("teleport_flags") && args["teleport_flags"] != null) + data.flags = args["teleport_flags"].AsUInteger(); + } + + protected virtual GridRegion ExtractGatekeeper(AgentDestinationData data) + { + return null; + } + + protected string GetCallerIP(Hashtable request) { if (!m_Proxy) return Util.GetCallerIP(request); @@ -418,7 +432,7 @@ namespace OpenSim.Server.Handlers.Simulation } // subclasses can override this - protected virtual bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, out string reason) + protected virtual bool CreateAgent(GridRegion gatekeeper, GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, bool fromLogin, out string reason) { return m_SimulationService.CreateAgent(destination, aCircuit, teleportFlags, out reason); } @@ -562,7 +576,6 @@ namespace OpenSim.Server.Handlers.Simulation //agent.Dump(); // This is one of the meanings of PUT agent result = UpdateAgent(destination, agent); - } else if ("AgentPosition".Equals(messageType)) { @@ -593,4 +606,14 @@ namespace OpenSim.Server.Handlers.Simulation return m_SimulationService.UpdateAgent(destination, agent); } } + + public class AgentDestinationData + { + public int x; + public int y; + public string name; + public UUID uuid; + public uint flags; + public bool fromLogin; + } } diff --git a/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs index 5bcff4883d..c9c6c31158 100644 --- a/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs @@ -53,7 +53,8 @@ namespace OpenSim.Services.Connectors.Hypergrid private IAssetService m_AssetService; - public GatekeeperServiceConnector() : base() + public GatekeeperServiceConnector() + : base() { } @@ -123,11 +124,13 @@ namespace OpenSim.Services.Connectors.Hypergrid realHandle = Convert.ToUInt64((string)hash["handle"]); //m_log.Debug(">> HERE, realHandle: " + realHandle); } - if (hash["region_image"] != null) { + if (hash["region_image"] != null) + { imageURL = (string)hash["region_image"]; //m_log.Debug(">> HERE, imageURL: " + imageURL); } - if (hash["external_name"] != null) { + if (hash["external_name"] != null) + { externalName = (string)hash["external_name"]; //m_log.Debug(">> HERE, externalName: " + externalName); } @@ -178,7 +181,7 @@ namespace OpenSim.Services.Connectors.Hypergrid //m_log.Debug("Size: " + m.PhysicalDimension.Height + "-" + m.PhysicalDimension.Width); imageData = OpenJPEG.EncodeFromImage(bitmap, true); } - + AssetBase ass = new AssetBase(UUID.Random(), "region " + name, (sbyte)AssetType.Texture, regionID.ToString()); // !!! for now @@ -257,7 +260,8 @@ namespace OpenSim.Services.Connectors.Hypergrid region.RegionName = (string)hash["region_name"]; //m_log.Debug(">> HERE, region_name: " + region.RegionName); } - if (hash["hostname"] != null) { + if (hash["hostname"] != null) + { region.ExternalHostName = (string)hash["hostname"]; //m_log.Debug(">> HERE, hostname: " + region.ExternalHostName); } @@ -275,10 +279,10 @@ namespace OpenSim.Services.Connectors.Hypergrid region.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), p); //m_log.Debug(">> HERE, internal_port: " + region.InternalEndPoint); } - + if (hash["server_uri"] != null) { - region.ServerURI = (string) hash["server_uri"]; + region.ServerURI = (string)hash["server_uri"]; //m_log.Debug(">> HERE, server_uri: " + region.ServerURI); } @@ -295,55 +299,5 @@ namespace OpenSim.Services.Connectors.Hypergrid return null; } - - public bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint flags, out string myipaddress, out string reason) - { - // m_log.DebugFormat("[GATEKEEPER SERVICE CONNECTOR]: CreateAgent start"); - - myipaddress = String.Empty; - reason = String.Empty; - - if (destination == null) - { - m_log.Debug("[GATEKEEPER SERVICE CONNECTOR]: Given destination is null"); - return false; - } - - string uri = destination.ServerURI + AgentPath() + aCircuit.AgentID + "/"; - - try - { - OSDMap args = aCircuit.PackAgentCircuitData(); - - args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); - args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); - args["destination_name"] = OSD.FromString(destination.RegionName); - args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); - args["teleport_flags"] = OSD.FromString(flags.ToString()); - - OSDMap result = WebUtil.PostToService(uri, args, 80000); - if (result["Success"].AsBoolean()) - { - OSDMap unpacked = (OSDMap)result["_Result"]; - - if (unpacked != null) - { - reason = unpacked["reason"].AsString(); - myipaddress = unpacked["your_ip"].AsString(); - return unpacked["success"].AsBoolean(); - } - } - - reason = result["Message"] != null ? result["Message"].AsString() : "error"; - return false; - } - catch (Exception e) - { - m_log.Warn("[REMOTE SIMULATION CONNECTOR]: CreateAgent failed with exception: " + e.ToString()); - reason = e.Message; - } - - return false; - } } } diff --git a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs index 47d0cce7fd..d8a3184780 100644 --- a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs @@ -44,13 +44,14 @@ using Nini.Config; namespace OpenSim.Services.Connectors.Hypergrid { - public class UserAgentServiceConnector : IUserAgentService + public class UserAgentServiceConnector : SimulationServiceConnector, IUserAgentService { private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - string m_ServerURL; + private string m_ServerURL; + private GridRegion m_Gatekeeper; public UserAgentServiceConnector(string url) : this(url, true) { @@ -104,9 +105,15 @@ namespace OpenSim.Services.Connectors.Hypergrid m_log.DebugFormat("[USER AGENT CONNECTOR]: UserAgentServiceConnector started for {0}", m_ServerURL); } + protected override string AgentPath() + { + return "homeagent/"; + } - // The Login service calls this interface with a non-null [client] ipaddress - public bool LoginAgentToGrid(AgentCircuitData aCircuit, GridRegion gatekeeper, GridRegion destination, IPEndPoint ipaddress, out string reason) + // The Login service calls this interface with fromLogin=true + // Sims call it with fromLogin=false + // Either way, this is verified by the handler + public bool LoginAgentToGrid(AgentCircuitData aCircuit, GridRegion gatekeeper, GridRegion destination, bool fromLogin, out string reason) { reason = String.Empty; @@ -117,119 +124,34 @@ namespace OpenSim.Services.Connectors.Hypergrid return false; } - string uri = m_ServerURL + "homeagent/" + aCircuit.AgentID + "/"; + GridRegion home = new GridRegion(); + home.ServerURI = m_ServerURL; + home.RegionID = destination.RegionID; + home.RegionLocX = destination.RegionLocX; + home.RegionLocY = destination.RegionLocY; - Console.WriteLine(" >>> LoginAgentToGrid <<< " + uri); + m_Gatekeeper = gatekeeper; - HttpWebRequest AgentCreateRequest = (HttpWebRequest)WebRequest.Create(uri); - AgentCreateRequest.Method = "POST"; - AgentCreateRequest.ContentType = "application/json"; - AgentCreateRequest.Timeout = 10000; - //AgentCreateRequest.KeepAlive = false; - //AgentCreateRequest.Headers.Add("Authorization", authKey); - - // Fill it in - OSDMap args = PackCreateAgentArguments(aCircuit, gatekeeper, destination, ipaddress); - - string strBuffer = ""; - byte[] buffer = new byte[1]; - try - { - strBuffer = OSDParser.SerializeJsonString(args); - Encoding str = Util.UTF8; - buffer = str.GetBytes(strBuffer); - - } - catch (Exception e) - { - m_log.WarnFormat("[USER AGENT CONNECTOR]: Exception thrown on serialization of ChildCreate: {0}", e.Message); - // ignore. buffer will be empty, caller should check. - } - - Stream os = null; - try - { // send the Post - AgentCreateRequest.ContentLength = buffer.Length; //Count bytes to send - os = AgentCreateRequest.GetRequestStream(); - os.Write(buffer, 0, strBuffer.Length); //Send it - m_log.InfoFormat("[USER AGENT CONNECTOR]: Posted CreateAgent request to remote sim {0}, region {1}, x={2} y={3}", - uri, destination.RegionName, destination.RegionLocX, destination.RegionLocY); - } - //catch (WebException ex) - catch - { - //m_log.InfoFormat("[USER AGENT CONNECTOR]: Bad send on ChildAgentUpdate {0}", ex.Message); - reason = "cannot contact remote region"; - return false; - } - finally - { - if (os != null) - os.Close(); - } - - // Let's wait for the response - //m_log.Info("[USER AGENT CONNECTOR]: Waiting for a reply after DoCreateChildAgentCall"); - - try - { - using (WebResponse webResponse = AgentCreateRequest.GetResponse()) - { - if (webResponse == null) - { - m_log.Info("[USER AGENT CONNECTOR]: Null reply on DoCreateChildAgentCall post"); - } - else - { - using (Stream s = webResponse.GetResponseStream()) - { - using (StreamReader sr = new StreamReader(s)) - { - string response = sr.ReadToEnd().Trim(); - m_log.InfoFormat("[USER AGENT CONNECTOR]: DoCreateChildAgentCall reply was {0} ", response); - - if (!String.IsNullOrEmpty(response)) - { - try - { - // we assume we got an OSDMap back - OSDMap r = Util.GetOSDMap(response); - bool success = r["success"].AsBoolean(); - reason = r["reason"].AsString(); - return success; - } - catch (NullReferenceException e) - { - m_log.InfoFormat("[USER AGENT CONNECTOR]: exception on reply of DoCreateChildAgentCall {0}", e.Message); - - // check for old style response - if (response.ToLower().StartsWith("true")) - return true; - - return false; - } - } - } - } - } - } - } - catch (WebException ex) - { - m_log.InfoFormat("[USER AGENT CONNECTOR]: exception on reply of DoCreateChildAgentCall {0}", ex.Message); - reason = "Destination did not reply"; - return false; - } - - return true; + Console.WriteLine(" >>> LoginAgentToGrid <<< " + home.ServerURI); + uint flags = fromLogin ? (uint)TeleportFlags.ViaLogin : (uint)TeleportFlags.ViaHome; + return CreateAgent(home, aCircuit, flags, out reason); } // The simulators call this interface public bool LoginAgentToGrid(AgentCircuitData aCircuit, GridRegion gatekeeper, GridRegion destination, out string reason) { - return LoginAgentToGrid(aCircuit, gatekeeper, destination, null, out reason); + return LoginAgentToGrid(aCircuit, gatekeeper, destination, false, out reason); + } + + protected override void PackData(OSDMap args, AgentCircuitData aCircuit, GridRegion destination, uint flags) + { + base.PackData(args, aCircuit, destination, flags); + args["gatekeeper_serveruri"] = OSD.FromString(m_Gatekeeper.ServerURI); + args["gatekeeper_host"] = OSD.FromString(m_Gatekeeper.ExternalHostName); + args["gatekeeper_port"] = OSD.FromString(m_Gatekeeper.HttpPort.ToString()); + args["destination_serveruri"] = OSD.FromString(destination.ServerURI); } protected OSDMap PackCreateAgentArguments(AgentCircuitData aCircuit, GridRegion gatekeeper, GridRegion destination, IPEndPoint ipaddress) diff --git a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs index 57f2ffa2d4..f51c809413 100644 --- a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs +++ b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs @@ -79,11 +79,27 @@ namespace OpenSim.Services.Connectors.Simulation return "agent/"; } + protected virtual void PackData(OSDMap args, AgentCircuitData aCircuit, GridRegion destination, uint flags) + { + args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); + args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); + args["destination_name"] = OSD.FromString(destination.RegionName); + args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); + args["teleport_flags"] = OSD.FromString(flags.ToString()); + } + public bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint flags, out string reason) { - // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: CreateAgent start"); - + string tmp = String.Empty; + return CreateAgent(destination, aCircuit, flags, out tmp, out reason); + } + + public bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint flags, out string myipaddress, out string reason) + { + m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: Creating agent at {0}", destination.ServerURI); reason = String.Empty; + myipaddress = String.Empty; + if (destination == null) { m_log.Debug("[REMOTE SIMULATION CONNECTOR]: Given destination is null"); @@ -95,12 +111,7 @@ namespace OpenSim.Services.Connectors.Simulation try { OSDMap args = aCircuit.PackAgentCircuitData(); - - args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); - args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); - args["destination_name"] = OSD.FromString(destination.RegionName); - args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); - args["teleport_flags"] = OSD.FromString(flags.ToString()); + PackData(args, aCircuit, destination, flags); OSDMap result = WebUtil.PostToServiceCompressed(uri, args, 30000); bool success = result["success"].AsBoolean(); @@ -110,6 +121,7 @@ namespace OpenSim.Services.Connectors.Simulation reason = data["reason"].AsString(); success = data["success"].AsBoolean(); + myipaddress = data["your_ip"].AsString(); return success; } @@ -124,6 +136,7 @@ namespace OpenSim.Services.Connectors.Simulation reason = data["reason"].AsString(); success = data["success"].AsBoolean(); + myipaddress = data["your_ip"].AsString(); m_log.WarnFormat( "[REMOTE SIMULATION CONNECTOR]: Remote simulator {0} did not accept compressed transfer, suggest updating it.", destination.RegionName); return success; @@ -228,7 +241,7 @@ namespace OpenSim.Services.Connectors.Simulation /// private bool UpdateAgent(GridRegion destination, IAgentData cAgentData, int timeout) { - // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: UpdateAgent start"); + // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: UpdateAgent in {0}", destination.ServerURI); // Eventually, we want to use a caps url instead of the agentID string uri = destination.ServerURI + AgentPath() + cAgentData.AgentID + "/"; diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs index 737e9c91af..733993fb04 100644 --- a/OpenSim/Services/HypergridService/UserAgentService.cs +++ b/OpenSim/Services/HypergridService/UserAgentService.cs @@ -210,10 +210,10 @@ namespace OpenSim.Services.HypergridService return home; } - public bool LoginAgentToGrid(AgentCircuitData agentCircuit, GridRegion gatekeeper, GridRegion finalDestination, IPEndPoint clientIP, out string reason) + public bool LoginAgentToGrid(AgentCircuitData agentCircuit, GridRegion gatekeeper, GridRegion finalDestination, bool fromLogin, out string reason) { m_log.DebugFormat("[USER AGENT SERVICE]: Request to login user {0} {1} (@{2}) to grid {3}", - agentCircuit.firstname, agentCircuit.lastname, ((clientIP == null) ? "stored IP" : clientIP.Address.ToString()), gatekeeper.ServerURI); + agentCircuit.firstname, agentCircuit.lastname, (fromLogin ? agentCircuit.IPAddress : "stored IP"), gatekeeper.ServerURI); string gridName = gatekeeper.ServerURI; @@ -265,7 +265,7 @@ namespace OpenSim.Services.HypergridService bool success = false; string myExternalIP = string.Empty; - m_log.DebugFormat("[USER AGENT SERVICE]: this grid: {0}, desired grid: {1}", m_GridName, gridName); + m_log.DebugFormat("[USER AGENT SERVICE]: this grid: {0}, desired grid: {1}, desired region: {2}", m_GridName, gridName, region.RegionID); if (m_GridName == gridName) success = m_GatekeeperService.LoginAgent(agentCircuit, finalDestination, out reason); @@ -296,8 +296,8 @@ namespace OpenSim.Services.HypergridService m_log.DebugFormat("[USER AGENT SERVICE]: Gatekeeper sees me as {0}", myExternalIP); // else set the IP addresses associated with this client - if (clientIP != null) - m_TravelingAgents[agentCircuit.SessionID].ClientIPAddress = clientIP.Address.ToString(); + if (fromLogin) + m_TravelingAgents[agentCircuit.SessionID].ClientIPAddress = agentCircuit.IPAddress; m_TravelingAgents[agentCircuit.SessionID].MyIpAddress = myExternalIP; return true; @@ -306,7 +306,7 @@ namespace OpenSim.Services.HypergridService public bool LoginAgentToGrid(AgentCircuitData agentCircuit, GridRegion gatekeeper, GridRegion finalDestination, out string reason) { reason = string.Empty; - return LoginAgentToGrid(agentCircuit, gatekeeper, finalDestination, null, out reason); + return LoginAgentToGrid(agentCircuit, gatekeeper, finalDestination, false, out reason); } private void SetClientIP(UUID sessionID, string ip) diff --git a/OpenSim/Services/Interfaces/IHypergridServices.cs b/OpenSim/Services/Interfaces/IHypergridServices.cs index 3dc877a870..f9e7f083b4 100644 --- a/OpenSim/Services/Interfaces/IHypergridServices.cs +++ b/OpenSim/Services/Interfaces/IHypergridServices.cs @@ -48,10 +48,7 @@ namespace OpenSim.Services.Interfaces /// public interface IUserAgentService { - // called by login service only - bool LoginAgentToGrid(AgentCircuitData agent, GridRegion gatekeeper, GridRegion finalDestination, IPEndPoint clientIP, out string reason); - // called by simulators - bool LoginAgentToGrid(AgentCircuitData agent, GridRegion gatekeeper, GridRegion finalDestination, out string reason); + bool LoginAgentToGrid(AgentCircuitData agent, GridRegion gatekeeper, GridRegion finalDestination, bool fromLogin, out string reason); void LogoutAgent(UUID userID, UUID sessionID); GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt); Dictionary GetServerURLs(UUID userID); diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index 10cf90f7c1..fe43582a89 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs @@ -933,7 +933,7 @@ namespace OpenSim.Services.LLLoginService private bool LaunchAgentIndirectly(GridRegion gatekeeper, GridRegion destination, AgentCircuitData aCircuit, IPEndPoint clientIP, out string reason) { m_log.Debug("[LLOGIN SERVICE] Launching agent at " + destination.RegionName); - if (m_UserAgentService.LoginAgentToGrid(aCircuit, gatekeeper, destination, clientIP, out reason)) + if (m_UserAgentService.LoginAgentToGrid(aCircuit, gatekeeper, destination, true, out reason)) return true; return false; } diff --git a/prebuild.xml b/prebuild.xml index 88db6ede06..4cf3b8358b 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -157,6 +157,7 @@ + @@ -744,6 +745,7 @@ +