clockwerk-opensim – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | vero | 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 | } |