Merge master into teravuswork

avinationmerge
teravus 2012-11-15 09:46:41 -05:00
commit dfac269032
336 changed files with 31041 additions and 13214 deletions

6
.gitignore vendored
View File

@ -29,9 +29,14 @@ addon-modules/
bin/Debug/*.dll bin/Debug/*.dll
bin/*.dll.mdb bin/*.dll.mdb
bin/*.db bin/*.db
bin/*.db-journal
bin/addin-db-* bin/addin-db-*
bin/*.dll bin/*.dll
bin/OpenSim.vshost.exe.config bin/OpenSim.vshost.exe.config
bin/OpenSim.32BitLaunch.vshost.exe.config
bin/OpenSim.32BitLaunch.log
UpgradeLog.XML
_UpgradeReport_Files/
bin/ScriptEngines/*-*-*-*-* bin/ScriptEngines/*-*-*-*-*
bin/ScriptEngines/*.dll bin/ScriptEngines/*.dll
bin/ScriptEngines/*/*.dll bin/ScriptEngines/*/*.dll
@ -64,6 +69,7 @@ Examples/*.dll
OpenSim.build OpenSim.build
OpenSim.sln OpenSim.sln
OpenSim.suo OpenSim.suo
OpenSim.userprefs
Prebuild/Prebuild.build Prebuild/Prebuild.build
Prebuild/Prebuild.sln Prebuild/Prebuild.sln
TestResult.xml TestResult.xml

View File

@ -135,14 +135,25 @@
<delete dir="%temp%"/> <delete dir="%temp%"/>
</target> </target>
<target name="torture" depends="build, find-nunit"> <target name="test-stress" depends="build, find-nunit">
<setenv name="MONO_THREADS_PER_CPU" value="100" /> <setenv name="MONO_THREADS_PER_CPU" value="100" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests.torture"> <exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests.stress">
<arg value="./bin/OpenSim.Tests.Torture.dll" /> <arg value="./bin/OpenSim.Tests.Stress.dll" />
</exec> </exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.tests.torture)==0}" /> <fail message="Failures reported in stress tests." unless="${int::parse(testresult.opensim.tests.stress)==0}" />
<delete dir="%temp%"/>
</target>
<target name="test-perf" depends="build, find-nunit">
<setenv name="MONO_THREADS_PER_CPU" value="100" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests.performance">
<arg value="./bin/OpenSim.Tests.Performance.dll" />
</exec>
<fail message="Failures reported in performance tests." unless="${int::parse(testresult.opensim.tests.performance)==0}" />
<delete dir="%temp%"/> <delete dir="%temp%"/>
</target> </target>

View File

@ -1,6 +1,4 @@
==== Building OpenSim ==== # Building on Windows
=== Building on Windows ===
Steps: Steps:
* runprebuild.bat * runprebuild.bat
@ -9,16 +7,15 @@ Steps:
* copy OpenSim.ini.example to OpenSim.ini and other appropriate files in bin/config-include * copy OpenSim.ini.example to OpenSim.ini and other appropriate files in bin/config-include
* run OpenSim.exe * run OpenSim.exe
=== Building on Linux === # Building on Linux
Prereqs: Prereqs:
* Mono >= 2.4.3 * Mono >= 2.4.3
* Nant >= 0.85 * Nant >= 0.85
* On some Linux distributions you may need to install additional packages. * On some Linux distributions you may need to install additional packages.
See http://opensimulator.org/wiki/Dependencies for more information. See http://opensimulator.org/wiki/Dependencies for more information.
* May also use xbuild (included in mono distributions)
* May also use xbuild (included in mono distributions) * May use Monodevelop, a cross-platform IDE
* May use Monodevelop, a cross-platform IDE
From the distribution type: From the distribution type:
* ./runprebuild.sh * ./runprebuild.sh
@ -27,13 +24,13 @@ From the distribution type:
* copy OpenSim.ini.example to OpenSim.ini and other appropriate files in bin/config-include * copy OpenSim.ini.example to OpenSim.ini and other appropriate files in bin/config-include
* run mono OpenSim.exe * run mono OpenSim.exe
=== Using Monodevelop === # Using Monodevelop
From the distribution type: From the distribution type:
* ./runprebuild.sh * ./runprebuild.sh
* type monodevelop OpenSim.sln * type monodevelop OpenSim.sln
=== References === # References
Helpful resources: Helpful resources:
* http://opensimulator.org/wiki/Build_Instructions * http://opensimulator.org/wiki/Build_Instructions

View File

@ -1,4 +1,4 @@
<<<>>>>The following people have contributed to OpenSim (Thank you <<<>>>>The following people have contributed to OpenSim (Thank you
for your effort!) for your effort!)
= Current OpenSim Developers (in very rough order of appearance) = = Current OpenSim Developers (in very rough order of appearance) =
@ -16,7 +16,7 @@ people that make the day to day of OpenSim happen.
* BlueWall (James Hughes) * BlueWall (James Hughes)
* Nebadon Izumi (Michael Cerquoni, OSgrid) * Nebadon Izumi (Michael Cerquoni, OSgrid)
* Snoopy Pfeffer * Snoopy Pfeffer
* Richard Adams (Intel) * Robert Adams (Intel)
= Core Developers Following the White Rabbit = = Core Developers Following the White Rabbit =
Core developers who have temporarily (we hope) gone chasing the white rabbit. Core developers who have temporarily (we hope) gone chasing the white rabbit.
@ -92,6 +92,7 @@ what it is today.
* Flyte Xevious * Flyte Xevious
* Garmin Kawaguichi * Garmin Kawaguichi
* Gryc Ueusp * Gryc Ueusp
* Hiro Lecker
* Imaze Rhiano * Imaze Rhiano
* Intimidated * Intimidated
* Jeremy Bongio (IBM) * Jeremy Bongio (IBM)
@ -181,12 +182,14 @@ what it is today.
This software uses components from the following developers: This software uses components from the following developers:
* Sleepycat Software (Berkeley DB) * Sleepycat Software (Berkeley DB)
* Aurora-Sim (http://aurora-sim.org)
* SQLite (Public Domain) * SQLite (Public Domain)
* XmlRpcCS (http://xmlrpccs.sf.net/) * XmlRpcCS (http://xmlrpccs.sf.net/)
* MySQL, Inc. (MySQL Connector/NET) * MySQL, Inc. (MySQL Connector/NET)
* NUnit (http://www.nunit.org) * NUnit (http://www.nunit.org)
* AGEIA Inc. (PhysX) * AGEIA Inc. (PhysX)
* Russel L. Smith (ODE) * Russel L. Smith (ODE)
* Erwin Coumans (Bullet)
* Prebuild (http://sourceforge.net/projects/dnpb/) * Prebuild (http://sourceforge.net/projects/dnpb/)
* LibOpenMetaverse (http://lib.openmetaverse.org/) * LibOpenMetaverse (http://lib.openmetaverse.org/)
* DotNetOpenMail v0.5.8b (http://dotnetopenmail.sourceforge.net) * DotNetOpenMail v0.5.8b (http://dotnetopenmail.sourceforge.net)
@ -208,3 +211,4 @@ In addition, we would like to thank:
* The NANT Developers * The NANT Developers
* Microsoft (.NET, MSSQL-Adapters) * Microsoft (.NET, MSSQL-Adapters)
*x *x

View File

@ -696,7 +696,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
region.ExternalHostName = (string) requestData["external_address"]; region.ExternalHostName = (string) requestData["external_address"];
bool persist = Convert.ToBoolean((string) requestData["persist"]); bool persist = Convert.ToBoolean(requestData["persist"]);
if (persist) if (persist)
{ {
// default place for region configuration files is in the // default place for region configuration files is in the
@ -852,7 +852,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
responseData["success"] = true; responseData["success"] = true;
responseData["region_name"] = region.RegionName; responseData["region_name"] = region.RegionName;
responseData["region_id"] = region.RegionID.ToString(); responseData["region_id"] = region.RegionID.ToString();
responseData["region_uuid"] = region.RegionID.ToString(); //Deprecate July 2012
m_log.Info("[RADMIN]: CreateRegion: request complete"); m_log.Info("[RADMIN]: CreateRegion: request complete");
} }
@ -1106,8 +1105,8 @@ namespace OpenSim.ApplicationPlugins.RemoteController
string lastName = (string) requestData["user_lastname"]; string lastName = (string) requestData["user_lastname"];
string password = (string) requestData["user_password"]; string password = (string) requestData["user_password"];
uint regionXLocation = Convert.ToUInt32((Int32) requestData["start_region_x"]); uint regionXLocation = Convert.ToUInt32(requestData["start_region_x"]);
uint regionYLocation = Convert.ToUInt32((Int32) requestData["start_region_y"]); uint regionYLocation = Convert.ToUInt32(requestData["start_region_y"]);
string email = ""; // empty string for email string email = ""; // empty string for email
if (requestData.Contains("user_email")) if (requestData.Contains("user_email"))
@ -1304,9 +1303,9 @@ namespace OpenSim.ApplicationPlugins.RemoteController
if (requestData.ContainsKey("user_password")) password = (string) requestData["user_password"]; if (requestData.ContainsKey("user_password")) password = (string) requestData["user_password"];
if (requestData.ContainsKey("start_region_x")) if (requestData.ContainsKey("start_region_x"))
regionXLocation = Convert.ToUInt32((Int32) requestData["start_region_x"]); regionXLocation = Convert.ToUInt32(requestData["start_region_x"]);
if (requestData.ContainsKey("start_region_y")) if (requestData.ContainsKey("start_region_y"))
regionYLocation = Convert.ToUInt32((Int32) requestData["start_region_y"]); regionYLocation = Convert.ToUInt32(requestData["start_region_y"]);
// if (requestData.ContainsKey("start_lookat_x")) // if (requestData.ContainsKey("start_lookat_x"))
// ulaX = Convert.ToUInt32((Int32) requestData["start_lookat_x"]); // ulaX = Convert.ToUInt32((Int32) requestData["start_lookat_x"]);
@ -1493,6 +1492,8 @@ namespace OpenSim.ApplicationPlugins.RemoteController
/// <description>profile url</description></item> /// <description>profile url</description></item>
/// <item><term>noassets</term> /// <item><term>noassets</term>
/// <description>true if no assets should be saved</description></item> /// <description>true if no assets should be saved</description></item>
/// <item><term>all</term>
/// <description>true to save all the regions in the simulator</description></item>
/// <item><term>perm</term> /// <item><term>perm</term>
/// <description>C and/or T</description></item> /// <description>C and/or T</description></item>
/// </list> /// </list>
@ -1549,6 +1550,11 @@ namespace OpenSim.ApplicationPlugins.RemoteController
options["checkPermissions"] = (string)requestData["perm"]; options["checkPermissions"] = (string)requestData["perm"];
} }
if ((string)requestData["all"] == "true")
{
options["all"] = (string)requestData["all"];
}
IRegionArchiverModule archiver = scene.RequestModuleInterface<IRegionArchiverModule>(); IRegionArchiverModule archiver = scene.RequestModuleInterface<IRegionArchiverModule>();
if (archiver != null) if (archiver != null)
@ -2008,29 +2014,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
{ {
return; return;
} }
#region Deprecate July 2012
//region_ID, regionid, region_uuid will be deprecated in July 2012!!!!!!
else if (requestData.ContainsKey("regionid") &&
!String.IsNullOrEmpty((string)requestData["regionid"]))
{
m_log.WarnFormat("[RADMIN]: Use of parameter regionid will be deprecated as of July 2012. Use region_id instead");
}
else if (requestData.ContainsKey("region_ID") &&
!String.IsNullOrEmpty((string)requestData["region_ID"]))
{
m_log.WarnFormat("[RADMIN]: Use of parameter region_ID will be deprecated as of July 2012. Use region_id instead");
}
else if (requestData.ContainsKey("regionID") &&
!String.IsNullOrEmpty((string)requestData["regionID"]))
{
m_log.WarnFormat("[RADMIN]: Use of parameter regionID will be deprecated as of July 2012. Use region_id instead");
}
else if (requestData.ContainsKey("region_uuid") &&
!String.IsNullOrEmpty((string)requestData["region_uuid"]))
{
m_log.WarnFormat("[RADMIN]: Use of parameter region_uuid will be deprecated as of July 2012. Use region_id instead");
}
#endregion
else else
{ {
responseData["accepted"] = false; responseData["accepted"] = false;
@ -2052,56 +2035,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
throw new Exception(String.Format("Region ID {0} not found", regionID)); throw new Exception(String.Format("Region ID {0} not found", regionID));
} }
} }
#region Deprecate July 2012
else if (requestData.ContainsKey("regionid") &&
!String.IsNullOrEmpty((string)requestData["regionid"]))
{
m_log.WarnFormat("[RADMIN]: Use of parameter regionid will be deprecated as of July 2012. Use region_id instead");
UUID regionID = (UUID)(string)requestData["regionid"];
if (!m_application.SceneManager.TryGetScene(regionID, out scene))
{
responseData["error"] = String.Format("Region ID {0} not found", regionID);
throw new Exception(String.Format("Region ID {0} not found", regionID));
}
}
else if (requestData.ContainsKey("region_ID") &&
!String.IsNullOrEmpty((string)requestData["region_ID"]))
{
m_log.WarnFormat("[RADMIN]: Use of parameter region_ID will be deprecated as of July 2012. Use region_id instead");
UUID regionID = (UUID)(string)requestData["region_ID"];
if (!m_application.SceneManager.TryGetScene(regionID, out scene))
{
responseData["error"] = String.Format("Region ID {0} not found", regionID);
throw new Exception(String.Format("Region ID {0} not found", regionID));
}
}
else if (requestData.ContainsKey("regionID") &&
!String.IsNullOrEmpty((string)requestData["regionID"]))
{
m_log.WarnFormat("[RADMIN]: Use of parameter regionID will be deprecated as of July 2012. Use region_id instead");
UUID regionID = (UUID)(string)requestData["regionID"];
if (!m_application.SceneManager.TryGetScene(regionID, out scene))
{
responseData["error"] = String.Format("Region ID {0} not found", regionID);
throw new Exception(String.Format("Region ID {0} not found", regionID));
}
}
else if (requestData.ContainsKey("region_uuid") &&
!String.IsNullOrEmpty((string)requestData["region_uuid"]))
{
m_log.WarnFormat("[RADMIN]: Use of parameter region_uuid will be deprecated as of July 2012. Use region_id instead");
UUID regionID = (UUID)(string)requestData["region_uuid"];
if (!m_application.SceneManager.TryGetScene(regionID, out scene))
{
responseData["error"] = String.Format("Region ID {0} not found", regionID);
throw new Exception(String.Format("Region ID {0} not found", regionID));
}
}
#endregion
else if (requestData.ContainsKey("region_name") && else if (requestData.ContainsKey("region_name") &&
!String.IsNullOrEmpty((string)requestData["region_name"])) !String.IsNullOrEmpty((string)requestData["region_name"]))
{ {

View File

@ -312,14 +312,16 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
// Now that everything is setup we can proceed to // Now that everything is setup we can proceed to
// add THIS agent to the HTTP server's handler list // add THIS agent to the HTTP server's handler list
if (!AddAgentHandler(Rest.Name,this)) // FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
{ // have to be handled through the AddHttpHandler interface.
Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId); // if (!AddAgentHandler(Rest.Name,this))
foreach (IRest handler in handlers) // {
{ // Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId);
handler.Close(); // foreach (IRest handler in handlers)
} // {
} // handler.Close();
// }
// }
} }
catch (Exception e) catch (Exception e)
@ -342,11 +344,13 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
{ {
Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId); Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId);
try // FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
{ // have to be handled through the AddHttpHandler interface.
RemoveAgentHandler(Rest.Name, this); // try
} // {
catch (KeyNotFoundException){} // RemoveAgentHandler(Rest.Name, this);
// }
// catch (KeyNotFoundException){}
foreach (IRest handler in handlers) foreach (IRest handler in handlers)
{ {

View File

@ -297,7 +297,9 @@ namespace OpenSim.ApplicationPlugins.Rest
{ {
if (!IsEnabled) return false; if (!IsEnabled) return false;
_agents.Add(agentName, handler); _agents.Add(agentName, handler);
return _httpd.AddAgentHandler(agentName, handler); // return _httpd.AddAgentHandler(agentName, handler);
return false;
} }
/// <summary> /// <summary>
@ -316,7 +318,7 @@ namespace OpenSim.ApplicationPlugins.Rest
if (_agents[agentName] == handler) if (_agents[agentName] == handler)
{ {
_agents.Remove(agentName); _agents.Remove(agentName);
return _httpd.RemoveAgentHandler(agentName, handler); // return _httpd.RemoveAgentHandler(agentName, handler);
} }
return false; return false;
} }
@ -358,10 +360,10 @@ namespace OpenSim.ApplicationPlugins.Rest
_httpd.RemoveStreamHandler(h.HttpMethod, h.Path); _httpd.RemoveStreamHandler(h.HttpMethod, h.Path);
} }
_handlers = null; _handlers = null;
foreach (KeyValuePair<string, IHttpAgentHandler> h in _agents) // foreach (KeyValuePair<string, IHttpAgentHandler> h in _agents)
{ // {
_httpd.RemoveAgentHandler(h.Key, h.Value); // _httpd.RemoveAgentHandler(h.Key, h.Value);
} // }
_agents = null; _agents = null;
} }

View File

@ -200,11 +200,25 @@ namespace OpenSim.Capabilities.Handlers
int start, end; int start, end;
if (TryParseRange(range, out start, out end)) if (TryParseRange(range, out start, out end))
{ {
// Before clamping start make sure we can satisfy it in order to avoid // Before clamping start make sure we can satisfy it in order to avoid
// sending back the last byte instead of an error status // sending back the last byte instead of an error status
if (start >= texture.Data.Length) if (start >= texture.Data.Length)
{ {
// m_log.DebugFormat(
// "[GETTEXTURE]: Client requested range for texture {0} starting at {1} but texture has end of {2}",
// texture.ID, start, texture.Data.Length);
// Stricly speaking, as per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, we should be sending back
// Requested Range Not Satisfiable (416) here. However, it appears that at least recent implementations
// of the Linden Lab viewer (3.2.1 and 3.3.4 and probably earlier), a viewer that has previously
// received a very small texture may attempt to fetch bytes from the server past the
// range of data that it received originally. Whether this happens appears to depend on whether
// the viewer's estimation of how large a request it needs to make for certain discard levels
// (http://wiki.secondlife.com/wiki/Image_System#Discard_Level_and_Mip_Mapping), chiefly discard
// level 2. If this estimate is greater than the total texture size, returning a RequestedRangeNotSatisfiable
// here will cause the viewer to treat the texture as bad and never display the full resolution
// However, if we return PartialContent (or OK) instead, the viewer will display that resolution.
// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; // response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable;
// viewers don't seem to handle RequestedRangeNotSatisfiable and keep retrying with same parameters // viewers don't seem to handle RequestedRangeNotSatisfiable and keep retrying with same parameters
response["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound; response["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
@ -215,7 +229,7 @@ namespace OpenSim.Capabilities.Handlers
start = Utils.Clamp(start, 0, end); start = Utils.Clamp(start, 0, end);
int len = end - start + 1; int len = end - start + 1;
//m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); // m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
response["content-type"] = texture.Metadata.ContentType; response["content-type"] = texture.Metadata.ContentType;

View File

@ -85,21 +85,6 @@ namespace OpenSim.Data
List<RegionData> GetHyperlinks(UUID scopeID); List<RegionData> GetHyperlinks(UUID scopeID);
} }
[Flags]
public enum RegionFlags : int
{
DefaultRegion = 1, // Used for new Rez. Random if multiple defined
FallbackRegion = 2, // Regions we redirect to when the destination is down
RegionOnline = 4, // Set when a region comes online, unset when it unregisters and DeleteOnUnregister is false
NoDirectLogin = 8, // Region unavailable for direct logins (by name)
Persistent = 16, // Don't remove on unregister
LockedOut = 32, // Don't allow registration
NoMove = 64, // Don't allow moving this region
Reservation = 128, // This is an inactive reservation
Authenticate = 256, // Require authentication
Hyperlink = 512 // Record represents a HG link
}
public class RegionDataDistanceCompare : IComparer<RegionData> public class RegionDataDistanceCompare : IComparer<RegionData>
{ {
private Vector2 m_origin; private Vector2 m_origin;

View File

@ -40,6 +40,11 @@ namespace OpenSim.Data
public UUID folderID; public UUID folderID;
public UUID agentID; public UUID agentID;
public UUID parentFolderID; public UUID parentFolderID;
public XInventoryFolder Clone()
{
return (XInventoryFolder)MemberwiseClone();
}
} }
public class XInventoryItem public class XInventoryItem
@ -64,6 +69,11 @@ namespace OpenSim.Data
public UUID avatarID; public UUID avatarID;
public UUID parentFolderID; public UUID parentFolderID;
public int inventoryGroupPermissions; public int inventoryGroupPermissions;
public XInventoryItem Clone()
{
return (XInventoryItem)MemberwiseClone();
}
} }
public interface IXInventoryData public interface IXInventoryData

View File

@ -37,6 +37,7 @@ using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using RegionFlags = OpenSim.Framework.RegionFlags;
namespace OpenSim.Data.MSSQL namespace OpenSim.Data.MSSQL
{ {

View File

@ -30,11 +30,11 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.Reflection; using System.Reflection;
using MySql.Data.MySqlClient;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Data; using OpenSim.Data;
using MySql.Data.MySqlClient; using RegionFlags = OpenSim.Framework.RegionFlags;
namespace OpenSim.Data.MySQL namespace OpenSim.Data.MySQL
{ {

View File

@ -747,6 +747,8 @@ namespace OpenSim.Data.MySQL
RegionLightShareData nWP = new RegionLightShareData(); RegionLightShareData nWP = new RegionLightShareData();
nWP.OnSave += StoreRegionWindlightSettings; nWP.OnSave += StoreRegionWindlightSettings;
lock (m_dbLock)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{ {
dbcon.Open(); dbcon.Open();
@ -764,7 +766,7 @@ namespace OpenSim.Data.MySQL
{ {
//No result, so store our default windlight profile and return it //No result, so store our default windlight profile and return it
nWP.regionID = regionUUID; nWP.regionID = regionUUID;
// StoreRegionWindlightSettings(nWP); // StoreRegionWindlightSettings(nWP);
return nWP; return nWP;
} }
else else
@ -836,6 +838,8 @@ namespace OpenSim.Data.MySQL
} }
} }
} }
}
return nWP; return nWP;
} }
@ -880,6 +884,8 @@ namespace OpenSim.Data.MySQL
} }
public virtual void StoreRegionWindlightSettings(RegionLightShareData wl) public virtual void StoreRegionWindlightSettings(RegionLightShareData wl)
{
lock (m_dbLock)
{ {
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{ {
@ -981,8 +987,11 @@ namespace OpenSim.Data.MySQL
} }
} }
} }
}
public virtual void RemoveRegionWindlightSettings(UUID regionID) public virtual void RemoveRegionWindlightSettings(UUID regionID)
{
lock (m_dbLock)
{ {
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{ {
@ -996,9 +1005,12 @@ namespace OpenSim.Data.MySQL
} }
} }
} }
}
#region RegionEnvironmentSettings #region RegionEnvironmentSettings
public string LoadRegionEnvironmentSettings(UUID regionUUID) public string LoadRegionEnvironmentSettings(UUID regionUUID)
{
lock (m_dbLock)
{ {
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{ {
@ -1024,8 +1036,11 @@ namespace OpenSim.Data.MySQL
} }
} }
} }
}
public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings)
{
lock (m_dbLock)
{ {
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{ {
@ -1042,8 +1057,11 @@ namespace OpenSim.Data.MySQL
} }
} }
} }
}
public void RemoveRegionEnvironmentSettings(UUID regionUUID) public void RemoveRegionEnvironmentSettings(UUID regionUUID)
{
lock (m_dbLock)
{ {
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{ {
@ -1057,6 +1075,7 @@ namespace OpenSim.Data.MySQL
} }
} }
} }
}
#endregion #endregion
public virtual void StoreRegionSettings(RegionSettings rs) public virtual void StoreRegionSettings(RegionSettings rs)

View File

@ -17,3 +17,8 @@ CREATE TABLE `GridUser` (
) ENGINE=InnoDB; ) ENGINE=InnoDB;
COMMIT; COMMIT;
:VERSION 2 # --------------------------
BEGIN;
COMMIT;

View File

@ -33,6 +33,7 @@ using OpenSim.Framework;
using OpenSim.Data; using OpenSim.Data;
using System.Reflection; using System.Reflection;
using log4net; using log4net;
using RegionFlags = OpenSim.Framework.RegionFlags;
namespace OpenSim.Data.Null namespace OpenSim.Data.Null
{ {

View File

@ -1366,6 +1366,13 @@ namespace OpenSim.Data.SQLite
createCol(land, "UserLookAtZ", typeof(Double)); createCol(land, "UserLookAtZ", typeof(Double));
createCol(land, "AuthbuyerID", typeof(String)); createCol(land, "AuthbuyerID", typeof(String));
createCol(land, "OtherCleanTime", typeof(Int32)); createCol(land, "OtherCleanTime", typeof(Int32));
createCol(land, "Dwell", typeof(Int32));
createCol(land, "MediaType", typeof(String));
createCol(land, "MediaDescription", typeof(String));
createCol(land, "MediaSize", typeof(String));
createCol(land, "MediaLoop", typeof(Boolean));
createCol(land, "ObscureMedia", typeof(Boolean));
createCol(land, "ObscureMusic", typeof(Boolean));
land.PrimaryKey = new DataColumn[] { land.Columns["UUID"] }; land.PrimaryKey = new DataColumn[] { land.Columns["UUID"] };
@ -1781,9 +1788,16 @@ namespace OpenSim.Data.SQLite
newData.PassHours = Convert.ToSingle(row["PassHours"]); newData.PassHours = Convert.ToSingle(row["PassHours"]);
newData.PassPrice = Convert.ToInt32(row["PassPrice"]); newData.PassPrice = Convert.ToInt32(row["PassPrice"]);
newData.SnapshotID = (UUID)(String)row["SnapshotUUID"]; newData.SnapshotID = (UUID)(String)row["SnapshotUUID"];
newData.Dwell = Convert.ToInt32(row["Dwell"]);
newData.MediaType = (String)row["MediaType"];
newData.MediaDescription = (String)row["MediaDescription"];
newData.MediaWidth = Convert.ToInt32((((string)row["MediaSize"]).Split(','))[0]);
newData.MediaHeight = Convert.ToInt32((((string)row["MediaSize"]).Split(','))[1]);
newData.MediaLoop = Convert.ToBoolean(row["MediaLoop"]);
newData.ObscureMedia = Convert.ToBoolean(row["ObscureMedia"]);
newData.ObscureMusic = Convert.ToBoolean(row["ObscureMusic"]);
try try
{ {
newData.UserLocation = newData.UserLocation =
new Vector3(Convert.ToSingle(row["UserLocationX"]), Convert.ToSingle(row["UserLocationY"]), new Vector3(Convert.ToSingle(row["UserLocationX"]), Convert.ToSingle(row["UserLocationY"]),
Convert.ToSingle(row["UserLocationZ"])); Convert.ToSingle(row["UserLocationZ"]));
@ -2195,12 +2209,13 @@ namespace OpenSim.Data.SQLite
row["UserLookAtZ"] = land.UserLookAt.Z; row["UserLookAtZ"] = land.UserLookAt.Z;
row["AuthbuyerID"] = land.AuthBuyerID.ToString(); row["AuthbuyerID"] = land.AuthBuyerID.ToString();
row["OtherCleanTime"] = land.OtherCleanTime; row["OtherCleanTime"] = land.OtherCleanTime;
row["Dwell"] = land.Dwell;
row["MediaType"] = land.MediaType; row["MediaType"] = land.MediaType;
row["MediaDescription"] = land.MediaDescription; row["MediaDescription"] = land.MediaDescription;
row["MediaSize"] = land.MediaWidth.ToString() + "," + land.MediaHeight.ToString(); row["MediaSize"] = String.Format("{0},{1}", land.MediaWidth, land.MediaHeight);
row["MediaLoop"] = land.MediaLoop.ToString(); row["MediaLoop"] = land.MediaLoop;
row["ObscureMusic"] = land.ObscureMusic.ToString(); row["ObscureMusic"] = land.ObscureMusic;
row["ObscureMedia"] = land.ObscureMedia.ToString(); row["ObscureMedia"] = land.ObscureMedia;
} }
/// <summary> /// <summary>

View File

@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Nini.Config;
using log4net;
using OpenMetaverse;
namespace OpenSim.Framework
{
public class AssetPermissions
{
private static readonly ILog m_log =
LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType);
private bool[] m_DisallowExport, m_DisallowImport;
private string[] m_AssetTypeNames;
public AssetPermissions(IConfig config)
{
Type enumType = typeof(AssetType);
m_AssetTypeNames = Enum.GetNames(enumType);
for (int i = 0; i < m_AssetTypeNames.Length; i++)
m_AssetTypeNames[i] = m_AssetTypeNames[i].ToLower();
int n = Enum.GetValues(enumType).Length;
m_DisallowExport = new bool[n];
m_DisallowImport = new bool[n];
LoadPermsFromConfig(config, "DisallowExport", m_DisallowExport);
LoadPermsFromConfig(config, "DisallowImport", m_DisallowImport);
}
private void LoadPermsFromConfig(IConfig assetConfig, string variable, bool[] bitArray)
{
if (assetConfig == null)
return;
string perms = assetConfig.GetString(variable, String.Empty);
string[] parts = perms.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string s in parts)
{
int index = Array.IndexOf(m_AssetTypeNames, s.Trim().ToLower());
if (index >= 0)
bitArray[index] = true;
else
m_log.WarnFormat("[Asset Permissions]: Invalid AssetType {0}", s);
}
}
public bool AllowedExport(sbyte type)
{
string assetTypeName = ((AssetType)type).ToString();
int index = Array.IndexOf(m_AssetTypeNames, assetTypeName.ToLower());
if (index >= 0 && m_DisallowExport[index])
{
m_log.DebugFormat("[Asset Permissions]: Export denied: configuration does not allow export of AssetType {0}", assetTypeName);
return false;
}
return true;
}
public bool AllowedImport(sbyte type)
{
string assetTypeName = ((AssetType)type).ToString();
int index = Array.IndexOf(m_AssetTypeNames, assetTypeName.ToLower());
if (index >= 0 && m_DisallowImport[index])
{
m_log.DebugFormat("[Asset Permissions]: Import denied: configuration does not allow import of AssetType {0}", assetTypeName);
return false;
}
return true;
}
}
}

View File

@ -358,6 +358,9 @@ namespace OpenSim.Framework
SetVisualParams(visualParams); SetVisualParams(visualParams);
} }
/// <summary>
/// Set avatar height by a calculation based on their visual parameters.
/// </summary>
public virtual void SetHeight() public virtual void SetHeight()
{ {
// Start with shortest possible female avatar height // Start with shortest possible female avatar height

View File

@ -199,7 +199,14 @@ namespace OpenSim.Framework
// //
public class Cache public class Cache
{ {
/// <summary>
/// Must only be accessed under lock.
/// </summary>
private List<CacheItemBase> m_Index = new List<CacheItemBase>(); private List<CacheItemBase> m_Index = new List<CacheItemBase>();
/// <summary>
/// Must only be accessed under m_Index lock.
/// </summary>
private Dictionary<string, CacheItemBase> m_Lookup = private Dictionary<string, CacheItemBase> m_Lookup =
new Dictionary<string, CacheItemBase>(); new Dictionary<string, CacheItemBase>();
@ -320,7 +327,6 @@ namespace OpenSim.Framework
{ {
if (m_Lookup.ContainsKey(index)) if (m_Lookup.ContainsKey(index))
item = m_Lookup[index]; item = m_Lookup[index];
}
if (item == null) if (item == null)
{ {
@ -332,6 +338,7 @@ namespace OpenSim.Framework
item.lastUsed = DateTime.Now; item.lastUsed = DateTime.Now;
Expire(true); Expire(true);
}
return item; return item;
} }
@ -385,7 +392,10 @@ namespace OpenSim.Framework
// //
public Object Find(Predicate<CacheItemBase> d) public Object Find(Predicate<CacheItemBase> d)
{ {
CacheItemBase item = m_Index.Find(d); CacheItemBase item;
lock (m_Index)
item = m_Index.Find(d);
if (item == null) if (item == null)
return null; return null;
@ -419,12 +429,12 @@ namespace OpenSim.Framework
public virtual void Store(string index, Object data, Type container, public virtual void Store(string index, Object data, Type container,
Object[] parameters) Object[] parameters)
{ {
Expire(false);
CacheItemBase item; CacheItemBase item;
lock (m_Index) lock (m_Index)
{ {
Expire(false);
if (m_Index.Contains(new CacheItemBase(index))) if (m_Index.Contains(new CacheItemBase(index)))
{ {
if ((m_Flags & CacheFlags.AllowUpdate) != 0) if ((m_Flags & CacheFlags.AllowUpdate) != 0)
@ -450,9 +460,17 @@ namespace OpenSim.Framework
m_Index.Add(item); m_Index.Add(item);
m_Lookup[index] = item; m_Lookup[index] = item;
} }
item.Store(data); item.Store(data);
} }
/// <summary>
/// Expire items as appropriate.
/// </summary>
/// <remarks>
/// Callers must lock m_Index.
/// </remarks>
/// <param name='getting'></param>
protected virtual void Expire(bool getting) protected virtual void Expire(bool getting)
{ {
if (getting && (m_Strategy == CacheStrategy.Aggressive)) if (getting && (m_Strategy == CacheStrategy.Aggressive))
@ -479,8 +497,6 @@ namespace OpenSim.Framework
if (Count < Size) if (Count < Size)
return; return;
lock (m_Index)
{
m_Index.Sort(new SortLRU()); m_Index.Sort(new SortLRU());
m_Index.Reverse(); m_Index.Reverse();
@ -513,14 +529,17 @@ namespace OpenSim.Framework
foreach (CacheItemBase item in m_Index) foreach (CacheItemBase item in m_Index)
m_Lookup[item.uuid] = item; m_Lookup[item.uuid] = item;
} }
}
break; break;
default: default:
break; break;
} }
} }
public void Invalidate(string uuid) public void Invalidate(string uuid)
{
lock (m_Index)
{ {
if (!m_Lookup.ContainsKey(uuid)) if (!m_Lookup.ContainsKey(uuid))
return; return;
@ -529,11 +548,15 @@ namespace OpenSim.Framework
m_Lookup.Remove(uuid); m_Lookup.Remove(uuid);
m_Index.Remove(item); m_Index.Remove(item);
} }
}
public void Clear() public void Clear()
{
lock (m_Index)
{ {
m_Index.Clear(); m_Index.Clear();
m_Lookup.Clear(); m_Lookup.Clear();
} }
} }
}
} }

View File

@ -33,7 +33,8 @@ namespace OpenSim.Framework.Client
{ {
event ChatMessage OnChatFromClient; event ChatMessage OnChatFromClient;
void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, byte source, void SendChatMessage(
string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, UUID ownerID, byte source,
byte audible); byte audible);
} }
} }

View File

@ -0,0 +1,228 @@
/*
* 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.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using log4net;
using OpenMetaverse;
namespace OpenSim.Framework.Console
{
public class ConsoleUtil
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public const int LocalIdNotFound = 0;
/// <summary>
/// Used by modules to display stock co-ordinate help, though possibly this should be under some general section
/// rather than in each help summary.
/// </summary>
public const string CoordHelp
= @"Each component of the coord is comma separated. There must be no spaces between the commas.
If you don't care about the z component you can simply omit it.
If you don't care about the x or y components then you can leave them blank (though a comma is still required)
If you want to specify the maxmimum value of a component then you can use ~ instead of a number
If you want to specify the minimum value of a component then you can use -~ instead of a number
e.g.
delete object pos 20,20,20 to 40,40,40
delete object pos 20,20 to 40,40
delete object pos ,20,20 to ,40,40
delete object pos ,,30 to ,,~
delete object pos ,,-~ to ,,30";
public const string MinRawConsoleVectorValue = "-~";
public const string MaxRawConsoleVectorValue = "~";
public const string VectorSeparator = ",";
public static char[] VectorSeparatorChars = VectorSeparator.ToCharArray();
/// <summary>
/// Check if the given file path exists.
/// </summary>
/// <remarks>If not, warning is printed to the given console.</remarks>
/// <returns>true if the file does not exist, false otherwise.</returns>
/// <param name='console'></param>
/// <param name='path'></param>
public static bool CheckFileDoesNotExist(ICommandConsole console, string path)
{
if (File.Exists(path))
{
console.OutputFormat("File {0} already exists. Please move or remove it.", path);
return false;
}
return true;
}
/// <summary>
/// Try to parse a console UUID from the console.
/// </summary>
/// <remarks>
/// Will complain to the console if parsing fails.
/// </remarks>
/// <returns></returns>
/// <param name='console'>If null then no complaint is printed.</param>
/// <param name='rawUuid'></param>
/// <param name='uuid'></param>
public static bool TryParseConsoleUuid(ICommandConsole console, string rawUuid, out UUID uuid)
{
if (!UUID.TryParse(rawUuid, out uuid))
{
if (console != null)
console.OutputFormat("{0} is not a valid uuid", rawUuid);
return false;
}
return true;
}
public static bool TryParseConsoleLocalId(ICommandConsole console, string rawLocalId, out uint localId)
{
if (!uint.TryParse(rawLocalId, out localId))
{
if (console != null)
console.OutputFormat("{0} is not a valid local id", localId);
return false;
}
if (localId == 0)
{
if (console != null)
console.OutputFormat("{0} is not a valid local id - it must be greater than 0", localId);
return false;
}
return true;
}
/// <summary>
/// Tries to parse the input as either a UUID or a local ID.
/// </summary>
/// <returns>true if parsing succeeded, false otherwise.</returns>
/// <param name='console'></param>
/// <param name='rawId'></param>
/// <param name='uuid'></param>
/// <param name='localId'>
/// Will be set to ConsoleUtil.LocalIdNotFound if parsing result was a UUID or no parse succeeded.
/// </param>
public static bool TryParseConsoleId(ICommandConsole console, string rawId, out UUID uuid, out uint localId)
{
if (TryParseConsoleUuid(null, rawId, out uuid))
{
localId = LocalIdNotFound;
return true;
}
if (TryParseConsoleLocalId(null, rawId, out localId))
{
return true;
}
if (console != null)
console.OutputFormat("{0} is not a valid UUID or local id", rawId);
return false;
}
/// <summary>
/// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
/// </summary>
/// <param name='rawConsoleVector'>/param>
/// <param name='vector'></param>
/// <returns></returns>
public static bool TryParseConsoleMinVector(string rawConsoleVector, out Vector3 vector)
{
return TryParseConsoleVector(rawConsoleVector, c => float.MinValue.ToString(), out vector);
}
/// <summary>
/// Convert a maximum vector input from the console to an OpenMetaverse.Vector3
/// </summary>
/// <param name='rawConsoleVector'>/param>
/// <param name='vector'></param>
/// <returns></returns>
public static bool TryParseConsoleMaxVector(string rawConsoleVector, out Vector3 vector)
{
return TryParseConsoleVector(rawConsoleVector, c => float.MaxValue.ToString(), out vector);
}
/// <summary>
/// Convert a vector input from the console to an OpenMetaverse.Vector3
/// </summary>
/// <param name='rawConsoleVector'>
/// A string in the form <x>,<y>,<z> where there is no space between values.
/// Any component can be missing (e.g. ,,40). blankComponentFunc is invoked to replace the blank with a suitable value
/// Also, if the blank component is at the end, then the comma can be missed off entirely (e.g. 40,30 or 40)
/// The strings "~" and "-~" are valid in components. The first substitutes float.MaxValue whilst the second is float.MinValue
/// Other than that, component values must be numeric.
/// </param>
/// <param name='blankComponentFunc'></param>
/// <param name='vector'></param>
/// <returns></returns>
public static bool TryParseConsoleVector(
string rawConsoleVector, Func<string, string> blankComponentFunc, out Vector3 vector)
{
List<string> components = rawConsoleVector.Split(VectorSeparatorChars).ToList();
if (components.Count < 1 || components.Count > 3)
{
vector = Vector3.Zero;
return false;
}
for (int i = components.Count; i < 3; i++)
components.Add("");
List<string> semiDigestedComponents
= components.ConvertAll<string>(
c =>
{
if (c == "")
return blankComponentFunc.Invoke(c);
else if (c == MaxRawConsoleVectorValue)
return float.MaxValue.ToString();
else if (c == MinRawConsoleVectorValue)
return float.MinValue.ToString();
else
return c;
});
string semiDigestedConsoleVector = string.Join(VectorSeparator, semiDigestedComponents.ToArray());
// m_log.DebugFormat("[CONSOLE UTIL]: Parsing {0} into OpenMetaverse.Vector3", semiDigestedConsoleVector);
return Vector3.TryParse(semiDigestedConsoleVector, out vector);
}
}
}

View File

@ -31,6 +31,7 @@ namespace OpenSim.Framework
public class Constants public class Constants
{ {
public const uint RegionSize = 256; public const uint RegionSize = 256;
public const uint RegionHeight = 4096;
public const byte TerrainPatchSize = 16; public const byte TerrainPatchSize = 16;
public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f"; public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f";

View File

@ -419,11 +419,11 @@ namespace OpenSim.Framework
public void SetFromFlags(ulong regionFlags) public void SetFromFlags(ulong regionFlags)
{ {
ResetHomeOnTeleport = ((regionFlags & (ulong)RegionFlags.ResetHomeOnTeleport) == (ulong)RegionFlags.ResetHomeOnTeleport); ResetHomeOnTeleport = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.ResetHomeOnTeleport) == (ulong)OpenMetaverse.RegionFlags.ResetHomeOnTeleport);
BlockDwell = ((regionFlags & (ulong)RegionFlags.BlockDwell) == (ulong)RegionFlags.BlockDwell); BlockDwell = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.BlockDwell) == (ulong)OpenMetaverse.RegionFlags.BlockDwell);
AllowLandmark = ((regionFlags & (ulong)RegionFlags.AllowLandmark) == (ulong)RegionFlags.AllowLandmark); AllowLandmark = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowLandmark) == (ulong)OpenMetaverse.RegionFlags.AllowLandmark);
AllowParcelChanges = ((regionFlags & (ulong)RegionFlags.AllowParcelChanges) == (ulong)RegionFlags.AllowParcelChanges); AllowParcelChanges = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowParcelChanges) == (ulong)OpenMetaverse.RegionFlags.AllowParcelChanges);
AllowSetHome = ((regionFlags & (ulong)RegionFlags.AllowSetHome) == (ulong)RegionFlags.AllowSetHome); AllowSetHome = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowSetHome) == (ulong)OpenMetaverse.RegionFlags.AllowSetHome);
} }
public bool GroupAccess(UUID groupID) public bool GroupAccess(UUID groupID)

View File

@ -44,7 +44,6 @@ namespace OpenSim.Framework
public Vector3 Position; public Vector3 Position;
public byte[] binaryBucket; public byte[] binaryBucket;
public uint ParentEstateID; public uint ParentEstateID;
public Guid RegionID; public Guid RegionID;
public uint timestamp; public uint timestamp;
@ -58,7 +57,7 @@ namespace OpenSim.Framework
string _fromAgentName, UUID _toAgentID, string _fromAgentName, UUID _toAgentID,
byte _dialog, bool _fromGroup, string _message, byte _dialog, bool _fromGroup, string _message,
UUID _imSessionID, bool _offline, Vector3 _position, UUID _imSessionID, bool _offline, Vector3 _position,
byte[] _binaryBucket) byte[] _binaryBucket, bool addTimestamp)
{ {
fromAgentID = _fromAgentID.Guid; fromAgentID = _fromAgentID.Guid;
fromAgentName = _fromAgentName; fromAgentName = _fromAgentName;
@ -79,6 +78,8 @@ namespace OpenSim.Framework
ParentEstateID = scene.RegionInfo.EstateSettings.ParentEstateID; ParentEstateID = scene.RegionInfo.EstateSettings.ParentEstateID;
RegionID = scene.RegionInfo.RegionSettings.RegionUUID.Guid; RegionID = scene.RegionInfo.RegionSettings.RegionUUID.Guid;
} }
if (addTimestamp)
timestamp = (uint)Util.UnixTimeSinceEpoch(); timestamp = (uint)Util.UnixTimeSinceEpoch();
} }
@ -87,7 +88,7 @@ namespace OpenSim.Framework
string _message, bool _offline, string _message, bool _offline,
Vector3 _position) : this(scene, _fromAgentID, _fromAgentName, Vector3 _position) : this(scene, _fromAgentID, _fromAgentName,
_toAgentID, _dialog, false, _message, _toAgentID, _dialog, false, _message,
_fromAgentID ^ _toAgentID, _offline, _position, new byte[0]) _fromAgentID ^ _toAgentID, _offline, _position, new byte[0], true)
{ {
} }
} }

View File

@ -815,8 +815,23 @@ namespace OpenSim.Framework
event Action<IClientAPI> OnRegionHandShakeReply; event Action<IClientAPI> OnRegionHandShakeReply;
event GenericCall1 OnRequestWearables; event GenericCall1 OnRequestWearables;
event Action<IClientAPI, bool> OnCompleteMovementToRegion; event Action<IClientAPI, bool> OnCompleteMovementToRegion;
/// <summary>
/// Called when an AgentUpdate message is received and before OnAgentUpdate.
/// </summary>
/// <remarks>
/// Listeners must not retain a reference to AgentUpdateArgs since this object may be reused for subsequent AgentUpdates.
/// </remarks>
event UpdateAgent OnPreAgentUpdate; event UpdateAgent OnPreAgentUpdate;
/// <summary>
/// Called when an AgentUpdate message is received and after OnPreAgentUpdate.
/// </summary>
/// <remarks>
/// Listeners must not retain a reference to AgentUpdateArgs since this object may be reused for subsequent AgentUpdates.
/// </remarks>
event UpdateAgent OnAgentUpdate; event UpdateAgent OnAgentUpdate;
event AgentRequestSit OnAgentRequestSit; event AgentRequestSit OnAgentRequestSit;
event AgentSit OnAgentSit; event AgentSit OnAgentSit;
event AvatarPickerRequest OnAvatarPickerRequest; event AvatarPickerRequest OnAvatarPickerRequest;
@ -1046,8 +1061,21 @@ namespace OpenSim.Framework
void InPacket(object NewPack); void InPacket(object NewPack);
void ProcessInPacket(Packet NewPack); void ProcessInPacket(Packet NewPack);
/// <summary>
/// Close this client
/// </summary>
void Close(); void Close();
void Close(bool sendStop);
/// <summary>
/// Close this client
/// </summary>
/// <param name='force'>
/// If true, attempts the close without checking active status. You do not want to try this except as a last
/// ditch attempt where Active == false but the ScenePresence still exists.
/// </param>
void Close(bool sendStop, bool force);
void Kick(string message); void Kick(string message);
/// <summary> /// <summary>
@ -1084,7 +1112,19 @@ namespace OpenSim.Framework
void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs); void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs);
void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args); void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args);
void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, byte source, /// <summary>
/// Send chat to the viewer.
/// </summary>
/// <param name='message'></param>
/// <param name='type'></param>
/// <param name='fromPos'></param>
/// <param name='fromName'></param>
/// <param name='fromAgentID'></param>
/// <param name='ownerID'></param>
/// <param name='source'></param>
/// <param name='audible'></param>
void SendChatMessage(
string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, UUID ownerID, byte source,
byte audible); byte audible);
void SendInstantMessage(GridInstantMessage im); void SendInstantMessage(GridInstantMessage im);

View File

@ -73,32 +73,26 @@ namespace OpenSim.Framework
{ {
} }
public InventoryFolderBase(UUID id) public InventoryFolderBase(UUID id) : this()
{ {
ID = id; ID = id;
} }
public InventoryFolderBase(UUID id, UUID owner) public InventoryFolderBase(UUID id, UUID owner) : this(id)
{ {
ID = id;
Owner = owner; Owner = owner;
} }
public InventoryFolderBase(UUID id, string name, UUID owner, UUID parent) public InventoryFolderBase(UUID id, string name, UUID owner, UUID parent) : this(id, owner)
{ {
ID = id;
Name = name; Name = name;
Owner = owner;
ParentID = parent; ParentID = parent;
} }
public InventoryFolderBase(UUID id, string name, UUID owner, short type, UUID parent, ushort version) public InventoryFolderBase(
UUID id, string name, UUID owner, short type, UUID parent, ushort version) : this(id, name, owner, parent)
{ {
ID = id;
Name = name;
Owner = owner;
Type = type; Type = type;
ParentID = parent;
Version = version; Version = version;
} }
} }

View File

@ -49,7 +49,7 @@ namespace OpenSim.Framework
// use only one serializer to give the runtime a chance to // use only one serializer to give the runtime a chance to
// optimize it (it won't do that if you use a new instance // optimize it (it won't do that if you use a new instance
// every time) // every time)
private static XmlSerializer serializer = new XmlSerializer(typeof (LandData)); private static XmlSerializer serializer = new XmlSerializer(typeof(LandData));
private Vector3 _AABBMax = new Vector3(); private Vector3 _AABBMax = new Vector3();
private Vector3 _AABBMin = new Vector3(); private Vector3 _AABBMin = new Vector3();
@ -65,11 +65,11 @@ namespace OpenSim.Framework
private byte[] _bitmap = new byte[512]; private byte[] _bitmap = new byte[512];
private string _description = String.Empty; private string _description = String.Empty;
private uint _flags = (uint) ParcelFlags.AllowFly | (uint) ParcelFlags.AllowLandmark | private uint _flags = (uint)ParcelFlags.AllowFly | (uint)ParcelFlags.AllowLandmark |
(uint) ParcelFlags.AllowAPrimitiveEntry | (uint)ParcelFlags.AllowAPrimitiveEntry |
(uint) ParcelFlags.AllowDeedToGroup | (uint)ParcelFlags.AllowDeedToGroup |
(uint) ParcelFlags.CreateObjects | (uint) ParcelFlags.AllowOtherScripts | (uint)ParcelFlags.CreateObjects | (uint)ParcelFlags.AllowOtherScripts |
(uint) ParcelFlags.SoundLocal | (uint) ParcelFlags.AllowVoiceChat; (uint)ParcelFlags.AllowVoiceChat;
private byte _landingType = 0; private byte _landingType = 0;
private string _name = "Your Parcel"; private string _name = "Your Parcel";
@ -97,16 +97,36 @@ namespace OpenSim.Framework
private bool _mediaLoop = false; private bool _mediaLoop = false;
private bool _obscureMusic = false; private bool _obscureMusic = false;
private bool _obscureMedia = false; private bool _obscureMedia = false;
private float _dwell = 0;
/// <summary>
/// Traffic count of parcel
/// </summary>
[XmlIgnore]
public float Dwell
{
get
{
return _dwell;
}
set
{
_dwell = value;
}
}
/// <summary> /// <summary>
/// Whether to obscure parcel media URL /// Whether to obscure parcel media URL
/// </summary> /// </summary>
[XmlIgnore] [XmlIgnore]
public bool ObscureMedia { public bool ObscureMedia
get { {
get
{
return _obscureMedia; return _obscureMedia;
} }
set { set
{
_obscureMedia = value; _obscureMedia = value;
} }
} }
@ -115,11 +135,14 @@ namespace OpenSim.Framework
/// Whether to obscure parcel music URL /// Whether to obscure parcel music URL
/// </summary> /// </summary>
[XmlIgnore] [XmlIgnore]
public bool ObscureMusic { public bool ObscureMusic
get { {
get
{
return _obscureMusic; return _obscureMusic;
} }
set { set
{
_obscureMusic = value; _obscureMusic = value;
} }
} }
@ -128,11 +151,14 @@ namespace OpenSim.Framework
/// Whether to loop parcel media /// Whether to loop parcel media
/// </summary> /// </summary>
[XmlIgnore] [XmlIgnore]
public bool MediaLoop { public bool MediaLoop
get { {
get
{
return _mediaLoop; return _mediaLoop;
} }
set { set
{
_mediaLoop = value; _mediaLoop = value;
} }
} }
@ -141,11 +167,14 @@ namespace OpenSim.Framework
/// Height of parcel media render /// Height of parcel media render
/// </summary> /// </summary>
[XmlIgnore] [XmlIgnore]
public int MediaHeight { public int MediaHeight
get { {
get
{
return _mediaHeight; return _mediaHeight;
} }
set { set
{
_mediaHeight = value; _mediaHeight = value;
} }
} }
@ -154,11 +183,14 @@ namespace OpenSim.Framework
/// Width of parcel media render /// Width of parcel media render
/// </summary> /// </summary>
[XmlIgnore] [XmlIgnore]
public int MediaWidth { public int MediaWidth
get { {
get
{
return _mediaWidth; return _mediaWidth;
} }
set { set
{
_mediaWidth = value; _mediaWidth = value;
} }
} }
@ -167,11 +199,14 @@ namespace OpenSim.Framework
/// Upper corner of the AABB for the parcel /// Upper corner of the AABB for the parcel
/// </summary> /// </summary>
[XmlIgnore] [XmlIgnore]
public Vector3 AABBMax { public Vector3 AABBMax
get { {
get
{
return _AABBMax; return _AABBMax;
} }
set { set
{
_AABBMax = value; _AABBMax = value;
} }
} }
@ -179,11 +214,14 @@ namespace OpenSim.Framework
/// Lower corner of the AABB for the parcel /// Lower corner of the AABB for the parcel
/// </summary> /// </summary>
[XmlIgnore] [XmlIgnore]
public Vector3 AABBMin { public Vector3 AABBMin
get { {
get
{
return _AABBMin; return _AABBMin;
} }
set { set
{
_AABBMin = value; _AABBMin = value;
} }
} }
@ -191,11 +229,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// Area in meters^2 the parcel contains /// Area in meters^2 the parcel contains
/// </summary> /// </summary>
public int Area { public int Area
get { {
get
{
return _area; return _area;
} }
set { set
{
_area = value; _area = value;
} }
} }
@ -203,11 +244,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// ID of auction (3rd Party Integration) when parcel is being auctioned /// ID of auction (3rd Party Integration) when parcel is being auctioned
/// </summary> /// </summary>
public uint AuctionID { public uint AuctionID
get { {
get
{
return _auctionID; return _auctionID;
} }
set { set
{
_auctionID = value; _auctionID = value;
} }
} }
@ -215,11 +259,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// UUID of authorized buyer of parcel. This is UUID.Zero if anyone can buy it. /// UUID of authorized buyer of parcel. This is UUID.Zero if anyone can buy it.
/// </summary> /// </summary>
public UUID AuthBuyerID { public UUID AuthBuyerID
get { {
get
{
return _authBuyerID; return _authBuyerID;
} }
set { set
{
_authBuyerID = value; _authBuyerID = value;
} }
} }
@ -227,11 +274,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// Category of parcel. Used for classifying the parcel in classified listings /// Category of parcel. Used for classifying the parcel in classified listings
/// </summary> /// </summary>
public ParcelCategory Category { public ParcelCategory Category
get { {
get
{
return _category; return _category;
} }
set { set
{
_category = value; _category = value;
} }
} }
@ -239,11 +289,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// Date that the current owner purchased or claimed the parcel /// Date that the current owner purchased or claimed the parcel
/// </summary> /// </summary>
public int ClaimDate { public int ClaimDate
get { {
get
{
return _claimDate; return _claimDate;
} }
set { set
{
_claimDate = value; _claimDate = value;
} }
} }
@ -251,11 +304,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// The last price that the parcel was sold at /// The last price that the parcel was sold at
/// </summary> /// </summary>
public int ClaimPrice { public int ClaimPrice
get { {
get
{
return _claimPrice; return _claimPrice;
} }
set { set
{
_claimPrice = value; _claimPrice = value;
} }
} }
@ -263,11 +319,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// Global ID for the parcel. (3rd Party Integration) /// Global ID for the parcel. (3rd Party Integration)
/// </summary> /// </summary>
public UUID GlobalID { public UUID GlobalID
get { {
get
{
return _globalID; return _globalID;
} }
set { set
{
_globalID = value; _globalID = value;
} }
} }
@ -275,11 +334,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// Unique ID of the Group that owns /// Unique ID of the Group that owns
/// </summary> /// </summary>
public UUID GroupID { public UUID GroupID
get { {
get
{
return _groupID; return _groupID;
} }
set { set
{
_groupID = value; _groupID = value;
} }
} }
@ -287,11 +349,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// Returns true if the Land Parcel is owned by a group /// Returns true if the Land Parcel is owned by a group
/// </summary> /// </summary>
public bool IsGroupOwned { public bool IsGroupOwned
get { {
get
{
return _isGroupOwned; return _isGroupOwned;
} }
set { set
{
_isGroupOwned = value; _isGroupOwned = value;
} }
} }
@ -299,11 +364,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// jp2 data for the image representative of the parcel in the parcel dialog /// jp2 data for the image representative of the parcel in the parcel dialog
/// </summary> /// </summary>
public byte[] Bitmap { public byte[] Bitmap
get { {
get
{
return _bitmap; return _bitmap;
} }
set { set
{
_bitmap = value; _bitmap = value;
} }
} }
@ -311,11 +379,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// Parcel Description /// Parcel Description
/// </summary> /// </summary>
public string Description { public string Description
get { {
get
{
return _description; return _description;
} }
set { set
{
_description = value; _description = value;
} }
} }
@ -323,11 +394,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// Parcel settings. Access flags, Fly, NoPush, Voice, Scripts allowed, etc. ParcelFlags /// Parcel settings. Access flags, Fly, NoPush, Voice, Scripts allowed, etc. ParcelFlags
/// </summary> /// </summary>
public uint Flags { public uint Flags
get { {
get
{
return _flags; return _flags;
} }
set { set
{
_flags = value; _flags = value;
} }
} }
@ -336,11 +410,14 @@ namespace OpenSim.Framework
/// Determines if people are able to teleport where they please on the parcel or if they /// Determines if people are able to teleport where they please on the parcel or if they
/// get constrainted to a specific point on teleport within the parcel /// get constrainted to a specific point on teleport within the parcel
/// </summary> /// </summary>
public byte LandingType { public byte LandingType
get { {
get
{
return _landingType; return _landingType;
} }
set { set
{
_landingType = value; _landingType = value;
} }
} }
@ -348,11 +425,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// Parcel Name /// Parcel Name
/// </summary> /// </summary>
public string Name { public string Name
get { {
get
{
return _name; return _name;
} }
set { set
{
_name = value; _name = value;
} }
} }
@ -360,11 +440,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// Status of Parcel, Leased, Abandoned, For Sale /// Status of Parcel, Leased, Abandoned, For Sale
/// </summary> /// </summary>
public ParcelStatus Status { public ParcelStatus Status
get { {
get
{
return _status; return _status;
} }
set { set
{
_status = value; _status = value;
} }
} }
@ -372,11 +455,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// Internal ID of the parcel. Sometimes the client will try to use this value /// Internal ID of the parcel. Sometimes the client will try to use this value
/// </summary> /// </summary>
public int LocalID { public int LocalID
get { {
get
{
return _localID; return _localID;
} }
set { set
{
_localID = value; _localID = value;
} }
} }
@ -384,11 +470,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// Determines if we scale the media based on the surface it's on /// Determines if we scale the media based on the surface it's on
/// </summary> /// </summary>
public byte MediaAutoScale { public byte MediaAutoScale
get { {
get
{
return _mediaAutoScale; return _mediaAutoScale;
} }
set { set
{
_mediaAutoScale = value; _mediaAutoScale = value;
} }
} }
@ -396,11 +485,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// Texture Guid to replace with the output of the media stream /// Texture Guid to replace with the output of the media stream
/// </summary> /// </summary>
public UUID MediaID { public UUID MediaID
get { {
get
{
return _mediaID; return _mediaID;
} }
set { set
{
_mediaID = value; _mediaID = value;
} }
} }
@ -408,11 +500,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// URL to the media file to display /// URL to the media file to display
/// </summary> /// </summary>
public string MediaURL { public string MediaURL
get { {
get
{
return _mediaURL; return _mediaURL;
} }
set { set
{
_mediaURL = value; _mediaURL = value;
} }
} }
@ -432,11 +527,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// URL to the shoutcast music stream to play on the parcel /// URL to the shoutcast music stream to play on the parcel
/// </summary> /// </summary>
public string MusicURL { public string MusicURL
get { {
get
{
return _musicURL; return _musicURL;
} }
set { set
{
_musicURL = value; _musicURL = value;
} }
} }
@ -445,11 +543,14 @@ namespace OpenSim.Framework
/// Owner Avatar or Group of the parcel. Naturally, all land masses must be /// Owner Avatar or Group of the parcel. Naturally, all land masses must be
/// owned by someone /// owned by someone
/// </summary> /// </summary>
public UUID OwnerID { public UUID OwnerID
get { {
get
{
return _ownerID; return _ownerID;
} }
set { set
{
_ownerID = value; _ownerID = value;
} }
} }
@ -457,11 +558,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// List of access data for the parcel. User data, some bitflags, and a time /// List of access data for the parcel. User data, some bitflags, and a time
/// </summary> /// </summary>
public List<LandAccessEntry> ParcelAccessList { public List<LandAccessEntry> ParcelAccessList
get { {
get
{
return _parcelAccessList; return _parcelAccessList;
} }
set { set
{
_parcelAccessList = value; _parcelAccessList = value;
} }
} }
@ -469,11 +573,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// How long in hours a Pass to the parcel is given /// How long in hours a Pass to the parcel is given
/// </summary> /// </summary>
public float PassHours { public float PassHours
get { {
get
{
return _passHours; return _passHours;
} }
set { set
{
_passHours = value; _passHours = value;
} }
} }
@ -481,11 +588,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// Price to purchase a Pass to a restricted parcel /// Price to purchase a Pass to a restricted parcel
/// </summary> /// </summary>
public int PassPrice { public int PassPrice
get { {
get
{
return _passPrice; return _passPrice;
} }
set { set
{
_passPrice = value; _passPrice = value;
} }
} }
@ -493,11 +603,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// When the parcel is being sold, this is the price to purchase the parcel /// When the parcel is being sold, this is the price to purchase the parcel
/// </summary> /// </summary>
public int SalePrice { public int SalePrice
get { {
get
{
return _salePrice; return _salePrice;
} }
set { set
{
_salePrice = value; _salePrice = value;
} }
} }
@ -506,11 +619,14 @@ namespace OpenSim.Framework
/// Number of meters^2 in the Simulator /// Number of meters^2 in the Simulator
/// </summary> /// </summary>
[XmlIgnore] [XmlIgnore]
public int SimwideArea { public int SimwideArea
get { {
get
{
return _simwideArea; return _simwideArea;
} }
set { set
{
_simwideArea = value; _simwideArea = value;
} }
} }
@ -519,11 +635,14 @@ namespace OpenSim.Framework
/// Number of SceneObjectPart in the Simulator /// Number of SceneObjectPart in the Simulator
/// </summary> /// </summary>
[XmlIgnore] [XmlIgnore]
public int SimwidePrims { public int SimwidePrims
get { {
get
{
return _simwidePrims; return _simwidePrims;
} }
set { set
{
_simwidePrims = value; _simwidePrims = value;
} }
} }
@ -531,11 +650,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// ID of the snapshot used in the client parcel dialog of the parcel /// ID of the snapshot used in the client parcel dialog of the parcel
/// </summary> /// </summary>
public UUID SnapshotID { public UUID SnapshotID
get { {
get
{
return _snapshotID; return _snapshotID;
} }
set { set
{
_snapshotID = value; _snapshotID = value;
} }
} }
@ -544,11 +666,14 @@ namespace OpenSim.Framework
/// When teleporting is restricted to a certain point, this is the location /// When teleporting is restricted to a certain point, this is the location
/// that the user will be redirected to /// that the user will be redirected to
/// </summary> /// </summary>
public Vector3 UserLocation { public Vector3 UserLocation
get { {
get
{
return _userLocation; return _userLocation;
} }
set { set
{
_userLocation = value; _userLocation = value;
} }
} }
@ -557,11 +682,14 @@ namespace OpenSim.Framework
/// When teleporting is restricted to a certain point, this is the rotation /// When teleporting is restricted to a certain point, this is the rotation
/// that the user will be positioned /// that the user will be positioned
/// </summary> /// </summary>
public Vector3 UserLookAt { public Vector3 UserLookAt
get { {
get
{
return _userLookAt; return _userLookAt;
} }
set { set
{
_userLookAt = value; _userLookAt = value;
} }
} }
@ -570,11 +698,14 @@ namespace OpenSim.Framework
/// Autoreturn number of minutes to return SceneObjectGroup that are owned by someone who doesn't own /// Autoreturn number of minutes to return SceneObjectGroup that are owned by someone who doesn't own
/// the parcel and isn't set to the same 'group' as the parcel. /// the parcel and isn't set to the same 'group' as the parcel.
/// </summary> /// </summary>
public int OtherCleanTime { public int OtherCleanTime
get { {
get
{
return _otherCleanTime; return _otherCleanTime;
} }
set { set
{
_otherCleanTime = value; _otherCleanTime = value;
} }
} }
@ -582,11 +713,14 @@ namespace OpenSim.Framework
/// <summary> /// <summary>
/// parcel media description /// parcel media description
/// </summary> /// </summary>
public string MediaDescription { public string MediaDescription
get { {
get
{
return _mediaDescription; return _mediaDescription;
} }
set { set
{
_mediaDescription = value; _mediaDescription = value;
} }
} }
@ -622,7 +756,7 @@ namespace OpenSim.Framework
landData._mediaURL = _mediaURL; landData._mediaURL = _mediaURL;
landData._musicURL = _musicURL; landData._musicURL = _musicURL;
landData._ownerID = _ownerID; landData._ownerID = _ownerID;
landData._bitmap = (byte[]) _bitmap.Clone(); landData._bitmap = (byte[])_bitmap.Clone();
landData._description = _description; landData._description = _description;
landData._flags = _flags; landData._flags = _flags;
landData._name = _name; landData._name = _name;
@ -643,6 +777,7 @@ namespace OpenSim.Framework
landData._obscureMedia = _obscureMedia; landData._obscureMedia = _obscureMedia;
landData._simwideArea = _simwideArea; landData._simwideArea = _simwideArea;
landData._simwidePrims = _simwidePrims; landData._simwidePrims = _simwidePrims;
landData._dwell = _dwell;
landData._parcelAccessList.Clear(); landData._parcelAccessList.Clear();
foreach (LandAccessEntry entry in _parcelAccessList) foreach (LandAccessEntry entry in _parcelAccessList)

View File

@ -43,27 +43,32 @@ namespace OpenSim.Framework.Monitoring
StringBuilder sb = new StringBuilder(Environment.NewLine); StringBuilder sb = new StringBuilder(Environment.NewLine);
sb.Append("MEMORY STATISTICS"); sb.Append("MEMORY STATISTICS");
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);
sb.Append( sb.AppendFormat(
string.Format(
"Allocated to OpenSim objects: {0} MB\n", "Allocated to OpenSim objects: {0} MB\n",
Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0))); Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0));
sb.AppendFormat(
"OpenSim last object memory churn : {0} MB/s\n",
Math.Round((MemoryWatchdog.LastMemoryChurn * 1000) / 1024.0 / 1024, 3));
sb.AppendFormat(
"OpenSim average object memory churn : {0} MB/s\n",
Math.Round((MemoryWatchdog.AverageMemoryChurn * 1000) / 1024.0 / 1024, 3));
Process myprocess = Process.GetCurrentProcess(); Process myprocess = Process.GetCurrentProcess();
if (!myprocess.HasExited) if (!myprocess.HasExited)
{ {
myprocess.Refresh(); myprocess.Refresh();
sb.Append( sb.AppendFormat(
string.Format(
"Process memory: Physical {0} MB \t Paged {1} MB \t Virtual {2} MB\n", "Process memory: Physical {0} MB \t Paged {1} MB \t Virtual {2} MB\n",
Math.Round(Process.GetCurrentProcess().WorkingSet64 / 1024.0 / 1024.0), Math.Round(Process.GetCurrentProcess().WorkingSet64 / 1024.0 / 1024.0),
Math.Round(Process.GetCurrentProcess().PagedMemorySize64 / 1024.0 / 1024.0), Math.Round(Process.GetCurrentProcess().PagedMemorySize64 / 1024.0 / 1024.0),
Math.Round(Process.GetCurrentProcess().VirtualMemorySize64 / 1024.0 / 1024.0))); Math.Round(Process.GetCurrentProcess().VirtualMemorySize64 / 1024.0 / 1024.0));
sb.Append( sb.AppendFormat(
string.Format(
"Peak process memory: Physical {0} MB \t Paged {1} MB \t Virtual {2} MB\n", "Peak process memory: Physical {0} MB \t Paged {1} MB \t Virtual {2} MB\n",
Math.Round(Process.GetCurrentProcess().PeakWorkingSet64 / 1024.0 / 1024.0), Math.Round(Process.GetCurrentProcess().PeakWorkingSet64 / 1024.0 / 1024.0),
Math.Round(Process.GetCurrentProcess().PeakPagedMemorySize64 / 1024.0 / 1024.0), Math.Round(Process.GetCurrentProcess().PeakPagedMemorySize64 / 1024.0 / 1024.0),
Math.Round(Process.GetCurrentProcess().PeakVirtualMemorySize64 / 1024.0 / 1024.0))); Math.Round(Process.GetCurrentProcess().PeakVirtualMemorySize64 / 1024.0 / 1024.0));
} }
else else
sb.Append("Process reported as Exited \n"); sb.Append("Process reported as Exited \n");

View File

@ -60,13 +60,21 @@ namespace OpenSim.Framework.Monitoring
private static bool m_enabled; private static bool m_enabled;
/// <summary> /// <summary>
/// Average memory churn in bytes per millisecond. /// Last memory churn in bytes per millisecond.
/// </summary> /// </summary>
public static double AverageMemoryChurn public static double AverageMemoryChurn
{ {
get { if (m_samples.Count > 0) return m_samples.Average(); else return 0; } get { if (m_samples.Count > 0) return m_samples.Average(); else return 0; }
} }
/// <summary>
/// Average memory churn in bytes per millisecond.
/// </summary>
public static double LastMemoryChurn
{
get { if (m_samples.Count > 0) return m_samples.Last(); else return 0; }
}
/// <summary> /// <summary>
/// Maximum number of statistical samples. /// Maximum number of statistical samples.
/// </summary> /// </summary>

View File

@ -355,10 +355,25 @@ Asset service request failures: {3}" + Environment.NewLine,
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);
sb.Append( sb.Append(
string.Format( string.Format(
"{0,6:0} {1,6:0} {2,6:0} {3,6:0} {4,6:0} {5,6:0.0} {6,6:0.0} {7,6:0.0} {8,6:0.0} {9,6:0.0} {10,6:0.0}", "{0,6:0} {1,6:0} {2,6:0} {3,6:0} {4,6:0} {5,6:0.0} {6,6:0.0} {7,6:0.0} {8,6:0.0} {9,6:0.0} {10,6:0.0}\n\n",
inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime, inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime,
netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime)); netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime));
sb.Append(Environment.NewLine);
Dictionary<string, Dictionary<string, Stat>> sceneStats;
if (StatsManager.TryGetStats("scene", out sceneStats))
{
foreach (KeyValuePair<string, Dictionary<string, Stat>> kvp in sceneStats)
{
foreach (Stat stat in kvp.Value.Values)
{
if (stat.Verbosity == StatVerbosity.Info)
{
sb.AppendFormat("{0} ({1}): {2}{3}\n", stat.Name, stat.Container, stat.Value, stat.UnitName);
}
}
}
}
/* /*
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);

View File

@ -25,6 +25,9 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using System;
using System.Collections.Generic;
namespace OpenSim.Framework.Monitoring namespace OpenSim.Framework.Monitoring
{ {
/// <summary> /// <summary>
@ -32,6 +35,24 @@ namespace OpenSim.Framework.Monitoring
/// </summary> /// </summary>
public class StatsManager public class StatsManager
{ {
// Subcommand used to list other stats.
public const string AllSubCommand = "all";
// Subcommand used to list other stats.
public const string ListSubCommand = "list";
// All subcommands
public static HashSet<string> SubCommands = new HashSet<string> { AllSubCommand, ListSubCommand };
/// <summary>
/// Registered stats categorized by category/container/shortname
/// </summary>
/// <remarks>
/// Do not add or remove directly from this dictionary.
/// </remarks>
public static Dictionary<string, Dictionary<string, Dictionary<string, Stat>>> RegisteredStats
= new Dictionary<string, Dictionary<string, Dictionary<string, Stat>>>();
private static AssetStatsCollector assetStats; private static AssetStatsCollector assetStats;
private static UserStatsCollector userStats; private static UserStatsCollector userStats;
private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector(); private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector();
@ -40,6 +61,75 @@ namespace OpenSim.Framework.Monitoring
public static UserStatsCollector UserStats { get { return userStats; } } public static UserStatsCollector UserStats { get { return userStats; } }
public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } } public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } }
public static void RegisterConsoleCommands(ICommandConsole console)
{
console.Commands.AddCommand(
"General",
false,
"show stats",
"show stats [list|all|<category>]",
"Show statistical information for this server",
"If no final argument is specified then legacy statistics information is currently shown.\n"
+ "If list is specified then statistic categories are shown.\n"
+ "If all is specified then all registered statistics are shown.\n"
+ "If a category name is specified then only statistics from that category are shown.\n"
+ "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS",
HandleShowStatsCommand);
}
public static void HandleShowStatsCommand(string module, string[] cmd)
{
ICommandConsole con = MainConsole.Instance;
if (cmd.Length > 2)
{
var categoryName = cmd[2];
if (categoryName == AllSubCommand)
{
foreach (var category in RegisteredStats.Values)
{
OutputCategoryStatsToConsole(con, category);
}
}
else if (categoryName == ListSubCommand)
{
con.Output("Statistic categories available are:");
foreach (string category in RegisteredStats.Keys)
con.OutputFormat(" {0}", category);
}
else
{
Dictionary<string, Dictionary<string, Stat>> category;
if (!RegisteredStats.TryGetValue(categoryName, out category))
{
con.OutputFormat("No such category as {0}", categoryName);
}
else
{
OutputCategoryStatsToConsole(con, category);
}
}
}
else
{
// Legacy
con.Output(SimExtraStats.Report());
}
}
private static void OutputCategoryStatsToConsole(
ICommandConsole con, Dictionary<string, Dictionary<string, Stat>> category)
{
foreach (var container in category.Values)
{
foreach (Stat stat in container.Values)
{
con.Output(stat.ToConsoleString());
}
}
}
/// <summary> /// <summary>
/// Start collecting statistics related to assets. /// Start collecting statistics related to assets.
/// Should only be called once. /// Should only be called once.
@ -61,5 +151,275 @@ namespace OpenSim.Framework.Monitoring
return userStats; return userStats;
} }
/// <summary>
/// Registers a statistic.
/// </summary>
/// <param name='stat'></param>
/// <returns></returns>
public static bool RegisterStat(Stat stat)
{
Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
Dictionary<string, Stat> container = null, newContainer;
lock (RegisteredStats)
{
// Stat name is not unique across category/container/shortname key.
// XXX: For now just return false. This is to avoid problems in regression tests where all tests
// in a class are run in the same instance of the VM.
if (TryGetStat(stat, out category, out container))
return false;
// We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
// This means that we don't need to lock or copy them on iteration, which will be a much more
// common operation after startup.
if (container != null)
newContainer = new Dictionary<string, Stat>(container);
else
newContainer = new Dictionary<string, Stat>();
if (category != null)
newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
else
newCategory = new Dictionary<string, Dictionary<string, Stat>>();
newContainer[stat.ShortName] = stat;
newCategory[stat.Container] = newContainer;
RegisteredStats[stat.Category] = newCategory;
}
return true;
}
/// <summary>
/// Deregister a statistic
/// </summary>>
/// <param name='stat'></param>
/// <returns></returns
public static bool DeregisterStat(Stat stat)
{
Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
Dictionary<string, Stat> container = null, newContainer;
lock (RegisteredStats)
{
if (!TryGetStat(stat, out category, out container))
return false;
newContainer = new Dictionary<string, Stat>(container);
newContainer.Remove(stat.ShortName);
newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
newCategory.Remove(stat.Container);
newCategory[stat.Container] = newContainer;
RegisteredStats[stat.Category] = newCategory;
return true;
}
}
public static bool TryGetStats(string category, out Dictionary<string, Dictionary<string, Stat>> stats)
{
return RegisteredStats.TryGetValue(category, out stats);
}
public static bool TryGetStat(
Stat stat,
out Dictionary<string, Dictionary<string, Stat>> category,
out Dictionary<string, Stat> container)
{
category = null;
container = null;
lock (RegisteredStats)
{
if (RegisteredStats.TryGetValue(stat.Category, out category))
{
if (category.TryGetValue(stat.Container, out container))
{
if (container.ContainsKey(stat.ShortName))
return true;
}
}
}
return false;
}
}
/// <summary>
/// Stat type.
/// </summary>
/// <remarks>
/// A push stat is one which is continually updated and so it's value can simply by read.
/// A pull stat is one where reading the value triggers a collection method - the stat is not continually updated.
/// </remarks>
public enum StatType
{
Push,
Pull
}
/// <summary>
/// Verbosity of stat.
/// </summary>
/// <remarks>
/// Info will always be displayed.
/// </remarks>
public enum StatVerbosity
{
Debug,
Info
}
/// <summary>
/// Holds individual static details
/// </summary>
public class Stat
{
/// <summary>
/// Category of this stat (e.g. cache, scene, etc).
/// </summary>
public string Category { get; private set; }
/// <summary>
/// Containing name for this stat.
/// FIXME: In the case of a scene, this is currently the scene name (though this leaves
/// us with a to-be-resolved problem of non-unique region names).
/// </summary>
/// <value>
/// The container.
/// </value>
public string Container { get; private set; }
public StatType StatType { get; private set; }
/// <summary>
/// Action used to update this stat when the value is requested if it's a pull type.
/// </summary>
public Action<Stat> PullAction { get; private set; }
public StatVerbosity Verbosity { get; private set; }
public string ShortName { get; private set; }
public string Name { get; private set; }
public string Description { get; private set; }
public virtual string UnitName { get; private set; }
public virtual double Value
{
get
{
// Asking for an update here means that the updater cannot access this value without infinite recursion.
// XXX: A slightly messy but simple solution may be to flick a flag so we can tell if this is being
// called by the pull action and just return the value.
if (StatType == StatType.Pull)
PullAction(this);
return m_value;
}
set
{
m_value = value;
}
}
private double m_value;
/// <summary>
/// Constructor
/// </summary>
/// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param>
/// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param>
/// <param name='description'>Description of stat</param>
/// <param name='unitName'>
/// Unit name for the stat. Should be preceeded by a space if the unit name isn't normally appeneded immediately to the value.
/// e.g. " frames"
/// </param>
/// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param>
/// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param>
/// <param name='type'>Push or pull</param>
/// <param name='pullAction'>Pull stats need an action to update the stat on request. Push stats should set null here.</param>
/// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param>
public Stat(
string shortName,
string name,
string description,
string unitName,
string category,
string container,
StatType type,
Action<Stat> pullAction,
StatVerbosity verbosity)
{
if (StatsManager.SubCommands.Contains(category))
throw new Exception(
string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category));
ShortName = shortName;
Name = name;
Description = description;
UnitName = unitName;
Category = category;
Container = container;
StatType = type;
if (StatType == StatType.Push && pullAction != null)
throw new Exception("A push stat cannot have a pull action");
else
PullAction = pullAction;
Verbosity = verbosity;
}
public virtual string ToConsoleString()
{
return string.Format(
"{0}.{1}.{2} : {3}{4}", Category, Container, ShortName, Value, UnitName);
}
}
public class PercentageStat : Stat
{
public int Antecedent { get; set; }
public int Consequent { get; set; }
public override double Value
{
get
{
int c = Consequent;
// Avoid any chance of a multi-threaded divide-by-zero
if (c == 0)
return 0;
return (double)Antecedent / c * 100;
}
set
{
throw new Exception("Cannot set value on a PercentageStat");
}
}
public PercentageStat(
string shortName,
string name,
string description,
string category,
string container,
StatType type,
Action<Stat> pullAction,
StatVerbosity verbosity)
: base(shortName, name, description, "%", category, container, type, pullAction, verbosity) {}
public override string ToConsoleString()
{
return string.Format(
"{0}.{1}.{2} : {3:0.##}{4} ({5}/{6})",
Category, Container, ShortName, Value, UnitName, Antecedent, Consequent);
}
} }
} }

View File

@ -89,6 +89,17 @@ namespace OpenSim.Framework.Monitoring
FirstTick = Environment.TickCount & Int32.MaxValue; FirstTick = Environment.TickCount & Int32.MaxValue;
LastTick = FirstTick; LastTick = FirstTick;
} }
public ThreadWatchdogInfo(ThreadWatchdogInfo previousTwi)
{
Thread = previousTwi.Thread;
FirstTick = previousTwi.FirstTick;
LastTick = previousTwi.LastTick;
Timeout = previousTwi.Timeout;
IsTimedOut = previousTwi.IsTimedOut;
AlarmIfTimeout = previousTwi.AlarmIfTimeout;
AlarmMethod = previousTwi.AlarmMethod;
}
} }
/// <summary> /// <summary>
@ -220,7 +231,25 @@ namespace OpenSim.Framework.Monitoring
private static bool RemoveThread(int threadID) private static bool RemoveThread(int threadID)
{ {
lock (m_threads) lock (m_threads)
return m_threads.Remove(threadID); {
ThreadWatchdogInfo twi;
if (m_threads.TryGetValue(threadID, out twi))
{
m_log.DebugFormat(
"[WATCHDOG]: Removing thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId);
m_threads.Remove(threadID);
return true;
}
else
{
m_log.WarnFormat(
"[WATCHDOG]: Requested to remove thread with ID {0} but this is not being monitored", threadID);
return false;
}
}
} }
public static bool AbortThread(int threadID) public static bool AbortThread(int threadID)
@ -335,7 +364,9 @@ namespace OpenSim.Framework.Monitoring
if (callbackInfos == null) if (callbackInfos == null)
callbackInfos = new List<ThreadWatchdogInfo>(); callbackInfos = new List<ThreadWatchdogInfo>();
callbackInfos.Add(threadInfo); // Send a copy of the watchdog info to prevent race conditions where the watchdog
// thread updates the monitoring info after an alarm has been sent out.
callbackInfos.Add(new ThreadWatchdogInfo(threadInfo));
} }
} }
} }

91
OpenSim/Framework/Pool.cs Normal file
View File

@ -0,0 +1,91 @@
/*
* 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.Collections.Generic;
namespace OpenSim.Framework
{
/// <summary>
/// Naive pool implementation.
/// </summary>
/// <remarks>
/// Currently assumes that objects are in a useable state when returned.
/// </remarks>
public class Pool<T>
{
/// <summary>
/// Number of objects in the pool.
/// </summary>
public int Count
{
get
{
lock (m_pool)
return m_pool.Count;
}
}
private Stack<T> m_pool;
/// <summary>
/// Maximum pool size. Beyond this, any returned objects are not pooled.
/// </summary>
private int m_maxPoolSize;
private Func<T> m_createFunction;
public Pool(Func<T> createFunction, int maxSize)
{
m_maxPoolSize = maxSize;
m_createFunction = createFunction;
m_pool = new Stack<T>(m_maxPoolSize);
}
public T GetObject()
{
lock (m_pool)
{
if (m_pool.Count > 0)
return m_pool.Pop();
else
return m_createFunction();
}
}
public void ReturnObject(T obj)
{
lock (m_pool)
{
if (m_pool.Count >= m_maxPoolSize)
return;
else
m_pool.Push(obj);
}
}
}
}

View File

@ -0,0 +1,53 @@
/*
* 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;
namespace OpenSim.Framework
{
/// <summary>
/// Region flags used internally by OpenSimulator to store installation specific information about regions.
/// </summary>
/// <remarks>
/// Don't confuse with OpenMetaverse.RegionFlags which are client facing flags (i.e. they go over the wire).
/// Returned by IGridService.GetRegionFlags()
/// </remarks>
[Flags]
public enum RegionFlags : int
{
DefaultRegion = 1, // Used for new Rez. Random if multiple defined
FallbackRegion = 2, // Regions we redirect to when the destination is down
RegionOnline = 4, // Set when a region comes online, unset when it unregisters and DeleteOnUnregister is false
NoDirectLogin = 8, // Region unavailable for direct logins (by name)
Persistent = 16, // Don't remove on unregister
LockedOut = 32, // Don't allow registration
NoMove = 64, // Don't allow moving this region
Reservation = 128, // This is an inactive reservation
Authenticate = 256, // Require authentication
Hyperlink = 512 // Record represents a HG link
}
}

View File

@ -122,10 +122,13 @@ namespace OpenSim.Framework
public UUID lastMapUUID = UUID.Zero; public UUID lastMapUUID = UUID.Zero;
public string lastMapRefresh = "0"; public string lastMapRefresh = "0";
private float m_nonphysPrimMin = 0;
private int m_nonphysPrimMax = 0; private int m_nonphysPrimMax = 0;
private float m_physPrimMin = 0;
private int m_physPrimMax = 0; private int m_physPrimMax = 0;
private bool m_clampPrimSize = false; private bool m_clampPrimSize = false;
private int m_objectCapacity = 0; private int m_objectCapacity = 0;
private int m_linksetCapacity = 0;
private int m_agentCapacity = 0; private int m_agentCapacity = 0;
private string m_regionType = String.Empty; private string m_regionType = String.Empty;
private RegionLightShareData m_windlight = new RegionLightShareData(); private RegionLightShareData m_windlight = new RegionLightShareData();
@ -287,11 +290,21 @@ namespace OpenSim.Framework
set { m_windlight = value; } set { m_windlight = value; }
} }
public float NonphysPrimMin
{
get { return m_nonphysPrimMin; }
}
public int NonphysPrimMax public int NonphysPrimMax
{ {
get { return m_nonphysPrimMax; } get { return m_nonphysPrimMax; }
} }
public float PhysPrimMin
{
get { return m_physPrimMin; }
}
public int PhysPrimMax public int PhysPrimMax
{ {
get { return m_physPrimMax; } get { return m_physPrimMax; }
@ -307,6 +320,11 @@ namespace OpenSim.Framework
get { return m_objectCapacity; } get { return m_objectCapacity; }
} }
public int LinksetCapacity
{
get { return m_linksetCapacity; }
}
public int AgentCapacity public int AgentCapacity
{ {
get { return m_agentCapacity; } get { return m_agentCapacity; }
@ -625,16 +643,31 @@ namespace OpenSim.Framework
m_regionType = config.GetString("RegionType", String.Empty); m_regionType = config.GetString("RegionType", String.Empty);
allKeys.Remove("RegionType"); allKeys.Remove("RegionType");
// Prim stuff #region Prim stuff
//
m_nonphysPrimMax = config.GetInt("NonphysicalPrimMax", 0); m_nonphysPrimMin = config.GetFloat("NonPhysicalPrimMin", 0);
allKeys.Remove("NonphysicalPrimMax"); allKeys.Remove("NonPhysicalPrimMin");
m_nonphysPrimMax = config.GetInt("NonPhysicalPrimMax", 0);
allKeys.Remove("NonPhysicalPrimMax");
m_physPrimMin = config.GetFloat("PhysicalPrimMin", 0);
allKeys.Remove("PhysicalPrimMin");
m_physPrimMax = config.GetInt("PhysicalPrimMax", 0); m_physPrimMax = config.GetInt("PhysicalPrimMax", 0);
allKeys.Remove("PhysicalPrimMax"); allKeys.Remove("PhysicalPrimMax");
m_clampPrimSize = config.GetBoolean("ClampPrimSize", false); m_clampPrimSize = config.GetBoolean("ClampPrimSize", false);
allKeys.Remove("ClampPrimSize"); allKeys.Remove("ClampPrimSize");
m_objectCapacity = config.GetInt("MaxPrims", 15000); m_objectCapacity = config.GetInt("MaxPrims", 15000);
allKeys.Remove("MaxPrims"); allKeys.Remove("MaxPrims");
m_linksetCapacity = config.GetInt("LinksetPrims", 0);
allKeys.Remove("LinksetPrims");
#endregion
m_agentCapacity = config.GetInt("MaxAgents", 100); m_agentCapacity = config.GetInt("MaxAgents", 100);
allKeys.Remove("MaxAgents"); allKeys.Remove("MaxAgents");
@ -673,16 +706,27 @@ namespace OpenSim.Framework
config.Set("ExternalHostName", m_externalHostName); config.Set("ExternalHostName", m_externalHostName);
if (m_nonphysPrimMax != 0) if (m_nonphysPrimMin > 0)
config.Set("NonphysicalPrimMax", m_nonphysPrimMin);
if (m_nonphysPrimMax > 0)
config.Set("NonphysicalPrimMax", m_nonphysPrimMax); config.Set("NonphysicalPrimMax", m_nonphysPrimMax);
if (m_physPrimMax != 0)
if (m_physPrimMin > 0)
config.Set("PhysicalPrimMax", m_physPrimMin);
if (m_physPrimMax > 0)
config.Set("PhysicalPrimMax", m_physPrimMax); config.Set("PhysicalPrimMax", m_physPrimMax);
config.Set("ClampPrimSize", m_clampPrimSize.ToString()); config.Set("ClampPrimSize", m_clampPrimSize.ToString());
if (m_objectCapacity != 0) if (m_objectCapacity > 0)
config.Set("MaxPrims", m_objectCapacity); config.Set("MaxPrims", m_objectCapacity);
if (m_agentCapacity != 0) if (m_linksetCapacity > 0)
config.Set("LinksetPrims", m_linksetCapacity);
if (m_agentCapacity > 0)
config.Set("MaxAgents", m_agentCapacity); config.Set("MaxAgents", m_agentCapacity);
if (ScopeID != UUID.Zero) if (ScopeID != UUID.Zero)
@ -759,9 +803,15 @@ namespace OpenSim.Framework
configMember.addConfigurationOption("lastmap_refresh", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, configMember.addConfigurationOption("lastmap_refresh", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
"Last Map Refresh", Util.UnixTimeSinceEpoch().ToString(), true); "Last Map Refresh", Util.UnixTimeSinceEpoch().ToString(), true);
configMember.addConfigurationOption("nonphysical_prim_min", ConfigurationOption.ConfigurationTypes.TYPE_FLOAT,
"Minimum size for nonphysical prims", m_nonphysPrimMin.ToString(), true);
configMember.addConfigurationOption("nonphysical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32, configMember.addConfigurationOption("nonphysical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
"Maximum size for nonphysical prims", m_nonphysPrimMax.ToString(), true); "Maximum size for nonphysical prims", m_nonphysPrimMax.ToString(), true);
configMember.addConfigurationOption("physical_prim_min", ConfigurationOption.ConfigurationTypes.TYPE_FLOAT,
"Minimum size for nonphysical prims", m_physPrimMin.ToString(), true);
configMember.addConfigurationOption("physical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32, configMember.addConfigurationOption("physical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
"Maximum size for physical prims", m_physPrimMax.ToString(), true); "Maximum size for physical prims", m_physPrimMax.ToString(), true);
@ -771,6 +821,9 @@ namespace OpenSim.Framework
configMember.addConfigurationOption("object_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32, configMember.addConfigurationOption("object_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
"Max objects this sim will hold", m_objectCapacity.ToString(), true); "Max objects this sim will hold", m_objectCapacity.ToString(), true);
configMember.addConfigurationOption("linkset_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
"Max prims an object will hold", m_linksetCapacity.ToString(), true);
configMember.addConfigurationOption("agent_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32, configMember.addConfigurationOption("agent_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
"Max avatars this sim will hold", m_agentCapacity.ToString(), true); "Max avatars this sim will hold", m_agentCapacity.ToString(), true);
@ -892,6 +945,9 @@ namespace OpenSim.Framework
case "object_capacity": case "object_capacity":
m_objectCapacity = (int)configuration_result; m_objectCapacity = (int)configuration_result;
break; break;
case "linkset_capacity":
m_linksetCapacity = (int)configuration_result;
break;
case "agent_capacity": case "agent_capacity":
m_agentCapacity = (int)configuration_result; m_agentCapacity = (int)configuration_result;
break; break;

View File

@ -52,6 +52,11 @@ namespace OpenSim.Framework.Serialization
/// </value> /// </value>
public const string INVENTORY_PATH = "inventory/"; public const string INVENTORY_PATH = "inventory/";
/// <value>
/// Path for regions in a multi-region archive
/// </value>
public const string REGIONS_PATH = "regions/";
/// <value> /// <value>
/// Path for the prims file /// Path for the prims file
/// </value> /// </value>

View File

@ -65,9 +65,14 @@ namespace OpenSim.Framework.Serialization
UserAccount account = userService.GetUserAccount(UUID.Zero, userId); UserAccount account = userService.GetUserAccount(UUID.Zero, userId);
if (account != null) if (account != null)
{
return MakeOspa(account.FirstName, account.LastName); return MakeOspa(account.FirstName, account.LastName);
}
// else // else
// {
// m_log.WarnFormat("[OSP RESOLVER]: No user account for {0}", userId); // m_log.WarnFormat("[OSP RESOLVER]: No user account for {0}", userId);
// System.Console.WriteLine("[OSP RESOLVER]: No user account for {0}", userId);
// }
return null; return null;
} }
@ -79,10 +84,13 @@ namespace OpenSim.Framework.Serialization
/// <returns></returns> /// <returns></returns>
public static string MakeOspa(string firstName, string lastName) public static string MakeOspa(string firstName, string lastName)
{ {
// m_log.DebugFormat("[OSP RESOLVER]: Making OSPA for {0} {1}", firstName, lastName); string ospa
= OSPA_PREFIX + OSPA_NAME_KEY + OSPA_PAIR_SEPARATOR + firstName + OSPA_NAME_VALUE_SEPARATOR + lastName;
return // m_log.DebugFormat("[OSP RESOLVER]: Made OSPA {0} for {1} {2}", ospa, firstName, lastName);
OSPA_PREFIX + OSPA_NAME_KEY + OSPA_PAIR_SEPARATOR + firstName + OSPA_NAME_VALUE_SEPARATOR + lastName; // System.Console.WriteLine("[OSP RESOLVER]: Made OSPA {0} for {1} {2}", ospa, firstName, lastName);
return ospa;
} }
/// <summary> /// <summary>

View File

@ -96,11 +96,6 @@ namespace OpenSim.Framework.Servers
get { return m_httpServer; } get { return m_httpServer; }
} }
/// <summary>
/// Holds the non-viewer statistics collection object for this service/server
/// </summary>
protected IStatsCollector m_stats;
public BaseOpenSimServer() public BaseOpenSimServer()
{ {
m_startuptime = DateTime.Now; m_startuptime = DateTime.Now;
@ -177,10 +172,6 @@ namespace OpenSim.Framework.Servers
"show info", "show info",
"Show general information about the server", HandleShow); "Show general information about the server", HandleShow);
m_console.Commands.AddCommand("General", false, "show stats",
"show stats",
"Show statistics", HandleShow);
m_console.Commands.AddCommand("General", false, "show threads", m_console.Commands.AddCommand("General", false, "show threads",
"show threads", "show threads",
"Show thread status", HandleShow); "Show thread status", HandleShow);
@ -201,9 +192,20 @@ namespace OpenSim.Framework.Servers
"threads show", "threads show",
"Show thread status. Synonym for \"show threads\"", "Show thread status. Synonym for \"show threads\"",
(string module, string[] args) => Notice(GetThreadsReport())); (string module, string[] args) => Notice(GetThreadsReport()));
m_console.Commands.AddCommand("General", false, "force gc",
"force gc",
"Manually invoke runtime garbage collection. For debugging purposes",
HandleForceGc);
} }
} }
private void HandleForceGc(string module, string[] args)
{
MainConsole.Instance.Output("Manually invoking runtime garbage collection");
GC.Collect();
}
/// <summary> /// <summary>
/// Should be overriden and referenced by descendents if they need to perform extra shutdown processing /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing
/// </summary> /// </summary>
@ -226,12 +228,7 @@ namespace OpenSim.Framework.Servers
{ {
StringBuilder sb = new StringBuilder("DIAGNOSTICS\n\n"); StringBuilder sb = new StringBuilder("DIAGNOSTICS\n\n");
sb.Append(GetUptimeReport()); sb.Append(GetUptimeReport());
sb.Append(StatsManager.SimExtraStats.Report());
if (m_stats != null)
{
sb.Append(m_stats.Report());
}
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);
sb.Append(GetThreadsReport()); sb.Append(GetThreadsReport());
@ -382,10 +379,6 @@ namespace OpenSim.Framework.Servers
{ {
Notice("set log level [level] - change the console logging level only. For example, off or debug."); Notice("set log level [level] - change the console logging level only. For example, off or debug.");
Notice("show info - show server information (e.g. startup path)."); Notice("show info - show server information (e.g. startup path).");
if (m_stats != null)
Notice("show stats - show statistical information for this server");
Notice("show threads - list tracked threads"); Notice("show threads - list tracked threads");
Notice("show uptime - show server startup time and uptime."); Notice("show uptime - show server startup time and uptime.");
Notice("show version - show server version."); Notice("show version - show server version.");
@ -409,11 +402,6 @@ namespace OpenSim.Framework.Servers
ShowInfo(); ShowInfo();
break; break;
case "stats":
if (m_stats != null)
Notice(m_stats.Report());
break;
case "threads": case "threads":
Notice(GetThreadsReport()); Notice(GetThreadsReport());
break; break;
@ -605,7 +593,6 @@ namespace OpenSim.Framework.Servers
public string osSecret { public string osSecret {
// Secret uuid for the simulator // Secret uuid for the simulator
get { return m_osSecret; } get { return m_osSecret; }
} }
public string StatReport(IOSHttpRequest httpRequest) public string StatReport(IOSHttpRequest httpRequest)
@ -613,11 +600,11 @@ namespace OpenSim.Framework.Servers
// If we catch a request for "callback", wrap the response in the value for jsonp // If we catch a request for "callback", wrap the response in the value for jsonp
if (httpRequest.Query.ContainsKey("callback")) if (httpRequest.Query.ContainsKey("callback"))
{ {
return httpRequest.Query["callback"].ToString() + "(" + m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");"; return httpRequest.Query["callback"].ToString() + "(" + StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");";
} }
else else
{ {
return m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version); return StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version);
} }
} }

View File

@ -54,8 +54,23 @@ namespace OpenSim.Framework.Servers.HttpServer
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); private HttpServerLogWriter httpserverlog = new HttpServerLogWriter();
/// <summary>
/// Gets or sets the debug level.
/// </summary>
/// <value>
/// See MainServer.DebugLevel.
/// </value>
public int DebugLevel { get; set; } public int DebugLevel { get; set; }
/// <summary>
/// Request number for diagnostic purposes.
/// </summary>
/// <remarks>
/// This is an internal number. In some debug situations an external number may also be supplied in the
/// opensim-request-id header but we are not currently logging this.
/// </remarks>
public int RequestNumber { get; private set; }
private volatile int NotSocketErrors = 0; private volatile int NotSocketErrors = 0;
public volatile bool HTTPDRunning = false; public volatile bool HTTPDRunning = false;
@ -67,7 +82,7 @@ namespace OpenSim.Framework.Servers.HttpServer
protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>(); protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>();
protected Dictionary<string, IRequestHandler> m_streamHandlers = new Dictionary<string, IRequestHandler>(); protected Dictionary<string, IRequestHandler> m_streamHandlers = new Dictionary<string, IRequestHandler>();
protected Dictionary<string, GenericHTTPMethod> m_HTTPHandlers = new Dictionary<string, GenericHTTPMethod>(); protected Dictionary<string, GenericHTTPMethod> m_HTTPHandlers = new Dictionary<string, GenericHTTPMethod>();
protected Dictionary<string, IHttpAgentHandler> m_agentHandlers = new Dictionary<string, IHttpAgentHandler>(); // protected Dictionary<string, IHttpAgentHandler> m_agentHandlers = new Dictionary<string, IHttpAgentHandler>();
protected Dictionary<string, PollServiceEventArgs> m_pollHandlers = protected Dictionary<string, PollServiceEventArgs> m_pollHandlers =
new Dictionary<string, PollServiceEventArgs>(); new Dictionary<string, PollServiceEventArgs>();
@ -245,29 +260,29 @@ namespace OpenSim.Framework.Servers.HttpServer
return new List<string>(m_pollHandlers.Keys); return new List<string>(m_pollHandlers.Keys);
} }
// Note that the agent string is provided simply to differentiate // // Note that the agent string is provided simply to differentiate
// the handlers - it is NOT required to be an actual agent header // // the handlers - it is NOT required to be an actual agent header
// value. // // value.
public bool AddAgentHandler(string agent, IHttpAgentHandler handler) // public bool AddAgentHandler(string agent, IHttpAgentHandler handler)
{ // {
lock (m_agentHandlers) // lock (m_agentHandlers)
{ // {
if (!m_agentHandlers.ContainsKey(agent)) // if (!m_agentHandlers.ContainsKey(agent))
{ // {
m_agentHandlers.Add(agent, handler); // m_agentHandlers.Add(agent, handler);
return true; // return true;
} // }
} // }
//
//must already have a handler for that path so return false // //must already have a handler for that path so return false
return false; // return false;
} // }
//
public List<string> GetAgentHandlerKeys() // public List<string> GetAgentHandlerKeys()
{ // {
lock (m_agentHandlers) // lock (m_agentHandlers)
return new List<string>(m_agentHandlers.Keys); // return new List<string>(m_agentHandlers.Keys);
} // }
public bool AddLLSDHandler(string path, LLSDMethod handler) public bool AddLLSDHandler(string path, LLSDMethod handler)
{ {
@ -296,6 +311,8 @@ namespace OpenSim.Framework.Servers.HttpServer
private void OnRequest(object source, RequestEventArgs args) private void OnRequest(object source, RequestEventArgs args)
{ {
RequestNumber++;
try try
{ {
IHttpClientContext context = (IHttpClientContext)source; IHttpClientContext context = (IHttpClientContext)source;
@ -406,7 +423,6 @@ namespace OpenSim.Framework.Servers.HttpServer
string requestMethod = request.HttpMethod; string requestMethod = request.HttpMethod;
string uriString = request.RawUrl; string uriString = request.RawUrl;
// string reqnum = "unknown";
int requestStartTick = Environment.TickCount; int requestStartTick = Environment.TickCount;
// Will be adjusted later on. // Will be adjusted later on.
@ -423,22 +439,22 @@ namespace OpenSim.Framework.Servers.HttpServer
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true); Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true);
// This is the REST agent interface. We require an agent to properly identify // // This is the REST agent interface. We require an agent to properly identify
// itself. If the REST handler recognizes the prefix it will attempt to // // itself. If the REST handler recognizes the prefix it will attempt to
// satisfy the request. If it is not recognizable, and no damage has occurred // // satisfy the request. If it is not recognizable, and no damage has occurred
// the request can be passed through to the other handlers. This is a low // // the request can be passed through to the other handlers. This is a low
// probability event; if a request is matched it is normally expected to be // // probability event; if a request is matched it is normally expected to be
// handled // // handled
IHttpAgentHandler agentHandler; // IHttpAgentHandler agentHandler;
//
if (TryGetAgentHandler(request, response, out agentHandler)) // if (TryGetAgentHandler(request, response, out agentHandler))
{ // {
if (HandleAgentRequest(agentHandler, request, response)) // if (HandleAgentRequest(agentHandler, request, response))
{ // {
requestEndTick = Environment.TickCount; // requestEndTick = Environment.TickCount;
return; // return;
} // }
} // }
//response.KeepAlive = true; //response.KeepAlive = true;
response.SendChunked = false; response.SendChunked = false;
@ -450,9 +466,7 @@ namespace OpenSim.Framework.Servers.HttpServer
if (TryGetStreamHandler(handlerKey, out requestHandler)) if (TryGetStreamHandler(handlerKey, out requestHandler))
{ {
if (DebugLevel >= 3) if (DebugLevel >= 3)
m_log.DebugFormat( LogIncomingToStreamHandler(request, requestHandler);
"[BASE HTTP SERVER]: Found stream handler for {0} {1} {2} {3}",
request.HttpMethod, request.Url.PathAndQuery, requestHandler.Name, requestHandler.Description);
response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type.
@ -529,11 +543,8 @@ namespace OpenSim.Framework.Servers.HttpServer
{ {
case null: case null:
case "text/html": case "text/html":
if (DebugLevel >= 3) if (DebugLevel >= 3)
m_log.DebugFormat( LogIncomingToContentTypeHandler(request);
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
buffer = HandleHTTPRequest(request, response); buffer = HandleHTTPRequest(request, response);
break; break;
@ -541,11 +552,8 @@ namespace OpenSim.Framework.Servers.HttpServer
case "application/llsd+xml": case "application/llsd+xml":
case "application/xml+llsd": case "application/xml+llsd":
case "application/llsd+json": case "application/llsd+json":
if (DebugLevel >= 3) if (DebugLevel >= 3)
m_log.DebugFormat( LogIncomingToContentTypeHandler(request);
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
buffer = HandleLLSDRequests(request, response); buffer = HandleLLSDRequests(request, response);
break; break;
@ -564,9 +572,7 @@ namespace OpenSim.Framework.Servers.HttpServer
if (DoWeHaveALLSDHandler(request.RawUrl)) if (DoWeHaveALLSDHandler(request.RawUrl))
{ {
if (DebugLevel >= 3) if (DebugLevel >= 3)
m_log.DebugFormat( LogIncomingToContentTypeHandler(request);
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
buffer = HandleLLSDRequests(request, response); buffer = HandleLLSDRequests(request, response);
} }
@ -574,18 +580,14 @@ namespace OpenSim.Framework.Servers.HttpServer
else if (DoWeHaveAHTTPHandler(request.RawUrl)) else if (DoWeHaveAHTTPHandler(request.RawUrl))
{ {
if (DebugLevel >= 3) if (DebugLevel >= 3)
m_log.DebugFormat( LogIncomingToContentTypeHandler(request);
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
buffer = HandleHTTPRequest(request, response); buffer = HandleHTTPRequest(request, response);
} }
else else
{ {
if (DebugLevel >= 3) if (DebugLevel >= 3)
m_log.DebugFormat( LogIncomingToXmlRpcHandler(request);
"[BASE HTTP SERVER]: Assuming a generic XMLRPC request for {0} {1}",
request.HttpMethod, request.Url.PathAndQuery);
// generic login request. // generic login request.
buffer = HandleXmlRpcRequests(request, response); buffer = HandleXmlRpcRequests(request, response);
@ -629,11 +631,11 @@ namespace OpenSim.Framework.Servers.HttpServer
} }
catch (IOException e) catch (IOException e)
{ {
m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.Message), e); m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e);
} }
catch (Exception e) catch (Exception e)
{ {
m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.Message), e); m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e);
SendHTML500(response); SendHTML500(response);
} }
finally finally
@ -644,14 +646,90 @@ namespace OpenSim.Framework.Servers.HttpServer
if (tickdiff > 3000 && (requestHandler == null || requestHandler.Name == null || requestHandler.Name != "GetTexture")) if (tickdiff > 3000 && (requestHandler == null || requestHandler.Name == null || requestHandler.Name != "GetTexture"))
{ {
m_log.InfoFormat( m_log.InfoFormat(
"[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} from {4} took {5}ms", "[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms",
RequestNumber,
requestMethod, requestMethod,
uriString, uriString,
requestHandler != null ? requestHandler.Name : "", requestHandler != null ? requestHandler.Name : "",
requestHandler != null ? requestHandler.Description : "", requestHandler != null ? requestHandler.Description : "",
request.RemoteIPEndPoint.ToString(), request.RemoteIPEndPoint,
tickdiff); tickdiff);
} }
else if (DebugLevel >= 4)
{
m_log.DebugFormat(
"[BASE HTTP SERVER]: HTTP IN {0} :{1} took {2}ms",
RequestNumber,
Port,
tickdiff);
}
}
}
private void LogIncomingToStreamHandler(OSHttpRequest request, IRequestHandler requestHandler)
{
m_log.DebugFormat(
"[BASE HTTP SERVER]: HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}",
RequestNumber,
Port,
request.HttpMethod,
request.Url.PathAndQuery,
requestHandler.Name,
requestHandler.Description,
request.RemoteIPEndPoint);
if (DebugLevel >= 5)
LogIncomingInDetail(request);
}
private void LogIncomingToContentTypeHandler(OSHttpRequest request)
{
m_log.DebugFormat(
"[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
RequestNumber,
Port,
(request.ContentType == null || request.ContentType == "") ? "not set" : request.ContentType,
request.HttpMethod,
request.Url.PathAndQuery,
request.RemoteIPEndPoint);
if (DebugLevel >= 5)
LogIncomingInDetail(request);
}
private void LogIncomingToXmlRpcHandler(OSHttpRequest request)
{
m_log.DebugFormat(
"[BASE HTTP SERVER]: HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}",
RequestNumber,
Port,
request.HttpMethod,
request.Url.PathAndQuery,
request.RemoteIPEndPoint);
if (DebugLevel >= 5)
LogIncomingInDetail(request);
}
private void LogIncomingInDetail(OSHttpRequest request)
{
using (StreamReader reader = new StreamReader(Util.Copy(request.InputStream), Encoding.UTF8))
{
string output;
if (DebugLevel == 5)
{
const int sampleLength = 80;
char[] sampleChars = new char[sampleLength];
reader.Read(sampleChars, 0, sampleLength);
output = new string(sampleChars);
}
else
{
output = reader.ReadToEnd();
}
m_log.DebugFormat("[BASE HTTP SERVER]: {0}...", output.Replace("\n", @"\n"));
} }
} }
@ -747,24 +825,24 @@ namespace OpenSim.Framework.Servers.HttpServer
} }
} }
private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler) // private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler)
{ // {
agentHandler = null; // agentHandler = null;
//
lock (m_agentHandlers) // lock (m_agentHandlers)
{ // {
foreach (IHttpAgentHandler handler in m_agentHandlers.Values) // foreach (IHttpAgentHandler handler in m_agentHandlers.Values)
{ // {
if (handler.Match(request, response)) // if (handler.Match(request, response))
{ // {
agentHandler = handler; // agentHandler = handler;
return true; // return true;
} // }
} // }
} // }
//
return false; // return false;
} // }
/// <summary> /// <summary>
/// Try all the registered xmlrpc handlers when an xmlrpc request is received. /// Try all the registered xmlrpc handlers when an xmlrpc request is received.
@ -1737,21 +1815,21 @@ namespace OpenSim.Framework.Servers.HttpServer
m_pollHandlers.Remove(path); m_pollHandlers.Remove(path);
} }
public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler) // public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler)
{ // {
lock (m_agentHandlers) // lock (m_agentHandlers)
{ // {
IHttpAgentHandler foundHandler; // IHttpAgentHandler foundHandler;
//
if (m_agentHandlers.TryGetValue(agent, out foundHandler) && foundHandler == handler) // if (m_agentHandlers.TryGetValue(agent, out foundHandler) && foundHandler == handler)
{ // {
m_agentHandlers.Remove(agent); // m_agentHandlers.Remove(agent);
return true; // return true;
} // }
} // }
//
return false; // return false;
} // }
public void RemoveXmlRPCHandler(string method) public void RemoveXmlRPCHandler(string method)
{ {

View File

@ -41,10 +41,10 @@ namespace OpenSim.Framework.Servers.HttpServer
uint Port { get; } uint Port { get; }
bool UseSSL { get; } bool UseSSL { get; }
// Note that the agent string is provided simply to differentiate // // Note that the agent string is provided simply to differentiate
// the handlers - it is NOT required to be an actual agent header // // the handlers - it is NOT required to be an actual agent header
// value. // // value.
bool AddAgentHandler(string agent, IHttpAgentHandler handler); // bool AddAgentHandler(string agent, IHttpAgentHandler handler);
/// <summary> /// <summary>
/// Add a handler for an HTTP request. /// Add a handler for an HTTP request.
@ -106,13 +106,13 @@ namespace OpenSim.Framework.Servers.HttpServer
bool SetDefaultLLSDHandler(DefaultLLSDMethod handler); bool SetDefaultLLSDHandler(DefaultLLSDMethod handler);
/// <summary> // /// <summary>
/// Remove the agent if it is registered. // /// Remove the agent if it is registered.
/// </summary> // /// </summary>
/// <param name="agent"></param> // /// <param name="agent"></param>
/// <param name="handler"></param> // /// <param name="handler"></param>
/// <returns></returns> // /// <returns></returns>
bool RemoveAgentHandler(string agent, IHttpAgentHandler handler); // bool RemoveAgentHandler(string agent, IHttpAgentHandler handler);
/// <summary> /// <summary>
/// Remove an HTTP handler /// Remove an HTTP handler

View File

@ -29,6 +29,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using System.Net; using System.Net;
using System.Text;
using log4net; using log4net;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Framework.Console; using OpenSim.Framework.Console;
@ -47,9 +48,12 @@ namespace OpenSim.Framework.Servers
/// Control the printing of certain debug messages. /// Control the printing of certain debug messages.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// If DebugLevel >= 1, then short warnings are logged when receiving bad input data. /// If DebugLevel >= 1 then short warnings are logged when receiving bad input data.
/// If DebugLevel >= 2, then long warnings are logged when receiving bad input data. /// If DebugLevel >= 2 then long warnings are logged when receiving bad input data.
/// If DebugLevel >= 3, then short notices about all incoming non-poll HTTP requests are logged. /// If DebugLevel >= 3 then short notices about all incoming non-poll HTTP requests are logged.
/// If DebugLevel >= 4 then the time taken to fulfill the request is logged.
/// If DebugLevel >= 5 then the start of the body of incoming non-poll HTTP requests will be logged.
/// If DebugLevel >= 6 then the entire body of incoming non-poll HTTP requests will be logged.
/// </remarks> /// </remarks>
public static int DebugLevel public static int DebugLevel
{ {
@ -101,17 +105,28 @@ namespace OpenSim.Framework.Servers
get { return new Dictionary<uint, BaseHttpServer>(m_Servers); } get { return new Dictionary<uint, BaseHttpServer>(m_Servers); }
} }
public static void RegisterHttpConsoleCommands(ICommandConsole console) public static void RegisterHttpConsoleCommands(ICommandConsole console)
{ {
console.Commands.AddCommand( console.Commands.AddCommand(
"Debug", false, "debug http", "debug http [<level>]", "Comms", false, "show http-handlers",
"Turn on inbound non-poll http request debugging.", "show http-handlers",
"If level <= 0, then no extra logging is done.\n" "Show all registered http handlers", HandleShowHttpHandlersCommand);
+ "If level >= 1, then short warnings are logged when receiving bad input data.\n"
+ "If level >= 2, then long warnings are logged when receiving bad input data.\n" console.Commands.AddCommand(
+ "If level >= 3, then short notices about all incoming non-poll HTTP requests are logged.\n" "Debug", false, "debug http", "debug http <in|out|all> [<level>]",
+ "If no level is specified then the current level is returned.", "Turn on http request logging.",
"If in or all and\n"
+ " level <= 0 then no extra logging is done.\n"
+ " level >= 1 then short warnings are logged when receiving bad input data.\n"
+ " level >= 2 then long warnings are logged when receiving bad input data.\n"
+ " level >= 3 then short notices about all incoming non-poll HTTP requests are logged.\n"
+ " level >= 4 then the time taken to fulfill the request is logged.\n"
+ " level >= 5 then a sample from the beginning of the incoming data is logged.\n"
+ " level >= 6 then the entire incoming data is logged.\n"
+ " no level is specified then the current level is returned.\n\n"
+ "If out or all and\n"
+ " level >= 3 then short notices about all outgoing requests going through WebUtil are logged.\n"
+ " level >= 4 then the time taken to fulfill the request is logged.\n",
HandleDebugHttpCommand); HandleDebugHttpCommand);
} }
@ -119,25 +134,120 @@ namespace OpenSim.Framework.Servers
/// Turn on some debugging values for OpenSim. /// Turn on some debugging values for OpenSim.
/// </summary> /// </summary>
/// <param name="args"></param> /// <param name="args"></param>
private static void HandleDebugHttpCommand(string module, string[] args) private static void HandleDebugHttpCommand(string module, string[] cmdparams)
{ {
if (args.Length == 3) if (cmdparams.Length < 3)
{ {
int newDebug; MainConsole.Instance.Output("Usage: debug http <in|out|all> 0..6");
if (int.TryParse(args[2], out newDebug)) return;
{
MainServer.DebugLevel = newDebug;
MainConsole.Instance.OutputFormat("Debug http level set to {0}", newDebug);
} }
}
else if (args.Length == 2) bool inReqs = false;
bool outReqs = false;
bool allReqs = false;
string subCommand = cmdparams[2];
if (subCommand.ToLower() == "in")
{ {
MainConsole.Instance.OutputFormat("Current debug http level is {0}", MainServer.DebugLevel); inReqs = true;
}
else if (subCommand.ToLower() == "out")
{
outReqs = true;
}
else if (subCommand.ToLower() == "all")
{
allReqs = true;
} }
else else
{ {
MainConsole.Instance.Output("Usage: debug http 0..3"); MainConsole.Instance.Output("You must specify in, out or all");
return;
} }
if (cmdparams.Length >= 4)
{
string rawNewDebug = cmdparams[3];
int newDebug;
if (!int.TryParse(rawNewDebug, out newDebug))
{
MainConsole.Instance.OutputFormat("{0} is not a valid debug level", rawNewDebug);
return;
}
if (newDebug < 0 || newDebug > 6)
{
MainConsole.Instance.OutputFormat("{0} is outside the valid debug level range of 0..6", newDebug);
return;
}
if (allReqs || inReqs)
{
MainServer.DebugLevel = newDebug;
MainConsole.Instance.OutputFormat("IN debug level set to {0}", newDebug);
}
if (allReqs || outReqs)
{
WebUtil.DebugLevel = newDebug;
MainConsole.Instance.OutputFormat("OUT debug level set to {0}", newDebug);
}
}
else
{
if (allReqs || inReqs)
MainConsole.Instance.OutputFormat("Current IN debug level is {0}", MainServer.DebugLevel);
if (allReqs || outReqs)
MainConsole.Instance.OutputFormat("Current OUT debug level is {0}", WebUtil.DebugLevel);
}
}
private static void HandleShowHttpHandlersCommand(string module, string[] args)
{
if (args.Length != 2)
{
MainConsole.Instance.Output("Usage: show http-handlers");
return;
}
StringBuilder handlers = new StringBuilder();
lock (m_Servers)
{
foreach (BaseHttpServer httpServer in m_Servers.Values)
{
handlers.AppendFormat(
"Registered HTTP Handlers for server at {0}:{1}\n", httpServer.ListenIPAddress, httpServer.Port);
handlers.AppendFormat("* XMLRPC:\n");
foreach (String s in httpServer.GetXmlRpcHandlerKeys())
handlers.AppendFormat("\t{0}\n", s);
handlers.AppendFormat("* HTTP:\n");
List<String> poll = httpServer.GetPollServiceHandlerKeys();
foreach (String s in httpServer.GetHTTPHandlerKeys())
handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty));
// handlers.AppendFormat("* Agent:\n");
// foreach (String s in httpServer.GetAgentHandlerKeys())
// handlers.AppendFormat("\t{0}\n", s);
handlers.AppendFormat("* LLSD:\n");
foreach (String s in httpServer.GetLLSDHandlerKeys())
handlers.AppendFormat("\t{0}\n", s);
handlers.AppendFormat("* StreamHandlers ({0}):\n", httpServer.GetStreamHandlerKeys().Count);
foreach (String s in httpServer.GetStreamHandlerKeys())
handlers.AppendFormat("\t{0}\n", s);
handlers.Append("\n");
}
}
MainConsole.Instance.Output(handlers.ToString());
} }
/// <summary> /// <summary>

View File

@ -29,7 +29,7 @@ namespace OpenSim
{ {
public class VersionInfo public class VersionInfo
{ {
private const string VERSION_NUMBER = "0.7.4CM"; private const string VERSION_NUMBER = "0.7.5CM";
private const Flavour VERSION_FLAVOUR = Flavour.Dev; private const Flavour VERSION_FLAVOUR = Flavour.Dev;
public enum Flavour public enum Flavour

View File

@ -39,10 +39,12 @@ using OpenMetaverse;
namespace OpenSim.Framework namespace OpenSim.Framework
{ {
/// <summary> /// <summary>
/// A dictionary for task inventory. /// A dictionary containing task inventory items. Indexed by item UUID.
/// </summary> /// </summary>
/// <remarks>
/// This class is not thread safe. Callers must synchronize on Dictionary methods or Clone() this object before /// This class is not thread safe. Callers must synchronize on Dictionary methods or Clone() this object before
/// iterating over it. /// iterating over it.
/// </remarks>
public class TaskInventoryDictionary : Dictionary<UUID, TaskInventoryItem>, public class TaskInventoryDictionary : Dictionary<UUID, TaskInventoryItem>,
ICloneable, IXmlSerializable ICloneable, IXmlSerializable
{ {

View File

@ -73,9 +73,6 @@ namespace OpenSim.Framework
private bool _ownerChanged = false; private bool _ownerChanged = false;
// This used ONLY during copy. It can't be relied on at other times!
private bool _scriptRunning = true;
public UUID AssetID { public UUID AssetID {
get { get {
return _assetID; return _assetID;
@ -353,14 +350,13 @@ namespace OpenSim.Framework
} }
} }
public bool ScriptRunning { /// <summary>
get { /// This used ONLY during copy. It can't be relied on at other times!
return _scriptRunning; /// </summary>
} /// <remarks>
set { /// For true script running status, use IEntityInventory.TryGetScriptInstanceRunning() for now.
_scriptRunning = value; /// </remarks>
} public bool ScriptRunning { get; set; }
}
// See ICloneable // See ICloneable
@ -388,6 +384,7 @@ namespace OpenSim.Framework
public TaskInventoryItem() public TaskInventoryItem()
{ {
ScriptRunning = true;
CreationDate = (uint)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; CreationDate = (uint)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
} }
} }

View File

@ -545,6 +545,19 @@ namespace OpenSim.Framework
return (x + y - (min >> 1) - (min >> 2) + (min >> 4)); return (x + y - (min >> 1) - (min >> 2) + (min >> 4));
} }
/// <summary>
/// Determines whether a point is inside a bounding box.
/// </summary>
/// <param name='v'></param>
/// <param name='min'></param>
/// <param name='max'></param>
/// <returns></returns>
public static bool IsInsideBox(Vector3 v, Vector3 min, Vector3 max)
{
return v.X >= min.X & v.Y >= min.Y && v.Z >= min.Z
&& v.X <= max.X && v.Y <= max.Y && v.Z <= max.Z;
}
/// <summary> /// <summary>
/// Are the co-ordinates of the new region visible from the old region? /// Are the co-ordinates of the new region visible from the old region?
/// </summary> /// </summary>
@ -862,6 +875,12 @@ namespace OpenSim.Framework
return Math.Min(Math.Max(x, min), max); return Math.Min(Math.Max(x, min), max);
} }
public static Vector3 Clip(Vector3 vec, float min, float max)
{
return new Vector3(Clip(vec.X, min, max), Clip(vec.Y, min, max),
Clip(vec.Z, min, max));
}
/// <summary> /// <summary>
/// Convert an UUID to a raw uuid string. Right now this is a string without hyphens. /// Convert an UUID to a raw uuid string. Right now this is a string without hyphens.
/// </summary> /// </summary>
@ -1013,6 +1032,38 @@ namespace OpenSim.Framework
} }
} }
/// <summary>
/// Copy data from one stream to another, leaving the read position of both streams at the beginning.
/// </summary>
/// <param name='inputStream'>
/// Input stream. Must be seekable.
/// </param>
/// <exception cref='ArgumentException'>
/// Thrown if the input stream is not seekable.
/// </exception>
public static Stream Copy(Stream inputStream)
{
if (!inputStream.CanSeek)
throw new ArgumentException("Util.Copy(Stream inputStream) must receive an inputStream that can seek");
const int readSize = 256;
byte[] buffer = new byte[readSize];
MemoryStream ms = new MemoryStream();
int count = inputStream.Read(buffer, 0, readSize);
while (count > 0)
{
ms.Write(buffer, 0, count);
count = inputStream.Read(buffer, 0, readSize);
}
ms.Position = 0;
inputStream.Position = 0;
return ms;
}
public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args) public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args)
{ {
return SendXmlRpcCommand(url, methodName, args); return SendXmlRpcCommand(url, methodName, args);

View File

@ -53,10 +53,18 @@ namespace OpenSim.Framework
LogManager.GetLogger( LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType); MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// Control the printing of certain debug messages.
/// </summary>
/// <remarks>
/// If DebugLevel >= 3 then short notices about outgoing HTTP requests are logged.
/// </remarks>
public static int DebugLevel { get; set; }
/// <summary> /// <summary>
/// Request number for diagnostic purposes. /// Request number for diagnostic purposes.
/// </summary> /// </summary>
public static int RequestNumber = 0; public static int RequestNumber { get; internal set; }
/// <summary> /// <summary>
/// this is the header field used to communicate the local request id /// this is the header field used to communicate the local request id
@ -146,7 +154,11 @@ namespace OpenSim.Framework
private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed) private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed)
{ {
int reqnum = RequestNumber++; int reqnum = RequestNumber++;
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
if (DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} ServiceOSD {1} {2} (timeout {3}, compressed {4})",
reqnum, method, url, timeout, compressed);
string errorMessage = "unknown error"; string errorMessage = "unknown error";
int tickstart = Util.EnvironmentTickCount(); int tickstart = Util.EnvironmentTickCount();
@ -230,7 +242,7 @@ namespace OpenSim.Framework
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > LongCallTime) if (tickdiff > LongCallTime)
m_log.InfoFormat( m_log.InfoFormat(
"[OSD REQUEST]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", "[WEB UTIL]: Slow ServiceOSD request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum, reqnum,
method, method,
url, url,
@ -239,10 +251,14 @@ namespace OpenSim.Framework
strBuffer != null strBuffer != null
? (strBuffer.Length > MaxRequestDiagLength ? strBuffer.Remove(MaxRequestDiagLength) : strBuffer) ? (strBuffer.Length > MaxRequestDiagLength ? strBuffer.Remove(MaxRequestDiagLength) : strBuffer)
: ""); : "");
else if (DebugLevel >= 4)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
reqnum, tickdiff, tickdata);
} }
m_log.DebugFormat( m_log.DebugFormat(
"[WEB UTIL]: <{0}> osd request for {1}, method {2} FAILED: {3}", reqnum, url, method, errorMessage); "[WEB UTIL]: ServiceOSD request {0} {1} {2} FAILED: {3}", reqnum, url, method, errorMessage);
return ErrorResponseMap(errorMessage); return ErrorResponseMap(errorMessage);
} }
@ -318,7 +334,11 @@ namespace OpenSim.Framework
{ {
int reqnum = RequestNumber++; int reqnum = RequestNumber++;
string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown"; string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown";
// m_log.DebugFormat("[WEB UTIL]: <{0}> start form request for {1}, method {2}",reqnum,url,method);
if (DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} ServiceForm {1} {2} (timeout {3})",
reqnum, method, url, timeout);
string errorMessage = "unknown error"; string errorMessage = "unknown error";
int tickstart = Util.EnvironmentTickCount(); int tickstart = Util.EnvironmentTickCount();
@ -381,7 +401,7 @@ namespace OpenSim.Framework
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > LongCallTime) if (tickdiff > LongCallTime)
m_log.InfoFormat( m_log.InfoFormat(
"[SERVICE FORM]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", "[WEB UTIL]: Slow ServiceForm request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum, reqnum,
method, method,
url, url,
@ -390,9 +410,13 @@ namespace OpenSim.Framework
queryString != null queryString != null
? (queryString.Length > MaxRequestDiagLength) ? queryString.Remove(MaxRequestDiagLength) : queryString ? (queryString.Length > MaxRequestDiagLength) ? queryString.Remove(MaxRequestDiagLength) : queryString
: ""); : "");
else if (DebugLevel >= 4)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
reqnum, tickdiff, tickdata);
} }
m_log.WarnFormat("[SERVICE FORM]: <{0}> form request to {1} failed: {2}", reqnum, url, errorMessage); m_log.WarnFormat("[WEB UTIL]: ServiceForm request {0} {1} {2} failed: {2}", reqnum, method, url, errorMessage);
return ErrorResponseMap(errorMessage); return ErrorResponseMap(errorMessage);
} }
@ -644,7 +668,6 @@ namespace OpenSim.Framework
/// <returns></returns> /// <returns></returns>
public static string[] GetPreferredImageTypes(string accept) public static string[] GetPreferredImageTypes(string accept)
{ {
if (accept == null || accept == string.Empty) if (accept == null || accept == string.Empty)
return new string[0]; return new string[0];
@ -703,14 +726,16 @@ namespace OpenSim.Framework
int maxConnections) int maxConnections)
{ {
int reqnum = WebUtil.RequestNumber++; int reqnum = WebUtil.RequestNumber++;
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
if (WebUtil.DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} AsynchronousRequestObject {1} {2}",
reqnum, verb, requestUrl);
int tickstart = Util.EnvironmentTickCount(); int tickstart = Util.EnvironmentTickCount();
// int tickdata = 0; // int tickdata = 0;
int tickdiff = 0; int tickdiff = 0;
// m_log.DebugFormat("[ASYNC REQUEST]: Starting {0} {1}", verb, requestUrl);
Type type = typeof(TRequest); Type type = typeof(TRequest);
WebRequest request = WebRequest.Create(requestUrl); WebRequest request = WebRequest.Create(requestUrl);
@ -868,7 +893,7 @@ namespace OpenSim.Framework
} }
m_log.InfoFormat( m_log.InfoFormat(
"[ASYNC REQUEST]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", "[ASYNC REQUEST]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum, reqnum,
verb, verb,
requestUrl, requestUrl,
@ -883,6 +908,12 @@ namespace OpenSim.Framework
requestUrl, requestUrl,
tickdiff); tickdiff);
} }
else if (WebUtil.DebugLevel >= 4)
{
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} took {1}ms",
reqnum, tickdiff);
}
} }
} }
@ -903,7 +934,11 @@ namespace OpenSim.Framework
public static string MakeRequest(string verb, string requestUrl, string obj) public static string MakeRequest(string verb, string requestUrl, string obj)
{ {
int reqnum = WebUtil.RequestNumber++; int reqnum = WebUtil.RequestNumber++;
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
if (WebUtil.DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} SynchronousRestForms {1} {2}",
reqnum, verb, requestUrl);
int tickstart = Util.EnvironmentTickCount(); int tickstart = Util.EnvironmentTickCount();
int tickdata = 0; int tickdata = 0;
@ -990,7 +1025,7 @@ namespace OpenSim.Framework
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > WebUtil.LongCallTime) if (tickdiff > WebUtil.LongCallTime)
m_log.InfoFormat( m_log.InfoFormat(
"[FORMS]: Slow request to <{0}> {1} {2} took {3}ms {4}ms writing {5}", "[FORMS]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum, reqnum,
verb, verb,
requestUrl, requestUrl,
@ -998,6 +1033,10 @@ namespace OpenSim.Framework
tickset, tickset,
tickdata, tickdata,
obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj); obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj);
else if (WebUtil.DebugLevel >= 4)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
reqnum, tickdiff, tickdata);
return respstring; return respstring;
} }
@ -1032,7 +1071,11 @@ namespace OpenSim.Framework
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections) public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections)
{ {
int reqnum = WebUtil.RequestNumber++; int reqnum = WebUtil.RequestNumber++;
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
if (WebUtil.DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} SynchronousRestObject {1} {2}",
reqnum, verb, requestUrl);
int tickstart = Util.EnvironmentTickCount(); int tickstart = Util.EnvironmentTickCount();
int tickdata = 0; int tickdata = 0;
@ -1151,7 +1194,7 @@ namespace OpenSim.Framework
} }
m_log.InfoFormat( m_log.InfoFormat(
"[SynchronousRestObjectRequester]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", "[SynchronousRestObjectRequester]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum, reqnum,
verb, verb,
requestUrl, requestUrl,
@ -1159,6 +1202,12 @@ namespace OpenSim.Framework
tickdata, tickdata,
originalRequest); originalRequest);
} }
else if (WebUtil.DebugLevel >= 4)
{
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
reqnum, tickdiff, tickdata);
}
return deserial; return deserial;
} }

View File

@ -35,6 +35,7 @@ using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Timers; using System.Timers;
using log4net; using log4net;
using NDesk.Options;
using Nini.Config; using Nini.Config;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
@ -253,8 +254,14 @@ namespace OpenSim
m_console.Commands.AddCommand("Debug", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug); m_console.Commands.AddCommand("Debug", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug);
m_console.Commands.AddCommand("Debug", false, "debug scene", m_console.Commands.AddCommand("Debug", false, "debug scene",
"debug scene <scripting> <collisions> <physics>", "debug scene active|collisions|physics|scripting|teleport true|false",
"Turn on scene debugging", Debug); "Turn on scene debugging.",
"If active is false then main scene update and maintenance loops are suspended.\n"
+ "If collisions is false then collisions with other objects are turned off.\n"
+ "If physics is false then all physics objects are non-physical.\n"
+ "If scripting is false then no scripting operations happen.\n"
+ "If teleport is true then some extra teleport debug information is logged.",
Debug);
m_console.Commands.AddCommand("General", false, "change region", m_console.Commands.AddCommand("General", false, "change region",
"change region <region name>", "change region <region name>",
@ -291,7 +298,7 @@ namespace OpenSim
m_console.Commands.AddCommand("Archiving", false, "save oar", m_console.Commands.AddCommand("Archiving", false, "save oar",
//"save oar [-v|--version=<N>] [-p|--profile=<url>] [<OAR path>]", //"save oar [-v|--version=<N>] [-p|--profile=<url>] [<OAR path>]",
"save oar [-h|--home=<url>] [--noassets] [--publish] [--perm=<permissions>] [<OAR path>]", "save oar [-h|--home=<url>] [--noassets] [--publish] [--perm=<permissions>] [--all] [<OAR path>]",
"Save a region's data to an OAR archive.", "Save a region's data to an OAR archive.",
// "-v|--version=<N> generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine // "-v|--version=<N> generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine
"-h|--home=<url> adds the url of the profile service to the saved user information.\n" "-h|--home=<url> adds the url of the profile service to the saved user information.\n"
@ -301,6 +308,7 @@ namespace OpenSim
+ " this is useful if you're making oars generally available that might be reloaded to the same grid from which you published\n" + " this is useful if you're making oars generally available that might be reloaded to the same grid from which you published\n"
+ "--perm=<permissions> stops objects with insufficient permissions from being saved to the OAR.\n" + "--perm=<permissions> stops objects with insufficient permissions from being saved to the OAR.\n"
+ " <permissions> can contain one or more of these characters: \"C\" = Copy, \"T\" = Transfer\n" + " <permissions> can contain one or more of these characters: \"C\" = Copy, \"T\" = Transfer\n"
+ "--all saves all the regions in the simulator, instead of just the current region.\n"
+ "The OAR path must be a filesystem path." + "The OAR path must be a filesystem path."
+ " If this is not given then the oar is saved to region.oar in the current directory.", + " If this is not given then the oar is saved to region.oar in the current directory.",
SaveOar); SaveOar);
@ -310,8 +318,11 @@ namespace OpenSim
"Change the scale of a named prim", HandleEditScale); "Change the scale of a named prim", HandleEditScale);
m_console.Commands.AddCommand("Users", false, "kick user", m_console.Commands.AddCommand("Users", false, "kick user",
"kick user <first> <last> [message]", "kick user <first> <last> [--force] [message]",
"Kick a user off the simulator", KickUserCommand); "Kick a user off the simulator",
"The --force option will kick the user without any checks to see whether it's already in the process of closing\n"
+ "Only use this option if you are sure the avatar is inactive and a normal kick user operation does not removed them",
KickUserCommand);
m_console.Commands.AddCommand("Users", false, "show users", m_console.Commands.AddCommand("Users", false, "show users",
"show users [full]", "show users [full]",
@ -328,10 +339,6 @@ namespace OpenSim
"show circuits", "show circuits",
"Show agent circuit data", HandleShow); "Show agent circuit data", HandleShow);
m_console.Commands.AddCommand("Comms", false, "show http-handlers",
"show http-handlers",
"Show all registered http handlers", HandleShow);
m_console.Commands.AddCommand("Comms", false, "show pending-objects", m_console.Commands.AddCommand("Comms", false, "show pending-objects",
"show pending-objects", "show pending-objects",
"Show # of objects on the pending queues of all scene viewers", HandleShow); "Show # of objects on the pending queues of all scene viewers", HandleShow);
@ -416,6 +423,7 @@ namespace OpenSim
{ {
RunCommandScript(m_shutdownCommandsFile); RunCommandScript(m_shutdownCommandsFile);
} }
base.ShutdownSpecific(); base.ShutdownSpecific();
} }
@ -453,11 +461,17 @@ namespace OpenSim
/// <param name="cmdparams">name of avatar to kick</param> /// <param name="cmdparams">name of avatar to kick</param>
private void KickUserCommand(string module, string[] cmdparams) private void KickUserCommand(string module, string[] cmdparams)
{ {
if (cmdparams.Length < 4) bool force = false;
OptionSet options = new OptionSet().Add("f|force", delegate (string v) { force = v != null; });
List<string> mainParams = options.Parse(cmdparams);
if (mainParams.Count < 4)
return; return;
string alert = null; string alert = null;
if (cmdparams.Length > 4) if (mainParams.Count > 4)
alert = String.Format("\n{0}\n", String.Join(" ", cmdparams, 4, cmdparams.Length - 4)); alert = String.Format("\n{0}\n", String.Join(" ", cmdparams, 4, cmdparams.Length - 4));
IList agents = SceneManager.GetCurrentSceneAvatars(); IList agents = SceneManager.GetCurrentSceneAvatars();
@ -466,8 +480,8 @@ namespace OpenSim
{ {
RegionInfo regionInfo = presence.Scene.RegionInfo; RegionInfo regionInfo = presence.Scene.RegionInfo;
if (presence.Firstname.ToLower().Contains(cmdparams[2].ToLower()) && if (presence.Firstname.ToLower().Contains(mainParams[2].ToLower()) &&
presence.Lastname.ToLower().Contains(cmdparams[3].ToLower())) presence.Lastname.ToLower().Contains(mainParams[3].ToLower()))
{ {
MainConsole.Instance.Output( MainConsole.Instance.Output(
String.Format( String.Format(
@ -480,7 +494,7 @@ namespace OpenSim
else else
presence.ControllingClient.Kick("\nYou have been logged out by an administrator.\n"); presence.ControllingClient.Kick("\nYou have been logged out by an administrator.\n");
presence.Scene.IncomingCloseAgent(presence.UUID); presence.Scene.IncomingCloseAgent(presence.UUID, force);
} }
} }
@ -922,7 +936,8 @@ namespace OpenSim
} }
else else
{ {
MainConsole.Instance.Output("Usage: debug scene scripting|collisions|physics|teleport true|false"); MainConsole.Instance.Output(
"Usage: debug scene active|scripting|collisions|physics|teleport true|false");
} }
break; break;
@ -1002,33 +1017,6 @@ namespace OpenSim
HandleShowCircuits(); HandleShowCircuits();
break; break;
case "http-handlers":
System.Text.StringBuilder handlers = new System.Text.StringBuilder("Registered HTTP Handlers:\n");
handlers.AppendFormat("* XMLRPC:\n");
foreach (String s in HttpServer.GetXmlRpcHandlerKeys())
handlers.AppendFormat("\t{0}\n", s);
handlers.AppendFormat("* HTTP:\n");
List<String> poll = HttpServer.GetPollServiceHandlerKeys();
foreach (String s in HttpServer.GetHTTPHandlerKeys())
handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty));
handlers.AppendFormat("* Agent:\n");
foreach (String s in HttpServer.GetAgentHandlerKeys())
handlers.AppendFormat("\t{0}\n", s);
handlers.AppendFormat("* LLSD:\n");
foreach (String s in HttpServer.GetLLSDHandlerKeys())
handlers.AppendFormat("\t{0}\n", s);
handlers.AppendFormat("* StreamHandlers ({0}):\n", HttpServer.GetStreamHandlerKeys().Count);
foreach (String s in HttpServer.GetStreamHandlerKeys())
handlers.AppendFormat("\t{0}\n", s);
MainConsole.Instance.Output(handlers.ToString());
break;
case "modules": case "modules":
MainConsole.Instance.Output("The currently loaded shared modules are:"); MainConsole.Instance.Output("The currently loaded shared modules are:");
foreach (IRegionModule module in m_moduleLoader.GetLoadedSharedModules) foreach (IRegionModule module in m_moduleLoader.GetLoadedSharedModules)
@ -1123,7 +1111,7 @@ namespace OpenSim
aCircuit.Name, aCircuit.Name,
aCircuit.child ? "child" : "root", aCircuit.child ? "child" : "root",
aCircuit.circuitcode.ToString(), aCircuit.circuitcode.ToString(),
aCircuit.IPAddress.ToString(), aCircuit.IPAddress != null ? aCircuit.IPAddress.ToString() : "not set",
aCircuit.Viewer); aCircuit.Viewer);
}); });

View File

@ -232,8 +232,6 @@ namespace OpenSim
base.StartupSpecific(); base.StartupSpecific();
m_stats = StatsManager.SimExtraStats;
// Create a ModuleLoader instance // Create a ModuleLoader instance
m_moduleLoader = new ModuleLoader(m_config.Source); m_moduleLoader = new ModuleLoader(m_config.Source);
@ -249,13 +247,14 @@ namespace OpenSim
plugin.PostInitialise(); plugin.PostInitialise();
} }
AddPluginCommands(); if (m_console != null)
{
StatsManager.RegisterConsoleCommands(m_console);
AddPluginCommands(m_console);
}
} }
protected virtual void AddPluginCommands() protected virtual void AddPluginCommands(CommandConsole console)
{
// If console exists add plugin commands.
if (m_console != null)
{ {
List<string> topics = GetHelpTopics(); List<string> topics = GetHelpTopics();
@ -265,11 +264,11 @@ namespace OpenSim
// This is a hack to allow the user to enter the help command in upper or lowercase. This will go // This is a hack to allow the user to enter the help command in upper or lowercase. This will go
// away at some point. // away at some point.
m_console.Commands.AddCommand(capitalizedTopic, false, "help " + topic, console.Commands.AddCommand(capitalizedTopic, false, "help " + topic,
"help " + capitalizedTopic, "help " + capitalizedTopic,
"Get help on plugin command '" + topic + "'", "Get help on plugin command '" + topic + "'",
HandleCommanderHelp); HandleCommanderHelp);
m_console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic, console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic,
"help " + capitalizedTopic, "help " + capitalizedTopic,
"Get help on plugin command '" + topic + "'", "Get help on plugin command '" + topic + "'",
HandleCommanderHelp); HandleCommanderHelp);
@ -289,14 +288,13 @@ namespace OpenSim
foreach (string command in commander.Commands.Keys) foreach (string command in commander.Commands.Keys)
{ {
m_console.Commands.AddCommand(capitalizedTopic, false, console.Commands.AddCommand(capitalizedTopic, false,
topic + " " + command, topic + " " + command,
topic + " " + commander.Commands[command].ShortHelp(), topic + " " + commander.Commands[command].ShortHelp(),
String.Empty, HandleCommanderCommand); String.Empty, HandleCommanderCommand);
} }
} }
} }
}
private void HandleCommanderCommand(string module, string[] cmd) private void HandleCommanderCommand(string module, string[] cmd)
{ {
@ -623,7 +621,7 @@ namespace OpenSim
if (account == null) if (account == null)
{ {
m_log.ErrorFormat( m_log.ErrorFormat(
"[OPENSIM]: Unable to store account. If this simulator is connected to a grid, you must create the estate owner account first."); "[OPENSIM]: Unable to store account. If this simulator is connected to a grid, you must create the estate owner account first at the grid level.");
} }
else else
{ {

View File

@ -241,8 +241,8 @@ namespace OpenSim.Region.ClientStack.Linden
m_HostCapsObj.RegisterHandler( m_HostCapsObj.RegisterHandler(
"SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest, "SEED", null)); "SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest, "SEED", null));
m_log.DebugFormat( // m_log.DebugFormat(
"[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID); // "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID);
//m_capsHandlers["MapLayer"] = //m_capsHandlers["MapLayer"] =
// new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST", // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST",
@ -337,11 +337,12 @@ namespace OpenSim.Region.ClientStack.Linden
public string SeedCapRequest(string request, string path, string param, public string SeedCapRequest(string request, string path, string param,
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{ {
// m_log.Debug("[CAPS]: Seed Caps Request in region: " + m_regionName); m_log.DebugFormat(
"[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
{ {
m_log.DebugFormat( m_log.WarnFormat(
"[CAPS]: Unauthorized CAPS client {0} from {1}", "[CAPS]: Unauthorized CAPS client {0} from {1}",
m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint); m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint);

View File

@ -94,7 +94,7 @@ namespace OpenSim.Region.ClientStack.Linden
//scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack); //scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack);
scene.EventManager.OnNewClient += OnNewClient; // scene.EventManager.OnNewClient += OnNewClient;
// TODO: Leaving these open, or closing them when we // TODO: Leaving these open, or closing them when we
// become a child is incorrect. It messes up TP in a big // become a child is incorrect. It messes up TP in a big
@ -102,6 +102,7 @@ namespace OpenSim.Region.ClientStack.Linden
// circuit is there. // circuit is there.
scene.EventManager.OnClientClosed += ClientClosed; scene.EventManager.OnClientClosed += ClientClosed;
scene.EventManager.OnMakeChildAgent += MakeChildAgent; scene.EventManager.OnMakeChildAgent += MakeChildAgent;
scene.EventManager.OnRegisterCaps += OnRegisterCaps; scene.EventManager.OnRegisterCaps += OnRegisterCaps;
@ -110,10 +111,10 @@ namespace OpenSim.Region.ClientStack.Linden
false, false,
"debug eq", "debug eq",
"debug eq [0|1|2]", "debug eq [0|1|2]",
"Turn on event queue debugging" "Turn on event queue debugging\n"
+ "<= 0 - turns off all event queue logging" + " <= 0 - turns off all event queue logging\n"
+ ">= 1 - turns on outgoing event logging" + " >= 1 - turns on outgoing event logging\n"
+ ">= 2 - turns on poll notification", + " >= 2 - turns on poll notification",
HandleDebugEq); HandleDebugEq);
} }
else else
@ -226,16 +227,6 @@ namespace OpenSim.Region.ClientStack.Linden
#endregion #endregion
private void OnNewClient(IClientAPI client)
{
//client.OnLogout += ClientClosed;
}
// private void ClientClosed(IClientAPI client)
// {
// ClientClosed(client.AgentId);
// }
private void ClientClosed(UUID agentID, Scene scene) private void ClientClosed(UUID agentID, Scene scene)
{ {
// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); // m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);

View File

@ -94,7 +94,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
UUID spId = TestHelpers.ParseTail(0x1); UUID spId = TestHelpers.ParseTail(0x1);
SceneHelpers.AddScenePresence(m_scene, spId); SceneHelpers.AddScenePresence(m_scene, spId);
m_scene.IncomingCloseAgent(spId); m_scene.IncomingCloseAgent(spId, false);
// TODO: Add more assertions for the other aspects of event queues // TODO: Add more assertions for the other aspects of event queues
Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0)); Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0));

View File

@ -109,7 +109,7 @@ namespace OpenSim.Region.ClientStack.Linden
UUID capID = UUID.Random(); UUID capID = UUID.Random();
m_log.DebugFormat("[REGION CONSOLE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); // m_log.DebugFormat("[REGION CONSOLE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
caps.RegisterHandler( caps.RegisterHandler(
"SimConsoleAsync", "SimConsoleAsync",
new ConsoleHandler("/CAPS/" + capID + "/", "SimConsoleAsync", agentID, this, m_scene)); new ConsoleHandler("/CAPS/" + capID + "/", "SimConsoleAsync", agentID, this, m_scene));

View File

@ -45,7 +45,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public Packet Packet; public Packet Packet;
/// <summary> /// <summary>
/// Default constructor /// No arg constructor.
/// </summary>
public IncomingPacket() {}
/// <summary>
/// Constructor
/// </summary> /// </summary>
/// <param name="client">Reference to the client this packet came from</param> /// <param name="client">Reference to the client this packet came from</param>
/// <param name="packet">Packet data</param> /// <param name="packet">Packet data</param>

View File

@ -47,6 +47,7 @@ using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces; using OpenSim.Services.Interfaces;
using Timer = System.Timers.Timer; using Timer = System.Timers.Timer;
using AssetLandmark = OpenSim.Framework.AssetLandmark; using AssetLandmark = OpenSim.Framework.AssetLandmark;
using RegionFlags = OpenMetaverse.RegionFlags;
using Nini.Config; using Nini.Config;
using System.IO; using System.IO;
@ -355,7 +356,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private bool m_deliverPackets = true; private bool m_deliverPackets = true;
private int m_animationSequenceNumber = 1; private int m_animationSequenceNumber = 1;
private bool m_SendLogoutPacketWhenClosing = true; private bool m_SendLogoutPacketWhenClosing = true;
private AgentUpdateArgs lastarg;
/// <summary>
/// We retain a single AgentUpdateArgs so that we can constantly reuse it rather than construct a new one for
/// every single incoming AgentUpdate. Every client sends 10 AgentUpdate UDP messages per second, even if it
/// is doing absolutely nothing.
/// </summary>
/// <remarks>
/// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
/// cannot retain a reference to it outside of that method.
/// </remarks>
private AgentUpdateArgs m_lastAgentUpdateArgs;
protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@ -510,19 +521,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// </summary> /// </summary>
public void Close() public void Close()
{ {
Close(true); Close(true, false);
} }
/// <summary> public void Close(bool sendStop, bool force)
/// Shut down the client view
/// </summary>
public void Close(bool sendStop)
{ {
// We lock here to prevent race conditions between two threads calling close simultaneously (e.g. // We lock here to prevent race conditions between two threads calling close simultaneously (e.g.
// a simultaneous relog just as a client is being closed out due to no packet ack from the old connection. // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
lock (CloseSyncLock) lock (CloseSyncLock)
{ {
if (!IsActive) // We still perform a force close inside the sync lock since this is intended to attempt close where
// there is some unidentified connection problem, not where we have issues due to deadlock
if (!IsActive && !force)
return; return;
IsActive = false; IsActive = false;
@ -837,8 +847,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
OutPacket(mov, ThrottleOutPacketType.Unknown); OutPacket(mov, ThrottleOutPacketType.Unknown);
} }
public void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName, public void SendChatMessage(
UUID fromAgentID, byte source, byte audible) string message, byte type, Vector3 fromPos, string fromName,
UUID fromAgentID, UUID ownerID, byte source, byte audible)
{ {
ChatFromSimulatorPacket reply = (ChatFromSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.ChatFromSimulator); ChatFromSimulatorPacket reply = (ChatFromSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.ChatFromSimulator);
reply.ChatData.Audible = audible; reply.ChatData.Audible = audible;
@ -847,7 +858,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
reply.ChatData.SourceType = source; reply.ChatData.SourceType = source;
reply.ChatData.Position = fromPos; reply.ChatData.Position = fromPos;
reply.ChatData.FromName = Util.StringToBytes256(fromName); reply.ChatData.FromName = Util.StringToBytes256(fromName);
reply.ChatData.OwnerID = fromAgentID; reply.ChatData.OwnerID = ownerID;
reply.ChatData.SourceID = fromAgentID; reply.ChatData.SourceID = fromAgentID;
OutPacket(reply, ThrottleOutPacketType.Unknown); OutPacket(reply, ThrottleOutPacketType.Unknown);
@ -3985,7 +3996,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); ImprovedTerseObjectUpdatePacket packet
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation; packet.RegionData.TimeDilation = timeDilation;
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@ -4030,7 +4042,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); ImprovedTerseObjectUpdatePacket packet
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
PacketType.ImprovedTerseObjectUpdate);
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation; packet.RegionData.TimeDilation = timeDilation;
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@ -4038,7 +4052,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
for (int i = 0; i < blocks.Count; i++) for (int i = 0; i < blocks.Count; i++)
packet.ObjectData[i] = blocks[i]; packet.ObjectData[i] = blocks[i];
OutPacket(packet, ThrottleOutPacketType.Task, true); OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
} }
#endregion Packet Sending #endregion Packet Sending
@ -5039,7 +5053,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2; Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2;
Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2; Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2;
ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock(); ImprovedTerseObjectUpdatePacket.ObjectDataBlock block
= PacketPool.Instance.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
block.Data = data; block.Data = data;
if (textureEntry != null && textureEntry.Length > 0) if (textureEntry != null && textureEntry.Length > 0)
@ -5289,14 +5305,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
protected virtual void RegisterLocalPacketHandlers() protected virtual void RegisterLocalPacketHandlers()
{ {
AddLocalPacketHandler(PacketType.LogoutRequest, HandleLogout); AddLocalPacketHandler(PacketType.LogoutRequest, HandleLogout);
// If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
// for each AgentUpdate packet.
AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false); AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false); AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false); AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false); AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false); AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false);
AddLocalPacketHandler(PacketType.ParcelBuy, HandleParcelBuyRequest, false); AddLocalPacketHandler(PacketType.ParcelBuy, HandleParcelBuyRequest, false);
AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest, false); AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest);
AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest, false); AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest);
AddLocalPacketHandler(PacketType.GenericMessage, HandleGenericMessage); AddLocalPacketHandler(PacketType.GenericMessage, HandleGenericMessage);
AddLocalPacketHandler(PacketType.AvatarPropertiesRequest, HandleAvatarPropertiesRequest); AddLocalPacketHandler(PacketType.AvatarPropertiesRequest, HandleAvatarPropertiesRequest);
AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer); AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer);
@ -5518,81 +5538,84 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region Scene/Avatar #region Scene/Avatar
private bool HandleAgentUpdate(IClientAPI sener, Packet Pack) private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
{ {
if (OnAgentUpdate != null) if (OnAgentUpdate != null)
{ {
bool update = false; AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
AgentUpdatePacket agenUpdate = (AgentUpdatePacket)Pack;
#region Packet Session and User Check #region Packet Session and User Check
if (agenUpdate.AgentData.SessionID != SessionId || agenUpdate.AgentData.AgentID != AgentId) if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId)
{
PacketPool.Instance.ReturnPacket(packet);
return false; return false;
}
#endregion #endregion
AgentUpdatePacket.AgentDataBlock x = agenUpdate.AgentData; bool update = false;
AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
// We can only check when we have something to check if (m_lastAgentUpdateArgs != null)
// against.
if (lastarg != null)
{ {
// These should be ordered from most-likely to
// least likely to change. I've made an initial
// guess at that.
update = update =
( (
(x.BodyRotation != lastarg.BodyRotation) || (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) ||
(x.CameraAtAxis != lastarg.CameraAtAxis) || (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) ||
(x.CameraCenter != lastarg.CameraCenter) || (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) ||
(x.CameraLeftAxis != lastarg.CameraLeftAxis) || (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
(x.CameraUpAxis != lastarg.CameraUpAxis) || (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
(x.ControlFlags != lastarg.ControlFlags) || (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
(x.ControlFlags != 0) || (x.ControlFlags != 0) ||
(x.Far != lastarg.Far) || (x.Far != m_lastAgentUpdateArgs.Far) ||
(x.Flags != lastarg.Flags) || (x.Flags != m_lastAgentUpdateArgs.Flags) ||
(x.State != lastarg.State) || (x.State != m_lastAgentUpdateArgs.State) ||
(x.HeadRotation != lastarg.HeadRotation) || (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) ||
(x.SessionID != lastarg.SessionID) || (x.SessionID != m_lastAgentUpdateArgs.SessionID) ||
(x.AgentID != lastarg.AgentID) (x.AgentID != m_lastAgentUpdateArgs.AgentID)
); );
} }
else else
{ {
m_lastAgentUpdateArgs = new AgentUpdateArgs();
update = true; update = true;
} }
// These should be ordered from most-likely to
// least likely to change. I've made an initial
// guess at that.
if (update) if (update)
{ {
// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); // m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name);
AgentUpdateArgs arg = new AgentUpdateArgs(); m_lastAgentUpdateArgs.AgentID = x.AgentID;
arg.AgentID = x.AgentID; m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation;
arg.BodyRotation = x.BodyRotation; m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
arg.CameraAtAxis = x.CameraAtAxis; m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter;
arg.CameraCenter = x.CameraCenter; m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
arg.CameraLeftAxis = x.CameraLeftAxis; m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
arg.CameraUpAxis = x.CameraUpAxis; m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags;
arg.ControlFlags = x.ControlFlags; m_lastAgentUpdateArgs.Far = x.Far;
arg.Far = x.Far; m_lastAgentUpdateArgs.Flags = x.Flags;
arg.Flags = x.Flags; m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation;
arg.HeadRotation = x.HeadRotation; m_lastAgentUpdateArgs.SessionID = x.SessionID;
arg.SessionID = x.SessionID; m_lastAgentUpdateArgs.State = x.State;
arg.State = x.State;
UpdateAgent handlerAgentUpdate = OnAgentUpdate; UpdateAgent handlerAgentUpdate = OnAgentUpdate;
UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
lastarg = arg; // save this set of arguments for nexttime
if (handlerPreAgentUpdate != null) if (handlerPreAgentUpdate != null)
OnPreAgentUpdate(this, arg); OnPreAgentUpdate(this, m_lastAgentUpdateArgs);
if (handlerAgentUpdate != null) if (handlerAgentUpdate != null)
OnAgentUpdate(this, arg); OnAgentUpdate(this, m_lastAgentUpdateArgs);
handlerAgentUpdate = null; handlerAgentUpdate = null;
handlerPreAgentUpdate = null; handlerPreAgentUpdate = null;
} }
} }
PacketPool.Instance.ReturnPacket(packet);
return true; return true;
} }
@ -5964,7 +5987,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
msgpack.MessageBlock.ID, msgpack.MessageBlock.ID,
msgpack.MessageBlock.Offline != 0 ? true : false, msgpack.MessageBlock.Offline != 0 ? true : false,
msgpack.MessageBlock.Position, msgpack.MessageBlock.Position,
msgpack.MessageBlock.BinaryBucket); msgpack.MessageBlock.BinaryBucket,
true);
handlerInstantMessage(this, im); handlerInstantMessage(this, im);
} }
@ -9251,7 +9275,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
} }
#endregion #endregion
switch (Utils.BytesToString(messagePacket.MethodData.Method)) string method = Utils.BytesToString(messagePacket.MethodData.Method);
switch (method)
{ {
case "getinfo": case "getinfo":
if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
@ -9567,7 +9593,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return true; return true;
default: default:
m_log.Error("EstateOwnerMessage: Unknown method requested\n" + messagePacket); m_log.WarnFormat(
"[LLCLIENTVIEW]: EstateOwnerMessage: Unknown method {0} requested for {1} in {2}",
method, Name, Scene.Name);
for (int i = 0; i < messagePacket.ParamList.Length; i++)
{
EstateOwnerMessagePacket.ParamListBlock block = messagePacket.ParamList[i];
string data = (string)Utils.BytesToString(block.Parameter);
m_log.DebugFormat("[LLCLIENTVIEW]: Param {0}={1}", i, data);
}
return true; return true;
} }
@ -11960,7 +11996,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
logPacket = false; logPacket = false;
if (DebugPacketLevel <= 50 if (DebugPacketLevel <= 50
& (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate)) && (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
logPacket = false; logPacket = false;
if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily) if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily)
@ -12034,8 +12070,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (!ProcessPacketMethod(packet)) if (!ProcessPacketMethod(packet))
m_log.Warn("[CLIENT]: unhandled packet " + packet.Type); m_log.Warn("[CLIENT]: unhandled packet " + packet.Type);
PacketPool.Instance.ReturnPacket(packet);
} }
private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket) private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
@ -12204,7 +12238,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
Kick(reason); Kick(reason);
Thread.Sleep(1000); Thread.Sleep(1000);
Close(); Disconnect();
} }
public void Disconnect() public void Disconnect()
@ -12492,7 +12526,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); ImprovedTerseObjectUpdatePacket packet
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
PacketType.ImprovedTerseObjectUpdate);
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation; packet.RegionData.TimeDilation = timeDilation;
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];

View File

@ -37,6 +37,7 @@ using log4net;
using Nini.Config; using Nini.Config;
using OpenMetaverse.Packets; using OpenMetaverse.Packets;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Framework.Monitoring; using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using OpenMetaverse; using OpenMetaverse;
@ -100,9 +101,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>The measured resolution of Environment.TickCount</summary> /// <summary>The measured resolution of Environment.TickCount</summary>
public readonly float TickCountResolution; public readonly float TickCountResolution;
/// <summary>Number of prim updates to put on the queue each time the /// <summary>Number of prim updates to put on the queue each time the
/// OnQueueEmpty event is triggered for updates</summary> /// OnQueueEmpty event is triggered for updates</summary>
public readonly int PrimUpdatesPerCallback; public readonly int PrimUpdatesPerCallback;
/// <summary>Number of texture packets to put on the queue each time the /// <summary>Number of texture packets to put on the queue each time the
/// OnQueueEmpty event is triggered for textures</summary> /// OnQueueEmpty event is triggered for textures</summary>
public readonly int TextureSendLimit; public readonly int TextureSendLimit;
@ -124,28 +127,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>Manages authentication for agent circuits</summary> /// <summary>Manages authentication for agent circuits</summary>
private AgentCircuitManager m_circuitManager; private AgentCircuitManager m_circuitManager;
/// <summary>Reference to the scene this UDP server is attached to</summary> /// <summary>Reference to the scene this UDP server is attached to</summary>
protected Scene m_scene; protected Scene m_scene;
/// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
private Location m_location; private Location m_location;
/// <summary>The size of the receive buffer for the UDP socket. This value /// <summary>The size of the receive buffer for the UDP socket. This value
/// is passed up to the operating system and used in the system networking /// is passed up to the operating system and used in the system networking
/// stack. Use zero to leave this value as the default</summary> /// stack. Use zero to leave this value as the default</summary>
private int m_recvBufferSize; private int m_recvBufferSize;
/// <summary>Flag to process packets asynchronously or synchronously</summary> /// <summary>Flag to process packets asynchronously or synchronously</summary>
private bool m_asyncPacketHandling; private bool m_asyncPacketHandling;
/// <summary>Tracks whether or not a packet was sent each round so we know /// <summary>Tracks whether or not a packet was sent each round so we know
/// whether or not to sleep</summary> /// whether or not to sleep</summary>
private bool m_packetSent; private bool m_packetSent;
/// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary> /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary>
private int m_elapsedMSSinceLastStatReport = 0; private int m_elapsedMSSinceLastStatReport = 0;
/// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary> /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary>
private int m_tickLastOutgoingPacketHandler; private int m_tickLastOutgoingPacketHandler;
/// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary> /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary>
private int m_elapsedMSOutgoingPacketHandler; private int m_elapsedMSOutgoingPacketHandler;
/// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary> /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary>
private int m_elapsed100MSOutgoingPacketHandler; private int m_elapsed100MSOutgoingPacketHandler;
/// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary> /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary>
private int m_elapsed500MSOutgoingPacketHandler; private int m_elapsed500MSOutgoingPacketHandler;
@ -159,6 +171,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
protected bool m_sendPing; protected bool m_sendPing;
private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
private Pool<IncomingPacket> m_incomingPacketPool;
private Stat m_incomingPacketPoolStat;
private int m_defaultRTO = 0; private int m_defaultRTO = 0;
private int m_maxRTO = 0; private int m_maxRTO = 0;
@ -180,7 +195,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// </summary> /// </summary>
private IClientAPI m_currentIncomingClient; private IClientAPI m_currentIncomingClient;
public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) public LLUDPServer(
IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port,
IConfigSource configSource, AgentCircuitManager circuitManager)
: base(listenIP, (int)port) : base(listenIP, (int)port)
{ {
#region Environment.TickCount Measurement #region Environment.TickCount Measurement
@ -202,6 +219,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_circuitManager = circuitManager; m_circuitManager = circuitManager;
int sceneThrottleBps = 0; int sceneThrottleBps = 0;
bool usePools = false;
IConfig config = configSource.Configs["ClientStack.LindenUDP"]; IConfig config = configSource.Configs["ClientStack.LindenUDP"];
if (config != null) if (config != null)
@ -227,6 +245,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_pausedAckTimeout = 1000 * 300; // 5 minutes m_pausedAckTimeout = 1000 * 300; // 5 minutes
} }
// FIXME: This actually only needs to be done once since the PacketPool is shared across all servers.
// However, there is no harm in temporarily doing it multiple times.
IConfig packetConfig = configSource.Configs["PacketPool"];
if (packetConfig != null)
{
PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
usePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", usePools);
}
#region BinaryStats #region BinaryStats
config = configSource.Configs["Statistics.Binary"]; config = configSource.Configs["Statistics.Binary"];
m_shouldCollectStats = false; m_shouldCollectStats = false;
@ -254,20 +282,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_throttle = new TokenBucket(null, sceneThrottleBps); m_throttle = new TokenBucket(null, sceneThrottleBps);
ThrottleRates = new ThrottleRates(configSource); ThrottleRates = new ThrottleRates(configSource);
if (usePools)
EnablePools();
} }
public void Start() public void Start()
{ {
if (m_scene == null) StartInbound();
throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); StartOutbound();
m_elapsedMSSinceLastStatReport = Environment.TickCount;
}
private void StartInbound()
{
m_log.InfoFormat( m_log.InfoFormat(
"[LLUDPSERVER]: Starting the LLUDP server in {0} mode", "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
m_asyncPacketHandling ? "asynchronous" : "synchronous"); m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools);
base.Start(m_recvBufferSize, m_asyncPacketHandling); base.StartInbound(m_recvBufferSize, m_asyncPacketHandling);
// Start the packet processing threads // This thread will process the packets received that are placed on the packetInbox
Watchdog.StartThread( Watchdog.StartThread(
IncomingPacketHandler, IncomingPacketHandler,
string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName), string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName),
@ -276,6 +312,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
true, true,
GetWatchdogIncomingAlarmData, GetWatchdogIncomingAlarmData,
Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
}
private new void StartOutbound()
{
m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server");
base.StartOutbound();
Watchdog.StartThread( Watchdog.StartThread(
OutgoingPacketHandler, OutgoingPacketHandler,
@ -285,8 +328,57 @@ namespace OpenSim.Region.ClientStack.LindenUDP
true, true,
GetWatchdogOutgoingAlarmData, GetWatchdogOutgoingAlarmData,
Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
}
m_elapsedMSSinceLastStatReport = Environment.TickCount; public void Stop()
{
m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
base.StopOutbound();
base.StopInbound();
}
protected override bool EnablePools()
{
if (!UsePools)
{
base.EnablePools();
m_incomingPacketPool = new Pool<IncomingPacket>(() => new IncomingPacket(), 500);
m_incomingPacketPoolStat
= new Stat(
"IncomingPacketPoolCount",
"Objects within incoming packet pool",
"The number of objects currently stored within the incoming packet pool",
"",
"clientstack",
"packetpool",
StatType.Pull,
stat => stat.Value = m_incomingPacketPool.Count,
StatVerbosity.Debug);
StatsManager.RegisterStat(m_incomingPacketPoolStat);
return true;
}
return false;
}
protected override bool DisablePools()
{
if (UsePools)
{
base.DisablePools();
StatsManager.DeregisterStat(m_incomingPacketPoolStat);
// We won't null out the pool to avoid a race condition with code that may be in the middle of using it.
return true;
}
return false;
} }
/// <summary> /// <summary>
@ -311,12 +403,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none"); m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none");
} }
public new void Stop()
{
m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
base.Stop();
}
public void AddScene(IScene scene) public void AddScene(IScene scene)
{ {
if (m_scene != null) if (m_scene != null)
@ -333,6 +419,117 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_scene = (Scene)scene; m_scene = (Scene)scene;
m_location = new Location(m_scene.RegionInfo.RegionHandle); m_location = new Location(m_scene.RegionInfo.RegionHandle);
MainConsole.Instance.Commands.AddCommand(
"Debug",
false,
"debug lludp start",
"debug lludp start <in|out|all>",
"Control LLUDP packet processing.",
"No effect if packet processing has already started.\n"
+ "in - start inbound processing.\n"
+ "out - start outbound processing.\n"
+ "all - start in and outbound processing.\n",
HandleStartCommand);
MainConsole.Instance.Commands.AddCommand(
"Debug",
false,
"debug lludp stop",
"debug lludp stop <in|out|all>",
"Stop LLUDP packet processing.",
"No effect if packet processing has already stopped.\n"
+ "in - stop inbound processing.\n"
+ "out - stop outbound processing.\n"
+ "all - stop in and outbound processing.\n",
HandleStopCommand);
MainConsole.Instance.Commands.AddCommand(
"Debug",
false,
"debug lludp pool",
"debug lludp pool <on|off>",
"Turn object pooling within the lludp component on or off.",
HandlePoolCommand);
MainConsole.Instance.Commands.AddCommand(
"Debug",
false,
"debug lludp status",
"debug lludp status",
"Return status of LLUDP packet processing.",
HandleStatusCommand);
}
private void HandleStartCommand(string module, string[] args)
{
if (args.Length != 4)
{
MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
return;
}
string subCommand = args[3];
if (subCommand == "in" || subCommand == "all")
StartInbound();
if (subCommand == "out" || subCommand == "all")
StartOutbound();
}
private void HandleStopCommand(string module, string[] args)
{
if (args.Length != 4)
{
MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
return;
}
string subCommand = args[3];
if (subCommand == "in" || subCommand == "all")
StopInbound();
if (subCommand == "out" || subCommand == "all")
StopOutbound();
}
private void HandlePoolCommand(string module, string[] args)
{
if (args.Length != 4)
{
MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
return;
}
string enabled = args[3];
if (enabled == "on")
{
if (EnablePools())
MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", m_scene.Name);
}
else if (enabled == "off")
{
if (DisablePools())
MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", m_scene.Name);
}
else
{
MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
}
}
private void HandleStatusCommand(string module, string[] args)
{
MainConsole.Instance.OutputFormat(
"IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled");
MainConsole.Instance.OutputFormat(
"OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off");
} }
public bool HandlesRegion(Location x) public bool HandlesRegion(Location x)
@ -416,6 +613,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
byte[] data = packet.ToBytes(); byte[] data = packet.ToBytes();
SendPacketData(udpClient, data, packet.Type, category, method); SendPacketData(udpClient, data, packet.Type, category, method);
} }
PacketPool.Instance.ReturnPacket(packet);
} }
/// <summary> /// <summary>
@ -700,7 +899,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
LLUDPClient udpClient = null; LLUDPClient udpClient = null;
Packet packet = null; Packet packet = null;
int packetEnd = buffer.DataLength - 1; int packetEnd = buffer.DataLength - 1;
IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; IPEndPoint endPoint = (IPEndPoint)buffer.RemoteEndPoint;
#region Decoding #region Decoding
@ -710,7 +909,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", // "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
return; // Drop undersizd packet return; // Drop undersized packet
} }
int headerLen = 7; int headerLen = 7;
@ -733,7 +932,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
try try
{ {
packet = Packet.BuildPacket(buffer.Data, ref packetEnd, // packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
// // Only allocate a buffer for zerodecoding if the packet is zerocoded
// ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
// If OpenSimUDPBase.UsePool == true (which is currently separate from the PacketPool) then we
// assume that packet construction does not retain a reference to byte[] buffer.Data (instead, all
// bytes are copied out).
packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd,
// Only allocate a buffer for zerodecoding if the packet is zerocoded // Only allocate a buffer for zerodecoding if the packet is zerocoded
((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
} }
@ -748,11 +953,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return; // Drop short packet return; // Drop short packet
} }
catch(Exception e) catch (Exception e)
{ {
if (m_malformedCount < 100) if (m_malformedCount < 100)
m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
m_malformedCount++; m_malformedCount++;
if ((m_malformedCount % 100000) == 0) if ((m_malformedCount % 100000) == 0)
m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount); m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
} }
@ -772,7 +979,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// If there is already a client for this endpoint, don't process UseCircuitCode // If there is already a client for this endpoint, don't process UseCircuitCode
IClientAPI client = null; IClientAPI client = null;
if (!m_scene.TryGetClient(address, out client)) if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
{ {
// UseCircuitCode handling // UseCircuitCode handling
if (packet.Type == PacketType.UseCircuitCode) if (packet.Type == PacketType.UseCircuitCode)
@ -780,13 +987,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// And if there is a UseCircuitCode pending, also drop it // And if there is a UseCircuitCode pending, also drop it
lock (m_pendingCache) lock (m_pendingCache)
{ {
if (m_pendingCache.Contains(address)) if (m_pendingCache.Contains(endPoint))
return; return;
m_pendingCache.AddOrUpdate(address, new Queue<UDPPacketBuffer>(), 60); m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
} }
object[] array = new object[] { buffer, packet }; // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
// buffer.
object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
Util.FireAndForget(HandleUseCircuitCode, array); Util.FireAndForget(HandleUseCircuitCode, array);
@ -798,7 +1007,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
lock (m_pendingCache) lock (m_pendingCache)
{ {
Queue<UDPPacketBuffer> queue; Queue<UDPPacketBuffer> queue;
if (m_pendingCache.TryGetValue(address, out queue)) if (m_pendingCache.TryGetValue(endPoint, out queue))
{ {
//m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type); //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
queue.Enqueue(buffer); queue.Enqueue(buffer);
@ -834,6 +1043,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Handle appended ACKs // Handle appended ACKs
if (packet.Header.AppendedAcks && packet.Header.AckList != null) if (packet.Header.AppendedAcks && packet.Header.AckList != null)
{ {
// m_log.DebugFormat(
// "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}",
// packet.Header.AckList.Length, client.Name, m_scene.Name);
for (int i = 0; i < packet.Header.AckList.Length; i++) for (int i = 0; i < packet.Header.AckList.Length; i++)
udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent); udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
} }
@ -843,6 +1056,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
PacketAckPacket ackPacket = (PacketAckPacket)packet; PacketAckPacket ackPacket = (PacketAckPacket)packet;
// m_log.DebugFormat(
// "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}",
// ackPacket.Packets.Length, client.Name, m_scene.Name);
for (int i = 0; i < ackPacket.Packets.Length; i++) for (int i = 0; i < ackPacket.Packets.Length; i++)
udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent); udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
@ -856,6 +1073,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (packet.Header.Reliable) if (packet.Header.Reliable)
{ {
// m_log.DebugFormat(
// "[LLUDPSERVER]: Adding ack request for {0} {1} from {2} in {3}",
// packet.Type, packet.Header.Sequence, client.Name, m_scene.Name);
udpClient.PendingAcks.Enqueue(packet.Header.Sequence); udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
// This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
@ -902,6 +1123,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (packet.Type == PacketType.StartPingCheck) if (packet.Type == PacketType.StartPingCheck)
{ {
// m_log.DebugFormat("[LLUDPSERVER]: Handling ping from {0} in {1}", client.Name, m_scene.Name);
// We don't need to do anything else with ping checks // We don't need to do anything else with ping checks
StartPingCheckPacket startPing = (StartPingCheckPacket)packet; StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
CompletePing(udpClient, startPing.PingID.PingID); CompletePing(udpClient, startPing.PingID.PingID);
@ -921,13 +1144,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#endregion Ping Check Handling #endregion Ping Check Handling
IncomingPacket incomingPacket;
// Inbox insertion // Inbox insertion
if (packet.Type == PacketType.AgentUpdate || if (UsePools)
packet.Type == PacketType.ChatFromViewer) {
packetInbox.EnqueueHigh(new IncomingPacket((LLClientView)client, packet)); incomingPacket = m_incomingPacketPool.GetObject();
incomingPacket.Client = (LLClientView)client;
incomingPacket.Packet = packet;
}
else else
packetInbox.EnqueueLow(new IncomingPacket((LLClientView)client, packet)); {
// packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet)); incomingPacket = new IncomingPacket((LLClientView)client, packet);
}
if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
incomingPacket.Packet.Type == PacketType.ChatFromViewer)
packetInbox.EnqueueHigh(incomingPacket);
else
packetInbox.EnqueueLow(incomingPacket);
} }
#region BinaryStats #region BinaryStats
@ -1013,21 +1248,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private void HandleUseCircuitCode(object o) private void HandleUseCircuitCode(object o)
{ {
IPEndPoint remoteEndPoint = null; IPEndPoint endPoint = null;
IClientAPI client = null; IClientAPI client = null;
try try
{ {
// DateTime startTime = DateTime.Now; // DateTime startTime = DateTime.Now;
object[] array = (object[])o; object[] array = (object[])o;
UDPPacketBuffer buffer = (UDPPacketBuffer)array[0]; endPoint = (IPEndPoint)array[0];
UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
m_log.DebugFormat( m_log.DebugFormat(
"[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, buffer.RemoteEndPoint); uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, endPoint);
remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;
AuthenticateResponse sessionInfo; AuthenticateResponse sessionInfo;
if (IsClientAuthorized(uccp, out sessionInfo)) if (IsClientAuthorized(uccp, out sessionInfo))
@ -1038,13 +1271,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
uccp.CircuitCode.Code, uccp.CircuitCode.Code,
uccp.CircuitCode.ID, uccp.CircuitCode.ID,
uccp.CircuitCode.SessionID, uccp.CircuitCode.SessionID,
remoteEndPoint, endPoint,
sessionInfo); sessionInfo);
// Send ack straight away to let the viewer know that the connection is active. // Send ack straight away to let the viewer know that the connection is active.
// The client will be null if it already exists (e.g. if on a region crossing the client sends a use // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
// circuit code to the existing child agent. This is not particularly obvious. // circuit code to the existing child agent. This is not particularly obvious.
SendAckImmediate(remoteEndPoint, uccp.Header.Sequence); SendAckImmediate(endPoint, uccp.Header.Sequence);
// We only want to send initial data to new clients, not ones which are being converted from child to root. // We only want to send initial data to new clients, not ones which are being converted from child to root.
if (client != null) if (client != null)
@ -1058,12 +1291,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
lock (m_pendingCache) lock (m_pendingCache)
{ {
if (!m_pendingCache.TryGetValue(remoteEndPoint, out queue)) if (!m_pendingCache.TryGetValue(endPoint, out queue))
{ {
m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
return; return;
} }
m_pendingCache.Remove(remoteEndPoint); m_pendingCache.Remove(endPoint);
} }
m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
@ -1081,9 +1314,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Don't create clients for unauthorized requesters. // Don't create clients for unauthorized requesters.
m_log.WarnFormat( m_log.WarnFormat(
"[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint); uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
lock (m_pendingCache) lock (m_pendingCache)
m_pendingCache.Remove(remoteEndPoint); m_pendingCache.Remove(endPoint);
} }
// m_log.DebugFormat( // m_log.DebugFormat(
@ -1095,7 +1328,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
m_log.ErrorFormat( m_log.ErrorFormat(
"[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
remoteEndPoint != null ? remoteEndPoint.ToString() : "n/a", endPoint != null ? endPoint.ToString() : "n/a",
client != null ? client.Name : "unknown", client != null ? client.Name : "unknown",
client != null ? client.AgentId.ToString() : "unknown", client != null ? client.AgentId.ToString() : "unknown",
e.Message, e.Message,
@ -1160,9 +1393,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
IClientAPI client = null; IClientAPI client = null;
// In priciple there shouldn't be more than one thread here, ever. // We currently synchronize this code across the whole scene to avoid issues such as
// But in case that happens, we need to synchronize this piece of code // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
// because it's too important // consistently, this lock could probably be removed.
lock (this) lock (this)
{ {
if (!m_scene.TryGetClient(agentID, out client)) if (!m_scene.TryGetClient(agentID, out client))
@ -1212,7 +1445,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// on to en-US to avoid number parsing issues // on to en-US to avoid number parsing issues
Culture.SetCurrentCulture(); Culture.SetCurrentCulture();
while (base.IsRunning) while (IsRunningInbound)
{ {
m_scene.ThreadAlive(1); m_scene.ThreadAlive(1);
try try
@ -1228,7 +1461,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
} }
if (packetInbox.Dequeue(100, ref incomingPacket)) if (packetInbox.Dequeue(100, ref incomingPacket))
{
ProcessInPacket(incomingPacket);//, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket); ProcessInPacket(incomingPacket);//, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket);
if (UsePools)
m_incomingPacketPool.ReturnObject(incomingPacket);
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -1255,7 +1493,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Action generic every round // Action generic every round
Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler; Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
while (base.IsRunning) while (base.IsRunningOutbound)
{ {
m_scene.ThreadAlive(2); m_scene.ThreadAlive(2);
try try
@ -1523,7 +1761,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (!client.IsLoggingOut) if (!client.IsLoggingOut)
{ {
client.IsLoggingOut = true; client.IsLoggingOut = true;
client.Close(false); client.Close(false, false);
} }
} }
} }

View File

@ -30,6 +30,8 @@ using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading; using System.Threading;
using log4net; using log4net;
using OpenSim.Framework;
using OpenSim.Framework.Monitoring;
namespace OpenMetaverse namespace OpenMetaverse
{ {
@ -58,17 +60,31 @@ namespace OpenMetaverse
/// <summary>Flag to process packets asynchronously or synchronously</summary> /// <summary>Flag to process packets asynchronously or synchronously</summary>
private bool m_asyncPacketHandling; private bool m_asyncPacketHandling;
/// <summary>The all important shutdown flag</summary> /// <summary>
private volatile bool m_shutdownFlag = true; /// Pool to use for handling data. May be null if UsePools = false;
/// </summary>
protected OpenSim.Framework.Pool<UDPPacketBuffer> m_pool;
/// <summary>Returns true if the server is currently listening, otherwise false</summary> /// <summary>
public bool IsRunning { get { return !m_shutdownFlag; } } /// Are we to use object pool(s) to reduce memory churn when receiving data?
/// </summary>
public bool UsePools { get; protected set; }
/// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary>
public bool IsRunningInbound { get; private set; }
/// <summary>Returns true if the server is currently sending outbound packets, otherwise false</summary>
/// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
public bool IsRunningOutbound { get; private set; }
private Stat m_poolCountStat;
/// <summary> /// <summary>
/// Default constructor /// Default constructor
/// </summary> /// </summary>
/// <param name="bindAddress">Local IP address to bind the server to</param> /// <param name="bindAddress">Local IP address to bind the server to</param>
/// <param name="port">Port to listening for incoming UDP packets on</param> /// <param name="port">Port to listening for incoming UDP packets on</param>
/// /// <param name="usePool">Are we to use an object pool to get objects for handing inbound data?</param>
public OpenSimUDPBase(IPAddress bindAddress, int port) public OpenSimUDPBase(IPAddress bindAddress, int port)
{ {
m_localBindAddress = bindAddress; m_localBindAddress = bindAddress;
@ -76,7 +92,7 @@ namespace OpenMetaverse
} }
/// <summary> /// <summary>
/// Start the UDP server /// Start inbound UDP packet handling.
/// </summary> /// </summary>
/// <param name="recvBufferSize">The size of the receive buffer for /// <param name="recvBufferSize">The size of the receive buffer for
/// the UDP socket. This value is passed up to the operating system /// the UDP socket. This value is passed up to the operating system
@ -91,11 +107,11 @@ namespace OpenMetaverse
/// manner (not throwing an exception when the remote side resets the /// manner (not throwing an exception when the remote side resets the
/// connection). This call is ignored on Mono where the flag is not /// connection). This call is ignored on Mono where the flag is not
/// necessary</remarks> /// necessary</remarks>
public void Start(int recvBufferSize, bool asyncPacketHandling) public void StartInbound(int recvBufferSize, bool asyncPacketHandling)
{ {
m_asyncPacketHandling = asyncPacketHandling; m_asyncPacketHandling = asyncPacketHandling;
if (m_shutdownFlag) if (!IsRunningInbound)
{ {
const int SIO_UDP_CONNRESET = -1744830452; const int SIO_UDP_CONNRESET = -1744830452;
@ -123,8 +139,7 @@ namespace OpenMetaverse
m_udpSocket.Bind(ipep); m_udpSocket.Bind(ipep);
// we're not shutting down, we're starting up IsRunningInbound = true;
m_shutdownFlag = false;
// kick off an async receive. The Start() method will return, the // kick off an async receive. The Start() method will return, the
// actual receives will occur asynchronously and will be caught in // actual receives will occur asynchronously and will be caught in
@ -134,28 +149,84 @@ namespace OpenMetaverse
} }
/// <summary> /// <summary>
/// Stops the UDP server /// Start outbound UDP packet handling.
/// </summary> /// </summary>
public void Stop() public void StartOutbound()
{ {
if (!m_shutdownFlag) IsRunningOutbound = true;
}
public void StopInbound()
{
if (IsRunningInbound)
{ {
// wait indefinitely for a writer lock. Once this is called, the .NET runtime // wait indefinitely for a writer lock. Once this is called, the .NET runtime
// will deny any more reader locks, in effect blocking all other send/receive // will deny any more reader locks, in effect blocking all other send/receive
// threads. Once we have the lock, we set shutdownFlag to inform the other // threads. Once we have the lock, we set IsRunningInbound = false to inform the other
// threads that the socket is closed. // threads that the socket is closed.
m_shutdownFlag = true; IsRunningInbound = false;
m_udpSocket.Close(); m_udpSocket.Close();
} }
} }
public void StopOutbound()
{
IsRunningOutbound = false;
}
protected virtual bool EnablePools()
{
if (!UsePools)
{
m_pool = new Pool<UDPPacketBuffer>(() => new UDPPacketBuffer(), 500);
m_poolCountStat
= new Stat(
"UDPPacketBufferPoolCount",
"Objects within the UDPPacketBuffer pool",
"The number of objects currently stored within the UDPPacketBuffer pool",
"",
"clientstack",
"packetpool",
StatType.Pull,
stat => stat.Value = m_pool.Count,
StatVerbosity.Debug);
StatsManager.RegisterStat(m_poolCountStat);
UsePools = true;
return true;
}
return false;
}
protected virtual bool DisablePools()
{
if (UsePools)
{
UsePools = false;
StatsManager.DeregisterStat(m_poolCountStat);
// We won't null out the pool to avoid a race condition with code that may be in the middle of using it.
return true;
}
return false;
}
private void AsyncBeginReceive() private void AsyncBeginReceive()
{ {
// allocate a packet buffer UDPPacketBuffer buf;
//WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut();
UDPPacketBuffer buf = new UDPPacketBuffer();
if (!m_shutdownFlag) if (UsePools)
buf = m_pool.GetObject();
else
buf = new UDPPacketBuffer();
if (IsRunningInbound)
{ {
try try
{ {
@ -208,7 +279,7 @@ namespace OpenMetaverse
{ {
// Asynchronous receive operations will complete here through the call // Asynchronous receive operations will complete here through the call
// to AsyncBeginReceive // to AsyncBeginReceive
if (!m_shutdownFlag) if (IsRunningInbound)
{ {
// Asynchronous mode will start another receive before the // Asynchronous mode will start another receive before the
// callback for this packet is even fired. Very parallel :-) // callback for this packet is even fired. Very parallel :-)
@ -217,8 +288,6 @@ namespace OpenMetaverse
// get the buffer that was created in AsyncBeginReceive // get the buffer that was created in AsyncBeginReceive
// this is the received data // this is the received data
//WrappedObject<UDPPacketBuffer> wrappedBuffer = (WrappedObject<UDPPacketBuffer>)iar.AsyncState;
//UDPPacketBuffer buffer = wrappedBuffer.Instance;
UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
try try
@ -235,7 +304,8 @@ namespace OpenMetaverse
catch (ObjectDisposedException) { } catch (ObjectDisposedException) { }
finally finally
{ {
//wrappedBuffer.Dispose(); if (UsePools)
m_pool.ReturnObject(buffer);
// Synchronous mode waits until the packet callback completes // Synchronous mode waits until the packet callback completes
// before starting the receive to fetch another packet // before starting the receive to fetch another packet
@ -248,7 +318,7 @@ namespace OpenMetaverse
public void AsyncBeginSend(UDPPacketBuffer buf) public void AsyncBeginSend(UDPPacketBuffer buf)
{ {
if (!m_shutdownFlag) if (IsRunningOutbound)
{ {
try try
{ {

View File

@ -31,10 +31,10 @@ using System.Reflection;
using OpenMetaverse; using OpenMetaverse;
using OpenMetaverse.Packets; using OpenMetaverse.Packets;
using log4net; using log4net;
using OpenSim.Framework.Monitoring;
namespace OpenSim.Framework namespace OpenSim.Region.ClientStack.LindenUDP
{ {
public sealed class PacketPool public sealed class PacketPool
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@ -44,14 +44,32 @@ namespace OpenSim.Framework
private bool packetPoolEnabled = true; private bool packetPoolEnabled = true;
private bool dataBlockPoolEnabled = true; private bool dataBlockPoolEnabled = true;
private PercentageStat m_packetsReusedStat = new PercentageStat(
"PacketsReused",
"Packets reused",
"Number of packets reused out of all requests to the packet pool",
"clientstack",
"packetpool",
StatType.Push,
null,
StatVerbosity.Debug);
private PercentageStat m_blocksReusedStat = new PercentageStat(
"PacketDataBlocksReused",
"Packet data blocks reused",
"Number of data blocks reused out of all requests to the packet pool",
"clientstack",
"packetpool",
StatType.Push,
null,
StatVerbosity.Debug);
/// <summary>
/// Pool of packets available for reuse.
/// </summary>
private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>(); private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>();
private static Dictionary<Type, Stack<Object>> DataBlocks = private static Dictionary<Type, Stack<Object>> DataBlocks = new Dictionary<Type, Stack<Object>>();
new Dictionary<Type, Stack<Object>>();
static PacketPool()
{
}
public static PacketPool Instance public static PacketPool Instance
{ {
@ -70,8 +88,45 @@ namespace OpenSim.Framework
get { return dataBlockPoolEnabled; } get { return dataBlockPoolEnabled; }
} }
private PacketPool()
{
StatsManager.RegisterStat(m_packetsReusedStat);
StatsManager.RegisterStat(m_blocksReusedStat);
StatsManager.RegisterStat(
new Stat(
"PacketsPoolCount",
"Objects within the packet pool",
"The number of objects currently stored within the packet pool",
"",
"clientstack",
"packetpool",
StatType.Pull,
stat => { lock (pool) { stat.Value = pool.Count; } },
StatVerbosity.Debug));
StatsManager.RegisterStat(
new Stat(
"PacketDataBlocksPoolCount",
"Objects within the packet data block pool",
"The number of objects currently stored within the packet data block pool",
"",
"clientstack",
"packetpool",
StatType.Pull,
stat => { lock (DataBlocks) { stat.Value = DataBlocks.Count; } },
StatVerbosity.Debug));
}
/// <summary>
/// Gets a packet of the given type.
/// </summary>
/// <param name='type'></param>
/// <returns>Guaranteed to always return a packet, whether from the pool or newly constructed.</returns>
public Packet GetPacket(PacketType type) public Packet GetPacket(PacketType type)
{ {
m_packetsReusedStat.Consequent++;
Packet packet; Packet packet;
if (!packetPoolEnabled) if (!packetPoolEnabled)
@ -81,13 +136,19 @@ namespace OpenSim.Framework
{ {
if (!pool.ContainsKey(type) || pool[type] == null || (pool[type]).Count == 0) if (!pool.ContainsKey(type) || pool[type] == null || (pool[type]).Count == 0)
{ {
// m_log.DebugFormat("[PACKETPOOL]: Building {0} packet", type);
// Creating a new packet if we cannot reuse an old package // Creating a new packet if we cannot reuse an old package
packet = Packet.BuildPacket(type); packet = Packet.BuildPacket(type);
} }
else else
{ {
// m_log.DebugFormat("[PACKETPOOL]: Pulling {0} packet", type);
// Recycle old packages // Recycle old packages
packet = (pool[type]).Pop(); m_packetsReusedStat.Antecedent++;
packet = pool[type].Pop();
} }
} }
@ -136,7 +197,7 @@ namespace OpenSim.Framework
{ {
PacketType type = GetType(bytes); PacketType type = GetType(bytes);
Array.Clear(zeroBuffer, 0, zeroBuffer.Length); // Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
int i = 0; int i = 0;
Packet packet = GetPacket(type); Packet packet = GetPacket(type);
@ -183,6 +244,7 @@ namespace OpenSim.Framework
switch (packet.Type) switch (packet.Type)
{ {
// List pooling packets here // List pooling packets here
case PacketType.AgentUpdate:
case PacketType.PacketAck: case PacketType.PacketAck:
case PacketType.ObjectUpdate: case PacketType.ObjectUpdate:
case PacketType.ImprovedTerseObjectUpdate: case PacketType.ImprovedTerseObjectUpdate:
@ -197,7 +259,9 @@ namespace OpenSim.Framework
if ((pool[type]).Count < 50) if ((pool[type]).Count < 50)
{ {
(pool[type]).Push(packet); // m_log.DebugFormat("[PACKETPOOL]: Pushing {0} packet", type);
pool[type].Push(packet);
} }
} }
break; break;
@ -209,17 +273,22 @@ namespace OpenSim.Framework
} }
} }
public static T GetDataBlock<T>() where T: new() public T GetDataBlock<T>() where T: new()
{ {
lock (DataBlocks) lock (DataBlocks)
{ {
m_blocksReusedStat.Consequent++;
Stack<Object> s; Stack<Object> s;
if (DataBlocks.TryGetValue(typeof(T), out s)) if (DataBlocks.TryGetValue(typeof(T), out s))
{ {
if (s.Count > 0) if (s.Count > 0)
{
m_blocksReusedStat.Antecedent++;
return (T)s.Pop(); return (T)s.Pop();
} }
}
else else
{ {
DataBlocks[typeof(T)] = new Stack<Object>(); DataBlocks[typeof(T)] = new Stack<Object>();
@ -229,7 +298,7 @@ namespace OpenSim.Framework
} }
} }
public static void ReturnDataBlock<T>(T block) where T: new() public void ReturnDataBlock<T>(T block) where T: new()
{ {
if (block == null) if (block == null)
return; return;

View File

@ -43,7 +43,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
/// This will contain basic tests for the LindenUDP client stack /// This will contain basic tests for the LindenUDP client stack
/// </summary> /// </summary>
[TestFixture] [TestFixture]
public class BasicCircuitTests public class BasicCircuitTests : OpenSimTestCase
{ {
private Scene m_scene; private Scene m_scene;
private TestLLUDPServer m_udpServer; private TestLLUDPServer m_udpServer;
@ -65,8 +65,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
} }
[SetUp] [SetUp]
public void SetUp() public override void SetUp()
{ {
base.SetUp();
m_scene = new SceneHelpers().SetupScene(); m_scene = new SceneHelpers().SetupScene();
} }
@ -143,7 +144,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
public void TestAddClient() public void TestAddClient()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// XmlConfigurator.Configure(); // TestHelpers.EnableLogging();
AddUdpServer(); AddUdpServer();

View File

@ -76,7 +76,7 @@ namespace OpenSim.Region.ClientStack
protected override void StartupSpecific() protected override void StartupSpecific()
{ {
SceneManager = new SceneManager(); SceneManager = SceneManager.Instance;
m_clientStackManager = CreateClientStackManager(); m_clientStackManager = CreateClientStackManager();
Initialize(); Initialize();

View File

@ -57,40 +57,37 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
} }
/// <summary> /// <summary>
/// Return a xfer uploader if one does not already exist. /// Return the xfer uploader for the given transaction.
/// </summary> /// </summary>
/// <remarks>
/// If an uploader does not already exist for this transaction then it is created, otherwise the existing
/// uploader is returned.
/// </remarks>
/// <param name="transactionID"></param> /// <param name="transactionID"></param>
/// <param name="assetID"> /// <returns>The asset xfer uploader</returns>
/// We must transfer the new asset ID into the uploader on creation, otherwise public AssetXferUploader RequestXferUploader(UUID transactionID)
/// we can see race conditions with other threads which can retrieve an item before it is updated with the new
/// asset id.
/// </param>
/// <returns>
/// The xfer uploader requested. Null if one is already in existence.
/// FIXME: This is a bizarre thing to do, and is probably meant to signal an error condition if multiple
/// transfers are made. Needs to be corrected.
/// </returns>
public AssetXferUploader RequestXferUploader(UUID transactionID, UUID assetID)
{ {
AssetXferUploader uploader;
lock (XferUploaders) lock (XferUploaders)
{ {
if (!XferUploaders.ContainsKey(transactionID)) if (!XferUploaders.ContainsKey(transactionID))
{ {
AssetXferUploader uploader = new AssetXferUploader(this, m_Scene, assetID, m_dumpAssetsToFile); uploader = new AssetXferUploader(this, m_Scene, transactionID, m_dumpAssetsToFile);
// m_log.DebugFormat( // m_log.DebugFormat(
// "[AGENT ASSETS TRANSACTIONS]: Adding asset xfer uploader {0} since it didn't previously exist", transactionID); // "[AGENT ASSETS TRANSACTIONS]: Adding asset xfer uploader {0} since it didn't previously exist", transactionID);
XferUploaders.Add(transactionID, uploader); XferUploaders.Add(transactionID, uploader);
}
else
{
uploader = XferUploaders[transactionID];
}
}
return uploader; return uploader;
} }
}
m_log.WarnFormat("[AGENT ASSETS TRANSACTIONS]: Ignoring request for asset xfer uploader {0} since it already exists", transactionID);
return null;
}
public void HandleXfer(ulong xferID, uint packetID, byte[] data) public void HandleXfer(ulong xferID, uint packetID, byte[] data)
{ {
@ -151,117 +148,30 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
string description, string name, sbyte invType, string description, string name, sbyte invType,
sbyte type, byte wearableType, uint nextOwnerMask) sbyte type, byte wearableType, uint nextOwnerMask)
{ {
AssetXferUploader uploader = null; AssetXferUploader uploader = RequestXferUploader(transactionID);
lock (XferUploaders)
{
if (XferUploaders.ContainsKey(transactionID))
uploader = XferUploaders[transactionID];
}
if (uploader != null)
{
uploader.RequestCreateInventoryItem( uploader.RequestCreateInventoryItem(
remoteClient, transactionID, folderID, remoteClient, folderID, callbackID,
callbackID, description, name, invType, type, description, name, invType, type, wearableType, nextOwnerMask);
wearableType, nextOwnerMask);
return true; return true;
} }
return false;
}
/// <summary>
/// Get an uploaded asset. If the data is successfully retrieved,
/// the transaction will be removed.
/// </summary>
/// <param name="transactionID"></param>
/// <returns>The asset if the upload has completed, null if it has not.</returns>
private AssetBase GetTransactionAsset(UUID transactionID)
{
lock (XferUploaders)
{
if (XferUploaders.ContainsKey(transactionID))
{
AssetXferUploader uploader = XferUploaders[transactionID];
AssetBase asset = uploader.GetAssetData();
RemoveXferUploader(transactionID);
return asset;
}
}
return null;
}
public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient, public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient,
SceneObjectPart part, UUID transactionID, SceneObjectPart part, UUID transactionID,
TaskInventoryItem item) TaskInventoryItem item)
{ {
AssetXferUploader uploader = null; AssetXferUploader uploader = RequestXferUploader(transactionID);
lock (XferUploaders) uploader.RequestUpdateTaskInventoryItem(remoteClient, item);
{
if (XferUploaders.ContainsKey(transactionID))
uploader = XferUploaders[transactionID];
}
if (uploader != null)
{
AssetBase asset = GetTransactionAsset(transactionID);
// Only legacy viewers use this, and they prefer CAPS, which
// we have, so this really never runs.
// Allow it, but only for "safe" types.
if ((InventoryType)item.InvType != InventoryType.Notecard &&
(InventoryType)item.InvType != InventoryType.LSL)
return;
if (asset != null)
{
// m_log.DebugFormat(
// "[AGENT ASSETS TRANSACTIONS]: Updating item {0} in {1} for transaction {2}",
// item.Name, part.Name, transactionID);
asset.FullID = UUID.Random();
asset.Name = item.Name;
asset.Description = item.Description;
asset.Type = (sbyte)item.Type;
item.AssetID = asset.FullID;
m_Scene.AssetService.Store(asset);
}
}
else
{
m_log.ErrorFormat(
"[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to update task inventory item {1} in {2}",
transactionID, item.Name, part.Name);
}
} }
public void RequestUpdateInventoryItem(IClientAPI remoteClient, public void RequestUpdateInventoryItem(IClientAPI remoteClient,
UUID transactionID, InventoryItemBase item) UUID transactionID, InventoryItemBase item)
{ {
AssetXferUploader uploader = null; AssetXferUploader uploader = RequestXferUploader(transactionID);
lock (XferUploaders) uploader.RequestUpdateInventoryItem(remoteClient, item);
{
if (XferUploaders.ContainsKey(transactionID))
uploader = XferUploaders[transactionID];
}
if (uploader != null)
{
uploader.RequestUpdateInventoryItem(remoteClient, transactionID, item);
}
else
{
m_log.ErrorFormat(
"[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to update inventory item {1} for {2}",
transactionID, item.Name, remoteClient.Name);
}
} }
} }
} }

View File

@ -215,7 +215,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item) IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item)
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[TRANSACTIONS MANAGER] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}", "[ASSET TRANSACTION MODULE] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}",
item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName); item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName);
AgentAssetTransactions transactions = AgentAssetTransactions transactions =
@ -274,13 +274,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
} }
AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId);
AssetXferUploader uploader = transactions.RequestXferUploader(transaction, assetID); AssetXferUploader uploader = transactions.RequestXferUploader(transaction);
uploader.StartUpload(remoteClient, assetID, transaction, type, data, storeLocal, tempFile);
if (uploader != null)
{
uploader.Initialise(remoteClient, assetID, transaction, type,
data, storeLocal, tempFile);
}
} }
/// <summary> /// <summary>

View File

@ -48,40 +48,76 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
}; };
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// Upload state.
/// </summary>
/// <remarks>
/// New -> Uploading -> Complete
/// </remarks>
private enum UploadState
{
New,
Uploading,
Complete
}
/// <summary> /// <summary>
/// Reference to the object that holds this uploader. Used to remove ourselves from it's list if we /// Reference to the object that holds this uploader. Used to remove ourselves from it's list if we
/// are performing a delayed update. /// are performing a delayed update.
/// </summary> /// </summary>
AgentAssetTransactions m_transactions; AgentAssetTransactions m_transactions;
private UploadState m_uploadState = UploadState.New;
private AssetBase m_asset; private AssetBase m_asset;
private UUID InventFolder = UUID.Zero; private UUID InventFolder = UUID.Zero;
private sbyte invType = 0; private sbyte invType = 0;
private bool m_createItem = false; private bool m_createItem;
private uint m_createItemCallback = 0; private uint m_createItemCallback;
private bool m_updateItem = false;
private bool m_updateItem;
private InventoryItemBase m_updateItemData; private InventoryItemBase m_updateItemData;
private bool m_updateTaskItem;
private TaskInventoryItem m_updateTaskItemData;
private string m_description = String.Empty; private string m_description = String.Empty;
private bool m_dumpAssetToFile; private bool m_dumpAssetToFile;
private bool m_finished = false;
private string m_name = String.Empty; private string m_name = String.Empty;
private bool m_storeLocal; // private bool m_storeLocal;
private uint nextPerm = 0; private uint nextPerm = 0;
private IClientAPI ourClient; private IClientAPI ourClient;
private UUID TransactionID = UUID.Zero;
private UUID m_transactionID;
private sbyte type = 0; private sbyte type = 0;
private byte wearableType = 0; private byte wearableType = 0;
private byte[] m_oldData = null; private byte[] m_oldData = null;
public ulong XferID; public ulong XferID;
private Scene m_Scene; private Scene m_Scene;
public AssetXferUploader(AgentAssetTransactions transactions, Scene scene, UUID assetID, bool dumpAssetToFile) /// <summary>
/// AssetXferUploader constructor
/// </summary>
/// <param name='transactions'>/param>
/// <param name='scene'></param>
/// <param name='transactionID'></param>
/// <param name='dumpAssetToFile'>
/// If true then when the asset is uploaded it is dumped to a file with the format
/// String.Format("{6}_{7}_{0:d2}{1:d2}{2:d2}_{3:d2}{4:d2}{5:d2}.dat",
/// now.Year, now.Month, now.Day, now.Hour, now.Minute,
/// now.Second, m_asset.Name, m_asset.Type);
/// for debugging purposes.
/// </param>
public AssetXferUploader(
AgentAssetTransactions transactions, Scene scene, UUID transactionID, bool dumpAssetToFile)
{ {
m_asset = new AssetBase();
m_transactions = transactions; m_transactions = transactions;
m_transactionID = transactionID;
m_Scene = scene; m_Scene = scene;
m_asset = new AssetBase() { FullID = assetID };
m_dumpAssetToFile = dumpAssetToFile; m_dumpAssetToFile = dumpAssetToFile;
} }
@ -127,30 +163,50 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
} }
/// <summary> /// <summary>
/// Initialise asset transfer from the client /// Start asset transfer from the client
/// </summary> /// </summary>
/// <param name="xferID"></param> /// <param name="remoteClient"></param>
/// <param name="packetID"></param> /// <param name="assetID"></param>
/// <param name="data"></param> /// <param name="transaction"></param>
public void Initialise(IClientAPI remoteClient, UUID assetID, /// <param name="type"></param>
UUID transaction, sbyte type, byte[] data, bool storeLocal, /// <param name="data">
/// Optional data. If present then the asset is created immediately with this data
/// rather than requesting an upload from the client. The data must be longer than 2 bytes.
/// </param>
/// <param name="storeLocal"></param>
/// <param name="tempFile"></param>
public void StartUpload(
IClientAPI remoteClient, UUID assetID, UUID transaction, sbyte type, byte[] data, bool storeLocal,
bool tempFile) bool tempFile)
{ {
// m_log.DebugFormat( // m_log.DebugFormat(
// "[ASSET XFER UPLOADER]: Initialised xfer from {0}, asset {1}, transaction {2}, type {3}, storeLocal {4}, tempFile {5}, already received data length {6}", // "[ASSET XFER UPLOADER]: Initialised xfer from {0}, asset {1}, transaction {2}, type {3}, storeLocal {4}, tempFile {5}, already received data length {6}",
// remoteClient.Name, assetID, transaction, type, storeLocal, tempFile, data.Length); // remoteClient.Name, assetID, transaction, type, storeLocal, tempFile, data.Length);
lock (this)
{
if (m_uploadState != UploadState.New)
{
m_log.WarnFormat(
"[ASSET XFER UPLOADER]: Tried to start upload of asset {0}, transaction {1} for {2} but this is already in state {3}. Aborting.",
assetID, transaction, remoteClient.Name, m_uploadState);
return;
}
m_uploadState = UploadState.Uploading;
}
ourClient = remoteClient; ourClient = remoteClient;
m_asset.Name = "blank";
m_asset.Description = "empty"; m_asset.FullID = assetID;
m_asset.Type = type; m_asset.Type = type;
m_asset.CreatorID = remoteClient.AgentId.ToString(); m_asset.CreatorID = remoteClient.AgentId.ToString();
m_asset.Data = data; m_asset.Data = data;
m_asset.Local = storeLocal; m_asset.Local = storeLocal;
m_asset.Temporary = tempFile; m_asset.Temporary = tempFile;
TransactionID = transaction; // m_storeLocal = storeLocal;
m_storeLocal = storeLocal;
if (m_asset.Data.Length > 2) if (m_asset.Data.Length > 2)
{ {
@ -175,36 +231,35 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
protected void SendCompleteMessage() protected void SendCompleteMessage()
{ {
ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true,
m_asset.FullID);
// We must lock in order to avoid a race with a separate thread dealing with an inventory item or create // We must lock in order to avoid a race with a separate thread dealing with an inventory item or create
// message from other client UDP. // message from other client UDP.
lock (this) lock (this)
{ {
m_finished = true; m_uploadState = UploadState.Complete;
ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true, m_asset.FullID);
if (m_createItem) if (m_createItem)
{ {
DoCreateItem(m_createItemCallback); CompleteCreateItem(m_createItemCallback);
} }
else if (m_updateItem) else if (m_updateItem)
{ {
StoreAssetForItemUpdate(m_updateItemData); CompleteItemUpdate(m_updateItemData);
// Remove ourselves from the list of transactions if completion was delayed until the transaction
// was complete.
// TODO: Should probably do the same for create item.
m_transactions.RemoveXferUploader(TransactionID);
} }
else if (m_storeLocal) else if (m_updateTaskItem)
{ {
m_Scene.AssetService.Store(m_asset); CompleteTaskItemUpdate(m_updateTaskItemData);
} }
// else if (m_storeLocal)
// {
// m_Scene.AssetService.Store(m_asset);
// }
} }
m_log.DebugFormat( m_log.DebugFormat(
"[ASSET XFER UPLOADER]: Uploaded asset {0} for transaction {1}", "[ASSET XFER UPLOADER]: Uploaded asset {0} for transaction {1}",
m_asset.FullID, TransactionID); m_asset.FullID, m_transactionID);
if (m_dumpAssetToFile) if (m_dumpAssetToFile)
{ {
@ -232,11 +287,9 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
} }
public void RequestCreateInventoryItem(IClientAPI remoteClient, public void RequestCreateInventoryItem(IClientAPI remoteClient,
UUID transactionID, UUID folderID, uint callbackID, UUID folderID, uint callbackID,
string description, string name, sbyte invType, string description, string name, sbyte invType,
sbyte type, byte wearableType, uint nextOwnerMask) sbyte type, byte wearableType, uint nextOwnerMask)
{
if (TransactionID == transactionID)
{ {
InventFolder = folderID; InventFolder = folderID;
m_name = name; m_name = name;
@ -252,9 +305,9 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
// We must lock to avoid a race with a separate thread uploading the asset. // We must lock to avoid a race with a separate thread uploading the asset.
lock (this) lock (this)
{ {
if (m_finished) if (m_uploadState == UploadState.Complete)
{ {
DoCreateItem(callbackID); CompleteCreateItem(callbackID);
} }
else else
{ {
@ -263,9 +316,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
} }
} }
} }
}
public void RequestUpdateInventoryItem(IClientAPI remoteClient, UUID transactionID, InventoryItemBase item) public void RequestUpdateInventoryItem(IClientAPI remoteClient, InventoryItemBase item)
{ {
// We must lock to avoid a race with a separate thread uploading the asset. // We must lock to avoid a race with a separate thread uploading the asset.
lock (this) lock (this)
@ -280,9 +332,9 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
item.AssetID = m_asset.FullID; item.AssetID = m_asset.FullID;
m_Scene.InventoryService.UpdateItem(item); m_Scene.InventoryService.UpdateItem(item);
if (m_finished) if (m_uploadState == UploadState.Complete)
{ {
StoreAssetForItemUpdate(item); CompleteItemUpdate(item);
} }
else else
{ {
@ -296,20 +348,59 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
} }
} }
public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient, TaskInventoryItem taskItem)
{
// We must lock to avoid a race with a separate thread uploading the asset.
lock (this)
{
m_asset.Name = taskItem.Name;
m_asset.Description = taskItem.Description;
m_asset.Type = (sbyte)taskItem.Type;
taskItem.AssetID = m_asset.FullID;
if (m_uploadState == UploadState.Complete)
{
CompleteTaskItemUpdate(taskItem);
}
else
{
m_updateTaskItem = true;
m_updateTaskItemData = taskItem;
}
}
}
/// <summary> /// <summary>
/// Store the asset for the given item. /// Store the asset for the given item when it has been uploaded.
/// </summary> /// </summary>
/// <param name="item"></param> /// <param name="item"></param>
private void StoreAssetForItemUpdate(InventoryItemBase item) private void CompleteItemUpdate(InventoryItemBase item)
{ {
// m_log.DebugFormat( // m_log.DebugFormat(
// "[ASSET XFER UPLOADER]: Storing asset {0} for earlier item update for {1} for {2}", // "[ASSET XFER UPLOADER]: Storing asset {0} for earlier item update for {1} for {2}",
// m_asset.FullID, item.Name, ourClient.Name); // m_asset.FullID, item.Name, ourClient.Name);
m_Scene.AssetService.Store(m_asset); m_Scene.AssetService.Store(m_asset);
m_transactions.RemoveXferUploader(m_transactionID);
} }
private void DoCreateItem(uint callbackID) /// <summary>
/// Store the asset for the given task item when it has been uploaded.
/// </summary>
/// <param name="taskItem"></param>
private void CompleteTaskItemUpdate(TaskInventoryItem taskItem)
{
// m_log.DebugFormat(
// "[ASSET XFER UPLOADER]: Storing asset {0} for earlier task item update for {1} for {2}",
// m_asset.FullID, taskItem.Name, ourClient.Name);
m_Scene.AssetService.Store(m_asset);
m_transactions.RemoveXferUploader(m_transactionID);
}
private void CompleteCreateItem(uint callbackID)
{ {
ValidateAssets(); ValidateAssets();
m_Scene.AssetService.Store(m_asset); m_Scene.AssetService.Store(m_asset);
@ -339,6 +430,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
ourClient.SendInventoryItemCreateUpdate(item, callbackID); ourClient.SendInventoryItemCreateUpdate(item, callbackID);
else else
ourClient.SendAlertMessage("Unable to create inventory item"); ourClient.SendAlertMessage("Unable to create inventory item");
m_transactions.RemoveXferUploader(m_transactionID);
} }
private void ValidateAssets() private void ValidateAssets()
@ -416,7 +509,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
/// <returns>null if the asset has not finished uploading</returns> /// <returns>null if the asset has not finished uploading</returns>
public AssetBase GetAssetData() public AssetBase GetAssetData()
{ {
if (m_finished) if (m_uploadState == UploadState.Complete)
{ {
ValidateAssets(); ValidateAssets();
return m_asset; return m_asset;
@ -469,4 +562,3 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
} }
} }
} }

View File

@ -52,7 +52,7 @@ using OpenSim.Services.Interfaces;
[assembly: Addin("FlotsamAssetCache", "1.1")] [assembly: Addin("FlotsamAssetCache", "1.1")]
[assembly: AddinDependency("OpenSim", "0.5")] [assembly: AddinDependency("OpenSim", "0.5")]
namespace Flotsam.RegionModules.AssetCache namespace OpenSim.Region.CoreModules.Asset
{ {
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
public class FlotsamAssetCache : ISharedRegionModule, IImprovedAssetCache, IAssetService public class FlotsamAssetCache : ISharedRegionModule, IImprovedAssetCache, IAssetService
@ -107,8 +107,6 @@ namespace Flotsam.RegionModules.AssetCache
private IAssetService m_AssetService; private IAssetService m_AssetService;
private List<Scene> m_Scenes = new List<Scene>(); private List<Scene> m_Scenes = new List<Scene>();
private bool m_DeepScanBeforePurge;
public FlotsamAssetCache() public FlotsamAssetCache()
{ {
m_InvalidChars.AddRange(Path.GetInvalidPathChars()); m_InvalidChars.AddRange(Path.GetInvalidPathChars());
@ -170,8 +168,6 @@ namespace Flotsam.RegionModules.AssetCache
m_CacheDirectoryTierLen = assetConfig.GetInt("CacheDirectoryTierLength", m_CacheDirectoryTierLen); m_CacheDirectoryTierLen = assetConfig.GetInt("CacheDirectoryTierLength", m_CacheDirectoryTierLen);
m_CacheWarnAt = assetConfig.GetInt("CacheWarnAt", m_CacheWarnAt); m_CacheWarnAt = assetConfig.GetInt("CacheWarnAt", m_CacheWarnAt);
m_DeepScanBeforePurge = assetConfig.GetBoolean("DeepScanBeforePurge", m_DeepScanBeforePurge);
} }
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Directory {0}", m_CacheDirectory); m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Directory {0}", m_CacheDirectory);
@ -519,13 +515,10 @@ namespace Flotsam.RegionModules.AssetCache
// Purge all files last accessed prior to this point // Purge all files last accessed prior to this point
DateTime purgeLine = DateTime.Now - m_FileExpiration; DateTime purgeLine = DateTime.Now - m_FileExpiration;
// An optional deep scan at this point will ensure assets present in scenes, // An asset cache may contain local non-temporary assets that are not in the asset service. Therefore,
// or referenced by objects in the scene, but not recently accessed // before cleaning up expired files we must scan the objects in the scene to make sure that we retain
// are not purged. // such local assets if they have not been recently accessed.
if (m_DeepScanBeforePurge) TouchAllSceneAssets(false);
{
CacheScenes();
}
foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
{ {
@ -718,11 +711,14 @@ namespace Flotsam.RegionModules.AssetCache
/// <summary> /// <summary>
/// Iterates through all Scenes, doing a deep scan through assets /// Iterates through all Scenes, doing a deep scan through assets
/// to cache all assets present in the scene or referenced by assets /// to update the access time of all assets present in the scene or referenced by assets
/// in the scene /// in the scene.
/// </summary> /// </summary>
/// <returns></returns> /// <param name="storeUncached">
private int CacheScenes() /// If true, then assets scanned which are not found in cache are added to the cache.
/// </param>
/// <returns>Number of distinct asset references found in the scene.</returns>
private int TouchAllSceneAssets(bool storeUncached)
{ {
UuidGatherer gatherer = new UuidGatherer(m_AssetService); UuidGatherer gatherer = new UuidGatherer(m_AssetService);
@ -745,7 +741,7 @@ namespace Flotsam.RegionModules.AssetCache
{ {
File.SetLastAccessTime(filename, DateTime.Now); File.SetLastAccessTime(filename, DateTime.Now);
} }
else else if (storeUncached)
{ {
m_AssetService.Get(assetID.ToString()); m_AssetService.Get(assetID.ToString());
} }
@ -873,13 +869,14 @@ namespace Flotsam.RegionModules.AssetCache
break; break;
case "assets": case "assets":
m_log.Info("[FLOTSAM ASSET CACHE]: Caching all assets, in all scenes."); m_log.Info("[FLOTSAM ASSET CACHE]: Ensuring assets are cached for all scenes.");
Util.FireAndForget(delegate { Util.FireAndForget(delegate {
int assetsCached = CacheScenes(); int assetReferenceTotal = TouchAllSceneAssets(true);
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Completed Scene Caching, {0} assets found.", assetsCached); m_log.InfoFormat(
"[FLOTSAM ASSET CACHE]: Completed check with {0} assets.",
assetReferenceTotal);
}); });
break; break;

View File

@ -35,7 +35,6 @@ using Nini.Config;
using NUnit.Framework; using NUnit.Framework;
using OpenMetaverse; using OpenMetaverse;
using OpenMetaverse.Assets; using OpenMetaverse.Assets;
using Flotsam.RegionModules.AssetCache;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Framework.Scenes.Serialization; using OpenSim.Region.Framework.Scenes.Serialization;

View File

@ -285,6 +285,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
} }
public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp) public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp)
{
if (!Enabled)
return false;
if (AttachObjectInternal(sp, group, attachmentPt, silent, useAttachData, temp))
{
m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
return true;
}
return false;
}
private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp)
{ {
lock (sp.AttachmentsSyncLock) lock (sp.AttachmentsSyncLock)
{ {
@ -460,6 +474,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
} }
public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId) public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId)
{
DetachSingleAttachmentToGround(sp, soLocalId, sp.AbsolutePosition, Quaternion.Identity);
}
public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId, Vector3 absolutePos, Quaternion absoluteRot)
{ {
if (!Enabled) if (!Enabled)
return; return;
@ -502,7 +521,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
so.FromItemID = UUID.Zero; so.FromItemID = UUID.Zero;
SceneObjectPart rootPart = so.RootPart; SceneObjectPart rootPart = so.RootPart;
so.AbsolutePosition = sp.AbsolutePosition; so.AbsolutePosition = absolutePos;
if (absoluteRot != Quaternion.Identity)
{
so.UpdateGroupRotationR(absoluteRot);
}
so.AttachedAvatar = UUID.Zero; so.AttachedAvatar = UUID.Zero;
rootPart.SetParentLocalId(0); rootPart.SetParentLocalId(0);
so.ClearPartAttachmentData(); so.ClearPartAttachmentData();
@ -616,9 +639,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (grp.HasGroupChanged) if (grp.HasGroupChanged)
{ {
// m_log.DebugFormat( m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}", "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}",
// grp.UUID, grp.AttachmentPoint); grp.UUID, grp.AttachmentPoint);
string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp, scriptedState); string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp, scriptedState);
@ -862,7 +885,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
// This will throw if the attachment fails // This will throw if the attachment fails
try try
{ {
AttachObject(sp, objatt, attachmentPt, false, false, false); AttachObjectInternal(sp, objatt, attachmentPt, false, false, false);
} }
catch (Exception e) catch (Exception e)
{ {
@ -933,6 +956,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID); InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID);
item = m_scene.InventoryService.GetItem(item); item = m_scene.InventoryService.GetItem(item);
if (item == null)
return;
bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID);
if (changed && m_scene.AvatarFactory != null) if (changed && m_scene.AvatarFactory != null)
{ {

View File

@ -62,7 +62,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
public class AttachmentsModuleTests : OpenSimTestCase public class AttachmentsModuleTests : OpenSimTestCase
{ {
private AutoResetEvent m_chatEvent = new AutoResetEvent(false); private AutoResetEvent m_chatEvent = new AutoResetEvent(false);
private OSChatMessage m_osChatMessageReceived; // private OSChatMessage m_osChatMessageReceived;
// Used to test whether the operations have fired the attach event. Must be reset after each test.
private int m_numberOfAttachEventsFired;
[TestFixtureSetUp] [TestFixtureSetUp]
public void FixtureInit() public void FixtureInit()
@ -83,7 +86,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
{ {
// Console.WriteLine("Got chat [{0}]", oscm.Message); // Console.WriteLine("Got chat [{0}]", oscm.Message);
m_osChatMessageReceived = oscm; // m_osChatMessageReceived = oscm;
m_chatEvent.Set(); m_chatEvent.Set();
} }
@ -99,6 +102,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
"attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config); "attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config);
SceneHelpers.SetupSceneModules(scene, config, modules.ToArray()); SceneHelpers.SetupSceneModules(scene, config, modules.ToArray());
scene.EventManager.OnAttach += (localID, itemID, avatarID) => m_numberOfAttachEventsFired++;
return scene; return scene;
} }
@ -181,6 +186,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
TestHelpers.InMethod(); TestHelpers.InMethod();
// TestHelpers.EnableLogging(); // TestHelpers.EnableLogging();
m_numberOfAttachEventsFired = 0;
Scene scene = CreateTestScene(); Scene scene = CreateTestScene();
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
@ -189,6 +196,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID); SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID);
m_numberOfAttachEventsFired = 0;
scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false); scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false);
// Check status on scene presence // Check status on scene presence
@ -216,7 +224,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// TestHelpers.DisableLogging(); // Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
} }
/// <summary> /// <summary>
@ -228,6 +237,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
TestHelpers.InMethod(); TestHelpers.InMethod();
// TestHelpers.EnableLogging(); // TestHelpers.EnableLogging();
m_numberOfAttachEventsFired = 0;
Scene scene = CreateTestScene(); Scene scene = CreateTestScene();
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
@ -247,6 +258,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Assert.That(sp.HasAttachments(), Is.False); Assert.That(sp.HasAttachments(), Is.False);
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
} }
[Test] [Test]
@ -261,6 +275,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
m_numberOfAttachEventsFired = 0;
scene.AttachmentsModule.RezSingleAttachmentFromInventory( scene.AttachmentsModule.RezSingleAttachmentFromInventory(
sp, attItem.ID, (uint)AttachmentPoint.Chest); sp, attItem.ID, (uint)AttachmentPoint.Chest);
@ -280,6 +295,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
} }
/// <summary> /// <summary>
@ -338,6 +356,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
ISceneEntity so ISceneEntity so
= scene.AttachmentsModule.RezSingleAttachmentFromInventory( = scene.AttachmentsModule.RezSingleAttachmentFromInventory(
sp, attItem.ID, (uint)AttachmentPoint.Chest); sp, attItem.ID, (uint)AttachmentPoint.Chest);
m_numberOfAttachEventsFired = 0;
scene.AttachmentsModule.DetachSingleAttachmentToGround(sp, so.LocalId); scene.AttachmentsModule.DetachSingleAttachmentToGround(sp, so.LocalId);
// Check scene presence status // Check scene presence status
@ -353,6 +373,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
// Check object in scene // Check object in scene
Assert.That(scene.GetSceneObjectGroup("att"), Is.Not.Null); Assert.That(scene.GetSceneObjectGroup("att"), Is.Not.Null);
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
} }
[Test] [Test]
@ -369,6 +392,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
SceneObjectGroup so SceneObjectGroup so
= (SceneObjectGroup)scene.AttachmentsModule.RezSingleAttachmentFromInventory( = (SceneObjectGroup)scene.AttachmentsModule.RezSingleAttachmentFromInventory(
sp, attItem.ID, (uint)AttachmentPoint.Chest); sp, attItem.ID, (uint)AttachmentPoint.Chest);
m_numberOfAttachEventsFired = 0;
scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, so); scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, so);
// Check status on scene presence // Check status on scene presence
@ -380,6 +405,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo(0)); Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo(0));
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(0)); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(0));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
} }
/// <summary> /// <summary>
@ -461,10 +489,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
SceneObjectGroup rezzedAtt = presence.GetAttachments()[0]; SceneObjectGroup rezzedAtt = presence.GetAttachments()[0];
scene.IncomingCloseAgent(presence.UUID); m_numberOfAttachEventsFired = 0;
scene.IncomingCloseAgent(presence.UUID, false);
// Check that we can't retrieve this attachment from the scene. // Check that we can't retrieve this attachment from the scene.
Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null); Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null);
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
} }
[Test] [Test]
@ -480,6 +512,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
acd.Appearance = new AvatarAppearance(); acd.Appearance = new AvatarAppearance();
acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID); acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID);
m_numberOfAttachEventsFired = 0;
ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd); ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd);
Assert.That(presence.HasAttachments(), Is.True); Assert.That(presence.HasAttachments(), Is.True);
@ -502,6 +536,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Assert.That(presence.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); Assert.That(presence.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// Check events. We expect OnAttach to fire on login.
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
} }
[Test] [Test]
@ -522,10 +559,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Vector3 newPosition = new Vector3(1, 2, 4); Vector3 newPosition = new Vector3(1, 2, 4);
m_numberOfAttachEventsFired = 0;
scene.SceneGraph.UpdatePrimGroupPosition(attSo.LocalId, newPosition, sp.ControllingClient); scene.SceneGraph.UpdatePrimGroupPosition(attSo.LocalId, newPosition, sp.ControllingClient);
Assert.That(attSo.AbsolutePosition, Is.EqualTo(sp.AbsolutePosition)); Assert.That(attSo.AbsolutePosition, Is.EqualTo(sp.AbsolutePosition));
Assert.That(attSo.RootPart.AttachedPos, Is.EqualTo(newPosition)); Assert.That(attSo.RootPart.AttachedPos, Is.EqualTo(newPosition));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
} }
[Test] [Test]
@ -574,6 +615,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Vector3 teleportPosition = new Vector3(10, 11, 12); Vector3 teleportPosition = new Vector3(10, 11, 12);
Vector3 teleportLookAt = new Vector3(20, 21, 22); Vector3 teleportLookAt = new Vector3(20, 21, 22);
m_numberOfAttachEventsFired = 0;
sceneA.RequestTeleportLocation( sceneA.RequestTeleportLocation(
beforeTeleportSp.ControllingClient, beforeTeleportSp.ControllingClient,
sceneB.RegionInfo.RegionHandle, sceneB.RegionInfo.RegionHandle,
@ -616,29 +658,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0)); Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0));
Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0)); Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0));
}
// I'm commenting this test because scene setup NEEDS InventoryService to // Check events
// be non-null Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
//[Test] }
// public void T032_CrossAttachments()
// {
// TestHelpers.InMethod();
//
// ScenePresence presence = scene.GetScenePresence(agent1);
// ScenePresence presence2 = scene2.GetScenePresence(agent1);
// presence2.AddAttachment(sog1);
// presence2.AddAttachment(sog2);
//
// ISharedRegionModule serialiser = new SerialiserModule();
// SceneHelpers.SetupSceneModules(scene, new IniConfigSource(), serialiser);
// SceneHelpers.SetupSceneModules(scene2, new IniConfigSource(), serialiser);
//
// Assert.That(presence.HasAttachments(), Is.False, "Presence has attachments before cross");
//
// //Assert.That(presence2.CrossAttachmentsIntoNewRegion(region1, true), Is.True, "Cross was not successful");
// Assert.That(presence2.HasAttachments(), Is.False, "Presence2 objects were not deleted");
// Assert.That(presence.HasAttachments(), Is.True, "Presence has not received new objects");
// }
} }
} }

View File

@ -533,6 +533,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
// Ignore ruth's assets // Ignore ruth's assets
if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID) if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID)
continue; continue;
InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID); InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID);
baseItem = invService.GetItem(baseItem); baseItem = invService.GetItem(baseItem);

View File

@ -197,6 +197,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
string fromName = c.From; string fromName = c.From;
string fromNamePrefix = ""; string fromNamePrefix = "";
UUID fromID = UUID.Zero; UUID fromID = UUID.Zero;
UUID ownerID = UUID.Zero;
string message = c.Message; string message = c.Message;
IScene scene = c.Scene; IScene scene = c.Scene;
UUID destination = c.Destination; UUID destination = c.Destination;
@ -224,11 +225,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
fromNamePrefix = m_adminPrefix; fromNamePrefix = m_adminPrefix;
} }
destination = UUID.Zero; // Avatars cant "SayTo" destination = UUID.Zero; // Avatars cant "SayTo"
ownerID = c.Sender.AgentId;
break; break;
case ChatSourceType.Object: case ChatSourceType.Object:
fromID = c.SenderUUID; fromID = c.SenderUUID;
if (c.SenderObject != null && c.SenderObject is SceneObjectPart)
ownerID = ((SceneObjectPart)c.SenderObject).OwnerID;
break; break;
} }
@ -262,9 +268,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
// objects on a parcel with access restrictions // objects on a parcel with access restrictions
if (c.Sender == null || Presencecheck.IsEitherBannedOrRestricted(c.Sender.AgentId) != true) if (c.Sender == null || Presencecheck.IsEitherBannedOrRestricted(c.Sender.AgentId) != true)
{ {
if (TrySendChatMessage(presence, fromPos, regionPos, fromID, fromNamePrefix + fromName, c.Type, message, sourceType)) if (destination != UUID.Zero)
{
if (TrySendChatMessage(presence, fromPos, regionPos, fromID, ownerID, fromNamePrefix + fromName, c.Type, message, sourceType, true))
receiverIDs.Add(presence.UUID); receiverIDs.Add(presence.UUID);
} }
else
{
if (TrySendChatMessage(presence, fromPos, regionPos, fromID, ownerID, fromNamePrefix + fromName, c.Type, message, sourceType, false))
receiverIDs.Add(presence.UUID);
}
}
} }
} }
); );
@ -324,7 +338,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
(((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId)) (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId))
return; return;
client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID, client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID, fromID,
(byte)sourceType, (byte)ChatAudibleLevel.Fully); (byte)sourceType, (byte)ChatAudibleLevel.Fully);
receiverIDs.Add(client.AgentId); receiverIDs.Add(client.AgentId);
} }
@ -341,15 +355,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
/// <param name="fromPos"></param> /// <param name="fromPos"></param>
/// <param name="regionPos">/param> /// <param name="regionPos">/param>
/// <param name="fromAgentID"></param> /// <param name="fromAgentID"></param>
/// <param name='ownerID'>
/// Owner of the message. For at least some messages from objects, this has to be correctly filled with the owner's UUID.
/// This is the case for script error messages in viewer 3 since LLViewer change EXT-7762
/// </param>
/// <param name="fromName"></param> /// <param name="fromName"></param>
/// <param name="type"></param> /// <param name="type"></param>
/// <param name="message"></param> /// <param name="message"></param>
/// <param name="src"></param> /// <param name="src"></param>
/// <returns>true if the message was sent to the receiver, false if it was not sent due to failing a /// <returns>true if the message was sent to the receiver, false if it was not sent due to failing a
/// precondition</returns> /// precondition</returns>
protected virtual bool TrySendChatMessage(ScenePresence presence, Vector3 fromPos, Vector3 regionPos, protected virtual bool TrySendChatMessage(
UUID fromAgentID, string fromName, ChatTypeEnum type, ScenePresence presence, Vector3 fromPos, Vector3 regionPos,
string message, ChatSourceType src) UUID fromAgentID, UUID ownerID, string fromName, ChatTypeEnum type,
string message, ChatSourceType src, bool ignoreDistance)
{ {
// don't send chat to child agents // don't send chat to child agents
if (presence.IsChildAgent) return false; if (presence.IsChildAgent) return false;
@ -369,8 +388,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
} }
// TODO: should change so the message is sent through the avatar rather than direct to the ClientView // TODO: should change so the message is sent through the avatar rather than direct to the ClientView
presence.ControllingClient.SendChatMessage(message, (byte) type, fromPos, fromName, presence.ControllingClient.SendChatMessage(
fromAgentID, (byte)src, (byte)ChatAudibleLevel.Fully); message, (byte) type, fromPos, fromName,
fromAgentID, ownerID, (byte)src, (byte)ChatAudibleLevel.Fully);
return true; return true;
} }

View File

@ -141,7 +141,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
client.FirstName+" "+client.LastName, client.FirstName+" "+client.LastName,
destID, (byte)211, false, destID, (byte)211, false,
String.Empty, String.Empty,
transactionID, false, new Vector3(), new byte[0]), transactionID, false, new Vector3(), new byte[0], true),
delegate(bool success) {} ); delegate(bool success) {} );
} }
} }

View File

@ -28,6 +28,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading; using System.Threading;
using log4net; using log4net;
@ -482,9 +483,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
Util.FireAndForget( Util.FireAndForget(
delegate delegate
{ {
m_log.DebugFormat( // m_log.DebugFormat(
"[FRIENDS MODULE]: Notifying {0} friends of {1} of online status {2}", // "[FRIENDS MODULE]: Notifying {0} friends of {1} of online status {2}",
friendList.Count, agentID, online); // friendList.Count, agentID, online);
// Notify about this user status // Notify about this user status
StatusNotify(friendList, agentID, online); StatusNotify(friendList, agentID, online);
@ -495,42 +496,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
protected virtual void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online) protected virtual void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online)
{ {
foreach (FriendInfo friend in friendList) List<string> friendStringIds = friendList.ConvertAll<string>(friend => friend.Friend);
List<string> remoteFriendStringIds = new List<string>();
foreach (string friendStringId in friendStringIds)
{ {
UUID friendID; UUID friendUuid;
if (UUID.TryParse(friend.Friend, out friendID)) if (UUID.TryParse(friendStringId, out friendUuid))
{ {
// Try local if (LocalStatusNotification(userID, friendUuid, online))
if (LocalStatusNotification(userID, friendID, online))
continue; continue;
// The friend is not here [as root]. Let's forward. remoteFriendStringIds.Add(friendStringId);
PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() });
if (friendSessions != null && friendSessions.Length > 0)
{
PresenceInfo friendSession = null;
foreach (PresenceInfo pinfo in friendSessions)
{
if (pinfo.RegionID != UUID.Zero) // let's guard against sessions-gone-bad
{
friendSession = pinfo;
break;
}
}
if (friendSession != null)
{
GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
//m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", region.RegionName);
m_FriendsSimConnector.StatusNotify(region, userID, friendID, online);
}
}
// Friend is not online. Ignore.
} }
else else
{ {
m_log.WarnFormat("[FRIENDS]: Error parsing friend ID {0}", friend.Friend); m_log.WarnFormat("[FRIENDS]: Error parsing friend ID {0}", friendStringId);
}
}
// We do this regrouping so that we can efficiently send a single request rather than one for each
// friend in what may be a very large friends list.
PresenceInfo[] friendSessions = PresenceService.GetAgents(remoteFriendStringIds.ToArray());
foreach (PresenceInfo friendSession in friendSessions)
{
// let's guard against sessions-gone-bad
if (friendSession.RegionID != UUID.Zero)
{
GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
//m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", region.RegionName);
m_FriendsSimConnector.StatusNotify(region, userID, friendSession.UserID, online);
} }
} }
} }

View File

@ -206,7 +206,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
transferModule.SendInstantMessage(new GridInstantMessage( transferModule.SendInstantMessage(new GridInstantMessage(
m_scene, godID, "God", agentID, (byte)250, false, m_scene, godID, "God", agentID, (byte)250, false,
Utils.BytesToString(reason), UUID.Zero, true, Utils.BytesToString(reason), UUID.Zero, true,
new Vector3(), new byte[] {(byte)kickflags}), new Vector3(), new byte[] {(byte)kickflags}, true),
delegate(bool success) {} ); delegate(bool success) {} );
} }
return; return;

View File

@ -166,7 +166,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
if (options.ContainsKey("verbose")) if (options.ContainsKey("verbose"))
m_log.InfoFormat( m_log.InfoFormat(
"[INVENTORY ARCHIVER]: Saving item {0} {1} with asset {2}", "[INVENTORY ARCHIVER]: Saving item {0} {1} (asset UUID {2})",
inventoryItem.ID, inventoryItem.Name, inventoryItem.AssetID); inventoryItem.ID, inventoryItem.Name, inventoryItem.AssetID);
string filename = path + CreateArchiveItemName(inventoryItem); string filename = path + CreateArchiveItemName(inventoryItem);
@ -337,11 +337,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
{ {
m_log.DebugFormat("[INVENTORY ARCHIVER]: Saving {0} assets for items", m_assetUuids.Count); m_log.DebugFormat("[INVENTORY ARCHIVER]: Saving {0} assets for items", m_assetUuids.Count);
new AssetsRequest( AssetsRequest ar
= new AssetsRequest(
new AssetsArchiver(m_archiveWriter), new AssetsArchiver(m_archiveWriter),
m_assetUuids, m_scene.AssetService, m_assetUuids, m_scene.AssetService,
m_scene.UserAccountService, m_scene.RegionInfo.ScopeID, m_scene.UserAccountService, m_scene.RegionInfo.ScopeID,
options, ReceivedAllAssets).Execute(); options, ReceivedAllAssets);
Util.FireAndForget(o => ar.Execute());
} }
else else
{ {

View File

@ -35,6 +35,7 @@ using Nini.Config;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Framework.Communications; using OpenSim.Framework.Communications;
using OpenSim.Framework.Console;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces; using OpenSim.Services.Interfaces;
@ -209,6 +210,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
Guid id, string firstName, string lastName, string invPath, string pass, string savePath, Guid id, string firstName, string lastName, string invPath, string pass, string savePath,
Dictionary<string, object> options) Dictionary<string, object> options)
{ {
// if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, savePath))
// return false;
if (m_scenes.Count > 0) if (m_scenes.Count > 0)
{ {
UserAccount userInfo = GetUserInfo(firstName, lastName, pass); UserAccount userInfo = GetUserInfo(firstName, lastName, pass);

View File

@ -83,6 +83,24 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
protected string m_item1Name = "Ray Gun Item"; protected string m_item1Name = "Ray Gun Item";
protected string m_coaItemName = "Coalesced Item"; protected string m_coaItemName = "Coalesced Item";
[TestFixtureSetUp]
public void FixtureSetup()
{
// Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
ConstructDefaultIarBytesForTestLoad();
}
[TestFixtureTearDown]
public void TearDown()
{
// We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
// threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
// tests really shouldn't).
Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
}
[SetUp] [SetUp]
public override void SetUp() public override void SetUp()
{ {
@ -90,12 +108,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
m_iarStream = new MemoryStream(m_iarStreamBytes); m_iarStream = new MemoryStream(m_iarStreamBytes);
} }
[TestFixtureSetUp]
public void FixtureSetup()
{
ConstructDefaultIarBytesForTestLoad();
}
protected void ConstructDefaultIarBytesForTestLoad() protected void ConstructDefaultIarBytesForTestLoad()
{ {
// log4net.Config.XmlConfigurator.Configure(); // log4net.Config.XmlConfigurator.Configure();

View File

@ -69,7 +69,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
public void TestLoadCoalesecedItem() public void TestLoadCoalesecedItem()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure(); // TestHelpers.EnableLogging();
UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "password"); UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "password");
m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream); m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream);
@ -350,38 +350,38 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL1.PrincipalID)); Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL1.PrincipalID));
} }
/// <summary> // /// <summary>
/// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where // /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where
/// an account exists with the same name as the creator, though not the same id. // /// an account exists with the same name as the creator, though not the same id.
/// </summary> // /// </summary>
[Test] // [Test]
public void TestLoadIarV0_1SameNameCreator() // public void TestLoadIarV0_1SameNameCreator()
{ // {
TestHelpers.InMethod(); // TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure(); // TestHelpers.EnableLogging();
//
UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood"); // UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood");
UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire"); // UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire");
//
m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream); // m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream);
InventoryItemBase foundItem1 // InventoryItemBase foundItem1
= InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name); // = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
//
Assert.That( // Assert.That(
foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()), // foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()),
"Loaded item non-uuid creator doesn't match original"); // "Loaded item non-uuid creator doesn't match original");
Assert.That( // Assert.That(
foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID), // foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID),
"Loaded item uuid creator doesn't match original"); // "Loaded item uuid creator doesn't match original");
Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID), // Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID),
"Loaded item owner doesn't match inventory reciever"); // "Loaded item owner doesn't match inventory reciever");
//
AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); // AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
string xmlData = Utils.BytesToString(asset1.Data); // string xmlData = Utils.BytesToString(asset1.Data);
SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); // SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
//
Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID)); // Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID));
} // }
/// <summary> /// <summary>
/// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where

View File

@ -38,15 +38,15 @@ using OpenSim.Services.Interfaces;
namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
{ {
public class InventoryTransferModule : IInventoryTransferModule, ISharedRegionModule public class InventoryTransferModule : ISharedRegionModule
{ {
private static readonly ILog m_log private static readonly ILog m_log
= LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
/// <summary> /// <summary>
private List<Scene> m_Scenelist = new List<Scene>(); private List<Scene> m_Scenelist = new List<Scene>();
private Dictionary<UUID, Scene> m_AgentRegions = // private Dictionary<UUID, Scene> m_AgentRegions =
new Dictionary<UUID, Scene>(); // new Dictionary<UUID, Scene>();
private IMessageTransferModule m_TransferModule = null; private IMessageTransferModule m_TransferModule = null;
private bool m_Enabled = true; private bool m_Enabled = true;
@ -76,12 +76,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
m_Scenelist.Add(scene); m_Scenelist.Add(scene);
scene.RegisterModuleInterface<IInventoryTransferModule>(this); // scene.RegisterModuleInterface<IInventoryTransferModule>(this);
scene.EventManager.OnNewClient += OnNewClient; scene.EventManager.OnNewClient += OnNewClient;
scene.EventManager.OnClientClosed += ClientLoggedOut; // scene.EventManager.OnClientClosed += ClientLoggedOut;
scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene; // scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene;
} }
public void RegionLoaded(Scene scene) public void RegionLoaded(Scene scene)
@ -96,9 +96,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
m_Scenelist.Clear(); m_Scenelist.Clear();
scene.EventManager.OnNewClient -= OnNewClient; scene.EventManager.OnNewClient -= OnNewClient;
scene.EventManager.OnClientClosed -= ClientLoggedOut; // scene.EventManager.OnClientClosed -= ClientLoggedOut;
scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene; // scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
} }
} }
} }
@ -106,9 +106,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
public void RemoveRegion(Scene scene) public void RemoveRegion(Scene scene)
{ {
scene.EventManager.OnNewClient -= OnNewClient; scene.EventManager.OnNewClient -= OnNewClient;
scene.EventManager.OnClientClosed -= ClientLoggedOut; // scene.EventManager.OnClientClosed -= ClientLoggedOut;
scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene; // scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
m_Scenelist.Remove(scene); m_Scenelist.Remove(scene);
} }
@ -138,10 +138,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
client.OnInstantMessage += OnInstantMessage; client.OnInstantMessage += OnInstantMessage;
} }
protected void OnSetRootAgentScene(UUID id, Scene scene) // protected void OnSetRootAgentScene(UUID id, Scene scene)
{ // {
m_AgentRegions[id] = scene; // m_AgentRegions[id] = scene;
} // }
private Scene FindClientScene(UUID agentId) private Scene FindClientScene(UUID agentId)
{ {
@ -313,6 +313,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
m_TransferModule.SendInstantMessage(im, delegate(bool success) {}); m_TransferModule.SendInstantMessage(im, delegate(bool success) {});
} }
} }
// XXX: This code was placed here to try and accomdate RLV which moves given folders named #RLV/~<name>
// to a folder called name in #RLV. However, this approach may not be ultimately correct - from analysis
// of Firestorm 4.2.2 on sending an InventoryOffered instead of TaskInventoryOffered (as was previously
// done), the viewer itself would appear to move and rename the folder, rather than the simulator doing it here.
else if (im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted) else if (im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted)
{ {
UUID destinationFolderID = UUID.Zero; UUID destinationFolderID = UUID.Zero;
@ -324,6 +329,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
if (destinationFolderID != UUID.Zero) if (destinationFolderID != UUID.Zero)
{ {
InventoryFolderBase destinationFolder = new InventoryFolderBase(destinationFolderID, client.AgentId);
if (destinationFolder == null)
{
m_log.WarnFormat(
"[INVENTORY TRANSFER]: TaskInventoryAccepted message from {0} in {1} specified folder {2} which does not exist",
client.Name, scene.Name, destinationFolderID);
return;
}
IInventoryService invService = scene.InventoryService; IInventoryService invService = scene.InventoryService;
UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip
@ -331,9 +346,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId); InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId);
item = invService.GetItem(item); item = invService.GetItem(item);
InventoryFolderBase folder = null; InventoryFolderBase folder = null;
UUID? previousParentFolderID = null;
if (item != null) // It's an item if (item != null) // It's an item
{ {
previousParentFolderID = item.Folder;
item.Folder = destinationFolderID; item.Folder = destinationFolderID;
invService.DeleteItems(item.Owner, new List<UUID>() { item.ID }); invService.DeleteItems(item.Owner, new List<UUID>() { item.ID });
@ -346,10 +363,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
if (folder != null) // It's a folder if (folder != null) // It's a folder
{ {
previousParentFolderID = folder.ParentID;
folder.ParentID = destinationFolderID; folder.ParentID = destinationFolderID;
invService.MoveFolder(folder); invService.MoveFolder(folder);
} }
} }
// Tell client about updates to original parent and new parent (this should probably be factored with existing move item/folder code).
if (previousParentFolderID != null)
{
InventoryFolderBase previousParentFolder
= new InventoryFolderBase((UUID)previousParentFolderID, client.AgentId);
previousParentFolder = invService.GetFolder(previousParentFolder);
scene.SendInventoryUpdate(client, previousParentFolder, true, true);
scene.SendInventoryUpdate(client, destinationFolder, true, true);
}
} }
} }
else if ( else if (
@ -370,9 +399,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId); InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId);
item = invService.GetItem(item); item = invService.GetItem(item);
InventoryFolderBase folder = null; InventoryFolderBase folder = null;
UUID? previousParentFolderID = null;
if (item != null && trashFolder != null) if (item != null && trashFolder != null)
{ {
previousParentFolderID = item.Folder;
item.Folder = trashFolder.ID; item.Folder = trashFolder.ID;
// Diva comment: can't we just update this item??? // Diva comment: can't we just update this item???
@ -388,6 +419,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
if (folder != null & trashFolder != null) if (folder != null & trashFolder != null)
{ {
previousParentFolderID = folder.ParentID;
folder.ParentID = trashFolder.ID; folder.ParentID = trashFolder.ID;
invService.MoveFolder(folder); invService.MoveFolder(folder);
client.SendBulkUpdateInventory(folder); client.SendBulkUpdateInventory(folder);
@ -408,6 +440,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
client.SendAgentAlertMessage("Unable to delete "+ client.SendAgentAlertMessage("Unable to delete "+
"received inventory" + reason, false); "received inventory" + reason, false);
} }
// Tell client about updates to original parent and new parent (this should probably be factored with existing move item/folder code).
else if (previousParentFolderID != null)
{
InventoryFolderBase previousParentFolder
= new InventoryFolderBase((UUID)previousParentFolderID, client.AgentId);
previousParentFolder = invService.GetFolder(previousParentFolder);
scene.SendInventoryUpdate(client, previousParentFolder, true, true);
scene.SendInventoryUpdate(client, trashFolder, true, true);
}
if (im.dialog == (byte)InstantMessageDialog.InventoryDeclined) if (im.dialog == (byte)InstantMessageDialog.InventoryDeclined)
{ {
@ -426,69 +468,69 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
} }
} }
public bool NeedSceneCacheClear(UUID agentID, Scene scene) // public bool NeedSceneCacheClear(UUID agentID, Scene scene)
{ // {
if (!m_AgentRegions.ContainsKey(agentID)) // if (!m_AgentRegions.ContainsKey(agentID))
{ // {
// Since we can get here two ways, we need to scan // // Since we can get here two ways, we need to scan
// the scenes here. This is somewhat more expensive // // the scenes here. This is somewhat more expensive
// but helps avoid a nasty bug // // but helps avoid a nasty bug
// // //
//
foreach (Scene s in m_Scenelist) // foreach (Scene s in m_Scenelist)
{ // {
ScenePresence presence; // ScenePresence presence;
//
if (s.TryGetScenePresence(agentID, out presence)) // if (s.TryGetScenePresence(agentID, out presence))
{ // {
// If the agent is in this scene, then we // // If the agent is in this scene, then we
// are being called twice in a single // // are being called twice in a single
// teleport. This is wasteful of cycles // // teleport. This is wasteful of cycles
// but harmless due to this 2nd level check // // but harmless due to this 2nd level check
// // //
// If the agent is found in another scene // // If the agent is found in another scene
// then the list wasn't current // // then the list wasn't current
// // //
// If the agent is totally unknown, then what // // If the agent is totally unknown, then what
// are we even doing here?? // // are we even doing here??
// // //
if (s == scene) // if (s == scene)
{ // {
//m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName); // //m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName);
return true; // return true;
} // }
else // else
{ // {
//m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName); // //m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName);
return false; // return false;
} // }
} // }
} // }
//m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName); // //m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName);
return true; // return true;
} // }
//
// The agent is left in current Scene, so we must be // // The agent is left in current Scene, so we must be
// going to another instance // // going to another instance
// // //
if (m_AgentRegions[agentID] == scene) // if (m_AgentRegions[agentID] == scene)
{ // {
//m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName); // //m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName);
m_AgentRegions.Remove(agentID); // m_AgentRegions.Remove(agentID);
return true; // return true;
} // }
//
// Another region has claimed the agent // // Another region has claimed the agent
// // //
//m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName); // //m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName);
return false; // return false;
} // }
//
public void ClientLoggedOut(UUID agentID, Scene scene) // public void ClientLoggedOut(UUID agentID, Scene scene)
{ // {
if (m_AgentRegions.ContainsKey(agentID)) // if (m_AgentRegions.ContainsKey(agentID))
m_AgentRegions.Remove(agentID); // m_AgentRegions.Remove(agentID);
} // }
/// <summary> /// <summary>
/// ///

View File

@ -186,7 +186,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
client.FirstName+" "+client.LastName, targetid, client.FirstName+" "+client.LastName, targetid,
(byte)InstantMessageDialog.RequestTeleport, false, (byte)InstantMessageDialog.RequestTeleport, false,
message, sessionID, false, presence.AbsolutePosition, message, sessionID, false, presence.AbsolutePosition,
new Byte[0]); new Byte[0], true);
m.RegionID = client.Scene.RegionInfo.RegionID.Guid; m.RegionID = client.Scene.RegionInfo.RegionID.Guid;
m_log.DebugFormat("[HG LURE MODULE]: RequestTeleport sessionID={0}, regionID={1}, message={2}", m.imSessionID, m.RegionID, m.message); m_log.DebugFormat("[HG LURE MODULE]: RequestTeleport sessionID={0}, regionID={1}, message={2}", m.imSessionID, m.RegionID, m.message);

View File

@ -173,7 +173,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
client.FirstName+" "+client.LastName, targetid, client.FirstName+" "+client.LastName, targetid,
(byte)InstantMessageDialog.GodLikeRequestTeleport, false, (byte)InstantMessageDialog.GodLikeRequestTeleport, false,
message, dest, false, presence.AbsolutePosition, message, dest, false, presence.AbsolutePosition,
new Byte[0]); new Byte[0], true);
} }
else else
{ {
@ -181,7 +181,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
client.FirstName+" "+client.LastName, targetid, client.FirstName+" "+client.LastName, targetid,
(byte)InstantMessageDialog.RequestTeleport, false, (byte)InstantMessageDialog.RequestTeleport, false,
message, dest, false, presence.AbsolutePosition, message, dest, false, presence.AbsolutePosition,
new Byte[0]); new Byte[0], true);
} }
if (m_TransferModule != null) if (m_TransferModule != null)

View File

@ -327,6 +327,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
return; return;
} }
// Validate assorted conditions
string reason = string.Empty;
if (!ValidateGenericConditions(sp, reg, finalDestination, teleportFlags, out reason))
{
sp.ControllingClient.SendTeleportFailed(reason);
return;
}
// //
// This is it // This is it
// //
@ -358,6 +366,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
} }
} }
// Nothing to validate here
protected virtual bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason)
{
reason = String.Empty;
return true;
}
/// <summary> /// <summary>
/// Determines whether this instance is within the max transfer distance. /// Determines whether this instance is within the max transfer distance.
/// </summary> /// </summary>
@ -473,10 +488,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// both regions // both regions
if (sp.ParentID != (uint)0) if (sp.ParentID != (uint)0)
sp.StandUp(); sp.StandUp();
else if (sp.Flying) else if (sp.Flying)
teleportFlags |= (uint)TeleportFlags.IsFlying; teleportFlags |= (uint)TeleportFlags.IsFlying;
// At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to
// the viewer. However, it might mean that the viewer does not see the black teleport screen (untested).
sp.ControllingClient.SendTeleportStart(teleportFlags); sp.ControllingClient.SendTeleportStart(teleportFlags);
// the avatar.Close below will clear the child region list. We need this below for (possibly) // the avatar.Close below will clear the child region list. We need this below for (possibly)
@ -552,8 +568,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// So let's wait // So let's wait
Thread.Sleep(200); Thread.Sleep(200);
// At least on LL 3.3.4 for teleports between different regions on the same simulator this appears
// unnecessary - teleport will succeed and SEED caps will be requested without it (though possibly
// only on TeleportFinish). This is untested for region teleport between different simulators
// though this probably also works.
m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath);
} }
else else
{ {
@ -574,7 +593,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
//sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent...");
if (!UpdateAgent(reg, finalDestination, agent)) if (!UpdateAgent(reg, finalDestination, agent, sp))
{ {
// Region doesn't take it // Region doesn't take it
m_log.WarnFormat( m_log.WarnFormat(
@ -650,7 +669,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// an agent cannot teleport back to this region if it has teleported away. // an agent cannot teleport back to this region if it has teleported away.
Thread.Sleep(3000); Thread.Sleep(3000);
sp.Scene.IncomingCloseAgent(sp.UUID); sp.Scene.IncomingCloseAgent(sp.UUID, false);
} }
else else
{ {
@ -658,13 +677,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
sp.Reset(); sp.Reset();
} }
// REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! // Commented pending deletion since this method no longer appears to do anything at all
if (sp.Scene.NeedSceneCacheClear(sp.UUID)) // // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
{ // if (sp.Scene.NeedSceneCacheClear(sp.UUID))
m_log.DebugFormat( // {
"[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed", // m_log.DebugFormat(
sp.UUID); // "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed",
} // sp.UUID);
// }
m_entityTransferStateMachine.ResetFromTransit(sp.UUID); m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
} }
@ -701,7 +721,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
return success; return success;
} }
protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent) protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent, ScenePresence sp)
{ {
return Scene.SimulationService.UpdateAgent(finalDestination, agent); return Scene.SimulationService.UpdateAgent(finalDestination, agent);
} }
@ -1013,6 +1033,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
Scene initiatingScene) Scene initiatingScene)
{ {
Thread.Sleep(10000); Thread.Sleep(10000);
IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>(); IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>();
if (im != null) if (im != null)
{ {
@ -1025,11 +1046,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
(uint)(int)position.X, (uint)(int)position.X,
(uint)(int)position.Y, (uint)(int)position.Y,
(uint)(int)position.Z); (uint)(int)position.Z);
GridInstantMessage m = new GridInstantMessage(initiatingScene, UUID.Zero,
"Region", agent.UUID, GridInstantMessage m
(byte)InstantMessageDialog.GodLikeRequestTeleport, false, = new GridInstantMessage(
"", gotoLocation, false, new Vector3(127, 0, 0), initiatingScene,
new Byte[0]); UUID.Zero,
"Region",
agent.UUID,
(byte)InstantMessageDialog.GodLikeRequestTeleport,
false,
"",
gotoLocation,
false,
new Vector3(127, 0, 0),
new Byte[0],
false);
im.SendInstantMessage(m, delegate(bool success) im.SendInstantMessage(m, delegate(bool success)
{ {
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Client Initiating Teleport sending IM success = {0}", success); m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Client Initiating Teleport sending IM success = {0}", success);
@ -1191,11 +1223,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// the user may change their profile information in other region, // the user may change their profile information in other region,
// so the userinfo in UserProfileCache is not reliable any more, delete it // so the userinfo in UserProfileCache is not reliable any more, delete it
// REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
if (agent.Scene.NeedSceneCacheClear(agent.UUID)) // if (agent.Scene.NeedSceneCacheClear(agent.UUID))
{ // {
m_log.DebugFormat( // m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID); // "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID);
} // }
//m_log.Debug("AFTER CROSS"); //m_log.Debug("AFTER CROSS");
//Scene.DumpChildrenSeeds(UUID); //Scene.DumpChildrenSeeds(UUID);

View File

@ -54,6 +54,59 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
private GatekeeperServiceConnector m_GatekeeperConnector; private GatekeeperServiceConnector m_GatekeeperConnector;
protected bool m_RestrictAppearanceAbroad;
protected string m_AccountName;
protected List<AvatarAppearance> m_ExportedAppearances;
protected List<AvatarAttachment> m_Attachs;
protected List<AvatarAppearance> ExportedAppearance
{
get
{
if (m_ExportedAppearances != null)
return m_ExportedAppearances;
m_ExportedAppearances = new List<AvatarAppearance>();
m_Attachs = new List<AvatarAttachment>();
string[] names = m_AccountName.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string name in names)
{
string[] parts = name.Trim().Split();
if (parts.Length != 2)
{
m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: Wrong user account name format {0}. Specify 'First Last'", name);
return null;
}
UserAccount account = Scene.UserAccountService.GetUserAccount(UUID.Zero, parts[0], parts[1]);
if (account == null)
{
m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: Unknown account {0}", m_AccountName);
return null;
}
AvatarAppearance a = Scene.AvatarService.GetAppearance(account.PrincipalID);
if (a != null)
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Successfully retrieved appearance for {0}", name);
foreach (AvatarAttachment att in a.GetAttachments())
{
InventoryItemBase item = new InventoryItemBase(att.ItemID, account.PrincipalID);
item = Scene.InventoryService.GetItem(item);
if (item != null)
a.SetAttachment(att.AttachPoint, att.ItemID, item.AssetID);
else
m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: Unable to retrieve item {0} from inventory {1}", att.ItemID, name);
}
m_ExportedAppearances.Add(a);
m_Attachs.AddRange(a.GetAttachments());
}
return m_ExportedAppearances;
}
}
#region ISharedRegionModule #region ISharedRegionModule
public override string Name public override string Name
@ -72,8 +125,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
{ {
IConfig transferConfig = source.Configs["EntityTransfer"]; IConfig transferConfig = source.Configs["EntityTransfer"];
if (transferConfig != null) if (transferConfig != null)
{
m_levelHGTeleport = transferConfig.GetInt("LevelHGTeleport", 0); m_levelHGTeleport = transferConfig.GetInt("LevelHGTeleport", 0);
m_RestrictAppearanceAbroad = transferConfig.GetBoolean("RestrictAppearanceAbroad", false);
if (m_RestrictAppearanceAbroad)
{
m_AccountName = transferConfig.GetString("AccountForAppearance", string.Empty);
if (m_AccountName == string.Empty)
m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: RestrictAppearanceAbroad is on, but no account has been given for avatar appearance!");
}
}
InitialiseCommon(source); InitialiseCommon(source);
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: {0} enabled.", Name); m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: {0} enabled.", Name);
} }
@ -85,7 +148,36 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
base.AddRegion(scene); base.AddRegion(scene);
if (m_Enabled) if (m_Enabled)
{
scene.RegisterModuleInterface<IUserAgentVerificationModule>(this); scene.RegisterModuleInterface<IUserAgentVerificationModule>(this);
scene.EventManager.OnIncomingSceneObject += OnIncomingSceneObject;
}
}
void OnIncomingSceneObject(SceneObjectGroup so)
{
if (!so.IsAttachment)
return;
if (so.Scene.UserManagementModule.IsLocalGridUser(so.AttachedAvatar))
return;
// foreign user
AgentCircuitData aCircuit = so.Scene.AuthenticateHandler.GetAgentCircuitData(so.AttachedAvatar);
if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0)
{
if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI"))
{
string url = aCircuit.ServiceURLs["AssetServerURI"].ToString();
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Incoming attachement {0} for HG user {1} with asset server {2}", so.Name, so.AttachedAvatar, url);
Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
HGUuidGatherer uuidGatherer = new HGUuidGatherer(so.Scene.AssetService, url);
uuidGatherer.GatherAssetUuids(so, ids);
foreach (KeyValuePair<UUID, AssetType> kvp in ids)
uuidGatherer.FetchAsset(kvp.Key);
}
}
} }
protected override void OnNewClient(IClientAPI client) protected override void OnNewClient(IClientAPI client)
@ -120,7 +212,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID); int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID);
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags); m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags);
if ((flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
{ {
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region {0} is hyperlink", region.RegionID); m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region {0} is hyperlink", region.RegionID);
GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID); GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID);
@ -140,7 +232,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
return true; return true;
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID); int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
return true; return true;
return false; return false;
@ -153,6 +245,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
{ {
// Log them out of this grid // Log them out of this grid
Scene.PresenceService.LogoutAgent(sp.ControllingClient.SessionId); Scene.PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
string userId = Scene.UserManagementModule.GetUserUUI(sp.UUID);
Scene.GridUserService.LoggedOut(userId, UUID.Zero, Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat);
} }
} }
@ -162,11 +256,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
reason = string.Empty; reason = string.Empty;
logout = false; logout = false;
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID); int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
{ {
// this user is going to another grid // this user is going to another grid
// check if HyperGrid teleport is allowed, based on user level // for local users, check if HyperGrid teleport is allowed, based on user level
if (sp.UserLevel < m_levelHGTeleport) if (Scene.UserManagementModule.IsLocalGridUser(sp.UUID) && sp.UserLevel < m_levelHGTeleport)
{ {
m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: Unable to HG teleport agent due to insufficient UserLevel."); m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: Unable to HG teleport agent due to insufficient UserLevel.");
reason = "Hypergrid teleport not allowed"; reason = "Hypergrid teleport not allowed";
@ -200,6 +294,124 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
TeleportHome(id, client); TeleportHome(id, client);
} }
protected override bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason)
{
reason = "Please wear your grid's allowed appearance before teleporting to another grid";
if (!m_RestrictAppearanceAbroad)
return true;
// The rest is only needed for controlling appearance
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
{
// this user is going to another grid
if (Scene.UserManagementModule.IsLocalGridUser(sp.UUID))
{
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: RestrictAppearanceAbroad is ON. Checking generic appearance");
// Check wearables
for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++)
{
for (int j = 0; j < sp.Appearance.Wearables[i].Count; j++)
{
if (sp.Appearance.Wearables[i] == null)
continue;
bool found = false;
foreach (AvatarAppearance a in ExportedAppearance)
if (a.Wearables[i] != null)
{
found = true;
break;
}
if (!found)
{
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Wearable not allowed to go outside {0}", i);
return false;
}
found = false;
foreach (AvatarAppearance a in ExportedAppearance)
if (sp.Appearance.Wearables[i][j].AssetID == a.Wearables[i][j].AssetID)
{
found = true;
break;
}
if (!found)
{
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Wearable not allowed to go outside {0}", i);
return false;
}
}
}
// Check attachments
foreach (AvatarAttachment att in sp.Appearance.GetAttachments())
{
bool found = false;
foreach (AvatarAttachment att2 in m_Attachs)
{
if (att2.AssetID == att.AssetID)
{
found = true;
break;
}
}
if (!found)
{
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Attachment not allowed to go outside {0}", att.AttachPoint);
return false;
}
}
}
}
reason = string.Empty;
return true;
}
//protected override bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agentData, ScenePresence sp)
//{
// int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
// if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
// {
// // this user is going to another grid
// if (m_RestrictAppearanceAbroad && Scene.UserManagementModule.IsLocalGridUser(agentData.AgentID))
// {
// // We need to strip the agent off its appearance
// m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: RestrictAppearanceAbroad is ON. Sending generic appearance");
// // Delete existing npc attachments
// Scene.AttachmentsModule.DeleteAttachmentsFromScene(sp, false);
// // XXX: We can't just use IAvatarFactoryModule.SetAppearance() yet since it doesn't transfer attachments
// AvatarAppearance newAppearance = new AvatarAppearance(ExportedAppearance, true);
// sp.Appearance = newAppearance;
// // Rez needed npc attachments
// Scene.AttachmentsModule.RezAttachments(sp);
// IAvatarFactoryModule module = Scene.RequestModuleInterface<IAvatarFactoryModule>();
// //module.SendAppearance(sp.UUID);
// module.RequestRebake(sp, false);
// Scene.AttachmentsModule.CopyAttachments(sp, agentData);
// agentData.Appearance = sp.Appearance;
// }
// }
// foreach (AvatarAttachment a in agentData.Appearance.GetAttachments())
// m_log.DebugFormat("[XXX]: {0}-{1}", a.ItemID, a.AssetID);
// return base.UpdateAgent(reg, finalDestination, agentData, sp);
//}
public override bool TeleportHome(UUID id, IClientAPI client) public override bool TeleportHome(UUID id, IClientAPI client)
{ {
m_log.DebugFormat( m_log.DebugFormat(

View File

@ -71,19 +71,19 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
#region Internal functions #region Internal functions
public AssetBase FetchAsset(string url, UUID assetID) public AssetMetadata FetchMetadata(string url, UUID assetID)
{ {
if (!url.EndsWith("/") && !url.EndsWith("=")) if (!url.EndsWith("/") && !url.EndsWith("="))
url = url + "/"; url = url + "/";
AssetBase asset = m_scene.AssetService.Get(url + assetID.ToString()); AssetMetadata meta = m_scene.AssetService.GetMetadata(url + assetID.ToString());
if (asset != null) if (meta != null)
{ m_log.DebugFormat("[HG ASSET MAPPER]: Fetched metadata for asset {0} of type {1} from {2} ", assetID, meta.Type, url);
m_log.DebugFormat("[HG ASSET MAPPER]: Copied asset {0} from {1} to local asset server. ", asset.ID, url); else
return asset; m_log.DebugFormat("[HG ASSET MAPPER]: Unable to fetched metadata for asset {0} from {1} ", assetID, url);
}
return null; return meta;
} }
public bool PostAsset(string url, AssetBase asset) public bool PostAsset(string url, AssetBase asset)
@ -93,6 +93,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
if (!url.EndsWith("/") && !url.EndsWith("=")) if (!url.EndsWith("/") && !url.EndsWith("="))
url = url + "/"; url = url + "/";
bool success = true;
// See long comment in AssetCache.AddAsset // See long comment in AssetCache.AddAsset
if (!asset.Temporary || asset.Local) if (!asset.Temporary || asset.Local)
{ {
@ -103,14 +104,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
// not having a global naming infrastructure // not having a global naming infrastructure
AssetBase asset1 = new AssetBase(asset.FullID, asset.Name, asset.Type, asset.Metadata.CreatorID); AssetBase asset1 = new AssetBase(asset.FullID, asset.Name, asset.Type, asset.Metadata.CreatorID);
Copy(asset, asset1); Copy(asset, asset1);
try
{
asset1.ID = url + asset.ID; asset1.ID = url + asset.ID;
}
catch
{
m_log.Warn("[HG ASSET MAPPER]: Oops.");
}
AdjustIdentifiers(asset1.Metadata); AdjustIdentifiers(asset1.Metadata);
if (asset1.Metadata.Type == (sbyte)AssetType.Object) if (asset1.Metadata.Type == (sbyte)AssetType.Object)
@ -118,10 +112,16 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
else else
asset1.Data = asset.Data; asset1.Data = asset.Data;
m_scene.AssetService.Store(asset1); string id = m_scene.AssetService.Store(asset1);
if (id == string.Empty)
{
m_log.DebugFormat("[HG ASSET MAPPER]: Asset server {0} did not accept {1}", url, asset.ID);
success = false;
}
else
m_log.DebugFormat("[HG ASSET MAPPER]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url); m_log.DebugFormat("[HG ASSET MAPPER]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url);
} }
return true; return success;
} }
else else
m_log.Warn("[HG ASSET MAPPER]: Tried to post asset to remote server, but asset not in local cache."); m_log.Warn("[HG ASSET MAPPER]: Tried to post asset to remote server, but asset not in local cache.");
@ -222,28 +222,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
public void Get(UUID assetID, UUID ownerID, string userAssetURL) public void Get(UUID assetID, UUID ownerID, string userAssetURL)
{ {
// Get the item from the remote asset server onto the local AssetCache // Get the item from the remote asset server onto the local AssetService
// and place an entry in m_assetMap
m_log.Debug("[HG ASSET MAPPER]: Fetching object " + assetID + " from asset server " + userAssetURL); AssetMetadata meta = FetchMetadata(userAssetURL, assetID);
AssetBase asset = FetchAsset(userAssetURL, assetID); if (meta == null)
return;
if (asset != null) // The act of gathering UUIDs downloads the assets from the remote server
{
// OK, now fetch the inside.
Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, userAssetURL); HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL);
uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids); uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids);
if (ids.ContainsKey(assetID))
ids.Remove(assetID);
foreach (UUID uuid in ids.Keys)
FetchAsset(userAssetURL, uuid);
m_log.DebugFormat("[HG ASSET MAPPER]: Successfully fetched asset {0} from asset server {1}", asset.ID, userAssetURL);
}
else
m_log.Warn("[HG ASSET MAPPER]: Could not fetch asset from remote asset server " + userAssetURL);
} }
@ -257,18 +246,22 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
if (asset != null) if (asset != null)
{ {
Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, string.Empty); HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, string.Empty);
uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids); uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids);
bool success = false;
foreach (UUID uuid in ids.Keys) foreach (UUID uuid in ids.Keys)
{ {
asset = m_scene.AssetService.Get(uuid.ToString()); asset = m_scene.AssetService.Get(uuid.ToString());
if (asset == null) if (asset == null)
m_log.DebugFormat("[HG ASSET MAPPER]: Could not find asset {0}", uuid); m_log.DebugFormat("[HG ASSET MAPPER]: Could not find asset {0}", uuid);
else else
PostAsset(userAssetURL, asset); success = PostAsset(userAssetURL, asset);
} }
// maybe all pieces got there... // maybe all pieces got there...
if (!success)
m_log.DebugFormat("[HG ASSET MAPPER]: Problems posting item {0} to asset server {1}", assetID, userAssetURL);
else
m_log.DebugFormat("[HG ASSET MAPPER]: Successfully posted item {0} to asset server {1}", assetID, userAssetURL); m_log.DebugFormat("[HG ASSET MAPPER]: Successfully posted item {0} to asset server {1}", assetID, userAssetURL);
} }

View File

@ -92,7 +92,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
m_HomeURI = thisModuleConfig.GetString("HomeURI", m_HomeURI); m_HomeURI = thisModuleConfig.GetString("HomeURI", m_HomeURI);
m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true); m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true);
m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", string.Empty); m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", string.Empty);
m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", false); m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", true);
} }
else else
m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!"); m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!");
@ -263,9 +263,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
//} //}
// OK, we're done fetching. Pass it up to the default RezObject // OK, we're done fetching. Pass it up to the default RezObject
return base.RezObject(remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, SceneObjectGroup sog = base.RezObject(remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection,
RezSelected, RemoveItem, fromTaskID, attachment); RezSelected, RemoveItem, fromTaskID, attachment);
if (sog == null)
remoteClient.SendAgentAlertMessage("Unable to rez: problem accessing inventory or locating assets", false);
return sog;
} }
public override void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver) public override void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver)
@ -308,6 +313,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
protected override InventoryItemBase GetItem(UUID agentID, UUID itemID) protected override InventoryItemBase GetItem(UUID agentID, UUID itemID)
{ {
InventoryItemBase item = base.GetItem(agentID, itemID); InventoryItemBase item = base.GetItem(agentID, itemID);
if (item == null)
return null;
string userAssetServer = string.Empty; string userAssetServer = string.Empty;
if (IsForeignUser(agentID, out userAssetServer)) if (IsForeignUser(agentID, out userAssetServer))
@ -344,6 +351,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
private void ProcessInventoryForArriving(IClientAPI client) private void ProcessInventoryForArriving(IClientAPI client)
{ {
// No-op for now, but we may need to do something for freign users inventory
} }
// //
@ -390,6 +398,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
private void ProcessInventoryForLeaving(IClientAPI client) private void ProcessInventoryForLeaving(IClientAPI client)
{ {
// No-op for now
} }
#endregion #endregion

View File

@ -95,14 +95,14 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
{ {
foreach (IMonitor monitor in m_staticMonitors) foreach (IMonitor monitor in m_staticMonitors)
{ {
m_log.InfoFormat( MainConsole.Instance.OutputFormat(
"[MONITOR MODULE]: {0} reports {1} = {2}", "[MONITOR MODULE]: {0} reports {1} = {2}",
m_scene.RegionInfo.RegionName, monitor.GetFriendlyName(), monitor.GetFriendlyValue()); m_scene.RegionInfo.RegionName, monitor.GetFriendlyName(), monitor.GetFriendlyValue());
} }
foreach (KeyValuePair<string, float> tuple in m_scene.StatsReporter.GetExtraSimStats()) foreach (KeyValuePair<string, float> tuple in m_scene.StatsReporter.GetExtraSimStats())
{ {
m_log.InfoFormat( MainConsole.Instance.OutputFormat(
"[MONITOR MODULE]: {0} reports {1} = {2}", "[MONITOR MODULE]: {0} reports {1} = {2}",
m_scene.RegionInfo.RegionName, tuple.Key, tuple.Value); m_scene.RegionInfo.RegionName, tuple.Key, tuple.Value);
} }

View File

@ -111,6 +111,15 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
Write(String.Format(line, args)); Write(String.Format(line, args));
} }
public void Flush()
{
if (!Enabled) return;
if (m_logFile != null)
{
m_logFile.Flush();
}
}
public void Write(string line) public void Write(string line)
{ {
if (!Enabled) return; if (!Enabled) return;

View File

@ -137,6 +137,9 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
ud.FirstName = words[0]; ud.FirstName = words[0];
ud.LastName = "@" + words[1]; ud.LastName = "@" + words[1];
users.Add(ud); users.Add(ud);
// WARNING! that uriStr is not quite right... it may be missing the / at the end,
// which will cause trouble (duplicate entries on some tables). We should
// get the UUI instead from the UAS. TO BE FIXED.
AddUser(userID, names[0], names[1], uriStr); AddUser(userID, names[0], names[1], uriStr);
m_log.DebugFormat("[USER MANAGEMENT MODULE]: User {0}@{1} found", words[0], words[1]); m_log.DebugFormat("[USER MANAGEMENT MODULE]: User {0}@{1} found", words[0], words[1]);
} }

View File

@ -31,6 +31,7 @@ using System.Reflection;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Framework.Console; using OpenSim.Framework.Console;
using OpenSim.Region.ClientStack.LindenUDP;
using OpenSim.Region.Framework; using OpenSim.Region.Framework;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
@ -429,8 +430,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
public void AddUser(UUID uuid, string first, string last, string homeURL) public void AddUser(UUID uuid, string first, string last, string homeURL)
{ {
// m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL); //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL);
AddUser(uuid, homeURL + ";" + first + " " + last); AddUser(uuid, homeURL + ";" + first + " " + last);
} }
@ -553,8 +553,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
MainConsole.Instance.Output("-----------------------------------------------------------------------------"); MainConsole.Instance.Output("-----------------------------------------------------------------------------");
foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache) foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache)
{ {
MainConsole.Instance.Output(String.Format("{0} {1} {2}", MainConsole.Instance.Output(String.Format("{0} {1} {2} ({3})",
kvp.Key, kvp.Value.FirstName, kvp.Value.LastName)); kvp.Key, kvp.Value.FirstName, kvp.Value.LastName, kvp.Value.HomeURL));
} }
return; return;

View File

@ -15,6 +15,7 @@
<RegionModule id="InventoryAccessModule" type="OpenSim.Region.CoreModules.Framework.InventoryAccess.BasicInventoryAccessModule" /> <RegionModule id="InventoryAccessModule" type="OpenSim.Region.CoreModules.Framework.InventoryAccess.BasicInventoryAccessModule" />
<RegionModule id="HGInventoryAccessModule" type="OpenSim.Region.CoreModules.Framework.InventoryAccess.HGInventoryAccessModule" /> <RegionModule id="HGInventoryAccessModule" type="OpenSim.Region.CoreModules.Framework.InventoryAccess.HGInventoryAccessModule" />
<RegionModule id="LandManagementModule" type="OpenSim.Region.CoreModules.World.Land.LandManagementModule" /> <RegionModule id="LandManagementModule" type="OpenSim.Region.CoreModules.World.Land.LandManagementModule" />
<RegionModule id="DwellModule" type="OpenSim.Region.CoreModules.World.Land.DwellModule" />
<RegionModule id="PrimCountModule" type="OpenSim.Region.CoreModules.World.Land.PrimCountModule" /> <RegionModule id="PrimCountModule" type="OpenSim.Region.CoreModules.World.Land.PrimCountModule" />
<RegionModule id="ExportSerialisationModule" type="OpenSim.Region.CoreModules.World.Serialiser.SerialiserModule" /> <RegionModule id="ExportSerialisationModule" type="OpenSim.Region.CoreModules.World.Serialiser.SerialiserModule" />
<RegionModule id="ArchiverModule" type="OpenSim.Region.CoreModules.World.Archiver.ArchiverModule" /> <RegionModule id="ArchiverModule" type="OpenSim.Region.CoreModules.World.Archiver.ArchiverModule" />

View File

@ -0,0 +1,61 @@
/*
* 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.Drawing;
using OpenSim.Region.Framework.Interfaces;
namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
{
public class DynamicTexture : IDynamicTexture
{
public string InputCommands { get; private set; }
public Uri InputUri { get; private set; }
public string InputParams { get; private set; }
public byte[] Data { get; private set; }
public Size Size { get; private set; }
public bool IsReuseable { get; private set; }
public DynamicTexture(string inputCommands, string inputParams, byte[] data, Size size, bool isReuseable)
{
InputCommands = inputCommands;
InputParams = inputParams;
Data = data;
Size = size;
IsReuseable = isReuseable;
}
public DynamicTexture(Uri inputUri, string inputParams, byte[] data, Size size, bool isReuseable)
{
InputUri = inputUri;
InputParams = inputParams;
Data = data;
Size = size;
IsReuseable = isReuseable;
}
}
}

View File

@ -42,13 +42,29 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
{ {
public class DynamicTextureModule : IRegionModule, IDynamicTextureManager public class DynamicTextureModule : IRegionModule, IDynamicTextureManager
{ {
//private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private const int ALL_SIDES = -1; private const int ALL_SIDES = -1;
public const int DISP_EXPIRE = 1; public const int DISP_EXPIRE = 1;
public const int DISP_TEMP = 2; public const int DISP_TEMP = 2;
/// <summary>
/// If true then where possible dynamic textures are reused.
/// </summary>
public bool ReuseTextures { get; set; }
/// <summary>
/// If false, then textures which have a low data size are not reused when ReuseTextures = true.
/// </summary>
/// <remarks>
/// LL viewers 3.3.4 and before appear to not fully render textures pulled from the viewer cache if those
/// textures have a relatively high pixel surface but a small data size. Typically, this appears to happen
/// if the data size is smaller than the viewer's discard level 2 size estimate. So if this is setting is
/// false, textures smaller than the calculation in IsSizeReuseable are always regenerated rather than reused
/// to work around this problem.</remarks>
public bool ReuseLowDataTextures { get; set; }
private Dictionary<UUID, Scene> RegisteredScenes = new Dictionary<UUID, Scene>(); private Dictionary<UUID, Scene> RegisteredScenes = new Dictionary<UUID, Scene>();
private Dictionary<string, IDynamicTextureRender> RenderPlugins = private Dictionary<string, IDynamicTextureRender> RenderPlugins =
@ -56,6 +72,15 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
private Dictionary<UUID, DynamicTextureUpdater> Updaters = new Dictionary<UUID, DynamicTextureUpdater>(); private Dictionary<UUID, DynamicTextureUpdater> Updaters = new Dictionary<UUID, DynamicTextureUpdater>();
/// <summary>
/// Record dynamic textures that we can reuse for a given data and parameter combination rather than
/// regenerate.
/// </summary>
/// <remarks>
/// Key is string.Format("{0}{1}", data
/// </remarks>
private Cache m_reuseableDynamicTextures;
#region IDynamicTextureManager Members #region IDynamicTextureManager Members
public void RegisterRender(string handleType, IDynamicTextureRender render) public void RegisterRender(string handleType, IDynamicTextureRender render)
@ -69,17 +94,17 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
/// <summary> /// <summary>
/// Called by code which actually renders the dynamic texture to supply texture data. /// Called by code which actually renders the dynamic texture to supply texture data.
/// </summary> /// </summary>
/// <param name="id"></param> /// <param name="updaterId"></param>
/// <param name="data"></param> /// <param name="texture"></param>
public void ReturnData(UUID id, byte[] data) public void ReturnData(UUID updaterId, IDynamicTexture texture)
{ {
DynamicTextureUpdater updater = null; DynamicTextureUpdater updater = null;
lock (Updaters) lock (Updaters)
{ {
if (Updaters.ContainsKey(id)) if (Updaters.ContainsKey(updaterId))
{ {
updater = Updaters[id]; updater = Updaters[updaterId];
} }
} }
@ -88,7 +113,16 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
if (RegisteredScenes.ContainsKey(updater.SimUUID)) if (RegisteredScenes.ContainsKey(updater.SimUUID))
{ {
Scene scene = RegisteredScenes[updater.SimUUID]; Scene scene = RegisteredScenes[updater.SimUUID];
updater.DataReceived(data, scene); UUID newTextureID = updater.DataReceived(texture.Data, scene);
if (ReuseTextures
&& !updater.BlendWithOldTexture
&& texture.IsReuseable
&& (ReuseLowDataTextures || IsDataSizeReuseable(texture)))
{
m_reuseableDynamicTextures.Store(
GenerateReusableTextureKey(texture.InputCommands, texture.InputParams), newTextureID);
}
} }
} }
@ -104,6 +138,27 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
} }
} }
/// <summary>
/// Determines whether the texture is reuseable based on its data size.
/// </summary>
/// <remarks>
/// This is a workaround for a viewer bug where very small data size textures relative to their pixel size
/// are not redisplayed properly when pulled from cache. The calculation here is based on the typical discard
/// level of 2, a 'rate' of 0.125 and 4 components (which makes for a factor of 0.5).
/// </remarks>
/// <returns></returns>
private bool IsDataSizeReuseable(IDynamicTexture texture)
{
// Console.WriteLine("{0} {1}", texture.Size.Width, texture.Size.Height);
int discardLevel2DataThreshold = (int)Math.Ceiling((texture.Size.Width >> 2) * (texture.Size.Height >> 2) * 0.5);
// m_log.DebugFormat(
// "[DYNAMIC TEXTURE MODULE]: Discard level 2 threshold {0}, texture data length {1}",
// discardLevel2DataThreshold, texture.Data.Length);
return discardLevel2DataThreshold < texture.Data.Length;
}
public UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, public UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url,
string extraParams, int updateTimer) string extraParams, int updateTimer)
{ {
@ -167,8 +222,25 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
public UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data, public UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data,
string extraParams, int updateTimer, bool SetBlending, int disp, byte AlphaValue, int face) string extraParams, int updateTimer, bool SetBlending, int disp, byte AlphaValue, int face)
{ {
if (RenderPlugins.ContainsKey(contentType)) if (!RenderPlugins.ContainsKey(contentType))
{ return UUID.Zero;
Scene scene;
RegisteredScenes.TryGetValue(simID, out scene);
if (scene == null)
return UUID.Zero;
SceneObjectPart part = scene.GetSceneObjectPart(primID);
if (part == null)
return UUID.Zero;
// If we want to reuse dynamic textures then we have to ignore any request from the caller to expire
// them.
if (ReuseTextures)
disp = disp & ~DISP_EXPIRE;
DynamicTextureUpdater updater = new DynamicTextureUpdater(); DynamicTextureUpdater updater = new DynamicTextureUpdater();
updater.SimUUID = simID; updater.SimUUID = simID;
updater.PrimID = primID; updater.PrimID = primID;
@ -183,6 +255,28 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
updater.Url = "Local image"; updater.Url = "Local image";
updater.Disp = disp; updater.Disp = disp;
object objReusableTextureUUID = null;
if (ReuseTextures && !updater.BlendWithOldTexture)
{
string reuseableTextureKey = GenerateReusableTextureKey(data, extraParams);
objReusableTextureUUID = m_reuseableDynamicTextures.Get(reuseableTextureKey);
if (objReusableTextureUUID != null)
{
// If something else has removed this temporary asset from the cache, detect and invalidate
// our cached uuid.
if (scene.AssetService.GetMetadata(objReusableTextureUUID.ToString()) == null)
{
m_reuseableDynamicTextures.Invalidate(reuseableTextureKey);
objReusableTextureUUID = null;
}
}
}
// We cannot reuse a dynamic texture if the data is going to be blended with something already there.
if (objReusableTextureUUID == null)
{
lock (Updaters) lock (Updaters)
{ {
if (!Updaters.ContainsKey(updater.UpdaterID)) if (!Updaters.ContainsKey(updater.UpdaterID))
@ -191,11 +285,29 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
} }
} }
// m_log.DebugFormat(
// "[DYNAMIC TEXTURE MODULE]: Requesting generation of new dynamic texture for {0} in {1}",
// part.Name, part.ParentGroup.Scene.Name);
RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams); RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams);
}
else
{
// m_log.DebugFormat(
// "[DYNAMIC TEXTURE MODULE]: Reusing cached texture {0} for {1} in {2}",
// objReusableTextureUUID, part.Name, part.ParentGroup.Scene.Name);
// No need to add to updaters as the texture is always the same. Not that this functionality
// apppears to be implemented anyway.
updater.UpdatePart(part, (UUID)objReusableTextureUUID);
}
return updater.UpdaterID; return updater.UpdaterID;
} }
return UUID.Zero; private string GenerateReusableTextureKey(string data, string extraParams)
{
return string.Format("{0}{1}", data, extraParams);
} }
public void GetDrawStringSize(string contentType, string text, string fontName, int fontSize, public void GetDrawStringSize(string contentType, string text, string fontName, int fontSize,
@ -215,6 +327,13 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
public void Initialise(Scene scene, IConfigSource config) public void Initialise(Scene scene, IConfigSource config)
{ {
IConfig texturesConfig = config.Configs["Textures"];
if (texturesConfig != null)
{
ReuseTextures = texturesConfig.GetBoolean("ReuseDynamicTextures", false);
ReuseLowDataTextures = texturesConfig.GetBoolean("ReuseDynamicLowDataTextures", false);
}
if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID)) if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID))
{ {
RegisteredScenes.Add(scene.RegionInfo.RegionID, scene); RegisteredScenes.Add(scene.RegionInfo.RegionID, scene);
@ -224,6 +343,11 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
public void PostInitialise() public void PostInitialise()
{ {
if (ReuseTextures)
{
m_reuseableDynamicTextures = new Cache(CacheMedium.Memory, CacheStrategy.Conservative);
m_reuseableDynamicTextures.DefaultTTL = new TimeSpan(24, 0, 0);
}
} }
public void Close() public void Close()
@ -268,10 +392,61 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
BodyData = null; BodyData = null;
} }
/// <summary>
/// Update the given part with the new texture.
/// </summary>
/// <returns>
/// The old texture UUID.
/// </returns>
public UUID UpdatePart(SceneObjectPart part, UUID textureID)
{
UUID oldID;
lock (part)
{
// mostly keep the values from before
Primitive.TextureEntry tmptex = part.Shape.Textures;
// FIXME: Need to return the appropriate ID if only a single face is replaced.
oldID = tmptex.DefaultTexture.TextureID;
if (Face == ALL_SIDES)
{
oldID = tmptex.DefaultTexture.TextureID;
tmptex.DefaultTexture.TextureID = textureID;
}
else
{
try
{
Primitive.TextureEntryFace texface = tmptex.CreateFace((uint)Face);
texface.TextureID = textureID;
tmptex.FaceTextures[Face] = texface;
}
catch (Exception)
{
tmptex.DefaultTexture.TextureID = textureID;
}
}
// I'm pretty sure we always want to force this to true
// I'm pretty sure noone whats to set fullbright true if it wasn't true before.
// tmptex.DefaultTexture.Fullbright = true;
part.UpdateTextureEntry(tmptex.GetBytes());
}
return oldID;
}
/// <summary> /// <summary>
/// Called once new texture data has been received for this updater. /// Called once new texture data has been received for this updater.
/// </summary> /// </summary>
public void DataReceived(byte[] data, Scene scene) /// <param name="data"></param>
/// <param name="scene"></param>
/// <param name="isReuseable">True if the data given is reuseable.</param>
/// <returns>The asset UUID given to the incoming data.</returns>
public UUID DataReceived(byte[] data, Scene scene)
{ {
SceneObjectPart part = scene.GetSceneObjectPart(PrimID); SceneObjectPart part = scene.GetSceneObjectPart(PrimID);
@ -281,7 +456,8 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
String.Format("DynamicTextureModule: Error preparing image using URL {0}", Url); String.Format("DynamicTextureModule: Error preparing image using URL {0}", Url);
scene.SimChat(Utils.StringToBytes(msg), ChatTypeEnum.Say, scene.SimChat(Utils.StringToBytes(msg), ChatTypeEnum.Say,
0, part.ParentGroup.RootPart.AbsolutePosition, part.Name, part.UUID, false); 0, part.ParentGroup.RootPart.AbsolutePosition, part.Name, part.UUID, false);
return;
return UUID.Zero;
} }
byte[] assetData = null; byte[] assetData = null;
@ -319,56 +495,29 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
IJ2KDecoder cacheLayerDecode = scene.RequestModuleInterface<IJ2KDecoder>(); IJ2KDecoder cacheLayerDecode = scene.RequestModuleInterface<IJ2KDecoder>();
if (cacheLayerDecode != null) if (cacheLayerDecode != null)
{ {
cacheLayerDecode.Decode(asset.FullID, asset.Data); if (!cacheLayerDecode.Decode(asset.FullID, asset.Data))
cacheLayerDecode = null; m_log.WarnFormat(
"[DYNAMIC TEXTURE MODULE]: Decoding of dynamically generated asset {0} for {1} in {2} failed",
asset.ID, part.Name, part.ParentGroup.Scene.Name);
} }
UUID oldID = UUID.Zero; UUID oldID = UpdatePart(part, asset.FullID);
lock (part)
{
// mostly keep the values from before
Primitive.TextureEntry tmptex = part.Shape.Textures;
// remove the old asset from the cache
oldID = tmptex.DefaultTexture.TextureID;
if (Face == ALL_SIDES)
{
tmptex.DefaultTexture.TextureID = asset.FullID;
}
else
{
try
{
Primitive.TextureEntryFace texface = tmptex.CreateFace((uint)Face);
texface.TextureID = asset.FullID;
tmptex.FaceTextures[Face] = texface;
}
catch (Exception)
{
tmptex.DefaultTexture.TextureID = asset.FullID;
}
}
// I'm pretty sure we always want to force this to true
// I'm pretty sure noone whats to set fullbright true if it wasn't true before.
// tmptex.DefaultTexture.Fullbright = true;
part.UpdateTextureEntry(tmptex.GetBytes());
}
if (oldID != UUID.Zero && ((Disp & DISP_EXPIRE) != 0)) if (oldID != UUID.Zero && ((Disp & DISP_EXPIRE) != 0))
{ {
if (oldAsset == null) oldAsset = scene.AssetService.Get(oldID.ToString()); if (oldAsset == null)
oldAsset = scene.AssetService.Get(oldID.ToString());
if (oldAsset != null) if (oldAsset != null)
{ {
if (oldAsset.Temporary == true) if (oldAsset.Temporary)
{ {
scene.AssetService.Delete(oldID.ToString()); scene.AssetService.Delete(oldID.ToString());
} }
} }
} }
return asset.FullID;
} }
private byte[] BlendTextures(byte[] frontImage, byte[] backImage, bool setNewAlpha, byte newAlpha) private byte[] BlendTextures(byte[] frontImage, byte[] backImage, bool setNewAlpha, byte newAlpha)

View File

@ -58,6 +58,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
public string body; public string body;
public int responseCode; public int responseCode;
public string responseBody; public string responseBody;
public string responseType = "text/plain";
//public ManualResetEvent ev; //public ManualResetEvent ev;
public bool requestDone; public bool requestDone;
public int startTime; public int startTime;
@ -270,6 +271,22 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
} }
} }
public void HttpContentType(UUID request, string type)
{
lock (m_UrlMap)
{
if (m_RequestMap.ContainsKey(request))
{
UrlData urlData = m_RequestMap[request];
urlData.requests[request].responseType = type;
}
else
{
m_log.Info("[HttpRequestHandler] There is no http-in request with id " + request.ToString());
}
}
}
public void HttpResponse(UUID request, int status, string body) public void HttpResponse(UUID request, int status, string body)
{ {
lock (m_RequestMap) lock (m_RequestMap)

View File

@ -32,6 +32,7 @@ using System.Net;
using Nini.Config; using Nini.Config;
using OpenMetaverse; using OpenMetaverse;
using OpenMetaverse.Imaging; using OpenMetaverse.Imaging;
using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using log4net; using log4net;
@ -67,12 +68,18 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
return true; return true;
} }
public byte[] ConvertUrl(string url, string extraParams) // public bool AlwaysIdenticalConversion(string bodyData, string extraParams)
// {
// // We don't support conversion of body data.
// return false;
// }
public IDynamicTexture ConvertUrl(string url, string extraParams)
{ {
return null; return null;
} }
public byte[] ConvertStream(Stream data, string extraParams) public IDynamicTexture ConvertData(string bodyData, string extraParams)
{ {
return null; return null;
} }
@ -165,11 +172,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
private void HttpRequestReturn(IAsyncResult result) private void HttpRequestReturn(IAsyncResult result)
{ {
RequestState state = (RequestState) result.AsyncState; RequestState state = (RequestState) result.AsyncState;
WebRequest request = (WebRequest) state.Request; WebRequest request = (WebRequest) state.Request;
Stream stream = null; Stream stream = null;
byte[] imageJ2000 = new byte[0]; byte[] imageJ2000 = new byte[0];
Size newSize = new Size(0, 0);
try try
{ {
@ -182,38 +189,44 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
try try
{ {
Bitmap image = new Bitmap(stream); Bitmap image = new Bitmap(stream);
Size newsize;
// TODO: make this a bit less hard coded // TODO: make this a bit less hard coded
if ((image.Height < 64) && (image.Width < 64)) if ((image.Height < 64) && (image.Width < 64))
{ {
newsize = new Size(32, 32); newSize.Width = 32;
newSize.Height = 32;
} }
else if ((image.Height < 128) && (image.Width < 128)) else if ((image.Height < 128) && (image.Width < 128))
{ {
newsize = new Size(64, 64); newSize.Width = 64;
newSize.Height = 64;
} }
else if ((image.Height < 256) && (image.Width < 256)) else if ((image.Height < 256) && (image.Width < 256))
{ {
newsize = new Size(128, 128); newSize.Width = 128;
newSize.Height = 128;
} }
else if ((image.Height < 512 && image.Width < 512)) else if ((image.Height < 512 && image.Width < 512))
{ {
newsize = new Size(256, 256); newSize.Width = 256;
newSize.Height = 256;
} }
else if ((image.Height < 1024 && image.Width < 1024)) else if ((image.Height < 1024 && image.Width < 1024))
{ {
newsize = new Size(512, 512); newSize.Width = 512;
newSize.Height = 512;
} }
else else
{ {
newsize = new Size(1024, 1024); newSize.Width = 1024;
newSize.Height = 1024;
} }
Bitmap resize = new Bitmap(image, newsize); using (Bitmap resize = new Bitmap(image, newSize))
{
imageJ2000 = OpenJPEG.EncodeFromImage(resize, true); imageJ2000 = OpenJPEG.EncodeFromImage(resize, true);
} }
}
catch (Exception) catch (Exception)
{ {
m_log.Error("[LOADIMAGEURLMODULE]: OpenJpeg Conversion Failed. Empty byte data returned!"); m_log.Error("[LOADIMAGEURLMODULE]: OpenJpeg Conversion Failed. Empty byte data returned!");
@ -227,7 +240,6 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
} }
catch (WebException) catch (WebException)
{ {
} }
finally finally
{ {
@ -236,9 +248,14 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
stream.Close(); stream.Close();
} }
} }
m_log.DebugFormat("[LOADIMAGEURLMODULE] Returning {0} bytes of image data for request {1}",
m_log.DebugFormat("[LOADIMAGEURLMODULE]: Returning {0} bytes of image data for request {1}",
imageJ2000.Length, state.RequestID); imageJ2000.Length, state.RequestID);
m_textureManager.ReturnData(state.RequestID, imageJ2000);
m_textureManager.ReturnData(
state.RequestID,
new OpenSim.Region.CoreModules.Scripting.DynamicTexture.DynamicTexture(
request.RequestUri, null, imageJ2000, newSize, false));
} }
#region Nested type: RequestState #region Nested type: RequestState

View File

@ -130,13 +130,25 @@ namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms
m_scriptModule.PostScriptEvent(script, "link_message", args); m_scriptModule.PostScriptEvent(script, "link_message", args);
} }
private static MethodInfo GetMethodInfoFromType(Type target, string meth, bool searchInstanceMethods)
{
BindingFlags getMethodFlags =
BindingFlags.NonPublic | BindingFlags.Public;
if (searchInstanceMethods)
getMethodFlags |= BindingFlags.Instance;
else
getMethodFlags |= BindingFlags.Static;
return target.GetMethod(meth, getMethodFlags);
}
public void RegisterScriptInvocation(object target, string meth) public void RegisterScriptInvocation(object target, string meth)
{ {
MethodInfo mi = target.GetType().GetMethod(meth, MethodInfo mi = GetMethodInfoFromType(target.GetType(), meth, true);
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (mi == null) if (mi == null)
{ {
m_log.WarnFormat("[MODULE COMMANDS] Failed to register method {0}",meth); m_log.WarnFormat("[MODULE COMMANDS] Failed to register method {0}", meth);
return; return;
} }
@ -151,10 +163,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms
public void RegisterScriptInvocation(object target, MethodInfo mi) public void RegisterScriptInvocation(object target, MethodInfo mi)
{ {
m_log.DebugFormat("[MODULE COMMANDS] Register method {0} from type {1}", mi.Name, target.GetType().Name); m_log.DebugFormat("[MODULE COMMANDS] Register method {0} from type {1}", mi.Name, (target is Type) ? ((Type)target).Name : target.GetType().Name);
Type delegateType; Type delegateType;
var typeArgs = mi.GetParameters() List<Type> typeArgs = mi.GetParameters()
.Select(p => p.ParameterType) .Select(p => p.ParameterType)
.ToList(); .ToList();
@ -168,22 +180,55 @@ namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms
delegateType = Expression.GetFuncType(typeArgs.ToArray()); delegateType = Expression.GetFuncType(typeArgs.ToArray());
} }
Delegate fcall = Delegate.CreateDelegate(delegateType, target, mi); Delegate fcall;
if (!(target is Type))
fcall = Delegate.CreateDelegate(delegateType, target, mi);
else
fcall = Delegate.CreateDelegate(delegateType, (Type)target, mi.Name);
lock (m_scriptInvocation) lock (m_scriptInvocation)
{ {
ParameterInfo[] parameters = fcall.Method.GetParameters (); ParameterInfo[] parameters = fcall.Method.GetParameters();
if (parameters.Length < 2) // Must have two UUID params if (parameters.Length < 2) // Must have two UUID params
return; return;
// Hide the first two parameters // Hide the first two parameters
Type[] parmTypes = new Type[parameters.Length - 2]; Type[] parmTypes = new Type[parameters.Length - 2];
for (int i = 2 ; i < parameters.Length ; i++) for (int i = 2; i < parameters.Length; i++)
parmTypes[i - 2] = parameters[i].ParameterType; parmTypes[i - 2] = parameters[i].ParameterType;
m_scriptInvocation[fcall.Method.Name] = new ScriptInvocationData(fcall.Method.Name, fcall, parmTypes, fcall.Method.ReturnType); m_scriptInvocation[fcall.Method.Name] = new ScriptInvocationData(fcall.Method.Name, fcall, parmTypes, fcall.Method.ReturnType);
} }
} }
public void RegisterScriptInvocation(Type target, string[] methods)
{
foreach (string method in methods)
{
MethodInfo mi = GetMethodInfoFromType(target, method, false);
if (mi == null)
m_log.WarnFormat("[MODULE COMMANDS] Failed to register method {0}", method);
else
RegisterScriptInvocation(target, mi);
}
}
public void RegisterScriptInvocations(IRegionModuleBase target)
{
foreach(MethodInfo method in target.GetType().GetMethods(
BindingFlags.Public | BindingFlags.Instance |
BindingFlags.Static))
{
if(method.GetCustomAttributes(
typeof(ScriptInvocationAttribute), true).Any())
{
if(method.IsStatic)
RegisterScriptInvocation(target.GetType(), method);
else
RegisterScriptInvocation(target, method);
}
}
}
public Delegate[] GetScriptInvocationList() public Delegate[] GetScriptInvocationList()
{ {
List<Delegate> ret = new List<Delegate>(); List<Delegate> ret = new List<Delegate>();
@ -285,6 +330,20 @@ namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms
} }
} }
public void RegisterConstants(IRegionModuleBase target)
{
foreach (FieldInfo field in target.GetType().GetFields(
BindingFlags.Public | BindingFlags.Static |
BindingFlags.Instance))
{
if (field.GetCustomAttributes(
typeof(ScriptConstantAttribute), true).Any())
{
RegisterConstant(field.Name, field.GetValue(target));
}
}
}
/// <summary> /// <summary>
/// Operation to check for a registered constant /// Operation to check for a registered constant
/// </summary> /// </summary>

View File

@ -45,31 +45,292 @@ using OpenSim.Tests.Common.Mock;
namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
{ {
[TestFixture] [TestFixture]
public class VectorRenderModuleTests public class VectorRenderModuleTests : OpenSimTestCase
{ {
Scene m_scene;
DynamicTextureModule m_dtm;
VectorRenderModule m_vrm;
private void SetupScene(bool reuseTextures)
{
m_scene = new SceneHelpers().SetupScene();
m_dtm = new DynamicTextureModule();
m_dtm.ReuseTextures = reuseTextures;
// m_dtm.ReuseLowDataTextures = reuseTextures;
m_vrm = new VectorRenderModule();
SceneHelpers.SetupSceneModules(m_scene, m_dtm, m_vrm);
}
[Test] [Test]
public void TestDraw() public void TestDraw()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
Scene scene = new SceneHelpers().SetupScene(); SetupScene(false);
DynamicTextureModule dtm = new DynamicTextureModule(); SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
VectorRenderModule vrm = new VectorRenderModule();
SceneHelpers.SetupSceneModules(scene, dtm, vrm);
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene);
UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
dtm.AddDynamicTextureData( m_dtm.AddDynamicTextureData(
scene.RegionInfo.RegionID, m_scene.RegionInfo.RegionID,
so.UUID, so.UUID,
vrm.GetContentType(), m_vrm.GetContentType(),
"PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;", "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;",
"", "",
0); 0);
Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
}
[Test]
public void TestRepeatSameDraw()
{
TestHelpers.InMethod();
string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
SetupScene(false);
SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
m_dtm.AddDynamicTextureData(
m_scene.RegionInfo.RegionID,
so.UUID,
m_vrm.GetContentType(),
dtText,
"",
0);
UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
m_dtm.AddDynamicTextureData(
m_scene.RegionInfo.RegionID,
so.UUID,
m_vrm.GetContentType(),
dtText,
"",
0);
Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
}
[Test]
public void TestRepeatSameDrawDifferentExtraParams()
{
TestHelpers.InMethod();
string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
SetupScene(false);
SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
m_dtm.AddDynamicTextureData(
m_scene.RegionInfo.RegionID,
so.UUID,
m_vrm.GetContentType(),
dtText,
"",
0);
UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
m_dtm.AddDynamicTextureData(
m_scene.RegionInfo.RegionID,
so.UUID,
m_vrm.GetContentType(),
dtText,
"alpha:250",
0);
Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
}
[Test]
public void TestRepeatSameDrawContainingImage()
{
TestHelpers.InMethod();
string dtText
= "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://localhost/shouldnotexist.png";
SetupScene(false);
SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
m_dtm.AddDynamicTextureData(
m_scene.RegionInfo.RegionID,
so.UUID,
m_vrm.GetContentType(),
dtText,
"",
0);
UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
m_dtm.AddDynamicTextureData(
m_scene.RegionInfo.RegionID,
so.UUID,
m_vrm.GetContentType(),
dtText,
"",
0);
Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
}
[Test]
public void TestDrawReusingTexture()
{
TestHelpers.InMethod();
SetupScene(true);
SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
m_dtm.AddDynamicTextureData(
m_scene.RegionInfo.RegionID,
so.UUID,
m_vrm.GetContentType(),
"PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;",
"",
0);
Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
} }
[Test]
public void TestRepeatSameDrawReusingTexture()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
SetupScene(true);
SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
m_dtm.AddDynamicTextureData(
m_scene.RegionInfo.RegionID,
so.UUID,
m_vrm.GetContentType(),
dtText,
"",
0);
UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
m_dtm.AddDynamicTextureData(
m_scene.RegionInfo.RegionID,
so.UUID,
m_vrm.GetContentType(),
dtText,
"",
0);
Assert.That(firstDynamicTextureID, Is.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
}
/// <summary>
/// Test a low data dynamically generated texture such that it is treated as a low data texture that causes
/// problems for current viewers.
/// </summary>
/// <remarks>
/// As we do not set DynamicTextureModule.ReuseLowDataTextures = true in this test, it should not reuse the
/// texture
/// </remarks>
[Test]
public void TestRepeatSameDrawLowDataTexture()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
SetupScene(true);
SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
m_dtm.AddDynamicTextureData(
m_scene.RegionInfo.RegionID,
so.UUID,
m_vrm.GetContentType(),
dtText,
"1024",
0);
UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
m_dtm.AddDynamicTextureData(
m_scene.RegionInfo.RegionID,
so.UUID,
m_vrm.GetContentType(),
dtText,
"1024",
0);
Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
}
[Test]
public void TestRepeatSameDrawDifferentExtraParamsReusingTexture()
{
TestHelpers.InMethod();
string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
SetupScene(true);
SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
m_dtm.AddDynamicTextureData(
m_scene.RegionInfo.RegionID,
so.UUID,
m_vrm.GetContentType(),
dtText,
"",
0);
UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
m_dtm.AddDynamicTextureData(
m_scene.RegionInfo.RegionID,
so.UUID,
m_vrm.GetContentType(),
dtText,
"alpha:250",
0);
Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
}
[Test]
public void TestRepeatSameDrawContainingImageReusingTexture()
{
TestHelpers.InMethod();
string dtText
= "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://localhost/shouldnotexist.png";
SetupScene(true);
SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
m_dtm.AddDynamicTextureData(
m_scene.RegionInfo.RegionID,
so.UUID,
m_vrm.GetContentType(),
dtText,
"",
0);
UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
m_dtm.AddDynamicTextureData(
m_scene.RegionInfo.RegionID,
so.UUID,
m_vrm.GetContentType(),
dtText,
"",
0);
Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
}
} }
} }

View File

@ -30,10 +30,12 @@ using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq;
using System.Net; using System.Net;
using Nini.Config; using Nini.Config;
using OpenMetaverse; using OpenMetaverse;
using OpenMetaverse.Imaging; using OpenMetaverse.Imaging;
using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using log4net; using log4net;
@ -45,9 +47,13 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
{ {
public class VectorRenderModule : IRegionModule, IDynamicTextureRender public class VectorRenderModule : IRegionModule, IDynamicTextureRender
{ {
// These fields exist for testing purposes, please do not remove.
// private static bool s_flipper;
// private static byte[] s_asset1Data;
// private static byte[] s_asset2Data;
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private string m_name = "VectorRenderModule";
private Scene m_scene; private Scene m_scene;
private IDynamicTextureManager m_textureManager; private IDynamicTextureManager m_textureManager;
private Graphics m_graph; private Graphics m_graph;
@ -61,12 +67,12 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
public string GetContentType() public string GetContentType()
{ {
return ("vector"); return "vector";
} }
public string GetName() public string GetName()
{ {
return m_name; return Name;
} }
public bool SupportsAsynchronous() public bool SupportsAsynchronous()
@ -74,14 +80,20 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
return true; return true;
} }
public byte[] ConvertUrl(string url, string extraParams) // public bool AlwaysIdenticalConversion(string bodyData, string extraParams)
// {
// string[] lines = GetLines(bodyData);
// return lines.Any((str, r) => str.StartsWith("Image"));
// }
public IDynamicTexture ConvertUrl(string url, string extraParams)
{ {
return null; return null;
} }
public byte[] ConvertStream(Stream data, string extraParams) public IDynamicTexture ConvertData(string bodyData, string extraParams)
{ {
return null; return Draw(bodyData, extraParams);
} }
public bool AsyncConvertUrl(UUID id, string url, string extraParams) public bool AsyncConvertUrl(UUID id, string url, string extraParams)
@ -91,16 +103,22 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
public bool AsyncConvertData(UUID id, string bodyData, string extraParams) public bool AsyncConvertData(UUID id, string bodyData, string extraParams)
{ {
Draw(bodyData, id, extraParams); // XXX: This isn't actually being done asynchronously!
m_textureManager.ReturnData(id, ConvertData(bodyData, extraParams));
return true; return true;
} }
public void GetDrawStringSize(string text, string fontName, int fontSize, public void GetDrawStringSize(string text, string fontName, int fontSize,
out double xSize, out double ySize) out double xSize, out double ySize)
{
lock (this)
{ {
using (Font myFont = new Font(fontName, fontSize)) using (Font myFont = new Font(fontName, fontSize))
{ {
SizeF stringSize = new SizeF(); SizeF stringSize = new SizeF();
// XXX: This lock may be unnecessary.
lock (m_graph) lock (m_graph)
{ {
stringSize = m_graph.MeasureString(text, myFont); stringSize = m_graph.MeasureString(text, myFont);
@ -109,6 +127,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
} }
} }
} }
}
#endregion #endregion
@ -144,6 +163,13 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
{ {
m_textureManager.RegisterRender(GetContentType(), this); m_textureManager.RegisterRender(GetContentType(), this);
} }
// This code exists for testing purposes, please do not remove.
// s_asset1Data = m_scene.AssetService.Get("00000000-0000-1111-9999-000000000001").Data;
// s_asset1Data = m_scene.AssetService.Get("9f4acf0d-1841-4e15-bdb8-3a12efc9dd8f").Data;
// Terrain dirt - smallest bin/assets file (6004 bytes)
// s_asset2Data = m_scene.AssetService.Get("b8d3965a-ad78-bf43-699b-bff8eca6c975").Data;
} }
public void Close() public void Close()
@ -152,7 +178,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
public string Name public string Name
{ {
get { return m_name; } get { return "VectorRenderModule"; }
} }
public bool IsSharedModule public bool IsSharedModule
@ -162,7 +188,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
#endregion #endregion
private void Draw(string data, UUID id, string extraParams) private IDynamicTexture Draw(string data, string extraParams)
{ {
// We need to cater for old scripts that didnt use extraParams neatly, they use either an integer size which represents both width and height, or setalpha // We need to cater for old scripts that didnt use extraParams neatly, they use either an integer size which represents both width and height, or setalpha
// we will now support multiple comma seperated params in the form width:256,height:512,alpha:255 // we will now support multiple comma seperated params in the form width:256,height:512,alpha:255
@ -305,8 +331,16 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
Bitmap bitmap = null; Bitmap bitmap = null;
Graphics graph = null; Graphics graph = null;
bool reuseable = false;
try try
{
// XXX: In testing, it appears that if multiple threads dispose of separate GDI+ objects simultaneously,
// the native malloc heap can become corrupted, possibly due to a double free(). This may be due to
// bugs in the underlying libcairo used by mono's libgdiplus.dll on Linux/OSX. These problems were
// seen with both libcario 1.10.2-6.1ubuntu3 and 1.8.10-2ubuntu1. They go away if disposal is perfomed
// under lock.
lock (this)
{ {
if (alpha == 256) if (alpha == 256)
bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb); bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb);
@ -336,10 +370,19 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
} }
} }
GDIDraw(data, graph, altDataDelim); GDIDraw(data, graph, altDataDelim, out reuseable);
}
byte[] imageJ2000 = new byte[0]; byte[] imageJ2000 = new byte[0];
// This code exists for testing purposes, please do not remove.
// if (s_flipper)
// imageJ2000 = s_asset1Data;
// else
// imageJ2000 = s_asset2Data;
//
// s_flipper = !s_flipper;
try try
{ {
imageJ2000 = OpenJPEG.EncodeFromImage(bitmap, true); imageJ2000 = OpenJPEG.EncodeFromImage(bitmap, true);
@ -351,9 +394,17 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
e.Message, e.StackTrace); e.Message, e.StackTrace);
} }
m_textureManager.ReturnData(id, imageJ2000); return new OpenSim.Region.CoreModules.Scripting.DynamicTexture.DynamicTexture(
data, extraParams, imageJ2000, new Size(width, height), reuseable);
} }
finally finally
{
// XXX: In testing, it appears that if multiple threads dispose of separate GDI+ objects simultaneously,
// the native malloc heap can become corrupted, possibly due to a double free(). This may be due to
// bugs in the underlying libcairo used by mono's libgdiplus.dll on Linux/OSX. These problems were
// seen with both libcario 1.10.2-6.1ubuntu3 and 1.8.10-2ubuntu1. They go away if disposal is perfomed
// under lock.
lock (this)
{ {
if (graph != null) if (graph != null)
graph.Dispose(); graph.Dispose();
@ -362,6 +413,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
bitmap.Dispose(); bitmap.Dispose();
} }
} }
}
private int parseIntParam(string strInt) private int parseIntParam(string strInt)
{ {
@ -418,8 +470,21 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
} }
*/ */
private void GDIDraw(string data, Graphics graph, char dataDelim) /// <summary>
/// Split input data into discrete command lines.
/// </summary>
/// <returns></returns>
/// <param name='data'></param>
/// <param name='dataDelim'></param>
private string[] GetLines(string data, char dataDelim)
{ {
char[] lineDelimiter = { dataDelim };
return data.Split(lineDelimiter);
}
private void GDIDraw(string data, Graphics graph, char dataDelim, out bool reuseable)
{
reuseable = true;
Point startPoint = new Point(0, 0); Point startPoint = new Point(0, 0);
Point endPoint = new Point(0, 0); Point endPoint = new Point(0, 0);
Pen drawPen = null; Pen drawPen = null;
@ -434,11 +499,9 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
myFont = new Font(fontName, fontSize); myFont = new Font(fontName, fontSize);
myBrush = new SolidBrush(Color.Black); myBrush = new SolidBrush(Color.Black);
char[] lineDelimiter = {dataDelim};
char[] partsDelimiter = {','}; char[] partsDelimiter = {','};
string[] lines = data.Split(lineDelimiter);
foreach (string line in lines) foreach (string line in GetLines(data, dataDelim))
{ {
string nextLine = line.Trim(); string nextLine = line.Trim();
//replace with switch, or even better, do some proper parsing //replace with switch, or even better, do some proper parsing
@ -469,6 +532,10 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
} }
else if (nextLine.StartsWith("Image")) else if (nextLine.StartsWith("Image"))
{ {
// We cannot reuse any generated texture involving fetching an image via HTTP since that image
// can change.
reuseable = false;
float x = 0; float x = 0;
float y = 0; float y = 0;
GetParams(partsDelimiter, ref nextLine, 5, ref x, ref y); GetParams(partsDelimiter, ref nextLine, 5, ref x, ref y);

View File

@ -28,6 +28,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.RegularExpressions;
using Nini.Config; using Nini.Config;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
@ -172,12 +173,42 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
/// <param name="hostID">UUID of the SceneObjectPart</param> /// <param name="hostID">UUID of the SceneObjectPart</param>
/// <param name="channel">channel to listen on</param> /// <param name="channel">channel to listen on</param>
/// <param name="name">name to filter on</param> /// <param name="name">name to filter on</param>
/// <param name="id">key to filter on (user given, could be totally faked)</param> /// <param name="id">
/// key to filter on (user given, could be totally faked)
/// </param>
/// <param name="msg">msg to filter on</param> /// <param name="msg">msg to filter on</param>
/// <returns>number of the scripts handle</returns> /// <returns>number of the scripts handle</returns>
public int Listen(uint localID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg) public int Listen(uint localID, UUID itemID, UUID hostID, int channel,
string name, UUID id, string msg)
{ {
return m_listenerManager.AddListener(localID, itemID, hostID, channel, name, id, msg); return m_listenerManager.AddListener(localID, itemID, hostID,
channel, name, id, msg);
}
/// <summary>
/// Create a listen event callback with the specified filters.
/// The parameters localID,itemID are needed to uniquely identify
/// the script during 'peek' time. Parameter hostID is needed to
/// determine the position of the script.
/// </summary>
/// <param name="localID">localID of the script engine</param>
/// <param name="itemID">UUID of the script engine</param>
/// <param name="hostID">UUID of the SceneObjectPart</param>
/// <param name="channel">channel to listen on</param>
/// <param name="name">name to filter on</param>
/// <param name="id">
/// key to filter on (user given, could be totally faked)
/// </param>
/// <param name="msg">msg to filter on</param>
/// <param name="regexBitfield">
/// Bitfield indicating which strings should be processed as regex.
/// </param>
/// <returns>number of the scripts handle</returns>
public int Listen(uint localID, UUID itemID, UUID hostID, int channel,
string name, UUID id, string msg, int regexBitfield)
{
return m_listenerManager.AddListener(localID, itemID, hostID,
channel, name, id, msg, regexBitfield);
} }
/// <summary> /// <summary>
@ -326,7 +357,7 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
if (channel == 0) if (channel == 0)
{ {
// Channel 0 goes to viewer ONLY // Channel 0 goes to viewer ONLY
m_scene.SimChat(Utils.StringToBytes(msg), ChatTypeEnum.Broadcast, 0, pos, name, id, false, false, target); m_scene.SimChat(Utils.StringToBytes(msg), ChatTypeEnum.Broadcast, 0, pos, name, id, target, false, false);
return true; return true;
} }
@ -470,15 +501,25 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
m_curlisteners = 0; m_curlisteners = 0;
} }
public int AddListener(uint localID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg) public int AddListener(uint localID, UUID itemID, UUID hostID,
int channel, string name, UUID id, string msg)
{
return AddListener(localID, itemID, hostID, channel, name, id,
msg, 0);
}
public int AddListener(uint localID, UUID itemID, UUID hostID,
int channel, string name, UUID id, string msg,
int regexBitfield)
{ {
// do we already have a match on this particular filter event? // do we already have a match on this particular filter event?
List<ListenerInfo> coll = GetListeners(itemID, channel, name, id, msg); List<ListenerInfo> coll = GetListeners(itemID, channel, name, id,
msg);
if (coll.Count > 0) if (coll.Count > 0)
{ {
// special case, called with same filter settings, return same handle // special case, called with same filter settings, return same
// (2008-05-02, tested on 1.21.1 server, still holds) // handle (2008-05-02, tested on 1.21.1 server, still holds)
return coll[0].GetHandle(); return coll[0].GetHandle();
} }
@ -490,7 +531,9 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
if (newHandle > 0) if (newHandle > 0)
{ {
ListenerInfo li = new ListenerInfo(newHandle, localID, itemID, hostID, channel, name, id, msg); ListenerInfo li = new ListenerInfo(newHandle, localID,
itemID, hostID, channel, name, id, msg,
regexBitfield);
List<ListenerInfo> listeners; List<ListenerInfo> listeners;
if (!m_listeners.TryGetValue(channel,out listeners)) if (!m_listeners.TryGetValue(channel,out listeners))
@ -631,6 +674,22 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
return -1; return -1;
} }
/// These are duplicated from ScriptBaseClass
/// http://opensimulator.org/mantis/view.php?id=6106#c21945
#region Constants for the bitfield parameter of osListenRegex
/// <summary>
/// process name parameter as regex
/// </summary>
public const int OS_LISTEN_REGEX_NAME = 0x1;
/// <summary>
/// process message parameter as regex
/// </summary>
public const int OS_LISTEN_REGEX_MESSAGE = 0x2;
#endregion
// Theres probably a more clever and efficient way to // Theres probably a more clever and efficient way to
// do this, maybe with regex. // do this, maybe with regex.
// PM2008: Ha, one could even be smart and define a specialized Enumerator. // PM2008: Ha, one could even be smart and define a specialized Enumerator.
@ -656,7 +715,10 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
{ {
continue; continue;
} }
if (li.GetName().Length > 0 && !li.GetName().Equals(name)) if (li.GetName().Length > 0 && (
((li.RegexBitfield & OS_LISTEN_REGEX_NAME) != OS_LISTEN_REGEX_NAME && !li.GetName().Equals(name)) ||
((li.RegexBitfield & OS_LISTEN_REGEX_NAME) == OS_LISTEN_REGEX_NAME && !Regex.IsMatch(name, li.GetName()))
))
{ {
continue; continue;
} }
@ -664,7 +726,10 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
{ {
continue; continue;
} }
if (li.GetMessage().Length > 0 && !li.GetMessage().Equals(msg)) if (li.GetMessage().Length > 0 && (
((li.RegexBitfield & OS_LISTEN_REGEX_MESSAGE) != OS_LISTEN_REGEX_MESSAGE && !li.GetMessage().Equals(msg)) ||
((li.RegexBitfield & OS_LISTEN_REGEX_MESSAGE) == OS_LISTEN_REGEX_MESSAGE && !Regex.IsMatch(msg, li.GetMessage()))
))
{ {
continue; continue;
} }
@ -697,10 +762,13 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
{ {
int idx = 0; int idx = 0;
Object[] item = new Object[6]; Object[] item = new Object[6];
int dataItemLength = 6;
while (idx < data.Length) while (idx < data.Length)
{ {
Array.Copy(data, idx, item, 0, 6); dataItemLength = (idx + 7 == data.Length || (idx + 7 < data.Length && data[idx + 7] is bool)) ? 7 : 6;
item = new Object[dataItemLength];
Array.Copy(data, idx, item, 0, dataItemLength);
ListenerInfo info = ListenerInfo info =
ListenerInfo.FromData(localID, itemID, hostID, item); ListenerInfo.FromData(localID, itemID, hostID, item);
@ -712,12 +780,12 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
m_listeners[(int)item[2]].Add(info); m_listeners[(int)item[2]].Add(info);
} }
idx+=6; idx+=dataItemLength;
} }
} }
} }
public class ListenerInfo: IWorldCommListenerInfo public class ListenerInfo : IWorldCommListenerInfo
{ {
private bool m_active; // Listener is active or not private bool m_active; // Listener is active or not
private int m_handle; // Assigned handle of this listener private int m_handle; // Assigned handle of this listener
@ -731,16 +799,29 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
public ListenerInfo(int handle, uint localID, UUID ItemID, UUID hostID, int channel, string name, UUID id, string message) public ListenerInfo(int handle, uint localID, UUID ItemID, UUID hostID, int channel, string name, UUID id, string message)
{ {
Initialise(handle, localID, ItemID, hostID, channel, name, id, message); Initialise(handle, localID, ItemID, hostID, channel, name, id,
message, 0);
}
public ListenerInfo(int handle, uint localID, UUID ItemID,
UUID hostID, int channel, string name, UUID id,
string message, int regexBitfield)
{
Initialise(handle, localID, ItemID, hostID, channel, name, id,
message, regexBitfield);
} }
public ListenerInfo(ListenerInfo li, string name, UUID id, string message) public ListenerInfo(ListenerInfo li, string name, UUID id, string message)
{ {
Initialise(li.m_handle, li.m_localID, li.m_itemID, li.m_hostID, li.m_channel, name, id, message); Initialise(li.m_handle, li.m_localID, li.m_itemID, li.m_hostID, li.m_channel, name, id, message, 0);
} }
private void Initialise(int handle, uint localID, UUID ItemID, UUID hostID, int channel, string name, public ListenerInfo(ListenerInfo li, string name, UUID id, string message, int regexBitfield)
UUID id, string message) {
Initialise(li.m_handle, li.m_localID, li.m_itemID, li.m_hostID, li.m_channel, name, id, message, regexBitfield);
}
private void Initialise(int handle, uint localID, UUID ItemID, UUID hostID, int channel, string name, UUID id, string message, int regexBitfield)
{ {
m_active = true; m_active = true;
m_handle = handle; m_handle = handle;
@ -751,11 +832,12 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
m_name = name; m_name = name;
m_id = id; m_id = id;
m_message = message; m_message = message;
RegexBitfield = regexBitfield;
} }
public Object[] GetSerializationData() public Object[] GetSerializationData()
{ {
Object[] data = new Object[6]; Object[] data = new Object[7];
data[0] = m_active; data[0] = m_active;
data[1] = m_handle; data[1] = m_handle;
@ -763,16 +845,19 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
data[3] = m_name; data[3] = m_name;
data[4] = m_id; data[4] = m_id;
data[5] = m_message; data[5] = m_message;
data[6] = RegexBitfield;
return data; return data;
} }
public static ListenerInfo FromData(uint localID, UUID ItemID, UUID hostID, Object[] data) public static ListenerInfo FromData(uint localID, UUID ItemID, UUID hostID, Object[] data)
{ {
ListenerInfo linfo = new ListenerInfo((int)data[1], localID, ListenerInfo linfo = new ListenerInfo((int)data[1], localID, ItemID, hostID, (int)data[2], (string)data[3], (UUID)data[4], (string)data[5]);
ItemID, hostID, (int)data[2], (string)data[3], linfo.m_active = (bool)data[0];
(UUID)data[4], (string)data[5]); if (data.Length >= 7)
linfo.m_active=(bool)data[0]; {
linfo.RegexBitfield = (int)data[6];
}
return linfo; return linfo;
} }
@ -831,5 +916,7 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
{ {
return m_id; return m_id;
} }
public int RegexBitfield { get; private set; }
} }
} }

View File

@ -56,6 +56,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
private bool m_Enabled = false; private bool m_Enabled = false;
private AssetPermissions m_AssetPerms;
public Type ReplaceableInterface public Type ReplaceableInterface
{ {
get { return null; } get { return null; }
@ -128,6 +130,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
if (m_LocalAssetServiceURI != string.Empty) if (m_LocalAssetServiceURI != string.Empty)
m_LocalAssetServiceURI = m_LocalAssetServiceURI.Trim('/'); m_LocalAssetServiceURI = m_LocalAssetServiceURI.Trim('/');
IConfig hgConfig = source.Configs["HGAssetService"];
m_AssetPerms = new AssetPermissions(hgConfig); // it's ok if arg is null
m_Enabled = true; m_Enabled = true;
m_log.Info("[HG ASSET CONNECTOR]: HG asset broker enabled"); m_log.Info("[HG ASSET CONNECTOR]: HG asset broker enabled");
} }
@ -206,14 +211,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
asset = m_HGService.Get(id); asset = m_HGService.Get(id);
if (asset != null) if (asset != null)
{ {
// Now store it locally // Now store it locally, if allowed
// For now, let me just do it for textures and scripts if (m_AssetPerms.AllowedImport(asset.Type))
if (((AssetType)asset.Type == AssetType.Texture) ||
((AssetType)asset.Type == AssetType.LSLBytecode) ||
((AssetType)asset.Type == AssetType.LSLText))
{
m_GridService.Store(asset); m_GridService.Store(asset);
} else
return null;
} }
} }
else else
@ -328,7 +330,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
string id = string.Empty; string id = string.Empty;
if (IsHG(asset.ID)) if (IsHG(asset.ID))
{
if (m_AssetPerms.AllowedExport(asset.Type))
id = m_HGService.Store(asset); id = m_HGService.Store(asset);
else
return String.Empty;
}
else else
id = m_GridService.Store(asset); id = m_GridService.Store(asset);

View File

@ -205,7 +205,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
{ {
// m_log.DebugFormat("[LOCAL ASSET SERVICES CONNECTOR]: Requesting data for asset {0}", id); // m_log.DebugFormat("[LOCAL ASSET SERVICES CONNECTOR]: Requesting data for asset {0}", id);
AssetBase asset = m_Cache.Get(id); AssetBase asset = null;
if (m_Cache != null)
asset = m_Cache.Get(id);
if (asset != null) if (asset != null)
return asset.Data; return asset.Data;

View File

@ -0,0 +1,136 @@
/*
* 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.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Threading;
using log4net.Config;
using Nini.Config;
using NUnit.Framework;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset;
using OpenSim.Tests.Common;
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests
{
[TestFixture]
public class AssetConnectorsTests : OpenSimTestCase
{
[Test]
public void TestAddAsset()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
IConfigSource config = new IniConfigSource();
config.AddConfig("Modules");
config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector");
config.AddConfig("AssetService");
config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService");
config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll");
LocalAssetServicesConnector lasc = new LocalAssetServicesConnector();
lasc.Initialise(config);
AssetBase a1 = AssetHelpers.CreateNotecardAsset();
lasc.Store(a1);
AssetBase retreivedA1 = lasc.Get(a1.ID);
Assert.That(retreivedA1.ID, Is.EqualTo(a1.ID));
Assert.That(retreivedA1.Metadata.ID, Is.EqualTo(a1.Metadata.ID));
Assert.That(retreivedA1.Data.Length, Is.EqualTo(a1.Data.Length));
AssetMetadata retrievedA1Metadata = lasc.GetMetadata(a1.ID);
Assert.That(retrievedA1Metadata.ID, Is.EqualTo(a1.ID));
byte[] retrievedA1Data = lasc.GetData(a1.ID);
Assert.That(retrievedA1Data.Length, Is.EqualTo(a1.Data.Length));
// TODO: Add cache and check that this does receive a copy of the asset
}
[Test]
public void TestAddTemporaryAsset()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
IConfigSource config = new IniConfigSource();
config.AddConfig("Modules");
config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector");
config.AddConfig("AssetService");
config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService");
config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll");
LocalAssetServicesConnector lasc = new LocalAssetServicesConnector();
lasc.Initialise(config);
AssetBase a1 = AssetHelpers.CreateNotecardAsset();
a1.Temporary = true;
lasc.Store(a1);
Assert.That(lasc.Get(a1.ID), Is.Null);
Assert.That(lasc.GetData(a1.ID), Is.Null);
Assert.That(lasc.GetMetadata(a1.ID), Is.Null);
// TODO: Add cache and check that this does receive a copy of the asset
}
[Test]
public void TestAddLocalAsset()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
IConfigSource config = new IniConfigSource();
config.AddConfig("Modules");
config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector");
config.AddConfig("AssetService");
config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService");
config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll");
LocalAssetServicesConnector lasc = new LocalAssetServicesConnector();
lasc.Initialise(config);
AssetBase a1 = AssetHelpers.CreateNotecardAsset();
a1.Local = true;
lasc.Store(a1);
Assert.That(lasc.Get(a1.ID), Is.Null);
Assert.That(lasc.GetData(a1.ID), Is.Null);
Assert.That(lasc.GetMetadata(a1.ID), Is.Null);
// TODO: Add cache and check that this does receive a copy of the asset
}
}
}

View File

@ -43,11 +43,15 @@ using OpenSim.Tests.Common;
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
{ {
[TestFixture] [TestFixture]
public class GridConnectorsTests public class GridConnectorsTests : OpenSimTestCase
{ {
LocalGridServicesConnector m_LocalConnector; LocalGridServicesConnector m_LocalConnector;
private void SetUp()
[SetUp]
public override void SetUp()
{ {
base.SetUp();
IConfigSource config = new IniConfigSource(); IConfigSource config = new IniConfigSource();
config.AddConfig("Modules"); config.AddConfig("Modules");
config.AddConfig("GridService"); config.AddConfig("GridService");
@ -71,8 +75,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
TestHelpers.InMethod(); TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure(); // log4net.Config.XmlConfigurator.Configure();
SetUp();
// Create 4 regions // Create 4 regions
GridRegion r1 = new GridRegion(); GridRegion r1 = new GridRegion();
r1.RegionName = "Test Region 1"; r1.RegionName = "Test Region 1";

View File

@ -65,11 +65,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
public void OnMakeRootAgent(ScenePresence sp) public void OnMakeRootAgent(ScenePresence sp)
{ {
// m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected root presence {0} in {1}", sp.UUID, sp.Scene.RegionInfo.RegionName);
if (sp.PresenceType != PresenceType.Npc) if (sp.PresenceType != PresenceType.Npc)
{
string userid = sp.Scene.UserManagementModule.GetUserUUI(sp.UUID);
//m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected root presence {0} in {1}", userid, sp.Scene.RegionInfo.RegionName);
m_GridUserService.SetLastPosition( m_GridUserService.SetLastPosition(
sp.UUID.ToString(), UUID.Zero, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); userid, UUID.Zero, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat);
}
} }
public void OnNewClient(IClientAPI client) public void OnNewClient(IClientAPI client)
@ -82,9 +84,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
if (client.SceneAgent.IsChildAgent) if (client.SceneAgent.IsChildAgent)
return; return;
// m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName); string userId = client.AgentId.ToString();
if (client.Scene is Scene)
{
Scene s = (Scene)client.Scene;
userId = s.UserManagementModule.GetUserUUI(client.AgentId);
}
//m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected client logout {0} in {1}", userId, client.Scene.RegionInfo.RegionName);
m_GridUserService.LoggedOut( m_GridUserService.LoggedOut(
client.AgentId.ToString(), client.SessionId, client.Scene.RegionInfo.RegionID, userId, client.SessionId, client.Scene.RegionInfo.RegionID,
client.SceneAgent.AbsolutePosition, client.SceneAgent.Lookat); client.SceneAgent.AbsolutePosition, client.SceneAgent.Lookat);
} }
} }

Some files were not shown because too many files have changed in this diff Show More