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/*.dll.mdb
bin/*.db
bin/*.db-journal
bin/addin-db-*
bin/*.dll
bin/OpenSim.vshost.exe.config
bin/OpenSim.32BitLaunch.vshost.exe.config
bin/OpenSim.32BitLaunch.log
UpgradeLog.XML
_UpgradeReport_Files/
bin/ScriptEngines/*-*-*-*-*
bin/ScriptEngines/*.dll
bin/ScriptEngines/*/*.dll
@ -64,6 +69,7 @@ Examples/*.dll
OpenSim.build
OpenSim.sln
OpenSim.suo
OpenSim.userprefs
Prebuild/Prebuild.build
Prebuild/Prebuild.sln
TestResult.xml

View File

@ -135,14 +135,25 @@
<delete dir="%temp%"/>
</target>
<target name="torture" depends="build, find-nunit">
<target name="test-stress" depends="build, find-nunit">
<setenv name="MONO_THREADS_PER_CPU" value="100" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests.torture">
<arg value="./bin/OpenSim.Tests.Torture.dll" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests.stress">
<arg value="./bin/OpenSim.Tests.Stress.dll" />
</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%"/>
</target>

View File

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

View File

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

View File

@ -696,7 +696,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
region.ExternalHostName = (string) requestData["external_address"];
bool persist = Convert.ToBoolean((string) requestData["persist"]);
bool persist = Convert.ToBoolean(requestData["persist"]);
if (persist)
{
// default place for region configuration files is in the
@ -852,7 +852,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
responseData["success"] = true;
responseData["region_name"] = region.RegionName;
responseData["region_id"] = region.RegionID.ToString();
responseData["region_uuid"] = region.RegionID.ToString(); //Deprecate July 2012
m_log.Info("[RADMIN]: CreateRegion: request complete");
}
@ -1106,8 +1105,8 @@ namespace OpenSim.ApplicationPlugins.RemoteController
string lastName = (string) requestData["user_lastname"];
string password = (string) requestData["user_password"];
uint regionXLocation = Convert.ToUInt32((Int32) requestData["start_region_x"]);
uint regionYLocation = Convert.ToUInt32((Int32) requestData["start_region_y"]);
uint regionXLocation = Convert.ToUInt32(requestData["start_region_x"]);
uint regionYLocation = Convert.ToUInt32(requestData["start_region_y"]);
string email = ""; // empty string for 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("start_region_x"))
regionXLocation = Convert.ToUInt32((Int32) requestData["start_region_x"]);
regionXLocation = Convert.ToUInt32(requestData["start_region_x"]);
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"))
// ulaX = Convert.ToUInt32((Int32) requestData["start_lookat_x"]);
@ -1493,6 +1492,8 @@ namespace OpenSim.ApplicationPlugins.RemoteController
/// <description>profile url</description></item>
/// <item><term>noassets</term>
/// <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>
/// <description>C and/or T</description></item>
/// </list>
@ -1549,6 +1550,11 @@ namespace OpenSim.ApplicationPlugins.RemoteController
options["checkPermissions"] = (string)requestData["perm"];
}
if ((string)requestData["all"] == "true")
{
options["all"] = (string)requestData["all"];
}
IRegionArchiverModule archiver = scene.RequestModuleInterface<IRegionArchiverModule>();
if (archiver != null)
@ -2008,29 +2014,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
{
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
{
responseData["accepted"] = false;
@ -2052,56 +2035,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
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") &&
!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
// add THIS agent to the HTTP server's handler list
if (!AddAgentHandler(Rest.Name,this))
{
Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId);
foreach (IRest handler in handlers)
{
handler.Close();
}
}
// 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.
// if (!AddAgentHandler(Rest.Name,this))
// {
// Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId);
// foreach (IRest handler in handlers)
// {
// handler.Close();
// }
// }
}
catch (Exception e)
@ -342,11 +344,13 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
{
Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId);
try
{
RemoveAgentHandler(Rest.Name, this);
}
catch (KeyNotFoundException){}
// 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.
// try
// {
// RemoveAgentHandler(Rest.Name, this);
// }
// catch (KeyNotFoundException){}
foreach (IRest handler in handlers)
{

View File

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

View File

@ -200,11 +200,25 @@ namespace OpenSim.Capabilities.Handlers
int start, end;
if (TryParseRange(range, out start, out end))
{
// Before clamping start make sure we can satisfy it in order to avoid
// sending back the last byte instead of an error status
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;
// viewers don't seem to handle RequestedRangeNotSatisfiable and keep retrying with same parameters
response["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;

View File

@ -85,21 +85,6 @@ namespace OpenSim.Data
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>
{
private Vector2 m_origin;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1366,6 +1366,13 @@ namespace OpenSim.Data.SQLite
createCol(land, "UserLookAtZ", typeof(Double));
createCol(land, "AuthbuyerID", typeof(String));
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"] };
@ -1781,9 +1788,16 @@ namespace OpenSim.Data.SQLite
newData.PassHours = Convert.ToSingle(row["PassHours"]);
newData.PassPrice = Convert.ToInt32(row["PassPrice"]);
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
{
newData.UserLocation =
new Vector3(Convert.ToSingle(row["UserLocationX"]), Convert.ToSingle(row["UserLocationY"]),
Convert.ToSingle(row["UserLocationZ"]));
@ -2195,12 +2209,13 @@ namespace OpenSim.Data.SQLite
row["UserLookAtZ"] = land.UserLookAt.Z;
row["AuthbuyerID"] = land.AuthBuyerID.ToString();
row["OtherCleanTime"] = land.OtherCleanTime;
row["Dwell"] = land.Dwell;
row["MediaType"] = land.MediaType;
row["MediaDescription"] = land.MediaDescription;
row["MediaSize"] = land.MediaWidth.ToString() + "," + land.MediaHeight.ToString();
row["MediaLoop"] = land.MediaLoop.ToString();
row["ObscureMusic"] = land.ObscureMusic.ToString();
row["ObscureMedia"] = land.ObscureMedia.ToString();
row["MediaSize"] = String.Format("{0},{1}", land.MediaWidth, land.MediaHeight);
row["MediaLoop"] = land.MediaLoop;
row["ObscureMusic"] = land.ObscureMusic;
row["ObscureMedia"] = land.ObscureMedia;
}
/// <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);
}
/// <summary>
/// Set avatar height by a calculation based on their visual parameters.
/// </summary>
public virtual void SetHeight()
{
// Start with shortest possible female avatar height

View File

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

View File

@ -33,7 +33,8 @@ namespace OpenSim.Framework.Client
{
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);
}
}

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 const uint RegionSize = 256;
public const uint RegionHeight = 4096;
public const byte TerrainPatchSize = 16;
public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f";

View File

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

View File

@ -44,7 +44,6 @@ namespace OpenSim.Framework
public Vector3 Position;
public byte[] binaryBucket;
public uint ParentEstateID;
public Guid RegionID;
public uint timestamp;
@ -58,7 +57,7 @@ namespace OpenSim.Framework
string _fromAgentName, UUID _toAgentID,
byte _dialog, bool _fromGroup, string _message,
UUID _imSessionID, bool _offline, Vector3 _position,
byte[] _binaryBucket)
byte[] _binaryBucket, bool addTimestamp)
{
fromAgentID = _fromAgentID.Guid;
fromAgentName = _fromAgentName;
@ -79,6 +78,8 @@ namespace OpenSim.Framework
ParentEstateID = scene.RegionInfo.EstateSettings.ParentEstateID;
RegionID = scene.RegionInfo.RegionSettings.RegionUUID.Guid;
}
if (addTimestamp)
timestamp = (uint)Util.UnixTimeSinceEpoch();
}
@ -87,7 +88,7 @@ namespace OpenSim.Framework
string _message, bool _offline,
Vector3 _position) : this(scene, _fromAgentID, _fromAgentName,
_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 GenericCall1 OnRequestWearables;
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;
/// <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 AgentRequestSit OnAgentRequestSit;
event AgentSit OnAgentSit;
event AvatarPickerRequest OnAvatarPickerRequest;
@ -1046,8 +1061,21 @@ namespace OpenSim.Framework
void InPacket(object NewPack);
void ProcessInPacket(Packet NewPack);
/// <summary>
/// Close this client
/// </summary>
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);
/// <summary>
@ -1084,7 +1112,19 @@ namespace OpenSim.Framework
void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs);
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);
void SendInstantMessage(GridInstantMessage im);

View File

@ -73,32 +73,26 @@ namespace OpenSim.Framework
{
}
public InventoryFolderBase(UUID id)
public InventoryFolderBase(UUID id) : this()
{
ID = id;
}
public InventoryFolderBase(UUID id, UUID owner)
public InventoryFolderBase(UUID id, UUID owner) : this(id)
{
ID = id;
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;
Owner = owner;
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;
ParentID = parent;
Version = version;
}
}

View File

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

View File

@ -43,27 +43,32 @@ namespace OpenSim.Framework.Monitoring
StringBuilder sb = new StringBuilder(Environment.NewLine);
sb.Append("MEMORY STATISTICS");
sb.Append(Environment.NewLine);
sb.Append(
string.Format(
sb.AppendFormat(
"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();
if (!myprocess.HasExited)
{
myprocess.Refresh();
sb.Append(
string.Format(
sb.AppendFormat(
"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().PagedMemorySize64 / 1024.0 / 1024.0),
Math.Round(Process.GetCurrentProcess().VirtualMemorySize64 / 1024.0 / 1024.0)));
sb.Append(
string.Format(
Math.Round(Process.GetCurrentProcess().VirtualMemorySize64 / 1024.0 / 1024.0));
sb.AppendFormat(
"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().PeakPagedMemorySize64 / 1024.0 / 1024.0),
Math.Round(Process.GetCurrentProcess().PeakVirtualMemorySize64 / 1024.0 / 1024.0)));
Math.Round(Process.GetCurrentProcess().PeakVirtualMemorySize64 / 1024.0 / 1024.0));
}
else
sb.Append("Process reported as Exited \n");

View File

@ -60,13 +60,21 @@ namespace OpenSim.Framework.Monitoring
private static bool m_enabled;
/// <summary>
/// Average memory churn in bytes per millisecond.
/// Last memory churn in bytes per millisecond.
/// </summary>
public static double AverageMemoryChurn
{
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>
/// Maximum number of statistical samples.
/// </summary>

View File

@ -355,10 +355,25 @@ Asset service request failures: {3}" + Environment.NewLine,
sb.Append(Environment.NewLine);
sb.Append(
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,
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);

View File

@ -25,6 +25,9 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
namespace OpenSim.Framework.Monitoring
{
/// <summary>
@ -32,6 +35,24 @@ namespace OpenSim.Framework.Monitoring
/// </summary>
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 UserStatsCollector userStats;
private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector();
@ -40,6 +61,75 @@ namespace OpenSim.Framework.Monitoring
public static UserStatsCollector UserStats { get { return userStats; } }
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>
/// Start collecting statistics related to assets.
/// Should only be called once.
@ -61,5 +151,275 @@ namespace OpenSim.Framework.Monitoring
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;
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>
@ -220,7 +231,25 @@ namespace OpenSim.Framework.Monitoring
private static bool RemoveThread(int threadID)
{
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)
@ -335,7 +364,9 @@ namespace OpenSim.Framework.Monitoring
if (callbackInfos == null)
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 string lastMapRefresh = "0";
private float m_nonphysPrimMin = 0;
private int m_nonphysPrimMax = 0;
private float m_physPrimMin = 0;
private int m_physPrimMax = 0;
private bool m_clampPrimSize = false;
private int m_objectCapacity = 0;
private int m_linksetCapacity = 0;
private int m_agentCapacity = 0;
private string m_regionType = String.Empty;
private RegionLightShareData m_windlight = new RegionLightShareData();
@ -287,11 +290,21 @@ namespace OpenSim.Framework
set { m_windlight = value; }
}
public float NonphysPrimMin
{
get { return m_nonphysPrimMin; }
}
public int NonphysPrimMax
{
get { return m_nonphysPrimMax; }
}
public float PhysPrimMin
{
get { return m_physPrimMin; }
}
public int PhysPrimMax
{
get { return m_physPrimMax; }
@ -307,6 +320,11 @@ namespace OpenSim.Framework
get { return m_objectCapacity; }
}
public int LinksetCapacity
{
get { return m_linksetCapacity; }
}
public int AgentCapacity
{
get { return m_agentCapacity; }
@ -625,16 +643,31 @@ namespace OpenSim.Framework
m_regionType = config.GetString("RegionType", String.Empty);
allKeys.Remove("RegionType");
// Prim stuff
//
m_nonphysPrimMax = config.GetInt("NonphysicalPrimMax", 0);
allKeys.Remove("NonphysicalPrimMax");
#region Prim stuff
m_nonphysPrimMin = config.GetFloat("NonPhysicalPrimMin", 0);
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);
allKeys.Remove("PhysicalPrimMax");
m_clampPrimSize = config.GetBoolean("ClampPrimSize", false);
allKeys.Remove("ClampPrimSize");
m_objectCapacity = config.GetInt("MaxPrims", 15000);
allKeys.Remove("MaxPrims");
m_linksetCapacity = config.GetInt("LinksetPrims", 0);
allKeys.Remove("LinksetPrims");
#endregion
m_agentCapacity = config.GetInt("MaxAgents", 100);
allKeys.Remove("MaxAgents");
@ -673,16 +706,27 @@ namespace OpenSim.Framework
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);
if (m_physPrimMax != 0)
if (m_physPrimMin > 0)
config.Set("PhysicalPrimMax", m_physPrimMin);
if (m_physPrimMax > 0)
config.Set("PhysicalPrimMax", m_physPrimMax);
config.Set("ClampPrimSize", m_clampPrimSize.ToString());
if (m_objectCapacity != 0)
if (m_objectCapacity > 0)
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);
if (ScopeID != UUID.Zero)
@ -759,9 +803,15 @@ namespace OpenSim.Framework
configMember.addConfigurationOption("lastmap_refresh", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
"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,
"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,
"Maximum size for physical prims", m_physPrimMax.ToString(), true);
@ -771,6 +821,9 @@ namespace OpenSim.Framework
configMember.addConfigurationOption("object_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
"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,
"Max avatars this sim will hold", m_agentCapacity.ToString(), true);
@ -892,6 +945,9 @@ namespace OpenSim.Framework
case "object_capacity":
m_objectCapacity = (int)configuration_result;
break;
case "linkset_capacity":
m_linksetCapacity = (int)configuration_result;
break;
case "agent_capacity":
m_agentCapacity = (int)configuration_result;
break;

View File

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

View File

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

View File

@ -96,11 +96,6 @@ namespace OpenSim.Framework.Servers
get { return m_httpServer; }
}
/// <summary>
/// Holds the non-viewer statistics collection object for this service/server
/// </summary>
protected IStatsCollector m_stats;
public BaseOpenSimServer()
{
m_startuptime = DateTime.Now;
@ -177,10 +172,6 @@ namespace OpenSim.Framework.Servers
"show info",
"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",
"show threads",
"Show thread status", HandleShow);
@ -201,9 +192,20 @@ namespace OpenSim.Framework.Servers
"threads show",
"Show thread status. Synonym for \"show threads\"",
(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>
/// Should be overriden and referenced by descendents if they need to perform extra shutdown processing
/// </summary>
@ -226,12 +228,7 @@ namespace OpenSim.Framework.Servers
{
StringBuilder sb = new StringBuilder("DIAGNOSTICS\n\n");
sb.Append(GetUptimeReport());
if (m_stats != null)
{
sb.Append(m_stats.Report());
}
sb.Append(StatsManager.SimExtraStats.Report());
sb.Append(Environment.NewLine);
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("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 uptime - show server startup time and uptime.");
Notice("show version - show server version.");
@ -409,11 +402,6 @@ namespace OpenSim.Framework.Servers
ShowInfo();
break;
case "stats":
if (m_stats != null)
Notice(m_stats.Report());
break;
case "threads":
Notice(GetThreadsReport());
break;
@ -605,7 +593,6 @@ namespace OpenSim.Framework.Servers
public string osSecret {
// Secret uuid for the simulator
get { return m_osSecret; }
}
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 (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
{
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 HttpServerLogWriter httpserverlog = new HttpServerLogWriter();
/// <summary>
/// Gets or sets the debug level.
/// </summary>
/// <value>
/// See MainServer.DebugLevel.
/// </value>
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;
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, IRequestHandler> m_streamHandlers = new Dictionary<string, IRequestHandler>();
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 =
new Dictionary<string, PollServiceEventArgs>();
@ -245,29 +260,29 @@ namespace OpenSim.Framework.Servers.HttpServer
return new List<string>(m_pollHandlers.Keys);
}
// Note that the agent string is provided simply to differentiate
// the handlers - it is NOT required to be an actual agent header
// value.
public bool AddAgentHandler(string agent, IHttpAgentHandler handler)
{
lock (m_agentHandlers)
{
if (!m_agentHandlers.ContainsKey(agent))
{
m_agentHandlers.Add(agent, handler);
return true;
}
}
//must already have a handler for that path so return false
return false;
}
public List<string> GetAgentHandlerKeys()
{
lock (m_agentHandlers)
return new List<string>(m_agentHandlers.Keys);
}
// // Note that the agent string is provided simply to differentiate
// // the handlers - it is NOT required to be an actual agent header
// // value.
// public bool AddAgentHandler(string agent, IHttpAgentHandler handler)
// {
// lock (m_agentHandlers)
// {
// if (!m_agentHandlers.ContainsKey(agent))
// {
// m_agentHandlers.Add(agent, handler);
// return true;
// }
// }
//
// //must already have a handler for that path so return false
// return false;
// }
//
// public List<string> GetAgentHandlerKeys()
// {
// lock (m_agentHandlers)
// return new List<string>(m_agentHandlers.Keys);
// }
public bool AddLLSDHandler(string path, LLSDMethod handler)
{
@ -296,6 +311,8 @@ namespace OpenSim.Framework.Servers.HttpServer
private void OnRequest(object source, RequestEventArgs args)
{
RequestNumber++;
try
{
IHttpClientContext context = (IHttpClientContext)source;
@ -406,7 +423,6 @@ namespace OpenSim.Framework.Servers.HttpServer
string requestMethod = request.HttpMethod;
string uriString = request.RawUrl;
// string reqnum = "unknown";
int requestStartTick = Environment.TickCount;
// Will be adjusted later on.
@ -423,22 +439,22 @@ namespace OpenSim.Framework.Servers.HttpServer
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true);
// 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
// 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
// probability event; if a request is matched it is normally expected to be
// handled
IHttpAgentHandler agentHandler;
if (TryGetAgentHandler(request, response, out agentHandler))
{
if (HandleAgentRequest(agentHandler, request, response))
{
requestEndTick = Environment.TickCount;
return;
}
}
// // 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
// // 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
// // probability event; if a request is matched it is normally expected to be
// // handled
// IHttpAgentHandler agentHandler;
//
// if (TryGetAgentHandler(request, response, out agentHandler))
// {
// if (HandleAgentRequest(agentHandler, request, response))
// {
// requestEndTick = Environment.TickCount;
// return;
// }
// }
//response.KeepAlive = true;
response.SendChunked = false;
@ -450,9 +466,7 @@ namespace OpenSim.Framework.Servers.HttpServer
if (TryGetStreamHandler(handlerKey, out requestHandler))
{
if (DebugLevel >= 3)
m_log.DebugFormat(
"[BASE HTTP SERVER]: Found stream handler for {0} {1} {2} {3}",
request.HttpMethod, request.Url.PathAndQuery, requestHandler.Name, requestHandler.Description);
LogIncomingToStreamHandler(request, requestHandler);
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 "text/html":
if (DebugLevel >= 3)
m_log.DebugFormat(
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
LogIncomingToContentTypeHandler(request);
buffer = HandleHTTPRequest(request, response);
break;
@ -541,11 +552,8 @@ namespace OpenSim.Framework.Servers.HttpServer
case "application/llsd+xml":
case "application/xml+llsd":
case "application/llsd+json":
if (DebugLevel >= 3)
m_log.DebugFormat(
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
LogIncomingToContentTypeHandler(request);
buffer = HandleLLSDRequests(request, response);
break;
@ -564,9 +572,7 @@ namespace OpenSim.Framework.Servers.HttpServer
if (DoWeHaveALLSDHandler(request.RawUrl))
{
if (DebugLevel >= 3)
m_log.DebugFormat(
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
LogIncomingToContentTypeHandler(request);
buffer = HandleLLSDRequests(request, response);
}
@ -574,18 +580,14 @@ namespace OpenSim.Framework.Servers.HttpServer
else if (DoWeHaveAHTTPHandler(request.RawUrl))
{
if (DebugLevel >= 3)
m_log.DebugFormat(
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
LogIncomingToContentTypeHandler(request);
buffer = HandleHTTPRequest(request, response);
}
else
{
if (DebugLevel >= 3)
m_log.DebugFormat(
"[BASE HTTP SERVER]: Assuming a generic XMLRPC request for {0} {1}",
request.HttpMethod, request.Url.PathAndQuery);
LogIncomingToXmlRpcHandler(request);
// generic login request.
buffer = HandleXmlRpcRequests(request, response);
@ -629,11 +631,11 @@ namespace OpenSim.Framework.Servers.HttpServer
}
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)
{
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);
}
finally
@ -644,14 +646,90 @@ namespace OpenSim.Framework.Servers.HttpServer
if (tickdiff > 3000 && (requestHandler == null || requestHandler.Name == null || requestHandler.Name != "GetTexture"))
{
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,
uriString,
requestHandler != null ? requestHandler.Name : "",
requestHandler != null ? requestHandler.Description : "",
request.RemoteIPEndPoint.ToString(),
request.RemoteIPEndPoint,
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)
{
agentHandler = null;
lock (m_agentHandlers)
{
foreach (IHttpAgentHandler handler in m_agentHandlers.Values)
{
if (handler.Match(request, response))
{
agentHandler = handler;
return true;
}
}
}
return false;
}
// private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler)
// {
// agentHandler = null;
//
// lock (m_agentHandlers)
// {
// foreach (IHttpAgentHandler handler in m_agentHandlers.Values)
// {
// if (handler.Match(request, response))
// {
// agentHandler = handler;
// return true;
// }
// }
// }
//
// return false;
// }
/// <summary>
/// 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);
}
public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler)
{
lock (m_agentHandlers)
{
IHttpAgentHandler foundHandler;
if (m_agentHandlers.TryGetValue(agent, out foundHandler) && foundHandler == handler)
{
m_agentHandlers.Remove(agent);
return true;
}
}
return false;
}
// public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler)
// {
// lock (m_agentHandlers)
// {
// IHttpAgentHandler foundHandler;
//
// if (m_agentHandlers.TryGetValue(agent, out foundHandler) && foundHandler == handler)
// {
// m_agentHandlers.Remove(agent);
// return true;
// }
// }
//
// return false;
// }
public void RemoveXmlRPCHandler(string method)
{

View File

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

View File

@ -29,6 +29,7 @@ using System;
using System.Collections.Generic;
using System.Reflection;
using System.Net;
using System.Text;
using log4net;
using OpenSim.Framework;
using OpenSim.Framework.Console;
@ -47,9 +48,12 @@ namespace OpenSim.Framework.Servers
/// Control the printing of certain debug messages.
/// </summary>
/// <remarks>
/// 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 >= 3, then short notices about all incoming non-poll HTTP requests are logged.
/// 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 >= 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>
public static int DebugLevel
{
@ -101,17 +105,28 @@ namespace OpenSim.Framework.Servers
get { return new Dictionary<uint, BaseHttpServer>(m_Servers); }
}
public static void RegisterHttpConsoleCommands(ICommandConsole console)
{
console.Commands.AddCommand(
"Debug", false, "debug http", "debug http [<level>]",
"Turn on inbound non-poll http request debugging.",
"If level <= 0, then no extra logging is done.\n"
+ "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"
+ "If level >= 3, then short notices about all incoming non-poll HTTP requests are logged.\n"
+ "If no level is specified then the current level is returned.",
"Comms", false, "show http-handlers",
"show http-handlers",
"Show all registered http handlers", HandleShowHttpHandlersCommand);
console.Commands.AddCommand(
"Debug", false, "debug http", "debug http <in|out|all> [<level>]",
"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);
}
@ -119,25 +134,120 @@ namespace OpenSim.Framework.Servers
/// Turn on some debugging values for OpenSim.
/// </summary>
/// <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;
if (int.TryParse(args[2], out newDebug))
{
MainServer.DebugLevel = newDebug;
MainConsole.Instance.OutputFormat("Debug http level set to {0}", newDebug);
MainConsole.Instance.Output("Usage: debug http <in|out|all> 0..6");
return;
}
}
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
{
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>

View File

@ -29,7 +29,7 @@ namespace OpenSim
{
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;
public enum Flavour

View File

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

View File

@ -73,9 +73,6 @@ namespace OpenSim.Framework
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 {
get {
return _assetID;
@ -353,14 +350,13 @@ namespace OpenSim.Framework
}
}
public bool ScriptRunning {
get {
return _scriptRunning;
}
set {
_scriptRunning = value;
}
}
/// <summary>
/// This used ONLY during copy. It can't be relied on at other times!
/// </summary>
/// <remarks>
/// For true script running status, use IEntityInventory.TryGetScriptInstanceRunning() for now.
/// </remarks>
public bool ScriptRunning { get; set; }
// See ICloneable
@ -388,6 +384,7 @@ namespace OpenSim.Framework
public TaskInventoryItem()
{
ScriptRunning = true;
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));
}
/// <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>
/// Are the co-ordinates of the new region visible from the old region?
/// </summary>
@ -862,6 +875,12 @@ namespace OpenSim.Framework
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>
/// Convert an UUID to a raw uuid string. Right now this is a string without hyphens.
/// </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)
{
return SendXmlRpcCommand(url, methodName, args);

View File

@ -53,10 +53,18 @@ namespace OpenSim.Framework
LogManager.GetLogger(
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>
/// Request number for diagnostic purposes.
/// </summary>
public static int RequestNumber = 0;
public static int RequestNumber { get; internal set; }
/// <summary>
/// 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)
{
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";
int tickstart = Util.EnvironmentTickCount();
@ -230,7 +242,7 @@ namespace OpenSim.Framework
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > LongCallTime)
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,
method,
url,
@ -239,10 +251,14 @@ namespace OpenSim.Framework
strBuffer != null
? (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(
"[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);
}
@ -318,7 +334,11 @@ namespace OpenSim.Framework
{
int reqnum = RequestNumber++;
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";
int tickstart = Util.EnvironmentTickCount();
@ -381,7 +401,7 @@ namespace OpenSim.Framework
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > LongCallTime)
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,
method,
url,
@ -390,9 +410,13 @@ namespace OpenSim.Framework
queryString != null
? (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);
}
@ -644,7 +668,6 @@ namespace OpenSim.Framework
/// <returns></returns>
public static string[] GetPreferredImageTypes(string accept)
{
if (accept == null || accept == string.Empty)
return new string[0];
@ -703,14 +726,16 @@ namespace OpenSim.Framework
int maxConnections)
{
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 tickdata = 0;
int tickdiff = 0;
// m_log.DebugFormat("[ASYNC REQUEST]: Starting {0} {1}", verb, requestUrl);
Type type = typeof(TRequest);
WebRequest request = WebRequest.Create(requestUrl);
@ -868,7 +893,7 @@ namespace OpenSim.Framework
}
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,
verb,
requestUrl,
@ -883,6 +908,12 @@ namespace OpenSim.Framework
requestUrl,
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)
{
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 tickdata = 0;
@ -990,7 +1025,7 @@ namespace OpenSim.Framework
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > WebUtil.LongCallTime)
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,
verb,
requestUrl,
@ -998,6 +1033,10 @@ namespace OpenSim.Framework
tickset,
tickdata,
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;
}
@ -1032,7 +1071,11 @@ namespace OpenSim.Framework
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections)
{
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 tickdata = 0;
@ -1151,7 +1194,7 @@ namespace OpenSim.Framework
}
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,
verb,
requestUrl,
@ -1159,6 +1202,12 @@ namespace OpenSim.Framework
tickdata,
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;
}

View File

@ -35,6 +35,7 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Timers;
using log4net;
using NDesk.Options;
using Nini.Config;
using OpenMetaverse;
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 scene",
"debug scene <scripting> <collisions> <physics>",
"Turn on scene debugging", Debug);
"debug scene active|collisions|physics|scripting|teleport true|false",
"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",
"change region <region name>",
@ -291,7 +298,7 @@ namespace OpenSim
m_console.Commands.AddCommand("Archiving", false, "save oar",
//"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.",
// "-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"
@ -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"
+ "--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"
+ "--all saves all the regions in the simulator, instead of just the current region.\n"
+ "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.",
SaveOar);
@ -310,8 +318,11 @@ namespace OpenSim
"Change the scale of a named prim", HandleEditScale);
m_console.Commands.AddCommand("Users", false, "kick user",
"kick user <first> <last> [message]",
"Kick a user off the simulator", KickUserCommand);
"kick user <first> <last> [--force] [message]",
"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",
"show users [full]",
@ -328,10 +339,6 @@ namespace OpenSim
"show circuits",
"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",
"show pending-objects",
"Show # of objects on the pending queues of all scene viewers", HandleShow);
@ -416,6 +423,7 @@ namespace OpenSim
{
RunCommandScript(m_shutdownCommandsFile);
}
base.ShutdownSpecific();
}
@ -453,11 +461,17 @@ namespace OpenSim
/// <param name="cmdparams">name of avatar to kick</param>
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;
string alert = null;
if (cmdparams.Length > 4)
if (mainParams.Count > 4)
alert = String.Format("\n{0}\n", String.Join(" ", cmdparams, 4, cmdparams.Length - 4));
IList agents = SceneManager.GetCurrentSceneAvatars();
@ -466,8 +480,8 @@ namespace OpenSim
{
RegionInfo regionInfo = presence.Scene.RegionInfo;
if (presence.Firstname.ToLower().Contains(cmdparams[2].ToLower()) &&
presence.Lastname.ToLower().Contains(cmdparams[3].ToLower()))
if (presence.Firstname.ToLower().Contains(mainParams[2].ToLower()) &&
presence.Lastname.ToLower().Contains(mainParams[3].ToLower()))
{
MainConsole.Instance.Output(
String.Format(
@ -480,7 +494,7 @@ namespace OpenSim
else
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
{
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;
@ -1002,33 +1017,6 @@ namespace OpenSim
HandleShowCircuits();
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":
MainConsole.Instance.Output("The currently loaded shared modules are:");
foreach (IRegionModule module in m_moduleLoader.GetLoadedSharedModules)
@ -1123,7 +1111,7 @@ namespace OpenSim
aCircuit.Name,
aCircuit.child ? "child" : "root",
aCircuit.circuitcode.ToString(),
aCircuit.IPAddress.ToString(),
aCircuit.IPAddress != null ? aCircuit.IPAddress.ToString() : "not set",
aCircuit.Viewer);
});

View File

@ -232,8 +232,6 @@ namespace OpenSim
base.StartupSpecific();
m_stats = StatsManager.SimExtraStats;
// Create a ModuleLoader instance
m_moduleLoader = new ModuleLoader(m_config.Source);
@ -249,13 +247,14 @@ namespace OpenSim
plugin.PostInitialise();
}
AddPluginCommands();
if (m_console != null)
{
StatsManager.RegisterConsoleCommands(m_console);
AddPluginCommands(m_console);
}
}
protected virtual void AddPluginCommands()
{
// If console exists add plugin commands.
if (m_console != null)
protected virtual void AddPluginCommands(CommandConsole console)
{
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
// away at some point.
m_console.Commands.AddCommand(capitalizedTopic, false, "help " + topic,
console.Commands.AddCommand(capitalizedTopic, false, "help " + topic,
"help " + capitalizedTopic,
"Get help on plugin command '" + topic + "'",
HandleCommanderHelp);
m_console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic,
console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic,
"help " + capitalizedTopic,
"Get help on plugin command '" + topic + "'",
HandleCommanderHelp);
@ -289,14 +288,13 @@ namespace OpenSim
foreach (string command in commander.Commands.Keys)
{
m_console.Commands.AddCommand(capitalizedTopic, false,
console.Commands.AddCommand(capitalizedTopic, false,
topic + " " + command,
topic + " " + commander.Commands[command].ShortHelp(),
String.Empty, HandleCommanderCommand);
}
}
}
}
private void HandleCommanderCommand(string module, string[] cmd)
{
@ -623,7 +621,7 @@ namespace OpenSim
if (account == null)
{
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
{

View File

@ -241,8 +241,8 @@ namespace OpenSim.Region.ClientStack.Linden
m_HostCapsObj.RegisterHandler(
"SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest, "SEED", null));
m_log.DebugFormat(
"[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID);
// m_log.DebugFormat(
// "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID);
//m_capsHandlers["MapLayer"] =
// new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST",
@ -337,11 +337,12 @@ namespace OpenSim.Region.ClientStack.Linden
public string SeedCapRequest(string request, string path, string param,
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))
{
m_log.DebugFormat(
m_log.WarnFormat(
"[CAPS]: Unauthorized CAPS client {0} from {1}",
m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint);

View File

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

View File

@ -109,7 +109,7 @@ namespace OpenSim.Region.ClientStack.Linden
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(
"SimConsoleAsync",
new ConsoleHandler("/CAPS/" + capID + "/", "SimConsoleAsync", agentID, this, m_scene));

View File

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

View File

@ -47,6 +47,7 @@ using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces;
using Timer = System.Timers.Timer;
using AssetLandmark = OpenSim.Framework.AssetLandmark;
using RegionFlags = OpenMetaverse.RegionFlags;
using Nini.Config;
using System.IO;
@ -355,7 +356,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private bool m_deliverPackets = true;
private int m_animationSequenceNumber = 1;
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<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@ -510,19 +521,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// </summary>
public void Close()
{
Close(true);
Close(true, false);
}
/// <summary>
/// Shut down the client view
/// </summary>
public void Close(bool sendStop)
public void Close(bool sendStop, bool force)
{
// 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.
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;
IsActive = false;
@ -837,8 +847,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
OutPacket(mov, ThrottleOutPacketType.Unknown);
}
public void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName,
UUID fromAgentID, byte source, byte audible)
public void SendChatMessage(
string message, byte type, Vector3 fromPos, string fromName,
UUID fromAgentID, UUID ownerID, byte source, byte audible)
{
ChatFromSimulatorPacket reply = (ChatFromSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.ChatFromSimulator);
reply.ChatData.Audible = audible;
@ -847,7 +858,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
reply.ChatData.SourceType = source;
reply.ChatData.Position = fromPos;
reply.ChatData.FromName = Util.StringToBytes256(fromName);
reply.ChatData.OwnerID = fromAgentID;
reply.ChatData.OwnerID = ownerID;
reply.ChatData.SourceID = fromAgentID;
OutPacket(reply, ThrottleOutPacketType.Unknown);
@ -3985,7 +3996,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
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.TimeDilation = timeDilation;
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@ -4030,7 +4042,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
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.TimeDilation = timeDilation;
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@ -4038,7 +4052,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
for (int i = 0; i < blocks.Count; 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
@ -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.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;
if (textureEntry != null && textureEntry.Length > 0)
@ -5289,14 +5305,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
protected virtual void RegisterLocalPacketHandlers()
{
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.ViewerEffect, HandleViewerEffect, false);
AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false);
AddLocalPacketHandler(PacketType.ParcelBuy, HandleParcelBuyRequest, false);
AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest, false);
AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest, false);
AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest);
AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest);
AddLocalPacketHandler(PacketType.GenericMessage, HandleGenericMessage);
AddLocalPacketHandler(PacketType.AvatarPropertiesRequest, HandleAvatarPropertiesRequest);
AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer);
@ -5518,81 +5538,84 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region Scene/Avatar
private bool HandleAgentUpdate(IClientAPI sener, Packet Pack)
private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
{
if (OnAgentUpdate != null)
{
bool update = false;
AgentUpdatePacket agenUpdate = (AgentUpdatePacket)Pack;
AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
#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;
}
#endregion
AgentUpdatePacket.AgentDataBlock x = agenUpdate.AgentData;
bool update = false;
AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
// We can only check when we have something to check
// against.
if (lastarg != null)
if (m_lastAgentUpdateArgs != null)
{
// These should be ordered from most-likely to
// least likely to change. I've made an initial
// guess at that.
update =
(
(x.BodyRotation != lastarg.BodyRotation) ||
(x.CameraAtAxis != lastarg.CameraAtAxis) ||
(x.CameraCenter != lastarg.CameraCenter) ||
(x.CameraLeftAxis != lastarg.CameraLeftAxis) ||
(x.CameraUpAxis != lastarg.CameraUpAxis) ||
(x.ControlFlags != lastarg.ControlFlags) ||
(x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) ||
(x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) ||
(x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) ||
(x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
(x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
(x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
(x.ControlFlags != 0) ||
(x.Far != lastarg.Far) ||
(x.Flags != lastarg.Flags) ||
(x.State != lastarg.State) ||
(x.HeadRotation != lastarg.HeadRotation) ||
(x.SessionID != lastarg.SessionID) ||
(x.AgentID != lastarg.AgentID)
(x.Far != m_lastAgentUpdateArgs.Far) ||
(x.Flags != m_lastAgentUpdateArgs.Flags) ||
(x.State != m_lastAgentUpdateArgs.State) ||
(x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) ||
(x.SessionID != m_lastAgentUpdateArgs.SessionID) ||
(x.AgentID != m_lastAgentUpdateArgs.AgentID)
);
}
else
{
m_lastAgentUpdateArgs = new AgentUpdateArgs();
update = true;
}
// These should be ordered from most-likely to
// least likely to change. I've made an initial
// guess at that.
if (update)
{
// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name);
AgentUpdateArgs arg = new AgentUpdateArgs();
arg.AgentID = x.AgentID;
arg.BodyRotation = x.BodyRotation;
arg.CameraAtAxis = x.CameraAtAxis;
arg.CameraCenter = x.CameraCenter;
arg.CameraLeftAxis = x.CameraLeftAxis;
arg.CameraUpAxis = x.CameraUpAxis;
arg.ControlFlags = x.ControlFlags;
arg.Far = x.Far;
arg.Flags = x.Flags;
arg.HeadRotation = x.HeadRotation;
arg.SessionID = x.SessionID;
arg.State = x.State;
m_lastAgentUpdateArgs.AgentID = x.AgentID;
m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation;
m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter;
m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags;
m_lastAgentUpdateArgs.Far = x.Far;
m_lastAgentUpdateArgs.Flags = x.Flags;
m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation;
m_lastAgentUpdateArgs.SessionID = x.SessionID;
m_lastAgentUpdateArgs.State = x.State;
UpdateAgent handlerAgentUpdate = OnAgentUpdate;
UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
lastarg = arg; // save this set of arguments for nexttime
if (handlerPreAgentUpdate != null)
OnPreAgentUpdate(this, arg);
OnPreAgentUpdate(this, m_lastAgentUpdateArgs);
if (handlerAgentUpdate != null)
OnAgentUpdate(this, arg);
OnAgentUpdate(this, m_lastAgentUpdateArgs);
handlerAgentUpdate = null;
handlerPreAgentUpdate = null;
}
}
PacketPool.Instance.ReturnPacket(packet);
return true;
}
@ -5964,7 +5987,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
msgpack.MessageBlock.ID,
msgpack.MessageBlock.Offline != 0 ? true : false,
msgpack.MessageBlock.Position,
msgpack.MessageBlock.BinaryBucket);
msgpack.MessageBlock.BinaryBucket,
true);
handlerInstantMessage(this, im);
}
@ -9251,7 +9275,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
#endregion
switch (Utils.BytesToString(messagePacket.MethodData.Method))
string method = Utils.BytesToString(messagePacket.MethodData.Method);
switch (method)
{
case "getinfo":
if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
@ -9567,7 +9593,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return true;
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;
}
@ -11960,7 +11996,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
logPacket = false;
if (DebugPacketLevel <= 50
& (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
&& (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
logPacket = false;
if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily)
@ -12034,8 +12070,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (!ProcessPacketMethod(packet))
m_log.Warn("[CLIENT]: unhandled packet " + packet.Type);
PacketPool.Instance.ReturnPacket(packet);
}
private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
@ -12204,7 +12238,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
Kick(reason);
Thread.Sleep(1000);
Close();
Disconnect();
}
public void Disconnect()
@ -12492,7 +12526,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
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.TimeDilation = timeDilation;
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];

View File

@ -37,6 +37,7 @@ using log4net;
using Nini.Config;
using OpenMetaverse.Packets;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Scenes;
using OpenMetaverse;
@ -100,9 +101,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>The measured resolution of Environment.TickCount</summary>
public readonly float TickCountResolution;
/// <summary>Number of prim updates to put on the queue each time the
/// OnQueueEmpty event is triggered for updates</summary>
public readonly int PrimUpdatesPerCallback;
/// <summary>Number of texture packets to put on the queue each time the
/// OnQueueEmpty event is triggered for textures</summary>
public readonly int TextureSendLimit;
@ -124,28 +127,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>Manages authentication for agent circuits</summary>
private AgentCircuitManager m_circuitManager;
/// <summary>Reference to the scene this UDP server is attached to</summary>
protected Scene m_scene;
/// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
private Location m_location;
/// <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
/// stack. Use zero to leave this value as the default</summary>
private int m_recvBufferSize;
/// <summary>Flag to process packets asynchronously or synchronously</summary>
private bool m_asyncPacketHandling;
/// <summary>Tracks whether or not a packet was sent each round so we know
/// whether or not to sleep</summary>
private bool m_packetSent;
/// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary>
private int m_elapsedMSSinceLastStatReport = 0;
/// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary>
private int m_tickLastOutgoingPacketHandler;
/// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary>
private int m_elapsedMSOutgoingPacketHandler;
/// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary>
private int m_elapsed100MSOutgoingPacketHandler;
/// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary>
private int m_elapsed500MSOutgoingPacketHandler;
@ -159,6 +171,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
protected bool m_sendPing;
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_maxRTO = 0;
@ -180,7 +195,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// </summary>
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)
{
#region Environment.TickCount Measurement
@ -202,6 +219,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_circuitManager = circuitManager;
int sceneThrottleBps = 0;
bool usePools = false;
IConfig config = configSource.Configs["ClientStack.LindenUDP"];
if (config != null)
@ -227,6 +245,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
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
config = configSource.Configs["Statistics.Binary"];
m_shouldCollectStats = false;
@ -254,20 +282,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_throttle = new TokenBucket(null, sceneThrottleBps);
ThrottleRates = new ThrottleRates(configSource);
if (usePools)
EnablePools();
}
public void Start()
{
if (m_scene == null)
throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference");
StartInbound();
StartOutbound();
m_elapsedMSSinceLastStatReport = Environment.TickCount;
}
private void StartInbound()
{
m_log.InfoFormat(
"[LLUDPSERVER]: Starting the LLUDP server in {0} mode",
m_asyncPacketHandling ? "asynchronous" : "synchronous");
"[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
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(
IncomingPacketHandler,
string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName),
@ -276,6 +312,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
true,
GetWatchdogIncomingAlarmData,
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(
OutgoingPacketHandler,
@ -285,8 +328,57 @@ namespace OpenSim.Region.ClientStack.LindenUDP
true,
GetWatchdogOutgoingAlarmData,
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>
@ -311,12 +403,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
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)
{
if (m_scene != null)
@ -333,6 +419,117 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_scene = (Scene)scene;
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)
@ -416,6 +613,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
byte[] data = packet.ToBytes();
SendPacketData(udpClient, data, packet.Type, category, method);
}
PacketPool.Instance.ReturnPacket(packet);
}
/// <summary>
@ -700,7 +899,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
LLUDPClient udpClient = null;
Packet packet = null;
int packetEnd = buffer.DataLength - 1;
IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint;
IPEndPoint endPoint = (IPEndPoint)buffer.RemoteEndPoint;
#region Decoding
@ -710,7 +909,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
return; // Drop undersizd packet
return; // Drop undersized packet
}
int headerLen = 7;
@ -733,7 +932,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
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
((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
}
@ -752,7 +957,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
if (m_malformedCount < 100)
m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
m_malformedCount++;
if ((m_malformedCount % 100000) == 0)
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
IClientAPI client = null;
if (!m_scene.TryGetClient(address, out client))
if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
{
// UseCircuitCode handling
if (packet.Type == PacketType.UseCircuitCode)
@ -780,13 +987,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// And if there is a UseCircuitCode pending, also drop it
lock (m_pendingCache)
{
if (m_pendingCache.Contains(address))
if (m_pendingCache.Contains(endPoint))
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);
@ -798,7 +1007,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
lock (m_pendingCache)
{
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);
queue.Enqueue(buffer);
@ -834,6 +1043,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Handle appended ACKs
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++)
udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
}
@ -843,6 +1056,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
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++)
udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
@ -856,6 +1073,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
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);
// 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)
{
// 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
StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
CompletePing(udpClient, startPing.PingID.PingID);
@ -921,13 +1144,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#endregion Ping Check Handling
IncomingPacket incomingPacket;
// Inbox insertion
if (packet.Type == PacketType.AgentUpdate ||
packet.Type == PacketType.ChatFromViewer)
packetInbox.EnqueueHigh(new IncomingPacket((LLClientView)client, packet));
if (UsePools)
{
incomingPacket = m_incomingPacketPool.GetObject();
incomingPacket.Client = (LLClientView)client;
incomingPacket.Packet = packet;
}
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
@ -1013,21 +1248,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private void HandleUseCircuitCode(object o)
{
IPEndPoint remoteEndPoint = null;
IPEndPoint endPoint = null;
IClientAPI client = null;
try
{
// DateTime startTime = DateTime.Now;
object[] array = (object[])o;
UDPPacketBuffer buffer = (UDPPacketBuffer)array[0];
endPoint = (IPEndPoint)array[0];
UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
m_log.DebugFormat(
"[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, buffer.RemoteEndPoint);
remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;
uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, endPoint);
AuthenticateResponse sessionInfo;
if (IsClientAuthorized(uccp, out sessionInfo))
@ -1038,13 +1271,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
uccp.CircuitCode.Code,
uccp.CircuitCode.ID,
uccp.CircuitCode.SessionID,
remoteEndPoint,
endPoint,
sessionInfo);
// 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
// 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.
if (client != null)
@ -1058,12 +1291,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
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");
return;
}
m_pendingCache.Remove(remoteEndPoint);
m_pendingCache.Remove(endPoint);
}
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.
m_log.WarnFormat(
"[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)
m_pendingCache.Remove(remoteEndPoint);
m_pendingCache.Remove(endPoint);
}
// m_log.DebugFormat(
@ -1095,7 +1328,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
m_log.ErrorFormat(
"[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.AgentId.ToString() : "unknown",
e.Message,
@ -1160,9 +1393,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
IClientAPI client = null;
// In priciple there shouldn't be more than one thread here, ever.
// But in case that happens, we need to synchronize this piece of code
// because it's too important
// We currently synchronize this code across the whole scene to avoid issues such as
// http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
// consistently, this lock could probably be removed.
lock (this)
{
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
Culture.SetCurrentCulture();
while (base.IsRunning)
while (IsRunningInbound)
{
m_scene.ThreadAlive(1);
try
@ -1228,7 +1461,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
if (packetInbox.Dequeue(100, ref incomingPacket))
{
ProcessInPacket(incomingPacket);//, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket);
if (UsePools)
m_incomingPacketPool.ReturnObject(incomingPacket);
}
}
catch (Exception ex)
{
@ -1255,7 +1493,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Action generic every round
Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
while (base.IsRunning)
while (base.IsRunningOutbound)
{
m_scene.ThreadAlive(2);
try
@ -1523,7 +1761,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (!client.IsLoggingOut)
{
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.Threading;
using log4net;
using OpenSim.Framework;
using OpenSim.Framework.Monitoring;
namespace OpenMetaverse
{
@ -58,17 +60,31 @@ namespace OpenMetaverse
/// <summary>Flag to process packets asynchronously or synchronously</summary>
private bool m_asyncPacketHandling;
/// <summary>The all important shutdown flag</summary>
private volatile bool m_shutdownFlag = true;
/// <summary>
/// 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>
public bool IsRunning { get { return !m_shutdownFlag; } }
/// <summary>
/// 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>
/// Default constructor
/// </summary>
/// <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="usePool">Are we to use an object pool to get objects for handing inbound data?</param>
public OpenSimUDPBase(IPAddress bindAddress, int port)
{
m_localBindAddress = bindAddress;
@ -76,7 +92,7 @@ namespace OpenMetaverse
}
/// <summary>
/// Start the UDP server
/// Start inbound UDP packet handling.
/// </summary>
/// <param name="recvBufferSize">The size of the receive buffer for
/// 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
/// connection). This call is ignored on Mono where the flag is not
/// necessary</remarks>
public void Start(int recvBufferSize, bool asyncPacketHandling)
public void StartInbound(int recvBufferSize, bool asyncPacketHandling)
{
m_asyncPacketHandling = asyncPacketHandling;
if (m_shutdownFlag)
if (!IsRunningInbound)
{
const int SIO_UDP_CONNRESET = -1744830452;
@ -123,8 +139,7 @@ namespace OpenMetaverse
m_udpSocket.Bind(ipep);
// we're not shutting down, we're starting up
m_shutdownFlag = false;
IsRunningInbound = true;
// kick off an async receive. The Start() method will return, the
// actual receives will occur asynchronously and will be caught in
@ -134,28 +149,84 @@ namespace OpenMetaverse
}
/// <summary>
/// Stops the UDP server
/// Start outbound UDP packet handling.
/// </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
// 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.
m_shutdownFlag = true;
IsRunningInbound = false;
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()
{
// allocate a packet buffer
//WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut();
UDPPacketBuffer buf = new UDPPacketBuffer();
UDPPacketBuffer buf;
if (!m_shutdownFlag)
if (UsePools)
buf = m_pool.GetObject();
else
buf = new UDPPacketBuffer();
if (IsRunningInbound)
{
try
{
@ -208,7 +279,7 @@ namespace OpenMetaverse
{
// Asynchronous receive operations will complete here through the call
// to AsyncBeginReceive
if (!m_shutdownFlag)
if (IsRunningInbound)
{
// Asynchronous mode will start another receive before the
// callback for this packet is even fired. Very parallel :-)
@ -217,8 +288,6 @@ namespace OpenMetaverse
// get the buffer that was created in AsyncBeginReceive
// this is the received data
//WrappedObject<UDPPacketBuffer> wrappedBuffer = (WrappedObject<UDPPacketBuffer>)iar.AsyncState;
//UDPPacketBuffer buffer = wrappedBuffer.Instance;
UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
try
@ -235,7 +304,8 @@ namespace OpenMetaverse
catch (ObjectDisposedException) { }
finally
{
//wrappedBuffer.Dispose();
if (UsePools)
m_pool.ReturnObject(buffer);
// Synchronous mode waits until the packet callback completes
// before starting the receive to fetch another packet
@ -248,7 +318,7 @@ namespace OpenMetaverse
public void AsyncBeginSend(UDPPacketBuffer buf)
{
if (!m_shutdownFlag)
if (IsRunningOutbound)
{
try
{

View File

@ -31,10 +31,10 @@ using System.Reflection;
using OpenMetaverse;
using OpenMetaverse.Packets;
using log4net;
using OpenSim.Framework.Monitoring;
namespace OpenSim.Framework
namespace OpenSim.Region.ClientStack.LindenUDP
{
public sealed class PacketPool
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@ -44,14 +44,32 @@ namespace OpenSim.Framework
private bool packetPoolEnabled = 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 static Dictionary<Type, Stack<Object>> DataBlocks =
new Dictionary<Type, Stack<Object>>();
static PacketPool()
{
}
private static Dictionary<Type, Stack<Object>> DataBlocks = new Dictionary<Type, Stack<Object>>();
public static PacketPool Instance
{
@ -70,8 +88,45 @@ namespace OpenSim.Framework
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)
{
m_packetsReusedStat.Consequent++;
Packet packet;
if (!packetPoolEnabled)
@ -81,13 +136,19 @@ namespace OpenSim.Framework
{
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
packet = Packet.BuildPacket(type);
}
else
{
// m_log.DebugFormat("[PACKETPOOL]: Pulling {0} packet", type);
// 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);
Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
// Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
int i = 0;
Packet packet = GetPacket(type);
@ -183,6 +244,7 @@ namespace OpenSim.Framework
switch (packet.Type)
{
// List pooling packets here
case PacketType.AgentUpdate:
case PacketType.PacketAck:
case PacketType.ObjectUpdate:
case PacketType.ImprovedTerseObjectUpdate:
@ -197,7 +259,9 @@ namespace OpenSim.Framework
if ((pool[type]).Count < 50)
{
(pool[type]).Push(packet);
// m_log.DebugFormat("[PACKETPOOL]: Pushing {0} packet", type);
pool[type].Push(packet);
}
}
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)
{
m_blocksReusedStat.Consequent++;
Stack<Object> s;
if (DataBlocks.TryGetValue(typeof(T), out s))
{
if (s.Count > 0)
{
m_blocksReusedStat.Antecedent++;
return (T)s.Pop();
}
}
else
{
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)
return;

View File

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

View File

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

View File

@ -57,40 +57,37 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
}
/// <summary>
/// Return a xfer uploader if one does not already exist.
/// Return the xfer uploader for the given transaction.
/// </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="assetID">
/// We must transfer the new asset ID into the uploader on creation, otherwise
/// 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)
/// <returns>The asset xfer uploader</returns>
public AssetXferUploader RequestXferUploader(UUID transactionID)
{
AssetXferUploader uploader;
lock (XferUploaders)
{
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(
// "[AGENT ASSETS TRANSACTIONS]: Adding asset xfer uploader {0} since it didn't previously exist", transactionID);
XferUploaders.Add(transactionID, uploader);
}
else
{
uploader = XferUploaders[transactionID];
}
}
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)
{
@ -151,117 +148,30 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
string description, string name, sbyte invType,
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(
remoteClient, transactionID, folderID,
callbackID, description, name, invType, type,
wearableType, nextOwnerMask);
remoteClient, folderID, callbackID,
description, name, invType, type, wearableType, nextOwnerMask);
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,
SceneObjectPart part, UUID transactionID,
TaskInventoryItem item)
{
AssetXferUploader uploader = null;
AssetXferUploader uploader = RequestXferUploader(transactionID);
lock (XferUploaders)
{
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);
}
uploader.RequestUpdateTaskInventoryItem(remoteClient, item);
}
public void RequestUpdateInventoryItem(IClientAPI remoteClient,
UUID transactionID, InventoryItemBase item)
{
AssetXferUploader uploader = null;
AssetXferUploader uploader = RequestXferUploader(transactionID);
lock (XferUploaders)
{
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);
}
uploader.RequestUpdateInventoryItem(remoteClient, item);
}
}
}

View File

@ -215,7 +215,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item)
{
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);
AgentAssetTransactions transactions =
@ -274,13 +274,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
}
AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId);
AssetXferUploader uploader = transactions.RequestXferUploader(transaction, assetID);
if (uploader != null)
{
uploader.Initialise(remoteClient, assetID, transaction, type,
data, storeLocal, tempFile);
}
AssetXferUploader uploader = transactions.RequestXferUploader(transaction);
uploader.StartUpload(remoteClient, assetID, transaction, type, data, storeLocal, tempFile);
}
/// <summary>

View File

@ -48,40 +48,76 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
};
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>
/// Reference to the object that holds this uploader. Used to remove ourselves from it's list if we
/// are performing a delayed update.
/// </summary>
AgentAssetTransactions m_transactions;
private UploadState m_uploadState = UploadState.New;
private AssetBase m_asset;
private UUID InventFolder = UUID.Zero;
private sbyte invType = 0;
private bool m_createItem = false;
private uint m_createItemCallback = 0;
private bool m_updateItem = false;
private bool m_createItem;
private uint m_createItemCallback;
private bool m_updateItem;
private InventoryItemBase m_updateItemData;
private bool m_updateTaskItem;
private TaskInventoryItem m_updateTaskItemData;
private string m_description = String.Empty;
private bool m_dumpAssetToFile;
private bool m_finished = false;
private string m_name = String.Empty;
private bool m_storeLocal;
// private bool m_storeLocal;
private uint nextPerm = 0;
private IClientAPI ourClient;
private UUID TransactionID = UUID.Zero;
private UUID m_transactionID;
private sbyte type = 0;
private byte wearableType = 0;
private byte[] m_oldData = null;
public ulong XferID;
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_transactionID = transactionID;
m_Scene = scene;
m_asset = new AssetBase() { FullID = assetID };
m_dumpAssetToFile = dumpAssetToFile;
}
@ -127,30 +163,50 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
}
/// <summary>
/// Initialise asset transfer from the client
/// Start asset transfer from the client
/// </summary>
/// <param name="xferID"></param>
/// <param name="packetID"></param>
/// <param name="data"></param>
public void Initialise(IClientAPI remoteClient, UUID assetID,
UUID transaction, sbyte type, byte[] data, bool storeLocal,
/// <param name="remoteClient"></param>
/// <param name="assetID"></param>
/// <param name="transaction"></param>
/// <param name="type"></param>
/// <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)
{
// 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}",
// 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;
m_asset.Name = "blank";
m_asset.Description = "empty";
m_asset.FullID = assetID;
m_asset.Type = type;
m_asset.CreatorID = remoteClient.AgentId.ToString();
m_asset.Data = data;
m_asset.Local = storeLocal;
m_asset.Temporary = tempFile;
TransactionID = transaction;
m_storeLocal = storeLocal;
// m_storeLocal = storeLocal;
if (m_asset.Data.Length > 2)
{
@ -175,36 +231,35 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
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
// message from other client UDP.
lock (this)
{
m_finished = true;
m_uploadState = UploadState.Complete;
ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true, m_asset.FullID);
if (m_createItem)
{
DoCreateItem(m_createItemCallback);
CompleteCreateItem(m_createItemCallback);
}
else if (m_updateItem)
{
StoreAssetForItemUpdate(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);
CompleteItemUpdate(m_updateItemData);
}
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(
"[ASSET XFER UPLOADER]: Uploaded asset {0} for transaction {1}",
m_asset.FullID, TransactionID);
m_asset.FullID, m_transactionID);
if (m_dumpAssetToFile)
{
@ -232,11 +287,9 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
}
public void RequestCreateInventoryItem(IClientAPI remoteClient,
UUID transactionID, UUID folderID, uint callbackID,
UUID folderID, uint callbackID,
string description, string name, sbyte invType,
sbyte type, byte wearableType, uint nextOwnerMask)
{
if (TransactionID == transactionID)
{
InventFolder = folderID;
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.
lock (this)
{
if (m_finished)
if (m_uploadState == UploadState.Complete)
{
DoCreateItem(callbackID);
CompleteCreateItem(callbackID);
}
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.
lock (this)
@ -280,9 +332,9 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
item.AssetID = m_asset.FullID;
m_Scene.InventoryService.UpdateItem(item);
if (m_finished)
if (m_uploadState == UploadState.Complete)
{
StoreAssetForItemUpdate(item);
CompleteItemUpdate(item);
}
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>
/// Store the asset for the given item.
/// Store the asset for the given item when it has been uploaded.
/// </summary>
/// <param name="item"></param>
private void StoreAssetForItemUpdate(InventoryItemBase item)
private void CompleteItemUpdate(InventoryItemBase item)
{
// m_log.DebugFormat(
// "[ASSET XFER UPLOADER]: Storing asset {0} for earlier item update for {1} for {2}",
// m_asset.FullID, item.Name, ourClient.Name);
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();
m_Scene.AssetService.Store(m_asset);
@ -339,6 +430,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
ourClient.SendInventoryItemCreateUpdate(item, callbackID);
else
ourClient.SendAlertMessage("Unable to create inventory item");
m_transactions.RemoveXferUploader(m_transactionID);
}
private void ValidateAssets()
@ -416,7 +509,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
/// <returns>null if the asset has not finished uploading</returns>
public AssetBase GetAssetData()
{
if (m_finished)
if (m_uploadState == UploadState.Complete)
{
ValidateAssets();
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: AddinDependency("OpenSim", "0.5")]
namespace Flotsam.RegionModules.AssetCache
namespace OpenSim.Region.CoreModules.Asset
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
public class FlotsamAssetCache : ISharedRegionModule, IImprovedAssetCache, IAssetService
@ -107,8 +107,6 @@ namespace Flotsam.RegionModules.AssetCache
private IAssetService m_AssetService;
private List<Scene> m_Scenes = new List<Scene>();
private bool m_DeepScanBeforePurge;
public FlotsamAssetCache()
{
m_InvalidChars.AddRange(Path.GetInvalidPathChars());
@ -170,8 +168,6 @@ namespace Flotsam.RegionModules.AssetCache
m_CacheDirectoryTierLen = assetConfig.GetInt("CacheDirectoryTierLength", m_CacheDirectoryTierLen);
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);
@ -519,13 +515,10 @@ namespace Flotsam.RegionModules.AssetCache
// Purge all files last accessed prior to this point
DateTime purgeLine = DateTime.Now - m_FileExpiration;
// An optional deep scan at this point will ensure assets present in scenes,
// or referenced by objects in the scene, but not recently accessed
// are not purged.
if (m_DeepScanBeforePurge)
{
CacheScenes();
}
// An asset cache may contain local non-temporary assets that are not in the asset service. Therefore,
// before cleaning up expired files we must scan the objects in the scene to make sure that we retain
// such local assets if they have not been recently accessed.
TouchAllSceneAssets(false);
foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
{
@ -718,11 +711,14 @@ namespace Flotsam.RegionModules.AssetCache
/// <summary>
/// Iterates through all Scenes, doing a deep scan through assets
/// to cache all assets present in the scene or referenced by assets
/// in the scene
/// to update the access time of all assets present in the scene or referenced by assets
/// in the scene.
/// </summary>
/// <returns></returns>
private int CacheScenes()
/// <param name="storeUncached">
/// 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);
@ -745,7 +741,7 @@ namespace Flotsam.RegionModules.AssetCache
{
File.SetLastAccessTime(filename, DateTime.Now);
}
else
else if (storeUncached)
{
m_AssetService.Get(assetID.ToString());
}
@ -873,13 +869,14 @@ namespace Flotsam.RegionModules.AssetCache
break;
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 {
int assetsCached = CacheScenes();
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Completed Scene Caching, {0} assets found.", assetsCached);
int assetReferenceTotal = TouchAllSceneAssets(true);
m_log.InfoFormat(
"[FLOTSAM ASSET CACHE]: Completed check with {0} assets.",
assetReferenceTotal);
});
break;

View File

@ -35,7 +35,6 @@ using Nini.Config;
using NUnit.Framework;
using OpenMetaverse;
using OpenMetaverse.Assets;
using Flotsam.RegionModules.AssetCache;
using OpenSim.Framework;
using OpenSim.Region.Framework.Scenes;
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)
{
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)
{
@ -460,6 +474,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
}
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)
return;
@ -502,7 +521,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
so.FromItemID = UUID.Zero;
SceneObjectPart rootPart = so.RootPart;
so.AbsolutePosition = sp.AbsolutePosition;
so.AbsolutePosition = absolutePos;
if (absoluteRot != Quaternion.Identity)
{
so.UpdateGroupRotationR(absoluteRot);
}
so.AttachedAvatar = UUID.Zero;
rootPart.SetParentLocalId(0);
so.ClearPartAttachmentData();
@ -616,9 +639,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (grp.HasGroupChanged)
{
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}",
// grp.UUID, grp.AttachmentPoint);
m_log.DebugFormat(
"[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}",
grp.UUID, grp.AttachmentPoint);
string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp, scriptedState);
@ -862,7 +885,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
// This will throw if the attachment fails
try
{
AttachObject(sp, objatt, attachmentPt, false, false, false);
AttachObjectInternal(sp, objatt, attachmentPt, false, false, false);
}
catch (Exception e)
{
@ -933,6 +956,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID);
item = m_scene.InventoryService.GetItem(item);
if (item == null)
return;
bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID);
if (changed && m_scene.AvatarFactory != null)
{

View File

@ -62,7 +62,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
public class AttachmentsModuleTests : OpenSimTestCase
{
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]
public void FixtureInit()
@ -83,7 +86,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
{
// Console.WriteLine("Got chat [{0}]", oscm.Message);
m_osChatMessageReceived = oscm;
// m_osChatMessageReceived = oscm;
m_chatEvent.Set();
}
@ -99,6 +102,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
"attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config);
SceneHelpers.SetupSceneModules(scene, config, modules.ToArray());
scene.EventManager.OnAttach += (localID, itemID, avatarID) => m_numberOfAttachEventsFired++;
return scene;
}
@ -181,6 +186,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
m_numberOfAttachEventsFired = 0;
Scene scene = CreateTestScene();
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
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);
m_numberOfAttachEventsFired = 0;
scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false);
// Check status on scene presence
@ -216,7 +224,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// TestHelpers.DisableLogging();
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
}
/// <summary>
@ -228,6 +237,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
m_numberOfAttachEventsFired = 0;
Scene scene = CreateTestScene();
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
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(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
}
[Test]
@ -261,6 +275,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
m_numberOfAttachEventsFired = 0;
scene.AttachmentsModule.RezSingleAttachmentFromInventory(
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(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
}
/// <summary>
@ -338,6 +356,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
ISceneEntity so
= scene.AttachmentsModule.RezSingleAttachmentFromInventory(
sp, attItem.ID, (uint)AttachmentPoint.Chest);
m_numberOfAttachEventsFired = 0;
scene.AttachmentsModule.DetachSingleAttachmentToGround(sp, so.LocalId);
// Check scene presence status
@ -353,6 +373,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
// Check object in scene
Assert.That(scene.GetSceneObjectGroup("att"), Is.Not.Null);
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
}
[Test]
@ -369,6 +392,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
SceneObjectGroup so
= (SceneObjectGroup)scene.AttachmentsModule.RezSingleAttachmentFromInventory(
sp, attItem.ID, (uint)AttachmentPoint.Chest);
m_numberOfAttachEventsFired = 0;
scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, so);
// 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(scene.GetSceneObjectGroups().Count, Is.EqualTo(0));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
}
/// <summary>
@ -461,10 +489,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
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.
Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null);
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
}
[Test]
@ -480,6 +512,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
acd.Appearance = new AvatarAppearance();
acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID);
m_numberOfAttachEventsFired = 0;
ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd);
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(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// Check events. We expect OnAttach to fire on login.
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
}
[Test]
@ -522,10 +559,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Vector3 newPosition = new Vector3(1, 2, 4);
m_numberOfAttachEventsFired = 0;
scene.SceneGraph.UpdatePrimGroupPosition(attSo.LocalId, newPosition, sp.ControllingClient);
Assert.That(attSo.AbsolutePosition, Is.EqualTo(sp.AbsolutePosition));
Assert.That(attSo.RootPart.AttachedPos, Is.EqualTo(newPosition));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
}
[Test]
@ -574,6 +615,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Vector3 teleportPosition = new Vector3(10, 11, 12);
Vector3 teleportLookAt = new Vector3(20, 21, 22);
m_numberOfAttachEventsFired = 0;
sceneA.RequestTeleportLocation(
beforeTeleportSp.ControllingClient,
sceneB.RegionInfo.RegionHandle,
@ -616,29 +658,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0));
Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0));
}
// I'm commenting this test because scene setup NEEDS InventoryService to
// be non-null
//[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");
// }
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
}
}
}

View File

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

View File

@ -197,6 +197,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
string fromName = c.From;
string fromNamePrefix = "";
UUID fromID = UUID.Zero;
UUID ownerID = UUID.Zero;
string message = c.Message;
IScene scene = c.Scene;
UUID destination = c.Destination;
@ -224,11 +225,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
fromNamePrefix = m_adminPrefix;
}
destination = UUID.Zero; // Avatars cant "SayTo"
ownerID = c.Sender.AgentId;
break;
case ChatSourceType.Object:
fromID = c.SenderUUID;
if (c.SenderObject != null && c.SenderObject is SceneObjectPart)
ownerID = ((SceneObjectPart)c.SenderObject).OwnerID;
break;
}
@ -262,9 +268,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
// objects on a parcel with access restrictions
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);
}
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))
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);
receiverIDs.Add(client.AgentId);
}
@ -341,15 +355,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
/// <param name="fromPos"></param>
/// <param name="regionPos">/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="type"></param>
/// <param name="message"></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
/// precondition</returns>
protected virtual bool TrySendChatMessage(ScenePresence presence, Vector3 fromPos, Vector3 regionPos,
UUID fromAgentID, string fromName, ChatTypeEnum type,
string message, ChatSourceType src)
protected virtual bool TrySendChatMessage(
ScenePresence presence, Vector3 fromPos, Vector3 regionPos,
UUID fromAgentID, UUID ownerID, string fromName, ChatTypeEnum type,
string message, ChatSourceType src, bool ignoreDistance)
{
// don't send chat to child agents
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
presence.ControllingClient.SendChatMessage(message, (byte) type, fromPos, fromName,
fromAgentID, (byte)src, (byte)ChatAudibleLevel.Fully);
presence.ControllingClient.SendChatMessage(
message, (byte) type, fromPos, fromName,
fromAgentID, ownerID, (byte)src, (byte)ChatAudibleLevel.Fully);
return true;
}

View File

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

View File

@ -28,6 +28,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using log4net;
@ -482,9 +483,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
Util.FireAndForget(
delegate
{
m_log.DebugFormat(
"[FRIENDS MODULE]: Notifying {0} friends of {1} of online status {2}",
friendList.Count, agentID, online);
// m_log.DebugFormat(
// "[FRIENDS MODULE]: Notifying {0} friends of {1} of online status {2}",
// friendList.Count, agentID, online);
// Notify about this user status
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)
{
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;
if (UUID.TryParse(friend.Friend, out friendID))
UUID friendUuid;
if (UUID.TryParse(friendStringId, out friendUuid))
{
// Try local
if (LocalStatusNotification(userID, friendID, online))
if (LocalStatusNotification(userID, friendUuid, online))
continue;
// The friend is not here [as root]. Let's forward.
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.
remoteFriendStringIds.Add(friendStringId);
}
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(
m_scene, godID, "God", agentID, (byte)250, false,
Utils.BytesToString(reason), UUID.Zero, true,
new Vector3(), new byte[] {(byte)kickflags}),
new Vector3(), new byte[] {(byte)kickflags}, true),
delegate(bool success) {} );
}
return;

View File

@ -166,7 +166,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
if (options.ContainsKey("verbose"))
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);
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);
new AssetsRequest(
AssetsRequest ar
= new AssetsRequest(
new AssetsArchiver(m_archiveWriter),
m_assetUuids, m_scene.AssetService,
m_scene.UserAccountService, m_scene.RegionInfo.ScopeID,
options, ReceivedAllAssets).Execute();
options, ReceivedAllAssets);
Util.FireAndForget(o => ar.Execute());
}
else
{

View File

@ -35,6 +35,7 @@ using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Communications;
using OpenSim.Framework.Console;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
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,
Dictionary<string, object> options)
{
// if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, savePath))
// return false;
if (m_scenes.Count > 0)
{
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_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]
public override void SetUp()
{
@ -90,12 +108,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
m_iarStream = new MemoryStream(m_iarStreamBytes);
}
[TestFixtureSetUp]
public void FixtureSetup()
{
ConstructDefaultIarBytesForTestLoad();
}
protected void ConstructDefaultIarBytesForTestLoad()
{
// log4net.Config.XmlConfigurator.Configure();

View File

@ -69,7 +69,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
public void TestLoadCoalesecedItem()
{
TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure();
// TestHelpers.EnableLogging();
UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "password");
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));
}
/// <summary>
/// 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.
/// </summary>
[Test]
public void TestLoadIarV0_1SameNameCreator()
{
TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure();
UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood");
UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire");
m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream);
InventoryItemBase foundItem1
= InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
Assert.That(
foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()),
"Loaded item non-uuid creator doesn't match original");
Assert.That(
foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID),
"Loaded item uuid creator doesn't match original");
Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID),
"Loaded item owner doesn't match inventory reciever");
AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
string xmlData = Utils.BytesToString(asset1.Data);
SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID));
}
// /// <summary>
// /// 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.
// /// </summary>
// [Test]
// public void TestLoadIarV0_1SameNameCreator()
// {
// TestHelpers.InMethod();
// TestHelpers.EnableLogging();
//
// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood");
// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire");
//
// m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream);
// InventoryItemBase foundItem1
// = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
//
// Assert.That(
// foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()),
// "Loaded item non-uuid creator doesn't match original");
// Assert.That(
// foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID),
// "Loaded item uuid creator doesn't match original");
// Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID),
// "Loaded item owner doesn't match inventory reciever");
//
// AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
// string xmlData = Utils.BytesToString(asset1.Data);
// SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
//
// Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID));
// }
/// <summary>
/// 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
{
public class InventoryTransferModule : IInventoryTransferModule, ISharedRegionModule
public class InventoryTransferModule : ISharedRegionModule
{
private static readonly ILog m_log
= LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
private List<Scene> m_Scenelist = new List<Scene>();
private Dictionary<UUID, Scene> m_AgentRegions =
new Dictionary<UUID, Scene>();
// private Dictionary<UUID, Scene> m_AgentRegions =
// new Dictionary<UUID, Scene>();
private IMessageTransferModule m_TransferModule = null;
private bool m_Enabled = true;
@ -76,12 +76,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
m_Scenelist.Add(scene);
scene.RegisterModuleInterface<IInventoryTransferModule>(this);
// scene.RegisterModuleInterface<IInventoryTransferModule>(this);
scene.EventManager.OnNewClient += OnNewClient;
scene.EventManager.OnClientClosed += ClientLoggedOut;
// scene.EventManager.OnClientClosed += ClientLoggedOut;
scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene;
// scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene;
}
public void RegionLoaded(Scene scene)
@ -96,9 +96,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
m_Scenelist.Clear();
scene.EventManager.OnNewClient -= OnNewClient;
scene.EventManager.OnClientClosed -= ClientLoggedOut;
// scene.EventManager.OnClientClosed -= ClientLoggedOut;
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)
{
scene.EventManager.OnNewClient -= OnNewClient;
scene.EventManager.OnClientClosed -= ClientLoggedOut;
// scene.EventManager.OnClientClosed -= ClientLoggedOut;
scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
// scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
m_Scenelist.Remove(scene);
}
@ -138,10 +138,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
client.OnInstantMessage += OnInstantMessage;
}
protected void OnSetRootAgentScene(UUID id, Scene scene)
{
m_AgentRegions[id] = scene;
}
// protected void OnSetRootAgentScene(UUID id, Scene scene)
// {
// m_AgentRegions[id] = scene;
// }
private Scene FindClientScene(UUID agentId)
{
@ -313,6 +313,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
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)
{
UUID destinationFolderID = UUID.Zero;
@ -324,6 +329,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
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;
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);
item = invService.GetItem(item);
InventoryFolderBase folder = null;
UUID? previousParentFolderID = null;
if (item != null) // It's an item
{
previousParentFolderID = item.Folder;
item.Folder = destinationFolderID;
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
{
previousParentFolderID = folder.ParentID;
folder.ParentID = destinationFolderID;
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 (
@ -370,9 +399,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId);
item = invService.GetItem(item);
InventoryFolderBase folder = null;
UUID? previousParentFolderID = null;
if (item != null && trashFolder != null)
{
previousParentFolderID = item.Folder;
item.Folder = trashFolder.ID;
// 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)
{
previousParentFolderID = folder.ParentID;
folder.ParentID = trashFolder.ID;
invService.MoveFolder(folder);
client.SendBulkUpdateInventory(folder);
@ -408,6 +440,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
client.SendAgentAlertMessage("Unable to delete "+
"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)
{
@ -426,69 +468,69 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
}
}
public bool NeedSceneCacheClear(UUID agentID, Scene scene)
{
if (!m_AgentRegions.ContainsKey(agentID))
{
// Since we can get here two ways, we need to scan
// the scenes here. This is somewhat more expensive
// but helps avoid a nasty bug
// public bool NeedSceneCacheClear(UUID agentID, Scene scene)
// {
// if (!m_AgentRegions.ContainsKey(agentID))
// {
// // Since we can get here two ways, we need to scan
// // the scenes here. This is somewhat more expensive
// // but helps avoid a nasty bug
// //
//
foreach (Scene s in m_Scenelist)
{
ScenePresence presence;
if (s.TryGetScenePresence(agentID, out presence))
{
// If the agent is in this scene, then we
// are being called twice in a single
// teleport. This is wasteful of cycles
// but harmless due to this 2nd level check
// foreach (Scene s in m_Scenelist)
// {
// ScenePresence presence;
//
// If the agent is found in another scene
// then the list wasn't current
// if (s.TryGetScenePresence(agentID, out presence))
// {
// // If the agent is in this scene, then we
// // are being called twice in a single
// // teleport. This is wasteful of cycles
// // but harmless due to this 2nd level check
// //
// // If the agent is found in another scene
// // then the list wasn't current
// //
// // If the agent is totally unknown, then what
// // are we even doing here??
// //
// if (s == scene)
// {
// //m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName);
// return true;
// }
// else
// {
// //m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName);
// return false;
// }
// }
// }
// //m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName);
// return true;
// }
//
// If the agent is totally unknown, then what
// are we even doing here??
// // The agent is left in current Scene, so we must be
// // going to another instance
// //
// if (m_AgentRegions[agentID] == scene)
// {
// //m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName);
// m_AgentRegions.Remove(agentID);
// return true;
// }
//
if (s == scene)
{
//m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName);
return true;
}
else
{
//m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName);
return false;
}
}
}
//m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName);
return true;
}
// The agent is left in current Scene, so we must be
// going to another instance
// // Another region has claimed the agent
// //
// //m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName);
// return false;
// }
//
if (m_AgentRegions[agentID] == scene)
{
//m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName);
m_AgentRegions.Remove(agentID);
return true;
}
// Another region has claimed the agent
//
//m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName);
return false;
}
public void ClientLoggedOut(UUID agentID, Scene scene)
{
if (m_AgentRegions.ContainsKey(agentID))
m_AgentRegions.Remove(agentID);
}
// public void ClientLoggedOut(UUID agentID, Scene scene)
// {
// if (m_AgentRegions.ContainsKey(agentID))
// m_AgentRegions.Remove(agentID);
// }
/// <summary>
///

View File

@ -186,7 +186,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
client.FirstName+" "+client.LastName, targetid,
(byte)InstantMessageDialog.RequestTeleport, false,
message, sessionID, false, presence.AbsolutePosition,
new Byte[0]);
new Byte[0], true);
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);

View File

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

View File

@ -327,6 +327,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
return;
}
// Validate assorted conditions
string reason = string.Empty;
if (!ValidateGenericConditions(sp, reg, finalDestination, teleportFlags, out reason))
{
sp.ControllingClient.SendTeleportFailed(reason);
return;
}
//
// 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>
/// Determines whether this instance is within the max transfer distance.
/// </summary>
@ -473,10 +488,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// both regions
if (sp.ParentID != (uint)0)
sp.StandUp();
else if (sp.Flying)
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);
// 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
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);
}
else
{
@ -574,7 +593,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
//sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent...");
if (!UpdateAgent(reg, finalDestination, agent))
if (!UpdateAgent(reg, finalDestination, agent, sp))
{
// Region doesn't take it
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.
Thread.Sleep(3000);
sp.Scene.IncomingCloseAgent(sp.UUID);
sp.Scene.IncomingCloseAgent(sp.UUID, false);
}
else
{
@ -658,13 +677,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
sp.Reset();
}
// 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",
sp.UUID);
}
// Commented pending deletion since this method no longer appears to do anything at all
// // 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",
// sp.UUID);
// }
m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
}
@ -701,7 +721,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
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);
}
@ -1013,6 +1033,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
Scene initiatingScene)
{
Thread.Sleep(10000);
IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>();
if (im != null)
{
@ -1025,11 +1046,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
(uint)(int)position.X,
(uint)(int)position.Y,
(uint)(int)position.Z);
GridInstantMessage m = new GridInstantMessage(initiatingScene, UUID.Zero,
"Region", agent.UUID,
(byte)InstantMessageDialog.GodLikeRequestTeleport, false,
"", gotoLocation, false, new Vector3(127, 0, 0),
new Byte[0]);
GridInstantMessage m
= new GridInstantMessage(
initiatingScene,
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)
{
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,
// so the userinfo in UserProfileCache is not reliable any more, delete it
// REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
if (agent.Scene.NeedSceneCacheClear(agent.UUID))
{
m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID);
}
// if (agent.Scene.NeedSceneCacheClear(agent.UUID))
// {
// m_log.DebugFormat(
// "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID);
// }
//m_log.Debug("AFTER CROSS");
//Scene.DumpChildrenSeeds(UUID);

View File

@ -54,6 +54,59 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
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
public override string Name
@ -72,8 +125,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
{
IConfig transferConfig = source.Configs["EntityTransfer"];
if (transferConfig != null)
{
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);
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: {0} enabled.", Name);
}
@ -85,7 +148,36 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
base.AddRegion(scene);
if (m_Enabled)
{
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)
@ -120,7 +212,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID);
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);
GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID);
@ -140,7 +232,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
return true;
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 false;
@ -153,6 +245,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
{
// Log them out of this grid
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;
logout = false;
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
// check if HyperGrid teleport is allowed, based on user level
if (sp.UserLevel < m_levelHGTeleport)
// for local users, check if HyperGrid teleport is allowed, based on user level
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.");
reason = "Hypergrid teleport not allowed";
@ -200,6 +294,124 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
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)
{
m_log.DebugFormat(

View File

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

View File

@ -92,7 +92,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
m_HomeURI = thisModuleConfig.GetString("HomeURI", m_HomeURI);
m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true);
m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", string.Empty);
m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", false);
m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", true);
}
else
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
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);
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)
@ -308,6 +313,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
protected override InventoryItemBase GetItem(UUID agentID, UUID itemID)
{
InventoryItemBase item = base.GetItem(agentID, itemID);
if (item == null)
return null;
string userAssetServer = string.Empty;
if (IsForeignUser(agentID, out userAssetServer))
@ -344,6 +351,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
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)
{
// No-op for now
}
#endregion

View File

@ -95,14 +95,14 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
{
foreach (IMonitor monitor in m_staticMonitors)
{
m_log.InfoFormat(
MainConsole.Instance.OutputFormat(
"[MONITOR MODULE]: {0} reports {1} = {2}",
m_scene.RegionInfo.RegionName, monitor.GetFriendlyName(), monitor.GetFriendlyValue());
}
foreach (KeyValuePair<string, float> tuple in m_scene.StatsReporter.GetExtraSimStats())
{
m_log.InfoFormat(
MainConsole.Instance.OutputFormat(
"[MONITOR MODULE]: {0} reports {1} = {2}",
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));
}
public void Flush()
{
if (!Enabled) return;
if (m_logFile != null)
{
m_logFile.Flush();
}
}
public void Write(string line)
{
if (!Enabled) return;

View File

@ -137,6 +137,9 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
ud.FirstName = words[0];
ud.LastName = "@" + words[1];
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);
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.Console;
using OpenSim.Region.ClientStack.LindenUDP;
using OpenSim.Region.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
@ -430,7 +431,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
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);
AddUser(uuid, homeURL + ";" + first + " " + last);
}
@ -553,8 +553,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
MainConsole.Instance.Output("-----------------------------------------------------------------------------");
foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache)
{
MainConsole.Instance.Output(String.Format("{0} {1} {2}",
kvp.Key, kvp.Value.FirstName, kvp.Value.LastName));
MainConsole.Instance.Output(String.Format("{0} {1} {2} ({3})",
kvp.Key, kvp.Value.FirstName, kvp.Value.LastName, kvp.Value.HomeURL));
}
return;

View File

@ -15,6 +15,7 @@
<RegionModule id="InventoryAccessModule" type="OpenSim.Region.CoreModules.Framework.InventoryAccess.BasicInventoryAccessModule" />
<RegionModule id="HGInventoryAccessModule" type="OpenSim.Region.CoreModules.Framework.InventoryAccess.HGInventoryAccessModule" />
<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="ExportSerialisationModule" type="OpenSim.Region.CoreModules.World.Serialiser.SerialiserModule" />
<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

@ -49,6 +49,22 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
public const int DISP_EXPIRE = 1;
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<string, IDynamicTextureRender> RenderPlugins =
@ -56,6 +72,15 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
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
public void RegisterRender(string handleType, IDynamicTextureRender render)
@ -69,17 +94,17 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
/// <summary>
/// Called by code which actually renders the dynamic texture to supply texture data.
/// </summary>
/// <param name="id"></param>
/// <param name="data"></param>
public void ReturnData(UUID id, byte[] data)
/// <param name="updaterId"></param>
/// <param name="texture"></param>
public void ReturnData(UUID updaterId, IDynamicTexture texture)
{
DynamicTextureUpdater updater = null;
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))
{
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,
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,
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();
updater.SimUUID = simID;
updater.PrimID = primID;
@ -183,6 +255,28 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
updater.Url = "Local image";
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)
{
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);
}
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 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,
@ -215,6 +327,13 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
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))
{
RegisteredScenes.Add(scene.RegionInfo.RegionID, scene);
@ -224,6 +343,11 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
public void PostInitialise()
{
if (ReuseTextures)
{
m_reuseableDynamicTextures = new Cache(CacheMedium.Memory, CacheStrategy.Conservative);
m_reuseableDynamicTextures.DefaultTTL = new TimeSpan(24, 0, 0);
}
}
public void Close()
@ -268,10 +392,61 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
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>
/// Called once new texture data has been received for this updater.
/// </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);
@ -281,7 +456,8 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
String.Format("DynamicTextureModule: Error preparing image using URL {0}", Url);
scene.SimChat(Utils.StringToBytes(msg), ChatTypeEnum.Say,
0, part.ParentGroup.RootPart.AbsolutePosition, part.Name, part.UUID, false);
return;
return UUID.Zero;
}
byte[] assetData = null;
@ -319,56 +495,29 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
IJ2KDecoder cacheLayerDecode = scene.RequestModuleInterface<IJ2KDecoder>();
if (cacheLayerDecode != null)
{
cacheLayerDecode.Decode(asset.FullID, asset.Data);
cacheLayerDecode = null;
if (!cacheLayerDecode.Decode(asset.FullID, asset.Data))
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;
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());
}
UUID oldID = UpdatePart(part, asset.FullID);
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.Temporary == true)
if (oldAsset.Temporary)
{
scene.AssetService.Delete(oldID.ToString());
}
}
}
return asset.FullID;
}
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 int responseCode;
public string responseBody;
public string responseType = "text/plain";
//public ManualResetEvent ev;
public bool requestDone;
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)
{
lock (m_RequestMap)

View File

@ -32,6 +32,7 @@ using System.Net;
using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.Imaging;
using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using log4net;
@ -67,12 +68,18 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
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;
}
public byte[] ConvertStream(Stream data, string extraParams)
public IDynamicTexture ConvertData(string bodyData, string extraParams)
{
return null;
}
@ -165,11 +172,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
private void HttpRequestReturn(IAsyncResult result)
{
RequestState state = (RequestState) result.AsyncState;
WebRequest request = (WebRequest) state.Request;
Stream stream = null;
byte[] imageJ2000 = new byte[0];
Size newSize = new Size(0, 0);
try
{
@ -182,38 +189,44 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
try
{
Bitmap image = new Bitmap(stream);
Size newsize;
// TODO: make this a bit less hard coded
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))
{
newsize = new Size(64, 64);
newSize.Width = 64;
newSize.Height = 64;
}
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))
{
newsize = new Size(256, 256);
newSize.Width = 256;
newSize.Height = 256;
}
else if ((image.Height < 1024 && image.Width < 1024))
{
newsize = new Size(512, 512);
newSize.Width = 512;
newSize.Height = 512;
}
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);
}
}
catch (Exception)
{
m_log.Error("[LOADIMAGEURLMODULE]: OpenJpeg Conversion Failed. Empty byte data returned!");
@ -227,7 +240,6 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
}
catch (WebException)
{
}
finally
{
@ -236,9 +248,14 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
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);
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

View File

@ -130,10 +130,22 @@ namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms
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)
{
MethodInfo mi = target.GetType().GetMethod(meth,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
MethodInfo mi = GetMethodInfoFromType(target.GetType(), meth, true);
if (mi == null)
{
m_log.WarnFormat("[MODULE COMMANDS] Failed to register method {0}", meth);
@ -151,10 +163,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms
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;
var typeArgs = mi.GetParameters()
List<Type> typeArgs = mi.GetParameters()
.Select(p => p.ParameterType)
.ToList();
@ -168,7 +180,11 @@ namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms
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)
{
@ -184,6 +200,35 @@ namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms
}
}
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()
{
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>
/// Operation to check for a registered constant
/// </summary>

View File

@ -45,31 +45,292 @@ using OpenSim.Tests.Common.Mock;
namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
{
[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]
public void TestDraw()
{
TestHelpers.InMethod();
Scene scene = new SceneHelpers().SetupScene();
DynamicTextureModule dtm = new DynamicTextureModule();
VectorRenderModule vrm = new VectorRenderModule();
SceneHelpers.SetupSceneModules(scene, dtm, vrm);
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene);
SetupScene(false);
SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
dtm.AddDynamicTextureData(
scene.RegionInfo.RegionID,
m_dtm.AddDynamicTextureData(
m_scene.RegionInfo.RegionID,
so.UUID,
vrm.GetContentType(),
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));
}
[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));
}
[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.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.Imaging;
using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using log4net;
@ -45,9 +47,13 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
{
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 string m_name = "VectorRenderModule";
private Scene m_scene;
private IDynamicTextureManager m_textureManager;
private Graphics m_graph;
@ -61,12 +67,12 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
public string GetContentType()
{
return ("vector");
return "vector";
}
public string GetName()
{
return m_name;
return Name;
}
public bool SupportsAsynchronous()
@ -74,14 +80,20 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
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;
}
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)
@ -91,16 +103,22 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
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;
}
public void GetDrawStringSize(string text, string fontName, int fontSize,
out double xSize, out double ySize)
{
lock (this)
{
using (Font myFont = new Font(fontName, fontSize))
{
SizeF stringSize = new SizeF();
// XXX: This lock may be unnecessary.
lock (m_graph)
{
stringSize = m_graph.MeasureString(text, myFont);
@ -109,6 +127,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
}
}
}
}
#endregion
@ -144,6 +163,13 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
{
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()
@ -152,7 +178,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
public string Name
{
get { return m_name; }
get { return "VectorRenderModule"; }
}
public bool IsSharedModule
@ -162,7 +188,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
#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 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;
Graphics graph = null;
bool reuseable = false;
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)
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];
// 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
{
imageJ2000 = OpenJPEG.EncodeFromImage(bitmap, true);
@ -351,9 +394,17 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
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
{
// 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)
graph.Dispose();
@ -362,6 +413,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
bitmap.Dispose();
}
}
}
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 endPoint = new Point(0, 0);
Pen drawPen = null;
@ -434,11 +499,9 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
myFont = new Font(fontName, fontSize);
myBrush = new SolidBrush(Color.Black);
char[] lineDelimiter = {dataDelim};
char[] partsDelimiter = {','};
string[] lines = data.Split(lineDelimiter);
foreach (string line in lines)
foreach (string line in GetLines(data, dataDelim))
{
string nextLine = line.Trim();
//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"))
{
// We cannot reuse any generated texture involving fetching an image via HTTP since that image
// can change.
reuseable = false;
float x = 0;
float y = 0;
GetParams(partsDelimiter, ref nextLine, 5, ref x, ref y);

View File

@ -28,6 +28,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
@ -172,12 +173,42 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
/// <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="id">
/// key to filter on (user given, could be totally faked)
/// </param>
/// <param name="msg">msg to filter on</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)
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>
@ -326,7 +357,7 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
if (channel == 0)
{
// 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;
}
@ -470,15 +501,25 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
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?
List<ListenerInfo> coll = GetListeners(itemID, channel, name, id, msg);
List<ListenerInfo> coll = GetListeners(itemID, channel, name, id,
msg);
if (coll.Count > 0)
{
// special case, called with same filter settings, return same handle
// (2008-05-02, tested on 1.21.1 server, still holds)
// special case, called with same filter settings, return same
// handle (2008-05-02, tested on 1.21.1 server, still holds)
return coll[0].GetHandle();
}
@ -490,7 +531,9 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
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;
if (!m_listeners.TryGetValue(channel,out listeners))
@ -631,6 +674,22 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
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
// do this, maybe with regex.
// PM2008: Ha, one could even be smart and define a specialized Enumerator.
@ -656,7 +715,10 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
{
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;
}
@ -664,7 +726,10 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
{
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;
}
@ -697,10 +762,13 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
{
int idx = 0;
Object[] item = new Object[6];
int dataItemLength = 6;
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.FromData(localID, itemID, hostID, item);
@ -712,7 +780,7 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
m_listeners[(int)item[2]].Add(info);
}
idx+=6;
idx+=dataItemLength;
}
}
}
@ -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)
{
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)
{
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,
UUID id, string message)
public ListenerInfo(ListenerInfo li, string name, UUID id, string message, int regexBitfield)
{
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_handle = handle;
@ -751,11 +832,12 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
m_name = name;
m_id = id;
m_message = message;
RegexBitfield = regexBitfield;
}
public Object[] GetSerializationData()
{
Object[] data = new Object[6];
Object[] data = new Object[7];
data[0] = m_active;
data[1] = m_handle;
@ -763,16 +845,19 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
data[3] = m_name;
data[4] = m_id;
data[5] = m_message;
data[6] = RegexBitfield;
return data;
}
public static ListenerInfo FromData(uint localID, UUID ItemID, UUID hostID, Object[] data)
{
ListenerInfo linfo = new ListenerInfo((int)data[1], localID,
ItemID, hostID, (int)data[2], (string)data[3],
(UUID)data[4], (string)data[5]);
ListenerInfo linfo = new ListenerInfo((int)data[1], localID, ItemID, hostID, (int)data[2], (string)data[3], (UUID)data[4], (string)data[5]);
linfo.m_active = (bool)data[0];
if (data.Length >= 7)
{
linfo.RegexBitfield = (int)data[6];
}
return linfo;
}
@ -831,5 +916,7 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
{
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 AssetPermissions m_AssetPerms;
public Type ReplaceableInterface
{
get { return null; }
@ -128,6 +130,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
if (m_LocalAssetServiceURI != string.Empty)
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_log.Info("[HG ASSET CONNECTOR]: HG asset broker enabled");
}
@ -206,14 +211,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
asset = m_HGService.Get(id);
if (asset != null)
{
// Now store it locally
// For now, let me just do it for textures and scripts
if (((AssetType)asset.Type == AssetType.Texture) ||
((AssetType)asset.Type == AssetType.LSLBytecode) ||
((AssetType)asset.Type == AssetType.LSLText))
{
// Now store it locally, if allowed
if (m_AssetPerms.AllowedImport(asset.Type))
m_GridService.Store(asset);
}
else
return null;
}
}
else
@ -328,7 +330,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
string id = string.Empty;
if (IsHG(asset.ID))
{
if (m_AssetPerms.AllowedExport(asset.Type))
id = m_HGService.Store(asset);
else
return String.Empty;
}
else
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);
AssetBase asset = m_Cache.Get(id);
AssetBase asset = null;
if (m_Cache != null)
asset = m_Cache.Get(id);
if (asset != null)
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
{
[TestFixture]
public class GridConnectorsTests
public class GridConnectorsTests : OpenSimTestCase
{
LocalGridServicesConnector m_LocalConnector;
private void SetUp()
[SetUp]
public override void SetUp()
{
base.SetUp();
IConfigSource config = new IniConfigSource();
config.AddConfig("Modules");
config.AddConfig("GridService");
@ -71,8 +75,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure();
SetUp();
// Create 4 regions
GridRegion r1 = new GridRegion();
r1.RegionName = "Test Region 1";

View File

@ -65,11 +65,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
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)
{
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(
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)
@ -82,9 +84,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
if (client.SceneAgent.IsChildAgent)
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(
client.AgentId.ToString(), client.SessionId, client.Scene.RegionInfo.RegionID,
userId, client.SessionId, client.Scene.RegionInfo.RegionID,
client.SceneAgent.AbsolutePosition, client.SceneAgent.Lookat);
}
}

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