opensim-development – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 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 {
40 /// <summary>
41 /// Starting class for the OpenSimulator Region
42 /// </summary>
43 public class Application
44 {
45 /// <summary>
46 /// Text Console Logger
47 /// </summary>
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49  
50 /// <summary>
51 /// Path to the main ini Configuration file
52 /// </summary>
53 public static string iniFilePath = "";
54  
55 /// <summary>
56 /// Save Crashes in the bin/crashes folder. Configurable with m_crashDir
57 /// </summary>
58 public static bool m_saveCrashDumps = false;
59  
60 /// <summary>
61 /// Directory to save crash reports to. Relative to bin/
62 /// </summary>
63 public static string m_crashDir = "crashes";
64  
65 /// <summary>
66 /// Instance of the OpenSim class. This could be OpenSim or OpenSimBackground depending on the configuration
67 /// </summary>
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  
79 // Add the arguments supplied when running the application to the configuration
80 ArgvConfigSource configSource = new ArgvConfigSource(args);
81  
82 // Configure Log4Net
83 configSource.AddSwitch("Startup", "logconfig");
84 string logConfigFile = configSource.Configs["Startup"].GetString("logconfig", String.Empty);
85 if (logConfigFile != String.Empty)
86 {
87 XmlConfigurator.Configure(new System.IO.FileInfo(logConfigFile));
88 m_log.InfoFormat("[OPENSIM MAIN]: configured log4net using \"{0}\" as configuration file",
89 logConfigFile);
90 }
91 else
92 {
93 XmlConfigurator.Configure();
94 m_log.Info("[OPENSIM MAIN]: configured log4net using default OpenSim.exe.config");
95 }
96  
97 m_log.InfoFormat(
98 "[OPENSIM MAIN]: System Locale is {0}", System.Threading.Thread.CurrentThread.CurrentCulture);
99  
100 string monoThreadsPerCpu = System.Environment.GetEnvironmentVariable("MONO_THREADS_PER_CPU");
101  
102 m_log.InfoFormat(
103 "[OPENSIM MAIN]: Environment variable MONO_THREADS_PER_CPU is {0}", monoThreadsPerCpu ?? "unset");
104  
105 // Verify the Threadpool allocates or uses enough worker and IO completion threads
106 // .NET 2.0, workerthreads default to 50 * numcores
107 // .NET 3.0, workerthreads defaults to 250 * numcores
108 // .NET 4.0, workerthreads are dynamic based on bitness and OS resources
109 // Max IO Completion threads are 1000 on all 3 CLRs
110 //
111 // Mono 2.10.9 to at least Mono 3.1, workerthreads default to 100 * numcores, iocp threads to 4 * numcores
112 int workerThreadsMin = 500;
113 int workerThreadsMax = 1000; // may need further adjustment to match other CLR
114 int iocpThreadsMin = 1000;
115 int iocpThreadsMax = 2000; // may need further adjustment to match other CLR
116  
117 {
118 int currentMinWorkerThreads, currentMinIocpThreads;
119 System.Threading.ThreadPool.GetMinThreads(out currentMinWorkerThreads, out currentMinIocpThreads);
120 m_log.InfoFormat(
121 "[OPENSIM MAIN]: Runtime gave us {0} min worker threads and {1} min IOCP threads",
122 currentMinWorkerThreads, currentMinIocpThreads);
123 }
124  
125 int workerThreads, iocpThreads;
126 System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
127 m_log.InfoFormat("[OPENSIM MAIN]: Runtime gave us {0} max worker threads and {1} max IOCP threads", workerThreads, iocpThreads);
128  
129 if (workerThreads < workerThreadsMin)
130 {
131 workerThreads = workerThreadsMin;
132 m_log.InfoFormat("[OPENSIM MAIN]: Bumping up to max worker threads to {0}",workerThreads);
133 }
134 if (workerThreads > workerThreadsMax)
135 {
136 workerThreads = workerThreadsMax;
137 m_log.InfoFormat("[OPENSIM MAIN]: Limiting max worker threads to {0}",workerThreads);
138 }
139  
140 // Increase the number of IOCP threads available.
141 // Mono defaults to a tragically low number (24 on 6-core / 8GB Fedora 17)
142 if (iocpThreads < iocpThreadsMin)
143 {
144 iocpThreads = iocpThreadsMin;
145 m_log.InfoFormat("[OPENSIM MAIN]: Bumping up max IOCP threads to {0}",iocpThreads);
146 }
147 // Make sure we don't overallocate IOCP threads and thrash system resources
148 if ( iocpThreads > iocpThreadsMax )
149 {
150 iocpThreads = iocpThreadsMax;
151 m_log.InfoFormat("[OPENSIM MAIN]: Limiting max IOCP completion threads to {0}",iocpThreads);
152 }
153 // set the resulting worker and IO completion thread counts back to ThreadPool
154 if ( System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads) )
155 {
156 m_log.InfoFormat(
157 "[OPENSIM MAIN]: Threadpool set to {0} max worker threads and {1} max IOCP threads",
158 workerThreads, iocpThreads);
159 }
160 else
161 {
162 m_log.Warn("[OPENSIM MAIN]: Threadpool reconfiguration failed, runtime defaults still in effect.");
163 }
164  
165 // Check if the system is compatible with OpenSimulator.
166 // Ensures that the minimum system requirements are met
167 string supported = String.Empty;
168 if (Util.IsEnvironmentSupported(ref supported))
169 {
170 m_log.Info("[OPENSIM MAIN]: Environment is supported by OpenSimulator.");
171 }
172 else
173 {
174 m_log.Warn("[OPENSIM MAIN]: Environment is not supported by OpenSimulator (" + supported + ")\n");
175 }
176  
177 // Configure nIni aliases and localles
178 Culture.SetCurrentCulture();
179  
180 // Validate that the user has the most basic configuration done
181 // If not, offer to do the most basic configuration for them warning them along the way of the importance of
182 // reading these files.
183 /*
184 m_log.Info("Checking for reguired configuration...\n");
185  
186 bool OpenSim_Ini = (File.Exists(Path.Combine(Util.configDir(), "OpenSim.ini")))
187 || (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  
191 bool StanaloneCommon_ProperCased = File.Exists(Path.Combine(Path.Combine(Util.configDir(), "config-include"), "StandaloneCommon.ini"));
192 bool StanaloneCommon_lowercased = File.Exists(Path.Combine(Path.Combine(Util.configDir(), "config-include"), "standalonecommon.ini"));
193 bool GridCommon_ProperCased = File.Exists(Path.Combine(Path.Combine(Util.configDir(), "config-include"), "GridCommon.ini"));
194 bool GridCommon_lowerCased = File.Exists(Path.Combine(Path.Combine(Util.configDir(), "config-include"), "gridcommon.ini"));
195  
196 if ((OpenSim_Ini)
197 && (
198 (StanaloneCommon_ProperCased
199 || StanaloneCommon_lowercased
200 || GridCommon_ProperCased
201 || GridCommon_lowerCased
202 )))
203 {
204 m_log.Info("Required Configuration Files Found\n");
205 }
206 else
207 {
208 MainConsole.Instance = new LocalConsole("Region");
209 string resp = MainConsole.Instance.CmdPrompt(
210 "\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?",
211 "yes");
212 if (resp == "yes")
213 {
214  
215 if (!(OpenSim_Ini))
216 {
217 try
218 {
219 File.Copy(Path.Combine(Util.configDir(), "OpenSim.ini.example"),
220 Path.Combine(Util.configDir(), "OpenSim.ini"));
221 } catch (UnauthorizedAccessException)
222 {
223 MainConsole.Instance.Output("Unable to Copy OpenSim.ini.example to OpenSim.ini, Make sure OpenSim has have the required permissions\n");
224 } catch (ArgumentException)
225 {
226 MainConsole.Instance.Output("Unable to Copy OpenSim.ini.example to OpenSim.ini, The current directory is invalid.\n");
227 } catch (System.IO.PathTooLongException)
228 {
229 MainConsole.Instance.Output("Unable to Copy OpenSim.ini.example to OpenSim.ini, the Path to these files is too long.\n");
230 } catch (System.IO.DirectoryNotFoundException)
231 {
232 MainConsole.Instance.Output("Unable to Copy OpenSim.ini.example to OpenSim.ini, the current directory is reporting as not found.\n");
233 } catch (System.IO.FileNotFoundException)
234 {
235 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");
236 } catch (System.IO.IOException)
237 {
238 // Destination file exists already or a hard drive failure... .. so we can just drop this one
239 //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");
240 } catch (System.NotSupportedException)
241 {
242 MainConsole.Instance.Output("Unable to Copy OpenSim.ini.example to OpenSim.ini, The current directory is invalid.\n");
243 }
244  
245 }
246 if (!(StanaloneCommon_ProperCased || StanaloneCommon_lowercased))
247 {
248 try
249 {
250 File.Copy(Path.Combine(Path.Combine(Util.configDir(), "config-include"), "StandaloneCommon.ini.example"),
251 Path.Combine(Path.Combine(Util.configDir(), "config-include"), "StandaloneCommon.ini"));
252 }
253 catch (UnauthorizedAccessException)
254 {
255 MainConsole.Instance.Output("Unable to Copy StandaloneCommon.ini.example to StandaloneCommon.ini, Make sure OpenSim has the required permissions\n");
256 }
257 catch (ArgumentException)
258 {
259 MainConsole.Instance.Output("Unable to Copy StandaloneCommon.ini.example to StandaloneCommon.ini, The current directory is invalid.\n");
260 }
261 catch (System.IO.PathTooLongException)
262 {
263 MainConsole.Instance.Output("Unable to Copy StandaloneCommon.ini.example to StandaloneCommon.ini, the Path to these files is too long.\n");
264 }
265 catch (System.IO.DirectoryNotFoundException)
266 {
267 MainConsole.Instance.Output("Unable to Copy StandaloneCommon.ini.example to StandaloneCommon.ini, the current directory is reporting as not found.\n");
268 }
269 catch (System.IO.FileNotFoundException)
270 {
271 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");
272 }
273 catch (System.IO.IOException)
274 {
275 // Destination file exists already or a hard drive failure... .. so we can just drop this one
276 //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");
277 }
278 catch (System.NotSupportedException)
279 {
280 MainConsole.Instance.Output("Unable to Copy StandaloneCommon.ini.example to StandaloneCommon.ini, The current directory is invalid.\n");
281 }
282 }
283 }
284 MainConsole.Instance = null;
285 }
286 */
287 configSource.Alias.AddAlias("On", true);
288 configSource.Alias.AddAlias("Off", false);
289 configSource.Alias.AddAlias("True", true);
290 configSource.Alias.AddAlias("False", false);
291 configSource.Alias.AddAlias("Yes", true);
292 configSource.Alias.AddAlias("No", false);
293  
294 configSource.AddSwitch("Startup", "background");
295 configSource.AddSwitch("Startup", "inifile");
296 configSource.AddSwitch("Startup", "inimaster");
297 configSource.AddSwitch("Startup", "inidirectory");
298 configSource.AddSwitch("Startup", "physics");
299 configSource.AddSwitch("Startup", "gui");
300 configSource.AddSwitch("Startup", "console");
301 configSource.AddSwitch("Startup", "save_crashes");
302 configSource.AddSwitch("Startup", "crash_dir");
303  
304 configSource.AddConfig("StandAlone");
305 configSource.AddConfig("Network");
306  
307 // Check if we're running in the background or not
308 bool background = configSource.Configs["Startup"].GetBoolean("background", false);
309  
310 // Check if we're saving crashes
311 m_saveCrashDumps = configSource.Configs["Startup"].GetBoolean("save_crashes", false);
312  
313 // load Crash directory config
314 m_crashDir = configSource.Configs["Startup"].GetString("crash_dir", m_crashDir);
315  
316 if (background)
317 {
318 m_sim = new OpenSimBackground(configSource);
319 m_sim.Startup();
320 }
321 else
322 {
323 m_sim = new OpenSim(configSource);
324  
325 m_sim.Startup();
326  
327 while (true)
328 {
329 try
330 {
331 // Block thread here for input
332 MainConsole.Instance.Prompt();
333 }
334 catch (Exception e)
335 {
336 m_log.ErrorFormat("Command error: {0}", e);
337 }
338 }
339 }
340 }
341  
342 private static bool _IsHandlingException = false; // Make sure we don't go recursive on ourself
343  
344 /// <summary>
345 /// Global exception handler -- all unhandlet exceptions end up here :)
346 /// </summary>
347 /// <param name="sender"></param>
348 /// <param name="e"></param>
349 private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
350 {
351 if (_IsHandlingException)
352 {
353 return;
354 }
355  
356 _IsHandlingException = true;
357 // TODO: Add config option to allow users to turn off error reporting
358 // TODO: Post error report (disabled for now)
359  
360 string msg = String.Empty;
361 msg += "\r\n";
362 msg += "APPLICATION EXCEPTION DETECTED: " + e.ToString() + "\r\n";
363 msg += "\r\n";
364  
365 msg += "Exception: " + e.ExceptionObject.ToString() + "\r\n";
366 Exception ex = (Exception) e.ExceptionObject;
367 if (ex.InnerException != null)
368 {
369 msg += "InnerException: " + ex.InnerException.ToString() + "\r\n";
370 }
371  
372 msg += "\r\n";
373 msg += "Application is terminating: " + e.IsTerminating.ToString() + "\r\n";
374  
375 m_log.ErrorFormat("[APPLICATION]: {0}", msg);
376  
377 if (m_saveCrashDumps)
378 {
379 // Log exception to disk
380 try
381 {
382 if (!Directory.Exists(m_crashDir))
383 {
384 Directory.CreateDirectory(m_crashDir);
385 }
386 string log = Util.GetUniqueFilename(ex.GetType() + ".txt");
387 using (StreamWriter m_crashLog = new StreamWriter(Path.Combine(m_crashDir, log)))
388 {
389 m_crashLog.WriteLine(msg);
390 }
391  
392 File.Copy("OpenSim.ini", Path.Combine(m_crashDir, log + "_OpenSim.ini"), true);
393 }
394 catch (Exception e2)
395 {
396 m_log.ErrorFormat("[CRASH LOGGER CRASHED]: {0}", e2);
397 }
398 }
399  
400 _IsHandlingException = false;
401 }
402 }
403 }