diff options
Diffstat (limited to 'OpenSim/Framework/Servers')
-rw-r--r-- | OpenSim/Framework/Servers/BaseOpenSimServer.cs | 455 | ||||
-rw-r--r-- | OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | 72 | ||||
-rw-r--r-- | OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs | 33 | ||||
-rw-r--r-- | OpenSim/Framework/Servers/Properties/AssemblyInfo.cs | 33 | ||||
-rw-r--r-- | OpenSim/Framework/Servers/ServerBase.cs | 677 | ||||
-rw-r--r-- | OpenSim/Framework/Servers/Tests/OSHttpTests.cs | 3 | ||||
-rw-r--r-- | OpenSim/Framework/Servers/Tests/VersionInfoTests.cs | 3 |
7 files changed, 771 insertions, 505 deletions
diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index aac9c45..c0dc907 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs | |||
@@ -27,7 +27,6 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Diagnostics; | ||
31 | using System.IO; | 30 | using System.IO; |
32 | using System.Reflection; | 31 | using System.Reflection; |
33 | using System.Text; | 32 | using System.Text; |
@@ -38,6 +37,8 @@ using log4net; | |||
38 | using log4net.Appender; | 37 | using log4net.Appender; |
39 | using log4net.Core; | 38 | using log4net.Core; |
40 | using log4net.Repository; | 39 | using log4net.Repository; |
40 | using OpenMetaverse; | ||
41 | using OpenMetaverse.StructuredData; | ||
41 | using OpenSim.Framework; | 42 | using OpenSim.Framework; |
42 | using OpenSim.Framework.Console; | 43 | using OpenSim.Framework.Console; |
43 | using OpenSim.Framework.Monitoring; | 44 | using OpenSim.Framework.Monitoring; |
@@ -45,16 +46,12 @@ using OpenSim.Framework.Servers; | |||
45 | using OpenSim.Framework.Servers.HttpServer; | 46 | using OpenSim.Framework.Servers.HttpServer; |
46 | using Timer=System.Timers.Timer; | 47 | using Timer=System.Timers.Timer; |
47 | 48 | ||
48 | using OpenMetaverse; | ||
49 | using OpenMetaverse.StructuredData; | ||
50 | |||
51 | |||
52 | namespace OpenSim.Framework.Servers | 49 | namespace OpenSim.Framework.Servers |
53 | { | 50 | { |
54 | /// <summary> | 51 | /// <summary> |
55 | /// Common base for the main OpenSimServers (user, grid, inventory, region, etc) | 52 | /// Common base for the main OpenSimServers (user, grid, inventory, region, etc) |
56 | /// </summary> | 53 | /// </summary> |
57 | public abstract class BaseOpenSimServer | 54 | public abstract class BaseOpenSimServer : ServerBase |
58 | { | 55 | { |
59 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 56 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
60 | 57 | ||
@@ -63,27 +60,6 @@ namespace OpenSim.Framework.Servers | |||
63 | /// server. | 60 | /// server. |
64 | /// </summary> | 61 | /// </summary> |
65 | private Timer m_periodicDiagnosticsTimer = new Timer(60 * 60 * 1000); | 62 | private Timer m_periodicDiagnosticsTimer = new Timer(60 * 60 * 1000); |
66 | |||
67 | protected CommandConsole m_console; | ||
68 | protected OpenSimAppender m_consoleAppender; | ||
69 | protected IAppender m_logFileAppender = null; | ||
70 | |||
71 | /// <summary> | ||
72 | /// Time at which this server was started | ||
73 | /// </summary> | ||
74 | protected DateTime m_startuptime; | ||
75 | |||
76 | /// <summary> | ||
77 | /// Record the initial startup directory for info purposes | ||
78 | /// </summary> | ||
79 | protected string m_startupDirectory = Environment.CurrentDirectory; | ||
80 | |||
81 | /// <summary> | ||
82 | /// Server version information. Usually VersionInfo + information about git commit, operating system, etc. | ||
83 | /// </summary> | ||
84 | protected string m_version; | ||
85 | |||
86 | protected string m_pidFile = String.Empty; | ||
87 | 63 | ||
88 | /// <summary> | 64 | /// <summary> |
89 | /// Random uuid for private data | 65 | /// Random uuid for private data |
@@ -96,30 +72,13 @@ namespace OpenSim.Framework.Servers | |||
96 | get { return m_httpServer; } | 72 | get { return m_httpServer; } |
97 | } | 73 | } |
98 | 74 | ||
99 | public BaseOpenSimServer() | 75 | public BaseOpenSimServer() : base() |
100 | { | 76 | { |
101 | m_startuptime = DateTime.Now; | ||
102 | m_version = VersionInfo.Version; | ||
103 | |||
104 | // Random uuid for private data | 77 | // Random uuid for private data |
105 | m_osSecret = UUID.Random().ToString(); | 78 | m_osSecret = UUID.Random().ToString(); |
106 | 79 | ||
107 | m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics); | 80 | m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics); |
108 | m_periodicDiagnosticsTimer.Enabled = true; | 81 | m_periodicDiagnosticsTimer.Enabled = true; |
109 | |||
110 | // This thread will go on to become the console listening thread | ||
111 | Thread.CurrentThread.Name = "ConsoleThread"; | ||
112 | |||
113 | ILoggerRepository repository = LogManager.GetRepository(); | ||
114 | IAppender[] appenders = repository.GetAppenders(); | ||
115 | |||
116 | foreach (IAppender appender in appenders) | ||
117 | { | ||
118 | if (appender.Name == "LogFileAppender") | ||
119 | { | ||
120 | m_logFileAppender = appender; | ||
121 | } | ||
122 | } | ||
123 | } | 82 | } |
124 | 83 | ||
125 | /// <summary> | 84 | /// <summary> |
@@ -127,72 +86,18 @@ namespace OpenSim.Framework.Servers | |||
127 | /// </summary> | 86 | /// </summary> |
128 | protected virtual void StartupSpecific() | 87 | protected virtual void StartupSpecific() |
129 | { | 88 | { |
130 | if (m_console != null) | 89 | if (m_console == null) |
131 | { | 90 | return; |
132 | ILoggerRepository repository = LogManager.GetRepository(); | ||
133 | IAppender[] appenders = repository.GetAppenders(); | ||
134 | |||
135 | foreach (IAppender appender in appenders) | ||
136 | { | ||
137 | if (appender.Name == "Console") | ||
138 | { | ||
139 | m_consoleAppender = (OpenSimAppender)appender; | ||
140 | break; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | if (null == m_consoleAppender) | ||
145 | { | ||
146 | Notice("No appender named Console found (see the log4net config file for this executable)!"); | ||
147 | } | ||
148 | else | ||
149 | { | ||
150 | m_consoleAppender.Console = m_console; | ||
151 | |||
152 | // If there is no threshold set then the threshold is effectively everything. | ||
153 | if (null == m_consoleAppender.Threshold) | ||
154 | m_consoleAppender.Threshold = Level.All; | ||
155 | |||
156 | Notice(String.Format("Console log level is {0}", m_consoleAppender.Threshold)); | ||
157 | } | ||
158 | |||
159 | m_console.Commands.AddCommand("General", false, "quit", | ||
160 | "quit", | ||
161 | "Quit the application", HandleQuit); | ||
162 | |||
163 | m_console.Commands.AddCommand("General", false, "shutdown", | ||
164 | "shutdown", | ||
165 | "Quit the application", HandleQuit); | ||
166 | |||
167 | m_console.Commands.AddCommand("General", false, "set log level", | ||
168 | "set log level <level>", | ||
169 | "Set the console logging level", HandleLogLevel); | ||
170 | |||
171 | m_console.Commands.AddCommand("General", false, "show info", | ||
172 | "show info", | ||
173 | "Show general information about the server", HandleShow); | ||
174 | |||
175 | m_console.Commands.AddCommand("General", false, "show threads", | ||
176 | "show threads", | ||
177 | "Show thread status", HandleShow); | ||
178 | |||
179 | m_console.Commands.AddCommand("General", false, "show uptime", | ||
180 | "show uptime", | ||
181 | "Show server uptime", HandleShow); | ||
182 | |||
183 | m_console.Commands.AddCommand("General", false, "show version", | ||
184 | "show version", | ||
185 | "Show server version", HandleShow); | ||
186 | 91 | ||
187 | m_console.Commands.AddCommand("General", false, "threads abort", | 92 | RegisterCommonCommands(); |
188 | "threads abort <thread-id>", | 93 | |
189 | "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort); | 94 | m_console.Commands.AddCommand("General", false, "quit", |
95 | "quit", | ||
96 | "Quit the application", HandleQuit); | ||
190 | 97 | ||
191 | m_console.Commands.AddCommand("General", false, "threads show", | 98 | m_console.Commands.AddCommand("General", false, "shutdown", |
192 | "threads show", | 99 | "shutdown", |
193 | "Show thread status. Synonym for \"show threads\"", | 100 | "Quit the application", HandleQuit); |
194 | (string module, string[] args) => Notice(GetThreadsReport())); | ||
195 | } | ||
196 | } | 101 | } |
197 | 102 | ||
198 | /// <summary> | 103 | /// <summary> |
@@ -225,74 +130,11 @@ namespace OpenSim.Framework.Servers | |||
225 | } | 130 | } |
226 | 131 | ||
227 | /// <summary> | 132 | /// <summary> |
228 | /// Get a report about the registered threads in this server. | ||
229 | /// </summary> | ||
230 | protected string GetThreadsReport() | ||
231 | { | ||
232 | // This should be a constant field. | ||
233 | string reportFormat = "{0,6} {1,35} {2,16} {3,13} {4,10} {5,30}"; | ||
234 | |||
235 | StringBuilder sb = new StringBuilder(); | ||
236 | Watchdog.ThreadWatchdogInfo[] threads = Watchdog.GetThreadsInfo(); | ||
237 | |||
238 | sb.Append(threads.Length + " threads are being tracked:" + Environment.NewLine); | ||
239 | |||
240 | int timeNow = Environment.TickCount & Int32.MaxValue; | ||
241 | |||
242 | sb.AppendFormat(reportFormat, "ID", "NAME", "LAST UPDATE (MS)", "LIFETIME (MS)", "PRIORITY", "STATE"); | ||
243 | sb.Append(Environment.NewLine); | ||
244 | |||
245 | foreach (Watchdog.ThreadWatchdogInfo twi in threads) | ||
246 | { | ||
247 | Thread t = twi.Thread; | ||
248 | |||
249 | sb.AppendFormat( | ||
250 | reportFormat, | ||
251 | t.ManagedThreadId, | ||
252 | t.Name, | ||
253 | timeNow - twi.LastTick, | ||
254 | timeNow - twi.FirstTick, | ||
255 | t.Priority, | ||
256 | t.ThreadState); | ||
257 | |||
258 | sb.Append("\n"); | ||
259 | } | ||
260 | |||
261 | sb.Append("\n"); | ||
262 | |||
263 | // For some reason mono 2.6.7 returns an empty threads set! Not going to confuse people by reporting | ||
264 | // zero active threads. | ||
265 | int totalThreads = Process.GetCurrentProcess().Threads.Count; | ||
266 | if (totalThreads > 0) | ||
267 | sb.AppendFormat("Total threads active: {0}\n\n", totalThreads); | ||
268 | |||
269 | sb.Append("Main threadpool (excluding script engine pools)\n"); | ||
270 | sb.Append(Util.GetThreadPoolReport()); | ||
271 | |||
272 | return sb.ToString(); | ||
273 | } | ||
274 | |||
275 | /// <summary> | ||
276 | /// Return a report about the uptime of this server | ||
277 | /// </summary> | ||
278 | /// <returns></returns> | ||
279 | protected string GetUptimeReport() | ||
280 | { | ||
281 | StringBuilder sb = new StringBuilder(String.Format("Time now is {0}\n", DateTime.Now)); | ||
282 | sb.Append(String.Format("Server has been running since {0}, {1}\n", m_startuptime.DayOfWeek, m_startuptime)); | ||
283 | sb.Append(String.Format("That is an elapsed time of {0}\n", DateTime.Now - m_startuptime)); | ||
284 | |||
285 | return sb.ToString(); | ||
286 | } | ||
287 | |||
288 | /// <summary> | ||
289 | /// Performs initialisation of the scene, such as loading configuration from disk. | 133 | /// Performs initialisation of the scene, such as loading configuration from disk. |
290 | /// </summary> | 134 | /// </summary> |
291 | public virtual void Startup() | 135 | public virtual void Startup() |
292 | { | 136 | { |
293 | m_log.Info("[STARTUP]: Beginning startup processing"); | 137 | m_log.Info("[STARTUP]: Beginning startup processing"); |
294 | |||
295 | EnhanceVersionInformation(); | ||
296 | 138 | ||
297 | m_log.Info("[STARTUP]: OpenSimulator version: " + m_version + Environment.NewLine); | 139 | m_log.Info("[STARTUP]: OpenSimulator version: " + m_version + Environment.NewLine); |
298 | // clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and | 140 | // clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and |
@@ -327,257 +169,7 @@ namespace OpenSim.Framework.Servers | |||
327 | private void HandleQuit(string module, string[] args) | 169 | private void HandleQuit(string module, string[] args) |
328 | { | 170 | { |
329 | Shutdown(); | 171 | Shutdown(); |
330 | } | 172 | } |
331 | |||
332 | private void HandleLogLevel(string module, string[] cmd) | ||
333 | { | ||
334 | if (null == m_consoleAppender) | ||
335 | { | ||
336 | Notice("No appender named Console found (see the log4net config file for this executable)!"); | ||
337 | return; | ||
338 | } | ||
339 | |||
340 | if (cmd.Length > 3) | ||
341 | { | ||
342 | string rawLevel = cmd[3]; | ||
343 | |||
344 | ILoggerRepository repository = LogManager.GetRepository(); | ||
345 | Level consoleLevel = repository.LevelMap[rawLevel]; | ||
346 | |||
347 | if (consoleLevel != null) | ||
348 | m_consoleAppender.Threshold = consoleLevel; | ||
349 | else | ||
350 | Notice( | ||
351 | String.Format( | ||
352 | "{0} is not a valid logging level. Valid logging levels are ALL, DEBUG, INFO, WARN, ERROR, FATAL, OFF", | ||
353 | rawLevel)); | ||
354 | } | ||
355 | |||
356 | Notice(String.Format("Console log level is {0}", m_consoleAppender.Threshold)); | ||
357 | } | ||
358 | |||
359 | /// <summary> | ||
360 | /// Show help information | ||
361 | /// </summary> | ||
362 | /// <param name="helpArgs"></param> | ||
363 | protected virtual void ShowHelp(string[] helpArgs) | ||
364 | { | ||
365 | Notice(""); | ||
366 | |||
367 | if (helpArgs.Length == 0) | ||
368 | { | ||
369 | Notice("set log level [level] - change the console logging level only. For example, off or debug."); | ||
370 | Notice("show info - show server information (e.g. startup path)."); | ||
371 | Notice("show threads - list tracked threads"); | ||
372 | Notice("show uptime - show server startup time and uptime."); | ||
373 | Notice("show version - show server version."); | ||
374 | Notice(""); | ||
375 | |||
376 | return; | ||
377 | } | ||
378 | } | ||
379 | |||
380 | public virtual void HandleShow(string module, string[] cmd) | ||
381 | { | ||
382 | List<string> args = new List<string>(cmd); | ||
383 | |||
384 | args.RemoveAt(0); | ||
385 | |||
386 | string[] showParams = args.ToArray(); | ||
387 | |||
388 | switch (showParams[0]) | ||
389 | { | ||
390 | case "info": | ||
391 | ShowInfo(); | ||
392 | break; | ||
393 | |||
394 | case "threads": | ||
395 | Notice(GetThreadsReport()); | ||
396 | break; | ||
397 | |||
398 | case "uptime": | ||
399 | Notice(GetUptimeReport()); | ||
400 | break; | ||
401 | |||
402 | case "version": | ||
403 | Notice(GetVersionText()); | ||
404 | break; | ||
405 | } | ||
406 | } | ||
407 | |||
408 | public virtual void HandleThreadsAbort(string module, string[] cmd) | ||
409 | { | ||
410 | if (cmd.Length != 3) | ||
411 | { | ||
412 | MainConsole.Instance.Output("Usage: threads abort <thread-id>"); | ||
413 | return; | ||
414 | } | ||
415 | |||
416 | int threadId; | ||
417 | if (!int.TryParse(cmd[2], out threadId)) | ||
418 | { | ||
419 | MainConsole.Instance.Output("ERROR: Thread id must be an integer"); | ||
420 | return; | ||
421 | } | ||
422 | |||
423 | if (Watchdog.AbortThread(threadId)) | ||
424 | MainConsole.Instance.OutputFormat("Aborted thread with id {0}", threadId); | ||
425 | else | ||
426 | MainConsole.Instance.OutputFormat("ERROR - Thread with id {0} not found in managed threads", threadId); | ||
427 | } | ||
428 | |||
429 | protected void ShowInfo() | ||
430 | { | ||
431 | Notice(GetVersionText()); | ||
432 | Notice("Startup directory: " + m_startupDirectory); | ||
433 | if (null != m_consoleAppender) | ||
434 | Notice(String.Format("Console log level: {0}", m_consoleAppender.Threshold)); | ||
435 | } | ||
436 | |||
437 | protected string GetVersionText() | ||
438 | { | ||
439 | return String.Format("Version: {0} (interface version {1})", m_version, VersionInfo.MajorInterfaceVersion); | ||
440 | } | ||
441 | |||
442 | /// <summary> | ||
443 | /// Console output is only possible if a console has been established. | ||
444 | /// That is something that cannot be determined within this class. So | ||
445 | /// all attempts to use the console MUST be verified. | ||
446 | /// </summary> | ||
447 | /// <param name="msg"></param> | ||
448 | protected void Notice(string msg) | ||
449 | { | ||
450 | if (m_console != null) | ||
451 | { | ||
452 | m_console.Output(msg); | ||
453 | } | ||
454 | } | ||
455 | |||
456 | /// <summary> | ||
457 | /// Console output is only possible if a console has been established. | ||
458 | /// That is something that cannot be determined within this class. So | ||
459 | /// all attempts to use the console MUST be verified. | ||
460 | /// </summary> | ||
461 | /// <param name="format"></param> | ||
462 | /// <param name="components"></param> | ||
463 | protected void Notice(string format, params string[] components) | ||
464 | { | ||
465 | if (m_console != null) | ||
466 | m_console.OutputFormat(format, components); | ||
467 | } | ||
468 | |||
469 | /// <summary> | ||
470 | /// Enhance the version string with extra information if it's available. | ||
471 | /// </summary> | ||
472 | protected void EnhanceVersionInformation() | ||
473 | { | ||
474 | string buildVersion = string.Empty; | ||
475 | |||
476 | // The subversion information is deprecated and will be removed at a later date | ||
477 | // Add subversion revision information if available | ||
478 | // Try file "svn_revision" in the current directory first, then the .svn info. | ||
479 | // This allows to make the revision available in simulators not running from the source tree. | ||
480 | // FIXME: Making an assumption about the directory we're currently in - we do this all over the place | ||
481 | // elsewhere as well | ||
482 | string gitDir = "../.git/"; | ||
483 | string gitRefPointerPath = gitDir + "HEAD"; | ||
484 | |||
485 | string svnRevisionFileName = "svn_revision"; | ||
486 | string svnFileName = ".svn/entries"; | ||
487 | string manualVersionFileName = ".version"; | ||
488 | string inputLine; | ||
489 | int strcmp; | ||
490 | |||
491 | if (File.Exists(manualVersionFileName)) | ||
492 | { | ||
493 | using (StreamReader CommitFile = File.OpenText(manualVersionFileName)) | ||
494 | buildVersion = CommitFile.ReadLine(); | ||
495 | |||
496 | m_version += buildVersion ?? ""; | ||
497 | } | ||
498 | else if (File.Exists(gitRefPointerPath)) | ||
499 | { | ||
500 | // m_log.DebugFormat("[OPENSIM]: Found {0}", gitRefPointerPath); | ||
501 | |||
502 | string rawPointer = ""; | ||
503 | |||
504 | using (StreamReader pointerFile = File.OpenText(gitRefPointerPath)) | ||
505 | rawPointer = pointerFile.ReadLine(); | ||
506 | |||
507 | // m_log.DebugFormat("[OPENSIM]: rawPointer [{0}]", rawPointer); | ||
508 | |||
509 | Match m = Regex.Match(rawPointer, "^ref: (.+)$"); | ||
510 | |||
511 | if (m.Success) | ||
512 | { | ||
513 | // m_log.DebugFormat("[OPENSIM]: Matched [{0}]", m.Groups[1].Value); | ||
514 | |||
515 | string gitRef = m.Groups[1].Value; | ||
516 | string gitRefPath = gitDir + gitRef; | ||
517 | if (File.Exists(gitRefPath)) | ||
518 | { | ||
519 | // m_log.DebugFormat("[OPENSIM]: Found gitRefPath [{0}]", gitRefPath); | ||
520 | |||
521 | using (StreamReader refFile = File.OpenText(gitRefPath)) | ||
522 | { | ||
523 | string gitHash = refFile.ReadLine(); | ||
524 | m_version += gitHash.Substring(0, 7); | ||
525 | } | ||
526 | } | ||
527 | } | ||
528 | } | ||
529 | else | ||
530 | { | ||
531 | // Remove the else logic when subversion mirror is no longer used | ||
532 | if (File.Exists(svnRevisionFileName)) | ||
533 | { | ||
534 | StreamReader RevisionFile = File.OpenText(svnRevisionFileName); | ||
535 | buildVersion = RevisionFile.ReadLine(); | ||
536 | buildVersion.Trim(); | ||
537 | RevisionFile.Close(); | ||
538 | } | ||
539 | |||
540 | if (string.IsNullOrEmpty(buildVersion) && File.Exists(svnFileName)) | ||
541 | { | ||
542 | StreamReader EntriesFile = File.OpenText(svnFileName); | ||
543 | inputLine = EntriesFile.ReadLine(); | ||
544 | while (inputLine != null) | ||
545 | { | ||
546 | // using the dir svn revision at the top of entries file | ||
547 | strcmp = String.Compare(inputLine, "dir"); | ||
548 | if (strcmp == 0) | ||
549 | { | ||
550 | buildVersion = EntriesFile.ReadLine(); | ||
551 | break; | ||
552 | } | ||
553 | else | ||
554 | { | ||
555 | inputLine = EntriesFile.ReadLine(); | ||
556 | } | ||
557 | } | ||
558 | EntriesFile.Close(); | ||
559 | } | ||
560 | |||
561 | m_version += string.IsNullOrEmpty(buildVersion) ? " " : ("." + buildVersion + " ").Substring(0, 6); | ||
562 | } | ||
563 | } | ||
564 | |||
565 | protected void CreatePIDFile(string path) | ||
566 | { | ||
567 | try | ||
568 | { | ||
569 | string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); | ||
570 | FileStream fs = File.Create(path); | ||
571 | |||
572 | Byte[] buf = Encoding.ASCII.GetBytes(pidstring); | ||
573 | fs.Write(buf, 0, buf.Length); | ||
574 | fs.Close(); | ||
575 | m_pidFile = path; | ||
576 | } | ||
577 | catch (Exception) | ||
578 | { | ||
579 | } | ||
580 | } | ||
581 | 173 | ||
582 | public string osSecret { | 174 | public string osSecret { |
583 | // Secret uuid for the simulator | 175 | // Secret uuid for the simulator |
@@ -596,20 +188,5 @@ namespace OpenSim.Framework.Servers | |||
596 | return StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version); | 188 | return StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version); |
597 | } | 189 | } |
598 | } | 190 | } |
599 | |||
600 | protected void RemovePIDFile() | ||
601 | { | ||
602 | if (m_pidFile != String.Empty) | ||
603 | { | ||
604 | try | ||
605 | { | ||
606 | File.Delete(m_pidFile); | ||
607 | m_pidFile = String.Empty; | ||
608 | } | ||
609 | catch (Exception) | ||
610 | { | ||
611 | } | ||
612 | } | ||
613 | } | ||
614 | } | 191 | } |
615 | } | 192 | } \ No newline at end of file |
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index b018e57..2cd626f 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | |||
@@ -542,11 +542,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
542 | { | 542 | { |
543 | case null: | 543 | case null: |
544 | case "text/html": | 544 | case "text/html": |
545 | |||
546 | if (DebugLevel >= 3) | 545 | if (DebugLevel >= 3) |
547 | m_log.DebugFormat( | 546 | LogIncomingToContentTypeHandler(request); |
548 | "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}", | ||
549 | RequestNumber, Port, request.ContentType, request.HttpMethod, request.Url.PathAndQuery, request.RemoteIPEndPoint); | ||
550 | 547 | ||
551 | buffer = HandleHTTPRequest(request, response); | 548 | buffer = HandleHTTPRequest(request, response); |
552 | break; | 549 | break; |
@@ -554,11 +551,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
554 | case "application/llsd+xml": | 551 | case "application/llsd+xml": |
555 | case "application/xml+llsd": | 552 | case "application/xml+llsd": |
556 | case "application/llsd+json": | 553 | case "application/llsd+json": |
557 | |||
558 | if (DebugLevel >= 3) | 554 | if (DebugLevel >= 3) |
559 | m_log.DebugFormat( | 555 | LogIncomingToContentTypeHandler(request); |
560 | "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}", | ||
561 | RequestNumber, Port, request.ContentType, request.HttpMethod, request.Url.PathAndQuery, request.RemoteIPEndPoint); | ||
562 | 556 | ||
563 | buffer = HandleLLSDRequests(request, response); | 557 | buffer = HandleLLSDRequests(request, response); |
564 | break; | 558 | break; |
@@ -693,7 +687,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
693 | "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}", | 687 | "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}", |
694 | RequestNumber, | 688 | RequestNumber, |
695 | Port, | 689 | Port, |
696 | request.ContentType, | 690 | (request.ContentType == null || request.ContentType == "") ? "not set" : request.ContentType, |
697 | request.HttpMethod, | 691 | request.HttpMethod, |
698 | request.Url.PathAndQuery, | 692 | request.Url.PathAndQuery, |
699 | request.RemoteIPEndPoint); | 693 | request.RemoteIPEndPoint); |
@@ -725,8 +719,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
725 | if (DebugLevel == 5) | 719 | if (DebugLevel == 5) |
726 | { | 720 | { |
727 | const int sampleLength = 80; | 721 | const int sampleLength = 80; |
728 | char[] sampleChars = new char[sampleLength]; | 722 | char[] sampleChars = new char[sampleLength + 3]; |
729 | reader.Read(sampleChars, 0, sampleLength); | 723 | reader.Read(sampleChars, 0, sampleLength); |
724 | sampleChars[80] = '.'; | ||
725 | sampleChars[81] = '.'; | ||
726 | sampleChars[82] = '.'; | ||
730 | output = new string(sampleChars); | 727 | output = new string(sampleChars); |
731 | } | 728 | } |
732 | else | 729 | else |
@@ -734,7 +731,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
734 | output = reader.ReadToEnd(); | 731 | output = reader.ReadToEnd(); |
735 | } | 732 | } |
736 | 733 | ||
737 | m_log.DebugFormat("[BASE HTTP SERVER]: {0}...", output.Replace("\n", @"\n")); | 734 | m_log.DebugFormat("[BASE HTTP SERVER]: {0}", output.Replace("\n", @"\n")); |
738 | } | 735 | } |
739 | } | 736 | } |
740 | 737 | ||
@@ -1285,59 +1282,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1285 | map["login"] = OSD.FromString("false"); | 1282 | map["login"] = OSD.FromString("false"); |
1286 | return map; | 1283 | return map; |
1287 | } | 1284 | } |
1288 | /// <summary> | ||
1289 | /// A specific agent handler was provided. Such a handler is expecetd to have an | ||
1290 | /// intimate, and highly specific relationship with the client. Consequently, | ||
1291 | /// nothing is done here. | ||
1292 | /// </summary> | ||
1293 | /// <param name="handler"></param> | ||
1294 | /// <param name="request"></param> | ||
1295 | /// <param name="response"></param> | ||
1296 | |||
1297 | private bool HandleAgentRequest(IHttpAgentHandler handler, OSHttpRequest request, OSHttpResponse response) | ||
1298 | { | ||
1299 | // In the case of REST, then handler is responsible for ALL aspects of | ||
1300 | // the request/response handling. Nothing is done here, not even encoding. | ||
1301 | |||
1302 | try | ||
1303 | { | ||
1304 | return handler.Handle(request, response); | ||
1305 | } | ||
1306 | catch (Exception e) | ||
1307 | { | ||
1308 | // If the handler did in fact close the stream, then this will blow | ||
1309 | // chunks. So that that doesn't disturb anybody we throw away any | ||
1310 | // and all exceptions raised. We've done our best to release the | ||
1311 | // client. | ||
1312 | try | ||
1313 | { | ||
1314 | m_log.Warn("[HTTP-AGENT]: Error - " + e.Message); | ||
1315 | response.SendChunked = false; | ||
1316 | response.KeepAlive = true; | ||
1317 | response.StatusCode = (int)OSHttpStatusCode.ServerErrorInternalError; | ||
1318 | //response.OutputStream.Close(); | ||
1319 | try | ||
1320 | { | ||
1321 | response.Send(); | ||
1322 | //response.FreeContext(); | ||
1323 | } | ||
1324 | catch (SocketException f) | ||
1325 | { | ||
1326 | // This has to be here to prevent a Linux/Mono crash | ||
1327 | m_log.Warn( | ||
1328 | String.Format("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux. ", f.Message), f); | ||
1329 | } | ||
1330 | } | ||
1331 | catch(Exception) | ||
1332 | { | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1336 | // Indicate that the request has been "handled" | ||
1337 | |||
1338 | return true; | ||
1339 | |||
1340 | } | ||
1341 | 1285 | ||
1342 | public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response) | 1286 | public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response) |
1343 | { | 1287 | { |
diff --git a/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs b/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..02ecc25 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs | |||
@@ -0,0 +1,33 @@ | |||
1 | using System.Reflection; | ||
2 | using System.Runtime.CompilerServices; | ||
3 | using System.Runtime.InteropServices; | ||
4 | |||
5 | // General Information about an assembly is controlled through the following | ||
6 | // set of attributes. Change these attribute values to modify the information | ||
7 | // associated with an assembly. | ||
8 | [assembly: AssemblyTitle("OpenSim.Framework.Servers.HttpServer")] | ||
9 | [assembly: AssemblyDescription("")] | ||
10 | [assembly: AssemblyConfiguration("")] | ||
11 | [assembly: AssemblyCompany("http://opensimulator.org")] | ||
12 | [assembly: AssemblyProduct("OpenSim")] | ||
13 | [assembly: AssemblyCopyright("OpenSimulator developers")] | ||
14 | [assembly: AssemblyTrademark("")] | ||
15 | [assembly: AssemblyCulture("")] | ||
16 | |||
17 | // Setting ComVisible to false makes the types in this assembly not visible | ||
18 | // to COM components. If you need to access a type in this assembly from | ||
19 | // COM, set the ComVisible attribute to true on that type. | ||
20 | [assembly: ComVisible(false)] | ||
21 | |||
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM | ||
23 | [assembly: Guid("c4ea5baa-81c4-4867-a645-1ec360c1f164")] | ||
24 | |||
25 | // Version information for an assembly consists of the following four values: | ||
26 | // | ||
27 | // Major Version | ||
28 | // Minor Version | ||
29 | // Build Number | ||
30 | // Revision | ||
31 | // | ||
32 | [assembly: AssemblyVersion("0.7.5.*")] | ||
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | ||
diff --git a/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs b/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..021f63c --- /dev/null +++ b/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs | |||
@@ -0,0 +1,33 @@ | |||
1 | using System.Reflection; | ||
2 | using System.Runtime.CompilerServices; | ||
3 | using System.Runtime.InteropServices; | ||
4 | |||
5 | // General Information about an assembly is controlled through the following | ||
6 | // set of attributes. Change these attribute values to modify the information | ||
7 | // associated with an assembly. | ||
8 | [assembly: AssemblyTitle("OpenSim.Framework.Servers")] | ||
9 | [assembly: AssemblyDescription("")] | ||
10 | [assembly: AssemblyConfiguration("")] | ||
11 | [assembly: AssemblyCompany("http://opensimulator.org")] | ||
12 | [assembly: AssemblyProduct("OpenSim")] | ||
13 | [assembly: AssemblyCopyright("OpenSimulator developers")] | ||
14 | [assembly: AssemblyTrademark("")] | ||
15 | [assembly: AssemblyCulture("")] | ||
16 | |||
17 | // Setting ComVisible to false makes the types in this assembly not visible | ||
18 | // to COM components. If you need to access a type in this assembly from | ||
19 | // COM, set the ComVisible attribute to true on that type. | ||
20 | [assembly: ComVisible(false)] | ||
21 | |||
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM | ||
23 | [assembly: Guid("b48e8b3e-5c5c-4673-b31f-21e13b8e568b")] | ||
24 | |||
25 | // Version information for an assembly consists of the following four values: | ||
26 | // | ||
27 | // Major Version | ||
28 | // Minor Version | ||
29 | // Build Number | ||
30 | // Revision | ||
31 | // | ||
32 | [assembly: AssemblyVersion("0.7.5.*")] | ||
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | ||
diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs new file mode 100644 index 0000000..47baac8 --- /dev/null +++ b/OpenSim/Framework/Servers/ServerBase.cs | |||
@@ -0,0 +1,677 @@ | |||
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.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | using System.IO; | ||
32 | using System.Reflection; | ||
33 | using System.Text; | ||
34 | using System.Text.RegularExpressions; | ||
35 | using System.Threading; | ||
36 | using log4net; | ||
37 | using log4net.Appender; | ||
38 | using log4net.Core; | ||
39 | using log4net.Repository; | ||
40 | using Nini.Config; | ||
41 | using OpenSim.Framework.Console; | ||
42 | using OpenSim.Framework.Monitoring; | ||
43 | |||
44 | namespace OpenSim.Framework.Servers | ||
45 | { | ||
46 | public class ServerBase | ||
47 | { | ||
48 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
49 | |||
50 | public IConfigSource Config { get; protected set; } | ||
51 | |||
52 | /// <summary> | ||
53 | /// Console to be used for any command line output. Can be null, in which case there should be no output. | ||
54 | /// </summary> | ||
55 | protected ICommandConsole m_console; | ||
56 | |||
57 | protected OpenSimAppender m_consoleAppender; | ||
58 | protected FileAppender m_logFileAppender; | ||
59 | |||
60 | protected DateTime m_startuptime; | ||
61 | protected string m_startupDirectory = Environment.CurrentDirectory; | ||
62 | |||
63 | protected string m_pidFile = String.Empty; | ||
64 | |||
65 | /// <summary> | ||
66 | /// Server version information. Usually VersionInfo + information about git commit, operating system, etc. | ||
67 | /// </summary> | ||
68 | protected string m_version; | ||
69 | |||
70 | public ServerBase() | ||
71 | { | ||
72 | m_startuptime = DateTime.Now; | ||
73 | m_version = VersionInfo.Version; | ||
74 | EnhanceVersionInformation(); | ||
75 | } | ||
76 | |||
77 | protected void CreatePIDFile(string path) | ||
78 | { | ||
79 | try | ||
80 | { | ||
81 | string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); | ||
82 | |||
83 | using (FileStream fs = File.Create(path)) | ||
84 | { | ||
85 | Byte[] buf = Encoding.ASCII.GetBytes(pidstring); | ||
86 | fs.Write(buf, 0, buf.Length); | ||
87 | } | ||
88 | |||
89 | m_pidFile = path; | ||
90 | |||
91 | m_log.InfoFormat("[SERVER BASE]: Created pid file {0}", m_pidFile); | ||
92 | } | ||
93 | catch (Exception e) | ||
94 | { | ||
95 | m_log.Warn(string.Format("[SERVER BASE]: Could not create PID file at {0} ", path), e); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | protected void RemovePIDFile() | ||
100 | { | ||
101 | if (m_pidFile != String.Empty) | ||
102 | { | ||
103 | try | ||
104 | { | ||
105 | File.Delete(m_pidFile); | ||
106 | } | ||
107 | catch (Exception e) | ||
108 | { | ||
109 | m_log.Error(string.Format("[SERVER BASE]: Error whilst removing {0} ", m_pidFile), e); | ||
110 | } | ||
111 | |||
112 | m_pidFile = String.Empty; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | public void RegisterCommonAppenders(IConfig startupConfig) | ||
117 | { | ||
118 | ILoggerRepository repository = LogManager.GetRepository(); | ||
119 | IAppender[] appenders = repository.GetAppenders(); | ||
120 | |||
121 | foreach (IAppender appender in appenders) | ||
122 | { | ||
123 | if (appender.Name == "Console") | ||
124 | { | ||
125 | m_consoleAppender = (OpenSimAppender)appender; | ||
126 | } | ||
127 | else if (appender.Name == "LogFileAppender") | ||
128 | { | ||
129 | m_logFileAppender = (FileAppender)appender; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | if (null == m_consoleAppender) | ||
134 | { | ||
135 | Notice("No appender named Console found (see the log4net config file for this executable)!"); | ||
136 | } | ||
137 | else | ||
138 | { | ||
139 | // FIXME: This should be done through an interface rather than casting. | ||
140 | m_consoleAppender.Console = (ConsoleBase)m_console; | ||
141 | |||
142 | // If there is no threshold set then the threshold is effectively everything. | ||
143 | if (null == m_consoleAppender.Threshold) | ||
144 | m_consoleAppender.Threshold = Level.All; | ||
145 | |||
146 | Notice(String.Format("Console log level is {0}", m_consoleAppender.Threshold)); | ||
147 | } | ||
148 | |||
149 | if (m_logFileAppender != null && startupConfig != null) | ||
150 | { | ||
151 | string cfgFileName = startupConfig.GetString("LogFile", null); | ||
152 | if (cfgFileName != null) | ||
153 | { | ||
154 | m_logFileAppender.File = cfgFileName; | ||
155 | m_logFileAppender.ActivateOptions(); | ||
156 | } | ||
157 | |||
158 | m_log.InfoFormat("[SERVER BASE]: Logging started to file {0}", m_logFileAppender.File); | ||
159 | } | ||
160 | } | ||
161 | |||
162 | /// <summary> | ||
163 | /// Register common commands once m_console has been set if it is going to be set | ||
164 | /// </summary> | ||
165 | public void RegisterCommonCommands() | ||
166 | { | ||
167 | if (m_console == null) | ||
168 | return; | ||
169 | |||
170 | m_console.Commands.AddCommand( | ||
171 | "General", false, "show info", "show info", "Show general information about the server", HandleShow); | ||
172 | |||
173 | m_console.Commands.AddCommand( | ||
174 | "General", false, "show version", "show version", "Show server version", HandleShow); | ||
175 | |||
176 | m_console.Commands.AddCommand( | ||
177 | "General", false, "show uptime", "show uptime", "Show server uptime", HandleShow); | ||
178 | |||
179 | m_console.Commands.AddCommand( | ||
180 | "General", false, "get log level", "get log level", "Get the current console logging level", | ||
181 | (mod, cmd) => ShowLogLevel()); | ||
182 | |||
183 | m_console.Commands.AddCommand( | ||
184 | "General", false, "set log level", "set log level <level>", | ||
185 | "Set the console logging level for this session.", HandleSetLogLevel); | ||
186 | |||
187 | m_console.Commands.AddCommand( | ||
188 | "General", false, "config set", | ||
189 | "config set <section> <key> <value>", | ||
190 | "Set a config option. In most cases this is not useful since changed parameters are not dynamically reloaded. Neither do changed parameters persist - you will have to change a config file manually and restart.", HandleConfig); | ||
191 | |||
192 | m_console.Commands.AddCommand( | ||
193 | "General", false, "config get", | ||
194 | "config get [<section>] [<key>]", | ||
195 | "Synonym for config show", | ||
196 | HandleConfig); | ||
197 | |||
198 | m_console.Commands.AddCommand( | ||
199 | "General", false, "config show", | ||
200 | "config show [<section>] [<key>]", | ||
201 | "Show config information", | ||
202 | "If neither section nor field are specified, then the whole current configuration is printed." + Environment.NewLine | ||
203 | + "If a section is given but not a field, then all fields in that section are printed.", | ||
204 | HandleConfig); | ||
205 | |||
206 | m_console.Commands.AddCommand( | ||
207 | "General", false, "config save", | ||
208 | "config save <path>", | ||
209 | "Save current configuration to a file at the given path", HandleConfig); | ||
210 | |||
211 | m_console.Commands.AddCommand( | ||
212 | "General", false, "command-script", | ||
213 | "command-script <script>", | ||
214 | "Run a command script from file", HandleScript); | ||
215 | |||
216 | m_console.Commands.AddCommand( | ||
217 | "General", false, "show threads", | ||
218 | "show threads", | ||
219 | "Show thread status", HandleShow); | ||
220 | |||
221 | m_console.Commands.AddCommand( | ||
222 | "General", false, "threads abort", | ||
223 | "threads abort <thread-id>", | ||
224 | "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort); | ||
225 | |||
226 | m_console.Commands.AddCommand( | ||
227 | "General", false, "threads show", | ||
228 | "threads show", | ||
229 | "Show thread status. Synonym for \"show threads\"", | ||
230 | (string module, string[] args) => Notice(GetThreadsReport())); | ||
231 | |||
232 | m_console.Commands.AddCommand( | ||
233 | "General", false, "force gc", | ||
234 | "force gc", | ||
235 | "Manually invoke runtime garbage collection. For debugging purposes", | ||
236 | HandleForceGc); | ||
237 | } | ||
238 | |||
239 | private void HandleForceGc(string module, string[] args) | ||
240 | { | ||
241 | Notice("Manually invoking runtime garbage collection"); | ||
242 | GC.Collect(); | ||
243 | } | ||
244 | |||
245 | public virtual void HandleShow(string module, string[] cmd) | ||
246 | { | ||
247 | List<string> args = new List<string>(cmd); | ||
248 | |||
249 | args.RemoveAt(0); | ||
250 | |||
251 | string[] showParams = args.ToArray(); | ||
252 | |||
253 | switch (showParams[0]) | ||
254 | { | ||
255 | case "info": | ||
256 | ShowInfo(); | ||
257 | break; | ||
258 | |||
259 | case "version": | ||
260 | Notice(GetVersionText()); | ||
261 | break; | ||
262 | |||
263 | case "uptime": | ||
264 | Notice(GetUptimeReport()); | ||
265 | break; | ||
266 | |||
267 | case "threads": | ||
268 | Notice(GetThreadsReport()); | ||
269 | break; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | /// <summary> | ||
274 | /// Change and load configuration file data. | ||
275 | /// </summary> | ||
276 | /// <param name="module"></param> | ||
277 | /// <param name="cmd"></param> | ||
278 | private void HandleConfig(string module, string[] cmd) | ||
279 | { | ||
280 | List<string> args = new List<string>(cmd); | ||
281 | args.RemoveAt(0); | ||
282 | string[] cmdparams = args.ToArray(); | ||
283 | |||
284 | if (cmdparams.Length > 0) | ||
285 | { | ||
286 | string firstParam = cmdparams[0].ToLower(); | ||
287 | |||
288 | switch (firstParam) | ||
289 | { | ||
290 | case "set": | ||
291 | if (cmdparams.Length < 4) | ||
292 | { | ||
293 | Notice("Syntax: config set <section> <key> <value>"); | ||
294 | Notice("Example: config set ScriptEngine.DotNetEngine NumberOfScriptThreads 5"); | ||
295 | } | ||
296 | else | ||
297 | { | ||
298 | IConfig c; | ||
299 | IConfigSource source = new IniConfigSource(); | ||
300 | c = source.AddConfig(cmdparams[1]); | ||
301 | if (c != null) | ||
302 | { | ||
303 | string _value = String.Join(" ", cmdparams, 3, cmdparams.Length - 3); | ||
304 | c.Set(cmdparams[2], _value); | ||
305 | Config.Merge(source); | ||
306 | |||
307 | Notice("In section [{0}], set {1} = {2}", c.Name, cmdparams[2], _value); | ||
308 | } | ||
309 | } | ||
310 | break; | ||
311 | |||
312 | case "get": | ||
313 | case "show": | ||
314 | if (cmdparams.Length == 1) | ||
315 | { | ||
316 | foreach (IConfig config in Config.Configs) | ||
317 | { | ||
318 | Notice("[{0}]", config.Name); | ||
319 | string[] keys = config.GetKeys(); | ||
320 | foreach (string key in keys) | ||
321 | Notice(" {0} = {1}", key, config.GetString(key)); | ||
322 | } | ||
323 | } | ||
324 | else if (cmdparams.Length == 2 || cmdparams.Length == 3) | ||
325 | { | ||
326 | IConfig config = Config.Configs[cmdparams[1]]; | ||
327 | if (config == null) | ||
328 | { | ||
329 | Notice("Section \"{0}\" does not exist.",cmdparams[1]); | ||
330 | break; | ||
331 | } | ||
332 | else | ||
333 | { | ||
334 | if (cmdparams.Length == 2) | ||
335 | { | ||
336 | Notice("[{0}]", config.Name); | ||
337 | foreach (string key in config.GetKeys()) | ||
338 | Notice(" {0} = {1}", key, config.GetString(key)); | ||
339 | } | ||
340 | else | ||
341 | { | ||
342 | Notice( | ||
343 | "config get {0} {1} : {2}", | ||
344 | cmdparams[1], cmdparams[2], config.GetString(cmdparams[2])); | ||
345 | } | ||
346 | } | ||
347 | } | ||
348 | else | ||
349 | { | ||
350 | Notice("Syntax: config {0} [<section>] [<key>]", firstParam); | ||
351 | Notice("Example: config {0} ScriptEngine.DotNetEngine NumberOfScriptThreads", firstParam); | ||
352 | } | ||
353 | |||
354 | break; | ||
355 | |||
356 | case "save": | ||
357 | if (cmdparams.Length < 2) | ||
358 | { | ||
359 | Notice("Syntax: config save <path>"); | ||
360 | return; | ||
361 | } | ||
362 | |||
363 | string path = cmdparams[1]; | ||
364 | Notice("Saving configuration file: {0}", path); | ||
365 | |||
366 | if (Config is IniConfigSource) | ||
367 | { | ||
368 | IniConfigSource iniCon = (IniConfigSource)Config; | ||
369 | iniCon.Save(path); | ||
370 | } | ||
371 | else if (Config is XmlConfigSource) | ||
372 | { | ||
373 | XmlConfigSource xmlCon = (XmlConfigSource)Config; | ||
374 | xmlCon.Save(path); | ||
375 | } | ||
376 | |||
377 | break; | ||
378 | } | ||
379 | } | ||
380 | } | ||
381 | |||
382 | private void HandleSetLogLevel(string module, string[] cmd) | ||
383 | { | ||
384 | if (cmd.Length != 4) | ||
385 | { | ||
386 | Notice("Usage: set log level <level>"); | ||
387 | return; | ||
388 | } | ||
389 | |||
390 | if (null == m_consoleAppender) | ||
391 | { | ||
392 | Notice("No appender named Console found (see the log4net config file for this executable)!"); | ||
393 | return; | ||
394 | } | ||
395 | |||
396 | string rawLevel = cmd[3]; | ||
397 | |||
398 | ILoggerRepository repository = LogManager.GetRepository(); | ||
399 | Level consoleLevel = repository.LevelMap[rawLevel]; | ||
400 | |||
401 | if (consoleLevel != null) | ||
402 | m_consoleAppender.Threshold = consoleLevel; | ||
403 | else | ||
404 | Notice( | ||
405 | "{0} is not a valid logging level. Valid logging levels are ALL, DEBUG, INFO, WARN, ERROR, FATAL, OFF", | ||
406 | rawLevel); | ||
407 | |||
408 | ShowLogLevel(); | ||
409 | } | ||
410 | |||
411 | private void ShowLogLevel() | ||
412 | { | ||
413 | Notice("Console log level is {0}", m_consoleAppender.Threshold); | ||
414 | } | ||
415 | |||
416 | protected virtual void HandleScript(string module, string[] parms) | ||
417 | { | ||
418 | if (parms.Length != 2) | ||
419 | { | ||
420 | Notice("Usage: command-script <path-to-script"); | ||
421 | return; | ||
422 | } | ||
423 | |||
424 | RunCommandScript(parms[1]); | ||
425 | } | ||
426 | |||
427 | /// <summary> | ||
428 | /// Run an optional startup list of commands | ||
429 | /// </summary> | ||
430 | /// <param name="fileName"></param> | ||
431 | protected void RunCommandScript(string fileName) | ||
432 | { | ||
433 | if (m_console == null) | ||
434 | return; | ||
435 | |||
436 | if (File.Exists(fileName)) | ||
437 | { | ||
438 | m_log.Info("[SERVER BASE]: Running " + fileName); | ||
439 | |||
440 | using (StreamReader readFile = File.OpenText(fileName)) | ||
441 | { | ||
442 | string currentCommand; | ||
443 | while ((currentCommand = readFile.ReadLine()) != null) | ||
444 | { | ||
445 | currentCommand = currentCommand.Trim(); | ||
446 | if (!(currentCommand == "" | ||
447 | || currentCommand.StartsWith(";") | ||
448 | || currentCommand.StartsWith("//") | ||
449 | || currentCommand.StartsWith("#"))) | ||
450 | { | ||
451 | m_log.Info("[SERVER BASE]: Running '" + currentCommand + "'"); | ||
452 | m_console.RunCommand(currentCommand); | ||
453 | } | ||
454 | } | ||
455 | } | ||
456 | } | ||
457 | } | ||
458 | |||
459 | /// <summary> | ||
460 | /// Return a report about the uptime of this server | ||
461 | /// </summary> | ||
462 | /// <returns></returns> | ||
463 | protected string GetUptimeReport() | ||
464 | { | ||
465 | StringBuilder sb = new StringBuilder(String.Format("Time now is {0}\n", DateTime.Now)); | ||
466 | sb.Append(String.Format("Server has been running since {0}, {1}\n", m_startuptime.DayOfWeek, m_startuptime)); | ||
467 | sb.Append(String.Format("That is an elapsed time of {0}\n", DateTime.Now - m_startuptime)); | ||
468 | |||
469 | return sb.ToString(); | ||
470 | } | ||
471 | |||
472 | protected void ShowInfo() | ||
473 | { | ||
474 | Notice(GetVersionText()); | ||
475 | Notice("Startup directory: " + m_startupDirectory); | ||
476 | if (null != m_consoleAppender) | ||
477 | Notice(String.Format("Console log level: {0}", m_consoleAppender.Threshold)); | ||
478 | } | ||
479 | |||
480 | /// <summary> | ||
481 | /// Enhance the version string with extra information if it's available. | ||
482 | /// </summary> | ||
483 | protected void EnhanceVersionInformation() | ||
484 | { | ||
485 | string buildVersion = string.Empty; | ||
486 | |||
487 | // The subversion information is deprecated and will be removed at a later date | ||
488 | // Add subversion revision information if available | ||
489 | // Try file "svn_revision" in the current directory first, then the .svn info. | ||
490 | // This allows to make the revision available in simulators not running from the source tree. | ||
491 | // FIXME: Making an assumption about the directory we're currently in - we do this all over the place | ||
492 | // elsewhere as well | ||
493 | string gitDir = "../.git/"; | ||
494 | string gitRefPointerPath = gitDir + "HEAD"; | ||
495 | |||
496 | string svnRevisionFileName = "svn_revision"; | ||
497 | string svnFileName = ".svn/entries"; | ||
498 | string manualVersionFileName = ".version"; | ||
499 | string inputLine; | ||
500 | int strcmp; | ||
501 | |||
502 | if (File.Exists(manualVersionFileName)) | ||
503 | { | ||
504 | using (StreamReader CommitFile = File.OpenText(manualVersionFileName)) | ||
505 | buildVersion = CommitFile.ReadLine(); | ||
506 | |||
507 | m_version += buildVersion ?? ""; | ||
508 | } | ||
509 | else if (File.Exists(gitRefPointerPath)) | ||
510 | { | ||
511 | // m_log.DebugFormat("[SERVER BASE]: Found {0}", gitRefPointerPath); | ||
512 | |||
513 | string rawPointer = ""; | ||
514 | |||
515 | using (StreamReader pointerFile = File.OpenText(gitRefPointerPath)) | ||
516 | rawPointer = pointerFile.ReadLine(); | ||
517 | |||
518 | // m_log.DebugFormat("[SERVER BASE]: rawPointer [{0}]", rawPointer); | ||
519 | |||
520 | Match m = Regex.Match(rawPointer, "^ref: (.+)$"); | ||
521 | |||
522 | if (m.Success) | ||
523 | { | ||
524 | // m_log.DebugFormat("[SERVER BASE]: Matched [{0}]", m.Groups[1].Value); | ||
525 | |||
526 | string gitRef = m.Groups[1].Value; | ||
527 | string gitRefPath = gitDir + gitRef; | ||
528 | if (File.Exists(gitRefPath)) | ||
529 | { | ||
530 | // m_log.DebugFormat("[SERVER BASE]: Found gitRefPath [{0}]", gitRefPath); | ||
531 | |||
532 | using (StreamReader refFile = File.OpenText(gitRefPath)) | ||
533 | { | ||
534 | string gitHash = refFile.ReadLine(); | ||
535 | m_version += gitHash.Substring(0, 7); | ||
536 | } | ||
537 | } | ||
538 | } | ||
539 | } | ||
540 | else | ||
541 | { | ||
542 | // Remove the else logic when subversion mirror is no longer used | ||
543 | if (File.Exists(svnRevisionFileName)) | ||
544 | { | ||
545 | StreamReader RevisionFile = File.OpenText(svnRevisionFileName); | ||
546 | buildVersion = RevisionFile.ReadLine(); | ||
547 | buildVersion.Trim(); | ||
548 | RevisionFile.Close(); | ||
549 | } | ||
550 | |||
551 | if (string.IsNullOrEmpty(buildVersion) && File.Exists(svnFileName)) | ||
552 | { | ||
553 | StreamReader EntriesFile = File.OpenText(svnFileName); | ||
554 | inputLine = EntriesFile.ReadLine(); | ||
555 | while (inputLine != null) | ||
556 | { | ||
557 | // using the dir svn revision at the top of entries file | ||
558 | strcmp = String.Compare(inputLine, "dir"); | ||
559 | if (strcmp == 0) | ||
560 | { | ||
561 | buildVersion = EntriesFile.ReadLine(); | ||
562 | break; | ||
563 | } | ||
564 | else | ||
565 | { | ||
566 | inputLine = EntriesFile.ReadLine(); | ||
567 | } | ||
568 | } | ||
569 | EntriesFile.Close(); | ||
570 | } | ||
571 | |||
572 | m_version += string.IsNullOrEmpty(buildVersion) ? " " : ("." + buildVersion + " ").Substring(0, 6); | ||
573 | } | ||
574 | } | ||
575 | |||
576 | protected string GetVersionText() | ||
577 | { | ||
578 | return String.Format("Version: {0} (interface version {1})", m_version, VersionInfo.MajorInterfaceVersion); | ||
579 | } | ||
580 | |||
581 | /// <summary> | ||
582 | /// Get a report about the registered threads in this server. | ||
583 | /// </summary> | ||
584 | protected string GetThreadsReport() | ||
585 | { | ||
586 | // This should be a constant field. | ||
587 | string reportFormat = "{0,6} {1,35} {2,16} {3,13} {4,10} {5,30}"; | ||
588 | |||
589 | StringBuilder sb = new StringBuilder(); | ||
590 | Watchdog.ThreadWatchdogInfo[] threads = Watchdog.GetThreadsInfo(); | ||
591 | |||
592 | sb.Append(threads.Length + " threads are being tracked:" + Environment.NewLine); | ||
593 | |||
594 | int timeNow = Environment.TickCount & Int32.MaxValue; | ||
595 | |||
596 | sb.AppendFormat(reportFormat, "ID", "NAME", "LAST UPDATE (MS)", "LIFETIME (MS)", "PRIORITY", "STATE"); | ||
597 | sb.Append(Environment.NewLine); | ||
598 | |||
599 | foreach (Watchdog.ThreadWatchdogInfo twi in threads) | ||
600 | { | ||
601 | Thread t = twi.Thread; | ||
602 | |||
603 | sb.AppendFormat( | ||
604 | reportFormat, | ||
605 | t.ManagedThreadId, | ||
606 | t.Name, | ||
607 | timeNow - twi.LastTick, | ||
608 | timeNow - twi.FirstTick, | ||
609 | t.Priority, | ||
610 | t.ThreadState); | ||
611 | |||
612 | sb.Append("\n"); | ||
613 | } | ||
614 | |||
615 | sb.Append("\n"); | ||
616 | |||
617 | // For some reason mono 2.6.7 returns an empty threads set! Not going to confuse people by reporting | ||
618 | // zero active threads. | ||
619 | int totalThreads = Process.GetCurrentProcess().Threads.Count; | ||
620 | if (totalThreads > 0) | ||
621 | sb.AppendFormat("Total threads active: {0}\n\n", totalThreads); | ||
622 | |||
623 | sb.Append("Main threadpool (excluding script engine pools)\n"); | ||
624 | sb.Append(Util.GetThreadPoolReport()); | ||
625 | |||
626 | return sb.ToString(); | ||
627 | } | ||
628 | |||
629 | public virtual void HandleThreadsAbort(string module, string[] cmd) | ||
630 | { | ||
631 | if (cmd.Length != 3) | ||
632 | { | ||
633 | MainConsole.Instance.Output("Usage: threads abort <thread-id>"); | ||
634 | return; | ||
635 | } | ||
636 | |||
637 | int threadId; | ||
638 | if (!int.TryParse(cmd[2], out threadId)) | ||
639 | { | ||
640 | MainConsole.Instance.Output("ERROR: Thread id must be an integer"); | ||
641 | return; | ||
642 | } | ||
643 | |||
644 | if (Watchdog.AbortThread(threadId)) | ||
645 | MainConsole.Instance.OutputFormat("Aborted thread with id {0}", threadId); | ||
646 | else | ||
647 | MainConsole.Instance.OutputFormat("ERROR - Thread with id {0} not found in managed threads", threadId); | ||
648 | } | ||
649 | |||
650 | /// <summary> | ||
651 | /// Console output is only possible if a console has been established. | ||
652 | /// That is something that cannot be determined within this class. So | ||
653 | /// all attempts to use the console MUST be verified. | ||
654 | /// </summary> | ||
655 | /// <param name="msg"></param> | ||
656 | protected void Notice(string msg) | ||
657 | { | ||
658 | if (m_console != null) | ||
659 | { | ||
660 | m_console.Output(msg); | ||
661 | } | ||
662 | } | ||
663 | |||
664 | /// <summary> | ||
665 | /// Console output is only possible if a console has been established. | ||
666 | /// That is something that cannot be determined within this class. So | ||
667 | /// all attempts to use the console MUST be verified. | ||
668 | /// </summary> | ||
669 | /// <param name="format"></param> | ||
670 | /// <param name="components"></param> | ||
671 | protected void Notice(string format, params object[] components) | ||
672 | { | ||
673 | if (m_console != null) | ||
674 | m_console.OutputFormat(format, components); | ||
675 | } | ||
676 | } | ||
677 | } \ No newline at end of file | ||
diff --git a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs index dc4eb8f..3412e0f 100644 --- a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs +++ b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs | |||
@@ -35,11 +35,12 @@ using HttpServer; | |||
35 | using HttpServer.FormDecoders; | 35 | using HttpServer.FormDecoders; |
36 | using NUnit.Framework; | 36 | using NUnit.Framework; |
37 | using OpenSim.Framework.Servers.HttpServer; | 37 | using OpenSim.Framework.Servers.HttpServer; |
38 | using OpenSim.Tests.Common; | ||
38 | 39 | ||
39 | namespace OpenSim.Framework.Servers.Tests | 40 | namespace OpenSim.Framework.Servers.Tests |
40 | { | 41 | { |
41 | [TestFixture] | 42 | [TestFixture] |
42 | public class OSHttpTests | 43 | public class OSHttpTests : OpenSimTestCase |
43 | { | 44 | { |
44 | // we need an IHttpClientContext for our tests | 45 | // we need an IHttpClientContext for our tests |
45 | public class TestHttpClientContext: IHttpClientContext | 46 | public class TestHttpClientContext: IHttpClientContext |
diff --git a/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs b/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs index 49e5061..480f2bb 100644 --- a/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs +++ b/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs | |||
@@ -29,11 +29,12 @@ using System; | |||
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Text; | 30 | using System.Text; |
31 | using NUnit.Framework; | 31 | using NUnit.Framework; |
32 | using OpenSim.Tests.Common; | ||
32 | 33 | ||
33 | namespace OpenSim.Framework.Servers.Tests | 34 | namespace OpenSim.Framework.Servers.Tests |
34 | { | 35 | { |
35 | [TestFixture] | 36 | [TestFixture] |
36 | public class VersionInfoTests | 37 | public class VersionInfoTests : OpenSimTestCase |
37 | { | 38 | { |
38 | [Test] | 39 | [Test] |
39 | public void TestVersionLength() | 40 | public void TestVersionLength() |