diff --git a/.nant/local.include b/.nant/local.include index 5e02665f2a..29674ab671 100644 --- a/.nant/local.include +++ b/.nant/local.include @@ -43,11 +43,6 @@ - - - - - @@ -106,17 +101,6 @@ - - - - - - - - - - - @@ -301,7 +279,6 @@ - diff --git a/OpenSim/Framework/ChildAgentDataUpdate.cs b/OpenSim/Framework/ChildAgentDataUpdate.cs index fee71f01c4..a1ac84c039 100644 --- a/OpenSim/Framework/ChildAgentDataUpdate.cs +++ b/OpenSim/Framework/ChildAgentDataUpdate.cs @@ -41,14 +41,14 @@ namespace OpenSim.Framework public Guid AgentID; public bool alwaysrun; public float AVHeight; - public sLLVector3 cameraPosition; + public Vector3 cameraPosition; public float drawdistance; public float godlevel; public uint GroupAccess; - public sLLVector3 Position; + public Vector3 Position; public ulong regionHandle; public byte[] throttles; - public sLLVector3 Velocity; + public Vector3 Velocity; public ChildAgentDataUpdate() { @@ -177,14 +177,13 @@ namespace OpenSim.Framework Size = new Vector3(); Size.Z = cAgent.AVHeight; - Center = new Vector3(cAgent.cameraPosition.x, cAgent.cameraPosition.y, cAgent.cameraPosition.z); + Center = cAgent.cameraPosition; Far = cAgent.drawdistance; - Position = new Vector3(cAgent.Position.x, cAgent.Position.y, cAgent.Position.z); + Position = cAgent.Position; RegionHandle = cAgent.regionHandle; Throttles = cAgent.throttles; - Velocity = new Vector3(cAgent.Velocity.x, cAgent.Velocity.y, cAgent.Velocity.z); + Velocity = cAgent.Velocity; } - } public class AgentGroupData diff --git a/OpenSim/Framework/MultipartForm.cs b/OpenSim/Framework/MultipartForm.cs new file mode 100644 index 0000000000..8ba6d22683 --- /dev/null +++ b/OpenSim/Framework/MultipartForm.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.IO; +using System.Text; + +namespace OpenSim.Framework +{ + public static class MultipartForm + { + #region Helper Classes + + public abstract class Element + { + public string Name; + } + + public class File : Element + { + public string Filename; + public string ContentType; + public byte[] Data; + + public File(string name, string filename, string contentType, byte[] data) + { + Name = name; + Filename = filename; + ContentType = contentType; + Data = data; + } + } + + public class Parameter : Element + { + public string Value; + + public Parameter(string name, string value) + { + Name = name; + Value = value; + } + } + + #endregion Helper Classes + + public static HttpWebResponse Post(HttpWebRequest request, List postParameters) + { + string boundary = Boundary(); + + // Set up the request properties + request.Method = "POST"; + request.ContentType = "multipart/form-data; boundary=" + boundary; + + #region Stream Writing + + using (MemoryStream formDataStream = new MemoryStream()) + { + foreach (var param in postParameters) + { + if (param is File) + { + File file = (File)param; + + // Add just the first part of this param, since we will write the file data directly to the Stream + string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\";\r\nContent-Type: {3}\r\n\r\n", + boundary, + file.Name, + !String.IsNullOrEmpty(file.Filename) ? file.Filename : "tempfile", + file.ContentType); + + formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, header.Length); + formDataStream.Write(file.Data, 0, file.Data.Length); + } + else + { + Parameter parameter = (Parameter)param; + + string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}\r\n", + boundary, + parameter.Name, + parameter.Value); + formDataStream.Write(Encoding.UTF8.GetBytes(postData), 0, postData.Length); + } + } + + // Add the end of the request + byte[] footer = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n"); + formDataStream.Write(footer, 0, footer.Length); + + request.ContentLength = formDataStream.Length; + + // Copy the temporary stream to the network stream + formDataStream.Seek(0, SeekOrigin.Begin); + using (Stream requestStream = request.GetRequestStream()) + formDataStream.CopyTo(requestStream, (int)formDataStream.Length); + } + + #endregion Stream Writing + + return request.GetResponse() as HttpWebResponse; + } + + private static string Boundary() + { + Random rnd = new Random(); + string formDataBoundary = String.Empty; + + while (formDataBoundary.Length < 15) + formDataBoundary = formDataBoundary + rnd.Next(); + + formDataBoundary = formDataBoundary.Substring(0, 15); + formDataBoundary = "-----------------------------" + formDataBoundary; + + return formDataBoundary; + } + } +} diff --git a/OpenSim/Framework/RegionCommsListener.cs b/OpenSim/Framework/RegionCommsListener.cs index 718a5563e9..3e0955d073 100644 --- a/OpenSim/Framework/RegionCommsListener.cs +++ b/OpenSim/Framework/RegionCommsListener.cs @@ -45,7 +45,7 @@ namespace OpenSim.Framework private GenericCall2 handlerExpectChildAgent = null; // OnExpectChildAgent; private ExpectUserDelegate handlerExpectUser = null; // OnExpectUser private UpdateNeighbours handlerNeighboursUpdate = null; // OnNeighboursUpdate; - private PrimCrossing handlerPrimCrossingIntoRegion = null; // OnPrimCrossingIntoRegion; +// private PrimCrossing handlerPrimCrossingIntoRegion = null; // OnPrimCrossingIntoRegion; private LogOffUser handlerLogOffUser = null; private GetLandData handlerGetLandData = null; diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs index 828bbfc6d0..05f9cf9b65 100644 --- a/OpenSim/Framework/RegionInfo.cs +++ b/OpenSim/Framework/RegionInfo.cs @@ -654,7 +654,7 @@ namespace OpenSim.Framework private void ReadNiniConfig(IConfigSource source, string name) { - bool creatingNew = false; +// bool creatingNew = false; if (source.Configs.Count == 0) { @@ -671,7 +671,7 @@ namespace OpenSim.Framework source.AddConfig(name); - creatingNew = true; +// creatingNew = true; } if (name == String.Empty) @@ -681,7 +681,7 @@ namespace OpenSim.Framework { source.AddConfig(name); - creatingNew = true; +// creatingNew = true; } IConfig config = source.Configs[name]; @@ -700,15 +700,8 @@ namespace OpenSim.Framework RegionID = new UUID(regionUUID); originRegionID = RegionID; // What IS this?! - - - // Region name - // + RegionName = name; - - - // Region location - // string location = config.GetString("Location", String.Empty); if (location == String.Empty) @@ -724,12 +717,9 @@ namespace OpenSim.Framework // Datastore (is this implemented? Omitted from example!) - // DataStore = config.GetString("Datastore", String.Empty); - // Internal IP - // IPAddress address; if (config.Contains("InternalAddress")) diff --git a/OpenSim/Framework/UntrustedWebRequest.cs b/OpenSim/Framework/UntrustedWebRequest.cs new file mode 100644 index 0000000000..1af7c41558 --- /dev/null +++ b/OpenSim/Framework/UntrustedWebRequest.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Security; +using System.Text; +using log4net; + +namespace OpenSim.Framework +{ + /// + /// Used for requests to untrusted endpoints that may potentially be + /// malicious + /// + public static class UntrustedHttpWebRequest + { + /// Setting this to true will allow HTTP connections to localhost + private const bool DEBUG = true; + + private static readonly ILog m_log = + LogManager.GetLogger( + System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + private static readonly ICollection allowableSchemes = new List { "http", "https" }; + + /// + /// Creates an HttpWebRequest that is hardened against malicious + /// endpoints after ensuring the given Uri is safe to retrieve + /// + /// Web location to request + /// A hardened HttpWebRequest if the uri was determined to be safe + /// If uri is null + /// If uri is unsafe + public static HttpWebRequest Create(Uri uri) + { + return Create(uri, DEBUG, 1000 * 5, 1000 * 20, 10); + } + + /// + /// Creates an HttpWebRequest that is hardened against malicious + /// endpoints after ensuring the given Uri is safe to retrieve + /// + /// Web location to request + /// True to allow connections to localhost, otherwise false + /// Read write timeout, in milliseconds + /// Connection timeout, in milliseconds + /// Maximum number of allowed redirects + /// A hardened HttpWebRequest if the uri was determined to be safe + /// If uri is null + /// If uri is unsafe + public static HttpWebRequest Create(Uri uri, bool allowLoopback, int readWriteTimeoutMS, int timeoutMS, int maximumRedirects) + { + if (uri == null) + throw new ArgumentNullException("uri"); + + if (!IsUriAllowable(uri, allowLoopback)) + throw new ArgumentException("Uri " + uri + " was rejected"); + + HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(uri); + httpWebRequest.MaximumAutomaticRedirections = maximumRedirects; + httpWebRequest.ReadWriteTimeout = readWriteTimeoutMS; + httpWebRequest.Timeout = timeoutMS; + httpWebRequest.KeepAlive = false; + + return httpWebRequest; + } + + public static string PostToUntrustedUrl(Uri url, string data) + { + try + { + byte[] requestData = System.Text.Encoding.UTF8.GetBytes(data); + + HttpWebRequest request = Create(url); + request.Method = "POST"; + request.ContentLength = requestData.Length; + request.ContentType = "application/x-www-form-urlencoded"; + + using (Stream requestStream = request.GetRequestStream()) + requestStream.Write(requestData, 0, requestData.Length); + + using (WebResponse response = request.GetResponse()) + { + using (Stream responseStream = response.GetResponseStream()) + return responseStream.GetStreamString(); + } + } + catch (Exception ex) + { + m_log.Warn("POST to untrusted URL " + url + " failed: " + ex.Message); + return null; + } + } + + public static string GetUntrustedUrl(Uri url) + { + try + { + HttpWebRequest request = Create(url); + + using (WebResponse response = request.GetResponse()) + { + using (Stream responseStream = response.GetResponseStream()) + return responseStream.GetStreamString(); + } + } + catch (Exception ex) + { + m_log.Warn("GET from untrusted URL " + url + " failed: " + ex.Message); + return null; + } + } + + /// + /// Determines whether a URI is allowed based on scheme and host name. + /// No requireSSL check is done here + /// + /// True to allow loopback addresses to be used + /// The URI to test for whether it should be allowed. + /// + /// true if [is URI allowable] [the specified URI]; otherwise, false. + /// + private static bool IsUriAllowable(Uri uri, bool allowLoopback) + { + if (!allowableSchemes.Contains(uri.Scheme)) + { + m_log.WarnFormat("Rejecting URL {0} because it uses a disallowed scheme.", uri); + return false; + } + + // Try to interpret the hostname as an IP address so we can test for internal + // IP address ranges. Note that IP addresses can appear in many forms + // (e.g. http://127.0.0.1, http://2130706433, http://0x0100007f, http://::1 + // So we convert them to a canonical IPAddress instance, and test for all + // non-routable IP ranges: 10.*.*.*, 127.*.*.*, ::1 + // Note that Uri.IsLoopback is very unreliable, not catching many of these variants. + IPAddress hostIPAddress; + if (IPAddress.TryParse(uri.DnsSafeHost, out hostIPAddress)) + { + byte[] addressBytes = hostIPAddress.GetAddressBytes(); + + // The host is actually an IP address. + switch (hostIPAddress.AddressFamily) + { + case System.Net.Sockets.AddressFamily.InterNetwork: + if (!allowLoopback && (addressBytes[0] == 127 || addressBytes[0] == 10)) + { + m_log.WarnFormat("Rejecting URL {0} because it is a loopback address.", uri); + return false; + } + break; + case System.Net.Sockets.AddressFamily.InterNetworkV6: + if (!allowLoopback && IsIPv6Loopback(hostIPAddress)) + { + m_log.WarnFormat("Rejecting URL {0} because it is a loopback address.", uri); + return false; + } + break; + default: + m_log.WarnFormat("Rejecting URL {0} because it does not use an IPv4 or IPv6 address.", uri); + return false; + } + } + else + { + // The host is given by name. We require names to contain periods to + // help make sure it's not an internal address. + if (!allowLoopback && !uri.Host.Contains(".")) + { + m_log.WarnFormat("Rejecting URL {0} because it does not contain a period in the host name.", uri); + return false; + } + } + + return true; + } + + /// + /// Determines whether an IP address is the IPv6 equivalent of "localhost/127.0.0.1". + /// + /// The ip address to check. + /// + /// true if this is a loopback IP address; false otherwise. + /// + private static bool IsIPv6Loopback(IPAddress ip) + { + if (ip == null) + throw new ArgumentNullException("ip"); + + byte[] addressBytes = ip.GetAddressBytes(); + for (int i = 0; i < addressBytes.Length - 1; i++) + { + if (addressBytes[i] != 0) + return false; + } + + if (addressBytes[addressBytes.Length - 1] != 1) + return false; + + return true; + } + } +} diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs new file mode 100644 index 0000000000..d9782ff9ac --- /dev/null +++ b/OpenSim/Framework/WebUtil.cs @@ -0,0 +1,330 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Net; +using System.Net.Security; +using System.Reflection; +using System.Text; +using System.Web; +using log4net; +using OpenSim.Framework.Servers.HttpServer; +using OpenMetaverse.StructuredData; + +namespace OpenSim.Framework +{ + /// + /// Miscellaneous static methods and extension methods related to the web + /// + public static class WebUtil + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Send LLSD to an HTTP client in application/llsd+json form + /// + /// HTTP response to send the data in + /// LLSD to send to the client + public static void SendJSONResponse(OSHttpResponse response, OSDMap body) + { + byte[] responseData = Encoding.UTF8.GetBytes(OSDParser.SerializeJsonString(body)); + + response.ContentEncoding = Encoding.UTF8; + response.ContentLength = responseData.Length; + response.ContentType = "application/llsd+json"; + response.Body.Write(responseData, 0, responseData.Length); + } + + /// + /// Send LLSD to an HTTP client in application/llsd+xml form + /// + /// HTTP response to send the data in + /// LLSD to send to the client + public static void SendXMLResponse(OSHttpResponse response, OSDMap body) + { + byte[] responseData = OSDParser.SerializeLLSDXmlBytes(body); + + response.ContentEncoding = Encoding.UTF8; + response.ContentLength = responseData.Length; + response.ContentType = "application/llsd+xml"; + response.Body.Write(responseData, 0, responseData.Length); + } + + /// + /// Make a GET or GET-like request to a web service that returns LLSD + /// or JSON data + /// + public static OSDMap ServiceRequest(string url, string httpVerb) + { + string errorMessage; + + try + { + HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); + request.Method = httpVerb; + + using (WebResponse response = request.GetResponse()) + { + using (Stream responseStream = response.GetResponseStream()) + { + try + { + string responseStr = responseStream.GetStreamString(); + OSD responseOSD = OSDParser.Deserialize(responseStr); + if (responseOSD.Type == OSDType.Map) + return (OSDMap)responseOSD; + else + errorMessage = "Response format was invalid."; + } + catch + { + errorMessage = "Failed to parse the response."; + } + } + } + } + catch (Exception ex) + { + m_log.Warn("GET from URL " + url + " failed: " + ex.Message); + errorMessage = ex.Message; + } + + return new OSDMap { { "Message", OSD.FromString("Service request failed. " + errorMessage) } }; + } + + /// + /// POST URL-encoded form data to a web service that returns LLSD or + /// JSON data + /// + public static OSDMap PostToService(string url, NameValueCollection data) + { + string errorMessage; + + try + { + string queryString = BuildQueryString(data); + byte[] requestData = System.Text.Encoding.UTF8.GetBytes(queryString); + + HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); + request.Method = "POST"; + request.ContentLength = requestData.Length; + request.ContentType = "application/x-www-form-urlencoded"; + + using (Stream requestStream = request.GetRequestStream()) + requestStream.Write(requestData, 0, requestData.Length); + + using (WebResponse response = request.GetResponse()) + { + using (Stream responseStream = response.GetResponseStream()) + { + try + { + string responseStr = responseStream.GetStreamString(); + OSD responseOSD = OSDParser.Deserialize(responseStr); + if (responseOSD.Type == OSDType.Map) + return (OSDMap)responseOSD; + else + errorMessage = "Response format was invalid."; + } + catch + { + errorMessage = "Failed to parse the response."; + } + } + } + } + catch (Exception ex) + { + m_log.Warn("POST to URL " + url + " failed: " + ex.Message); + errorMessage = ex.Message; + } + + return new OSDMap { { "Message", OSD.FromString("Service request failed. " + errorMessage) } }; + } + + #region Uri + + /// + /// Combines a Uri that can contain both a base Uri and relative path + /// with a second relative path fragment + /// + /// Starting (base) Uri + /// Relative path fragment to append to the end + /// of the Uri + /// The combined Uri + /// This is similar to the Uri constructor that takes a base + /// Uri and the relative path, except this method can append a relative + /// path fragment on to an existing relative path + public static Uri Combine(this Uri uri, string fragment) + { + string fragment1 = uri.Fragment; + string fragment2 = fragment; + + if (!fragment1.EndsWith("/")) + fragment1 = fragment1 + '/'; + if (fragment2.StartsWith("/")) + fragment2 = fragment2.Substring(1); + + return new Uri(uri, fragment1 + fragment2); + } + + /// + /// Combines a Uri that can contain both a base Uri and relative path + /// with a second relative path fragment. If the fragment is absolute, + /// it will be returned without modification + /// + /// Starting (base) Uri + /// Relative path fragment to append to the end + /// of the Uri, or an absolute Uri to return unmodified + /// The combined Uri + public static Uri Combine(this Uri uri, Uri fragment) + { + if (fragment.IsAbsoluteUri) + return fragment; + + string fragment1 = uri.Fragment; + string fragment2 = fragment.ToString(); + + if (!fragment1.EndsWith("/")) + fragment1 = fragment1 + '/'; + if (fragment2.StartsWith("/")) + fragment2 = fragment2.Substring(1); + + return new Uri(uri, fragment1 + fragment2); + } + + /// + /// Appends a query string to a Uri that may or may not have existing + /// query parameters + /// + /// Uri to append the query to + /// Query string to append. Can either start with ? + /// or just containg key/value pairs + /// String representation of the Uri with the query string + /// appended + public static string AppendQuery(this Uri uri, string query) + { + if (String.IsNullOrEmpty(query)) + return uri.ToString(); + + if (query[0] == '?' || query[0] == '&') + query = query.Substring(1); + + string uriStr = uri.ToString(); + + if (uriStr.Contains("?")) + return uriStr + '&' + query; + else + return uriStr + '?' + query; + } + + #endregion Uri + + #region NameValueCollection + + /// + /// Convert a NameValueCollection into a query string. This is the + /// inverse of HttpUtility.ParseQueryString() + /// + /// Collection of key/value pairs to convert + /// A query string with URL-escaped values + public static string BuildQueryString(NameValueCollection parameters) + { + List items = new List(parameters.Count); + + foreach (string key in parameters.Keys) + { + foreach (string value in parameters.GetValues(key)) + items.Add(String.Concat(key, "=", HttpUtility.UrlEncode(value ?? String.Empty))); + } + + return String.Join("&", items.ToArray()); + } + + /// + /// + /// + /// + /// + /// + public static string GetOne(this NameValueCollection collection, string key) + { + string[] values = collection.GetValues(key); + if (values != null && values.Length > 0) + return values[0]; + + return null; + } + + #endregion NameValueCollection + + #region Stream + + /// + /// Copies the contents of one stream to another, starting at the + /// current position of each stream + /// + /// The stream to copy from, at the position + /// where copying should begin + /// The stream to copy to, at the position where + /// bytes should be written + /// The maximum bytes to copy + /// The total number of bytes copied + /// + /// Copying begins at the streams' current positions. The positions are + /// NOT reset after copying is complete. + /// + public static int CopyTo(this Stream copyFrom, Stream copyTo, int maximumBytesToCopy) + { + byte[] buffer = new byte[4096]; + int readBytes; + int totalCopiedBytes = 0; + + while ((readBytes = copyFrom.Read(buffer, 0, Math.Min(4096, maximumBytesToCopy))) > 0) + { + int writeBytes = Math.Min(maximumBytesToCopy, readBytes); + copyTo.Write(buffer, 0, writeBytes); + totalCopiedBytes += writeBytes; + maximumBytesToCopy -= writeBytes; + } + + return totalCopiedBytes; + } + + /// + /// Converts an entire stream to a string, regardless of current stream + /// position + /// + /// The stream to convert to a string + /// + /// When this method is done, the stream position will be + /// reset to its previous position before this method was called + public static string GetStreamString(this Stream stream) + { + string value = null; + + if (stream != null && stream.CanRead) + { + long rewindPos = -1; + + if (stream.CanSeek) + { + rewindPos = stream.Position; + stream.Seek(0, SeekOrigin.Begin); + } + + StreamReader reader = new StreamReader(stream); + value = reader.ReadToEnd(); + + if (rewindPos >= 0) + stream.Seek(rewindPos, SeekOrigin.Begin); + } + + return value; + } + + #endregion Stream + } +} diff --git a/OpenSim/Framework/sLLVector3.cs b/OpenSim/Framework/sLLVector3.cs deleted file mode 100644 index 49940c46f8..0000000000 --- a/OpenSim/Framework/sLLVector3.cs +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 OpenMetaverse; - -namespace OpenSim.Framework -{ - [Serializable] - public class sLLVector3 - { - public float x = 0; - public float y = 0; - public float z = 0; - - public sLLVector3() - { - } - - public sLLVector3(Vector3 v) - { - x = v.X; - y = v.Y; - z = v.Z; - } - } -} \ No newline at end of file diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 16960378ba..2c8d88b5df 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -97,6 +97,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientIPEndpoint, IStatsCollector { + /// + /// Debug packet level. At the moment, only 255 does anything (prints out all in and out packets). + /// + protected int m_debugPacketLevel = 0; + #region Events public event GenericMessage OnGenericMessage; @@ -472,6 +477,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void SetDebugPacketLevel(int newDebug) { + m_debugPacketLevel = newDebug; } #region Client Methods @@ -10939,7 +10945,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP LLUDPServer.LogPacketHeader(false, m_circuitCode, 0, packet.Type, (ushort)packet.Length); #endregion BinaryStats - m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, true); + OutPacket(packet, throttlePacketType, true); } /// @@ -10952,6 +10958,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// handles splitting manually protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting) { + if (m_debugPacketLevel >= 255) + m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); + m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); } @@ -11023,10 +11032,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// OpenMetaverse.packet public void ProcessInPacket(Packet Pack) { -// m_log.DebugFormat("[CLIENT]: Packet IN {0}", Pack); + if (m_debugPacketLevel >= 255) + m_log.DebugFormat("[CLIENT]: Packet IN {0}", Pack.Type); if (!ProcessPacketMethod(Pack)) - m_log.Warn("[CLIENT]: unhandled packet " + Pack); + m_log.Warn("[CLIENT]: unhandled packet " + Pack.Type); PacketPool.Instance.ReturnPacket(Pack); } diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index e0df2881ed..0fc467bc43 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -411,6 +411,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess /// /// Rez an object into the scene from the user's inventory /// + /// FIXME: It would be really nice if inventory access modules didn't also actually do the work of rezzing + /// things to the scene. The caller should be doing that, I think. /// /// /// @@ -500,13 +502,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess group.RootPart.IsAttachment = true; } - m_Scene.AddNewSceneObject(group, true); + // For attachments, we must make sure that only a single object update occurs after we've finished + // all the necessary operations. + m_Scene.AddNewSceneObject(group, true, false); // m_log.InfoFormat("ray end point for inventory rezz is {0} {1} {2} ", RayEnd.X, RayEnd.Y, RayEnd.Z); // if attachment we set it's asset id so object updates can reflect that // if not, we set it's position in world. if (!attachment) { + group.ScheduleGroupForFullUpdate(); + float offsetHeight = 0; pos = m_Scene.GetNewRezLocation( RayStart, RayEnd, RayTargetID, Quaternion.Identity, @@ -562,6 +568,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess part.GroupMask = 0; // DO NOT propagate here } } + group.ApplyNextOwnerPermissions(); } } @@ -569,7 +576,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess foreach (SceneObjectPart part in partList) { if (part.OwnerID != item.Owner) - { + { part.LastOwnerID = part.OwnerID; part.OwnerID = item.Owner; part.Inventory.ChangeInventoryOwner(item.Owner); @@ -591,10 +598,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { group.ClearPartAttachmentData(); } - } - - if (!attachment) - { + // Fire on_rez group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 0); diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index e458ecf8bf..9cbaffc7b6 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -1846,9 +1846,18 @@ namespace OpenSim.Region.Framework.Scenes EventManager.TriggerOnAttach(localID, itemID, avatarID); } - public UUID RezSingleAttachment(IClientAPI remoteClient, UUID itemID, - uint AttachmentPt) + /// + /// Called when the client receives a request to rez a single attachment on to the avatar from inventory + /// (RezSingleAttachmentFromInv packet). + /// + /// + /// + /// + /// + public UUID RezSingleAttachment(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) { + m_log.DebugFormat("[USER INVENTORY]: Rezzing single attachment from item {0} for {1}", itemID, remoteClient.Name); + SceneObjectGroup att = m_sceneGraph.RezSingleAttachment(remoteClient, itemID, AttachmentPt); if (att == null) @@ -1860,9 +1869,20 @@ namespace OpenSim.Region.Framework.Scenes return RezSingleAttachment(att, remoteClient, itemID, AttachmentPt); } - public UUID RezSingleAttachment(SceneObjectGroup att, - IClientAPI remoteClient, UUID itemID, uint AttachmentPt) + /// + /// Update the user inventory to reflect an attachment + /// + /// + /// + /// + /// + /// + public UUID RezSingleAttachment(SceneObjectGroup att, IClientAPI remoteClient, UUID itemID, uint AttachmentPt) { + m_log.DebugFormat( + "[USER INVENTORY]: Updating inventory of {0} to show attachment of {1} (item ID {2})", + remoteClient.Name, att.Name, itemID); + if (!att.IsDeleted) AttachmentPt = att.RootPart.AttachmentPoint; @@ -1901,8 +1921,19 @@ namespace OpenSim.Region.Framework.Scenes return m_sceneGraph.AttachObject(controllingClient, localID, attachPoint, rot, pos, silent); } + /// + /// This registers the item as attached in a user's inventory + /// + /// + /// + /// + /// public void AttachObject(IClientAPI remoteClient, uint AttachmentPt, UUID itemID, SceneObjectGroup att) { +// m_log.DebugFormat( +// "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", +// att.Name, remoteClient.Name, AttachmentPt, itemID); + if (UUID.Zero == itemID) { m_log.Error("[SCENE INVENTORY]: Unable to save attachment. Error inventory item ID."); @@ -1930,10 +1961,7 @@ namespace OpenSim.Region.Framework.Scenes presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID /* att.UUID */); if (m_AvatarFactory != null) - { m_AvatarFactory.UpdateDatabase(remoteClient.AgentId, presence.Appearance); - } - } } @@ -2016,6 +2044,7 @@ namespace OpenSim.Region.Framework.Scenes { sog.SetOwnerId(ownerID); sog.SetGroup(groupID, remoteClient); + sog.ScheduleGroupForFullUpdate(); foreach (SceneObjectPart child in sog.Children.Values) child.Inventory.ChangeInventoryOwner(ownerID); @@ -2037,6 +2066,7 @@ namespace OpenSim.Region.Framework.Scenes sog.SetOwnerId(groupID); sog.ApplyNextOwnerPermissions(); } + } foreach (uint localID in localIDs) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 181b7c50fb..a84f966b49 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -1933,14 +1933,22 @@ namespace OpenSim.Region.Framework.Scenes //m_log.DebugFormat( // "[SCENE]: Scene.AddNewPrim() pcode {0} called for {1} in {2}", shape.PCode, ownerID, RegionInfo.RegionName); + SceneObjectGroup sceneObject = null; + // If an entity creator has been registered for this prim type then use that if (m_entityCreators.ContainsKey((PCode)shape.PCode)) - return m_entityCreators[(PCode)shape.PCode].CreateEntity(ownerID, groupID, pos, rot, shape); + { + sceneObject = m_entityCreators[(PCode)shape.PCode].CreateEntity(ownerID, groupID, pos, rot, shape); + } + else + { + // Otherwise, use this default creation code; + sceneObject = new SceneObjectGroup(ownerID, pos, rot, shape); + AddNewSceneObject(sceneObject, true); + sceneObject.SetGroup(groupID, null); + } - // Otherwise, use this default creation code; - SceneObjectGroup sceneObject = new SceneObjectGroup(ownerID, pos, rot, shape); - AddNewSceneObject(sceneObject, true); - sceneObject.SetGroup(groupID, null); + sceneObject.ScheduleGroupForFullUpdate(); return sceneObject; } @@ -1968,7 +1976,7 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Add a newly created object to the scene + /// Add a newly created object to the scene. Updates are also sent to viewers. /// /// /// @@ -1977,8 +1985,25 @@ namespace OpenSim.Region.Framework.Scenes /// public bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup) { - return m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup); + return AddNewSceneObject(sceneObject, attachToBackup, true); } + + /// + /// Add a newly created object to the scene + /// + /// + /// + /// If true, the object is made persistent into the scene. + /// If false, the object will not persist over server restarts + /// + /// + /// If true, updates for the new scene object are sent to all viewers in range. + /// If false, it is left to the caller to schedule the update + /// + public bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) + { + return m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup, sendClientUpdates); + } /// /// Delete every object from the scene @@ -3170,7 +3195,6 @@ namespace OpenSim.Region.Framework.Scenes m_sceneGridService.OnLogOffUser += HandleLogOffUserFromGrid; m_sceneGridService.KiPrimitive += SendKillObject; m_sceneGridService.OnGetLandData += GetLandData; - } /// diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs index 8a74d7b388..9d0e6f4553 100644 --- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs +++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs @@ -103,15 +103,15 @@ namespace OpenSim.Region.Framework.Scenes /// public event GetLandData OnGetLandData; - private AgentCrossing handlerAvatarCrossingIntoRegion = null; // OnAvatarCrossingIntoRegion; - private ExpectUserDelegate handlerExpectUser = null; // OnExpectUser; - private CloseAgentConnection handlerCloseAgentConnection = null; // OnCloseAgentConnection; - private PrimCrossing handlerPrimCrossingIntoRegion = null; // OnPrimCrossingIntoRegion; +// private AgentCrossing handlerAvatarCrossingIntoRegion = null; // OnAvatarCrossingIntoRegion; +// private ExpectUserDelegate handlerExpectUser = null; // OnExpectUser; +// private CloseAgentConnection handlerCloseAgentConnection = null; // OnCloseAgentConnection; +// private PrimCrossing handlerPrimCrossingIntoRegion = null; // OnPrimCrossingIntoRegion; //private RegionUp handlerRegionUp = null; // OnRegionUp; - private ChildAgentUpdate handlerChildAgentUpdate = null; // OnChildAgentUpdate; +// private ChildAgentUpdate handlerChildAgentUpdate = null; // OnChildAgentUpdate; //private RemoveKnownRegionsFromAvatarList handlerRemoveKnownRegionFromAvatar = null; // OnRemoveKnownRegionFromAvatar; - private LogOffUser handlerLogOffUser = null; - private GetLandData handlerGetLandData = null; // OnGetLandData +// private LogOffUser handlerLogOffUser = null; +// private GetLandData handlerGetLandData = null; // OnGetLandData public KiPrimitiveDelegate KiPrimitive; diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 928dc97263..cac768e565 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -253,7 +253,7 @@ namespace OpenSim.Region.Framework.Scenes sceneObject.HasGroupChanged = true; } - return AddSceneObject(sceneObject, attachToBackup); + return AddSceneObject(sceneObject, attachToBackup, true); } /// @@ -268,12 +268,12 @@ namespace OpenSim.Region.Framework.Scenes /// /// true if the object was added, false if an object with the same uuid was already in the scene /// - protected internal bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup) + protected internal bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) { // Ensure that we persist this new scene object sceneObject.HasGroupChanged = true; - return AddSceneObject(sceneObject, attachToBackup); + return AddSceneObject(sceneObject, attachToBackup, sendClientUpdates); } /// @@ -285,12 +285,19 @@ namespace OpenSim.Region.Framework.Scenes /// If true, the object is made persistent into the scene. /// If false, the object will not persist over server restarts /// - /// true if the object was added, false if an object with the same uuid was already in the scene + /// + /// If true, updates for the new scene object are sent to all viewers in range. + /// If false, it is left to the caller to schedule the update + /// + /// + /// true if the object was added, false if an object with the same uuid was already in the scene /// - protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup) + protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) { if (sceneObject == null || sceneObject.RootPart == null || sceneObject.RootPart.UUID == UUID.Zero) return false; + + bool alreadyExisted = false; if (m_parentScene.m_clampPrimSize) { @@ -311,6 +318,9 @@ namespace OpenSim.Region.Framework.Scenes sceneObject.AttachToScene(m_parentScene); + if (sendClientUpdates) + sceneObject.ScheduleGroupForFullUpdate(); + lock (sceneObject) { if (!Entities.ContainsKey(sceneObject.UUID)) @@ -334,12 +344,14 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectGroupsByLocalID[part.LocalId] = sceneObject; } } - - return true; + } + else + { + alreadyExisted = true; } } - return false; + return alreadyExisted; } /// @@ -549,7 +561,10 @@ namespace OpenSim.Region.Framework.Scenes itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, false, false, remoteClient.AgentId, true); - +// m_log.DebugFormat( +// "[SCENE GRAPH]: Retrieved single object {0} for attachment to {1} on point {2}", +// objatt.Name, remoteClient.Name, AttachmentPt); + if (objatt != null) { bool tainted = false; @@ -557,16 +572,27 @@ namespace OpenSim.Region.Framework.Scenes tainted = true; AttachObject(remoteClient, objatt.LocalId, AttachmentPt, Quaternion.Identity, objatt.AbsolutePosition, false); - objatt.ScheduleGroupForFullUpdate(); + //objatt.ScheduleGroupForFullUpdate(); if (tainted) objatt.HasGroupChanged = true; // Fire after attach, so we don't get messy perms dialogs // 3 == AttachedRez objatt.CreateScriptInstances(0, true, m_parentScene.DefaultScriptEngine, 3); + + // Do this last so that event listeners have access to all the effects of the attachment + m_parentScene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId); } + else + { + m_log.WarnFormat( + "[SCENE GRAPH]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", + itemID, remoteClient.Name, AttachmentPt); + } + return objatt; } + return null; } diff --git a/OpenSim/Region/Framework/Scenes/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs index 6395d9868b..680c39a622 100644 --- a/OpenSim/Region/Framework/Scenes/SceneManager.cs +++ b/OpenSim/Region/Framework/Scenes/SceneManager.cs @@ -422,7 +422,7 @@ namespace OpenSim.Region.Framework.Scenes if (!scenePresence.IsChildAgent) { - m_log.ErrorFormat("Packet debug for {0} {1} set to {2}", + m_log.DebugFormat("Packet debug for {0} {1} set to {2}", scenePresence.Firstname, scenePresence.Lastname, newDebug); diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 2a4e5a23b6..8c5a9a6d82 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -488,8 +488,8 @@ namespace OpenSim.Region.Framework.Scenes private List m_PlaySoundSlavePrims = new List(); public List PlaySoundSlavePrims { - get { return m_LoopSoundSlavePrims; } - set { m_LoopSoundSlavePrims = value; } + get { return m_PlaySoundSlavePrims; } + set { m_PlaySoundSlavePrims = value; } } private SceneObjectPart m_LoopSoundMasterPrim = null; @@ -641,8 +641,10 @@ namespace OpenSim.Region.Framework.Scenes } ApplyPhysics(m_scene.m_physicalPrim); - - ScheduleGroupForFullUpdate(); + + // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled + // for the same object with very different properties. The caller must schedule the update. + //ScheduleGroupForFullUpdate(); } public Vector3 GroupScale() @@ -1044,10 +1046,11 @@ namespace OpenSim.Region.Framework.Scenes // don't attach attachments to child agents if (avatar.IsChildAgent) return; +// m_log.DebugFormat("[SOG]: Adding attachment {0} to avatar {1}", Name, avatar.Name); + DetachFromBackup(); // Remove from database and parcel prim count - // m_scene.DeleteFromStorage(UUID); m_scene.EventManager.TriggerParcelPrimCountTainted(); @@ -1073,7 +1076,6 @@ namespace OpenSim.Region.Framework.Scenes SetAttachmentPoint(Convert.ToByte(attachmentpoint)); avatar.AddAttachment(this); - m_log.Debug("[SOG]: Added attachment " + UUID + " to avatar " + avatar.UUID); if (!silent) { @@ -1090,6 +1092,12 @@ namespace OpenSim.Region.Framework.Scenes ScheduleGroupForFullUpdate(); } } + else + { + m_log.WarnFormat( + "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present", + UUID, agentID, Scene.RegionInfo.RegionName); + } } public byte GetAttachmentPoint() @@ -1596,11 +1604,10 @@ namespace OpenSim.Region.Framework.Scenes #endregion - #region Client Updating - public void SendFullUpdateToClient(IClientAPI remoteClient) { - SendPartFullUpdate(remoteClient, RootPart, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID)); + RootPart.SendFullUpdate( + remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID)); lockPartsForRead(true); { @@ -1608,42 +1615,12 @@ namespace OpenSim.Region.Framework.Scenes { if (part != RootPart) - SendPartFullUpdate(remoteClient, part, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID)); - + part.SendFullUpdate( + remoteClient, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID)); } } - lockPartsForRead(false); - } - - /// - /// Send a full update to the client for the given part - /// - /// - /// - internal void SendPartFullUpdate(IClientAPI remoteClient, SceneObjectPart part, uint clientFlags) - { -// m_log.DebugFormat( -// "[SOG]: Sendinging part full update to {0} for {1} {2}", remoteClient.Name, part.Name, part.LocalId); - - if (m_rootPart.UUID == part.UUID) - { - if (IsAttachment) - { - part.SendFullUpdateToClient(remoteClient, m_rootPart.AttachedPos, clientFlags); - } - else - { - part.SendFullUpdateToClient(remoteClient, AbsolutePosition, clientFlags); - } - } - else - { - part.SendFullUpdateToClient(remoteClient, clientFlags); - } } - #endregion - #region Copying /// @@ -2108,6 +2085,8 @@ namespace OpenSim.Region.Framework.Scenes public void ScheduleFullUpdateToAvatar(ScenePresence presence) { +// m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1} just to avatar {2}", Name, UUID, presence.Name); + RootPart.AddFullUpdateToAvatar(presence); lockPartsForRead(true); @@ -2126,14 +2105,12 @@ namespace OpenSim.Region.Framework.Scenes public void ScheduleTerseUpdateToAvatar(ScenePresence presence) { lockPartsForRead(true); + + foreach (SceneObjectPart part in m_parts.Values) { - foreach (SceneObjectPart part in m_parts.Values) - { - - part.AddTerseUpdateToAvatar(presence); - - } + part.AddTerseUpdateToAvatar(presence); } + lockPartsForRead(false); } @@ -2142,6 +2119,8 @@ namespace OpenSim.Region.Framework.Scenes /// public void ScheduleGroupForFullUpdate() { +// m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, UUID); + checkAtTargets(); RootPart.ScheduleFullUpdate(); @@ -2164,14 +2143,12 @@ namespace OpenSim.Region.Framework.Scenes public void ScheduleGroupForTerseUpdate() { lockPartsForRead(true); + + foreach (SceneObjectPart part in m_parts.Values) { - foreach (SceneObjectPart part in m_parts.Values) - { - - part.ScheduleTerseUpdate(); - - } + part.ScheduleTerseUpdate(); } + lockPartsForRead(false); } @@ -2179,9 +2156,11 @@ namespace OpenSim.Region.Framework.Scenes /// Immediately send a full update for this scene object. /// public void SendGroupFullUpdate() - { + { if (IsDeleted) return; + +// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); RootPart.SendFullUpdateToAllClients(); @@ -2201,7 +2180,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// Immediately send an update for this scene object's root prim only. /// This is for updates regarding the object as a whole, and none of its parts in particular. - /// Note: this may not be cused by opensim (it probably should) but it's used by + /// Note: this may not be used by opensim (it probably should) but it's used by /// external modules. /// public void SendGroupRootTerseUpdate() @@ -2216,6 +2195,7 @@ namespace OpenSim.Region.Framework.Scenes { if (m_scene == null) // Need to check here as it's null during object creation return; + m_scene.SceneGraph.AddToUpdateList(this); } @@ -3718,7 +3698,10 @@ namespace OpenSim.Region.Framework.Scenes HasGroupChanged = true; } lockPartsForRead(false); - ScheduleGroupForFullUpdate(); + + // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled + // for the same object with very different properties. The caller must schedule the update. + //ScheduleGroupForFullUpdate(); } public void TriggerScriptChangedEvent(Changed val) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 57635f5ac9..badf782354 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -573,8 +573,8 @@ namespace OpenSim.Region.Framework.Scenes private List m_PlaySoundSlavePrims = new List(); public List PlaySoundSlavePrims { - get { return m_LoopSoundSlavePrims; } - set { m_LoopSoundSlavePrims = value; } + get { return m_PlaySoundSlavePrims; } + set { m_PlaySoundSlavePrims = value; } } private SceneObjectPart m_LoopSoundMasterPrim = null; @@ -2842,29 +2842,59 @@ namespace OpenSim.Region.Framework.Scenes } } - /// - /// - /// - /// - public void SendFullUpdate(IClientAPI remoteClient, uint clientFlags) - { - m_parentGroup.SendPartFullUpdate(remoteClient, this, clientFlags); - } +// /// +// /// +// /// +// /// +// public void SendFullUpdate(IClientAPI remoteClient, uint clientFlags) +// { +// m_parentGroup.SendPartFullUpdate(remoteClient, this, clientFlags); +// } + /// - /// + /// Send a full update to the client for the given part + /// + /// + /// + protected internal void SendFullUpdate(IClientAPI remoteClient, uint clientFlags) + { +// m_log.DebugFormat( +// "[SOG]: Sendinging part full update to {0} for {1} {2}", remoteClient.Name, part.Name, part.LocalId); + + if (IsRoot) + { + if (IsAttachment) + { + SendFullUpdateToClient(remoteClient, AttachedPos, clientFlags); + } + else + { + SendFullUpdateToClient(remoteClient, AbsolutePosition, clientFlags); + } + } + else + { + SendFullUpdateToClient(remoteClient, clientFlags); + } + } + + /// + /// Send a full update for this part to all clients. /// public void SendFullUpdateToAllClients() { ScenePresence[] avatars = m_parentGroup.Scene.GetScenePresences(); for (int i = 0; i < avatars.Length; i++) { - // Ugly reference :( - m_parentGroup.SendPartFullUpdate(avatars[i].ControllingClient, this, - avatars[i].GenerateClientFlags(UUID)); + SendFullUpdate(avatars[i].ControllingClient, avatars[i].GenerateClientFlags(UUID)); } } + /// + /// Send a full update to all clients except the one nominated. + /// + /// public void SendFullUpdateToAllClientsExcept(UUID agentID) { ScenePresence[] avatars = m_parentGroup.Scene.GetScenePresences(); @@ -2872,10 +2902,7 @@ namespace OpenSim.Region.Framework.Scenes { // Ugly reference :( if (avatars[i].UUID != agentID) - { - m_parentGroup.SendPartFullUpdate(avatars[i].ControllingClient, this, - avatars[i].GenerateClientFlags(UUID)); - } + SendFullUpdate(avatars[i].ControllingClient, avatars[i].GenerateClientFlags(UUID)); } } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 453523afd8..9dbe332acc 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -875,40 +875,15 @@ namespace OpenSim.Region.Framework.Scenes } } - if (pos.X < 0 || pos.Y < 0 || pos.Z < 0) + if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f) { - Vector3 emergencyPos = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 128); - - if (pos.X < 0) - { - emergencyPos.X = (int)Constants.RegionSize + pos.X; - if (!(pos.Y < 0)) - emergencyPos.Y = pos.Y; - if (!(pos.Z < 0)) - emergencyPos.X = pos.X; - } - if (pos.Y < 0) - { - emergencyPos.Y = (int)Constants.RegionSize + pos.Y; - if (!(pos.X < 0)) - emergencyPos.X = pos.X; - if (!(pos.Z < 0)) - emergencyPos.Z = pos.Z; - } - if (pos.Z < 0) - { - if (!(pos.X < 0)) - emergencyPos.X = pos.X; - if (!(pos.Y < 0)) - emergencyPos.Y = pos.Y; - //Leave as 128 - } - m_log.WarnFormat( - "[SCENE PRESENCE]: MakeRootAgent() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", - pos, Name, UUID, emergencyPos); + "[SCENE PRESENCE]: MakeRootAgent() was given an illegal position of {0} for avatar {1}, {2}. Clamping", + pos, Name, UUID); - pos = emergencyPos; + if (pos.X < 0f) pos.X = 0f; + if (pos.Y < 0f) pos.Y = 0f; + if (pos.Z < 0f) pos.Z = 0f; } float localAVHeight = 1.56f; @@ -919,7 +894,7 @@ namespace OpenSim.Region.Framework.Scenes float posZLimit = 0; - if (pos.X protected void CheckForSignificantMovement() { - if (Util.GetDistanceTo(AbsolutePosition, posLastSignificantMove) > 0.5) + // Movement updates for agents in neighboring regions are sent directly to clients. + // This value only affects how often agent positions are sent to neighbor regions + // for things such as distance-based update prioritization + const float SIGNIFICANT_MOVEMENT = 2.0f; + + if (Util.GetDistanceTo(AbsolutePosition, posLastSignificantMove) > SIGNIFICANT_MOVEMENT) { posLastSignificantMove = AbsolutePosition; m_scene.EventManager.TriggerSignificantClientMovement(m_controllingClient); @@ -2897,13 +2877,13 @@ namespace OpenSim.Region.Framework.Scenes cadu.AgentID = UUID.Guid; cadu.alwaysrun = m_setAlwaysRun; cadu.AVHeight = m_avHeight; - sLLVector3 tempCameraCenter = new sLLVector3(new Vector3(m_CameraCenter.X, m_CameraCenter.Y, m_CameraCenter.Z)); + Vector3 tempCameraCenter = m_CameraCenter; cadu.cameraPosition = tempCameraCenter; cadu.drawdistance = m_DrawDistance; if (m_scene.Permissions.IsGod(new UUID(cadu.AgentID))) cadu.godlevel = m_godlevel; cadu.GroupAccess = 0; - cadu.Position = new sLLVector3(AbsolutePosition); + cadu.Position = AbsolutePosition; cadu.regionHandle = m_rootRegionHandle; float multiplier = 1; int innacurateNeighbors = m_scene.GetInaccurateNeighborCount(); @@ -2918,7 +2898,7 @@ namespace OpenSim.Region.Framework.Scenes //m_log.Info("[NeighborThrottle]: " + m_scene.GetInaccurateNeighborCount().ToString() + " - m: " + multiplier.ToString()); cadu.throttles = ControllingClient.GetThrottlesPacked(multiplier); - cadu.Velocity = new sLLVector3(Velocity); + cadu.Velocity = Velocity; AgentPosition agentpos = new AgentPosition(); agentpos.CopyFrom(cadu); diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs index e87b1f4d90..1ea52c5c4e 100644 --- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs @@ -416,7 +416,6 @@ namespace OpenSim.Region.ScriptEngine.Shared public list(params object[] args) { - m_data = new object[args.Length]; m_data = args; } diff --git a/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs b/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs index 021dcf3e91..2fc92487d6 100644 --- a/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs +++ b/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs @@ -47,9 +47,9 @@ namespace OpenSim.Services.AuthenticationService public class PasswordAuthenticationService : AuthenticationServiceBase, IAuthenticationService { - //private static readonly ILog m_log = - // LogManager.GetLogger( - // MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); public PasswordAuthenticationService(IConfigSource config) : base(config) @@ -59,23 +59,27 @@ namespace OpenSim.Services.AuthenticationService public string Authenticate(UUID principalID, string password, int lifetime) { AuthenticationData data = m_Database.Get(principalID); - - if (!data.Data.ContainsKey("passwordHash") || - !data.Data.ContainsKey("passwordSalt")) + + if (data != null && data.Data != null) { - return String.Empty; - } - - string hashed = Util.Md5Hash(password + ":" + - data.Data["passwordSalt"].ToString()); - - //m_log.DebugFormat("[PASS AUTH]: got {0}; hashed = {1}; stored = {2}", password, hashed, data.Data["passwordHash"].ToString()); - - if (data.Data["passwordHash"].ToString() == hashed) - { - return GetToken(principalID, lifetime); + if (!data.Data.ContainsKey("passwordHash") || + !data.Data.ContainsKey("passwordSalt")) + { + return String.Empty; + } + + string hashed = Util.Md5Hash(password + ":" + + data.Data["passwordSalt"].ToString()); + + //m_log.DebugFormat("[PASS AUTH]: got {0}; hashed = {1}; stored = {2}", password, hashed, data.Data["passwordHash"].ToString()); + + if (data.Data["passwordHash"].ToString() == hashed) + { + return GetToken(principalID, lifetime); + } } + m_log.DebugFormat("[AUTH SERVICE]: PrincipalID {0} or its data not found", principalID); return String.Empty; } } diff --git a/OpenSim/Services/Base/ServiceBase.cs b/OpenSim/Services/Base/ServiceBase.cs index 8e24d8517c..91d5c5650c 100644 --- a/OpenSim/Services/Base/ServiceBase.cs +++ b/OpenSim/Services/Base/ServiceBase.cs @@ -26,7 +26,9 @@ */ using System; +using System.Collections.Generic; using System.Reflection; +using log4net; using Nini.Config; using OpenSim.Services.Interfaces; @@ -34,6 +36,8 @@ namespace OpenSim.Services.Base { public class ServiceBase { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + public T LoadPlugin(string dllName) where T:class { return LoadPlugin(dllName, new Object[0]); @@ -61,8 +65,12 @@ namespace OpenSim.Services.Base { Assembly pluginAssembly = Assembly.LoadFrom(dllName); +// m_log.DebugFormat("[SERVICE BASE]: Found assembly {0}", dllName); + foreach (Type pluginType in pluginAssembly.GetTypes()) { +// m_log.DebugFormat("[SERVICE BASE]: Found type {0}", pluginType); + if (pluginType.IsPublic) { if (className != String.Empty && @@ -86,7 +94,15 @@ namespace OpenSim.Services.Base } catch (Exception e) { - Console.WriteLine("XXX Exception " + e.StackTrace); + List strArgs = new List(); + foreach (Object arg in args) + strArgs.Add(arg.ToString()); + + m_log.Error( + string.Format( + "[SERVICE BASE]: Failed to load plugin {0} from {1} with args {2}", + interfaceName, dllName, string.Join(", ", strArgs.ToArray())), e); + return null; } } @@ -95,4 +111,4 @@ namespace OpenSim.Services.Base { } } -} +} \ No newline at end of file diff --git a/OpenSim/Services/Friends/FriendsServiceBase.cs b/OpenSim/Services/Friends/FriendsServiceBase.cs index 9858972311..6ab0bff0a8 100644 --- a/OpenSim/Services/Friends/FriendsServiceBase.cs +++ b/OpenSim/Services/Friends/FriendsServiceBase.cs @@ -27,13 +27,12 @@ using System; using System.Reflection; +using log4net; using Nini.Config; using OpenSim.Framework; using OpenSim.Data; using OpenSim.Services.Interfaces; using OpenSim.Services.Base; -using Nini.Config; -using log4net; namespace OpenSim.Services.Friends { @@ -80,7 +79,11 @@ namespace OpenSim.Services.Friends m_Database = LoadPlugin(dllName, new Object[] { connString, realm }); if (m_Database == null) - throw new Exception("Could not find a storage interface in the given module"); + { + throw new Exception( + string.Format( + "Could not find a storage interface {0} in the given StorageProvider {1}", "IFriendsData", dllName)); + } } } } diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index 1d734ebc2f..ee93f73cde 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs @@ -247,6 +247,7 @@ namespace OpenSim.Services.LLLoginService LLLoginResponse response = new LLLoginResponse(account, aCircuit, presence, destination, inventorySkel, friendsList, m_LibraryService, where, startLocation, position, lookAt, m_WelcomeMessage, home, clientIP); + m_log.DebugFormat("[LLOGIN SERVICE]: All clear. Sending login response to client."); return response; } catch (Exception e) diff --git a/OpenSim/Services/UserAccountService/UserAccountService.cs b/OpenSim/Services/UserAccountService/UserAccountService.cs index e498bd5e70..ca6e44ac14 100644 --- a/OpenSim/Services/UserAccountService/UserAccountService.cs +++ b/OpenSim/Services/UserAccountService/UserAccountService.cs @@ -280,6 +280,15 @@ namespace OpenSim.Services.UserAccountService if (null == account) { account = new UserAccount(UUID.Zero, firstName, lastName, email); + if (account.ServiceURLs == null) + { + account.ServiceURLs = new Dictionary(); + account.ServiceURLs["HomeURI"] = string.Empty; + account.ServiceURLs["GatekeeperURI"] = string.Empty; + account.ServiceURLs["InventoryServerURI"] = string.Empty; + account.ServiceURLs["AssetServerURI"] = string.Empty; + } + if (StoreUserAccount(account)) { bool success = false; diff --git a/bin/config-include/Standalone.ini b/bin/config-include/Standalone.ini index bf693a18ec..30113708a1 100644 --- a/bin/config-include/Standalone.ini +++ b/bin/config-include/Standalone.ini @@ -24,10 +24,11 @@ [InventoryService] LocalServiceModule = "OpenSim.Services.InventoryService.dll:InventoryService" + [LibraryService] - LocalServiceModule = "OpenSim.Services.InventoryService.dll:LibraryService" - LibraryName = "OpenSim Library" - DefaultLibrary = "./inventory/Libraries.xml" + LocalServiceModule = "OpenSim.Services.InventoryService.dll:LibraryService" + LibraryName = "OpenSim Library" + DefaultLibrary = "./inventory/Libraries.xml" [AvatarService] LocalServiceModule = "OpenSim.Services.AvatarService.dll:AvatarService" @@ -52,6 +53,7 @@ [UserAccountService] LocalServiceModule = "OpenSim.Services.UserAccountService.dll:UserAccountService" ConnectionString = "URI=file:userprofiles.db,version=3" + ;; These are for creating new accounts AuthenticationService = "OpenSim.Services.AuthenticationService.dll:PasswordAuthenticationService" PresenceService = "OpenSim.Services.PresenceService.dll:PresenceService" diff --git a/prebuild.xml b/prebuild.xml index cdf11694e1..dab3512637 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -157,6 +157,7 @@ + @@ -1569,42 +1570,6 @@ - - - - ../../../../bin/ - - - - - ../../../../bin/ - - - - ../../../../bin/ - - - - - - - - - - - - - - - - - - - - - - - @@ -1629,7 +1594,6 @@ - @@ -1669,7 +1633,6 @@ - @@ -1743,10 +1706,7 @@ - - - @@ -2815,7 +2775,6 @@ - @@ -3049,7 +3008,6 @@ - @@ -3113,7 +3071,6 @@ -