OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
Application.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.IO;
30 using System.Net;
31 using System.Reflection;
32 using log4net;
33 using log4net.Config;
34 using Nini.Config;
35 using OpenSim.Framework;
36 using OpenSim.Framework.Console;
37 
38 namespace OpenSim
39 {
43  public class Application
44  {
48  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49 
53  public static string iniFilePath = "";
54 
58  public static bool m_saveCrashDumps = false;
59 
63  public static string m_crashDir = "crashes";
64 
68  protected static OpenSimBase m_sim = null;
69 
70  //could move our main function into OpenSimMain and kill this class
71  public static void Main(string[] args)
72  {
73  // First line, hook the appdomain to the crash reporter
74  AppDomain.CurrentDomain.UnhandledException +=
75  new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
76 
77  ServicePointManager.DefaultConnectionLimit = 12;
78  ServicePointManager.UseNagleAlgorithm = false;
79 
80  // Add the arguments supplied when running the application to the configuration
81  ArgvConfigSource configSource = new ArgvConfigSource(args);
82 
83  // Configure Log4Net
84  configSource.AddSwitch("Startup", "logconfig");
85  string logConfigFile = configSource.Configs["Startup"].GetString("logconfig", String.Empty);
86  if (logConfigFile != String.Empty)
87  {
88  XmlConfigurator.Configure(new System.IO.FileInfo(logConfigFile));
89  m_log.InfoFormat("[OPENSIM MAIN]: configured log4net using \"{0}\" as configuration file",
90  logConfigFile);
91  }
92  else
93  {
94  XmlConfigurator.Configure();
95  m_log.Info("[OPENSIM MAIN]: configured log4net using default OpenSim.exe.config");
96  }
97 
98  m_log.InfoFormat(
99  "[OPENSIM MAIN]: System Locale is {0}", System.Threading.Thread.CurrentThread.CurrentCulture);
100 
101  string monoThreadsPerCpu = System.Environment.GetEnvironmentVariable("MONO_THREADS_PER_CPU");
102 
103  m_log.InfoFormat(
104  "[OPENSIM MAIN]: Environment variable MONO_THREADS_PER_CPU is {0}", monoThreadsPerCpu ?? "unset");
105 
106  // Verify the Threadpool allocates or uses enough worker and IO completion threads
107  // .NET 2.0, workerthreads default to 50 * numcores
108  // .NET 3.0, workerthreads defaults to 250 * numcores
109  // .NET 4.0, workerthreads are dynamic based on bitness and OS resources
110  // Max IO Completion threads are 1000 on all 3 CLRs
111  //
112  // Mono 2.10.9 to at least Mono 3.1, workerthreads default to 100 * numcores, iocp threads to 4 * numcores
113  int workerThreadsMin = 500;
114  int workerThreadsMax = 1000; // may need further adjustment to match other CLR
115  int iocpThreadsMin = 1000;
116  int iocpThreadsMax = 2000; // may need further adjustment to match other CLR
117 
118  {
119  int currentMinWorkerThreads, currentMinIocpThreads;
120  System.Threading.ThreadPool.GetMinThreads(out currentMinWorkerThreads, out currentMinIocpThreads);
121  m_log.InfoFormat(
122  "[OPENSIM MAIN]: Runtime gave us {0} min worker threads and {1} min IOCP threads",
123  currentMinWorkerThreads, currentMinIocpThreads);
124  }
125 
126  int workerThreads, iocpThreads;
127  System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
128  m_log.InfoFormat("[OPENSIM MAIN]: Runtime gave us {0} max worker threads and {1} max IOCP threads", workerThreads, iocpThreads);
129 
130  if (workerThreads < workerThreadsMin)
131  {
132  workerThreads = workerThreadsMin;
133  m_log.InfoFormat("[OPENSIM MAIN]: Bumping up max worker threads to {0}",workerThreads);
134  }
135  if (workerThreads > workerThreadsMax)
136  {
137  workerThreads = workerThreadsMax;
138  m_log.InfoFormat("[OPENSIM MAIN]: Limiting max worker threads to {0}",workerThreads);
139  }
140 
141  // Increase the number of IOCP threads available.
142  // Mono defaults to a tragically low number (24 on 6-core / 8GB Fedora 17)
143  if (iocpThreads < iocpThreadsMin)
144  {
145  iocpThreads = iocpThreadsMin;
146  m_log.InfoFormat("[OPENSIM MAIN]: Bumping up max IOCP threads to {0}",iocpThreads);
147  }
148  // Make sure we don't overallocate IOCP threads and thrash system resources
149  if ( iocpThreads > iocpThreadsMax )
150  {
151  iocpThreads = iocpThreadsMax;
152  m_log.InfoFormat("[OPENSIM MAIN]: Limiting max IOCP completion threads to {0}",iocpThreads);
153  }
154  // set the resulting worker and IO completion thread counts back to ThreadPool
155  if ( System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads) )
156  {
157  m_log.InfoFormat(
158  "[OPENSIM MAIN]: Threadpool set to {0} max worker threads and {1} max IOCP threads",
159  workerThreads, iocpThreads);
160  }
161  else
162  {
163  m_log.Warn("[OPENSIM MAIN]: Threadpool reconfiguration failed, runtime defaults still in effect.");
164  }
165 
166  // Check if the system is compatible with OpenSimulator.
167  // Ensures that the minimum system requirements are met
168  string supported = String.Empty;
169  if (Util.IsEnvironmentSupported(ref supported))
170  {
171  m_log.Info("[OPENSIM MAIN]: Environment is supported by OpenSimulator.");
172  }
173  else
174  {
175  m_log.Warn("[OPENSIM MAIN]: Environment is not supported by OpenSimulator (" + supported + ")\n");
176  }
177 
178  // Configure nIni aliases and localles
179  Culture.SetCurrentCulture();
180 
181  // Validate that the user has the most basic configuration done
182  // If not, offer to do the most basic configuration for them warning them along the way of the importance of
183  // reading these files.
184  /*
185  m_log.Info("Checking for reguired configuration...\n");
186 
187  bool OpenSim_Ini = (File.Exists(Path.Combine(Util.configDir(), "OpenSim.ini")))
188  || (File.Exists(Path.Combine(Util.configDir(), "opensim.ini")))
189  || (File.Exists(Path.Combine(Util.configDir(), "openSim.ini")))
190  || (File.Exists(Path.Combine(Util.configDir(), "Opensim.ini")));
191 
192  bool StanaloneCommon_ProperCased = File.Exists(Path.Combine(Path.Combine(Util.configDir(), "config-include"), "StandaloneCommon.ini"));
193  bool StanaloneCommon_lowercased = File.Exists(Path.Combine(Path.Combine(Util.configDir(), "config-include"), "standalonecommon.ini"));
194  bool GridCommon_ProperCased = File.Exists(Path.Combine(Path.Combine(Util.configDir(), "config-include"), "GridCommon.ini"));
195  bool GridCommon_lowerCased = File.Exists(Path.Combine(Path.Combine(Util.configDir(), "config-include"), "gridcommon.ini"));
196 
197  if ((OpenSim_Ini)
198  && (
199  (StanaloneCommon_ProperCased
200  || StanaloneCommon_lowercased
201  || GridCommon_ProperCased
202  || GridCommon_lowerCased
203  )))
204  {
205  m_log.Info("Required Configuration Files Found\n");
206  }
207  else
208  {
209  MainConsole.Instance = new LocalConsole("Region");
210  string resp = MainConsole.Instance.CmdPrompt(
211  "\n\n*************Required Configuration files not found.*************\n\n OpenSimulator will not run without these files.\n\nRemember, these file names are Case Sensitive in Linux and Proper Cased.\n1. ./OpenSim.ini\nand\n2. ./config-include/StandaloneCommon.ini \nor\n3. ./config-include/GridCommon.ini\n\nAlso, you will want to examine these files in great detail because only the basic system will load by default. OpenSimulator can do a LOT more if you spend a little time going through these files.\n\n" + ": " + "Do you want to copy the most basic Defaults from standalone?",
212  "yes");
213  if (resp == "yes")
214  {
215 
216  if (!(OpenSim_Ini))
217  {
218  try
219  {
220  File.Copy(Path.Combine(Util.configDir(), "OpenSim.ini.example"),
221  Path.Combine(Util.configDir(), "OpenSim.ini"));
222  } catch (UnauthorizedAccessException)
223  {
224  MainConsole.Instance.Output("Unable to Copy OpenSim.ini.example to OpenSim.ini, Make sure OpenSim has have the required permissions\n");
225  } catch (ArgumentException)
226  {
227  MainConsole.Instance.Output("Unable to Copy OpenSim.ini.example to OpenSim.ini, The current directory is invalid.\n");
228  } catch (System.IO.PathTooLongException)
229  {
230  MainConsole.Instance.Output("Unable to Copy OpenSim.ini.example to OpenSim.ini, the Path to these files is too long.\n");
231  } catch (System.IO.DirectoryNotFoundException)
232  {
233  MainConsole.Instance.Output("Unable to Copy OpenSim.ini.example to OpenSim.ini, the current directory is reporting as not found.\n");
234  } catch (System.IO.FileNotFoundException)
235  {
236  MainConsole.Instance.Output("Unable to Copy OpenSim.ini.example to OpenSim.ini, the example is not found, please make sure that the example files exist.\n");
237  } catch (System.IO.IOException)
238  {
239  // Destination file exists already or a hard drive failure... .. so we can just drop this one
240  //MainConsole.Instance.Output("Unable to Copy OpenSim.ini.example to OpenSim.ini, the example is not found, please make sure that the example files exist.\n");
241  } catch (System.NotSupportedException)
242  {
243  MainConsole.Instance.Output("Unable to Copy OpenSim.ini.example to OpenSim.ini, The current directory is invalid.\n");
244  }
245 
246  }
247  if (!(StanaloneCommon_ProperCased || StanaloneCommon_lowercased))
248  {
249  try
250  {
251  File.Copy(Path.Combine(Path.Combine(Util.configDir(), "config-include"), "StandaloneCommon.ini.example"),
252  Path.Combine(Path.Combine(Util.configDir(), "config-include"), "StandaloneCommon.ini"));
253  }
254  catch (UnauthorizedAccessException)
255  {
256  MainConsole.Instance.Output("Unable to Copy StandaloneCommon.ini.example to StandaloneCommon.ini, Make sure OpenSim has the required permissions\n");
257  }
258  catch (ArgumentException)
259  {
260  MainConsole.Instance.Output("Unable to Copy StandaloneCommon.ini.example to StandaloneCommon.ini, The current directory is invalid.\n");
261  }
262  catch (System.IO.PathTooLongException)
263  {
264  MainConsole.Instance.Output("Unable to Copy StandaloneCommon.ini.example to StandaloneCommon.ini, the Path to these files is too long.\n");
265  }
266  catch (System.IO.DirectoryNotFoundException)
267  {
268  MainConsole.Instance.Output("Unable to Copy StandaloneCommon.ini.example to StandaloneCommon.ini, the current directory is reporting as not found.\n");
269  }
270  catch (System.IO.FileNotFoundException)
271  {
272  MainConsole.Instance.Output("Unable to Copy StandaloneCommon.ini.example to StandaloneCommon.ini, the example is not found, please make sure that the example files exist.\n");
273  }
274  catch (System.IO.IOException)
275  {
276  // Destination file exists already or a hard drive failure... .. so we can just drop this one
277  //MainConsole.Instance.Output("Unable to Copy OpenSim.ini.example to OpenSim.ini, the example is not found, please make sure that the example files exist.\n");
278  }
279  catch (System.NotSupportedException)
280  {
281  MainConsole.Instance.Output("Unable to Copy StandaloneCommon.ini.example to StandaloneCommon.ini, The current directory is invalid.\n");
282  }
283  }
284  }
285  MainConsole.Instance = null;
286  }
287  */
288  configSource.Alias.AddAlias("On", true);
289  configSource.Alias.AddAlias("Off", false);
290  configSource.Alias.AddAlias("True", true);
291  configSource.Alias.AddAlias("False", false);
292  configSource.Alias.AddAlias("Yes", true);
293  configSource.Alias.AddAlias("No", false);
294 
295  configSource.AddSwitch("Startup", "background");
296  configSource.AddSwitch("Startup", "inifile");
297  configSource.AddSwitch("Startup", "inimaster");
298  configSource.AddSwitch("Startup", "inidirectory");
299  configSource.AddSwitch("Startup", "physics");
300  configSource.AddSwitch("Startup", "gui");
301  configSource.AddSwitch("Startup", "console");
302  configSource.AddSwitch("Startup", "save_crashes");
303  configSource.AddSwitch("Startup", "crash_dir");
304 
305  configSource.AddConfig("StandAlone");
306  configSource.AddConfig("Network");
307 
308  // Check if we're running in the background or not
309  bool background = configSource.Configs["Startup"].GetBoolean("background", false);
310 
311  // Check if we're saving crashes
312  m_saveCrashDumps = configSource.Configs["Startup"].GetBoolean("save_crashes", false);
313 
314  // load Crash directory config
315  m_crashDir = configSource.Configs["Startup"].GetString("crash_dir", m_crashDir);
316 
317  if (background)
318  {
319  m_sim = new OpenSimBackground(configSource);
320  m_sim.Startup();
321  }
322  else
323  {
324  m_sim = new OpenSim(configSource);
325 
326  m_sim.Startup();
327 
328  while (true)
329  {
330  try
331  {
332  // Block thread here for input
333  MainConsole.Instance.Prompt();
334  }
335  catch (Exception e)
336  {
337  m_log.ErrorFormat("Command error: {0}", e);
338  }
339  }
340  }
341  }
342 
343  private static bool _IsHandlingException = false; // Make sure we don't go recursive on ourself
344 
350  private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
351  {
352  if (_IsHandlingException)
353  {
354  return;
355  }
356 
357  _IsHandlingException = true;
358  // TODO: Add config option to allow users to turn off error reporting
359  // TODO: Post error report (disabled for now)
360 
361  string msg = String.Empty;
362  msg += "\r\n";
363  msg += "APPLICATION EXCEPTION DETECTED: " + e.ToString() + "\r\n";
364  msg += "\r\n";
365 
366  msg += "Exception: " + e.ExceptionObject.ToString() + "\r\n";
367  Exception ex = (Exception) e.ExceptionObject;
368  if (ex.InnerException != null)
369  {
370  msg += "InnerException: " + ex.InnerException.ToString() + "\r\n";
371  }
372 
373  msg += "\r\n";
374  msg += "Application is terminating: " + e.IsTerminating.ToString() + "\r\n";
375 
376  m_log.ErrorFormat("[APPLICATION]: {0}", msg);
377 
378  if (m_saveCrashDumps)
379  {
380  // Log exception to disk
381  try
382  {
383  if (!Directory.Exists(m_crashDir))
384  {
385  Directory.CreateDirectory(m_crashDir);
386  }
387  string log = Util.GetUniqueFilename(ex.GetType() + ".txt");
388  using (StreamWriter m_crashLog = new StreamWriter(Path.Combine(m_crashDir, log)))
389  {
390  m_crashLog.WriteLine(msg);
391  }
392 
393  File.Copy("OpenSim.ini", Path.Combine(m_crashDir, log + "_OpenSim.ini"), true);
394  }
395  catch (Exception e2)
396  {
397  m_log.ErrorFormat("[CRASH LOGGER CRASHED]: {0}", e2);
398  }
399  }
400 
401  _IsHandlingException = false;
402  }
403  }
404 }
static void Main(string[] args)
Definition: Application.cs:71
Starting class for the OpenSimulator Region
Definition: Application.cs:43
static string m_crashDir
Directory to save crash reports to. Relative to bin/
Definition: Application.cs:63
Consoleless OpenSimulator region server
static OpenSimBase m_sim
Instance of the OpenSim class. This could be OpenSim or OpenSimBackground depending on the configurat...
Definition: Application.cs:68
static bool m_saveCrashDumps
Save Crashes in the bin/crashes folder. Configurable with m_crashDir
Definition: Application.cs:58
Interactive OpenSim region server
Definition: OpenSim.cs:55
static string iniFilePath
Path to the main ini Configuration file
Definition: Application.cs:53
Common OpenSimulator simulator code
Definition: OpenSimBase.cs:58