/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the OpenSimulator Project nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ using System; using System.IO; using System.Xml; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api; using log4net; using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat; using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; namespace OpenSim.Region.ScriptEngine.Yengine { public partial class XMRInstance { /********************************************************************************\ * The only method of interest to outside this module is GetExecutionState() * * which captures the current state of the script into an XML document. * * * * The rest of this module contains support routines for GetExecutionState(). * \********************************************************************************/ /** * @brief Create an XML element that gives the current state of the script. * * globalsandstackdump * m_Running * * * Updates the .state file while we're at it. */ public XmlElement GetExecutionState(XmlDocument doc) { // When we're detaching an attachment, we need to wait here. // Change this to a 5 second timeout. If things do mess up, // we don't want to be stuck forever. // m_DetachReady.WaitOne(5000, false); XmlElement scriptStateN = doc.CreateElement("", "ScriptState", ""); scriptStateN.SetAttribute("Engine", m_Engine.ScriptEngineName); scriptStateN.SetAttribute("Asset", m_Item.AssetID.ToString()); scriptStateN.SetAttribute("SourceHash", m_ObjCode.sourceHash); // Make sure we aren't executing part of the script so it stays // stable. Setting suspendOnCheckRun tells CheckRun() to suspend // and return out so RunOne() will release the lock asap. suspendOnCheckRunHold = true; lock(m_RunLock) { m_RunOnePhase = "GetExecutionState enter"; CheckRunLockInvariants(true); // Get copy of script globals and stack in relocateable form. Byte[] snapshotBytes; using (MemoryStream snapshotStream = new MemoryStream()) { MigrateOutEventHandler(snapshotStream); snapshotBytes = snapshotStream.ToArray(); } string snapshotString = Convert.ToBase64String(snapshotBytes); XmlElement snapshotN = doc.CreateElement("", "Snapshot", ""); snapshotN.AppendChild(doc.CreateTextNode(snapshotString)); scriptStateN.AppendChild(snapshotN); m_RunOnePhase = "GetExecutionState B"; CheckRunLockInvariants(true); // "Running" says whether or not we are accepting new events. XmlElement runningN = doc.CreateElement("", "Running", ""); runningN.AppendChild(doc.CreateTextNode(m_Running.ToString())); scriptStateN.AppendChild(runningN); m_RunOnePhase = "GetExecutionState C"; CheckRunLockInvariants(true); // "DoGblInit" says whether or not default:state_entry() will init global vars. XmlElement doGblInitN = doc.CreateElement("", "DoGblInit", ""); doGblInitN.AppendChild(doc.CreateTextNode(doGblInit.ToString())); scriptStateN.AppendChild(doGblInitN); m_RunOnePhase = "GetExecutionState D"; CheckRunLockInvariants(true); // More misc data. XmlNode permissionsN = doc.CreateElement("", "Permissions", ""); scriptStateN.AppendChild(permissionsN); XmlAttribute granterA = doc.CreateAttribute("", "granter", ""); granterA.Value = m_Item.PermsGranter.ToString(); permissionsN.Attributes.Append(granterA); XmlAttribute maskA = doc.CreateAttribute("", "mask", ""); maskA.Value = m_Item.PermsMask.ToString(); permissionsN.Attributes.Append(maskA); m_RunOnePhase = "GetExecutionState E"; CheckRunLockInvariants(true); // "DetectParams" are returned by llDetected...() script functions // for the currently active event, if any. if(m_DetectParams != null) { XmlElement detParArrayN = doc.CreateElement("", "DetectArray", ""); AppendXMLDetectArray(doc, detParArrayN, m_DetectParams); scriptStateN.AppendChild(detParArrayN); } m_RunOnePhase = "GetExecutionState F"; CheckRunLockInvariants(true); // Save any events we have in the queue. // // // ... ... // ... ... // // ... // XmlElement queuedEventsN = doc.CreateElement("", "EventQueue", ""); lock(m_QueueLock) { foreach(EventParams evt in m_EventQueue) { XmlElement singleEventN = doc.CreateElement("", "Event", ""); singleEventN.SetAttribute("Name", evt.EventName); AppendXMLObjectArray(doc, singleEventN, evt.Params, "param"); AppendXMLDetectArray(doc, singleEventN, evt.DetectParams); queuedEventsN.AppendChild(singleEventN); } } scriptStateN.AppendChild(queuedEventsN); m_RunOnePhase = "GetExecutionState G"; CheckRunLockInvariants(true); // "Plugins" indicate enabled timers and listens, etc. Object[] pluginData = AsyncCommandManager.GetSerializationData(m_Engine, m_ItemID); XmlNode plugins = doc.CreateElement("", "Plugins", ""); AppendXMLObjectArray(doc, plugins, pluginData, "plugin"); scriptStateN.AppendChild(plugins); m_RunOnePhase = "GetExecutionState H"; CheckRunLockInvariants(true); // Let script run again. suspendOnCheckRunHold = false; m_RunOnePhase = "GetExecutionState leave"; CheckRunLockInvariants(true); } // scriptStateN represents the contents of the .state file so // write the .state file while we are here. using(FileStream fs = File.Create(m_StateFileName)) { using(StreamWriter sw = new StreamWriter(fs)) sw.Write(scriptStateN.OuterXml); } return scriptStateN; } /** * @brief Write script state to output stream. * Input: * stream = stream to write event handler state information to */ private void MigrateOutEventHandler(Stream stream) { // Write script state out, frames and all, to the stream. // Does not change script state. stream.WriteByte(migrationVersion); stream.WriteByte((byte)16); this.MigrateOut(new BinaryWriter(stream)); } /** * @brief Convert an DetectParams[] to corresponding XML. * DetectParams[] holds the values retrievable by llDetected...() for * a given event. */ private static void AppendXMLDetectArray(XmlDocument doc, XmlElement parent, DetectParams[] detect) { foreach(DetectParams d in detect) { XmlElement detectParamsN = GetXMLDetect(doc, d); parent.AppendChild(detectParamsN); } } private static XmlElement GetXMLDetect(XmlDocument doc, DetectParams d) { XmlElement detectParamsN = doc.CreateElement("", "DetectParams", ""); XmlAttribute d_key = doc.CreateAttribute("", "key", ""); d_key.Value = d.Key.ToString(); detectParamsN.Attributes.Append(d_key); XmlAttribute pos = doc.CreateAttribute("", "pos", ""); pos.Value = d.OffsetPos.ToString(); detectParamsN.Attributes.Append(pos); XmlAttribute d_linkNum = doc.CreateAttribute("", "linkNum", ""); d_linkNum.Value = d.LinkNum.ToString(); detectParamsN.Attributes.Append(d_linkNum); XmlAttribute d_group = doc.CreateAttribute("", "group", ""); d_group.Value = d.Group.ToString(); detectParamsN.Attributes.Append(d_group); XmlAttribute d_name = doc.CreateAttribute("", "name", ""); d_name.Value = d.Name.ToString(); detectParamsN.Attributes.Append(d_name); XmlAttribute d_owner = doc.CreateAttribute("", "owner", ""); d_owner.Value = d.Owner.ToString(); detectParamsN.Attributes.Append(d_owner); XmlAttribute d_position = doc.CreateAttribute("", "position", ""); d_position.Value = d.Position.ToString(); detectParamsN.Attributes.Append(d_position); XmlAttribute d_rotation = doc.CreateAttribute("", "rotation", ""); d_rotation.Value = d.Rotation.ToString(); detectParamsN.Attributes.Append(d_rotation); XmlAttribute d_type = doc.CreateAttribute("", "type", ""); d_type.Value = d.Type.ToString(); detectParamsN.Attributes.Append(d_type); XmlAttribute d_velocity = doc.CreateAttribute("", "velocity", ""); d_velocity.Value = d.Velocity.ToString(); detectParamsN.Attributes.Append(d_velocity); return detectParamsN; } /** * @brief Append elements of an array of objects to an XML parent. * @param doc = document the parent is part of * @param parent = parent to append the items to * @param array = array of objects * @param tag = ... for each element */ private static void AppendXMLObjectArray(XmlDocument doc, XmlNode parent, object[] array, string tag) { foreach(object o in array) { XmlElement element = GetXMLObject(doc, o, tag); parent.AppendChild(element); } } /** * @brief Get and XML representation of an object. * @param doc = document the tag will be put in * @param o = object to be represented * @param tag = ... */ private static XmlElement GetXMLObject(XmlDocument doc, object o, string tag) { XmlAttribute typ = doc.CreateAttribute("", "type", ""); XmlElement n = doc.CreateElement("", tag, ""); if(o is LSL_List) { typ.Value = "list"; n.Attributes.Append(typ); AppendXMLObjectArray(doc, n, ((LSL_List)o).Data, "item"); } else { typ.Value = o.GetType().ToString(); n.Attributes.Append(typ); n.AppendChild(doc.CreateTextNode(o.ToString())); } return n; } } }