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.Collections;
30 using System.Collections.Generic;
31 using System.Globalization;
32 using System.IO;
33 using System.Linq;
34 using System.Reflection;
35 using System.Security;
36 using System.Security.Policy;
37 using System.Text;
38 using System.Threading;
39 using System.Xml;
40 using OpenMetaverse;
41 using OpenMetaverse.StructuredData;
42 using log4net;
43 using Nini.Config;
44 using Amib.Threading;
45 using OpenSim.Framework;
46 using OpenSim.Framework.Console;
47 using OpenSim.Region.Framework.Scenes;
48 using OpenSim.Region.Framework.Interfaces;
49 using OpenSim.Region.ScriptEngine.Interfaces;
50 using OpenSim.Region.ScriptEngine.Shared;
51 using OpenSim.Region.ScriptEngine.Shared.CodeTools;
52 using OpenSim.Region.ScriptEngine.Shared.Instance;
53 using OpenSim.Region.ScriptEngine.Shared.Api;
54 using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
55 using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
56 using OpenSim.Region.ScriptEngine.XEngine.ScriptBase;
57 using Timer = OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer;
58  
59 using ScriptCompileQueue = OpenSim.Framework.LocklessQueue<object[]>;
60  
61 namespace OpenSim.Region.ScriptEngine.XEngine
62 {
63 public class XEngine : INonSharedRegionModule, IScriptModule, IScriptEngine
64 {
65 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
66  
67 /// <summary>
68 /// Control the printing of certain debug messages.
69 /// </summary>
70 /// <remarks>
71 /// If DebugLevel >= 1, then we log every time that a script is started.
72 /// </remarks>
73 // public int DebugLevel { get; set; }
74  
75 private SmartThreadPool m_ThreadPool;
76 private int m_MaxScriptQueue;
77 private Scene m_Scene;
78 private IConfig m_ScriptConfig = null;
79 private IConfigSource m_ConfigSource = null;
80 private ICompiler m_Compiler;
81 private int m_MinThreads;
82 private int m_MaxThreads;
83  
84 /// <summary>
85 /// Amount of time to delay before starting.
86 /// </summary>
87 private int m_StartDelay;
88  
89 private int m_IdleTimeout;
90 private int m_StackSize;
91 private int m_SleepTime;
92 private int m_SaveTime;
93 private ThreadPriority m_Prio;
94 private bool m_Enabled = false;
95 private bool m_InitialStartup = true;
96 private int m_ScriptFailCount; // Number of script fails since compile queue was last empty
97 private string m_ScriptErrorMessage;
98 private Dictionary<string, string> m_uniqueScripts = new Dictionary<string, string>();
99 private bool m_AppDomainLoading;
100 private Dictionary<UUID,ArrayList> m_ScriptErrors =
101 new Dictionary<UUID,ArrayList>();
102  
103 // disable warning: need to keep a reference to XEngine.EventManager
104 // alive to avoid it being garbage collected
105 #pragma warning disable 414
106 private EventManager m_EventManager;
107 #pragma warning restore 414
108 private IXmlRpcRouter m_XmlRpcRouter;
109 private int m_EventLimit;
110 private bool m_KillTimedOutScripts;
111  
112 /// <summary>
113 /// Number of milliseconds we will wait for a script event to complete on script stop before we forcibly abort
114 /// its thread.
115 /// </summary>
116 /// <remarks>
117 /// It appears that if a script thread is aborted whilst it is holding ReaderWriterLockSlim (possibly the write
118 /// lock) then the lock is not properly released. This causes mono 2.6, 2.10 and possibly
119 /// later to crash, sometimes with symptoms such as a leap to 100% script usage and a vm thead dump showing
120 /// all threads waiting on release of ReaderWriterLockSlim write thread which none of the threads listed
121 /// actually hold.
122 ///
123 /// Pausing for event completion reduces the risk of this happening. However, it may be that aborting threads
124 /// is not a mono issue per se but rather a risky activity in itself in an AppDomain that is not immediately
125 /// shutting down.
126 /// </remarks>
127 private int m_WaitForEventCompletionOnScriptStop = 1000;
128  
129 private string m_ScriptEnginesPath = null;
130  
131 private ExpiringCache<UUID, bool> m_runFlags = new ExpiringCache<UUID, bool>();
132  
133 /// <summary>
134 /// Is the entire simulator in the process of shutting down?
135 /// </summary>
136 private bool m_SimulatorShuttingDown;
137  
138 private static List<XEngine> m_ScriptEngines =
139 new List<XEngine>();
140  
141 // Maps the local id to the script inventory items in it
142  
143 private Dictionary<uint, List<UUID> > m_PrimObjects =
144 new Dictionary<uint, List<UUID> >();
145  
146 // Maps the UUID above to the script instance
147  
148 private Dictionary<UUID, IScriptInstance> m_Scripts =
149 new Dictionary<UUID, IScriptInstance>();
150  
151 // Maps the asset ID to the assembly
152  
153 private Dictionary<UUID, string> m_Assemblies =
154 new Dictionary<UUID, string>();
155  
156 private Dictionary<string, int> m_AddingAssemblies =
157 new Dictionary<string, int>();
158  
159 // This will list AppDomains by script asset
160  
161 private Dictionary<UUID, AppDomain> m_AppDomains =
162 new Dictionary<UUID, AppDomain>();
163  
164 // List the scripts running in each appdomain
165  
166 private Dictionary<UUID, List<UUID> > m_DomainScripts =
167 new Dictionary<UUID, List<UUID> >();
168  
169 private ScriptCompileQueue m_CompileQueue = new ScriptCompileQueue();
170 IWorkItemResult m_CurrentCompile = null;
171 private Dictionary<UUID, int> m_CompileDict = new Dictionary<UUID, int>();
172  
173 private ScriptEngineConsoleCommands m_consoleCommands;
174  
175 public string ScriptEngineName
176 {
177 get { return "XEngine"; }
178 }
179  
180 public string ScriptClassName { get; private set; }
181  
182 public string ScriptBaseClassName { get; private set; }
183  
184 public ParameterInfo[] ScriptBaseClassParameters { get; private set; }
185  
186 public string[] ScriptReferencedAssemblies { get; private set; }
187  
188 public Scene World
189 {
190 get { return m_Scene; }
191 }
192  
193 public static List<XEngine> ScriptEngines
194 {
195 get { return m_ScriptEngines; }
196 }
197  
198 public IScriptModule ScriptModule
199 {
200 get { return this; }
201 }
202  
203 // private struct RezScriptParms
204 // {
205 // uint LocalID;
206 // UUID ItemID;
207 // string Script;
208 // }
209  
210 public IConfig Config
211 {
212 get { return m_ScriptConfig; }
213 }
214  
215 public string ScriptEnginePath
216 {
217 get { return m_ScriptEnginesPath; }
218 }
219  
220 public IConfigSource ConfigSource
221 {
222 get { return m_ConfigSource; }
223 }
224  
225 /// <summary>
226 /// Event fired after the script engine has finished removing a script.
227 /// </summary>
228 public event ScriptRemoved OnScriptRemoved;
229  
230 /// <summary>
231 /// Event fired after the script engine has finished removing a script from an object.
232 /// </summary>
233 public event ObjectRemoved OnObjectRemoved;
234  
235 public void Initialise(IConfigSource configSource)
236 {
237 if (configSource.Configs["XEngine"] == null)
238 return;
239  
240 m_ScriptConfig = configSource.Configs["XEngine"];
241 m_ConfigSource = configSource;
242  
243 string rawScriptStopStrategy = m_ScriptConfig.GetString("ScriptStopStrategy", "abort");
244  
245 m_log.InfoFormat("[XEngine]: Script stop strategy is {0}", rawScriptStopStrategy);
246  
247 if (rawScriptStopStrategy == "co-op")
248 {
249 ScriptClassName = "XEngineScript";
250 ScriptBaseClassName = typeof(XEngineScriptBase).FullName;
251 ScriptBaseClassParameters = typeof(XEngineScriptBase).GetConstructor(new Type[] { typeof(WaitHandle) }).GetParameters();
252 ScriptReferencedAssemblies = new string[] { Path.GetFileName(typeof(XEngineScriptBase).Assembly.Location) };
253 }
254 else
255 {
256 ScriptClassName = "Script";
257 ScriptBaseClassName = typeof(ScriptBaseClass).FullName;
258 }
259  
260 // Console.WriteLine("ASSEMBLY NAME: {0}", ScriptReferencedAssemblies[0]);
261 }
262  
263 public void AddRegion(Scene scene)
264 {
265 if (m_ScriptConfig == null)
266 return;
267  
268 m_ScriptFailCount = 0;
269 m_ScriptErrorMessage = String.Empty;
270  
271 m_Enabled = m_ScriptConfig.GetBoolean("Enabled", true);
272  
273 if (!m_Enabled)
274 return;
275  
276 AppDomain.CurrentDomain.AssemblyResolve +=
277 OnAssemblyResolve;
278  
279 m_Scene = scene;
280 m_log.InfoFormat("[XEngine]: Initializing scripts in region {0}", m_Scene.RegionInfo.RegionName);
281  
282 m_MinThreads = m_ScriptConfig.GetInt("MinThreads", 2);
283 m_MaxThreads = m_ScriptConfig.GetInt("MaxThreads", 100);
284 m_IdleTimeout = m_ScriptConfig.GetInt("IdleTimeout", 60);
285 string priority = m_ScriptConfig.GetString("Priority", "BelowNormal");
286 m_StartDelay = m_ScriptConfig.GetInt("StartDelay", 15000);
287 m_MaxScriptQueue = m_ScriptConfig.GetInt("MaxScriptEventQueue",300);
288 m_StackSize = m_ScriptConfig.GetInt("ThreadStackSize", 262144);
289 m_SleepTime = m_ScriptConfig.GetInt("MaintenanceInterval", 10) * 1000;
290 m_AppDomainLoading = m_ScriptConfig.GetBoolean("AppDomainLoading", true);
291  
292 m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30);
293 m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false);
294 m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000;
295 m_WaitForEventCompletionOnScriptStop
296 = m_ScriptConfig.GetInt("WaitForEventCompletionOnScriptStop", m_WaitForEventCompletionOnScriptStop);
297  
298 m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines");
299  
300 m_Prio = ThreadPriority.BelowNormal;
301 switch (priority)
302 {
303 case "Lowest":
304 m_Prio = ThreadPriority.Lowest;
305 break;
306 case "BelowNormal":
307 m_Prio = ThreadPriority.BelowNormal;
308 break;
309 case "Normal":
310 m_Prio = ThreadPriority.Normal;
311 break;
312 case "AboveNormal":
313 m_Prio = ThreadPriority.AboveNormal;
314 break;
315 case "Highest":
316 m_Prio = ThreadPriority.Highest;
317 break;
318 default:
319 m_log.ErrorFormat("[XEngine] Invalid thread priority: '{0}'. Assuming BelowNormal", priority);
320 break;
321 }
322  
323 lock (m_ScriptEngines)
324 {
325 m_ScriptEngines.Add(this);
326 }
327  
328 // Needs to be here so we can queue the scripts that need starting
329 //
330 m_Scene.EventManager.OnRezScript += OnRezScript;
331  
332 // Complete basic setup of the thread pool
333 //
334 SetupEngine(m_MinThreads, m_MaxThreads, m_IdleTimeout, m_Prio,
335 m_MaxScriptQueue, m_StackSize);
336  
337 m_Scene.StackModuleInterface<IScriptModule>(this);
338  
339 m_XmlRpcRouter = m_Scene.RequestModuleInterface<IXmlRpcRouter>();
340 if (m_XmlRpcRouter != null)
341 {
342 OnScriptRemoved += m_XmlRpcRouter.ScriptRemoved;
343 OnObjectRemoved += m_XmlRpcRouter.ObjectRemoved;
344 }
345  
346 m_consoleCommands = new ScriptEngineConsoleCommands(this);
347 m_consoleCommands.RegisterCommands();
348  
349 MainConsole.Instance.Commands.AddCommand(
350 "Scripts", false, "xengine status", "xengine status", "Show status information",
351 "Show status information on the script engine.",
352 HandleShowStatus);
353  
354 MainConsole.Instance.Commands.AddCommand(
355 "Scripts", false, "scripts show", "scripts show [<script-item-uuid>+]", "Show script information",
356 "Show information on all scripts known to the script engine.\n"
357 + "If one or more <script-item-uuid>s are given then only information on that script will be shown.",
358 HandleShowScripts);
359  
360 MainConsole.Instance.Commands.AddCommand(
361 "Scripts", false, "show scripts", "show scripts [<script-item-uuid>+]", "Show script information",
362 "Synonym for scripts show command", HandleShowScripts);
363  
364 MainConsole.Instance.Commands.AddCommand(
365 "Scripts", false, "scripts suspend", "scripts suspend [<script-item-uuid>+]", "Suspends all running scripts",
366 "Suspends all currently running scripts. This only suspends event delivery, it will not suspend a"
367 + " script that is currently processing an event.\n"
368 + "Suspended scripts will continue to accumulate events but won't process them.\n"
369 + "If one or more <script-item-uuid>s are given then only that script will be suspended. Otherwise, all suitable scripts are suspended.",
370 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleSuspendScript));
371  
372 MainConsole.Instance.Commands.AddCommand(
373 "Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>+]", "Resumes all suspended scripts",
374 "Resumes all currently suspended scripts.\n"
375 + "Resumed scripts will process all events accumulated whilst suspended.\n"
376 + "If one or more <script-item-uuid>s are given then only that script will be resumed. Otherwise, all suitable scripts are resumed.",
377 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript));
378  
379 MainConsole.Instance.Commands.AddCommand(
380 "Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>+]", "Stops all running scripts",
381 "Stops all running scripts.\n"
382 + "If one or more <script-item-uuid>s are given then only that script will be stopped. Otherwise, all suitable scripts are stopped.",
383 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript));
384  
385 MainConsole.Instance.Commands.AddCommand(
386 "Scripts", false, "scripts start", "scripts start [<script-item-uuid>+]", "Starts all stopped scripts",
387 "Starts all stopped scripts.\n"
388 + "If one or more <script-item-uuid>s are given then only that script will be started. Otherwise, all suitable scripts are started.",
389 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript));
390  
391 MainConsole.Instance.Commands.AddCommand(
392 "Scripts", false, "debug scripts log", "debug scripts log <item-id> <log-level>", "Extra debug logging for a script",
393 "Activates or deactivates extra debug logging for the given script.\n"
394 + "Level == 0, deactivate extra debug logging.\n"
395 + "Level >= 1, log state changes.\n"
396 + "Level >= 2, log event invocations.\n",
397 HandleDebugScriptLogCommand);
398  
399 // MainConsole.Instance.Commands.AddCommand(
400 // "Debug", false, "debug xengine", "debug xengine [<level>]",
401 // "Turn on detailed xengine debugging.",
402 // "If level <= 0, then no extra logging is done.\n"
403 // + "If level >= 1, then we log every time that a script is started.",
404 // HandleDebugLevelCommand);
405 }
406  
407 private void HandleDebugScriptLogCommand(string module, string[] args)
408 {
409 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
410 return;
411  
412 if (args.Length != 5)
413 {
414 MainConsole.Instance.Output("Usage: debug script log <item-id> <log-level>");
415 return;
416 }
417  
418 UUID itemId;
419  
420 if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, args[3], out itemId))
421 return;
422  
423 int newLevel;
424  
425 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out newLevel))
426 return;
427  
428 IScriptInstance si;
429  
430 lock (m_Scripts)
431 {
432 // XXX: We can't give the user feedback on a bad item id because this may apply to a different script
433 // engine
434 if (!m_Scripts.TryGetValue(itemId, out si))
435 return;
436 }
437  
438 si.DebugLevel = newLevel;
439 MainConsole.Instance.OutputFormat("Set debug level of {0} {1} to {2}", si.ScriptName, si.ItemID, newLevel);
440 }
441  
442 /// <summary>
443 /// Change debug level
444 /// </summary>
445 /// <param name="module"></param>
446 /// <param name="args"></param>
447 // private void HandleDebugLevelCommand(string module, string[] args)
448 // {
449 // if (args.Length == 3)
450 // {
451 // int newDebug;
452 // if (int.TryParse(args[2], out newDebug))
453 // {
454 // DebugLevel = newDebug;
455 // MainConsole.Instance.OutputFormat("Debug level set to {0}", newDebug);
456 // }
457 // }
458 // else if (args.Length == 2)
459 // {
460 // MainConsole.Instance.OutputFormat("Current debug level is {0}", DebugLevel);
461 // }
462 // else
463 // {
464 // MainConsole.Instance.Output("Usage: debug xengine 0..1");
465 // }
466 // }
467  
468 /// <summary>
469 /// Parse the raw item id into a script instance from the command params if it's present.
470 /// </summary>
471 /// <param name="cmdparams"></param>
472 /// <param name="instance"></param>
473 /// <param name="comparer">Basis on which to sort output. Can be null if no sort needs to take place</param>
474 private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action)
475 {
476 HandleScriptsAction<object>(cmdparams, action, null);
477 }
478  
479 /// <summary>
480 /// Parse the raw item id into a script instance from the command params if it's present.
481 /// </summary>
482 /// <param name="cmdparams"></param>
483 /// <param name="instance"></param>
484 /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param>
485 private void HandleScriptsAction<TKey>(
486 string[] cmdparams, Action<IScriptInstance> action, System.Func<IScriptInstance, TKey> keySelector)
487 {
488 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
489 return;
490  
491 lock (m_Scripts)
492 {
493 string rawItemId;
494 UUID itemId = UUID.Zero;
495  
496 if (cmdparams.Length == 2)
497 {
498 IEnumerable<IScriptInstance> scripts = m_Scripts.Values;
499  
500 if (keySelector != null)
501 scripts = scripts.OrderBy<IScriptInstance, TKey>(keySelector);
502  
503 foreach (IScriptInstance instance in scripts)
504 action(instance);
505  
506 return;
507 }
508  
509 for (int i = 2; i < cmdparams.Length; i++)
510 {
511 rawItemId = cmdparams[i];
512  
513 if (!UUID.TryParse(rawItemId, out itemId))
514 {
515 MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid UUID", rawItemId);
516 continue;
517 }
518  
519 if (itemId != UUID.Zero)
520 {
521 IScriptInstance instance = GetInstance(itemId);
522 if (instance == null)
523 {
524 // Commented out for now since this will cause false reports on simulators with more than
525 // one scene where the current command line set region is 'root' (which causes commands to
526 // go to both regions... (sigh)
527 // MainConsole.Instance.OutputFormat("Error - No item found with id {0}", itemId);
528 continue;
529 }
530 else
531 {
532 action(instance);
533 }
534 }
535 }
536 }
537 }
538  
539 private void HandleShowStatus(string module, string[] cmdparams)
540 {
541 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
542 return;
543  
544 MainConsole.Instance.Output(GetStatusReport());
545 }
546  
547 public string GetStatusReport()
548 {
549 StringBuilder sb = new StringBuilder();
550 sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName);
551  
552 long scriptsLoaded, eventsQueued = 0, eventsProcessed = 0;
553  
554 lock (m_Scripts)
555 {
556 scriptsLoaded = m_Scripts.Count;
557  
558 foreach (IScriptInstance si in m_Scripts.Values)
559 {
560 eventsQueued += si.EventsQueued;
561 eventsProcessed += si.EventsProcessed;
562 }
563 }
564  
565 sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded);
566 sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count);
567 sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count);
568 sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads);
569 sb.AppendFormat("Min threads : {0}\n", m_ThreadPool.MinThreads);
570 sb.AppendFormat("Allocated threads : {0}\n", m_ThreadPool.ActiveThreads);
571 sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads);
572 sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks);
573 // sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count);
574 sb.AppendFormat("Events queued : {0}\n", eventsQueued);
575 sb.AppendFormat("Events processed : {0}\n", eventsProcessed);
576  
577 SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this);
578 sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0);
579  
580 Dataserver ds = AsyncCommandManager.GetDataserverPlugin(this);
581 sb.AppendFormat("Dataserver requests : {0}\n", ds != null ? ds.DataserverRequestsCount : 0);
582  
583 Timer t = AsyncCommandManager.GetTimerPlugin(this);
584 sb.AppendFormat("Timers : {0}\n", t != null ? t.TimersCount : 0);
585  
586 Listener l = AsyncCommandManager.GetListenerPlugin(this);
587 sb.AppendFormat("Listeners : {0}\n", l != null ? l.ListenerCount : 0);
588  
589 return sb.ToString();
590 }
591  
592 public void HandleShowScripts(string module, string[] cmdparams)
593 {
594 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
595 return;
596  
597 if (cmdparams.Length == 2)
598 {
599 lock (m_Scripts)
600 {
601 MainConsole.Instance.OutputFormat(
602 "Showing {0} scripts in {1}", m_Scripts.Count, m_Scene.RegionInfo.RegionName);
603 }
604 }
605  
606 HandleScriptsAction<long>(cmdparams, HandleShowScript, si => si.EventsProcessed);
607 }
608  
609 private void HandleShowScript(IScriptInstance instance)
610 {
611 SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID);
612 string status;
613  
614 if (instance.ShuttingDown)
615 {
616 status = "shutting down";
617 }
618 else if (instance.Suspended)
619 {
620 status = "suspended";
621 }
622 else if (!instance.Running)
623 {
624 status = "stopped";
625 }
626 else
627 {
628 status = "running";
629 }
630  
631 StringBuilder sb = new StringBuilder();
632  
633 sb.AppendFormat("Script name : {0}\n", instance.ScriptName);
634 sb.AppendFormat("Status : {0}\n", status);
635 sb.AppendFormat("Queued events : {0}\n", instance.EventsQueued);
636 sb.AppendFormat("Processed events : {0}\n", instance.EventsProcessed);
637 sb.AppendFormat("Item UUID : {0}\n", instance.ItemID);
638 sb.AppendFormat("Asset UUID : {0}\n", instance.AssetID);
639 sb.AppendFormat("Containing part name: {0}\n", instance.PrimName);
640 sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID);
641 sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition);
642  
643 MainConsole.Instance.Output(sb.ToString());
644 }
645  
646 private void HandleSuspendScript(IScriptInstance instance)
647 {
648 if (!instance.Suspended)
649 {
650 instance.Suspend();
651  
652 SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID);
653 MainConsole.Instance.OutputFormat(
654 "Suspended {0}.{1}, item UUID {2}, prim UUID {3} @ {4}",
655 instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, sop.AbsolutePosition);
656 }
657 }
658  
659 private void HandleResumeScript(IScriptInstance instance)
660 {
661 if (instance.Suspended)
662 {
663 instance.Resume();
664  
665 SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID);
666 MainConsole.Instance.OutputFormat(
667 "Resumed {0}.{1}, item UUID {2}, prim UUID {3} @ {4}",
668 instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, sop.AbsolutePosition);
669 }
670 }
671  
672 private void HandleStartScript(IScriptInstance instance)
673 {
674 if (!instance.Running)
675 {
676 instance.Start();
677  
678 SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID);
679 MainConsole.Instance.OutputFormat(
680 "Started {0}.{1}, item UUID {2}, prim UUID {3} @ {4}",
681 instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, sop.AbsolutePosition);
682 }
683 }
684  
685 private void HandleStopScript(IScriptInstance instance)
686 {
687 if (instance.Running)
688 {
689 instance.Stop(0);
690  
691 SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID);
692 MainConsole.Instance.OutputFormat(
693 "Stopped {0}.{1}, item UUID {2}, prim UUID {3} @ {4}",
694 instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, sop.AbsolutePosition);
695 }
696 }
697  
698 public void RemoveRegion(Scene scene)
699 {
700 if (!m_Enabled)
701 return;
702  
703 lock (m_Scripts)
704 {
705 m_log.InfoFormat(
706 "[XEngine]: Shutting down {0} scripts in {1}", m_Scripts.Count, m_Scene.RegionInfo.RegionName);
707  
708 foreach (IScriptInstance instance in m_Scripts.Values)
709 {
710 // Force a final state save
711 //
712 if (m_Assemblies.ContainsKey(instance.AssetID))
713 {
714 string assembly = m_Assemblies[instance.AssetID];
715  
716 try
717 {
718 instance.SaveState(assembly);
719 }
720 catch (Exception e)
721 {
722 m_log.Error(
723 string.Format(
724 "[XEngine]: Failed final state save for script {0}.{1}, item UUID {2}, prim UUID {3} in {4}. Exception ",
725 instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name)
726 , e);
727 }
728 }
729  
730 // Clear the event queue and abort the instance thread
731 //
732 instance.ClearQueue();
733 instance.Stop(0);
734  
735 // Release events, timer, etc
736 //
737 instance.DestroyScriptInstance();
738  
739 // Unload scripts and app domains.
740 // Must be done explicitly because they have infinite
741 // lifetime.
742 // However, don't bother to do this if the simulator is shutting
743 // down since it takes a long time with many scripts.
744 if (!m_SimulatorShuttingDown)
745 {
746 m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
747 if (m_DomainScripts[instance.AppDomain].Count == 0)
748 {
749 m_DomainScripts.Remove(instance.AppDomain);
750 UnloadAppDomain(instance.AppDomain);
751 }
752 }
753 }
754  
755 m_Scripts.Clear();
756 m_PrimObjects.Clear();
757 m_Assemblies.Clear();
758 m_DomainScripts.Clear();
759 }
760 lock (m_ScriptEngines)
761 {
762 m_ScriptEngines.Remove(this);
763 }
764 }
765  
766 public void RegionLoaded(Scene scene)
767 {
768 if (!m_Enabled)
769 return;
770  
771 m_EventManager = new EventManager(this);
772  
773 m_Compiler = new Compiler(this);
774  
775 m_Scene.EventManager.OnRemoveScript += OnRemoveScript;
776 m_Scene.EventManager.OnScriptReset += OnScriptReset;
777 m_Scene.EventManager.OnStartScript += OnStartScript;
778 m_Scene.EventManager.OnStopScript += OnStopScript;
779 m_Scene.EventManager.OnGetScriptRunning += OnGetScriptRunning;
780 m_Scene.EventManager.OnShutdown += OnShutdown;
781  
782 // If region ready has been triggered, then the region had no scripts to compile and completed its other
783 // work.
784 m_Scene.EventManager.OnRegionReadyStatusChange += s => { if (s.Ready) m_InitialStartup = false; };
785  
786 if (m_SleepTime > 0)
787 {
788 m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoMaintenance),
789 new Object[]{ m_SleepTime });
790 }
791  
792 if (m_SaveTime > 0)
793 {
794 m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup),
795 new Object[] { m_SaveTime });
796 }
797 }
798  
799 public void StartProcessing()
800 {
801 m_ThreadPool.Start();
802 }
803  
804 public void Close()
805 {
806 if (!m_Enabled)
807 return;
808  
809 lock (m_ScriptEngines)
810 {
811 if (m_ScriptEngines.Contains(this))
812 m_ScriptEngines.Remove(this);
813 }
814 }
815  
816 public object DoBackup(object o)
817 {
818 Object[] p = (Object[])o;
819 int saveTime = (int)p[0];
820  
821 if (saveTime > 0)
822 System.Threading.Thread.Sleep(saveTime);
823  
824 // m_log.Debug("[XEngine] Backing up script states");
825  
826 List<IScriptInstance> instances = new List<IScriptInstance>();
827  
828 lock (m_Scripts)
829 {
830 foreach (IScriptInstance instance in m_Scripts.Values)
831 instances.Add(instance);
832 }
833  
834 foreach (IScriptInstance i in instances)
835 {
836 string assembly = String.Empty;
837  
838 lock (m_Scripts)
839 {
840 if (!m_Assemblies.ContainsKey(i.AssetID))
841 continue;
842 assembly = m_Assemblies[i.AssetID];
843 }
844  
845 try
846 {
847 i.SaveState(assembly);
848 }
849 catch (Exception e)
850 {
851 m_log.Error(
852 string.Format(
853 "[XEngine]: Failed to save state of script {0}.{1}, item UUID {2}, prim UUID {3} in {4}. Exception ",
854 i.PrimName, i.ScriptName, i.ItemID, i.ObjectID, World.Name)
855 , e);
856 }
857 }
858  
859 instances.Clear();
860  
861 if (saveTime > 0)
862 m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup),
863 new Object[] { saveTime });
864  
865 return 0;
866 }
867  
868 public void SaveAllState()
869 {
870 foreach (IScriptInstance inst in m_Scripts.Values)
871 {
872 if (inst.EventTime() > m_EventLimit)
873 {
874 inst.Stop(100);
875 if (!m_KillTimedOutScripts)
876 inst.Start();
877 }
878 }
879 }
880  
881 public object DoMaintenance(object p)
882 {
883 object[] parms = (object[])p;
884 int sleepTime = (int)parms[0];
885  
886 SaveAllState();
887  
888 System.Threading.Thread.Sleep(sleepTime);
889  
890 m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoMaintenance),
891 new Object[]{ sleepTime });
892  
893 return 0;
894 }
895  
896 public Type ReplaceableInterface
897 {
898 get { return null; }
899 }
900  
901 public string Name
902 {
903 get { return "XEngine"; }
904 }
905  
906 public void OnRezScript(uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine, int stateSource)
907 {
908 // m_log.DebugFormat(
909 // "[XEngine]: OnRezScript event triggered for script {0}, startParam {1}, postOnRez {2}, engine {3}, stateSource {4}, script\n{5}",
910 // itemID, startParam, postOnRez, engine, stateSource, script);
911  
912 if (script.StartsWith("//MRM:"))
913 return;
914  
915 List<IScriptModule> engines = new List<IScriptModule>(m_Scene.RequestModuleInterfaces<IScriptModule>());
916  
917 List<string> names = new List<string>();
918 foreach (IScriptModule m in engines)
919 names.Add(m.ScriptEngineName);
920  
921 int lineEnd = script.IndexOf('\n');
922  
923 if (lineEnd > 1)
924 {
925 string firstline = script.Substring(0, lineEnd).Trim();
926  
927 int colon = firstline.IndexOf(':');
928 if (firstline.Length > 2 && firstline.Substring(0, 2) == "//" && colon != -1)
929 {
930 string engineName = firstline.Substring(2, colon - 2);
931  
932 if (names.Contains(engineName))
933 {
934 engine = engineName;
935 script = "//" + script.Substring(colon + 1);
936 }
937 else
938 {
939 if (engine == ScriptEngineName)
940 {
941 // If we are falling back on XEngine as the default engine, then only complain to the user
942 // if a script language has been explicitly set and it's one that we recognize or there are
943 // no non-whitespace characters after the colon.
944 //
945 // If the script is
946 // explicitly not allowed or the script is not in LSL then the user will be informed by a later compiler message.
947 //
948 // If the colon ends the line then we'll risk the false positive as this is more likely
949 // to signal a real scriptengine line where the user wants to use the default compile language.
950 //
951 // This avoids the overwhelming number of false positives where we're in this code because
952 // there's a colon in a comment in the first line of a script for entirely
953 // unrelated reasons (e.g. vim settings).
954 //
955 // TODO: A better fix would be to deprecate simple : detection and look for some less likely
956 // string to begin the comment (like #! in unix shell scripts).
957 bool warnRunningInXEngine = false;
958 string restOfFirstLine = firstline.Substring(colon + 1);
959  
960 // FIXME: These are hardcoded because they are currently hardcoded in Compiler.cs
961 if (restOfFirstLine.StartsWith("c#")
962 || restOfFirstLine.StartsWith("vb")
963 || restOfFirstLine.StartsWith("lsl")
964 || restOfFirstLine.StartsWith("js")
965 || restOfFirstLine.StartsWith("yp")
966 || restOfFirstLine.Length == 0)
967 warnRunningInXEngine = true;
968  
969 if (warnRunningInXEngine)
970 {
971 SceneObjectPart part =
972 m_Scene.GetSceneObjectPart(
973 localID);
974  
975 TaskInventoryItem item =
976 part.Inventory.GetInventoryItem(itemID);
977  
978 ScenePresence presence =
979 m_Scene.GetScenePresence(
980 item.OwnerID);
981  
982 if (presence != null)
983 {
984 presence.ControllingClient.SendAgentAlertMessage(
985 "Selected engine unavailable. "+
986 "Running script on "+
987 ScriptEngineName,
988 false);
989 }
990 }
991 }
992 }
993 }
994 }
995  
996 if (engine != ScriptEngineName)
997 return;
998  
999 // If we've seen this exact script text before, use that reference instead
1000 if (m_uniqueScripts.ContainsKey(script))
1001 script = m_uniqueScripts[script];
1002 else
1003 m_uniqueScripts[script] = script;
1004  
1005 Object[] parms = new Object[]{localID, itemID, script, startParam, postOnRez, (StateSource)stateSource};
1006  
1007 if (stateSource == (int)StateSource.ScriptedRez)
1008 {
1009 lock (m_CompileDict)
1010 {
1011 m_CompileDict[itemID] = 0;
1012 }
1013  
1014 DoOnRezScript(parms);
1015 }
1016 else
1017 {
1018 m_CompileQueue.Enqueue(parms);
1019 lock (m_CompileDict)
1020 {
1021 m_CompileDict[itemID] = 0;
1022 }
1023  
1024 // m_log.DebugFormat("[XEngine]: Added script {0} to compile queue", itemID);
1025  
1026 if (m_CurrentCompile == null)
1027 {
1028 // NOTE: Although we use a lockless queue, the lock here
1029 // is required. It ensures that there are never two
1030 // compile threads running, which, due to a race
1031 // conndition, might otherwise happen
1032 //
1033 lock (m_CompileQueue)
1034 {
1035 if (m_CurrentCompile == null)
1036 m_CurrentCompile = m_ThreadPool.QueueWorkItem(DoOnRezScriptQueue, null);
1037 }
1038 }
1039 }
1040 }
1041  
1042 public Object DoOnRezScriptQueue(Object dummy)
1043 {
1044 if (m_InitialStartup)
1045 {
1046 // This delay exists to stop mono problems where script compilation and startup would stop the sim
1047 // working properly for the session.
1048 System.Threading.Thread.Sleep(m_StartDelay);
1049  
1050 m_log.InfoFormat("[XEngine]: Performing initial script startup on {0}", m_Scene.Name);
1051 }
1052  
1053 object[] o;
1054  
1055 int scriptsStarted = 0;
1056  
1057 while (m_CompileQueue.Dequeue(out o))
1058 {
1059 if (DoOnRezScript(o))
1060 {
1061 scriptsStarted++;
1062  
1063 if (m_InitialStartup)
1064 if (scriptsStarted % 50 == 0)
1065 m_log.InfoFormat(
1066 "[XEngine]: Started {0} scripts in {1}", scriptsStarted, m_Scene.Name);
1067 }
1068 }
1069  
1070 if (m_InitialStartup)
1071 m_log.InfoFormat(
1072 "[XEngine]: Completed starting {0} scripts on {1}", scriptsStarted, m_Scene.Name);
1073  
1074 // NOTE: Despite having a lockless queue, this lock is required
1075 // to make sure there is never no compile thread while there
1076 // are still scripts to compile. This could otherwise happen
1077 // due to a race condition
1078 //
1079 lock (m_CompileQueue)
1080 m_CurrentCompile = null;
1081  
1082 m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount,
1083 m_ScriptErrorMessage);
1084  
1085 m_ScriptFailCount = 0;
1086 m_InitialStartup = false;
1087  
1088 return null;
1089 }
1090  
1091 private bool DoOnRezScript(object[] parms)
1092 {
1093 Object[] p = parms;
1094 uint localID = (uint)p[0];
1095 UUID itemID = (UUID)p[1];
1096 string script =(string)p[2];
1097 int startParam = (int)p[3];
1098 bool postOnRez = (bool)p[4];
1099 StateSource stateSource = (StateSource)p[5];
1100  
1101 // m_log.DebugFormat("[XEngine]: DoOnRezScript called for script {0}", itemID);
1102  
1103 lock (m_CompileDict)
1104 {
1105 if (!m_CompileDict.ContainsKey(itemID))
1106 return false;
1107 m_CompileDict.Remove(itemID);
1108 }
1109  
1110 // Get the asset ID of the script, so we can check if we
1111 // already have it.
1112  
1113 // We must look for the part outside the m_Scripts lock because GetSceneObjectPart later triggers the
1114 // m_parts lock on SOG. At the same time, a scene object that is being deleted will take the m_parts lock
1115 // and then later on try to take the m_scripts lock in this class when it calls OnRemoveScript()
1116 SceneObjectPart part = m_Scene.GetSceneObjectPart(localID);
1117 if (part == null)
1118 {
1119 m_log.ErrorFormat("[Script]: SceneObjectPart with localID {0} unavailable. Script NOT started.", localID);
1120 m_ScriptErrorMessage += "SceneObjectPart unavailable. Script NOT started.\n";
1121 m_ScriptFailCount++;
1122 return false;
1123 }
1124  
1125 TaskInventoryItem item = part.Inventory.GetInventoryItem(itemID);
1126 if (item == null)
1127 {
1128 m_ScriptErrorMessage += "Can't find script inventory item.\n";
1129 m_ScriptFailCount++;
1130 return false;
1131 }
1132  
1133 m_log.DebugFormat(
1134 "[XEngine]: Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}",
1135 part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID,
1136 part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName);
1137  
1138 UUID assetID = item.AssetID;
1139  
1140 ScenePresence presence = m_Scene.GetScenePresence(item.OwnerID);
1141  
1142 string assembly = "";
1143  
1144 Culture.SetCurrentCulture();
1145  
1146 Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap;
1147  
1148 lock (m_ScriptErrors)
1149 {
1150 try
1151 {
1152 lock (m_AddingAssemblies)
1153 {
1154 m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assembly, out linemap);
1155  
1156 if (!m_AddingAssemblies.ContainsKey(assembly)) {
1157 m_AddingAssemblies[assembly] = 1;
1158 } else {
1159 m_AddingAssemblies[assembly]++;
1160 }
1161 }
1162  
1163 string[] warnings = m_Compiler.GetWarnings();
1164  
1165 if (warnings != null && warnings.Length != 0)
1166 {
1167 foreach (string warning in warnings)
1168 {
1169 if (!m_ScriptErrors.ContainsKey(itemID))
1170 m_ScriptErrors[itemID] = new ArrayList();
1171  
1172 m_ScriptErrors[itemID].Add(warning);
1173 // try
1174 // {
1175 // // DISPLAY WARNING INWORLD
1176 // string text = "Warning:\n" + warning;
1177 // if (text.Length > 1000)
1178 // text = text.Substring(0, 1000);
1179 // if (!ShowScriptSaveResponse(item.OwnerID,
1180 // assetID, text, true))
1181 // {
1182 // if (presence != null && (!postOnRez))
1183 // presence.ControllingClient.SendAgentAlertMessage("Script saved with warnings, check debug window!", false);
1184 //
1185 // World.SimChat(Utils.StringToBytes(text),
1186 // ChatTypeEnum.DebugChannel, 2147483647,
1187 // part.AbsolutePosition,
1188 // part.Name, part.UUID, false);
1189 // }
1190 // }
1191 // catch (Exception e2) // LEGIT: User Scripting
1192 // {
1193 // m_log.Error("[XEngine]: " +
1194 // "Error displaying warning in-world: " +
1195 // e2.ToString());
1196 // m_log.Error("[XEngine]: " +
1197 // "Warning:\r\n" +
1198 // warning);
1199 // }
1200 }
1201 }
1202 }
1203 catch (Exception e)
1204 {
1205 // m_log.ErrorFormat(
1206 // "[XEngine]: Exception when rezzing script with item ID {0}, {1}{2}",
1207 // itemID, e.Message, e.StackTrace);
1208  
1209 // try
1210 // {
1211 if (!m_ScriptErrors.ContainsKey(itemID))
1212 m_ScriptErrors[itemID] = new ArrayList();
1213 // DISPLAY ERROR INWORLD
1214 // m_ScriptErrorMessage += "Failed to compile script in object: '" + part.ParentGroup.RootPart.Name + "' Script name: '" + item.Name + "' Error message: " + e.Message.ToString();
1215 //
1216 m_ScriptFailCount++;
1217 m_ScriptErrors[itemID].Add(e.Message.ToString());
1218 // string text = "Error compiling script '" + item.Name + "':\n" + e.Message.ToString();
1219 // if (text.Length > 1000)
1220 // text = text.Substring(0, 1000);
1221 // if (!ShowScriptSaveResponse(item.OwnerID,
1222 // assetID, text, false))
1223 // {
1224 // if (presence != null && (!postOnRez))
1225 // presence.ControllingClient.SendAgentAlertMessage("Script saved with errors, check debug window!", false);
1226 // World.SimChat(Utils.StringToBytes(text),
1227 // ChatTypeEnum.DebugChannel, 2147483647,
1228 // part.AbsolutePosition,
1229 // part.Name, part.UUID, false);
1230 // }
1231 // }
1232 // catch (Exception e2) // LEGIT: User Scripting
1233 // {
1234 // m_log.Error("[XEngine]: "+
1235 // "Error displaying error in-world: " +
1236 // e2.ToString());
1237 // m_log.Error("[XEngine]: " +
1238 // "Errormessage: Error compiling script:\r\n" +
1239 // e.Message.ToString());
1240 // }
1241  
1242 return false;
1243 }
1244 }
1245  
1246 ScriptInstance instance = null;
1247 lock (m_Scripts)
1248 {
1249 // Create the object record
1250 if ((!m_Scripts.ContainsKey(itemID)) ||
1251 (m_Scripts[itemID].AssetID != assetID))
1252 {
1253 UUID appDomain = assetID;
1254  
1255 if (part.ParentGroup.IsAttachment)
1256 appDomain = part.ParentGroup.RootPart.UUID;
1257  
1258 if (!m_AppDomains.ContainsKey(appDomain))
1259 {
1260 try
1261 {
1262 AppDomainSetup appSetup = new AppDomainSetup();
1263 appSetup.PrivateBinPath = Path.Combine(
1264 m_ScriptEnginesPath,
1265 m_Scene.RegionInfo.RegionID.ToString());
1266  
1267 Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
1268 Evidence evidence = new Evidence(baseEvidence);
1269  
1270 AppDomain sandbox;
1271 if (m_AppDomainLoading)
1272 {
1273 sandbox = AppDomain.CreateDomain(
1274 m_Scene.RegionInfo.RegionID.ToString(),
1275 evidence, appSetup);
1276 sandbox.AssemblyResolve +=
1277 new ResolveEventHandler(
1278 AssemblyResolver.OnAssemblyResolve);
1279 }
1280 else
1281 {
1282 sandbox = AppDomain.CurrentDomain;
1283 }
1284  
1285 //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel();
1286 //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition();
1287 //PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet");
1288 //PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet);
1289 //CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement);
1290 //sandboxPolicy.RootCodeGroup = sandboxCodeGroup;
1291 //sandbox.SetAppDomainPolicy(sandboxPolicy);
1292  
1293 m_AppDomains[appDomain] = sandbox;
1294  
1295 m_DomainScripts[appDomain] = new List<UUID>();
1296 }
1297 catch (Exception e)
1298 {
1299 m_log.ErrorFormat("[XEngine] Exception creating app domain:\n {0}", e.ToString());
1300 m_ScriptErrorMessage += "Exception creating app domain:\n";
1301 m_ScriptFailCount++;
1302 lock (m_AddingAssemblies)
1303 {
1304 m_AddingAssemblies[assembly]--;
1305 }
1306 return false;
1307 }
1308 }
1309 m_DomainScripts[appDomain].Add(itemID);
1310  
1311 instance = new ScriptInstance(this, part,
1312 item,
1313 startParam, postOnRez,
1314 m_MaxScriptQueue);
1315  
1316 if (!instance.Load(m_AppDomains[appDomain], assembly, stateSource))
1317 return false;
1318  
1319 // if (DebugLevel >= 1)
1320 // m_log.DebugFormat(
1321 // "[XEngine] Loaded script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}",
1322 // part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID,
1323 // part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName);
1324  
1325 if (presence != null)
1326 {
1327 ShowScriptSaveResponse(item.OwnerID,
1328 assetID, "Compile successful", true);
1329 }
1330  
1331 instance.AppDomain = appDomain;
1332 instance.LineMap = linemap;
1333  
1334 m_Scripts[itemID] = instance;
1335 }
1336 }
1337  
1338 lock (m_PrimObjects)
1339 {
1340 if (!m_PrimObjects.ContainsKey(localID))
1341 m_PrimObjects[localID] = new List<UUID>();
1342  
1343 if (!m_PrimObjects[localID].Contains(itemID))
1344 m_PrimObjects[localID].Add(itemID);
1345 }
1346  
1347 if (!m_Assemblies.ContainsKey(assetID))
1348 m_Assemblies[assetID] = assembly;
1349  
1350 lock (m_AddingAssemblies)
1351 {
1352 m_AddingAssemblies[assembly]--;
1353 }
1354  
1355 if (instance != null)
1356 instance.Init();
1357  
1358 bool runIt;
1359 if (m_runFlags.TryGetValue(itemID, out runIt))
1360 {
1361 if (!runIt)
1362 StopScript(itemID);
1363 m_runFlags.Remove(itemID);
1364 }
1365  
1366 return true;
1367 }
1368  
1369 public void OnRemoveScript(uint localID, UUID itemID)
1370 {
1371 // If it's not yet been compiled, make sure we don't try
1372 lock (m_CompileDict)
1373 {
1374 if (m_CompileDict.ContainsKey(itemID))
1375 m_CompileDict.Remove(itemID);
1376 }
1377  
1378 IScriptInstance instance = null;
1379  
1380 lock (m_Scripts)
1381 {
1382 // Do we even have it?
1383 if (!m_Scripts.ContainsKey(itemID))
1384 return;
1385  
1386 instance = m_Scripts[itemID];
1387 m_Scripts.Remove(itemID);
1388 }
1389  
1390 instance.ClearQueue();
1391  
1392 instance.Stop(m_WaitForEventCompletionOnScriptStop);
1393  
1394 // bool objectRemoved = false;
1395  
1396 lock (m_PrimObjects)
1397 {
1398 // Remove the script from it's prim
1399 if (m_PrimObjects.ContainsKey(localID))
1400 {
1401 // Remove inventory item record
1402 if (m_PrimObjects[localID].Contains(itemID))
1403 m_PrimObjects[localID].Remove(itemID);
1404  
1405 // If there are no more scripts, remove prim
1406 if (m_PrimObjects[localID].Count == 0)
1407 {
1408 m_PrimObjects.Remove(localID);
1409 // objectRemoved = true;
1410 }
1411 }
1412 }
1413  
1414 instance.RemoveState();
1415 instance.DestroyScriptInstance();
1416  
1417 m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
1418 if (m_DomainScripts[instance.AppDomain].Count == 0)
1419 {
1420 m_DomainScripts.Remove(instance.AppDomain);
1421 UnloadAppDomain(instance.AppDomain);
1422 }
1423  
1424 ObjectRemoved handlerObjectRemoved = OnObjectRemoved;
1425 if (handlerObjectRemoved != null)
1426 handlerObjectRemoved(instance.ObjectID);
1427  
1428 ScriptRemoved handlerScriptRemoved = OnScriptRemoved;
1429 if (handlerScriptRemoved != null)
1430 handlerScriptRemoved(itemID);
1431 }
1432  
1433 public void OnScriptReset(uint localID, UUID itemID)
1434 {
1435 ResetScript(itemID);
1436 }
1437  
1438 public void OnStartScript(uint localID, UUID itemID)
1439 {
1440 StartScript(itemID);
1441 }
1442  
1443 public void OnStopScript(uint localID, UUID itemID)
1444 {
1445 StopScript(itemID);
1446 }
1447  
1448 private void CleanAssemblies()
1449 {
1450 List<UUID> assetIDList = new List<UUID>(m_Assemblies.Keys);
1451  
1452 foreach (IScriptInstance i in m_Scripts.Values)
1453 {
1454 if (assetIDList.Contains(i.AssetID))
1455 assetIDList.Remove(i.AssetID);
1456 }
1457  
1458 lock (m_AddingAssemblies)
1459 {
1460 foreach (UUID assetID in assetIDList)
1461 {
1462 // Do not remove assembly files if another instance of the script
1463 // is currently initialising
1464 if (!m_AddingAssemblies.ContainsKey(m_Assemblies[assetID])
1465 || m_AddingAssemblies[m_Assemblies[assetID]] == 0)
1466 {
1467 // m_log.DebugFormat("[XEngine] Removing unreferenced assembly {0}", m_Assemblies[assetID]);
1468 try
1469 {
1470 if (File.Exists(m_Assemblies[assetID]))
1471 File.Delete(m_Assemblies[assetID]);
1472  
1473 if (File.Exists(m_Assemblies[assetID]+".text"))
1474 File.Delete(m_Assemblies[assetID]+".text");
1475  
1476 if (File.Exists(m_Assemblies[assetID]+".mdb"))
1477 File.Delete(m_Assemblies[assetID]+".mdb");
1478  
1479 if (File.Exists(m_Assemblies[assetID]+".map"))
1480 File.Delete(m_Assemblies[assetID]+".map");
1481 }
1482 catch (Exception)
1483 {
1484 }
1485 m_Assemblies.Remove(assetID);
1486 }
1487 }
1488 }
1489 }
1490  
1491 private void UnloadAppDomain(UUID id)
1492 {
1493 if (m_AppDomains.ContainsKey(id))
1494 {
1495 AppDomain domain = m_AppDomains[id];
1496 m_AppDomains.Remove(id);
1497  
1498 if (domain != AppDomain.CurrentDomain)
1499 AppDomain.Unload(domain);
1500 domain = null;
1501 // m_log.DebugFormat("[XEngine] Unloaded app domain {0}", id.ToString());
1502 }
1503 }
1504  
1505 //
1506 // Start processing
1507 //
1508 private void SetupEngine(int minThreads, int maxThreads,
1509 int idleTimeout, ThreadPriority threadPriority,
1510 int maxScriptQueue, int stackSize)
1511 {
1512 m_MaxScriptQueue = maxScriptQueue;
1513  
1514 STPStartInfo startInfo = new STPStartInfo();
1515 startInfo.ThreadPoolName = "XEngine";
1516 startInfo.IdleTimeout = idleTimeout * 1000; // convert to seconds as stated in .ini
1517 startInfo.MaxWorkerThreads = maxThreads;
1518 startInfo.MinWorkerThreads = minThreads;
1519 startInfo.ThreadPriority = threadPriority;;
1520 startInfo.MaxStackSize = stackSize;
1521 startInfo.StartSuspended = true;
1522  
1523 m_ThreadPool = new SmartThreadPool(startInfo);
1524 }
1525  
1526 //
1527 // Used by script instances to queue event handler jobs
1528 //
1529 public IScriptWorkItem QueueEventHandler(object parms)
1530 {
1531 return new XWorkItem(m_ThreadPool.QueueWorkItem(
1532 new WorkItemCallback(this.ProcessEventHandler),
1533 parms));
1534 }
1535  
1536 /// <summary>
1537 /// Process a previously posted script event.
1538 /// </summary>
1539 /// <param name="parms"></param>
1540 /// <returns></returns>
1541 private object ProcessEventHandler(object parms)
1542 {
1543 Culture.SetCurrentCulture();
1544  
1545 IScriptInstance instance = (ScriptInstance) parms;
1546  
1547 //m_log.DebugFormat("[XEngine]: Processing event for {0}", instance);
1548  
1549 return instance.EventProcessor();
1550 }
1551  
1552 /// <summary>
1553 /// Post event to an entire prim
1554 /// </summary>
1555 /// <param name="localID"></param>
1556 /// <param name="p"></param>
1557 /// <returns></returns>
1558 public bool PostObjectEvent(uint localID, EventParams p)
1559 {
1560 bool result = false;
1561 List<UUID> uuids = null;
1562  
1563 lock (m_PrimObjects)
1564 {
1565 if (!m_PrimObjects.ContainsKey(localID))
1566 return false;
1567  
1568 uuids = m_PrimObjects[localID];
1569  
1570 foreach (UUID itemID in uuids)
1571 {
1572 IScriptInstance instance = null;
1573 try
1574 {
1575 if (m_Scripts.ContainsKey(itemID))
1576 instance = m_Scripts[itemID];
1577 }
1578 catch { /* ignore race conditions */ }
1579  
1580 if (instance != null)
1581 {
1582 instance.PostEvent(p);
1583 result = true;
1584 }
1585 }
1586 }
1587  
1588 return result;
1589 }
1590  
1591 /// <summary>
1592 /// Post an event to a single script
1593 /// </summary>
1594 /// <param name="itemID"></param>
1595 /// <param name="p"></param>
1596 /// <returns></returns>
1597 public bool PostScriptEvent(UUID itemID, EventParams p)
1598 {
1599 if (m_Scripts.ContainsKey(itemID))
1600 {
1601 IScriptInstance instance = m_Scripts[itemID];
1602 if (instance != null)
1603 instance.PostEvent(p);
1604 return true;
1605 }
1606 return false;
1607 }
1608  
1609 public bool PostScriptEvent(UUID itemID, string name, Object[] p)
1610 {
1611 Object[] lsl_p = new Object[p.Length];
1612 for (int i = 0; i < p.Length ; i++)
1613 {
1614 if (p[i] is int)
1615 lsl_p[i] = new LSL_Types.LSLInteger((int)p[i]);
1616 else if (p[i] is string)
1617 lsl_p[i] = new LSL_Types.LSLString((string)p[i]);
1618 else if (p[i] is Vector3)
1619 lsl_p[i] = new LSL_Types.Vector3((Vector3)p[i]);
1620 else if (p[i] is Quaternion)
1621 lsl_p[i] = new LSL_Types.Quaternion((Quaternion)p[i]);
1622 else if (p[i] is float)
1623 lsl_p[i] = new LSL_Types.LSLFloat((float)p[i]);
1624 else
1625 lsl_p[i] = p[i];
1626 }
1627  
1628 return PostScriptEvent(itemID, new EventParams(name, lsl_p, new DetectParams[0]));
1629 }
1630  
1631 public bool PostObjectEvent(UUID itemID, string name, Object[] p)
1632 {
1633 SceneObjectPart part = m_Scene.GetSceneObjectPart(itemID);
1634 if (part == null)
1635 return false;
1636  
1637 Object[] lsl_p = new Object[p.Length];
1638 for (int i = 0; i < p.Length ; i++)
1639 {
1640 if (p[i] is int)
1641 lsl_p[i] = new LSL_Types.LSLInteger((int)p[i]);
1642 else if (p[i] is string)
1643 lsl_p[i] = new LSL_Types.LSLString((string)p[i]);
1644 else if (p[i] is Vector3)
1645 lsl_p[i] = new LSL_Types.Vector3((Vector3)p[i]);
1646 else if (p[i] is Quaternion)
1647 lsl_p[i] = new LSL_Types.Quaternion((Quaternion)p[i]);
1648 else if (p[i] is float)
1649 lsl_p[i] = new LSL_Types.LSLFloat((float)p[i]);
1650 else
1651 lsl_p[i] = p[i];
1652 }
1653  
1654 return PostObjectEvent(part.LocalId, new EventParams(name, lsl_p, new DetectParams[0]));
1655 }
1656  
1657 public Assembly OnAssemblyResolve(object sender,
1658 ResolveEventArgs args)
1659 {
1660 if (!(sender is System.AppDomain))
1661 return null;
1662  
1663 string[] pathList = new string[] {"bin", m_ScriptEnginesPath,
1664 Path.Combine(m_ScriptEnginesPath,
1665 m_Scene.RegionInfo.RegionID.ToString())};
1666  
1667 string assemblyName = args.Name;
1668 if (assemblyName.IndexOf(",") != -1)
1669 assemblyName = args.Name.Substring(0, args.Name.IndexOf(","));
1670  
1671 foreach (string s in pathList)
1672 {
1673 string path = Path.Combine(Directory.GetCurrentDirectory(),
1674 Path.Combine(s, assemblyName))+".dll";
1675  
1676 // Console.WriteLine("[XEngine]: Trying to resolve {0}", path);
1677  
1678 if (File.Exists(path))
1679 return Assembly.LoadFrom(path);
1680 }
1681  
1682 return null;
1683 }
1684  
1685 private IScriptInstance GetInstance(UUID itemID)
1686 {
1687 IScriptInstance instance;
1688 lock (m_Scripts)
1689 {
1690 if (!m_Scripts.ContainsKey(itemID))
1691 return null;
1692 instance = m_Scripts[itemID];
1693 }
1694 return instance;
1695 }
1696  
1697 public void SetScriptState(UUID itemID, bool running)
1698 {
1699 IScriptInstance instance = GetInstance(itemID);
1700 if (instance != null)
1701 {
1702 if (running)
1703 instance.Start();
1704 else
1705 instance.Stop(100);
1706 }
1707 }
1708  
1709 public bool GetScriptState(UUID itemID)
1710 {
1711 IScriptInstance instance = GetInstance(itemID);
1712 return instance != null && instance.Running;
1713 }
1714  
1715 public void ApiResetScript(UUID itemID)
1716 {
1717 IScriptInstance instance = GetInstance(itemID);
1718 if (instance != null)
1719 instance.ApiResetScript();
1720 }
1721  
1722 public void ResetScript(UUID itemID)
1723 {
1724 IScriptInstance instance = GetInstance(itemID);
1725 if (instance != null)
1726 instance.ResetScript(m_WaitForEventCompletionOnScriptStop);
1727 }
1728  
1729 public void StartScript(UUID itemID)
1730 {
1731 IScriptInstance instance = GetInstance(itemID);
1732 if (instance != null)
1733 instance.Start();
1734 else
1735 m_runFlags.AddOrUpdate(itemID, true, 240);
1736 }
1737  
1738 public void StopScript(UUID itemID)
1739 {
1740 IScriptInstance instance = GetInstance(itemID);
1741  
1742 if (instance != null)
1743 {
1744 instance.Stop(m_WaitForEventCompletionOnScriptStop);
1745 }
1746 else
1747 {
1748 // m_log.DebugFormat("[XENGINE]: Could not find script with ID {0} to stop in {1}", itemID, World.Name);
1749 m_runFlags.AddOrUpdate(itemID, false, 240);
1750 }
1751 }
1752  
1753 public DetectParams GetDetectParams(UUID itemID, int idx)
1754 {
1755 IScriptInstance instance = GetInstance(itemID);
1756 return instance != null ? instance.GetDetectParams(idx) : null;
1757 }
1758  
1759 public void SetMinEventDelay(UUID itemID, double delay)
1760 {
1761 IScriptInstance instance = GetInstance(itemID);
1762 if (instance != null)
1763 instance.MinEventDelay = delay;
1764 }
1765  
1766 public UUID GetDetectID(UUID itemID, int idx)
1767 {
1768 IScriptInstance instance = GetInstance(itemID);
1769 return instance != null ? instance.GetDetectID(idx) : UUID.Zero;
1770 }
1771  
1772 public void SetState(UUID itemID, string newState)
1773 {
1774 IScriptInstance instance = GetInstance(itemID);
1775 if (instance == null)
1776 return;
1777 instance.SetState(newState);
1778 }
1779  
1780 public int GetStartParameter(UUID itemID)
1781 {
1782 IScriptInstance instance = GetInstance(itemID);
1783 return instance == null ? 0 : instance.StartParam;
1784 }
1785  
1786 public void OnShutdown()
1787 {
1788 m_SimulatorShuttingDown = true;
1789  
1790 List<IScriptInstance> instances = new List<IScriptInstance>();
1791  
1792 lock (m_Scripts)
1793 {
1794 foreach (IScriptInstance instance in m_Scripts.Values)
1795 instances.Add(instance);
1796 }
1797  
1798 foreach (IScriptInstance i in instances)
1799 {
1800 // Stop the script, even forcibly if needed. Then flag
1801 // it as shutting down and restore the previous run state
1802 // for serialization, so the scripts don't come back
1803 // dead after region restart
1804 //
1805 bool prevRunning = i.Running;
1806 i.Stop(50);
1807 i.ShuttingDown = true;
1808 i.Running = prevRunning;
1809 }
1810  
1811 DoBackup(new Object[] {0});
1812 }
1813  
1814 public IScriptApi GetApi(UUID itemID, string name)
1815 {
1816 IScriptInstance instance = GetInstance(itemID);
1817 return instance == null ? null : instance.GetApi(name);
1818 }
1819  
1820 public void OnGetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID)
1821 {
1822 IScriptInstance instance = GetInstance(itemID);
1823 if (instance == null)
1824 return;
1825 IEventQueue eq = World.RequestModuleInterface<IEventQueue>();
1826 if (eq == null)
1827 {
1828 controllingClient.SendScriptRunningReply(objectID, itemID,
1829 GetScriptState(itemID));
1830 }
1831 else
1832 {
1833 eq.Enqueue(eq.ScriptRunningEvent(objectID, itemID, GetScriptState(itemID), true),
1834 controllingClient.AgentId);
1835 }
1836 }
1837  
1838 public string GetXMLState(UUID itemID)
1839 {
1840 // m_log.DebugFormat("[XEngine]: Getting XML state for script instance {0}", itemID);
1841  
1842 IScriptInstance instance = GetInstance(itemID);
1843 if (instance == null)
1844 {
1845 // m_log.DebugFormat("[XEngine]: Found no script instance for {0}, returning empty string", itemID);
1846 return "";
1847 }
1848  
1849 string xml = instance.GetXMLState();
1850  
1851 XmlDocument sdoc = new XmlDocument();
1852 bool loadedState = true;
1853 try
1854 {
1855 sdoc.LoadXml(xml);
1856 }
1857 catch (System.Xml.XmlException)
1858 {
1859 loadedState = false;
1860 }
1861  
1862 XmlNodeList rootL = null;
1863 XmlNode rootNode = null;
1864 if (loadedState)
1865 {
1866 rootL = sdoc.GetElementsByTagName("ScriptState");
1867 rootNode = rootL[0];
1868 }
1869  
1870 // Create <State UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx">
1871 XmlDocument doc = new XmlDocument();
1872 XmlElement stateData = doc.CreateElement("", "State", "");
1873 XmlAttribute stateID = doc.CreateAttribute("", "UUID", "");
1874 stateID.Value = itemID.ToString();
1875 stateData.Attributes.Append(stateID);
1876 XmlAttribute assetID = doc.CreateAttribute("", "Asset", "");
1877 assetID.Value = instance.AssetID.ToString();
1878 stateData.Attributes.Append(assetID);
1879 XmlAttribute engineName = doc.CreateAttribute("", "Engine", "");
1880 engineName.Value = ScriptEngineName;
1881 stateData.Attributes.Append(engineName);
1882 doc.AppendChild(stateData);
1883  
1884 XmlNode xmlstate = null;
1885  
1886 // Add <ScriptState>...</ScriptState>
1887 if (loadedState)
1888 {
1889 xmlstate = doc.ImportNode(rootNode, true);
1890 }
1891 else
1892 {
1893 xmlstate = doc.CreateElement("", "ScriptState", "");
1894 }
1895  
1896 stateData.AppendChild(xmlstate);
1897  
1898 string assemName = instance.GetAssemblyName();
1899  
1900 string fn = Path.GetFileName(assemName);
1901  
1902 string assem = String.Empty;
1903  
1904 if (File.Exists(assemName + ".text"))
1905 {
1906 FileInfo tfi = new FileInfo(assemName + ".text");
1907  
1908 if (tfi != null)
1909 {
1910 Byte[] tdata = new Byte[tfi.Length];
1911  
1912 try
1913 {
1914 using (FileStream tfs = File.Open(assemName + ".text",
1915 FileMode.Open, FileAccess.Read))
1916 {
1917 tfs.Read(tdata, 0, tdata.Length);
1918 }
1919  
1920 assem = Encoding.ASCII.GetString(tdata);
1921 }
1922 catch (Exception e)
1923 {
1924 m_log.ErrorFormat(
1925 "[XEngine]: Unable to open script textfile {0}{1}, reason: {2}",
1926 assemName, ".text", e.Message);
1927 }
1928 }
1929 }
1930 else
1931 {
1932 FileInfo fi = new FileInfo(assemName);
1933  
1934 if (fi != null)
1935 {
1936 Byte[] data = new Byte[fi.Length];
1937  
1938 try
1939 {
1940 using (FileStream fs = File.Open(assemName, FileMode.Open, FileAccess.Read))
1941 {
1942 fs.Read(data, 0, data.Length);
1943 }
1944  
1945 assem = System.Convert.ToBase64String(data);
1946 }
1947 catch (Exception e)
1948 {
1949 m_log.ErrorFormat(
1950 "[XEngine]: Unable to open script assembly {0}, reason: {1}", assemName, e.Message);
1951 }
1952 }
1953 }
1954  
1955 string map = String.Empty;
1956  
1957 if (File.Exists(fn + ".map"))
1958 {
1959 using (FileStream mfs = File.Open(fn + ".map", FileMode.Open, FileAccess.Read))
1960 {
1961 using (StreamReader msr = new StreamReader(mfs))
1962 {
1963 map = msr.ReadToEnd();
1964 }
1965 }
1966 }
1967  
1968 XmlElement assemblyData = doc.CreateElement("", "Assembly", "");
1969 XmlAttribute assemblyName = doc.CreateAttribute("", "Filename", "");
1970  
1971 assemblyName.Value = fn;
1972 assemblyData.Attributes.Append(assemblyName);
1973  
1974 assemblyData.InnerText = assem;
1975  
1976 stateData.AppendChild(assemblyData);
1977  
1978 XmlElement mapData = doc.CreateElement("", "LineMap", "");
1979 XmlAttribute mapName = doc.CreateAttribute("", "Filename", "");
1980  
1981 mapName.Value = fn + ".map";
1982 mapData.Attributes.Append(mapName);
1983  
1984 mapData.InnerText = map;
1985  
1986 stateData.AppendChild(mapData);
1987  
1988 // m_log.DebugFormat("[XEngine]: Got XML state for {0}", itemID);
1989  
1990 return doc.InnerXml;
1991 }
1992  
1993 private bool ShowScriptSaveResponse(UUID ownerID, UUID assetID, string text, bool compiled)
1994 {
1995 return false;
1996 }
1997  
1998 public bool SetXMLState(UUID itemID, string xml)
1999 {
2000 // m_log.DebugFormat("[XEngine]: Writing state for script item with ID {0}", itemID);
2001  
2002 if (xml == String.Empty)
2003 return false;
2004  
2005 XmlDocument doc = new XmlDocument();
2006  
2007 try
2008 {
2009 doc.LoadXml(xml);
2010 }
2011 catch (Exception)
2012 {
2013 m_log.Error("[XEngine]: Exception decoding XML data from region transfer");
2014 return false;
2015 }
2016  
2017 XmlNodeList rootL = doc.GetElementsByTagName("State");
2018 if (rootL.Count < 1)
2019 return false;
2020  
2021 XmlElement rootE = (XmlElement)rootL[0];
2022  
2023 if (rootE.GetAttribute("Engine") != ScriptEngineName)
2024 return false;
2025  
2026 // On rez from inventory, that ID will have changed. It was only
2027 // advisory anyway. So we don't check it anymore.
2028 //
2029 // if (rootE.GetAttribute("UUID") != itemID.ToString())
2030 // return;
2031  
2032 XmlNodeList stateL = rootE.GetElementsByTagName("ScriptState");
2033  
2034 if (stateL.Count != 1)
2035 return false;
2036  
2037 XmlElement stateE = (XmlElement)stateL[0];
2038  
2039 if (World.m_trustBinaries)
2040 {
2041 XmlNodeList assemL = rootE.GetElementsByTagName("Assembly");
2042  
2043 if (assemL.Count != 1)
2044 return false;
2045  
2046 XmlElement assemE = (XmlElement)assemL[0];
2047  
2048 string fn = assemE.GetAttribute("Filename");
2049 string base64 = assemE.InnerText;
2050  
2051 string path = Path.Combine(m_ScriptEnginesPath, World.RegionInfo.RegionID.ToString());
2052 path = Path.Combine(path, fn);
2053  
2054 if (!File.Exists(path))
2055 {
2056 Byte[] filedata = Convert.FromBase64String(base64);
2057  
2058 try
2059 {
2060 using (FileStream fs = File.Create(path))
2061 {
2062 // m_log.DebugFormat("[XEngine]: Writing assembly file {0}", path);
2063  
2064 fs.Write(filedata, 0, filedata.Length);
2065 }
2066 }
2067 catch (IOException ex)
2068 {
2069 // if there already exists a file at that location, it may be locked.
2070 m_log.ErrorFormat("[XEngine]: Error whilst writing assembly file {0}, {1}", path, ex.Message);
2071 }
2072  
2073 string textpath = path + ".text";
2074 try
2075 {
2076 using (FileStream fs = File.Create(textpath))
2077 {
2078 using (StreamWriter sw = new StreamWriter(fs))
2079 {
2080 // m_log.DebugFormat("[XEngine]: Writing .text file {0}", textpath);
2081  
2082 sw.Write(base64);
2083 }
2084 }
2085 }
2086 catch (IOException ex)
2087 {
2088 // if there already exists a file at that location, it may be locked.
2089 m_log.ErrorFormat("[XEngine]: Error whilst writing .text file {0}, {1}", textpath, ex.Message);
2090 }
2091 }
2092  
2093 XmlNodeList mapL = rootE.GetElementsByTagName("LineMap");
2094 if (mapL.Count > 0)
2095 {
2096 XmlElement mapE = (XmlElement)mapL[0];
2097  
2098 string mappath = Path.Combine(m_ScriptEnginesPath, World.RegionInfo.RegionID.ToString());
2099 mappath = Path.Combine(mappath, mapE.GetAttribute("Filename"));
2100  
2101 try
2102 {
2103 using (FileStream mfs = File.Create(mappath))
2104 {
2105 using (StreamWriter msw = new StreamWriter(mfs))
2106 {
2107 // m_log.DebugFormat("[XEngine]: Writing linemap file {0}", mappath);
2108  
2109 msw.Write(mapE.InnerText);
2110 }
2111 }
2112 }
2113 catch (IOException ex)
2114 {
2115 // if there already exists a file at that location, it may be locked.
2116 m_log.ErrorFormat("[XEngine]: Linemap file {0} already exists! {1}", mappath, ex.Message);
2117 }
2118 }
2119 }
2120  
2121 string statepath = Path.Combine(m_ScriptEnginesPath, World.RegionInfo.RegionID.ToString());
2122 statepath = Path.Combine(statepath, itemID.ToString() + ".state");
2123  
2124 try
2125 {
2126 using (FileStream sfs = File.Create(statepath))
2127 {
2128 using (StreamWriter ssw = new StreamWriter(sfs))
2129 {
2130 // m_log.DebugFormat("[XEngine]: Writing state file {0}", statepath);
2131  
2132 ssw.Write(stateE.OuterXml);
2133 }
2134 }
2135 }
2136 catch (IOException ex)
2137 {
2138 // if there already exists a file at that location, it may be locked.
2139 m_log.ErrorFormat("[XEngine]: Error whilst writing state file {0}, {1}", statepath, ex.Message);
2140 }
2141  
2142 return true;
2143 }
2144  
2145 public ArrayList GetScriptErrors(UUID itemID)
2146 {
2147 System.Threading.Thread.Sleep(1000);
2148  
2149 lock (m_ScriptErrors)
2150 {
2151 if (m_ScriptErrors.ContainsKey(itemID))
2152 {
2153 ArrayList ret = m_ScriptErrors[itemID];
2154 m_ScriptErrors.Remove(itemID);
2155 return ret;
2156 }
2157 return new ArrayList();
2158 }
2159 }
2160  
2161 public Dictionary<uint, float> GetObjectScriptsExecutionTimes()
2162 {
2163 long tickNow = Util.EnvironmentTickCount();
2164 Dictionary<uint, float> topScripts = new Dictionary<uint, float>();
2165  
2166 lock (m_Scripts)
2167 {
2168 foreach (IScriptInstance si in m_Scripts.Values)
2169 {
2170 if (!topScripts.ContainsKey(si.LocalID))
2171 topScripts[si.RootLocalID] = 0;
2172  
2173 topScripts[si.RootLocalID] += CalculateAdjustedExectionTime(si, tickNow);
2174 }
2175 }
2176  
2177 return topScripts;
2178 }
2179  
2180 public float GetScriptExecutionTime(List<UUID> itemIDs)
2181 {
2182 if (itemIDs == null|| itemIDs.Count == 0)
2183 {
2184 return 0.0f;
2185 }
2186 float time = 0.0f;
2187 long tickNow = Util.EnvironmentTickCount();
2188 IScriptInstance si;
2189 // Calculate the time for all scripts that this engine is executing
2190 // Ignore any others
2191 foreach (UUID id in itemIDs)
2192 {
2193 si = GetInstance(id);
2194 if (si != null && si.Running)
2195 {
2196 time += CalculateAdjustedExectionTime(si, tickNow);
2197 }
2198 }
2199 return time;
2200 }
2201  
2202 private float CalculateAdjustedExectionTime(IScriptInstance si, long tickNow)
2203 {
2204 long ticksElapsed = tickNow - si.MeasurementPeriodTickStart;
2205  
2206 // Avoid divide by zero
2207 if (ticksElapsed == 0)
2208 ticksElapsed = 1;
2209  
2210 // Scale execution time to the ideal 55 fps frame time for these reasons.
2211 //
2212 // 1) XEngine does not execute scripts per frame, unlike other script engines. Hence, there is no
2213 // 'script execution time per frame', which is the original purpose of this value.
2214 //
2215 // 2) Giving the raw execution times is misleading since scripts start at different times, making
2216 // it impossible to compare scripts.
2217 //
2218 // 3) Scaling the raw execution time to the time that the script has been running is better but
2219 // is still misleading since a script that has just been rezzed may appear to have been running
2220 // for much longer.
2221 //
2222 // 4) Hence, we scale execution time to an idealised frame time (55 fps). This is also not perfect
2223 // since the figure does not represent actual execution time and very hard running scripts will
2224 // never exceed 18ms (though this is a very high number for script execution so is a warning sign).
2225 return ((float)si.MeasurementPeriodExecutionTime / ticksElapsed) * 18.1818f;
2226 }
2227  
2228 public void SuspendScript(UUID itemID)
2229 {
2230 // m_log.DebugFormat("[XEngine]: Received request to suspend script with ID {0}", itemID);
2231  
2232 IScriptInstance instance = GetInstance(itemID);
2233 if (instance != null)
2234 instance.Suspend();
2235 // else
2236 // m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID);
2237 }
2238  
2239 public void ResumeScript(UUID itemID)
2240 {
2241 // m_log.DebugFormat("[XEngine]: Received request to resume script with ID {0}", itemID);
2242  
2243 IScriptInstance instance = GetInstance(itemID);
2244 if (instance != null)
2245 instance.Resume();
2246 // else
2247 // m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID);
2248 }
2249  
2250 public bool HasScript(UUID itemID, out bool running)
2251 {
2252 running = true;
2253  
2254 IScriptInstance instance = GetInstance(itemID);
2255 if (instance == null)
2256 return false;
2257  
2258 running = instance.Running;
2259 return true;
2260 }
2261 }
2262 }