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